UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
coreaudio.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2011-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
43#ifdef HAVE_CONFIG_H
44#include "config.h"
45#endif // HAVE_CONFIG_H
46#include "config_unix.h"
47#include "config_win32.h"
48
49#include <AudioUnit/AudioUnit.h>
50#include <Availability.h>
51#include <chrono>
52#include <cinttypes>
53#include <climits>
54#include <CoreAudio/AudioHardware.h>
55#include <iostream>
56#include <stdlib.h>
57#include <string>
58#include <string.h>
59
62#include "audio/types.h"
63#include "debug.h"
64#include "lib_common.h"
65#include "utils/audio_buffer.h"
66#include "utils/color_out.h"
67#include "utils/macos.h"
68#include "utils/ring_buffer.h"
69
70using namespace std::chrono;
71using std::cout;
72using std::stoi;
73
74constexpr int DEFAULT_BUFLEN_MS = 50;
75constexpr int CA_DIR = 1;
76#define NO_DATA_STOP_SEC 2
77#define MOD_NAME "[CoreAudio play.] "
78
80 AudioComponentInstance auHALComponentInstance;
82 void *buffer; // audio buffer
85 steady_clock::time_point last_audio_read;
86 bool quiet;
89};
90
91static OSStatus theRenderProc(void *inRefCon,
92 AudioUnitRenderActionFlags *inActionFlags,
93 const AudioTimeStamp *inTimeStamp,
94 UInt32 inBusNumber, UInt32 inNumFrames,
95 AudioBufferList *ioData);
96
97static OSStatus theRenderProc(void *inRefCon,
98 AudioUnitRenderActionFlags *inActionFlags,
99 const AudioTimeStamp *inTimeStamp,
100 UInt32 inBusNumber, UInt32 inNumFrames,
101 AudioBufferList *ioData)
102{
103 UNUSED(inActionFlags);
104 UNUSED(inTimeStamp);
105 UNUSED(inBusNumber);
106
107 struct state_ca_playback * s = (struct state_ca_playback *) inRefCon;
108 int write_bytes = inNumFrames * s->audio_packet_size;
109
110 int ret = s->buffer_fns->read(s->buffer, (char *) ioData->mBuffers[0].mData, write_bytes);
111 ioData->mBuffers[0].mDataByteSize = ret;
112
113 if(ret < write_bytes) {
114 if (!s->quiet) {
115 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Audio buffer underflow (" << write_bytes << " requested, " << ret << " written).\n";
116 }
117 //memset(ioData->mBuffers[0].mData, 0, write_bytes);
118 ioData->mBuffers[0].mDataByteSize = ret;
119 if (!s->quiet && duration_cast<seconds>(steady_clock::now() - s->last_audio_read).count() > NO_DATA_STOP_SEC) {
120 LOG(LOG_LEVEL_WARNING) << MOD_NAME "No data for " << NO_DATA_STOP_SEC << " seconds! Stopping.\n";
121 s->quiet = true;
122 }
123 } else {
124 if (s->quiet) {
125 LOG(LOG_LEVEL_NOTICE) << MOD_NAME "Starting again.\n";
126 }
127 s->quiet = false;
128 s->last_audio_read = steady_clock::now();
129 }
130 return noErr;
131}
132
133static bool audio_play_ca_ctl(void *state [[gnu::unused]], int request, void *data, size_t *len)
134{
135 switch (request) {
137 if (*len >= sizeof(struct audio_desc)) {
138 struct audio_desc desc;
139 memcpy(&desc, data, sizeof desc);
140 desc.codec = AC_PCM;
141 memcpy(data, &desc, sizeof desc);
142 *len = sizeof desc;
143 return true;
144 } else{
145 return false;
146 }
147 default:
148 return false;
149 }
150}
151
152ADD_TO_PARAM("ca-disable-adaptive-buf", "* ca-disable-adaptive-buf\n"
153 " Core Audio - use fixed audio playback buffer instead of an adaptive one\n");
155{
156 struct state_ca_playback *s = (struct state_ca_playback *)state;
157 AudioStreamBasicDescription stream_desc;
158 UInt32 size;
159 OSStatus ret = noErr;
160 AURenderCallbackStruct renderStruct;
161
162 LOG(LOG_LEVEL_NOTICE) << MOD_NAME "Audio reinitialized to " << desc.bps * 8 << "-bit, " << desc.ch_count << " channels, " << desc.sample_rate << " Hz\n";
163
164 if (s->initialized) {
165 ret = AudioOutputUnitStop(s->auHALComponentInstance);
166 if(ret) {
167 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Cannot stop AUHAL instance: " << get_osstatus_str(ret) << ".\n";
168 goto error;
169 }
170
171 ret = AudioUnitUninitialize(s->auHALComponentInstance);
172 if(ret) {
173 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Cannot uninitialize AUHAL instance: " << get_osstatus_str(ret) << ".\n";
174 goto error;
175 }
176 s->initialized = false;
177 }
178
179 s->desc = desc;
180
181 if (s->buffer_fns) {
182 s->buffer_fns->destroy(s->buffer);
183 s->buffer_fns = nullptr;
184 s->buffer = nullptr;
185 }
186
187 {
188 if (get_commandline_param("audio-disable-adaptive-buffer") != nullptr || get_commandline_param("ca-disable-adaptive-buf") != nullptr) {
189 if (get_commandline_param("ca-disable-adaptive-buf") != nullptr) {
190 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Param \"ca-disable-adaptive-buf\" is deprecated, use audio-disable-adaptive-bufer instead.\n";
191 }
192 int buf_len = desc.bps * desc.ch_count * (desc.sample_rate * s->buf_len_ms / 1000);
193 s->buffer = ring_buffer_init(buf_len);
195 } else {
196 s->buffer = audio_buffer_init(desc.sample_rate, desc.bps, desc.ch_count, s->buf_len_ms);
198 }
199 }
200
201 size = sizeof(stream_desc);
202 ret = AudioUnitGetProperty(s->auHALComponentInstance, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
203 0, &stream_desc, &size);
204 if(ret) {
205 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Cannot get device format from AUHAL instance: " << get_osstatus_str(ret) << ".\n";
206 goto error;
207 }
208 stream_desc.mSampleRate = desc.sample_rate;
209 stream_desc.mFormatID = kAudioFormatLinearPCM;
210 stream_desc.mChannelsPerFrame = desc.ch_count;
211 stream_desc.mBitsPerChannel = desc.bps * 8;
212 stream_desc.mFormatFlags = kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
213 stream_desc.mFramesPerPacket = 1;
214 s->audio_packet_size = stream_desc.mBytesPerFrame = stream_desc.mBytesPerPacket = stream_desc.mFramesPerPacket * desc.ch_count * desc.bps;
215
216 ret = AudioUnitSetProperty(s->auHALComponentInstance, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
217 0, &stream_desc, sizeof(stream_desc));
218 if(ret) {
219 LOG(LOG_LEVEL_ERROR) << "Cannot set device format to AUHAL instance: " << get_osstatus_str(ret) << ".\n";
220 goto error;
221 }
222
223 renderStruct.inputProc = theRenderProc;
224 renderStruct.inputProcRefCon = s;
225 ret = AudioUnitSetProperty(s->auHALComponentInstance, kAudioUnitProperty_SetRenderCallback,
226 kAudioUnitScope_Input, 0, &renderStruct, sizeof(AURenderCallbackStruct));
227 if(ret) {
228 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Cannot register audio processing callback: " << get_osstatus_str(ret) << ".\n";
229 goto error;
230 }
231
232 ret = AudioUnitInitialize(s->auHALComponentInstance);
233 if(ret) {
234 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Cannot initialize AUHAL: " << get_osstatus_str(ret) << ".\n";
235 goto error;
236 }
237
238 ret = AudioOutputUnitStart(s->auHALComponentInstance);
239 if(ret) {
240 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Cannot start AUHAL: " << get_osstatus_str(ret) << ".\n";
241 goto error;
242 }
243
244 s->initialized = true;
245
246 return true;
247
248error:
249 return false;
250}
251
252
253// https://stackoverflow.com/questions/4575408/audioobjectgetpropertydata-to-get-a-list-of-input-devices#answer-4577271
254static bool is_requested_direction(AudioObjectPropertyAddress propertyAddress, AudioDeviceID *audioDevice) {
255 // Determine if the device is an input/output device (it is an input/output device if it has input/output channels)
256 UInt32 size = 0;
257 OSStatus status;
258 propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
259 status = AudioObjectGetPropertyDataSize(*audioDevice, &propertyAddress, 0, NULL, &size);
260 if(kAudioHardwareNoError != status) {
261 LOG(LOG_LEVEL_ERROR) << MOD_NAME "AudioObjectGetPropertyDataSize (kAudioDevicePropertyStreamConfiguration) failed: " << status << "\n";
262 return false;
263 }
264
265 AudioBufferList *bufferList = static_cast<AudioBufferList *>(malloc(size));
266 if(NULL == bufferList) {
267 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Unable to allocate memory\n";
268 return false;
269 }
270 status = AudioObjectGetPropertyData(*audioDevice, &propertyAddress, 0, NULL, &size, bufferList);
271 if(kAudioHardwareNoError != status || 0 == bufferList->mNumberBuffers) {
272 if(kAudioHardwareNoError != status)
273 LOG(LOG_LEVEL_ERROR) << MOD_NAME "AudioObjectGetPropertyData (kAudioDevicePropertyStreamConfiguration) failed: " << status << "\n";
274 free(bufferList);
275 return false;
276 }
277 free(bufferList);
278 return true;
279}
280
281void audio_ca_get_device_name(AudioDeviceID dev_id, size_t namebuf_len, char *namebuf)
282{
283 AudioObjectPropertyAddress propertyAddress{};
284 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
285 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
286 propertyAddress.mElement = kAudioObjectPropertyElementMain;
287 propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
288 CFStringRef deviceName = NULL;
289 UInt32 size = sizeof(deviceName);
290 if (OSStatus ret = AudioObjectGetPropertyData(dev_id, &propertyAddress, 0, NULL, &size, &deviceName)) {
291 log_msg(LOG_LEVEL_WARNING, "[CoreAudio] Cannot get device %" PRIu32 " name: %s\n",
292 dev_id, get_osstatus_str(ret));
293 snprintf(namebuf, namebuf_len, "CoreAudio device #%" PRIu32 " (unable to get name)", dev_id);
294 return;
295 }
296 CFStringGetCString(deviceName, namebuf, namebuf_len, kCFStringEncodingMacRoman);
297 CFRelease(deviceName);
298}
299
305void audio_ca_probe(struct device_info **available_devices, int *count, int dir)
306{
307 assert(dir == -1 || dir == 1);
308 *available_devices =
309 (struct device_info *) calloc(1, sizeof(struct device_info));
310 snprintf((*available_devices)[0].dev, sizeof(*available_devices)[0].dev,
311 "");
312 snprintf((*available_devices)[0].name,
313 sizeof(*available_devices)[0].name, "Default CoreAudio %s",
314 dir == -1 ? "capture" : "playback");
315 *count = 1;
316
317 int dev_count;
318 AudioDeviceID *dev_ids;
319 OSStatus ret;
320 UInt32 size;
321 AudioObjectPropertyAddress propertyAddress;
322
323 propertyAddress.mSelector = kAudioHardwarePropertyDevices;
324 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
325 propertyAddress.mElement = kAudioObjectPropertyElementMain;
326 ret = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size);
327 if (ret) {
328 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot get device list size: %s\n", get_osstatus_str(ret));
329 goto error;
330 }
331 dev_ids = (AudioDeviceID *) malloc(size);
332 dev_count = size / sizeof(AudioDeviceID);
333 ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, dev_ids);
334 if (ret) {
335 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot get device list: %s\n", get_osstatus_str(ret));
336 goto error;
337 }
338
339 propertyAddress.mScope = dir == -1 ? kAudioObjectPropertyScopeInput : kAudioObjectPropertyScopeOutput;
340 for (int i = 0; i < dev_count; ++i) {
341 if (dir != 0 && !is_requested_direction(propertyAddress, &dev_ids[i])) {
342 continue;
343 }
344
345 (*count)++;
346 *available_devices = (struct device_info *) realloc(*available_devices, *count * sizeof(struct device_info));
347 memset(&(*available_devices)[*count - 1], 0, sizeof(struct device_info));
348
349 audio_ca_get_device_name(dev_ids[i], sizeof (*available_devices)[*count - 1].name,
350 (char *) (*available_devices)[*count - 1].name);
351 snprintf((*available_devices)[*count - 1].dev, sizeof (*available_devices)[*count - 1].dev,
352 ":%" PRIu32, dev_ids[i]);
353 }
354 free(dev_ids);
355
356 return;
357
358error:
359 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Error obtaining device list.\n";
360}
361
368AudioDeviceID
370{
371 struct device_info *devices = NULL;
372 int count = 0;
373 audio_ca_probe(&devices, &count, dir);
374 for (int i = 0; i < count; ++i) {
375 if (strstr(devices[i].name, name) != NULL) {
376 return atoi(devices[i].dev + 1);
377 }
378 }
379 return UINT_MAX;
380}
381
382static void audio_play_ca_probe(struct device_info **available_devices, int *count, void (**deleter)(void *))
383{
384 *deleter = free;
385 audio_ca_probe(available_devices, count, 1);
386}
387
389{
390 cout << "Core Audio playback usage:\n";
391 col() << SBOLD(SRED("\t-r coreaudio") << "[:<index>|:<name>] "
392 "[--param audio-buffer-len=<len_ms>] [--param audio-disable-adaptive-buffer]") << "\n";
393 col() << "where\n\t" << SBOLD("<name>") << " - device name substring (case sensitive)\n\n";
394 printf("Available CoreAudio playback devices:\n");
395 struct device_info *available_devices;
396 int count;
397 void (*deleter)(void *);
398 audio_play_ca_probe(&available_devices, &count, &deleter);
399
400 for (int i = 0; i < count; ++i) {
401 color_printf("\t" TBOLD("coreaudio%-4s") ": %s\n", available_devices[i].dev, available_devices[i].name);
402 }
403 deleter ? deleter(available_devices) : free(available_devices);
404}
405
406
407static void * audio_play_ca_init(const char *cfg)
408{
409 OSStatus ret = noErr;
410 AudioComponent comp;
411 AudioComponentDescription comp_desc;
412 AudioDeviceID device;
413
414 struct state_ca_playback *s = new struct state_ca_playback();
415
416 if (const char *val = get_commandline_param("audio-buffer-len")) {
417 s->buf_len_ms = atoi(val);
418 if (s->buf_len_ms <= 0 || s->buf_len_ms >= 10000) {
419 LOG(LOG_LEVEL_ERROR) << MOD_NAME "Wrong value \"" << val << "\" given to \"audio-buffer-len\", allowed range (0, 10000).\n";
420 goto error;
421 }
422 }
423
424 //There are several different types of Audio Units.
425 //Some audio units serve as Outputs, Mixers, or DSP
426 //units. See AUComponent.h for listing
427 comp_desc.componentType = kAudioUnitType_Output;
428
429 //Every Component has a subType, which will give a clearer picture
430 //of what this components function will be.
431 //comp_desc.componentSubType = kAudioUnitSubType_DefaultOutput;
432 comp_desc.componentSubType = kAudioUnitSubType_HALOutput;
433
434 //all Audio Units in AUComponent.h must use
435 //"kAudioUnitManufacturer_Apple" as the Manufacturer
436 comp_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
437 comp_desc.componentFlags = 0;
438 comp_desc.componentFlagsMask = 0;
439
440 comp = AudioComponentFindNext(NULL, &comp_desc);
441 if (!comp) {
442 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot find audio component!\n");
443 goto error;
444 }
445 ret = AudioComponentInstanceNew(comp, &s->auHALComponentInstance);
446 if (ret != noErr) {
447 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot open audio component: %s\n", get_osstatus_str(ret));
448 goto error;
449 }
450
451 s->buffer = NULL;
452
453 if ((ret = AudioUnitUninitialize(s->auHALComponentInstance)) != noErr) {
454 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot initialize audio unit: %s\n", get_osstatus_str(ret));
455 goto error;
456 }
457
458 if (strcmp(cfg, "help") == 0) {
460 delete s;
461 return INIT_NOERR;
462 }
463 if (strlen(cfg) > 0) {
464 try {
465 device = stoi(cfg);
466 } catch (std::invalid_argument &e) {
467 device = audio_ca_get_device_by_name(cfg, CA_DIR);
468 if (device == UINT_MAX) {
471 "Wrong device index "
472 "or unrecognized name \"%s\"!\n",
473 cfg);
474 goto error;
475 }
476 }
477 } else {
478 AudioObjectPropertyAddress propertyAddress;
479 UInt32 size = sizeof device;
480 propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
481 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
482 propertyAddress.mElement = kAudioObjectPropertyElementMain;
483 if ((ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, &device)) != noErr) {
484 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot get default audio device: %s\n", get_osstatus_str(ret));
485 goto error;
486 }
487 }
488 char device_name[128];
489 audio_ca_get_device_name(device, sizeof device_name, device_name);
490 log_msg(LOG_LEVEL_INFO, MOD_NAME "Using device: %s\n", device_name);
491
492 if (get_commandline_param("ca-disable-adaptive-buf") == nullptr &&
493 get_commandline_param("audio-disable-adaptive-buffer") == nullptr) {
494 LOG(LOG_LEVEL_WARNING) << MOD_NAME "Using adaptive buffer. "
495 "In case of problems, try \"--param audio-disable-adaptive-buffer\" "
496 "option.\n";
497 }
498
499 ret = AudioUnitSetProperty(s->auHALComponentInstance,
500 kAudioOutputUnitProperty_CurrentDevice,
501 kAudioUnitScope_Global,
502 1,
503 &device,
504 sizeof(device));
505 if (ret) {
506 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot set audio properties: %s\n", get_osstatus_str(ret));
507 goto error;
508 }
509
510 return s;
511
512error:
513 delete s;
514 return NULL;
515}
516
517static void audio_play_ca_put_frame(void *state, const struct audio_frame *frame)
518{
519 struct state_ca_playback *s = (struct state_ca_playback *)state;
520
521 s->buffer_fns->write(s->buffer, frame->data, frame->data_len);
522}
523
524static void audio_play_ca_done(void *state)
525{
526 struct state_ca_playback *s = (struct state_ca_playback *)state;
527
528 if (s->initialized) {
529 AudioOutputUnitStop(s->auHALComponentInstance);
530 AudioUnitUninitialize(s->auHALComponentInstance);
531 }
532 if (s->buffer_fns) {
533 s->buffer_fns->destroy(s->buffer);
534 }
535 delete s;
536}
537
546
548
#define UNUSED(x)
void ** state
int void * val
struct video_desc desc
struct video_frame * frame
int void size_t * len
int void(** deleter)(void *))
This file contains definition of some common audio types.
@ AC_PCM
Definition types.h:53
struct audio_buffer_api audio_buffer_fns
struct audio_buffer * audio_buffer_init(int sample_rate, int bps, int ch_count, int suggested_latency_ms)
#define AUDIO_PLAYBACK_CTL_QUERY_FORMAT
#define AUDIO_PLAYBACK_ABI_VERSION
int color_printf(const char *format,...)
#define SRED(x)
Definition color_out.h:85
#define SBOLD(x)
Definition color_out.h:80
#define TBOLD(x)
Definition color_out.h:70
static OSStatus theRenderProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
Definition coreaudio.cpp:97
static bool audio_play_ca_ctl(void *state, int request, void *data, size_t *len)
static const struct audio_playback_info aplay_coreaudio_info
constexpr int DEFAULT_BUFLEN_MS
Definition coreaudio.cpp:74
void audio_ca_probe(struct device_info **available_devices, int *count, int dir)
static void audio_play_ca_put_frame(void *state, const struct audio_frame *frame)
constexpr int CA_DIR
Definition coreaudio.cpp:75
AudioDeviceID audio_ca_get_device_by_name(const char *name, int dir)
void audio_ca_get_device_name(AudioDeviceID dev_id, size_t namebuf_len, char *namebuf)
static void audio_play_ca_done(void *state)
#define MOD_NAME
Definition coreaudio.cpp:77
#define NO_DATA_STOP_SEC
Definition coreaudio.cpp:76
static bool is_requested_direction(AudioObjectPropertyAddress propertyAddress, AudioDeviceID *audioDevice)
static void audio_play_ca_help()
static void * audio_play_ca_init(const char *cfg)
static bool audio_play_ca_reconfigure(void *state, struct audio_desc desc)
static void audio_play_ca_probe(struct device_info **available_devices, int *count, void(**deleter)(void *))
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG(level)
Definition debug.h:313
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
int count
Definition hd-rum.c:44
const char * get_commandline_param(const char *key)
Definition host.cpp:894
#define ADD_TO_PARAM(param, doc)
Definition host.h:203
#define INIT_NOERR
Definition host.h:73
@ LIBRARY_CLASS_AUDIO_PLAYBACK
Definition lib_common.h:77
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define kAudioObjectPropertyElementMain
Definition macos.h:50
const char * get_osstatus_str(OSStatus err)
Definition macos.m:106
struct audio_buffer_api ring_buffer_fns
struct ring_buffer * ring_buffer_init(int size)
const char * name
Definition settings.cpp:193
int(* read)(void *buf, char *out, int max_len)
void(* write)(void *buf, const char *in, int len)
void(* destroy)(void *buf)
struct used to comunicate with audio capture/playback device
Definition types.h:99
char dev[1024]
Definition types.h:383
struct audio_desc desc
Definition coreaudio.cpp:81
bool quiet
do not report buffer underruns if we do not receive data at all for a long period
Definition coreaudio.cpp:86
AudioComponentInstance auHALComponentInstance
Definition coreaudio.cpp:80
struct audio_buffer_api * buffer_fns
Definition coreaudio.cpp:83
steady_clock::time_point last_audio_read
Definition coreaudio.cpp:85