Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getting `DOMException: Failed due to shutdown` when trying to record stream from screen+microphone

I am building an extension that records my screen and microphone audio as well.

Overview:

I have content.js which tries to get the access of navigator.mediaDevices.getUserMedia({... in the succession I send message to the background.js which again tries to access navigator.mediaDevices.getUserMedia({... over here I am recording the audio stream. In addition to this, I have popup.html which have a start button on clicking the button I am recording the screen. But in the full process I am getting the error DOMException: Failed due to shutdown.

Also, I am aware there have been questions on the above error (the famous one Chrome Extension - getUserMedia throws "NotAllowedError: Failed due to shutdown") but didn’t help me much.

content.js

navigator.mediaDevices.getUserMedia({
   audio: { echoCancellation: true }
   })
    .then((e) => { chrome.runtime.sendMessage({ from: 'success' })})
    .catch((e) => {console.log(e);});

Background.js

var recorder = null;
chrome.runtime.onMessage.addListener(gotMessage);

function gotMessage(message) {
   if(message.from === 'success') {
      navigator.mediaDevices.getUserMedia({
        audio: { echoCancellation: true }
      })
      .then((e) => { 
                var chunks = [];
                var options = {
                    mimeType: 'audio/webm',
                };
                recorder = new MediaRecorder(e, options);
                recorder.ondataavailable = function (event) {
                    if (event.data.size > 0) {
                        chunks.push(event.data);
                    }
                };
                recorder.onstop = function () {
                    var superBuffer = new Blob(chunks, {
                        type: 'audio/webm',
                    });

                    var url = URL.createObjectURL(superBuffer);
                };
                recorder.start();
      })
      .catch((e) => {console.log(e);});
}

popup.js:

let btnStartTab = document.getElementById('start');
let btnStartTab1 = document.getElementById('stop');

btnStartTab.addEventListener('click', function (event) {
    chrome.runtime.sendMessage({ from: 'start' });
});

btnStartTab1.addEventListener('click', function (event) {
    chrome.runtime.sendMessage({ from: 'stop' });
});

manifest.json

{
    "name": "My Recorer",
    "version": "1.0",
    "manifest_version": 2,
    "background": {
        "scripts": ["background.js"],
        "persistent": true
    },
    "browser_action": {
        "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",
        "activeTab",
        "downloads",
        "<all_urls>"
    ]
}


like image 913
GMAC Avatar asked Oct 28 '25 10:10

GMAC


1 Answers

After deep searching and help from SO foundation found a way to reach the solution thought of sharing.

So, we need to understand that background doesn’t have control over DOM that's why we need to take help from contentscript.js and below architecture is important :

enter image description here

  • In my case, I am injecting contentscript.js from manifest.json but one can use executescript() to inject the script.
  • contentscript.js will create an iframe with display none with iframe.src = chrome.extension.getURL('audiosources.html'); above is important!!
  • Also, audiosources.html is under web_accessible_resources in manifest.json
  • The body of above HTML will have <script src="audiosources.js"></script> only.
  • audiosources.js is the oe which will help to get rid of the error here I am getting access to navigator.mediaDevices.getUserMedia(...) and all the mic devices. here on success it will send message to background.js.
  • Now, background.js will do its magic of tabCapture with navigator.mediaDevices.getUserMedia and here we need to apply logic for merging.
like image 92
GMAC Avatar answered Oct 30 '25 01:10

GMAC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!