在以前《Unity利用Sapi進行windows語音開發》中,本計劃不許備繼續作語音識別。由於在unity3d中已經提供了語音識別的相關方法,詳見unity3d的官方文檔:https://docs.unity3d.com/ScriptReference/Windows.Speech.KeywordRecognizer.html。可是有一點是這個只支持win10。對於win7用戶來講,若是不使用百度語音或者科大訊飛語音的話,那麼使用SAPI就是最好的方式了。一樣的,因爲Unity中沒法直接使用SAPI,因此只能按照原來的思路,把它寫到一個exe工具中,而後再由unity3d來調用。html
仍是繼續以前的工程,可是爲了規範一些,我把工程名稱從SpeechTest改成了Speech。而且重構了Socket通訊結構,將本來的SocketExtra分爲了SocketBase,SocketServer和SocketClient。這樣作的目的就是簡單化,而且增長SocketServer發送信息到SocketClient的功能。git
這是工程的最終結構圖github
因爲speech加入了語音識別功能,因此爲了區別以前的通訊信息,從新整理定義了新的通訊數據結構。通訊數據結構定爲二進制數據,前4位是一個int32型的命令碼,這些命令碼有不一樣的含義和內容:windows
當speech收到1時,進行初始化。收到2的信息時,讀取以後的文本數據,而後交由Speecher來發音。收到3時,讀取後面的數據,若是是1,則開始進行錄音識別,若是是0則中止錄音識別。api
Speech代碼NetServer.cs數據結構
public bool NetReciveMsg(byte[] recivebuffer, int netID) { var arg = new ByteOutArg(recivebuffer); var cmd = arg.ReadInt32(); switch ((EmCmd)cmd) { case EmCmd.Init: Init(); break; case EmCmd.Speak: var str = arg.ReadString(); Console.WriteLine(str); m_speecher.Speak(str); return true; case EmCmd.Recognize: var scmd = arg.ReadInt32(); if (scmd == 1) m_recognizer.BeginRec(); if (scmd == 0) m_recognizer.EndRec(); return true; default: throw new ArgumentOutOfRangeException(); } return false; }
在unity發送的代碼。(ByteInArg是一個簡單地寫如byte[]數據的類)socket
/***測試代碼,可刪除Start***/ public void OnGUI() { if (GUILayout.Button("Connect")) { StartCoroutine(Connect()); } if (GUILayout.Button("InitServer")) { StartCoroutine(InitServer()); } if (GUILayout.Button("Speak")) { Speak("hello world"); } if (GUILayout.Button("Recognize Start")) { Recognize(true); } if (GUILayout.Button("Recognize End")) { Recognize(false); } } /***測試代碼,可刪除End***/ private void Recognize(bool tf) { var arg = new ByteInArg(); arg.Write(3); arg.Write(tf ? 1 : 0); NetSendMsg(arg.GetBuffer()); } public IEnumerator Connect() { m_socket = new SocketClient(this); m_socket.Connect("127.0.0.1", 9903); while (!m_socket.Connected) { yield return 1; } } public IEnumerator InitServer() { var arg = new ByteInArg(); arg.Write(1); NetSendMsg(arg.GetBuffer()); yield return 1; } public void Speech(string str) { if (m_socket.Connected) { var arg = new ByteInArg(); arg.Write(2); arg.Write(str); //var bytes = Encoding.Default.GetBytes(str); NetSendMsg(arg.GetBuffer()); } }
封裝SAPI的語音識別模塊這方面的代碼不少,也比較簡單。這裏建立的Recognizer類,代碼更改自http://kevin19900306.iteye.com/blog/1206534,其中的含義能夠查閱SAPI的相關文檔。Recognizer類有構造函數,兩個接口,一個回調向外提供。這兩個接口爲開始識別BeginRec和中止識別EndRec,當識別完成時,使用回調,將識別的文字傳出。函數
在speech的NetServer.cs中,回調相關的代碼以下工具
public void Init() { m_speecher = new Speecher(); m_recognizer = new Recognizer { OnRecognized = OnRecognized }; Console.WriteLine("初始化完成"); } private void OnRecognized(string text) { var arg = new ByteInArg(); arg.Write(text); NetSendMsg(arg.GetBuffer()); }
運行unity3d,畫面中出現5個按鈕,分別爲Connect,InitServer,Speak,Recognize Start,Recognize End。依次點擊Connect,InitServer。而後點擊Speak,聽到「hello world」語音。點擊Recognize Start,對麥克風說任何中文,能夠看到debug輸出對應的文字。點擊Recognize End中止識別。測試
源代碼下載https://github.com/CodeGize/UnitySapi/
轉載請保留