策略详情
媒体参与度


AudioContext音频API的实现

new Audio音频API的实现


相关实践
网页端
使用new Audio创建的音频对象进行音频播放的时候,如果用户没有与页面进行交互,那么会报错如下:

使用AudioContext创建的对象播放音频,不会报错,但是会有警告如下:

以上报错都是在用户与页面交互前,创建音频对象的时候报错。我们通过websocket推送的音频消息,只要用户没有与页面有交互,都不会进行播放。直到用户点击了页面,与页面进行了交互,我们后续的websocket音频消息才能正常播放。
钉钉桌面端
我们将我们的H5应用集成到钉钉桌面端,在网页端出现的无交互不播放的问题,在钉钉桌面端不存在。
但是钉钉桌面端又存在其他问题。
(1)钉钉桌面端挂后台定时任务放缓
由于收到节能机制影响,导致ws断线重连的时候延迟到2分钟后才发起重连
我们使用web worker可以绕开节能机制的影响
bash
// timer-worker.js
let timers = {};
self.onmessage = function(e) {
const { type, id, delay } = e.data;
switch(type) {
case 'setInterval':
timers[id] = setInterval(() => {
postMessage({ type: 'interval', id });
}, delay);
break;
case 'setTimeout':
timers[id] = setTimeout(() => {
postMessage({ type: 'timeout', id });
delete timers[id];
}, delay);
break;
case 'clearInterval':
case 'clearTimeout':
if (timers[id]) {
clearInterval(timers[id]);
clearTimeout(timers[id]);
delete timers[id];
}
break;
}
};
bash
// timer-worker-class.js
class WorkerTimer {
constructor() {
this.worker = new Worker('resources/central/common/timer-worker.js');
this.callbacks = {};
this.currentId = 0;
this.worker.onmessage = (e) => {
const { type, id } = e.data;
if (this.callbacks[id]) {
this.callbacks[id]();
if (type === 'timeout') {
delete this.callbacks[id];
}
}
};
}
setInterval(callback, delay) {
const id = ++this.currentId;
this.callbacks[id] = callback;
this.worker.postMessage({ type: 'setInterval', id, delay });
return id;
}
setTimeout(callback, delay) {
const id = ++this.currentId;
this.callbacks[id] = callback;
this.worker.postMessage({ type: 'setTimeout', id, delay });
return id;
}
clearInterval(id) {
if (this.callbacks[id]) {
this.worker.postMessage({ type: 'clearInterval', id });
delete this.callbacks[id];
}
}
clearTimeout(id) {
if (this.callbacks[id]) {
this.worker.postMessage({ type: 'clearTimeout', id });
delete this.callbacks[id];
}
}
}
项目代码中使用如下
bash
workerTimer:new WorkerTimer(),
vm.workerTimer.clearInterval(vm.heartbeatTimer);
vm.workerTimer.setInterval
如上确实解决了定时任务放缓的问题。
(2)钉钉桌面端挂后台声音积压和声音丢失
钉钉桌面端最小化的时候,等待2分钟后派单,无声音播报,若立马切前台,会发出语音(如果派单了多条,那么此时会同时发出多条语音)。若等待时间较久,那么语音会丢失。
且切换前台的时候,websocket的onmessage回调方才执行。
问题在咨询钉钉专家团队,尚未解决。
(3)钉钉桌面端挂前台websocket三分钟一断开
通过添加心跳协议解决该问题,同时保证断线重连。websocket代码如下:
bash
isConnecting:false,
heartbeatInterval:30000,
heartbeatTimer:null,
reconnectInterval:300,
setNoticeSocket(time){
let vm = this;
console.log("重连setNoticeSocket",vm.isConnecting,'new Date()',new Date(),'time-notifyConnetTime',time);
if(vm.isConnecting){
return;
}
if (typeof (WebSocket) == "undefined"){
console.log("current web client is not support for websocket.")
} else {
let host = window.location.host;
let scheme = window.location.protocol;
let ws = 'ws://' + host;
if (scheme.toLowerCase() == 'https:'){
ws = 'wss://' + host;
}
let name= JSON.parse(localStorage.getItem('user')).user.replace(/\\/g,"*");
let url = '/central/notify/refresh/'+name;
console.log("重连newwebsocket前",new Date(),'vm.noticeSocket',vm.noticeSocket,'vm.noticeSocket.readyState',vm.noticeSocket && vm.noticeSocket.readyState)
if(!vm.noticeSocket || (vm.noticeSocket && vm.noticeSocket.readyState === WebSocket.CLOSED)){
console.log("重连newwebsocket",new Date(),'vm.noticeSocket.readyState',vm.noticeSocket && vm.noticeSocket.readyState,'time--notifyConnetTime',time)
vm.isConnecting = true;
vm.noticeSocket = new WebSocket(ws+url);
vm.noticeSocket.onopen = function () {
console.log("重连成功onopen",new Date())
vm.isConnecting = false;
vm.notifyConnetTime = 0;
let data = {
use:"FILTER",
perspective:localStorage.getItem('perspective'),
status: "0",
id:'READ'
};
vm.noticeSocket.send(JSON.stringify(data))
vm.heartbeatTimer && vm.workerTimer.clearInterval(vm.heartbeatTimer);
vm.heartbeatTimer = vm.workerTimer.setInterval(() => {
if (vm.noticeSocket.readyState === WebSocket.OPEN) {
vm.noticeSocket.send(JSON.stringify({ type: 'heartbeat' }));
}
}, vm.heartbeatInterval);
};
vm.noticeSocket.onmessage = function (message) {
let res = message.data;
console.log("接收到ws消息----",res,new Date())
if(!res) return;
try{
let data = JSON.parse(res);
}catch(err){
}
};
vm.noticeSocket.onclose = function (message) {
vm.isConnecting = false;
vm.heartbeatTimer && vm.workerTimer.clearInterval(vm.heartbeatTimer);
vm.heartbeatTimer = null;
vm.reconnetNotice('来自close');
};
vm.noticeSocket.onerror = function (message) {
vm.isConnecting = false;
vm.heartbeatTimer && vm.workerTimer.clearInterval(vm.heartbeatTimer);
vm.heartbeatTimer = null;
vm.noticeSocket.close();
};
}
}
},
reconnetNotice(type){
let vm = this;
console.log("reconnetNotice-发起重连type",type,vm.notifyConnetTime,'new Date()',new Date())
// if(vm.notifyConnetTime<20){
vm.workerTimer.setTimeout(()=>{
vm.notifyConnetTime=vm.notifyConnetTime +1;
console.log("重连执行--vm.notifyConnetTime",type,vm.notifyConnetTime,'date',new Date())
vm.setNoticeSocket(vm.notifyConnetTime)
},vm.reconnectInterval)
// }
return;
},
(4)钉钉桌面端挂后台websocket五分钟一断开
问题在咨询钉钉专家团队,尚未解决。