I'm really struggling with something... I have a couple of sentences that I want to read, both verbally through tts speek function, and via text on screen, one sentence at a time.
I have the textview area ready, but putting it together is what I'm not getting. Either it will read all the sentences and only show the last one, or it will show and read only the first sentence.
Anyone know i how I can accomplish this goal?
I just ran into this issue, according to the speak method, use an UtteranceProgressListener. I found out this is not executed on the UI thread, so I had to use runOnUiThread() to get back to update the activity.
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
}
#Override
public void onDone(String utteranceId) {
LettersActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// Do something on UI thread
}
});
}
#Override
public void onError(String utteranceId) {
Log.e(TAG, "error on " + utteranceId);
}
});
boolean speakingEnd = tts.isSpeaking();
do{
speakingEnd = tts.isSpeaking();
} while (speakingEnd);
//Continue with code
public void speak(String message){
tts.speak(message, TextToSpeech.QUEUE_FLUSH, null);
while (tts.isSpeaking()){
System.Out.Println("Do something or nothing while speaking..")
}
}
Try this
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener{
private boolean initialized;
private String queuedText;
private String TAG = "TTS";
private TextToSpeech tts;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tts = new TextToSpeech(this /* context */, this /* listener */);
tts.setOnUtteranceProgressListener(mProgressListener);
speak("hello world");
}
public void speak(String text) {
if (!initialized) {
queuedText = text;
return;
}
queuedText = null;
setTtsListener(); // no longer creates a new UtteranceProgressListener each time
HashMap<String, String> map = new HashMap<String, String>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "MessageId");
tts.speak(text, TextToSpeech.QUEUE_ADD, map);
}
private void setTtsListener() {
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
initialized = true;
tts.setLanguage(Locale.ENGLISH);
if (queuedText != null) {
speak(queuedText);
}
}
}
private abstract class runnable implements Runnable {
}
private UtteranceProgressListener mProgressListener = new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
} // Do nothing
#Override
public void onError(String utteranceId) {
} // Do nothing.
#Override
public void onDone(String utteranceId) {
new Thread()
{
public void run()
{
MainActivity.this.runOnUiThread(new runnable()
{
public void run()
{
Toast.makeText(getBaseContext(), "TTS Completed", Toast.LENGTH_SHORT).show();
}
});
}
}.start();
}
};
}
Related
This is a test activity when the button is pressed the textToSpeech works just fine, but it wont work when the function playString() is called, playString() is being called from the onCreate() of this TestActivity.
public class TestActivity extends Activity {
TextToSpeech textToSpeech;
EditText editText;
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
editText=(EditText)findViewById(R.id.editText);
button=(Button)findViewById(R.id.button);
textToSpeech=new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) {
textToSpeech.setLanguage(Locale.UK);
}
}
});
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String sentence = "Testing String";
textToSpeech.speak(sentence, TextToSpeech.QUEUE_FLUSH, null);
}
});
playString();
}
public void playString(){
String sentence = "Testing String";
textToSpeech.speak(sentence, TextToSpeech.QUEUE_FLUSH, null);
}
public void onPause(){
if(textToSpeech !=null){
textToSpeech.stop();
textToSpeech.shutdown();
}
super.onPause();
}
}
From documentation:
TextToSpeech instance can only be used to synthesize text once it has completed its initialization.
Initialization may take long time (on my device it's take ~30 seconds), so you can't use handler with some random delay.
Instead, you can place playString() in onInit block right after textToSpeech.setLanguage(Locale.UK);, so string will be played when it can be played.
Please use below code in oncreate method to call the texttospeech:
textToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
textToSpeech.setLanguage(Locale.UK);
}
}
});
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
String sentence = "Testing String";
textToSpeech.speak(sentence, TextToSpeech.QUEUE_FLUSH, null);
}
}, 500);
In Android TextToSpeech, How come we know either Speech is finished. I want to change icon after speech finished. I declared tts.speak() in Button Onclick Listener. i used thread postdelayed handler to change icon after some time. but the text to read changes different at different times.It didnt worked out. CheckThemestart(),ChangeThemeStop() are functions to change the icon.
i declared the following in OnCreate() :
tts = new TextToSpeech(getContext(), new
TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status != TextToSpeech.ERROR) {
tts.setLanguage(Locale.UK);
tts.speak("",TextToSpeech.QUEUE_FLUSH,null);
}
Button-onClickListener :
if (!tts.isSpeaking()) {
CheckThemeStart();
tts.speak(plainText, TextToSpeech.QUEUE_FLUSH, null);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//change icon after spoken
CheckThemeStop();
}
}, 15000);
} else {
CheckThemeStop();
tts.stop();
}
You can register UtteranceProgressListener for tts start and end times and error handling.
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String s) {
}
#Override
public void onDone(String s) {
}
#Override
public void onError(String s) {
}
});
If we declare a hasmap parameter with unique string ID and pass that id to compare utterence id if matches it execute what you declare inside onUtterenceCompletedListener().
The following is code snippet.
HashMap<String,String> params=new HashMap<String, String>();
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"SpeakID");
tts.speak(plainText, TextToSpeech.QUEUE_FLUSH,params);
tts.setOnUtteranceCompletedListener(new TextToSpeech.OnUtteranceCompletedListener() {
#Override
public void onUtteranceCompleted(String utteranceId) {
if(utteranceId.equals("SpeakID"))
{
CheckThemeStop();
}
}
});
I am getting error "android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views" when I call listenButton.setAlpha((float)1) in the code below. I understand why, but how can I then modify a button when I receive the onDone event?
public class MainActivity extends ActionBarActivity implements TextToSpeech.OnInitListener {
[...]
#Override
// OnInitListener method to receive the TTS engine status
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
ttsOK = true;
tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onDone(String utteranceId) {
Button listenButton = (Button) findViewById(R.id.listentts);
listenButton.setAlpha((float)1);
listenButton.setClickable(true);
}
#Override
public void onError(String utteranceId) {
Log.d("MainActivity", "Progress on Error " + utteranceId);
}
#Override
public void onStart(String utteranceId) {
Log.d("MainActivity", "Progress on Start " + utteranceId);
}
});
}
else {
ttsOK = false;
}
}
[...]
}
Every View has a Handler associated with it, so there's no need to create a new one.
final View v = findViewById(R.id.listentts); // could be a class member
v.getHandler().post(new Runnable() {
#Override
public void run() {
v.setAlpha(1.0f);
v.setClickable(true);
}
});
Try this:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Button listenButton = (Button) findViewById(R.id.listentts);
listenButton.setAlpha((float)1);
listenButton.setClickable(true);
}
});
Here is my code, I have a series of questions that will be asked by TTS and after every question speech recognizer will be invoked.My utterance listener is never being called.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_speech_recognizer);
tts = new TextToSpeech(this /* context */, this /* listener */);
}
//This is called after first time user clicks a button
private void processEnquiry() {
// TODO Auto-generated method stub
for(int i=0;i<EnquiryList.size();i++)
{
speak(EnquiryList.get(i).toString());
}
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
initialized = true;
tts.setLanguage(Locale.ENGLISH);
if (queuedText != null) {
speak(queuedText);
}
}
}
public void speak(String text) {
// If not yet initialized, queue up the text.
if (!initialized) {
queuedText = text;
return;
}
queuedText = null;
// Before speaking the current text, stop any ongoing speech.
//tts.stop();
// Speak the text.
setTtsListener();
HashMap<String, String> map = new HashMap<String, String>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"MessageId");
tts.speak(text, TextToSpeech.QUEUE_ADD, map);
}
private void setTtsListener()
{
final SpeechRecognizer callWithResult = this;
int listenerResult = tts.setOnUtteranceProgressListener(new UtteranceProgressListener()
{
#Override
public void onDone(String utteranceId)
{
callWithResult.onDone(utteranceId);
}
#Override
public void onError(String utteranceId)
{
callWithResult.onError(utteranceId);
}
#Override
public void onStart(String utteranceId)
{
callWithResult.onStart(utteranceId);
}
});
if (listenerResult != TextToSpeech.SUCCESS)
{
Log.e(TAG, "failed to add utterance progress listener");
}
}
public void onDone(String utteranceId)
{
callSpeechRecognition();
}
public void onError(String utteranceId)
{
}
public void onStart(String utteranceId)
{
}
TextToSpeech.SUCCESS returns 0.
Here's a modified version of your script, where the onDone() method in the Utterance listener is called. I have eliminated many features that are not directly connected to the TTS playback, to create a barebones sample. If this works for you, then you can add back the other features one by one, testing that nothing breaks on the way.
import android.app.Activity;
import android.os.Bundle;
import android.speech.SpeechRecognizer;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.util.Log;
import android.view.View;
import java.util.HashMap;
import java.util.Locale;
public class MainActivity extends Activity implements TextToSpeech.OnInitListener {
private TextToSpeech tts;
private SpeechRecognizer sr;
private boolean initialized;
private String queuedText;
private String TAG = "TTS";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_speech_recognizer);
tts = new TextToSpeech(this /* context */, this /* listener */);
tts.setOnUtteranceProgressListener(mProgressListener);
sr = SpeechRecognizer.createSpeechRecognizer(this); // added
}
// Modified for testing purposes
//This is called after first time user clicks a button
/*
private void processEnquiry() {
for (int i = 0; i < EnquiryList.size(); i++) {
speak(EnquiryList.get(i).toString());
}
}
*/
public void processEnquiry(View v) {
speak("Process enquiry");
}
// End of modification
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
initialized = true;
tts.setLanguage(Locale.ENGLISH);
if (queuedText != null) {
speak(queuedText);
}
}
}
public void speak(String text) {
// If not yet initialized, queue up the text.
if (!initialized) {
queuedText = text;
return;
}
queuedText = null;
// Before speaking the current text, stop any ongoing speech.
//tts.stop();
// Speak the text.
setTtsListener(); // no longer creates a new UtteranceProgressListener each time
HashMap<String, String> map = new HashMap<String, String>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "MessageId");
tts.speak(text, TextToSpeech.QUEUE_ADD, map);
}
private void setTtsListener() {
// Method radically simplified; callWithResult is retained but not used here
final SpeechRecognizer callWithResult = sr; // was `this`
}
private UtteranceProgressListener mProgressListener = new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
} // Do nothing
#Override
public void onError(String utteranceId) {
} // Do nothing.
#Override
public void onDone(String utteranceId) {
callSpeechRecognition();
}
};
private void callSpeechRecognition() {
Log.d(TAG, "callSpeechRecognition() called");
}
}
I'm not sure exactly and not sure if this answer will help you, but I think you should not set UtteranceProgressListener every time you request TTS to speak, instead you should set the listener at onInit() once.
And note that the empty text will not be spoken so no callback will be invoked as well.
Though basically setting the listener after TTS initialization looks fine for me and works without problems on my Nexus5 and GalaxyS4, even if setting the listener every time I request TTS to speak, so there might be some device specific problems or some TTS engine specific problems.
Oops I forgot to mention that UtteranceProgressListener is available on API level 15 and above, so the listener will no be invoked on API level 14 and below.
I'm implementing an Interactive Voice Response application on Android. I would like to know how to determine when the tts.speak() function has done talking so I can call my speech recognizer function.
public class TTSActivity extends Activity implements OnInitListener, OnUtteranceCompletedListener, ... {
private TextToSpeech mTts;
...........
private void speak(String text) {
if(text != null) {
HashMap<String, String> myHashAlarm = new HashMap<String, String>();
myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_STREAM, String.valueOf(AudioManager.STREAM_ALARM));
myHashAlarm.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "SOME MESSAGE");
mTts.speak(text, TextToSpeech.QUEUE_FLUSH, myHashAlarm);
}
}
// Fired after TTS initialization
public void onInit(int status) {
if(status == TextToSpeech.SUCCESS) {
mTts.setOnUtteranceCompletedListener(this);
}
}
// It's callback
public void onUtteranceCompleted(String utteranceId) {
Log.i(TAG, utteranceId); //utteranceId == "SOME MESSAGE"
}
...........
}
Read A good tutorial
The setOnUtteranceCompletedListener is deprecated since API level 15. Instead, use setOnUtteranceProgressListener.
I found a code snippet (here) that made it really easy for me to know when text to speech is finished:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
myTTS.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onDone(String utteranceId) {
// Log.d("MainActivity", "TTS finished");
}
#Override
public void onError(String utteranceId) {
}
#Override
public void onStart(String utteranceId) {
}
});
} else {
Log.e("MainActivity", "Initilization Failed!");
}
}
http://www.codota.com/android/scenarios/52fcbd34da0ae25e0f855408/android.speech.tts.TextToSpeech?tag=dragonfly
To know when TTS is finished you have to call the setOnUtteranceProgressListener which has 3 call back methods onStart,onDone and onError
then include a Utterance Id to the speak method
Code Snippet
textToSpeech=new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status==TextToSpeech.SUCCESS){
int result=textToSpeech.setLanguage(Locale.ENGLISH);
if (result==TextToSpeech.LANG_MISSING_DATA||result==TextToSpeech.LANG_NOT_SUPPORTED){
Log.i("TextToSpeech","Language Not Supported");
}
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
Log.i("TextToSpeech","On Start");
}
#Override
public void onDone(String utteranceId) {
Log.i("TextToSpeech","On Done");
}
#Override
public void onError(String utteranceId) {
Log.i("TextToSpeech","On Error");
}
});
}else {
Log.i("TextToSpeech","Initialization Failed");
}
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textToSpeech.speak(text,TextToSpeech.QUEUE_FLUSH,null,TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
}
I noticed that there are people having problems in the use of TextToSpeech to ask that the solution to you
How to know when TTS is finished?
without use setOnUtteranceCompletedListener
public void isTTSSpeaking(){
final Handler h =new Handler();
Runnable r = new Runnable() {
public void run() {
if (!tts.isSpeaking()) {
onTTSSpeechFinished();
}
h.postDelayed(this, 1000);
}
};
h.postDelayed(r, 1000);
}
Try this following code which shows a toast after TTS completed. Replace toast with your own action.
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener{
private boolean initialized;
private String queuedText;
private String TAG = "TTS";
private TextToSpeech tts;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tts = new TextToSpeech(this /* context */, this /* listener */);
tts.setOnUtteranceProgressListener(mProgressListener);
speak("hello world");
}
public void speak(String text) {
if (!initialized) {
queuedText = text;
return;
}
queuedText = null;
setTtsListener(); // no longer creates a new UtteranceProgressListener each time
HashMap<String, String> map = new HashMap<String, String>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "MessageId");
tts.speak(text, TextToSpeech.QUEUE_ADD, map);
}
private void setTtsListener() {
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
initialized = true;
tts.setLanguage(Locale.ENGLISH);
if (queuedText != null) {
speak(queuedText);
}
}
}
private abstract class runnable implements Runnable {
}
private UtteranceProgressListener mProgressListener = new UtteranceProgressListener() {
#Override
public void onStart(String utteranceId) {
} // Do nothing
#Override
public void onError(String utteranceId) {
} // Do nothing.
#Override
public void onDone(String utteranceId) {
new Thread()
{
public void run()
{
MainActivity.this.runOnUiThread(new runnable()
{
public void run()
{
Toast.makeText(getBaseContext(), "TTS Completed", Toast.LENGTH_SHORT).show();
}
});
}
}.start();
}
}; }
With this code I solved the problem. I wanted the start button to stay lit as long as someone was speaking. Maybe this will help someone.
public void _tts_speak_lenght() {
t2 = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (TTS.isSpeaking()) {
isSpeaking = true;
}
else {
if (!TTS.isSpeaking()) {
t2.cancel();
isSpeaking = false;
imgBtn_startReader.setImageResource(R.drawable.ic_start_off);
}
}
}
});
}
};
_timer.scheduleAtFixedRate(t2, (int)(0), (int)(100));
}
use a SpeakableListener when do text to speak.
private volatile boolean finished;
private SpeakableListener listener = new SpeakableListener() {
#Override
public void markerReached(SpeakableEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void speakableCancelled(SpeakableEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void speakableEnded(SpeakableEvent arg0) {
TestSpeaker.this.finished = true;
}
#Override
public void speakablePaused(SpeakableEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void speakableResumed(SpeakableEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void speakableStarted(SpeakableEvent arg0) {
TestSpeaker.this.finished = false;
}
#Override
public void topOfQueue(SpeakableEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void wordStarted(SpeakableEvent arg0) {
// TODO Auto-generated method stub
}
};
/** Speak the following string. */
public void sayIt(String str) {
System.out.print(" " + str + " ");
/* The the synthesizer to speak. */
synthesizer.speakPlainText(str, listener);