Skip to content

Instantly share code, notes, and snippets.

@inolen
Created February 12, 2019 07:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save inolen/35fa98f685e49a814ff3ce8b9a7b6b3e to your computer and use it in GitHub Desktop.
Save inolen/35fa98f685e49a814ff3ce8b9a7b6b3e to your computer and use it in GitHub Desktop.
diff --git a/deps/sdl2/include/SDL_audio.h b/deps/sdl2/include/SDL_audio.h
index d3e1bface..06efb24b9 100644
--- a/deps/sdl2/include/SDL_audio.h
+++ b/deps/sdl2/include/SDL_audio.h
@@ -634,6 +634,8 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst,
SDL_AudioFormat format,
Uint32 len, int volume);
+extern DECLSPEC int SDLCALL SDL_WriteAudio(SDL_AudioDeviceID dev, const void *buffer, int buflen);
+
/**
* Queue more audio on non-callback devices.
*
diff --git a/deps/sdl2/src/audio/SDL_audio.c b/deps/sdl2/src/audio/SDL_audio.c
index 97bb2ddd9..49146a9d1 100644
--- a/deps/sdl2/src/audio/SDL_audio.c
+++ b/deps/sdl2/src/audio/SDL_audio.c
@@ -661,24 +661,7 @@ SDL_RunAudio(void *devicep)
while (!SDL_AtomicGet(&device->shutdown)) {
current_audio.impl.BeginLoopIteration(device);
data_len = device->callbackspec.size;
-
- /* Fill the current buffer with sound */
- if (!device->stream && SDL_AtomicGet(&device->enabled)) {
- SDL_assert(data_len == device->spec.size);
- data = current_audio.impl.GetDeviceBuf(device);
- } else {
- /* if the device isn't enabled, we still write to the
- work_buffer, so the app's callback will fire with
- a regular frequency, in case they depend on that
- for timing or progress. They can use hotplug
- now to know if the device failed.
- Streaming playback uses work_buffer, too. */
- data = NULL;
- }
-
- if (data == NULL) {
- data = device->work_buffer;
- }
+ data = device->work_buffer;
/* !!! FIXME: this should be LockDevice. */
SDL_LockMutex(device->mixer_lock);
@@ -695,9 +678,7 @@ SDL_RunAudio(void *devicep)
SDL_AudioStreamPut(device->stream, data, data_len);
while (SDL_AudioStreamAvailable(device->stream) >= ((int) device->spec.size)) {
- int got;
- data = SDL_AtomicGet(&device->enabled) ? current_audio.impl.GetDeviceBuf(device) : NULL;
- got = SDL_AudioStreamGet(device->stream, data ? data : device->work_buffer, device->spec.size);
+ int got = SDL_AudioStreamGet(device->stream, device->work_buffer, device->spec.size);
SDL_assert((got < 0) || (got == device->spec.size));
if (data == NULL) { /* device is having issues... */
@@ -707,18 +688,12 @@ SDL_RunAudio(void *devicep)
if (got != device->spec.size) {
SDL_memset(data, device->spec.silence, device->spec.size);
}
- current_audio.impl.PlayDevice(device);
- current_audio.impl.WaitDevice(device);
+ current_audio.impl.WriteDevice(device, device->work_buffer, device->spec.size);
}
}
- } else if (data == device->work_buffer) {
- /* nothing to do; pause like we queued a buffer to play. */
- const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
- SDL_Delay(delay);
- } else { /* writing directly to the device. */
- /* queue this buffer and wait for it to finish playing. */
- current_audio.impl.PlayDevice(device);
- current_audio.impl.WaitDevice(device);
+ } else {
+ /* writing directly to the device. */
+ current_audio.impl.WriteDevice(device, data, data_len);
}
}
@@ -1369,6 +1344,7 @@ open_audio_device(const char *devname, int iscapture,
open_devices[id] = device; /* add it to our list of open devices. */
+#if 0
/* Start the audio thread if necessary */
if (!current_audio.impl.ProvidesOwnCallbackThread) {
/* Start the audio thread */
@@ -1386,6 +1362,7 @@ open_audio_device(const char *devname, int iscapture,
return 0;
}
}
+#endif
return device->id;
}
@@ -1520,6 +1497,28 @@ SDL_CloseAudio(void)
SDL_CloseAudioDevice(1);
}
+int
+SDL_WriteAudio(SDL_AudioDeviceID devid, const void *buffer, int buflen) {
+ SDL_AudioDevice *device = get_audio_device(devid);
+
+ if (!device) {
+ return -1;
+ }
+
+ if (device->stream) {
+ SDL_AudioStreamPut(device->stream, buffer, buflen);
+ SDL_AudioStreamFlush(device->stream);
+
+ int buflen2 = SDL_AudioStreamAvailable(device->stream);
+ SDL_AudioStreamGet(device->stream, device->work_buffer, buflen2);
+
+ buffer = device->work_buffer;
+ buflen = buflen2;
+ }
+
+ return current_audio.impl.WriteDevice(device, buffer, buflen);
+}
+
void
SDL_AudioQuit(void)
{
diff --git a/deps/sdl2/src/audio/SDL_sysaudio.h b/deps/sdl2/src/audio/SDL_sysaudio.h
index f0e1f3dad..4e3c962c4 100644
--- a/deps/sdl2/src/audio/SDL_sysaudio.h
+++ b/deps/sdl2/src/audio/SDL_sysaudio.h
@@ -71,6 +71,7 @@ typedef struct SDL_AudioDriverImpl
void (*BeginLoopIteration)(_THIS); /* Called by audio thread at top of loop */
void (*WaitDevice) (_THIS);
void (*PlayDevice) (_THIS);
+ int (*WriteDevice)(_THIS, const void *buffer, int buflen);
int (*GetPendingBytes) (_THIS);
Uint8 *(*GetDeviceBuf) (_THIS);
int (*CaptureFromDevice) (_THIS, void *buffer, int buflen);
diff --git a/deps/sdl2/src/audio/alsa/SDL_alsa_audio.c b/deps/sdl2/src/audio/alsa/SDL_alsa_audio.c
index 2ce270583..7d954ab97 100644
--- a/deps/sdl2/src/audio/alsa/SDL_alsa_audio.c
+++ b/deps/sdl2/src/audio/alsa/SDL_alsa_audio.c
@@ -363,6 +363,53 @@ ALSA_PlayDevice(_THIS)
}
}
+static int
+ALSA_WriteDevice(_THIS, const void *buffer, int buflen)
+{
+ const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
+ this->spec.channels;
+ snd_pcm_sframes_t frames_total = buflen / frame_size;
+ snd_pcm_sframes_t frames_left = frames_total;
+
+ while (frames_left) {
+ int status = ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1);
+
+ if (status == -EPIPE || status == -ESTRPIPE || status == -EINTR) {
+ if (ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 1) < 0) {
+ fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
+ ALSA_snd_strerror(status));
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return -1;
+ }
+ continue;
+ }
+
+ snd_pcm_sframes_t wrote = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
+ buffer, frames_left);
+ if (wrote == -EPIPE || wrote == -ESTRPIPE || wrote == -EINTR) {
+ if (ALSA_snd_pcm_recover(this->hidden->pcm_handle, wrote, 1) < 0) {
+ fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
+ ALSA_snd_strerror(wrote));
+ SDL_OpenedAudioDeviceDisconnected(this);
+ return -1;
+ }
+ continue;
+ } else if (wrote == -EAGAIN) {
+ /* Apparently snd_pcm_recover() doesn't handle this case -
+ does it assume snd_pcm_wait() above? */
+ SDL_Delay(1);
+ continue;
+ } else if (wrote < 0) {
+ return -1;
+ }
+
+ buffer += wrote * frame_size;
+ frames_left -= wrote;
+ }
+
+ return (frames_total - frames_left) * frame_size;
+}
+
static Uint8 *
ALSA_GetDeviceBuf(_THIS)
{
@@ -945,12 +992,12 @@ ALSA_Init(SDL_AudioDriverImpl * impl)
impl->OpenDevice = ALSA_OpenDevice;
impl->WaitDevice = ALSA_WaitDevice;
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
+ impl->WriteDevice = ALSA_WriteDevice;
impl->PlayDevice = ALSA_PlayDevice;
impl->CloseDevice = ALSA_CloseDevice;
impl->Deinitialize = ALSA_Deinitialize;
impl->CaptureFromDevice = ALSA_CaptureFromDevice;
impl->FlushCapture = ALSA_FlushCapture;
-
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
diff --git a/deps/sdl2/src/audio/wasapi/SDL_wasapi.c b/deps/sdl2/src/audio/wasapi/SDL_wasapi.c
index b7c8dda5d..8b2e8d10d 100644
--- a/deps/sdl2/src/audio/wasapi/SDL_wasapi.c
+++ b/deps/sdl2/src/audio/wasapi/SDL_wasapi.c
@@ -314,6 +314,49 @@ WASAPI_GetDeviceBuf(_THIS)
return (Uint8 *) buffer;
}
+static int
+WASAPI_WriteDevice(_THIS, const void *buffer, int buflen)
+{
+ int frames_total = buflen / this->hidden->framesize;
+ int frames_left = frames_total;
+
+ while (frames_left) {
+ DWORD res = WaitForSingleObject(this->hidden->event, INFINITE);
+ if (res != WAIT_OBJECT_0) {
+ return -1;
+ }
+
+ const UINT32 maxpadding = this->spec.samples;
+ UINT32 padding = 0;
+ if (WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) {
+ return -1;
+ }
+
+ int avail_frames = maxpadding - padding;
+ if (!avail_frames) {
+ continue;
+ }
+
+ int write_frames = frames_left < avail_frames ? frames_left : avail_frames;
+
+ BYTE *out;
+ if (WasapiFailed(this, IAudioRenderClient_GetBuffer(this->hidden->render, write_frames, &out))) {
+ return -1;
+ }
+
+ memcpy(out, buffer, write_frames * this->hidden->framesize);
+
+ if (WasapiFailed(this, IAudioRenderClient_ReleaseBuffer(this->hidden->render, write_frames, 0))) {
+ return -1;
+ }
+
+ buffer += write_frames * this->hidden->framesize;
+ frames_left -= write_frames;
+ }
+
+ return (frames_total - frames_left) * this->hidden->framesize;
+}
+
static void
WASAPI_PlayDevice(_THIS)
{
@@ -757,6 +800,7 @@ WASAPI_Init(SDL_AudioDriverImpl * impl)
impl->ThreadDeinit = WASAPI_ThreadDeinit;
impl->BeginLoopIteration = WASAPI_BeginLoopIteration;
impl->OpenDevice = WASAPI_OpenDevice;
+ impl->WriteDevice = WASAPI_WriteDevice;
impl->PlayDevice = WASAPI_PlayDevice;
impl->WaitDevice = WASAPI_WaitDevice;
impl->GetPendingBytes = WASAPI_GetPendingBytes;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment