7

Is there a way to play an audio file from a service worker?

I'm trying to use io.sound library but it is a JavaScript plugin that requires window, so it doesn't work.

EDIT

As suggested by Jeff I'm trying to open a new window and post a message to that window. this is my code:

function notifyClientToPlaySound() {
  idbKeyval.get('pageToOpenOnNotification')
    .then(url => {

        console.log("notifyClientToPlaySound", url);

        clients.matchAll({
            type: "window"
            //includeUncontrolled: true
        })
        .then((windowClients) => {

            console.log("notifyClientToPlaySound - windowClients", windowClients);
            for (var i = 0; i < windowClients.length; i++) {
                var client = windowClients[i];
                if (client.url === url && "focus" in client) {
                    notify({ event: "push" });
                    return client.focus();
                }
            }

            //https://developer.mozilla.org/en-US/docs/Web/API/Clients/openWindow
            if (clients.openWindow) {
                return clients.openWindow("/")
                    .then(() => {
                        notify({ event: "push" });
                    });
            }
        })
    });
}

This function is now called from event.waitUntil(..) inside self.addEventListener("push", (event) => { ... }

self.addEventListener("push", (event) => {
   console.log("[serviceWorker] Push message received", event);

   event.waitUntil(
      idbKeyval.get('fetchNotificationDataUrl')
        .then(url => {
            console.log("[serviceWorker] Fetching notification data from -> " + url);

            return fetch(url, {
                credentials: "include"
            });
        })
        .then(response => {
            if (response.status !== 200) {
                // Either show a message to the user explaining the error  
                // or enter a generic message and handle the
                // onnotificationclick event to direct the user to a web page  
                console.log("[serviceWorker] Looks like there was a problem. Status Code: " + response.status);
                throw new Error();
            }

            // Examine the text in the response  
            return response.json();
        })
        .then(data => {
            if (!data) {
                console.error("[serviceWorker] The API returned no data. Showing default notification", data);
                //throw new Error();
                showDefaultNotification({ url: "/" });
            }

            notifyClientToPlaySound(); <------ HERE

            var title = data.Title;
            var message = data.Message;
            var icon = data.Icon;
            var tag = data.Tag;
            var url = data.Url;

            return self.registration.showNotification(title, {
                body: message,
                icon: icon,
                tag: tag,
                data: {
                    url: url
                },
                requireInteraction: true
            });
        })
        .catch(error => {
            console.error("[serviceWorker] Unable to retrieve data", error);

            var title = "An error occurred";
            var message = "We were unable to get the information for this push message";
            var icon = "/favicon.ico";
            var tag = "notification-error";
            return self.registration.showNotification(title, {
                body: message,
                icon: icon,
                tag: tag,
                data: {
                    url: "/"
                },
                requireInteraction: true
            });
        })
   );
});

But when clients.openWindow is called, it returns the following exception:

Uncaught (in promise) DOMException: Not allowed to open a window.

How can I solve this?

Androidian
  • 1,035
  • 1
  • 16
  • 40

1 Answers1

6

The living specification for the Web Notifications API does reference a sound property that could be specified when showing a notification, and would theoretically allow you to play the sound of your choosing when showing a notification from a service worker.

However, while the specification references this property, as of the time of this writing, it's not supported in any browsers.

Update (Aug. '19): It looks like reference to sound has been removed from https://notifications.spec.whatwg.org/#alerting-the-user

Your best bet would be post a message along to an open window that's controlled by the current service worker, and have the window play the sound in response to the message event.

If there is no controlled client available (e.g. because your service worker has been awoken by a push event, and your site isn't currently open in a browser) then you'd have the option of opening a new window inside your notificationclick handler, which is triggered in response to a user clicking on the notification you display in your push event handler. You can then post a message to that new window.

Jeff Posnick
  • 53,580
  • 14
  • 141
  • 167
  • Unfortunately I can't open a new window because of "Uncaught (in promise) DOMException: Not allowed to open a window." I've updated my question with the code – Androidian Feb 16 '17 at 16:26
  • 3
    @Androidian you can't open a window in response to a push event - you'll need to show a notification, then listen to the notificationclick event, and open a window then. – Alastair Mar 08 '17 at 13:05
  • @JeffPosnick how about the current status? Your link on browser support (developer.mozilla...) is not working now. The sound parameter in options doesn't seem to work now also. Is that so? – mythicalcoder Aug 21 '19 at 21:29
  • It looks like sound has been abandoned from the spec. I've updated the answer to reflect that. – Jeff Posnick Aug 22 '19 at 20:03
  • hm. thanks, @JeffPosnick. How about PWAs on mobile? How should one approach having sound play from the background! or what's the alternative. – mythicalcoder Aug 22 '19 at 20:43