Play audio from background script in chrome extention manifest v3

Viewed 1338

In manifest v2 i used to play audio from background script like this

new Audio(url)

But in manivest v3 same script is showing error

Uncaught ReferenceError: Audio is not defined

How to Play audio from background script(which is changed to service worker in v3) in chrome extention?

1 Answers

Update #1

Seems like there is some work being done on a feature called offscreen documents for MV3. With this new API, extensions will be able to open limited, offscreen documents having access to DOM APIs.

More info in the proposal. And here you can track its development.

However, this won't be the final solution. As stated in the proposal, long term, Chromium intends to support many of these capabilities directly within extension service workers.

Original answer

As written in the official documentation:

It's not currently possible to play or capture media directly in a service worker. In order for a Manifest V3 extension to leverage the web's media playback and capture capabilities, the extension will need to create a window environment using either chrome.windows.create() or chrome.tabs.create(). Once created, the extension can use message passing to coordinate between the playback document and service worker.

Until they do something about this, (hopefully, they eventually will - considering the usage of "currently" in their article) here is a quick workaround:

audio.html

<link href='icon.png' rel='icon' type='image/x-icon'>
<title>Notification</title>
<script src="audio.js"></script>
<style> :root { color-scheme: light dark }</style>

audio.js

resizeTo(0, 0);
onload = () => {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    let audio = new Audio(urlParams.get('src'));
    audio.volume = urlParams.get('volume');
    audio.play();
    setTimeout(close, urlParams.get('length'));
}

background.js (the service worker)

function playSound() {
    let url = chrome.runtime.getURL('audio.html');

    // set this string dynamically in your code, this is just an example
    // this will play success.wav at half the volume and close the popup after a second
    url += '?volume=0.5&src=success.wav&length=1000';

    chrome.windows.create({
        type: 'popup',
        focused: true,
        top: 1,
        left: 1,
        height: 1,
        width: 1,
        url,
    })

}

Once playSound() gets called, it will create a popup that will play the sound. It's a good idea to set the popup's icon to your extension's icon with the <link> tag so your users will know where the popup came from.

Note that audio.js must be linked from a separate file. Otherwise, you would receive an inline script policy violation error.

Further ideas

If you play sounds while sending toast notifications with the chrome.notifications API, You might want to move your popup behind the notification. An easy way to do that is to create the popup in the bottom right corner with: top: 99999, left: 99999 Then in your javascript: moveTo(window.screenX - 100, window.screenY);

Alternatively, you could turn the popup itself into the toast notification.

Related