From c91fe1ef4ccc0b5820d7b2ef82cf4af435062d5d Mon Sep 17 00:00:00 2001 From: Etienne Dechamps Date: Sat, 4 Feb 2023 11:01:11 +0000 Subject: [PATCH] Allow multiple PortAudioRedirector instances Fixes #183 --- src/flexasio/FlexASIOUtil/portaudio.cpp | 51 ++++++++++++++++++------- src/flexasio/FlexASIOUtil/portaudio.h | 26 ++++++++++--- 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/flexasio/FlexASIOUtil/portaudio.cpp b/src/flexasio/FlexASIOUtil/portaudio.cpp index 044498c5..42ec7e39 100644 --- a/src/flexasio/FlexASIOUtil/portaudio.cpp +++ b/src/flexasio/FlexASIOUtil/portaudio.cpp @@ -37,30 +37,55 @@ typedef struct PaUtilHostApiSpecificStreamInfoHeader namespace flexasio { - PortAudioDebugRedirector::PortAudioDebugRedirector(Write write) { - write(std::string("PortAudio version: ") + Pa_GetVersionText()); - write("Enabling PortAudio debug output redirection"); - if (this->write) abort(); - this->write = std::move(write); - PaUtil_SetDebugPrintFunction(DebugPrint); + PortAudioDebugRedirector::Singleton::~Singleton() { + Check(); + if (write) abort(); } - PortAudioDebugRedirector::~PortAudioDebugRedirector() { + void PortAudioDebugRedirector::Singleton::Start(Write write) { + const std::lock_guard lock(mutex); + Check(); + + if (referenceCount > 0) { + if (write != this->write) abort(); + } else { + this->write = write; + write(std::string("PortAudio version: ") + Pa_GetVersionText()); + write("Enabling PortAudio debug output redirection"); + PaUtil_SetDebugPrintFunction(DebugPrint); + } + + ++referenceCount; + } + + void PortAudioDebugRedirector::Singleton::Stop() { + const std::lock_guard lock(mutex); + Check(); + if (!write) abort(); + + --referenceCount; + if (referenceCount > 0) return; + this->write("Disabling PortAudio debug output redirection"); PaUtil_SetDebugPrintFunction(NULL); - if (!this->write) abort(); - this->write = nullptr; + write = nullptr; } - void PortAudioDebugRedirector::DebugPrint(const char* str) { - if (!PortAudioDebugRedirector::write) abort(); + void PortAudioDebugRedirector::Singleton::DebugPrint(const char* str) { + singleton.Check(); + const auto write = singleton.write; + if (!write) abort(); std::string_view line(str); while (!line.empty() && isspace(static_cast(line.back()))) line.remove_suffix(1); - PortAudioDebugRedirector::write(line); + write(line); + } + + void PortAudioDebugRedirector::Singleton::Check() const { + if ((referenceCount != 0) != !!write) abort(); } - PortAudioDebugRedirector::Write PortAudioDebugRedirector::write; + PortAudioDebugRedirector::Singleton PortAudioDebugRedirector::singleton; std::string GetHostApiTypeIdString(PaHostApiTypeId hostApiTypeId) { return ::dechamps_cpputil::EnumToString(hostApiTypeId, { diff --git a/src/flexasio/FlexASIOUtil/portaudio.h b/src/flexasio/FlexASIOUtil/portaudio.h index b7bc7dc9..fbf1fb88 100644 --- a/src/flexasio/FlexASIOUtil/portaudio.h +++ b/src/flexasio/FlexASIOUtil/portaudio.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -14,15 +15,30 @@ namespace flexasio { class PortAudioDebugRedirector final { public: - using Write = std::function; + using Write = void(std::string_view); - explicit PortAudioDebugRedirector(Write write); - ~PortAudioDebugRedirector(); + explicit PortAudioDebugRedirector(Write write) { singleton.Start(write); } + ~PortAudioDebugRedirector() { singleton.Stop(); }; private: - static void DebugPrint(const char*); + class Singleton final { + public: + ~Singleton(); - static Write write; + void Start(Write); + void Stop(); + + private: + std::mutex mutex; + size_t referenceCount = 0; + Write* write = nullptr; + + static void DebugPrint(const char*); + + void Check() const; + }; + + static Singleton singleton; }; std::string GetHostApiTypeIdString(PaHostApiTypeId hostApiTypeId);