android speech-recognition android-4.2-jelly-bean

Reconocimiento de voz de Android como un servicio en Android 4.1 y 4.2



speech-recognition android-4.2-jelly-bean (4)

Logré obtener un reconocimiento de voz continuo trabajando (usando la clase SpeechRecognizer) como un servicio en todas las versiones de Android hasta 4.1. Mi pregunta es que funcione en las versiones 4.1 y 4.2 ya que se sabe que hay un problema porque la API no hace lo que se documenta en unos pocos segundos después de que se inicia el reconocimiento de voz, si no se ha detectado la entrada de voz, entonces es como si el reconocedor de voz muere en silencio. ( http://code.google.com/p/android/issues/detail?id=37883 )

He encontrado una pregunta que propone una solución a este problema (el reconocimiento de voz deja de escuchar después de unos segundos ), pero no estoy seguro de cómo implementar el controlador requerido para esta solución. Soy consciente del ''bip'' que sucederá cada pocos segundos que esta solución alternativa causará, pero obtener un reconocimiento de voz continuo es más importante para mí.

Si alguien tiene otras soluciones alternativas, me gustaría escucharlas también.


Esta es una solución para la versión de Android 4.1.1.

public class MyService extends Service { protected AudioManager mAudioManager; protected SpeechRecognizer mSpeechRecognizer; protected Intent mSpeechRecognizerIntent; protected final Messenger mServerMessenger = new Messenger(new IncomingHandler(this)); protected boolean mIsListening; protected volatile boolean mIsCountDownOn; private boolean mIsStreamSolo; static final int MSG_RECOGNIZER_START_LISTENING = 1; static final int MSG_RECOGNIZER_CANCEL = 2; @Override public void onCreate() { super.onCreate(); mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this); mSpeechRecognizer.setRecognitionListener(new SpeechRecognitionListener()); mSpeechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName()); } protected static class IncomingHandler extends Handler { private WeakReference<MyService> mtarget; IncomingHandler(MyService target) { mtarget = new WeakReference<MyService>(target); } @Override public void handleMessage(Message msg) { final MyService target = mtarget.get(); switch (msg.what) { case MSG_RECOGNIZER_START_LISTENING: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { // turn off beep sound if (!mIsStreamSolo) { mAudioManager.setStreamSolo(AudioManager.STREAM_VOICE_CALL, true); mIsStreamSolo = true; } } if (!target.mIsListening) { target.mSpeechRecognizer.startListening(target.mSpeechRecognizerIntent); target.mIsListening = true; //Log.d(TAG, "message start listening"); //$NON-NLS-1$ } break; case MSG_RECOGNIZER_CANCEL: if (mIsStreamSolo) { mAudioManager.setStreamSolo(AudioManager.STREAM_VOICE_CALL, false); mIsStreamSolo = false; } target.mSpeechRecognizer.cancel(); target.mIsListening = false; //Log.d(TAG, "message canceled recognizer"); //$NON-NLS-1$ break; } } } // Count down timer for Jelly Bean work around protected CountDownTimer mNoSpeechCountDown = new CountDownTimer(5000, 5000) { @Override public void onTick(long millisUntilFinished) { // TODO Auto-generated method stub } @Override public void onFinish() { mIsCountDownOn = false; Message message = Message.obtain(null, MSG_RECOGNIZER_CANCEL); try { mServerMessenger.send(message); message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING); mServerMessenger.send(message); } catch (RemoteException e) { } } }; @Override public void onDestroy() { super.onDestroy(); if (mIsCountDownOn) { mNoSpeechCountDown.cancel(); } if (mSpeechRecognizer != null) { mSpeechRecognizer.destroy(); } } protected class SpeechRecognitionListener implements RecognitionListener { @Override public void onBeginningOfSpeech() { // speech input will be processed, so there is no need for count down anymore if (mIsCountDownOn) { mIsCountDownOn = false; mNoSpeechCountDown.cancel(); } //Log.d(TAG, "onBeginingOfSpeech"); //$NON-NLS-1$ } @Override public void onBufferReceived(byte[] buffer) { } @Override public void onEndOfSpeech() { //Log.d(TAG, "onEndOfSpeech"); //$NON-NLS-1$ } @Override public void onError(int error) { if (mIsCountDownOn) { mIsCountDownOn = false; mNoSpeechCountDown.cancel(); } mIsListening = false; Message message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING); try { mServerMessenger.send(message); } catch (RemoteException e) { } //Log.d(TAG, "error = " + error); //$NON-NLS-1$ } @Override public void onEvent(int eventType, Bundle params) { } @Override public void onPartialResults(Bundle partialResults) { } @Override public void onReadyForSpeech(Bundle params) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { mIsCountDownOn = true; mNoSpeechCountDown.start(); } Log.d(TAG, "onReadyForSpeech"); //$NON-NLS-1$ } @Override public void onResults(Bundle results) { //Log.d(TAG, "onResults"); //$NON-NLS-1$ } @Override public void onRmsChanged(float rmsdB) { } } }

16/02/2013 - Corrige el sonido del pitido si usas Text To Speech en tu aplicación, asegúrate de desactivar Solo stream en onResults


Para cualquiera de ustedes que está tratando de silenciar el pitido, regrabando la respuesta @HoanNguyen que es muy buena, pero tenga cuidado como se dice en el conjunto api setStreamSolo es acumulativo, por lo tanto, si hay un error en el reconocimiento de voz y se produce un error ( por ejemplo, no hay conexión a Internet), luego setStremSolo true se llama una y otra vez, lo que hará que su aplicación silencie todo el teléfono (¡muy mal)! la solución a eso es agregar el setStremMute (falso) al speechRecognizer onError.


Si realmente desea implementar la escucha continua sin conexión a Internet, debe considerar paquetes de terceros, uno de ellos es CMUSphinx, consultar la demostración de Pocketsphinx android, por ejemplo, cómo escuchar palabras clave de manera eficiente en línea y reaccionar a los comandos específicos como una frase clave "oh poderosa computadora". El código para hacer eso es simple:

creas un reconocedor y simplemente agregas búsqueda de palabras clave:

recognizer = defaultSetup() .setAcousticModel(new File(modelsDir, "hmm/en-us-semi")) .setDictionary(new File(modelsDir, "lm/cmu07a.dic")) .setKeywordThreshold(1e-5f) .getRecognizer(); recognizer.addListener(this); recognizer.addKeywordSearch(KWS_SEARCH_NAME, KEYPHRASE); switchSearch(KWS_SEARCH_NAME);

y define un oyente:

@Override public void onPartialResult(Hypothesis hypothesis) { String text = hypothesis.getHypstr(); if (text.equals(KEYPHRASE)) // do something }