Phaser Audio Delay

Phaser Audio Delay

This has happened to me so many times. I’m facing a Phaser audio delay again! I’ve got the game ready to go! The art assets are in, the scoreboards are working and the game has to launch tomorrow! I quickly throw in some background music and put it in a loop. The game starts, but where is the music???

Wait 3 seconds…

There it is! It is an annoying delay, but we’ve got to launch so I ignore it. What else can I do?

The Problem

Now that I’m not under the gun for a deadline, let’s step back and look at what is happening. I preload the music so why the delay?

I’ve put together a sample to show you the problem. Here is the code as I normally would load music. We will place an image so you can see that the images are loading at a normal speed. Also included is a timer so you can see how many seconds pass before the delay.

var StateMain = {
    preload: function() {
        game.load.audio("music", "audio/music.mp3");
        game.load.image("title", "images/Cool-Game-Title.png");
    },
    create: function() {
        this.secs = 0;
        //create the music
        var music = game.add.audio("music");
        //play the music
        music.play();
        //
        //
        //
        //put the title on screen
        var title = game.add.image(game.width / 2, game.height / 2, "title");
        title.anchor.set(0.5, 0.5);
        //make the timer text
        this.timeText = game.add.text(game.width / 2, 100, "0",{fill:'#ffffff'});
        this.timeText.anchor.set(0.5, 0.5);
        //start counting seconds
        game.time.events.loop(Phaser.Timer.SECOND, this.tick, this);
    },
    tick: function() {
    	this.secs++;
        this.timeText.text = this.secs;
    },
    update: function() {}
}

See audio text example 1 here

The Reason

So what’s going on here? What is causing this Phaser audio delay anyway? Why is it taking a few seconds to play even if it is preloaded? Well, I found some answers in this post that points out that as well as needing to be loaded, the audio also needs to be decoded. This is what the browser is doing while we are waiting for it to play.

The Solution

Phaser has the capability to detect if a music file has been decoded or not.

game.cache.isSoundDecoded('music');

That statement will return a true or false. So the solution we can use is to load everything on a separate state called stateLoad. After the preload is done, we will use the update function to check if the music is decoded. If it is, we will switch states to stateMain. It is a well-accepted fact in the game industry that the user is more willing to wait on a loading screen than they are after the game is started. Normally we would include a load bar or some messages on the loading screen but this will suffice for a technical example.

StateLoad
var StateLoad = {
        preload: function() {
            game.load.audio("music", "audio/music.mp3");
            game.load.image("title", "images/Cool-Game-Title.png");
        },
        create: function() {
        	//only fires after preload is done
            var statText = game.add.text(game.width / 2, 100, "Decoding....", {
                fill: '#ffffff'
            });
            statText.anchor.set(.5, .5);
        },
        update: function() {
        	//check to see if the audio is decoded
            if (game.cache.isSoundDecoded('music')) {
                    game.state.start("StateMain");
                }
            }
        }
StateMain
var StateMain = {
    preload: function() {
       //moved loading here to stateLoad
    },
    create: function() {
        this.secs = 0;
        //create the music
        var music = game.add.audio("music");
        //play the music
        music.play();
        //
        //
        //
        //put the title on screen
        var title = game.add.image(game.width / 2, game.height / 2, "title");
        title.anchor.set(0.5, 0.5);
        //make the timer text
        this.timeText = game.add.text(game.width / 2, 100, "0",{fill:'#ffffff'});
        this.timeText.anchor.set(0.5, 0.5);
        //start counting seconds
        game.time.events.loop(Phaser.Timer.SECOND, this.tick, this);
    },
    tick: function() {
    	this.secs++;
        this.timeText.text = this.secs;
    },
    update: function() {}
}

And here is the result. See audio text example 2 here

Results may vary, but on my localhost, the music played on zero for the second test and about 3 for the first test.

7 thoughts on “Phaser Audio Delay”

    1. You certainly can. Generally, I only use it for background music. This is because the background music files are much larger and by the time I need to use a sound effect file it is already decoded and ready to go.

  1. Dude you saved my life! My new project is all about audio (procrastination of words). It may look normal to let user wait for a sec but why not use that simple solution to make it look natural? Thanks

    1. Do you have a fix yet? I tried loading the assets in a loading screen and starting the game scene after load completes.. but that is working on some devices and not on some devices.. when i try the decodeAudio function mentioned in the documentation it gives me an error saying such a function doesnt exist.

Leave a Comment