forked from yanw/App_win_iot_V2.0
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.
330 lines
12 KiB
330 lines
12 KiB
using NAudio.Wave;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using WebSocket4Net;
|
|
|
|
namespace IOTContainer.Common
|
|
{
|
|
internal class BaiduSpeechForWebApi
|
|
{
|
|
private const int appid = 101476776;//到控制台-语音合成页面获取
|
|
private const String apiSecret = "GXfbPhns1Lhmq0BChJgVuUe3acQBOn4w";//到控制台-语音合成页面获取
|
|
private const String apiKey = "CTY1O4eGFxUn1rU5PRyUzdAy";//到控制台-语音合成页面获取
|
|
enum Status
|
|
{
|
|
FirstFrame = 0,
|
|
ContinueFrame = 1,
|
|
LastFrame = 2
|
|
}
|
|
private static WebSocket webSocket;
|
|
private static IWaveIn recorder;//录音机
|
|
private static volatile Status status = Status.FirstFrame;
|
|
private int deviceNumber = 0; // 选择的录音设备下标。多个设备时可设置为用户选择
|
|
/// <summary>
|
|
/// 单例模式
|
|
/// </summary>
|
|
public static BaiduSpeechForWebApi baiduSpeechForWebApi
|
|
{
|
|
get
|
|
{
|
|
if (_baiduSpeechForWebApi == null)
|
|
_baiduSpeechForWebApi = new BaiduSpeechForWebApi();
|
|
return _baiduSpeechForWebApi;
|
|
}
|
|
}
|
|
|
|
private static BaiduSpeechForWebApi _baiduSpeechForWebApi = new BaiduSpeechForWebApi();
|
|
|
|
private BaiduSpeechForWebApi() { }
|
|
public void startVoice()
|
|
{
|
|
status = Status.FirstFrame;
|
|
string url = !string.IsNullOrEmpty(ComParameters.Parameters.baiduVoiceServer) ? ComParameters.Parameters.baiduVoiceServer : "vop.baidu.com";
|
|
StartBaiduSpeech(url);
|
|
}
|
|
public void stopVoice()
|
|
{
|
|
status = Status.LastFrame;
|
|
recorder.DataAvailable -= OnDataAvailable;
|
|
dynamic frame = new JObject();
|
|
frame.type = "FINISH";
|
|
webSocket.Send(frame.ToString());
|
|
recorder.StopRecording();
|
|
Thread.Sleep(1000);
|
|
webSocket.Close();
|
|
}
|
|
public static void StartBaiduSpeech(string url)
|
|
{
|
|
try
|
|
{
|
|
Log.MyLog.WriteLogFile("StartBaiduSpeech:Enter", "BaiDuSpeech");
|
|
string ts = GenerateTimeStamp();
|
|
Log.MyLog.WriteLogFile("GenerateTimeStamp:" + ts, "BaiDuSpeech");
|
|
string yb = EncryptUtil.HMACSHA1Text(EncryptUtil.GetMd5Code(appid + ts), apiKey);
|
|
Log.MyLog.WriteLogFile("yb:" + yb, "BaiDuSpeech");
|
|
string uril = $"ws://{url}/realtime_asr?sn=" + Guid.NewGuid().ToString();
|
|
Log.MyLog.WriteLogFile("uril:" + uril, "BaiDuSpeech");
|
|
|
|
try
|
|
{
|
|
//开始请求 WebSocket
|
|
webSocket = new WebSocket(uril);
|
|
webSocket.Opened += OnOpened;
|
|
webSocket.DataReceived += OnDataReceived;
|
|
webSocket.MessageReceived += OnMessageReceived;
|
|
webSocket.Closed += OnClosed;
|
|
webSocket.Error += OnError;
|
|
webSocket.Open();
|
|
Log.MyLog.WriteLogFile("开始请求 WebSocket", "BaiDuSpeech");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
Log.MyLog.WriteLogFile("WebSocket:" + ex.ToString(), "BaiDuSpeech"); ;
|
|
}
|
|
// 初始化录音机
|
|
try
|
|
{
|
|
recorder = new WaveInEvent { WaveFormat = new WaveFormat(16000, 1) };
|
|
recorder.DataAvailable += OnDataAvailable;
|
|
recorder.RecordingStopped += OnRecordingStopped;
|
|
Log.MyLog.WriteLogFile("录音机初始化完成", "BaiDuSpeech");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.MyLog.WriteLogFile("recorder:" + ex.ToString(), "BaiDuSpeech");
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
Log.MyLog.WriteLogFile("StartBaiduSpeech:" + ex.ToString(), "BaiDuSpeech");
|
|
}
|
|
|
|
}
|
|
private static void OnDataAvailable(object sender, WaveInEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
//Log.MyLog.WriteLogFile("OnDataAvailable:status:" + status, "BaiDuSpeech");
|
|
switch (status)
|
|
{
|
|
case Status.FirstFrame://握手
|
|
{
|
|
dynamic frame = new JObject();
|
|
frame.type = "START";
|
|
frame.data = new JObject
|
|
{
|
|
{ "appid",appid},
|
|
{ "appkey",apiKey},
|
|
{ "dev_pid",15372},
|
|
{ "cuid","cuid-1"},
|
|
{ "format","pcm"},
|
|
{ "sample",16000},
|
|
};
|
|
webSocket.Send(frame.ToString());
|
|
status = Status.ContinueFrame;
|
|
}
|
|
break;
|
|
case Status.ContinueFrame://开始发送
|
|
{
|
|
dynamic frame = new JObject();
|
|
frame = Convert.ToBase64String(e.Buffer);
|
|
webSocket.Send(e.Buffer, 0, e.Buffer.Length);
|
|
}
|
|
break;
|
|
case Status.LastFrame://关闭
|
|
{
|
|
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
Log.MyLog.WriteLogFile("OnDataAvailable:" + ex.ToString(), "BaiDuSpeech");
|
|
}
|
|
//Log.MyLog.WriteLogFile("status:"+ status, "BaiDuSpeech");
|
|
|
|
}
|
|
/// <summary>
|
|
/// 检查麦克风
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private static void OnOpened(object sender, EventArgs e)
|
|
{
|
|
Log.MyLog.WriteLogFile("OnOpened", "BaiDuSpeech");
|
|
try
|
|
{
|
|
|
|
|
|
recorder.StartRecording();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
Log.MyLog.WriteLogFile("未插入麦克风,程序关闭", "BaiDuSpeech");
|
|
}
|
|
|
|
}
|
|
//返回结果处理
|
|
private static void OnMessageReceived(object sender, MessageReceivedEventArgs e)
|
|
{
|
|
//返回的JSON串"{\"err_msg\":\"OK\",\"err_no\":0,\"log_id\":1542502511,\"result\":\"你好\",\"sn\":\"c36964c8-d86c-4a06-b7cf-8939539d3eb8_ws_1\",\"type\":\"MID_TEXT\"}\n"
|
|
//Console.WriteLine(e.Message);
|
|
try
|
|
{
|
|
dynamic msg = JsonConvert.DeserializeObject(e.Message);
|
|
|
|
//Log.MyLog.WriteLogFile("OnMessageReceived:" + e.Message, "BaiDuSpeech");
|
|
if (msg.err_msg != "OK")
|
|
{
|
|
|
|
Log.MyLog.WriteLogFile($"error => {msg.message},err_no => {msg.err_no}", "BaiDuSpeech");
|
|
return;
|
|
}
|
|
string ws = null;
|
|
if (msg.err_msg == "OK" && msg.type == "FIN_TEXT")
|
|
{
|
|
ws = msg.result;
|
|
Log.MyLog.WriteLogFile(ws, "BaiDuSpeech");
|
|
ComParameters.Parameters.EdgeWindow.SendVoiceMsgBaidu("{\"code\": \"200\",\"msg\": \"" + ws + "\",\"data\": { \"ModelType\" : \"\", \"ActionType\" : \"\", \"query\":\"???\" , \"ttsMsg\":\"录音结束\"}}");
|
|
}
|
|
//var ws = msg.result;
|
|
if (ws == null)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
Log.MyLog.WriteLogFile("OnMessageReceived:" + ex.ToString(), "BaiDuSpeech");
|
|
}
|
|
}
|
|
private static void OnError(object sender, SuperSocket.ClientEngine.ErrorEventArgs e)
|
|
{
|
|
Log.MyLog.WriteLogFile("OnError", "BaiDuSpeech");
|
|
Log.MyLog.WriteLogFile(e.Exception.Message, "BaiDuSpeech");
|
|
|
|
}
|
|
private static void OnClosed(object sender, EventArgs e)
|
|
{
|
|
Log.MyLog.WriteLogFile("OnClosed", "BaiDuSpeech");
|
|
//recorder.DataAvailable -= OnDataAvailable;
|
|
|
|
}
|
|
|
|
|
|
private static void OnDataReceived(object sender, DataReceivedEventArgs e)
|
|
{
|
|
Log.MyLog.WriteLogFile("OnDataReceived", "BaiDuSpeech");
|
|
Log.MyLog.WriteLogFile(e.Data.Length.ToString(), "BaiDuSpeech");
|
|
}
|
|
|
|
|
|
private static void OnRecordingStopped(object sender, StoppedEventArgs e)
|
|
{
|
|
Log.MyLog.WriteLogFile("OnRecordingStopped", "BaiDuSpeech");
|
|
Log.MyLog.WriteLogFile(e.Exception?.Message, "BaiDuSpeech");
|
|
}
|
|
/// <summary>
|
|
/// 时间戳
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static string GenerateTimeStamp()
|
|
{
|
|
try
|
|
{
|
|
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
return Convert.ToInt64(ts.TotalSeconds).ToString();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
Log.MyLog.WriteLogFile("GenerateTimeStamp:" + ex.ToString(), "BaiDuSpeech");
|
|
return null;
|
|
}
|
|
|
|
}
|
|
}
|
|
public class EncryptUtil
|
|
{
|
|
|
|
public static string GetMd5Code(string text)
|
|
{
|
|
try
|
|
{
|
|
//MD5类是抽象类
|
|
MD5 md5 = MD5.Create();
|
|
//需要将字符串转成字节数组
|
|
byte[] buffer = Encoding.Default.GetBytes(text);
|
|
//加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择
|
|
byte[] md5buffer = md5.ComputeHash(buffer);
|
|
string str = null;
|
|
// 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
|
|
foreach (byte b in md5buffer)
|
|
{
|
|
//得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符
|
|
//但是在和对方测试过程中,发现我这边的MD5加密编码,经常出现少一位或几位的问题;
|
|
//后来分析发现是 字符串格式符的问题, X 表示大写, x 表示小写,
|
|
//X2和x2表示不省略首位为0的十六进制数字;
|
|
str += b.ToString("x2");
|
|
}
|
|
//Console.WriteLine(str);//202cb962ac59075b964b07152d234b70
|
|
return str;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
//System.Diagnostics.Debug.WriteLine("GetMd5Code exception:" + e.Message);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
#region HMACSHA1加密 对二进制数据转Base64后再返回
|
|
/// <summary>
|
|
/// HMACSHA1加密
|
|
/// </summary>
|
|
/// <param name="text">要加密的原串</param>
|
|
///<param name="key">私钥</param>
|
|
/// <returns></returns>
|
|
public static string HMACSHA1Text(string text, string key)
|
|
{
|
|
try
|
|
{
|
|
//HMACSHA1加密
|
|
HMACSHA1 hmacsha1 = new HMACSHA1
|
|
{
|
|
Key = System.Text.Encoding.UTF8.GetBytes(key)
|
|
};
|
|
|
|
byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(text);
|
|
byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
|
|
|
|
return Convert.ToBase64String(hashBytes);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
//System.Diagnostics.Debug.WriteLine("HMACSHA1Text exception:" + e.Message);
|
|
}
|
|
return null;
|
|
}
|
|
#endregion
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|