Click here to Skip to main content
16,015,559 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I'm including voice commands for my Android game in Unity. The speech recognition is triggered via button, and the recognized command is supposed to be shown on a TextMeshPro onscreen. At first it looks like it's working, but the TextMeshPro isn't being updated and no logs are shown after triggering the speech recognition. This is my code:

Java plugin:
Java
package com.example.unityandroidplswork;

import android.content.Intent;
import android.app.Activity;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;

import java.util.ArrayList;


public class STTPlugin{
    private static final int REQUEST_CODE = 1234;
    private static final String TAG = "SpeechRecognitionPlugin";
    private Activity activity;
    private SpeechRecognizer speechRecognizer;
    private SpeechRecognitionResultListener resultListener;
    private Context context;

    public STTPlugin(Context context) {

        this.context = context;
    }

    public void startSpeechRecognition(SpeechRecognitionResultListener listener, int requestCode) {
        if (SpeechRecognizer.isRecognitionAvailable(context) {
            resultListener = listener;
            if (speechRecognizer == null) {
                speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context);
            }
            Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
            intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
            intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, context.getPackageName());
            intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 10);
            activity = (Activity) context;
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    speechRecognizer.startListening(intent);
                    activity.startActivityForResult(intent, requestCode);
                    Log.d(TAG, "Escuchando...");
                    showToast("Escuchando...");
                }
            });
        } else {
            Log.d(TAG, "Reconocimiento no disponible.");
        }

    }

    private void showToast(String message) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }

    public void stopSpeechRecognition() {
        if (speechRecognizer != null) {
            speechRecognizer.stopListening();
        }
    }

    private ArrayList<String> processRecognitionResults(ArrayList<String> results) {
        return results;
    }



    public void handleActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) {
            ArrayList<String> results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
            if (resultListener != null) {
                String[] resultsArray = results.toArray(new String[0]);
                resultListener.onResults(results);
            }
        }
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        handleActivityResult(requestCode, resultCode, data);
    }

    public interface SpeechRecognitionResultListener {
        void onResults(ArrayList<String> results);
    }


}


C# script:

C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
using TMPro;

public class SpeechRecog : MonoBehaviour
{

    private AndroidJavaObject speechRecPlugin;
    public TextMeshProUGUI textofresult;
    private int requestCode = 1234;

    private List<string> recognizedCommands = new List<string>() {
        "izquierda", "derecha", "arriba", "abajo"
    };

    private Dictionary<string, Action> commandActions = new Dictionary<string, Action>() {
        {"izquierda", () => Debug.Log("Comando: izquierda")},
        {"derecha", () => Debug.Log("Comando: derecha")}
    };

    private bool isSpeechRecognitionActive = false;

    // Start is called before the first frame update
    void Start()
    {
        AndroidJavaObject activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
        speechRecPlugin = new AndroidJavaObject("com.example.unityandroidplswork.STTPlugin", activity);
        if(!Permission.HasUserAuthorizedPermission(Permission.Microphone)) {
            Permission.RequestUserPermission(Permission.Microphone);
        }
    }

    public void StartSpeechRecognition() {
        StartCoroutine(StartSpeechRecognitionCoroutine);
    }

    private IEnumerator StartSpeechRecognitionCoroutine() {
        yield return null;
        CallOnMainThread(() => {
            SpeechRecognitionResultListenerWrapper speechRecognitionResultListener = new SpeechRecognitionResultListenerWrapper(this);
            speechRecPlugin.Call("startSpeechRecognition", speechRecognitionResultListener, requestCode);
        });
    }

    public void StopSpeechRecognition() {
        CallOnMainThread(() =>
        {
            speechRecPlugin.Call("stopSpeechRecognition");
        });
    }

    private void ProcessRecognitionResults(List<string> results) {
        string recognizedtext = "";
        foreach(string result in results) {
            Debug.Log("Result: " + result);
            recognizedtext += result + " ";
            if (recognizedCommands.Contains(result)) {
                if (commandActions.ContainsKey(result)) {
                    commandActions[result].Invoke();
                }
            }
        }
        CallOnMainThread(() =>
        {
            textofresult.text = recognizedtext;
        });
    }

    private void CallOnMainThread(System.Action action) {
        AndroidJavaClass unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject activity = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity);
        activity.Call("runOnUiThread", new AndroidJavaRunnable(() => {
            action.Invoke();
        }));
    }


    private class SpeechRecognitionResultListener : AndroidJavaProxy {

        private SpeechRecog plugin;

        public SpeechRecognitionResultListener(SpeechRecog plugin) : base("com.example.unityandroidplswork.STTPlugin$SpeechRecognitionResultListener") {
            this.plugin = plugin;
        }

        public void onResults(AndroidJavaObject results) {
            var resultArray = results.Call<string[]>("toArray");
            List<string> stringList = new List<string>(resultArray);
            plugin.ProcessRecognitionResults(stringList);
        }
    }

    private class SpeechRecognitionResultListenerWrapper : AndroidJavaProxy {
        private SpeechRecog plugin;

        public SpeechRecognitionResultListenerWrapper(SpeechRecog plugin) : base("com.example.unityandroidplswork.STTPlugin$SpeechRecognitionResultListener") {
            this.plugin = plugin;
        }

        public void onResults(AndroidJavaObject results) {
            string[] resultArray = AndroidJNIHelper.ConvertFromJNIArray<string[]>(results.GetRawObject());
            List<string> stringList = new List<string>(resultArray);
            plugin.ProcessRecognitionResults(stringList);
        }
    }

    // Update is called once per frame
    void Update()
    {

    }
}









What I have tried:

I tried adding log messages to debug, and I also checked the Logcat filters to make sure I'm not hidding the missing logs, but this doesn't seem to be the problem.
The only logs that are not showing are the ones inside the ProcessRecognitionResults method, and since the TextMeshPro update is also done here, I suppose that the issue is related to this method, so I tried to rewrite it several times but nothing worked.
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900