uniapp实现微信小程序websocket+背景音频语音播报 您所在的位置:网站首页 支付宝vivo播放器播放器能否用于微信的播报 uniapp实现微信小程序websocket+背景音频语音播报

uniapp实现微信小程序websocket+背景音频语音播报

2024-07-04 02:35| 来源: 网络整理| 查看: 265

业务需求:根据后台返回消息播报语音,要求后台运行可继续播报

实现步骤:

建立socket连接监听消息,并建立心跳检测机制,防止socket意外断连将接收到的文字信息转化为音频文件使用uni.getBackgroundAudioManager(),实现后台运行可以持续播报音频解决并发问题,同时接收多个文件按顺序播报

1. 建立socket连接

onShow() { const SocketTask = getApp().globalData.SocketTask; if (!SocketTask) { this.linkSocket(); } } async linkSocket() { // 连接Socket服务器 let SocketTask; const TOKEN = store.getters['base/_token']; await new Promise((resolve, reject) => { SocketTask = uni.connectSocket({ url: wsUrl, header: { 'content-type': 'application/json', Authorization: TOKEN }, success: () => { console.log(`WebSocket connect成功`); resolve(); }, fail: () => { console.log('WebSocket connect失败'); reject(); } }); }); SocketTask.id = this.randomInt(1000, 9999); // 初始化心跳,心跳用于检测连接是否正常 SocketTask.heartCheck = { ...heartCheck }; SocketTask.reconnectObj = { ...reconnectObj }; // 赋值全局变量,用于判断是否已连接 getApp().globalData.SocketTask = this.SocketTask = SocketTask; // 开始监听 this.initEventHandle(this.SocketTask); } randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); }

定义心跳对象

// ws 心跳对象 let heartCheck = { timeout: 5000, // 收到pong后再次发ping的间隔时间;也是ws连接不上的最大等待时间 之后关掉连接并重连 timeoutObj: null, serverTimeoutObj: null, reset: function() { clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(SocketTask) { this.timeoutObj = setTimeout(() => { SocketTask.send({ data: 'ping' }); this.serverTimeoutObj = setTimeout(() => { SocketTask.close(); }, this.timeout); }, this.timeout); } };

消息监听

initEventHandle(SocketTask) { // 监听消息 SocketTask.onMessage(res => { // 心跳检测,后台返回pong表示连接正常 if (res.data === 'pong') { SocketTask.heartCheck.reset().start(SocketTask); } else { this.toAudioText = res.data; // 接收到文字消息转语音 this.getMp3(); } }); SocketTask.onOpen(() => { console.log(`${SocketTask.id} WebSocket onOpen`); SocketTask.heartCheck.reset().start(SocketTask); SocketTask.heartCheck.isAlive = true; }); SocketTask.onError(res => { console.log(`${SocketTask.id} WebSocket onError`, res); this.reconnect(SocketTask); }); SocketTask.onClose(res => { console.log(`${SocketTask.id} WebSocket onClose`, res); SocketTask.heartCheck.isAlive = false; if (res.code === 4000 || res.code === 4001) { console.log(`${SocketTask.id} WebSocket ${res.code}关闭`); } else { // 非正常关闭 重连 this.reconnect(SocketTask); } }); }

重连机制

let reconnectObj = { timeout: 5000, // 重连间隔时间 timer: null, // 重连计时器 lock: false, // 重连锁 limit: 0 // 重连最多次数 }; ... reconnect(SocketTask) { if (SocketTask.reconnectObj.lock) return; SocketTask.reconnectObj.lock = true; clearTimeout(SocketTask.reconnectObj.timer); if (SocketTask.reconnectObj.limit < 24) { SocketTask.reconnectObj.timer = setTimeout(() => { this.linkSocket(); SocketTask.reconnectObj.lock = false; }, SocketTask.reconnectObj.timeout); SocketTask.reconnectObj.limit++; } else { console.log(`${SocketTask.id}WebSocket reach limit 24!!!!!!!`); uni.showToast({ title: '很抱歉,您与服务器失去连接,请重启小程序', icon: 'none' }); } }

2.使用零七生活API完成文字转语音,api返回二进制音频流,直接在小程序无法播放,需要使用writeFile写入文件后可播放,注意播放完成后使用fs.unlink删除本地文件

const fs = uni.getFileSystemManager(); // 文件管理器API ... getMp3() { const target = `${wx.env.USER_DATA_PATH}/${new Date().getTime()}.mp3`; return new Promise((resolve, reject) => { uni.request({ url: `https://api.oick.cn/txt/apiz.php?text=${this.toAudioText}&spd=5`, method: 'GET', responseType: 'arraybuffer', // 注意此处,否则返回音频格式不可用 success: (res: any) => { fs.writeFile({ filePath: target, data: res.data, encoding: 'binary', success: res => { // 将接收到的消息推进消息队列 this.playAudio.push(target); }, fail: err => { console.log(err); } }); }, fail: (err: any) => { reject(err); } }); }); }

3. 播放背景音频:注意需要在 app.json 中配置 requiredBackgroundModes 属性

为了实现锁屏也可接收消息,进入页面后开始循环播放空音频,保证音频播放不中断,接收到消息后播放消息队列;

const backgroundAudioManager = uni.getBackgroundAudioManager(); ... onShow() { //循环播放音频 this.playInit(); } playInit() { backgroundAudioManager.title = '语音播报'; backgroundAudioManager.src = kong; backgroundAudioManager.onEnded(() => { if (this.index < this.playAudio.length) { console.log('播放列表:', this.playAudio); backgroundAudioManager.src = this.playAudio[this.index]; // backgroundAudioManager.src = ding; this.index++; } else { backgroundAudioManager.src = kong; // 清空播放列表 if (this.index > 0) { this.clearFile(); this.playAudio = []; this.index = 0; } } }); }

4.解决并发问题,定义playAudio数组用于存放音频队列,当接收多个消息时,将消息推入数组,当播放完一个音频后,检测数组是否为空,如果不为空,播放消息音频,否则继续播放空音频。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有