From c92ceca5ce9f219a5f803cdb0ddc354b7d5e1dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Fri, 19 Aug 2022 10:38:13 +0200 Subject: [PATCH] Make audio thread control flags safe --- drivers/alsa/audio_driver_alsa.cpp | 25 +++++++-------- drivers/alsa/audio_driver_alsa.h | 6 ++-- drivers/alsamidi/midi_driver_alsamidi.cpp | 8 ++--- drivers/alsamidi/midi_driver_alsamidi.h | 3 +- .../pulseaudio/audio_driver_pulseaudio.cpp | 30 +++++++---------- drivers/pulseaudio/audio_driver_pulseaudio.h | 6 ++-- drivers/wasapi/audio_driver_wasapi.cpp | 32 ++++++++----------- drivers/wasapi/audio_driver_wasapi.h | 7 ++-- drivers/xaudio2/audio_driver_xaudio2.cpp | 17 +++++----- drivers/xaudio2/audio_driver_xaudio2.h | 6 ++-- servers/audio/audio_driver_dummy.cpp | 17 +++++----- servers/audio/audio_driver_dummy.h | 6 ++-- 12 files changed, 73 insertions(+), 90 deletions(-) diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 876aa08e358..5222b99cf92 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -168,9 +168,8 @@ Error AudioDriverALSA::init() { return ERR_CANT_OPEN; } - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); Error err = init_device(); if (err == OK) { @@ -183,11 +182,11 @@ Error AudioDriverALSA::init() { void AudioDriverALSA::thread_func(void *p_udata) { AudioDriverALSA *ad = (AudioDriverALSA *)p_udata; - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { ad->lock(); ad->start_counting_ticks(); - if (!ad->active) { + if (!ad->active.is_set()) { for (uint64_t i = 0; i < ad->period_size * ad->channels; i++) { ad->samples_out.write[i] = 0; } @@ -203,7 +202,7 @@ void AudioDriverALSA::thread_func(void *p_udata) { int todo = ad->period_size; int total = 0; - while (todo && !ad->exit_thread) { + while (todo && !ad->exit_thread.is_set()) { int16_t *src = (int16_t *)ad->samples_out.ptr(); int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo); @@ -222,8 +221,8 @@ void AudioDriverALSA::thread_func(void *p_udata) { wrote = snd_pcm_recover(ad->pcm_handle, wrote, 0); if (wrote < 0) { ERR_PRINT("ALSA: Failed and can't recover: " + String(snd_strerror(wrote))); - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); } } } @@ -241,8 +240,8 @@ void AudioDriverALSA::thread_func(void *p_udata) { err = ad->init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); } } } @@ -250,12 +249,10 @@ void AudioDriverALSA::thread_func(void *p_udata) { ad->stop_counting_ticks(); ad->unlock(); } - - ad->thread_exited = true; } void AudioDriverALSA::start() { - active = true; + active.set(); } int AudioDriverALSA::get_mix_rate() const { @@ -327,7 +324,7 @@ void AudioDriverALSA::finish_device() { } void AudioDriverALSA::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_device(); diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index e61fe6f1bab..082a377aac8 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/drivers/alsa/audio_driver_alsa.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/audio_server.h" #include "asound-so_wrap.h" @@ -64,9 +65,8 @@ class AudioDriverALSA : public AudioDriver { snd_pcm_uframes_t period_size; int channels; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; public: const char *get_name() const { diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp index ba9287b18ae..73f6a2eaa72 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.cpp +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -79,7 +79,7 @@ void MIDIDriverALSAMidi::thread_func(void *p_udata) { int expected_size = 255; int bytes = 0; - while (!md->exit_thread) { + while (!md->exit_thread.is_set()) { int ret; md->lock(); @@ -149,14 +149,14 @@ Error MIDIDriverALSAMidi::open() { } snd_device_name_free_hint(hints); - exit_thread = false; + exit_thread.clear(); thread.start(MIDIDriverALSAMidi::thread_func, this); return OK; } void MIDIDriverALSAMidi::close() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); for (int i = 0; i < connected_inputs.size(); i++) { @@ -193,7 +193,7 @@ PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() { } MIDIDriverALSAMidi::MIDIDriverALSAMidi() { - exit_thread = false; + exit_thread.clear(); } MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h index dada62a1054..96554f462d8 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.h +++ b/drivers/alsamidi/midi_driver_alsamidi.h @@ -36,6 +36,7 @@ #include "core/os/midi_driver.h" #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "core/vector.h" #include "../alsa/asound-so_wrap.h" @@ -47,7 +48,7 @@ class MIDIDriverALSAMidi : public MIDIDriver { Vector connected_inputs; - bool exit_thread; + SafeFlag exit_thread; static void thread_func(void *p_udata); diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index fd0fccb3f9e..55baf7afa2b 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -285,9 +285,8 @@ Error AudioDriverPulseAudio::init() { return ERR_CANT_OPEN; } - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); mix_rate = GLOBAL_GET("audio/mix_rate"); @@ -384,7 +383,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { size_t avail_bytes = 0; uint64_t default_device_msec = OS::get_singleton()->get_ticks_msec(); - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { size_t read_bytes = 0; size_t written_bytes = 0; @@ -394,7 +393,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { int16_t *out_ptr = ad->samples_out.ptrw(); - if (!ad->active) { + if (!ad->active.is_set()) { for (unsigned int i = 0; i < ad->pa_buffer_size; i++) { out_ptr[i] = 0; } @@ -464,8 +463,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { err = ad->init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } } @@ -503,8 +502,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { Error err = ad->init_device(); if (err != OK) { ERR_PRINT("PulseAudio: init_device error"); - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } @@ -557,8 +556,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { err = ad->capture_init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } } @@ -573,12 +572,10 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { OS::get_singleton()->delay_usec(1000); } } - - ad->thread_exited = true; } void AudioDriverPulseAudio::start() { - active = true; + active.set(); } int AudioDriverPulseAudio::get_mix_rate() const { @@ -663,7 +660,7 @@ void AudioDriverPulseAudio::finish() { return; } - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_device(); @@ -840,9 +837,6 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() : channels(0), pa_ready(0), pa_status(0), - active(false), - thread_exited(false), - exit_thread(false), latency(0) { samples_in.clear(); samples_out.clear(); diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index 125dd34b927..bbe45ca91d3 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/audio_server.h" #include "pulse-so_wrap.h" @@ -70,9 +71,8 @@ class AudioDriverPulseAudio : public AudioDriver { Array pa_devices; Array pa_rec_devices; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; float latency; diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index fcde0c05b8b..ce599f7ee64 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -365,12 +365,12 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) { } Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) { - if (p_device->active) { + if (p_device->active.is_set()) { if (p_device->audio_client) { p_device->audio_client->Stop(); } - p_device->active = false; + p_device->active.clear(); } SAFE_RELEASE(p_device->audio_client) @@ -396,8 +396,7 @@ Error AudioDriverWASAPI::init() { ERR_PRINT("WASAPI: init_render_device error"); } - exit_thread = false; - thread_exited = false; + exit_thread.clear(); thread.start(thread_func, this); @@ -543,7 +542,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { uint32_t avail_frames = 0; uint32_t write_ofs = 0; - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { uint32_t read_frames = 0; uint32_t written_frames = 0; @@ -551,7 +550,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { ad->lock(); ad->start_counting_ticks(); - if (ad->audio_output.active) { + if (ad->audio_output.active.is_set()) { ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); } else { for (int i = 0; i < ad->samples_in.size(); i++) { @@ -617,7 +616,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } } else { ERR_PRINT("WASAPI: Get buffer error"); - ad->exit_thread = true; + ad->exit_thread.set(); } } } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { @@ -666,7 +665,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { write_ofs = 0; } - if (ad->audio_input.active) { + if (ad->audio_input.active.is_set()) { UINT32 packet_length = 0; BYTE *data; UINT32 num_frames_available; @@ -745,8 +744,6 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { OS::get_singleton()->delay_usec(1000); } } - - ad->thread_exited = true; } void AudioDriverWASAPI::start() { @@ -755,7 +752,7 @@ void AudioDriverWASAPI::start() { if (hr != S_OK) { ERR_PRINT("WASAPI: Start failed"); } else { - audio_output.active = true; + audio_output.active.set(); } } } @@ -769,7 +766,7 @@ void AudioDriverWASAPI::unlock() { } void AudioDriverWASAPI::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_capture_device(); @@ -783,19 +780,19 @@ Error AudioDriverWASAPI::capture_start() { return err; } - if (audio_input.active) { + if (audio_input.active.is_set()) { return FAILED; } audio_input.audio_client->Start(); - audio_input.active = true; + audio_input.active.set(); return OK; } Error AudioDriverWASAPI::capture_stop() { - if (audio_input.active) { + if (audio_input.active.is_set()) { audio_input.audio_client->Stop(); - audio_input.active = false; + audio_input.active.clear(); return OK; } @@ -827,9 +824,6 @@ AudioDriverWASAPI::AudioDriverWASAPI() { channels = 0; mix_rate = 0; buffer_frames = 0; - - thread_exited = false; - exit_thread = false; } #endif diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 5bf8aa3b887..e708906bb4b 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/audio_server.h" #include @@ -48,7 +49,7 @@ class AudioDriverWASAPI : public AudioDriver { IAudioClient *audio_client; IAudioRenderClient *render_client; IAudioCaptureClient *capture_client; - bool active; + SafeFlag active; WORD format_tag; WORD bits_per_sample; @@ -62,7 +63,6 @@ class AudioDriverWASAPI : public AudioDriver { audio_client(NULL), render_client(NULL), capture_client(NULL), - active(false), format_tag(0), bits_per_sample(0), channels(0), @@ -84,8 +84,7 @@ class AudioDriverWASAPI : public AudioDriver { int mix_rate; int buffer_frames; - bool thread_exited; - mutable bool exit_thread; + SafeFlag exit_thread; static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample); static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i); diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index 14b21d0f52e..e86c74bc4a7 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -38,9 +38,8 @@ const char *AudioDriverXAudio2::get_name() const { } Error AudioDriverXAudio2::init() { - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); pcm_open = false; samples_in = NULL; @@ -86,17 +85,19 @@ Error AudioDriverXAudio2::init() { void AudioDriverXAudio2::thread_func(void *p_udata) { AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata; - while (!ad->exit_thread) { - if (!ad->active) { + while (!ad->exit_thread.is_set()) { + if (!ad->active.is_set()) { for (int i = 0; i < AUDIO_BUFFERS; i++) { ad->xaudio_buffer[i].Flags = XAUDIO2_END_OF_STREAM; } } else { ad->lock(); + ad->start_counting_ticks(); ad->audio_server_process(ad->buffer_size, ad->samples_in); + ad->stop_counting_ticks(); ad->unlock(); for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { @@ -117,12 +118,10 @@ void AudioDriverXAudio2::thread_func(void *p_udata) { } } } - - ad->thread_exited = true; } void AudioDriverXAudio2::start() { - active = true; + active.set(); HRESULT hr = source_voice->Start(0); ERR_FAIL_COND_MSG(hr != S_OK, "Error starting XAudio2 driver. Error code: " + itos(hr) + "."); } @@ -156,7 +155,7 @@ void AudioDriverXAudio2::finish() { if (!thread.is_started()) return; - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); if (source_voice) { diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h index 5c1382b4cf1..4a161fc39da 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.h +++ b/drivers/xaudio2/audio_driver_xaudio2.h @@ -33,6 +33,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/audio_server.h" #include @@ -77,9 +78,8 @@ class AudioDriverXAudio2 : public AudioDriver { int channels; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; bool pcm_open; WAVEFORMATEX wave_format; diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index 216df99ca28..e53d5f42004 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -34,9 +34,8 @@ #include "core/project_settings.h" Error AudioDriverDummy::init() { - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); samples_in = nullptr; mix_rate = GLOBAL_GET("audio/mix_rate"); @@ -58,23 +57,23 @@ void AudioDriverDummy::thread_func(void *p_udata) { uint64_t usdelay = (ad->buffer_frames / float(ad->mix_rate)) * 1000000; - while (!ad->exit_thread) { - if (ad->active) { + while (!ad->exit_thread.is_set()) { + if (ad->active.is_set()) { ad->lock(); + ad->start_counting_ticks(); ad->audio_server_process(ad->buffer_frames, ad->samples_in); + ad->stop_counting_ticks(); ad->unlock(); }; OS::get_singleton()->delay_usec(usdelay); }; - - ad->thread_exited = true; }; void AudioDriverDummy::start() { - active = true; + active.set(); }; int AudioDriverDummy::get_mix_rate() const { @@ -94,7 +93,7 @@ void AudioDriverDummy::unlock() { }; void AudioDriverDummy::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); if (samples_in) { diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h index 5c93533a99b..b04ce73c854 100644 --- a/servers/audio/audio_driver_dummy.h +++ b/servers/audio/audio_driver_dummy.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" class AudioDriverDummy : public AudioDriver { Thread thread; @@ -50,9 +51,8 @@ class AudioDriverDummy : public AudioDriver { int channels; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; public: const char *get_name() const {