From ee099750079ed30326dd6e3be0df32f2d68d474c Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 Aug 2016 00:18:56 -0400 Subject: [PATCH 01/55] audio: Initial bits to enable audio capture support. --- .hgignore | 1 + src/audio/SDL_audio.c | 2 +- test/Makefile.in | 4 + test/testaudiocapture.c | 161 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 test/testaudiocapture.c diff --git a/.hgignore b/.hgignore index 84122f80f9deb..fc65a7f0c65a8 100644 --- a/.hgignore +++ b/.hgignore @@ -120,6 +120,7 @@ test/testbounds test/torturethread test/testdisplayinfo test/testqsort +test/testaudiocapture test/*.exe test/*.dSYM buildbot diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 05674eb863b33..eb1dd5e92e8e1 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -317,7 +317,7 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, static SDL_INLINE int add_capture_device(const char *name, void *handle) { - /* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/ + SDL_assert(current_audio.impl.HasCaptureSupport); return add_audio_device(name, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount); } diff --git a/test/Makefile.in b/test/Makefile.in index b5fbc737c268c..68f0d3dabd348 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -13,6 +13,7 @@ TARGETS = \ loopwavequeue$(EXE) \ testatomic$(EXE) \ testaudioinfo$(EXE) \ + testaudiocapture$(EXE) \ testautomation$(EXE) \ testbounds$(EXE) \ testcustomcursor$(EXE) \ @@ -113,6 +114,9 @@ testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c testaudiohotplug$(EXE): $(srcdir)/testaudiohotplug.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) +testaudiocapture$(EXE): $(srcdir)/testaudiocapture.c + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + testatomic$(EXE): $(srcdir)/testatomic.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c new file mode 100644 index 0000000000000..ce96c61001a4d --- /dev/null +++ b/test/testaudiocapture.c @@ -0,0 +1,161 @@ +/* + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ +#include "SDL.h" + +#ifdef __EMSCRIPTEN__ +#include +#endif + +#define CAPTURE_SECONDS 5 + +static SDL_AudioSpec spec; +static Uint8 *sound = NULL; /* Pointer to wave data */ +static Uint32 soundlen = 0; /* Length of wave data */ +static Uint32 processed = 0; +static SDL_AudioDeviceID devid = 0; + +void SDLCALL +capture_callback(void *arg, Uint8 * stream, int len) +{ + const int avail = (int) (soundlen - processed); + if (len > avail) { + len = avail; + } + + /*SDL_Log("CAPTURE CALLBACK: %d more bytes\n", len);*/ + SDL_memcpy(sound + processed, stream, len); + processed += len; +} + +void SDLCALL +play_callback(void *arg, Uint8 * stream, int len) +{ + const Uint8 *waveptr = sound + processed; + const int avail = soundlen - processed; + int cpy = len; + if (cpy > avail) { + cpy = avail; + } + + /*SDL_Log("PLAY CALLBACK: %d more bytes\n", cpy);*/ + SDL_memcpy(stream, waveptr, cpy); + processed += cpy; + + len -= cpy; + if (len > 0) { + SDL_memset(stream + cpy, spec.silence, len); + } +} + +static void +loop() +{ + SDL_Event e; + SDL_bool please_quit = SDL_FALSE; + + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) { + please_quit = SDL_TRUE; + } + } + + if ((!please_quit) && (processed >= soundlen)) { + processed = 0; + if (spec.callback == capture_callback) { + SDL_Log("Done recording, playing back...\n"); + SDL_PauseAudioDevice(devid, 1); + SDL_CloseAudioDevice(devid); + + spec.callback = play_callback; + devid = SDL_OpenAudioDevice(NULL, 0, &spec, &spec, 0); + if (!devid) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for playback!\n"); + SDL_Quit(); + exit(1); + } + + SDL_PauseAudioDevice(devid, 0); + } else { + SDL_Log("Done playing back.\n"); + please_quit = SDL_TRUE; + } + } + + if (please_quit) { + /* stop playing back, quit. */ + SDL_Log("Shutting down.\n"); + SDL_PauseAudioDevice(devid, 1); + SDL_CloseAudioDevice(devid); + SDL_free(sound); + sound = NULL; + SDL_Quit(); + #ifdef __EMSCRIPTEN__ + emscripten_cancel_main_loop(); + #endif + exit(0); + } +} + +int +main(int argc, char **argv) +{ + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + /* Load the SDL library */ + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + return (1); + } + + /* Android apparently needs a window...? */ + #ifdef __ANDROID__ + SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0); + #endif + + SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + + SDL_zero(spec); + spec.freq = 44100; + spec.format = AUDIO_F32SYS; + spec.channels = 1; + spec.samples = 1024; + spec.callback = capture_callback; + + soundlen = spec.freq * (SDL_AUDIO_BITSIZE(spec.format) / 8) * spec.channels * CAPTURE_SECONDS; + sound = (Uint8 *) SDL_malloc(soundlen); + if (!sound) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n"); + SDL_Quit(); + return 1; + } + + devid = SDL_OpenAudioDevice(NULL, 1, &spec, &spec, 0); + if (!devid) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError()); + SDL_free(sound); + SDL_Quit(); + exit(1); + } + + SDL_Log("Recording for %d seconds...\n", CAPTURE_SECONDS); + SDL_PauseAudioDevice(devid, 0); + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (1) { loop(); SDL_Delay(16); } +#endif + + return 0; +} + From 015dd8dd1d9db9cbf4db174a3e842824b1d4d8e5 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 Aug 2016 00:20:47 -0400 Subject: [PATCH 02/55] audio: Implemented capture support for Mac OS X CoreAudio. I don't know what iOS wants yet, so this code might work there, too...? --- src/audio/coreaudio/SDL_coreaudio.c | 142 +++++++++++++++++++++++----- src/audio/coreaudio/SDL_coreaudio.h | 1 + 2 files changed, 118 insertions(+), 25 deletions(-) diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index 3641d530c7464..3bf66d618e1e7 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -185,7 +185,7 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) #if DEBUG_COREAUDIO printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n", ((iscapture) ? "capture" : "output"), - (int) *devCount, ptr, (int) dev); + (int) i, ptr, (int) dev); #endif addfn(ptr, iscapture, dev, addfndata); } @@ -324,18 +324,52 @@ outputCallback(void *inRefCon, } } - return 0; + return noErr; } static OSStatus inputCallback(void *inRefCon, - AudioUnitRenderActionFlags * ioActionFlags, - const AudioTimeStamp * inTimeStamp, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, - AudioBufferList * ioData) + AudioBufferList *ioData) { - /* err = AudioUnitRender(afr->fAudioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, afr->fAudioBuffer); */ - /* !!! FIXME: write me! */ + SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon; + if (!this->enabled || this->paused) { + return noErr; /* just drop this if we're not accepting input. */ + } + + const OSStatus err = AudioUnitRender(this->hidden->audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &this->hidden->captureBufferList); + SDL_assert(this->hidden->captureBufferList.mNumberBuffers == 1); + + if (err == noErr) { + const AudioBuffer *abuf = &this->hidden->captureBufferList.mBuffers[0]; + UInt32 remaining = abuf->mDataByteSize; + const Uint8 *ptr = (const Uint8 *) abuf->mData; + + /* No SDL conversion should be needed here, ever, since we accept + any input format in OpenAudio, and leave the conversion to CoreAudio. + */ + while (remaining > 0) { + UInt32 len = this->hidden->bufferSize - this->hidden->bufferOffset; + if (len > remaining) + len = remaining; + + SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len); + ptr += len; + remaining -= len; + this->hidden->bufferOffset += len; + + if (this->hidden->bufferOffset >= this->hidden->bufferSize) { + SDL_LockMutex(this->mixer_lock); + (*this->spec.callback)(this->spec.userdata, + this->hidden->buffer, this->hidden->bufferSize); + SDL_UnlockMutex(this->mixer_lock); + this->hidden->bufferOffset = 0; + } + } + } + return noErr; } @@ -394,20 +428,21 @@ COREAUDIO_CloseDevice(_THIS) const int iscapture = this->iscapture; const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus); - const AudioUnitScope scope = - ((iscapture) ? kAudioUnitScope_Output : - kAudioUnitScope_Input); /* stop processing the audio unit */ AudioOutputUnitStop(this->hidden->audioUnit); /* Remove the input callback */ - SDL_memset(&callback, 0, sizeof(AURenderCallbackStruct)); + SDL_zero(callback); AudioUnitSetProperty(this->hidden->audioUnit, - kAudioUnitProperty_SetRenderCallback, - scope, bus, &callback, sizeof(callback)); + iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Global, bus, &callback, sizeof(callback)); AudioComponentInstanceDispose(this->hidden->audioUnit); this->hidden->audioUnitOpened = 0; + + #if MACOSX_COREAUDIO + SDL_free(this->hidden->captureBufferList.mBuffers[0].mData); + #endif } SDL_free(this->hidden->buffer); SDL_free(this->hidden); @@ -480,9 +515,6 @@ prepare_audiounit(_THIS, void *handle, int iscapture, AudioComponent comp = NULL; const AudioUnitElement output_bus = 0; const AudioUnitElement input_bus = 1; - const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus); - const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output : - kAudioUnitScope_Input); #if MACOSX_COREAUDIO if (!prepare_device(this, handle, iscapture)) { @@ -495,7 +527,7 @@ prepare_audiounit(_THIS, void *handle, int iscapture, desc.componentManufacturer = kAudioUnitManufacturer_Apple; #if MACOSX_COREAUDIO - desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentSubType = iscapture ? kAudioUnitSubType_HALOutput : kAudioUnitSubType_DefaultOutput; #else desc.componentSubType = kAudioUnitSubType_RemoteIO; #endif @@ -513,9 +545,28 @@ prepare_audiounit(_THIS, void *handle, int iscapture, this->hidden->audioUnitOpened = 1; #if MACOSX_COREAUDIO + if (iscapture) { /* have to do EnableIO only for capture devices. */ + UInt32 enable = 1; + result = AudioUnitSetProperty(this->hidden->audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, input_bus, + &enable, sizeof (enable)); + CHECK_RESULT + ("AudioUnitSetProperty (kAudioOutputUnitProperty_EnableIO input bus)"); + + enable = 0; + result = AudioUnitSetProperty(this->hidden->audioUnit, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, output_bus, + &enable, sizeof (enable)); + CHECK_RESULT + ("AudioUnitSetProperty (kAudioOutputUnitProperty_EnableIO output bus)"); + } + + /* this is always on the output_bus, even for capture devices. */ result = AudioUnitSetProperty(this->hidden->audioUnit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, + kAudioUnitScope_Global, output_bus, &this->hidden->deviceID, sizeof(AudioDeviceID)); CHECK_RESULT @@ -525,16 +576,47 @@ prepare_audiounit(_THIS, void *handle, int iscapture, /* Set the data format of the audio unit. */ result = AudioUnitSetProperty(this->hidden->audioUnit, kAudioUnitProperty_StreamFormat, - scope, bus, strdesc, sizeof(*strdesc)); + iscapture ? kAudioUnitScope_Output : kAudioUnitScope_Input, + iscapture ? input_bus : output_bus, + strdesc, sizeof (*strdesc)); CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)"); +#if MACOSX_COREAUDIO + if (iscapture) { /* only need to do this for capture devices. */ + void *ptr; + UInt32 framesize = 0; + UInt32 propsize = sizeof (UInt32); + + result = AudioUnitGetProperty(this->hidden->audioUnit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, output_bus, + &framesize, &propsize); + CHECK_RESULT + ("AudioUnitGetProperty (kAudioDevicePropertyBufferFrameSize)"); + + framesize *= SDL_AUDIO_BITSIZE(this->spec.format) / 8; + ptr = SDL_calloc(1, framesize); + if (ptr == NULL) { + COREAUDIO_CloseDevice(this); + SDL_OutOfMemory(); + return 0; + } + + this->hidden->captureBufferList.mNumberBuffers = 1; + this->hidden->captureBufferList.mBuffers[0].mNumberChannels = this->spec.channels; + this->hidden->captureBufferList.mBuffers[0].mDataByteSize = framesize; + this->hidden->captureBufferList.mBuffers[0].mData = ptr; + } +#endif + /* Set the audio callback */ - SDL_memset(&callback, 0, sizeof(AURenderCallbackStruct)); + SDL_zero(callback); callback.inputProc = ((iscapture) ? inputCallback : outputCallback); callback.inputProcRefCon = this; + result = AudioUnitSetProperty(this->hidden->audioUnit, - kAudioUnitProperty_SetRenderCallback, - scope, bus, &callback, sizeof(callback)); + iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Global, output_bus, &callback, sizeof(callback)); CHECK_RESULT ("AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)"); @@ -542,8 +624,15 @@ prepare_audiounit(_THIS, void *handle, int iscapture, SDL_CalculateAudioSpec(&this->spec); /* Allocate a sample buffer */ - this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size; + this->hidden->bufferSize = this->spec.size; + this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize; + this->hidden->buffer = SDL_malloc(this->hidden->bufferSize); + if (this->hidden->buffer == NULL) { + COREAUDIO_CloseDevice(this); + SDL_OutOfMemory(); + return 0; + } result = AudioUnitInitialize(this->hidden->audioUnit); CHECK_RESULT("AudioUnitInitialize"); @@ -552,6 +641,8 @@ prepare_audiounit(_THIS, void *handle, int iscapture, result = AudioOutputUnitStart(this->hidden->audioUnit); CHECK_RESULT("AudioOutputUnitStart"); +/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */ +/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */ #if MACOSX_COREAUDIO /* Fire a callback if the device stops being "alive" (disconnected, etc). */ AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); @@ -575,10 +666,10 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Setup a AudioStreamBasicDescription with the requested format */ - SDL_memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription)); + SDL_zero(strdesc); strdesc.mFormatID = kAudioFormatLinearPCM; strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked; strdesc.mChannelsPerFrame = this->spec.channels; @@ -651,6 +742,7 @@ COREAUDIO_Init(SDL_AudioDriverImpl * impl) #if MACOSX_COREAUDIO impl->DetectDevices = COREAUDIO_DetectDevices; AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL); + impl->HasCaptureSupport = 1; #else impl->OnlyHasDefaultOutputDevice = 1; diff --git a/src/audio/coreaudio/SDL_coreaudio.h b/src/audio/coreaudio/SDL_coreaudio.h index 577f9fb320995..95e1215619487 100644 --- a/src/audio/coreaudio/SDL_coreaudio.h +++ b/src/audio/coreaudio/SDL_coreaudio.h @@ -50,6 +50,7 @@ struct SDL_PrivateAudioData UInt32 bufferSize; #if MACOSX_COREAUDIO AudioDeviceID deviceID; + AudioBufferList captureBufferList; #endif }; From c754662dda0d9c5698e7ebb5f8dfafc8efa914e4 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 Aug 2016 11:45:45 -0400 Subject: [PATCH 03/55] audio: Make SDL_AudioDevice::shutdown an atomic value. Just to make sure this get communicated to the audio thread properly. --- src/audio/SDL_audio.c | 6 +++--- src/audio/SDL_sysaudio.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index eb1dd5e92e8e1..b7dab5c947642 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -103,7 +103,7 @@ static const AudioBootStrap *const bootstrap[] = { &ESD_bootstrap, #endif #if SDL_AUDIO_DRIVER_NACL - &NACLAUD_bootstrap, + &NACLAUD_bootstrap, #endif #if SDL_AUDIO_DRIVER_NAS &NAS_bootstrap, @@ -611,7 +611,7 @@ SDL_RunAudio(void *devicep) current_audio.impl.ThreadInit(device); /* Loop, filling the audio buffers */ - while (!device->shutdown) { + while (!SDL_AtomicGet(&device->shutdown)) { /* Fill the current buffer with sound */ if (device->convert.needed) { stream = device->convert.buf; @@ -874,7 +874,7 @@ static void close_audio_device(SDL_AudioDevice * device) { device->enabled = 0; - device->shutdown = 1; + SDL_AtomicSet(&device->shutdown, 1); if (device->thread != NULL) { SDL_WaitThread(device->thread, NULL); } diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 426a190f18516..3fb4c5cb4987b 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -157,10 +157,10 @@ struct SDL_AudioDevice SDL_AudioStreamer streamer; /* Current state flags */ - /* !!! FIXME: should be SDL_bool */ + SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */ + /* !!! FIXME: these should be SDL_bool */ int iscapture; int enabled; /* true if device is functioning and connected. */ - int shutdown; /* true if we are signaling the play thread to end. */ int paused; int opened; From a94376c72dd569a3be971e4745676265d821b74f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 Aug 2016 11:47:02 -0400 Subject: [PATCH 04/55] nacl: unlock audio thread mutex when done with it. --- src/audio/nacl/SDL_naclaudio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index 2d1ee73e9d90f..450a369b4a023 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -51,7 +51,7 @@ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelt static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data) { SDL_AudioDevice* _this = (SDL_AudioDevice*) data; - SDL_LockMutex(private->mutex); + SDL_LockMutex(private->mutex); /* !!! FIXME: is this mutex necessary? */ if (_this->enabled && !_this->paused) { if (_this->convert.needed) { @@ -71,7 +71,7 @@ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelt SDL_memset(samples, 0, buffer_size); } - return; + SDL_UnlockMutex(private->mutex); } static void NACLAUD_CloseDevice(SDL_AudioDevice *device) { From 67f2538c41664f66f06d42df8e875e99883ea962 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 Aug 2016 13:32:27 -0400 Subject: [PATCH 05/55] audio: changed some internal ints to be SDL_bools. --- src/audio/SDL_audio.c | 17 +++++++++-------- src/audio/SDL_sysaudio.h | 9 ++++----- src/audio/qsa/SDL_qsa_audio.c | 2 +- src/audio/qsa/SDL_qsa_audio.h | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index b7dab5c947642..8fee9dccc18b6 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -373,7 +373,7 @@ void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device) /* Ends the audio callback and mark the device as STOPPED, but the app still needs to close the device to free resources. */ current_audio.impl.LockDevice(device); - device->enabled = 0; + device->enabled = SDL_FALSE; current_audio.impl.UnlockDevice(device); /* Post the event, if desired */ @@ -873,7 +873,7 @@ SDL_GetAudioDeviceName(int index, int iscapture) static void close_audio_device(SDL_AudioDevice * device) { - device->enabled = 0; + device->enabled = SDL_FALSE; SDL_AtomicSet(&device->shutdown, 1); if (device->thread != NULL) { SDL_WaitThread(device->thread, NULL); @@ -887,7 +887,7 @@ close_audio_device(SDL_AudioDevice * device) } if (device->opened) { current_audio.impl.CloseDevice(device); - device->opened = 0; + device->opened = SDL_FALSE; } free_audio_queue(device->buffer_queue_head); @@ -1074,11 +1074,12 @@ open_audio_device(const char *devname, int iscapture, return 0; } SDL_zerop(device); + SDL_AtomicSet(&device->shutdown, 0); /* just in case. */ device->id = id + 1; device->spec = *obtained; - device->enabled = 1; - device->paused = 1; - device->iscapture = iscapture; + device->enabled = SDL_TRUE; + device->paused = SDL_TRUE; + device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE; /* Create a mutex for locking the sound buffers */ if (!current_audio.impl.SkipMixerLock) { @@ -1094,7 +1095,7 @@ open_audio_device(const char *devname, int iscapture, close_audio_device(device); return 0; } - device->opened = 1; + device->opened = SDL_TRUE; /* See if we need to do any conversion */ build_cvt = SDL_FALSE; @@ -1278,7 +1279,7 @@ SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on) SDL_AudioDevice *device = get_audio_device(devid); if (device) { current_audio.impl.LockDevice(device); - device->paused = pause_on; + device->paused = pause_on ? SDL_TRUE : SDL_FALSE; current_audio.impl.UnlockDevice(device); } } diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 3fb4c5cb4987b..fcf441d0ef595 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -158,11 +158,10 @@ struct SDL_AudioDevice /* Current state flags */ SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */ - /* !!! FIXME: these should be SDL_bool */ - int iscapture; - int enabled; /* true if device is functioning and connected. */ - int paused; - int opened; + SDL_bool iscapture; + SDL_bool enabled; /* true if device is functioning and connected. */ + SDL_bool paused; + SDL_bool opened; /* Fake audio buffer for when the audio hardware is busy */ Uint8 *fake_stream; diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index 1899ca6d94b1c..1742fe3f619ea 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -371,7 +371,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) QSA_InitAudioParams(&cparams); /* Initialize channel direction: capture or playback */ - this->hidden->iscapture = iscapture; + this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE; if (device != NULL) { /* Open requested audio device */ diff --git a/src/audio/qsa/SDL_qsa_audio.h b/src/audio/qsa/SDL_qsa_audio.h index 53d37e96fd41f..19a2215aada77 100644 --- a/src/audio/qsa/SDL_qsa_audio.h +++ b/src/audio/qsa/SDL_qsa_audio.h @@ -34,7 +34,7 @@ struct SDL_PrivateAudioData { /* SDL capture state */ - int iscapture; + SDL_bool iscapture; /* The audio device handle */ int cardno; From ca57b9ee111c454d937c78fe8c4a57ce065c30f4 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 Aug 2016 13:36:43 -0400 Subject: [PATCH 06/55] BUGS.txt: Bugzilla supports SSL; changed link to https:// ... --- BUGS.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUGS.txt b/BUGS.txt index 7ef5538752094..aa52e61fdd06f 100644 --- a/BUGS.txt +++ b/BUGS.txt @@ -1,7 +1,7 @@ Bugs are now managed in the SDL bug tracker, here: - http://bugzilla.libsdl.org/ + https://bugzilla.libsdl.org/ You may report bugs there, and search to see if a given issue has already been reported, discussed, and maybe even fixed. From b35b9f950e9aaf3a925760be7b116f9aea297a61 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Aug 2016 13:38:56 -0400 Subject: [PATCH 07/55] testaudiocapture: Let specific devices be opened. --- test/testaudiocapture.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c index ce96c61001a4d..30742f96b36f2 100644 --- a/test/testaudiocapture.c +++ b/test/testaudiocapture.c @@ -108,6 +108,11 @@ loop() int main(int argc, char **argv) { + /* (argv[1] == NULL means "open default device.") */ + const char *devname = argv[1]; + int devcount; + int i; + /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -124,6 +129,11 @@ main(int argc, char **argv) SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + devcount = SDL_GetNumAudioDevices(SDL_TRUE); + for (i = 0; i < devcount; i++) { + SDL_Log(" Capture device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_TRUE)); + } + SDL_zero(spec); spec.freq = 44100; spec.format = AUDIO_F32SYS; @@ -139,7 +149,12 @@ main(int argc, char **argv) return 1; } - devid = SDL_OpenAudioDevice(NULL, 1, &spec, &spec, 0); + SDL_Log("Opening device %s%s%s...\n", + devname ? "'" : "", + devname ? devname : "[[default]]", + devname ? "'" : ""); + + devid = SDL_OpenAudioDevice(argv[1], SDL_TRUE, &spec, &spec, 0); if (!devid) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError()); SDL_free(sound); From 6d5c9c1e675718716cc117c6d8a71ce0c0818de2 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Aug 2016 13:48:52 -0400 Subject: [PATCH 08/55] audio: Made some SDL_AudioDevice fields atomic. This makes sure they're properly communicated to the audio threads. --- src/audio/SDL_audio.c | 25 +++++++++++----------- src/audio/SDL_sysaudio.h | 6 +++--- src/audio/alsa/SDL_alsa_audio.c | 2 +- src/audio/android/SDL_androidaudio.c | 6 +++--- src/audio/coreaudio/SDL_coreaudio.c | 6 +++--- src/audio/emscripten/SDL_emscriptenaudio.c | 8 +++---- src/audio/haiku/SDL_haikuaudio.cc | 5 +++-- src/audio/nacl/SDL_naclaudio.c | 2 +- src/audio/pulseaudio/SDL_pulseaudio.c | 6 +++--- src/audio/qsa/SDL_qsa_audio.c | 4 ++-- src/audio/xaudio2/SDL_xaudio2.c | 6 +++--- 11 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 8fee9dccc18b6..934652a8e5f02 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -366,14 +366,14 @@ void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device) { SDL_assert(get_audio_device(device->id) == device); - if (!device->enabled) { + if (!SDL_AtomicGet(&device->enabled)) { return; } /* Ends the audio callback and mark the device as STOPPED, but the app still needs to close the device to free resources. */ current_audio.impl.LockDevice(device); - device->enabled = SDL_FALSE; + SDL_AtomicSet(&device->enabled, 0); current_audio.impl.UnlockDevice(device); /* Post the event, if desired */ @@ -615,7 +615,7 @@ SDL_RunAudio(void *devicep) /* Fill the current buffer with sound */ if (device->convert.needed) { stream = device->convert.buf; - } else if (device->enabled) { + } else if (SDL_AtomicGet(&device->enabled)) { stream = current_audio.impl.GetDeviceBuf(device); } else { /* if the device isn't enabled, we still write to the @@ -632,7 +632,7 @@ SDL_RunAudio(void *devicep) /* !!! FIXME: this should be LockDevice. */ SDL_LockMutex(device->mixer_lock); - if (device->paused) { + if (SDL_AtomicGet(&device->paused)) { SDL_memset(stream, silence, stream_len); } else { (*fill) (udata, stream, stream_len); @@ -640,7 +640,7 @@ SDL_RunAudio(void *devicep) SDL_UnlockMutex(device->mixer_lock); /* Convert the audio if necessary */ - if (device->enabled && device->convert.needed) { + if (device->convert.needed && SDL_AtomicGet(&device->enabled)) { SDL_ConvertAudio(&device->convert); stream = current_audio.impl.GetDeviceBuf(device); if (stream == NULL) { @@ -873,8 +873,8 @@ SDL_GetAudioDeviceName(int index, int iscapture) static void close_audio_device(SDL_AudioDevice * device) { - device->enabled = SDL_FALSE; SDL_AtomicSet(&device->shutdown, 1); + SDL_AtomicSet(&device->enabled, 0); if (device->thread != NULL) { SDL_WaitThread(device->thread, NULL); } @@ -1074,13 +1074,14 @@ open_audio_device(const char *devname, int iscapture, return 0; } SDL_zerop(device); - SDL_AtomicSet(&device->shutdown, 0); /* just in case. */ device->id = id + 1; device->spec = *obtained; - device->enabled = SDL_TRUE; - device->paused = SDL_TRUE; device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE; + SDL_AtomicSet(&device->shutdown, 0); /* just in case. */ + SDL_AtomicSet(&device->paused, 1); + SDL_AtomicSet(&device->enabled, 1); + /* Create a mutex for locking the sound buffers */ if (!current_audio.impl.SkipMixerLock) { device->mixer_lock = SDL_CreateMutex(); @@ -1256,8 +1257,8 @@ SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid) { SDL_AudioDevice *device = get_audio_device(devid); SDL_AudioStatus status = SDL_AUDIO_STOPPED; - if (device && device->enabled) { - if (device->paused) { + if (device && SDL_AtomicGet(&device->enabled)) { + if (SDL_AtomicGet(&device->paused)) { status = SDL_AUDIO_PAUSED; } else { status = SDL_AUDIO_PLAYING; @@ -1279,7 +1280,7 @@ SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on) SDL_AudioDevice *device = get_audio_device(devid); if (device) { current_audio.impl.LockDevice(device); - device->paused = pause_on ? SDL_TRUE : SDL_FALSE; + SDL_AtomicSet(&device->paused, pause_on ? 1 : 0); current_audio.impl.UnlockDevice(device); } } diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index fcf441d0ef595..0b35b27544ce9 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -158,10 +158,10 @@ struct SDL_AudioDevice /* Current state flags */ SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */ - SDL_bool iscapture; - SDL_bool enabled; /* true if device is functioning and connected. */ - SDL_bool paused; + SDL_atomic_t enabled; /* true if device is functioning and connected. */ + SDL_atomic_t paused; SDL_bool opened; + SDL_bool iscapture; /* Fake audio buffer for when the audio hardware is busy */ Uint8 *fake_stream; diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 1a84380f2fa35..e9f672f8c1fee 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -311,7 +311,7 @@ ALSA_PlayDevice(_THIS) swizzle_alsa_channels(this); - while ( frames_left > 0 && this->enabled ) { + while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) { /* !!! FIXME: This works, but needs more testing before going live */ /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */ status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index 4a4faadcfbc5f..047793a6078fb 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -151,13 +151,13 @@ void AndroidAUD_PauseDevices(void) struct SDL_PrivateAudioData *private; if(audioDevice != NULL && audioDevice->hidden != NULL) { private = (struct SDL_PrivateAudioData *) audioDevice->hidden; - if (audioDevice->paused) { + if (SDL_AtomicGet(&audioDevice->paused)) { /* The device is already paused, leave it alone */ private->resume = SDL_FALSE; } else { SDL_LockMutex(audioDevice->mixer_lock); - audioDevice->paused = SDL_TRUE; + SDL_AtomicSet(&audioDevice->paused, 1); private->resume = SDL_TRUE; } } @@ -171,7 +171,7 @@ void AndroidAUD_ResumeDevices(void) if(audioDevice != NULL && audioDevice->hidden != NULL) { private = (struct SDL_PrivateAudioData *) audioDevice->hidden; if (private->resume) { - audioDevice->paused = SDL_FALSE; + SDL_AtomicSet(&audioDevice->paused, 0); private->resume = SDL_FALSE; SDL_UnlockMutex(audioDevice->mixer_lock); } diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index 3bf66d618e1e7..2385995fd0038 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -283,7 +283,7 @@ outputCallback(void *inRefCon, UInt32 i; /* Only do anything if audio is enabled and not paused */ - if (!this->enabled || this->paused) { + if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { for (i = 0; i < ioData->mNumberBuffers; i++) { abuf = &ioData->mBuffers[i]; SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize); @@ -335,7 +335,7 @@ inputCallback(void *inRefCon, AudioBufferList *ioData) { SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon; - if (!this->enabled || this->paused) { + if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { return noErr; /* just drop this if we're not accepting input. */ } @@ -391,7 +391,7 @@ device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectProperty UInt32 size = sizeof (isAlive); OSStatus error; - if (!this->enabled) { + if (!SDL_AtomicGet(&this->enabled)) { return 0; /* already known to be dead. */ } diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c index 8378233ca22ce..ea42723c28973 100644 --- a/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -63,12 +63,10 @@ HandleAudioProcess(_THIS) int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8; int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8; - /* Only do soemthing if audio is enabled */ - if (!this->enabled) - return; - - if (this->paused) + /* Only do something if audio is enabled */ + if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { return; + } if (this->convert.needed) { if (this->hidden->conv_in_len != 0) { diff --git a/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc index 38f3b962188c7..de364b0ef2bb5 100644 --- a/src/audio/haiku/SDL_haikuaudio.cc +++ b/src/audio/haiku/SDL_haikuaudio.cc @@ -49,10 +49,11 @@ FillSound(void *device, void *stream, size_t len, SDL_AudioDevice *audio = (SDL_AudioDevice *) device; /* Only do soemthing if audio is enabled */ - if (!audio->enabled) + if (!SDL_AtomicGet(&audio->enabled)) { return; + } - if (!audio->paused) { + if (!SDL_AtomicGet(&audio->paused)) { if (audio->convert.needed) { SDL_LockMutex(audio->mixer_lock); (*audio->spec.callback) (audio->spec.userdata, diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index 450a369b4a023..8f1c51ac51622 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -53,7 +53,7 @@ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelt SDL_LockMutex(private->mutex); /* !!! FIXME: is this mutex necessary? */ - if (_this->enabled && !_this->paused) { + if (SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) { if (_this->convert.needed) { SDL_LockMutex(_this->mixer_lock); (*_this->spec.callback) (_this->spec.userdata, diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index fdf38c8177a8b..4fed80963ccc4 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -326,7 +326,7 @@ PULSEAUDIO_WaitDevice(_THIS) { struct SDL_PrivateAudioData *h = this->hidden; - while (this->enabled) { + while (SDL_AtomicGet(&this->enabled)) { if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { @@ -344,7 +344,7 @@ PULSEAUDIO_PlayDevice(_THIS) { /* Write the audio data */ struct SDL_PrivateAudioData *h = this->hidden; - if (this->enabled) { + if (SDL_AtomicGet(&this->enabled)) { if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) { SDL_OpenedAudioDeviceDisconnected(this); } @@ -360,7 +360,7 @@ stream_drain_complete(pa_stream *s, int success, void *userdata) static void PULSEAUDIO_WaitDone(_THIS) { - if (this->enabled) { + if (SDL_AtomicGet(&this->enabled)) { struct SDL_PrivateAudioData *h = this->hidden; pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL); if (o) { diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index 1742fe3f619ea..88d29f9308626 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -229,7 +229,7 @@ QSA_PlayDevice(_THIS) int towrite; void *pcmbuffer; - if ((!this->enabled) || (!this->hidden)) { + if (!SDL_AtomicGet(&this->enabled) || !this->hidden) { return; } @@ -305,7 +305,7 @@ QSA_PlayDevice(_THIS) towrite -= written; pcmbuffer += written * this->spec.channels; } - } while ((towrite > 0) && (this->enabled)); + } while ((towrite > 0) && SDL_AtomicGet(&this->enabled)); /* If we couldn't write, assume fatal error for now */ if (towrite != 0) { diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c index dff234b40171c..ba9ad9fbc9e3e 100644 --- a/src/audio/xaudio2/SDL_xaudio2.c +++ b/src/audio/xaudio2/SDL_xaudio2.c @@ -195,7 +195,7 @@ XAUDIO2_PlayDevice(_THIS) IXAudio2SourceVoice *source = this->hidden->source; HRESULT result = S_OK; - if (!this->enabled) { /* shutting down? */ + if (!SDL_AtomicGet(&this->enabled)) { /* shutting down? */ return; } @@ -226,7 +226,7 @@ XAUDIO2_PlayDevice(_THIS) static void XAUDIO2_WaitDevice(_THIS) { - if (this->enabled) { + if (SDL_AtomicGet(&this->enabled)) { SDL_SemWait(this->hidden->semaphore); } } @@ -236,7 +236,7 @@ XAUDIO2_WaitDone(_THIS) { IXAudio2SourceVoice *source = this->hidden->source; XAUDIO2_VOICE_STATE state; - SDL_assert(!this->enabled); /* flag that stops playing. */ + SDL_assert(!SDL_AtomicGet(&this->enabled)); /* flag that stops playing. */ IXAudio2SourceVoice_Discontinuity(source); #if SDL_XAUDIO2_WIN8 IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED); From 0d0f7080a37958e31d0697e0ce3d87e1b97c5692 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Aug 2016 13:50:21 -0400 Subject: [PATCH 09/55] audio: implemented higher level infrastructure for running capture devices. --- src/audio/SDL_audio.c | 107 +++++++++++++++++++++++++++++++++++++-- src/audio/SDL_audio_c.h | 3 -- src/audio/SDL_sysaudio.h | 2 + 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 934652a8e5f02..b8b045a7cbee4 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -206,6 +206,17 @@ SDL_AudioWaitDone_Default(_THIS) { /* no-op. */ } +static int +SDL_AudioCaptureFromDevice_Default(_THIS, void *buffer, int buflen) +{ + return -1; /* just fail immediately. */ +} + +static void +SDL_AudioFlushCapture_Default(_THIS) +{ /* no-op. */ +} + static void SDL_AudioCloseDevice_Default(_THIS) { /* no-op. */ @@ -279,6 +290,8 @@ finalize_audio_entry_points(void) FILL_STUB(GetPendingBytes); FILL_STUB(GetDeviceBuf); FILL_STUB(WaitDone); + FILL_STUB(CaptureFromDevice); + FILL_STUB(FlushCapture); FILL_STUB(CloseDevice); FILL_STUB(LockDevice); FILL_STUB(UnlockDevice); @@ -592,7 +605,7 @@ SDL_ClearQueuedAudio(SDL_AudioDeviceID devid) /* The general mixing thread function */ -int SDLCALL +static int SDLCALL SDL_RunAudio(void *devicep) { SDL_AudioDevice *device = (SDL_AudioDevice *) devicep; @@ -601,7 +614,9 @@ SDL_RunAudio(void *devicep) const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size; Uint8 *stream; void *udata = device->spec.userdata; - void (SDLCALL *fill) (void *, Uint8 *, int) = device->spec.callback; + void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback; + + SDL_assert(!device->iscapture); /* The audio mixing is always a high priority thread */ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); @@ -635,7 +650,7 @@ SDL_RunAudio(void *devicep) if (SDL_AtomicGet(&device->paused)) { SDL_memset(stream, silence, stream_len); } else { - (*fill) (udata, stream, stream_len); + (*callback) (udata, stream, stream_len); } SDL_UnlockMutex(device->mixer_lock); @@ -661,11 +676,92 @@ SDL_RunAudio(void *devicep) } /* Wait for the audio to drain. */ + /* !!! FIXME: can we rename this WaitDrain? */ current_audio.impl.WaitDone(device); return 0; } +/* The general capture thread function */ +static int SDLCALL +SDL_CaptureAudio(void *devicep) +{ + SDL_AudioDevice *device = (SDL_AudioDevice *) devicep; + const int silence = (int) device->spec.silence; + const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq); + const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size; + Uint8 *stream; + void *udata = device->spec.userdata; + void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback; + + SDL_assert(device->iscapture); + + /* The audio mixing is always a high priority thread */ + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); + + /* Perform any thread setup */ + device->threadid = SDL_ThreadID(); + current_audio.impl.ThreadInit(device); + + /* Loop, filling the audio buffers */ + while (!SDL_AtomicGet(&device->shutdown)) { + int still_need; + Uint8 *ptr; + + if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) { + SDL_Delay(delay); /* just so we don't cook the CPU. */ + current_audio.impl.FlushCapture(device); /* dump anything pending. */ + continue; + } + + /* Fill the current buffer with sound */ + still_need = stream_len; + if (device->convert.needed) { + ptr = stream = device->convert.buf; + } else { + /* just use the "fake" stream to hold data read from the device. */ + ptr = stream = device->fake_stream; + } + + /* We still read from the device when "paused" to keep the state sane, + and block when there isn't data so this thread isn't eating CPU. + But we don't process it further or call the app's callback. */ + + while (still_need > 0) { + const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need); + SDL_assert(rc != 0); /* device should have blocked, failed, or returned data. */ + SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */ + if (rc > 0) { + still_need -= rc; + ptr += rc; + } else { /* uhoh, device failed for some reason! */ + SDL_OpenedAudioDeviceDisconnected(device); + break; + } + } + + if (still_need > 0) { + /* Keep any data we already read, silence the rest. */ + SDL_memset(ptr, silence, still_need); + } + + if (device->convert.needed) { + SDL_ConvertAudio(&device->convert); + } + + /* !!! FIXME: this should be LockDevice. */ + SDL_LockMutex(device->mixer_lock); + if (!SDL_AtomicGet(&device->paused)) { + (*callback)(udata, stream, stream_len); + } + SDL_UnlockMutex(device->mixer_lock); + } + + current_audio.impl.FlushCapture(device); + + return 0; +} + static SDL_AudioFormat SDL_ParseAudioFormat(const char *string) @@ -1198,10 +1294,11 @@ open_audio_device(const char *devname, int iscapture, /* !!! FIXME: we don't force the audio thread stack size here because it calls into user code, but maybe we should? */ /* buffer queueing callback only needs a few bytes, so make the stack tiny. */ char name[64]; - const size_t stacksize = (device->spec.callback == SDL_BufferQueueDrainCallback) ? 64 * 1024 : 0; + const SDL_bool is_internal_thread = (device->spec.callback == SDL_BufferQueueDrainCallback); + const size_t stacksize = is_internal_thread ? 64 * 1024 : 0; SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id); - device->thread = SDL_CreateThreadInternal(SDL_RunAudio, name, stacksize, device); + device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, name, stacksize, device); if (device->thread == NULL) { SDL_CloseAudioDevice(device->id); diff --git a/src/audio/SDL_audio_c.h b/src/audio/SDL_audio_c.h index b03a9156f6013..7cde3a662531d 100644 --- a/src/audio/SDL_audio_c.h +++ b/src/audio/SDL_audio_c.h @@ -29,9 +29,6 @@ extern SDL_AudioFormat SDL_NextAudioFormat(void); /* Function to calculate the size and silence for a SDL_AudioSpec */ extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec); -/* The actual mixing thread function */ -extern int SDLCALL SDL_RunAudio(void *audiop); - /* this is used internally to access some autogenerated code. */ typedef struct { diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 0b35b27544ce9..d3a48cc3741bb 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -76,6 +76,8 @@ typedef struct SDL_AudioDriverImpl int (*GetPendingBytes) (_THIS); Uint8 *(*GetDeviceBuf) (_THIS); void (*WaitDone) (_THIS); + int (*CaptureFromDevice) (_THIS, void *buffer, int buflen); + void (*FlushCapture) (_THIS); void (*CloseDevice) (_THIS); void (*LockDevice) (_THIS); void (*UnlockDevice) (_THIS); From d662bc04a53ab77ee0742025bc2543aef0e32305 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Aug 2016 13:50:58 -0400 Subject: [PATCH 10/55] pulseaudio: Implemented audio capture support! --- src/audio/pulseaudio/SDL_pulseaudio.c | 147 ++++++++++++++++++++++---- src/audio/pulseaudio/SDL_pulseaudio.h | 3 + 2 files changed, 130 insertions(+), 20 deletions(-) diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index 4fed80963ccc4..cc9a4db6c3cd2 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -100,12 +100,19 @@ static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *, const char *, const pa_sample_spec *, const pa_channel_map *); static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *, const char *, const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *); +static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *, + const pa_buffer_attr *, pa_stream_flags_t); static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *); static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *); +static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *); static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t, pa_free_cb_t, int64_t, pa_seek_mode_t); static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *, pa_stream_success_cb_t, void *); +static int (*PULSEAUDIO_pa_stream_peek) (pa_stream *, const void **, size_t *); +static int (*PULSEAUDIO_pa_stream_drop) (pa_stream *); +static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *, + pa_stream_success_cb_t, void *); static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *); static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *); @@ -206,11 +213,16 @@ load_pulseaudio_syms(void) SDL_PULSEAUDIO_SYM(pa_context_unref); SDL_PULSEAUDIO_SYM(pa_stream_new); SDL_PULSEAUDIO_SYM(pa_stream_connect_playback); + SDL_PULSEAUDIO_SYM(pa_stream_connect_record); SDL_PULSEAUDIO_SYM(pa_stream_get_state); SDL_PULSEAUDIO_SYM(pa_stream_writable_size); + SDL_PULSEAUDIO_SYM(pa_stream_readable_size); SDL_PULSEAUDIO_SYM(pa_stream_write); SDL_PULSEAUDIO_SYM(pa_stream_drain); SDL_PULSEAUDIO_SYM(pa_stream_disconnect); + SDL_PULSEAUDIO_SYM(pa_stream_peek); + SDL_PULSEAUDIO_SYM(pa_stream_drop); + SDL_PULSEAUDIO_SYM(pa_stream_flush); SDL_PULSEAUDIO_SYM(pa_stream_unref); SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto); SDL_PULSEAUDIO_SYM(pa_strerror); @@ -239,6 +251,12 @@ getAppName(void) return "SDL Application"; /* oh well. */ } +static void +stream_operation_complete_no_op(pa_stream *s, int success, void *userdata) +{ + /* no-op for pa_stream_drain(), etc, to use for callback. */ +} + static void WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o) { @@ -351,18 +369,12 @@ PULSEAUDIO_PlayDevice(_THIS) } } -static void -stream_drain_complete(pa_stream *s, int success, void *userdata) -{ - /* no-op for pa_stream_drain() to use for callback. */ -} - static void PULSEAUDIO_WaitDone(_THIS) { if (SDL_AtomicGet(&this->enabled)) { struct SDL_PrivateAudioData *h = this->hidden; - pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL); + pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_operation_complete_no_op, NULL); if (o) { while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) { if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || @@ -386,10 +398,75 @@ PULSEAUDIO_GetDeviceBuf(_THIS) } +static int +PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + struct SDL_PrivateAudioData *h = this->hidden; + const void *data = NULL; + size_t nbytes = 0; + + while (SDL_AtomicGet(&this->enabled)) { + if (h->capturebuf != NULL) { + const int cpy = SDL_min(buflen, h->capturelen); + SDL_memcpy(buffer, h->capturebuf, cpy); + /*printf("PULSEAUDIO: fed %d captured bytes\n", cpy);*/ + h->capturebuf += cpy; + h->capturelen -= cpy; + if (h->capturelen == 0) { + h->capturebuf = NULL; + PULSEAUDIO_pa_stream_drop(h->stream); /* done with this fragment. */ + } + return cpy; /* new data, return it. */ + } + + if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || + PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || + PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { + SDL_OpenedAudioDeviceDisconnected(this); + return -1; /* uhoh, pulse failed! */ + } + + if (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0) { + continue; /* no data available yet. */ + } + + /* a new fragment is available! */ + PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes); + SDL_assert(nbytes > 0); + if (data == NULL) { /* NULL==buffer had a hole. Ignore that. */ + PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */ + } else { + /* store this fragment's data, start feeding it to SDL. */ + /*printf("PULSEAUDIO: captured %d new bytes\n", (int) nbytes);*/ + h->capturebuf = (const Uint8 *) data; + h->capturelen = nbytes; + } + } + + return -1; /* not enabled? */ +} + +static void +PULSEAUDIO_FlushCapture(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + + if (h->capturebuf != NULL) { + PULSEAUDIO_pa_stream_drop(h->stream); + h->capturebuf = NULL; + h->capturelen = 0; + } + + WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_stream_flush(h->stream, stream_operation_complete_no_op, NULL)); +} + static void PULSEAUDIO_CloseDevice(_THIS) { if (this->hidden != NULL) { + if (this->hidden->capturebuf != NULL) { + PULSEAUDIO_pa_stream_drop(this->hidden->stream); + } SDL_FreeAudioMem(this->hidden->mixbuf); SDL_free(this->hidden->device_name); if (this->hidden->stream) { @@ -403,7 +480,16 @@ PULSEAUDIO_CloseDevice(_THIS) } static void -DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) +SinkDeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) +{ + if (i) { + char **devname = (char **) data; + *devname = SDL_strdup(i->name); + } +} + +static void +SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, void *data) { if (i) { char **devname = (char **) data; @@ -412,7 +498,7 @@ DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data } static SDL_bool -FindDeviceName(struct SDL_PrivateAudioData *h, void *handle) +FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle) { const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1; @@ -420,7 +506,16 @@ FindDeviceName(struct SDL_PrivateAudioData *h, void *handle) return SDL_TRUE; } - WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, DeviceNameCallback, &h->device_name)); + if (iscapture) { + WaitForPulseOperation(h->mainloop, + PULSEAUDIO_pa_context_get_source_info_by_index(h->context, idx, + SourceDeviceNameCallback, &h->device_name)); + } else { + WaitForPulseOperation(h->mainloop, + PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, + SinkDeviceNameCallback, &h->device_name)); + } + return (h->device_name != NULL); } @@ -434,6 +529,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) pa_channel_map pacmap; pa_stream_flags_t flags = 0; int state = 0; + int rc = 0; /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) @@ -495,13 +591,15 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Allocate mixing buffer */ - h->mixlen = this->spec.size; - h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen); - if (h->mixbuf == NULL) { - PULSEAUDIO_CloseDevice(this); - return SDL_OutOfMemory(); + if (!iscapture) { + h->mixlen = this->spec.size; + h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen); + if (h->mixbuf == NULL) { + PULSEAUDIO_CloseDevice(this); + return SDL_OutOfMemory(); + } + SDL_memset(h->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(h->mixbuf, this->spec.silence, this->spec.size); paspec.channels = this->spec.channels; paspec.rate = this->spec.freq; @@ -527,9 +625,9 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_SetError("Could not connect to PulseAudio server"); } - if (!FindDeviceName(h, handle)) { + if (!FindDeviceName(h, iscapture, handle)) { PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Requested PulseAudio sink missing?"); + return SDL_SetError("Requested PulseAudio sink/source missing?"); } /* The SDL ALSA output hints us that we use Windows' channel mapping */ @@ -555,8 +653,13 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) flags |= PA_STREAM_DONT_MOVE; } - if (PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, - NULL, NULL) < 0) { + if (iscapture) { + rc = PULSEAUDIO_pa_stream_connect_record(h->stream, h->device_name, &paattr, flags); + } else { + rc = PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL); + } + + if (rc < 0) { PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect PulseAudio stream"); } @@ -687,6 +790,10 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = PULSEAUDIO_CloseDevice; impl->WaitDone = PULSEAUDIO_WaitDone; impl->Deinitialize = PULSEAUDIO_Deinitialize; + impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice; + impl->FlushCapture = PULSEAUDIO_FlushCapture; + + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } diff --git a/src/audio/pulseaudio/SDL_pulseaudio.h b/src/audio/pulseaudio/SDL_pulseaudio.h index c57ab71329834..e12000f2a046c 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.h +++ b/src/audio/pulseaudio/SDL_pulseaudio.h @@ -42,6 +42,9 @@ struct SDL_PrivateAudioData /* Raw mixing buffer */ Uint8 *mixbuf; int mixlen; + + const Uint8 *capturebuf; + int capturelen; }; #endif /* _SDL_pulseaudio_h */ From 6bd1ec6bb0008c71b2e9f138687214b8b6739a60 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Aug 2016 15:04:33 -0400 Subject: [PATCH 11/55] audio: a little more robustness in the capture device's thread. --- src/audio/SDL_audio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index b8b045a7cbee4..e55923ff4e412 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -729,7 +729,6 @@ SDL_CaptureAudio(void *devicep) while (still_need > 0) { const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need); - SDL_assert(rc != 0); /* device should have blocked, failed, or returned data. */ SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */ if (rc > 0) { still_need -= rc; @@ -751,7 +750,9 @@ SDL_CaptureAudio(void *devicep) /* !!! FIXME: this should be LockDevice. */ SDL_LockMutex(device->mixer_lock); - if (!SDL_AtomicGet(&device->paused)) { + if (SDL_AtomicGet(&device->paused)) { + current_audio.impl.FlushCapture(device); /* one snuck in! */ + } else { (*callback)(udata, stream, stream_len); } SDL_UnlockMutex(device->mixer_lock); From 754efd43f4574df0e78716d0e72226c32b75993d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Aug 2016 15:06:05 -0400 Subject: [PATCH 12/55] alsa: Cleaned up the 5.1 swizzle mess a little. Shouldn't this be something ALSA handles for us with channel maps, so we can just delete this code? --- src/audio/alsa/SDL_alsa_audio.c | 49 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index e9f672f8c1fee..56e55cd256ecc 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -241,37 +241,37 @@ ALSA_WaitDevice(_THIS) * "For Linux ALSA, this is FL-FR-RL-RR-C-LFE * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR" */ -#define SWIZ6(T) \ - T *ptr = (T *) this->hidden->mixbuf; \ +#define SWIZ6(T, buf, numframes) \ + T *ptr = (T *) buf; \ Uint32 i; \ - for (i = 0; i < this->spec.samples; i++, ptr += 6) { \ + for (i = 0; i < numframes; i++, ptr += 6) { \ T tmp; \ tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \ tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \ } static SDL_INLINE void -swizzle_alsa_channels_6_64bit(_THIS) +swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen) { - SWIZ6(Uint64); + SWIZ6(Uint64, buffer, bufferlen); } static SDL_INLINE void -swizzle_alsa_channels_6_32bit(_THIS) +swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen) { - SWIZ6(Uint32); + SWIZ6(Uint32, buffer, bufferlen); } static SDL_INLINE void -swizzle_alsa_channels_6_16bit(_THIS) +swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen) { - SWIZ6(Uint16); + SWIZ6(Uint16, buffer, bufferlen); } static SDL_INLINE void -swizzle_alsa_channels_6_8bit(_THIS) +swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen) { - SWIZ6(Uint8); + SWIZ6(Uint8, buffer, bufferlen); } #undef SWIZ6 @@ -282,18 +282,16 @@ swizzle_alsa_channels_6_8bit(_THIS) * channels from Windows/Mac order to the format alsalib will want. */ static SDL_INLINE void -swizzle_alsa_channels(_THIS) +swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen) { if (this->spec.channels == 6) { - const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */ - if (fmtsize == 16) - swizzle_alsa_channels_6_16bit(this); - else if (fmtsize == 8) - swizzle_alsa_channels_6_8bit(this); - else if (fmtsize == 32) - swizzle_alsa_channels_6_32bit(this); - else if (fmtsize == 64) - swizzle_alsa_channels_6_64bit(this); + switch (SDL_AUDIO_BITSIZE(this->spec.format)) { + case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen); break; + case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen); break; + case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen); break; + case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen); break; + default: SDL_assert(!"unhandled bitsize"); break; + } } /* !!! FIXME: update this for 7.1 if needed, later. */ @@ -303,19 +301,18 @@ swizzle_alsa_channels(_THIS) static void ALSA_PlayDevice(_THIS) { - int status; const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf; - const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) * + const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) * this->spec.channels; snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples); - swizzle_alsa_channels(this); + swizzle_alsa_channels(this, this->hidden->mixbuf, frames_left); while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) { /* !!! FIXME: This works, but needs more testing before going live */ /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */ - status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, - sample_buf, frames_left); + int status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, + sample_buf, frames_left); if (status < 0) { if (status == -EAGAIN) { From 41e8f9ede41dedf96121f858fca20b3c809835cc Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Aug 2016 15:06:40 -0400 Subject: [PATCH 13/55] alsa: Implemented audio capture support! --- src/audio/alsa/SDL_alsa_audio.c | 68 +++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 56e55cd256ecc..ef3b4c706d759 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -29,6 +29,7 @@ #include #include +#include "SDL_assert.h" #include "SDL_timer.h" #include "SDL_audio.h" #include "../SDL_audiomem.h" @@ -42,8 +43,10 @@ static int (*ALSA_snd_pcm_open) (snd_pcm_t **, const char *, snd_pcm_stream_t, int); static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm); -static snd_pcm_sframes_t(*ALSA_snd_pcm_writei) +static snd_pcm_sframes_t (*ALSA_snd_pcm_writei) (snd_pcm_t *, const void *, snd_pcm_uframes_t); +static snd_pcm_sframes_t (*ALSA_snd_pcm_readi) + (snd_pcm_t *, void *, snd_pcm_uframes_t); static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int); static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *); static int (*ALSA_snd_pcm_drain) (snd_pcm_t *); @@ -85,6 +88,7 @@ static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int); static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int); static int (*ALSA_snd_pcm_sw_params_set_avail_min) (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t); +static int (*ALSA_snd_pcm_reset)(snd_pcm_t *); static int (*ALSA_snd_device_name_hint) (int, const char *, void ***); static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *); static int (*ALSA_snd_device_name_free_hint) (void **); @@ -121,6 +125,7 @@ load_alsa_syms(void) SDL_ALSA_SYM(snd_pcm_open); SDL_ALSA_SYM(snd_pcm_close); SDL_ALSA_SYM(snd_pcm_writei); + SDL_ALSA_SYM(snd_pcm_readi); SDL_ALSA_SYM(snd_pcm_recover); SDL_ALSA_SYM(snd_pcm_prepare); SDL_ALSA_SYM(snd_pcm_drain); @@ -147,6 +152,7 @@ load_alsa_syms(void) SDL_ALSA_SYM(snd_pcm_nonblock); SDL_ALSA_SYM(snd_pcm_wait); SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min); + SDL_ALSA_SYM(snd_pcm_reset); SDL_ALSA_SYM(snd_device_name_hint); SDL_ALSA_SYM(snd_device_name_get_hint); SDL_ALSA_SYM(snd_device_name_free_hint); @@ -342,6 +348,57 @@ ALSA_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } +static int +ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + Uint8 *sample_buf = (Uint8 *) buffer; + const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) * + this->spec.channels; + const int total_frames = buflen / frame_size; + snd_pcm_uframes_t frames_left = total_frames; + + SDL_assert((buflen % frame_size) == 0); + + while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) { + /* !!! FIXME: This works, but needs more testing before going live */ + /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */ + int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle, + sample_buf, frames_left); + + if (status < 0) { + /*printf("ALSA: capture error %d\n", status);*/ + if (status == -EAGAIN) { + /* Apparently snd_pcm_recover() doesn't handle this case - + does it assume snd_pcm_wait() above? */ + SDL_Delay(1); + continue; + } + status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0); + if (status < 0) { + /* Hmm, not much we can do - abort */ + fprintf(stderr, "ALSA read failed (unrecoverable): %s\n", + ALSA_snd_strerror(status)); + return -1; + } + continue; + } + + /*printf("ALSA: captured %d bytes\n", status * frame_size);*/ + sample_buf += status * frame_size; + frames_left -= status; + } + + swizzle_alsa_channels(this, buffer, total_frames - frames_left); + + return (total_frames - frames_left) * frame_size; +} + +static void +ALSA_FlushCapture(_THIS) +{ + ALSA_snd_pcm_reset(this->hidden->pcm_handle); +} + static void ALSA_CloseDevice(_THIS) { @@ -493,8 +550,9 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Open the audio device */ /* Name of device should depend on # channels in spec */ status = ALSA_snd_pcm_open(&pcm_handle, - get_audio_device(handle, this->spec.channels), - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + get_audio_device(handle, this->spec.channels), + iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK); if (status < 0) { ALSA_CloseDevice(this); @@ -757,6 +815,10 @@ ALSA_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = ALSA_CloseDevice; impl->Deinitialize = ALSA_Deinitialize; impl->FreeDeviceHandle = ALSA_FreeDeviceHandle; + impl->CaptureFromDevice = ALSA_CaptureFromDevice; + impl->FlushCapture = ALSA_FlushCapture; + + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } From f758483a288fb104ee264b2f73570ea7d00850a6 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 2 Aug 2016 19:17:51 -0400 Subject: [PATCH 14/55] testaudiocapture: Make a simple green/red window when recording/playing. --- test/testaudiocapture.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c index 30742f96b36f2..7faeb825a9e3a 100644 --- a/test/testaudiocapture.c +++ b/test/testaudiocapture.c @@ -17,6 +17,12 @@ #define CAPTURE_SECONDS 5 +#define DO_VIDEO defined(__ANDROID__) || defined(__IPHONEOS__) || defined(__EMSCRIPTEN__) +#if DO_VIDEO +static SDL_Window *window = NULL; +static SDL_Renderer *renderer = NULL; +#endif + static SDL_AudioSpec spec; static Uint8 *sound = NULL; /* Pointer to wave data */ static Uint32 soundlen = 0; /* Length of wave data */ @@ -68,6 +74,16 @@ loop() } } + #if DO_VIDEO + if (spec.callback == capture_callback) { + SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); + } else { + SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + } + SDL_RenderClear(renderer); + SDL_RenderPresent(renderer); + #endif + if ((!please_quit) && (processed >= soundlen)) { processed = 0; if (spec.callback == capture_callback) { @@ -123,8 +139,12 @@ main(int argc, char **argv) } /* Android apparently needs a window...? */ - #ifdef __ANDROID__ - SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0); + #if DO_VIDEO + window = SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, SDL_WINDOW_FULLSCREEN_DESKTOP); + renderer = SDL_CreateRenderer(window, -1, 0); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + SDL_RenderPresent(renderer); #endif SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); From a9ef240cefb88cac59c6876b30141856d4de2252 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 00:30:12 -0400 Subject: [PATCH 15/55] coreaudio: Implemented audio capture for iOS. --- src/audio/coreaudio/SDL_coreaudio.c | 55 +++++++++++++++++++++++------ src/audio/coreaudio/SDL_coreaudio.h | 2 +- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index 2385995fd0038..d70196b9e5bba 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -268,6 +268,27 @@ device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectP } #endif + +static int open_playback_devices = 0; +static int open_capture_devices = 0; + +static void update_audio_session() +{ +#if !MACOSX_COREAUDIO + /* !!! FIXME: move this to AVAudioSession. This is deprecated, and the new version is available as of (ancient!) iOS 3.0 */ + UInt32 category; + if (open_playback_devices && open_capture_devices) { + category = kAudioSessionCategory_PlayAndRecord; + } else if (open_capture_devices) { + category = kAudioSessionCategory_RecordAudio; + } else { /* nothing open, or just playing audio. */ + category = kAudioSessionCategory_AmbientSound; + } + AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof (UInt32), &category); +#endif +} + + /* The CoreAudio callback */ static OSStatus outputCallback(void *inRefCon, @@ -416,6 +437,7 @@ static void COREAUDIO_CloseDevice(_THIS) { if (this->hidden != NULL) { + const int iscapture = this->iscapture; if (this->hidden->audioUnitOpened) { #if MACOSX_COREAUDIO /* Unregister our disconnect callback. */ @@ -425,7 +447,6 @@ COREAUDIO_CloseDevice(_THIS) AURenderCallbackStruct callback; const AudioUnitElement output_bus = 0; const AudioUnitElement input_bus = 1; - const int iscapture = this->iscapture; const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus); @@ -440,13 +461,19 @@ COREAUDIO_CloseDevice(_THIS) AudioComponentInstanceDispose(this->hidden->audioUnit); this->hidden->audioUnitOpened = 0; - #if MACOSX_COREAUDIO SDL_free(this->hidden->captureBufferList.mBuffers[0].mData); - #endif + } SDL_free(this->hidden->buffer); SDL_free(this->hidden); this->hidden = NULL; + + if (iscapture) { + open_capture_devices--; + } else { + open_playback_devices--; + } + update_audio_session(); } } @@ -544,7 +571,6 @@ prepare_audiounit(_THIS, void *handle, int iscapture, this->hidden->audioUnitOpened = 1; -#if MACOSX_COREAUDIO if (iscapture) { /* have to do EnableIO only for capture devices. */ UInt32 enable = 1; result = AudioUnitSetProperty(this->hidden->audioUnit, @@ -563,6 +589,7 @@ prepare_audiounit(_THIS, void *handle, int iscapture, ("AudioUnitSetProperty (kAudioOutputUnitProperty_EnableIO output bus)"); } +#if MACOSX_COREAUDIO /* this is always on the output_bus, even for capture devices. */ result = AudioUnitSetProperty(this->hidden->audioUnit, kAudioOutputUnitProperty_CurrentDevice, @@ -581,14 +608,13 @@ prepare_audiounit(_THIS, void *handle, int iscapture, strdesc, sizeof (*strdesc)); CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)"); -#if MACOSX_COREAUDIO if (iscapture) { /* only need to do this for capture devices. */ void *ptr; UInt32 framesize = 0; UInt32 propsize = sizeof (UInt32); result = AudioUnitGetProperty(this->hidden->audioUnit, - kAudioDevicePropertyBufferFrameSize, + kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, output_bus, &framesize, &propsize); CHECK_RESULT @@ -601,13 +627,11 @@ prepare_audiounit(_THIS, void *handle, int iscapture, SDL_OutOfMemory(); return 0; } - this->hidden->captureBufferList.mNumberBuffers = 1; this->hidden->captureBufferList.mBuffers[0].mNumberChannels = this->spec.channels; this->hidden->captureBufferList.mBuffers[0].mDataByteSize = framesize; this->hidden->captureBufferList.mBuffers[0].mData = ptr; } -#endif /* Set the audio callback */ SDL_zero(callback); @@ -616,7 +640,9 @@ prepare_audiounit(_THIS, void *handle, int iscapture, result = AudioUnitSetProperty(this->hidden->audioUnit, iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Global, output_bus, &callback, sizeof(callback)); + kAudioUnitScope_Global, + iscapture ? input_bus : output_bus, + &callback, sizeof (callback)); CHECK_RESULT ("AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)"); @@ -668,6 +694,13 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } SDL_zerop(this->hidden); + if (iscapture) { + open_capture_devices++; + } else { + open_playback_devices++; + } + update_audio_session(); + /* Setup a AudioStreamBasicDescription with the requested format */ SDL_zero(strdesc); strdesc.mFormatID = kAudioFormatLinearPCM; @@ -742,20 +775,22 @@ COREAUDIO_Init(SDL_AudioDriverImpl * impl) #if MACOSX_COREAUDIO impl->DetectDevices = COREAUDIO_DetectDevices; AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL); - impl->HasCaptureSupport = 1; #else impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultInputDevice = 1; /* Set category to ambient sound so that other music continues playing. You can change this at runtime in your own code if you need different behavior. If this is common, we can add an SDL hint for this. */ + /* !!! FIXME: move this to AVAudioSession. This is deprecated, and the new version is available as of (ancient!) iOS 3.0 */ AudioSessionInitialize(NULL, NULL, NULL, nil); UInt32 category = kAudioSessionCategory_AmbientSound; AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(UInt32), &category); #endif impl->ProvidesOwnCallbackThread = 1; + impl->HasCaptureSupport = 1; return 1; /* this audio target is available. */ } diff --git a/src/audio/coreaudio/SDL_coreaudio.h b/src/audio/coreaudio/SDL_coreaudio.h index 95e1215619487..329073233efcb 100644 --- a/src/audio/coreaudio/SDL_coreaudio.h +++ b/src/audio/coreaudio/SDL_coreaudio.h @@ -48,9 +48,9 @@ struct SDL_PrivateAudioData void *buffer; UInt32 bufferOffset; UInt32 bufferSize; + AudioBufferList captureBufferList; #if MACOSX_COREAUDIO AudioDeviceID deviceID; - AudioBufferList captureBufferList; #endif }; From 3ed9b0f567456904603f156a00ca885507fb384e Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 00:31:08 -0400 Subject: [PATCH 16/55] testaudiocapture: made test app interactive. (hold down mouse/finger to record, then it plays back what it heard. Repeat.) --- test/testaudiocapture.c | 123 +++++++++++++--------------------------- 1 file changed, 38 insertions(+), 85 deletions(-) diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c index 7faeb825a9e3a..2c6b7a9525bbc 100644 --- a/test/testaudiocapture.c +++ b/test/testaudiocapture.c @@ -15,104 +15,61 @@ #include #endif -#define CAPTURE_SECONDS 5 - -#define DO_VIDEO defined(__ANDROID__) || defined(__IPHONEOS__) || defined(__EMSCRIPTEN__) -#if DO_VIDEO static SDL_Window *window = NULL; static SDL_Renderer *renderer = NULL; -#endif - static SDL_AudioSpec spec; -static Uint8 *sound = NULL; /* Pointer to wave data */ -static Uint32 soundlen = 0; /* Length of wave data */ -static Uint32 processed = 0; -static SDL_AudioDeviceID devid = 0; +static SDL_AudioDeviceID devid_in = 0; +static SDL_AudioDeviceID devid_out = 0; void SDLCALL capture_callback(void *arg, Uint8 * stream, int len) { - const int avail = (int) (soundlen - processed); - if (len > avail) { - len = avail; - } - - /*SDL_Log("CAPTURE CALLBACK: %d more bytes\n", len);*/ - SDL_memcpy(sound + processed, stream, len); - processed += len; -} - -void SDLCALL -play_callback(void *arg, Uint8 * stream, int len) -{ - const Uint8 *waveptr = sound + processed; - const int avail = soundlen - processed; - int cpy = len; - if (cpy > avail) { - cpy = avail; - } - - /*SDL_Log("PLAY CALLBACK: %d more bytes\n", cpy);*/ - SDL_memcpy(stream, waveptr, cpy); - processed += cpy; - - len -= cpy; - if (len > 0) { - SDL_memset(stream + cpy, spec.silence, len); - } + SDL_QueueAudio(devid_out, stream, len); } static void loop() { - SDL_Event e; SDL_bool please_quit = SDL_FALSE; + SDL_Event e; while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) { please_quit = SDL_TRUE; + } else if (e.type == SDL_KEYDOWN) { + if (e.key.keysym.sym == SDLK_ESCAPE) { + please_quit = SDL_TRUE; + } + } else if (e.type == SDL_MOUSEBUTTONDOWN) { + if (e.button.button == 1) { + SDL_PauseAudioDevice(devid_out, SDL_TRUE); + SDL_PauseAudioDevice(devid_in, SDL_FALSE); + } + } else if (e.type == SDL_MOUSEBUTTONUP) { + if (e.button.button == 1) { + SDL_PauseAudioDevice(devid_in, SDL_TRUE); + SDL_PauseAudioDevice(devid_out, SDL_FALSE); + } } } - #if DO_VIDEO - if (spec.callback == capture_callback) { + if (SDL_GetAudioDeviceStatus(devid_in) == SDL_AUDIO_PLAYING) { SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); } else { SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); } SDL_RenderClear(renderer); SDL_RenderPresent(renderer); - #endif - - if ((!please_quit) && (processed >= soundlen)) { - processed = 0; - if (spec.callback == capture_callback) { - SDL_Log("Done recording, playing back...\n"); - SDL_PauseAudioDevice(devid, 1); - SDL_CloseAudioDevice(devid); - - spec.callback = play_callback; - devid = SDL_OpenAudioDevice(NULL, 0, &spec, &spec, 0); - if (!devid) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for playback!\n"); - SDL_Quit(); - exit(1); - } - - SDL_PauseAudioDevice(devid, 0); - } else { - SDL_Log("Done playing back.\n"); - please_quit = SDL_TRUE; - } - } if (please_quit) { /* stop playing back, quit. */ SDL_Log("Shutting down.\n"); - SDL_PauseAudioDevice(devid, 1); - SDL_CloseAudioDevice(devid); - SDL_free(sound); - sound = NULL; + SDL_PauseAudioDevice(devid_in, 1); + SDL_CloseAudioDevice(devid_in); + SDL_PauseAudioDevice(devid_out, 1); + SDL_CloseAudioDevice(devid_out); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); SDL_Quit(); #ifdef __EMSCRIPTEN__ emscripten_cancel_main_loop(); @@ -138,14 +95,11 @@ main(int argc, char **argv) return (1); } - /* Android apparently needs a window...? */ - #if DO_VIDEO window = SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, SDL_WINDOW_FULLSCREEN_DESKTOP); renderer = SDL_CreateRenderer(window, -1, 0); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); SDL_RenderPresent(renderer); - #endif SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); @@ -161,29 +115,28 @@ main(int argc, char **argv) spec.samples = 1024; spec.callback = capture_callback; - soundlen = spec.freq * (SDL_AUDIO_BITSIZE(spec.format) / 8) * spec.channels * CAPTURE_SECONDS; - sound = (Uint8 *) SDL_malloc(soundlen); - if (!sound) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n"); - SDL_Quit(); - return 1; - } - - SDL_Log("Opening device %s%s%s...\n", + SDL_Log("Opening capture device %s%s%s...\n", devname ? "'" : "", devname ? devname : "[[default]]", devname ? "'" : ""); - devid = SDL_OpenAudioDevice(argv[1], SDL_TRUE, &spec, &spec, 0); - if (!devid) { + devid_in = SDL_OpenAudioDevice(argv[1], SDL_TRUE, &spec, &spec, 0); + if (!devid_in) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError()); + SDL_Quit(); + exit(1); + } + + SDL_Log("Opening default playback device...\n"); + spec.callback = NULL; + devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &spec, &spec, 0); + if (!devid_out) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError()); - SDL_free(sound); SDL_Quit(); exit(1); } - SDL_Log("Recording for %d seconds...\n", CAPTURE_SECONDS); - SDL_PauseAudioDevice(devid, 0); + SDL_Log("Ready! Hold down mouse or finger to record!\n"); #ifdef __EMSCRIPTEN__ emscripten_set_main_loop(loop, 0, 1); From 38f4b68ca7b4e22c3dd6c6cee33a818460fd1329 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 01:00:30 -0400 Subject: [PATCH 17/55] alsa: capture devices don't need a mixbuf allocated. --- src/audio/alsa/SDL_alsa_audio.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index ef3b4c706d759..8102226365c59 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -700,13 +700,15 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - ALSA_CloseDevice(this); - return SDL_OutOfMemory(); + if (!iscapture) { + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + ALSA_CloseDevice(this); + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); /* Switch to blocking mode for playback */ ALSA_snd_pcm_nonblock(pcm_handle, 0); From a7dddacd9949bee58399499fc48d96b5e07c0435 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 01:01:44 -0400 Subject: [PATCH 18/55] arts: implemented audio capture support. (completely untested! Not even compiled!!). --- src/audio/arts/SDL_artsaudio.c | 55 +++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 5d40cd14e8f24..ce8c9d8818ea6 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -54,12 +54,16 @@ static void (*SDL_NAME(arts_free)) (void); static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, int channels, const char *name); +static arts_stream_t(*SDL_NAME(arts_record_stream)) (int rate, int bits, + int channels, + const char *name); static int (*SDL_NAME(arts_stream_set)) (arts_stream_t s, arts_parameter_t param, int value); static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s, arts_parameter_t param); static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer, int count); +static int (*SDL_NAME(arts_read)) (arts_stream_t s, void *buffer, int count); static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); static int (*SDL_NAME(arts_suspend))(void); static int (*SDL_NAME(arts_suspended)) (void); @@ -75,9 +79,11 @@ static struct SDL_ARTS_SYM(arts_init), SDL_ARTS_SYM(arts_free), SDL_ARTS_SYM(arts_play_stream), + SDL_ARTS_SYM(arts_record_stream), SDL_ARTS_SYM(arts_stream_set), SDL_ARTS_SYM(arts_stream_get), SDL_ARTS_SYM(arts_write), + SDL_ARTS_SYM(arts_read), SDL_ARTS_SYM(arts_close_stream), SDL_ARTS_SYM(arts_suspend), SDL_ARTS_SYM(arts_suspended), @@ -199,6 +205,27 @@ ARTS_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } +static int +ARTS_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + return SDL_NAME(arts_read) (this->hidden->stream, buffer, buflen); +} + +static void +ARTS_FlushCapture(_THIS) +{ + arts_stream_t stream = this->hidden->stream; + int remain = SDL_NAME(arts_stream_get)(stream, ARTS_P_BUFFER_SPACE); + Uint8 buf[512]; + while (space > 0) { + const int len = SDL_min(sizeof (buf), remain); + const int br = SDL_NAME(arts_read)(stream, buf, len); + if (br <= 0) { + return; /* oh well. */ + } + space -= br; + } +} static void ARTS_CloseDevice(_THIS) @@ -278,19 +305,20 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_NAME(arts_error_text) (rc)); } - if (!ARTS_Suspend()) { - ARTS_CloseDevice(this); - return SDL_SetError("ARTS can not open audio device"); + if (iscapture) { + this->hidden->stream = SDL_NAME(arts_record_stream) (this->spec.freq, + bits, + this->spec.channels, + "SDL"); + } else { + this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq, + bits, + this->spec.channels, + "SDL"); + /* Play nothing so we have at least one write (server bug workaround). */ + SDL_NAME(arts_write) (this->hidden->stream, "", 0); } - this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq, - bits, - this->spec.channels, - "SDL"); - - /* Play nothing so we have at least one write (server bug workaround). */ - SDL_NAME(arts_write) (this->hidden->stream, "", 0); - /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(&this->spec); @@ -369,7 +397,12 @@ ARTS_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = ARTS_CloseDevice; impl->WaitDone = ARTS_WaitDone; impl->Deinitialize = ARTS_Deinitialize; + impl->CaptureFromDevice = ARTS_CaptureFromDevice; + impl->FlushCapture = ARTS_FlushCapture; + impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultInputDevice = 1; + impl->HasCaptureSupport = 1; return 1; /* this audio target is available. */ } From ecbd625c4b556855a6013825114bb16b374c3706 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 01:53:59 -0400 Subject: [PATCH 19/55] arts: Patched to (maybe) compile. --- src/audio/arts/SDL_artsaudio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index ce8c9d8818ea6..1ab7c2dee3a66 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -217,13 +217,13 @@ ARTS_FlushCapture(_THIS) arts_stream_t stream = this->hidden->stream; int remain = SDL_NAME(arts_stream_get)(stream, ARTS_P_BUFFER_SPACE); Uint8 buf[512]; - while (space > 0) { + while (remain > 0) { const int len = SDL_min(sizeof (buf), remain); const int br = SDL_NAME(arts_read)(stream, buf, len); if (br <= 0) { return; /* oh well. */ } - space -= br; + remain -= br; } } From d30a2f5ad89d3f0472435165e4d3d26db13090e8 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 01:56:58 -0400 Subject: [PATCH 20/55] bsdaudio: this appears to be using the wrong variable...? (We probably never noticed because this is meant to block until it fully writes a buffer, and would only trigger an issue if we had a short write that wasn't otherwise an error condition.) --- src/audio/bsd/SDL_bsdaudio.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index eeb257371fc06..07fd7fadc51db 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -182,11 +182,15 @@ BSDAUDIO_PlayDevice(_THIS) break; } - if (p < written +#ifdef DEBUG_AUDIO + fprintf(stderr, "Wrote %d bytes of audio data\n", written); +#endif + + if (p < this->hidden->mixlen || ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) { SDL_Delay(1); /* Let a little CPU time go by */ } - } while (p < written); + } while (p < this->hidden->mixlen); /* If timer synchronization is enabled, set the next write frame */ if (this->hidden->frame_ticks) { @@ -197,9 +201,6 @@ BSDAUDIO_PlayDevice(_THIS) if (written < 0) { SDL_OpenedAudioDeviceDisconnected(this); } -#ifdef DEBUG_AUDIO - fprintf(stderr, "Wrote %d bytes of audio data\n", written); -#endif } static Uint8 * From 9dd8477a21ec768d5dd7b3f9c2521d407b5ca6fc Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 01:57:41 -0400 Subject: [PATCH 21/55] bsdaudio: first shot at audio capture support! (untested, uncompiled...for now.) --- src/audio/bsd/SDL_bsdaudio.c | 137 +++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 37 deletions(-) diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index 07fd7fadc51db..d55a9d3c3ff0d 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -63,13 +63,17 @@ BSDAUDIO_Status(_THIS) #ifdef DEBUG_AUDIO /* *INDENT-OFF* */ audio_info_t info; + const audio_prinfo *prinfo; if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) { fprintf(stderr, "AUDIO_GETINFO failed.\n"); return; } + + prinfo = this->iscapture ? &info.play : &info.record; + fprintf(stderr, "\n" - "[play/record info]\n" + "[%s info]\n" "buffer size : %d bytes\n" "sample rate : %i Hz\n" "channels : %i\n" @@ -83,18 +87,19 @@ BSDAUDIO_Status(_THIS) "waiting : %s\n" "active : %s\n" "", - info.play.buffer_size, - info.play.sample_rate, - info.play.channels, - info.play.precision, - info.play.encoding, - info.play.seek, - info.play.samples, - info.play.eof, - info.play.pause ? "yes" : "no", - info.play.error ? "yes" : "no", - info.play.waiting ? "yes" : "no", - info.play.active ? "yes" : "no"); + this->iscapture ? "record" : "play", + prinfo->buffer_size, + prinfo->sample_rate, + prinfo->channels, + prinfo->precision, + prinfo->encoding, + prinfo->seek, + prinfo->samples, + prinfo->eof, + prinfo->pause ? "yes" : "no", + prinfo->error ? "yes" : "no", + prinfo->waiting ? "yes" : "no", + prinfo->active ? "yes" : "no"); fprintf(stderr, "\n" "[audio info]\n" @@ -209,6 +214,57 @@ BSDAUDIO_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } + +static int +BSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen) +{ + Uint8 *buffer = (Uint8 *) _buffer; + int br, p = 0; + + /* Write the audio data, checking for EAGAIN on broken audio drivers */ + do { + br = read(this->hidden->audio_fd, buffer + p, buflen - p); + if (br > 0) + p += br; + if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) { + /* Non recoverable error has occurred. It should be reported!!! */ + perror("audio"); + return p ? p : -1; + } + +#ifdef DEBUG_AUDIO + fprintf(stderr, "Captured %d bytes of audio data\n", br); +#endif + + if (p < buflen + || ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) { + SDL_Delay(1); /* Let a little CPU time go by */ + } + } while (p < buflen); +} + +static void +BSDAUDIO_FlushCapture(_THIS) +{ + audio_info_t info; + size_t remain; + Uint8 buf[512]; + + if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) { + return; /* oh well. */ + } + + remain = (size_t) (info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8)); + while (remain > 0) { + const size_t len = SDL_min(sizeof (buf), remain); + const int br = read(this->hidden->audio_fd, buf, len); + if (br <= 0) { + return; /* oh well. */ + } + remain -= br; + } +} + static void BSDAUDIO_CloseDevice(_THIS) { @@ -227,9 +283,10 @@ BSDAUDIO_CloseDevice(_THIS) static int BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { - const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); + const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT; SDL_AudioFormat format = 0; audio_info_t info; + audio_prinfo *prinfo = iscapture ? &info.play : &info.record; /* We don't care what the devname is...we'll try to open anything. */ /* ...but default to first name in the list... */ @@ -260,7 +317,7 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Set to play mode */ - info.mode = AUMODE_PLAY; + info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY; if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) { BSDAUDIO_CloseDevice(this); return SDL_SetError("Couldn't put device into play mode"); @@ -271,28 +328,28 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) format; format = SDL_NextAudioFormat()) { switch (format) { case AUDIO_U8: - info.play.encoding = AUDIO_ENCODING_ULINEAR; - info.play.precision = 8; + prinfo->encoding = AUDIO_ENCODING_ULINEAR; + prinfo->precision = 8; break; case AUDIO_S8: - info.play.encoding = AUDIO_ENCODING_SLINEAR; - info.play.precision = 8; + prinfo->encoding = AUDIO_ENCODING_SLINEAR; + prinfo->precision = 8; break; case AUDIO_S16LSB: - info.play.encoding = AUDIO_ENCODING_SLINEAR_LE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE; + prinfo->precision = 16; break; case AUDIO_S16MSB: - info.play.encoding = AUDIO_ENCODING_SLINEAR_BE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE; + prinfo->precision = 16; break; case AUDIO_U16LSB: - info.play.encoding = AUDIO_ENCODING_ULINEAR_LE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE; + prinfo->precision = 16; break; case AUDIO_U16MSB: - info.play.encoding = AUDIO_ENCODING_ULINEAR_BE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE; + prinfo->precision = 16; break; default: continue; @@ -311,26 +368,29 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->spec.format = format; AUDIO_INITINFO(&info); - info.play.channels = this->spec.channels; + prinfo->channels = this->spec.channels; if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) { this->spec.channels = 1; } AUDIO_INITINFO(&info); - info.play.sample_rate = this->spec.freq; + prinfo->sample_rate = this->spec.freq; info.blocksize = this->spec.size; info.hiwat = 5; info.lowat = 3; (void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info); (void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info); - this->spec.freq = info.play.sample_rate; - /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - BSDAUDIO_CloseDevice(this); - return SDL_OutOfMemory(); + this->spec.freq = prinfo->sample_rate; + + if (!iscapture) { + /* Allocate mixing buffer */ + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + BSDAUDIO_CloseDevice(this); + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); BSDAUDIO_Status(this); @@ -348,7 +408,10 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = BSDAUDIO_WaitDevice; impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf; impl->CloseDevice = BSDAUDIO_CloseDevice; + impl->CaptureFromDevice = BSDAUDIO_CaptureFromDevice; + impl->FlushCapture = BSDAUDIO_FlushCapture; + impl->HasCaptureSupport = SDL_TRUE; impl->AllowsArbitraryDeviceNames = 1; return 1; /* this audio target is available. */ From 17246ba95ec6b3ad212aa9d28fd2ffae0e97b96d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 02:18:47 -0400 Subject: [PATCH 22/55] dummy audio: Implemented dummy audio capture support. :) --- src/audio/dummy/SDL_dummyaudio.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/audio/dummy/SDL_dummyaudio.c b/src/audio/dummy/SDL_dummyaudio.c index 107f0b073feca..00458d2566411 100644 --- a/src/audio/dummy/SDL_dummyaudio.c +++ b/src/audio/dummy/SDL_dummyaudio.c @@ -32,12 +32,28 @@ DUMMYAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return 0; /* always succeeds. */ } +static int +DUMMYAUD_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + /* Delay to make this sort of simulate real audio input. */ + SDL_Delay((device->spec.samples * 1000) / device->spec.freq); + + /* always return a full buffer of silence. */ + SDL_memset(buffer, this->spec.silence, buflen); + return buflen; +} + static int DUMMYAUD_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ impl->OpenDevice = DUMMYAUD_OpenDevice; + impl->CaptureFromDevice = DUMMYAUD_CaptureFromDevice; + impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultInputDevice = 1; + impl->HasCaptureSupport = SDL_TRUE; + return 1; /* this audio target is available. */ } From 20cd5e44ce2970eb9385a5b9573bdaa095e510d0 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Aug 2016 16:54:10 -0400 Subject: [PATCH 23/55] dummy audio: Patched to compile. --- src/audio/dummy/SDL_dummyaudio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/audio/dummy/SDL_dummyaudio.c b/src/audio/dummy/SDL_dummyaudio.c index 00458d2566411..f100585a49fb5 100644 --- a/src/audio/dummy/SDL_dummyaudio.c +++ b/src/audio/dummy/SDL_dummyaudio.c @@ -22,6 +22,7 @@ /* Output audio to nowhere... */ +#include "SDL_timer.h" #include "SDL_audio.h" #include "../SDL_audio_c.h" #include "SDL_dummyaudio.h" @@ -36,7 +37,7 @@ static int DUMMYAUD_CaptureFromDevice(_THIS, void *buffer, int buflen) { /* Delay to make this sort of simulate real audio input. */ - SDL_Delay((device->spec.samples * 1000) / device->spec.freq); + SDL_Delay((this->spec.samples * 1000) / this->spec.freq); /* always return a full buffer of silence. */ SDL_memset(buffer, this->spec.silence, buflen); From 30a9139bc3db13218929138ac06969cb017aaaf7 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 4 Aug 2016 11:51:17 -0400 Subject: [PATCH 24/55] arts: backed out audio capture support. Turns out that libartsc isn't thread-safe, so if we run a capture and playback device at the same time, it often crashes in arts's internal event loop. We could throw mutexes around the read/write calls, but these are meant to block, so one device could cause serious latency and stutter in the other. Since this audio target isn't in high-demand (Ubuntu hasn't offered a libartsc package for years), I'm just backing out the capture support. If someone needs it, they can pull it out of the revision history. --- src/audio/arts/SDL_artsaudio.c | 55 +++++++--------------------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 1ab7c2dee3a66..5d40cd14e8f24 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -54,16 +54,12 @@ static void (*SDL_NAME(arts_free)) (void); static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, int channels, const char *name); -static arts_stream_t(*SDL_NAME(arts_record_stream)) (int rate, int bits, - int channels, - const char *name); static int (*SDL_NAME(arts_stream_set)) (arts_stream_t s, arts_parameter_t param, int value); static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s, arts_parameter_t param); static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer, int count); -static int (*SDL_NAME(arts_read)) (arts_stream_t s, void *buffer, int count); static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); static int (*SDL_NAME(arts_suspend))(void); static int (*SDL_NAME(arts_suspended)) (void); @@ -79,11 +75,9 @@ static struct SDL_ARTS_SYM(arts_init), SDL_ARTS_SYM(arts_free), SDL_ARTS_SYM(arts_play_stream), - SDL_ARTS_SYM(arts_record_stream), SDL_ARTS_SYM(arts_stream_set), SDL_ARTS_SYM(arts_stream_get), SDL_ARTS_SYM(arts_write), - SDL_ARTS_SYM(arts_read), SDL_ARTS_SYM(arts_close_stream), SDL_ARTS_SYM(arts_suspend), SDL_ARTS_SYM(arts_suspended), @@ -205,27 +199,6 @@ ARTS_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } -static int -ARTS_CaptureFromDevice(_THIS, void *buffer, int buflen) -{ - return SDL_NAME(arts_read) (this->hidden->stream, buffer, buflen); -} - -static void -ARTS_FlushCapture(_THIS) -{ - arts_stream_t stream = this->hidden->stream; - int remain = SDL_NAME(arts_stream_get)(stream, ARTS_P_BUFFER_SPACE); - Uint8 buf[512]; - while (remain > 0) { - const int len = SDL_min(sizeof (buf), remain); - const int br = SDL_NAME(arts_read)(stream, buf, len); - if (br <= 0) { - return; /* oh well. */ - } - remain -= br; - } -} static void ARTS_CloseDevice(_THIS) @@ -305,20 +278,19 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_NAME(arts_error_text) (rc)); } - if (iscapture) { - this->hidden->stream = SDL_NAME(arts_record_stream) (this->spec.freq, - bits, - this->spec.channels, - "SDL"); - } else { - this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq, - bits, - this->spec.channels, - "SDL"); - /* Play nothing so we have at least one write (server bug workaround). */ - SDL_NAME(arts_write) (this->hidden->stream, "", 0); + if (!ARTS_Suspend()) { + ARTS_CloseDevice(this); + return SDL_SetError("ARTS can not open audio device"); } + this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq, + bits, + this->spec.channels, + "SDL"); + + /* Play nothing so we have at least one write (server bug workaround). */ + SDL_NAME(arts_write) (this->hidden->stream, "", 0); + /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(&this->spec); @@ -397,12 +369,7 @@ ARTS_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = ARTS_CloseDevice; impl->WaitDone = ARTS_WaitDone; impl->Deinitialize = ARTS_Deinitialize; - impl->CaptureFromDevice = ARTS_CaptureFromDevice; - impl->FlushCapture = ARTS_FlushCapture; - impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultInputDevice = 1; - impl->HasCaptureSupport = 1; return 1; /* this audio target is available. */ } From 9b647727752623da94ec99f1ecda64cdbb5e64f8 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 5 Aug 2016 01:44:41 -0400 Subject: [PATCH 25/55] audio: Clean up some CloseDevice() interface details. - It's now always called if device->hidden isn't NULL, even if OpenDevice() failed halfway through. This lets implementation code not have to clean up itself on every possible failure point; just return an error and SDL will handle it for you. - Implementations can assume this->hidden != NULL and not check for it. - implementations don't have to set this->hidden = NULL when done, because the caller is always about to free(this). - Don't reset other fields that are in a block of memory about to be free()'d. - Implementations all now free things like internal mix buffers last, after closing devices and such, to guarantee they definitely aren't in use anymore at the point of deallocation. --- src/audio/SDL_audio.c | 8 ++- src/audio/SDL_sysaudio.h | 1 - src/audio/alsa/SDL_alsa_audio.c | 27 ++------ src/audio/android/SDL_androidaudio.c | 6 +- src/audio/arts/SDL_artsaudio.c | 20 ++---- src/audio/bsd/SDL_bsdaudio.c | 16 ++--- src/audio/coreaudio/SDL_coreaudio.c | 75 +++++++++------------- src/audio/directsound/SDL_directsound.c | 21 ++---- src/audio/disk/SDL_diskaudio.c | 15 ++--- src/audio/dsp/SDL_dspaudio.c | 22 ++----- src/audio/emscripten/SDL_emscriptenaudio.c | 12 +--- src/audio/esd/SDL_esdaudio.c | 17 ++--- src/audio/fusionsound/SDL_fsaudio.c | 26 +++----- src/audio/haiku/SDL_haikuaudio.cc | 15 ++--- src/audio/nacl/SDL_naclaudio.c | 2 - src/audio/nas/SDL_nasaudio.c | 17 ++--- src/audio/paudio/SDL_paudio.c | 19 ++---- src/audio/psp/SDL_pspaudio.c | 10 +-- src/audio/pulseaudio/SDL_pulseaudio.c | 26 +++----- src/audio/qsa/SDL_qsa_audio.c | 40 ++++-------- src/audio/sndio/SDL_sndioaudio.c | 18 ++---- src/audio/sun/SDL_sunaudio.c | 16 ++--- src/audio/winmm/SDL_winmm.c | 55 ++++++---------- src/audio/xaudio2/SDL_xaudio2.c | 54 +++++++--------- 24 files changed, 168 insertions(+), 370 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index e55923ff4e412..80bae07c83847 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -982,9 +982,8 @@ close_audio_device(SDL_AudioDevice * device) if (device->convert.needed) { SDL_FreeAudioMem(device->convert.buf); } - if (device->opened) { + if (device->hidden != NULL) { current_audio.impl.CloseDevice(device); - device->opened = SDL_FALSE; } free_audio_queue(device->buffer_queue_head); @@ -1193,7 +1192,10 @@ open_audio_device(const char *devname, int iscapture, close_audio_device(device); return 0; } - device->opened = SDL_TRUE; + + /* if your target really doesn't need it, set it to 0x1 or something. */ + /* otherwise, close_audio_device() won't call impl.CloseDevice(). */ + SDL_assert(device->hidden != NULL); /* See if we need to do any conversion */ build_cvt = SDL_FALSE; diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index d3a48cc3741bb..5b56e8b56f1ab 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -162,7 +162,6 @@ struct SDL_AudioDevice SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */ SDL_atomic_t enabled; /* true if device is functioning and connected. */ SDL_atomic_t paused; - SDL_bool opened; SDL_bool iscapture; /* Fake audio buffer for when the audio hardware is busy */ diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 8102226365c59..f38e3ba13af8e 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -402,17 +402,12 @@ ALSA_FlushCapture(_THIS) static void ALSA_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->pcm_handle) { - ALSA_snd_pcm_drain(this->hidden->pcm_handle); - ALSA_snd_pcm_close(this->hidden->pcm_handle); - this->hidden->pcm_handle = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->pcm_handle) { + ALSA_snd_pcm_drain(this->hidden->pcm_handle); + ALSA_snd_pcm_close(this->hidden->pcm_handle); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -555,7 +550,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SND_PCM_NONBLOCK); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't open audio device: %s", ALSA_snd_strerror(status)); } @@ -566,7 +560,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) snd_pcm_hw_params_alloca(&hwparams); status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't get hardware config: %s", ALSA_snd_strerror(status)); } @@ -575,7 +568,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't set interleaved access: %s", ALSA_snd_strerror(status)); } @@ -629,7 +621,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -641,7 +632,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (status < 0) { status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't set audio channels"); } this->spec.channels = channels; @@ -652,7 +642,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, NULL); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't set audio frequency: %s", ALSA_snd_strerror(status)); } @@ -664,7 +653,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Failed to set desired buffer size, do the best you can... */ status = ALSA_set_period_size(this, hwparams, 1); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status)); } } @@ -672,26 +660,22 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) snd_pcm_sw_params_alloca(&swparams); status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't get software config: %s", ALSA_snd_strerror(status)); } status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("Couldn't set minimum available samples: %s", ALSA_snd_strerror(status)); } status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't set start threshold: %s", ALSA_snd_strerror(status)); } status = ALSA_snd_pcm_sw_params(pcm_handle, swparams); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("Couldn't set software audio parameters: %s", ALSA_snd_strerror(status)); } @@ -704,7 +688,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - ALSA_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index 047793a6078fb..2cedca0818ef4 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -44,6 +44,7 @@ AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_SetError("Capture not supported on Android"); } + /* !!! FIXME: higher level will prevent this now. Lose this check (and global?). */ if (audioDevice != NULL) { return SDL_SetError("Only one audio device at a time please!"); } @@ -115,10 +116,7 @@ AndroidAUD_CloseDevice(_THIS) Android_JNI_CloseAudioDevice(); if (audioDevice == this) { - if (audioDevice->hidden != NULL) { - SDL_free(this->hidden); - this->hidden = NULL; - } + SDL_free(this->hidden); audioDevice = NULL; } } diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 5d40cd14e8f24..3f4ba81a311b0 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -203,17 +203,12 @@ ARTS_GetDeviceBuf(_THIS) static void ARTS_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->stream) { - SDL_NAME(arts_close_stream) (this->hidden->stream); - this->hidden->stream = 0; - } - SDL_NAME(arts_free) (); - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->stream) { + SDL_NAME(arts_close_stream) (this->hidden->stream); } + SDL_NAME(arts_free) (); + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -267,19 +262,16 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (format == 0) { - ARTS_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; if ((rc = SDL_NAME(arts_init) ()) != 0) { - ARTS_CloseDevice(this); return SDL_SetError("Unable to initialize ARTS: %s", SDL_NAME(arts_error_text) (rc)); } if (!ARTS_Suspend()) { - ARTS_CloseDevice(this); return SDL_SetError("ARTS can not open audio device"); } @@ -297,7 +289,6 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Determine the power of two of the fragment size */ for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec); if ((0x01 << frag_spec) != this->spec.size) { - ARTS_CloseDevice(this); return SDL_SetError("Fragment size must be a power of two"); } frag_spec |= 0x00020000; /* two fragments, for low latency */ @@ -318,7 +309,6 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - ARTS_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index d55a9d3c3ff0d..6858f1e5704eb 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -268,16 +268,11 @@ BSDAUDIO_FlushCapture(_THIS) static void BSDAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->audio_fd >= 0) { - close(this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -319,7 +314,6 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Set to play mode */ info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY; if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) { - BSDAUDIO_CloseDevice(this); return SDL_SetError("Couldn't put device into play mode"); } @@ -361,7 +355,6 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!format) { - BSDAUDIO_CloseDevice(this); return SDL_SetError("No supported encoding for 0x%x", this->spec.format); } @@ -386,7 +379,6 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - BSDAUDIO_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index d70196b9e5bba..ea9088fea05a0 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -22,6 +22,8 @@ #if SDL_AUDIO_DRIVER_COREAUDIO +/* !!! FIXME: clean out some of the macro salsa in here. */ + #include "SDL_audio.h" #include "../SDL_audio_c.h" #include "../SDL_sysaudio.h" @@ -30,11 +32,8 @@ #define DEBUG_COREAUDIO 0 -static void COREAUDIO_CloseDevice(_THIS); - #define CHECK_RESULT(msg) \ if (result != noErr) { \ - COREAUDIO_CloseDevice(this); \ SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \ return 0; \ } @@ -436,45 +435,39 @@ device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectProperty static void COREAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - const int iscapture = this->iscapture; - if (this->hidden->audioUnitOpened) { - #if MACOSX_COREAUDIO - /* Unregister our disconnect callback. */ - AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); - #endif - - AURenderCallbackStruct callback; - const AudioUnitElement output_bus = 0; - const AudioUnitElement input_bus = 1; - const AudioUnitElement bus = - ((iscapture) ? input_bus : output_bus); - - /* stop processing the audio unit */ - AudioOutputUnitStop(this->hidden->audioUnit); - - /* Remove the input callback */ - SDL_zero(callback); - AudioUnitSetProperty(this->hidden->audioUnit, - iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Global, bus, &callback, sizeof(callback)); - AudioComponentInstanceDispose(this->hidden->audioUnit); - this->hidden->audioUnitOpened = 0; - - SDL_free(this->hidden->captureBufferList.mBuffers[0].mData); + const int iscapture = this->iscapture; + if (this->hidden->audioUnitOpened) { + #if MACOSX_COREAUDIO + /* Unregister our disconnect callback. */ + AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); + #endif + + AURenderCallbackStruct callback; + const AudioUnitElement output_bus = 0; + const AudioUnitElement input_bus = 1; + const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus); + + /* stop processing the audio unit */ + AudioOutputUnitStop(this->hidden->audioUnit); + + /* Remove the input callback */ + SDL_zero(callback); + AudioUnitSetProperty(this->hidden->audioUnit, + iscapture ? kAudioOutputUnitProperty_SetInputCallback : kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Global, bus, &callback, sizeof(callback)); + AudioComponentInstanceDispose(this->hidden->audioUnit); + } - } - SDL_free(this->hidden->buffer); - SDL_free(this->hidden); - this->hidden = NULL; + SDL_free(this->hidden->captureBufferList.mBuffers[0].mData); + SDL_free(this->hidden->buffer); + SDL_free(this->hidden); - if (iscapture) { - open_capture_devices--; - } else { - open_playback_devices--; - } - update_audio_session(); + if (iscapture) { + open_capture_devices--; + } else { + open_playback_devices--; } + update_audio_session(); } #if MACOSX_COREAUDIO @@ -623,7 +616,6 @@ prepare_audiounit(_THIS, void *handle, int iscapture, framesize *= SDL_AUDIO_BITSIZE(this->spec.format) / 8; ptr = SDL_calloc(1, framesize); if (ptr == NULL) { - COREAUDIO_CloseDevice(this); SDL_OutOfMemory(); return 0; } @@ -655,7 +647,6 @@ prepare_audiounit(_THIS, void *handle, int iscapture, this->hidden->buffer = SDL_malloc(this->hidden->bufferSize); if (this->hidden->buffer == NULL) { - COREAUDIO_CloseDevice(this); SDL_OutOfMemory(); return 0; } @@ -737,7 +728,6 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_datatype) { /* shouldn't happen, but just in case... */ - COREAUDIO_CloseDevice(this); return SDL_SetError("Unsupported audio format"); } @@ -747,7 +737,6 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; if (!prepare_audiounit(this, handle, iscapture, &strdesc)) { - COREAUDIO_CloseDevice(this); return -1; /* prepare_audiounit() will call SDL_SetError()... */ } diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index 065e163a67912..5450a4355f63f 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -322,20 +322,13 @@ DSOUND_WaitDone(_THIS) static void DSOUND_CloseDevice(_THIS) { - if (this->hidden != NULL) { - if (this->hidden->sound != NULL) { - if (this->hidden->mixbuf != NULL) { - /* Clean up the audio buffer */ - IDirectSoundBuffer_Release(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - } - IDirectSound_Release(this->hidden->sound); - this->hidden->sound = NULL; - } - - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->mixbuf != NULL) { + IDirectSoundBuffer_Release(this->hidden->mixbuf); + } + if (this->hidden->sound != NULL) { + IDirectSound_Release(this->hidden->sound); } + SDL_free(this->hidden); } /* This function tries to create a secondary audio buffer, and returns the @@ -443,7 +436,6 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Open the audio device */ result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL); if (result != DS_OK) { - DSOUND_CloseDevice(this); return SetDSerror("DirectSoundCreate", result); } @@ -465,7 +457,6 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_format) { - DSOUND_CloseDevice(this); if (tried_format) { return -1; /* CreateSecondary() should have called SDL_SetError(). */ } diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index 28745f9d0494e..54d759a8a5687 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -87,16 +87,11 @@ DISKAUD_GetDeviceBuf(_THIS) static void DISKAUD_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->output != NULL) { - SDL_RWclose(this->hidden->output); - this->hidden->output = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->output != NULL) { + SDL_RWclose(this->hidden->output); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -120,14 +115,12 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Open the audio device */ this->hidden->output = SDL_RWFromFile(fname, "wb"); if (this->hidden->output == NULL) { - DISKAUD_CloseDevice(this); return -1; } /* Allocate mixing buffer */ this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - DISKAUD_CloseDevice(this); return -1; } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index 17e029e1d5e03..6a945c66fa597 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -60,16 +60,11 @@ DSP_DetectDevices(void) static void DSP_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->audio_fd >= 0) { - close(this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } @@ -111,7 +106,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Open the audio device */ this->hidden->audio_fd = open(devname, flags, 0); if (this->hidden->audio_fd < 0) { - DSP_CloseDevice(this); return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno)); } this->hidden->mixbuf = NULL; @@ -122,7 +116,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) ctlflags = fcntl(this->hidden->audio_fd, F_GETFL); ctlflags &= ~O_NONBLOCK; if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) { - DSP_CloseDevice(this); return SDL_SetError("Couldn't set audio blocking mode"); } } @@ -130,7 +123,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Get a list of supported hardware formats */ if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { perror("SNDCTL_DSP_GETFMTS"); - DSP_CloseDevice(this); return SDL_SetError("Couldn't get audio format list"); } @@ -187,7 +179,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (format == 0) { - DSP_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -197,7 +188,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { perror("SNDCTL_DSP_SETFMT"); - DSP_CloseDevice(this); return SDL_SetError("Couldn't set audio format"); } @@ -205,7 +195,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) value = this->spec.channels; if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) { perror("SNDCTL_DSP_CHANNELS"); - DSP_CloseDevice(this); return SDL_SetError("Cannot set the number of channels"); } this->spec.channels = value; @@ -214,7 +203,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) value = this->spec.freq; if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { perror("SNDCTL_DSP_SPEED"); - DSP_CloseDevice(this); return SDL_SetError("Couldn't set audio frequency"); } this->spec.freq = value; @@ -225,7 +213,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Determine the power of two of the fragment size */ for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec); if ((0x01U << frag_spec) != this->spec.size) { - DSP_CloseDevice(this); return SDL_SetError("Fragment size must be a power of two"); } frag_spec |= 0x00020000; /* two fragments, for low latency */ @@ -253,7 +240,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - DSP_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c index ea42723c28973..a354aaf27dd52 100644 --- a/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -136,16 +136,8 @@ HandleAudioProcess(_THIS) static void Emscripten_CloseDevice(_THIS) { - if (this->hidden != NULL) { - if (this->hidden->mixbuf != NULL) { - /* Clean up the audio buffer */ - SDL_free(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - } - - SDL_free(this->hidden); - this->hidden = NULL; - } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int diff --git a/src/audio/esd/SDL_esdaudio.c b/src/audio/esd/SDL_esdaudio.c index 6a7882dcbd68c..5053935176065 100644 --- a/src/audio/esd/SDL_esdaudio.c +++ b/src/audio/esd/SDL_esdaudio.c @@ -174,17 +174,11 @@ ESD_GetDeviceBuf(_THIS) static void ESD_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->audio_fd >= 0) { - SDL_NAME(esd_close) (this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->audio_fd >= 0) { + SDL_NAME(esd_close) (this->hidden->audio_fd); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } /* Try to get the name of the program */ @@ -252,7 +246,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!found) { - ESD_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } @@ -271,7 +264,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) get_progname()); if (this->hidden->audio_fd < 0) { - ESD_CloseDevice(this); return SDL_SetError("Couldn't open ESD connection"); } @@ -285,7 +277,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - ESD_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); diff --git a/src/audio/fusionsound/SDL_fsaudio.c b/src/audio/fusionsound/SDL_fsaudio.c index b22a3e9a33d30..d72bb981b8575 100644 --- a/src/audio/fusionsound/SDL_fsaudio.c +++ b/src/audio/fusionsound/SDL_fsaudio.c @@ -22,6 +22,8 @@ #if SDL_AUDIO_DRIVER_FUSIONSOUND +/* !!! FIXME: why is this is SDL_FS_* instead of FUSIONSOUND_*? */ + /* Allow access to a raw mixing buffer */ #ifdef HAVE_SIGNAL_H @@ -168,20 +170,14 @@ SDL_FS_GetDeviceBuf(_THIS) static void SDL_FS_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->stream) { - this->hidden->stream->Release(this->hidden->stream); - this->hidden->stream = NULL; - } - if (this->hidden->fs) { - this->hidden->fs->Release(this->hidden->fs); - this->hidden->fs = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->stream) { + this->hidden->stream->Release(this->hidden->stream); + } + if (this->hidden->fs) { + this->hidden->fs->Release(this->hidden->fs); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } @@ -239,7 +235,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (format == 0) { - SDL_FS_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -247,7 +242,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Retrieve the main sound interface. */ ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs); if (ret) { - SDL_FS_CloseDevice(this); return SDL_SetError("Unable to initialize FusionSound: %d", ret); } @@ -266,7 +260,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->fs->CreateStream(this->hidden->fs, &desc, &this->hidden->stream); if (ret) { - SDL_FS_CloseDevice(this); return SDL_SetError("Unable to create FusionSoundStream: %d", ret); } @@ -287,7 +280,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - SDL_FS_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); diff --git a/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc index de364b0ef2bb5..31543f318ba22 100644 --- a/src/audio/haiku/SDL_haikuaudio.cc +++ b/src/audio/haiku/SDL_haikuaudio.cc @@ -74,16 +74,11 @@ FillSound(void *device, void *stream, size_t len, static void HAIKUAUDIO_CloseDevice(_THIS) { - if (_this->hidden != NULL) { - if (_this->hidden->audio_obj) { - _this->hidden->audio_obj->Stop(); - delete _this->hidden->audio_obj; - _this->hidden->audio_obj = NULL; - } - - delete _this->hidden; - _this->hidden = NULL; + if (_this->hidden->audio_obj) { + _this->hidden->audio_obj->Stop(); + delete _this->hidden->audio_obj; } + delete _this->hidden; } @@ -177,7 +172,6 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_datatype) { /* shouldn't happen, but just in case... */ - HAIKUAUDIO_CloseDevice(_this); return SDL_SetError("Unsupported audio format"); } @@ -196,7 +190,6 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (_this->hidden->audio_obj->Start() == B_NO_ERROR) { _this->hidden->audio_obj->SetHasData(true); } else { - HAIKUAUDIO_CloseDevice(_this); return SDL_SetError("Unable to start Be audio"); } diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index 8f1c51ac51622..7b4c73624ddb9 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -43,8 +43,6 @@ #define SAMPLE_FRAME_COUNT 4096 /* Audio driver functions */ -static int NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture); -static void NACLAUD_CloseDevice(_THIS); static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data); /* FIXME: Make use of latency if needed */ diff --git a/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c index 9de5ff8b4285f..66af12c9100ea 100644 --- a/src/audio/nas/SDL_nasaudio.c +++ b/src/audio/nas/SDL_nasaudio.c @@ -190,16 +190,11 @@ NAS_GetDeviceBuf(_THIS) static void NAS_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->aud) { - NAS_AuCloseServer(this->hidden->aud); - this->hidden->aud = 0; - } - SDL_free(this->hidden); - this2 = this->hidden = NULL; + if (this->hidden->aud) { + NAS_AuCloseServer(this->hidden->aud); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } static unsigned char @@ -300,21 +295,18 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (format == 0) { - NAS_CloseDevice(this); return SDL_SetError("NAS: Couldn't find any hardware audio formats"); } this->spec.format = test_format; this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL); if (this->hidden->aud == 0) { - NAS_CloseDevice(this); return SDL_SetError("NAS: Couldn't open connection to NAS server"); } this->hidden->dev = find_device(this, this->spec.channels); if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) { - NAS_CloseDevice(this); return SDL_SetError("NAS: Couldn't find a fitting device on NAS server"); } @@ -347,7 +339,6 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - NAS_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); diff --git a/src/audio/paudio/SDL_paudio.c b/src/audio/paudio/SDL_paudio.c index 14c9701f46c20..269506e2d4df6 100644 --- a/src/audio/paudio/SDL_paudio.c +++ b/src/audio/paudio/SDL_paudio.c @@ -228,16 +228,11 @@ PAUDIO_GetDeviceBuf(_THIS) static void PAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->audio_fd >= 0) { - close(this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -268,7 +263,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); this->hidden->audio_fd = fd; if (fd < 0) { - PAUDIO_CloseDevice(this); return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); } @@ -277,7 +271,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) * that we can have. */ if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { - PAUDIO_CloseDevice(this); return SDL_SetError("Couldn't get audio buffer information"); } @@ -391,7 +384,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) #ifdef DEBUG_AUDIO fprintf(stderr, "Couldn't find any hardware audio formats\n"); #endif - PAUDIO_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -449,7 +441,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (err != NULL) { - PAUDIO_CloseDevice(this); return SDL_SetError("Paudio: %s", err); } @@ -457,7 +448,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - PAUDIO_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); @@ -492,7 +482,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) paud_control.ioctl_request = AUDIO_START; paud_control.position = 0; if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) { - PAUDIO_CloseDevice(this); #ifdef DEBUG_AUDIO fprintf(stderr, "Can't start audio play\n"); #endif diff --git a/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c index 8f8311417c079..a69bc831d73f7 100644 --- a/src/audio/psp/SDL_pspaudio.c +++ b/src/audio/psp/SDL_pspaudio.c @@ -126,14 +126,11 @@ static void PSPAUD_CloseDevice(_THIS) { if (this->hidden->channel >= 0) { sceAudioChRelease(this->hidden->channel); - this->hidden->channel = -1; - } - - if (this->hidden->rawbuf != NULL) { - free(this->hidden->rawbuf); - this->hidden->rawbuf = NULL; } + free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */ + SDL_free(this->hidden); } + static void PSPAUD_ThreadInit(_THIS) { /* Increase the priority of this audio thread by 1 to put it @@ -151,7 +148,6 @@ static void PSPAUD_ThreadInit(_THIS) static int PSPAUD_Init(SDL_AudioDriverImpl * impl) { - /* Set the function pointers */ impl->OpenDevice = PSPAUD_OpenDevice; impl->PlayDevice = PSPAUD_PlayDevice; diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index cc9a4db6c3cd2..6582da6aa51be 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -463,20 +463,18 @@ PULSEAUDIO_FlushCapture(_THIS) static void PULSEAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { + if (this->hidden->stream) { if (this->hidden->capturebuf != NULL) { PULSEAUDIO_pa_stream_drop(this->hidden->stream); } - SDL_FreeAudioMem(this->hidden->mixbuf); - SDL_free(this->hidden->device_name); - if (this->hidden->stream) { - PULSEAUDIO_pa_stream_disconnect(this->hidden->stream); - PULSEAUDIO_pa_stream_unref(this->hidden->stream); - } - DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context); - SDL_free(this->hidden); - this->hidden = NULL; + PULSEAUDIO_pa_stream_disconnect(this->hidden->stream); + PULSEAUDIO_pa_stream_unref(this->hidden->stream); } + + DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context); + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->device_name); + SDL_free(this->hidden); } static void @@ -579,7 +577,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (paspec.format == PA_SAMPLE_INVALID) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -595,7 +592,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) h->mixlen = this->spec.size; h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen); if (h->mixbuf == NULL) { - PULSEAUDIO_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(h->mixbuf, this->spec.silence, this->spec.size); @@ -621,12 +617,10 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) #endif if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect to PulseAudio server"); } if (!FindDeviceName(h, iscapture, handle)) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Requested PulseAudio sink/source missing?"); } @@ -643,7 +637,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) ); if (h->stream == NULL) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not set up PulseAudio stream"); } @@ -660,18 +653,15 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (rc < 0) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect PulseAudio stream"); } do { if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("pa_mainloop_iterate() failed"); } state = PULSEAUDIO_pa_stream_get_state(h->stream); if (!PA_STREAM_IS_GOOD(state)) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect PulseAudio stream"); } } while (state != PA_STREAM_READY); diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index 88d29f9308626..4847d167b65a6 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -322,27 +322,21 @@ QSA_GetDeviceBuf(_THIS) static void QSA_CloseDevice(_THIS) { - if (this->hidden != NULL) { - if (this->hidden->audio_handle != NULL) { - if (!this->hidden->iscapture) { - /* Finish playing available samples */ - snd_pcm_plugin_flush(this->hidden->audio_handle, - SND_PCM_CHANNEL_PLAYBACK); - } else { - /* Cancel unread samples during capture */ - snd_pcm_plugin_flush(this->hidden->audio_handle, - SND_PCM_CHANNEL_CAPTURE); - } - snd_pcm_close(this->hidden->audio_handle); - this->hidden->audio_handle = NULL; + if (this->hidden->audio_handle != NULL) { + if (!this->hidden->iscapture) { + /* Finish playing available samples */ + snd_pcm_plugin_flush(this->hidden->audio_handle, + SND_PCM_CHANNEL_PLAYBACK); + } else { + /* Cancel unread samples during capture */ + snd_pcm_plugin_flush(this->hidden->audio_handle, + SND_PCM_CHANNEL_CAPTURE); } - - SDL_FreeAudioMem(this->hidden->pcm_buf); - this->hidden->pcm_buf = NULL; - - SDL_free(this->hidden); - this->hidden = NULL; + snd_pcm_close(this->hidden->audio_handle); } + + SDL_FreeAudioMem(this->hidden->pcm_buf); + SDL_free(this->hidden); } static int @@ -391,7 +385,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Check if requested device is opened */ if (status < 0) { this->hidden->audio_handle = NULL; - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_open", status); } @@ -401,7 +394,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) snd_pcm_plugin_set_disable(this->hidden->audio_handle, PLUGIN_DISABLE_MMAP); if (status < 0) { - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_plugin_set_disable", status); } } @@ -487,7 +479,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* assumes test_format not 0 on success */ if (test_format == 0) { - QSA_CloseDevice(this); return SDL_SetError("QSA: Couldn't find any hardware audio formats"); } @@ -505,7 +496,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Setup the transfer parameters according to cparams */ status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams); if (status < 0) { - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_channel_params", status); } @@ -519,7 +509,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Setup an audio channel */ if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) { - QSA_CloseDevice(this); return SDL_SetError("QSA: Unable to setup channel"); } @@ -542,7 +531,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->pcm_buf = (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len); if (this->hidden->pcm_buf == NULL) { - QSA_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->pcm_buf, this->spec.silence, @@ -560,7 +548,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (this->hidden->audio_fd < 0) { - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_file_descriptor", status); } @@ -578,7 +565,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (status < 0) { - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_plugin_prepare", status); } diff --git a/src/audio/sndio/SDL_sndioaudio.c b/src/audio/sndio/SDL_sndioaudio.c index 64565ae886398..9022fd8e1b84d 100644 --- a/src/audio/sndio/SDL_sndioaudio.c +++ b/src/audio/sndio/SDL_sndioaudio.c @@ -180,16 +180,11 @@ SNDIO_WaitDone(_THIS) static void SNDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if ( this->hidden->dev != NULL ) { - SNDIO_sio_close(this->hidden->dev); - this->hidden->dev = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; + if ( this->hidden->dev != NULL ) { + SNDIO_sio_close(this->hidden->dev); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -210,7 +205,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* !!! FIXME: SIO_DEVANY can be a specific device... */ if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) { - SNDIO_CloseDevice(this); return SDL_SetError("sio_open() failed"); } @@ -233,7 +227,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) continue; } if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) { - SNDIO_CloseDevice(this); return SDL_SetError("sio_getpar() failed"); } if (par.bps != SIO_BPS(par.bits)) { @@ -248,7 +241,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (status < 0) { - SNDIO_CloseDevice(this); return SDL_SetError("sndio: Couldn't find any hardware audio formats"); } @@ -269,7 +261,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) else if ((par.bps == 1) && (!par.sig)) this->spec.format = AUDIO_U8; else { - SNDIO_CloseDevice(this); return SDL_SetError("sndio: Got unsupported hardware audio format."); } @@ -284,7 +275,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - SNDIO_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); diff --git a/src/audio/sun/SDL_sunaudio.c b/src/audio/sun/SDL_sunaudio.c index 71029d21fe937..c40e0384498ba 100644 --- a/src/audio/sun/SDL_sunaudio.c +++ b/src/audio/sun/SDL_sunaudio.c @@ -183,18 +183,12 @@ SUNAUDIO_GetDeviceBuf(_THIS) static void SUNAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - SDL_free(this->hidden->ulaw_buf); - this->hidden->ulaw_buf = NULL; - if (this->hidden->audio_fd >= 0) { - close(this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - SDL_free(this->hidden); - this->hidden = NULL; + SDL_free(this->hidden->ulaw_buf); + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); } + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden); } static int diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index 6d05a65ef5d2e..6ef893235117e 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -155,42 +155,31 @@ WINMM_WaitDone(_THIS) static void WINMM_CloseDevice(_THIS) { - /* Close up audio */ - if (this->hidden != NULL) { - int i; + int i; - if (this->hidden->audio_sem) { - CloseHandle(this->hidden->audio_sem); - this->hidden->audio_sem = 0; - } - - /* Clean up mixing buffers */ - for (i = 0; i < NUM_BUFFERS; ++i) { - if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { - waveOutUnprepareHeader(this->hidden->hout, - &this->hidden->wavebuf[i], - sizeof(this->hidden->wavebuf[i])); - this->hidden->wavebuf[i].dwUser = 0xFFFF; - } - } - - /* Free raw mixing buffer */ - SDL_free(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; + if (this->hidden->audio_sem) { + CloseHandle(this->hidden->audio_sem); + } - if (this->hidden->hin) { - waveInClose(this->hidden->hin); - this->hidden->hin = 0; + /* Clean up mixing buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { + waveOutUnprepareHeader(this->hidden->hout, + &this->hidden->wavebuf[i], + sizeof (this->hidden->wavebuf[i])); } + } - if (this->hidden->hout) { - waveOutClose(this->hidden->hout); - this->hidden->hout = 0; - } + if (this->hidden->hin) { + waveInClose(this->hidden->hin); + } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->hout) { + waveOutClose(this->hidden->hout); } + + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static SDL_bool @@ -269,7 +258,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_datatype) { - WINMM_CloseDevice(this); return SDL_SetError("Unsupported audio format"); } @@ -288,7 +276,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (result != MMSYSERR_NOERROR) { - WINMM_CloseDevice(this); return SetMMerror("waveOutOpen()", result); } #ifdef SOUND_DEBUG @@ -299,7 +286,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) result = waveOutGetDevCaps((UINT) this->hidden->hout, &caps, sizeof(caps)); if (result != MMSYSERR_NOERROR) { - WINMM_CloseDevice(this); return SetMMerror("waveOutGetDevCaps()", result); } printf("Audio device: %s\n", caps.szPname); @@ -310,7 +296,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->audio_sem = CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); if (this->hidden->audio_sem == NULL) { - WINMM_CloseDevice(this); return SDL_SetError("Couldn't create semaphore"); } @@ -318,7 +303,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size); if (this->hidden->mixbuf == NULL) { - WINMM_CloseDevice(this); return SDL_OutOfMemory(); } for (i = 0; i < NUM_BUFFERS; ++i) { @@ -332,7 +316,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) &this->hidden->wavebuf[i], sizeof(this->hidden->wavebuf[i])); if (result != MMSYSERR_NOERROR) { - WINMM_CloseDevice(this); return SetMMerror("waveOutPrepareHeader()", result); } } diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c index ba9ad9fbc9e3e..b300bcdd6d31e 100644 --- a/src/audio/xaudio2/SDL_xaudio2.c +++ b/src/audio/xaudio2/SDL_xaudio2.c @@ -257,33 +257,30 @@ XAUDIO2_WaitDone(_THIS) static void XAUDIO2_CloseDevice(_THIS) { - if (this->hidden != NULL) { - IXAudio2 *ixa2 = this->hidden->ixa2; - IXAudio2SourceVoice *source = this->hidden->source; - IXAudio2MasteringVoice *mastering = this->hidden->mastering; - - if (source != NULL) { - IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW); - IXAudio2SourceVoice_FlushSourceBuffers(source); - IXAudio2SourceVoice_DestroyVoice(source); - } - if (ixa2 != NULL) { - IXAudio2_StopEngine(ixa2); - } - if (mastering != NULL) { - IXAudio2MasteringVoice_DestroyVoice(mastering); - } - if (ixa2 != NULL) { - IXAudio2_Release(ixa2); - } - SDL_free(this->hidden->mixbuf); - if (this->hidden->semaphore != NULL) { - SDL_DestroySemaphore(this->hidden->semaphore); - } + IXAudio2 *ixa2 = this->hidden->ixa2; + IXAudio2SourceVoice *source = this->hidden->source; + IXAudio2MasteringVoice *mastering = this->hidden->mastering; - SDL_free(this->hidden); - this->hidden = NULL; + if (source != NULL) { + IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(source); + IXAudio2SourceVoice_DestroyVoice(source); } + if (ixa2 != NULL) { + IXAudio2_StopEngine(ixa2); + } + if (mastering != NULL) { + IXAudio2MasteringVoice_DestroyVoice(mastering); + } + if (ixa2 != NULL) { + IXAudio2_Release(ixa2); + } + if (this->hidden->semaphore != NULL) { + SDL_DestroySemaphore(this->hidden->semaphore); + } + + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -350,7 +347,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->ixa2 = ixa2; this->hidden->semaphore = SDL_CreateSemaphore(1); if (this->hidden->semaphore == NULL) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: CreateSemaphore() failed!"); } @@ -368,7 +364,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_format) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Unsupported audio format"); } @@ -379,7 +374,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - XAUDIO2_CloseDevice(this); return SDL_OutOfMemory(); } this->hidden->nextbuf = this->hidden->mixbuf; @@ -401,7 +395,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->spec.freq, 0, devId, NULL); #endif if (result != S_OK) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't create mastering voice"); } @@ -436,7 +429,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) #endif if (result != S_OK) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't create source voice"); } this->hidden->source = source; @@ -444,13 +436,11 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Start everything playing! */ result = IXAudio2_StartEngine(ixa2); if (result != S_OK) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't start engine"); } result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW); if (result != S_OK) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't start source voice"); } From 979de761c987dcf538487a8f4e307c73e21a6cfc Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 5 Aug 2016 01:44:15 -0400 Subject: [PATCH 26/55] audio: Removed internal SDL_audiomem.h and macros. I think this was important for SDL 1.2 because some targets needed special device memory for DMA buffers or locked memory buffers for use in hardware interrupts or something, but since it just defines to SDL_malloc and SDL_free now, I took it out for clarity's sake. --- VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj | 1 - .../UWP_VS2015/SDL-UWP.vcxproj.filters | 3 --- .../WinPhone80_VS2012/SDL-WinPhone80.vcxproj | 1 - .../SDL-WinPhone80.vcxproj.filters | 3 --- .../WinPhone81_VS2013/SDL-WinPhone81.vcxproj | 1 - .../SDL-WinPhone81.vcxproj.filters | 3 --- .../WinRT80_VS2012/SDL-WinRT80.vcxproj | 1 - .../SDL-WinRT80.vcxproj.filters | 3 --- .../WinRT81_VS2013/SDL-WinRT81.vcxproj | 1 - .../SDL-WinRT81.vcxproj.filters | 3 --- VisualC/SDL/SDL.vcxproj | 1 - VisualC/SDL/SDL.vcxproj.filters | 1 - VisualC/SDL/SDL_VS2008.vcproj | 4 --- Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj | 2 -- Xcode/SDL/SDL.xcodeproj/project.pbxproj | 8 ------ premake/VisualC/VS2008/SDL2/SDL2.vcproj | 4 --- premake/VisualC/VS2010/SDL2/SDL2.vcxproj | 1 - .../VisualC/VS2010/SDL2/SDL2.vcxproj.filters | 3 --- premake/VisualC/VS2012/SDL2/SDL2.vcxproj | 1 - .../VisualC/VS2012/SDL2/SDL2.vcxproj.filters | 3 --- .../SDL2/SDL2.xcodeproj/project.pbxproj | 2 -- .../SDL2/SDL2.xcodeproj/project.pbxproj | 2 -- .../SDL2/SDL2.xcodeproj/project.pbxproj | 2 -- src/audio/SDL_audio.c | 14 +++++------ src/audio/SDL_audiomem.h | 25 ------------------- src/audio/alsa/SDL_alsa_audio.c | 5 ++-- src/audio/arts/SDL_artsaudio.c | 5 ++-- src/audio/bsd/SDL_bsdaudio.c | 5 ++-- src/audio/disk/SDL_diskaudio.c | 5 ++-- src/audio/dsp/SDL_dspaudio.c | 5 ++-- src/audio/esd/SDL_esdaudio.c | 5 ++-- src/audio/fusionsound/SDL_fsaudio.c | 5 ++-- src/audio/nacl/SDL_naclaudio.c | 1 - src/audio/nas/SDL_nasaudio.c | 5 ++-- src/audio/paudio/SDL_paudio.c | 5 ++-- src/audio/psp/SDL_pspaudio.c | 1 - src/audio/pulseaudio/SDL_pulseaudio.c | 5 ++-- src/audio/qsa/SDL_qsa_audio.c | 5 ++-- src/audio/sndio/SDL_sndioaudio.c | 5 ++-- src/audio/sun/SDL_sunaudio.c | 5 ++-- 40 files changed, 32 insertions(+), 128 deletions(-) delete mode 100644 src/audio/SDL_audiomem.h diff --git a/VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj b/VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj index 305a3ca5f14a5..25e414a708506 100644 --- a/VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj +++ b/VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj @@ -81,7 +81,6 @@ - diff --git a/VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj.filters b/VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj.filters index b8c6d712d989b..874df6acebdb6 100644 --- a/VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj.filters +++ b/VisualC-WinRT/UWP_VS2015/SDL-UWP.vcxproj.filters @@ -174,9 +174,6 @@ Source Files - - Source Files - Source Files diff --git a/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.vcxproj b/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.vcxproj index 3776d2433b661..997101d8718f1 100644 --- a/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.vcxproj +++ b/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.vcxproj @@ -208,7 +208,6 @@ - diff --git a/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.vcxproj.filters b/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.vcxproj.filters index 1f4df44e41f18..f699eec489f45 100644 --- a/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.vcxproj.filters +++ b/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.vcxproj.filters @@ -159,9 +159,6 @@ Source Files - - Source Files - Source Files diff --git a/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.vcxproj b/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.vcxproj index 573bc4286ca3a..e40a6577f4ed7 100644 --- a/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.vcxproj +++ b/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.vcxproj @@ -73,7 +73,6 @@ - diff --git a/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.vcxproj.filters b/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.vcxproj.filters index 907e1bfb7f92d..a36ce69e10420 100644 --- a/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.vcxproj.filters +++ b/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.vcxproj.filters @@ -174,9 +174,6 @@ Source Files - - Source Files - Source Files diff --git a/VisualC-WinRT/WinRT80_VS2012/SDL-WinRT80.vcxproj b/VisualC-WinRT/WinRT80_VS2012/SDL-WinRT80.vcxproj index fbcd94b6b6c28..6dd130f572b5a 100644 --- a/VisualC-WinRT/WinRT80_VS2012/SDL-WinRT80.vcxproj +++ b/VisualC-WinRT/WinRT80_VS2012/SDL-WinRT80.vcxproj @@ -279,7 +279,6 @@ - diff --git a/VisualC-WinRT/WinRT80_VS2012/SDL-WinRT80.vcxproj.filters b/VisualC-WinRT/WinRT80_VS2012/SDL-WinRT80.vcxproj.filters index aa539d37e160b..0e07f29a9eecd 100644 --- a/VisualC-WinRT/WinRT80_VS2012/SDL-WinRT80.vcxproj.filters +++ b/VisualC-WinRT/WinRT80_VS2012/SDL-WinRT80.vcxproj.filters @@ -417,9 +417,6 @@ Header Files - - Source Files - Source Files diff --git a/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.vcxproj b/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.vcxproj index a56516ead6539..21a452cd27088 100644 --- a/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.vcxproj +++ b/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.vcxproj @@ -81,7 +81,6 @@ - diff --git a/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.vcxproj.filters b/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.vcxproj.filters index a36811dd4b19d..e3e208cc08d74 100644 --- a/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.vcxproj.filters +++ b/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.vcxproj.filters @@ -174,9 +174,6 @@ Source Files - - Source Files - Source Files diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj index 595e2d44305d6..56274818a1b02 100644 --- a/VisualC/SDL/SDL.vcxproj +++ b/VisualC/SDL/SDL.vcxproj @@ -294,7 +294,6 @@ - diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters index a2ba2cb5cc343..36b6c5077695d 100644 --- a/VisualC/SDL/SDL.vcxproj.filters +++ b/VisualC/SDL/SDL.vcxproj.filters @@ -230,7 +230,6 @@ - diff --git a/VisualC/SDL/SDL_VS2008.vcproj b/VisualC/SDL/SDL_VS2008.vcproj index 3d3d39969ac68..e2e021f1a810e 100644 --- a/VisualC/SDL/SDL_VS2008.vcproj +++ b/VisualC/SDL/SDL_VS2008.vcproj @@ -771,10 +771,6 @@ RelativePath="..\..\src\audio\SDL_audiodev_c.h" > - - diff --git a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj index b0830bf46fed6..e21f9d2e90059 100755 --- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj @@ -376,7 +376,6 @@ FD99B9440DD52EDC00FB1D6B /* SDL_audio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audio.c; sourceTree = ""; }; FD99B9450DD52EDC00FB1D6B /* SDL_audio_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audio_c.h; sourceTree = ""; }; FD99B9460DD52EDC00FB1D6B /* SDL_audiocvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiocvt.c; sourceTree = ""; }; - FD99B9490DD52EDC00FB1D6B /* SDL_audiomem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audiomem.h; sourceTree = ""; }; FD99B94A0DD52EDC00FB1D6B /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiotypecvt.c; sourceTree = ""; }; FD99B94B0DD52EDC00FB1D6B /* SDL_mixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_mixer.c; sourceTree = ""; }; FD99B9520DD52EDC00FB1D6B /* SDL_sysaudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysaudio.h; sourceTree = ""; }; @@ -795,7 +794,6 @@ FD99B9440DD52EDC00FB1D6B /* SDL_audio.c */, FD99B9450DD52EDC00FB1D6B /* SDL_audio_c.h */, FD99B9460DD52EDC00FB1D6B /* SDL_audiocvt.c */, - FD99B9490DD52EDC00FB1D6B /* SDL_audiomem.h */, FD99B94A0DD52EDC00FB1D6B /* SDL_audiotypecvt.c */, FD99B94B0DD52EDC00FB1D6B /* SDL_mixer.c */, FD99B9520DD52EDC00FB1D6B /* SDL_sysaudio.h */, diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj index 9d685daf62baf..6b1e1f9cb6eef 100755 --- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -64,7 +64,6 @@ 04BD002812E6671800899322 /* SDL_audiocvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB612E6671700899322 /* SDL_audiocvt.c */; }; 04BD002912E6671800899322 /* SDL_audiodev.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB712E6671700899322 /* SDL_audiodev.c */; }; 04BD002A12E6671800899322 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; }; - 04BD002B12E6671800899322 /* SDL_audiomem.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB912E6671700899322 /* SDL_audiomem.h */; }; 04BD002C12E6671800899322 /* SDL_audiotypecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */; }; 04BD002D12E6671800899322 /* SDL_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBB12E6671700899322 /* SDL_mixer.c */; }; 04BD003412E6671800899322 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; }; @@ -218,7 +217,6 @@ 04BD024412E6671800899322 /* SDL_audiocvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB612E6671700899322 /* SDL_audiocvt.c */; }; 04BD024512E6671800899322 /* SDL_audiodev.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDB712E6671700899322 /* SDL_audiodev.c */; }; 04BD024612E6671800899322 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; }; - 04BD024712E6671800899322 /* SDL_audiomem.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB912E6671700899322 /* SDL_audiomem.h */; }; 04BD024812E6671800899322 /* SDL_audiotypecvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */; }; 04BD024912E6671800899322 /* SDL_mixer.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BDFDBB12E6671700899322 /* SDL_mixer.c */; }; 04BD025012E6671800899322 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; }; @@ -563,7 +561,6 @@ DB313F7617554B71006C0E22 /* SDL_coreaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDA112E6671700899322 /* SDL_coreaudio.h */; }; DB313F7717554B71006C0E22 /* SDL_audio_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB512E6671700899322 /* SDL_audio_c.h */; }; DB313F7817554B71006C0E22 /* SDL_audiodev_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */; }; - DB313F7917554B71006C0E22 /* SDL_audiomem.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDB912E6671700899322 /* SDL_audiomem.h */; }; DB313F7A17554B71006C0E22 /* SDL_sysaudio.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC212E6671700899322 /* SDL_sysaudio.h */; }; DB313F7B17554B71006C0E22 /* SDL_wave.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDC412E6671700899322 /* SDL_wave.h */; }; DB313F7C17554B71006C0E22 /* blank_cursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BDFDD612E6671700899322 /* blank_cursor.h */; }; @@ -864,7 +861,6 @@ 04BDFDB612E6671700899322 /* SDL_audiocvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiocvt.c; sourceTree = ""; }; 04BDFDB712E6671700899322 /* SDL_audiodev.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiodev.c; sourceTree = ""; }; 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audiodev_c.h; sourceTree = ""; }; - 04BDFDB912E6671700899322 /* SDL_audiomem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_audiomem.h; sourceTree = ""; }; 04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audiotypecvt.c; sourceTree = ""; }; 04BDFDBB12E6671700899322 /* SDL_mixer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_mixer.c; sourceTree = ""; }; 04BDFDC212E6671700899322 /* SDL_sysaudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysaudio.h; sourceTree = ""; }; @@ -1307,7 +1303,6 @@ 04BDFDB612E6671700899322 /* SDL_audiocvt.c */, 04BDFDB712E6671700899322 /* SDL_audiodev.c */, 04BDFDB812E6671700899322 /* SDL_audiodev_c.h */, - 04BDFDB912E6671700899322 /* SDL_audiomem.h */, 04BDFDBA12E6671700899322 /* SDL_audiotypecvt.c */, 04BDFDBB12E6671700899322 /* SDL_mixer.c */, 04BDFDC212E6671700899322 /* SDL_sysaudio.h */, @@ -1840,7 +1835,6 @@ 04BD001912E6671800899322 /* SDL_coreaudio.h in Headers */, 04BD002712E6671800899322 /* SDL_audio_c.h in Headers */, 04BD002A12E6671800899322 /* SDL_audiodev_c.h in Headers */, - 04BD002B12E6671800899322 /* SDL_audiomem.h in Headers */, 04BD003412E6671800899322 /* SDL_sysaudio.h in Headers */, 04BD003612E6671800899322 /* SDL_wave.h in Headers */, 04BD004212E6671800899322 /* blank_cursor.h in Headers */, @@ -1996,7 +1990,6 @@ 04BD024312E6671800899322 /* SDL_audio_c.h in Headers */, 04BD024612E6671800899322 /* SDL_audiodev_c.h in Headers */, AAC070FD195606770073DCDF /* SDL_opengles2_gl2.h in Headers */, - 04BD024712E6671800899322 /* SDL_audiomem.h in Headers */, 04BD025012E6671800899322 /* SDL_sysaudio.h in Headers */, 04BD025212E6671800899322 /* SDL_wave.h in Headers */, 04BD025D12E6671800899322 /* blank_cursor.h in Headers */, @@ -2151,7 +2144,6 @@ DB313F7717554B71006C0E22 /* SDL_audio_c.h in Headers */, DB313F7817554B71006C0E22 /* SDL_audiodev_c.h in Headers */, AAC070FE195606770073DCDF /* SDL_opengles2_gl2.h in Headers */, - DB313F7917554B71006C0E22 /* SDL_audiomem.h in Headers */, DB313F7A17554B71006C0E22 /* SDL_sysaudio.h in Headers */, DB313F7B17554B71006C0E22 /* SDL_wave.h in Headers */, DB313F7C17554B71006C0E22 /* blank_cursor.h in Headers */, diff --git a/premake/VisualC/VS2008/SDL2/SDL2.vcproj b/premake/VisualC/VS2008/SDL2/SDL2.vcproj index 20ff3d60515fc..ecf934e800c04 100755 --- a/premake/VisualC/VS2008/SDL2/SDL2.vcproj +++ b/premake/VisualC/VS2008/SDL2/SDL2.vcproj @@ -418,10 +418,6 @@ RelativePath="..\..\..\..\src\audio\SDL_audiodev_c.h" > - - diff --git a/premake/VisualC/VS2010/SDL2/SDL2.vcxproj b/premake/VisualC/VS2010/SDL2/SDL2.vcxproj index a34fa4b06caf7..15db66247643e 100755 --- a/premake/VisualC/VS2010/SDL2/SDL2.vcxproj +++ b/premake/VisualC/VS2010/SDL2/SDL2.vcxproj @@ -113,7 +113,6 @@ - diff --git a/premake/VisualC/VS2010/SDL2/SDL2.vcxproj.filters b/premake/VisualC/VS2010/SDL2/SDL2.vcxproj.filters index e5af43ce40b13..3456e87e6bae2 100755 --- a/premake/VisualC/VS2010/SDL2/SDL2.vcxproj.filters +++ b/premake/VisualC/VS2010/SDL2/SDL2.vcxproj.filters @@ -123,9 +123,6 @@ src\audio - - src\audio - src\audio diff --git a/premake/VisualC/VS2012/SDL2/SDL2.vcxproj b/premake/VisualC/VS2012/SDL2/SDL2.vcxproj index c7dd06f0937ec..cff34ff0308a0 100755 --- a/premake/VisualC/VS2012/SDL2/SDL2.vcxproj +++ b/premake/VisualC/VS2012/SDL2/SDL2.vcxproj @@ -115,7 +115,6 @@ - diff --git a/premake/VisualC/VS2012/SDL2/SDL2.vcxproj.filters b/premake/VisualC/VS2012/SDL2/SDL2.vcxproj.filters index 32b1bdd2ff10d..a03ab498124ad 100755 --- a/premake/VisualC/VS2012/SDL2/SDL2.vcxproj.filters +++ b/premake/VisualC/VS2012/SDL2/SDL2.vcxproj.filters @@ -123,9 +123,6 @@ src\audio - - src\audio - src\audio diff --git a/premake/Xcode-iOS/SDL2/SDL2.xcodeproj/project.pbxproj b/premake/Xcode-iOS/SDL2/SDL2.xcodeproj/project.pbxproj index 4dbfb523c67fa..80be6759e19cb 100755 --- a/premake/Xcode-iOS/SDL2/SDL2.xcodeproj/project.pbxproj +++ b/premake/Xcode-iOS/SDL2/SDL2.xcodeproj/project.pbxproj @@ -127,7 +127,6 @@ 4DBB70D75469728B342373E8 /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../src/audio/SDL_audiocvt.c"; sourceTree = ""; }; 48886D482B5239D2429E422D /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../src/audio/SDL_audiodev.c"; sourceTree = ""; }; 227E138737440F101016545F /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../src/audio/SDL_audiodev_c.h"; sourceTree = ""; }; - 5C3C744F22823D470BED10D6 /* SDL_audiomem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiomem.h"; path = "../../../src/audio/SDL_audiomem.h"; sourceTree = ""; }; 0F175E65628D4137386B7A6D /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../src/audio/SDL_audiotypecvt.c"; sourceTree = ""; }; 77537CFB490A3599736F3830 /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../src/audio/SDL_mixer.c"; sourceTree = ""; }; 591062475F93492D625F7D3B /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../src/audio/SDL_sysaudio.h"; sourceTree = ""; }; @@ -369,7 +368,6 @@ 4DBB70D75469728B342373E8 /* SDL_audiocvt.c */, 48886D482B5239D2429E422D /* SDL_audiodev.c */, 227E138737440F101016545F /* SDL_audiodev_c.h */, - 5C3C744F22823D470BED10D6 /* SDL_audiomem.h */, 0F175E65628D4137386B7A6D /* SDL_audiotypecvt.c */, 77537CFB490A3599736F3830 /* SDL_mixer.c */, 591062475F93492D625F7D3B /* SDL_sysaudio.h */, diff --git a/premake/Xcode/Xcode3/SDL2/SDL2.xcodeproj/project.pbxproj b/premake/Xcode/Xcode3/SDL2/SDL2.xcodeproj/project.pbxproj index 9ba1b0b6fe2af..f2be9ff46b377 100755 --- a/premake/Xcode/Xcode3/SDL2/SDL2.xcodeproj/project.pbxproj +++ b/premake/Xcode/Xcode3/SDL2/SDL2.xcodeproj/project.pbxproj @@ -146,7 +146,6 @@ 2BA37BD372FE166821D80A1E /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../../src/audio/SDL_audiocvt.c"; sourceTree = ""; }; 5D2936CF698D392735D76E9E /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../../src/audio/SDL_audiodev.c"; sourceTree = ""; }; 1F255A29771744AC1DFE48A0 /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../../src/audio/SDL_audiodev_c.h"; sourceTree = ""; }; - 14AA3D784A5D4B873D657338 /* SDL_audiomem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiomem.h"; path = "../../../../src/audio/SDL_audiomem.h"; sourceTree = ""; }; 76263CFA4F4A3E8E74966406 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../../src/audio/SDL_audiotypecvt.c"; sourceTree = ""; }; 748562A8151756FF3FE91679 /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../../src/audio/SDL_mixer.c"; sourceTree = ""; }; 7B696A2B3C9847A40FD30FA2 /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../../src/audio/SDL_sysaudio.h"; sourceTree = ""; }; @@ -425,7 +424,6 @@ 2BA37BD372FE166821D80A1E /* SDL_audiocvt.c */, 5D2936CF698D392735D76E9E /* SDL_audiodev.c */, 1F255A29771744AC1DFE48A0 /* SDL_audiodev_c.h */, - 14AA3D784A5D4B873D657338 /* SDL_audiomem.h */, 76263CFA4F4A3E8E74966406 /* SDL_audiotypecvt.c */, 748562A8151756FF3FE91679 /* SDL_mixer.c */, 7B696A2B3C9847A40FD30FA2 /* SDL_sysaudio.h */, diff --git a/premake/Xcode/Xcode4/SDL2/SDL2.xcodeproj/project.pbxproj b/premake/Xcode/Xcode4/SDL2/SDL2.xcodeproj/project.pbxproj index d930889b87033..aa7d339a7717d 100755 --- a/premake/Xcode/Xcode4/SDL2/SDL2.xcodeproj/project.pbxproj +++ b/premake/Xcode/Xcode4/SDL2/SDL2.xcodeproj/project.pbxproj @@ -146,7 +146,6 @@ 07B907294E82663A7E91738C /* SDL_audiocvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiocvt.c"; path = "../../../../src/audio/SDL_audiocvt.c"; sourceTree = ""; }; 5AAD4B726237251050431873 /* SDL_audiodev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiodev.c"; path = "../../../../src/audio/SDL_audiodev.c"; sourceTree = ""; }; 15895798549516351860492E /* SDL_audiodev_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiodev_c.h"; path = "../../../../src/audio/SDL_audiodev_c.h"; sourceTree = ""; }; - 0D3062CE47BF5D5934AB598D /* SDL_audiomem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_audiomem.h"; path = "../../../../src/audio/SDL_audiomem.h"; sourceTree = ""; }; 5B0759ED16B35B9A6B027892 /* SDL_audiotypecvt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_audiotypecvt.c"; path = "../../../../src/audio/SDL_audiotypecvt.c"; sourceTree = ""; }; 2B8C7A19218A1FFC6D376B1D /* SDL_mixer.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "SDL_mixer.c"; path = "../../../../src/audio/SDL_mixer.c"; sourceTree = ""; }; 09E4653E4CD964410C0E71BA /* SDL_sysaudio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SDL_sysaudio.h"; path = "../../../../src/audio/SDL_sysaudio.h"; sourceTree = ""; }; @@ -425,7 +424,6 @@ 07B907294E82663A7E91738C /* SDL_audiocvt.c */, 5AAD4B726237251050431873 /* SDL_audiodev.c */, 15895798549516351860492E /* SDL_audiodev_c.h */, - 0D3062CE47BF5D5934AB598D /* SDL_audiomem.h */, 5B0759ED16B35B9A6B027892 /* SDL_audiotypecvt.c */, 2B8C7A19218A1FFC6D376B1D /* SDL_mixer.c */, 09E4653E4CD964410C0E71BA /* SDL_sysaudio.h */, diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 80bae07c83847..139520448db3f 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -25,7 +25,6 @@ #include "SDL.h" #include "SDL_audio.h" #include "SDL_audio_c.h" -#include "SDL_audiomem.h" #include "SDL_sysaudio.h" #include "../thread/SDL_systhread.h" @@ -978,9 +977,9 @@ close_audio_device(SDL_AudioDevice * device) if (device->mixer_lock != NULL) { SDL_DestroyMutex(device->mixer_lock); } - SDL_FreeAudioMem(device->fake_stream); + SDL_free(device->fake_stream); if (device->convert.needed) { - SDL_FreeAudioMem(device->convert.buf); + SDL_free(device->convert.buf); } if (device->hidden != NULL) { current_audio.impl.CloseDevice(device); @@ -989,7 +988,7 @@ close_audio_device(SDL_AudioDevice * device) free_audio_queue(device->buffer_queue_head); free_audio_queue(device->buffer_queue_pool); - SDL_FreeAudioMem(device); + SDL_free(device); } @@ -1164,12 +1163,11 @@ open_audio_device(const char *devname, int iscapture, } } - device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice)); + device = (SDL_AudioDevice *) SDL_calloc(1, sizeof (SDL_AudioDevice)); if (device == NULL) { SDL_OutOfMemory(); return 0; } - SDL_zerop(device); device->id = id + 1; device->spec = *obtained; device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE; @@ -1245,7 +1243,7 @@ open_audio_device(const char *devname, int iscapture, device->convert.len_ratio); device->convert.buf = - (Uint8 *) SDL_AllocAudioMem(device->convert.len * + (Uint8 *) SDL_malloc(device->convert.len * device->convert.len_mult); if (device->convert.buf == NULL) { close_audio_device(device); @@ -1261,7 +1259,7 @@ open_audio_device(const char *devname, int iscapture, stream_len = device->spec.size; } SDL_assert(stream_len > 0); - device->fake_stream = (Uint8 *)SDL_AllocAudioMem(stream_len); + device->fake_stream = (Uint8 *) SDL_malloc(stream_len); if (device->fake_stream == NULL) { close_audio_device(device); SDL_OutOfMemory(); diff --git a/src/audio/SDL_audiomem.h b/src/audio/SDL_audiomem.h deleted file mode 100644 index 091d15c29874a..0000000000000 --- a/src/audio/SDL_audiomem.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2016 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "../SDL_internal.h" - -#define SDL_AllocAudioMem SDL_malloc -#define SDL_FreeAudioMem SDL_free -/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index f38e3ba13af8e..833c5cea3abde 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -32,7 +32,6 @@ #include "SDL_assert.h" #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_alsa_audio.h" @@ -406,7 +405,7 @@ ALSA_CloseDevice(_THIS) ALSA_snd_pcm_drain(this->hidden->pcm_handle); ALSA_snd_pcm_close(this->hidden->pcm_handle); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -686,7 +685,7 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ if (!iscapture) { this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 3f4ba81a311b0..91d1d041c3ebe 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -32,7 +32,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_artsaudio.h" @@ -207,7 +206,7 @@ ARTS_CloseDevice(_THIS) SDL_NAME(arts_close_stream) (this->hidden->stream); } SDL_NAME(arts_free) (); - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -307,7 +306,7 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index 6858f1e5704eb..1d9da4ee0846b 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -38,7 +38,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "SDL_bsdaudio.h" @@ -271,7 +270,7 @@ BSDAUDIO_CloseDevice(_THIS) if (this->hidden->audio_fd >= 0) { close(this->hidden->audio_fd); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -377,7 +376,7 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (!iscapture) { /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index 54d759a8a5687..fb684d2c6bd3d 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -31,7 +31,6 @@ #include "SDL_rwops.h" #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_diskaudio.h" @@ -90,7 +89,7 @@ DISKAUD_CloseDevice(_THIS) if (this->hidden->output != NULL) { SDL_RWclose(this->hidden->output); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -119,7 +118,7 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } /* Allocate mixing buffer */ - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return -1; } diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index 6a945c66fa597..3bfdb98576f0d 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -44,7 +44,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "SDL_dspaudio.h" @@ -63,7 +62,7 @@ DSP_CloseDevice(_THIS) if (this->hidden->audio_fd >= 0) { close(this->hidden->audio_fd); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -238,7 +237,7 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/esd/SDL_esdaudio.c b/src/audio/esd/SDL_esdaudio.c index 5053935176065..f80f3dd22daa6 100644 --- a/src/audio/esd/SDL_esdaudio.c +++ b/src/audio/esd/SDL_esdaudio.c @@ -32,7 +32,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_esdaudio.h" @@ -177,7 +176,7 @@ ESD_CloseDevice(_THIS) if (this->hidden->audio_fd >= 0) { SDL_NAME(esd_close) (this->hidden->audio_fd); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -275,7 +274,7 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/fusionsound/SDL_fsaudio.c b/src/audio/fusionsound/SDL_fsaudio.c index d72bb981b8575..72c8309fe6a9c 100644 --- a/src/audio/fusionsound/SDL_fsaudio.c +++ b/src/audio/fusionsound/SDL_fsaudio.c @@ -33,7 +33,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_fsaudio.h" @@ -176,7 +175,7 @@ SDL_FS_CloseDevice(_THIS) if (this->hidden->fs) { this->hidden->fs->Release(this->hidden->fs); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -278,7 +277,7 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index 7b4c73624ddb9..5b8c2dd0beab7 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -27,7 +27,6 @@ #include "SDL_audio.h" #include "SDL_mutex.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" diff --git a/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c index 66af12c9100ea..c9b39c632d727 100644 --- a/src/audio/nas/SDL_nasaudio.c +++ b/src/audio/nas/SDL_nasaudio.c @@ -30,7 +30,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" #include "SDL_loadso.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_nasaudio.h" @@ -193,7 +192,7 @@ NAS_CloseDevice(_THIS) if (this->hidden->aud) { NAS_AuCloseServer(this->hidden->aud); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -337,7 +336,7 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/paudio/SDL_paudio.c b/src/audio/paudio/SDL_paudio.c index 269506e2d4df6..9191a3ed9a481 100644 --- a/src/audio/paudio/SDL_paudio.c +++ b/src/audio/paudio/SDL_paudio.c @@ -35,7 +35,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" #include "SDL_stdinc.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_paudio.h" @@ -231,7 +230,7 @@ PAUDIO_CloseDevice(_THIS) if (this->hidden->audio_fd >= 0) { close(this->hidden->audio_fd); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -446,7 +445,7 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c index a69bc831d73f7..f29f85ae7e99a 100644 --- a/src/audio/psp/SDL_pspaudio.c +++ b/src/audio/psp/SDL_pspaudio.c @@ -30,7 +30,6 @@ #include "SDL_audio.h" #include "SDL_error.h" #include "SDL_timer.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "../SDL_sysaudio.h" diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index 6582da6aa51be..1ac772c06b751 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -42,7 +42,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_pulseaudio.h" #include "SDL_loadso.h" @@ -472,7 +471,7 @@ PULSEAUDIO_CloseDevice(_THIS) } DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context); - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden->device_name); SDL_free(this->hidden); } @@ -590,7 +589,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ if (!iscapture) { h->mixlen = this->spec.size; - h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen); + h->mixbuf = (Uint8 *) SDL_malloc(h->mixlen); if (h->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index 4847d167b65a6..a4384e7fd4d42 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -45,7 +45,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_qsa_audio.h" @@ -335,7 +334,7 @@ QSA_CloseDevice(_THIS) snd_pcm_close(this->hidden->audio_handle); } - SDL_FreeAudioMem(this->hidden->pcm_buf); + SDL_free(this->hidden->pcm_buf); SDL_free(this->hidden); } @@ -529,7 +528,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) * closest multiple) */ this->hidden->pcm_buf = - (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len); + (Uint8 *) SDL_malloc(this->hidden->pcm_len); if (this->hidden->pcm_buf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/sndio/SDL_sndioaudio.c b/src/audio/sndio/SDL_sndioaudio.c index 9022fd8e1b84d..309e503a5e2f5 100644 --- a/src/audio/sndio/SDL_sndioaudio.c +++ b/src/audio/sndio/SDL_sndioaudio.c @@ -36,7 +36,6 @@ #include #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_sndioaudio.h" @@ -183,7 +182,7 @@ SNDIO_CloseDevice(_THIS) if ( this->hidden->dev != NULL ) { SNDIO_sio_close(this->hidden->dev); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -273,7 +272,7 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/sun/SDL_sunaudio.c b/src/audio/sun/SDL_sunaudio.c index c40e0384498ba..fb90146c5c1f6 100644 --- a/src/audio/sun/SDL_sunaudio.c +++ b/src/audio/sun/SDL_sunaudio.c @@ -40,7 +40,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "SDL_sunaudio.h" @@ -187,7 +186,7 @@ SUNAUDIO_CloseDevice(_THIS) if (this->hidden->audio_fd >= 0) { close(this->hidden->audio_fd); } - SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -334,7 +333,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Allocate mixing buffer */ - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->spec.size); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } From 761a79788c42e7ce39929e58d07d5606d880a778 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 5 Aug 2016 01:59:06 -0400 Subject: [PATCH 27/55] audio: changed some SDL_memset() calls to SDL_zero(), other minor corrections. --- src/audio/SDL_wave.c | 2 +- src/audio/alsa/SDL_alsa_audio.c | 2 +- src/audio/arts/SDL_artsaudio.c | 2 +- src/audio/bsd/SDL_bsdaudio.c | 2 +- src/audio/directsound/SDL_directsound.c | 2 +- src/audio/disk/SDL_diskaudio.c | 2 +- src/audio/dsp/SDL_dspaudio.c | 2 +- src/audio/emscripten/SDL_emscriptenaudio.c | 2 +- src/audio/esd/SDL_esdaudio.c | 2 +- src/audio/fusionsound/SDL_fsaudio.c | 2 +- src/audio/haiku/SDL_haikuaudio.cc | 4 ++-- src/audio/nacl/SDL_naclaudio.c | 2 +- src/audio/nas/SDL_nasaudio.c | 2 +- src/audio/paudio/SDL_paudio.c | 2 +- src/audio/psp/SDL_pspaudio.c | 2 +- src/audio/pulseaudio/SDL_pulseaudio.c | 5 ++--- src/audio/qsa/SDL_qsa_audio.c | 22 +++++++++------------- src/audio/sndio/SDL_sndioaudio.c | 2 +- src/audio/sun/SDL_sunaudio.c | 2 +- src/audio/winmm/SDL_winmm.c | 6 +++--- src/audio/xaudio2/SDL_xaudio2.c | 4 ++-- 21 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/audio/SDL_wave.c b/src/audio/SDL_wave.c index 99daac64ba786..d173b4a9217f5 100644 --- a/src/audio/SDL_wave.c +++ b/src/audio/SDL_wave.c @@ -504,7 +504,7 @@ SDL_LoadWAV_RW(SDL_RWops * src, int freesrc, was_error = 1; goto done; } - SDL_memset(spec, 0, (sizeof *spec)); + SDL_zerop(spec); spec->freq = SDL_SwapLE32(format->frequency); if (IEEE_float_encoded) { diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 833c5cea3abde..b029b667dd302 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -539,7 +539,7 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ /* Name of device should depend on # channels in spec */ diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 91d1d041c3ebe..a7e4aa601a7d0 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -235,7 +235,7 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Try for a closest match on audio format */ for (test_format = SDL_FirstAudioFormat(this->spec.format); diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index 1d9da4ee0846b..6a970b9c70a4e 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -297,7 +297,7 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ this->hidden->audio_fd = open(devname, flags, 0); diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index 5450a4355f63f..0f17362b9c05b 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -431,7 +431,7 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL); diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index fb684d2c6bd3d..97f979b02e957 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -105,7 +105,7 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, sizeof(*this->hidden)); + SDL_zerop(this->hidden); this->hidden->mixlen = this->spec.size; this->hidden->write_delay = diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index 3bfdb98576f0d..f267f84d6b07e 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -100,7 +100,7 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ this->hidden->audio_fd = open(devname, flags, 0); diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c index a354aaf27dd52..e3251dbe59a9f 100644 --- a/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -171,7 +171,7 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* based on parts of library_sdl.js */ diff --git a/src/audio/esd/SDL_esdaudio.c b/src/audio/esd/SDL_esdaudio.c index f80f3dd22daa6..3eb71979106d6 100644 --- a/src/audio/esd/SDL_esdaudio.c +++ b/src/audio/esd/SDL_esdaudio.c @@ -220,7 +220,7 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); this->hidden->audio_fd = -1; /* Convert audio spec to the ESD audio format */ diff --git a/src/audio/fusionsound/SDL_fsaudio.c b/src/audio/fusionsound/SDL_fsaudio.c index 72c8309fe6a9c..00f015bba3e94 100644 --- a/src/audio/fusionsound/SDL_fsaudio.c +++ b/src/audio/fusionsound/SDL_fsaudio.c @@ -195,7 +195,7 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Try for a closest match on audio format */ for (test_format = SDL_FirstAudioFormat(this->spec.format); diff --git a/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc index 31543f318ba22..e4a3307207d88 100644 --- a/src/audio/haiku/SDL_haikuaudio.cc +++ b/src/audio/haiku/SDL_haikuaudio.cc @@ -118,10 +118,10 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (_this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(_this->hidden, 0, (sizeof *_this->hidden)); + SDL_zerop(this->hidden); /* Parse the audio format and fill the Be raw audio format */ - SDL_memset(&format, '\0', sizeof(media_raw_audio_format)); + SDL_zero(format); format.byte_order = B_MEDIA_LITTLE_ENDIAN; format.frame_rate = (float) _this->spec.freq; format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */ diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index 5b8c2dd0beab7..b85eab2fea33b 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -65,7 +65,7 @@ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelt SDL_UnlockMutex(_this->mixer_lock); } } else { - SDL_memset(samples, 0, buffer_size); + SDL_memset(samples, _this->spec.silence, buffer_size); } SDL_UnlockMutex(private->mutex); diff --git a/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c index c9b39c632d727..a4236ae18cbe7 100644 --- a/src/audio/nas/SDL_nasaudio.c +++ b/src/audio/nas/SDL_nasaudio.c @@ -282,7 +282,7 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Try for a closest match on audio format */ format = 0; diff --git a/src/audio/paudio/SDL_paudio.c b/src/audio/paudio/SDL_paudio.c index 9191a3ed9a481..57202245f628c 100644 --- a/src/audio/paudio/SDL_paudio.c +++ b/src/audio/paudio/SDL_paudio.c @@ -256,7 +256,7 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); diff --git a/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c index f29f85ae7e99a..176aed41f68a2 100644 --- a/src/audio/psp/SDL_pspaudio.c +++ b/src/audio/psp/SDL_pspaudio.c @@ -50,7 +50,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, sizeof(*this->hidden)); + SDL_zerop(this->hidden); switch (this->spec.format & 0xff) { case 8: case 16: diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index 1ac772c06b751..64fc5d32632e1 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -529,13 +529,12 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) int rc = 0; /* Initialize all variables that we clean on shutdown */ - this->hidden = (struct SDL_PrivateAudioData *) + h = this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); - h = this->hidden; + SDL_zerop(this->hidden); paspec.format = PA_SAMPLE_INVALID; diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index a4384e7fd4d42..4ca7a12060535 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -137,8 +137,7 @@ QSA_ThreadInit(_THIS) static void QSA_InitAudioParams(snd_pcm_channel_params_t * cpars) { - SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t)); - + SDL_zerop(cpars); cpars->channel = SND_PCM_CHANNEL_PLAYBACK; cpars->mode = SND_PCM_MODE_BLOCK; cpars->start_mode = SND_PCM_START_DATA; @@ -261,7 +260,7 @@ QSA_PlayDevice(_THIS) continue; } else { if ((errno == EINVAL) || (errno == EIO)) { - SDL_memset(&cstatus, 0, sizeof(cstatus)); + SDL_zero(cstatus); if (!this->hidden->iscapture) { cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; } else { @@ -358,7 +357,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData)); + SDL_zerop(this->hidden); /* Initialize channel transfer parameters to default */ QSA_InitAudioParams(&cparams); @@ -499,7 +498,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } /* Make sure channel is setup right one last time */ - SDL_memset(&csetup, 0, sizeof(csetup)); + SDL_zero(csetup); if (!this->hidden->iscapture) { csetup.channel = SND_PCM_CHANNEL_PLAYBACK; } else { @@ -731,10 +730,9 @@ static void QSA_Deinitialize(void) { /* Clear devices array on shutdown */ - SDL_memset(qsa_playback_device, 0x00, - sizeof(QSA_Device) * QSA_MAX_DEVICES); - SDL_memset(qsa_capture_device, 0x00, - sizeof(QSA_Device) * QSA_MAX_DEVICES); + /* !!! FIXME: we zero these on init...any reason to do it here? */ + SDL_zero(qsa_playback_device); + SDL_zero(qsa_capture_device); qsa_playback_devices = 0; qsa_capture_devices = 0; } @@ -746,10 +744,8 @@ QSA_Init(SDL_AudioDriverImpl * impl) int32_t status = 0; /* Clear devices array */ - SDL_memset(qsa_playback_device, 0x00, - sizeof(QSA_Device) * QSA_MAX_DEVICES); - SDL_memset(qsa_capture_device, 0x00, - sizeof(QSA_Device) * QSA_MAX_DEVICES); + SDL_zero(qsa_playback_device); + SDL_zero(qsa_capture_device); qsa_playback_devices = 0; qsa_capture_devices = 0; diff --git a/src/audio/sndio/SDL_sndioaudio.c b/src/audio/sndio/SDL_sndioaudio.c index 309e503a5e2f5..797204fce6ebd 100644 --- a/src/audio/sndio/SDL_sndioaudio.c +++ b/src/audio/sndio/SDL_sndioaudio.c @@ -198,7 +198,7 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, sizeof(*this->hidden)); + SDL_zerop(this->hidden); this->hidden->mixlen = this->spec.size; diff --git a/src/audio/sun/SDL_sunaudio.c b/src/audio/sun/SDL_sunaudio.c index fb90146c5c1f6..b994c12c361e0 100644 --- a/src/audio/sun/SDL_sunaudio.c +++ b/src/audio/sun/SDL_sunaudio.c @@ -212,7 +212,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ this->hidden->audio_fd = open(devname, flags, 0); diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index 6ef893235117e..da9312dff1034 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -228,7 +228,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Initialize the wavebuf structures for closing */ for (i = 0; i < NUM_BUFFERS; ++i) @@ -305,9 +305,9 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } + + SDL_zero(this->hidden->wavebuf); for (i = 0; i < NUM_BUFFERS; ++i) { - SDL_memset(&this->hidden->wavebuf[i], 0, - sizeof(this->hidden->wavebuf[i])); this->hidden->wavebuf[i].dwBufferLength = this->spec.size; this->hidden->wavebuf[i].dwFlags = WHDR_DONE; this->hidden->wavebuf[i].lpData = diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c index b300bcdd6d31e..1724e31b39d4c 100644 --- a/src/audio/xaudio2/SDL_xaudio2.c +++ b/src/audio/xaudio2/SDL_xaudio2.c @@ -342,7 +342,7 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) IXAudio2_Release(ixa2); return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); this->hidden->ixa2 = ixa2; this->hidden->semaphore = SDL_CreateSemaphore(1); @@ -377,7 +377,7 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_OutOfMemory(); } this->hidden->nextbuf = this->hidden->mixbuf; - SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen); + SDL_memset(this->hidden->mixbuf, this->spec.silence, 2 * this->hidden->mixlen); /* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On Xbox360, this means 5.1 output, but on Windows, it means "figure out From 9b2a59ef054b98a24f1217f5550e8de92be2e42d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 5 Aug 2016 02:04:48 -0400 Subject: [PATCH 28/55] audio: Changed OnlyHasDefaultInputDevice to OnlyHasDefaultCaptureDevice. --- src/audio/SDL_audio.c | 4 ++-- src/audio/SDL_sysaudio.h | 2 +- src/audio/android/SDL_androidaudio.c | 2 +- src/audio/coreaudio/SDL_coreaudio.c | 2 +- src/audio/dummy/SDL_dummyaudio.c | 2 +- src/audio/psp/SDL_pspaudio.c | 2 +- src/audio/qsa/SDL_qsa_audio.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 139520448db3f..4c43693427167 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -165,7 +165,7 @@ SDL_AudioDetectDevices_Default(void) { /* you have to write your own implementation if these assertions fail. */ SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice); - SDL_assert(current_audio.impl.OnlyHasDefaultInputDevice || !current_audio.impl.HasCaptureSupport); + SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport); SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1)); if (current_audio.impl.HasCaptureSupport) { @@ -1111,7 +1111,7 @@ open_audio_device(const char *devname, int iscapture, * opens of the default system device. */ - if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { + if ((iscapture) && (current_audio.impl.OnlyHasDefaultCaptureDevice)) { if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) { SDL_SetError("No such device"); return 0; diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 5b56e8b56f1ab..c44d999cd491e 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -92,7 +92,7 @@ typedef struct SDL_AudioDriverImpl int SkipMixerLock; /* !!! FIXME: do we need this anymore? */ int HasCaptureSupport; int OnlyHasDefaultOutputDevice; - int OnlyHasDefaultInputDevice; + int OnlyHasDefaultCaptureDevice; int AllowsArbitraryDeviceNames; } SDL_AudioDriverImpl; diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index 2cedca0818ef4..c575643b6686e 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -133,7 +133,7 @@ AndroidAUD_Init(SDL_AudioDriverImpl * impl) /* and the capabilities */ impl->HasCaptureSupport = 0; /* TODO */ impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultInputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; return 1; /* this audio target is available. */ } diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index ea9088fea05a0..7a11c20889ff4 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -766,7 +766,7 @@ COREAUDIO_Init(SDL_AudioDriverImpl * impl) AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL); #else impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultInputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; /* Set category to ambient sound so that other music continues playing. You can change this at runtime in your own code if you need different diff --git a/src/audio/dummy/SDL_dummyaudio.c b/src/audio/dummy/SDL_dummyaudio.c index f100585a49fb5..0f5e42c9589c3 100644 --- a/src/audio/dummy/SDL_dummyaudio.c +++ b/src/audio/dummy/SDL_dummyaudio.c @@ -52,7 +52,7 @@ DUMMYAUD_Init(SDL_AudioDriverImpl * impl) impl->CaptureFromDevice = DUMMYAUD_CaptureFromDevice; impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultInputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ diff --git a/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c index 176aed41f68a2..fec5dfa35b35e 100644 --- a/src/audio/psp/SDL_pspaudio.c +++ b/src/audio/psp/SDL_pspaudio.c @@ -161,7 +161,7 @@ PSPAUD_Init(SDL_AudioDriverImpl * impl) /* impl->HasCaptureSupport = 1; - impl->OnlyHasDefaultInputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; */ /* impl->DetectDevices = DSOUND_DetectDevices; diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index 4ca7a12060535..c8f9fa91addc5 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -769,7 +769,7 @@ QSA_Init(SDL_AudioDriverImpl * impl) impl->SkipMixerLock = 0; impl->HasCaptureSupport = 1; impl->OnlyHasDefaultOutputDevice = 0; - impl->OnlyHasDefaultInputDevice = 0; + impl->OnlyHasDefaultCaptureDevice = 0; /* Check if io-audio manager is running or not */ status = snd_cards(); From 9a33154450dfebd899c51b5ab1b9f4ffd3b44a65 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 5 Aug 2016 04:23:32 -0400 Subject: [PATCH 29/55] nas: initial shot at audio capture support. Compiles, but not tested. --- src/audio/nas/SDL_nasaudio.c | 146 ++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 35 deletions(-) diff --git a/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c index a4236ae18cbe7..fe15cd6962efe 100644 --- a/src/audio/nas/SDL_nasaudio.c +++ b/src/audio/nas/SDL_nasaudio.c @@ -33,18 +33,18 @@ #include "../SDL_audio_c.h" #include "SDL_nasaudio.h" -static struct SDL_PrivateAudioData *this2 = NULL; - - static void (*NAS_AuCloseServer) (AuServer *); static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *); static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *); +static void (*NAS_AuHandleEvents) (AuServer *); static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *); static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *); static void (*NAS_AuSetElements) (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *); static void (*NAS_AuWriteElement) (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *); +static AuUint32 (*NAS_AuReadElement) + (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuStatus *); static AuServer *(*NAS_AuOpenServer) (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **); static AuEventHandlerRec *(*NAS_AuRegisterEventHandler) @@ -79,10 +79,12 @@ load_nas_syms(void) SDL_NAS_SYM(AuCloseServer); SDL_NAS_SYM(AuNextEvent); SDL_NAS_SYM(AuDispatchEvent); + SDL_NAS_SYM(AuHandleEvents); SDL_NAS_SYM(AuCreateFlow); SDL_NAS_SYM(AuStartFlow); SDL_NAS_SYM(AuSetElements); SDL_NAS_SYM(AuWriteElement); + SDL_NAS_SYM(AuReadElement); SDL_NAS_SYM(AuOpenServer); SDL_NAS_SYM(AuRegisterEventHandler); return 0; @@ -186,6 +188,45 @@ NAS_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } +static int +NAS_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + struct SDL_PrivateAudioData *h = this->hidden; + int retval; + + while (SDL_TRUE) { + /* just keep the event queue moving and the server chattering. */ + NAS_AuHandleEvents(h->aud); + + retval = (int) NAS_AuReadElement(h->aud, h->flow, 1, buflen, buffer, NULL); + /*printf("read %d capture bytes\n", (int) retval);*/ + if (retval == 0) { + SDL_Delay(10); /* don't burn the CPU if we're waiting for data. */ + } else { + break; + } + } + + return retval; +} + +static void +NAS_FlushCapture(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + AuUint32 total = 0; + AuUint32 br; + Uint8 buf[512]; + + do { + /* just keep the event queue moving and the server chattering. */ + NAS_AuHandleEvents(h->aud); + br = NAS_AuReadElement(h->aud, h->flow, 1, sizeof (buf), buf, NULL); + /*printf("flushed %d capture bytes\n", (int) br);*/ + total += br; + } while ((br == sizeof (buf)) && (total < this->spec.size)); +} + static void NAS_CloseDevice(_THIS) { @@ -219,6 +260,12 @@ sdlformat_to_auformat(unsigned int fmt) static AuBool event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd) { + SDL_AudioDevice *this = (SDL_AudioDevice *) hnd->data; + struct SDL_PrivateAudioData *h = this->hidden; + if (this->iscapture) { + return AuTrue; /* we don't (currently) care about any of this for capture devices */ + } + switch (ev->type) { case AuEventTypeElementNotify: { @@ -226,24 +273,24 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd) switch (event->kind) { case AuElementNotifyKindLowWater: - if (this2->buf_free >= 0) { - this2->really += event->num_bytes; - gettimeofday(&this2->last_tv, 0); - this2->buf_free += event->num_bytes; + if (h->buf_free >= 0) { + h->really += event->num_bytes; + gettimeofday(&h->last_tv, 0); + h->buf_free += event->num_bytes; } else { - this2->buf_free = event->num_bytes; + h->buf_free = event->num_bytes; } break; case AuElementNotifyKindState: switch (event->cur_state) { case AuStatePause: if (event->reason != AuReasonUser) { - if (this2->buf_free >= 0) { - this2->really += event->num_bytes; - gettimeofday(&this2->last_tv, 0); - this2->buf_free += event->num_bytes; + if (h->buf_free >= 0) { + h->really += event->num_bytes; + gettimeofday(&h->last_tv, 0); + h->buf_free += event->num_bytes; } else { - this2->buf_free = event->num_bytes; + h->buf_free = event->num_bytes; } } break; @@ -255,15 +302,29 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd) } static AuDeviceID -find_device(_THIS, int nch) +find_device(_THIS) { /* These "Au" things are all macros, not functions... */ + struct SDL_PrivateAudioData *h = this->hidden; + const unsigned int devicekind = this->iscapture ? AuComponentKindPhysicalInput : AuComponentKindPhysicalOutput; + const int numdevs = AuServerNumDevices(h->aud); + const int nch = this->spec.channels; int i; - for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) { - if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) == - AuComponentKindPhysicalOutput) && - AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) { - return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i)); + + /* Try to find exact match on channels first... */ + for (i = 0; i < numdevs; i++) { + const AuDeviceAttributes *dev = AuServerDevice(h->aud, i); + if ((AuDeviceKind(dev) == devicekind) && (AuDeviceNumTracks(dev) == nch)) { + return AuDeviceIdentifier(dev); + } + } + + /* Take anything, then... */ + for (i = 0; i < numdevs; i++) { + const AuDeviceAttributes *dev = AuServerDevice(h->aud, i); + if (AuDeviceKind(dev) == devicekind) { + this->spec.channels = AuDeviceNumTracks(dev); + return AuDeviceIdentifier(dev); } } return AuNone; @@ -303,7 +364,7 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_SetError("NAS: Couldn't open connection to NAS server"); } - this->hidden->dev = find_device(this, this->spec.channels); + this->hidden->dev = find_device(this); if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) { return SDL_SetError("NAS: Couldn't find a fitting device on NAS server"); @@ -319,28 +380,38 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(&this->spec); - this2 = this->hidden; + if (iscapture) { + AuMakeElementImportDevice(elms, this->spec.freq, this->hidden->dev, + AuUnlimitedSamples, 0, NULL); + AuMakeElementExportClient(elms + 1, 0, this->spec.freq, format, + this->spec.channels, AuTrue, buffer_size, + buffer_size, 0, NULL); + } else { + AuMakeElementImportClient(elms, this->spec.freq, format, + this->spec.channels, AuTrue, buffer_size, + buffer_size / 4, 0, NULL); + AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq, + AuUnlimitedSamples, 0, NULL); + } + + NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, + 2, elms, NULL); - AuMakeElementImportClient(elms, this->spec.freq, format, - this->spec.channels, AuTrue, buffer_size, - buffer_size / 4, 0, NULL); - AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq, - AuUnlimitedSamples, 0, NULL); - NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, - NULL); NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow, event_handler, - (AuPointer) NULL); + (AuPointer) this); NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL); /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - return SDL_OutOfMemory(); + if (!iscapture) { + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); /* We're ready to rock and roll. :-) */ return 0; @@ -371,9 +442,14 @@ NAS_Init(SDL_AudioDriverImpl * impl) impl->PlayDevice = NAS_PlayDevice; impl->WaitDevice = NAS_WaitDevice; impl->GetDeviceBuf = NAS_GetDeviceBuf; + impl->CaptureFromDevice = NAS_CaptureFromDevice; + impl->FlushCapture = NAS_FlushCapture; impl->CloseDevice = NAS_CloseDevice; impl->Deinitialize = NAS_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */ + + impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } From e7347a4027b8d3e156ec367cb9623571a3066b0e Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2016 02:27:55 -0400 Subject: [PATCH 30/55] audio: SDL_ClearQueuedAudio() should free everything but two packets. Otherwise, if you had a massive, one-time queue buildup, the memory from that remains allocated until you close the device. Also, if you are just using a reasonable amount of space, this would previously cause you to reallocate it over and over instead of keeping a little bit of memory around. --- src/audio/SDL_audio.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 4c43693427167..ec3817bb487d7 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -586,20 +586,44 @@ void SDL_ClearQueuedAudio(SDL_AudioDeviceID devid) { SDL_AudioDevice *device = get_audio_device(devid); - SDL_AudioBufferQueue *buffer = NULL; + SDL_AudioBufferQueue *packet; + if (!device) { return; /* nothing to do. */ } /* Blank out the device and release the mutex. Free it afterwards. */ current_audio.impl.LockDevice(device); - buffer = device->buffer_queue_head; + + /* merge the available pool and the current queue into one list. */ + packet = device->buffer_queue_head; + if (packet) { + device->buffer_queue_tail->next = device->buffer_queue_pool; + } else { + packet = device->buffer_queue_pool; + } + + /* Remove the queued packets from the device. */ device->buffer_queue_tail = NULL; device->buffer_queue_head = NULL; device->queued_bytes = 0; + device->buffer_queue_pool = packet; + + /* Keep up to two packets in the pool to reduce future malloc pressure. */ + if (packet) { + if (!packet->next) { + packet = NULL; /* one packet (the only one) for the pool. */ + } else { + SDL_AudioBufferQueue *next = packet->next->next; + packet->next->next = NULL; /* two packets for the pool. */ + packet = next; /* rest will be freed. */ + } + } + current_audio.impl.UnlockDevice(device); - free_audio_queue(buffer); + /* free any extra packets we didn't keep in the pool. */ + free_audio_queue(packet); } From 7bfe494c62ce8b2517acb0366ccc1b9654895dd9 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2016 02:45:51 -0400 Subject: [PATCH 31/55] testaudiocapture: don't use fullscreen for the window. --- test/testaudiocapture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c index 2c6b7a9525bbc..3b3f8a4f1fdde 100644 --- a/test/testaudiocapture.c +++ b/test/testaudiocapture.c @@ -95,7 +95,7 @@ main(int argc, char **argv) return (1); } - window = SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, SDL_WINDOW_FULLSCREEN_DESKTOP); + window = SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0); renderer = SDL_CreateRenderer(window, -1, 0); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); From 73153901714ae077c0d35c1be17139fd2eb8034c Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2016 02:47:27 -0400 Subject: [PATCH 32/55] audio: Implemented buffer queueing for capture devices (SDL_DequeueAudio()). --- include/SDL_audio.h | 95 +++++++++++--- src/audio/SDL_audio.c | 203 ++++++++++++++++++++---------- src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + 4 files changed, 218 insertions(+), 82 deletions(-) diff --git a/include/SDL_audio.h b/include/SDL_audio.h index 4f6552146891c..d51f0d1ce2b46 100644 --- a/include/SDL_audio.h +++ b/include/SDL_audio.h @@ -278,7 +278,8 @@ extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(void); * protect data structures that it accesses by calling SDL_LockAudio() * and SDL_UnlockAudio() in your code. Alternately, you may pass a NULL * pointer here, and call SDL_QueueAudio() with some frequency, to queue - * more audio samples to be played. + * more audio samples to be played (or for capture devices, call + * SDL_DequeueAudio() with some frequency, to obtain audio samples). * - \c desired->userdata is passed as the first parameter to your callback * function. If you passed a NULL callback, this value is ignored. * @@ -482,6 +483,10 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst, /** * Queue more audio on non-callback devices. * + * (If you are looking to retrieve queued audio from a non-callback capture + * device, you want SDL_DequeueAudio() instead. This will return -1 to + * signify an error if you use it with capture devices.) + * * SDL offers two ways to feed audio to the device: you can either supply a * callback that SDL triggers with some frequency to obtain more audio * (pull method), or you can supply no callback, and then SDL will expect @@ -516,21 +521,76 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst, */ extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *data, Uint32 len); +/** + * Dequeue more audio on non-callback devices. + * + * (If you are looking to queue audio for output on a non-callback playback + * device, you want SDL_QueueAudio() instead. This will always return 0 + * if you use it with playback devices.) + * + * SDL offers two ways to retrieve audio from a capture device: you can + * either supply a callback that SDL triggers with some frequency as the + * device records more audio data, (push method), or you can supply no + * callback, and then SDL will expect you to retrieve data at regular + * intervals (pull method) with this function. + * + * There are no limits on the amount of data you can queue, short of + * exhaustion of address space. Data from the device will keep queuing as + * necessary without further intervention from you. This means you will + * eventually run out of memory if you aren't routinely dequeueing data. + * + * Capture devices will not queue data when paused; if you are expecting + * to not need captured audio for some length of time, use + * SDL_PauseAudioDevice() to stop the capture device from queueing more + * data. This can be useful during, say, level loading times. When + * unpaused, capture devices will start queueing data from that point, + * having flushed any capturable data available while paused. + * + * This function is thread-safe, but dequeueing from the same device from + * two threads at once does not promise which thread will dequeued data + * first. + * + * You may not dequeue audio from a device that is using an + * application-supplied callback; doing so returns an error. You have to use + * the audio callback, or dequeue audio with this function, but not both. + * + * You should not call SDL_LockAudio() on the device before queueing; SDL + * handles locking internally for this function. + * + * \param dev The device ID from which we will dequeue audio. + * \param data A pointer into where audio data should be copied. + * \param len The number of bytes (not samples!) to which (data) points. + * \return number of bytes dequeued, which could be less than requested. + * + * \sa SDL_GetQueuedAudioSize + * \sa SDL_ClearQueuedAudio + */ +extern DECLSPEC Uint32 SDLCALL SDL_DequeueAudio(SDL_AudioDeviceID dev, void *data, Uint32 len); + /** * Get the number of bytes of still-queued audio. * - * This is the number of bytes that have been queued for playback with - * SDL_QueueAudio(), but have not yet been sent to the hardware. + * For playback device: + * + * This is the number of bytes that have been queued for playback with + * SDL_QueueAudio(), but have not yet been sent to the hardware. This + * number may shrink at any time, so this only informs of pending data. + * + * Once we've sent it to the hardware, this function can not decide the + * exact byte boundary of what has been played. It's possible that we just + * gave the hardware several kilobytes right before you called this + * function, but it hasn't played any of it yet, or maybe half of it, etc. + * + * For capture devices: * - * Once we've sent it to the hardware, this function can not decide the exact - * byte boundary of what has been played. It's possible that we just gave the - * hardware several kilobytes right before you called this function, but it - * hasn't played any of it yet, or maybe half of it, etc. + * This is the number of bytes that have been captured by the device and + * are waiting for you to dequeue. This number may grow at any time, so + * this only informs of the lower-bound of available data. * * You may not queue audio on a device that is using an application-supplied * callback; calling this function on such a device always returns 0. - * You have to use the audio callback or queue audio with SDL_QueueAudio(), - * but not both. + * You have to queue audio with SDL_QueueAudio()/SDL_DequeueAudio(), or use + * the audio callback, but not both. * * You should not call SDL_LockAudio() on the device before querying; SDL * handles locking internally for this function. @@ -544,10 +604,17 @@ extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *da extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev); /** - * Drop any queued audio data waiting to be sent to the hardware. + * Drop any queued audio data. For playback devices, this is any queued data + * still waiting to be submitted to the hardware. For capture devices, this + * is any data that was queued by the device that hasn't yet been dequeued by + * the application. * - * Immediately after this call, SDL_GetQueuedAudioSize() will return 0 and - * the hardware will start playing silence if more audio isn't queued. + * Immediately after this call, SDL_GetQueuedAudioSize() will return 0. For + * playback devices, the hardware will start playing silence if more audio + * isn't queued. Unpaused capture devices will start filling the queue again + * as soon as they have more data available (which, depending on the state + * of the hardware and the thread, could be before this function call + * returns!). * * This will not prevent playback of queued audio that's already been sent * to the hardware, as we can not undo that, so expect there to be some @@ -557,8 +624,8 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev); * * You may not queue audio on a device that is using an application-supplied * callback; calling this function on such a device is always a no-op. - * You have to use the audio callback or queue audio with SDL_QueueAudio(), - * but not both. + * You have to queue audio with SDL_QueueAudio()/SDL_DequeueAudio(), or use + * the audio callback, but not both. * * You should not call SDL_LockAudio() on the device before clearing the * queue; SDL handles locking internally for this function. diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index ec3817bb487d7..a57ed2e6336b1 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -433,77 +433,24 @@ SDL_RemoveAudioDevice(const int iscapture, void *handle) /* this expects that you managed thread safety elsewhere. */ static void -free_audio_queue(SDL_AudioBufferQueue *buffer) +free_audio_queue(SDL_AudioBufferQueue *packet) { - while (buffer) { - SDL_AudioBufferQueue *next = buffer->next; - SDL_free(buffer); - buffer = next; + while (packet) { + SDL_AudioBufferQueue *next = packet->next; + SDL_free(packet); + packet = next; } } -static void SDLCALL -SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int _len) -{ - /* this function always holds the mixer lock before being called. */ - Uint32 len = (Uint32) _len; - SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; - SDL_AudioBufferQueue *buffer; - - SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */ - SDL_assert(_len >= 0); /* this shouldn't ever happen, right?! */ - - while ((len > 0) && ((buffer = device->buffer_queue_head) != NULL)) { - const Uint32 avail = buffer->datalen - buffer->startpos; - const Uint32 cpy = SDL_min(len, avail); - SDL_assert(device->queued_bytes >= avail); - - SDL_memcpy(stream, buffer->data + buffer->startpos, cpy); - buffer->startpos += cpy; - stream += cpy; - device->queued_bytes -= cpy; - len -= cpy; - - if (buffer->startpos == buffer->datalen) { /* packet is done, put it in the pool. */ - device->buffer_queue_head = buffer->next; - SDL_assert((buffer->next != NULL) || (buffer == device->buffer_queue_tail)); - buffer->next = device->buffer_queue_pool; - device->buffer_queue_pool = buffer; - } - } - - SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0)); - - if (len > 0) { /* fill any remaining space in the stream with silence. */ - SDL_assert(device->buffer_queue_head == NULL); - SDL_memset(stream, device->spec.silence, len); - } - - if (device->buffer_queue_head == NULL) { - device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */ - } -} - -int -SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len) +/* NOTE: This assumes you'll hold the mixer lock before calling! */ +static int +queue_audio_to_device(SDL_AudioDevice *device, const Uint8 *data, Uint32 len) { - SDL_AudioDevice *device = get_audio_device(devid); - const Uint8 *data = (const Uint8 *) _data; SDL_AudioBufferQueue *orighead; SDL_AudioBufferQueue *origtail; Uint32 origlen; Uint32 datalen; - if (!device) { - return -1; /* get_audio_device() will have set the error state */ - } - - if (device->spec.callback != SDL_BufferQueueDrainCallback) { - return SDL_SetError("Audio device has a callback, queueing not allowed"); - } - - current_audio.impl.LockDevice(device); - orighead = device->buffer_queue_head; origtail = device->buffer_queue_tail; origlen = origtail ? origtail->datalen : 0; @@ -533,8 +480,6 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len) device->buffer_queue_tail = origtail; device->buffer_queue_pool = NULL; - current_audio.impl.UnlockDevice(device); - free_audio_queue(packet); /* give back what we can. */ return SDL_OutOfMemory(); @@ -561,22 +506,142 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len) device->queued_bytes += datalen; } - current_audio.impl.UnlockDevice(device); - return 0; } +/* NOTE: This assumes you'll hold the mixer lock before calling! */ +static Uint32 +dequeue_audio_from_device(SDL_AudioDevice *device, Uint8 *stream, Uint32 len) +{ + SDL_AudioBufferQueue *packet; + Uint8 *ptr = stream; + + while ((len > 0) && ((packet = device->buffer_queue_head) != NULL)) { + const Uint32 avail = packet->datalen - packet->startpos; + const Uint32 cpy = SDL_min(len, avail); + SDL_assert(device->queued_bytes >= avail); + + SDL_memcpy(ptr, packet->data + packet->startpos, cpy); + packet->startpos += cpy; + ptr += cpy; + device->queued_bytes -= cpy; + len -= cpy; + + if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */ + device->buffer_queue_head = packet->next; + SDL_assert((packet->next != NULL) || (packet == device->buffer_queue_tail)); + packet->next = device->buffer_queue_pool; + device->buffer_queue_pool = packet; + } + } + + SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0)); + + if (device->buffer_queue_head == NULL) { + device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */ + } + + return (Uint32) (ptr - stream); +} + +static void SDLCALL +SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len) +{ + /* this function always holds the mixer lock before being called. */ + SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; + Uint32 written; + + SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */ + SDL_assert(!device->iscapture); /* this shouldn't ever happen, right?! */ + SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */ + + written = dequeue_audio_from_device(device, stream, (Uint32) len); + stream += written; + len -= (int) written; + + if (len > 0) { /* fill any remaining space in the stream with silence. */ + SDL_assert(device->buffer_queue_head == NULL); + SDL_memset(stream, device->spec.silence, len); + } +} + +static void SDLCALL +SDL_BufferQueueFillCallback(void *userdata, Uint8 *stream, int len) +{ + /* this function always holds the mixer lock before being called. */ + SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; + + SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */ + SDL_assert(device->iscapture); /* this shouldn't ever happen, right?! */ + SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */ + + /* note that if this needs to allocate more space and run out of memory, + we have no choice but to quietly drop the data and hope it works out + later, but you probably have bigger problems in this case anyhow. */ + queue_audio_to_device(device, stream, (Uint32) len); +} + +int +SDL_QueueAudio(SDL_AudioDeviceID devid, const void *data, Uint32 len) +{ + SDL_AudioDevice *device = get_audio_device(devid); + int rc = 0; + + if (!device) { + return -1; /* get_audio_device() will have set the error state */ + } else if (device->iscapture) { + return SDL_SetError("This is a capture device, queueing not allowed"); + } else if (device->spec.callback != SDL_BufferQueueDrainCallback) { + return SDL_SetError("Audio device has a callback, queueing not allowed"); + } + + if (len > 0) { + current_audio.impl.LockDevice(device); + rc = queue_audio_to_device(device, data, len); + current_audio.impl.UnlockDevice(device); + } + + return rc; +} + +Uint32 +SDL_DequeueAudio(SDL_AudioDeviceID devid, void *data, Uint32 len) +{ + SDL_AudioDevice *device = get_audio_device(devid); + Uint32 rc; + + if ( (len == 0) || /* nothing to do? */ + (!device) || /* called with bogus device id */ + (!device->iscapture) || /* playback devices can't dequeue */ + (device->spec.callback != SDL_BufferQueueFillCallback) ) { /* not set for queueing */ + return 0; /* just report zero bytes dequeued. */ + } + + current_audio.impl.LockDevice(device); + rc = dequeue_audio_from_device(device, data, len); + current_audio.impl.UnlockDevice(device); + return rc; +} + Uint32 SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid) { Uint32 retval = 0; SDL_AudioDevice *device = get_audio_device(devid); + if (!device) { + return 0; + } + /* Nothing to do unless we're set up for queueing. */ - if (device && (device->spec.callback == SDL_BufferQueueDrainCallback)) { + if (device->spec.callback == SDL_BufferQueueDrainCallback) { current_audio.impl.LockDevice(device); retval = device->queued_bytes + current_audio.impl.GetPendingBytes(device); current_audio.impl.UnlockDevice(device); + } else if (device->spec.callback == SDL_BufferQueueFillCallback) { + current_audio.impl.LockDevice(device); + retval = device->queued_bytes; + current_audio.impl.UnlockDevice(device); } return retval; @@ -1305,7 +1370,7 @@ open_audio_device(const char *devname, int iscapture, } } - device->spec.callback = SDL_BufferQueueDrainCallback; + device->spec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback; device->spec.userdata = device; } @@ -1319,7 +1384,9 @@ open_audio_device(const char *devname, int iscapture, /* !!! FIXME: we don't force the audio thread stack size here because it calls into user code, but maybe we should? */ /* buffer queueing callback only needs a few bytes, so make the stack tiny. */ char name[64]; - const SDL_bool is_internal_thread = (device->spec.callback == SDL_BufferQueueDrainCallback); + const SDL_bool is_internal_thread = + (device->spec.callback == SDL_BufferQueueDrainCallback) || + (device->spec.callback == SDL_BufferQueueFillCallback); const size_t stacksize = is_internal_thread ? 64 * 1024 : 0; SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id); diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 50bbc3526525a..dfde8e732ff99 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -605,3 +605,4 @@ #define SDL_SetWindowModalFor SDL_SetWindowModalFor_REAL #define SDL_RenderSetIntegerScale SDL_RenderSetIntegerScale_REAL #define SDL_RenderGetIntegerScale SDL_RenderGetIntegerScale_REAL +#define SDL_DequeueAudio SDL_DequeueAudio_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index e73b0d9b70481..dabda3de81a04 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -639,3 +639,4 @@ SDL_DYNAPI_PROC(int,SDL_SetWindowInputFocus,(SDL_Window *a),(a),return) SDL_DYNAPI_PROC(int,SDL_SetWindowModalFor,(SDL_Window *a, SDL_Window *b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_RenderSetIntegerScale,(SDL_Renderer *a, SDL_bool b),(a,b),return) SDL_DYNAPI_PROC(SDL_bool,SDL_RenderGetIntegerScale,(SDL_Renderer *a),(a),return) +SDL_DYNAPI_PROC(Uint32,SDL_DequeueAudio,(SDL_AudioDeviceID a, void *b, Uint32 c),(a,b,c),return) From a15b9740449965fd1e549624c78aa81d069144a1 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2016 02:48:00 -0400 Subject: [PATCH 33/55] testaudiocapture: use capture device buffer queueing, for better test coverage. --- test/testaudiocapture.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c index 3b3f8a4f1fdde..8e614e9b4444a 100644 --- a/test/testaudiocapture.c +++ b/test/testaudiocapture.c @@ -21,12 +21,6 @@ static SDL_AudioSpec spec; static SDL_AudioDeviceID devid_in = 0; static SDL_AudioDeviceID devid_out = 0; -void SDLCALL -capture_callback(void *arg, Uint8 * stream, int len) -{ - SDL_QueueAudio(devid_out, stream, len); -} - static void loop() { @@ -76,6 +70,18 @@ loop() #endif exit(0); } + + /* Note that it would be easier to just have a one-line function that + calls SDL_QueueAudio() as a capture device callback, but we're + trying to test the API, so we use SDL_DequeueAudio() here. */ + while (SDL_TRUE) { + Uint8 buf[1024]; + const Uint32 br = SDL_DequeueAudio(devid_in, buf, sizeof (buf)); + SDL_QueueAudio(devid_out, buf, br); + if (br < sizeof (buf)) { + break; + } + } } int @@ -113,7 +119,7 @@ main(int argc, char **argv) spec.format = AUDIO_F32SYS; spec.channels = 1; spec.samples = 1024; - spec.callback = capture_callback; + spec.callback = NULL; SDL_Log("Opening capture device %s%s%s...\n", devname ? "'" : "", @@ -128,7 +134,6 @@ main(int argc, char **argv) } SDL_Log("Opening default playback device...\n"); - spec.callback = NULL; devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &spec, &spec, 0); if (!devid_out) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError()); From 978df1ad746dca3bc4cfbe29ade83e93c1304d7c Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2016 03:39:15 -0400 Subject: [PATCH 34/55] disk audio: Implemented "capture" support, cleaned up some things. --- src/audio/SDL_audio.c | 5 -- src/audio/SDL_sysaudio.h | 4 ++ src/audio/disk/SDL_diskaudio.c | 114 ++++++++++++++++++++++----------- src/audio/disk/SDL_diskaudio.h | 5 +- 4 files changed, 82 insertions(+), 46 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index a57ed2e6336b1..cabf560983f81 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -33,11 +33,6 @@ static SDL_AudioDriver current_audio; static SDL_AudioDevice *open_devices[16]; -/* !!! FIXME: These are wordy and unlocalized... */ -#define DEFAULT_OUTPUT_DEVNAME "System audio output device" -#define DEFAULT_INPUT_DEVNAME "System audio capture device" - - /* * Not all of these will be compiled and linked in, but it's convenient * to have a complete list here and saves yet-another block of #ifdefs... diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index c44d999cd491e..1bb1324abb3fa 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -26,6 +26,10 @@ #include "SDL_mutex.h" #include "SDL_thread.h" +/* !!! FIXME: These are wordy and unlocalized... */ +#define DEFAULT_OUTPUT_DEVNAME "System audio output device" +#define DEFAULT_INPUT_DEVNAME "System audio capture device" + /* The SDL audio driver */ typedef struct SDL_AudioDevice SDL_AudioDevice; #define _THIS SDL_AudioDevice *_this diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index 97f979b02e957..af03573229230 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -34,42 +34,31 @@ #include "../SDL_audio_c.h" #include "SDL_diskaudio.h" +/* !!! FIXME: these should be SDL hints, not environment variables. */ /* environment variables and defaults. */ #define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE" #define DISKDEFAULT_OUTFILE "sdlaudio.raw" -#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY" -#define DISKDEFAULT_WRITEDELAY 150 - -static const char * -DISKAUD_GetOutputFilename(const char *devname) -{ - if (devname == NULL) { - devname = SDL_getenv(DISKENVR_OUTFILE); - if (devname == NULL) { - devname = DISKDEFAULT_OUTFILE; - } - } - return devname; -} +#define DISKENVR_INFILE "SDL_DISKAUDIOFILEIN" +#define DISKDEFAULT_INFILE "sdlaudio-in.raw" +#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY" +#define DISKDEFAULT_IODELAY 150 /* This function waits until it is possible to write a full sound buffer */ static void DISKAUD_WaitDevice(_THIS) { - SDL_Delay(this->hidden->write_delay); + SDL_Delay(this->hidden->io_delay); } static void DISKAUD_PlayDevice(_THIS) { - size_t written; - - /* Write the audio data */ - written = SDL_RWwrite(this->hidden->output, - this->hidden->mixbuf, 1, this->hidden->mixlen); + const size_t written = SDL_RWwrite(this->hidden->io, + this->hidden->mixbuf, + 1, this->spec.size); /* If we couldn't write, assume fatal error for now */ - if (written != this->hidden->mixlen) { + if (written != this->spec.size) { SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO @@ -83,22 +72,66 @@ DISKAUD_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } +static int +DISKAUD_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + struct SDL_PrivateAudioData *h = this->hidden; + const int origbuflen = buflen; + + SDL_Delay(h->io_delay); + + if (h->io) { + const size_t br = SDL_RWread(h->io, buffer, 1, buflen); + buflen -= (int) br; + buffer = ((Uint8 *) buffer) + br; + if (buflen > 0) { /* EOF (or error, but whatever). */ + SDL_RWclose(h->io); + h->io = NULL; + } + } + + /* if we ran out of file, just write silence. */ + SDL_memset(buffer, this->spec.silence, buflen); + + return origbuflen; +} + +static void +DISKAUD_FlushCapture(_THIS) +{ + /* no op...we don't advance the file pointer or anything. */ +} + + static void DISKAUD_CloseDevice(_THIS) { - if (this->hidden->output != NULL) { - SDL_RWclose(this->hidden->output); + if (this->hidden->io != NULL) { + SDL_RWclose(this->hidden->io); } SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } + +static const char * +get_filename(const int iscapture, const char *devname) +{ + if (devname == NULL) { + devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE); + if (devname == NULL) { + devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE; + } + } + return devname; +} + static int DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { /* handle != NULL means "user specified the placeholder name on the fake detected device list" */ - const char *fname = DISKAUD_GetOutputFilename(handle ? NULL : devname); - const char *envr = SDL_getenv(DISKENVR_WRITEDELAY); + const char *fname = get_filename(iscapture, handle ? NULL : devname); + const char *envr = SDL_getenv(DISKENVR_IODELAY); this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); @@ -107,27 +140,28 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } SDL_zerop(this->hidden); - this->hidden->mixlen = this->spec.size; - this->hidden->write_delay = - (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY; + this->hidden->io_delay = (envr) ? SDL_atoi(envr) : DISKDEFAULT_IODELAY; /* Open the audio device */ - this->hidden->output = SDL_RWFromFile(fname, "wb"); - if (this->hidden->output == NULL) { + this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb"); + if (this->hidden->io == NULL) { return -1; } /* Allocate mixing buffer */ - this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - return -1; + if (!iscapture) { + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size); + if (this->hidden->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); #if HAVE_STDIO_H fprintf(stderr, - "WARNING: You are using the SDL disk writer audio driver!\n" - " Writing to file [%s].\n", fname); + "WARNING: You are using the SDL disk i/o audio driver!\n" + " %s file [%s].\n", iscapture ? "Reading from" : "Writing to", + fname); #endif /* We're ready to rock and roll. :-) */ @@ -137,8 +171,8 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) static void DISKAUD_DetectDevices(void) { - /* !!! FIXME: stole this literal string from DEFAULT_OUTPUT_DEVNAME in SDL_audio.c */ - SDL_AddAudioDevice(SDL_FALSE, "System audio output device", (void *) 0x1); + SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1); + SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2); } static int @@ -149,10 +183,14 @@ DISKAUD_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = DISKAUD_WaitDevice; impl->PlayDevice = DISKAUD_PlayDevice; impl->GetDeviceBuf = DISKAUD_GetDeviceBuf; + impl->CaptureFromDevice = DISKAUD_CaptureFromDevice; + impl->FlushCapture = DISKAUD_FlushCapture; + impl->CloseDevice = DISKAUD_CloseDevice; impl->DetectDevices = DISKAUD_DetectDevices; impl->AllowsArbitraryDeviceNames = 1; + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } diff --git a/src/audio/disk/SDL_diskaudio.h b/src/audio/disk/SDL_diskaudio.h index b5666f7fcb075..ad152a9ceb16c 100644 --- a/src/audio/disk/SDL_diskaudio.h +++ b/src/audio/disk/SDL_diskaudio.h @@ -32,10 +32,9 @@ struct SDL_PrivateAudioData { /* The file descriptor for the audio device */ - SDL_RWops *output; + SDL_RWops *io; + Uint32 io_delay; Uint8 *mixbuf; - Uint32 mixlen; - Uint32 write_delay; }; #endif /* _SDL_diskaudio_h */ From 4499e5bcc6f26ccc4926e0e956fab21cc138373f Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2016 03:45:45 -0400 Subject: [PATCH 35/55] disk audio: Make default i/o delay match what device is meant to be running at. --- src/audio/disk/SDL_diskaudio.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index af03573229230..a2dd4829522ca 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -41,7 +41,6 @@ #define DISKENVR_INFILE "SDL_DISKAUDIOFILEIN" #define DISKDEFAULT_INFILE "sdlaudio-in.raw" #define DISKENVR_IODELAY "SDL_DISKAUDIODELAY" -#define DISKDEFAULT_IODELAY 150 /* This function waits until it is possible to write a full sound buffer */ static void @@ -140,7 +139,11 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } SDL_zerop(this->hidden); - this->hidden->io_delay = (envr) ? SDL_atoi(envr) : DISKDEFAULT_IODELAY; + if (envr != NULL) { + this->hidden->io_delay = SDL_atoi(envr); + } else { + this->hidden->io_delay = ((this->spec.samples * 1000) / this->spec.freq); + } /* Open the audio device */ this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb"); From 51d15233800eca1e4e0a818e8bdd173d3a473ce1 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2016 19:34:32 -0400 Subject: [PATCH 36/55] winmm: Implemented audio capture support. --- src/audio/winmm/SDL_winmm.c | 146 +++++++++++++++++++++++++++++------- 1 file changed, 120 insertions(+), 26 deletions(-) diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index da9312dff1034..f4a9feaa504d3 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -27,6 +27,7 @@ #include "../../core/windows/SDL_windows.h" #include +#include "SDL_assert.h" #include "SDL_timer.h" #include "SDL_audio.h" #include "../SDL_audio_c.h" @@ -152,30 +153,83 @@ WINMM_WaitDone(_THIS) } while (left > 0); } +static int +WINMM_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + const int nextbuf = this->hidden->next_buffer; + MMRESULT result; + + SDL_assert(buflen == this->spec.size); + + /* Wait for an audio chunk to finish */ + WaitForSingleObject(this->hidden->audio_sem, INFINITE); + + /* Copy it to caller's buffer... */ + SDL_memcpy(buffer, this->hidden->wavebuf[nextbuf].lpData, this->spec.size); + + /* requeue the buffer that just finished. */ + result = waveInAddBuffer(this->hidden->hin, + &this->hidden->wavebuf[nextbuf], + sizeof (this->hidden->wavebuf[nextbuf])); + if (result != MMSYSERR_NOERROR) { + return -1; /* uhoh! Disable the device. */ + } + + /* queue the next buffer in sequence, next time. */ + this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS; + return this->spec.size; +} + +static void +WINMM_FlushCapture(_THIS) +{ + /* Wait for an audio chunk to finish */ + if (WaitForSingleObject(this->hidden->audio_sem, 0) == WAIT_OBJECT_0) { + const int nextbuf = this->hidden->next_buffer; + /* requeue the buffer that just finished without reading from it. */ + waveInAddBuffer(this->hidden->hin, + &this->hidden->wavebuf[nextbuf], + sizeof (this->hidden->wavebuf[nextbuf])); + this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS; + } +} + static void WINMM_CloseDevice(_THIS) { int i; - if (this->hidden->audio_sem) { - CloseHandle(this->hidden->audio_sem); - } + if (this->hidden->hout) { + waveOutReset(this->hidden->hout); - /* Clean up mixing buffers */ - for (i = 0; i < NUM_BUFFERS; ++i) { - if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { - waveOutUnprepareHeader(this->hidden->hout, - &this->hidden->wavebuf[i], - sizeof (this->hidden->wavebuf[i])); + /* Clean up mixing buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { + waveOutUnprepareHeader(this->hidden->hout, + &this->hidden->wavebuf[i], + sizeof (this->hidden->wavebuf[i])); + } } + + waveOutClose(this->hidden->hout); } if (this->hidden->hin) { + waveInReset(this->hidden->hin); + + /* Clean up mixing buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { + waveInUnprepareHeader(this->hidden->hin, + &this->hidden->wavebuf[i], + sizeof (this->hidden->wavebuf[i])); + } + } waveInClose(this->hidden->hin); } - if (this->hidden->hout) { - waveOutClose(this->hidden->hout); + if (this->hidden->audio_sem) { + CloseHandle(this->hidden->audio_sem); } SDL_free(this->hidden->mixbuf); @@ -269,32 +323,44 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) result = waveInOpen(&this->hidden->hin, devId, &waveformat, (DWORD_PTR) CaptureSound, (DWORD_PTR) this, CALLBACK_FUNCTION); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveInOpen()", result); + } } else { result = waveOutOpen(&this->hidden->hout, devId, &waveformat, (DWORD_PTR) FillSound, (DWORD_PTR) this, CALLBACK_FUNCTION); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveOutOpen()", result); + } } - if (result != MMSYSERR_NOERROR) { - return SetMMerror("waveOutOpen()", result); - } #ifdef SOUND_DEBUG /* Check the sound device we retrieved */ { - WAVEOUTCAPS caps; - - result = waveOutGetDevCaps((UINT) this->hidden->hout, - &caps, sizeof(caps)); - if (result != MMSYSERR_NOERROR) { - return SetMMerror("waveOutGetDevCaps()", result); + if (iscapture) { + WAVEINCAPS caps; + result = waveInGetDevCaps((UINT) this->hidden->hout, + &caps, sizeof (caps)); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveInGetDevCaps()", result); + } + printf("Audio device: %s\n", caps.szPname); + } else { + WAVEOUTCAPS caps; + result = waveOutGetDevCaps((UINT) this->hidden->hout, + &caps, sizeof(caps)); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveOutGetDevCaps()", result); + } + printf("Audio device: %s\n", caps.szPname); } - printf("Audio device: %s\n", caps.szPname); } #endif /* Create the audio buffer semaphore */ this->hidden->audio_sem = - CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); + CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL); if (this->hidden->audio_sem == NULL) { return SDL_SetError("Couldn't create semaphore"); } @@ -312,11 +378,35 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->wavebuf[i].dwFlags = WHDR_DONE; this->hidden->wavebuf[i].lpData = (LPSTR) & this->hidden->mixbuf[i * this->spec.size]; - result = waveOutPrepareHeader(this->hidden->hout, - &this->hidden->wavebuf[i], - sizeof(this->hidden->wavebuf[i])); + + if (iscapture) { + result = waveInPrepareHeader(this->hidden->hin, + &this->hidden->wavebuf[i], + sizeof(this->hidden->wavebuf[i])); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveInPrepareHeader()", result); + } + + result = waveInAddBuffer(this->hidden->hin, + &this->hidden->wavebuf[i], + sizeof(this->hidden->wavebuf[i])); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveInAddBuffer()", result); + } + } else { + result = waveOutPrepareHeader(this->hidden->hout, + &this->hidden->wavebuf[i], + sizeof(this->hidden->wavebuf[i])); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveOutPrepareHeader()", result); + } + } + } + + if (iscapture) { + result = waveInStart(this->hidden->hin); if (result != MMSYSERR_NOERROR) { - return SetMMerror("waveOutPrepareHeader()", result); + return SetMMerror("waveInStart()", result); } } @@ -334,8 +424,12 @@ WINMM_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = WINMM_WaitDevice; impl->WaitDone = WINMM_WaitDone; impl->GetDeviceBuf = WINMM_GetDeviceBuf; + impl->CaptureFromDevice = WINMM_CaptureFromDevice; + impl->FlushCapture = WINMM_FlushCapture; impl->CloseDevice = WINMM_CloseDevice; + impl->HasCaptureSupport = SDL_TRUE; + return 1; /* this audio target is available. */ } From ff7df7e687edf175dae34578f4aaa0954cc2b0c1 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 6 Aug 2016 23:05:02 -0400 Subject: [PATCH 37/55] winmm: Added a FIXME for truncated device names. --- src/audio/winmm/SDL_winmm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index f4a9feaa504d3..4573984cc7c11 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -37,6 +37,21 @@ #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif +/* !!! FIXME: + +WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's +longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which +will give you a name GUID. The full name is in the Windows Registry under +that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories + +Note that drivers can report GUID_NULL for the name GUID, in which case, +Windows makes a best effort to fill in those 31 bytes in the usual place. +This info summarized from MSDN: + +http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx + +*/ + #define DETECT_DEV_IMPL(iscap, typ, capstyp) \ static void DetectWave##typ##Devs(void) { \ const UINT iscapture = iscap ? 1 : 0; \ From a0ff2554c1f0144efb83547a39b4997ee6d81c55 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 7 Aug 2016 01:48:38 -0400 Subject: [PATCH 38/55] winmm: Try to get full device names from the Windows Registry. --- src/audio/winmm/SDL_winmm.c | 66 ++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index 4573984cc7c11..dea1aac28f30b 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -37,8 +37,7 @@ #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif -/* !!! FIXME: - +/* WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which will give you a name GUID. The full name is in the Windows Registry under @@ -50,17 +49,74 @@ This info summarized from MSDN: http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx +Always look this up in the registry if possible, because the strings are +different! At least on Win10, I see "Yeti Stereo Microphone" in the +Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh. */ +static char * +LookupDeviceName(const WCHAR *name, const GUID *guid) +{ + static const GUID nullguid = { 0 }; + const unsigned char *ptr; + char keystr[128]; + WCHAR *strw = NULL; + SDL_bool rc; + HKEY hkey; + DWORD len = 0; + char *retval = NULL; + + if (SDL_memcmp(guid, &nullguid, sizeof (*guid)) == 0) { + return WIN_StringToUTF8(name); /* No GUID, go with what we've got. */ + } + + ptr = (const char *) guid; + SDL_snprintf(keystr, sizeof (keystr), + "System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6], + ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]); + + strw = WIN_UTF8ToString(keystr); + rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS); + SDL_free(strw); + if (!rc) { + return WIN_StringToUTF8(name); /* oh well. */ + } + + rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS); + if (!rc) { + RegCloseKey(hkey); + return WIN_StringToUTF8(name); /* oh well. */ + } + + strw = (WCHAR *) SDL_malloc(len + sizeof (WCHAR)); + if (!strw) { + RegCloseKey(hkey); + return WIN_StringToUTF8(name); /* oh well. */ + } + + rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE) strw, &len) == ERROR_SUCCESS); + RegCloseKey(hkey); + if (!rc) { + SDL_free(strw); + return WIN_StringToUTF8(name); /* oh well. */ + } + + strw[len / 2] = 0; /* make sure it's null-terminated. */ + + retval = WIN_StringToUTF8(strw); + SDL_free(strw); + return retval ? retval : WIN_StringToUTF8(name); +} #define DETECT_DEV_IMPL(iscap, typ, capstyp) \ static void DetectWave##typ##Devs(void) { \ const UINT iscapture = iscap ? 1 : 0; \ const UINT devcount = wave##typ##GetNumDevs(); \ - capstyp caps; \ + capstyp##2W caps; \ UINT i; \ for (i = 0; i < devcount; i++) { \ - if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \ - char *name = WIN_StringToUTF8(caps.szPname); \ + if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \ + char *name = LookupDeviceName(caps.szPname,&caps.NameGuid); \ if (name != NULL) { \ SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \ SDL_free(name); \ From df4985e20758e5df5142d305ea23400ced39e590 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 7 Aug 2016 02:43:20 -0400 Subject: [PATCH 39/55] dsp: Implemented audio capture support. --- src/audio/dsp/SDL_dspaudio.c | 49 ++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index f267f84d6b07e..a5a31b3aa88c9 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -107,9 +107,8 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden->audio_fd < 0) { return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno)); } - this->hidden->mixbuf = NULL; - /* Make the file descriptor use blocking writes with fcntl() */ + /* Make the file descriptor use blocking i/o with fcntl() */ { long ctlflags; ctlflags = fcntl(this->hidden->audio_fd, F_GETFL); @@ -236,12 +235,14 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) #endif /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - return SDL_OutOfMemory(); + if (!iscapture) { + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); /* We're ready to rock and roll. :-) */ return 0; @@ -251,14 +252,13 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) static void DSP_PlayDevice(_THIS) { - const Uint8 *mixbuf = this->hidden->mixbuf; - const int mixlen = this->hidden->mixlen; - if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) { + struct SDL_PrivateAudioData *h = this->hidden; + if (write(h->audio_fd, h->mixbuf, h->mixlen) == -1) { perror("Audio write"); SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO - fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); + fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen); #endif } @@ -268,6 +268,30 @@ DSP_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } +static int +DSP_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + return (int) read(this->hidden->audio_fd, buffer, buflen); +} + +static void +DSP_FlushCapture(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + audio_buf_info info; + if (ioctl(h->audio_fd, SNDCTL_DSP_GETISPACE, &info) == 0) { + while (info.bytes > 0) { + char buf[512]; + const size_t len = SDL_min(sizeof (buf), info.bytes); + const ssize_t br = read(h->audio_fd, buf, len); + if (br <= 0) { + break; + } + info.bytes -= br; + } + } +} + static int DSP_Init(SDL_AudioDriverImpl * impl) { @@ -277,8 +301,11 @@ DSP_Init(SDL_AudioDriverImpl * impl) impl->PlayDevice = DSP_PlayDevice; impl->GetDeviceBuf = DSP_GetDeviceBuf; impl->CloseDevice = DSP_CloseDevice; + impl->CaptureFromDevice = DSP_CaptureFromDevice; + impl->FlushCapture = DSP_FlushCapture; impl->AllowsArbitraryDeviceNames = 1; + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } From be8d7a46fb862b8ecd56c8e4edf705b218cd0af9 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 9 Aug 2016 00:44:05 -0400 Subject: [PATCH 40/55] audio: simplifed check for internal callback. Easier to check when it's NULL instead of a list of known internal functions. --- src/audio/SDL_audio.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index cabf560983f81..ec65d0c2dfc40 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -1143,6 +1143,7 @@ open_audio_device(const char *devname, int iscapture, const SDL_AudioSpec * desired, SDL_AudioSpec * obtained, int allowed_changes, int min_id) { + const SDL_bool is_internal_thread = (desired->callback != NULL); SDL_AudioDeviceID id = 0; SDL_AudioSpec _obtained; SDL_AudioDevice *device; @@ -1379,11 +1380,7 @@ open_audio_device(const char *devname, int iscapture, /* !!! FIXME: we don't force the audio thread stack size here because it calls into user code, but maybe we should? */ /* buffer queueing callback only needs a few bytes, so make the stack tiny. */ char name[64]; - const SDL_bool is_internal_thread = - (device->spec.callback == SDL_BufferQueueDrainCallback) || - (device->spec.callback == SDL_BufferQueueFillCallback); const size_t stacksize = is_internal_thread ? 64 * 1024 : 0; - SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id); device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, name, stacksize, device); From a05bde217000c628ffb16100b8f1a507a118ecb7 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 9 Aug 2016 00:44:59 -0400 Subject: [PATCH 41/55] audio: Only allocate fake_stream if we're using the standard audio threads. --- src/audio/SDL_audio.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index ec65d0c2dfc40..6456389007d27 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -1149,7 +1149,6 @@ open_audio_device(const char *devname, int iscapture, SDL_AudioDevice *device; SDL_bool build_cvt; void *handle = NULL; - Uint32 stream_len; int i = 0; if (!SDL_WasInit(SDL_INIT_AUDIO)) { @@ -1338,19 +1337,6 @@ open_audio_device(const char *devname, int iscapture, } } - /* Allocate a fake audio memory buffer */ - stream_len = (device->convert.needed) ? device->convert.len_cvt : 0; - if (device->spec.size > stream_len) { - stream_len = device->spec.size; - } - SDL_assert(stream_len > 0); - device->fake_stream = (Uint8 *) SDL_malloc(stream_len); - if (device->fake_stream == NULL) { - close_audio_device(device); - SDL_OutOfMemory(); - return 0; - } - if (device->spec.callback == NULL) { /* use buffer queueing? */ /* pool a few packets to start. Enough for two callbacks. */ const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN; @@ -1377,6 +1363,20 @@ open_audio_device(const char *devname, int iscapture, if (!current_audio.impl.ProvidesOwnCallbackThread) { /* Start the audio thread */ + /* Allocate a fake audio buffer; only used by our internal threads. */ + Uint32 stream_len = (device->convert.needed) ? device->convert.len_cvt : 0; + if (device->spec.size > stream_len) { + stream_len = device->spec.size; + } + SDL_assert(stream_len > 0); + + device->fake_stream = (Uint8 *) SDL_malloc(stream_len); + if (device->fake_stream == NULL) { + close_audio_device(device); + SDL_OutOfMemory(); + return 0; + } + /* !!! FIXME: we don't force the audio thread stack size here because it calls into user code, but maybe we should? */ /* buffer queueing callback only needs a few bytes, so make the stack tiny. */ char name[64]; From 3139e5d16b9b84d8f2463ca4c7d7fba19fe76f26 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 9 Aug 2016 16:57:49 -0400 Subject: [PATCH 42/55] testaudiocapture: open capture device to same spec as output device. ...since our resampler is still terrible (sorry!). --- test/testaudiocapture.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c index 8e614e9b4444a..f04d359a3c94d 100644 --- a/test/testaudiocapture.c +++ b/test/testaudiocapture.c @@ -11,6 +11,8 @@ */ #include "SDL.h" +#include + #ifdef __EMSCRIPTEN__ #include #endif @@ -89,6 +91,7 @@ main(int argc, char **argv) { /* (argv[1] == NULL means "open default device.") */ const char *devname = argv[1]; + SDL_AudioSpec wanted; int devcount; int i; @@ -114,12 +117,28 @@ main(int argc, char **argv) SDL_Log(" Capture device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_TRUE)); } + SDL_zero(wanted); + wanted.freq = 44100; + wanted.format = AUDIO_F32SYS; + wanted.channels = 1; + wanted.samples = 1024; + wanted.callback = NULL; + SDL_zero(spec); - spec.freq = 44100; - spec.format = AUDIO_F32SYS; - spec.channels = 1; - spec.samples = 1024; - spec.callback = NULL; + + /* DirectSound can fail in some instances if you open the same hardware + for both capture and output and didn't open the output end first, + according to the docs, so if you're doing something like this, always + open your capture devices second in case you land in those bizarre + circumstances. */ + + SDL_Log("Opening default playback device...\n"); + devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &wanted, &spec, SDL_AUDIO_ALLOW_ANY_CHANGE); + if (!devid_out) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError()); + SDL_Quit(); + exit(1); + } SDL_Log("Opening capture device %s%s%s...\n", devname ? "'" : "", @@ -133,14 +152,6 @@ main(int argc, char **argv) exit(1); } - SDL_Log("Opening default playback device...\n"); - devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &spec, &spec, 0); - if (!devid_out) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError()); - SDL_Quit(); - exit(1); - } - SDL_Log("Ready! Hold down mouse or finger to record!\n"); #ifdef __EMSCRIPTEN__ From 5de11a5fc5fd3c597d987d0160a452f8ed674ee7 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 9 Aug 2016 16:58:06 -0400 Subject: [PATCH 43/55] Added a FIXME. --- src/audio/coreaudio/SDL_coreaudio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index 7a11c20889ff4..83a66a33955e8 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -375,6 +375,7 @@ inputCallback(void *inRefCon, if (len > remaining) len = remaining; + /* !!! FIXME: why are we copying here? just pass the buffer to the callback? */ SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len); ptr += len; remaining -= len; From 358a168c9d1b1b9972ecd13f7240855001396bc1 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 9 Aug 2016 16:58:32 -0400 Subject: [PATCH 44/55] emscripten audio: Added audio capture support. --- src/audio/emscripten/SDL_emscriptenaudio.c | 241 +++++++++++++++++---- 1 file changed, 201 insertions(+), 40 deletions(-) diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c index e3251dbe59a9f..cf4893315dba4 100644 --- a/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -61,7 +61,6 @@ HandleAudioProcess(_THIS) Uint8 *buf = NULL; int byte_len = 0; int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8; - int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8; /* Only do something if audio is enabled */ if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { @@ -69,6 +68,8 @@ HandleAudioProcess(_THIS) } if (this->convert.needed) { + const int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8; + if (this->hidden->conv_in_len != 0) { this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels; } @@ -133,9 +134,100 @@ HandleAudioProcess(_THIS) } } +static void +HandleCaptureProcess(_THIS) +{ + Uint8 *buf; + int buflen; + + /* Only do something if audio is enabled */ + if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { + return; + } + + if (this->convert.needed) { + buf = this->convert.buf; + buflen = this->convert.len_cvt; + } else { + if (!this->hidden->mixbuf) { + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size); + if (!this->hidden->mixbuf) { + return; /* oh well. */ + } + } + buf = this->hidden->mixbuf; + buflen = this->spec.size; + } + + EM_ASM_ARGS({ + var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels; + if (numChannels == 1) { /* fastpath this a little for the common (mono) case. */ + var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(0); + if (channelData.length != $1) { + throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!'; + } + for (var j = 0; j < $1; ++j) { + setValue($0 + (j * 4), channelData[j], 'float'); + } + } else { + for (var c = 0; c < numChannels; ++c) { + var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c); + if (channelData.length != $1) { + throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!'; + } + + for (var j = 0; j < $1; ++j) { + setValue($0 + (((j * numChannels) + c) * 4), channelData[j], 'float'); + } + } + } + }, buf, (this->spec.size / sizeof (float)) / this->spec.channels); + + /* okay, we've got an interleaved float32 array in C now. */ + + if (this->convert.needed) { + SDL_ConvertAudio(&this->convert); + } + + /* Send it to the app. */ + (*this->spec.callback) (this->spec.userdata, buf, buflen); +} + + + static void Emscripten_CloseDevice(_THIS) { + EM_ASM_({ + if ($0) { + if (SDL2.capture.silenceTimer !== undefined) { + clearTimeout(SDL2.capture.silenceTimer); + } + if (SDL2.capture.scriptProcessorNode !== undefined) { + SDL2.capture.scriptProcessorNode.disconnect(); + SDL2.capture.scriptProcessorNode = undefined; + } + if (SDL2.capture.mediaStreamNode !== undefined) { + SDL2.capture.mediaStreamNode.disconnect(); + SDL2.capture.mediaStreamNode = undefined; + } + if (SDL2.capture.silenceBuffer !== undefined) { + SDL2.capture.silenceBuffer = undefined + } + SDL2.capture = undefined; + } else { + if (SDL2.audio.scriptProcessorNode != undefined) { + SDL2.audio.scriptProcessorNode.disconnect(); + SDL2.audio.scriptProcessorNode = undefined; + } + SDL2.audio = undefined; + } + if ((SDL2.audioContext !== undefined) && (SDL2.audio === undefined) && (SDL2.capture === undefined)) { + SDL2.audioContext.close(); + SDL2.audioContext = undefined; + } + }, this->iscapture); + SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -144,11 +236,38 @@ static int Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_bool valid_format = SDL_FALSE; - SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); + SDL_AudioFormat test_format; int i; float f; int result; + /* based on parts of library_sdl.js */ + + /* create context (TODO: this puts stuff in the global namespace...)*/ + result = EM_ASM_INT({ + if(typeof(SDL2) === 'undefined') { + SDL2 = {}; + } + if (!$0) { + SDL2.audio = {}; + } else { + SDL2.capture = {}; + } + + if (!SDL2.audioContext) { + if (typeof(AudioContext) !== 'undefined') { + SDL2.audioContext = new AudioContext(); + } else if (typeof(webkitAudioContext) !== 'undefined') { + SDL2.audioContext = new webkitAudioContext(); + } + } + return SDL2.audioContext === undefined ? -1 : 0; + }, iscapture); + if (result < 0) { + return SDL_SetError("Web Audio API is not available!"); + } + + test_format = SDL_FirstAudioFormat(this->spec.format); while ((!valid_format) && (test_format)) { switch (test_format) { case AUDIO_F32: /* web audio only supports floats */ @@ -173,34 +292,9 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } SDL_zerop(this->hidden); - /* based on parts of library_sdl.js */ - - /* create context (TODO: this puts stuff in the global namespace...)*/ - result = EM_ASM_INT_V({ - if(typeof(SDL2) === 'undefined') - SDL2 = {}; - - if(typeof(SDL2.audio) === 'undefined') - SDL2.audio = {}; - - if (!SDL2.audioContext) { - if (typeof(AudioContext) !== 'undefined') { - SDL2.audioContext = new AudioContext(); - } else if (typeof(webkitAudioContext) !== 'undefined') { - SDL2.audioContext = new webkitAudioContext(); - } else { - return -1; - } - } - return 0; - }); - if (result < 0) { - return SDL_SetError("Web Audio API is not available!"); - } - /* limit to native freq */ - int sampleRate = EM_ASM_INT_V({ - return SDL2.audioContext['sampleRate']; + const int sampleRate = EM_ASM_INT_V({ + return SDL2.audioContext.sampleRate; }); if(this->spec.freq != sampleRate) { @@ -217,15 +311,71 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); - /* setup a ScriptProcessorNode */ - EM_ASM_ARGS({ - SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0); - SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) { - SDL2.audio.currentOutputBuffer = e['outputBuffer']; - Runtime.dynCall('vi', $2, [$3]); - }; - SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']); - }, this->spec.channels, this->spec.samples, HandleAudioProcess, this); + if (iscapture) { + /* The idea is to take the capture media stream, hook it up to an + audio graph where we can pass it through a ScriptProcessorNode + to access the raw PCM samples and push them to the SDL app's + callback. From there, we "process" the audio data into silence + and forget about it. */ + + /* This should, strictly speaking, use MediaRecorder for capture, but + this API is cleaner to use and better supported, and fires a + callback whenever there's enough data to fire down into the app. + The downside is that we are spending CPU time silencing a buffer + that the audiocontext uselessly mixes into any output. On the + upside, both of those things are not only run in native code in + the browser, they're probably SIMD code, too. MediaRecorder + feels like it's a pretty inefficient tapdance in similar ways, + to be honest. */ + + EM_ASM_({ + var have_microphone = function(stream) { + clearTimeout(SDL2.capture.silenceTimer); + SDL2.capture.silenceTimer = undefined; + SDL2.capture.mediaStreamNode = SDL2.audioContext.createMediaStreamSource(stream); + SDL2.capture.scriptProcessorNode = SDL2.audioContext.createScriptProcessor($1, $0, 1); + SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) { + audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0); + SDL2.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer; + Runtime.dynCall('vi', $2, [$3]); + }; + SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode); + SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination); + }; + + var no_microphone = function(error) { + console.log('we DO NOT have a microphone! (' + error.name + ')...leaving silence callback running.'); + }; + + /* we write silence to the audio callback until the microphone is available (user approves use, etc). */ + SDL2.capture.silenceBuffer = SDL2.audioContext.createBuffer($0, $1, SDL2.audioContext.sampleRate); + SDL2.capture.silenceBuffer.getChannelData(0).fill(0.0); + + var silence_callback = function() { + SDL2.capture.currentCaptureBuffer = SDL2.capture.silenceBuffer; + Runtime.dynCall('vi', $2, [$3]); + }; + + SDL2.capture.silenceTimer = setTimeout(silence_callback, $1 / SDL2.audioContext.sampleRate); + + if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) { + navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone); + } else if (navigator.webkitGetUserMedia !== undefined) { + navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone); + } + }, this->spec.channels, this->spec.samples, HandleCaptureProcess, this); + } else { + /* setup a ScriptProcessorNode */ + EM_ASM_ARGS({ + SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0); + SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) { + SDL2.audio.currentOutputBuffer = e['outputBuffer']; + Runtime.dynCall('vi', $2, [$3]); + }; + SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']); + }, this->spec.channels, this->spec.samples, HandleAudioProcess, this); + } + return 0; } @@ -236,7 +386,6 @@ Emscripten_Init(SDL_AudioDriverImpl * impl) impl->OpenDevice = Emscripten_OpenDevice; impl->CloseDevice = Emscripten_CloseDevice; - /* only one output */ impl->OnlyHasDefaultOutputDevice = 1; /* no threads here */ @@ -244,7 +393,7 @@ Emscripten_Init(SDL_AudioDriverImpl * impl) impl->ProvidesOwnCallbackThread = 1; /* check availability */ - int available = EM_ASM_INT_V({ + const int available = EM_ASM_INT_V({ if (typeof(AudioContext) !== 'undefined') { return 1; } else if (typeof(webkitAudioContext) !== 'undefined') { @@ -257,6 +406,18 @@ Emscripten_Init(SDL_AudioDriverImpl * impl) SDL_SetError("No audio context available"); } + const int capture_available = available && EM_ASM_INT_V({ + if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) { + return 1; + } else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') { + return 1; + } + return 0; + }); + + impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE; + impl->OnlyHasDefaultCaptureDevice = capture_available ? SDL_TRUE : SDL_FALSE; + return available; } From 7a8e4cb019fb90df43025b3a328097a8076a6681 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 9 Aug 2016 19:35:46 -0400 Subject: [PATCH 45/55] directsound: recalculate audiospec size before creating secondary buffer. I think this was a bug before? Maybe I'm misunderstanding this, but it looks like it was working because we allocate room for 8 chunks... --- src/audio/directsound/SDL_directsound.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index 0f17362b9c05b..f48d3005e11ca 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -361,9 +361,6 @@ CreateSecondary(_THIS, HWND focus) wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8); wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign; - /* Update the fragment size as size in bytes */ - SDL_CalculateAudioSpec(&this->spec); - /* Try to set primary mixing privileges */ if (focus) { result = IDirectSound_SetCooperativeLevel(sndObj, @@ -447,6 +444,8 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) case AUDIO_F32: tried_format = SDL_TRUE; this->spec.format = test_format; + /* Update the fragment size as size in bytes */ + SDL_CalculateAudioSpec(&this->spec); this->hidden->num_buffers = CreateSecondary(this, NULL); if (this->hidden->num_buffers > 0) { valid_format = SDL_TRUE; From 244d2dbcd54d241cd86f3c8e78985a109be8d383 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 10 Aug 2016 14:13:48 -0400 Subject: [PATCH 46/55] emscripten audio: fix timer on capture's silence callback. --- src/audio/emscripten/SDL_emscriptenaudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c index cf4893315dba4..2800a3bba2ed2 100644 --- a/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -356,7 +356,7 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) Runtime.dynCall('vi', $2, [$3]); }; - SDL2.capture.silenceTimer = setTimeout(silence_callback, $1 / SDL2.audioContext.sampleRate); + SDL2.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000); if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) { navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone); From b879595a2a65e7b3b0e6f6a9b1c094fc485dea25 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 10 Aug 2016 14:14:14 -0400 Subject: [PATCH 47/55] audio: Patched to compile on C89 compilers. --- src/audio/SDL_audio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 6456389007d27..1d6374548a374 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -1362,6 +1362,10 @@ open_audio_device(const char *devname, int iscapture, /* Start the audio thread if necessary */ if (!current_audio.impl.ProvidesOwnCallbackThread) { /* Start the audio thread */ + /* !!! FIXME: we don't force the audio thread stack size here if it calls into user code, but maybe we should? */ + /* buffer queueing callback only needs a few bytes, so make the stack tiny. */ + const size_t stacksize = is_internal_thread ? 64 * 1024 : 0; + char threadname[64]; /* Allocate a fake audio buffer; only used by our internal threads. */ Uint32 stream_len = (device->convert.needed) ? device->convert.len_cvt : 0; @@ -1377,12 +1381,8 @@ open_audio_device(const char *devname, int iscapture, return 0; } - /* !!! FIXME: we don't force the audio thread stack size here because it calls into user code, but maybe we should? */ - /* buffer queueing callback only needs a few bytes, so make the stack tiny. */ - char name[64]; - const size_t stacksize = is_internal_thread ? 64 * 1024 : 0; - SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id); - device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, name, stacksize, device); + SDL_snprintf(threadname, sizeof (threadname), "SDLAudioDev%d", (int) device->id); + device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, stacksize, device); if (device->thread == NULL) { SDL_CloseAudioDevice(device->id); From 21c7fe00603e52b76a79543bde5e86cef4d36167 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 10 Aug 2016 15:34:24 -0400 Subject: [PATCH 48/55] windows: directsound should also map audio device GUIDs to proper names. Moved this code from winmm into core so both can use it. DirectSound (at least on Win10) also returns truncated device names, even though it's handed in as a string pointer and not a static-sized buffer. :/ --- src/audio/directsound/SDL_directsound.c | 2 +- src/audio/winmm/SDL_winmm.c | 73 +----------------------- src/core/windows/SDL_windows.c | 74 +++++++++++++++++++++++++ src/core/windows/SDL_windows.h | 3 + 4 files changed, 79 insertions(+), 73 deletions(-) diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index f48d3005e11ca..ea8e17ce9a8cc 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -155,7 +155,7 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data) { const int iscapture = (int) ((size_t) data); if (guid != NULL) { /* skip default device */ - char *str = WIN_StringToUTF8(desc); + char *str = WIN_LookupAudioDeviceName(desc, guid); if (str != NULL) { LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID)); SDL_memcpy(cpyguid, guid, sizeof (GUID)); diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index dea1aac28f30b..1cf8020990da1 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -37,77 +37,6 @@ #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif -/* -WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's -longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which -will give you a name GUID. The full name is in the Windows Registry under -that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories - -Note that drivers can report GUID_NULL for the name GUID, in which case, -Windows makes a best effort to fill in those 31 bytes in the usual place. -This info summarized from MSDN: - -http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx - -Always look this up in the registry if possible, because the strings are -different! At least on Win10, I see "Yeti Stereo Microphone" in the -Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh. -*/ -static char * -LookupDeviceName(const WCHAR *name, const GUID *guid) -{ - static const GUID nullguid = { 0 }; - const unsigned char *ptr; - char keystr[128]; - WCHAR *strw = NULL; - SDL_bool rc; - HKEY hkey; - DWORD len = 0; - char *retval = NULL; - - if (SDL_memcmp(guid, &nullguid, sizeof (*guid)) == 0) { - return WIN_StringToUTF8(name); /* No GUID, go with what we've got. */ - } - - ptr = (const char *) guid; - SDL_snprintf(keystr, sizeof (keystr), - "System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6], - ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]); - - strw = WIN_UTF8ToString(keystr); - rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS); - SDL_free(strw); - if (!rc) { - return WIN_StringToUTF8(name); /* oh well. */ - } - - rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS); - if (!rc) { - RegCloseKey(hkey); - return WIN_StringToUTF8(name); /* oh well. */ - } - - strw = (WCHAR *) SDL_malloc(len + sizeof (WCHAR)); - if (!strw) { - RegCloseKey(hkey); - return WIN_StringToUTF8(name); /* oh well. */ - } - - rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE) strw, &len) == ERROR_SUCCESS); - RegCloseKey(hkey); - if (!rc) { - SDL_free(strw); - return WIN_StringToUTF8(name); /* oh well. */ - } - - strw[len / 2] = 0; /* make sure it's null-terminated. */ - - retval = WIN_StringToUTF8(strw); - SDL_free(strw); - return retval ? retval : WIN_StringToUTF8(name); -} - #define DETECT_DEV_IMPL(iscap, typ, capstyp) \ static void DetectWave##typ##Devs(void) { \ const UINT iscapture = iscap ? 1 : 0; \ @@ -116,7 +45,7 @@ static void DetectWave##typ##Devs(void) { \ UINT i; \ for (i = 0; i < devcount; i++) { \ if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \ - char *name = LookupDeviceName(caps.szPname,&caps.NameGuid); \ + char *name = WIN_LookupAudioDeviceName(caps.szPname,&caps.NameGuid); \ if (name != NULL) { \ SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \ SDL_free(name); \ diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c index bc4afe0aa6da9..a1d366b244d9b 100644 --- a/src/core/windows/SDL_windows.c +++ b/src/core/windows/SDL_windows.c @@ -124,6 +124,80 @@ BOOL WIN_IsWindowsVistaOrGreater() #endif } +/* +WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's +longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which +will give you a name GUID. The full name is in the Windows Registry under +that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories + +Note that drivers can report GUID_NULL for the name GUID, in which case, +Windows makes a best effort to fill in those 31 bytes in the usual place. +This info summarized from MSDN: + +http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx + +Always look this up in the registry if possible, because the strings are +different! At least on Win10, I see "Yeti Stereo Microphone" in the +Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh. + +(Also, DirectSound shouldn't be limited to 32 chars, but its device enum +has the same problem.) +*/ +char * +WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid) +{ + static const GUID nullguid = { 0 }; + const unsigned char *ptr; + char keystr[128]; + WCHAR *strw = NULL; + SDL_bool rc; + HKEY hkey; + DWORD len = 0; + char *retval = NULL; + + if (SDL_memcmp(guid, &nullguid, sizeof (*guid)) == 0) { + return WIN_StringToUTF8(name); /* No GUID, go with what we've got. */ + } + + ptr = (const char *) guid; + SDL_snprintf(keystr, sizeof (keystr), + "System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6], + ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]); + + strw = WIN_UTF8ToString(keystr); + rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS); + SDL_free(strw); + if (!rc) { + return WIN_StringToUTF8(name); /* oh well. */ + } + + rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS); + if (!rc) { + RegCloseKey(hkey); + return WIN_StringToUTF8(name); /* oh well. */ + } + + strw = (WCHAR *) SDL_malloc(len + sizeof (WCHAR)); + if (!strw) { + RegCloseKey(hkey); + return WIN_StringToUTF8(name); /* oh well. */ + } + + rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE) strw, &len) == ERROR_SUCCESS); + RegCloseKey(hkey); + if (!rc) { + SDL_free(strw); + return WIN_StringToUTF8(name); /* oh well. */ + } + + strw[len / 2] = 0; /* make sure it's null-terminated. */ + + retval = WIN_StringToUTF8(strw); + SDL_free(strw); + return retval ? retval : WIN_StringToUTF8(name); +} + #endif /* __WIN32__ || __WINRT__ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h index 0c99b03d42a9b..0f67e4be5e7e5 100644 --- a/src/core/windows/SDL_windows.h +++ b/src/core/windows/SDL_windows.h @@ -59,6 +59,9 @@ extern void WIN_CoUninitialize(void); /* Returns SDL_TRUE if we're running on Windows Vista and newer */ extern BOOL WIN_IsWindowsVistaOrGreater(); +/* You need to SDL_free() the result of this call. */ +extern char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid); + #endif /* _INCLUDED_WINDOWS_H */ /* vi: set ts=4 sw=4 expandtab: */ From b78ec974969ca1f43fd7ec41fd3810a54bbdc746 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 10 Aug 2016 16:00:16 -0400 Subject: [PATCH 49/55] directsound: Implemented audio capture support. --- src/audio/directsound/SDL_directsound.c | 251 +++++++++++++++++------- src/audio/directsound/SDL_directsound.h | 3 +- 2 files changed, 185 insertions(+), 69 deletions(-) diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index ea8e17ce9a8cc..55259e7e6b2cf 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -24,6 +24,7 @@ /* Allow access to a raw mixing buffer */ +#include "SDL_assert.h" #include "SDL_timer.h" #include "SDL_loadso.h" #include "SDL_audio.h" @@ -36,11 +37,13 @@ /* DirectX function pointers for audio */ static void* DSoundDLL = NULL; -typedef HRESULT(WINAPI*fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN); -typedef HRESULT(WINAPI*fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); -typedef HRESULT(WINAPI*fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID); +typedef HRESULT (WINAPI *fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN); +typedef HRESULT (WINAPI *fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); +typedef HRESULT (WINAPI *fnDirectSoundCaptureCreate8)(LPCGUID,LPDIRECTSOUNDCAPTURE8 *,LPUNKNOWN); +typedef HRESULT (WINAPI *fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID); static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL; static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL; +static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL; static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL; static void @@ -48,6 +51,7 @@ DSOUND_Unload(void) { pDirectSoundCreate8 = NULL; pDirectSoundEnumerateW = NULL; + pDirectSoundCaptureCreate8 = NULL; pDirectSoundCaptureEnumerateW = NULL; if (DSoundDLL != NULL) { @@ -76,6 +80,7 @@ DSOUND_Load(void) loaded = 1; /* will reset if necessary. */ DSOUNDLOAD(DirectSoundCreate8); DSOUNDLOAD(DirectSoundEnumerateW); + DSOUNDLOAD(DirectSoundCaptureCreate8); DSOUNDLOAD(DirectSoundCaptureEnumerateW); #undef DSOUNDLOAD @@ -197,7 +202,7 @@ DSOUND_WaitDevice(_THIS) return; } - while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) { + while ((cursor / this->spec.size) == this->hidden->lastchunk) { /* FIXME: find out how much time is left and sleep that long */ SDL_Delay(1); @@ -239,9 +244,8 @@ DSOUND_PlayDevice(_THIS) if (this->hidden->locked_buf) { IDirectSoundBuffer_Unlock(this->hidden->mixbuf, this->hidden->locked_buf, - this->hidden->mixlen, NULL, 0); + this->spec.size, NULL, 0); } - } static Uint8 * @@ -265,7 +269,7 @@ DSOUND_GetDeviceBuf(_THIS) SetDSerror("DirectSound GetCurrentPosition", result); return (NULL); } - cursor /= this->hidden->mixlen; + cursor /= this->spec.size; #ifdef DEBUG_SOUND /* Detect audio dropouts */ { @@ -281,17 +285,17 @@ DSOUND_GetDeviceBuf(_THIS) #endif this->hidden->lastchunk = cursor; cursor = (cursor + 1) % this->hidden->num_buffers; - cursor *= this->hidden->mixlen; + cursor *= this->spec.size; /* Lock the audio buffer */ result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor, - this->hidden->mixlen, + this->spec.size, (LPVOID *) & this->hidden->locked_buf, &rawlen, NULL, &junk, 0); if (result == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(this->hidden->mixbuf); result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor, - this->hidden->mixlen, + this->spec.size, (LPVOID *) & this-> hidden->locked_buf, &rawlen, NULL, &junk, 0); @@ -310,7 +314,7 @@ DSOUND_WaitDone(_THIS) /* Wait for the playing chunk to finish */ if (stream != NULL) { - SDL_memset(stream, this->spec.silence, this->hidden->mixlen); + SDL_memset(stream, this->spec.silence, this->spec.size); DSOUND_PlayDevice(this); } DSOUND_WaitDevice(this); @@ -319,83 +323,106 @@ DSOUND_WaitDone(_THIS) IDirectSoundBuffer_Stop(this->hidden->mixbuf); } +static int +DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + struct SDL_PrivateAudioData *h = this->hidden; + DWORD junk, cursor, ptr1len, ptr2len; + VOID *ptr1, *ptr2; + + SDL_assert(buflen == this->spec.size); + + while (SDL_TRUE) { + if (SDL_AtomicGet(&this->shutdown)) { /* in case the buffer froze... */ + SDL_memset(buffer, this->spec.silence, buflen); + return buflen; + } + + if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) { + return -1; + } + if ((cursor / this->spec.size) == h->lastchunk) { + SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */ + } else { + break; + } + } + + if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) { + return -1; + } + + SDL_assert(ptr1len == this->spec.size); + SDL_assert(ptr2 == NULL); + SDL_assert(ptr2len == 0); + + SDL_memcpy(buffer, ptr1, ptr1len); + + if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) { + return -1; + } + + h->lastchunk = (h->lastchunk + 1) % h->num_buffers; + + return ptr1len; +} + +static void +DSOUND_FlushCapture(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + DWORD junk, cursor; + if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) { + h->lastchunk = cursor / this->spec.size; + } +} + static void DSOUND_CloseDevice(_THIS) { if (this->hidden->mixbuf != NULL) { + IDirectSoundBuffer_Stop(this->hidden->mixbuf); IDirectSoundBuffer_Release(this->hidden->mixbuf); } if (this->hidden->sound != NULL) { IDirectSound_Release(this->hidden->sound); } + if (this->hidden->capturebuf != NULL) { + IDirectSoundCaptureBuffer_Stop(this->hidden->capturebuf); + IDirectSoundCaptureBuffer_Release(this->hidden->capturebuf); + } + if (this->hidden->capture != NULL) { + IDirectSoundCapture_Release(this->hidden->capture); + } SDL_free(this->hidden); } /* This function tries to create a secondary audio buffer, and returns the - number of audio chunks available in the created buffer. + number of audio chunks available in the created buffer. This is for + playback devices, not capture. */ static int -CreateSecondary(_THIS, HWND focus) +CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt) { LPDIRECTSOUND sndObj = this->hidden->sound; LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf; - Uint32 chunksize = this->spec.size; - const int numchunks = 8; HRESULT result = DS_OK; DSBUFFERDESC format; LPVOID pvAudioPtr1, pvAudioPtr2; DWORD dwAudioBytes1, dwAudioBytes2; - WAVEFORMATEX wfmt; - - SDL_zero(wfmt); - - if (SDL_AUDIO_ISFLOAT(this->spec.format)) { - wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - } else { - wfmt.wFormatTag = WAVE_FORMAT_PCM; - } - - wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format); - wfmt.nChannels = this->spec.channels; - wfmt.nSamplesPerSec = this->spec.freq; - wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8); - wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign; - - /* Try to set primary mixing privileges */ - if (focus) { - result = IDirectSound_SetCooperativeLevel(sndObj, - focus, DSSCL_PRIORITY); - } else { - result = IDirectSound_SetCooperativeLevel(sndObj, - GetDesktopWindow(), - DSSCL_NORMAL); - } - if (result != DS_OK) { - return SetDSerror("DirectSound SetCooperativeLevel", result); - } /* Try to create the secondary buffer */ SDL_zero(format); format.dwSize = sizeof(format); format.dwFlags = DSBCAPS_GETCURRENTPOSITION2; - if (!focus) { - format.dwFlags |= DSBCAPS_GLOBALFOCUS; - } else { - format.dwFlags |= DSBCAPS_STICKYFOCUS; - } - format.dwBufferBytes = numchunks * chunksize; - if ((format.dwBufferBytes < DSBSIZE_MIN) || - (format.dwBufferBytes > DSBSIZE_MAX)) { - return SDL_SetError("Sound buffer size must be between %d and %d", - DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks); - } - format.dwReserved = 0; - format.lpwfxFormat = &wfmt; + format.dwFlags |= DSBCAPS_GLOBALFOCUS; + format.dwBufferBytes = bufsize; + format.lpwfxFormat = wfmt; result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL); if (result != DS_OK) { return SetDSerror("DirectSound CreateSoundBuffer", result); } - IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt); + IDirectSoundBuffer_SetFormat(*sndbuf, wfmt); /* Silence the initial audio buffer */ result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes, @@ -410,18 +437,65 @@ CreateSecondary(_THIS, HWND focus) } /* We're ready to go */ - return (numchunks); + return 0; +} + +/* This function tries to create a capture buffer, and returns the + number of audio chunks available in the created buffer. This is for + capture devices, not playback. +*/ +static int +CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt) +{ + LPDIRECTSOUNDCAPTURE capture = this->hidden->capture; + LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf; + DSCBUFFERDESC format; +// DWORD junk, cursor; + HRESULT result; + + SDL_zero(format); + format.dwSize = sizeof (format); + format.dwFlags = DSCBCAPS_WAVEMAPPED; + format.dwBufferBytes = bufsize; + format.lpwfxFormat = wfmt; + + result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL); + if (result != DS_OK) { + return SetDSerror("DirectSound CreateCaptureBuffer", result); + } + + result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING); + if (result != DS_OK) { + IDirectSoundCaptureBuffer_Release(*capturebuf); + return SetDSerror("DirectSound Start", result); + } + +#if 0 + /* presumably this starts at zero, but just in case... */ + result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor); + if (result != DS_OK) { + IDirectSoundCaptureBuffer_Stop(*capturebuf); + IDirectSoundCaptureBuffer_Release(*capturebuf); + return SetDSerror("DirectSound GetCurrentPosition", result); + } + + this->hidden->lastchunk = cursor / this->spec.size; +#endif + + return 0; } static int DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { + const DWORD numchunks = 8; HRESULT result; SDL_bool valid_format = SDL_FALSE; SDL_bool tried_format = SDL_FALSE; SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); LPGUID guid = (LPGUID) handle; - + DWORD bufsize; + /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); @@ -431,9 +505,22 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_zerop(this->hidden); /* Open the audio device */ - result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL); - if (result != DS_OK) { - return SetDSerror("DirectSoundCreate", result); + if (iscapture) { + result = pDirectSoundCaptureCreate8(guid, &this->hidden->capture, NULL); + if (result != DS_OK) { + return SetDSerror("DirectSoundCaptureCreate8", result); + } + } else { + result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL); + if (result != DS_OK) { + return SetDSerror("DirectSoundCreate8", result); + } + result = IDirectSound_SetCooperativeLevel(this->hidden->sound, + GetDesktopWindow(), + DSSCL_NORMAL); + if (result != DS_OK) { + return SetDSerror("DirectSound SetCooperativeLevel", result); + } } while ((!valid_format) && (test_format)) { @@ -443,12 +530,38 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) case AUDIO_S32: case AUDIO_F32: tried_format = SDL_TRUE; + this->spec.format = test_format; + /* Update the fragment size as size in bytes */ SDL_CalculateAudioSpec(&this->spec); - this->hidden->num_buffers = CreateSecondary(this, NULL); - if (this->hidden->num_buffers > 0) { - valid_format = SDL_TRUE; + + bufsize = numchunks * this->spec.size; + if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) { + SDL_SetError("Sound buffer size must be between %d and %d", + (DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks, + DSBSIZE_MAX / numchunks); + } else { + int rc; + WAVEFORMATEX wfmt; + SDL_zero(wfmt); + if (SDL_AUDIO_ISFLOAT(this->spec.format)) { + wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + } else { + wfmt.wFormatTag = WAVE_FORMAT_PCM; + } + + wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format); + wfmt.nChannels = this->spec.channels; + wfmt.nSamplesPerSec = this->spec.freq; + wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8); + wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign; + + rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt); + if (rc == 0) { + this->hidden->num_buffers = numchunks; + valid_format = SDL_TRUE; + } } break; } @@ -462,8 +575,7 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_SetError("DirectSound: Unsupported audio format"); } - /* The buffer will auto-start playing in DSOUND_WaitDevice() */ - this->hidden->mixlen = this->spec.size; + /* Playback buffers will auto-start playing in DSOUND_WaitDevice() */ return 0; /* good to go. */ } @@ -490,11 +602,14 @@ DSOUND_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = DSOUND_WaitDevice; impl->WaitDone = DSOUND_WaitDone; impl->GetDeviceBuf = DSOUND_GetDeviceBuf; + impl->CaptureFromDevice = DSOUND_CaptureFromDevice; + impl->FlushCapture = DSOUND_FlushCapture; impl->CloseDevice = DSOUND_CloseDevice; impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle; - impl->Deinitialize = DSOUND_Deinitialize; + impl->HasCaptureSupport = SDL_TRUE; + return 1; /* this audio target is available. */ } diff --git a/src/audio/directsound/SDL_directsound.h b/src/audio/directsound/SDL_directsound.h index 0d5f6bd76c684..d646c303f55dd 100644 --- a/src/audio/directsound/SDL_directsound.h +++ b/src/audio/directsound/SDL_directsound.h @@ -35,8 +35,9 @@ struct SDL_PrivateAudioData { LPDIRECTSOUND sound; LPDIRECTSOUNDBUFFER mixbuf; + LPDIRECTSOUNDCAPTURE capture; + LPDIRECTSOUNDCAPTUREBUFFER capturebuf; int num_buffers; - int mixlen; DWORD lastchunk; Uint8 *locked_buf; }; From 8f0af7735460d33ef1f70c6ffd91007b29609d0b Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 11 Aug 2016 22:04:49 -0400 Subject: [PATCH 50/55] android: implement audio capture support. --- android-project/AndroidManifest.xml | 3 + .../src/org/libsdl/app/SDLActivity.java | 65 +++++++- src/audio/android/SDL_androidaudio.c | 73 +++++++-- src/core/android/SDL_android.c | 150 ++++++++++++++---- src/core/android/SDL_android.h | 6 +- 5 files changed, 249 insertions(+), 48 deletions(-) diff --git a/android-project/AndroidManifest.xml b/android-project/AndroidManifest.xml index 328e08c5f1bf1..8557a4b7dd9c6 100644 --- a/android-project/AndroidManifest.xml +++ b/android-project/AndroidManifest.xml @@ -17,6 +17,9 @@ + + +