diff options
author | Jukka Jylänki <jujjyl@gmail.com> | 2013-11-10 12:13:39 +0200 |
---|---|---|
committer | Jukka Jylänki <jujjyl@gmail.com> | 2013-11-10 12:13:39 +0200 |
commit | 27b9b4870698b2d1bbd9676939dce6abb0a640e9 (patch) | |
tree | 978c2cb058f0ce393f8699698d2f98c896708ee1 | |
parent | e0268fa1035a718341c53921eee9318d4a8033cd (diff) |
Support SDL audio sample size of 512 samples. Make the SDL audio buffer queueing logic more resilient for jitter, and factor out a common parameter 'SDL.audio.numSimultaneouslyQueuedBuffers' that can be used to tune for a good quality<->latency balance.
-rw-r--r-- | src/library_sdl.js | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/src/library_sdl.js b/src/library_sdl.js index 5b43b7ab..e69009af 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1469,7 +1469,7 @@ var LibrarySDL = { } else if (SDL.audio.channels != 1 && SDL.audio.channels != 2) { // Unsure what SDL audio spec supports. Web Audio spec supports up to 32 channels. console.log('Warning: Using untested number of audio channels ' + SDL.audio.channels); } - if (SDL.audio.samples < 1024 || SDL.audio.samples > 524288 /* arbitrary cap */) { + if (SDL.audio.samples < 512 || SDL.audio.samples > 524288 /* arbitrary cap */) { throw 'Unsupported audio callback buffer size ' + SDL.audio.samples + '!'; } else if ((SDL.audio.samples & (SDL.audio.samples-1)) != 0) { throw 'Audio callback buffer size ' + SDL.audio.samples + ' must be a power-of-two!'; @@ -1480,6 +1480,10 @@ var LibrarySDL = { SDL.audio.bufferSize = totalSamples*SDL.audio.bytesPerSample; SDL.audio.buffer = _malloc(SDL.audio.bufferSize); + // To account for jittering in frametimes, always have multiple audio buffers queued up for the audio output device. + // This helps that we won't starve that easily if a frame takes long to complete. + SDL.audio.numSimultaneouslyQueuedBuffers = 3; + // Create a callback function that will be routinely called to ask more audio data from the user application. SDL.audio.caller = function SDL_audio_caller() { if (!SDL.audio) { @@ -1496,6 +1500,7 @@ var LibrarySDL = { SDL.audio.mozBuffer = new Float32Array(totalSamples); SDL.audio.nextPlayTime = 0; SDL.audio.pushAudio = function SDL_audio_pushAudio(ptr, size) { + --SDL.audio.numAudioTimersPending; var mozBuffer = SDL.audio.mozBuffer; // The input audio data for SDL audio is either 8-bit or 16-bit interleaved across channels, output for Mozilla Audio Data API // needs to be Float32 interleaved, so perform a sample conversion. @@ -1514,15 +1519,21 @@ var LibrarySDL = { // Compute when the next audio callback should be called. var curtime = Date.now() / 1000.0 - SDL.audio.startTime; - if (curtime > SDL.audio.nextPlayTime && SDL.audio.nextPlayTime != 0) { - console.log('warning: Audio callback had starved sending audio by ' + (curtime - SDL.audio.nextPlayTime) + ' seconds.'); - } +// if (curtime > SDL.audio.nextPlayTime && SDL.audio.nextPlayTime != 0) { +// console.log('warning: Audio callback had starved sending audio by ' + (curtime - SDL.audio.nextPlayTime) + ' seconds.'); +// } var playtime = Math.max(curtime, SDL.audio.nextPlayTime); var buffer_duration = SDL.audio.samples / SDL.audio.freq; SDL.audio.nextPlayTime = playtime + buffer_duration; - // Schedule the next audio callback call. + // Schedule the next audio callback call to occur when the current one finishes. SDL.audio.timer = Browser.safeSetTimeout(SDL.audio.caller, 1000.0 * (playtime-curtime)); - } + ++SDL.audio.numAudioTimersPending; + // And also schedule extra buffers _now_ if we have too few in queue. + if (SDL.audio.numAudioTimersPending < SDL.audio.numSimultaneouslyQueuedBuffers) { + ++SDL.audio.numAudioTimersPending; + Browser.safeSetTimeout(SDL.audio.caller, 1.0); + } + } } else { // Initialize Web Audio API if we haven't done so yet. Note: Only initialize Web Audio context ever once on the web page, // since initializing multiple times fails on Chrome saying 'audio resources have been exhausted'. @@ -1601,8 +1612,8 @@ var LibrarySDL = { ++SDL.audio.numAudioTimersPending; } - // If we are risking starving, immediately queue an extra second buffer. - if (secsUntilNextCall <= buffer_duration && SDL.audio.numAudioTimersPending <= 1) { + // If we are risking starving, immediately queue extra buffers. + if (secsUntilNextCall <= buffer_duration && SDL.audio.numAudioTimersPending < SDL.audio.numSimultaneouslyQueuedBuffers) { ++SDL.audio.numAudioTimersPending; Browser.safeSetTimeout(SDL.audio.caller, 1.0); } |