OiO.lk Blog javascript Audio Recording Javascript Chrome extension working with Youtube but not working on Google Meet Mic to record audio
javascript

Audio Recording Javascript Chrome extension working with Youtube but not working on Google Meet Mic to record audio


I have fully working code which starts, stop recording audio from a tab. It also plays and download the most recent recorded audio. I tested it both Youtube and Google Meet. It captures the speaker output but when I try to capture mic audio from Google Meet, it fails. What should I be modifying in the code so that it captures both mic as well speaker audio?

Manifest.json

{
  "name": "Tab Capture - Recorder",
  "description": "Records the current tab in an offscreen document.",
  "version": "1",
  "manifest_version": 3,
  "minimum_chrome_version": "116",
  "action": {
    "default_popup": "popup.html",
    "default_icon": "not-recording.png"
  },
  "permissions": ["tabCapture", "offscreen", "storage", "contextMenus"]
}

offscreen.js

chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
  if (message.target === 'offscreen') {
    switch (message.type) {
      case 'start-recording':
        startRecording(message.data);
        break;
      case 'stop-recording':
        stopRecording();
        break;
      case 'play-audio':
        playAudio();
        break;
      case 'download-audio':
        downloadAudio();
        break;
      default:
        throw new Error('Unrecognized message:', message.type);
    }
  } else if (message.type === 'check-audio') {
    sendResponse({ audioAvailable: audioBlobs.length > 0 });
    return true;
  }
});

let recorder;
let data = [];
let audioBlobs = []; // Array to store audio blobs

async function startRecording(streamId) {
  if (recorder?.state === 'recording') {
    throw new Error('Called startRecording while recording is in progress.');
  }

  const media = await navigator.mediaDevices.getUserMedia({ 
    audio: {
      mandatory: {
        chromeMediaSource: 'tab',
        chromeMediaSourceId: streamId
      }
    }
  });

  const output = new AudioContext();
  const source = output.createMediaStreamSource(media);
  source.connect(output.destination);

  recorder = new MediaRecorder(media, { mimeType: 'audio/webm' });
  recorder.ondataavailable = (event) => data.push(event.data);
  recorder.onstop = () => {
    const blob = new Blob(data, { type: 'audio/webm' });
    audioBlobs.push(blob); // Store the blob in the array
    data = [];
  };
  recorder.start();

  window.location.hash="recording";
}

async function stopRecording() {
  recorder.stop();
  recorder.stream.getTracks().forEach((t) => t.stop());
  window.location.hash="";
}

function playAudio() {
  if (audioBlobs.length > 0) {
    const lastBlob = audioBlobs[audioBlobs.length - 1];
    const audioUrl = URL.createObjectURL(lastBlob);
    const audio = new Audio(audioUrl);
    audio.play();
  } else {
    console.error('No audio available to play.');
  }
}

function downloadAudio() {
  if (audioBlobs.length > 0) {
    const lastBlob = audioBlobs[audioBlobs.length - 1];
    const audioUrl = URL.createObjectURL(lastBlob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = audioUrl;
    a.download = 'recording.webm';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  } else {
    console.error('No audio available to download.');
  }
}

popup.js

document.addEventListener('DOMContentLoaded', () => {
  const isRecording = localStorage.getItem('isRecording') === 'true';

  document.getElementById('startButton').disabled = isRecording;
  document.getElementById('stopButton').disabled = !isRecording;

  // Check if there are any audio recordings stored
  chrome.runtime.sendMessage({ type: 'check-audio' }, (response) => {
    const audioAvailable = response.audioAvailable;
    document.getElementById('playButton').disabled = !audioAvailable;
    document.getElementById('downloadButton').disabled = !audioAvailable;
  });
});

document.getElementById('startButton').addEventListener('click', async () => {
  document.getElementById('startButton').disabled = true;
  document.getElementById('stopButton').disabled = false;
  document.getElementById('playButton').disabled = true;
  document.getElementById('downloadButton').disabled = true;

  localStorage.setItem('isRecording', 'true');

  const existingContexts = await chrome.runtime.getContexts({});
  let offscreenDocument = existingContexts.find(
    (c) => c.contextType === 'OFFSCREEN_DOCUMENT'
  );

  if (!offscreenDocument) {
    await chrome.offscreen.createDocument({
      url: 'offscreen.html',
      reasons: ['USER_MEDIA'],
      justification: 'Recording from chrome.tabCapture API'
    });
  }

  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  const streamId = await chrome.tabCapture.getMediaStreamId({ targetTabId: tab.id });

  chrome.runtime.sendMessage({
    type: 'start-recording',
    target: 'offscreen',
    data: streamId
  });
});

document.getElementById('stopButton').addEventListener('click', () => {
  document.getElementById('startButton').disabled = false;
  document.getElementById('stopButton').disabled = true;

  chrome.runtime.sendMessage({
    type: 'stop-recording',
    target: 'offscreen'
  }, () => {
    chrome.runtime.sendMessage({ type: 'check-audio' }, (response) => {
      const audioAvailable = response.audioAvailable;
      document.getElementById('playButton').disabled = !audioAvailable;
      document.getElementById('downloadButton').disabled = !audioAvailable;
    });
  });

  localStorage.setItem('isRecording', 'false');
});

document.getElementById('playButton').addEventListener('click', () => {
  chrome.runtime.sendMessage({
    type: 'play-audio',
    target: 'offscreen'
  });
});

document.getElementById('downloadButton').addEventListener('click', () => {
  chrome.runtime.sendMessage({
    type: 'download-audio',
    target: 'offscreen'
  });
});



You need to sign in to view this answers

Exit mobile version