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();
            });
        }
    },
}
相关推荐
奔跑的呱呱牛18 分钟前
geojson-to-wkt 坐标格式转换
javascript·arcgis
C_心欲无痕30 分钟前
Docker 本地部署 CSR 前端项目完整指南
前端·docker·容器
康一夏1 小时前
React面试题,封装useEffect
前端·javascript·react.js
Full Stack Developme1 小时前
Redis 持久化 备份 还原
前端·chrome
猪猪拆迁队2 小时前
2025年终总结-都在喊前端已死,这一年我的焦虑、挣扎与重组:AI 时代如何摆正自己的位置
前端·后端·ai编程
❆VE❆2 小时前
WebSocket与SSE深度对比:技术差异、场景选型及一些疑惑
前端·javascript·网络·websocket·网络协议·sse
ConardLi2 小时前
SFT、RAG 调优效率翻倍!垂直领域大模型评估实战指南
前端·javascript·后端
rgeshfgreh2 小时前
Java高性能开发:Redis7持久化实战
前端·bootstrap·mybatis
李剑一2 小时前
uni-app使用html5+创建webview,可以控制窗口大小、显隐、与uni通信
前端·trae
Hooray3 小时前
2026年,站在职业生涯十字路口的我该何去何从?
前端·后端