Android语音识别:在JB 4.1.2上重复调用SpeechRecognizer.startListening()失败

Mik*_*679 13 service android speech-recognition listener

我有一个服务,我会反复开始一个语音识别监听器,所以我可以有一个开放式会话供用户说话.该类还处理Jelly Bean中的问题,如果在5秒内没有听到语音,则会抛出ERROR_SPEECH_TIMEOUT.基本上这是有效的.但是,如果我反复调用Recognizer.startListening(recognizerIntent),它会默默地失败,因为在这种情况下从不调用onBeginningOfSpeech().现在如果我只是不说话我的Jelly Bean超时处理程序将每次都重启监听器而不会失败.似乎只有在调用onResults()之后才会失败,因为WAS会听到语音.在调用onResults()之后,肯定会调用recognizer.startListening(recognizerIntent),但就像我说的那样,没有任何反应.当它失败时它是随机的,Logcat中没有任何东西可以指出问题所在.我只是不知道还有什么可以尝试.希望你们之一的Android语音识别专家之前已经看过这个...

最低:2.2目标:在JB:Android 4.1.2上进行测试


更多信息(11-01-13)我的HTC One的4.3更新肯定解决了这个问题.我下面的语音识别服务现在可靠且准确.我已经跑了至少几分钟没有错误.至于4.1.2,在我更新到4.3之前,它看起来似乎工作得更好(谷歌是否改变了他们的任何内容?)......我不知道,但它仍然会遗漏一些所说的话,偶尔也会没有错误,只是停止听(在这种情况下永远不会调用onBeginningOfSpeech()).我想我将不得不就这个问题警告我的用户有关Android 4.1.2的问题,因为我已经尽可能地使用了我的代码.

