audio in my phaser.js game is not playing on android devices

Viewed 132

I have the following code in preload:

this.load.audio('theme', './audio/theme.mp3');

and in create():

gameState.music = this.sound.add('theme');
gameState.music.play();
gameState.music.loop = true; 

I also added in config following some info i found out there:

audio: {
    disableWebAudio: true
}

It works on desktop and iphone, but not on android. Funny thing that it worked before i made some - unrelated to audio - changes to the game.

2 Answers

There are some points to unpack, so I opted, for a anwser instead of a comment.
(Sorry that it is so long, I tried to keep it short)

  1. You change the Audio file type from mp3 (which is well supported over many devices, especially older), to ogg which is not as well supported _(tipp: best info page for information to browser feature support)

    • specific android version support say's android 5.0+ should be able to play ogg file (android version table), I tested it on Android 5.5, it works. So if the andorid version is not under 5.0, and you tap the screen only once, and no sound is playing, there is a different issue.
    • iphone should not work (ogg is not supported, if I can belief the apple forum posts), but I tested it on iPhone SE 2015 and it works. Strange
      • btw.: fullscreen also works, but only on the safari browser, not chrome I tap scrolled
  2. Mobile devices need user interaction to play sounds/music, so if you let the page load and don't tap the screen, the music shouldn't (won't) play. After tap the music starts. This is the part, where we are entering uncharted territory:

    • You are starting the music in the Scene 'FirstScene', but this Scene is stopped after first tap. Theoretically everything in the Scene will/should be unloaded, but the music plays on. (This fact seems to be know, but is still Strange, to me)

Personally I would:

  • call the play() function only after a user interaction, this prevents possible problems due to the "browser blocking",
  • use mp3 since it wider supported,
  • [and optional] if possible keep the sounds / music it the same Scene, and if the scene is closed/stopped, I would stop any audio, that was initiated in that Scene. Or even handle all the sound in a seperate always running scene like mentioned, in this forum post. (But I usually always have a "always-running"-scene which manages my scene switches and other background actions)

But, it seems okay, since currently it works on my local server, for:

  • Win10 Chrome 104+
  • iPhone SE 2015 safari, fullscreen won't work on iphone, if we can trust this site
  • Android 5.5 Chrome
  • Android 11.0 Chrome

Update Sound Manager Option:

an "easy" way is to add 2 extra Scenes

BootScene:

class BootScene extends Phaser.Scene {
    constructor(){
        super({ key: 'BootScene' })
    }

    create() {
        // `launch` starts a scene without stopping other
        this.scene.launch('FirstScene');
        this.scene.launch('SoundScene');
    }
}

SoundScene:
Scene that runs parallel to the game

class SoundScene extends Phaser.Scene {
    constructor(){
        super({ key: 'SoundScene' })
    }

    preload(){
        this.load.audio('theme', './audio/theme.ogg');
    }

    create() {
        this.input.once('pointerdown', _ => {
            gameState.music = this.sound.add('theme');
            gameState.music.play();
            gameState.music.loop = true; 
        });
    }

}

And make some minor tweaks:

index.html
(add new Scenes)

...
  <script src="BootScene.js"></script>
  <script src="SoundScene.js"></script>
...

game.js
(add new Scenes to config)

...
config = {
    ...
    scene: [BootScene, SoundScene, FirstScene, ...],
    ...
}
...

FirstScene.js:

  • Remove the theme stuff from preload and the create function.
  • add extra checks to prevent errors (check if gameState.music is set already)
update() {
     if (gameState.music && !document.hasFocus()) {
         gameState.music.pause(); 
    }
    if (gameState.music && document.hasFocus()) {
        gameState.music.resume();
    }
 }

After some digging and some testing here some more infos, on how to get the Audio, work consistently, on iphone or Android:

  1. It seems that for Mobile (iOs or Android) you might need to unlock the audio/sound.

in the SoundScene just adapt the create function, to mirror these changes:

 create() {
    this.input.once('pointerdown', _ => {
        // UNLOCK audio, doesn't work immediately on iphone
        this.sound.unlock();
        gameState.music = this.sound.add('theme2', {loop: true});
        
        // if unlock worked, just play the sound
        if(!this.sound.locked){
            gameState.music.play();
        } 
        else {  // IF Not wait on unlock event 
            this.sound.once(Phaser.Sound.Events.UNLOCKED, () => {
                gameState.music.play();
            })
        }
    });
}
  1. With the current config / code, this should work with Android, but not with iPhone.
  2. If you remove the disableWebAudio:true from the config configutation in the game.js - file, than it works on iPhone, but not on Android. Strange

Currently this are the only two configurations, how I could get the audio to work on android and iPhone. I couldn't find a single configuration, that works for both.

Update: I retested everything, it seems to work, with the SoundScene changes, on win 10, android and iphone, with disableWebAudio:true using a mp3- file.

Related