0

I'm trying to develop something similar to Google Assistant. So when I say "OK app", it should handle. So I have just created a service that is running in the background:

public class SttService extends Service implements RecognitionListener {
    private static final String TAG = "SstService";
    SpeechRecognizer mSpeech;

    private void speak() {
        mSpeech = SpeechRecognizer.createSpeechRecognizer(SttService.this);
        mSpeech.setRecognitionListener(SttService.this);

        Intent intent1 = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent1.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "en");

        mSpeech.startListening(intent1);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand: I am running");

        speak();

        return START_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: ");
        return null;
    }

    @Override
    public void onReadyForSpeech(Bundle params) {
        Log.e(TAG, "onReadyForSpeech: ");
    }

    @Override
    public void onBeginningOfSpeech() {
        Log.e(TAG, "onBeginningOfSpeech: ");
    }

    @Override
    public void onRmsChanged(float rmsdB) {
        // Log.e(TAG, "onRmsChanged: ");
    }

    @Override
    public void onBufferReceived(byte[] buffer) {
        Log.e(TAG, "onBufferReceived: ");
    }

    @Override
    public void onEndOfSpeech() {
        Log.e(TAG, "onEndOfSpeech: ");
    }

    @Override
    public void onError(int error) {
        Log.e(TAG, "onError: " + error);
        if (error == 7) {
            speak();
        }
    }

    @Override
    public void onResults(Bundle results) {
        ArrayList<String> resultsStringArrayList = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
        String mainResult = resultsStringArrayList.get(0);
        Log.e(TAG, "onResults: " + mainResult);

        if (mainResult.equalsIgnoreCase("Okay App")) {
            System.out.println("What's up?");
        }

        mSpeech.destroy();
        mSpeech = null;
        speak();

    }

    @Override
    public void onPartialResults(Bundle partialResults) {
        Log.e(TAG, "onPartialResults: ");
    }

    @Override
    public void onEvent(int eventType, Bundle params) {
        Log.e(TAG, "onEvent: ");
    }
}

My problem is that the app is not listening permanently. It starts listening and then there is a result. When I don't say anything, it will be listening for about 2 seconds, then SpeechRecognizer will be destroyed, so another speech can begin. So in the time when it is getting destroyed, there is a break and when I say something in the meantime, it will not be recognized.

My app is not doing what I want. Probably I am doing it completely the wrong way. So what I am trying to achieve is a SpeechRecognizer that runs permanently and only handles when I say "Okay App". How can I do this?

xRay
  • 543
  • 1
  • 5
  • 29

1 Answers1

1

That's how SpeechRecognizer is designed. It's not meant for permanent background listening, it's meant for short term immediate responses. Like when someone hits the mic button in the search bar. If you want permanent background listening, you're going to have to go lower level and do it yourself.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • Thanks for your answer! So what is an approach to do it yourself? Can you give me a hint? – xRay Nov 20 '21 at 03:27
  • 1
    I'd look into working with existing assistants, some of them are extendable. If you really wanted to do this, you'd need to take control of the mic, and you'd need to use a foreground service, and you'd need to be whitelisted from power restrictions. Then you'd need to process the sound data yourself (there's libraries to do this). It's a lot of work. – Gabe Sechan Nov 20 '21 at 03:36