3

I need the TextToSpeech engine to speak my words one by one, and I am trying to catch the end of speaking of one word to start speaking the next one. But the OnUtteranceCompletedListener cause some delay of the speech. So my question is, how can I fix this or make a better implementation of the OnUtteranceCompletedListener?

public class AndroidTextToSpeechActivity extends Activity implements TextToSpeech.OnInitListener {

    int result = 0, CURRENT_WORD = 0;
    HashMap<String, String> myHash;
    String[] words;
    Button btnSpeak;
    TextToSpeech tts;
    Handler hand = new Handler();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        text = "Hi there how are you";
        words = text.split(" ", 50);
        myHash = new HashMap<String, String>();
        tts = new TextToSpeech(this, this);

        btnSpeak = (Button) findViewById(R.id.btnSpeak);
        btnSpeak.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                hand.postDelayed(run, 300);
            }
        });
    }

    @Override
    public void onInit(int status) {
        if (status == TextToSpeech.SUCCESS) {
            result = tts.setLanguage(Locale.getDefault());
            tts.setPitch(1f);
            tts.setSpeechRate(1f);
        } else
            Log.e("TTS", "Init failed");
    }

    Runnable run = new Runnable() {
        public void run() {
            text = words[CURRENT_WORD];
            tts.speak(text, 1, myHash);
            tts.setOnUtteranceCompletedListener(new OnUtteranceCompletedListener() {

                @Override
                public void onUtteranceCompleted(String utteranceId) {
                    CURRENT_WORD++;
                    hand.post(run1);
                }
            }); 
        }
    };

}
AndyFaizan
  • 1,833
  • 21
  • 30
eevan2go
  • 31
  • 4

2 Answers2

2

You can speed it up by not recreating the OnUtteranceCompleteListener in each run

OnUtteranceCompletedListener listener=new OnUtteranceCompletedListener(){
    @Override
    public void onUtteranceCompleted(String utteranceId) {
        CURRENT_WORD++;
        hand.post(run1);
    }
}
tts.setOnUtteranceCompletedListener(listener);
Runnable run = new Runnable() {
    public void run() {
        text = words[CURRENT_WORD];
        tts.speak(text, 1, myHash);
    }
};

Furthamore, instead of using a Runnable to call the speek() method of the engine through a handler, you can use the onUtteranceCompleted method to call the speak() method

OnUtteranceCompletedListener listener=new OnUtteranceCompletedListener(){
    @Override
    public void onUtteranceCompleted(String utteranceId) {
        CURRENT_WORD++;
        if(CURRENT_WORD<max_words){
            String text=words[CURRENT_WORD];
            tts.speak(text,1,myHash);
        }
    }
}
tts.setOnUtteranceCompletedListener(listener);
Runnable run = new Runnable() {
    public void run() {
        text = words[CURRENT_WORD];
        tts.speak(text, 1, myHash);
    }
};
  • 1
    Yes, this simplified my code a lot and cut the initializations of the listener and the runnable. Now the delay is smaller, but still about 1 second which is too much in speaking. – eevan2go Mar 20 '14 at 12:31
  • can you say how much was the reduction in the delay? – Blagoj Atanasovski Mar 20 '14 at 12:54
  • about 40 milliseconds I guess, but still the pause between each word is longer than the normal about 200 milliseconds(0.2 sec) these numbers are really little, but in normal speed of speaking the pause is about 0.5 seconds, and this pause is about 0.8 which makes the speech sounds strange. – eevan2go Mar 20 '14 at 13:55
0

Your code will fail if Locale.getDefault() language is not supported or need data files. Also, if onInit() has not returned 300 ms after you pressed the btnSpeak, speak() will not function. You should disable btnSpeak in the xml layout file and enable it in onInit. In the btnSpeak listener loop through words and call speak()

btnSpeak = (Button) findViewById(R.id.btnSpeak);
    btnSpeak.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View arg0) {
            for (int i = 0; i < words.length; i++) {
                tts.speak(text, 1, myHash);
                // call playSilence (long durationInMs, 1, myHash) 
                // if you want a slight delay between each word.
            }
        }
    });
Hoan Nguyen
  • 18,033
  • 3
  • 50
  • 54
  • Your code is correct, but not solving my delay problem because in the complete code I am making some animation when a word is spoken, that's why I have to catch the event Utterance Completed for each word. I posted only this part of the code, because no matter of the animation or anything else, the delay is created in the OnUtteranceCompletedListener. The comment for the localisation is also correct and I am doing those checks(and disabling of the button) in the complete code. – eevan2go Mar 19 '14 at 08:19