Skip to content

Instantly share code, notes, and snippets.

@mosluce
Last active May 25, 2017 00:49
Show Gist options
  • Save mosluce/a4f3e0a7e51d9b8a7a36860806cf90df to your computer and use it in GitHub Desktop.
Save mosluce/a4f3e0a7e51d9b8a7a36860806cf90df to your computer and use it in GitHub Desktop.
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