MayaFlux 0.3.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RtAudioSingleton.hpp
Go to the documentation of this file.
1#pragma once
2
3#ifdef RTAUDIO_BACKEND
4#include "RtAudio.h"
5#endif
6
8
9namespace MayaFlux::Core {
10
11/**
12 * @class RtAudioSingleton
13 * @brief Thread-safe global access point for audio system resources
14 *
15 * Implements the Singleton pattern to provide controlled, centralized access
16 * to the RtAudio subsystem. Ensures that only one instance of the audio driver
17 * exists throughout the application lifecycle, preventing resource conflicts
18 * and maintaining system stability.
19 *
20 * This class enforces strict resource management with the following guarantees:
21 * - Thread safety through mutex-protected access
22 * - Lazy initialization of the audio subsystem
23 * - Exclusive stream ownership validation
24 * - Proper resource cleanup on application termination
25 */
27private:
28 /** @brief Singleton instance of the RtAudio driver (nullptr until first access) */
29 static std::unique_ptr<RtAudio> s_instance;
30
31 /** @brief Synchronization primitive for thread-safe access to the singleton */
32 static std::mutex s_mutex;
33
34 /** @brief Stream state flag to enforce exclusive stream ownership */
35 static bool s_stream_open;
36
37 /** @brief Preferred RtAudio API, if specified */
38 static std::optional<RtAudio::Api> s_preferred_api;
39
40 /**
41 * @brief Private constructor prevents direct instantiation
42 *
43 * Enforces the Singleton pattern by making the constructor inaccessible
44 * to client code, ensuring all access occurs through the static interface.
45 */
46 RtAudioSingleton() = default;
47
48public:
49 /**
50 * @brief Provides access to the RtAudio instance with lazy initialization
51 * @return Pointer to the singleton RtAudio instance
52 *
53 * Thread-safe accessor that creates the RtAudio instance on first access
54 * and returns the existing instance on subsequent calls. The returned
55 * pointer remains valid until cleanup() is called.
56 */
57 static RtAudio* get_instance()
58 {
59 std::lock_guard<std::mutex> lock(s_mutex);
60 if (!s_instance) {
61 if (s_preferred_api.has_value()) {
62 s_instance = std::make_unique<RtAudio>(*s_preferred_api);
63 } else {
64 s_instance = std::make_unique<RtAudio>();
65 }
66 }
67 return s_instance.get();
68 }
69
70 /**
71 * @brief Sets the preferred audio API before instance creation
72 * @param api RtAudio API to use (JACK, ALSA, PULSE, etc.)
73 * @throws std::runtime_error if instance already exists
74 */
75 static void set_preferred_api(RtAudio::Api api)
76 {
77 std::lock_guard<std::mutex> lock(s_mutex);
78 if (s_instance) {
79 error<std::runtime_error>(
82 std::source_location::current(),
83 "Cannot set API preference after RtAudio instance created");
84 }
85 s_preferred_api = api;
86 }
87
88 /**
89 * @brief Registers an active audio stream in the system
90 * @throws std::runtime_error if a stream is already open
91 *
92 * Thread-safe method that enforces the constraint of having only
93 * one active audio stream at any time. This prevents resource conflicts
94 * that could lead to audio glitches or system instability.
95 */
96 static void mark_stream_open()
97 {
98 std::lock_guard<std::mutex> lock(s_mutex);
99 if (s_stream_open) {
100 error<std::runtime_error>(
103 std::source_location::current(),
104 "Attempted to open a second RtAudio stream when one is already open");
105 }
106 s_stream_open = true;
107 }
108
109 /**
110 * @brief Deregisters an active audio stream from the system
111 *
112 * Thread-safe method that updates the internal state to reflect
113 * that no audio stream is currently active, allowing a new stream
114 * to be opened if needed.
115 */
116 static void mark_stream_closed()
117 {
118 std::lock_guard<std::mutex> lock(s_mutex);
119 s_stream_open = false;
120 }
121
122 /**
123 * @brief Checks if an audio stream is currently active
124 * @return True if a stream is open, false otherwise
125 *
126 * Thread-safe method that provides the current state of stream
127 * ownership without modifying any internal state.
128 */
129 static bool is_stream_open()
130 {
131 std::lock_guard<std::mutex> lock(s_mutex);
132 return s_stream_open;
133 }
134
135 /**
136 * @brief Releases all audio system resources
137 *
138 * Thread-safe method that performs complete cleanup of the audio
139 * subsystem, including stopping and closing any active streams
140 * and releasing the RtAudio instance. This method is idempotent
141 * and can be safely called multiple times.
142 *
143 * This method should be called only before application termination to
144 * ensure proper resource deallocation and prevent memory leaks. It is not
145 * intended for general use and should not be called during normal
146 * application operation.
147 */
148 static void cleanup()
149 {
150 std::lock_guard<std::mutex> lock(s_mutex);
151 if (s_instance && s_stream_open) {
152 try {
153 if (s_instance->isStreamRunning()) {
154 s_instance->stopStream();
155 }
156 if (s_instance->isStreamOpen()) {
157 s_instance->closeStream();
158 }
159 s_stream_open = false;
160 } catch (const RtAudioErrorType& e) {
161 error_rethrow(
164 std::source_location::current(),
165 "Error during RtAudio cleanup: {}",
166 s_instance->getErrorText());
167 }
168 }
169 if (s_instance) {
170 s_instance.reset();
171 }
172 }
173};
174
175}
static std::optional< RtAudio::Api > s_preferred_api
Preferred RtAudio API, if specified.
static bool is_stream_open()
Checks if an audio stream is currently active.
static void mark_stream_closed()
Deregisters an active audio stream from the system.
static void set_preferred_api(RtAudio::Api api)
Sets the preferred audio API before instance creation.
static std::unique_ptr< RtAudio > s_instance
Singleton instance of the RtAudio driver (nullptr until first access)
static bool s_stream_open
Stream state flag to enforce exclusive stream ownership.
static RtAudio * get_instance()
Provides access to the RtAudio instance with lazy initialization.
static std::mutex s_mutex
Synchronization primitive for thread-safe access to the singleton.
static void mark_stream_open()
Registers an active audio stream in the system.
RtAudioSingleton()=default
Private constructor prevents direct instantiation.
static void cleanup()
Releases all audio system resources.
Thread-safe global access point for audio system resources.
@ AudioBackend
Audio processing backend (RtAudio, JACK, ASIO)
@ Core
Core engine, backend, subsystems.