You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

630 lines
26 KiB

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<string, System.Net.WebSockets.WebSocket> _sockets = new ConcurrentDictionary<string, System.Net.WebSockets.WebSocket>();
public static List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();
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;
}
/// <summary>
/// 开始录音
/// </summary>
/// <param name="filename">保存的文件名</param>
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<string>("code");
if (code == "500")
{
var voiceData = Jo.Value<JObject>("data");
var voiceCode = voiceData.Value<string>("voiceCode");
var mallCode = voiceData.Value<string>("mallCode");
if (!string.IsNullOrEmpty(voiceCode))
{
var voiceFile = Directory.GetCurrentDirectory() + "\\r.wav";
var formDatas = new List<FormItemModel>();
//添加文件
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);
}
}
}
}
/// <summary>
/// 结束录音
/// </summary>
/// <returns></returns>
internal bool StopRecorder()
{
waveIn.StopRecording();
return true;
}
/// <summary>
/// 录音结束回调函数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnRecordingStopped(object sender, StoppedEventArgs e)
{
writer.Dispose();
run_iatlast();
// 通知结束事件
StoppedEvent(this, EventArgs.Empty);
}
/// <summary>
/// 录音回调函数,写入数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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");
}
}
/// <summary>
/// 使用Post方法获取字符串结果
/// </summary>
/// <param name="url"></param>
/// <param name="formItems">Post表单内容</param>
/// <param name="cookieContainer"></param>
/// <param name="timeOut">默认20秒</param>
/// <param name="encoding">响应内容的编码类型(默认utf-8)</param>
/// <returns></returns>
public static string PostForm(string url, List<FormItemModel> 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 "";
}
}
}
}