From a24148e15ffd3fe3fe3c5ee22fd6bbd7351c7539 Mon Sep 17 00:00:00 2001 From: Mason Remaley Date: Wed, 12 Oct 2022 06:32:43 -0700 Subject: [PATCH] Always use WASAPI's callback mode (#264) * Hardcodes wasapi GUIDs when compiling as C * Uses the user requested buffer size on wasapi Windows appears to automatically adjust the timer period when you use a small buffer, meaning that using a fraction of a large buffer is unreliable unless you call timeBeginPeriod. Seems simpler to just request the desired size directly. I'll do some further investigations into this, if it seems like the right change to make I'll update the docs as well if needed. * Switches to event driven callbacks on wasapi * Removes some commented out code, moves class variable to local --- src/wasapi.c | 60 +++++++++++++++++----------------------------------- src/wasapi.h | 1 - 2 files changed, 19 insertions(+), 42 deletions(-) diff --git a/src/wasapi.c b/src/wasapi.c index 205010d..3a157eb 100644 --- a/src/wasapi.c +++ b/src/wasapi.c @@ -1281,9 +1281,10 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP CoTaskMemFree(mix_format); mix_format = NULL; flags = osw->need_resample ? AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY : 0; + flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK; share_mode = AUDCLNT_SHAREMODE_SHARED; periodicity = 0; - buffer_duration = to_reference_time(4.0); + buffer_duration = to_reference_time(outstream->software_latency); } to_wave_format_layout(&outstream->layout, &wave_format); to_wave_format_format(outstream->format, &wave_format); @@ -1313,6 +1314,7 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP CoTaskMemFree(mix_format); mix_format = NULL; flags = osw->need_resample ? AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY : 0; + flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK; to_wave_format_layout(&outstream->layout, &wave_format); to_wave_format_format(outstream->format, &wave_format); complete_wave_format_data(&wave_format); @@ -1353,10 +1355,8 @@ static int outstream_do_open(struct SoundIoPrivate *si, struct SoundIoOutStreamP } outstream->software_latency = osw->buffer_frame_count / (double)outstream->sample_rate; - if (osw->is_raw) { - if (FAILED(hr = IAudioClient_SetEventHandle(osw->audio_client, osw->h_event))) { - return SoundIoErrorOpeningDevice; - } + if (FAILED(hr = IAudioClient_SetEventHandle(osw->audio_client, osw->h_event))) { + return SoundIoErrorOpeningDevice; } if (outstream->name) { @@ -1408,13 +1408,13 @@ static void outstream_shared_run(struct SoundIoOutStreamPrivate *os) { outstream->error_callback(outstream, SoundIoErrorStreaming); return; } - osw->writable_frame_count = osw->buffer_frame_count - frames_used; - if (osw->writable_frame_count <= 0) { + int writable_frame_count = osw->buffer_frame_count - frames_used; + if (writable_frame_count <= 0) { outstream->error_callback(outstream, SoundIoErrorStreaming); return; } int frame_count_min = soundio_int_max(0, (int)osw->min_padding_frames - (int)frames_used); - outstream->write_callback(outstream, frame_count_min, osw->writable_frame_count); + outstream->write_callback(outstream, frame_count_min, writable_frame_count); if (FAILED(hr = IAudioClient_Start(osw->audio_client))) { outstream->error_callback(outstream, SoundIoErrorStreaming); @@ -1422,20 +1422,8 @@ static void outstream_shared_run(struct SoundIoOutStreamPrivate *os) { } for (;;) { - if (FAILED(hr = IAudioClient_GetCurrentPadding(osw->audio_client, &frames_used))) { - outstream->error_callback(outstream, SoundIoErrorStreaming); + if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osw->thread_exit_flag)) return; - } - osw->writable_frame_count = osw->buffer_frame_count - frames_used; - double time_until_underrun = frames_used / (double)outstream->sample_rate; - double wait_time = time_until_underrun / 2.0; - soundio_os_mutex_lock(osw->mutex); - soundio_os_cond_timed_wait(osw->cond, osw->mutex, wait_time); - if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osw->thread_exit_flag)) { - soundio_os_mutex_unlock(osw->mutex); - return; - } - soundio_os_mutex_unlock(osw->mutex); bool reset_buffer = false; if (!SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osw->clear_buffer_flag)) { if (!osw->is_paused) { @@ -1473,12 +1461,12 @@ static void outstream_shared_run(struct SoundIoOutStreamPrivate *os) { outstream->error_callback(outstream, SoundIoErrorStreaming); return; } - osw->writable_frame_count = osw->buffer_frame_count - frames_used; - if (osw->writable_frame_count > 0) { + int writable_frame_count = osw->buffer_frame_count - frames_used; + if (writable_frame_count > 0) { if (frames_used == 0 && !reset_buffer) outstream->underflow_callback(outstream); int frame_count_min = soundio_int_max(0, (int)osw->min_padding_frames - (int)frames_used); - outstream->write_callback(outstream, frame_count_min, osw->writable_frame_count); + outstream->write_callback(outstream, frame_count_min, writable_frame_count); } } } @@ -1598,12 +1586,10 @@ static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStr return SoundIoErrorNoMem; } - if (osw->is_raw) { - osw->h_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!osw->h_event) { - outstream_destroy_wasapi(si, os); - return SoundIoErrorOpeningDevice; - } + osw->h_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!osw->h_event) { + outstream_destroy_wasapi(si, os); + return SoundIoErrorOpeningDevice; } SOUNDIO_ATOMIC_FLAG_TEST_AND_SET(osw->thread_exit_flag); @@ -1633,13 +1619,7 @@ static int outstream_pause_wasapi(struct SoundIoPrivate *si, struct SoundIoOutSt SOUNDIO_ATOMIC_STORE(osw->desired_pause_state, pause); SOUNDIO_ATOMIC_FLAG_CLEAR(osw->pause_resume_flag); - if (osw->h_event) { - SetEvent(osw->h_event); - } else { - soundio_os_mutex_lock(osw->mutex); - soundio_os_cond_signal(osw->cond, osw->mutex); - soundio_os_mutex_unlock(osw->mutex); - } + SetEvent(osw->h_event); return 0; } @@ -1694,13 +1674,11 @@ static int outstream_end_write_wasapi(struct SoundIoPrivate *si, struct SoundIoO static int outstream_clear_buffer_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) { struct SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi; - if (osw->h_event) { + if (osw->is_raw) { return SoundIoErrorIncompatibleDevice; } else { SOUNDIO_ATOMIC_FLAG_CLEAR(osw->clear_buffer_flag); - soundio_os_mutex_lock(osw->mutex); - soundio_os_cond_signal(osw->cond, osw->mutex); - soundio_os_mutex_unlock(osw->mutex); + SetEvent(osw->h_event); } return 0; diff --git a/src/wasapi.h b/src/wasapi.h index cdb15fb..f6db7f7 100644 --- a/src/wasapi.h +++ b/src/wasapi.h @@ -73,7 +73,6 @@ struct SoundIoOutStreamWasapi { struct SoundIoOsCond *start_cond; struct SoundIoAtomicFlag thread_exit_flag; bool is_raw; - int writable_frame_count; UINT32 buffer_frame_count; int write_frame_count; HANDLE h_event;