Skip to content

Instantly share code, notes, and snippets.

Created June 14, 2014 14:59
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
A TTS (Text-To-Speech) wrapper with extended functionality, designed to be robust and easy to use.
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.util.Log;
import java.util.HashMap;
* A TTS (Text-To-Speech) wrapper with extended functionality, designed to be robust and easy to use.
* @author Lukas Knuth
* @version 1.0
public final class TTS implements TextToSpeech.OnUtteranceCompletedListener {
private TextToSpeech tts;
private final AudioManager am;
private int speech_count = 0;
private final HashMap<String, String> tts_params = new HashMap<String, String>();
private final AudioManager.OnAudioFocusChangeListener afl = new AudioManager.OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
// TODO React to audio-focus changes here!
public interface InitCallback{
* Initialisation was successful, work with the TTS.
public void initSuccess(TTS tts);
* There was an error while initialising the engine.
* @param reason error-number, as returned by {@link android.speech.tts.TextToSpeech.OnInitListener#onInit(int)}.
public void initFail(int reason);
* Creates a new Text-To-Speech engine.
* @param callback will be called, once the engine is initialised and ready for usage.
* @throws java.lang.IllegalStateException you can't initialize this object with a
* {@code context} from an Activity that has not yet completed it's {@link}
* method. Maybe do it in {@link} instead?
public TTS(Context context, final InitCallback callback){
// TTS Parameters:
this.tts_params.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_MUSIC));
this.tts_params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "PLACEHOLDER"); // We only need this so the utterance-complete listener gets called...
// Initialise TTS:
am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
tts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS){
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override public void onStart(String s) {}
@Override public void onError(String s) {}
public void onDone(String utterance_id) {
} else {
} else if (status == TextToSpeech.ERROR) {
* Shutdown the TTS-Engine.
* @param stop_immediately whether the TTS-engine should let any previously queued speeches
* finish, or stop them (and the engine) immediatly.
public void shutdown(boolean stop_immediately){
if (stop_immediately){
* <p>Queue a text for reading out. This will only queue this text and waits, until any earlier
* text's are done playing. Also, Music volume will be lowered (if supported by the current
* media-player) while the text is spoken.</p>
* <p>This method returns immediately after queuing the text.</p>
* @param text the text to read out.
* @return whether the text was successfully queued for reading out, or not.
public boolean queueSpeech(String text){
// Media-Player should lower volume:
int focus_res = am.requestAudioFocus(
// Talk:
if (focus_res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED){
// Add the text to the queue:
int queue_res = tts.speak(text, TextToSpeech.QUEUE_ADD, this.tts_params);
if (queue_res == TextToSpeech.SUCCESS){
// Successfully queued:
return true;
return false;
public void onUtteranceCompleted(String utterance_id) {
if (speech_count == 0){
// No more speeches are queued, give focus back:
Copy link

kasnder commented Jul 6, 2021

Again, thanks for the clarification! I think I had forgotten that Java lives in its own weird world..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment