private void OnSpeechRecognizing(object sender, TranslationRecognitionEventArgs e) { Recognizing?.Invoke(sender, e); }
protected async Task MessageLoop(CancellationToken ct) { ProvidingState = ProvidingStateType.Initialized; try { Func <Task <bool> > connectAction = async() => { var connectionResult = await Connect(ct); if (connectionResult.isSuccess == false) { LastErrorString = connectionResult.message; ErrorOccured?.Invoke(this, LastErrorString); return(false); } Trace?.Invoke(this, "Connection complete."); return(true); }; sendQueue.Clear(); CancellationTokenSource receiveTokenSource = new CancellationTokenSource(); CancellationToken receiveToken = receiveTokenSource.Token; Task?receiveTask = null; char[] charsToTrim = { ' ', '\x00' }; while (!ct.IsCancellationRequested) { if (ProvidingState == ProvidingStateType.Initialized || (receiveTask != null && receiveTask.Status == TaskStatus.RanToCompletion)) { Trace?.Invoke(this, "Try to connect."); if (receiveTask != null && receiveTask.Status == TaskStatus.Running) { receiveTokenSource?.Cancel(); await receiveTask; } var connectResult = await connectAction(); if (!connectResult) { break; } receiveTask?.Dispose(); receiveTokenSource = new CancellationTokenSource(); receiveToken = receiveTokenSource.Token; receiveTask = Task.Run(() => ReceiveLoop(receiveToken), receiveToken); } string receiveData; if (receiveQueue.TryDequeue(out receiveData)) { receiveData = receiveData.Trim(charsToTrim); //Debug.WriteLine(String.Format("Recieve: {0}", receiveData)); // セッションタイムアウト等による切断 // 実際は強制的に切断されていたりするのでここを通らなかったりする if (receiveData.StartsWith("p") && receiveData.Length > 3) { Debug.WriteLine("Timeout occured."); Trace?.Invoke(this, receiveData.Substring(1).Trim()); RecognizingState = RecognizingStateType.NotRecognizing; DetectingState = DetectingStateType.NotDetecting; ProvidingState = ProvidingStateType.Initialized; continue; } // エラー処理 if ((receiveData.StartsWith("e") && receiveData.Length > 3)) { LastErrorString = receiveData; ErrorOccured?.Invoke(this, receiveData.Substring(1)); ProvidingState = ProvidingStateType.Error; RecognizingState = RecognizingStateType.NotRecognizing; DetectingState = DetectingStateType.NotDetecting; break; } // 発話区間開始 if (receiveData.StartsWith("S")) { uint startMiliSec; if (uint.TryParse(receiveData.Substring(2), out startMiliSec)) { //Debug.WriteLine(String.Format("S: {0}", receiveData)); VoiceStart?.Invoke(this, startMiliSec); } DetectingState = DetectingStateType.Detecting; } // 発話区間終了 if (receiveData.StartsWith("E")) { uint endMiliSec; if (uint.TryParse(receiveData.Substring(2), out endMiliSec)) { //Debug.WriteLine(String.Format("E: {0}", receiveData)); VoiceEnd?.Invoke(this, endMiliSec); } DetectingState = DetectingStateType.NotDetecting; } // 認識処理開始 if (receiveData.StartsWith("C")) { RecognizingState = RecognizingStateType.Recognizing; RecognizeStarting?.Invoke(this, true); } // 認識処理返却 if (receiveData.StartsWith("U") || receiveData.StartsWith("A")) { try { //Debug.WriteLine(receiveData.Substring(2).Trim()); var result = JsonSerializer.Deserialize <SpeechRecognitionEventArgs>(receiveData.Substring(2), jsonSerializerOptions); if (receiveData.StartsWith("U")) { // 認識途中 Recognizing?.Invoke(this, result); } else if (receiveData.StartsWith("A")) { // 認識終了 Recognized?.Invoke(this, result); RecognizingState = RecognizingStateType.NotRecognizing; } } catch (JsonException ex) { Debug.WriteLine(ex.Message); } } } // 受信が異常終了していないか確認 if (receiveTask != null && receiveTask.Status == TaskStatus.Faulted) { Debug.WriteLine(String.Format("Loop:ReceiveWSException: {0}", receiveTask.Exception.InnerException.Message)); ErrorOccured?.Invoke(this, String.Format("ReceiveTaskException")); break; } // 音声データを送る byte[] sendData; if (wsAmiVoice.State == WebSocketState.Open && sendQueue.TryDequeue(out sendData)) { sendData = prefixC.Concat(sendData).ToArray(); if (sendData.Length == 0) { continue; } try { await wsAmiVoice.SendAsync(sendData, WebSocketMessageType.Binary, true, CancellationToken.None); } catch (Exception ex) when(ex is WebSocketException || ex is IOException) { var sendErrString = String.Format("Send:WebSocketException: {0}", ex.Message); Trace?.Invoke(this, sendErrString); } } } // 終了処理 byte[] endArray = new byte[] { (byte)CommandType.End }; await wsAmiVoice.SendAsync(endArray, WebSocketMessageType.Text, true, CancellationToken.None); string disconnectionStr = ""; while (wsAmiVoice.State == WebSocketState.Open && receiveTask != null && receiveTask.Status == TaskStatus.Running) { if (!receiveQueue.TryDequeue(out disconnectionStr)) { continue; } if (disconnectionStr.StartsWith("e") && disconnectionStr.Length == 1) { receiveTokenSource?.Cancel(); receiveTask.Wait(1000); ProvidingState = ProvidingStateType.Initialized; RecognizingState = RecognizingStateType.NotRecognizing; DetectingState = DetectingStateType.NotDetecting; RecognizeStopped?.Invoke(this, true); } else if (disconnectionStr.StartsWith("e")) { RecognizingState = RecognizingStateType.NotRecognizing; DetectingState = DetectingStateType.NotDetecting; ProvidingState = ProvidingStateType.Error; LastErrorString = disconnectionStr.Substring(2); ErrorOccured?.Invoke(this, LastErrorString); } } if (receiveTokenSource != null && !receiveTokenSource.IsCancellationRequested) { receiveTokenSource.Cancel(); if (receiveTask != null && receiveTask.Status == TaskStatus.Running) { receiveTask.Wait(3000); } } } catch (WebSocketException ex) { ErrorOccured?.Invoke(this, String.Format("Loop:WebSocketException: {0}", ex.Message)); } finally { if (wsAmiVoice.State == WebSocketState.Open) { try { await wsAmiVoice.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None); } catch (WebSocketException ex) { Debug.WriteLine(String.Format("Close:WebSocketException: {0} - {1}", ex.Message, wsAmiVoice.State.ToString())); } } } Trace?.Invoke(this, "Disconnected."); }