10

TTS initialization error was observed in the following scenarios, that too randomly.

  • TTS engine is installed, voice set is present and sample tts can be played from the Accessibility options.

  • The TTS initialization fails randomly on the same device where it was previously initialized and playing.

  • This issue was observed in different devices(One plus,Asus,Samsung) and various Android OS versions.

Code Snippet:

public class TTSHandler implements OnInitListener {

public EPUBReader context;
private TextToSpeech tts;
private HashMap<String, String> ttsMap;
private boolean isTtsPlaying = false,shouldResume = false,initialised = false,
            ttsModeEnabled = false;
private String textToRead;
private GoogleVersionPreferences mSharedPreferences;
private AudioManager mAudioManager;


@SuppressWarnings("deprecation")
public TTSHandler(EPUBReader context){

    this.context = context;
    tts = new TextToSpeech(context,this);

}

@Override
public void onInit(int status) {
    Log.d("TTS", "onInit called");
    if(status == TextToSpeech.SUCCESS){

        initialised = true;
        Log.d("TTS", "initialised success: status = "+status);
        initTTSComponents();

    }else{
        initialised = false;
        Log.d("TTS", " initialised failed: status ="+status);
    }

}

/**
 * called form JavascriptInterface
 * @param text is the sentence to be read
 */
public void readText(String text){

    if(text!=null){
        textToRead = text;
    }
    ttsMap = new HashMap<String, String>();
    ttsMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, textToRead);
    //for Next/Prev
    isTtsPlaying = true; 
    context.runOnUiThread(new Runnable(){
        @Override
        public void run() {
            context.toggleTtsIcons();
        }

    });

    tts.speak(textToRead,0, ttsMap);

}

/**
 * called to play,pause or resume tts play. 
 */
public void playPauseReading(){
    context.lockOrientationChange();
    AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    int volume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);

    if(isTtsPlaying){

        isTtsPlaying = false;
        shouldResume = true;
        tts.stop();

    }else{

        isTtsPlaying = true;

        if(shouldResume){
            shouldResume = false;
            requestAudioFocusForTTS();
            JavaScriptInterface.loadJavascript("javascript:resumeUsingTts()", context.getEPUBReaderFragment().getWebview());
        }else{
            requestAudioFocusForTTS();
            if(volume <= 1){
                Toast.makeText(context,context.getResources().getString(R.string.tts_volume_alert), 300).show();
            }
            int dir = mSharedPreferences.getEpubNavigationSetting(context.bookId);
            JavaScriptInterface.loadJavascript("javascript:playFromRange("+dir+")", context.getEPUBReaderFragment().getWebview());

        }
    }
    context.toggleTtsIcons();
}

/**
 * called to stop playing tts 
 * highlight will be removed and we will hide the tts controls
 */
public void stopReading(){

    if(tts !=null && ttsModeEnabled){
        isTtsPlaying = false;
        shouldResume = false;
        ttsModeEnabled = false;
        tts.stop();
        Toast.makeText(context,context.getResources().getString(R.string.tts_stop) , 300).show();
        JavaScriptInterface.loadJavascript("javascript:stopUsingTts()", 
                context.getEPUBReaderFragment().getWebview());
        abandonAudioFocus();
        context.runOnUiThread(new Runnable(){

            @Override
            public void run() {
                context.toggleControlPanel(false);
                context.unlockOrientationChange();
                context.invalidateOptionsMenu();
            }

        });


    }
}


/**
 * To check the whether tts is playing or not 
 * @return
 */
public boolean isReading(){
    if(tts.isSpeaking()){
        return true;
    }
        return false;
}

/**
 *  called from javascriptInterface at the end of a chapter
 *  
 */
public void stopReadingOnEndOfChapter(){

    Log.d("TTS", "stopReadingOnEndOfChapter");
    shouldResume = false;
    isTtsPlaying = false;
    ttsModeEnabled = false;
    abandonAudioFocus();
    context.runOnUiThread(new Runnable(){

        @Override
        public void run() {
            context.toggleControlPanel(false);
            context.unlockOrientationChange();
            context.invalidateOptionsMenu();
            Toast.makeText(context,context.getResources().getString(R.string.end_of_chapter) , 300).show();

        }});


}

/**
 * called from javascriptInterface to disable tts mode when the chapter doesnt have any text content.
 */
public void stopOnNoContent(){

    Toast.makeText(context,context.getResources().getString(R.string.tts_no_content) , 300).show();
    shouldResume = false;
    isTtsPlaying = false;
    ttsModeEnabled = false;
    abandonAudioFocus();
    context.runOnUiThread(new Runnable(){

        @Override
        public void run() {
            context.toggleControlPanel(false);
            context.unlockOrientationChange();
            context.invalidateOptionsMenu();

        }});
}

