Reconnaissance vocale Android en tant que service sur Android 4.1 & 4.2

j'ai réussi à obtenir la reconnaissance vocale continue de travail (en utilisant la classe SpeechRecognizer) comme un service sur toutes les versions Android jusqu'à 4.1. Ma question concerne le fait de le faire fonctionner sur les versions 4.1 et 4.2 comme on le sait, il y a un problème dans le fait que l'API ne fonctionne pas comme prévu, quelques secondes après le début de la reconnaissance vocale, si aucune entrée vocale n'a été détectée, alors c'est comme si l'appareil de reconnaissance vocale meurt silencieusement. ( http://code.google.com/p/android/issues/detail?id=37883 )

j'ai trouvé une question qui propose une solution de rechange à ce problème ( la reconnaissance vocale cesse d'écouter après quelques secondes ), mais je ne sais pas comment mettre en œuvre le Gestionnaire requis pour cette solution. Je suis conscient du " bip " qui se produira toutes les quelques secondes que cette solution provoquera, mais obtenir une reconnaissance vocale continue est plus important pour moi.

si quelqu'un a d'autres solutions de rechange, j'aimerais les entendre aussi.

51
demandé sur Community 2013-02-18 20:17:59

4 réponses

il s'agit d'un work-around pour 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)
        {

        }

    }
}

02/16/2013 - Fix beep sound si vous utilisez du texte pour parler dans votre application, assurez-vous d'éteindre le flux Solo en onResults

48
répondu Hoan Nguyen 2014-02-17 06:45:25

si vous voulez vraiment mettre en œuvre l'écoute continue sans connexion internet, vous devez considérer les paquets tiers, L'un d'eux est CMUSphinx, cochez Pocketsphinx android demo par exemple comment écouter pour mot-clé efficacement dans offline et réagir sur les commandes spécifiques comme une phrase clé"oh mighty computer". Le code pour faire cela est simple:

vous créez un recognizer et il suffit d'ajouter le mot-clé spotting recherche:

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

et définir un auditeur:

@Override
public void onPartialResult(Hypothesis hypothesis) {
    String text = hypothesis.getHypstr();
    if (text.equals(KEYPHRASE))
      //  do something
} 
15
répondu Nikolay Shmyrev 2014-05-10 08:36:03

pour tous ceux d'entre vous qui tentent de réduire au silence le son du bip, en reformulant la réponse de @HoanNguyen qui est très bonne, mais attention comme dit dans le jeu d'api setStreamSolo est cumulative donc s'il y a une erreur dans la reconnaissance vocale et sur l'erreur est appelé(par exemple pas de connexion internet) alors setStremSolo true est appelé encore et encore ce qui se traduira par votre application réduire au silence le téléphone entier (très mauvais)! la solution à cela est d'ajouter le setStremMute (false) au speechRecognizer onError.

9
répondu Eran Katsav 2014-07-19 22:00:09

Découvrez mon application de démonstration : https://github.com/galrom/ContinuesVoiceRecognition

je recommande D'utiliser PockeySphix et SpeechRecognizer.

8
répondu Gal Rom 2015-11-16 20:27:20