Gravação de áudio e captura de tela

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

Gravação de tela

Para gravação de tela, chame getDisplayMedia(), que aciona a caixa de diálogo mostrada abaixo. Isso permite que o usuário selecione qual guia, janela ou tela ele quer compartilhar e indica claramente que a gravação está em andamento.

Caixa de diálogo de compartilhamento de tela para example.com
Caixa de diálogo de compartilhamento de tela para 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 for chamado em 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 em várias navegações, use um documento fora da tela com o motivo DISPLAY_MEDIA.

Captura de guias 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 em uma guia específica, e você quer começar a capturar a guia imediatamente sem essa solicitação.

Gravar áudio e vídeo em segundo plano

A partir do Chrome 116, é possível chamar a API browser.tabCapture em um service worker para receber um ID de stream após um gesto do usuário. Em seguida, ele pode ser transmitido a um documento fora da tela para iniciar a gravação.

No service worker:

browser.action.onClicked.addListener(async (tab) => {
  const existingContexts = await browser.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 browser.offscreen.createDocument({
      url: 'offscreen.html',
      reasons: ['USER_MEDIA'],
      justification: 'Recording from browser.tabCapture API',
    });
  }

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

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

Em seguida, no documento offscreen:

browser.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 record the MediaStream.
  }
});

Para um exemplo completo, consulte a amostra 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 browser.tabCapture em um service worker nem consumir um ID de stream criado por essa API em um documento invisível. Ambos são requisitos para a abordagem acima.

Em vez disso, abra uma página de extensão em uma nova guia ou janela e acesse uma transmissão diretamente. Defina a propriedade targetTabId para capturar a guia correta.

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

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

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

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

Outra opção é 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 para gravar.

Gravar áudio em um pop-up

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

browser.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ê precisar 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 um stream, consulte a API MediaRecorder.