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:
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:
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;
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.