使用 AudioContext restart 音频

使用 AudioContext restart 音频📌 前言 📌 问题复现 我在页面上定义了两个按钮(一个播放按钮,一个暂停按钮)和一个选择文件的 input ,我想要实现的功能是点击播放就能播放,点击暂停就能暂停,所以呢我会定义了两个点击事件(播放和

📌 前言

为什么是 restart 呢,因为我遇到的问题是点击播放后无论如何再次点击播放,它就报错

(index):41 Uncaught DOMException: Failed to execute ‘start’ on ‘AudioBufferSourceNode’: cannot call start more than once. at HTMLButtonElement. 

📌 问题复现

我在页面上定义了两个按钮(一个播放按钮,一个暂停按钮)和一个选择文件的 input ,我想要实现的功能是点击播放就能播放,点击暂停就能暂停,所以呢我会定义了两个点击事件(播放和暂停)

接下来使用 audioContext 来实现音乐播放,为了兼容各个浏览器,我首先写了各个浏览器获取 audioContext 的方法

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();

然后创建 createBufferSource() 对象对音频播放这个功能来说是必须的,于是就有了下面的错误代码,我紧接着就在 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 对象来异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,然后监听其 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>

📌 效果图

image-20210810181454875

今天的文章使用 AudioContext restart 音频分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/16059.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注