diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 27b2633cfb..992cfde99e 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -414,6 +414,7 @@ static void SDL_AudioThreadInit_Default(SDL_AudioDevice *device) { /* no-op. */ static void SDL_AudioThreadDeinit_Default(SDL_AudioDevice *device) { /* no-op. */ } static void SDL_AudioWaitDevice_Default(SDL_AudioDevice *device) { /* no-op. */ } static void SDL_AudioPlayDevice_Default(SDL_AudioDevice *device, int buffer_size) { /* no-op. */ } +static void SDL_AudioWaitCaptureDevice_Default(SDL_AudioDevice *device) { /* no-op. */ } static void SDL_AudioFlushCapture_Default(SDL_AudioDevice *device) { /* no-op. */ } static void SDL_AudioCloseDevice_Default(SDL_AudioDevice *device) { /* no-op. */ } static void SDL_AudioDeinitialize_Default(void) { /* no-op. */ } @@ -458,6 +459,7 @@ static void CompleteAudioEntryPoints(void) FILL_STUB(WaitDevice); FILL_STUB(PlayDevice); FILL_STUB(GetDeviceBuf); + FILL_STUB(WaitCaptureDevice); FILL_STUB(CaptureFromDevice); FILL_STUB(FlushCapture); FILL_STUB(CloseDevice); @@ -769,6 +771,7 @@ SDL_bool SDL_CaptureAudioThreadIterate(SDL_AudioDevice *device) } else if (device->logical_devices == NULL) { current_audio.impl.FlushCapture(device); // nothing wants data, dump anything pending. } else { + // this SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitCaptureDevice! const int rc = current_audio.impl.CaptureFromDevice(device, device->work_buffer, device->buffer_size); if (rc < 0) { // uhoh, device failed for some reason! retval = SDL_FALSE; @@ -818,7 +821,11 @@ static int SDLCALL CaptureAudioThread(void *devicep) // thread entry point SDL_assert(device != NULL); SDL_assert(device->iscapture); SDL_CaptureAudioThreadSetup(device); - while (SDL_CaptureAudioThreadIterate(device)) { /* spin, CaptureAudioThreadIterate will block if necessary. !!! FIXME: maybe this is bad. */ } + + do { + current_audio.impl.WaitCaptureDevice(device); + } while (SDL_CaptureAudioThreadIterate(device)); + SDL_CaptureAudioThreadShutdown(device); return 0; } diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 38bfa2a3f0..b9c7da6cc4 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -109,6 +109,7 @@ typedef struct SDL_AudioDriverImpl void (*WaitDevice)(SDL_AudioDevice *device); void (*PlayDevice)(SDL_AudioDevice *device, int buffer_size); Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size); + void (*WaitCaptureDevice)(SDL_AudioDevice *device); int (*CaptureFromDevice)(SDL_AudioDevice *device, void *buffer, int buflen); void (*FlushCapture)(SDL_AudioDevice *device); void (*CloseDevice)(SDL_AudioDevice *device); diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index 517a4859ee..e96014ce95 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -162,6 +162,7 @@ static SDL_bool DISKAUDIO_Init(SDL_AudioDriverImpl *impl) /* Set the function pointers */ impl->OpenDevice = DISKAUDIO_OpenDevice; impl->WaitDevice = DISKAUDIO_WaitDevice; + impl->WaitCaptureDevice = DISKAUDIO_WaitDevice; impl->PlayDevice = DISKAUDIO_PlayDevice; impl->GetDeviceBuf = DISKAUDIO_GetDeviceBuf; impl->CaptureFromDevice = DISKAUDIO_CaptureFromDevice; diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index c5189b7652..fcd9d15ecf 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -429,62 +429,65 @@ static void ReadCallback(pa_stream *p, size_t nbytes, void *userdata) PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); /* the capture code queries what it needs, we just need to signal to end any wait */ } -static int PULSEAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen) +static void PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device) { struct SDL_PrivateAudioData *h = device->hidden; - const void *data = NULL; - size_t nbytes = 0; - int retval = 0; + + if (h->capturebuf != NULL) { + return; // there's still data available to read. + } PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop); while (!SDL_AtomicGet(&device->shutdown)) { - 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. */ - } - retval = cpy; /* new data, return it. */ + PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop); + if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) { + //printf("PULSEAUDIO DEVICE FAILURE IN WAITCAPTUREDEVICE!\n"); + SDL_AudioDeviceDisconnected(device); break; - } - - while (!SDL_AtomicGet(&device->shutdown) && (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0)) { - PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop); - if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) { - /*printf("PULSEAUDIO DEVICE FAILURE IN CAPTUREFROMDEVICE!\n");*/ - SDL_AudioDeviceDisconnected(device); - retval = -1; + } else if (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0) { + // a new fragment is available! + const void *data = NULL; + size_t nbytes = 0; + PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes); + SDL_assert(nbytes > 0); + if (data == NULL) { // If NULL, then the buffer had a hole, ignore that + PULSEAUDIO_pa_stream_drop(h->stream); // drop this fragment. + } else { + // store this fragment's data for use with CaptureFromDevice + //printf("PULSEAUDIO: captured %d new bytes\n", (int) nbytes); + h->capturebuf = (const Uint8 *)data; + h->capturelen = nbytes; break; } } - - if ((retval == -1) || SDL_AtomicGet(&device->shutdown)) { /* in case this happened while we were blocking. */ - retval = -1; - break; - } - - /* a new fragment is available! */ - PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes); - SDL_assert(nbytes > 0); - /* If data == NULL, then the buffer had a hole, ignore that */ - if (data == NULL) { - 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; - } } PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop); +} - return retval; +static int PULSEAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen) +{ + struct SDL_PrivateAudioData *h = device->hidden; + + if (h->capturebuf != NULL) { + const int cpy = SDL_min(buflen, h->capturelen); + if (cpy > 0) { + //printf("PULSEAUDIO: fed %d captured bytes\n", cpy); + SDL_memcpy(buffer, h->capturebuf, cpy); + h->capturebuf += cpy; + h->capturelen -= cpy; + } + if (h->capturelen == 0) { + h->capturebuf = NULL; + PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop); // don't know if you _have_ to lock for this, but just in case. + PULSEAUDIO_pa_stream_drop(h->stream); // done with this fragment. + PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop); + } + return cpy; /* new data, return it. */ + } + + return 0; } static void PULSEAUDIO_FlushCapture(SDL_AudioDevice *device) @@ -991,6 +994,7 @@ static SDL_bool PULSEAUDIO_Init(SDL_AudioDriverImpl *impl) impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf; impl->CloseDevice = PULSEAUDIO_CloseDevice; impl->Deinitialize = PULSEAUDIO_Deinitialize; + impl->WaitCaptureDevice = PULSEAUDIO_WaitCaptureDevice; impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice; impl->FlushCapture = PULSEAUDIO_FlushCapture; #if 0