如何获取HTML5音频的持续时间

45

我在页面中有一个 HTML5 的 <audio> 标签,但如何知道它的播放时长?

<audio controls="">
    <source src="p4.2.mp3">
</audio>
8个回答

29

2020年的解决方案:

当音频元数据尚未加载时,你会得到 undefinedNaN(不是一个数字)。因此,有些人建议使用 onloadedmetadata 确保首先获取音频文件的元数据。此外,大多数人没有提到的是,你必须使用类似于 [0] 这样的方式来定位音频 DOM 元素的第一个索引:

-- 原生 JavaScript:

var audio = document.getElementById('audio-1');
audio.onloadedmetadata = function() {
  alert(audio.duration);
};
如果这个方法行不通,可以尝试这个方法,但它不是很可靠,而且还要依赖用户的连接。
setTimeout(function () {
    var audio = document.getElementById('audio-1');
    console.log("audio", audio.duration);
}, 100);

-- JQuery:

$(document).ready(function() {
   var audio = $("#audio-1")[0];
   $("#audio-1").on("loadedmetadata", function() {
       alert(audio.duration);
   }); 
});

“$(“#audio-1”)[0];” 从何时起成为了 Vanilla Javascript?你的两个例子都是 jQuery 的,不确定你是否理解它们之间的区别。这里应该使用“document.getElementById('audio-1');”来代替 Vanilla Javascript。 - Richard Edwards
1
@RichardEdwards 感谢您指出这一点。在我写下这个答案的时候,我主要使用了JQuery,后来完全转向了Vanilla JS,没有注意到这个错别字。 - AlexioVay

17
var au = document.createElement('audio');
au.addEventListener('loadedmetadata',function(){
    au.setAttribute('data-time',au.duration);
},false);

11
在上面的评论中提到,解决方案是将事件处理程序绑定到loadedmetadata事件。这是我如何做到的 -
audio.onloadedmetadata = function() {
  alert(audio.duration);
};

5

我曾苦恼于在React组件中加载持续时间,因此遵循@AlexioVay的解决方案,如果您正在使用React,则以下是答案:

假设您正在使用ref用于音频组件类,您需要针对audio元素进行播放/暂停处理程序。

<audio /> 元素:

<audio ref={audio => { this.audio = audio }} src={this.props.src} preload="auto" />

在你的 componentDidMount() 中:
componentDidMount() {

    const audio = this.audio

    audio.onloadedmetadata = () => {
        console.log(audio.duration)
        this.setState({
           duration: this.formatTime(audio.duration.toFixed(0))
        })
    }
}

最后是 formatTime() 函数:

formatTime(seconds) {
    const h = Math.floor(seconds / 3600)
    const m = Math.floor((seconds % 3600) / 60)
    const s = seconds % 60
    return [h, m > 9 ? m : h ? '0' + m : m || '0', s > 9 ? s : '0' + s]
        .filter(a => a)
        .join(':')
}

当音频 src 数据加载完成后,时间长度将以 h:mm:ss 的格式显示。非常棒。


谢谢提到我。你能否也提供一下你的React hooks解决方案? - AlexioVay

1
我使用了“canplaythrough”事件来获取音轨的持续时间。我有一个情况,在这种情况下我有两个播放器,我想在第一个播放器完成前2秒停止第二个播放器。
$('#' + _currentPlayerID).on("canplaythrough", function (e) {   
    var seconds = e.currentTarget.duration;    
    var trackmills = seconds * 1000;
    var subTimeout = trackmills - 2000; //2 seconds before end

    //console.log('seconds ' + seconds);
    //console.log('trackmills ' + trackmills);
    //console.log('subTimeout ' + subTimeout);

    //Stop playing before the end of thet track
    //clear this event in the Pause Event
    _player2TimeoutEvent = setTimeout(function () { pausePlayer2(); }, subTimeout);

});

0

只需使用audioElement.duration


5
不,它不起作用,我尝试了 var audio = $('#audio')[0]; console.log('audio', audio.duration); 但是结果是 NaN - hh54188
1
这将提供正确的持续时间(在Firefox中测试过),但仅在loadedmetadata事件发生后。 - Michael Franzl
1
似乎当您使用setTimeout(function () { ... }, 10);而不是立即执行时,它可以正常工作。 - AlexioVay
@AlexioVay 关于超时的说法是正确的,文件需要加载一段时间后才能进行测试。 - Jeff Clayton

-1
为了获得阅读结束,必须使用事件'onended'并将'loop=false'。如果'loop=true',则'onended'不起作用;)
要创建播放列表,必须设置'loop=false'以使用'onended'事件以播放下一首歌曲。
对于持续时间,如果您的脚本正确完成,则可以在任何地方恢复持续时间。如果'duration'的值为NaN,则浏览器无法找到该文件。如果值为'Infinity'或'INF',则是流式传输,在这种情况下,相对于阅读时间'currentime'添加1分钟。 对于* I.E来说,这很糟糕。当前时间可能大于持续时间,在这种情况下,您需要执行以下操作: var duration = (this.currentime> this.duration)? this.currenttime: this.duration;
这就是(O_°)

-2

最好像这样使用事件...

ObjectAudio.onprogress  =function(){
    if(this.buffered.length){
    var itimeend = (this.buffered.length>1)? this.buffered.end(this.buffered.length-1):this.buffered.end(0);
    ....
        Your code here.......
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接