Android Spracherkennung als Dienst für Android 4.1 & 4.2

Ich habe es geschafft, kontinuierliche Spracherkennung (unter Verwendung der SpeechRecognizer-class) als Dienst für alle Android-Versionen bis 4.1 zu bekommen. Meine Frage bezieht sich darauf, dass es an den Versionen 4.1 und 4.2 funktioniert, da bekannt ist, dass es ein Problem gibt, dass die API nicht so funktioniert, wie einige Sekunden nachdem die Spracherkennung gestartet wurde, wenn keine Spracheingabe erkannt wurde wenn der Spracherkenner still stirbt. ( http://code.google.com/p/android/issues/detail?id=37883 )

Ich habe eine Frage gefunden, die eine Lösung für dieses Problem vorschlägt (die Spracherkennung hört nach ein paar Sekunden auf zu horchen ), aber ich bin unsicher, wie ich den für diese Lösung erforderlichen Handler implementieren soll. Ich bin mir des “Pieps” bewusst, der alle paar Sekunden auftritt, den diese Problemumgehung verursacht, aber eine kontinuierliche Spracherkennung ist für mich wichtiger.

Wenn jemand andere alternative Workarounds hat, möchte ich diese auch hören.

Dies ist eine Arbeit für Android-Version 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 mtarget; IncomingHandler(MyService target) { mtarget = new WeakReference(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 – Fix-Piepton Wenn du Text-to-Speech in deiner App verwendest, achte darauf, den Solo-Stream in onResults zu deaktivieren

Wenn Sie wirklich ununterbrochenes Hören ohne Internet-Verbindung implementieren möchten, müssen Sie Pakete von Drittanbietern in Betracht ziehen, eine von ihnen ist CMUSphinx, überprüfen Sie zum Beispiel pocketsphinx android-Demo, wie Sie effizient nach Begriffen im Offline-Modus suchen und auf bestimmte Befehle reagieren “oh mächtiger Computer”. Der Code dafür ist einfach:

Sie erstellen einen Erkenner und fügen Stichwortsuche einfach hinzu:

 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); 

und definiere einen Listener:

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

Für jeden von euch, die versuchen, den Signalton zum Schweigen zu bringen, die @HoanNguyen-Antwort, die sehr gut ist, aber wie im Api-Set gesagt vorsichtig ist, setStreamSolo ist kumulativ, wenn es einen Fehler in der Spracherkennung gibt und ein Fehler aufgerufen wird ( zum Beispiel keine Internetverbindung), dann wird setStremSolo true immer wieder aufgerufen, was dazu führt, dass Ihre App das ganze Telefon zum Schweigen bringt (sehr schlecht)! Die Lösung besteht darin, setStremMute (false) zu speechRecognizer onError hinzuzufügen.

schau dir meine Demo-App an: https://github.com/galrom/ContinuesVoiceRecognition

Ich empfehle, PockeySphix und SpeechRecognizer zu verwenden.