using Container.Viewmodel; using Fleck; using NAudio.Wave; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Net; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Container.Common { public class WebsocketForVoice { //public static ConcurrentDictionary _sockets = new ConcurrentDictionary(); public static List allSockets = new List(); static bool flag = true; private static Class_Log log = new Class_Log(); //日志记录文件 private static App app = ((App)System.Windows.Application.Current); private int deviceNumber = 0; // 选择的录音设备下标。多个设备时可设置为用户选择 private WaveIn waveIn; // waveIn操作类 private WaveFormat recordingFormat; // 录音格式 private WaveFileWriter writer; // 录音文件操作类 public event EventHandler StoppedEvent = delegate { }; // 录音结束事件 public event EventHandler DataAvailableEvent = delegate { }; // 录音过程中接收到数据事件 private byte[] wavdata; private int aud_stat = AudioStatus.MSP_AUDIO_SAMPLE_FIRST;//音频状态 StringBuilder result = new StringBuilder();//存储最终识别的结果 int totalLength = 0;//用来记录总的识别后的结果的长度,判断是否超过缓存最大值 private int ep_stat = EpStatus.MSP_EP_LOOKING_FOR_SPEECH;//端点状态 private int rec_stat = RecogStatus.MSP_REC_STATUS_SUCCESS;//识别状态 int errcode = (int)Errors.MSP_SUCCESS; bool isClose = false; public void openSocket() { try { IatNativeMethods.initVoice(); // 设置录音格式WaveFormat(16000, 16, 1); //recordingFormat = new WaveFormat(16000, 8, WaveIn.GetCapabilities(deviceNumber).Channels); recordingFormat = new WaveFormat(16000, 16, 1); // 设置麦克风操作对象 waveIn = new WaveIn(); waveIn.DeviceNumber = deviceNumber; // 设置使用的录音设备 waveIn.DataAvailable += OnDataAviailable; // 接收到音频数据时,写入文件 waveIn.RecordingStopped += OnRecordingStopped; // 录音结束时执行 waveIn.WaveFormat = recordingFormat; FleckLog.Level = LogLevel.Debug; var ws = ConfigurationManager.AppSettings["websocketUrlForVoice"]; var server = new WebSocketServer(ws); server.Start(socket => { socket.OnOpen = () => //当建立Socket链接时执行此方法 { allSockets.Add(socket); }; socket.OnClose = () =>// 当关闭Socket链接十执行此方法 { allSockets.Remove(socket); }; socket.OnMessage = message =>// 接收客户端发送过来的信息 { if (message == "record" && flag) { startRecord(); isClose = false; } else if (message == "close" && !flag) { isClose = true; StopRecorder(); flag = true; } }; }); } catch (Exception e) { log.WriteLogFile(e.ToString(), "recorderror"); } } private void startRecord() { flag = false; log.WriteLogFile("录音进入时间" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), "录音"); try { StartRecorder(); } catch (Exception e) { log.WriteLogFile("---------22222222222-------" + "record" + e.Message, "recorderror"); } } private static string PostUrl(string url, string postData) { string result = string.Empty; try { HttpWebRequest wbRequest = (HttpWebRequest)WebRequest.Create(url); wbRequest.Method = "POST"; wbRequest.ContentType = "application/x-www-form-urlencoded"; wbRequest.ContentLength = Encoding.UTF8.GetByteCount(postData); using (Stream requestStream = wbRequest.GetRequestStream()) { using (StreamWriter swrite = new StreamWriter(requestStream)) { swrite.Write(postData); } } HttpWebResponse wbResponse = (HttpWebResponse)wbRequest.GetResponse(); using (Stream responseStream = wbResponse.GetResponseStream()) { using (StreamReader sread = new StreamReader(responseStream)) { result = sread.ReadToEnd(); } } } catch (Exception ex) { log.WriteLogFile("PostUrl异常" + url + "---------------" + postData, "recorderror"); log.WriteLogFile("PostUrl异常" + ex.ToString(), "recorderror"); } return result; } /// /// 开始录音 /// /// 保存的文件名 internal bool StartRecorder(string filename = "r.wav") { try { totalLength = 0; // 设置文件操作类 writer = new WaveFileWriter(filename, recordingFormat); result.Clear(); // 开始录音 waveIn.StartRecording(); int errcode = (int)Errors.MSP_SUCCESS; string session_begin_params = "sub=iat,domain=iat,language=zh_cn,accent=mandarin,sample_rate=16000,result_type=plain,result_encoding=gb2312"; IatNativeMethods.session_id = IatNativeMethods.QISRSessionBegin(null, session_begin_params, ref errcode); if (errcode != (int)Errors.MSP_SUCCESS) { flag = true; string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; SendMsg(result); StopRecorder(); } } catch (Exception e) { log.WriteLogFile(e.ToString(), "record"); } return true; } private void run_iat(byte[] _wavdata) { try { wavdata = _wavdata; if (wavdata == null || wavdata.Length == 0) { try { wavdata = System.IO.File.ReadAllBytes("wav/test.wav"); } catch (Exception e) { //System.Diagnostics.Debug.WriteLine(e.Message); //wavdata = null; } } //wavdata = System.IO.File.ReadAllBytes("wav/r.wav"); int res = IatNativeMethods.QISRAudioWrite(IatNativeMethods.session_id, wavdata, (uint)wavdata.Length, aud_stat, ref ep_stat, ref rec_stat); if (res != (int)Errors.MSP_SUCCESS) { flag = true; string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; SendMsg(result); log.WriteLogFile("写入识别的音频失败!" + res); StopRecorder(); return; } if (RecogStatus.MSP_REC_STATUS_SUCCESS != rec_stat) { IntPtr now_result = IatNativeMethods.QISRGetResult(IatNativeMethods.session_id, ref rec_stat, 0, ref errcode); if (errcode != (int)Errors.MSP_SUCCESS) { flag = true; log.WriteLogFile("获取结果失败:" + errcode); string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; SendMsg(result); StopRecorder(); return; } if (now_result != null) { int length = now_result.ToString().Length; totalLength += length; if (totalLength > 4096) { flag = true; log.WriteLogFile("缓存空间不够" + totalLength); string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; SendMsg(result); StopRecorder(); return; } result.Append(Marshal.PtrToStringAnsi(now_result)); } } if (EpStatus.MSP_EP_AFTER_SPEECH == ep_stat) { //run_iatlast(); StopRecorder(); return; } } catch (Exception ex) { log.WriteLogFile(ex.ToString(), "recorderror"); } //Thread.Sleep(150);//防止频繁占用cpu } private void run_iatlast() { var res = IatNativeMethods.QISRAudioWrite(IatNativeMethods.session_id, null, 0, AudioStatus.MSP_AUDIO_SAMPLE_LAST, ref ep_stat, ref rec_stat); if (res != (int)Errors.MSP_SUCCESS) { flag = true; string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; SendMsg(result); log.WriteLogFile("写入音频失败!" + res); StopRecorder(); return; } while (RecogStatus.MSP_REC_STATUS_COMPLETE != rec_stat) { IntPtr now_result = IatNativeMethods.QISRGetResult(IatNativeMethods.session_id, ref rec_stat, 0, ref errcode); if (errcode != (int)Errors.MSP_SUCCESS) { flag = true; log.WriteLogFile("获取结果失败:" + errcode); string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; SendMsg(result); StopRecorder(); return; } if (now_result != null) { int length = now_result.ToString().Length; totalLength += length; if (totalLength > 4096) { flag = true; log.WriteLogFile("缓存空间不够" + totalLength); string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; SendMsg(result); StopRecorder(); } result.Append(Marshal.PtrToStringAnsi(now_result)); } Thread.Sleep(150);//防止频繁占用cpu } QISRSessionEnd(); //int ret = IatNativeMethods.QISRSessionEnd(IatNativeMethods.session_id, "normal end"); //if (errcode != (int)Errors.MSP_SUCCESS) //{ // flag = true; // log.WriteLogFile("QISRSessionEnd failed, error code is: %d" + ret); // string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; // WebsocketForVoice.allSockets.ToList().ForEach(s => s.Send(result)); //} //if (result.Length > 0) //{ // string resultReturn = "{\"code\": \"100\",\"msg\": \""+ result.ToString() + "\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"录音结束\"}}"; // //最终方法 // WebsocketForVoice.allSockets.ToList().ForEach(s => s.Send(resultReturn)); // var url = app.kioskUrl + "/Video/VoiceSearch"; // StringBuilder sb = new StringBuilder(); // sb.Append("Query=" + WebUtility.UrlEncode(result.ToString()) + "&IP=" + app.LocalIP); // resultReturn = PostUrl(url, sb.ToString()); // WebsocketForVoice.allSockets.ToList().ForEach(s => s.Send(resultReturn)); // flag = true; //} } private void SendMsg(string result) { if (!isClose) { WebsocketForVoice.allSockets.ToList().ForEach(s => s.Send(result)); } } private void QISRSessionEnd() { int ret = IatNativeMethods.QISRSessionEnd(IatNativeMethods.session_id, "normal end"); if (!isClose) { if (errcode != (int)Errors.MSP_SUCCESS) { flag = true; log.WriteLogFile("QISRSessionEnd failed, error code is: %d" + ret); string result = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"未识别到语音输入\"}}"; SendMsg(result); } else { if (result.Length > 0) { string resultReturn = "{\"code\": \"201\",\"msg\": \"" + result.ToString() + "\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"录音结束\"}}"; //最终方法 WebsocketForVoice.allSockets.ToList().ForEach(s => s.Send(resultReturn)); var url = app.kioskUrl + "/Api/Video/VoiceSearch"; StringBuilder sb = new StringBuilder(); sb.Append("Query=" + WebUtility.UrlEncode(result.ToString()) + "&IP=" + app.LocalIP); resultReturn = PostUrl(url, sb.ToString()); if (!isClose) { SendMsg(resultReturn); } if (ConfigurationManager.AppSettings["isvoiceup"] == "1") { Action action = new Action(() => { var Jo = JObject.Parse(resultReturn); string code = Jo.Value("code"); if (code == "500") { var voiceData = Jo.Value("data"); var voiceCode = voiceData.Value("voiceCode"); var mallCode = voiceData.Value("mallCode"); if (!string.IsNullOrEmpty(voiceCode)) { var voiceFile = Directory.GetCurrentDirectory() + "\\r.wav"; var formDatas = new List(); //添加文件 formDatas.Add(new FormItemModel() { Key = "wav", Value = "", FileName = DateTime.Now.Ticks.ToString("x") + ".wav", FileContent = File.OpenRead(voiceFile), voiceCode = voiceCode, mallCode = mallCode }); //添加文件 formDatas.Add(new FormItemModel() { Key = "voiceCode", Value = voiceCode, }); //添加文件 formDatas.Add(new FormItemModel() { Key = "mallCode", Value = mallCode, }); var result = PostForm(app.kioskUrl + "/SaasApi/Statistics/UpLoadVoiceFiles", formDatas); } } }); action.BeginInvoke(null, null); } flag = true; } else { flag = true; string resultReturn = "{\"code\": \"401\",\"msg\": \"未识别到语音输入\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"录音结束\"}}"; SendMsg(resultReturn); } } } } /// /// 结束录音 /// /// internal bool StopRecorder() { waveIn.StopRecording(); return true; } /// /// 录音结束回调函数 /// /// /// private void OnRecordingStopped(object sender, StoppedEventArgs e) { writer.Dispose(); run_iatlast(); // 通知结束事件 StoppedEvent(this, EventArgs.Empty); } /// /// 录音回调函数,写入数据 /// /// /// private void OnDataAviailable(object sender, WaveInEventArgs e) { try { byte[] buffer = e.Buffer; int bytesRecorded = e.BytesRecorded; long maxFileLength = this.recordingFormat.AverageBytesPerSecond * 60; var toWrite = (int)Math.Min(maxFileLength - writer.Length, bytesRecorded); if (toWrite > 0) { writer.Write(buffer, 0, bytesRecorded); run_iat(buffer); aud_stat = AudioStatus.MSP_AUDIO_SAMPLE_CONTINUE; } DataAvailableEvent(this, EventArgs.Empty); } catch (Exception ex) { log.WriteLogFile(ex.ToString(), "recorderror"); } } /// /// 使用Post方法获取字符串结果 /// /// /// Post表单内容 /// /// 默认20秒 /// 响应内容的编码类型(默认utf-8) /// public static string PostForm(string url, List formItems, CookieContainer cookieContainer = null, string refererUrl = null, Encoding encoding = null, int timeOut = 10000) { try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); #region 初始化请求对象 request.Method = "POST"; request.Timeout = timeOut; request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"; request.KeepAlive = true; request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"; if (!string.IsNullOrEmpty(refererUrl)) request.Referer = refererUrl; if (cookieContainer != null) request.CookieContainer = cookieContainer; #endregion string boundary = "----" + DateTime.Now.Ticks.ToString("x");//分隔符 request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary); //请求流 var postStream = new MemoryStream(); #region 处理Form表单请求内容 //是否用Form上传文件 var formUploadFile = formItems != null && formItems.Count > 0; if (formUploadFile) { //文件数据模板 string fileFormdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + "\r\nContent-Type: application/octet-stream" + "\r\n\r\n"; //文本数据模板 string dataFormdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"" + "\r\n\r\n{1}"; foreach (var item in formItems) { string formdata = null; if (item.IsFile) { //上传文件 formdata = string.Format( fileFormdataTemplate, item.Key, //表单键 item.FileName); } else { //上传文本 formdata = string.Format( dataFormdataTemplate, item.Key, item.Value); } //统一处理 byte[] formdataBytes = null; //第一行不需要换行 if (postStream.Length == 0) formdataBytes = Encoding.UTF8.GetBytes(formdata.Substring(2, formdata.Length - 2)); else formdataBytes = Encoding.UTF8.GetBytes(formdata); postStream.Write(formdataBytes, 0, formdataBytes.Length); //写入文件内容 if (item.FileContent != null && item.FileContent.Length > 0) { using (var stream = item.FileContent) { byte[] buffer = new byte[1024]; int bytesRead = 0; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0) { postStream.Write(buffer, 0, bytesRead); } } } } //结尾 var footer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n"); postStream.Write(footer, 0, footer.Length); } else { request.ContentType = "application/x-www-form-urlencoded"; } #endregion request.ContentLength = postStream.Length; #region 输入二进制流 if (postStream != null) { postStream.Position = 0; //直接写入流 Stream requestStream = request.GetRequestStream(); byte[] buffer = new byte[1024]; int bytesRead = 0; while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0) { requestStream.Write(buffer, 0, bytesRead); } ////debug //postStream.Seek(0, SeekOrigin.Begin); //StreamReader sr = new StreamReader(postStream); //var postStr = sr.ReadToEnd(); postStream.Close();//关闭文件访问 } #endregion HttpWebResponse response = (HttpWebResponse)request.GetResponse(); if (cookieContainer != null) { response.Cookies = cookieContainer.GetCookies(response.ResponseUri); } using (Stream responseStream = response.GetResponseStream()) { using (StreamReader myStreamReader = new StreamReader(responseStream, encoding ?? Encoding.UTF8)) { string retString = myStreamReader.ReadToEnd(); return retString; } } } catch (Exception e) { log.WriteLogFile(e.ToString(), "voiceerror"); return ""; } } } }