Recording Mic/Audio from offscreen document

2,094 views
Skip to first unread message

Coure 2011

unread,
Dec 26, 2023, 12:48:30 AM12/26/23
to Chromium Extensions
Hi,

I am getting error "Uncaught (in promise) DOMException: Permission dismissed"
when running the code
navigator.mediaDevices.getUserMedia({ audio: true, video: true })

The above code is in index.html which is created as offscreen document
await chrome.offscreen.createDocument({
    url: 'dist/offscreen/index.html',
    reasons: ['DISPLAY_MEDIA', 'USER_MEDIA'],
    justification: 'To record tab or window or screen',
});

manifest:
permissions: ['audio', 'video']

thx



Jackie Han

unread,
Dec 26, 2023, 1:52:06 AM12/26/23
to Coure 2011, Chromium Extensions

--
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/5e6fcd3a-02e1-4f89-aeae-d766a88cb3a0n%40chromium.org.

Coure 2011

unread,
Jan 8, 2024, 12:56:32 AM1/8/24
to Chromium Extensions, Jackie Han, Chromium Extensions, Coure 2011
Thanks for pointing to the guide. I was able to record audio using getUserMedia({ audio: true; }), but now facing 2 issues
-- It works find on windows but on Mac I am still getting " Uncaught (in promise) DOMException: Permission dismissed", I have allowed mic in privacy for chrome.
-- On windows although it records but it never asked for permission to allow mic/cam.

Coure 2011

unread,
Jan 8, 2024, 1:42:40 AM1/8/24
to Chromium Extensions, Coure 2011, Jackie Han, Chromium Extensions
Ok, I found that the permission error is thrown on windows as well. As its not asking for permissions so if I explicitly set Allow from site settings then it works fine both on windows and mac.
I allowed mic from
Extension > Details > Site Settings > Permissions > Microphone : Allow

So, the question is how I can ask user for permission and remember it instead of manually setting the value.

Jackie Han

unread,
Jan 8, 2024, 7:26:39 AM1/8/24
to Coure 2011, Chromium Extensions
Did you use the method of the article? It already provides a solution.
In that article, it uses `chrome.tabCapture.getMediaStreamId()` to get `streamId`, then passes `streamId` to `navigator.mediaDevices.getUserMedia()` .
chrome.tabCapture API already use the permission "tabCapture", so getUserMedia() doesn't require Web permission.

Oliver Dunk

unread,
Jan 8, 2024, 11:11:07 AM1/8/24
to Jackie Han, Coure 2011, Chromium Extensions
If you require both audio and video access, the best option is the web permissions.request API.

You might also be interested in this experiment I did a while back which shows how to combine audio and video streams in an offscreen document: https://github.com/GoogleChrome/chrome-extensions-samples/commit/9ee3bb917bc2fd21f3b70ff02b36125170dcefb3

Note that the commit above doesn't add the necessary permission requests. I'm hoping to document this whole flow better soon.
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB


--
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.

Jackie Han

unread,
Jan 8, 2024, 3:52:03 PM1/8/24
to Oliver Dunk, Coure 2011, Chromium Extensions
If you require both audio and video access, the best option is the web permissions.request API.

The link above is browser extensions permissions api, not web permissions api. Web permissions api is this link .

Note 1: navigator.mediaDevices.getUserMedia() is a permission-aware api. When you call it, it will request web permission. But in an offscreen document, it will fail. If you open a normal extension page in a tab, call getUserMedia() will request web permission,  but it fails in an offscreen document. 

Note 2: request web permission will also fail in the popup page and side panel page.

Note 3: "tabCapture" permission is an extension permission. It overlaps with web permission. Web permission or Extension permission, you can use one of them.

https://github.com/GoogleChrome/chrome-extensions-samples/commit/9ee3bb917bc2fd21f3b70ff02b36125170dcefb3

Above commit is at "tabcapture-mic" branch, not merged in "main" branch.

