21 #include "../../SDL_internal.h" 23 #if SDL_AUDIO_DRIVER_EMSCRIPTEN 27 #include "../SDL_audio_c.h" 30 #include <emscripten/emscripten.h> 37 if (this->hidden->write_off + this->convert.len_cvt > this->hidden->mixlen) {
38 if (this->hidden->write_off > this->hidden->read_off) {
40 this->hidden->mixbuf + this->hidden->read_off,
41 this->hidden->mixlen - this->hidden->read_off);
42 this->hidden->write_off = this->hidden->write_off - this->hidden->read_off;
44 this->hidden->write_off = 0;
46 this->hidden->read_off = 0;
49 SDL_memcpy(this->hidden->mixbuf + this->hidden->write_off,
51 this->convert.len_cvt);
52 this->hidden->write_off += this->convert.len_cvt;
53 byte_len = this->hidden->write_off - this->hidden->read_off;
59 HandleAudioProcess(
_THIS)
70 if (this->convert.needed) {
73 if (this->hidden->conv_in_len != 0) {
74 this->convert.len = this->hidden->conv_in_len * bytes_in * this->
spec.
channels;
81 buf = this->convert.buf;
82 byte_len = this->convert.len_cvt;
86 if (!this->hidden->mixbuf) {
87 this->hidden->mixlen = this->
spec.
size > byte_len ? this->
spec.
size * 2 : byte_len * 2;
88 this->hidden->mixbuf =
SDL_malloc(this->hidden->mixlen);
92 byte_len = copyData(
this);
100 byte_len = copyData(
this);
104 buf = this->hidden->mixbuf + this->hidden->read_off;
105 this->hidden->read_off += byte_len;
109 if (!this->hidden->mixbuf) {
110 this->hidden->mixlen = this->
spec.
size;
111 this->hidden->mixbuf =
SDL_malloc(this->hidden->mixlen);
114 this->hidden->mixbuf,
115 this->hidden->mixlen);
116 buf = this->hidden->mixbuf;
117 byte_len = this->hidden->mixlen;
122 var numChannels = SDL2.audio.currentOutputBuffer[
'numberOfChannels'];
123 for (var
c = 0;
c < numChannels; ++
c) {
124 var channelData = SDL2.audio.currentOutputBuffer[
'getChannelData'](
c);
125 if (channelData.length != $1) {
126 throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length +
' samples vs expected ' + $1 +
' samples!';
129 for (var
j = 0;
j < $1; ++
j) {
130 channelData[
j] = HEAPF32[$0 + ((
j*numChannels +
c) << 2) >> 2];
138 HandleCaptureProcess(
_THIS)
148 if (this->convert.needed) {
149 buf = this->convert.buf;
150 buflen = this->convert.len_cvt;
152 if (!this->hidden->mixbuf) {
154 if (!this->hidden->mixbuf) {
158 buf = this->hidden->mixbuf;
163 var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels;
164 if (numChannels == 1) {
165 var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(0);
166 if (channelData.length != $1) {
167 throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length +
' samples vs expected ' + $1 +
' samples!';
169 for (var
j = 0;
j < $1; ++
j) {
170 setValue($0 + (
j * 4), channelData[
j],
'float');
173 for (var
c = 0;
c < numChannels; ++
c) {
174 var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(
c);
175 if (channelData.length != $1) {
176 throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length +
' samples vs expected ' + $1 +
' samples!';
179 for (var
j = 0;
j < $1; ++
j) {
180 setValue($0 + (((
j * numChannels) +
c) * 4), channelData[
j],
'float');
188 if (this->convert.needed) {
199 EMSCRIPTENAUDIO_CloseDevice(
_THIS)
203 if (SDL2.capture.silenceTimer !== undefined) {
204 clearTimeout(SDL2.capture.silenceTimer);
206 if (SDL2.capture.stream !== undefined) {
207 var tracks = SDL2.capture.stream.getAudioTracks();
208 for (var i = 0; i < tracks.length; i++) {
209 SDL2.capture.stream.removeTrack(tracks[i]);
211 SDL2.capture.stream = undefined;
213 if (SDL2.capture.scriptProcessorNode !== undefined) {
214 SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {};
215 SDL2.capture.scriptProcessorNode.disconnect();
216 SDL2.capture.scriptProcessorNode = undefined;
218 if (SDL2.capture.mediaStreamNode !== undefined) {
219 SDL2.capture.mediaStreamNode.disconnect();
220 SDL2.capture.mediaStreamNode = undefined;
222 if (SDL2.capture.silenceBuffer !== undefined) {
223 SDL2.capture.silenceBuffer = undefined
225 SDL2.capture = undefined;
227 if (SDL2.audio.scriptProcessorNode != undefined) {
228 SDL2.audio.scriptProcessorNode.disconnect();
229 SDL2.audio.scriptProcessorNode = undefined;
231 SDL2.audio = undefined;
233 if ((SDL2.audioContext !== undefined) && (SDL2.audio === undefined) && (SDL2.capture === undefined)) {
234 SDL2.audioContext.close();
235 SDL2.audioContext = undefined;
244 EMSCRIPTENAUDIO_OpenDevice(
_THIS,
void *handle,
const char *devname,
int iscapture)
255 result = EM_ASM_INT({
256 if(typeof(SDL2) ===
'undefined') {
265 if (!SDL2.audioContext) {
266 if (typeof(AudioContext) !==
'undefined') {
267 SDL2.audioContext = new AudioContext();
268 }
else if (typeof(webkitAudioContext) !==
'undefined') {
269 SDL2.audioContext =
new webkitAudioContext();
272 return SDL2.audioContext === undefined ? -1 : 0;
279 while ((!valid_format) && (test_format)) {
280 switch (test_format) {
298 if (this->hidden ==
NULL) {
304 const int sampleRate = EM_ASM_INT_V({
305 return SDL2.audioContext.sampleRate;
310 f = (float)i / (
float)sampleRate * (float)this->
spec.
freq;
312 this->hidden->conv_in_len =
SDL_floor(f);
340 var have_microphone =
function(
stream) {
342 if (SDL2.capture.silenceTimer !== undefined) {
343 clearTimeout(SDL2.capture.silenceTimer);
344 SDL2.capture.silenceTimer = undefined;
346 SDL2.capture.mediaStreamNode = SDL2.audioContext.createMediaStreamSource(
stream);
347 SDL2.capture.scriptProcessorNode = SDL2.audioContext.createScriptProcessor($1, $0, 1);
348 SDL2.capture.scriptProcessorNode.onaudioprocess =
function(audioProcessingEvent) {
349 if ((SDL2 === undefined) || (SDL2.capture === undefined)) {
return; }
350 audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0);
351 SDL2.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer;
352 Runtime.dynCall(
'vi', $2, [$3]);
354 SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode);
355 SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination);
356 SDL2.capture.stream =
stream;
359 var no_microphone =
function(error) {
364 SDL2.capture.silenceBuffer = SDL2.audioContext.createBuffer($0, $1, SDL2.audioContext.sampleRate);
365 SDL2.capture.silenceBuffer.getChannelData(0).fill(0.0);
366 var silence_callback =
function() {
367 SDL2.capture.currentCaptureBuffer = SDL2.capture.silenceBuffer;
368 Runtime.dynCall(
'vi', $2, [$3]);
371 SDL2.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000);
373 if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) {
374 navigator.mediaDevices.getUserMedia({
audio:
true, video:
false }).then(have_microphone).catch(no_microphone);
375 }
else if (navigator.webkitGetUserMedia !== undefined) {
376 navigator.webkitGetUserMedia({
audio:
true, video:
false }, have_microphone, no_microphone);
382 SDL2.audio.scriptProcessorNode = SDL2.audioContext[
'createScriptProcessor']($1, 0, $0);
383 SDL2.audio.scriptProcessorNode[
'onaudioprocess'] =
function (
e) {
384 if ((SDL2 === undefined) || (SDL2.audio === undefined)) {
return; }
385 SDL2.audio.currentOutputBuffer =
e[
'outputBuffer'];
386 Runtime.dynCall(
'vi', $2, [$3]);
388 SDL2.audio.scriptProcessorNode[
'connect'](SDL2.audioContext[
'destination']);
399 impl->
OpenDevice = EMSCRIPTENAUDIO_OpenDevice;
409 const int available = EM_ASM_INT_V({
410 if (typeof(AudioContext) !==
'undefined') {
412 }
else if (typeof(webkitAudioContext) !==
'undefined') {
422 const int capture_available = available && EM_ASM_INT_V({
423 if ((typeof(navigator.mediaDevices) !==
'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !==
'undefined')) {
425 }
else if (typeof(navigator.webkitGetUserMedia) !==
'undefined') {
438 "emscripten",
"SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, 0
SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format)
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 Uint32 * e
int ProvidesOwnCallbackThread
Uint16 SDL_AudioFormat
Audio format flags.
int OnlyHasDefaultCaptureDevice
SDL_AudioFormat SDL_NextAudioFormat(void)
int OnlyHasDefaultOutputDevice
uint8_t Uint8
An unsigned 8-bit integer type.
#define SDL_AUDIO_BITSIZE(x)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
SDL_AudioCallback callback
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLenum GLsizei const GLuint GLboolean enabled
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
int(* OpenDevice)(_THIS, void *handle, const char *devname, int iscapture)
#define SDL_OutOfMemory()
void(* CloseDevice)(_THIS)
AudioBootStrap EMSCRIPTENAUDIO_bootstrap