Blog Archive

Android TextToSpeech example with onUtteranceCompleted issue resolved

Android added the Text-to-Speech (TTS) capability Starting with Android 1.6(API Level 4). TTS enables your Android device to "speak" text of different languages. The TTS engine that ships with the Android platform supports a number of languages: English, French, German, Italian and Spanish. Also, depending on which side of the Atlantic you are on, American and British accents for English are both supported.

The issue with the android onUtteranceCompleted method example in the documentation is the string comparison as shown in the example.

public void onUtteranceCompleted(String uttId) {
    if (uttId == "end of wakeup message ID") {
        playAnnoyingMusic();
    }
}

Tip: You mush replace that with == with String.equals() or String.equalsIgnoreCase() methods.


Android TextToSpeech example with onUtteranceCompleted


Sample code to demonstrate Android Text-to-Speech (TTS) capability


Source code for AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.as400samplecode"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="13" />

    <application android:icon="@drawable/icon" android:label="@string/app_name"
        android:theme="@android:style/Theme.Holo.Light">
       
        <activity android:name=".AndroidTextToSpeechActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>

Source code for main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/hello" />
    <EditText android:id="@+id/yourText" android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button android:id="@+id/speak" android:layout_width="wrap_content"
        android:layout_height="wrap_content" android:text="Android Please Talk" />
</LinearLayout>

Source code for AndroidTextToSpeechActivity

package com.as400samplecode;

import java.util.HashMap;
import java.util.Locale;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class AndroidTextToSpeechActivity extends Activity implements OnInitListener, OnUtteranceCompletedListener{

    private int MY_DATA_CHECK_CODE = 1;
    private TextToSpeech tts;
    private EditText yourText;
    private Button speakButton;

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

        yourText = (EditText) findViewById(R.id.yourText);
        speakButton = (Button) findViewById(R.id.speak);

        speakButton.setOnClickListener(new OnClickListener() {           
            public void onClick(View v) {

                //QUEUE_ADD: Queue mode where the new entry is added at the end of the playback queue.
                //QUEUE_FLUSH: Queue mode where all entries in the playback queue 
                //(media to be played and text to be synthesized) are dropped 
                //and replaced by the new entry.

                String inputText = yourText.getText().toString();
                if (inputText!=null && inputText.length()>0) {
                    for(int i=0;i<3;i++){
                        tts.speak(inputText, TextToSpeech.QUEUE_ADD, null);
                    }
                    // Set utteranceId to know when a particular utterance is done playing
                    HashMap<String, String> myHash = new HashMap<String, String>();
                    myHash.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"done");
                    tts.speak("I am done talking", TextToSpeech.QUEUE_ADD, myHash);
                }
            }
        });

        //check for the presence of the TTS resources with the corresponding intent
        Intent checkIntent = new Intent();
        checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);

    }

    // A successful check will be marked by a CHECK_VOICE_DATA_PASS result code, 
    // indicating this device is ready to speak, after the creation of our TextToSpeech object. 
    // If not, we need to let the user know to install the data that's required for the device 
    // to become a multi-lingual talking machine! Downloading and installing the data is 
    // accomplished by firing off the ACTION_INSTALL_TTS_DATA intent, which will take the 
    // user to Android Market, and will let her/him initiate the download. Installation of 
    // the data will happen automatically once the download completes. Here is an example 
    // of what your implementation of onActivityResult()
    
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == MY_DATA_CHECK_CODE) {
            if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
                // Success, create the TTS instance
                tts = new TextToSpeech(this, this);
            } 
            else {
                // TextToSpeech data is missing, install it
                Intent installIntent = new Intent();
                installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                startActivity(installIntent);
            }
        }
    }

    @Override
    public void onInit(int status) {       
        if (status == TextToSpeech.SUCCESS) {
            Toast.makeText(this,"Text-To-Speech engine is Ready", Toast.LENGTH_SHORT).show();
            //Set language
            tts.setLanguage(Locale.US);
            // Set listener to know when a particular utterance is done playing
            int result = tts.setOnUtteranceCompletedListener(this);
            Log.v("AndroidTextToSpeechActivity", "Result: " + result);
        }
        else if (status == TextToSpeech.ERROR) {
            Toast.makeText(this,"Error initializing Text-To-Speech engine", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onDestroy() {
        Log.v("AndroidTextToSpeechActivity", "onDestory");
        super.onDestroy();
        if (tts  != null) {
            tts.shutdown();
        }
    }

    /*speak() calls are asynchronous, so they will return well before the text is done 
     * being synthesized and played by Android, regardless of the use of QUEUE_FLUSH or QUEUE_ADD. 
     * But you might need to know when a particular utterance is done playing. We also need to make 
     * sure our activity implements the TextToSpeech.OnUtteranceCompletedListener interface
     */
    @Override
    public void onUtteranceCompleted(String uttId) {
        Log.v("AndroidTextToSpeechActivity", uttId);
        if (uttId.equalsIgnoreCase("done")) {
            Log.v("AndroidTextToSpeechActivity", "Done talking, end of message");
        } 
    }

}

4 comments :

  1. I did a workarround apart from using onUtteranceCompleted() mthod,
    See the following
    --------------------------------
    boolean speakingEnd = tts.isSpeaking();
    do {
    speakingEnd = tts.isSpeaking();
    } while ((speakingEnd));
    finish();
    -------------------------

    ReplyDelete
  2. i m using tts to read string arrays item one by one using for loop. but it always speal last item. how to set tts to speak one string after another with a 1 sec delay.

    ReplyDelete