HTML5 音频元素 - 某些 Android 浏览器错误报告的曲目长度

HTML5 Audio element - Track length misreported by some Android browsers

本文关键字:报告 曲目 错误 浏览器 元素 音频 某些 Android HTML5      更新时间:2023-09-26

我正在使用HTML5 <audio>元素开发音频播放器,并试图跨浏览器解决一些问题。

此播放器配置为在单击其他轨道的链接时在音轨之间切换。在内部,它会暂停 <audio> 元素,将其currentTime设置为 0(如 HTML5 音频在 Android 4.0.4 设备本机浏览器中未多次播放中所述),并在使用指定的新源轨道创建新的<audio>元素之前将其从 DOM 中删除。在元素上调用 play() 方法以加载曲目并开始播放。

在桌面浏览器,iPhone和iPad上,这工作正常。它也适用于同事的三星Galaxy S3 Mini。但是,在另一部测试手机(全尺寸三星Galaxy S3)上,后续曲目的播放失败 - 曲目甚至无法播放,并且在播放栏中显示为已完成。在我的摩托罗拉Xoom平板电脑上的库存Android 4.1.2浏览器上也是如此。

页面加载时指定的第一个轨道始终工作正常。

在 JavaScript 代码中添加了一些调试语句,特别是 timeupdate 回调函数后,我发现在播放失败的情况下,引发 timeupdate 时,<audio> 元素的duration在两个实例中的值为 1。通常,对于 3-3 分钟的曲目,持续时间从 350 到刚刚超过 1000 不等。这就解释了为什么播放栏立即显示新加载的曲目已完成播放。

我认为后续曲目没有正确加载; 即使它之前已经加载并缓存在手机上,它肯定必须能够正确加载。所有曲目都是MP3,可以在相应的浏览器中播放。

我在这里错过了什么?知道问题是什么以及如何让它工作吗?

非常感谢。

更多信息:我已经将其他事件连接到 <audio> 元素以跟踪可能发生的事情:

  • progress(带有缓冲范围的报告)
  • loadedmetadata
  • canplay
  • error

在桌面上(正常工作),事件如下: timeupdate(具有 NaN 持续时间)、progress x3(0 个缓冲范围)、loadedmetadatacanplay、持续时间为 121.172368 的timeupdateprogress具有 1 个缓冲范围 [0, 11.507715],随着曲目继续播放,后跟一系列timeupdateprogress事件。iPhone也有类似的事件序列。

在三星 S3 上,我收到以下事件:持续时间为 1 的timeupdate,后跟 progress(0 个缓冲范围)、loadedmetadatacanplay ,最后是持续时间仍为 1 的timeupdate

此页面在解释事件和数据结构方面非常有用:http://www.sitepoint.com/essential-audio-and-video-events-for-html5/

好吧,我终于解决了它:

  • 首先,我更新了音频实现以在切换轨道时重复使用相同的<audio>元素,确保在更改src之前暂停音频,等等。这可能会也可能不会产生任何积极影响,尽管这是一种保证我们没有太多<audio>元素可能漂浮在内存中的方法,特别是如果某些未知手机一次只能处理一个实例。
  • 在切换曲目之前,我添加了一个保护子句来停止任何当前播放的音频,并确保如果没有加载音频,pause()或设置currentTime都不会导致错误:

    if (audioPlayerElement.readyState > 0)
    {
        audioPlayerElement.pause();
        audioPlayerElement.currentTime = 0;
    }
    
  • 由于后续曲目是自动播放的,因此需要修复语句的顺序。

对轨道持续时间的误报是<audio>要素使用方式中一个更大问题的征兆。以前,我已经初始化了音频播放器,如下所示:

  1. 创建<audio>元素/将src设置为MP3曲目的新URL
  2. <audio>元素调用load()
  3. 绑定timeupdateended事件
  4. 由于这是自动播放,因此将 autoplay 属性添加到 <audio> 元素
  5. 由于这是一个自动播放,因此在<audio>元素上称为play()

(在上面的步骤 1 和 2 之间执行了用于调试跟踪的loadedmetadatacanplayprogress事件的绑定。

我发现这个序列的问题是:

  • 如果设置了 autoplay 属性,则调用play()是多余的;并且
  • 添加 autoplay 属性应在调用 load() 之前进行,因为一旦缓冲了足够的数据load()就会自动开始播放曲目。

因此,有效的最后步骤是:

  1. <audio> 元素的 src 属性设置为 MP3 曲目的新 URL
  2. 绑定timeupdateended事件
  3. 由于这是自动播放,因此将 autoplay 属性添加到 <audio> 元素
  4. <audio>元素上调用load()

play()功能仅在单击播放/暂停按钮或从轨道栏上的特定位置开始播放时适用。

最后,值得注意的是,在 iOS 设备和某些 Android 设备(取决于浏览器)上,如果播放器初始化为在页面加载时开始播放,则会自动播放。在此类设备上,仅当执行可以追溯到点击事件(或类似事件)时,自动播放才有效。在更新视觉对象以指示"正在播放"状态时,请记住这一点 - canplay事件处理程序似乎是执行此操作的好地方。

我将

完全回答您的问题,因为它对我也很有用 - 如果您有更好的解决方案,请告诉我:)

我将保留每个声音所需的所有元数据的哈希值。这个哈希可能只是来自服务器的 json 响应 - 例如:

app.sounds.metadata = {
    "enter the sandman": {
        "artist": "Metaliica",
        "album": "Metallica.",
        "description": "Lorem ipsum dolor sit amet."
        "genre": "metal",
        "duration": 19920,
        "playcount": 312
    },
    "piano man": {
        "artist": "Billy Joel",
        "album": "You're my home",
        "description": "Lorem ipsum dolor sit amet."
        "genre": "Soft rock",
        "duration": 16200,
        "playcount": 135,
    }
}

我的音频元素将被声明为:

<audio data-sound="piano man">
    <source src="piano_man.ogg" type="audio/ogg">
    <source src="piano_man.mp3" type="audio/mpeg">
</audio>

现在,当我使用我的声音时,我只能使用:
var html5offset = 1000

var meta = app.sounds.metadata[sound.getAttribute("data-sound")];
var soundduration = meta.duration || sound.duration*html5offset;