当前位置: 首页 > news >正文

uniapp安卓端实现语音合成播报

最初尝试使用讯飞语音合成方式,能获取到语音数据,但是数据是base64格式的,在安卓端无法播放,网上有说通过转成blob格式的url可以播放,但是uniapp不支持转换的api;于是后面又想其他办法,使用安卓插件播报原生安卓语音播报插件 - DCloud 插件市场

方案一(讯飞语音合成)

1.在讯飞后台注册登录获得APPID等信息  讯飞语音合成控制台

2.在项目根目录使用npm安装crypto-js

npm i crypto-js

3.新建xunfei.js文件,替换讯飞的APPID等3个配置

// 讯飞语音合成api文档	https://www.xfyun.cn/doc/tts/online_tts/API.html
import CryptoJS from 'crypto-js'
import {Base64} from './base64.js';const APPID = "替换自己的APPID";
const API_SECRET = "替换自己的API_SECRET";
const API_KEY = "替换自己的API_KEY";const URL = "wss://tts-api.xfyun.cn/v2/tts"
const HOST = "tts-api.xfyun.cn"function getWssUrl(date) {date = date||(new Date().toGMTString())let signatureOrigin = `host: ${HOST}\ndate: ${date}\nGET /v2/tts HTTP/1.1`let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, API_SECRET)let signature = CryptoJS.enc.Base64.stringify(signatureSha)let authorizationOrigin = `api_key="${API_KEY}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`let authStr = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(authorizationOrigin))return URL + "?authorization=" + authStr + "&date=" + date + "&host=" + HOST}
const wssUrl=getWssUrl()
// console.log("讯飞语音合成wssUrl",wssUrl)export const speak = (word) => {if (!word) {return}const socketTask=uni.connectSocket({url: wssUrl,success: res=> {console.log("讯飞websocket连接成功",res);},fail: err=> {console.log("讯飞websocket连接失败",err);},});//连接建立完毕,读取数据识别let buffs = ""socketTask.onOpen(data => {let params = {"common": {"app_id": APPID},"business": {// aue: "raw",aue: "lame",//mp3 (当aue=lame时需传参sfl=1)sfl: 1,//开启流式返回mp3格式音频auf: "audio/L16;rate=16000",vcn: "xiaoyan",//aisjiuxu	aisxping aisjinger aisbabyxutte: "UTF8",speed:60,//默认50,可选0-100volume:80,//默认50,可选0-100},"data": {"text": Base64.encode(word),"status": 2}}socketTask.send({data:JSON.stringify(params),success: res=> {console.log("讯飞websocket发送成功",res);},fail: err=> {console.log("讯飞websocket发送失败",err);},})socketTask.onMessage(res => {let ds = JSON.parse(res.data)console.log("接收到websocket消息:",ds)buffs+=ds.data.audio//返回的是base64数据if (ds.code === 0 && ds.data.status === 2) { //status为2表示合成完成console.log("音频合成完成");toPlay();socketTask.close();}})})socketTask.onError(err=>{console.log("讯飞websocket发生错误",err);})function toPlay() {const base64data='data:audio/mp3;base64,' + buffslet audioContext = uni.createInnerAudioContext();audioContext.autoplay = true;audioContext.src = base64dataaudioContext.play()audioContext.onEnded(() => {console.log("播放完成");audioContext.destroy()audioContext=null})audioContext.onCanplay(() => {console.log("可以播放音频了");})audioContext.onPlay(() => {console.log('开始播放');});audioContext.onError((res) => {console.log("播放失败",res);});}}

上面引入的base64.js,也可以自己npm安装base64插件

export const Base64 = {keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',encode(input) {let output = '';let chr1, chr2, chr3, enc1, enc2, enc3, enc4;let i = 0;input = Base64.utf8Encode(input);while (i < input.length) {chr1 = input.charCodeAt(i++);chr2 = input.charCodeAt(i++);chr3 = input.charCodeAt(i++);enc1 = chr1 >> 2;enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);enc4 = chr3 & 63;if (isNaN(chr2)) {enc3 = enc4 = 64;} else if (isNaN(chr3)) {enc4 = 64;}output = output +Base64.keyStr.charAt(enc1) + Base64.keyStr.charAt(enc2) +Base64.keyStr.charAt(enc3) + Base64.keyStr.charAt(enc4);}return output;},decode(input) {let output = '';let chr1, chr2, chr3;let enc1, enc2, enc3, enc4;let i = 0;input = input.replace(/[^A-Za-z0-9+/=]/g, '');while (i < input.length) {enc1 = Base64.keyStr.indexOf(input.charAt(i++));enc2 = Base64.keyStr.indexOf(input.charAt(i++));enc3 = Base64.keyStr.indexOf(input.charAt(i++));enc4 = Base64.keyStr.indexOf(input.charAt(i++));chr1 = (enc1 << 2) | (enc2 >> 4);chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);chr3 = ((enc3 & 3) << 6) | enc4;output = output + String.fromCharCode(chr1);if (enc3 !== 64) {output = output + String.fromCharCode(chr2);}if (enc4 !== 64) {output = output + String.fromCharCode(chr3);}}output = Base64.utf8Decode(output);return output;},utf8Encode(string) {string = string.replace(/\r\n/g, '\n');let utfString = '';for (let i = 0; i < string.length; i++) {let c = string.charCodeAt(i);if (c < 128) {utfString += String.fromCharCode(c);} else if ((c > 127) && (c < 2048)) {utfString += String.fromCharCode((c >> 6) | 192);utfString += String.fromCharCode((c & 63) | 128);} else {utfString += String.fromCharCode((c >> 12) | 224);utfString += String.fromCharCode(((c >> 6) & 63) | 128);utfString += String.fromCharCode((c & 63) | 128);}}return utfString;},utf8Decode(utfString) {let string = '';let i = 0;let c = 0;let c2 = 0;let c3 = 0;while (i < utfString.length) {c = utfString.charCodeAt(i);if (c < 128) {string += String.fromCharCode(c);i++;} else if ((c > 191) && (c < 224)) {c2 = utfString.charCodeAt(i + 1);string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));i += 2;} else {c2 = utfString.charCodeAt(i + 1);c3 = utfString.charCodeAt(i + 2);string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));i += 3;}}return string;}
};

