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

Chrome音频录制扩展无法捕获Google Meet麦克风音频,需实现扬声器与麦克风音频分文件录制

Chrome音频录制扩展无法捕获Google Meet麦克风音频,需实现扬声器与麦克风音频分文件录制

看起来你现在的核心问题是:现有扩展能捕获Chrome标签页的扬声器输出,但拿不到Google Meet里的麦克风音频,还得把两个音频流分别存成mic.wav和speaker.wav对吧?我来给你拆解下修改步骤,都是针对Manifest V3扩展的实操方案:

第一步:补全扩展权限(必须先改这个)

你的manifest.json里现在的权限不够,要捕获标签页音频和本地麦克风,得加上两个关键权限:

  • tabCapture:专门用于捕获Chrome标签页的音频/视频流
  • audioCapture:用于获取本地麦克风的音频权限

修改后的权限部分大概是这样:

"permissions": ["offscreen", "contextMenus", "activeTab", "tabCapture", "audioCapture"]

第二步:拆分音频捕获逻辑(核心改动)

之前你应该是只捕获了标签页的音频流,但Google Meet的麦克风是本地输入设备,和标签页输出流是两个独立的媒体流,得分开捕获:

  • 标签页扬声器流:用chrome.tabCapture.capture获取,对应Meet里的其他参与者声音+系统播放的音频
  • 本地麦克风流:用navigator.mediaDevices.getUserMedia获取,对应你自己的麦克风输入

具体逻辑(放到Offscreen文档里,因为Manifest V3不允许在Popup直接处理媒体流)

在你的offscreen.js里,要维护两个独立的录制实例和数据缓存:

// 初始化两个录制器和缓存数组
let speakerRecorder = null;
let micRecorder = null;
let speakerAudioChunks = [];
let micAudioChunks = [];

// 监听Popup发来的消息
chrome.runtime.onMessage.addListener(async (msg, sender, sendResp) => {
  if (msg.action === "start-recording") {
    // 1. 捕获标签页扬声器音频
    try {
      const tabAudioStream = await chrome.tabCapture.capture({
        audio: true,
        video: false,
        audioConstraints: {
          // 关闭回声消除和降噪,避免影响原始音频
          echoCancellation: false,
          noiseSuppression: false,
          autoGainControl: false
        }
      });
      // 初始化扬声器录制器
      speakerRecorder = new MediaRecorder(tabAudioStream, { mimeType: "audio/wav" });
      speakerRecorder.ondataavailable = (e) => {
        if (e.data.size > 0) speakerAudioChunks.push(e.data);
      };
      speakerRecorder.onstop = () => {
        // 生成扬声器音频Blob,发给Popup下载
        const speakerBlob = new Blob(speakerAudioChunks, { type: "audio/wav" });
        chrome.runtime.sendMessage({ action: "download-speaker", blob: speakerBlob });
        speakerAudioChunks = []; // 清空缓存
      };
      speakerRecorder.start();
    } catch (err) {
      console.error("捕获标签页音频失败:", err);
    }

    // 2. 捕获本地麦克风音频
    try {
      const micAudioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
      // 初始化麦克风录制器
      micRecorder = new MediaRecorder(micAudioStream, { mimeType: "audio/wav" });
      micRecorder.ondataavailable = (e) => {
        if (e.data.size > 0) micAudioChunks.push(e.data);
      };
      micRecorder.onstop = () => {
        // 生成麦克风音频Blob,发给Popup下载
        const micBlob = new Blob(micAudioChunks, { type: "audio/wav" });
        chrome.runtime.sendMessage({ action: "download-mic", blob: micBlob });
        micAudioChunks = []; // 清空缓存
      };
      micRecorder.start();
    } catch (err) {
      console.error("捕获麦克风音频失败:", err);
    }
  } else if (msg.action === "stop-recording") {
    // 停止两个录制器并释放流资源
    if (speakerRecorder && speakerRecorder.state !== "inactive") {
      speakerRecorder.stop();
      speakerRecorder.stream.getTracks().forEach(track => track.stop());
    }
    if (micRecorder && micRecorder.state !== "inactive") {
      micRecorder.stop();
      micRecorder.stream.getTracks().forEach(track => track.stop());
    }
  }
});

第三步:修改Popup的下载逻辑

在你的popup.js里,要监听Offscreen发来的Blob数据,分别触发下载:

chrome.runtime.onMessage.addListener((msg, sender, sendResp) => {
  // 处理扬声器音频下载
  if (msg.action === "download-speaker") {
    const url = URL.createObjectURL(msg.blob);
    const downloadLink = document.createElement("a");
    downloadLink.href = url;
    downloadLink.download = "speaker.wav";
    downloadLink.click();
    URL.revokeObjectURL(url); // 释放资源
  }
  // 处理麦克风音频下载
  else if (msg.action === "download-mic") {
    const url = URL.createObjectURL(msg.blob);
    const downloadLink = document.createElement("a");
    downloadLink.href = url;
    downloadLink.download = "mic.wav";
    downloadLink.click();
    URL.revokeObjectURL(url);
  }
});

第四步:添加权限请求逻辑

第一次使用时,用户需要授予扩展捕获音频的权限,所以在Popup的开始录制按钮点击事件里,要先检查并请求权限:

async function requestNecessaryPermissions() {
  const requiredPermissions = {
    permissions: ["tabCapture", "audioCapture"]
  };
  const isGranted = await chrome.permissions.request(requiredPermissions);
  if (!isGranted) {
    alert("必须授予音频捕获权限才能进行录制哦");
    return false;
  }
  return true;
}

// 绑定到开始录制按钮的点击事件
document.getElementById("start-btn").addEventListener("click", async () => {
  const hasPermissions = await requestNecessaryPermissions();
  if (!hasPermissions) return;
  // 确保Offscreen文档已打开
  await chrome.offscreen.createDocument({
    url: "offscreen.html",
    reasons: ["AUDIO_CAPTURE"],
    justification: "录制标签页和麦克风音频"
  });
  // 发送开始录制消息给Offscreen
  chrome.runtime.sendMessage({ action: "start-recording" });
  // 这里可以更新图标为录制中状态
});

额外注意点

  1. 音频格式兼容:如果你的Chrome版本不支持audio/wav作为MediaRecorder的MIME类型,可以先用audio/webm录制,之后再转成WAV格式(需要额外写转码逻辑,比如用AudioContext提取原始PCM数据,再拼接WAV文件头)
  2. Offscreen文档生命周期:录制过程中不要关闭Popup,否则Offscreen文档可能会被销毁,导致录制中断
  3. Google Meet的特殊情况:tabCapture捕获的是标签页的输出音频,也就是Meet里混合后的所有声音(包括其他参与者和系统提示音),而getUserMedia捕获的是你本地麦克风的原始输入,完全分开,符合你的需求

备注:内容来源于stack exchange,提问作者Deshwal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 13:03:01