Coure 2011

unread,
Jan 9, 2024, 12:01:19 AM1/9/24
to Chromium Extensions, Jackie Han, Coure 2011, Chromium Extensions, Oliver Dunk
After going through all different options,  I think for now best option for me would be (pointed in Note 1) to create a temp page {extension-id}/get-mic.html and asking for permission there.
This way the permissions are asked for the extension and not for the specific page.

Oliver Dunk

unread,
Jan 9, 2024, 6:02:06 AM1/9/24
to Coure 2011, Chromium Extensions, Jackie Han
The link above is browser extensions permissions api, not web permissions api. Web permissions api is this link.

Thanks Jackie. I thought there was a similar request API for the web, so when I saw that, I quickly grabbed the link. I think I was thinking of `navigator.permissions.query` though. You're right that the best approach here would be to attempt to start an audio stream with `getUserMedia` to get permission and then immediately close it afterwards. A little unfortunate but I think the best option for now.

Above commit is at "tabcapture-mic" branch, not merged in "main" branch.

Yeah, I'd like to work it into the sample but haven't had a chance yet. Uploaded it as a branch so I can at least share it when people ask :)
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

Kourosh Ghaffari

unread,
Apr 29, 2024, 2:15:39 PM4/29/24
to Chromium Extensions, Coure 2011, Jackie Han, Chromium Extensions, Oliver Dunk
Hey! I'm going through the same struggle right now and I'm trying to follow your approach but am failing. 

I'm a newbie dev so I might be missing something simple, but any chance you could give more insight into how you create the temp page, ask for permission, and then ensure that the user's permissions are saved? 

Faraz Shuja

unread,
Apr 30, 2024, 4:52:34 AM4/30/24
to Chromium Extensions, Kourosh Ghaffari, Chromium Extensions

Listen to some button click handler and then can call createOffScreen() method.
// helper.ts
export async function createOffscreen() {
  if (await chrome.offscreen.hasDocument()) {
    return;

  }

  await chrome.offscreen.createDocument({
    url: 'dist/offscreen/index.html',
    // https://developer.chrome.com/docs/extensions/reference/offscreen/#type-Reason

    reasons: ['DISPLAY_MEDIA', 'USER_MEDIA'],
    justification: 'To record tab or window or screen',
  });
}

export async function closeOffscreen() {
  if (await chrome.offscreen.hasDocument()) {
    chrome.offscreen.closeDocument();
  }
}

and then invoking display media
// offscreen/index.html
function invokeGetDisplayMedia(
  success: (value: MediaStream) => MediaStream | void,
  error: (reason: Error) => void,
) {
  const displaymediastreamconstraints = {
    video: true,
  };

  navigator.mediaDevices
    .getDisplayMedia(displaymediastreamconstraints)
    .then(success)
    .catch(error);
}

Justin Mann

unread,
Feb 27, 2025, 1:51:53 PM2/27/25
to Chromium Extensions, Faraz Shuja, Kourosh Ghaffari, Chromium Extensions
I am hitting the NotAllowedError: Permission dismissed issue when trying to using audio or video inside of chrome extension sidepanel on Mac.

I created a very simple sample here: https://github.com/justinmann/sidepanel-audio-issue

Patrick Kettner

unread,
Feb 27, 2025, 1:54:32 PM2/27/25
to Justin Mann, Chromium Extensions, Faraz Shuja, Kourosh Ghaffari
The microphone permission is attached to an origin, for an extension that would be chrome-extension://YOUR_EXTENSION_ID. The issue you are hitting is requesting microphone access in environments that do not have the UX affordance to request it. As a result, the request fails and you get the permission denied error as though the user declined the request. The workaround I would normally suggest is to programatically open a chrome extension page as a full tab to request the permission. Once it is granted, the sidepanel can access it. So within your sidepanel.html, have something like

