本文意在讲解如何利用讯飞官方提供的API通过讯飞服务实时的进行文字转语音。

先决条件:需要在讯飞官网注册自己的账号,拿到讯飞给的APPID、APISecret、APIKey,这三个字段是访问讯飞服务器时生成鉴权必备的。

一、点击这里进入讯飞语音合成官网,右上角登陆自己的账号(没有就注册)。点击右上角控制台创建自己的应用,应用名自己随便起,创建完之后讯飞会自动给这个应用创建APPID、APISecret、APIKey三个字段,如下图:

创建新应用后点击进入就能看到讯飞给该应用分配的APPID、APISecret、APIKey三个字段,如图:

二、下面正式讲解讯飞API的使用方法。

按照上图标识位置进入讯飞WebAPI。

本人建议一步一步的阅读该API文档,不要跳读,不然会把自己搞晕,遇到读不懂的地方无需纠结,继续往下读就行,耐心读完之后前面不懂得地方自然而然就通了。

讯飞API文档有几点说的很清楚:(1)推荐的是WebSocket连接;(2)需要生成鉴权进行握手协议;(3)连接成功后即返回HTTP 101状态码,再进行文字转语音的请求

下面开始正式讲解:

1、生成鉴权

生成鉴权分三步:

(1)组装鉴权原始参数signature_origin

格式如下:

signature_origin="host: tts-api.xfyun.cn\ndate:Thu, 01, Aug  2019 01:53:21 GMT\nGET /v2/tts HTTP/1.1"

第一个host参数:就用 tts-api.xfyun.cn 不用变

第二个date参数:当前时间戳,官方要求RFC1123格式,DateTime.Now.ToString("r")这样就能获取该格式的当前时间戳

第三个request-line参数:就用 GET /v2/tts HTTP/1.1 不用变

(2)使用hmac-sha256算法对signature_origin进行加密,得到signature_sha

此步骤需要APISecrect一起做为参数进行加密
signature_sha = HmacSHA256(signature_origin, APISecret);

HmacSHA256方法如下:

    //加密算法HmacSHA256  private static string HmacSHA256(string secret, string signKey){string signRet = string.Empty;using (HMACSHA256 mac = new HMACSHA256(Encoding.UTF8.GetBytes(signKey))){byte[] hash = mac.ComputeHash(Encoding.UTF8.GetBytes(secret));signRet = Convert.ToBase64String(hash);//signRet = ToHexString(hash); ;}return signRet;}

(3)对signature_sha进行base64编码获取最终的signature

signature = ToBase64String(signature_sha);

    /// <summary>/// 转成Base64编码/// </summary>/// <param name="value"></param>/// <returns></returns>public static string ToBase64String(string value){if (value == null || value == ""){return "";}byte[] bytes = Encoding.UTF8.GetBytes(value);return Convert.ToBase64String(bytes);}

(4)使用上面获取到的signature、APIKey等拼接authorization_origin参数

string auth = "api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"";
 authorization_origin = string.Format(auth, APIKey, "hmac-sha256", "host date request-line", signature);

api_Key:是你自己的APIKey

algorithm:是加密算法名,就用"hmac-sha256",不用变

headers:是参与签名的,是固定的无需变host date request-line

signature:就是上一步生成的signature

(5) 最后一步:使用base64编码对authorization_origin进行编码就能获取到最终的鉴权

authorization = ToBase64String(authorization_origin);

代码如下:

    /// <summary>/// 组装生成鉴权/// </summary>private void ComposeAuthUrl(Uri uri,string date){        signature_origin = string.Format("host: " + uri.Host + "\ndate: " + date + "\nGET " + uri.AbsolutePath + " HTTP/1.1");Debug.Log("signature_origin: " + signature_origin);signature_sha = HmacSHA256(signature_origin, APISecret); //使用hmac - sha256算法结合apiSecret对signature_origin签名Debug.Log("signature_sha: " + signature_sha);signature = signature_sha;Debug.Log("signature: " + signature);string auth = "api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"";authorization_origin = string.Format(auth, APIKey, "hmac-sha256", "host date request-line", signature); //参数介绍:APIKey,加密算法名,headers是参与签名的参数(该参数名是固定的"host date request-line"),生成的签名Debug.Log("authorization_origin: " + authorization_origin);authorization = ToBase64String(authorization_origin);Debug.Log("authorization: " + authorization);}

