WebRTC音视频开发:React+Flutter+Go实战
上QQ阅读APP看书,第一时间看更新

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 音量检测效果图