在之前的博文Web前端JS如何获取 Video/Audio 视音频声道(左右声道|多声道)、视音频轨道、音频流数据中,介绍了通过使用AudioContext.createScriptProcessor()方法来获取视音频音轨(声道)数据。但由于W3C不再推荐使用该AudioContext.createScriptProcessor()特性。所以在不久的将来也许会从相关的Web标准中移除,也许正准备移除或出于兼容性而保留。
但尽管如此:目前所有现代浏览器包括早期点的浏览器均得到了很好的支持,暂时还没有看到在哪个浏览器上被正式的移除。
通过对比:在尝试使用 AudioWorkletNode() 来替代上面的createScriptProcessor() ,AudioWorkletNode()在目前看来几乎所有的主流浏览器都支持它,但需要注意的是:它现在还是一项实验性技术。
以上两个API从性能上相比较:AudioWorkletNode() 比 ScriptProcessorNode() 性能要更好些,并且更易于使用,并且它还支持更多个的输入和输出通道。
在Web浏览器中,想要获取多媒体文件的相关数据信息,需要借助对应的API来完成,比如获取视音文件的音频信息,就需要用到Web Audio API,通过该API我们可以轻松做到播放声音、获取声音数据,修改声音数据、甚至还可以制造声音。
Web Audio API 提供了在 Web 上控制音频的一个非常有效通用的系统,允许开发者来自选音频源,对音频添加特效,使音频可视化,添加空间效果(如平移),等等。
它可以设置不同的音频来源(包括节点、 ArrayBuffer 、用户设备等),对音频添加音效,生成可视化图形等。
Web Audio API 使用户可以在音频上下文(AudioContext)中进行音频操作,具有模块化路由的特点。在音频节点上操作进行基础的音频,它们连接在一起构成音频路由图。
即使在单个上下文中也支持多源,尽管这些音频源具有多种不同类型通道布局。这种模块化设计提供了灵活创建动态效果的复合音频的方法。
Web Audio API 是 JavaScript 中主要用于在网页应用中处理音频请求的一个高级应用接口,其复杂度比Canvas相关的API还要高,如果将Web Audio API 和 Canvas相关API 相结合起来使用能做出很多有趣的东西,比如:音频数据可视化、峰值电平、响度跳表等。这个 API 目的是用于让最新技术与传统的游戏音频引擎的综合处理相兼容,也即尽力提供一些桌面音频处理程序的要求。
AudioContext接口表示由链接在一起的音频模块构建的音频处理图,每个模块由一个AudioNode表示。音频上下文控制它包含的节点的创建和音频处理或解码的执行。在做任何其他操作之前,你需要创建一个AudioContext对象,因为所有事情都是在上下文中发生的。建议创建一个AudioContext对象并复用它,而不是每次初始化一个新的AudioContext对象,并且可以对多个不同的音频源和管道同时使用一个AudioContext对象。
📢需要注意: 在没有和用户进行交互时,直接通过代码运行
new AudioContext()
时!浏览器会发出:The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page.
意思是说:不允许启动AudioContext。必须要用户在页面上做出手势后才能 创建 或 恢复。
??主要原因:浏览器这样做其目的是,为了防止不必要的自动播放音频,一些浏览器不允许在首次创建网络音频API的AudioContext时启动。它必须在用户与页面交互后通过在上下文AudioContext对象上调用resume()方法来启动。
📊解决方案:不同的浏览器以不同的方式实现此要求:如使用调用AudioContext.resume()的方法来激活它。
- Chrome和Edge浏览器:就是先不运行new AudioContext()。等到用户单击事件的回调 或 向音频 / 视频元素的 播放事件添加侦听器来恢复。想了解更多:https://developer.chrome.com/blog/autoplay/#webaudio
- Firefox浏览器:目前还能直接运行 new AudioContext();
- Webkit/Safari 浏览器:最初已暂停。只能通过附加到单击事件的回调来恢复 - (就是通过附加到单击事件的回调或通过向音频/视频元素的事件添加侦听器来恢复)。
??主要原因:四个字【为了安全】,当在使用或元素,媒体源与网站不在同一域上(就是视音频的src域名地址和当前运行代码的域名地址不是同一个域名时),则会导至MediaElementAudioSource零输出。
📊解决方案:为媒体提供服务的服务器必须在响应中添加一个带有网站域的访问控制允许来源标头(就是在src媒体源服务器中添加请求白名单,这个只要对接或联调过后端API接口的小伙伴都知道的!)。想了解更多:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Attributes/crossorigin
了解更多相关标准 和 API:https://www.w3.org/TR/webaudio、https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API
由于video和audio都有音频,所以我们可以video或者audio来获取输入源,除此以外,我们还可以通过 navigator.getUserMedia API 或 Ajax请求的方式来获取输入源。
<video loop controls>
<source src="./media/xxx.mp4" type="video/mp4" />
</video>
<audio loop controls>
<source src="./media/xxx.mp3" type="audio/mp3" />
</audio>
虽然AudioWorkletNode这个接口可以在 secure contexts 之外调用,但是 BaseAudioContext.audioWorklet (en-US) 属性不行,从而 AudioWorkletProcessor 不能在外部定义。
Web Audio API 中的 AudioWorkletNode 接口代表了用户定义的AudioNode的基类,该基类可以与其他节点一起连接到音频路由图。其具有关联的AudioWorkletProcessor, 它在 Web Audio 执行实际的音频处理。
简单来说,就是由于AudioWorkletNode为了提升性能,借助了Web Worker来配合使用,调用如下processor.js中
processor.js
class RandomNoiseProcessor extends AudioWorkletProcessor {
process(inputs, outputs, parameters) {
this.port.postMessage(inputs[0]);
return true;
}
};
try {
registerProcessor("mu-processor", RandomNoiseProcessor);
} catch (error) {
console.log('无法注册样本处理器。这可能意味着它已经注册了。', error);
}
JS关键代码
// 创建一个 AudioContext 环境
const ac = new (window.AudioContext || window.webkitAudioContext)();
// 从 video 或 audio 标签元素中拿到输入源
const audio = document.querySelector("video");
// const audio = document.querySelector("audio");
// 创建并获取输入源
const audioSource = ac.createMediaElementSource(audio);
// 创建音频处理器
await ac.audioWorklet.addModule('./processor.js');
const node = new AudioWorkletNode(ac, 'mu-processor');
// 链接音频处理器
audioSource.connect(node).connect(ac.destination);
// connect到扬声器
audioSource.connect(ac.destination);
// 监听音频处理器每次处理的样本帧
node.port.onmessage= (evt) => {
//注: 声轨(声道)的数量是 取决于 当前播放的视音频本身有的声轨(声道)!!
const [l, r, sl, sr, ...more] = evt.data;
// 声轨1(左声道)样本帧数据
console.log('左声道样本帧数据:', l);
// 声轨2(右声道)样本帧数据
console.log('右声道样本帧数据:', r);
// 声轨3(左环绕声道)样本帧数据
console.log('左环绕声道样本帧数据:', sl);
// 声轨4(右环绕声道)样本帧数据
console.log('右环绕声道样本帧数据:', sr);
// 其他更多声轨
console.log('其他更多声道样本帧数据:', more);
};
可以通过添加本地的视频 或 音频文件,来测试对应的声道,并实时的渲染到响度跳表中,需要注意的是,音频峰值电平跳表从-60开始的原因主要是,当输出音量接近满载时,THD(总谐波失真)的表现会比较差,此时产生的谐波会盖掉原本存在的背景噪音,影响到测试成绩。因此,采用-60dB的测试信号。
音频峰值电平跳表值:通常在-60dB到+3dB之间。在音频设备测试中,跳表值反映了设备的频率响应和增益。不同的音频设备可能会有不同的跳表值范围,根据测试标准和设备要求而定,更多相关标准和算法从这里 ITU R-REC-BS.1770 获得了解。
为了能在项目上提高开发效率,我将其封装发布至Npm上,在我们Web前端常用的开发框架(如:Vue.js,React.js,Angular.js等)中,使用Npm命令直接下载安装即可:
Npm安装命令:
npm i @muguilin/web-audio-track
Yarn安装命令:
yarn add @muguilin/web-audio-track