MayaFlux 0.3.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RtAudioBackend.cpp
Go to the documentation of this file.
1#include "RtAudioBackend.hpp"
4
5namespace {
6
7RtAudio::Api to_rtaudio_api(MayaFlux::Core::GlobalStreamInfo::AudioApi api)
8{
10 switch (api) {
11 case Api::ALSA:
12 return RtAudio::LINUX_ALSA;
13 case Api::PULSE:
14 return RtAudio::LINUX_PULSE;
15 case Api::JACK:
16 return RtAudio::UNIX_JACK;
17 case Api::CORE:
18 return RtAudio::MACOSX_CORE;
19 case Api::WASAPI:
20 return RtAudio::WINDOWS_WASAPI;
21 case Api::ASIO:
22 return RtAudio::WINDOWS_ASIO;
23 case Api::DS:
24 return RtAudio::WINDOWS_DS;
25 case Api::OSS:
26 return RtAudio::LINUX_OSS;
27 default:
28 return RtAudio::UNSPECIFIED;
29 }
30}
31
32}
33
34namespace MayaFlux::Core {
35
37 : m_context(RtAudioSingleton::get_instance())
38{
39}
40
42
43std::unique_ptr<AudioDevice> RtAudioBackend::create_device_manager()
44{
45 return std::make_unique<RtAudioDevice>(m_context);
46}
47
48std::unique_ptr<AudioStream> RtAudioBackend::create_stream(
49 unsigned int output_device_id,
50 unsigned int input_device_id,
51 GlobalStreamInfo& stream_info,
52 void* user_data)
53{
54 return std::make_unique<RtAudioStream>(
56 output_device_id,
57 input_device_id,
58 stream_info,
59 user_data);
60}
61
63{
64 return RtAudio::getVersion();
65}
66
68{
69 return m_context->getCurrentApi();
70}
71
76
78 : m_context(context)
79 , m_defaultOutputDevice(0)
80 , m_defaultInputDevice(0)
81{
82 if (!context) {
83 throw std::invalid_argument("RtAudioDevice: context must not be null");
84 }
85
86 if (m_context->getDeviceCount() == 0) {
87 throw std::runtime_error("No audio devices found");
88 }
89
90 m_defaultOutputDevice = m_context->getDefaultOutputDevice();
91 m_defaultInputDevice = m_context->getDefaultInputDevice();
92
93 for (unsigned int id : m_context->getDeviceIds()) {
94 try {
95 RtAudio::DeviceInfo info = m_context->getDeviceInfo(id);
96
97 if (info.outputChannels > 0) {
100 }
101
102 if (info.inputChannels > 0) {
105 }
106 } catch (RtAudioErrorType& e) {
107 std::cerr << "Error probing device: " << id << ": " << e << "\n";
108 }
109 }
110}
111
112std::vector<DeviceInfo> RtAudioDevice::get_output_devices() const
113{
114 return m_output_devices;
115}
116
117std::vector<DeviceInfo> RtAudioDevice::get_input_devices() const
118{
119 return m_input_devices;
120}
121
123{
125}
126
128{
130}
131
133 RtAudio* context,
134 unsigned int output_device_id,
135 unsigned int input_device_id,
136 GlobalStreamInfo& streamInfo,
137 void* userData)
138 : m_context(context)
139 , m_out_parameters()
140 , m_options()
141 , m_userData(userData)
142 , m_isOpen(false)
143 , m_isRunning(false)
144 , m_stream_info(streamInfo)
145{
146 if (!context) {
147 throw std::invalid_argument("RtAudioStream: context must not be null");
148 }
149
150 m_out_parameters.deviceId = output_device_id;
151 m_out_parameters.nChannels = streamInfo.output.channels;
152
153 m_in_parameters.deviceId = input_device_id;
154
156}
157
159{
160 if (is_running()) {
161 stop();
162 }
163 if (is_open()) {
164 close();
165 }
166}
167
169{
170 m_options.flags = 0;
171
172 switch (m_stream_info.priority) {
174 m_options.flags |= RTAUDIO_SCHEDULE_REALTIME;
175 break;
177 default:
178 break;
179 }
180
182 m_options.flags |= RTAUDIO_NONINTERLEAVED;
183 }
184
185 if (m_stream_info.buffer_count > 0) {
186 m_options.numberOfBuffers = static_cast<unsigned int>(m_stream_info.buffer_count);
187 }
188
189 m_options.priority = 0;
190
191 auto rtSpecificOpt = m_stream_info.backend_options.find("rtaudio.exclusive");
192 if (rtSpecificOpt != m_stream_info.backend_options.end()) {
193 try {
194 bool exclusive = std::any_cast<bool>(rtSpecificOpt->second);
195 if (exclusive) {
196#ifdef _WIN32
197 m_options.flags |= RtAudio::Api::WINDOWS_WASAPI;
198#endif
199 }
200 } catch (const std::bad_any_cast&) {
201 error_rethrow(
204 std::source_location::current(),
205 "Invalid type for rtaudio.exclusive option; expected bool");
206 }
207 }
208}
209
211{
212 if (is_open()) {
213 return;
214 }
215
216 try {
217 RtAudioFormat format = RTAUDIO_FLOAT64;
218
219 switch (m_stream_info.format) {
221 format = RTAUDIO_FLOAT32;
222 break;
224 format = RTAUDIO_FLOAT64;
225 break;
227 format = RTAUDIO_SINT16;
228 break;
230 format = RTAUDIO_SINT24;
231 break;
233 format = RTAUDIO_SINT32;
234 break;
235 }
236
237 RtAudio::StreamParameters* inputParamsPtr = nullptr;
238
241 inputParamsPtr = &m_in_parameters;
242 }
243
244 unsigned int requested_buffer = m_stream_info.buffer_size;
245
246#ifdef MAYAFLUX_PLATFORM_LINUX
247 if (m_context->getCurrentApi() == RtAudio::UNIX_JACK) {
248 setenv("PIPEWIRE_QUANTUM",
249 std::to_string(m_stream_info.buffer_size).c_str(), 0);
250 setenv("PIPEWIRE_LATENCY",
252 }
253#endif // MAYAFLUX_PLATFORM_LINUX
254
256
257 m_context->openStream(
259 inputParamsPtr,
260 format,
264 this,
265 &m_options);
266
267 if (m_stream_info.buffer_size != requested_buffer) {
270 "Audio backend changed buffer size from {} to {}. "
271 "Set GlobalStreamInfo.buffer_size = {} before initialization to avoid mismatch.",
273 }
274
275 m_isOpen = true;
276 } catch (const RtAudioErrorType& e) {
278 m_isOpen = false;
279
280 error_rethrow(
283 std::source_location::current(),
284 "Failed to open RtAudio stream: {}",
285 m_context->getErrorText());
286 }
287}
288
290{
291 if (!is_open()) {
292 throw std::runtime_error("Cannot start stream: stream not open");
293 }
294
295 if (is_running()) {
296 return;
297 }
298
299 try {
300 m_context->startStream();
301 m_isRunning = true;
302 } catch (const RtAudioErrorType& e) {
303 error_rethrow(
306 std::source_location::current(),
307 "Failed to start RtAudio stream: {}",
308 m_context->getErrorText());
309 }
310}
311
313{
314 if (!is_running()) {
315 return;
316 }
317
318 try {
319 m_context->stopStream();
320 m_isRunning = false;
321 } catch (const RtAudioErrorType& e) {
322 error_rethrow(
325 std::source_location::current(),
326 "Failed to stop RtAudio stream: {}",
327 m_context->getErrorText());
328 }
329}
330
332{
333 if (!m_isOpen || !m_context) {
334 return;
335 }
336
337 if (is_running()) {
338 stop();
339 }
340
341 try {
342 if (m_context->isStreamOpen()) {
343 m_context->closeStream();
345 }
346 m_isOpen = false;
347 } catch (const RtAudioErrorType& e) {
348 m_isOpen = false;
350
351 error_rethrow(
354 std::source_location::current(),
355 "Failed to close RtAudio stream: {}",
356 m_context->getErrorText());
357 }
358}
359
361{
362 return m_isRunning && m_context->isStreamRunning();
363}
364
366{
367 return m_isOpen && m_context->isStreamOpen();
368}
369
371 std::function<int(void*, void*, unsigned int)> processCallback)
372{
373 m_process_callback = std::move(processCallback);
374}
375
377 void* output_buffer,
378 void* input_buffer,
379 unsigned int num_frames,
380 double /*stream_time*/,
381 RtAudioStreamStatus /*status*/,
382 void* user_data)
383{
384 auto stream = static_cast<RtAudioStream*>(user_data);
385
386 if (stream && stream->m_process_callback) {
387 return stream->m_process_callback(output_buffer, input_buffer, num_frames);
388 }
389
390 return 0;
391}
392
393std::unique_ptr<IAudioBackend> AudioBackendFactory::create_backend(
395 std::optional<Core::GlobalStreamInfo::AudioApi> api_preference)
396{
397 switch (type) {
399 if (api_preference) {
400 auto pref_api = to_rtaudio_api(*api_preference);
401 if (pref_api != RtAudio::UNSPECIFIED) {
403 "Setting RtAudio preferred API to {}",
404 RtAudio::getApiDisplayName(pref_api));
405
407 to_rtaudio_api(*api_preference));
408 }
409 }
410 return std::make_unique<RtAudioBackend>();
411 default:
412 throw std::runtime_error("Unsupported audio backend type");
413 }
414}
415
416} // namespace MayaFlux::Core
#define MF_INFO(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
static std::unique_ptr< IAudioBackend > create_backend(Core::AudioBackendType type, std::optional< GlobalStreamInfo::AudioApi > api_preference=std::nullopt)
Creates a specific audio backend implementation.
std::unique_ptr< AudioStream > create_stream(unsigned int output_device_id, unsigned int input_device_id, GlobalStreamInfo &stream_info, void *user_data) override
Creates an RtAudio-specific audio stream.
int get_api_type() const override
Retrieves the RtAudio API type identifier.
std::string get_version_string() const override
Retrieves the RtAudio library version.
RtAudio * m_context
Pointer to the underlying RtAudio context.
void cleanup() override
Releases all resources held by the backend.
RtAudioBackend()
Initializes the RtAudio backend.
std::unique_ptr< AudioDevice > create_device_manager() override
Creates an RtAudio-specific device manager.
~RtAudioBackend() override
Cleans up the RtAudio backend.
std::vector< DeviceInfo > m_output_devices
Cached list of output devices.
unsigned int m_defaultOutputDevice
System identifier for the default output device.
RtAudioDevice(RtAudio *context)
Initializes the device manager with an RtAudio context.
RtAudio * m_context
Pointer to the underlying RtAudio context.
std::vector< DeviceInfo > get_input_devices() const override
Retrieves information about all available input devices.
std::vector< DeviceInfo > m_input_devices
Cached list of input devices.
std::vector< DeviceInfo > get_output_devices() const override
Retrieves information about all available output devices.
unsigned int get_default_output_device() const override
Gets the system's primary output device identifier.
unsigned int get_default_input_device() const override
Gets the system's primary input device identifier.
unsigned int m_defaultInputDevice
System identifier for the default input device.
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 void mark_stream_open()
Registers an active audio stream in the system.
static void cleanup()
Releases all audio system resources.
Thread-safe global access point for audio system resources.
RtAudio::StreamOptions m_options
RtAudio-specific stream options.
void set_process_callback(std::function< int(void *, void *, unsigned int)> processCallback) override
Sets the function to process audio data.
void start() override
Activates the audio stream and begins data transfer.
void stop() override
Deactivates the audio stream and halts data transfer.
RtAudioStream(RtAudio *context, unsigned int output_device_id, unsigned int input_device_id, GlobalStreamInfo &streamInfo, void *userData)
Initializes an audio stream with the specified configuration.
void configure_stream_options()
Configures RtAudio stream options based on GlobalStreamInfo.
~RtAudioStream() override
Ensures proper cleanup of stream resources.
bool m_isOpen
Flag indicating if the stream is currently open.
GlobalStreamInfo & m_stream_info
Copy of the stream configuration for reference.
bool is_open() const override
Checks if the stream is initialized and ready for activation.
void open() override
Initializes the audio stream and allocates required resources.
bool m_isRunning
Flag indicating if the stream is currently running.
RtAudio::StreamParameters m_in_parameters
RtAudio-specific stream input configuration parameters.
RtAudio::StreamParameters m_out_parameters
RtAudio-specific stream output configuration parameters.
void close() override
Terminates the audio stream and releases all resources.
RtAudio * m_context
Pointer to the underlying RtAudio context.
std::function< int(void *, void *, unsigned int)> m_process_callback
User-provided callback function for audio processing.
static int rtAudioCallback(void *output_buffer, void *input_buffer, unsigned int num_frames, double stream_time, RtAudioStreamStatus status, void *user_data)
Static callback function for the RtAudio API.
bool is_running() const override
Checks if the stream is actively processing audio data.
RtAudio implementation of the audio stream interface.
static DeviceInfo convert_device_info(const RtAudio::DeviceInfo &rtInfo, unsigned int id, unsigned int defaultOutputDevice, unsigned int defaultInputDevice)
Converts RtAudio-specific device information to the engine's device model.
@ AudioBackend
Audio processing backend (RtAudio, JACK, ASIO)
std::string format_runtime(std::string_view fmt_str, Args &&... args)
Definition Format.hpp:36
@ Core
Core engine, backend, subsystems.
uint32_t channels
Number of discrete channels in this set.
bool enabled
Whether this channel set is active in the stream.
uint32_t buffer_size
Number of samples per processing block.
ChannelConfig input
Configuration for input signal channels (disabled by default)
AudioApi
Enumeration of supported audio APIs for wrapper backends like RtAudio.
uint32_t sample_rate
Number of samples processed per second (Hz)
@ FLOAT64
64-bit floating point representation (-1.0 to 1.0)
@ INT16
16-bit integer representation (-32768 to 32767)
@ INT32
32-bit integer representation (-2147483648 to 2147483647)
@ INT24
24-bit integer representation (-8388608 to 8388607)
@ FLOAT32
32-bit floating point representation (-1.0 to 1.0)
ChannelConfig output
Configuration for output signal channels.
AudioFormat format
Sample data format for stream processing.
@ REALTIME
Maximum resource priority with timing guarantees.
StreamPriority priority
System resource priority for audio processing.
double buffer_count
Number of buffers in the processing queue (0 for system default)
std::unordered_map< std::string, std::any > backend_options
Backend-specific configuration parameters.
bool non_interleaved
Channel organization mode (true: planar, false: interleaved)
Comprehensive configuration for digital audio stream processing.