更多信息(09-17-13)据说,9月底有一个Android更新(4.3)将发布给HTC(http://www.ubergizmo.com/2013/09/htc-one-to-receive) -android-4-3-jelly-bean-update-this-9月/).所以希望这将解决该设备上的这个问题.对于运行Android 4.1.2且暂时停留在该版本上的应用用户来说问题仍然存在.我仍然不知道在这些情况下该怎么做,并希望这是唯一的Android版本与此问题.有没有办法找出有多少设备正在运行4.1.2?

更多信息(09-15-13)在这篇文章中:谷歌语音识别器不能在Android 4.x上启动.作者说他正在HTC上看到这个问题.我也有一个HTC,我看到这个问题(Android 4.1.2).我想知道这是HTC独有的吗?(或运行Android 4.1.2的任何设备) - 我无法确认在所有运行JB的最新设备上难以测试.作者进一步指出他的Nexxus 4.2.2工作正常.谁能告诉我他们看到这个问题的设备?

更多信息(9-08-13)为了确认我的代码没有问题,我也在Android 2.3.3上进行了测试,并且我能够连续25次调用onResult()> startListening().在定位Android 4.1.2时,我无法通过3或4次通话.我不敢相信没有其他人遇到过这个问题?

public class VoiceRecogService extends Service
{
    protected AudioManager mAudioManager; 
    protected SpeechRecognizer mSpeechRecognizer;
    protected Intent mSpeechRecognizerIntent;
    protected RecognitionListener mSpeechRecognizerListner;
    //protected final Messenger mServerMessenger = new Messenger(new IncomingHandler(this));

    protected volatile boolean mIsListening;
    protected volatile boolean mIsCountDownOn;

    static final int MSG_RECOGNIZER_START_LISTENING = 1;
    static final int MSG_RECOGNIZER_CANCEL = 2;

    private int mBindFlag;
    private Messenger mServiceMessenger;

    private Context m_ctx;

    private Handler mHandler = new Handler();
    //private boolean m_bReadyForSpeechReceived = false;

    @Override
    public void onCreate()
    {
        super.onCreate();
        m_ctx = this;

        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 

        //do not mute beep when speech listening first kicks off
        Log.d("TESTING: SPEECH SERVICE: CALL START", "onCreate()"); 
        startListening(false);
    }
    private void startListening(boolean bMuteSound){
        Log.d("TESTING: SPEECH SERVICE: startListening()", mIsListening? "true":"false"); 
        if (bMuteSound==true && Build.VERSION.SDK_INT >= 16)//Build.VERSION_CODES.JELLY_BEAN)
        {
            // turn off beep sound  
            mAudioManager.setStreamMute(AudioManager.STREAM_SYSTEM, true);
        }
        if (!mIsListening)
        {
             //mSpeechRecognizer.startListening(mSpeechRecognizerIntent);
             recognizeSpeechDirectly ();
             mIsListening = true;

        }
    }

    /////////////////////////////////////////////////////////////////////////
    /**
     * lazy initialize the speech recognizer
     */
    private SpeechRecognizer getSpeechRecognizer()
    {
        if (mSpeechRecognizer == null)
        {
            mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(m_ctx);
        }
        return mSpeechRecognizer;
    }
    private RecognitionListener getSpeechRecognizerListner()
    {
        if (mSpeechRecognizerListner == null)
        {
            mSpeechRecognizerListner = new SpeechRecognitionListener();
        }
        return mSpeechRecognizerListner;
    }

    private void recognizeSpeechDirectly()
    {
        Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        // accept partial results if they come
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);

        recognizeSpeechDirectly(m_ctx,recognizerIntent, getSpeechRecognizerListner(), getSpeechRecognizer());
    }
    public static void recognizeSpeechDirectly(Context context, 
                                               Intent recognizerIntent, 
                                               RecognitionListener listener,
                                               SpeechRecognizer recognizer)
    {
        //need to have a calling package for it to work
        if (!recognizerIntent.hasExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE))
        {
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, "com.dummy");
        }

        recognizer.setRecognitionListener(listener);
        recognizer.startListening(recognizerIntent);
    }
    ////////////////////////////////////////////////////////////////////////////

    public void stop()
    {
        if (getSpeechRecognizer() != null)
        {
            getSpeechRecognizer().stopListening();
            getSpeechRecognizer().cancel();
            getSpeechRecognizer().destroy();

            mIsListening = false;
            if (Build.VERSION.SDK_INT >= 16);//Build.VERSION_CODES.JELLY_BEAN)
                mAudioManager.setStreamMute(AudioManager.STREAM_SYSTEM, false);
        }
    }

    // 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;
            Log.d("TESTING: SPEECH SERVICE: CALL START", "onFinish()"); 
            startListening(true);
        }
    };

    @Override
    public void onDestroy()
    {
        super.onDestroy();

        if (mIsCountDownOn)
        {
            mNoSpeechCountDown.cancel();
        }
        if (mSpeechRecognizer != null)
        {
            mSpeechRecognizer.destroy();
        }
    }

    protected class SpeechRecognitionListener implements RecognitionListener
    {
        @Override
        public void onReadyForSpeech(Bundle params)
        {
            if (Build.VERSION.SDK_INT >= 16)//Build.VERSION_CODES.JELLY_BEAN)
            {
                mIsCountDownOn = true;
                mNoSpeechCountDown.start();
            }
            Log.d("TESTING: SPEECH SERVICE", "onReadyForSpeech"); 
        }
        @Override
        public void onBeginningOfSpeech()
        {
            // speech input will be processed, so there is no need for count down anymore
            if (mIsCountDownOn)
            {
                mIsCountDownOn = false;
                mNoSpeechCountDown.cancel();
            }               
        }
        @Override
        public void onEndOfSpeech()
        {
            Log.d("TESTING: SPEECH SERVICE", "onEndOfSpeech"); 
        }

        @Override
        public void onBufferReceived(byte[] buffer)
        {
            //Log.d("TESTING: SPEECH SERVICE", buffer + new String(new byte[] {0x63})); 
        }

        @Override
        public void onError(int error)
        {
            if ((error == SpeechRecognizer.ERROR_NO_MATCH)
                    || (error == SpeechRecognizer.ERROR_SPEECH_TIMEOUT)){
                if (mIsCountDownOn)
                {
                    mIsCountDownOn = false;
                    mNoSpeechCountDown.cancel();
                }
                 mIsListening = false;
                 Log.d("TESTING: SPEECH SERVICE: CALL START", "onError()"); 
                 startListening(true);
            }
        }

        @Override
        public void onEvent(int eventType, Bundle params)
        {

        }

        @Override
        public void onPartialResults(Bundle partialResults)
        {

        }

        @Override
        public void onResults(Bundle results)
        {
             //String str = new String();
             //Log.d(TAG, "onResults " + results);
             ArrayList data = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);

             //if(data.size() >=1){
             //  //check for save it:
             //}

             for (int i = 0; i < data.size(); i++)
             {
                 Log.d("TESTING: SPEECH SERVICE", (String)data.get(i));
             }

             //if no "save it" somewhere in there, then continue:
             if (mIsCountDownOn)
             {
                 mIsCountDownOn = false;
             }
             mIsListening = false;
             Log.d("TESTING: SPEECH SERVICE: CALL START", "onResults()"); 

             startListening(true);
        }
        @Override
        public void onRmsChanged(float rmsdB)
        {

        }
    }
    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 7

