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

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

实现步骤:

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

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数组用于存放音频队列,当接收多个消息时,将消息推入数组,当播放完一个音频后,检测数组是否为空,如果不为空,播放消息音频,否则继续播放空音频。

  • 1
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
uniapp微信小程序中连接websocket,你需要使用uni-app提供的uni-ws组件。具体操作步骤如下: 1. 在你的uni-app项目中,创建一个新的页面,并在该页面中引入uni-ws组件 2. 在页面的data中定义websocket连接对象,并设置websocket服务器的地址 3. 在页面的onLoad生命周期函数中,使用uni.connectSocket()方法连接websocket服务器,并将连接对象赋值给data中的websocket对象 4. 监听websocket连接事件,并在连接成功后发送消息给服务器 5. 监听websocket消息事件,并在接收到消息后更新页面数据或执行相应操作 以下是一个简单的示例代码: ``` <template> <view> <text>{{message}}</text> </view> </template> <script> export default { data() { return { websocket: null, message: "" } }, onLoad() { this.connectWebSocket(); }, methods: { connectWebSocket() { const url = "ws://localhost:8080"; // websocket服务器地址 this.websocket = uni.connectSocket({ url, success: () => { console.log("websocket连接成功"); } }); this.websocket.onOpen(() => { console.log("websocket连接已打开"); const msg = "Hello, WebSocket!"; this.websocket.send({ data: msg }); }); this.websocket.onMessage((res) => { console.log("websocket收到消息:", res); this.message = res.data; }); this.websocket.onError((err) => { console.error("websocket连接出现错误:", err); }); this.websocket.onClose(() => { console.log("websocket连接已关闭"); }); } } } </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值