249 lines
8.4 KiB
C#
249 lines
8.4 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|