4.在main.js中引入

import {speak} from './xunfei.js' 
Vue.prototype.$speak=speak//后续直接在需要的地方通过this.$speak('需要播报的文字')

PS:该方式在H5端播放短文本语句可以正常播放,长文本的播放不了,可以尝试分段播放,将websocket收到的数据push到一个数组中,然后一段一段播放(会有卡顿现象);在安卓端直接播放不了;大家有需要的可以尝试将base64转为blob,再用URL.createObjectURL()转换成临时url地址,或者服务端转成mp3数据

方案二(原生安卓语音播报插件) 推荐此方式,没有播报条数限制,讯飞每天有500条免费额度

在插件市场购买(0元)云打包插件 插件地址 然后按下图步骤选择该插件,然后重新制作自定义调试基座

然后在main.js中导入插件

// #ifdef APP
// 原生安卓语音播报插件,手机端可用,PDA需要安装tts语音引擎
let androidTTSPlugin = uni.requireNativePlugin('Tellsea-AndroidTTSPlugin');
androidTTSPlugin.init((e) => {let res = JSON.parse(e);if (res.code == 200) {console.log("初始化成功",res.msg);} else {console.log("初始化失败",res.msg);}
});
androidTTSPlugin.testPlugin('测试插件', (e) => {let res = JSON.parse(e);if (res.code == 200) {console.log('测试成功');} else {console.log("测试失败",res.msg);}
});
Vue.prototype.$speak=text=>{androidTTSPlugin.textToSpeech(text, (e) => {let res = JSON.parse(e);if (res.code == 200) {console.log("播报成功",res.msg);} else {console.log("播报失败",res.msg);}});
}
// #endif

后面在页面中使用语音播报api

this.$speak("上班了,打卡成功")

PS:如果设备播报没有声音需要查看设备是否安装了TTS语音引擎,没有的话可以安装微软的TTS语音引擎,安装完成之后,在 设置->文字转语音输出->首选引擎 将安装的TTS设置为首选引擎,然后打开TTS引擎 配置电池优化为允许后台持续运行

下载地址:下载地址

http://www.lryc.cn/news/395439.html

相关文章:

  • Studying-代码随想录训练营day31| 56.合并区间、738.单调递增的数字、968.监控二叉树、贪心算法总结
  • springboot装修接单平台-计算机毕业设计源码25005
  • matlab仿真 信道(下)
  • 华宇携TAS应用中间件亮相2024年山东江信智能信创产品推介会
  • 单向链表的数据存储(申请堆空间)
  • MySQL8之mysql-community-common的作用
  • Emacs有什么优点,用Emacs写程序真的比IDE更方便吗?
  • 如何切换手机的ip地址
  • 前端画图引擎ZRender,echarts的渲染器,你知道吗?
  • web前端开发——标签一
  • 【深度学习】探讨最新的深度学习算法、模型创新以及在图像识别、自然语言处理等领域的应用进展
  • 使用 mongo2neo4j 和 SemSpect 通过各种方式进行图探索
  • 淘宝卖家难免遇到的商品问题 在淘宝买的东西出问题了,该如何维权
  • ffmpeg 安装 h264(x264)encoder
  • Java项目:基于SSM框架实现的健康综合咨询问诊平台【ssm+B/S架构+源码+数据库+毕业论文】
  • SpringBoot源码阅读(4)——事件
  • EDI安全:如何在2024年保护您的数据免受安全和隐私威胁
  • RabbitMQ快速入门 - 图像化界面的简单操作
  • 新版亚组交互效应函数(P for interaction)newscitb5 1.3版本发布--用于一键生成交互效应表
  • gpt讲 Observable 对象
  • STM32的SPI接口详解
  • 谷歌+火狐浏览器——实现生成二维码并实现拖动——js技能提升
  • 128陷阱详解(从源码分析)
  • 点云处理实操 基于多项式重构的平滑和法线估计
  • MongoDB在Linux下的安装与基本操作指南
  • 端口占用快速解决
  • 普中51单片机:矩阵按键扫描与应用详解(五)
  • SQLite Glob 子句
  • Redis基础教程(十七):Redis数据备份与恢复
  • 基于FPGA的千兆以太网设计(1)----大白话解释什么是以太网