使用audio标签遇到的两个问题及解决方案

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用audio标签遇到的两个问题及解决方案相关的知识,希望对你有一定的参考价值。

参考技术A

  公司的项目需要使用这个标签。在使用的过程中遇到了两个问题:一个是 部分手机浏览器无法实现自动播放(同样也无法使用js控制实现自动播放) ,还有一个是 部分浏览器audio标签无法正常响应ended(播放结束)事件,无法获取audio标签的duration属性的值 。这里分享一下我的处理方法,希望能够帮助到同样遇到类似问题的同学

  知道了原因那么自然就很好处理了。对于这个问题,网上大多处理方式都是先监听用户的DOM操作,如果事件响应了音频还没有播放,则播放音频。

  而我们这边的业务需求,需要一开始就获取自动播放的权限(音频是我们应用的一个关键功能),所以我们的处理方式是页面开始就引导用户点击。

  这里,用户点击之后才能使用我们服务。用户点击之后,我们也就获取到了js控制自动播放的权限了。

  如果你们的业务需求无法使用以上方式在一开始就让用户点击、获取播放权限,而且音频并非页面加载完就必须播放(例如背景音乐之类的)。那么可以先判断一下当前浏览器是否支持自动播放,如果支持则页面加载完立即播放音频,如果不支持则监听用户的DOM操作再播放音频。

  这里我写一个audioPlayPlugin.js,对audio标签的常用操作进行了一些简单的封装。 github地址 , coding地址

  因为业务需求,我必须监听音频的各种状态(播放中timeupdate、暂停pause、播放结束ended、缓冲waiting)等,但是在部分手机浏览器(例如MIUI的系统浏览器)中监听不了ended事件。也无法获取audio标签的duration属性的值(如果能够获取duration属性的值,就可以通过监听timeupdate事件,判断currrentTime和duration是否相等来模拟ended事件)。

  起初看到文章说是 Response Headers的content-type属性值为audio/x-mpeg导致的(浏览器不支持x-mpeg模式),把值设置为audio/mpeg即可。然而,找到后端说了这事儿,他弄了半天把content-type属性值设为audio/mpeg,然而问题并没有解决。

  最后我做了一个测试,同一个音频直接放在网站目录下用相对路径就可以正常监听ended事件,也能正常获取duration属性值。生产环境我们的文件是在阿里云上,使用绝对路径。对比了一下headers信息,发现唯一不同的地方就是Status Code不同。能正常监听的Status Code是206,不正常的是200。206是分段加载,具体各种status code可以戳 这里 。

  第二天,后端主动问我那个问题解决了没。我就说了我的发现,最后后端将音频文件的返回方式调整为206后,问题成功解决。

  总结一下: 发生这个问题的原因是音频类型文件请求的响应方式不对 。其实默认的响应方式就是206,只是我们后端在设置文件响应方式的默认配置时,直接copy了一些配置文件,其实并不知道他修改了音频文件的响应方式。

  以上是我使用<audio>标签时遇到的两个问题,和我的解决方案。希望能够帮助到各位同学。

  

HTML <audio> 标签的 canplaythrough 无法在移动设备上触发

【中文标题】HTML <audio> 标签的 canplaythrough 无法在移动设备上触发【英文标题】:HTML <audio> tag's canplaythrough not firing on mobile 【发布时间】:2016-03-01 02:32:30 【问题描述】:

我正在使用 HTML 5 &lt;audio&gt; 标签。我觉得它很酷,但只是遇到了一个非常奇怪的情况。简而言之,canplaythrough 不会像预期的那样在移动设备上触发。

在这种情况下,我在网页上有几个按钮:

<button id="sndbtn01" onclick="createAudioById('01')">Audio 01</button>
<button id="sndbtn02" onclick="createAudioById('02')">Audio 02</button>
<button id="sndbtn03" onclick="createAudioById('03')">Audio 03</button>
<button id="sndbtn04" onclick="createAudioById('04')">Audio 04</button>

我希望在单击“Audio 01”时播放 01.mp3,以及单击“Audio 02”、“Audio 03”、“Audio 04”按钮的类似动作。而且我希望在点击按钮的时候创建&lt;audio&gt;标签,这样我就可以在不预加载所有内容的情况下节省流量。

