语音相关-浏览器的自动播放策略研究和websocket研究

策略详情

媒体参与度
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五分钟一断开

问题在咨询钉钉专家团队,尚未解决。

相关推荐
兴达易控2 小时前
信捷V5 - F5变频器接入到Profibus网络的关键
网络协议
计算机毕设定制辅导-无忧学长5 小时前
分布式系统中的 Kafka:流量削峰与异步解耦(二)
microsoft·kafka·linq
小毛驴8507 小时前
httpclient实现http连接池
网络·网络协议·http
2501_916007477 小时前
定位接口偶发超时的实战分析:iOS抓包流程的完整复现
websocket·网络协议·tcp/ip·http·网络安全·https·udp
2501_916013747 小时前
iOS应用启动时间优化:通过多工具协作提升iOS App性能表现
websocket·网络协议·tcp/ip·http·网络安全·https·udp
23级二本计科8 小时前
RPC常见问题回答
网络协议·面试·rpc
2501_916008898 小时前
iOS APP上架App Store实践:通过自动化流程和辅助工具高效提
websocket·网络协议·tcp/ip·http·网络安全·https·udp
ZC1111K11 小时前
java springboot 模拟https请求
网络协议·http·https
CaracalTiger15 小时前
HTTP 协议的基本概念(请求/响应流程、状态码、Header、方法)问题解决方案大全
开发语言·网络·python·深度学习·网络协议·http·pip