我在Nexus 5的Android 4.4 KitKat上,它有同样的问题.我认为这可能是一个Android错误,因为我没有看到任何人有一个干净的解决方案.
此解决方案类似于Andrew_CS解决方案,但我认为它实际上允许更好的识别.安德鲁斯解决方案是不断启动和停止识别器,你必须跟踪事情的状态,如果你正在处理语音.这个新的解决方案/解决方案基本上是这样的:

  • 一旦onResults被调用并且我们的结果被处理,我们就会启动一个计时器.
  • 如果一切正常,将调用onReadyForSpeech,我们可以取消我们的计时器.
  • 如果操作不正常,我们的计时器结束,我们重新启动语音识别器并再次启动计时器.
  • 确保您也在OnDestroy方法中取消计时器.

如果你找到更好的方法,请告诉我,但这似乎现在工作得非常好.如果我们能够真正证明这是一个Android错误,我会喜欢有人将其提交给Google.

            @Override
        public void onReadyForSpeech(Bundle params) {
            Log.d("Speech", "onReadyForSpeech: Cancel Timer");
            if(mTimer != null) {
                mTimer.cancel();
            }
        }


        @Override
        public void onResults(Bundle results) {
            //If the timer is available, cancel it so it doesn't interrupt our result processing
            if(mTimer != null){
                mTimer.cancel();
            }
            Log.d("Speech", "onResults");
            //Start processing data
            ArrayList<String> strlist = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
            for (int i = 0; i < strlist.size();i++ ) {
                Log.d("Speech", "YOU SAID: " + strlist.get(i));
            }
            //Start listening again
            Log.d("Speech", "onResults: Start Listening");
            mSpeechRecognizer.startListening(mRecognizerIntent);
            //Start a timer in case OnReadyForSpeech is never called back (Android Bug?)
            Log.d("Speech", "onResults: Start a timer");
            if(mTimer == null) {
                mTimer = new CountDownTimer(2000, 500) {
                    @Override
                    public void onTick(long l) {
                    }

                    @Override
                    public void onFinish() {
                        Log.d("Speech", "Timer.onFinish: Timer Finished, Restart recognizer");
                        mSpeechRecognizer.cancel();
                        mSpeechRecognizer.startListening(mRecognizerIntent);
                    }
                };
            }
            mTimer.start();
        }
Run Code Online (Sandbox Code Playgroud)


pbe*_*lov 1

尝试使用SpeechRecognizer单个实例,无需在stop()方法上重新创建它。在 onCreate() 中调用getSpeechRecognizer()并忘记它。但不要忘记在 onDestroy() 方法中销毁。