uni-app:实现长连接语音文件发送
涉及内容:
-
音频录制
-
长连接websocket
-
音频录制:详情可见https://blog.csdn.net/qq_44429079/article/details/116990979
-
长连接:
在项目中新建一个uni.socket.js的文件:
代码如下:
/*
* @Author: UpYou
* @Date: 2020-12-25 9:14:50
* @LastEditTime: 2020-12-28 15:41:31
* @Description: uni.socket plug-in is developed based on uniapp...
*/
import Vue from 'vue'
export default class Socket {
constructor(option = {}) {
this._url = option.url;
// 是否设置重新连接
this._reconnection = option.reconnection || true;
// 是否建立缓存池,默认true,如果建立缓存池,会将因为程序错误导致未发送成功的消息发送
this._buffer = option.buffer || true;
/// on方法注册的事件
this.on_register = {};
// 是否已成功连接
this._connectioned = false;
// 缓存池
this._buffer_register = [];
// 发送缓存池的数据
this._auto_emit_buffer_data = option.autoEmitBuffer || false;
// 被动断开
this.closed = false;
// 开始重连
this.begin_reconnection = false;
//是否打印
this.log=option.log?option.log:false;
//是否发送心跳
this.heart_state=option.heart_state?option.heart_state:false;
// 多少毫秒发送一次心跳
this._heart_rate = option.heartRate > 0 ? option.heartRate : 60000;
// 后端心跳字段
this._heart_rate_type = option.heartRateType || 'HEARTBEAT';
this.init();
}
/**
* 注册一个事件
* @param {Object} event 事件
* @param {Object} handler 事件处理者
* @param {Boolean} single 此handler是否只处理一次
*/
async on(event, handler, single = false) {
// const eType = await this.getType(event);
// if (eType === "[object String]" && eType.trim() !== "") {
let isSingle = true;
if (single && this.on_register[event] !== undefined) {
for (let i = 0; i < this.on_register[event].length; i++) {
if (handler === handlers[i]) {
isSingle = false;
break;
}
}
}
if ((!single) || (isSingle && single)) {
if (this.on_register[event] === undefined) {
this.on_register[event] = [];
}
this.on_register[event].push(handler);
}
if(this.log)console.log('建立监听事件',event,this.on_register);
// }
}
/**
* 移除指定注册的事件
* @param {Object} name 事件名称
*/
async removeEventByName(name) {
if(this.log)console.log('移除全部事件',event)
return Promise.then(() => {
delete this.on_register[name]
});
}
/**
* 给缓存池添加记录
*/
async addBuffer(data = {}) {
const da = JSON.stringify(data);
this._buffer_register.push(data);
}
/**
* 获取缓存池
*/
async getBuffer() {
return this._buffer_register;
}
/**
* 获取连接状态
* @return {number} 0 表示连接中,1表示连接成功,2表示重连中,3表示失败
*/
async getState() {
return this.begin_reconnection ? 2 : (this._connectioned ? 1 : (this.isError ? 3 : 0))
}
/**
* 关闭当前socket
*/
async close() {
this.closed = true;
this.SocketTask && this._connectioned && this.SocketTask.close();
}
/**
* 发送消息
*/
async emit(event, data = {},noString = false) {
// if (this.getType(event) === "[object Object]" && this.getType(event) === "[object String]") {
// let e = data;
// data = event;
// event = e;
// }
if(this.log)console.log('发送消息',event,data)
if(this.noString){
this.SocketTask.send(data);
return
}
if (this.SocketTask) {
const da = {
type: event,
data: data
};
console.log(noString?data:JSON.stringify(da))
this.SocketTask.send({
data: noString?data:JSON.stringify(da),
fail: (e) => {
// 消息发送失败时将消息缓存
this.addBuffer(da);
throw new Error('Failed to send message to server... ' + e);
}
});
} else {
throw new Error("The socket is not initialization or connection error!");
}
}
/**
* 将缓存池的数据发送
*/
async sendBufferRegister() {
if (this._connectioned) {
// 缓存池备份
const backup = JSON.parse(JSON.stringify(this._bufer_register));
let del_count = 0;
for (var i = 0; i < backup.length; i++) {
const buffer = backup[i - del_count];
this.SocketTask.send({
data: buffer,
success: () => {
backup.splice(i, 1);
del_count++;
}
});
}
this._bufer_register = backup;
}
}
/**
* 发生错误
* @param {Object} callback
*/
async error(err) {
this.isError = true;
if (this.on_register['error'] !== undefined) {
this.invokeHandlerFunctionOnRegistr('error', err);
}
}
/**
* 重新连接错误
* @param {Object} err 错误信息
*/
async reconnectionError(err) {
this.isError = true;
if (this.on_register['reconnectionerror'] !== undefined) {
this.invokeHandlerFunctionOnRegistr('reconnectionerror', err);
}
}
/**
* 连接成功
*/
async connectioned() {
this.isError = false;
// 关闭重连状态
this.begin_reconnection = false;
this._connectioned = true;
if (this.on_register['connectioned'] !== undefined) {
this.invokeHandlerFunctionOnRegistr('connectioned');
}
if(this.log)console.log('socket连接成功');
// 给服务器发送心跳
this.beginSendHeartBeat();
}
/**
* 开始发送心跳
*/
async beginSendHeartBeat() {
if(!this.heart_state){
return
}
this._heart_rate_interval = setInterval(res => {
this.emit(this._heart_rate_type);
this._heart_rate_interval && clearInterval(this._heart_rate_interval);
this.emitMessageToTargetEventByName('HEARTBEAT', {
msg: 'Send a heartbeat to the server...'
})
}, this._heart_rate);
}
/**
* 将心跳结束
*/
async killApp() {
this._heart_rate_interval && clearInterval(this._heart_rate_interval);
}
/**
* 重连socket
*/
async reconnection() {
// 处于与服务器断开状态并且不是被动断开
this._connectioned = false;
if (!this.closed) {
this.reconnection_time = setTimeout(() => {
this.begin_reconnection = true;
this.connection();
}, 1000);
}
}
/**
* 初始化程序
*/
async init() {
this.connection();
// 发送缓存池中的数据
if (this._auto_emit_buffer_data) {
setInterval(() => {
this._connectioned && this.sendBufferRegister();
}, 20000);
}
}
/**
* 连接socket
*/
async connection() {
// 是否有重连任务
if (this.reconnection_time) {
clearTimeout(this.reconnection_time);
}
/// 创建一个socket对象,返回socket连接
const SocketTask = uni.connectSocket({
url: this._url,
success: () => {
}
});
/// 打开连接的监听
SocketTask.onOpen(() => {
this.SocketTask = SocketTask;
// 标记已成功连接socket
this._connectioned = true;
SocketTask.onClose(() => {
// 重新连接
if (!this.closed) {
this.reconnection();
}
});
this.connectioned();
});
SocketTask.onMessage((msg) => {
try {
console.log(msg)
// const data = JSON.parse(msg.data);
// if(this.log)console.log('客户端收到消息',data.type,data);
// if(data.data.code&&data.data.code==1){
// Vue.prototype.$msg(data.data.message)
// }
// if (data['type'] && data['data']) {
// this.emitMessageToTargetEventByName(data['type'], data['data']);
// } else {
// this.emitToClientAllEvent(msg);
// this.emitToClientNotNameEvents(msg);
// }
} catch (e) {
/// 服务器发来的不是一个标准的数据
this.emitToClientNotNameEvents(msg);
}
});
/// 连接打开失败
SocketTask.onError((res) => {
if(this.log)console.log('连接打开失败');
// 不在重连状态
if (!this.begin_reconnection) {
this.error(res);
} else {
this.reconnectionError(res)
}
// 重新连接
this.reconnection();
})
}
/**
* 注销监听
*/
off(event, handler) {
const handlers = this.on_register;
for (let i = 0; i < handlers[event].length; i++) {
if (handler === handlers[event][i]) {
handlers[event].splice(i, 1);
}
}
if(this.log)console.log('注销单事件',event,handler,this.on_register,handlers)
return this.off;
}
// async function handler
/**
* 给指定的事件发送消息
* @param {Object} name 事件名称
*/
async emitMessageToTargetEventByName(name, data) {
this.invokeHandlerFunctionOnRegistr(name, data);
}
/**
* 联系使用on(**)注册的事件
*/
async emitToClientNotNameEvents(msg) {
this.invokeHandlerFunctionOnRegistr("**", msg);
}
/**
* 联系使用on(*)注册的事件
*/
async emitToClientAllEvent(data) {
this.invokeHandlerFunctionOnRegistr("*", data);
}
/**
* 获取对象类型
* @param {Object} o 需要验证的对象
* 判断type是否为字符串
*/
async getType(o) {
return Object.prototype.toString.call(o);
}
/**
* 给指定的事件发送数据
* @param {Object} register 事件
* @param {Object} data 需要发送的数据
*/
async invokeHandlerFunctionOnRegistr(register, data) {
if (this.on_register[register] !== undefined) {
const eventList = this.on_register[register];
for (var i = 0; i < eventList.length; i++) {
const event = eventList[i];
event(data);
}
}
}
}
在main.js中导入:
import UniSocket from "@/common/uni.socket.js"
Vue.prototype.$socket = new UniSocket({
// url接口地址 ws http,wss https
url: "ws://120.77.251.202:4000",
log: true
});
部分方法:首先将录音得到的blob文件转为arraybuffer类型,我看uni-app的文档,websocket支持的只有string和arraybuffer类型
say() {
// 开始录音,再次点击上传给后端,自动生成一个新的对话框
if (this.ly_start == true) {
// 开始录音
this.startRecord()
} else {
this.endRecord()
// 结束录音
let blob = recorder.getWAVBlob();
this.blob2 = blob
// blob转换成file对象
this.nowFile = new window.File(
[blob],
'ex.mp3', {
type: 'audio/wav'
}
);
// blob转arrayBuffer对象
var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = (event) => {
arrayBuffer = event.target.result;
this.arrayBuffer2 = arrayBuffer
console.log(arrayBuffer)
//传输三个参数,第三个参数为true后,仅发送第二个参数作为socket报文
// this.sends(arrayBuffer)
};
fileReader.readAsArrayBuffer(blob);
}
this.ly_start = !this.ly_start
},
发送:
sends() { this.$socket.emit('webSocket', this.arrayBuffer2, true) },