mirror of
https://github.com/Ryujinx/SDL.git
synced 2024-12-23 20:25:33 +00:00
audio: implemented higher level infrastructure for running capture devices.
This commit is contained in:
parent
6d5c9c1e67
commit
0d0f7080a3
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue