|
// Did we get a WebAudio Source? This is suboptimal; Music should be loaded |
|
// as HTML5 Audio so it can be streamed |
|
if( track instanceof ig.Sound.WebAudioSource ) { |
|
// Since this error will likely occour at game start, we stop the game |
|
// to not produce any more errors. |
|
ig.system.stopRunLoop(); |
|
throw( |
|
"Sound '"+path+"' loaded as Multichannel but used for Music. " + |
|
"Set the multiChannel param to false when loading, e.g.: new ig.Sound(path, false)" |
|
); |
|
} |
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:
- Brief laggy moment when sounds first enable (noticeable FPS jitter)
- 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:
|
document.addEventListener('touchstart', this.boundWebAudioUnlock, false); |
|
|
|
} |
|
}, |
|
|
|
unlockWebAudio: function() { |
|
document.removeEventListener('touchstart', this.boundWebAudioUnlock, false); |
|
|
|
// create empty buffer |
|
var buffer = this.audioContext.createBuffer(1, 1, 22050); |
|
var source = this.audioContext.createBufferSource(); |
|
source.buffer = buffer; |
|
|
|
source.connect(this.audioContext.destination); |
|
source.start(0); |
|
}, |
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...