所以,我有 JavaScript 代码:

  var audioObj = ;
  function createAudioById(id)
    var p = audioObj[id];
    // alert(1)
    if (p != undefined) 
      alert(2);
      p.play();
      return;
     else 
      alert(3);
      p = new Audio();
      p.addEventListener('canplaythrough', function(e)
        e.currentTarget.removeEventListener('canplaythrough', arguments.callee);
        alert(4);
        p.play();
      );
      p.src = '../snds/'+id+'.mp3';
      audioObj[id] = p;
    
  

但这种行为在移动设备上很奇怪:

在手机 (iPhone) 上:

    首先单击button 01 会触发(3),然后什么也没有发生 - canplaythrough 事件从未被触发并且音频从未播放过 - 与预期不同:(4) 应该被触发并且音频应该被播放; 如果我再次单击该按钮,(2) 将触发并播放音频。但奇怪的是,音频开始播放几秒钟后,(4) 就被触发了。 如果我在播放音频时单击按钮,(2) 会被触发并且没有任何反应,音频会继续播放 - 正如预期的那样; 如果我在音频播放完毕时点击按钮,(2) 将被触发,音频已播放,(4) 永远不会弹出 - 正如预期的那样。

【问题讨论】:

【参考方案1】:

在桌面上:

我不明白为什么这是奇怪的行为。您首先检查名称为“01”的音频是否存在。它没有,所以你创建它,当它完成加载并可以播放时,事件监听器被触发并开始播放。

然后,您在播放时再次按下该按钮。您检查名称为“01”的音频是否存在 - 它确实存在,因为您之前创建了它并且它仍在播放。因此,定义了 p 并且 (2) 触发。音频一直在播放,因为您告诉它播放,它已经在播放了。

然后,当音频停止并按下按钮时,您检查名称为“01”的音频是否存在。它仍然存在——它停止播放了,但它仍然存在,只是因为歌曲结束而暂停了。所以(2)触发器,你告诉它播放,但事件监听器仍在监听,你从未破坏它,所以当它重新下载歌曲时,canplaythrough 被第二次触发。这都是正常的行为。

在移动设备上: 你有完全相同的设置,除了这一次无论出于何种原因 canplaythrough 事件没有触发。我不知道为什么会这样,但这是另一个问题。除此之外,这种行为很容易解释。您创建了新的音频,由于某种原因该事件没有被触发,所以当您再次单击该按钮时,音频仍然存在,从您之前创建它时开始播放并开始播放。然后,当歌曲结束时,音频仍然存在并且仍然有事件侦听器,但是再一次,由于某种原因,事件侦听器根本不起作用,但音频仍然会播放,因为它仍然存在。

【讨论】:

感谢回复,我又试了一次,发现canplaythrough每次调用audioelement.play()都会触发; - 这有点奇怪。无论如何,在这种情况下如何删除事件监听器?您是否知道为什么该事件没有在移动设备上触发? 我不知道为什么不能在移动设备上触发 canplaythrough,但是要删除事件侦听器,只需在事件侦听器触发的函数中添加 e.currentTarget.removeEventListener('canplaythrough')在第一次触发事件侦听器时摆脱它。确保将参数 e 添加到函数开头,如 function handler(e) 谢谢,我已经更新了问题,但是在添加 e.currentTarget.removeEventListener('canplaythrough') 之后,(4) 仍在触发 - 您可以看到我最新代码的已编辑问题。 为了让 e.currentTarget.removeEventListener 工作,函数需要有一个名字,它不能是匿名的。使用函数处理程序(e) 我忘记传递参考了。我只是通过使用e.currentTarget.removeEventListener('canplaythrough', arguments.callee);来解决它,谢谢!

以上是关于使用audio标签遇到的两个问题及解决方案的主要内容,如果未能解决你的问题,请参考以下文章

Spark 1.x 爆内存相关问题汇总及解

Firefox关于Audio事件的bug及解决方案

深刻求解答:ios使用audio标签不能播放网络音频 求解决方案!!!

移动浏览器中 html5 <audio> 标签的功能障碍

java 死锁产生原因及解锁(转)

sqlServer查看死锁及解锁