You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何捕获Google Meet传入音频流?已实现视频捕获求音频方案

解决Google Meet音频流捕获问题

你的代码目前只处理了首次检测到的MediaStream,但Google Meet的音频和视频可能通过独立轨道或延迟加载的方式传输,导致音频轨道未被纳入录制范围。以下是具体修正方案:

核心问题分析

  1. MediaRecorder的局限性:创建MediaRecorder时会绑定当前MediaStream的轨道集合,后续添加到该流的轨道不会被自动录制。
  2. 轨道传输时机:Google Meet的音频轨道可能晚于视频轨道到达,或作为独立轨道触发ontrack事件,你的代码未处理动态轨道添加。

修正后的代码实现

我们通过合并所有音视频轨道到一个统一的MediaStream,并动态响应轨道变化来解决问题:

// 合并所有音视频轨道的统一流
const combinedStream = new MediaStream();
// 全局录制器实例
let activeRecorder = null;
// 存储已处理的轨道ID,避免重复添加
const processedTrackIds = new Set();

// 重写setRemoteDescription拦截轨道
const originalSetRemoteDescription = RTCPeerConnection.prototype.setRemoteDescription;
RTCPeerConnection.prototype.setRemoteDescription = async function(desc) {
    const result = await originalSetRemoteDescription.call(this, desc).catch(console.error);
    
    // 监听所有 incoming tracks
    this.ontrack = (event) => {
        const track = event.track;
        // 跳过已处理的轨道
        if (processedTrackIds.has(track.id)) return;
        processedTrackIds.add(track.id);
        
        console.log(`Received ${track.kind} track: ${track.id}`);
        // 将轨道添加到合并流
        combinedStream.addTrack(track);
        
        // 启动或重启录制器(仅当无活跃录制器时)
        if (!activeRecorder || activeRecorder.state === 'inactive') {
            activeRecorder = createRecorder(combinedStream, 'meet-recording');
        }
    };
    
    // 监听轨道移除(比如用户静音/关闭摄像头)
    this.onremovetrack = (event) => {
        const track = event.track;
        processedTrackIds.delete(track.id);
        combinedStream.removeTrack(track);
    };
    
    return result;
};

// 创建录制器的函数
function createRecorder(stream, id) {
    // 指定包含音视频的MIME类型
    const options = { mimeType: 'video/webm; codecs=vp9,opus' };
    // 检查浏览器支持性
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.warn('指定格式不支持,降级为默认格式');
        delete options.mimeType;
    }
    
    const recorder = new MediaRecorder(stream, options);
    const chunks = [];
    
    recorder.ondataavailable = event => {
        if (event.data.size > 0) {
            chunks.push(event.data);
        }
    };
    
    recorder.onstop = () => {
        const blob = new Blob(chunks, { type: recorder.mimeType });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        a.download = `${id}__${new Date().toISOString().slice(0, 19)}.webm`;
        document.body.appendChild(a);
        a.click();
        
        setTimeout(() => {
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
            // 重置状态
            processedTrackIds.clear();
            activeRecorder = null;
        }, 100);
    };
    
    recorder.start();
    console.log('录制已启动');
    return recorder;
}

// 停止录制
function stopRecording() {
    if (activeRecorder && activeRecorder.state !== 'inactive') {
        activeRecorder.stop();
    }
}

关键改进点

  • 使用统一的combinedStream合并所有音视频轨道,确保录制内容完整
  • 跟踪已处理的轨道ID,避免重复添加
  • 监听onremovetrack事件,同步移除无效轨道
  • 显式指定支持音视频的MIME类型,提升兼容性

技术学习方向

  1. WebRTC基础:深入理解RTCPeerConnection的轨道传输机制、MediaStream和MediaStreamTrack的生命周期
  2. MediaRecorder API:掌握录制参数配置、格式兼容性、动态轨道处理的限制
  3. 浏览器媒体机制:了解同源策略、媒体权限、扩展脚本的上下文隔离规则
  4. 媒体处理进阶:学习轨道分离/合并、格式转码等高级操作

内容的提问来源于stack exchange,提问作者Curious66

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:58:14