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(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 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; } } }