Gravação de áudio e captura de tela

Este guia explica as diferentes abordagens para gravar áudio e vídeo de uma guia, janela ou tela usando APIs como chrome.tabCapture ou getDisplayMedia().

Gravação de tela

Para gravação de tela, chame getDisplayMedia(), que aciona a caixa de diálogo mostrada abaixo. Isso fornece ao usuário a capacidade de selecionar qual guia, janela ou tela ele quer compartilhar e fornece uma indicação clara de que a gravação está ocorrendo.

Caixa de diálogo de compartilhamento de tela de example.com
Caixa de diálogo de compartilhamento de tela de example.com.

O exemplo a seguir solicita acesso para gravar áudio e vídeo.

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

Se chamada dentro de um script de conteúdo, a gravação será encerrada automaticamente quando o usuário navegar para uma nova página. Para gravar em segundo plano e nas navegações, use um documento fora da tela com o motivo DISPLAY_MEDIA.

Captura de guia com base no gesto do usuário

Chamar getDisplayMedia() faz com que o navegador mostre uma caixa de diálogo perguntando ao usuário o que ele quer compartilhar. No entanto, em alguns casos, o usuário acabou de clicar no botão de ação para invocar sua extensão para uma guia específica, e você quer começar a capturar a guia imediatamente sem essa solicitação.

Grave áudio e vídeo em segundo plano

A partir do Chrome 116, é possível chamar a API chrome.tabCapture em um service worker para receber um ID de stream após o gesto do usuário. Essa informação pode ser transmitida para um documento fora da tela para começar a gravação.

No 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
  });
});

Em seguida, no documento fora da tela:

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.
  }
});

Para ver um exemplo completo, consulte o exemplo Captura de guia - Gravador.

Gravar áudio e vídeo em uma nova guia

Antes do Chrome 116, não era possível usar a API chrome.tabCapture em um service worker ou consumir um ID de stream criado por essa API em um documento fora da tela. Ambos são requisitos da abordagem acima.

Em vez disso, é possível abrir uma página de extensão em uma nova guia ou janela e acessar um stream diretamente. Defina a propriedade targetTabId para capturar a guia correta.

Comece abrindo uma página de extensão (talvez no pop-up ou no service worker):

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

Em seguida, na página da extensão:

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);
});

Como alternativa, você pode usar a abordagem de gravação de tela, que permite gravar em segundo plano usando um documento fora da tela, mas mostra ao usuário uma caixa de diálogo para selecionar uma guia, janela ou tela de gravação.

Gravar áudio em um pop-up

Se você só precisa gravar áudio, pode acessar um stream diretamente no pop-up da extensão usando chrome.tabCapture.capture. Quando o pop-up for fechado, a gravação será interrompida.

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)
});

Se você precisa que a gravação persista em várias navegações, use a abordagem descrita na seção anterior.

Outras considerações

Para mais informações sobre como gravar uma transmissão, consulte a API MediaRecorder.