webentwicklung-frage-antwort-db.com.de

Android Spracherkennung als Dienst auf Android= 4.1 & 4.2

Ich habe es geschafft, die fortlaufende Spracherkennung (mithilfe der SpeechRecognizer-Klasse) als Dienst für alle Android Versionen bis 4.1. Meine Frage betrifft das Funktionieren mit den so genannten Versionen 4.1 und 4.2 Ein Problem besteht darin, dass die API einige Sekunden nach dem Start der Spracherkennung nicht die dokumentierte Funktion ausführt. Wenn keine Spracheingabe erkannt wurde, ist dies so, als ob die Spracherkennung stillschweigend ausfällt. ( http://code.google.com/p/Android/issues/detail?id=3788 )

Ich habe eine Frage gefunden, die eine Umgehung dieses Problems vorschlägt ( Spracherkennung hört nach einigen Sekunden auf zu lauschen ), bin mir jedoch nicht sicher, wie der für diese Lösung erforderliche Handler implementiert werden soll. Ich bin mir bewusst, dass alle paar Sekunden ein Piepton zu hören ist, den diese Problemumgehung verursacht. Eine kontinuierliche Spracherkennung ist jedoch für mich wichtiger.

Wenn jemand andere alternative Problemumgehungen hat, würde ich diese auch gerne hören.

52
Graham Laming

Dies ist ein Workaround 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<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 - Beep-Sound korrigiert, wenn Sie Text To Speech in Ihrer App verwenden, stellen Sie sicher, dass der Solo-Stream in onResults deaktiviert ist

48
Hoan Nguyen

Wenn Sie wirklich kontinuierliches Hören ohne Internetverbindung implementieren möchten, müssen Sie Pakete von Drittanbietern in Betracht ziehen. Eines davon ist CMUSphinx. Überprüfen Sie die Pocketsphinx Android -Demo zum Beispiel, wie man im Offline-Modus effizient nach Schlüsselwörtern sucht und auf bestimmte Befehle reagiert, zum Beispiel auf die Schlüsselphrase "oh mächtiger Computer". Der Code dafür ist einfach:

sie erstellen einen Erkenner und fügen einfach die Keyword-Suche 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
} 
17
Nikolay Shmyrev

Für jeden von Ihnen, der versucht, den Signalton auszuschalten, ist es kumulativ, die Antwort @HoanNguyen neu zu bewerten, was sehr gut ist, aber Vorsicht geboten ist, wie im API-Set angegeben. zum Beispiel keine Internetverbindung), dann wird setStremSolo true immer wieder aufgerufen, was dazu führt, dass Ihre App das gesamte Telefon stummschaltet (sehr schlecht)! Die Lösung hierfür besteht darin, setStremMute (false) zum speechRecognizer onError hinzuzufügen.

9
Eran Katsav

schauen Sie sich meine Demo-App an: https://github.com/galrom/ContinuesVoiceRecognition

Ich empfehle sowohl PockeySphix als auch SpeechRecognizer zu verwenden.

9
Gal Rom