phaserjs / phaser

Phaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
https://phaser.io
MIT License
36.91k stars 7.08k forks source link

Chrome 55 now requires audio to be unlocked by user gestures, fails playing audio on Android in iframe #2913

Closed AleBles closed 7 years ago

AleBles commented 7 years ago

We've noticed this on a large number of portals where games are generally included with iFrames. We've been having this issue in Phaser 2.6.2, but I think this'll happen in any version available.

Basicly the Chromium team decided that, as in Safari iOS, WebAudio should only be actived trough a user gesture. But the problem is that they do it slightly different compared to Safari. Now this works fine on most platforms. but somehow manages to not work on Chrome - Android.

A comment in the WebAudio repo tells us that when we want to unlock the audio (Phaser.SoundManager#unlock) we need to check the state of the AudioContext and manually resume() the context when it's state is 'suspened'

A quick&dirty workaround for me is adding the following code in my boot state:

if (this.game.device.android && this.game.device.chrome && this.game.device.chromeVersion >= 55) {
    this.game.sound.setTouchLock();
    this.game.input.touch.addTouchLockCallback(function () {
        if (this.noAudio || !this.touchLocked || this._unlockSource !== null) {
            return true;
        }
        if (this.usingWebAudio) {
            // Create empty buffer and play it
            // The SoundManager.update loop captures the state of it and then resets touchLocked to false

            var buffer = this.context.createBuffer(1, 1, 22050);
            this._unlockSource = this.context.createBufferSource();
            this._unlockSource.buffer = buffer;
            this._unlockSource.connect(this.context.destination);

            if (this._unlockSource.start === undefined) {
                this._unlockSource.noteOn(0);
            }
            else {
                this._unlockSource.start(0);
            }

            //Hello Chrome 55!
            if (this._unlockSource.context.state === 'suspended') {
                this._unlockSource.context.resume();
            }
        }

        //  We can remove the event because we've done what we needed (started the unlock sound playing)
        return true;

    }, this.game.sound, true);
}
photonstorm commented 7 years ago

FFS Chrome. Thanks for the heads-up. Any chance of a CE PR? (if not I'll add it myself, as this is quite important)

AleBles commented 7 years ago

I would love too, but since we're not on CE yet I have a entire portfolio of games to adjust :P (also, not all our games are on 2.6 yet :( )

PonyOny commented 7 years ago

@AleBles I'm facing the same issue but your snippet is not working for me, could you explain where are getting the "this.context" from? is this.context refered to AudioContext?. I have placed the code in the boot state and I dont have this.context, I have tried to instanciate the AudioContext and try to apply your logic but I still have no sound on Chrome 55 & Android.

Thanks.

SBCGames commented 7 years ago

@AleBles @PonyOny - it "almost" worked for me. I had to comment out line:

this.game.sound.setTouchLock();

and replace it with:

this.game.sound.touchLocked = true;

Problem was, that call to setTouchLock() also set touch callback to original unlock() method:

this.game.input.touch.addTouchLockCallback(this.unlock, this);

and original unlock() method and method in this patch were fighting for touchLocked variable.

(my setup was: Phaser 2.6.1 + Android Chrome browser v55 + Facebook Instant game)

@PonyOny method is called in context of SoundManager (see this.game.sound in the very end). context property of SoundManager class. You do not have to care about it.

bobonthenet commented 7 years ago

I have added this issue to the Phaser-CE repo. It looks like that had not been done.

photonstorm commented 7 years ago

Thank you for taking the time to open this issue. However, official support for Phaser 2 has now ended as we focus on preparing Phaser 3 for beta release. In a bid to keep the project tidy, and avoid confusion, we are closing all v2 related issues.

This does not mean your issue won't be looked-at. In November 2016 the Phaser CE (Community Edition) project began. The aim of Phaser CE was to allow the community to continue v2 development. Since then it has gained significant traction, with many updates and releases.

If you are still interested in having your issue investigated we strongly recommend testing the latest Phaser CE release. And only if the problem persists, opening an issue on the Phaser CE repo.