13

私は音声認識リスナーを繰り返し開始するサービスを持っているので、ユーザーが話す自由なセッションを持つことができます。このクラスは、5 秒間音声が聞こえない場合に ERROR_SPEECH_TIMEOUT がスローされる Jelly Bean の問題も処理します。したがって、基本的にこれは機能します。ただし、これを繰り返し呼び出すと、 onBeginningOfSpeech() が呼び出されないという事実からも明らかなように、暗黙のうちに失敗します。ここで、まったく話さなければ、Jelly Bean のタイムアウト ハンドラが毎回確実にリスナーを再起動します。音声が聞こえたため、 onResults() が呼び出された後にのみ失敗するようです。onResults() が呼び出された後は、recognirer.startListening(recognizerIntent) が確実に呼び出されますが、私が言ったように、何も起こりません。失敗した場合、それはランダムであり、問​​題が何であるかを示す Logcat には何もありません。他に何を試すべきかわかりません。うまくいけば、Android 音声認識の専門家の 1 人がこれを以前に見たことがあるでしょう...

最小: 2.2 ターゲット: JB でのテスト: Android 4.1.2


詳細情報 (11-01-13) 私の HTC One の 4.3 アップデートは、この問題に確実に対処しています。以下の私の音声認識サービスは、信頼性が高く正確になりました。エラーなしで少なくとも数分間実行しました。4.1.2 に関しては、4.3 にアップデートする前はうまく機能しているように見えました (Google は何か変更を加えましたか?)...わかりませんが、まだいくつかの単語が読み上げられず、場合によってはエラーが発生しませんでした。聞くのをやめるだけです (この場合、onBeginningOfSpeech() は呼び出されません)。コードでできる限りのことを行ったので、この問題に関して Android 4.1.2 についてユーザーに警告する必要があると思います。

詳細情報 (09-17-13) おそらく、9 月末に HTC の Android アップデート (4.3) が来る予定です ( http://www.ubergizmo.com/2013/09/htc-one-to-receive -android-4-3-jelly-bean-update-this-september/ )。そのデバイスでこの問題が解決されることを願っています。Android 4.1.2 を実行していて、そのバージョンをしばらく使用しているアプリ ユーザーにとっては、問題は残っています。そのような場合にどうすればよいかはまだわかりません。うまくいけば、それがこの問題のある唯一の Android バージョンです。4.1.2 を実行しているデバイスの数を確認する方法はありますか??

詳細情報 (09-15-13) この投稿では、Google 音声認識エンジンが Android 4.x で起動しません。著者は、彼の HTC one でこの問題が発生していると述べています。(Android 4.1.2) でこの問題が発生している HTC も持っています。これはHTCのものに特有のものでしょうか?(または Android 4.1.2 を実行しているデバイス) - JB を実行しているすべての最新のデバイスでテストするのは難しいため、確認できません。著者はさらに、彼の Nexxus 4.2.2 は問題なく動作すると述べています。この問題が発生するデバイスを教えてください。

詳細情報 (9-08-13) 私のコードに問題がないことを確認するために、Android 2.3.3 でもこれをテストし、onResult() > startListening() を 25 回続けて呼び出すことができました。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;
    }
}
4

4 に答える 4

7

Nexus 5 で Android 4.4 KitKat を使用していますが、これと同じ問題があります。クリーンなソリューションを持っている人を見たことがないので、Android のバグである可能性が高いと思います。
このソリューションは Andrew_CS ソリューションに似ていますが、実際には認識が向上していると思います。Andrews のソリューションは、認識エンジンを常に開始および停止しているため、音声を処理しているかどうかなどの状態を追跡する必要があります。この新しいソリューション/回避策は、基本的にこれを行います。

  • 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();
        }
于 2013-11-28T03:19:51.020 に答える
2

以下を使用できます。

intent.putExtra("android.speech.extra.DICTATION_MODE", true);

このコードにより、サービスは長時間リッスンします。

于 2015-07-24T07:27:03.580 に答える
1

SpeechRecognizerの単一インスタンスを使用してみてください。 stop()メソッドで再作成する必要はありません。onCreate( ) で getSpeechRecognizer()を呼び出して、忘れてください。ただし、 onDestroy() メソッドで破棄することを忘れないでください。

于 2013-09-19T20:35:31.157 に答える
1

この問題を回避するために、CountDownTimer を使用して、cancel と startListening を段階的に呼び出しました。

_timer = new CountDownTimer(300000000, 1000){
    @Override
    public void onTick(long millisUntilFinished){
        if(!_processingSpeech){
            _mSpeechRecognizer.cancel();
            _mSpeechRecognizer.startListening(_mSpeechRecognizerIntent);
        }
    }

    @Override
    public void onFinish(){
        setUpTimer();
    }
};
_processingSpeech = false;
_timer.start();

RecognitionListener メソッドでブール値の processingSpeech を使用して、入力の取得/処理中にキャンセルして再起動しないようにしました。

これが役立つかどうか、またはさらに情報が必要な場合はお知らせください。幸運を!

于 2013-09-28T21:33:10.880 に答える