简体   繁体   English

Android 4.1 和 4.2 上的 Android 语音识别即服务

[英]Android Speech Recognition as a service on Android 4.1 & 4.2

I have managed to get continuous speech recognition working (using the SpeechRecognizer class) as a service on all Android versions up to 4.1.我已经成功地将连续语音识别工作(使用 SpeechRecognizer 类)作为服务在所有 Android 版本(最高 4.1)上运行。 My question concerns getting it working on versions 4.1 and 4.2 as it is known there is a problem in that the API doesn't do as documented in that a few seconds after voice recognition is started, if no voice input has been detected then it's as if the speech recogniser dies silently.我的问题涉及让它在 4.1 和 4.2 版本上工作,因为众所周知,存在一个问题,即在语音识别开始几秒钟后,API 没有按照文档中的说明执行,如果没有检测到语音输入,则它就像如果语音识别器无声地死亡。 ( http://code.google.com/p/android/issues/detail?id=37883 ) http://code.google.com/p/android/issues/detail?id=37883

I have found a question which proposes a work-around to this problem ( Voice Recognition stops listening after a few seconds ), but I am unsure as how to implement the Handler required for this solution.我发现了一个问题,该问题提出了解决此问题的方法( 语音识别在几秒钟后停止侦听),但我不确定如何实现此解决方案所需的处理程序。 I am aware of the 'beep' that will happen every few seconds that this workaround will cause, but getting continuous voice recognition is more important for me.我知道这种变通方法会导致每隔几秒钟发出一次“哔哔声”,但获得持续的语音识别对我来说更为重要。

If anyone has any other alternative workarounds then I'd like to hear those too.如果有人有任何其他替代解决方法,那么我也想听听。

This is a work around for android version 4.1.1.这是 android 版本 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 if you use Text To Speech in your app make sure to turn off Solo stream in onResults 02/16/2013 - 如果您在应用程序中使用 Text To Speech 修复哔声,请确保关闭 onResults 中的 Solo 流

If you really want to implement continuous listening without internet connection you need to consider third-party packages, one of them is CMUSphinx, check Pocketsphinx android demo for example how to listen for keyword efficiently in offline and react on the specific commands like a key phrase "oh mighty computer".如果你真的想在没有互联网连接的情况下实现连续监听,你需要考虑第三方包,其中之一是 CMUSphinx,查看Pocketsphinx android 演示,例如如何在离线状态下有效地监听关键字并对特定命令做出反应,比如关键短语“哦,强大的电脑”。 The code to do that is simple:执行此操作的代码很简单:

you create a recognizer and just add keyword spotting search:您创建一个识别器并添加关键字发现搜索:

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

and define a listener:并定义一个监听器:

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

For any of you who are trying to silence the beep sound, regrading the @HoanNguyen answer which is very good but be careful as said in the api set setStreamSolo is cumulative so if there is in error in the speech recognition and on error is called(for example no internet connection) then setStremSolo true is called again and again which will result in your app silencing the whole phone (very bad)!对于任何试图使哔声静音的人,重新分级 @HoanNguyen 的答案,这是非常好的,但要小心,如 api 集中所说,setStreamSolo 是累积性的,因此如果语音识别中出现错误,则调用错误(例如没有互联网连接)然后 setStremSolo true 被一次又一次地调用,这将导致您的应用程序使整个手机静音(非常糟糕)! the solution to that is to add the setStremMute(false) to the speechRecognizer onError.解决方案是将 setStremMute(false) 添加到 SpeechRecognizer onError 中。

check out my demo app : https://github.com/galrom/ContinuesVoiceRecognition查看我的演示应用程序: https : //github.com/galrom/ContinuesVoiceRecognition

I recommand to use both PockeySphix and SpeechRecognizer.我建议同时使用 PockeySphix 和 SpeechRecognizer。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM