使用 AudioContext restart 音频
Posted 码小余の博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 AudioContext restart 音频相关的知识,希望对你有一定的参考价值。
使用 AudioContext restart 音频
📌 前言
为什么是 restart 呢,因为我遇到的问题是点击播放后无论如何再次点击播放,它就报错
(index):41 Uncaught DOMException: Failed to execute ‘start’ on ‘AudioBufferSourceNode’: cannot call start more than once.
at htmlButtonElement.
📌 问题复现
我在页面上定义了两个按钮(一个播放按钮,一个暂停按钮)和一个选择文件的 input ,我想要实现的功能是点击播放就能播放,点击暂停就能暂停,所以呢我会定义了两个点击事件(播放和暂停)
接下来使用 [audioContext
](AudioContext - Web APIs | MDN (mozilla.org)) 来实现音乐播放,为了兼容各个浏览器,我首先写了各个浏览器获取 audioContext
的方法
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
然后创建 [createBufferSource()
](AudioContext.createBufferSource() - Web API 接口参考 | MDN (mozilla.org)) 对象对音频播放这个功能来说是必须的,于是就有了下面的错误代码,我紧接着就在 audioCtx
变量后面新建了 createBufferSource
变量
var AudioBufferSourceNode = audioCtx.createBufferSource()
var play = document.getElementById("play")
var pause = document.getElementById("pause")
var bufferData = null
注意:上面的 AudioBufferSourceNode 是这篇文章所述的问题所在
然后是监听 input
上的 change
事件,当用户选择音频文件后执行回调函数中的代码
document.getElementById("loadfile").addEventListener("change", function () {
var file = this.files[0] // 获取音频文件对象
// ... 其他代码
}
然后在拿到音频文件对象后创建 [FileReader
](FileReader - Web API 接口参考 | MDN (mozilla.org)) 对象来异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,然后监听其 load
事件,当音频文件加载完毕后使用 decodeAudioData
对其进行解码操作,decodeAudioData 中有两个参数,第一个是 audioData音频数据;第二个是一个回调函数,它返回一个 buffer
缓存,当拿到成功 buffer
后就说明音频加载完毕了,现在就可以点击播放和暂停了
document.getElementById("loadfile").addEventListener("change", function () {
var file = this.files[0]
var fr = new FileReader()
fr.addEventListener("load", function(e) {
audioCtx.decodeAudioData(e.target.result, function(buffer){
// playFun(buffer); // 解码后返回的AudioBuffer对象作为播放函数的参数传入
console.log("音乐载入完毕");
bufferData = buffer
/* 写到 decodeAudioData 事件内部,当音乐加载完毕后才能执行播放和暂停 */
// 播放
play.addEventListener("click", function () {
console.log("播放");
AudioBufferSourceNode.buffer = bufferData // AudioBuffer数据赋值给buffer属性
AudioBufferSourceNode.connect(audioCtx.destination); // 如果只是播放音频,这边就直接将AudioBufferSourceNode连接到AudioDestinationNode
AudioBufferSourceNode.start(0); // 开始播放音频
console.log("音乐状态:", audioCtx.state);
})
// 暂停
pause.addEventListener("click", function () {
console.log("暂停");
AudioBufferSourceNode.stop(0) // 停止播放音乐
console.log("音乐状态:", audioCtx.state);
})
},function(err){
console.log(err);
})
})
fr.readAsArrayBuffer(file);
})
注意:以上代码是bug代码,请谨慎复制进行使用
📌 问题解决
在我查阅大部分资料之后,同样是没有找到合适的答案,但是在寻找答案的同时也给我带来了灵感,那就是如果重复点击播放的话,而当前的 AudioBufferSourceNode 还是用的旧的(没有更新或重新赋值),则会出现本文提到的那个错误,或找不到 buffer 之类的红色错误,所以说,我应该在点击播放时为 AudioBufferSourceNode
重新赋值
一起来实现吧~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<button id="play">播放</button>
<button id="pause">暂停</button>
<input type="file" id="loadfile">
</div>
<script>
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var AudioBufferSourceNode = null
var play = document.getElementById("play")
var pause = document.getElementById("pause")
var bufferData = null
document.getElementById("loadfile").addEventListener("change", function () {
var file = this.files[0]
var fr = new FileReader()
fr.addEventListener("load", function(e) {
audioCtx.decodeAudioData(e.target.result, function(buffer){
// playFun(buffer); // 解码后返回的AudioBuffer对象作为播放函数的参数传入
console.log("音乐载入完毕");
bufferData = buffer
/* 写到 decodeAudioData 事件内部,当音乐加载完毕后才能执行播放和暂停 */
// 播放
play.addEventListener("click", function () {
console.log("播放");
AudioBufferSourceNode = audioCtx.createBufferSource() // 必须在播放时重新创建 AudioBufferSourceNode 对象,否则会出现不能再次播放的问题
AudioBufferSourceNode.buffer = bufferData // AudioBuffer数据赋值给buffer属性
AudioBufferSourceNode.connect(audioCtx.destination); // 如果只是播放音频,这边就直接将AudioBufferSourceNode连接到AudioDestinationNode
AudioBufferSourceNode.start(0); // 开始播放音频
console.log("音乐状态:", audioCtx.state);
})
// 暂停
pause.addEventListener("click", function () {
console.log("暂停");
AudioBufferSourceNode.stop(0) // 停止播放音乐
console.log("音乐状态:", audioCtx.state);
})
},function(err){
console.log(err);
})
})
fr.readAsArrayBuffer(file);
})
</script>
</body>
</html>
📌 效果图
以上是关于使用 AudioContext restart 音频的主要内容,如果未能解决你的问题,请参考以下文章