【问题标题】:How to set the currentTime in HTML5 audio object when audio file is online?音频文件在线时如何在 HTML5 音频对象中设置 currentTime?
【发布时间】:2018-09-02 14:32:11
【问题描述】:

我有一个 JavaScript 音频播放器,带有向前/向后跳过 10 第二个按钮。我通过设置音频元素的currentTime 来做到这一点:

function Player(skipTime)
{
    this.skipTime = skipTime;
    this.waitLoad = false;

    // initialise main narration audio
    this.narration = new Audio(getFileName(dynamicNarration));
    this.narration.preload = "auto";
    this.narration.addEventListener('canplaythrough', () => { this.loaded();       });
    this.narration.addEventListener('timeupdate',     () => { this.seek();         });
    this.narration.addEventListener('ended',          () => { this.ended();        });
    this.narration.addEventListener('waiting',        () => { this.audioWaiting(); });
    this.narration.addEventListener('playing',        () => { this.loaded();       });
}

Player.prototype = {
    rew: function rew()
    {
        if (!this.waitLoad) {
            this.skip(-this.skipTime);
        }
    },

    ffw: function ffw()
    {
        if (!this.waitLoad) {
            this.skip(this.skipTime);
        }
    },

    skip: function skip(amount)
    {
        const curTime = this.narration.currentTime;
        const newTime = curTime + amount;
        console.log(`Changing currentTime (${curTime}) to ${newTime}`);
        this.narration.currentTime = newTime;
        console.log(`Result: currentTime = ${this.narration.currentTime}`);
    },

    loaded: function loaded()
    {
        if (this.waitLoad) {
            this.waitLoad = false;
            playButton.removeClass('loading');
        }
    },

    audioWaiting: function audioWaiting()
    {
        if (!this.waitLoad) {
            this.waitLoad = true;
            playButton.addClass('loading');
        }
    },
}

(我在这里包括了一些我正在附加的事件侦听器,因为以前我调试过一个类似的问题,因为事件侦听器中的冲突。不过,这次彻底调试了事件侦听器,我不 认为这是问题的根源。)

虽然这一切在我的本地副本上都可以正常工作,但当我测试在线版本时,我得到以下结果:

  • Chrome:将播放位置重置为0。最后的控制台行读取结果:currentTime = 0
  • Safari: 根本不改变播放位置。最后的console.log 行给出的currentTime 值等于newTime(即使播放位置实际上没有改变)。
  • Firefox: 向前跳过作品;向后跳过会中断音频几秒钟,然后它会从播放头所在的几秒钟前再次开始播放。在这两种情况下,最后的 console.log 行给出的 currentTime 值等于 newTime

这个问题一定与音频的加载方式有关。我尝试添加另一个控制台日志行来显示buffered 的开始值和结束值。

在 Chrome 中,它会在当前播放位置后上升到 2 秒。在 Safari 中,它上升到 ~170 秒,而在 Firefox 中,它似乎缓冲了完整的音频长度。

但是,在每种情况下,buffered 对象的开头都是 0

有人知道可能出了什么问题吗?

【问题讨论】:

  • Igid,如果您对我下面的回答感到满意,请在我的回答左侧将其标记为已接受或给我写反馈。
  • @lgid 您能否提供您正在使用的文件的样本?它是什么类型的?我已经使用托管在某处的 mp3 文件尝试了您的代码,并且它按预期工作。

标签: javascript event-handling html5-audio dom-events audio-player


【解决方案1】:

正确加载音频文件和使用属性有一些要求。 您在提供文件时的响应需要具有以下标头。

接受范围:字节

内容长度:BYTE_LENGTH_OF_YOUR_FILE

内容范围:字节 0-BYTE_LENGTH_OF_YOUR_FILE/BYTE_LENGTH_OF_YOUR_FILE

内容类型:音频/mp3

我和我的同事为此苦苦挣扎了几天,终于成功了

Image of Response header for an audio file

【讨论】:

  • 你现在添加这个答案真是巧合!我刚刚回到了音频流的世界,通过在 PWA 上为音频文件实现服务工作者缓存机制,我在过去几天里学到了关于范围标头的全部知识。我正在为自己的答案添加解释并对此表示赞同。
  • 为我工作!我的 API 正在发送 AAC 字节,并且设置正确的监听器工作得很好。
【解决方案2】:

如果您的浏览器没有加载音频,则无法播放音频。浏览器不知道您的音频文件,因此它会尝试从一开始就播放您的音频。可能您的音频可能只有 1 秒长甚至更短。

解决方案

您必须等待loadedmetadata 事件,之后您可以从任何时间位置播放您的音频。在此事件之后,您的浏览器会知道有关您的音频文件的所有相关信息。

请按如下方式更改您的代码:

