Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio set to loop infinitely stops, when next loop triggers while switched to another tab. #6702

Closed
michalfialadev opened this issue Dec 30, 2023 · 5 comments · May be fixed by jonesrussell/nishman#6

Comments

@michalfialadev
Copy link

michalfialadev commented Dec 30, 2023

Version

  • Phaser Version: 3.60.0
  • Operating system: Win11
  • Browser: any / all (tested: Firefox Win11, Chrome Win11, Android, MacOS Safari)

Description

Posting following issue report as an info dump without source attached, cant create a repro due to time constraints (maybe later, seeing as i have 30days before closure..). Was able to work around the issue (@see below). Searched first, couldnt find a similar report, so here goes..

Im making a game, where if browser window goes out of focus, music mutes (not sfx, just music). For playing music only, i use separate 'audio' scene, which, when focus is lost, calls this.audioScene.sound.mute = true; and false, when focus is regained. Also i call this.audioScene.sound.pauseOnBlur = false; because the default focus handling / audio mute/unmute didn't always work as expected (all browsers/OSes..). So i funnel all the events (BLUR, FOCUS, HIDDEN, VISIBLE, PAUSE, RESUME) into 2 exit points onFocusGained and onFocusLost and handle the scene audio muting manually there.

Everything works wonders. Music is set to loop, loosing focus mutes it, regain of focus unmutes, works on all browsers/systems, all good. Except one strange issue - and this might be possibly unrelated to the muting code, it is likely related to the gain/loss of focus and how looping is handled internally by phaser during such situation (loss of focus as result of being switched to another tab during a loop trigger).

The issue is this: if i wait for a 1minute long infinitely looping music track to reach its end, and 5 seconds before it reaches its end (and Phaser makes the next loop of the music play), when i switch to another tab on FF/Chrome/MacOS Safari/whatever (this is 5 seconds before the end of the track, which is set to loop infinitely), and come back 10 seconds later (5 seconds after it should have been made to loop to the next loop), then the music unmutes and plays again (good), but 1 minute later, when the next loop should be started by Phaser, it wont start the next loop, and the music instead stops when the current loop finishes. This is unrelated to scene's audio's mute, since i can simply call resume() on the music track and it will start again; it simply will not be auto looped to next loop by phaser if it finishes its current loop. This auto looping bug only happens, when another tab is focused (game looses focus), while the next loop should start (and even then, it just stop looping after current music loop ends).

To work around this, i just opted to use pause/resume on currently playing music track, instead of scene.audio.mute {false|true}, when in|out of focus, that seems to 'work-around' well.

Example Test Code

WIP or none

@Scross086
Copy link

I believe our team has also seen this issue multiple times on 3.7

@XWILKINX
Copy link

Still happens on 3.85.0!

@photonstorm
Copy link
Collaborator

If it was fixed, this issue would be closed.

@photonstorm
Copy link
Collaborator

This, like lots of things in the Sound Manager, is a bit of a pain in the arse to resolve.

The AudioBufferSourceNode calls onended internally. This checks if the source is the same as the one in the WebAudioSound. If it is, it sets hasLooped = true and the update method recognises this and does the actual update. Of course, if the tab doesn't have focus, update doesn't run. Plus, if the tab doesn't have focus, the shape of the Source node changes, causing the type comparison check to fail, causing hasLooped to not be set.

Even better, looping is handled by setting the rate of the sound node to zero once the 'time' has expired. Then creating a brand new sound node. For every single iteration of the loop.

Annoyingly, the source node has a native, built-in loop property - if set to true the sound just keeps looping forever! Even when the tab isn't focused. And you can set the start/end points of the loop as well. As a bonus, you don't need to be constantly creating a brand new source node every time it loops.

However, there is no event or callback from web audio when a loop happens, which means no 'native' way to emit the Phaser LOOPED event. So that's wonderful, too. As it means the sound would actually loop, even out of focus, but the in-game events would not, so they'd be out of sync. Although I feel like this isn't really an issue, as you should account for it in your code.

So right now I'm tempted to use the native loop property of the source node, for seamless non-destructive looping. But it's a reasonably large internal change with unknown repercussions elsewhere. I'll have a think about it, but this may just need saving for our brand new Sound API.

@photonstorm
Copy link
Collaborator

Ok, have found a workaround for now and it's part of v3.85. The following test shows it working:

class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.audio('theme', [
            'assets/audio/kyobi/wavs/nextLevel.wav'
        ]);
    }

    create ()
    {
        this.add.text(32, 32, 'Click to start music', { fill: '#ffffff' });

        this.sound.pauseOnBlur = false;

        this.input.once('pointerdown', () => {

            const music = this.sound.add('theme');

            music.play({ loop: true });

            this.add.text(32, 64, '5 seconds until loop', { fill: '#ffffff' });

        });
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

(assets are in examples repo)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants