- Print
- DarkLight
Overview
The built-in speech command engine allows multiple applications to each register their own unique vocabulary. As the user switches between applications, the engine automatically switches to the correct vocabulary. Only the active application receives the recognized phrases.
Applications with only a single vocabulary can get the behavior they desire with very little coding consideration. Applications with multiple activities and multiple vocabularies have special considerations discussed here.
Single Activity and Single Vocabulary
Applications with only a single vocabulary in a single Activity can do the required registration in the onCreate() method, and the required cleanup in the onDestroy().
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
// Register to receive intent that are generated by the Speech Command engine
registerReceiver(this, new IntentFilter(VuzixSpeechClient.ACTION_VOICE_COMMAND));
// Create a VuzixSpeechClient from the SDK and customize the vocabulary
VuzixSpeechClient sc = new VuzixSpeechClient(this);
sc.insertPhrase(MainActivity.getResources().getString(R.string.btn_text_clear));
}
catch (NoClassDefFoundError e) {
Toast.makeText(this, "Cannot find Vuzix Speech SDK", Toast.LENGTH_LONG).show();
}
catch (Exception e) {
Log.e(TAG, "Error setting custom vocabulary: " + e.getMessage());
}
}
@Override protected void onDestroy() {
// Remove the dynamic registration to the Vuzix Speech SDK
unregisterReceiver(this);
super.onDestroy();
}
This application is similar to the ones described in the preceding knowledge base articles, and ensures only the correct commands are received. Unfortunately, this only works in the simplest cases. It requires your application have only a single activity using speech commands, and the vocabulary never be changed within your application.
Multiple Vocabularies
A single Activity will have a single vocabulary associated with it. The Activity can modify that vocabulary at any time by calling deletePhrase(), insertPhrase(), insertIntentPhrase(), and insertKeycodePhrase().
The default intent with an action VuzixSpeechClient.ACTION_VOICE_COMMAND will still be used, so there is no need to call registerReceiver() when changing the existing vocabulary.
For example:
private void enableScanButton(boolean isEnabled ) {
mScanButton.setEnabled(isEnabled);
String scanBarcode = getResources().getString(R.string.scan_barcode);
if (isEnabled ) {
sc.insertPhrase(scanBarcode);
}
else {
sc.deletePhrase(scanBarcode);
}
}
This same behavior could be achieved by inserting that scanBarcode phrase in the onCreate() and simply ignoring it when it is not expected. But many developers prefer actively modifying the vocabulary as shown above.
Multiple Activities
Many applications consist of multiple activities. If each Activity were to be registered for the same speech intents, both would receive the commands. This would cause significant confusion if not handled properly. There are a few easy mechanisms that can be used to solve this.
You can dynamically un-register and re-register for the intents based on the activity life cycle, or you can choose to receive a custom unique intent for each phrase. Both are described in sub-sections below.
Multiple Activities - Dynamic Registration
One mechanism to ensure the correct speech commands are routed to the correct activity within a multi-activity application is for each activity to dynamically register and unregister for the speech intent. Each activity will receive the same default intent action, but only while in the foreground.
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
// Create a VuzixSpeechClient from the SDK and customize the vocabulary
VuzixSpeechClient sc = new VuzixSpeechClient(this);
sc.insertPhrase(mMainActivity.getResources().getString(R.string.btn_text_clear));
}
catch (NoClassDefFoundError e) {
Toast.makeText(this, "Cannot find Vuzix Speech SDK", Toast.LENGTH_LONG).show();
}
catch (Exception e) {
Log.e(TAG, "Error setting custom vocabulary: " + e.getMessage());
}
}
@Override protect void onResume() {
super.onResume();
// Dynamically register to receive intent from the Vuzix Speech SDK
registerReceiver(this, new IntentFilter(VuzixSpeechClient.ACTION_VOICE_COMMAND));
}
@Override protected void onPause() {
// Remove the dynamic registration to the Vuzix Speech SDK
unregisterReceiver(this);
super.onPause();
}
In this example, each activity creates its vocabulary once. Each time an activity is paused, it unregisters and stops receiving speech commands. Each time an activity is resumed, it re-registers and resumes receiving speech commands.
This allows multiple activities to co-exist in a single application and each get speech commands only when they are active.
The only downside to this mechanism is the activity will not get the command engine state changes while it is not active. For example, it will not know if the speech command engine has become disabled or has timed out. For many applications this does not impact the behavior, and this mechanism is the most appropriate.
Multiple Activities - Unique Intents
Another mechanism exists to control the routing of speech commands. This uses slightly more code than dynamically registering and un-registering to receive the intents and allows all activities to receive the advanced command engine state data, without receiving the incorrect speech commands. This should be used when it is important to maintain the state of the speech command engine in your activities.
The speech engine allows a developer to specify a custom intent action, instead of relying on the default VuzixSpeechClient.ACTION_VOICE_COMMAND action.
The custom intents do not have any extras, so you must have one custom intent per phrase. Each activity will create a unique intent for each phrase, such as:
public final String CUSTOM_BARCODE_INTENT = "com.vuzix.sample.MainActivity.BarcodeIntent";
public final String CUSTOM_SETTINGS_INTENT = "com.vuzix.sample.MainActivity.SettingsIntent";
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
// Create a VuzixSpeechClient from the SDK VuzixSpeechClient sc = new VuzixSpeechClient(this);
// Associate the phrase "Scan Barcode" with generating the CUSTOM_BARCODE_INTENT intent
final String barcodeIntentId = "ScanBarcodeId";
registerReceiver(this, new IntentFilter(CUSTOM_BARCODE_INTENT));
sc.defineIntent(barcodeIntentId, new Intent(CUSTOM_BARCODE_INTENT) );
sc.insertIntentPhrase("Scan Barcode", barcodeIntentId);
// Associate the phrase "Show Settings" with generating the CUSTOM_SETTINGS_INTENT intent
final String showSettingsId = "ShowSettingId";
registerReceiver(this, new IntentFilter(CUSTOM_SETTINGS_INTENT));
sc.defineIntent(showSettingsId, new Intent(CUSTOM_SETTINGS_INTENT) );
sc.insertIntentPhrase("Show Settings", showSettingsId);
}
catch (NoClassDefFoundError e) {
Toast.makeText(this, "Cannot find Vuzix Speech SDK", Toast.LENGTH_LONG).show();
}
catch (Exception e) {
Log.e(TAG, "Error setting custom vocabulary: " + e.getMessage());
}
}
@Override public void onReceive(Context context, Intent intent) {
// Now we have a unique action for each phrase
if (intent.getAction().equals(CUSTOM_BARCODE_INTENT)) {
// todo: scan barcode
}
else if (intent.getAction().equals(CUSTOM_SETTINGS_INTENT)) {
// todo: open settings menu
}
}
@Override protected void onDestroy() {
unregisterReceiver(this);
super.onDestroy();
}
In the above example, we have a single intent action for each vocabulary word. These each include "MainActivity" in this example. To continue this pattern, you would create other activities with unique names such as "SettingsActivity". This makes the processing very deterministic. Each activity only registers for its own unique intents.
As the user switches between activities, the vocabulary will be changed in the engine, and even if both activities recognize the same phrase, the unique intent will be generated based on the current active activity.
You can create common code to insert common phrases, you just need to be sure to append an Activity name to each so they are not confused. For example:
public final String PACKAGE_PREFIX = "com.vuzix.sample.";
public final String CUSTOM_BARCODE_INTENT = ".BarcodeIntent";
public String GetBarcodeIntentActionName(String ActivityName) {
return (PACKAGE_PREFIX + ActivityName + CUSTOM_BARCODE_INTENT);
}
protected void InsertCustomVocab(String ActivityName) {
try {
// Create a VuzixSpeechClient from the SDK
VuzixSpeechClient sc = new VuzixSpeechClient(this);
// Associate the phrase "Scan Barcode" with generating the unique intent for the calling activity
final String barcodeIntentId = "ScanBarcodeId" + ActivityName;
sc.defineIntent(barcodeIntentId, new Intent(GetBarcodeIntentActionName(ActivityName)));
sc.insertIntentPhrase("Scan Barcode", barcodeIntentId);
}
catch (NoClassDefFoundError e) {
Toast.makeText(this, "Cannot find Vuzix Speech SDK", Toast.LENGTH_LONG).show();
}
catch (Exception e) {
Log.e(TAG, "Error setting custom vocabulary: " + e.getMessage());
}
}
With combinations of these techniques you can define custom vocabularies in the various onCreate() methods of your activities. These vocabularies generate unique intent actions for each phrase within each Activity. The system will ensure the correct phrases are delivered to the correct activities.
Storing and Retrieving Vocabularies
Some developers find themselves switching between a few fixed vocabularies. One mechanism that may aid this is storing and retrieving the vocabularies.
A snapshot of the current vocabulary can be taken with:
sc.storeVocabulary("My save point name");
The name you provide must be unique within your Activity or the previous save point will be overwritten.
A saved vocabulary may be retrieved at any point in time. This operation completely changes from whatever the current vocabulary is to what it was at the point in time when it was saved. This is done with a single call to:
sc.retrieveVocabulary("My save point name");
A single save point may be restored multiple times. When you no longer need the saved state you can remove it with:
sc.removeVocabulary("My save point name");
Note: removing the stored vocabulary does not affect the the phrases for which the engine is actively listening. It simply removes the save point so it may not be used again in the future.
Beginning with SDK v1.91 you can list all saved vocabulary names. The list will be returned as a List.
List<String> storedVocabularyNames = sc.getStoredVocabularyNames();
Summary
By using the techniques described here, your can create an application that dynamically modifies the vocabulary within activities,. You can also create multiple activities that use the same or different vocabularies, and each activity will get the correct speech commands.