|
@@ -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);
|