|
@@ -183,6 +183,12 @@ static void EMSCRIPTENAUDIO_CloseDevice(_THIS)
|
|
|
SDL2.audio.scriptProcessorNode.disconnect();
|
|
|
SDL2.audio.scriptProcessorNode = undefined;
|
|
|
}
|
|
|
+ if (SDL2.audio.silenceTimer !== undefined) {
|
|
|
+ clearInterval(SDL2.audio.silenceTimer);
|
|
|
+ }
|
|
|
+ if (SDL2.audio.silenceBuffer !== undefined) {
|
|
|
+ SDL2.audio.silenceBuffer = undefined
|
|
|
+ }
|
|
|
SDL2.audio = undefined;
|
|
|
}
|
|
|
if ((SDL2.audioContext !== undefined) && (SDL2.audio === undefined) && (SDL2.capture === undefined)) {
|
|
@@ -227,7 +233,9 @@ static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
|
|
|
SDL2.audioContext = new webkitAudioContext();
|
|
|
}
|
|
|
if (SDL2.audioContext) {
|
|
|
- autoResumeAudioContext(SDL2.audioContext);
|
|
|
+ if ((typeof navigator.userActivation) === 'undefined') { // Firefox doesn't have this (as of August 2023), use autoResumeAudioContext instead.
|
|
|
+ autoResumeAudioContext(SDL2.audioContext);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
return SDL2.audioContext === undefined ? -1 : 0;
|
|
@@ -298,6 +306,7 @@ static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
|
|
|
if (SDL2.capture.silenceTimer !== undefined) {
|
|
|
clearTimeout(SDL2.capture.silenceTimer);
|
|
|
SDL2.capture.silenceTimer = undefined;
|
|
|
+ SDL2.capture.silenceBuffer = undefined
|
|
|
}
|
|
|
SDL2.capture.mediaStreamNode = SDL2.audioContext.createMediaStreamSource(stream);
|
|
|
SDL2.capture.scriptProcessorNode = SDL2.audioContext.createScriptProcessor($1, $0, 1);
|
|
@@ -339,10 +348,37 @@ static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
|
|
|
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
|
|
|
SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
|
|
|
if ((SDL2 === undefined) || (SDL2.audio === undefined)) { return; }
|
|
|
+ // if we're actually running the node, we don't need the fake callback anymore, so kill it.
|
|
|
+ if (SDL2.audio.silenceTimer !== undefined) {
|
|
|
+ clearInterval(SDL2.audio.silenceTimer);
|
|
|
+ SDL2.audio.silenceTimer = undefined;
|
|
|
+ SDL2.audio.silenceBuffer = undefined;
|
|
|
+ }
|
|
|
SDL2.audio.currentOutputBuffer = e['outputBuffer'];
|
|
|
dynCall('vi', $2, [$3]);
|
|
|
};
|
|
|
+
|
|
|
SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
|
|
|
+
|
|
|
+ if (SDL2.audioContext.state === 'suspended') { // uhoh, autoplay is blocked.
|
|
|
+ SDL2.audio.silenceBuffer = SDL2.audioContext.createBuffer($0, $1, SDL2.audioContext.sampleRate);
|
|
|
+ SDL2.audio.silenceBuffer.getChannelData(0).fill(0.0);
|
|
|
+ var silence_callback = function() {
|
|
|
+ if ((typeof navigator.userActivation) !== 'undefined') { // Almost everything modern except Firefox (as of August 2023)
|
|
|
+ if (navigator.userActivation.hasBeenActive) {
|
|
|
+ SDL2.audioContext.resume();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // the buffer that gets filled here just gets ignored, so the app can make progress
|
|
|
+ // and/or avoid flooding audio queues until we can actually play audio.
|
|
|
+ SDL2.audio.currentOutputBuffer = SDL2.audio.silenceBuffer;
|
|
|
+ dynCall('vi', $2, [$3]);
|
|
|
+ SDL2.audio.currentOutputBuffer = undefined;
|
|
|
+ };
|
|
|
+
|
|
|
+ SDL2.audio.silenceTimer = setInterval(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000);
|
|
|
+ }
|
|
|
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
|
|
|
}
|
|
|
/* *INDENT-ON* */ /* clang-format on */
|