进行到这里的同学已经完成了一半的工作量了。

2、利用生成的鉴权、RFC1123格式时间戳、host作为url参数进行websocket请求

void Init(){webSocket = new WebSocket(new Uri(GetUrl(url)));webSocket.OnOpen += OnOpen;webSocket.OnBinary += OnBinaryReceived;webSocket.OnMessage += OnMessage;webSocket.OnError += OnError;webSocket.OnClosed += OnClosed;Connect();}private void Connect(){webSocket.Open();Debug.Log("讯飞WebSocket打开成功!");}private void OnOpen(WebSocket ws){Debug.Log("讯飞WebSocket连接成功!");isConnecting = true;}private void OnBinaryReceived(WebSocket ws, byte[] data){ }private void OnError(WebSocket ws,Exception ex){isConnecting = false;string sf = string.Format("编码{0},详细信息{1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message);Debug.Log("错误编码: "+sf);}private void OnClosed(WebSocket ws,UInt16 code,string message){isConnecting = false;Debug.Log("讯飞WebSocket连接关闭!");}string GetUrl(string url){Uri uri = new Uri(url);string date = DateTime.Now.ToString("r"); //官方文档要求时间必须是UTC+0或GMT时区,RFC1123格式(Thu, 01 Aug 2019 01:53:21 GMT)。ComposeAuthUrl(uri,date);string uriStr = string.Format("{0}?authorization={1}&date={2}&host={3}", uri, authorization, date, uri.Host); //生成最终鉴权return uriStr;}

3、到这一步就实现了和讯飞服务器的连接,接下来把你要生成的语音内容传给服务器讯飞就会自动给你传回需要的语音,下面按照API组装参数即可

参数组装代码:

    /// <summary>/// 按照官方API组装传输参数/// </summary>/// <returns></returns>private JsonData CreateJsonData(){JsonData requestObj = new JsonData();requestObj["common"] = new JsonData();JsonData commonJson = new JsonData();commonJson["app_id"] = APPID;requestObj["common"] = commonJson;requestObj["business"] = new JsonData();JsonData bussinessJson = new JsonData();bussinessJson["aue"] = "raw";bussinessJson["vcn"] = "xiaoyan";bussinessJson["pitch"] = 50;bussinessJson["speed"] = 50;bussinessJson["tte"] = "UTF8";requestObj["business"] = bussinessJson;requestObj["data"] = new JsonData();JsonData dataJson = new JsonData();dataJson["status"] = 2;dataJson["text"] = ToBase64String(text);requestObj["data"] = dataJson;return requestObj;}

通过websocket向讯飞服务器发送请求

 /// <summary>/// WebSocket Send/// </summary>private void SendMessage(){JsonData jsonData = CreateJsonData();webSocket.Send(JsonMapper.ToJson(jsonData));}

返回参数见API文档即可,怎么接收随你

至此讯飞API请求就算结束了,原代码如下:

using BestHTTP.WebSocket;
using LitJson;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;public class XunFeiAPIWebSocket : MonoBehaviour
{private string url = "wss://tts-api.xfyun.cn/v2/tts";WebSocket webSocket;bool isConnecting;string APPID = "xxxxxx"; //你自己的APPIDstring APISecret = "xxxxxxxx";string APIKey = "xxxxxxxx";string signature_origin = ""; //原始签名string signature_sha = ""; //使用hmac-sha256算法加密后的signaturestring signature; //最终编码后的签名string authorization_origin; //原始鉴权string authorization; //最终编码后的鉴权string text = "你好小薇,现在时间是多少呀!"; //要转换的文本int audioLength; //语音长度Queue<float> audionQue = new Queue<float>(); //转后的语音队列AudioSource audioSource;// Start is called before the first frame updatevoid Start(){Init();}void Init(){audioLength = 0;audionQue.Clear();if (audioSource == null){audioSource = gameObject.GetComponent<AudioSource>();}webSocket = new WebSocket(new Uri(GetUrl(url)));webSocket.OnOpen += OnOpen;webSocket.OnBinary += OnBinaryReceived;webSocket.OnMessage += OnMessage;webSocket.OnError += OnError;webSocket.OnClosed += OnClosed;Connect();}private void Connect(){webSocket.Open();Debug.Log("讯飞WebSocket打开成功!");}private void OnOpen(WebSocket ws){Debug.Log("讯飞WebSocket连接成功!");isConnecting = true;if (isConnecting){SendMessage();}}private void OnBinaryReceived(WebSocket ws, byte[] data){}private void OnMessage(WebSocket ws, string message){JsonData js = JsonMapper.ToObject(message);if (js["message"].ToString() == "success"){if (js["data"] != null){if (js["data"]["audio"] != null){float[] fs = bytesToFloat(Convert.FromBase64String(js["data"]["audio"].ToString()));audioLength += fs.Length;foreach (float f in fs){audionQue.Enqueue(f);}if ((int)js["data"]["status"] == 2) //2为结束标志符{//ws.Close();audioSource.clip = AudioClip.Create("MySinusoid", 16000 * 60, 1, 16000, true, OnAudioRead); //要生成的音频名称、样本帧数(乘以60代表采样时长为1分钟)、每帧的声道数、剪辑采样频率、音频是否以流格式传输、调用该回调以生成样本数据块AudioClip cp = audioSource.clip;//audioSource.clip. = audioSource.time / 5;audioSource.Play();}}}}}/// <summary>/// 采样回调/// </summary>/// <param name="data"></param>void OnAudioRead(float[] data){for (int i = 0; i < data.Length; i++){if (audionQue.Count > 0)data[i] = audionQue.Dequeue();else{if (webSocket == null || !webSocket.IsOpen)audioLength++;data[i] = 0;}}}private void OnError(WebSocket ws, Exception ex){isConnecting = false;string sf = string.Format("编码{0},详细信息{1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message);Debug.Log("错误编码: " + sf);}private void OnClosed(WebSocket ws, UInt16 code, string message){isConnecting = false;Debug.Log("讯飞WebSocket连接关闭!");}string GetUrl(string url){Uri uri = new Uri(url);string date = DateTime.Now.ToString("r"); //官方文档要求时间必须是UTC+0或GMT时区,RFC1123格式(Thu, 01 Aug 2019 01:53:21 GMT)。ComposeAuthUrl(uri,date);string uriStr = string.Format("{0}?authorization={1}&date={2}&host={3}", uri, authorization, date, uri.Host); //生成最终鉴权return uriStr;}/// <summary>/// 组装生成鉴权/// </summary>private void ComposeAuthUrl(Uri uri,string date){        signature_origin = string.Format("host: " + uri.Host + "\ndate: " + date + "\nGET " + uri.AbsolutePath + " HTTP/1.1");Debug.Log("signature_origin: " + signature_origin);signature_sha = HmacSHA256(signature_origin, APISecret); //使用hmac - sha256算法结合apiSecret对signature_origin签名Debug.Log("signature_sha: " + signature_sha);signature = signature_sha;Debug.Log("signature: " + signature);string auth = "api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"";authorization_origin = string.Format(auth, APIKey, "hmac-sha256", "host date request-line", signature); //参数介绍:APIKey,加密算法名,headers是参与签名的参数(该参数名是固定的"host date request-line"),生成的签名Debug.Log("authorization_origin: " + authorization_origin);authorization = ToBase64String(authorization_origin);Debug.Log("authorization: " + authorization);}/// <summary>/// WebSocket Send/// </summary>private void SendMessage(){JsonData jsonData = CreateJsonData();webSocket.Send(JsonMapper.ToJson(jsonData));}/// <summary>/// 按照官方API组装传输参数/// </summary>/// <returns></returns>private JsonData CreateJsonData(){JsonData requestObj = new JsonData();requestObj["common"] = new JsonData();JsonData commonJson = new JsonData();commonJson["app_id"] = APPID;requestObj["common"] = commonJson;requestObj["business"] = new JsonData();JsonData bussinessJson = new JsonData();bussinessJson["aue"] = "raw";bussinessJson["vcn"] = "xiaoyan";bussinessJson["pitch"] = 50;bussinessJson["speed"] = 50;bussinessJson["tte"] = "UTF8";requestObj["business"] = bussinessJson;requestObj["data"] = new JsonData();JsonData dataJson = new JsonData();dataJson["status"] = 2;dataJson["text"] = ToBase64String(text);requestObj["data"] = dataJson;return requestObj;}//加密算法HmacSHA256  private static string HmacSHA256(string secret, string signKey){string signRet = string.Empty;using (HMACSHA256 mac = new HMACSHA256(Encoding.UTF8.GetBytes(signKey))){byte[] hash = mac.ComputeHash(Encoding.UTF8.GetBytes(secret));signRet = Convert.ToBase64String(hash);}return signRet;}//byte[]转16进制格式stringpublic static string ToHexString(byte[] bytes){string hexString = string.Empty;if (bytes != null){StringBuilder strB = new StringBuilder();foreach (byte b in bytes){strB.AppendFormat("{0:x2}", b);}hexString = strB.ToString();}return hexString;}///编码public static string EncodeBase64(string code_type, string code){string encode = "";byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code);try{encode = Convert.ToBase64String(bytes);}catch{encode = code;}return encode;}public static string ToBase64String(string value){if (value == null || value == ""){return "";}byte[] bytes = Encoding.UTF8.GetBytes(value);return Convert.ToBase64String(bytes);}/// <summary>/// byte[]数组转化为AudioClip可读取的float[]类型/// </summary>/// <param name="byteArray"></param>/// <returns></returns>public static float[] bytesToFloat(byte[] byteArray){float[] sounddata = new float[byteArray.Length / 2];for (int i = 0; i < sounddata.Length; i++){sounddata[i] = bytesToFloat(byteArray[i * 2], byteArray[i * 2 + 1]);}return sounddata;}static float bytesToFloat(byte firstByte, byte secondByte){// convert two bytes to one short (little endian)//小端和大端顺序要调整short s;if (BitConverter.IsLittleEndian)s = (short)((secondByte << 8) | firstByte);elses = (short)((firstByte << 8) | secondByte);// convert to range from -1 to (just below) 1return s / 32768.0F;}
}

该代码里的注释很详细,如还有不懂评论区留言

新建一个空场景,场景里随便建一个物体,物体挂上Audio Source组件,然后将该脚本挂上去就能直接将  string text = "你好小薇,现在时间是多少呀!"; 这句话读出来

注:需要两个插件 com.bestHttp和LitJson,百度下载导入到项目里即可,需要的评论区留言

Unity接讯飞在线语音API相关推荐

  1. Unity 讯飞实时语音转写(二)—— 接收转写结果

    目录 Unity 讯飞实时语音转写(一)-- 使用WebSocket连接讯飞语音服务器 Unity 讯飞实时语音转写(二)-- 接收转写结果 Unity 讯飞实时语音转写(三)-- 分析转写结果 正文 ...

  2. UNITY 接讯飞语音过程总结

    UNITY 接讯飞语音过程总结 11:13 2017/3/14 1,安装问题:JDK与ECLIPSE位数一定要对应,32位对64位会出现 java was returned ....code 13的弹 ...

  3. vue 讯飞在线文字合成语音,文字转成语音

    资源链接: 讯飞在线语音合成demo.tts_ws_js_demo.rar-互联网文档类资源-CSDN下载

  4. Unity与讯飞的aiui交互

    前言最近项目是做机器人,机器人最大的(普通的)AI功能就是语音交流,所以AIUI就是一个很好的选择.AIUI是封装了,讯飞的语音合成.语音识别等功能,重点是它有个兜底功能选择,还有技能工作室的加持,虽 ...

  5. Unity 接讯飞离线语音识别

    Unity 接入讯飞离线SDK , 有一些坑记录一下. 在开发者平台注册之后,申请应用,下载SDK包.这个sdk包和你的appid是对应的,不能使用别人的sdk包,然后用自己的appid 这是SDK文 ...

  6. asr语音转写_python 腾讯/百度/讯飞 ASR 语音转文字

    因为项目中有需要把微信里的语音转成文本处理, 本次只说语音转文本. 需要注意的是平台对语音的格式有要求, 所以我们需要对语音进行转换格式. 语音转换 使用的工具是ffmpeg, ffmpeg的安装和配 ...

  7. 讯飞智能语音鼠标G50:AI语音、转写翻译、记录截图一键搞定!

    随着互联网的发展,智能鼠标已经成为我们生活和工作中不可或缺的组成部分.然而,鼠标滚轮异响.按键失灵.驱动难用.手感不合适等一系列问题仍时有发生,所以选择一款智能鼠标尤为重要,它不仅可以提高我们的工作效 ...

  8. 讯飞离线语音命令词识别

    讯飞离线语音命令词识别 强烈推荐 分享一个大神的人工智能教程.零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来! 网址:http://www.captainbed.net/yancyang ...

  9. Android 讯飞离线语音听写/离线语音识别SDK

    平台 Android + 讯飞离线语音SDK SDK包 下载路径及方法见讯飞官方SDK文档: 离线语音听写 Android SDK 文档 # 在开发者控制台, 可以直接下载SDK. SDK包中的文件结 ...

最新文章

  1. 香港城市大学、港理工招收博士生,有奖学金机会
  2. 超越YOLOv5,1.3M超轻量,高效易用,目标检测领域这一个就够了
  3. 一个websocket 可以多个页面创建吗_实战分享|给我一个Puppeteer,没有爬不了的网站
  4. matlab2018b中svm无法运行,关于matlab2018a版本错误使用 svmclassify 分类器
  5. [译] 关于CSS中的float和position (父容器div内的子元素div为float时,父元素无法撑开(或高度自适应)的解决方式)
  6. Jmeter 的json Extractor
  7. 苹果自研5nm芯片M1首次亮相,搭载新MacBook Air
  8. bzoj 2431: [HAOI2009]逆序对数列
  9. 生产者消费者线程在QueueT中实现多线程同步
  10. Python struct模块与简单使用
  11. 手机做linux启动盘,教你制作Linux操作系统的USB启动盘
  12. 如何操作才能实现音频合并无缝衔接?只要掌握这个技巧
  13. 计算机去掉word2007,研习office 2007兼容包怎么卸载
  14. ppt快速美化四步法
  15. CSPS2019Day2T1(Emiya家今天的饭)题解
  16. VPLS原理+两个实验
  17. 【MyBatis】 动态SQL——模糊查询 LIKE
  18. MyBatis-Plus DQL与其他知识点
  19. 技术开放、平等普惠,蚂蚁金服ATEC科技大会闪耀狮城新加坡
  20. uhs3内存卡有哪些_可能是目前性价比最高的UHS-II SD卡

热门文章

  1. 年份好就多往前跑跑 年份不好就走慢点?是看天吃饭吗?
  2. 3DCAT首届行业生态交流会|燧光CTO 戴景文:云渲染 XR大发展的助推器
  3. 蓝牙耳机哪款延迟低?低延迟蓝牙耳机推荐
  4. matlab 绘制系统的单位阶跃响应曲线 并编写程序求峰值时间 超调量 [李园7舍_404]
  5. 通用的三视图和正等轴测图的绘制(C++实现)
  6. 数据结构实验四 约瑟夫生死游戏
  7. 解决笔记本电脑无法共享wifi问题
  8. 面试被当成菜鸟,程序员:当场摘帽子,面试官:明天来上班!
  9. Python opencv3安装
  10. solidwors中装配图视图是斜的处理办法