I am developing a research app in which the phone reads the users questions from a form using voice (I'm using TextToSpeech to read the questions) and the user has to fill the form by talking for which I am using the SpeechRecognizer class.
I am using UtteranceProgressListener to detect when the phone has stopped talking so that I can start SpeechRecognizer. But everytime, the phone is skipping the first question in the app and is only asking the last question. I fail to understand why this is happening. I'll be grateful of any help or insight into this.
On top of that, I am getting this in my Log, which I'm not even sure is related to the problem.
W/TextToSpeech: setLanguage failed: TTS engine connection not fully set up
speak failed: TTS engine connection not fully set up
And this is the code: I have written two UtteranceProgressListeners, one for each question.
public class PastDisastersActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener, RecognitionListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_past_disasters);
params = new HashMap<>();
progressBar = (ProgressBar) findViewById(R.id.speechProgressBar);
progressBar.setVisibility(View.INVISIBLE);
speech = SpeechRecognizer.createSpeechRecognizer(this);
Log.i(LOG_TAG, "isRecognitionAvailable: " + SpeechRecognizer.isRecognitionAvailable(this));
speech.setRecognitionListener(this);
recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE,
"en");
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 3);
handler = new Handler(getApplicationContext().getMainLooper());
introduction();
getVoiceInputForDisaster();
getVoiceInputForTime();
getVoiceInputForSeverity();
for (String name: this.params.keySet()){
Log.i(LOG_TAG,name);
}
}
private void introduction() {
final String toSpeak ="There are three questions in the new page. The questions are on "+ textView10.getText () + "," + textView11.getText() + "," + textView12.getText();
textToSpeech=new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) {
textToSpeech.setLanguage(Locale.UK);
textToSpeech.setOnUtteranceProgressListener(mProgressListenerIntroduction);
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(41));
textToSpeech.speak(toSpeak, TextToSpeech.QUEUE_FLUSH, params);
}
}
});
}
private void getVoiceInputForDisaster() {
final String toSpeak = "Which disaster do you want to update information about? There are four choices. They are "+disastersArray[0]+", "+disastersArray[1]+", "+disastersArray[2]+" or "+disastersArray[3];
textToSpeech=new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR) {
textToSpeech.setLanguage(Locale.UK);
textToSpeech.setOnUtteranceProgressListener(mProgressListenerDisaster);
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(20));
textToSpeech.speak(toSpeak, TextToSpeech.QUEUE_FLUSH, params);
}
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_RECORD_PERMISSION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
speech.startListening(recognizerIntent);
} else {
Toast.makeText(PastDisastersActivity.this, "Permission Denied by Android!", Toast
.LENGTH_SHORT).show();
}
}
}
@Override
public void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
if (speech != null) {
speech.destroy();
Log.i(LOG_TAG, "destroy");
}
}
@Override
public void onBeginningOfSpeech() {
Log.i(LOG_TAG, "onBeginningOfSpeech");
progressBar.setIndeterminate(false);
progressBar.setMax(10);
}
@Override
public void onRmsChanged(float rmsdB) {
}
@Override
public void onBufferReceived(byte[] buffer) {
Log.i(LOG_TAG, "onBufferReceived: " + buffer);
}
@Override
public void onEndOfSpeech() {
Log.i(LOG_TAG, "onEndOfSpeech");
progressBar.setIndeterminate(true);
}
@Override
public void onError(int errorCode) {
String errorMessage = getErrorText(errorCode);
Log.d(LOG_TAG, "FAILED " + errorMessage);
Toast.makeText(PastDisastersActivity.this, errorMessage, Toast.LENGTH_LONG).show();
}
@Override
public void onEvent(int arg0, Bundle arg1) {
Log.i(LOG_TAG, "onEvent");
}
@Override
public void onPartialResults(Bundle arg0) {
Log.i(LOG_TAG, "onPartialResults");
}
@Override
public void onReadyForSpeech(Bundle arg0) {
Log.i(LOG_TAG, "onReadyForSpeech");
}
@Override
public void onResults(Bundle results) {
Log.i(LOG_TAG, "onResults");
ArrayList<String> matches = results
.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
text = "";
for (String result : matches)
text += result + "\n";
//Processing
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
private abstract class CustomRunnable implements Runnable {
}
private UtteranceProgressListener mProgressListenerIntroduction = new UtteranceProgressListener() {
@Override
public void onStart(String utteranceId) {
//Toast.makeText(PastDisastersActivity.this,"In OnStart",Toast.LENGTH_LONG).show();
handler.post(new CustomRunnable() {
@Override
public void run() {
progressBar.setIndeterminate(false);
progressBar.setVisibility(View.INVISIBLE);
speech.stopListening();
}
});
} // Do nothing
@Override
public void onError(String utteranceId) {
} // Do nothing.
@Override
public void onDone(String utteranceId) {
new Thread()
{
public void run()
{
handler.post(new CustomRunnable()
{
public void run()
{
Toast.makeText(getBaseContext(), "TTS Completed", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(true);
ActivityCompat.requestPermissions
(PastDisastersActivity.this,
new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_PERMISSION);
}
});
}
}.start();
}
};
private UtteranceProgressListener mProgressListenerDisaster = new UtteranceProgressListener() {
@Override
public void onStart(String utteranceId) {
//Toast.makeText(PastDisastersActivity.this,"In OnStart",Toast.LENGTH_LONG).show();
handler.post(new CustomRunnable() {
@Override
public void run() {
progressBar.setIndeterminate(false);
progressBar.setVisibility(View.INVISIBLE);
speech.stopListening();
}
});
} // Do nothing
@Override
public void onError(String utteranceId) {
} // Do nothing.
@Override
public void onDone(String utteranceId) {
new Thread()
{
public void run()
{
handler.post(new CustomRunnable()
{
public void run()
{
Toast.makeText(getBaseContext(), "TTS Completed", Toast.LENGTH_LONG).show();
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(true);
ActivityCompat.requestPermissions
(PastDisastersActivity.this,
new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_PERMISSION);
}
});
}
}.start();
}
};
You're calling TTS in this way :
And, each of the methods contains TTS Variable initialization code (
ttsVar = new TextToSpeech(...);) andttsvar.speak(...).You don't wait for one method call to finish and start another one, even you change the
TextToSpeechobject instance and the text too.That's why the previous calls are finished before they start! And you're getting the last one working.
You've to manage it getting done one-by-one yourself. Hope this will help.