/**
 * called from javascript to stop tts while user taps on links
 */
public void stopTtsOnLinks(){

    if(isReading() || shouldResume)
        Toast.makeText(context,context.getResources().getString(R.string.tts_stop) , 300).show();

    shouldResume = false;
    isTtsPlaying = false;
    ttsModeEnabled = false;
    tts.stop();
    context.toggleControlPanel(false);
    context.unlockOrientationChange();
    abandonAudioFocus();

}

/**
 * Will release the resources used by the TTS engine 
 */
public void shutDownTTS(){
    if(tts !=null){
        tts.shutdown();
    }
}

/**
 * called from EPUBReader to set the speech rate
 * @param speechRate
 */
public void setSpeechRate(int value){

    switch(value){
        case 0:
            tts.setSpeechRate((float)0.1);
            break;
        case 1:
            tts.setSpeechRate((float)0.5);
            break;
        case 2:
            tts.setSpeechRate((float)1);
            break;
        case 3:
            tts.setSpeechRate((float)1.5);
            break;
        case 4:
            tts.setSpeechRate((float)2);
            break;

    }

}

/**
 * called form EPUBReader to start playing the next line 
 */
public void playNext(){
    isTtsPlaying = false;
    tts.stop();
    JavaScriptInterface.loadJavascript("javascript:readNext()",context.getEPUBReaderFragment().getWebview());
}

/**
 * called form EPUBReader to start playing the previous line
 */
public void playPrevious(){
    isTtsPlaying = false;
    tts.stop();
    JavaScriptInterface.loadJavascript("javascript:playPrevious()",context.getEPUBReaderFragment().getWebview());
}

/**
 * if TTS engine is initialised successfully,
 *  we will set the listener and other components.
 */
private void initTTSComponents(){

    mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    tts.setSpeechRate(1);
    mSharedPreferences = GoogleVersionPreferences.getGoogleAppVersion(context);

    tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {

            @Override
            public void onStart(String utteranceId) {
                Log.d("TTS", "onStart:"+utteranceId);
            }

            @Override
            public void onError(String utteranceId) {
                Log.d("TTS", "onError ID:"+utteranceId);

            }

            @Override
            public void onDone(String utteranceId) {
                Log.d("BUG", "onDone, isTtsPlaying:"+isTtsPlaying);
                if(isTtsPlaying){
                    JavaScriptInterface.loadJavascript("javascript:readNext();",
                            ((EPUBReader) context).getEPUBReaderFragment().getWebview());
                }
            }

        });

}

/**
 * Requests audio focus so that when TTS starts 
 * other audio apps will be paused/ducked as per the app.
 */
private void requestAudioFocusForTTS(){

    mAudioManager.requestAudioFocus(null,AudioManager.STREAM_MUSIC , AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE);
}

/**
 *Will abandon the received audio Focus so that the 
 *previous app can attain it.
 */
private void abandonAudioFocus(){

    mAudioManager.abandonAudioFocus(null);
}




/**
 * getters and setters
 * @param value
 */
public void setisTtsPlaying(boolean value){
    isTtsPlaying = value;
}

public boolean isTtsPlaying(){
    return isTtsPlaying;
}

public void setshouldResume(boolean value){
     shouldResume = value;
}

public boolean shouldResume(){
    return shouldResume;
}

public boolean isTtsInitialised(){
    return initialised;
}

public boolean ttsModeEnabled(){
    return ttsModeEnabled;
}

public void setttsModeEnabled(boolean value){
    ttsModeEnabled = value;
}

}

Note: Logs collected:

For Samsung device(TabS 10.5 OS:5.0.2): E/SamsungTTS(20259): onLoadLanguage() - SamsungTTS is not yet ready.

For One plus one(OS:6.0.1):

08-08 18:54:53.112: W/TextToSpeech(22946): stop failed: TTS engine connection not fully set up 08-08 18:56:15.869: I/TextToSpeech(22946): Sucessfully bound to com.google.android.tts 08-08 18:56:16.060: I/TextToSpeech(22946): Connected to ComponentInfo{com.google.android.tts/com.google.android.tts.service.GoogleTTSService}

