0

I've been stuck on this for the last 5 hours...and so I'm coming to you guys for your help. I have read this:

Android Speech Recognition as a service on Android 4.1 & 4.2

The code that the answer suggests is the following:

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

        }

    }
}

I am confused on what the IncomingHandler.class does, and what method calls handlemessage . Im also confused on how this code is continuously running, because I don't see the listener getting re-instantiated after onResults. Can anyone mind explaining? Maybe even adding comments in to help me understand? Thanks so much!

Community
  • 1
  • 1
  • Any feedback would be greatly appreciated! I have been stuck for 5 hours, and would really appreciate anything! Again, thanks so much :) – user5800052 Jan 17 '16 at 00:12

1 Answers1

0

I am confused on what the IncomingHandler.class does, and what method calls handlemessage

Handler handles messages within service. It is required to use handler and timer because you can not restart recognizer immediately, you need to give it some time and only then restart.

handleMessage is called by Messenger code when you send a message to the messenger. You can read class description here:

https://developer.android.com/guide/components/bound-services.html#Messenger

Message is sent when timeout is expired by the following lines:

            mServerMessenger.send(message);
            message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING);
            mServerMessenger.send(message)

because I don't see the listener getting re-instantiated after onResults.

Right, it does not restart directly, instead it starts a timer in

    public void onReadyForSpeech(Bundle params)
            mNoSpeechCountDown.start();

and timer when ready sends the message

           @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);
        }
    }
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Nikolay Shmyrev
  • 24,897
  • 5
  • 43
  • 87
  • Thanks so much for answering my question, but I am still very confused. I'm not understanding the point of the timer fully yet...Also, does the message go to the handler? Then what does the `Switch` in the handler check for? What is `msg.what`? Could you edit your answer to explain? Maybe make an edit to show the steps this code takes, because I am really confused on which method gets called when. – user5800052 Jan 17 '16 at 00:26
  • There are two message types - START_LISTENING and CANCEL. You check message type and act on it. Timer is required because internal recognizer restrictions, you just need to take it for granted. – Nikolay Shmyrev Jan 17 '16 at 00:29
  • In modern approach to UI development code is not sequential, you should not expect it to be a sequence of steps. Instead, the code is a set of "handlers" exchanging "messages" and acting on them. You can read more on even-driven development here: https://en.wikipedia.org/wiki/Event-driven_programming – Nikolay Shmyrev Jan 17 '16 at 00:31
  • Okay, so I'll forget about the timer. What method passes the message to the handler? You said it gets passed when the timer ends...but I don't get why we even need that timer. Also, what is `onError`? Why are `static final int MSG_RECOGNIZER_START_LISTENING = 1;` and `static final int MSG_RECOGNIZER_CANCEL = 2;` ? What is `IncomingHandler`? – user5800052 Jan 17 '16 at 00:34
  • Okay, but could you explain when each method gets called, because that is where I am mainly confused. Also, what word is this code looking for? – user5800052 Jan 17 '16 at 00:35
  • The main reason I got this code was to make some code that runs in the background and is always listening for certain keywords, like "OK google". Does this code even do that? How can I do that? (I have seen that you are the voice recognition expert :) ) Thanks so much! – user5800052 Jan 17 '16 at 00:37
  • I'm sorry if I'm asking for too much in my last comment...do you mind answering the third to last comment? Thanks so much. – user5800052 Jan 17 '16 at 00:54