3

I wrote the following code:

public class MainActivity extends Activity {

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

   private TextToSpeech mTTS;

   @Override
   protected void onPause() {
       super.onPause();
       if (mTTS != null) {
           mTTS.stop();
           mTTS.shutdown();
       }
   }

   @Override
   protected void onResume() {
       super.onResume();
       mTTS = new TextToSpeech(getApplicationContext(),
               new TextToSpeech.OnInitListener() {
                   @Override
                   public void onInit(int status) {
                       if(status != TextToSpeech.ERROR){
                           mTTS.setLanguage(Locale.ENGLISH);
                           mTTS.speak("Hello!", TextToSpeech.QUEUE_FLUSH, null);
                       }
                   }
               });       
   }

   public void onButtonClick(View view) {
       mTTS.speak("Hello!", TextToSpeech.QUEUE_FLUSH, null);
   }
}

But this code: mTTS = new TextToSpeech(... freezes the UI thread for 5–8 seconds.

I noticed that the delay happens on this line in logcat (first line):

07-13 11:51:11.304    5296-5296/com.example.TextToSpeachTest I/TextToSpeech﹕ Connected to ComponentInfo{com.google.android.tts/com.google.android.tts.service.GoogleTTSService}
07-13 11:51:17.317    5296-5296/com.example.TextToSpeachTest I/Choreographer﹕ Skipped 391 frames!  The application may be doing too much work on its main thread.

I tried to put it inside AsyncTask:

@Override
protected void onResume() {
    super.onResume();

    MyAsyncTask newTask = new MyAsyncTask() {
        protected void onPostExecute(Boolean result) {
        }
    };
    newTask.context = getApplicationContext();
    newTask.execute();
}
...

class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> {
    private TextToSpeech mTTS;
    public Context context;
    @Override
    protected Boolean doInBackground(Void... arg0) {
        mTTS = new TextToSpeech(context,
                new TextToSpeech.OnInitListener() {
                    @Override
                    public void onInit(int status) {
                        if(status != TextToSpeech.ERROR){
                            mTTS.setLanguage(Locale.ENGLISH);
                            mTTS.speak("Hello!", TextToSpeech.QUEUE_FLUSH, null);
                        }
                    }
                });
        return true;
    }
}

But nothing changed. Could you please advise a proper solution/idea?

This delay manifests on my Phone LG L4 II (E440). On Nexus 10 – no delays. I tried different talking apps from Play Store on my LG L4. On some apps there is also UI blocking, but some work without the blocking. This means – it is possible to implement. But how?

ViH
  • 419
  • 2
  • 14

2 Answers2

7

Your code is OK, you don't need to call TextToSpeech constructor from a different thread.

Actually, the problem is in the implementation of some TextToSpeech libraries that use main UI thread to do the speech processing.

The solution is making the TextToSpeech processing to run in a separated process, different from the process of the UI thread. In that way, UI interaction and speech processing is done in the main thread of two different process. The only way that I found to do it is creating the TextToSpeech object and control code in an Android Service with its own process.

In order to create a Service with its own process, configuration in AndroidManifest.xml must include the property: android:process:

    <service
        android:name=".TtsService"
        android:enabled="true"
        android:exported="false"
        android:process="com.example.ttsservice">
    </service>

This introduce complexity because now the Activity must bind the Service using a Messenger or AIDL (http://developer.android.com/guide/components/bound-services.html) to manage the TextToSpeech features.

  • Thank you for the answer and important information. I already gave this TTS up because of this delay. Later I'll try your solution with services (if Google won't fix it). – ViH Aug 14 '14 at 16:18
0

You dont have to do the speech on a background thread.

IMO - you need to implement (TextToSpeech.OnInitListener, UtteranceProgressListener)

                     tts.setOnUtteranceProgressListener(new UtteranceProgressListener()
                     {
                         @Override
                         public void onDone(String utteranceId)
                         {
                             onDoneSpeaking(utteranceId);
                         }

                         @Override
                         public void onError(String utteranceId)
                         {
                         }

                         @Override
                         public void onStart(String utteranceId)
                         {
                         }
                     });
...

    public void onInit(int status) {
        if ( status == TextToSpeech.SUCCESS ) {
            int result = tts.setLanguage( Locale.US );
            if ( result == TextToSpeech.LANG_MISSING_DATA ||
                    result == TextToSpeech.LANG_NOT_SUPPORTED ) {
                Log.e("MainActivity#onInit", "set lang error with "+result);
            }
            else {
                tts.speak(mcomment.substring(left, right), TextToSpeech.QUEUE_FLUSH, null);
Robert Rowntree
  • 6,230
  • 2
  • 24
  • 43
  • TextToSpeech.OnInitListener is already implemented (first code). I have just implemented the UtteranceProgressListener – nothing changed. – ViH Jul 12 '14 at 15:21
  • go back to the android samples ... review it ... ./sdkRoot/samples/legacy/ttsEngine ... introduce it into your existing app just as it appears in the sample/fragment – Robert Rowntree Jul 12 '14 at 15:40
  • I've reviewed this Android Sample. Do you recommend to implement a service? – ViH Jul 13 '14 at 04:56
  • No I don't use that in my app on tts. – Robert Rowntree Jul 13 '14 at 07:48