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

Chrome扩展录制屏幕与麦克风时出现DOMException: Failed due to shutdown错误

错误根因
  • 违反Chrome媒体权限调用规则:你的逻辑是页面加载后content.js自动发起麦克风权限请求,申请成功后直接触发background.js自动调用getUserMedia,整个流程没有任何用户主动交互(比如点击按钮)作为触发前提,Chrome会直接拦截这类无用户交互的媒体访问请求,抛出DOMException: Failed due to shutdown错误。
  • 逻辑链路不完整:你当前的background.js仅处理了content.js发送的success消息,完全没有适配popup点击发送的start/stop控制消息,录制逻辑和用户操作完全脱节。
  • 缺失必要权限:manifest.json中未声明audioCapture麦克风捕获权限,权限不足也会导致媒体请求被拦截。
  • 冗余的重复调用:content.js已经完成权限申请的前提下,background.js无需重复发起相同的getUserMedia请求,额外增加了异常概率。
解决方案

1. 修改manifest.json补充权限

在permissions数组中新增麦克风捕获权限,同时补上缺失的popup入口配置:

{
    "name": "My Recorer",
    "version": "1.0",
    "manifest_version": 2,
    "background": {
        "scripts": ["background.js"],
        "persistent": true
    },
    "browser_action": {
        "default_popup": "popup.html",
        "default_icon": "test.png"
    },
    "commands": {
        "run-foo": {
            "suggested_key": {
                "default": "Ctrl + Shift + Y",
                "mac": "Command+Shift+Y"
            },
            "description": "Run \"foo\" on the current page."
        },
        "_execute_action": {
            "suggested_key": {
                "default": "Ctrl + Shift + Y",
                "mac": "Command+Shift+Y"
            }
        }
    },
    "permissions": [
        "activeTab",
        "clipboardWrite",
        "declarativeContent",
        "storage",
        "tabs",
        "tabCapture",
        "desktopCapture",
        "alarms",
        "downloads",
        "audioCapture",
        "<all_urls>"
    ]
}

2. 删除content.js的自动请求逻辑

直接删除content.js中原有的自动调用getUserMedia的代码,避免无交互的权限请求触发拦截。如果后续需要注入页面逻辑可以保留content.js文件,但不要在页面加载时自动发起媒体请求。

3. 重写background.js逻辑

将媒体请求和录制逻辑全部绑定到popup点击触发的消息回调中,同时支持屏幕+麦克风音频合并录制:

var screenRecorder = null;
var screenChunks = [];
let micStream = null;

chrome.runtime.onMessage.addListener(gotMessage);

async function gotMessage(message) {
   if(message.from === 'start') {
      try {
        // popup点击属于合法用户交互,此时调用getUserMedia不会被拦截
        micStream = await navigator.mediaDevices.getUserMedia({
          audio: { echoCancellation: true }
        });
        // 获取当前标签页的屏幕流,可根据需求替换为desktopCapture录全屏
        const screenStream = await chrome.tabCapture.capture({
          audio: true,
          video: true
        });
        // 合并麦克风音频和屏幕音频
        const combinedAudioTracks = [...screenStream.getAudioTracks(), ...micStream.getAudioTracks()];
        const combinedStream = new MediaStream([...screenStream.getVideoTracks(), ...combinedAudioTracks]);

        // 初始化录制器
        const options = { mimeType: 'video/webm;codecs=vp9,opus' };
        screenRecorder = new MediaRecorder(combinedStream, options);
        screenChunks = [];
        
        screenRecorder.ondataavailable = (event) => {
          if (event.data.size > 0) screenChunks.push(event.data);
        };

        screenRecorder.onstop = () => {
          // 释放流资源
          micStream.getTracks().forEach(track => track.stop());
          screenStream.getTracks().forEach(track => track.stop());
          
          const resultBlob = new Blob(screenChunks, { type: 'video/webm' });
          const url = URL.createObjectURL(resultBlob);
          // 自带下载逻辑可直接使用
          chrome.downloads.download({
            url: url,
            filename: `录制文件_${Date.now()}.webm`
          });
        };

        screenRecorder.start();
      } catch (e) {
        console.error('录制初始化失败', e);
      }
   } else if (message.from === 'stop') {
      if (screenRecorder && screenRecorder.state !== 'inactive') {
        screenRecorder.stop();
      }
   }
}

4. 保留原popup.js逻辑即可

原有的popup按钮点击发消息的逻辑不需要修改,已经可以和新的background逻辑适配。

修改后所有媒体请求都在用户点击popup按钮的交互上下文触发,完全符合Chrome的权限规则,不会再触发对应错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 00:09:03