处理浏览器的自动播放策略
操作场景
为了改善用户体验,浏览器加强了对自动播放策略(Autoplay)的限制:浏览器在没有交互操作之前不允许有声音的媒体自动播放。
各个浏览器关于自动播放策略有不同的实现,详情可参考以下文章:
- Chrome: Autoplay Policy Changes
- Safari: Auto-Play Policy Changes for macOS
- Firefox: Allow or block media autoplay in Firefox
在使用 ZEGO Web SDK 拉流时,媒体流中包含音频且未静音会受到浏览器自动播放策略的限制,导致音频不能正常播放。
操作步骤
为了解决上述播放失败的问题,本文将分两种情况介绍绕过 Autoplay 限制的方案:
- 播放失败时绕过 Autoplay 限制
- 直接绕过 Autoplay 限制
播放失败时绕过 Autoplay 限制
在实际使用中,页面并不是 100% 被 Autoplay 限制,随着用户使用这个页面的次数增加,浏览器会将这个页面加入自己的 Autoplay 白名单列表中。根据这个原理,开发者可在检测到播放失败时,引导用户点击页面上的某个位置来恢复播放。
// myVideo: 开发者自己的渲染标签,标签添加了autoplay属性,且不存在muted属性或muted=true
let autoPlay = false;
myVideo.oncanplay = ()=>{
setTimeOut(()=>{
autoPlay = !myVideo.paused
},1000)
}
注意:本地流一般不会有 Autoplay 限制(因为不会播放声音),只需处理远端流即可。
直接绕过 Autoplay 限制
可以通过如下两种方案实现直接绕过 Autoplay 限制:
方案 | 说明 | 适用场景 |
---|---|---|
方案一 | 设置 video 或 audio 标签的 muted 属性为 true 后再进行播放,媒体不包含声音时不会被 Autoplay 限制。 | 产品设计要求在没有用户操作的前提下自动播放媒体。 |
方案二 | 通过 UI 和产品设计让用户和页面发生交互操作(点击或触摸),在用户操作后再调用 video 或 audio 标签的 play 方法进行播放。 | 产品设计允许在播放媒体之前用户和页面产生某些交互,比如用户在进入直播间后需要点击某些按钮才会开始订阅主播。 |
注意:无论使用哪种方案,在自动播放策略的限制下,没有用户操作之前都不可能自动播放有声媒体。虽然浏览器会在本地维护一个白名单来决定对哪些网站解除自动播放限制,但该白名单无法通过 Javascript 探测到。
方案一:设置 muted
属性为 true
设置 video
或 audio
标签的 muted
属性为 true ,媒体先通过静音的方式自动播放,等页面上出现任何交互操作时,再自动切成有声媒体的播放。
-
注册一个全局的事件。
document.body.addEventListener("touchstart") // 监听触摸操作
或者
document.body.addEventListener("mousedown") // 监听点击操作
-
通过 createStream 接口获取远端流,将媒体流赋值给媒体标签的
srcObject
属性,设置相应媒体标签的muted
属性为 true。const remoteStream = await zg.startPlayingStream(streamID); // video为本地 <video> 或 <audio> 对象 video.srcObject = remoteStream; video.muted = true;
-
在第一步注册的事件回调中,将媒体标签的
muted
属性设置为 false,页面监听到交互操作时自动切换为有声媒体进行播放。video.muted = false;
方案二:提前产生交互行为
确保在将媒体流设置到媒体标签之前,用户和页面发生过交互行为即可绕过 Autoplay 限制。
对于桌面端的浏览器,这个方案可以绕过大部分 Autoplay 限制,但是在 iOS Safari/Webview 上,自动播放策略会更为严格。如果需要兼容 iOS Safari/WebView,推荐做如下特殊处理。
针对 iOS Safari/WebView 的特殊处理
注意:iOS Safari 只允许通过用户交互来触发有声媒体的播放,而不是在用户交互后就打开 Autoplay 限制。
-
媒体流自动播放时,设置
muted
为 true。<video id="video" autoplay muted playsinline></video>
-
在每个媒体流播放时,指定相应的 HTMLElement 容器绑定交互事件(点击或触摸)。
const play = document.getElementById('play'); play.addEventListener('click', () => { });
-
在播放界面上通过图标显示当前媒体流被静音,引导用户点击。
<div id="play">播放</div>
-
当用户点击某个媒体流的播放界面(刚刚绑定的容器)时,在事件的回调中将这个流再次播放,设置
muted
为 false,并更改静音图标。video.muted = false;