2

I created a continuous speech recognition Android app by following this thread, it works perfectly on my Moto G (4.4.2) but for some reason it crashes on 2.3.5 and 2.3.6, I already tried by removing the timer workaround for 4.1 and newer versions and it's the same. The thing is that it works fine when I say words but when it catches some noise (like a mouse click) it takes like 10 seconds recognizing (or whatever it does after onEndOfSpeech()) and then it throws an ERROR_NETWORK_TIMEOUT.

My problem might be related to this one, but inmy case the error always happens.

I would really appreciate some help here.

Update:

Here is a minimum example which is based on the first link I mention, it still fails to me, additionally I had to add the service to the manifest (<service android:name="com.test.MyService"></service>), the two text views in activity_main.xml and RECORD_AUDIO permission.

MainActivity:

public class MainActivity extends Activity {

protected static final boolean DEBUG = false;
protected static final String TAG = null;
private int mBindFlag;
private MainActivity activityContext;
private Intent speechService;
public static TextView methodText;
public static TextView resultsText;
private static Messenger mServiceMessenger;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    methodText = (TextView) findViewById(R.id.textView1);
    resultsText = (TextView) findViewById(R.id.textView2);
    activityContext = this;
    speechService = new Intent(activityContext, MyService.class);
    activityContext.startService(speechService);
    mBindFlag = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH ? 0 : Context.BIND_ABOVE_CLIENT;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
protected void onStart() {
    super.onStart();
    bindService(new Intent(this, MyService.class), mServiceConnection, mBindFlag);
}

@Override
protected void onStop()
{
    super.onStop();

    if (mServiceMessenger != null)
    {
        unbindService(mServiceConnection);
        mServiceMessenger = null;
    }
}

private final ServiceConnection mServiceConnection = new ServiceConnection()
{
    @Override
    public void onServiceConnected(ComponentName name, IBinder service)
    {
        if (DEBUG) {Log.d(TAG, "onServiceConnected");} //$NON-NLS-1$

        mServiceMessenger = new Messenger(service);
       sendMessage(MyService.MSG_RECOGNIZER_START_LISTENING);
    }

    @Override
    public void onServiceDisconnected(ComponentName name)
    {
        if (DEBUG) {Log.d(TAG, "onServiceDisconnected");} //$NON-NLS-1$
        mServiceMessenger = null;
    }

}; // mServiceConnection

public static void sendMessage(int type){

     Message msg = new Message();
     msg.what = type; 

     try
     {
         mServiceMessenger.send(msg);
     } 
     catch (RemoteException e)
     {
         e.printStackTrace();
     }
}

@Override
protected void onDestroy(){
    super.onDestroy();
    activityContext.stopService(speechService);
}
}

Service class:

public class MyService extends Service{
protected static 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 static boolean mIsStreamSolo;

static final int MSG_RECOGNIZER_START_LISTENING = 1;
static final int MSG_RECOGNIZER_CANCEL = 2;
private static final String TAG = null;

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

    MainActivity.methodText.setText("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)
    {
        MainActivity.methodText.setText("handleMessage");

        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)
    {
        MainActivity.methodText.setText("onTick");
        // TODO Auto-generated method stub

    }

    @Override
    public void onFinish()
    {

        MainActivity.methodText.setText("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();

    MainActivity.methodText.setText("onDestroy");

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

protected class SpeechRecognitionListener implements RecognitionListener
{
    private static final String TAG = "SpeechApp";

    @Override
    public void onBeginningOfSpeech()
    {
        MainActivity.methodText.setText("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)
    {
        MainActivity.methodText.setText("onBufferReceived");
    }

    @Override
    public void onEndOfSpeech()
    {
        //Log.d(TAG, "onEndOfSpeech"); //$NON-NLS-1$
        MainActivity.methodText.setText("onEndOfSpeech");
     }

    @Override
    public void onError(int error)
    {
        MainActivity.methodText.setText("onError");

        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)
    {
        MainActivity.methodText.setText("onEvent");
    }

    @Override
    public void onPartialResults(Bundle partialResults)
    {
        MainActivity.methodText.setText("onPartialResults");
    }

    @Override
    public void onReadyForSpeech(Bundle params)
    {
        MainActivity.methodText.setText("onReadyForSpeech");

        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)
    {
        MainActivity.methodText.setText("onResults");

        System.out.println(results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION));
        MainActivity.resultsText.setText(results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION).toString());
        mIsListening = false;
        MainActivity.sendMessage(MyService.MSG_RECOGNIZER_START_LISTENING);
    }

    @Override
    public void onRmsChanged(float rmsdB)
    {
        MainActivity.methodText.setText("onRmsChanged");
    }

}

@Override
public IBinder onBind(Intent intent) {

    MainActivity.methodText.setText("onBind");

    // TODO Auto-generated method stub
    Log.d(TAG, "onBind");  //$NON-NLS-1$
    return mServerMessenger.getBinder();
}
}
Community
  • 1
  • 1
DiegoSahagun
  • 730
  • 1
  • 11
  • 22
  • I have version 2.2 and it works fine. In the thread you mention in onError I send a START_LISTENING message as a general case, you have to take care of particular error. It seems that your network connection is lost, turn off wifi connection in your device and see if it still happens. – Hoan Nguyen Feb 25 '14 at 17:52
  • Many thanks for your reply, I am totally hitting a wall here. I send a START_LISTENING in onError too but it takes around 10 seconds to throw the ERROR_NETWORK_TIMEOUT, that wouldn't be a useful workaround for my case. It is quite weird, I can say for example 15 words in a row and it will recognize them and it will be responsive almost immediately, but when I make a noise like tapping a table with a nail it gets lost in the recognition and after around ten seconds it throws the timeout. When I turn the WiFi off I get an ERROR_NETWORK as expected. – DiegoSahagun Feb 25 '14 at 18:29
  • don't your device has a data plan that you can connect using cell tower? You can try to register for network connection and see if there is any state changed between onEndOfSpeech and onError. – Hoan Nguyen Feb 25 '14 at 19:05
  • Oh, you're right. I've just inserted a sim card with data plan to the phone I am working on and got exactly the same result, works with voice, breaks with noise. The current status of my application is a little different to your answer in the other thread, I will try with exactly your code to see if there is any difference. – DiegoSahagun Feb 25 '14 at 19:22
  • I updated the description and added an example which is almost the same as [your answer](http://stackoverflow.com/questions/14940657/android-speech-recognition-as-a-service-on-android-4-1-4-2), I still have the problem I mention. – DiegoSahagun Feb 26 '14 at 11:28

0 Answers0