WebRtc实时音波

摘要:

最近在做音视频相关业务,用的到了webRtc技术,掌握这些方法可以结合业务做,麦克风检测、录制音频,都是可以的;基本操作和其它方法都写好在methods中了;

全局变量
typescript 复制代码
// 后续会创建AnalyserNode对象
let analyser: any = null;
// 后续赋值canvas标签对象
let canvas: any = null;
// canvas 2d对象
let canvasCtx: any = null;
let audioSteam: any = { // 获取音视频MediaStream对象
    current: null
}
HTML
html 复制代码
<div>
    // 绘制音波
    <canvas id="devDetectionMicroCanvas" className={style.audio_canvas}></canvas>
    // 实时播放
    <audio id="devDetectionMicroRef" autoPlay></audio>
</div>
获取音视频流
typescript 复制代码
// 使用getUserMedia API获取音频流。
navigator.mediaDevices.getUserMedia({
    audio: true
}).then(stream => {
    /* MediaStream赋值到全局对象,后续使用 */
    audioSteam.current = stream;
    /* 获取当前采集设备名称 */
    methods.handleStreamGetMicroName();
    /* 把媒体流赋值给audio标签进行试试播放 */
    methods.handleAudioPlay();
    /* 开始准备制作试试音波 */
    methods.handleCanvasAudioContext();
})
.catch(error => {
    let errorMessage = error + '';
    if (errorMessage.includes('Permission denied')) {
        errorMessage = '请开启麦克风权限';
    } else if (errorMessage.includes('Requested device not found')) {
        errorMessage = '请检测麦克风是否插入';
    };
    console.log('error', errorMessage)
});
其它方法
typescript 复制代码
const methods = {
    // 处理canvas和audioContext
    handleCanvasAudioContext() {
         // 1. 使用AudioContext API创建一个AudioContext对象,并将音频流添加到它上面
        const audioContext = new AudioContext();
        const source = audioContext.createMediaStreamSource(stream);
        // 2. 创建AnalyserNode对象,并将其连接到source节点。
        analyser = audioContext.createAnalyser();
        source.connect(analyser);
        // 3. 获取实时音频数据并将其转换为可视化数据。例如,可以使用getByteTimeDomainData()方法获取时域数据,并将其转换为音波。
        canvas = document.getElementById("devDetectionMicroCanvas");
        canvasCtx = canvas.getContext("2d");
        // 4.启动波纹动画
        methods.drawWaveform();
    },
    // 波纹动画
    drawWaveform() {
        const stream = audioSteam.current;
        // 获取时域数据
        const dataArray = new Uint8Array(analyser.fftSize);
        analyser.getByteTimeDomainData(dataArray);

        // 绘制音波
        canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
        canvasCtx.lineWidth = 2;
        canvasCtx.strokeStyle = "rgb(69, 255, 56)";
        canvasCtx.beginPath();
        const sliceWidth = canvas.width * 1.0 / analyser.fftSize;
        let x = 0;
        for(let i = 0; i < analyser.fftSize; i++) {
            const v = dataArray[i] / 128.0;
            const y = v * canvas.height / 2;
            if(i === 0) {
                canvasCtx.moveTo(x, y);
            } else {
                canvasCtx.lineTo(x, y);
            }
            x += sliceWidth;
        }
        canvasCtx.stroke();
        requestAnimationFrame(methods.drawWaveform);
    },
    // 获取采集设备名称
    handleStreamGetMicroName(){
        if (audioSteam.current) {
            const audioTrack = audioSteam.current.getAudioTracks()[0];
            // audioTrack.label;
            console.log('当前采集设备名称', audioTrack.label);
        }
    },
    // 处理audio播放
    handleAudioPlay() {
        const stream = audioSteam.current;
        const elm: HTMLVideoElement | any = document.getElementById('devDetectionMicroRef');
        if (elm) {
            elm.srcObject = stream;
        }
    },
    // 停止麦克采集
    stopAudioSteam() {
        if (audioSteam.current) {
            audioSteam.current.getTracks().forEach((sender: any) => {
                sender.stop();
            });
        }
    },
}
相关推荐
古时的风筝1 分钟前
花10 分钟时间,把终端改造成“生产力武器”:Ghostty + Yazi + Lazygit 配置全流程
前端·后端·程序员
Cache技术分享2 分钟前
340. Java Stream API - 理解并行流的额外开销
前端·后端
我叫黑大帅13 分钟前
前端如何利用 GitHub Actions 自动构建并发布到 GitHub Pages?
前端·面试·github
smallLabel17 分钟前
记一次 OpenClaw 飞书插件接入填坑指南: Error: spawn EINVAL
前端
zzjyr19 分钟前
react前端项目 fetch原生 与 umijs request 四种请求区别
前端
我叫黑大帅19 分钟前
前端总说的防抖与节流到底是什么?
前端·javascript·面试
小时前端20 分钟前
微信小程序选不了本地文件?用 web-view + H5 一招搞定
前端·微信小程序·uni-app
71Ove20 分钟前
告别手写字符串!UniApp 路由全自动类型生成工具
前端
掘金安东尼22 分钟前
从平面到空间:用 React Three Fiber 构建 3D 产品网格
前端·javascript·面试
小时前端22 分钟前
HTTPS 页面加载 HTTP 脚本被拦?同源代理来救场
前端·https