我正在开发与 dialogflow 集成的 android 中的 SpeechRecognizer 模块。我几乎完成了集成,它工作正常,但面临一个问题。问题是当 TTS 说出响应时,在完成语音麦克风启用之前,它还会捕获响应而不是仅捕获用户话语。
所以我想知道我怎样才能知道 TTS 说完回复?我已经通过使用 onUtteranceCompleted() 方法尝试了 Google 解决方案,并且我也尝试了 setOnUtteranceProgressListener() 方法,但似乎没有工作。我想在 asynctask 中实现这些方法,以便可以在后台完成。我怎样才能做到这一点?
这是我尝试过的代码:
import android.Manifest;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.speech.tts.TextToSpeech;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import ai.api.PartialResultsListener;
import ai.api.android.AIConfiguration;
import ai.api.android.GsonFactory;
import ai.api.model.AIError;
import ai.api.model.AIResponse;
import ai.api.ui.AIDialog;
import android.os.AsyncTask;
import com.google.gson.Gson;
public class VoiceActivity extends AppCompatActivity implements View.OnClickListener, TextToSpeech.OnInitListener, RecognitionListener {
private AIDialog.AIDialogListener resultsListener;
private static final int REQUEST_AUDIO_PERMISSIONS_ID = 33;
private Gson gson = GsonFactory.getGson();
private ListView wordList;
TextView txtmain;
private static final int VR_REQUEST = 999;
//Log tag for output information
private final String LOG_TAG = "SpeechRepeatActivity";//***enter your own tag here***
//variable for checking TTS engine data on user device
private int MY_DATA_CHECK_CODE = 0;
//Text To Speech instance
private TextToSpeech tts;
AIButton aiButton;
EditText time;
TextView matchcall;
// private SpeechRecognizer speech = null;
private Intent recognizerIntent;
TextView tvOutput ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_voice);
aiButton = (AIButton) findViewById(R.id.speech_btn);
txtmain =findViewById(R.id.txtmain);
wordList = findViewById(R.id.word_list);
tvOutput = findViewById(R.id.tvOutput);
time = (EditText) findViewById(R.id.in_time);
matchcall = (TextView) findViewById(R.id.matchcall);
final AsyncTaskRunner runner = new AsyncTaskRunner();
initService();
PackageManager packManager = getPackageManager();
List<ResolveInfo> intActivities = packManager.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
if (intActivities.size() != 0) {
//speech recognition is supported - detect user button clicks
aiButton.setOnClickListener(this);
//prepare the TTS to repeat chosen words
Intent checkTTSIntent = new Intent();
//check TTS data
checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
//start the checking Intent - will retrieve result in onActivityResult
startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);
} else {
//speech recognition not supported, disable button and output message
aiButton.setEnabled(false);
Toast.makeText(this, "Oops - Speech recognition not supported!", Toast.LENGTH_LONG).show();
}
}
private void setAIButtonCallback(final AIButton aiButton) {
aiButton.setResultsListener(new AIButton.AIButtonListener() {
@Override
public void onResult(final AIResponse result) {
if (resultsListener != null) {
resultsListener.onResult(result);
Log.e(LOG_TAG,"onResult=="+result.getResult().getResolvedQuery());
final String speech = result.getResult().getFulfillment().getSpeech();
tvOutput.setText(speech);
}
}
@Override
public void onError(final AIError error) {
if (resultsListener != null) {
resultsListener.onError(error);
Log.e(LOG_TAG,"onError=="+error);
}
}
@Override
public void onCancelled() {
if (resultsListener != null) {
resultsListener.onCancelled();
Log.e(LOG_TAG,"onCancelled==");
}
}
});
aiButton.setPartialResultsListener(new PartialResultsListener() {
@Override
public void onPartialResults(final List<String> partialResults) {
final String result = partialResults.get(0);
if (!TextUtils.isEmpty(result)) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
txtmain.setText(result);
}
});
}
}
});
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.speech_btn) {
//listen for results
listenToSpeech();
}
}
@Override
public void onInit(int status) {
//if successful, set locale
if (status == TextToSpeech.SUCCESS)
tts.setLanguage(Locale.UK);//***choose your own locale here***
}
private void listenToSpeech() {
SpeechRecognizer speech = SpeechRecognizer.createSpeechRecognizer(this);
speech.setRecognitionListener(this);
recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE,"en");
recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,this.getPackageName());
recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,this.getPackageName());
recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 3);
//start listening
speech.startListening(recognizerIntent);
}
@Override
public void onResults(Bundle results) {
Log.i(LOG_TAG, "onResults");
ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
/* wordList.setAdapter(new ArrayAdapter<String>(this, R.layout.word, matches));
new Handler().post(new Runnable() {
@Override
public void run() {
wordList.performItemClick(
wordList.getChildAt(0),
0,
wordList.getAdapter().getItemId(0));
wordList.getChildAt(0).setBackgroundColor(0xFFD3D3D3);
}
});*/
String wordChosen = matches.get(0);
tvOutput.setText(wordChosen);
try {
AsyncTaskRunner runner = new AsyncTaskRunner();
runner.execute(wordChosen);
// aiButton.textRequest(text);
//runner.doInBackground(text);
} catch (Exception e) {
e.printStackTrace();
}
}
private class AsyncTaskRunner extends AsyncTask<String, AIResponse, AIResponse> {
private AIResponse resp;
ProgressDialog progressDialog;
@Override
protected AIResponse doInBackground(String... params) {
Log.e(LOG_TAG,"doInBackground=="+params[0]);
try {
resp = aiButton.textRequest(String.valueOf(params[0]));
}
catch (Exception e) {
e.printStackTrace();
}
return resp;
}
protected void onPostExecute(AIResponse result) {
Log.e(LOG_TAG,"onPostExecute== result=="+result.getResult().getFulfillment().getSpeech());
// execution of result of Long time consuming operation
findViewById(R.id.progBar).setVisibility(View.GONE);
txtmain.setText(result.getResult().getFulfillment().getSpeech());
String speech = result.getResult().getFulfillment().getSpeech();
tts.speak( speech, TextToSpeech.QUEUE_FLUSH, null);
Toast.makeText(VoiceActivity.this, speech, Toast.LENGTH_SHORT).show();
listenToSpeech();
}
@Override
protected void onPreExecute() {
Log.e(LOG_TAG,"onPreExecute==");
findViewById(R.id.progBar).setVisibility(View.VISIBLE);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//check speech recognition result
if (requestCode == VR_REQUEST && resultCode == RESULT_OK)
{
//store the returned word list as an ArrayList
ArrayList<String> suggestedWords = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
//set the retrieved list to display in the ListView using an ArrayAdapter
wordList.setAdapter(new ArrayAdapter<String>(this, R.layout.word, suggestedWords));
/*new Handler().post(new Runnable() {
@Override
public void run() {
wordList.performItemClick(
wordList.getChildAt(0),
0,
wordList.getAdapter().getItemId(0));
wordList.getChildAt(0).setBackgroundColor(0xFFD3D3D3);
}
});*/
tvOutput.setText(suggestedWords.get(0));
}
if (requestCode == MY_DATA_CHECK_CODE)
{
//we have the data - create a TTS instance
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS)
tts = new TextToSpeech(this, this);
//data not installed, prompt the user to install it
else
{
//intent will take user to TTS download page in Google Play
Intent installTTSIntent = new Intent();
installTTSIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installTTSIntent);
}
}
//call superclass method
super.onActivityResult(requestCode, resultCode, data);
}
private void initService() {
final AIConfiguration config = new AIConfiguration("a73d5e88477e4926ae84af46f24e0aaa",
AIConfiguration.SupportedLanguages.English,
AIConfiguration.RecognitionEngine.Google);
aiButton.initialize(config);
setAIButtonCallback(aiButton);
Log.i(LOG_TAG, "initService:::::: ");
}
@Override
protected void onPause() {
super.onPause();
// speech.stopListening();
// use this method to disconnect from speech recognition service
new java.util.Timer().schedule(
new java.util.TimerTask() {
@Override
public void run() {
// your code here
}
},
5000
);
// Not destroying the SpeechRecognition object in onPause method would block other apps from using SpeechRecognition service
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onStop() {
Log.i(LOG_TAG, "stop");
super.onStop();
/* if (speech != null) {
speech.destroy();*/
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//}
@Override
protected void onStart() {
super.onStart();
checkAudioRecordPermission();
}
protected void checkAudioRecordPermission() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.RECORD_AUDIO)) {
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_AUDIO_PERMISSIONS_ID);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_AUDIO_PERMISSIONS_ID: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
}
return;
}
}
}
@Override
public void onReadyForSpeech(Bundle bundle) {
}
@Override
public void onBeginningOfSpeech() {
}
@Override
public void onRmsChanged(float v) {
}
@Override
public void onBufferReceived(byte[] bytes) {
}
@Override
public void onEndOfSpeech() {
//speech.stopListening();
}
@Override
public void onError(int errorcode) {
String errorMessage = getErrorText(errorcode);
Log.i(LOG_TAG, "FAILED " + errorMessage);
// speech.stopListening();
// listenToSpeech();
}
public String getErrorText(int errorCode) {
String message;
switch (errorCode) {
case SpeechRecognizer.ERROR_AUDIO:
message = "Audio recording error";
break;
case SpeechRecognizer.ERROR_CLIENT:
message = "Client side error";
break;
case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS:
message = "Insufficient permissions";
break;
case SpeechRecognizer.ERROR_NETWORK:
message = "Network error";
break;
case SpeechRecognizer.ERROR_NETWORK_TIMEOUT:
message = "Network timeout";
break;
case SpeechRecognizer.ERROR_NO_MATCH:
message = "No match";
break;
case SpeechRecognizer.ERROR_RECOGNIZER_BUSY:
message = "RecognitionService busy";
break;
case SpeechRecognizer.ERROR_SERVER:
message = "error from server";
break;
case SpeechRecognizer.ERROR_SPEECH_TIMEOUT:
message = "No speech input";
//speech.stopListening();
break;
default:
message = "Didn't understand, please try again.";
break;
}
return message;
}
@Override
public void onPartialResults(Bundle bundle) {
}
@Override
public void onEvent(int i, Bundle bundle) {
}
}