phoboslab / Impact

HTML5 Game Engine
MIT License
2k stars 202 forks source link

Stop forcing single-channel audio in ig.Music? #42

Open Joncom opened 5 years ago

Joncom commented 5 years ago

https://github.com/phoboslab/Impact/blob/3b6d3b5fa34f12fd20b16e214a9dfc745316a6fe/lib/impact/sound.js#L239-L249

As the above snippet mentions, an advantage to using "HTML5 Audio" for music, is that it the audio can be streamed. And Impact enforces this preference by throwing an error.

However, I can think of at least one advantage to allowing "Web Audio" to be used...

Getting sounds to play at all in mobile browsers is a bit finicky:

To prevent annoying ads during mobile web browsing, all sounds are always disabled by default (on iOS Safari at least), until at least one sound has been played in the actual callback of a touchend event, which can only triggered by the user himself.

With "Web Audio", the solution is easy:

In the case of "Web Audio", playing a single sound in this callback will enable all other and future "Web Audio" playback. Playing one sound enables all the others.

However, with "HTML Audio", it's more cumbersome:

Each and every individual sound file must be played in this callback, to enable each one for future playback.

Here is the basic solution to get audio enabled on mobile browsers:

ig.system.canvas.addEventListener('touchend', function() {
    if( !ig.game.mobileAudioEnabled ) {

        // Playing a single "Web Audio" source will enable all others
        ig.game.silent.play();
        ig.game.silent.stop();

        // Each "HTML5 Audio" source much be enabled invididually
        for(var i=0; i<ig.game.tracks.length; i++) {
            ig.game.tracks[i].play();
            ig.game.tracks[i].stop();
        }

        ig.game.mobileAudioEnabled = true;
    }
}, false);

Although this works to enable all sounds, it has 2 issues:

1) Brief laggy moment when sounds first enable (noticeable FPS jitter) 2) The tracks in ig.game.tracks can be heard for a split second

If ig.Music were modified to allow tracks to be "Web Audio" instead of "HTML5 Audio", I think issues 1 and 2 would both be resolved.

ig.system.canvas.addEventListener('touchend', function() {
    if( !ig.game.mobileAudioEnabled ) {
        ig.game.silent.play();
        ig.game.silent.stop();
        ig.game.mobileAudioEnabled = true;
    }
}, false);

Just thinking out loud here... Maybe it would be an idea to allow both types of audio for music, so that if streaming is important, that works, and if streaming is not important but support for mobile audio is, that option works a bit nicer too.

Edit:

Hmm. I just noticed there's actually already some audio unlock logic in sound.js:

https://github.com/phoboslab/Impact/blob/6c4a603d00f2db7fd0254efb6e0da2740d0f6ab1/lib/impact/sound.js#L37-L52

However, this logic does not work, which is why I came up with my own unlock logic in the first place.

But the follow patch fixes it:

diff --git a/lib/impact/sound.js b/lib/impact/sound.js
index 50d74be..afcc7a4 100644
--- a/lib/impact/sound.js
+++ b/lib/impact/sound.js
@@ -34,13 +34,13 @@ ig.SoundManager = ig.Class.extend({
                if( ig.Sound.enabled && ig.Sound.useWebAudio ) {
                        this.audioContext = new AudioContext();
                        this.boundWebAudioUnlock = this.unlockWebAudio.bind(this);
-                       document.addEventListener('touchstart', this.boundWebAudioUnlock, false);
+                       ig.system.canvas.addEventListener('touchstart', this.boundWebAudioUnlock, false);

                }
        },

        unlockWebAudio: function() {
-               document.removeEventListener('touchstart', this.boundWebAudioUnlock, false);
+               ig.system.canvas.removeEventListener('touchstart', this.boundWebAudioUnlock, false);

                // create empty buffer
                var buffer = this.audioContext.createBuffer(1, 1, 22050);

As far as I can tell though, Impact still has no "audio unlock" for HTML5 audio...

swashvirus commented 5 years ago

its 9days any new solution on this issue 😃 failed to execute 'play' on 'htmlmediaelement'

Joncom commented 5 years ago

Fixed the broken Web Audio unlocking: 1425a041e3a85fa00bc8e7a86d6f84aab67a6104

However, HTML5 Audio still does not get unlocked automatically, and still faces the problem of causing a moment of FPS lag and/or making audible nose for brief moment while unlocking, so not sure about how to fix that yet...

Thinking the best way forward might be to make Web Audio the default for music, with fallback/optional support for HTML5 for people who need the audio streaming feature...

Joncom commented 5 years ago

On a related note, I'm seeing an audio error at https://playbiolab.com/ before the game even starts.

Screen Shot 2019-08-27 at 11 40 44 PM