admin管理员组

文章数量:1289836

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();
                }
            }

            //
            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?

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/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?

Share Improve this question edited Feb 16, 2017 at 16:25 Androidian asked Feb 16, 2017 at 8:33 AndroidianAndroidian 1,0751 gold badge17 silver badges43 bronze badges 1
  • Apologies; I've updated my answer accordingly. – Jeff Posnick Commented Mar 8, 2017 at 16:16
Add a ment  | 

1 Answer 1

Reset to default 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/#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.

本文标签: javascriptPlay a sound from a Service WorkerStack Overflow