录音和屏幕截图

本指南介绍了使用 chrome.tabCapturegetDisplayMedia() 等 API 从标签页、窗口或屏幕中录制音频和视频的不同方法。

屏幕录制

对于屏幕录制,请调用 getDisplayMedia(),这会触发如下所示的对话框。这让用户能够选择他们要分享的标签页、窗口或屏幕,并清晰地指示正在进行录制。

example.com 的屏幕共享对话框
example.com 的屏幕共享对话框。

以下示例请求录制音频和视频的权限。

const stream = await navigator.mediaDevices.getDisplayMedia({ audio: true, video: true });

如果在内容脚本中调用,则当用户导航到新页面时,录制会自动结束。如需在后台和导航中录音,请使用包含 DISPLAY_MEDIA 原因的屏幕外文档

基于用户手势捕获标签页

调用 getDisplayMedia() 会在浏览器中显示一个对话框,询问用户想要分享什么内容。但在某些情况下,用户只需点击操作按钮即可针对特定标签页调用扩展程序,而您希望立即开始捕获该标签页,而不显示此提示。

在后台录制音频和视频

从 Chrome 116 开始,您可以在 Service Worker 中调用 chrome.tabCapture API,以便在用户手势后获取数据流 ID。然后,可以将这些内容传递到屏幕外文档以开始录制。

在您的 Service Worker 中:

chrome.action.onClicked.addListener(async (tab) => {
  const existingContexts = await chrome.runtime.getContexts({});

  const offscreenDocument = existingContexts.find(
    (c) => c.contextType === 'OFFSCREEN_DOCUMENT'
  );

  // If an offscreen document is not already open, create one.
  if (!offscreenDocument) {
    // Create an offscreen document.
    await chrome.offscreen.createDocument({
      url: 'offscreen.html',
      reasons: ['USER_MEDIA'],
      justification: 'Recording from chrome.tabCapture API',
    });
  }

  // Get a MediaStream for the active tab.
  const streamId = await chrome.tabCapture.getMediaStreamId({
    targetTabId: tab.id
  });

  // Send the stream ID to the offscreen document to start recording.
  chrome.runtime.sendMessage({
    type: 'start-recording',
    target: 'offscreen',
    data: streamId
  });
});

然后,在屏幕外文档中执行以下操作:

chrome.runtime.onMessage.addListener(async (message) => {
  if (message.target !== 'offscreen') return;
  
  if (message.type === 'start-recording') {
    const media = await navigator.mediaDevices.getUserMedia({
      audio: {
        mandatory: {
          chromeMediaSource: "tab",
          chromeMediaSourceId: message.data,
        },
      },
      video: {
        mandatory: {
          chromeMediaSource: "tab",
          chromeMediaSourceId: message.data,
        },
      },
    });

    // Continue to play the captured audio to the user.
    const output = new AudioContext();
    const source = output.createMediaStreamSource(media);
    source.connect(output.destination);

    // TODO: Do something to recording the MediaStream.
  }
});

如需查看完整示例,请参阅标签页捕获 - 记录器示例。

在新标签页中录制音频和视频

在 Chrome 116 之前,您无法在 Service Worker 中使用 chrome.tabCapture API,也无法在屏幕外文档中使用该 API 创建的数据流 ID。上述两个要求都是对上述方法的要求。

不过,您可以在新标签页或窗口中打开扩展程序页面,然后直接获取数据流。设置 targetTabId 属性以捕获正确的标签页。

首先打开一个扩展程序页面(可能是在弹出式窗口或 Service Worker 中):

chrome.windows.create({ url: chrome.runtime.getURL("recorder.html") });

然后,在您的扩展程序页面中执行以下操作:

chrome.tabCapture.getMediaStreamId({ targetTabId: tabId }, async (id) => {
  const media = await navigator.mediaDevices.getUserMedia({
    audio: {
      mandatory: {
        chromeMediaSource: "tab",
        chromeMediaSourceId: id,
      },
    },
    video: {
      mandatory: {
        chromeMediaSource: "tab",
        chromeMediaSourceId: id,
      },
    },
  });

  // Continue to play the captured audio to the user.
  const output = new AudioContext();
  const source = output.createMediaStreamSource(media);
  source.connect(output.destination);
});

或者,考虑使用屏幕录制方法,该方法允许您使用屏幕外文档在后台进行录制,但会向用户显示一个对话框,供其选择要从哪个标签页、窗口或屏幕中进行录制。

在弹出式窗口中录制音频

如果您只需要录制音频,可以使用 chrome.tabCapture.capture 直接在扩展程序弹出式窗口中获取流。关闭弹出式窗口后,系统即会停止录制。

chrome.tabCapture.capture({ audio: true }, (stream) => {
  // Continue to play the captured audio to the user.
  const output = new AudioContext();
  const source = output.createMediaStreamSource(stream);
  source.connect(output.destination);

  // TODO: Do something with the stream (e.g record it)
});

如果您需要在导航后保留记录,请考虑使用上一部分中介绍的方法。

其他注意事项

如需详细了解如何录制音频流,请参阅 MediaRecorder API。