Unity对接科大讯飞实时语音转写WebAPI(Windows平台)(二)

上一篇中,用到的是MicPhone类,然后遗留问题是yield return new WaitForSecondsRealtime(0.04f)导致消息发送得很慢,语音识别不及时。

上一篇链接:Unity对接科大讯飞实时语音转写WebAPI(Windows平台)_unity webgl对接讯飞实时语音听写-CSDN博客

本篇将使用NAudio.Wave.WaveIn类完成麦克风语音数据的获取,属性BufferMilliseconds可以控制数据时间间隔;发送依然使用WebSocketSharp.WebSocket。直接贴代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using WebSocketSharp;
using System.Text;
using System.Security.Cryptography;
using LitJson;
using Newtonsoft.Json;using NAudio.Wave;public class SpeechHelper2 : MonoBehaviour
{private WaveIn audioClip;WebSocket speechWebSocket;private System.Action<string> resultCallback;private System.Action errorCallback;private static Queue<string> messageQueue = new Queue<string>();private static Queue<byte[]> requestQueue = new Queue<byte[]>();public void InitSpeechHelper(System.Action<string> textCallback, Action _errorCallback){resultCallback = textCallback;errorCallback = _errorCallback;}private void AudioClip_DataAvailable(object sender, WaveInEventArgs e){//UnityEngine.Debug.Log("AudioClip_DataAvailable");requestQueue.Enqueue(e.Buffer);}public bool StartSpeech(){if (speechWebSocket != null && speechWebSocket.ReadyState == WebSocketState.Open){//Debug.LogWarning("开始语音识别失败!,等待上次识别连接结束");MessageMng.Ins.ShowFloatTip("请等待上次识别结束");return false;}if (WaveIn.DeviceCount <= 0) {//Debug.LogWarning("找不到麦克风");MessageMng.Ins.ShowTipMsg("找不到麦克风!");return false;}messageQueue.Clear();audioClip = new WaveIn();WaveFormat waveFormat = new WaveFormat(16000, 16, 1);audioClip.BufferMilliseconds = 80;audioClip.WaveFormat = waveFormat;audioClip.DataAvailable += AudioClip_DataAvailable;audioClip.StartRecording();ConnectSpeechWebSocket();return true;}public void StopSpeech(){try{Debug.Log("识别结束,停止录音");audioClip.StopRecording();audioClip.Dispose();SendEndMsg(null);}catch(Exception ex){Debug.LogError(ex.Message);}}void ConnectSpeechWebSocket(){try{speechWebSocket = new WebSocket(GetWebSocketUrl());}catch (Exception ex){UnityEngine.Debug.LogError(ex.Message);return;}speechWebSocket.OnOpen += (sender, e) =>{Debug.Log("OnOpen");speechWebSocket.OnClose += OnWebSocketClose;};speechWebSocket.OnMessage += OnInitMessage;speechWebSocket.OnError += OnError;speechWebSocket.ConnectAsync();}void OnWebSocketClose(object sender, CloseEventArgs e){Debug.Log("OnWebSocketClose");}void OnInitMessage(object sender, MessageEventArgs e){UnityEngine.Debug.Log("qqqqqqqqqqqqqWebSocket数据返回:" + e.Data);messageQueue.Enqueue(e.Data);}private void MainThreadOnMessage(string message){try{XFResponse response = JsonConvert.DeserializeObject<XFResponse>(message);if (0 != response.code){errorCallback?.Invoke();MessageMng.Ins.ShowFloatTip("连接出错,请重试!");return;}if (response.action.Equals("result")){var result = ParseXunfeiRecognitionResult(response.data);if (result.IsFinal){//Debug.Log("Text最终:" + result.Text);resultCallback?.Invoke(result.Text);}else{//Debug.Log("Text中间:" + result.Text);}}}catch (Exception ex){Debug.LogError(ex.Message);}}void OnError(object sender, WebSocketSharp.ErrorEventArgs e){UnityEngine.Debug.Log("WebSoclet:发生错误:" + e.Message);}public SpeechRecognitionResult ParseXunfeiRecognitionResult(string dataJson){StringBuilder builder = new StringBuilder();SpeechRecognitionResult res = new SpeechRecognitionResult();try{JsonData data = JsonMapper.ToObject(dataJson);JsonData cn = data["cn"];JsonData st = cn["st"];if (st["ed"].ToString().Equals("0")){res.IsFinal = false;}else{res.IsFinal = true;}JsonData rtArry = st["rt"];foreach (JsonData rtObject in rtArry){JsonData wsArr = rtObject["ws"];foreach (JsonData wsObject in wsArr){JsonData cwArr = wsObject["cw"];foreach (JsonData cwObject in cwArr){builder.Append(cwObject["w"].ToString());}}}}catch (Exception ex){Debug.LogError(ex.Message);}res.Text = builder.ToString();res.type = ASRResultType.TEXT;return res;}void SendData(byte[] voiceData){//Debug.Log("SendData:" + voiceData.Length + ",time:" + Time.realtimeSinceStartup);if (speechWebSocket.ReadyState != WebSocketState.Open){return;}try{if (speechWebSocket != null && speechWebSocket.IsAlive){speechWebSocket.SendAsync(voiceData, success =>{if (success){//UnityEngine.Debug.Log("WebSoclet:发送成功:" + voiceData.Length);}else{//UnityEngine.Debug.Log("WebSoclet:发送失败:");}});}}catch{}}void SendEndMsg(System.Action callback){string endMsg = "{\"end\": true}";byte[] data = Encoding.UTF8.GetBytes(endMsg);try{if (speechWebSocket != null && speechWebSocket.IsAlive){speechWebSocket.SendAsync(data, success =>{if (success){UnityEngine.Debug.Log("WebSoclet:发送END成功:" + data.Length);}else{UnityEngine.Debug.Log("WebSoclet:发送END失败:");}callback?.Invoke();});}}catch{}}private string GetWebSocketUrl(){string appid = "appid";string ts = GetCurrentUnixTimestampMillis().ToString();string baseString = appid + ts;string md5 = GetMD5Hash(baseString);UnityEngine.Debug.Log("baseString:" + baseString + ",md5:" + md5);string sha1 = CalculateHmacSha1(md5, "appsecret");string signa = sha1;string url = string.Format("ws://rtasr.xfyun.cn/v1/ws?appid={0}&ts={1}&signa={2}", appid, ts, signa);UnityEngine.Debug.Log(url);return url;}private long GetCurrentUnixTimestampMillis(){DateTime unixStartTime = new DateTime(1970, 1, 1).ToLocalTime();DateTime now = DateTime.Now;// DateTime.UtcNow;TimeSpan timeSpan = now - unixStartTime;long timestamp = (long)timeSpan.TotalSeconds;return timestamp;}public string GetMD5Hash(string input){MD5 md5Hasher = MD5.Create();byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));StringBuilder sBuilder = new StringBuilder();for (int i = 0; i < data.Length; i++){sBuilder.Append(data[i].ToString("x2"));}return sBuilder.ToString();}public string CalculateHmacSha1(string data, string key){HMACSHA1 hmac = new HMACSHA1(Encoding.UTF8.GetBytes(key));byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));return Convert.ToBase64String(hashBytes);}private void Update(){if (messageQueue.Count > 0){MainThreadOnMessage(messageQueue.Dequeue());}if(requestQueue.Count > 0){SendData(requestQueue.Dequeue());}}private void OnApplicationQuit(){audioClip.StopRecording();audioClip.Dispose();}
}

BufferMilliseconds我这里设置的80,数据长度会大于1280,讯飞也是可以完成识别的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/841312.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt-C++笔记之使用QtConcurrent异步地执行槽函数中的内容,使其不阻塞主界面

qt-C笔记之使用QtConcurrent异步地执行槽函数中的内容&#xff0c;使其不阻塞主界面 code review! 文章目录 qt-C笔记之使用QtConcurrent异步地执行槽函数中的内容&#xff0c;使其不阻塞主界面1.QtConcurrent::run基本用法基本用法启动一个全局函数或静态成员函数使用 Lambda…

iOS--锁的学习

iOS--锁的学习 锁的介绍线程安全 锁的分类自旋锁和互斥锁OSSpinLockos_unfair_lockpthread_mutexpthread_mutex的属性 NSLockNSRecursiveLockNSConditionNSConditionLockdispatch_semaphoredispatch_queuesynchronizedatomicpthread_rwlock&#xff1a;读写锁dispatch_barrier_…

摸鱼大数据——Hive基础理论知识——Hive基础架构

1、Hive和MapReduce的关系 1- 用户在Hive上编写数据分析的SQL语句&#xff0c;然后再通过Hive将SQL语句翻译成MapReduce程序代码&#xff0c;最后提交到Yarn集群上进行运行 2- 大家可以将Hive理解成有道词典&#xff0c;帮助你翻译英文 2、Hive架构 用户接口: 包括 CLI、JDBC/…

武汉大学化学与分子科学学院雷爱义教授

国务院政府特殊津贴专家(2020)&#xff0c;第四届Yoshida Prize(吉田奖&#xff0c;2019)&#xff0c;国家“万人计划”科技创新领军人才(2017)&#xff0c;国家中青年科技创新领军人才(2015)&#xff0c;英国皇家化学学会会士(2015)&#xff0c;长江学者特聘教授(2014)&#x…

【数字移动通信】期末突击

文章目录 复习题一.简答题1、常用的移动通信系统有哪些?2、分别列出1G,2G,3G,4G的典型系统或标准&#xff1f;3、移动通信信道的基本特征&#xff1f;4、电波传播预测模型是用来计算什么量的&#xff0c;在选择传播预测模型时&#xff0c;主要考虑哪些因素&#xff1f;5、什么…

Java+Swing+Mysql实现飞机订票系统

一、系统介绍 1.开发环境 操作系统&#xff1a;Win10 开发工具 &#xff1a;Eclipse2021 JDK版本&#xff1a;jdk1.8 数据库&#xff1a;Mysql8.0 2.技术选型 JavaSwingMysql 3.功能模块 4.数据库设计 1.用户表&#xff08;users&#xff09; 字段名称 类型 记录内容…

脑机接口习题

9-12章习题 填空题 EEG电极分为 主动电极 和 被动电极 &#xff0c;其中 被动电极 直接与放大器连接&#xff0c; 主动电极 包含一个1~10倍的前置放大。除抗混淆滤波器&#xff0c;放大系统也包含由电阻器、电容器构成的模拟滤波器&#xff0c;把信号频率内容限制在一个特定的…

B树与B+树区别

B树和B树是常见的数据库索引结构&#xff0c;都具有相较于二叉树层级较少&#xff0c;查找效率高的特点&#xff0c;它们之间有以下几个主要区别&#xff1a; 1.节点存储数据的方式不同 B树的叶子结点和非叶子节点都会存储数据&#xff0c;指针和数据共同保存在同一节点中B树…

SpringMVC相关知识集锦----1

一、springMVC框架的了解 springMVC是一个基于java的实现了MVC设计模式的请求驱动类型的轻量级web框架,通过把model,view,controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发. 二、springMVC主要组件 1.前端控制器(dispatcherservlet):接收请…

【深度学习】复习温故而知新1

数据集ref&#xff1a;https://raw.githubusercontent.com/justinge/pic-go-for-xbotgo/master/Income1.csv X torch.from_numpy(data.Education.values.reshape(-1,1).astype(np.float32)) Y torch.from_numpy(data.Income.values.reshape(-1,1).astype(np.float32))y_pred…

当标签中出现输入了字母或者数字直接在一行上,没有换行的 情况时怎么办

当标签块中输入的是包含字母或者数字的时候&#xff0c;他不会换行&#xff0c;在一行上显示滚动条的形式&#xff0c;而我们想让他走正常文档流&#xff0c;该换行的时候换行 想要的如下效果 给相应的元素块添加该代码即可 word-break: break-all; .card-content { …

Dubbo与Spring Cloud等微服务框架的深度比较及选型指南

在当今的微服务架构领域&#xff0c;Dubbo与Spring Cloud作为两大主流框架&#xff0c;各自拥有独特的设计理念与技术优势&#xff0c;广泛应用于不同规模和类型的项目中。本文将从多个维度深入比较Dubbo、Spring Cloud以及其他代表性微服务框架&#xff08;如gRPC、Istio&…

酷开科技大屏营销,多元需求唤醒“客厅经济”

随着科技的发展和消费者习惯的变化&#xff0c;OTT大屏营销正逐渐成为客厅经济的新风向。OTT不仅改变了人们获取信息和娱乐的方式&#xff0c;也为品牌营销提供了新的机遇和挑战&#xff0c;OTT大屏营销已经成为客厅经济的重要组成部分。酷开科技通过其自主研发的智能电视操作系…

搜维尔科技:第九届元宇宙数字人设计大赛入围作品名单

随着第九届元宇宙数字人设计大赛渐近尾声&#xff0c;各院校提交的数字人作品已陆续完成评分统计汇总工作&#xff01;现将入围名单公布&#xff0c;请入围团队尽可能到场参加大赛颁奖典礼&#xff0c;具体获奖名次将在颁奖典礼中现场公布&#xff01; 颁奖典礼时间、地点&…

Codeforces Round 946 (Div. 3) C D

比赛链接&#xff1a;Dashboard - Codeforces Round 946 (Div. 3) - Codeforces 写在前面:比赛时C题卡了挺久&#xff0c;还没做出来&#xff08;qwq&#xff09;&#xff0c;D题也只是草草看了几眼&#xff0c;看榜单D题过的人数大于C题&#xff0c;写不出C题导致没心思看D题了…

不小心关闭了Linux的终端窗口怎么恢复文件?

当你在用vim编写程序的时候&#xff0c;没有保存你正在编写的程序&#xff0c;不小心关闭了窗口&#xff0c;而当你重新进入这个.c文件的时候&#xff0c;发现变成了只读文件&#xff1f;而且没有刚刚写的程序了&#xff1f;那刚刚写的程序是不是白写了&#xff1f; 不要慌&am…

一文了解 - GPS/DR组合定位技术

GPS Global Position System 全球定位系统这个大家都很熟悉&#xff0c; 不做太多介绍。 DR Dead Reckoning 车辆推算定位法&#xff0c; 一种常用的辅助的车辆定位技术。 DR系统的优点&#xff1a; 不需要发射和接收信号&#xff1b; 不受电磁波干扰。 DR系统的缺点&#x…

项目管理-质量管理

目录 一、质量管理概述 1.1 GB/T16260.1-2006 定义 1.2 GB/T19000-ISO 9000(2000)系列标准定义 二、软件质量模型 2.1 软件全生命周期质量模型 2.1.1 内部和外部质量的质量模型 2.1.2 使用质量的质量模型 2.1.3 McCall 质量模型 2.1.4 质量特性度量 2.1.5 相关概念 三…

【全开源】多功能投票小程序(ThinkPHP+FastAdmin+Uniapp)

打造高效、便捷的投票体验 一、引言 在数字化快速发展的今天&#xff0c;投票作为一种常见的决策方式&#xff0c;其便捷性和效率性显得尤为重要。为了满足不同场景下的投票需求&#xff0c;我们推出了这款多功能投票小程序系统源码。该系统源码设计灵活、功能丰富&#xff0…