Android语音识别作为Android 4.1和4.2的服务
我已经成功地将持续的语音识别工作(使用SpeechRecognizer类)作为所有Android版本(最高4.1)的服务。 我的问题涉及到它在版本4.1和4.2上的工作,因为它是已知的有一个问题,因为在语音识别开始后几秒钟,API没有logging,如果没有检测到语音input,那么它是如果语音识别器默默地死亡。 ( http://code.google.com/p/android/issues/detail?id=37883 )
我发现一个问题提出了解决这个问题的方法( 几秒钟后语音识别停止监听 ),但是我不确定如何实现此解决scheme所需的处理程序。 我知道这种解决方法每隔几秒钟就会发生一次“嘟嘟”,但获得连续的语音识别对我来说更为重要。
如果有人有其他替代解决办法,那么我也想听到这些。
这是一个解决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) { } } }
2013年2月16日 – 修复嘟嘟声,如果您在您的应用程序中使用文本到语音,请确保在onResultsclosuresSolostream
如果你真的想实现没有互联网连接的连续聆听,你需要考虑第三方包,其中之一是CMUSphinx,检查Pocketsphinx android演示例如如何有效地在离线侦听关键字,并对特定命令作出反应,如关键短语“哦,强大的电脑”。 这样做的代码很简单:
您创build一个识别器,只需添加关键字点击search:
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);
并定义一个监听器:
@Override public void onPartialResult(Hypothesis hypothesis) { String text = hypothesis.getHypstr(); if (text.equals(KEYPHRASE)) // do something }
对于任何一个正在尝试沉默嘟嘟声的人来说,重新编写@HoanNguyen的答案非常好,但要小心,因为在api set中setStreamSolo是累积性的,所以如果在语音识别中出现错误并且错误被调用(例如没有互联网连接),然后setStremSolo true被再次调用,这将导致您的应用程序沉默整个手机(非常糟糕)! 解决scheme是将setStremMute(false)添加到speechRecognizer onError。
看看我的演示程序: https : //github.com/galrom/ContinuesVoiceRecognition
我build议使用PockeySphix和SpeechRecognizer。