Midhun Kumar
  • 549
  • 5
  • 23
  • You are not getting any errors ?. Also if(tts != null){ tts.shutdown(); } use this code on onStop() to shutdown it properly after each use. – Sunil Sunny Jul 25 '16 at 06:07
  • When you say 'initialisation fails', do you mean `onInit()` returns `ERROR`? – brandall Jul 25 '16 at 11:46
  • if(tts != null){tts.shoutdown();} is executed in the onStop(); @sunilsunny – Midhun Kumar Jul 26 '16 at 07:17
  • @brandall the onInit() itself is not called. – Midhun Kumar Jul 26 '16 at 07:37
  • Also, I have a Service which downloads epubs(ebooks) from internet. And whenever i have started downloading something, onInit() itself is not called. @brandall – Midhun Kumar Jul 26 '16 at 07:52
  • Whenever you use the Text to Speech object, it needs to be initialised. If `onInit` is not called, or does not return `SUCCESS` then there is an error in your code. You'd need to post it in order for someone to help. – brandall Jul 26 '16 at 13:31
  • @brandall i have added the code snippet, the same code works fine most of the cases and randomly it fails too. Also any info regarding why it fails when downloading is happening as mentioned in the previous comment – Midhun Kumar Jul 26 '16 at 14:10
  • There doesn't seem to be anything wrong with what you've posted. It may be how it runs from your service. If the service is already running, then `onStartCommand()` will be called, rather than `onCreate()`. Are you only initialising in the latter? I'm guessing, without seeing your service code. – brandall Jul 27 '16 at 12:18
  • @brandall sorry but i didn't understand what you were talking about service. My TTS is initialized from an Activity not from Service. And ebook download happens in a service – Midhun Kumar Jul 27 '16 at 12:26
  • I see, I thought they were connected. You'd need to post your full Activity code, as without seeing where you are attempting to initialise the TTS and destroying it - and calling speak, I'd be guessing as to the cause. – brandall Jul 27 '16 at 12:41
  • @brandall hi, i have added the whole TTSHandler class here. And the object is created at the end of onCreate() of my Activity which holds my WebView. – Midhun Kumar Aug 05 '16 at 10:03
  • Also the issue appears more often after generating signed apks. – Midhun Kumar Aug 31 '16 at 04:57
  • if signed builds has some issues then it is something related to your proguard file. just check if you have correct rules for TTS packages. – Ankit Sep 22 '16 at 13:53
  • @Ankit we have added exceptions for TTS class in proguard, also the issue can be observed in debug mode also. And mainly in debug and signed mode this issue is observed randomly. ie we dont have any definite steps to reproduce it – Midhun Kumar Sep 22 '16 at 14:56
  • if so add more logs for each method start, stop and other places. make same tag for everything so you can filter logs for that. – Ankit Sep 23 '16 at 19:55
  • Hi @Ankit, we actually did that. Added logs at the start and ending of the constructor and both got logged properly. Once we call tts = new TextToSpeech(context,this); we are supposed to get a call to onInit() with the result of initialization. We also have logs in onInit() too. And found out that onInit() itself is not getting called. – Midhun Kumar Sep 26 '16 at 05:25
  • Have you checked if you are passing correct context? – Ankit Sep 26 '16 at 07:10
  • @Ankit previously we were passing the activity context. Now am checking by passing application context. – Midhun Kumar Sep 26 '16 at 07:32
  • @Ankit With application context also we are facing the same issue, onInit() doesnt get called. That too randomly, most of the time it worked and all of a sudden it didn't. – Midhun Kumar Sep 26 '16 at 12:39
  • Hi @Ankit, We have a Service which is used to download books, and when we have books in downloading state and try to initialize TTS, onInit() doesn't get called sometimes. – Midhun Kumar Sep 27 '16 at 06:06
  • In my case, *onInit()* is getting called with Error status in one of the Huawei device P40 lite :(. In rest other devices, it seems to be working fine. – Narendra Singh Apr 13 '20 at 13:38

2 Answers2

10

I had this TTS Initialization failed because I was using Android 11 Emulator and it requires to mention this in the Android Manifest

<queries>
        <intent>
            <action android:name="android.intent.action.TTS_SERVICE" />
        </intent>
</queries>
Arjupta
  • 141
  • 1
  • 4
0

In Android Studio, TextToSpeech initialization is failing on Pixel C, Nexus 7, and Nexus 10 tablet emulators running API 30. It looks like a bug. Declaring TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE in the queries elements of the manifest does not fix the bug when the tablet emulator is running API 30. Here is what was added to the manifest:

<queries>
    <intent>
        <action android:name="android.intent.action.TTS_SERVICE" />
    </intent>
</queries>

For the manifest requirement, see https://developer.android.com/reference/android/speech/tts/TextToSpeech

I found that a Nexus 5x emulator running API 30 with TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE in the queries elements of the manifest ; and Pixel C, Nexus 7, and Nexus 10 tablet emulators running API 29 in Android Studio allow for successful initialization of TextToSpeech.