音频(Audio)实现技术
重要通知
类目简介
基本概况
- HTML DOM Audio 对象: https://www.runoob.com/jsref/dom-obj-audio.html
- HTML 音频/视频: https://www.runoob.com/tags/ref-av-dom.html
- Web Audio API: https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API
- Web Audio API: https://webaudio.github.io/web-audio-api/
- HTMLAudioElement: https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLAudioElement
- HTMLMedia: https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLMediaElement
- AudioBuffer: https://developer.mozilla.org/zh-CN/docs/Web/API/AudioBuffer
音频格式MIME类型
----------------------------------------------
Format MIME-type
----------------------------------------------
MP3 audio/mpeg
Ogg audio/ogg
Wav audio/wav
----------------------------------------------
音频格式
pcm格式
PCM(Pulse-code modulation,脉冲编码调制)是一种音频原始数据格式,是将模拟电信号转化为数字信号的一种技术,涉及采样、量化和编码三个过程。
代码示例
const loadAudioData = function(url) {
return new Promise((resolve, reject) => {
const audio = document.createElement('audio');
audio.src = url;
audio.onloadeddata = function() {
resolve(audio);
}
audio.onerror = function() {
reject();
}
});
}
const url = 'https://test.ysunlight.com/Reference/audio/mov.mp4';
loadAudioData(url).then((audio) => {
audio.autoplay = 'autoplay';
audio.controls = 'controls';
audio.muted = 'muted';
// document.body.append(audio);
window.setTimeout(() => {
audio.click();
// audio.play();
});
});
Web Audio API
上传音频
const fileEl: HTMLInputElement = document.createElement("input");
if (!fileEl) return;
fileEl.setAttribute("type", "file");
fileEl.setAttribute("accept", "audio/mpeg,audio/ogg,audio/wav");
fileEl.click();
const getFileData = (fileTarget: HTMLInputElement) => {
return new Promise((resolve) => {
fileTarget.onchange = async function (e) {
// @ts-ignore # 忽视本行代码的小错误
resolve(e.target.files[0]);
};
});
};
const fileData = await getFileData(fileEl);
const base64AudioData = "data:audio/mpeg;base64,...";
const blobLink = base64ToBlobUrl(base64AudioData);
const audio = new Audio();
audio.src = blobLink;
audio.play();
// 将Base64编码的字符串转换为Blob URL的函数
function base64ToBlobUrl(base64Data) {
const byteCharacters = atob(base64Data.split(',')[1]);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'audio/mpeg' }); // 根据你的音频类型调整MIME类型
return URL.createObjectURL(blob); // 创建Blob URL
}
创建对象
一些经常被使用的属性,包括 src、currentTime、duration、paused、muted 和 volume。
const audioEl = new Audio("car_horn.wav");
audioEl.addEventListener("loadeddata", () => {
let duration = audioEl.duration;
// duration 变量现在存放音频的播放时长(单位秒)
});
音频生命周期事件
当音频/视频处于加载过程中时,会依次发生以下事件。
- loadstart
- durationchange
- loadedmetadata
- loadeddata
- progress
- canplay
- canplaythrough
API事件
- loadstart:客户端开始请求数据。
- progress:正在播放的时候不停触发,如果暂停不会触发,触发的时间间隔比较大。
- play:play()和autopaly播放时,类似事件onplaying。
- pause:pause()方法触发时。
- ended:当结束播放时。
- timeupdate:当前播放时间发生改变的时候,播放中常用的时间处理,如果暂停不会触发,触发的时间间隔比较小。
- canplaythrough:歌曲已经载入完成。
- canplay:缓冲至可播放状态,类似事件onloadedmetadata、onloadedmetadata。
拼接多个base64语音流
// 语音处理模型
const audioList = [
"data:audio/mpeg;base64,........",
"data:audio/mpeg;base64,........",
"data:audio/mpeg;base64,........",
"data:audio/mpeg;base64,........"
],
function audioModel() {
const blobList = audioList.map((blob) => {
return base64ToBlob(blob);
});
concatenateBlobs(blobList).then(function (combinedBlob) {
// 现在combinedBlob是拼接后的语音文件Blob对象
var url = URL.createObjectURL(combinedBlob);
// 可以使用这个URL来播放或下载语音文件
var audio = new Audio(url);
audio.play();
// 注意:在实际应用中,需要在适当的时候释放创建的URL资源
// URL.revokeObjectURL(url);
});
}
// 将Base64字符串转换为Blob对象
function base64ToBlob(base64, mime) {
var parts = base64.split(';base64,');
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
// 拼接两个Base64编码的语音文件
async function concatenateBlobs(blobArray = []) {
const _array = [];
for (let i = 0; i < blobArray.length; i++) {
const result = transFileReaders(blobArray[i]);
_array.push(result);
}
return Promise.all(_array).then(function (results) {
var combined = new Blob(results, { type: "audio/mpeg" });
return combined;
});
}
function transFileReaders(blob = "") {
var reader = new FileReader();
reader.readAsArrayBuffer(blob);
return new Promise((resolve) => {
reader.onload = function () {
resolve(reader.result);
}
});
}
音频 (Audio)元素
<audio>
提供了播放音频文件的标准。
注意事项
现代浏览器已经屏蔽了音频自动播放时携带音量的问题,即若设置自动播放需静音模式。
- Web Audio API:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API
- HTML DOM Audio 对象:https://www.runoob.com/jsref/dom-obj-audio.html
音频格式的MIME类型
- MP3:type="audio/mpeg"
- Ogg:type="audio/ogg"
- Wav:type="audio/wav"
<audio controls>
<source src="music.ogg" type="audio/ogg">
<source src="music.mp3" type="audio/mpeg">
<source src="music.wav" type="audio/wav">
</audio>
获取音频数据
export function generateAudioData(
url: string,
options = {} as Record<string, any>
) {
const { type, progress } = options;
const audio = document.createElement("audio");
const source = document.createElement("source");
source.src = url;
source.type = type || "audio/mpeg";
audio.appendChild(source);
return new Promise((resolve, reject) => {
audio.onloadeddata = function () {
resolve(audio);
};
audio.onprogress = function (e) {
progress && progress(e);
};
audio.onerror = function () {
reject(null);
};
});
}
const audio = await generateAudioData(url);
console.info(audio.duration);
场景代码
window.setTimeout(function() {
var total = Math.floor(audioPlayer.duration);
var audioControl = function() {
var time = audioPlayer.currentTime;
//防止死缓
console.log(time);
if (time >= total) {
current.attr("data-state", "false");
button.attr("src", path + controlArray[0]);
current.removeClass('audio-play');
audioPlayer.pause();
window.clearInterval(interval);
}
};
interval = window.setInterval(audioControl, 1000);
}, 150);
音频源
音频源渠道
- 直接通过 Javascript 生成声音节点产生(例如一个振动发声器)
- 由脉冲编码调制产生的原始数据(音频环境中可以调用一些方法来解码部分支持的格式)
- 从 HTML 元素中(例如
<video>
或者<audio>
标签) - 直接通过一个 WebRTC (en-US) MediaStream 获取流媒体(例如一个摄像头或麦克风)