Question

I'm trying to get TTS to run in the background. But, I never get any sound. I have a broadcast receiver which starts a service. I put my TTS code in both of those, but it never speaks. I know the method is being called (I put a breakpoint on it), but it still doesn't work.

Here's my log, but it doesn't seem to contain anything about the TTS service.

10-04 22:45:30.663: WARN/InputManagerService(209): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@4423df40
10-04 22:45:37.363: INFO/PollingManager(449): calculateShortestInterval(): shortest interval is 540000
10-04 22:45:37.413: INFO/TLSStateManager(449): org.apache.harmony.nio.internal.SocketChannelImpl@4400ece0: Wrote out 29 bytes of data with 0 bytes remaining.
10-04 22:45:38.043: ERROR/IMAPEmailService(480): Can't create default IMAP system folder Trash. Please reconfigure the folder names.
10-04 22:45:40.123: ERROR/EONS(303): EF_PNN: No short Name
10-04 22:45:41.543: ERROR/WMSTS(171): Month is invalid: 0
10-04 22:45:42.043: WARN/AudioFlinger(172): write blocked for 212 msecs, 24 delayed writes, thread 0xb998

Thanks everyone in advance!

Was it helpful?

Solution

It would help to see your TTS code to make it easier for people to help you. Since I already have TTS working in a BroadcastReceiver, here's an example trimmed down from my code.

public static class TTS extends Service implements TextToSpeech.OnInitListener, OnUtteranceCompletedListener {
    private TextToSpeech mTts;
    private String spokenText;

    @Override
    public void onCreate() {
        mTts = new TextToSpeech(this, this);
        // This is a good place to set spokenText
    }

    @Override
    public void onInit(int status) {
        if (status == TextToSpeech.SUCCESS) {
            int result = mTts.setLanguage(Locale.US);
            if (result != TextToSpeech.LANG_MISSING_DATA && result != TextToSpeech.LANG_NOT_SUPPORTED) {
                mTts.speak(spokenText, TextToSpeech.QUEUE_FLUSH, null);
            }
        }
    }

    @Override
    public void onUtteranceCompleted(String uttId) {
        stopSelf();
    }

    @Override
    public void onDestroy() {
        if (mTts != null) {
            mTts.stop();
            mTts.shutdown();
        }
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
}

Start the TTS service at the point in your BroadcastReceiver where you want it to speak:

context.startService(new Intent(context, TTS.class));

I hope this helps someone if not the asker (I'm sure he got it working by now).

OTHER TIPS

you can also try this,if the text to be spoken is coming from a broadcast listener.first create a service

public class MyTell extends Service implements OnInitListener{
   public MyTell() {
   }

   public static TextToSpeech mTts;

   @Override
   public IBinder onBind(Intent intent) {
       return null;
   }

   public void onStart(Intent intent, int startId) {
       // TODO Auto-generated method stub
       mPreferences = getSharedPreferences(Mysettings.PREF_NAME, Service.MODE_PRIVATE);

       pit = Float.parseFloat(mPreferences.getString("pit","0.8"));
       rate = Float.parseFloat(mPreferences.getString("rate","1.1"));
       mTts = new TextToSpeech(this, this);
       super.onStart(intent, startId);
   }

public void onInit(int status) {
    // TODO Auto-generated method stub
    if (status == TextToSpeech.SUCCESS) {
        if (mTts.isLanguageAvailable(Locale.UK) >= 0)

        Toast.makeText( MyTell.this,
                "Sucessfull intialization of Text-To-Speech engine Mytell ",
                Toast.LENGTH_LONG).show();
        mTts.setLanguage(Locale.UK);

        mTts.setPitch(pit);
        mTts.setSpeechRate(rate);

    } else if (status == TextToSpeech.ERROR) {
        Toast.makeText(MyTell.this,
                "Unable to initialize Text-To-Speech engine",
                Toast.LENGTH_LONG).show();
    }
}}

then create the listener where you're insert your text

public class MyBroadCast extends BroadcastReceiver {
    public MyPop() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        //here is where you're use the service you created to speak the text
        MyTell.mTts.speak("Text to be spoken", TextToSpeech.QUEUE_FLUSH,null);

    }
}

make sure you start the service before you use the tts engine and also check if a tts engine is available

Its working for me (just add on mainfest permision)

public class TES extends Service implements TextToSpeech.OnInitListener {

  private TextToSpeech tts;

  @Override
  public IBinder onBind(Intent arg0) {
    return null;
  }

  @Override
  public void onCreate() {
    super.onCreate();
  }

  @Override
  public void onDestroy() {
    // TODO Auto-generated method stub
    if (tts != null) {
        tts.stop();
        tts.shutdown();
    }
    super.onDestroy();
  }

  @Override
  public void onStart(Intent intent, int startId) {
    tts = new TextToSpeech(this, this);
    speakOut();
  }

  @Override
  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("TTS", "This Language is not supported");
      }
      speakOut();
    } else {
      Log.e("TTS", "Initilization Failed!");
    }
  }

  private void speakOut() {
    tts.speak("its working", TextToSpeech.QUEUE_FLUSH, null);
  }
}

Android TTS is a bounded service. Broadcast receiver has a limited context and can't bind himself to any service. However, It can START a service. All the examples shown here are of services that starting the TTS engine and of receiver that starts them. You can also do it with activity but if you don't need UI a service is better. I just think it's a good idea to understand how it works and why is works. Good luck.

Using Kotlin, the above answers can be re-written as:

Receiver:

class MyReceiver : BroadcastReceiver() {
    val ttsService = Intent(context, TTS::class.java)
    context.startService(ttsService)
}

Service:

class TTS : Service(), TextToSpeech.OnInitListener {
    private var mTts: TextToSpeech? = null
    private var spokenText: String? = null

    override fun onCreate() {
        mTts = TextToSpeech(this, this)
        // This is a good place to set spokenText
        spokenText = "Hello!.."
    }

    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
           val result = mTts!!.setLanguage(Locale.US)
            if (result != TextToSpeech.LANG_MISSING_DATA && result != TextToSpeech.LANG_NOT_SUPPORTED) {
                Thread().run {
                    mTts!!.apply {
                        speak(spokenText, TextToSpeech.QUEUE_FLUSH, null, null)
                    }
                    Thread.sleep(10000)
                    stopSelf()
                }
            }
        } else if (status == TextToSpeech.ERROR) {
           stopSelf()
        }
    }

    override fun onDestroy() {
       if (mTts != null) {
            mTts!!.stop()
            mTts!!.shutdown()
        }
        super.onDestroy()
    }

    override fun onBind(arg0: Intent): IBinder? {
        return null
    }
}

And in the Manifest:

<receiver
    android:name=".MyReceiver">
    <intent-filter>
        <action android:name="android.intent.action.xxxx" />
    </intent-filter>
</receiver>

<service android:name=".TTS" />

Android-O onwards using service for things like this has background restrictions. One can use JobIntentService to achieve the same as shown here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top