function Player(skipTime)
{
    this.skipTime = skipTime;

    // initialise main narration audio
    this.narration = new Audio(getFileName(dynamicNarration));
    this.narration.preload = "auto";
    this.narration.addEventListener('canplaythrough', () => { this.loaded();       });
    this.narration.addEventListener('timeupdate',     () => { this.seek();         });
    this.narration.addEventListener('ended',          () => { this.ended();        });
    this.narration.addEventListener('waiting',        () => { this.audioWaiting(); });
    this.narration.addEventListener('playing',        () => { this.loaded();       });

    this.narration.addEventListener('loadedmetadata', () => {playButton.removeClass('loading');});

    playButton.addClass('loading');
}

Player.prototype =
{
    rew: function()
    {
        this.skip(-this.skipTime);
    },

    ffw: function()
    {
        this.skip(this.skipTime);
    },

    skip: function(amount)
    {
        var curTime = this.narration.currentTime;
        var newTime = curTime + amount;
        console.log(`Changing currentTime (${curTime}) to ${newTime}`);
        this.narration.currentTime = newTime;
        console.log(`Result: currentTime = ${this.narration.currentTime}`);
    }
};

但是,如果您不想长时间等待音频加载,那么您只有一个选择:将所有音频文件转换为 dataURL 格式,如下所示:

var data = "data:audio/mp3;base64,...

但在这种情况下,您必须等待页面加载,而不是加载一个音频文件。而通过音频文件加载,它只是元数据,而且速度更快。

【讨论】:

  • 我也尝试添加一个loadedmetadata 事件监听器。但是,由于这发生在音频已经播放后,元数据早就已经加载了。事实上,我在播放器逻辑的其他部分使用了持续时间。
  • @Igid,我在您的代码中看不到任何持续时间。我是否正确回答了您的问题?如果您对我的回答感到满意,请在我的回答左侧将其标记为已接受和/或投票。
  • 我的意思是我的实际生产代码也使用持续时间,它不包含在我的简化示例中。感谢您的回复,但不,等待元数据加载对我没有帮助,因为它在我播放文件之前很久就加载了。
  • @Igid,但它是唯一一种在线播放文件的方法。您的本地文件不需要它,您可以在页面加载后立即播放它们,但使用在线文件 - 您只有一种方式 - 您必须等待 loadedmetadata 事件。这很长,因为您的页面已经在浏览器中加载,并且文件中的元数据必须在页面加载后从您的服务器加载..
  • 我确实通过添加带有控制台日志的事件侦听器来测试这一点。 loadedmetadata 事件在我按下播放之前触发。所以等待这个事件并不能解决我的问题。
【解决方案3】:

这解决了我的问题...

    private refreshSrc() {
      const src = this.media.src;
      this.media.src = '';
      this.media.src = src;
    }

【讨论】:

    【解决方案4】:

    我找到了解决问题的方法,如果不完全是解释的话。

    我的托管服务提供商使用 CDN,它必须将资源的 URL 替换为不同域的 URL。我的音频资源的 URL 是由 JS 动态构建的,因为它们有一个随机元素;因此,替换 URL 的部署过程没有为我的音频文件捕获这些。为了解决这个问题,我手动从 CDN 中排除了音频文件,这意味着我可以使用相对文件路径来引用它们。

    当我遇到这个问题时,情况就是这样。

    然后,由于一个单独的问题,我采取了不同的方法:我将音频文件重新放在 CDN 上,并编写了一个函数来提取我需要用来检索文件的域名。当我这样做时,突然间我发现与设置currentTime 有关的所有问题都消失了。 不知何故,没有 CDN 上的文件严重干扰了浏览器有序加载它们的能力。

    如果有人可以自愿解释为什么会这样,我很想听听......

    编辑

    我一直在从事另一个涉及流式音频的项目,这次也支持 PWA,因此我必须在我的服务工作者中为音频文件实现缓存机制。通过this guide,我了解了范围请求的所有缺陷,并且现在明白如果无法对具有范围标头的请求提供正确的响应,将会破坏某些浏览器上的搜索。

    似乎在上述情况下,当我从 CDN 中排除我的文件时,它们是从不支持范围标头的地方提供的。当我将它们移回 CDN 时,这已得到修复,因为它一定是在明确支持流媒体的情况下构建的。

    Here 很好地解释了对范围请求的正确响应。但是对于在使用第三方托管服务时遇到此问题的任何人,只要知道他们可能不支持流媒体的范围标头就足够了。如果您想验证是否是这种情况,您可以查询音频对象的持续时间。至少在 Safari 的情况下,当它无法成功发出范围请求时,持续时间设置为无穷大,此时将禁用搜索。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-23
      • 2016-08-30
      • 1970-01-01
      • 2014-10-17
      • 2016-09-04
      • 2014-02-23
      • 2012-03-22
      • 2020-04-29
      相关资源
      最近更新 更多