 <p>Ok, I've got it figured out now! What was happening is it was trying to speak before <code>TTS</code> was initialized. So in a thread I wait for ready to not == 999. Once its either 1 or anything else we'll then take care of speaking. This might not be safe putting it in a while loop but... It's working nonetheless.</p> <pre><code>import java.util.HashMap; import java.util.Locale; import android.app.Service; import android.content.Intent; import android.media.AudioManager; import android.os.IBinder; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener; import android.util.Log; public class TTSService extends Service implements OnInitListener, OnUtteranceCompletedListener { TextToSpeech mTTS; int ready = 999; @Override public void onCreate() { Log.d("", "TTSService Created!"); mTTS = new TextToSpeech(getApplicationContext(), this); new Thread(new Runnable() { @Override public void run() { while(ready == 999) { //wait } if(ready==1){ HashMap&lt;String, String&gt; myHashStream = new HashMap&lt;String, String&gt;(); myHashStream.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_NOTIFICATION)); myHashStream.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "1"); mTTS.setLanguage(Locale.US); //mTTS.setOnUtteranceCompletedListener(this); mTTS.speak("I'm saying some stuff to you!", TextToSpeech.QUEUE_FLUSH, myHashStream); } else { Log.d("", "not ready"); } } }).start(); stopSelf(); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { mTTS.shutdown(); super.onDestroy(); } @Override public void onInit(int status) { Log.d("", "TTSService onInit: " + String.valueOf(status)); if (status == TextToSpeech.SUCCESS) { ready = 1; } else { ready = 0; Log.d("", "failed to initialize"); } } public void onUtteranceCompleted(String uttId) { Log.d("", "done uttering"); if(uttId == "1") { mTTS.shutdown(); } } } </code></pre>