```js
function async getMic() {
  const micPermission = await navigator.permissions.query({name: "microphone"});

  if (micPermission.state !== "granted") {
    chrome.tabs.create({url: "request-mic.html"}, (tab) => {
      chrome.tabs.onRemoved.addListener(function listener(tabId) {
        if (tabId === tab.id) {
          chrome.tabs.onRemoved.removeListener(listener); // Remove listener after execution
          getMic();
        }
      });
    })
  } else {
    const mic = navigator.mediaDevices.getUserMedia({audio: true})
  }
}
```

Where you create a `request-mic.html` page in your extension that just calls

```js
   navigator.permissions.request({ name: "microphone" })
```

Patrick Kettner

unread,
Feb 27, 2025, 2:50:03 PM2/27/25
to Justin Mann, Chromium Extensions, Faraz Shuja, Kourosh Ghaffari
Thanks so much, Justin! I absolutely agree that it is a bug in chromium, to be clear 
On Thu, Feb 27, 2025 at 11:47 AM Justin Mann <justi...@gmail.com> wrote:
I can confirm that this approach does work, I have updated my sample app to use this method:
https://github.com/justinmann/sidepanel-audio-issue

I do not see a great way to notify the sidePanel when the permission request is complete, so I had to put in a timer to just keep checking in a loop. 

IMO, I feel this is a bug in chromium. The sidePanel & popup both display web content and should be capable of presenting permission prompts.

Justin Mann

unread,
Feb 28, 2025, 5:38:12 AM2/28/25
to Chromium Extensions, Patrick Kettner, Chromium Extensions, Faraz Shuja, Kourosh Ghaffari, Justin Mann
I can confirm that this approach does work, I have updated my sample app to use this method:
https://github.com/justinmann/sidepanel-audio-issue

I do not see a great way to notify the sidePanel when the permission request is complete, so I had to put in a timer to just keep checking in a loop. 

IMO, I feel this is a bug in chromium. The sidePanel & popup both display web content and should be capable of presenting permission prompts.

On Thursday, February 27, 2025 at 10:54:32 AM UTC-8 Patrick Kettner wrote:

Sebastian Benz

unread,
Mar 13, 2025, 12:28:27 PM3/13/25
to Patrick Kettner, Justin Mann, Chromium Extensions, Faraz Shuja, Kourosh Ghaffari
Hey Justin,

> I do not see a great way to notify the sidePanel when the permission request is complete,

I'm curious, Is there a reason why you can't notify the sidepanel via sendMesssage? 

Thanks,

Sebastian

Justin Mann

unread,
Mar 13, 2025, 12:57:05 PM3/13/25
to Chromium Extensions, Sebastian Benz, Justin Mann, Chromium Extensions, Faraz Shuja, Kourosh Ghaffari, Patrick Kettner
That should work. I have not tried it. I choose to handle permission requests during install instead of on-demand, the on-demand process just seemed like a poor user experience.

Another issue, when I open my page from my chrome extension to request permission, the area in the nav bar that usually shows page permissions is replaced with a chrome extension button. The chrome extension button does not let you change permissions. So, if the user ever denies mic permission, they would need to figure out the fairly complex process of opening "Manage Extensions", find extension, "Details", "Site Settings". Eventually, I am going to record a YT video to explain this process to the user and show it on permission failure, but that is a poor user experience.

FYI, here is the final workflow that I built. I trigger all permission requests during the install process:
https://chromewebstore.google.com/detail/sociable/haodmoihodngjigfdbojjnohohndoopp

Screenshot 2025-03-13 at 9.51.01 AM.png

Justin Mann

unread,
Mar 13, 2025, 12:58:19 PM3/13/25
to Chromium Extensions, Justin Mann, Sebastian Benz, Chromium Extensions, Faraz Shuja, Kourosh Ghaffari, Patrick Kettner
Also, removing the chrome extension and re-installing does not reset the site permissions.
Reply all
Reply to author
Forward
0 new messages