In the Android 5 I faced with strange problem. The first call to the startListening
of SpeechRecognizer results to the onError with error code 7 (ERROR_NO_MATCH).
I made test app with the following code:
if (speechRecognizer == null) {
speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
speechRecognizer.setRecognitionListener(new RecognitionListener() {
@Override
public void onReadyForSpeech(Bundle bundle) {
Log.d(TAG, "onReadyForSpeech");
}
@Override
public void onBeginningOfSpeech() {
Log.d(TAG, "onBeginningOfSpeech");
}
@Override
public void onRmsChanged(float v) {
Log.d(TAG, "onRmsChanged");
}
@Override
public void onBufferReceived(byte[] bytes) {
Log.d(TAG, "onBufferReceived");
}
@Override
public void onEndOfSpeech() {
Log.d(TAG, "onEndOfSpeech");
}
@Override
public void onError(int i) {
Log.d(TAG, "onError " + i);
}
@Override
public void onResults(Bundle bundle) {
Log.d(TAG, "onResults");
}
@Override
public void onPartialResults(Bundle bundle) {
Log.d(TAG, "onPartialResults");
}
@Override
public void onEvent(int i, Bundle bundle) {
Log.d(TAG, "onEvent");
}
});
}
final Intent sttIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
sttIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
sttIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "en");
sttIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "en");
speechRecognizer.startListening(sttIntent);
And have this log messages after first startListening
call:
onError 7
onReadyForSpeech
onBeginningOfSpeech
onEndOfSpeech
onResults
And following messages after another startListening
calls:
onRmsChanged
...
onRmsChanged
onReadyForSpeech
onRmsChanged
...
onRmsChanged
onBeginningOfSpeech
onRmsChanged
...
onRmsChanged
onEndOfSpeech
onRmsChanged
onRmsChanged
onRmsChanged
onResults
So, what is the reason of this error and how do I fix it?
I had the same problem but I couldn't find a workaround, so I ended up just calling return inside onError if the time between startListening and onError is unreasonably short.
protected long mSpeechRecognizerStartListeningTime = 0;
protected synchronized void speechRecognizerStartListening(Intent intent) {
if (mSpeechRecognizer != null) {
this.mSpeechRecognizerStartListeningTime = System.currentTimeMillis();
RLog.d(this, "speechRecognizerStartListening");
this.mSpeechRecognizer.startListening(intent);
}
}
...
@Override
public synchronized void onError(int error) {
RLog.i(this, this.hashCode() + " - onError:" + error);
// Sometime onError will get called after onResults so we keep a boolean to ignore error also
if (mSuccess) {
RLog.w(this, "Already success, ignoring error");
return;
}
long duration = System.currentTimeMillis() - mSpeechRecognizerStartListeningTime;
if (duration < 500 && error == SpeechRecognizer.ERROR_NO_MATCH) {
RLog.w(this, "Doesn't seem like the system tried to listen at all. duration = " + duration + "ms. This might be a bug with onError and startListening methods of SpeechRecognizer");
RLog.w(this, "Going to ignore the error");
return;
}
// -- actual error handing code goes here.
}
As soon as you configure the "Okay Google" function to every screen the error appears.
So this seems to be the reason!
Deactivate the function and the problem should be solved
Done one workaround.
This is a regular flow
onReadyForSpeech -->onBeginningOfSpeech-->onEndOfSpeech -->onResults
But weired flow
onError(no match) -->onReadyForSpeech -->onBeginningOfSpeech-->onEndOfSpeech -->onResults
So set a boolean on the end of speech to true. and check onError to make sure that it has thrown an error after an end of speech!
speech.startListening(recognizerIntent);
isEndOfSpeech = false;
@Override
public void onError(int error) {
if (!isEndOfSpeech)
return;
}
@Override
public void onEndOfSpeech() {
isEndOfSpeech = true;
}
I had the same problem on several devices. It seems onError(7) is always called before onReadyForSpeech(), so if to avoid using ugly times, you can do something like:
public void start(){
performingSpeechSetup = true;
speechRecognizer.startListening(intent);
}
and in the RecognitionListener:
public void onReadyForSpeech(Bundle bundle) {
performingSpeechSetup = false;
}
@Override
public void onError(int error) {
if (performingSpeechSetup && error == SpeechRecognizer.ERROR_NO_MATCH) return;
// else handle error
}
Turned out to be very easy in my case. The launching sound of the voice recognition was too loud and triggered the listening process at the very beginning. Turn down the system sound would help. (The volume key)