5.4 音量检测
用户的麦克风等硬件设备有时可能无法使用,这时就需要一些检测手段来检测其设备使用状况。音量检测是一个有效的办法,通过观察音量值是否大于0,可以判断此麦克风是否正常。接下来了解一下HTML5有关音频处理的重要接口AudioContext。
AudioContext是一个专门用于音频处理的接口,工作原理是将AudioContext创建出来的各种节点(AudioNode)相互连接,音频数据流经这些节点并作出相应处理。AudioContext可以控制它所包含节点的音频处理、解码操作的执行。做任何事情之前都要先创建AudioContext对象,因为一切都发生在这个环境之中。
接下来通过一个示例来详细阐述如何检测并展示麦克风音量。具体步骤如下。
步骤1 打开h5-samples工程下的src目录,添加volume文件夹,同时添加AudioVolume.jsx及soundmeter.js文件。其中soundmeter.js为一个音频处理的第三方库,用于测算音量值。
步骤2 创建AudioContext对象,由于浏览器兼容性问题,我们需要为不同浏览器配置AudioContext,在这里可以用下面这个表达式来统一对AudioContext的访问。
//AudioContext用于管理和播放所有声音 window.AudioContext = window.AudioContext || window.webkitAudioContext; //实例化AudioContext window.audioContext = new AudioContext();
步骤3 实例化SoundMeter对象,将window.audioContext传给SoundMeter,用于进行声音音量测算。代码如下所示。
soundMeter = window.soundMeter = new SoundMeter(window.audioContext);
步骤4 根据约束条件调用getUserMedia()方法,把返回的音频流与SoundMeter对象连接起来。处理代码大致如下所示。
handleSuccess = (stream) => { ... //将声音测量对象与流连接起来 soundMeter.connectToSource(stream); //开始实时读取音量值 ... }
步骤5 每隔100毫秒读取一次SoundMeter里测量的音量值,再乘以一个系数,可以得到音量条的宽度,然后界面部分根据这个宽度值动态改变div宽度。处理过程大致如下所示。
//音频音量处理 soundMeterProcess = () => { //读取音量值,再乘以一个系数,可以得到音量条的宽度 ... //设置音量值状态 ... //每隔100毫秒调用一次soundMeterProcess函数,模拟实时检测音频音量 ... }
这里设置成100毫秒的作用就是让音量检测达到每秒10次,这样你可以通过肉眼观察到音量条动态变化的过程,即一闪一闪的效果。
步骤6 在页面渲染部分添加一个特殊的div标签用于展示音量的变化情况,然后在src目录下的App.jsx及Samples.jsx里加上链接及路由绑定,这可参考第3章。完整的代码如下所示。
import React from "react"; import SoundMeter from './soundmeter'; //定义音量测算对象 let soundMeter; /** * 音频音量检测示例 */ class AudioVolume extends React.Component { constructor(props) { super(props) this.state = { //音量值 audioLevel: 0, } } componentDidMount() { try { //AudioContext用于管理和播放所有的声音 window.AudioContext = window.AudioContext || window.webkitAudioContext; //实例化AudioContext window.audioContext = new AudioContext(); } catch (e) { console.log('网页音频API不支持。'); } //SoundMeter声音测量,用于进行声音音量测算 soundMeter = window.soundMeter = new SoundMeter(window.audioContext); const constraints = window.constraints = { //启用音频 audio: true, //禁用视频 video: false }; //根据约束条件获取媒体 navigator.mediaDevices.getUserMedia(constraints).then(this.handleSuccess). catch(this.handleError); } //获取媒体成功 handleSuccess = (stream) => { window.stream = stream; //将声音测量对象与流连接起来 soundMeter.connectToSource(stream); //开始实时读取音量值 setTimeout(this.soundMeterProcess, 100); } //音频音量处理 soundMeterProcess = () => { //读取音量值,再乘以一个系数,可以得到音量条的宽度 var val = (window.soundMeter.instant.toFixed(2) * 348) + 1; //设置音量值状态 this.setState({ audioLevel: val }); //每隔100毫秒调用一次soundMeterProcess函数,模拟实时检测音频音量 setTimeout(this.soundMeterProcess, 100); } //错误处理 handleError(error) { console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name); } render() { return ( <div className="container"> <h1> <span>音量检测示例</span> </h1> {/* 这是使用了一个div来作为音量条的展示,高度固定,宽度根据音量值来动态变化 */} <div style={{ width: this.state.audioLevel + 'px', height: '10px', backgroundColor: '#8dc63f', marginTop: '20px', }}> </div> </div> ); } } //导出组件 export default AudioVolume;
运行程序后,对着麦克风说话可以看到音量条一闪一闪的,表示你的麦克风可以使用,运行效果如图5-2所示。
图5-2 音量检测效果图