Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android "speak failed: not bound to tts engine"

Tags:

My android application has text to speak feature and more then one activity uses this feature. So created a static helper class to made this easy.

import java.util.Locale;

import android.content.Context;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.util.Log;

public class TextToSpeechController implements OnInitListener {

    private static final String TAG = "TextToSpeechController";
    private TextToSpeech myTTS;
    private String textToSpeak;
    private Context context;

    private static TextToSpeechController singleton;

    public static TextToSpeechController getInstance(Context ctx) {
        if (singleton == null)
            singleton = new TextToSpeechController(ctx);
        return singleton;
    }

    private TextToSpeechController(Context ctx) {
        context = ctx;
    }

    public void speak(String text) {
        textToSpeak = text;

        if (myTTS == null) {
            // currently can't change Locale until speech ends
            try {
                // Initialize text-to-speech. This is an asynchronous operation.
                // The OnInitListener (second argument) is called after
                // initialization completes.
                myTTS = new TextToSpeech(context, this);

            } catch (Exception e) {             
                e.printStackTrace();
            }
        }

        sayText();

    }

    public void onInit(int initStatus) {
        if (initStatus == TextToSpeech.SUCCESS) {
            if (myTTS.isLanguageAvailable(Locale.UK) == TextToSpeech.LANG_AVAILABLE)
                myTTS.setLanguage(Locale.UK);
        }

        // status can be either TextToSpeech.SUCCESS or TextToSpeech.ERROR.
        if (initStatus == TextToSpeech.SUCCESS) {
            int result = myTTS.setLanguage(Locale.UK);
            if (result == TextToSpeech.LANG_MISSING_DATA
                    || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                Log.e(TAG, "TTS missing or not supported (" + result + ")");
                // Language data is missing or the language is not supported.
                // showError(R.string.tts_lang_not_available);

            } else {
                // Initialization failed.
                Log.e(TAG, "Error occured");
            }

        }
    }

    private void sayText() {
        // ask TTs to say the text
        myTTS.speak(this.textToSpeak, TextToSpeech.QUEUE_FLUSH,     null);
    }

    public void stopTTS() {
        if (myTTS != null) {
            myTTS.shutdown();
            myTTS.stop();
            myTTS = null;
        }
    }

}

I am using this helper class like this.

TextToSpeechController.getInstance(this).speak(readableMessage);

But sometimes i see an error like line beloew at LogCat.

"speak:failed not bound to tts engine"

No exception thrown but nothing readed by TTS. I realized that if i triggered activity from BroadcastReceiver, i got this error. Otherwise if manually open activity from application code works with no problem.

Here is the BroadcastReceiver code

private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);            
        String readableMessage = intent.getExtras().getString(READABLE_MESSAGE);    

        Bundle b = new Bundle();
        b.putString(EXTRA_MESSAGE, newMessage);
        b.putString(READABLE_MESSAGE, readableMessage);
        Intent newIntent = new Intent("android.intent.action.MAIN");
        newIntent.setClass(context, Speak.class);
        newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        newIntent.putExtra("MessageReceived", b);
        newIntent.putExtra("CallType", CallType.NOTIFICATION);
        context.startActivity(newIntent);           
    }
};
like image 490
bahadir arslan Avatar asked Aug 02 '12 13:08

bahadir arslan


Video Answer


2 Answers

Your code is not waiting for the asynch return from the constructor of the TextToSpeech class. You even have a comment that says it is asynch. Why it always fails in the Receiver but not the Activity I am not sure - other then maybe the Activity as a foreground task has higher priority and it happen to complete before you call sayText.

You need to wait to call sayText until the init call returns in the case where it has to new up a new TTS object.

like image 150
Kaediil Avatar answered Sep 23 '22 03:09

Kaediil


Here is the code I use for text to speech. For my code simply type speakWords("say something"); in any activity.

public class VoiceRecognition extends Activity implements OnClickListener,
        OnInitListener {

    public static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;

    public Button speakButton;
    // TTS object
    public TextToSpeech myTTS;
    // status check code
    public int MY_DATA_CHECK_CODE = 0;

    // setup TTS
    public void onInit(int initStatus) {

        // check for successful instantiation
        if (initStatus == TextToSpeech.SUCCESS) {
            if (myTTS.isLanguageAvailable(Locale.US) == TextToSpeech.LANG_AVAILABLE)
                myTTS.setLanguage(Locale.US);
        } else if (initStatus == TextToSpeech.ERROR) {
            Toast.makeText(this, "Sorry! Text To Speech failed...",
                    Toast.LENGTH_LONG).show();
        }
    }

    /**
     * Called with the activity is first created.
     */
    @Override
    public void onCreate(Bundle voiceinput) {
        super.onCreate(voiceinput);

        // Inflate our UI from its XML layout description.
        setContentView(R.layout.voice_recognition);

        // check for TTS data
        Intent checkTTSIntent = new Intent();
        checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);

    }

    // speak the user text
    public void speakWords(String speech) {

        // speak straight away
        myTTS.speak(speech, TextToSpeech.QUEUE_FLUSH, null);
    }


    public void onClick(View v) {
        speakWords("hello";
    }


    /**
     * Handle the results from the recognition activity.
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (requestCode == MY_DATA_CHECK_CODE) {
            if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
                // the user has the necessary data - create the TTS
                myTTS = new TextToSpeech(this, this);
            } else {
                // no data - install it now
                Intent installTTSIntent = new Intent();
                installTTSIntent
                        .setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                startActivity(installTTSIntent);
            }
        }

        super.onActivityResult(requestCode, resultCode, data);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myTTS.shutdown();
    }
like image 35
Sam Bevins Avatar answered Sep 23 '22 03:09

Sam Bevins