- Print
- DarkLight
Overview
Your app can easily implement the Vuzix Speech SDK to allow custom phrases to be spoken at any time, without the system automatically placing any UI elements on your screens. This provides the most features of the SDK to be used by your app and gives you the greatest control over the presentation in your user interface.
Creating the Speech Client
To work with the Vuzix Speech SDK, you first create a VuzixSpeechClient, and pass it your Activity
Java
import com.vuzix.sdk.speechrecognitionservice.VuzixSpeechClient;
Activity myActivity = this;
VuzixSpeechClient sc = new VuzixSpeechClient(myActivity);
Handling Exceptions
It is possible for a user to attempt to run code compiled against the Vuzix Speech SDK on non-Vuzix hardware. This will generate a RuntimeException "Stub!" to be thrown. It is also possible to write an application against the latest Vuzix Speech SDK, and have customers attempt to run the application on older devices. Any calls to unsupported interfaces will cause a NoClassDefFoundError. For this reason all SDK calls should be inside try / catch blocks.
Java
// Surround the creation of the VuzixSpeechClient with a try/catch for non-Vuzix hardware
VuzixSpeechClient sc;
try {
sc = new VuzixSpeechClient(myActivity);
}
catch(RuntimeException e) {
if(e.getMessage().equals("Stub!")) {
// This is not being run on Vuzix hardware (or the Proguard rules are incorrect)
// Alert the user, or insert recovery here.
}
else {
// Other RuntimeException to be handled
}
}
// Surround all speech client commands with a try/catch for unsupported interfaces
try {
// sc.anySdkCommandHere();
}
catch(NoClassDefFoundError e) {
// The hardware does not support the specific command expected by the Vuzix Speech SDK.
// Alert the user, or insert recovery here.
}
For brevity, this remainder of this article will omit the try/catch blocks, but creating a robust application requires they be present.
Debugging the Current Vocabulary
To aid in debugging, it is often important while manipulating the vocabulary to dump the active vocabulary to the log. You may use the above getPhrases() for this, or if you prefer, you may use the dump() command to generate a pre-formatted block of text.
Java
Log.i(LOG_TAG, sc.dump());
Adding Custom Trigger Phrases
When the speech command engine is enabled but idle it is listening only for a trigger phrase, also known as a "wake word". Once the trigger phrase is recognized, the engine transitions to the active state where it listens for the full vocabulary (such as "go home" and "select this"). By default the wake word is "Hello Vuzix". You can insert custom wake word phrases using the following commands.
Java
sc.insertWakeWordPhrase("hey sleek glasses"); // Add application specific wake-up phrase
Once active, the speech engine will time-out after the period configured in the system settings and return to the idle state that listens only for the trigger phrases. The operator can circumvent the timeout and immediately return to idle by saying a voice-off phrase. By default the voice-off phrase is "voice off" and "speech off". You can insert custom voice-off phrases using the following commands.
Java
sc.insertVoiceOffPhrase("privacy please"); // Add application specific stop listening phrase
Adding Phrases to Receive Keycodes
You can register for a spoken command that will generate a keycode. This keycode will behave exactly the same as if a USB keyboard were present and generated that key. This capability is implemented by mapping phrases to Android key events (android.view.KeyEvent).
Java
sc.insertKeycodePhrase("toggle caps lock", KEYCODE_CAPS_LOCK);
Log.i(LOG_TAG, sc.dump());
Keycodes added by your application will be processed in addition to the Keycodes in the base vocabulary set:
|
|
Keycodes denoted as "(repeats)" will generate the keycode repeating at a fixed interval until terminated by speaking any other valid phrase. The phrase "stop" terminates the repeating keycodes with no further behavior.
Receiving Intents
Many custom behaviors can be created using keycodes as described above, but usually we want a block of code to be run when a voice command is given by the user. We do this by receiving intents. Most developers can simply use the standard speech SDK intent.
Using the Standard Intent
Adding Phrases to Receive the Standard Intent
The most common use for the speech command engine is to receive intents which can trigger any custom actions, rather than simply receiving keycodes. To do this you must have a broadcast receiver in your application such as:
Java
public class VoiceCmdReceiver extends BroadcastReceiver { ... }
The broadcast receiver must register with Android for the Vuzix speech intent. This can be done in the constructor as shown here.
Java
public class VoiceCmdReceiver extends BroadcastReceiver {
public VoiceCmdReceiver(MainActivity iActivity) {
iActivity.registerReceiver(this, new IntentFilter(VuzixSpeechClient.ACTION_VOICE_COMMAND));
...
}
}
The phrases you want to receive can be inserted in the same constructor. This is done using insertPhrase() which registers a phrase for the speech SDK intent. The parameter is a string containing the phrase for which you want the device to listen.
Java
public class VoiceCmdReceiver extends BroadcastReceiver {
public VoiceCmdReceiver(MainActivity iActivity) {
iActivity.registerReceiver(this, new IntentFilter(VuzixSpeechClient.ACTION_VOICE_COMMAND));
VuzixSpeechClient sc = new VuzixSpeechClient(iActivity);
sc.insertPhrase( "testing" );
Log.i( LOG_TAG, sc.dump() );
}
}
Now handle the speech SDK intent VuzixSpeechClient.ACTION_VOICE_COMMAND in your onReceive() method. In this scenario, whatever phrase you used in insertPhrase() will be provided in the the received intent as a string extra named VuzixSpeechClient.PHRASE_STRING_EXTRA.
Note: if the phrase contains spaces, they will be replaced by underscores.
Java
public class VoiceCmdReceiver extends BroadcastReceiver {
public VoiceCmdReceiver(MainActivity iActivity) {...}
@Override public void onReceive(Context context, Intent intent) {
// All phrases registered with insertPhrase() match ACTION_VOICE_COMMAND
if (intent.getAction().equals(VuzixSpeechClient.ACTION_VOICE_COMMAND)) {
String phrase = intent.getStringExtra(VuzixSpeechClient.PHRASE_STRING_EXTRA);
if (phrase != null ) {
if (phrase.equals(sc.convertPhraseToReplyFormat("testing"))) {
// todo: take action upon hearing the spoken phrase "testing"
}
}
}
}
}
With the above example in place, you will be able to say "Hello Vuzix" to activate the recognizer, followed by "testing" and your //todo code will execute.
When calling phrase.equals if the phrase contains spaces, they will be replaced by underscores. Because of this it is best practice to call convertPhraseToReplyFormat() to account for all changes from the inserted phrase to the returned phrase.
The Speech Command engine always broadcasts the phrase that was registered in insertPhrase(). Note: If the phrase contains spaces, they will be replaced by underscores.
Specifying Substitution Text for the Standard Intent
As mentioned above, the string that was recognized is returned, with spaces replaced by underscores. That can be somewhat cumbersome to the developer, especially since we expect recognized spoken phrases to be localized into many languages.
To make this easier, insertPhrase() can take an optional substitution string parameter. When phrases are inserted this way, the substitution text passed to insertPhrase() will be provided in the the received intent as a string extra named VuzixSpeechClient.PHRASE_STRING_EXTRA, rather than the spoken phrase.
Note: the substitution string may not contain spaces.
This example updates the original by replacing the hard-coded strings properly. Notice insertPhrase() is given two parameters, and it is the second that is used by the onReceive() method.
This now gives us a complete solution to receive a custom phrase and handle it properly.
Java
public class VoiceCmdReceiver extends BroadcastReceiver {
final String MATCH_TESTING = "Phrase_Testing";
public VoiceCmdReceiver(MainActivity iActivity) {
iActivity.registerReceiver(this, new IntentFilter(VuzixSpeechClient.ACTION_VOICE_COMMAND));
VuzixSpeechClient sc = new VuzixSpeechClient(iActivity);
// strings.xml contains: <string name="spoken_phrase_testing">testing</string>
sc.insertPhrase( iActivity.getResources().getString(R.string.spoken_phrase_testing), MATCH_TESTING);
Log.i( LOG_TAG, sc.dump() );
}
@Override public void onReceive(Context context, Intent intent) {
// All phrases registered with insertPhrase() match ACTION_VOICE_COMMAND if (intent.getAction().equals(VuzixSpeechClient.ACTION_VOICE_COMMAND)) {
String phrase = intent.getStringExtra(VuzixSpeechClient.PHRASE_STRING_EXTRA);
if (phrase != null ) {
if (phrase.equals(MATCH_TESTING)) {
// todo: take action upon hearing the spoken phrase "testing"
}
}
}
}
}
The substitution parameter also allows us to create multiple phrases that perform the same action. Phrases in the command engine must be unique but substitution text does not.
We could have multiple insertPhrase() calls with different phrase parameters and identical substitutions. Use this technique to simplify your code in situations where you do not need to differentiate between phrases. For example, the phrases "start call" and "make a call" can have the same substitution.
Using Custom Intents
There may be instances where using a custom intent, rather than the default SDK intent is preferred. This may be useful to automatically launch a specific Activity from any location in your application, without needing to duplicating the listener logic in every BroadcastReciever.
Adding Phrases to Receive Custom Intents
To add even more flexibility, the speech SDK can send any intent you define, rather than only sending its own ACTION_VOICE_COMMAND. This is especially useful for creating multiple broadcast receivers and directing the intents properly.
We define intents by calling defineIntent() and providing a unique text label for each intent. When we want to specify a phrase that will broadcast that intent, we identify it with that same text label.
Note, this example differs from the above in that the CUSTOM_SDK_INTENT is used in place of ACTION_VOICE_COMMAND
Java
public class VoiceCmdReceiver extends BroadcastReceiver {
public final String CUSTOM_SDK_INTENT = "com.your_company.CustomIntent";
final String CUSTOM_EVENT = "my_event";
public VoiceCmdReceiver(MainActivity iActivity) {
iActivity.registerReceiver(this, new IntentFilter(CUSTOM_SDK_INTENT);
VuzixSpeechClient sc = new VuzixSpeechClient(iActivity);
Intent customSdkIntent = new Intent(mMainActivity.CUSTOM_SDK_INTENT);
sc.defineIntent(CUSTOM_EVENT, customSdkIntent );
// strings.xml contains: <string name="spoken_phrase_testing">testing my voice application</string>
sc.insertIntentPhrase( iActivity.getResources().getString(R.string.spoken_phrase_testing), CUSTOM_EVENT);
Log.i( LOG_TAG, sc.dump() );
}
@Override public void onReceive(Context context, Intent intent) {
// Since we only registered one phrase to this intent, we don't need any further switching. We know we got our CUSTOM_EVENT
// todo: add test behavior
}
}
The system can support multiple broadcast receivers. Each receiver simply registers for the intents it expects to receive. They do not need to be in the same class that creates the VuzixSpeechClient.
Deleting a Custom Intent
Beginning with SDK v1.91 you can delete a custom intent. Call the deleteIntent() method and supply the label of the intent you previously defined. This will automatically delete any phrase that would have generated this intent.
Java
// Voice command custom intent names
final String TOAST_EVENT = "other_toast";
...
sc.deleteIntent(TOAST_EVENT);
Listing all Intent Labels
Beginning with SDK v1.91 you can list all intent labels. The list will be returned as a List.
Java
List<String> intentLabels = sc.getIntentLabels();
Removing Existing Phrases
Any phrases may be deleted once they are no longer applicable to the state of your application by calling deletePhrase().
Please note, phrases in the default vocabulary can be also be removed with this mechanism. Please see the Editing the Base Vocabulary section of this Knowledge Base for detailed instructions on how to properly customize the base vocabulary.
Java
sc.deletePhrase("pick this");
sc.deletePhrase("scroll right");
Checking the Engine Version
As mentioned above, it is possible for the SDK to expose newer calls than what is supported by a given device OS version. You can query getEngineVersion() to determine the version of the engine on the device to allow you to protect newer SDK calls with conditional logic to eliminate possible NoClassDefFoundError from being generated. For example, if you know the device is running SDK v1.8 you would not attempt calls introduced in v1.9.
Because getEngineVersion() is a newer SDK call, it should itself be protected.
Java
float version = 1.4f;
// The first stable SDK released with M300 v1.2.6
try {
version = sc.getEngineVersion();
Log.d(mMainActivity.LOG_TAG, "Device is running SDK v" + version);
}
catch (NoSuchMethodError e) {
Log.d(mMainActivity.LOG_TAG, "Device is running SDK prior to v1.8. Assuming version " + version);
}
Sample Project
A sample application for Android Studio demonstrating the Vuzix Speech SDK is available to download here.