0

I am using aidl to invoke speech recognition in a service . the recognition happens in the service and passes the recognition back to the app.

the problem is that the method startListening created an exception :

java.lang.RuntimeException: SpeechRecognizer should be used only from the application's main thread
                                                                               at android.speech.SpeechRecognizer.checkIsCalledFromMainThread(SpeechRecognizer.java:325)
                                                                               at android.speech.SpeechRecognizer.startListening(SpeechRecognizer.java:266)
                                                                               at .InputService$InputBind.speechActivated(InputService.java:79)
                                                                               at .InputBinder$Stub.onTransact(InputBinder.java:50)
                                                                               at android.os.Binder.execTransact(Binder.java:461)

here is my service :

public class InputService extends Service implements Actions , Constants {

    private static final int VOICE_MAX_RESULTS = 5;
    private SpeechRecognizer speechRecognizer;
    private static final String TAG = "InputService";
    private InputBind inputBind;

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG , "onBind called");
        if (speechRecognizer == null){
            speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
        }
        speechRecognizer.setRecognitionListener(inputBind);

        inputBind = new InputBind(speechRecognizer);
        return (inputBind);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG , "Service created");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {


        return START_STICKY;
    }

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

    }


    private static class InputBind extends InputBinder.Stub implements RecognitionListener{
        private InputCallback callback;
        private SpeechRecognizer speechRecognizer;
        public InputBind(SpeechRecognizer speechRecognizer){
            this.speechRecognizer = speechRecognizer;
        }
        @Override
        public void speechActivated(InputCallback cb) throws RemoteException {
            callback = cb;
            Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "cmn-Hans-CN");
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "cmn-Hans-HK");
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,"voice.recognition.test");
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, VOICE_MAX_RESULTS);
            speechRecognizer.startListening(recognizerIntent);
        }

        @Override
        public void onReadyForSpeech(Bundle params) {
            try {
                callback.readyForSpeech();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onBeginningOfSpeech() {

        }

        @Override
        public void onRmsChanged(float rmsdB) {

        }

        @Override
        public void onBufferReceived(byte[] buffer) {

        }

        @Override
        public void onEndOfSpeech() {
            try {
                callback.speechEnded();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onError(int error) {
            try {
                callback.speechEnded();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onResults(Bundle results) {
            boolean foundWord = false;
            Log.v(TAG , "onResults Called" );
            ArrayList data =results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
            for (int i = 0; i < data.size(); i++)
            {
                Log.d(TAG, "result " + data.get(i) );
                String result = data.get(i).toString();
                switch (result){
                    case LEFT_ENG:
                    case LEFT_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(LEFT);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case RIGHT_ENG:
                    case RIGHT_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(RIGHT);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case SELECT_ENG:
                    case SELECT_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(SELECT);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case BACK_ENG:
                    case BACK_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(BACK);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case BASKET_ENG:
                    case BASKET_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(BASKET);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case EXIT_ENG:
                    case EXIT_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(EXIT);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                }
                if(foundWord)
                    return;
            }
        }

        @Override
        public void onPartialResults(Bundle partialResults) {

        }

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

        }

    }

}

speechActivated is a the method that I invoke in the main app when I want to activate speech recognition. why does it say that I am not on the main thread ? and where else can I invoke startListening ?

yanish
  • 257
  • 2
  • 15
  • I think it means that you cannot call this in a `Service`. It has to be called from the Main Thread which Is the Activity and so – KISHORE_ZE May 01 '16 at 14:33
  • @KISHORE_ZE this is just a service without an activity – yanish May 01 '16 at 14:38
  • I meant that you cannot call this from a service. You need to have an activity where you can call it from. That's what I assume from your error log – KISHORE_ZE May 01 '16 at 15:03
  • You need to create recognizer in onCreate, not in onBind – Nikolay Shmyrev May 01 '16 at 16:30
  • Possible duplicate of [Android Speech Recognition as a service on Android 4.1 & 4.2](http://stackoverflow.com/questions/14940657/android-speech-recognition-as-a-service-on-android-4-1-4-2) – Nikolay Shmyrev May 01 '16 at 16:30

1 Answers1

0

The exception is explicit enough: you must call this method from the Main thread. That doesn't look thread efficient but that's how the API works.

The documentation is clear about it:

This class's methods must be invoked only from the main application thread.

Stephen Vinouze
  • 1,815
  • 1
  • 17
  • 28