1

I am working on speechRecognizer module in android integrated with dialogflow. I have almost completed the integration and it's working fine but facing one issue. The issue is when TTS is speaking the response, before completing the speech mic gets enabled and it capture the response also instead of user utterance only.

So I want to know how can I get to know that TTS finished speaking the response? I have tried Google solution by using onUtteranceCompleted() method and also I have tried on setOnUtteranceProgressListener() method but doesn't seems to be working. I want to implement these methods in asynctask So that it can be done in background. How can I do that?

Here is the code that I have tried:

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) {

    }


}
halfer
  • 19,824
  • 17
  • 99
  • 186
Gautam Bothra
  • 565
  • 1
  • 8
  • 23
  • You shouldn't need to use asynctask because the onCompleted callbacks are called on a background thread by default. I would suggest including enough code in your question so that people have a chance of helping you with the fact that "it doesn't seem to be working." – Nerdy Bunz Sep 19 '19 at 20:41
  • Updated the question with code. let me know if anyone requires more details. – Gautam Bothra Sep 20 '19 at 05:13

0 Answers0