Health/Assets/_VoiceAssistant/Scripts/Voice/Azure/VWU_Azure.cs

249 lines
8.4 KiB
C#
Raw Normal View History

2023-11-21 08:57:37 +00:00
using UnityEngine;
using UnityEngine.UI;
using Microsoft.CognitiveServices.Speech;
using System.Threading.Tasks;
using System.IO;
using System;
using System.Collections;
using Microsoft.CognitiveServices.Speech.Audio;
using System.Threading;
#if PLATFORM_ANDROID
using UnityEngine.Android;
using UnityEngine.Networking;
#endif
#if PLATFORM_IOS
using UnityEngine.iOS;
using System.Collections;
#endif
public class VWU_Azure : VoiceWakeUp
{
// Hook up the two properties below with a Text and Button object in your UI.
//public Text outputText;
//public Button startRecoButton;
private object threadLocker = new object();
private bool waitingForReco;
private string message="";
private bool micPermissionGranted = false;
private string kwsModelDir;
[SerializeField]
private string key = "";
[SerializeField]
private string ServiceRegion = "eastasia";
[SerializeField]
private string kwsModelFile = "kws.table";
private const string keyword = "hey mike";
SpeechRecognizer speechRecognizer;
SpeechConfig config;
KeywordRecognitionModel model;
#if PLATFORM_ANDROID || PLATFORM_IOS
// Required to manifest microphone permission, cf.
// https://docs.unity3d.com/Manual/android-manifest.html
private Microphone mic;
#endif
#if PLATFORM_ANDROID
IEnumerator CopyKwsModelFileFromStreamingAssetsAsync()
{
string fromFile = Application.streamingAssetsPath + Path.DirectorySeparatorChar + "VoiceAssistant" + Path.DirectorySeparatorChar + kwsModelFile;
string toFile = Application.persistentDataPath + Path.DirectorySeparatorChar + "VoiceAssistant" + Path.DirectorySeparatorChar + kwsModelFile;
UnityWebRequest downloader = UnityWebRequest.Get(fromFile);
var req=downloader.SendWebRequest();
yield return req;
DownloadHandler handler = downloader.downloadHandler;
if(!Directory.Exists(Application.persistentDataPath + Path.DirectorySeparatorChar + "VoiceAssistant"))
{
Directory.CreateDirectory(Application.persistentDataPath + Path.DirectorySeparatorChar + "VoiceAssistant");
}
File.WriteAllBytes(toFile, handler.data);
downloader.Dispose();
}
#endif
IEnumerator Start()
{
//AudioRecorder.Instance.StartRecord();
Debug.Log("Start enter");
yield return CopyKwsModelFileFromStreamingAssetsAsync();
Init();
Debug.Log("Start exit");
}
void Update()
{
if(IsEnable)
{
if (recgnizeStatus == RecgnizeStatus.RecgnizeSucceed)
{
if (callback != null)
callback(true);
Dispose();
}
else if (recgnizeStatus == RecgnizeStatus.RecgnizeFailed)
{
if (callback != null)
callback(false);
Dispose();
}
}
}
private void OnDisable()
{
Dispose();
}
public override void Init()
{
base.Init();
config = SpeechConfig.FromSubscription(key, ServiceRegion);
#if PLATFORM_ANDROID
kwsModelDir = Application.persistentDataPath + Path.DirectorySeparatorChar + "VoiceAssistant" + Path.DirectorySeparatorChar + kwsModelFile;
#else
kwsModelDir = Application.streamingAssetsPath + Path.DirectorySeparatorChar + "VoiceAssistant" + Path.DirectorySeparatorChar + kwsModelFile;
#endif
model = KeywordRecognitionModel.FromFile(kwsModelDir);
IsEnable = true;
}
async void KeywordRecognition()
{
//bool succeed = false;
try
{
Debug.Log(Thread.CurrentThread.ManagedThreadId);
lock (threadLocker)
{
waitingForReco = true;
}
var stopRecognition = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
var resultStr = "";
using (speechRecognizer = new SpeechRecognizer(config))
{
speechRecognizer.Recognized += (s, e) =>
{
if (e.Result.Reason == ResultReason.RecognizedKeyword)
{
resultStr = $"RECOGNIZED KEYWORD: '{e.Result.Text}'";
recgnizeStatus = RecgnizeStatus.RecgnizeSucceed;
//succeed = true;
}
else if (e.Result.Reason == ResultReason.RecognizedSpeech)
{
resultStr = $"RECOGNIZED: '{e.Result.Text}'";
}
else if (e.Result.Reason == ResultReason.NoMatch)
{
recgnizeStatus = RecgnizeStatus.RecgnizeFailed;
//succeed = false;
resultStr = "NOMATCH: Speech could not be recognized.";
}
UnityEngine.Debug.Log(resultStr);
lock (threadLocker)
{
message = resultStr;
}
};
speechRecognizer.Canceled += (s, e) =>
{
var cancellation = CancellationDetails.FromResult(e.Result);
resultStr = $"CANCELED: Reason={cancellation.Reason} ErrorDetails={cancellation.ErrorDetails}";
UnityEngine.Debug.Log(resultStr);
if (cancellation.Reason == CancellationReason.Error)
{
recgnizeStatus = RecgnizeStatus.RecgnizeFailed;
//succeed = false;
lock (threadLocker)
{
message = resultStr;
}
}
stopRecognition.TrySetResult(0);
};
speechRecognizer.SessionStarted += (s, e) =>
{
UnityEngine.Debug.Log("\nSession started event.");
};
speechRecognizer.SessionStopped += (s, e) =>
{
UnityEngine.Debug.Log("\nSession stopped event.");
UnityEngine.Debug.Log("\nStop recognition.");
stopRecognition.TrySetResult(0);
};
UnityEngine.Debug.Log($"Say something starting with the keyword '{keyword}' followed by whatever you want...");
if (speechRecognizer != null)
// Starts continuous recognition using the keyword model. Use StopKeywordRecognitionAsync() to stop recognition.
await speechRecognizer.StartKeywordRecognitionAsync(model).ConfigureAwait(false);
// Waits for a single successful keyword-triggered speech recognition (or error).
// Use Task.WaitAny to keep the task rooted.
Task.WaitAny(new[] { stopRecognition.Task });
if(speechRecognizer!=null)
await speechRecognizer.StopKeywordRecognitionAsync().ConfigureAwait(false);
Debug.Log("退出语音唤醒");
lock (threadLocker)
{
waitingForReco = false;
}
}
}
catch (Exception ex)
{
lock (threadLocker)
{
message = "Exception: " + ex.ToString();
Debug.LogError(message);
waitingForReco = false;
recgnizeStatus = RecgnizeStatus.RecgnizeFailed;
//succeed = false;
}
}
//recgnizeStatus = succeed ? RecgnizeStatus.RecgnizeSucceed : RecgnizeStatus.RecgnizeFailed;
}
public override void StartRecgnition(Action<bool> callback)
{
if (!IsEnable)
{
Debug.Log("暂不可用");
return;
}
base.StartRecgnition(callback);
KeywordRecognition();
recgnizeStatus = RecgnizeStatus.Recgnizing;
}
public override async void StopRecognition()
{
if(recgnizeStatus == RecgnizeStatus.Recgnizing)
{
await speechRecognizer.StopKeywordRecognitionAsync().ConfigureAwait(false);
Dispose();
}
}
void Dispose()
{
callback = null;
recgnizeStatus = RecgnizeStatus.Idle;
waitingForReco = false;
if (speechRecognizer != null)
{
speechRecognizer = null;
}
}
}