Распознавание речи Android как услуга на Android 4.1 & 4.2
мне удалось получить непрерывное распознавание речи (используя класс SpeechRecognizer) в качестве службы на всех версиях Android до 4.1. Мой вопрос касается того, чтобы он работал на версиях 4.1 и 4.2 как известно, есть проблема в том, что API не делает так, как описано в том, что через несколько секунд после запуска распознавания голоса, если голосовой ввод не был обнаружен, то это как если бы распознаватель речи умирает молча. (http://code.google.com/p/android/issues/detail?id=37883)
Я нашел вопрос, который предлагает обойти эту проблему (распознавание голоса прекращает прослушивание через несколько секунд), но я не уверен, как реализовать обработчик необходимые для этого решения. Я знаю о "звуковом сигнале", который будет происходить каждые несколько секунд, что вызовет этот обходной путь, но получение непрерывного распознавания голоса более важно для меня.
Если кто-то есть ли другие альтернативные обходные пути, то я хотел бы услышать их тоже.
4 ответов:
Это работа вокруг для 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-исправить звуковой сигнал если вы используете текст в речь в вашем приложении убедитесь, что отключить Solo stream в onResults
Если вы действительно хотите реализовать непрерывное прослушивание без подключения к интернету, вам нужно рассмотреть сторонние пакеты, одним из которых является CMUSphinx, проверьте Pocketsphinx андроид демо например, как эффективно слушать ключевое слово в автономном режиме и реагировать на конкретные команды, такие как ключевая фраза "Oh mighty computer". Код для этого прост:
вы создаете распознаватель и просто добавляете поиск по ключевым словам:
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 setStreamSolo является кумулятивным, поэтому, если есть ошибка в распознавании речи и при ошибке вызывается (например, нет подключения к интернету), то setStremSolo true вызывается снова и снова, что приведет к тому, что ваше приложение заставит замолчать весь телефон (очень плохо)! решение этой проблемы заключается в добавлении setStremMute (false) в speechRecognizer метод onerror.
проверьте мое демо-приложение : https://github.com/galrom/ContinuesVoiceRecognition
Я рекомендую использовать как PockeySphix, так и SpeechRecognizer.
Comments