Question

Standard Android SpeechRecognizer was working perfectly on Google Glass XE16 - XE16.2
Then the XE17 update suddenly broke everything, with the following error and no callbacks to the Listener anymore:

E/AndroidRuntime(6321): FATAL EXCEPTION: main 
E/AndroidRuntime(6321): Process: com.google.glass.voice, PID: 6321 
E/AndroidRuntime(6321): java.lang.NullPointerException: VoiceEngine.startListening: voiceConfig cannot be null
E/AndroidRuntime(6321): at com.google.glass.predicates.Assert.assertNotNull(Assert.java:68)
E/AndroidRuntime(6321): at com.google.glass.voice.VoiceEngine.startListening(VoiceEngine.java:650)
E/AndroidRuntime(6321): at com.google.glass.voice.VoiceService$VoiceServiceBinder.startListening(VoiceService.java:116)
E/AndroidRuntime(6321): at com.google.glass.voice.GlassRecognitionService.attachCallback(GlassRecognitionService.java:272)
E/AndroidRuntime(6321): at com.google.glass.voice.GlassRecognitionService.onStartListening(GlassRecognitionService.java:216)
E/AndroidRuntime(6321): at android.speech.RecognitionService.dispatchStartListening(RecognitionService.java:98)
E/AndroidRuntime(6321): at android.speech.RecognitionService.access$000(RecognitionService.java:36)
E/AndroidRuntime(6321): at android.speech.RecognitionService$1.handleMessage(RecognitionService.java:79)
E/AndroidRuntime(6321): at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(6321): at android.os.Looper.loop(Looper.java:149)

By disassembling the GlassVoice.apk (located in /system/priv-app/), I was able to find out that you can add these two extras to your SpeechRecognizer's Intent, and it fixes the NullPointerException :

 
//mSpeechIntent.putExtra( GlassSpeechRecognizer.EXTRA_VOICE_CONFIG_NAME, "Toto");
mSpeechIntent.putExtra( "voiceConfigName", "Toto");
//mSpeechIntent.putExtra( GlassSpeechRecognizer.EXTRA_VOICE_COMMANDS, new String[]{"red","green","blue"} );
mSpeechIntent.putExtra( "extraVoiceCommands", new String[] {"red","green","blue"}); // Command phrases allowed!
 

The problem is, as they moved the GlassVoice.apk in a private space, that you cannot load any class of it from your own app. I did not find out how to work around this -- if you know how, help would be much appreciated!

With that, I can see in the logs that one phrase has been recognized when I speak, but I don't have any callback on the usual listener.


Some of the interesting logs (word "red" recognized, but no callbacks):

I/RecognizerController(1818): attachVoiceInputCallback
W/RecognizerController(1818): queueingGrecoListener was null in attachVoiceInputCallback
...
I/VoiceEngine[20daf4b4](1818): Hotword recognizer triggered a recognition result
...
I/SavedAudioStorage(1818): Saved SavedAudioRecord [id=null, filename=/data/data/com.google.glass.voice/recorded_audio/20140508_171311_197.pcm, recognized=true, synced=false, timestamp=1399594400939, recognizedCommands=red:2000:2620, sampleRate=16000]

How can we work around this?



EDIT WITH ANSWER!

Thanks to @pscholl, I found a workaround. If your app is simple and does not include many jars, just look at @pscholl solution.

In my case, adding GlassVoice-xe17.apk, which contains thousands of methods, made my app hit the infamous "64K methods" Android ceiling. If you don't know what this terrible limit is, just think about the "640K in MS-DOS", reinvented by Android (Dalvik VM).

First I tried to turn ProGuard on, in order to shrink my app, by removing all unused methods: the problem is that it is a nightmare to configure, and after hours of failed attempts, I was still having unexpected classes missing and cryptic errors.

So I turned to Dex loading, as explained here: https://github.com/mmin18/Dex65536. The problem is that GlassVoice.apk includes all com.google.common package, that I also use through Guava. In the Dex65536 solution, the classloader loads the class from the external APK first (nice hack, that you can't turn around), and therefore it was not working.

I ended up coding a "class pre-loader", invoked before the additional Dex ClassLoader is added. Drop me a line if you're interested in the code (but it's far from being optimal).

That was tough and ugly! I hope the Glass Dev Team will solve the voice problem soon, with a neat solution -- not like this one :-)

Was it helpful?

Solution

Still works fine for me on XE17 with the method described here: Glass voice command nearest match from given list, maybe you called the initial setVoiceConfig with a null

OTHER TIPS

Alternatively if you can just fallback to the android speech recognizer. This is not nearly as elegant as the Glass code.

private void displaySpeechRecognizer() {
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "What is your favorite color (e.g. Red, Blue Green)");
        startActivityForResult(intent, SPEECH_REQUEST);
}
private   @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent data) {
        if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
            String results = StringUtils.join(data.getStringArrayListExtra(
                    RecognizerIntent.EXTRA_RESULTS));
             //TODO: your switch based on string results.  Not you may need to do a fuzzy match based on confidence scores.
         }   
}

http://developer.android.com/reference/android/speech/RecognizerIntent.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top