Make audio thread control flags safe

This commit is contained in:
Pedro J. Estébanez 2022-08-19 10:38:13 +02:00
parent dff0e76910
commit c92ceca5ce
12 changed files with 73 additions and 90 deletions

View file

@ -168,9 +168,8 @@ Error AudioDriverALSA::init() {
return ERR_CANT_OPEN; return ERR_CANT_OPEN;
} }
active = false; active.clear();
thread_exited = false; exit_thread.clear();
exit_thread = false;
Error err = init_device(); Error err = init_device();
if (err == OK) { if (err == OK) {
@ -183,11 +182,11 @@ Error AudioDriverALSA::init() {
void AudioDriverALSA::thread_func(void *p_udata) { void AudioDriverALSA::thread_func(void *p_udata) {
AudioDriverALSA *ad = (AudioDriverALSA *)p_udata; AudioDriverALSA *ad = (AudioDriverALSA *)p_udata;
while (!ad->exit_thread) { while (!ad->exit_thread.is_set()) {
ad->lock(); ad->lock();
ad->start_counting_ticks(); ad->start_counting_ticks();
if (!ad->active) { if (!ad->active.is_set()) {
for (uint64_t i = 0; i < ad->period_size * ad->channels; i++) { for (uint64_t i = 0; i < ad->period_size * ad->channels; i++) {
ad->samples_out.write[i] = 0; ad->samples_out.write[i] = 0;
} }
@ -203,7 +202,7 @@ void AudioDriverALSA::thread_func(void *p_udata) {
int todo = ad->period_size; int todo = ad->period_size;
int total = 0; int total = 0;
while (todo && !ad->exit_thread) { while (todo && !ad->exit_thread.is_set()) {
int16_t *src = (int16_t *)ad->samples_out.ptr(); int16_t *src = (int16_t *)ad->samples_out.ptr();
int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo); 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); wrote = snd_pcm_recover(ad->pcm_handle, wrote, 0);
if (wrote < 0) { if (wrote < 0) {
ERR_PRINT("ALSA: Failed and can't recover: " + String(snd_strerror(wrote))); ERR_PRINT("ALSA: Failed and can't recover: " + String(snd_strerror(wrote)));
ad->active = false; ad->active.clear();
ad->exit_thread = true; ad->exit_thread.set();
} }
} }
} }
@ -241,8 +240,8 @@ void AudioDriverALSA::thread_func(void *p_udata) {
err = ad->init_device(); err = ad->init_device();
if (err != OK) { if (err != OK) {
ad->active = false; ad->active.clear();
ad->exit_thread = true; ad->exit_thread.set();
} }
} }
} }
@ -250,12 +249,10 @@ void AudioDriverALSA::thread_func(void *p_udata) {
ad->stop_counting_ticks(); ad->stop_counting_ticks();
ad->unlock(); ad->unlock();
} }
ad->thread_exited = true;
} }
void AudioDriverALSA::start() { void AudioDriverALSA::start() {
active = true; active.set();
} }
int AudioDriverALSA::get_mix_rate() const { int AudioDriverALSA::get_mix_rate() const {
@ -327,7 +324,7 @@ void AudioDriverALSA::finish_device() {
} }
void AudioDriverALSA::finish() { void AudioDriverALSA::finish() {
exit_thread = true; exit_thread.set();
thread.wait_to_finish(); thread.wait_to_finish();
finish_device(); finish_device();

View file

@ -35,6 +35,7 @@
#include "core/os/mutex.h" #include "core/os/mutex.h"
#include "core/os/thread.h" #include "core/os/thread.h"
#include "core/safe_refcount.h"
#include "servers/audio_server.h" #include "servers/audio_server.h"
#include "asound-so_wrap.h" #include "asound-so_wrap.h"
@ -64,9 +65,8 @@ class AudioDriverALSA : public AudioDriver {
snd_pcm_uframes_t period_size; snd_pcm_uframes_t period_size;
int channels; int channels;
bool active; SafeFlag active;
bool thread_exited; SafeFlag exit_thread;
mutable bool exit_thread;
public: public:
const char *get_name() const { const char *get_name() const {

View file

@ -79,7 +79,7 @@ void MIDIDriverALSAMidi::thread_func(void *p_udata) {
int expected_size = 255; int expected_size = 255;
int bytes = 0; int bytes = 0;
while (!md->exit_thread) { while (!md->exit_thread.is_set()) {
int ret; int ret;
md->lock(); md->lock();
@ -149,14 +149,14 @@ Error MIDIDriverALSAMidi::open() {
} }
snd_device_name_free_hint(hints); snd_device_name_free_hint(hints);
exit_thread = false; exit_thread.clear();
thread.start(MIDIDriverALSAMidi::thread_func, this); thread.start(MIDIDriverALSAMidi::thread_func, this);
return OK; return OK;
} }
void MIDIDriverALSAMidi::close() { void MIDIDriverALSAMidi::close() {
exit_thread = true; exit_thread.set();
thread.wait_to_finish(); thread.wait_to_finish();
for (int i = 0; i < connected_inputs.size(); i++) { for (int i = 0; i < connected_inputs.size(); i++) {
@ -193,7 +193,7 @@ PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
} }
MIDIDriverALSAMidi::MIDIDriverALSAMidi() { MIDIDriverALSAMidi::MIDIDriverALSAMidi() {
exit_thread = false; exit_thread.clear();
} }
MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { MIDIDriverALSAMidi::~MIDIDriverALSAMidi() {

View file

@ -36,6 +36,7 @@
#include "core/os/midi_driver.h" #include "core/os/midi_driver.h"
#include "core/os/mutex.h" #include "core/os/mutex.h"
#include "core/os/thread.h" #include "core/os/thread.h"
#include "core/safe_refcount.h"
#include "core/vector.h" #include "core/vector.h"
#include "../alsa/asound-so_wrap.h" #include "../alsa/asound-so_wrap.h"
@ -47,7 +48,7 @@ class MIDIDriverALSAMidi : public MIDIDriver {
Vector<snd_rawmidi_t *> connected_inputs; Vector<snd_rawmidi_t *> connected_inputs;
bool exit_thread; SafeFlag exit_thread;
static void thread_func(void *p_udata); static void thread_func(void *p_udata);

View file

@ -285,9 +285,8 @@ Error AudioDriverPulseAudio::init() {
return ERR_CANT_OPEN; return ERR_CANT_OPEN;
} }
active = false; active.clear();
thread_exited = false; exit_thread.clear();
exit_thread = false;
mix_rate = GLOBAL_GET("audio/mix_rate"); mix_rate = GLOBAL_GET("audio/mix_rate");
@ -384,7 +383,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
size_t avail_bytes = 0; size_t avail_bytes = 0;
uint64_t default_device_msec = OS::get_singleton()->get_ticks_msec(); 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 read_bytes = 0;
size_t written_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(); 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++) { for (unsigned int i = 0; i < ad->pa_buffer_size; i++) {
out_ptr[i] = 0; out_ptr[i] = 0;
} }
@ -464,8 +463,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
err = ad->init_device(); err = ad->init_device();
if (err != OK) { if (err != OK) {
ad->active = false; ad->active.clear();
ad->exit_thread = true; ad->exit_thread.set();
break; break;
} }
} }
@ -503,8 +502,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
Error err = ad->init_device(); Error err = ad->init_device();
if (err != OK) { if (err != OK) {
ERR_PRINT("PulseAudio: init_device error"); ERR_PRINT("PulseAudio: init_device error");
ad->active = false; ad->active.clear();
ad->exit_thread = true; ad->exit_thread.set();
break; break;
} }
@ -557,8 +556,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
err = ad->capture_init_device(); err = ad->capture_init_device();
if (err != OK) { if (err != OK) {
ad->active = false; ad->active.clear();
ad->exit_thread = true; ad->exit_thread.set();
break; break;
} }
} }
@ -573,12 +572,10 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
OS::get_singleton()->delay_usec(1000); OS::get_singleton()->delay_usec(1000);
} }
} }
ad->thread_exited = true;
} }
void AudioDriverPulseAudio::start() { void AudioDriverPulseAudio::start() {
active = true; active.set();
} }
int AudioDriverPulseAudio::get_mix_rate() const { int AudioDriverPulseAudio::get_mix_rate() const {
@ -663,7 +660,7 @@ void AudioDriverPulseAudio::finish() {
return; return;
} }
exit_thread = true; exit_thread.set();
thread.wait_to_finish(); thread.wait_to_finish();
finish_device(); finish_device();
@ -840,9 +837,6 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() :
channels(0), channels(0),
pa_ready(0), pa_ready(0),
pa_status(0), pa_status(0),
active(false),
thread_exited(false),
exit_thread(false),
latency(0) { latency(0) {
samples_in.clear(); samples_in.clear();
samples_out.clear(); samples_out.clear();

View file

@ -35,6 +35,7 @@
#include "core/os/mutex.h" #include "core/os/mutex.h"
#include "core/os/thread.h" #include "core/os/thread.h"
#include "core/safe_refcount.h"
#include "servers/audio_server.h" #include "servers/audio_server.h"
#include "pulse-so_wrap.h" #include "pulse-so_wrap.h"
@ -70,9 +71,8 @@ class AudioDriverPulseAudio : public AudioDriver {
Array pa_devices; Array pa_devices;
Array pa_rec_devices; Array pa_rec_devices;
bool active; SafeFlag active;
bool thread_exited; SafeFlag exit_thread;
mutable bool exit_thread;
float latency; float latency;

View file

@ -365,12 +365,12 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) {
} }
Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) { Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) {
if (p_device->active) { if (p_device->active.is_set()) {
if (p_device->audio_client) { if (p_device->audio_client) {
p_device->audio_client->Stop(); p_device->audio_client->Stop();
} }
p_device->active = false; p_device->active.clear();
} }
SAFE_RELEASE(p_device->audio_client) SAFE_RELEASE(p_device->audio_client)
@ -396,8 +396,7 @@ Error AudioDriverWASAPI::init() {
ERR_PRINT("WASAPI: init_render_device error"); ERR_PRINT("WASAPI: init_render_device error");
} }
exit_thread = false; exit_thread.clear();
thread_exited = false;
thread.start(thread_func, this); thread.start(thread_func, this);
@ -543,7 +542,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
uint32_t avail_frames = 0; uint32_t avail_frames = 0;
uint32_t write_ofs = 0; uint32_t write_ofs = 0;
while (!ad->exit_thread) { while (!ad->exit_thread.is_set()) {
uint32_t read_frames = 0; uint32_t read_frames = 0;
uint32_t written_frames = 0; uint32_t written_frames = 0;
@ -551,7 +550,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
ad->lock(); ad->lock();
ad->start_counting_ticks(); 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()); ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
} else { } else {
for (int i = 0; i < ad->samples_in.size(); i++) { for (int i = 0; i < ad->samples_in.size(); i++) {
@ -617,7 +616,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
} }
} else { } else {
ERR_PRINT("WASAPI: Get buffer error"); ERR_PRINT("WASAPI: Get buffer error");
ad->exit_thread = true; ad->exit_thread.set();
} }
} }
} else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
@ -666,7 +665,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
write_ofs = 0; write_ofs = 0;
} }
if (ad->audio_input.active) { if (ad->audio_input.active.is_set()) {
UINT32 packet_length = 0; UINT32 packet_length = 0;
BYTE *data; BYTE *data;
UINT32 num_frames_available; UINT32 num_frames_available;
@ -745,8 +744,6 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
OS::get_singleton()->delay_usec(1000); OS::get_singleton()->delay_usec(1000);
} }
} }
ad->thread_exited = true;
} }
void AudioDriverWASAPI::start() { void AudioDriverWASAPI::start() {
@ -755,7 +752,7 @@ void AudioDriverWASAPI::start() {
if (hr != S_OK) { if (hr != S_OK) {
ERR_PRINT("WASAPI: Start failed"); ERR_PRINT("WASAPI: Start failed");
} else { } else {
audio_output.active = true; audio_output.active.set();
} }
} }
} }
@ -769,7 +766,7 @@ void AudioDriverWASAPI::unlock() {
} }
void AudioDriverWASAPI::finish() { void AudioDriverWASAPI::finish() {
exit_thread = true; exit_thread.set();
thread.wait_to_finish(); thread.wait_to_finish();
finish_capture_device(); finish_capture_device();
@ -783,19 +780,19 @@ Error AudioDriverWASAPI::capture_start() {
return err; return err;
} }
if (audio_input.active) { if (audio_input.active.is_set()) {
return FAILED; return FAILED;
} }
audio_input.audio_client->Start(); audio_input.audio_client->Start();
audio_input.active = true; audio_input.active.set();
return OK; return OK;
} }
Error AudioDriverWASAPI::capture_stop() { Error AudioDriverWASAPI::capture_stop() {
if (audio_input.active) { if (audio_input.active.is_set()) {
audio_input.audio_client->Stop(); audio_input.audio_client->Stop();
audio_input.active = false; audio_input.active.clear();
return OK; return OK;
} }
@ -827,9 +824,6 @@ AudioDriverWASAPI::AudioDriverWASAPI() {
channels = 0; channels = 0;
mix_rate = 0; mix_rate = 0;
buffer_frames = 0; buffer_frames = 0;
thread_exited = false;
exit_thread = false;
} }
#endif #endif

View file

@ -35,6 +35,7 @@
#include "core/os/mutex.h" #include "core/os/mutex.h"
#include "core/os/thread.h" #include "core/os/thread.h"
#include "core/safe_refcount.h"
#include "servers/audio_server.h" #include "servers/audio_server.h"
#include <audioclient.h> #include <audioclient.h>
@ -48,7 +49,7 @@ class AudioDriverWASAPI : public AudioDriver {
IAudioClient *audio_client; IAudioClient *audio_client;
IAudioRenderClient *render_client; IAudioRenderClient *render_client;
IAudioCaptureClient *capture_client; IAudioCaptureClient *capture_client;
bool active; SafeFlag active;
WORD format_tag; WORD format_tag;
WORD bits_per_sample; WORD bits_per_sample;
@ -62,7 +63,6 @@ class AudioDriverWASAPI : public AudioDriver {
audio_client(NULL), audio_client(NULL),
render_client(NULL), render_client(NULL),
capture_client(NULL), capture_client(NULL),
active(false),
format_tag(0), format_tag(0),
bits_per_sample(0), bits_per_sample(0),
channels(0), channels(0),
@ -84,8 +84,7 @@ class AudioDriverWASAPI : public AudioDriver {
int mix_rate; int mix_rate;
int buffer_frames; int buffer_frames;
bool thread_exited; SafeFlag exit_thread;
mutable bool 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_ 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); static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i);

View file

@ -38,9 +38,8 @@ const char *AudioDriverXAudio2::get_name() const {
} }
Error AudioDriverXAudio2::init() { Error AudioDriverXAudio2::init() {
active = false; active.clear();
thread_exited = false; exit_thread.clear();
exit_thread = false;
pcm_open = false; pcm_open = false;
samples_in = NULL; samples_in = NULL;
@ -86,17 +85,19 @@ Error AudioDriverXAudio2::init() {
void AudioDriverXAudio2::thread_func(void *p_udata) { void AudioDriverXAudio2::thread_func(void *p_udata) {
AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata; AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata;
while (!ad->exit_thread) { while (!ad->exit_thread.is_set()) {
if (!ad->active) { if (!ad->active.is_set()) {
for (int i = 0; i < AUDIO_BUFFERS; i++) { for (int i = 0; i < AUDIO_BUFFERS; i++) {
ad->xaudio_buffer[i].Flags = XAUDIO2_END_OF_STREAM; ad->xaudio_buffer[i].Flags = XAUDIO2_END_OF_STREAM;
} }
} else { } else {
ad->lock(); ad->lock();
ad->start_counting_ticks();
ad->audio_server_process(ad->buffer_size, ad->samples_in); ad->audio_server_process(ad->buffer_size, ad->samples_in);
ad->stop_counting_ticks();
ad->unlock(); ad->unlock();
for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { 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() { void AudioDriverXAudio2::start() {
active = true; active.set();
HRESULT hr = source_voice->Start(0); HRESULT hr = source_voice->Start(0);
ERR_FAIL_COND_MSG(hr != S_OK, "Error starting XAudio2 driver. Error code: " + itos(hr) + "."); 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()) if (!thread.is_started())
return; return;
exit_thread = true; exit_thread.set();
thread.wait_to_finish(); thread.wait_to_finish();
if (source_voice) { if (source_voice) {

View file

@ -33,6 +33,7 @@
#include "core/os/mutex.h" #include "core/os/mutex.h"
#include "core/os/thread.h" #include "core/os/thread.h"
#include "core/safe_refcount.h"
#include "servers/audio_server.h" #include "servers/audio_server.h"
#include <mmsystem.h> #include <mmsystem.h>
@ -77,9 +78,8 @@ class AudioDriverXAudio2 : public AudioDriver {
int channels; int channels;
bool active; SafeFlag active;
bool thread_exited; SafeFlag exit_thread;
mutable bool exit_thread;
bool pcm_open; bool pcm_open;
WAVEFORMATEX wave_format; WAVEFORMATEX wave_format;

View file

@ -34,9 +34,8 @@
#include "core/project_settings.h" #include "core/project_settings.h"
Error AudioDriverDummy::init() { Error AudioDriverDummy::init() {
active = false; active.clear();
thread_exited = false; exit_thread.clear();
exit_thread = false;
samples_in = nullptr; samples_in = nullptr;
mix_rate = GLOBAL_GET("audio/mix_rate"); 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; uint64_t usdelay = (ad->buffer_frames / float(ad->mix_rate)) * 1000000;
while (!ad->exit_thread) { while (!ad->exit_thread.is_set()) {
if (ad->active) { if (ad->active.is_set()) {
ad->lock(); ad->lock();
ad->start_counting_ticks();
ad->audio_server_process(ad->buffer_frames, ad->samples_in); ad->audio_server_process(ad->buffer_frames, ad->samples_in);
ad->stop_counting_ticks();
ad->unlock(); ad->unlock();
}; };
OS::get_singleton()->delay_usec(usdelay); OS::get_singleton()->delay_usec(usdelay);
}; };
ad->thread_exited = true;
}; };
void AudioDriverDummy::start() { void AudioDriverDummy::start() {
active = true; active.set();
}; };
int AudioDriverDummy::get_mix_rate() const { int AudioDriverDummy::get_mix_rate() const {
@ -94,7 +93,7 @@ void AudioDriverDummy::unlock() {
}; };
void AudioDriverDummy::finish() { void AudioDriverDummy::finish() {
exit_thread = true; exit_thread.set();
thread.wait_to_finish(); thread.wait_to_finish();
if (samples_in) { if (samples_in) {

View file

@ -35,6 +35,7 @@
#include "core/os/mutex.h" #include "core/os/mutex.h"
#include "core/os/thread.h" #include "core/os/thread.h"
#include "core/safe_refcount.h"
class AudioDriverDummy : public AudioDriver { class AudioDriverDummy : public AudioDriver {
Thread thread; Thread thread;
@ -50,9 +51,8 @@ class AudioDriverDummy : public AudioDriver {
int channels; int channels;
bool active; SafeFlag active;
bool thread_exited; SafeFlag exit_thread;
mutable bool exit_thread;
public: public:
const char *get_name() const { const char *get_name() const {