goldfire / howler.js

Javascript audio library for the modern web.
https://howlerjs.com
MIT License
23.87k stars 2.23k forks source link

Chrome autoplay policy changes #939

Open robbue opened 6 years ago

robbue commented 6 years ago

Chrome 66 have changed its autoplay policy:

An AudioContext must be created or resumed after the document received a user gesture to enable audio playback. https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio

mobileAutoEnable could be updated to adjust for Chrome (desktop and mobile) as well.

RichardGale commented 5 years ago

You're probably also tired that Microsoft stopped supporting MS DOS ON PURPOSE and broke THOUSANDS and THOUSANDS of MS DOS games. I guess those devs either stopped writing for MS DOS or moved with the times and switched to Windows.

Tectract commented 5 years ago

DOS still works.

hmans commented 4 years ago

If my employees said that to someone in a support ticket on my repos, I'd fire their asses so fast their head would spin.

Howler is not commercial software, and GitHub Issues is not a support ticket system.

Tectract commented 4 years ago

I'm still angry about this MAJOR BUG that they introduced into Chrome. I'm just an end-user here to say "shit is broken, because of a major upstream bug". Anyone who calls breaking sound on pretty much every site out there, for all use-cases, a "feature", is a tool.

AlGantori commented 4 years ago

Can someone show some code to detect this situation, or help me fix below, thank you.

I added listening for onplayerror which seems to fire/emit and I am able to show a pause button. However when the user presses the button and the code attempts audio.play no sound plays out, I run into a loop?

Even though intellisense in VSCode does not show it I am treating Howler.play to return a promise.

What did I miss?

There is apparently a couple of parameters with onplayerror accord to the documentation, how do I retrieve those?

  // 20160820
    PlayOne(Media: string) {
        Log.Called(this, "PlayOne", "Media is", Media)
        return new Promise((resolve, reject) => { // return a promise
            this.audio = new Howl({ src: [Media] });                     // create audio wo/ src
            //
            // https://github.com/goldfire/howler.js#onloaderror-function
            this.audio.on('loaderror', () => {
                Log.Event(this, "AudioPlayList", "loaderror")
                reject(Media);
                // reject;
            });
            this.audio.on('onplayerror ', () => {
                Log.Event(this, "AudioPlayList", "onplayerror")
                resolve(Media);
                // reject;
            });
            this.audio.on('end', () => {
                Log.Event(this, "AudioPlayList", "audio ENDED")
                resolve(Media);
                return resolve;
            });

            return this.audio.play()
        });
    }

from the View controller of the application I catch the failed promise like so to tell the view to handle and react by displaying the pause button.

                // -) Invoke the Sound playing
                let Sound = this.Slides.Audio(this.Slides.Index)
                this.AudioPlayList.Play(Sound).then(data => {
                    Log.Promise(this, "PlayIndex", "AudioPlayList.Play", "Done Playing")
                })
                    .catch(error => {
                        Log.X(this, "PlayIndex", "AudioPlayList.Play", error)
                        // https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#best-practices
                        this.UQSView.RequireUserGestureToPlay()
                    })

image

Feel free to fix my "promise" handling and coding I am just hacking my way to JS via TS. One minute I think I understand Promises and then the next minute it's like I never heard of them before.

AlGantori commented 4 years ago

@goldfire thank you for providing a component that works.

I think you mean by "The library would still be detecting that the audio is locked either way, that would be able to be checked at a global level." that option 1 would be available as well?

IOW, there is a simple mean for the app to detect the situation (a user interaction is required by chrome) and the app retry or create a new howler.play() upon the user click some play/pause/resume button?

Thank you for clarifying, that's the behavior I am trying to fix/code the above reply/request.

stefan-reich commented 4 years ago

So kindly tell me, is there still any way to reliably play a notification sound in a Chrome background tab?

I have to chime in with the Chrome critics in saying that Google should at least have given us an option to declare a website "trusted" so it can play sound at any time.

Gavitron commented 3 years ago

hi, so I was trying to resurrect the venerable hypnotoad site, which is basically an animated frog and a background sound that needs to play as soon as the page loads, with zero user interaction. How can I make a page play a sound as soon as it is the active page, without having to design an onerous UI forcing the user to click? this site was literally a gif & an mp3 before the Chrome developers removed the feature. can I use an onHover event instead of an onClick?

stefan-reich commented 3 years ago

@Gavitron No, user needs to click.

ltakato commented 3 years ago

@stefan-reich did you find a solution? I'm trying to achieve an issue like you said. It works after clicking, but when user refresh page, browser asks again for interaction/gesture.

stefan-reich commented 3 years ago

@ltakato I don't think there is a solution... user needs to click first. You can try to never actually switch pages, for example by using a frame set or by converting the website into a single page with JavaScript reloads (hard but possible). That you keep a page loaded and thus Chrome remembers that the user has clicked.

If user presses F5... you're just lost.

georgiosd commented 3 years ago

Is anyone having success unlocking with the example given in the docs here? https://github.com/goldfire/howler.js#mobilechrome-playback

I can play the audio after the unlock event but Chrome is muted!