浏览器通过原生JS实现音频播放控制功能
- 一. AudioContext介绍
- 二. FileReader介绍
- 三. 音频播放执行流程
- 四. 音频播放主要代码简述
- 五. 播放本地文件
-
- 1. 创建Input, 提供文件选择框
- 2. 创建Button, 提供本地文件播放控制
- 3. 播放按钮触发方法
- 六. 播放URL地址获取音频
-
- 1. 创建Input, 提供地址输入框
- 2. 创建Button, 提供URL地址获取音频播放控制
- 3. 播放按钮触发方法
- 七. 将音频绑定到Audio元素上
- 八. Audio元素播放JS控制
- 九. Vue样式
- 十. Vue完整代码
一. AudioContext介绍
- AudioContext接口表示由链接在一起的音频模块构建的音频处理图,每个模块由一个AudioNode表示。音频上下文控制它包含的节点的创建和音频处理或解码的执行。在做任何其他操作之前,您需要创建一个AudioContext对象,因为所有事情都是在上下文中发生的。建议创建一个AudioContext对象并复用它,而不是每次初始化一个新的AudioContext对象,并且可以对多个不同的音频源和管道同时使用一个AudioContext对象。详情
- AudioContext 兼容写法
createAudioContext() {
if (!window.AudioContext) {
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
}
return new window.AudioContext();
}
二. FileReader介绍
- FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。详情
- FileReader使用模板
let fileReader = new FileReader();
fileReader.onabort= (e) => {
在读取操作被中断时触发的操作 };
fileReader.onloadstart = (e) => {
在读取操作开始时触发的操作 };
fileReader.onload = (e) => {
在读取操作完成时触发的操作 };
fileReader.onerror= (e) => {
在读取操作发生错误时触发的操作 };
fileReader.onloadend= (e) => {
在读取操作结束时(要么成功,要么失败)触发的操作 };
fileReader.abort();
fileReader.readAsArrayBuffer(data);
fileReader.readAsText();
......
三. 音频播放执行流程
传递
传递
读取成功传递
读取失败结束
解析成功
解析失败结束
XHR通过URL获取音频ArrayBuffer或Blob
FileReader 对象
Input_type=File_选择本地音频文件
AudioContext获取实例
提示信息结束
音频源解析 decodeAudioData
创建音频源 audioBufferSourceNode
音频播放控制
四. 音频播放主要代码简述
play(file) {
let audioContext = this.createAudioContext();
if (!audioContext) {
return;
}
let fileReader = new FileReader();
fileReader.onload = (e) => {
this.relevance(e.target.result);
audioContext.decodeAudioData(e.target.result, (buffer) => {
let audioBufferSourceNode = audioContext.createBufferSource();
let analyser = audioContext.createAnalyser();
audioBufferSourceNode.connect(analyser);
analyser.connect(audioContext.destination);
audioBufferSourceNode.buffer = buffer;
audioBufferSourceNode.start = audioBufferSourceNode.start || audioBufferSourceNode.noteOn;
audioBufferSourceNode.stop = audioBufferSourceNode.stop || audioBufferSourceNode.noteOff;
audioBufferSourceNode.start(0);
audioBufferSourceNode.onended = (e) => {
console.log(e);
};
this.$audioContext = audioContext;
}, (e) => {
console.error(e);
},);
};
fileReader.onerror = (e) => {
console.error('Fail to read the file!', e);
};
fileReader.readAsArrayBuffer(file);
},
五. 播放本地文件
1. 创建Input, 提供文件选择框
<input id="file" type="file" placeholder="请选择本地音频文件"/>
2. 创建Button, 提供本地文件播放控制
<Button size="small" @click="file_play">播放文件内容</Button>
3. 播放按钮触发方法
file_play() {
let files = document.getElementById('file').files;
if (!files) {
return;
}
let file = files[0];
this.play(file);
}
六. 播放URL地址获取音频
1. 创建Input, 提供地址输入框
<input id="url" placeholder="填写URL"/>
2. 创建Button, 提供URL地址获取音频播放控制
<Button size="small" @click="url_play">播放链接内容</Button>
3. 播放按钮触发方法
createXHR() {
if (typeof XMLHttpRequest != "undefined") {
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined") {
if (typeof arguments.callee.activeXString != "string") {
let versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];
for (let i = 0, len = versions.length; i < len; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex) {
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}
url_play() {
let url = document.getElementById('url').value;
let form = new FormData();
let xhr = this.createXHR();
xhr.withCredentials = true;
xhr.responseType = "blob";
xhr.open("GET", url, true);
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
let response = xhr.response;
this.play(response);
} else {
console.warn('请求失败');
}
}
};
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.send(form);
}
七. 将音频绑定到Audio元素上
- 音频信息绑定到Audio元素上后, 可以对Audio元素进行播放控制, 可以跳过AudioContext, audioBufferSourceNode播放控制, 两者可任选其中一种进行播放控制.
- 相对来说, Audio元素播放控制相对方便一些.
relevance(arrayBuffer) {
let url = URL.createObjectURL(new Blob([arrayBuffer], {
'type': 'audio/mpeg'}));
this.$refs.recordPlayer.src = url;
}
八. Audio元素播放JS控制
let player = document.getElementById('player')
player.paly();
player.pause();
九. Vue样式
十. Vue完整代码
<template>
<div style="height: 100%;width: 350pt;margin: 100pt auto;">
<audio id="player" ref="recordPlayer" controls src=""></audio>
<div style="height: 20pt;"></div>
<input id="file" type="file" placeholder="请选择本地音频文件"/>
<Button size="small" @click="file_play">播放文件内容</Button>
<div style="height: 20pt;"></div>
<input id="url" placeholder="填写URL"/>
<Button size="small" @click="url_play">播放链接内容</Button>
<div style="height: 20pt;"></div>
<div>
<ButtonGroup>
<Button size="small" @click="resume">继续</Button>
<Button size="small" @click="suspend">暂停</Button>
</ButtonGroup>
</div>
</div>
</template>
<script>
export default {
name: "home",
mounted() {
},
methods: {
createXHR() {
if (typeof XMLHttpRequest != "undefined") {
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined") {
if (typeof arguments.callee.activeXString != "string") {
let versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];
for (let i = 0, len = versions.length; i < len; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex) {
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
},
createAudioContext() {
if (!window.AudioContext) {
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
}
return new window.AudioContext();
},
resume() {
this.$audioContext.resume();
},
suspend() {
this.$audioContext.suspend();
},
file_play() {
let files = document.getElementById('file').files;
if (!files) {
return;
}
let file = files[0];
this.play(file);
},
url_play() {
let url = document.getElementById('url').value;
let form = new FormData();
let xhr = this.createXHR();
xhr.withCredentials = true;
xhr.responseType = "blob";
xhr.open("GET", url, true);
xhr.onreadystatechange = () => {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
let response = xhr.response;
this.play(response);
} else {
console.warn('请求失败');
}
}
};
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.send(form);
},
relevance(arrayBuffer) {
let url = URL.createObjectURL(new Blob([arrayBuffer], {
'type': 'audio/mpeg'}));
this.$refs.recordPlayer.src = url;
},
play(file) {
let audioContext = this.createAudioContext();
if (!audioContext) {
return;
}
let fileReader = new FileReader();
fileReader.onload = (e) => {
this.relevance(e.target.result);
audioContext.decodeAudioData(e.target.result, (buffer) => {
let audioBufferSourceNode = audioContext.createBufferSource();
let analyser = audioContext.createAnalyser();
audioBufferSourceNode.connect(analyser);
analyser.connect(audioContext.destination);
audioBufferSourceNode.buffer = buffer;
audioBufferSourceNode.start = audioBufferSourceNode.start || audioBufferSourceNode.noteOn;
audioBufferSourceNode.stop = audioBufferSourceNode.stop || audioBufferSourceNode.noteOff;
audioBufferSourceNode.start(0);
audioBufferSourceNode.onended = (e) => {
console.log(e);
};
this.$audioContext = audioContext;
}, (e) => {
console.error(e);
},);
};
fileReader.onerror = (e) => {
console.error('Fail to read the file!', e);
};
fileReader.readAsArrayBuffer(file);
},
},
}
</script>
<style scoped></style>