aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJukka Jylänki <jujjyl@gmail.com>2013-11-10 12:13:39 +0200
committerJukka Jylänki <jujjyl@gmail.com>2013-11-10 12:13:39 +0200
commit27b9b4870698b2d1bbd9676939dce6abb0a640e9 (patch)
tree978c2cb058f0ce393f8699698d2f98c896708ee1
parente0268fa1035a718341c53921eee9318d4a8033cd (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.js27
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);
}