Last active
May 25, 2017 00:49
-
-
Save mosluce/a4f3e0a7e51d9b8a7a36860806cf90df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Net; | |
using System.Net.Security; | |
using System.Security.Cryptography.X509Certificates; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using UnityEngine; | |
using UnityEngine.Networking; | |
using UnityEngine.UI; | |
public class UnityBingSpeech : MonoBehaviour | |
{ | |
public static readonly string FetchTokenUri = "https://api.cognitive.microsoft.com/sts/v1.0"; | |
public string subscriptionKey; | |
private string token; | |
private Timer accessTokenRenewer; | |
//Access token expires every 10 minutes. Renew it every 9 minutes. | |
private const int RefreshTokenDuration = 9; | |
public GameObject startButton; | |
public GameObject stopButton; | |
public GameObject outputContent; | |
public GameObject outputContainer; | |
private AudioClip recordAudioClip; | |
private string recordDevice; | |
void Start() | |
{ | |
// fix: Windows TLS error | |
ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback; | |
Authentication(subscriptionKey); | |
} | |
private bool MyRemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) | |
{ | |
bool isOk = true; | |
// If there are errors in the certificate chain, look at each error to determine the cause. | |
if (sslPolicyErrors != SslPolicyErrors.None) | |
{ | |
for (int i = 0; i < chain.ChainStatus.Length; i++) | |
{ | |
if (chain.ChainStatus[i].Status != X509ChainStatusFlags.RevocationStatusUnknown) | |
{ | |
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; | |
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; | |
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0); | |
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags; | |
bool chainIsValid = chain.Build((X509Certificate2)certificate); | |
if (!chainIsValid) | |
{ | |
isOk = false; | |
} | |
} | |
} | |
} | |
return isOk; | |
} | |
void Update() | |
{ | |
} | |
public void StartRecording() | |
{ | |
startButton.GetComponent<Button>().interactable = false; | |
stopButton.GetComponent<Button>().interactable = true; | |
recordDevice = Microphone.devices[0]; | |
recordAudioClip = Microphone.Start(recordDevice, false, 3, 44100); | |
} | |
public async void StopRecording() | |
{ | |
startButton.GetComponent<Button>().interactable = true; | |
stopButton.GetComponent<Button>().interactable = false; | |
var wavData = WavUtility.FromAudioClip(recordAudioClip); | |
await SpeechToText(wavData); | |
Microphone.End(recordDevice); | |
} | |
private async Task<bool> SpeechToText(byte[] wavData) | |
{ | |
var requestUri = "https://speech.platform.bing.com/speech/recognition/interactive/cognitiveservices/v1?language=zh-TW"; | |
HttpWebRequest request = null; | |
request = (HttpWebRequest)HttpWebRequest.Create(requestUri); | |
request.SendChunked = true; | |
request.Accept = @"application/json;text/xml"; | |
request.Method = "POST"; | |
request.ProtocolVersion = HttpVersion.Version11; | |
request.ContentType = @"audio/wav; codec=""audio/pcm""; samplerate=16000"; | |
request.Headers["Authorization"] = "Bearer " + token; | |
Debug.Log("Writing request stream..."); | |
await Task.Factory.StartNew(() => | |
{ | |
using (Stream requestStream = request.GetRequestStream()) | |
{ | |
requestStream.Write(wavData, 0, wavData.Length); | |
// Flush | |
requestStream.Flush(); | |
} | |
}); | |
Debug.Log("Read response stream..."); | |
var result = await Task.Factory.StartNew(() => | |
{ | |
string responseString = ""; | |
Debug.Log("Response:"); | |
using (WebResponse response = request.GetResponse()) | |
{ | |
Debug.Log(((HttpWebResponse)response).StatusCode); | |
using (StreamReader sr = new StreamReader(response.GetResponseStream())) | |
{ | |
responseString = sr.ReadToEnd(); | |
} | |
Debug.Log(responseString); | |
return JsonUtility.FromJson<SpeechResult>(responseString); | |
} | |
}); | |
if (result.RecognitionStatus == "Success") | |
{ | |
outputContent.GetComponent<Text>().text += string.Format("{0}\n", result.DisplayText); | |
return true; | |
} | |
return false; | |
} | |
public async void Authentication(string subscriptionKey) | |
{ | |
this.subscriptionKey = subscriptionKey; | |
this.token = await FetchToken(FetchTokenUri, subscriptionKey); | |
// renew the token on set duration. | |
accessTokenRenewer = new Timer(new TimerCallback(OnTokenExpiredCallback), | |
this, | |
TimeSpan.FromMinutes(RefreshTokenDuration), | |
TimeSpan.FromMilliseconds(-1)); | |
} | |
public string GetAccessToken() | |
{ | |
return this.token; | |
} | |
private async void RenewAccessToken() | |
{ | |
this.token = await FetchToken(FetchTokenUri, this.subscriptionKey); | |
Debug.Log("Renewed token."); | |
} | |
private void OnTokenExpiredCallback(object stateInfo) | |
{ | |
try | |
{ | |
RenewAccessToken(); | |
} | |
catch (Exception ex) | |
{ | |
Debug.Log(string.Format("Failed renewing access token. Details: {0}", ex.Message)); | |
} | |
finally | |
{ | |
try | |
{ | |
accessTokenRenewer.Change(TimeSpan.FromMinutes(RefreshTokenDuration), TimeSpan.FromMilliseconds(-1)); | |
} | |
catch (Exception ex) | |
{ | |
Debug.Log(string.Format("Failed to reschedule the timer to renew access token. Details: {0}", ex.Message)); | |
} | |
} | |
} | |
private async Task<string> FetchToken(string fetchUri, string subscriptionKey) | |
{ | |
return await Task<string>.Factory.StartNew(() => | |
{ | |
var www = (HttpWebRequest)HttpWebRequest.Create(fetchUri + "/issueToken"); | |
www.Method = "POST"; | |
www.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey); | |
var res = www.GetResponse(); | |
var reader = new StreamReader(res.GetResponseStream()); | |
var token = reader.ReadToEnd(); | |
Debug.Log(token); | |
return token; | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment