Search code examples
javaandroidspeech-recognitionnsspeechrecognizer

SpeechRecognizer | What happend (nothing happend) after say nothing?


I dont find an answer on google or i dont get the right words for it.

So the SpeechRecognizer works fine. But when i hear the beep (i use it without the google dialog) and i say nothing for about 3 seconds or more, its like the recognizer do nothing and fade away, no second beep to hear, no onResult(), no EndofSpeech.

So what happend when the Recognizer is listening and you say nothing? Which method get fired?

EDIT: After all it works, big thanks to OpiateFuchs and his realy good comments and answers. I edit the simplified code that way, that you guys can see how to make it.
onPartialResult() is called often even if you say nothing, but when this happen the partialResult String is empty, so if its empty you know nothing was spoken. (Idea from OpiateFuchs)

Thats my simplified Code which is important for the Recognizer:

public Constructor (){
        speech = SpeechRecognizer.createSpeechRecognizer(context);
        speech.setRecognitionListener(this);
        recogIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        recogIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "de");
        speech.startListening();
}

public void startListening(){
    speech.startListening(recogIntent);
    if(timerRunning==false){
        setcdt();
        mCountDownTimer.start();
        timerRunning=true;
    }
}

@Override
public void onReadyForSpeech(Bundle params) {

}

@Override
public void onBeginningOfSpeech() {

}

@Override
public void onRmsChanged(float rmsdB) {

}

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

}

@Override
public void onEndOfSpeech() {
    Toast.makeText(c, "work", Toast.LENGTH_SHORT);
    //too see if its called
}

@Override
public void onError(int error) {

}

@Override
public void onResults(Bundle results) {
    ArrayList<String> matches = results
            .getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);

    Toast.makeText(c, matches.get(0), Toast.LENGTH_LONG).show();
    speech.cancel();
    analyse(matches.get(0));
    m.next(); //calls the Recognizer again

}

@Override
public void onPartialResults(Bundle partialResults) {
ArrayList<String> matches = partialResults
            .getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);

    if(matches.get(0).length() == 0){
        m.tv.append("nothing"); //show on textview

    }
    else{
        m.tv.append("cancel timer "); //show on textview
        mCountDownTimer.cancel();
        hasSpoken = true;
        timerRunning = false;
    }

}

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

}

//innerclass
public class FinishSpeechRecognizerTimer extends CountDownTimer {

    public FinishSpeechRecognizerTimer(long startTime, long interval){
        super(startTime,interval);

    }

    @Override
    public void onFinish(){
        timerRunning = false;
        if (hasSpoken==false){
            m.tv.append("nospeak ");
            speech.cancel();
            m.tv.append("listen again after no speak ");
            startListening();
        }
    }

    @Override
    public void onTick(long millisUntilFinish){

    }
}

public void setcdt(){
    startTime = 5000;
    interval = 4000; //want no onTick - interval > startTime
    timerRunning = false;
    hasSpoken = false;
    mCountDownTimer = new FinishSpeechRecognizerTimer(startTime, interval);
}

Solution

  • For this discussion I try to provide an example from scratch which should lead you into the right direction. As said in the comments, it seems that the SpeechRecognition does not stop from itself if nothing is said, so you simply could implement a CountDownTimer for example and finish the SpeechRecognizer after a certain time:

    make global SpeechRecognizer (like you have done), boolean and CountdownTimer objects :

    private SpeechRecognizer speech;   
    private boolean hasSpoken=false;
    private CountDownTimer mCountDownTimer;
    private long startTime = 30000L;
    private long interval = 1000L;
    private boolean timerRunning = false;
    

    extend the CountDownTimer class:

    public class FinishSpeechRecognizerTimer extends CountDownTimer{
    
            public FinishSpeechRecognizerTimer(long startTime, long interval){
              super(startTime,interval);
    
               }
    
             @Override
             public void onFinish(){
    
                 if(hasSpoken==false){
                    speech.cancel();
                }
    
               timerRunning=false;
    
              }
    
             @Override
             public void onTick(long millisUntilFinish){
    
               //do whatever you want to do
    
           }
    }
    

    initialize

    speech = SpeechRecognizer.createSpeechRecognizer(yourContext);
    mCountDownTimer = new FinishSpeechRecognizerTimer(startTime, interval);
    

    start it and at the same time start the CountDownTimer:

    speech.startListening(recogIntent);
    if(timerRunning==false){
    mCountDownTimer.start();
    timerRunning=true;
    }
    

    And as soon as something is spoken, set the boolean value hasSpoken to true and cancel the timer:

    @Override
    public void onBeginningOfSpeech() {
       hasSpoken=true;
       mCountDownTimer.cancel();
       timerRunning=false;
    }
    

    As I said, it´s from scratch, can´t guarantee that this is working. This example starts the CountDownTimer for 30 seconds and checks every second if something is spoken. How long you want to wait is up to you.

    EDIT

    Turns out that in some cases the onBeginOfSpeech() method is called multiple times without anybody is speaking. For everyone who is interested:

    instead of doing that stuff in onBeginOfSpeech(), you can use the method onPartialResult():

    @Override
    public void onPartialResults(Bundle partialResults) {
    ArrayList<String> matches = results
                .getStringArrayList(SpeechRecognizer.RESULT_RECOGNITION);
     if(matches.size()==0){
    
            hasSpoken=false;
    
     }else{
    
      hasSpoken=true;
      mCountDownTimer.cancel();
           timerRunning=false;
       }
    }