--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -30,28 +30,22 @@
#include "cubeb_resampler.h"
#include "cubeb_ring_array.h"
#include "cubeb_utils.h"
#include <algorithm>
#include <atomic>
#include <vector>
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
-typedef UInt32 AudioFormatFlags;
+typedef UInt32 AudioFormatFlags;
#endif
#define AU_OUT_BUS 0
#define AU_IN_BUS 1
-#define fieldOffset(type, field) ((size_t) &((type *) 0)->field)
-
-#define PRINT_ERROR_CODE(str, r) do { \
- LOG("System call failed: %s (rv: %d)", str, (int) r); \
- } while(0)
-
const char * DISPATCH_QUEUE_LABEL = "org.mozilla.cubeb";
#ifdef ALOGV
#undef ALOGV
#endif
#define ALOGV(msg, ...) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{LOGV(msg, ##__VA_ARGS__);})
#ifdef ALOG
@@ -67,44 +61,92 @@ const uint32_t SAFE_MAX_LATENCY_FRAMES =
void audiounit_stream_stop_internal(cubeb_stream * stm);
void audiounit_stream_start_internal(cubeb_stream * stm);
static void audiounit_close_stream(cubeb_stream *stm);
static int audiounit_setup_stream(cubeb_stream *stm);
static int audiounit_create_unit(AudioUnit * unit, bool is_input,
const cubeb_stream_params * /* stream_params */,
AudioDeviceID device);
-static cubeb_channel_layout audiounit_get_channel_layout(bool preferred);
extern cubeb_ops const audiounit_ops;
struct cubeb {
cubeb_ops const * ops = &audiounit_ops;
owned_critical_section mutex;
std::atomic<int> active_streams{ 0 };
uint32_t global_latency_frames = 0;
cubeb_device_collection_changed_callback collection_changed_callback = nullptr;
void * collection_changed_user_ptr = nullptr;
/* Differentiate input from output devices. */
cubeb_device_type collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN;
std::vector<AudioObjectID> devtype_device_array;
// The queue is asynchronously deallocated once all references to it are released
dispatch_queue_t serial_queue = dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL);
+ // Current used channel layout
+ cubeb_channel_layout layout;
};
struct auto_array_wrapper {
virtual void push(void * elements, size_t length) = 0;
virtual size_t length() = 0;
virtual void push_silence(size_t length) = 0;
virtual bool pop(size_t length) = 0;
virtual void * data() = 0;
virtual void clear() = 0;
virtual ~auto_array_wrapper() {}
};
+template <typename T>
+struct auto_array_wrapper_impl : public auto_array_wrapper {
+ explicit auto_array_wrapper_impl(uint32_t size)
+ : ar(size)
+ {}
+
+ void push(void * elements, size_t length) override {
+ auto_lock l(lock);
+ ar.push(static_cast<T *>(elements), length);
+ }
+
+ size_t length() override {
+ auto_lock l(lock);
+ return ar.length();
+ }
+
+ void push_silence(size_t length) override {
+ auto_lock l(lock);
+ ar.push_silence(length);
+ }
+
+ bool pop(size_t length) override {
+ auto_lock l(lock);
+ return ar.pop(nullptr, length);
+ }
+
+ // XXX: Taking the lock here is pointless.
+ void * data() override {
+ auto_lock l(lock);
+ return ar.data();
+ }
+
+ void clear() override {
+ auto_lock l(lock);
+ ar.clear();
+ }
+
+ ~auto_array_wrapper_impl() {
+ auto_lock l(lock);
+ ar.clear();
+ }
+
+private:
+ owned_critical_section lock;
+ auto_array<T> ar;
+};
+
class auto_channel_layout
{
public:
auto_channel_layout()
: layout(nullptr)
{
}
@@ -143,68 +185,32 @@ private:
free(layout);
layout = NULL;
}
}
AudioChannelLayout * layout;
};
-template <typename T>
-struct auto_array_wrapper_impl : public auto_array_wrapper {
- explicit auto_array_wrapper_impl(uint32_t size)
- : ar(size)
- {}
-
- void push(void * elements, size_t length) override {
- auto_lock l(lock);
- ar.push(static_cast<T *>(elements), length);
- }
-
- size_t length() override {
- auto_lock l(lock);
- return ar.length();
- }
-
- void push_silence(size_t length) override {
- auto_lock l(lock);
- ar.push_silence(length);
- }
-
- bool pop(size_t length) override {
- auto_lock l(lock);
- return ar.pop(nullptr, length);
- }
-
- // XXX: Taking the lock here is pointless.
- void * data() override {
- auto_lock l(lock);
- return ar.data();
- }
-
- void clear() override {
- auto_lock l(lock);
- ar.clear();
- }
-
- ~auto_array_wrapper_impl() {
- auto_lock l(lock);
- ar.clear();
- }
-
-private:
- owned_critical_section lock;
- auto_array<T> ar;
-};
-
enum io_side {
INPUT,
OUTPUT,
};
+static char const *
+to_string(io_side side)
+{
+ switch (side) {
+ case INPUT:
+ return "input";
+ case OUTPUT:
+ return "output";
+ }
+}
+
struct cubeb_stream {
explicit cubeb_stream(cubeb * context);
cubeb * context;
cubeb_data_callback data_callback = nullptr;
cubeb_state_callback state_callback = nullptr;
cubeb_device_changed_callback device_changed_callback = nullptr;
/* Stream creation parameters */
@@ -373,17 +379,17 @@ audiounit_render_input(cubeb_stream * st
OSStatus r = AudioUnitRender(stm->input_unit,
flags,
tstamp,
bus,
input_frames,
&input_buffer_list);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitRender", r);
+ LOG("AudioUnitRender rv=%d", r);
return r;
}
/* Copy input data in linear buffer. */
stm->input_linear_buffer->push(input_buffer_list.mBuffers[0].mData,
input_frames * stm->input_desc.mChannelsPerFrame);
/* Advance input frame counter. */
@@ -611,17 +617,17 @@ audiounit_get_output_device_id(AudioDevi
r = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&output_device_address,
0,
NULL,
&size,
device_id);
if (r != noErr) {
- PRINT_ERROR_CODE("output_device_id", r);
+ LOG("output_device_id rv=%d", r);
return CUBEB_ERROR;
}
return CUBEB_OK;
}
static int
audiounit_get_input_device_id(AudioDeviceID * device_id)
@@ -796,62 +802,62 @@ audiounit_install_device_changed_callbac
r = audiounit_get_output_device_id(&output_dev_id);
if (r != noErr) {
return CUBEB_ERROR;
}
r = audiounit_add_listener(stm, output_dev_id, kAudioDevicePropertyDataSource,
kAudioDevicePropertyScopeOutput, &audiounit_property_listener_callback);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource", r);
+ LOG("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource rv=%d", r);
return CUBEB_ERROR;
}
/* This event will notify us when the default audio device changes,
* for example when the user plugs in a USB headset and the system chooses it
* automatically as the default, or when another device is chosen in the
* dropdown list. */
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice", r);
+ LOG("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv=%d", r);
return CUBEB_ERROR;
}
}
if (stm->input_unit) {
/* This event will notify us when the data source on the input device changes. */
AudioDeviceID input_dev_id;
r = audiounit_get_input_device_id(&input_dev_id);
if (r != noErr) {
return CUBEB_ERROR;
}
r = audiounit_add_listener(stm, input_dev_id, kAudioDevicePropertyDataSource,
kAudioDevicePropertyScopeInput, &audiounit_property_listener_callback);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource", r);
+ LOG("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource rv=%d", r);
return CUBEB_ERROR;
}
/* This event will notify us when the default input device changes. */
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice", r);
+ LOG("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv=%d", r);
return CUBEB_ERROR;
}
/* Event to notify when the input is going away. */
AudioDeviceID dev = stm->input_device ? stm->input_device :
audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
r = audiounit_add_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
+ LOG("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive rv=%d", r);
return CUBEB_ERROR;
}
}
return CUBEB_OK;
}
static int
@@ -899,17 +905,17 @@ audiounit_uninstall_device_changed_callb
}
/* Event to notify when the input is going away. */
AudioDeviceID dev = stm->input_device ? stm->input_device :
audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
r = audiounit_remove_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
+ LOG("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDeviceIsAlive rv=%d", r);
return CUBEB_ERROR;
}
}
return CUBEB_OK;
}
/* Get the acceptable buffer size (in frames) that this device can work with. */
static int
@@ -934,17 +940,17 @@ audiounit_get_acceptable_latency_range(A
r = AudioObjectGetPropertyData(output_device_id,
&output_device_buffer_size_range,
0,
NULL,
&size,
latency_range);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioObjectGetPropertyData/buffer size range", r);
+ LOG("AudioObjectGetPropertyData/buffer size range rv=%d", r);
return CUBEB_ERROR;
}
return CUBEB_OK;
}
#endif /* !TARGET_OS_IPHONE */
static AudioObjectID
@@ -997,17 +1003,17 @@ audiounit_get_max_channel_count(cubeb *
r = AudioObjectGetPropertyData(output_device_id,
&stream_format_address,
0,
NULL,
&size,
&stream_format);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioObjectPropertyAddress/StreamFormat", r);
+ LOG("AudioObjectPropertyAddress/StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
*max_channels = stream_format.mChannelsPerFrame;
#endif
return CUBEB_OK;
}
@@ -1066,27 +1072,121 @@ audiounit_get_preferred_sample_rate(cube
return CUBEB_ERROR;
}
*rate = static_cast<uint32_t>(fsamplerate);
#endif
return CUBEB_OK;
}
+static cubeb_channel_layout
+audiounit_convert_channel_layout(AudioChannelLayout * layout)
+{
+ if (layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
+ // kAudioChannelLayoutTag_UseChannelBitmap
+ // kAudioChannelLayoutTag_Mono
+ // kAudioChannelLayoutTag_Stereo
+ // ....
+ LOG("Only handle UseChannelDescriptions for now.\n");
+ return CUBEB_LAYOUT_UNDEFINED;
+ }
+
+ cubeb_channel_map cm;
+ cm.channels = layout->mNumberChannelDescriptions;
+ for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) {
+ cm.map[i] = channel_label_to_cubeb_channel(layout->mChannelDescriptions[i].mChannelLabel);
+ }
+
+ return cubeb_channel_map_to_layout(&cm);
+}
+
+static cubeb_channel_layout
+audiounit_get_current_channel_layout(AudioUnit output_unit)
+{
+ OSStatus rv = noErr;
+ UInt32 size = 0;
+ rv = AudioUnitGetPropertyInfo(output_unit,
+ kAudioUnitProperty_AudioChannelLayout,
+ kAudioUnitScope_Output,
+ AU_OUT_BUS,
+ &size,
+ nullptr);
+ if (rv != noErr) {
+ LOG("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout rv=%d", rv);
+ return CUBEB_LAYOUT_UNDEFINED;
+ }
+ assert(size > 0);
+
+ auto_channel_layout layout(size);
+ rv = AudioUnitGetProperty(output_unit,
+ kAudioUnitProperty_AudioChannelLayout,
+ kAudioUnitScope_Output,
+ AU_OUT_BUS,
+ layout.get(),
+ &size);
+ if (rv != noErr) {
+ LOG("AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout rv=%d", rv);
+ return CUBEB_LAYOUT_UNDEFINED;
+ }
+
+ return audiounit_convert_channel_layout(layout.get());
+}
+
+static cubeb_channel_layout
+audiounit_get_preferred_channel_layout()
+{
+ OSStatus rv = noErr;
+ UInt32 size = 0;
+ AudioDeviceID id;
+
+ if (audiounit_get_output_device_id(&id) != CUBEB_OK) {
+ return CUBEB_LAYOUT_UNDEFINED;
+ }
+
+ AudioObjectPropertyAddress adr = { kAudioDevicePropertyPreferredChannelLayout,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster };
+ rv = AudioObjectGetPropertyDataSize(id, &adr, 0, NULL, &size);
+ if (rv != noErr) {
+ return CUBEB_LAYOUT_UNDEFINED;
+ }
+ assert(size > 0);
+
+ auto_channel_layout layout(size);
+ rv = AudioObjectGetPropertyData(id, &adr, 0, NULL, &size, layout.get());
+ if (rv != noErr) {
+ return CUBEB_LAYOUT_UNDEFINED;
+ }
+
+ return audiounit_convert_channel_layout(layout.get());
+}
+
static int
-audiounit_get_preferred_channel_layout(cubeb * /* ctx */, cubeb_channel_layout * layout)
+audiounit_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layout)
{
// The preferred layout is only returned when the connected sound device
// (e.g. ASUS Xonar U7), has preferred layout setting.
// For default output on Mac, there is no preferred channel layout,
// so it might return UNDEFINED.
- // In that case, we should get the channel configuration directly.
- *layout = audiounit_get_channel_layout(true);
+ *layout = audiounit_get_preferred_channel_layout();
+
+ // If the preferred channel layout is UNDEFINED, then we try to access the
+ // current applied channel layout.
if (*layout == CUBEB_LAYOUT_UNDEFINED) {
- *layout = audiounit_get_channel_layout(false);
+ // If we already have at least one cubeb stream, then the current channel
+ // layout must be updated. We can return it directly.
+ if (ctx->active_streams) {
+ return ctx->layout;
+ }
+
+ // If there is no existed stream, then we create a default ouput unit and
+ // use it to get the current used channel layout.
+ AudioUnit output_unit;
+ audiounit_create_unit(&output_unit, false, nullptr, 0);
+ *layout = audiounit_get_current_channel_layout(output_unit);
}
if (*layout == CUBEB_LAYOUT_UNDEFINED) {
return CUBEB_ERROR;
}
return CUBEB_OK;
}
@@ -1150,20 +1250,24 @@ audio_stream_desc_init(AudioStreamBasicD
ss->mBytesPerPacket = ss->mBytesPerFrame * ss->mFramesPerPacket;
ss->mReserved = 0;
return CUBEB_OK;
}
static int
-audiounit_layout_init(AudioUnit * unit,
- io_side side,
- const cubeb_stream_params * stream_params)
+audiounit_set_channel_layout(AudioUnit unit,
+ io_side side,
+ const cubeb_stream_params * stream_params)
{
+ if (side != OUTPUT) {
+ return CUBEB_ERROR;
+ }
+
assert(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
assert(stream_params->channels == CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels);
OSStatus r;
auto_channel_layout layout(sizeof(AudioChannelLayout));
switch (stream_params->layout) {
case CUBEB_LAYOUT_DUAL_MONO:
@@ -1194,45 +1298,59 @@ audiounit_layout_init(AudioUnit * unit,
default:
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_Unknown;
break;
}
// For those layouts that can't be matched to coreaudio's predefined layout,
// we use customized layout.
if (layout.get()->mChannelLayoutTag == kAudioChannelLayoutTag_Unknown) {
- size_t size = fieldOffset(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
+ size_t size = offsetof(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
layout.reset(size);
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
layout.get()->mNumberChannelDescriptions = stream_params->channels;
for (UInt32 i = 0 ; i < stream_params->channels ; ++i) {
layout.get()->mChannelDescriptions[i].mChannelLabel =
cubeb_channel_to_channel_label(CHANNEL_INDEX_TO_ORDER[stream_params->layout][i]);
layout.get()->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
}
}
- r = AudioUnitSetProperty(*unit,
+ r = AudioUnitSetProperty(unit,
kAudioUnitProperty_AudioChannelLayout,
- side == INPUT ? kAudioUnitScope_Output : kAudioUnitScope_Input,
- side == INPUT ? AU_IN_BUS : AU_OUT_BUS,
+ kAudioUnitScope_Input,
+ AU_OUT_BUS,
layout.get(),
layout.size());
if (r != noErr) {
- if (side == INPUT) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_AudioChannelLayout", r);
- } else {
- PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_AudioChannelLayout", r);
- }
+ LOG("AudioUnitSetProperty/%s/kAudioUnitProperty_AudioChannelLayout rv=%d", to_string(side), r);
return CUBEB_ERROR;
}
return CUBEB_OK;
}
+void
+audiounit_layout_init(cubeb_stream * stm, io_side side)
+{
+ // We currently don't support the input layout setting.
+ if (side == INPUT) {
+ return;
+ }
+
+ audiounit_set_channel_layout(stm->output_unit, OUTPUT, &stm->output_stream_params);
+
+ // Update the current used channel layout for the cubeb context.
+ // Notice that this channel layout may be different from the layout we set above,
+ // because OSX doesn't return error when the output device can NOT provide
+ // our desired layout. Thus, we update the layout evertime when the cubeb_stream
+ // is created and use it when we need to mix audio data.
+ stm->context->layout = audiounit_get_current_channel_layout(stm->output_unit);
+}
+
static int
audiounit_create_unit(AudioUnit * unit,
bool is_input,
const cubeb_stream_params * /* stream_params */,
AudioDeviceID device)
{
AudioComponentDescription desc;
AudioComponent comp;
@@ -1262,51 +1380,51 @@ audiounit_create_unit(AudioUnit * unit,
comp = AudioComponentFindNext(NULL, &desc);
if (comp == NULL) {
LOG("Could not find matching audio hardware.");
return CUBEB_ERROR;
}
rv = AudioComponentInstanceNew(comp, unit);
if (rv != noErr) {
- PRINT_ERROR_CODE("AudioComponentInstanceNew", rv);
+ LOG("AudioComponentInstanceNew rv=%d", rv);
return CUBEB_ERROR;
}
if (!use_default_output) {
enable = 1;
rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
is_input ? kAudioUnitScope_Input : kAudioUnitScope_Output,
is_input ? AU_IN_BUS : AU_OUT_BUS, &enable, sizeof(UInt32));
if (rv != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
+ LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO rv=%d", rv);
return CUBEB_ERROR;
}
enable = 0;
rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
is_input ? kAudioUnitScope_Output : kAudioUnitScope_Input,
is_input ? AU_OUT_BUS : AU_IN_BUS, &enable, sizeof(UInt32));
if (rv != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
+ LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO rv=%d", rv);
return CUBEB_ERROR;
}
if (device == 0) {
assert(is_input);
devid = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
} else {
devid = device;
}
rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
is_input ? AU_IN_BUS : AU_OUT_BUS,
&devid, sizeof(AudioDeviceID));
if (rv != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice", rv);
+ LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice rv=%d", rv);
return CUBEB_ERROR;
}
}
return CUBEB_OK;
}
static int
@@ -1341,34 +1459,34 @@ audiounit_clamp_latency(cubeb_stream * s
if (stm->output_unit) {
r = AudioUnitGetProperty(stm->output_unit,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Output,
AU_OUT_BUS,
&output_buffer_size,
&size);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
+ LOG("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize rv=%d", r);
return 0;
}
output_buffer_size = std::max(std::min<uint32_t>(output_buffer_size, SAFE_MAX_LATENCY_FRAMES),
SAFE_MIN_LATENCY_FRAMES);
}
UInt32 input_buffer_size = 0;
if (stm->input_unit) {
r = AudioUnitGetProperty(stm->input_unit,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Input,
AU_IN_BUS,
&input_buffer_size,
&size);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
+ LOG("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize rv=%d", r);
return 0;
}
input_buffer_size = std::max(std::min<uint32_t>(input_buffer_size, SAFE_MAX_LATENCY_FRAMES),
SAFE_MIN_LATENCY_FRAMES);
}
// Every following active streams can only set smaller latency
@@ -1393,26 +1511,26 @@ audiounit_clamp_latency(cubeb_stream * s
* - register a listener for the buffer size property
* - change the property
* - wait until the listener is executed
* - property has changed, remove the listener
* */
static void
buffer_size_changed_callback(void * inClientData,
AudioUnit inUnit,
- AudioUnitPropertyID inPropertyID,
- AudioUnitScope inScope,
- AudioUnitElement inElement)
+ AudioUnitPropertyID inPropertyID,
+ AudioUnitScope inScope,
+ AudioUnitElement inElement)
{
cubeb_stream * stm = (cubeb_stream *)inClientData;
AudioUnit au = inUnit;
AudioUnitScope au_scope = kAudioUnitScope_Input;
AudioUnitElement au_element = inElement;
- const char * au_type = "output";
+ char const * au_type = "output";
if (au == stm->input_unit) {
au_scope = kAudioUnitScope_Output;
au_type = "input";
}
switch (inPropertyID) {
@@ -1441,85 +1559,67 @@ buffer_size_changed_callback(void * inCl
}
static int
audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side side)
{
AudioUnit au = stm->output_unit;
AudioUnitScope au_scope = kAudioUnitScope_Input;
AudioUnitElement au_element = AU_OUT_BUS;
- const char * au_type = "output";
if (side == INPUT) {
au = stm->input_unit;
au_scope = kAudioUnitScope_Output;
au_element = AU_IN_BUS;
- au_type = "input";
}
uint32_t buffer_frames = 0;
UInt32 size = sizeof(buffer_frames);
int r = AudioUnitGetProperty(au,
kAudioDevicePropertyBufferFrameSize,
au_scope,
au_element,
&buffer_frames,
&size);
if (r != noErr) {
- if (side == INPUT) {
- PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
- } else {
- PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
- }
+ LOG("AudioUnitGetProperty/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
return CUBEB_ERROR;
}
if (new_size_frames == buffer_frames) {
- LOG("(%p) No need to update %s buffer size already %u frames", stm, au_type, buffer_frames);
+ LOG("(%p) No need to update %s buffer size already %u frames", stm, to_string(side), buffer_frames);
return CUBEB_OK;
}
r = AudioUnitAddPropertyListener(au,
kAudioDevicePropertyBufferFrameSize,
buffer_size_changed_callback,
stm);
if (r != noErr) {
- if (side == INPUT) {
- PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
- } else {
- PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
- }
+ LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
return CUBEB_ERROR;
}
stm->buffer_size_change_state = false;
r = AudioUnitSetProperty(au,
kAudioDevicePropertyBufferFrameSize,
au_scope,
au_element,
&new_size_frames,
sizeof(new_size_frames));
if (r != noErr) {
- if (side == INPUT) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
- } else {
- PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
- }
+ LOG("AudioUnitSetProperty/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
r = AudioUnitRemovePropertyListenerWithUserData(au,
kAudioDevicePropertyBufferFrameSize,
buffer_size_changed_callback,
stm);
if (r != noErr) {
- if (side == INPUT) {
- PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
- } else {
- PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
- }
+ LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
}
return CUBEB_ERROR;
}
int count = 0;
while (!stm->buffer_size_change_state && count++ < 30) {
struct timespec req, rem;
@@ -1531,30 +1631,26 @@ audiounit_set_buffer_size(cubeb_stream *
LOG("(%p) audiounit_set_buffer_size : wait count = %d", stm, count);
}
r = AudioUnitRemovePropertyListenerWithUserData(au,
kAudioDevicePropertyBufferFrameSize,
buffer_size_changed_callback,
stm);
if (r != noErr) {
- if (side == INPUT) {
- PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
- } else {
- PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
- }
+ LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
return CUBEB_ERROR;
}
if (!stm->buffer_size_change_state && count >= 30) {
LOG("(%p) Error, did not get buffer size change callback ...", stm);
return CUBEB_ERROR;
}
- LOG("(%p) %s buffer size changed to %u frames.", stm, au_type, new_size_frames);
+ LOG("(%p) %s buffer size changed to %u frames.", stm, to_string(side), new_size_frames);
return CUBEB_OK;
}
static int
audiounit_configure_input(cubeb_stream * stm)
{
int r = 0;
UInt32 size;
@@ -1569,17 +1665,17 @@ audiounit_configure_input(cubeb_stream *
size = sizeof(AudioStreamBasicDescription);
r = AudioUnitGetProperty(stm->input_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
AU_IN_BUS,
&input_hw_desc,
&size);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat", r);
+ LOG("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
stm->input_hw_rate = input_hw_desc.mSampleRate;
LOG("(%p) Input device sampling rate: %.2f", stm, stm->input_hw_rate);
/* Set format description according to the input params. */
r = audio_stream_desc_init(&stm->input_desc, &stm->input_stream_params);
if (r != CUBEB_OK) {
@@ -1602,29 +1698,29 @@ audiounit_configure_input(cubeb_stream *
r = AudioUnitSetProperty(stm->input_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
AU_IN_BUS,
&src_desc,
sizeof(AudioStreamBasicDescription));
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat", r);
+ LOG("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
/* Frames per buffer in the input callback. */
r = AudioUnitSetProperty(stm->input_unit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global,
AU_IN_BUS,
&stm->input_buffer_frames,
sizeof(UInt32));
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice", r);
+ LOG("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice rv=%d", r);
return CUBEB_ERROR;
}
// Input only capacity
unsigned int array_capacity = 1;
if (has_output(stm)) {
// Full-duplex increase capacity
array_capacity = 8;
@@ -1639,17 +1735,17 @@ audiounit_configure_input(cubeb_stream *
r = AudioUnitSetProperty(stm->input_unit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
AU_OUT_BUS,
&aurcbs_in,
sizeof(aurcbs_in));
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback", r);
+ LOG("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback rv=%d", r);
return CUBEB_ERROR;
}
LOG("(%p) Input audiounit init successfully.", stm);
return CUBEB_OK;
}
static int
@@ -1676,30 +1772,30 @@ audiounit_configure_output(cubeb_stream
memset(&output_hw_desc, 0, size);
r = AudioUnitGetProperty(stm->output_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
AU_OUT_BUS,
&output_hw_desc,
&size);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioUnitProperty_StreamFormat", r);
+ LOG("AudioUnitGetProperty/output/kAudioUnitProperty_StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
stm->output_hw_rate = output_hw_desc.mSampleRate;
LOG("(%p) Output device sampling rate: %.2f", stm, output_hw_desc.mSampleRate);
r = AudioUnitSetProperty(stm->output_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
AU_OUT_BUS,
&stm->output_desc,
sizeof(AudioStreamBasicDescription));
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat", r);
+ LOG("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
r = audiounit_set_buffer_size(stm, stm->latency_frames, OUTPUT);
if (r != CUBEB_OK) {
LOG("(%p) Error in change output buffer size.", stm);
return CUBEB_ERROR;
}
@@ -1707,35 +1803,35 @@ audiounit_configure_output(cubeb_stream
/* Frames per buffer in the input callback. */
r = AudioUnitSetProperty(stm->output_unit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global,
AU_OUT_BUS,
&stm->latency_frames,
sizeof(UInt32));
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_MaximumFramesPerSlice", r);
+ LOG("AudioUnitSetProperty/output/kAudioUnitProperty_MaximumFramesPerSlice rv=%d", r);
return CUBEB_ERROR;
}
assert(stm->output_unit != NULL);
aurcbs_out.inputProc = audiounit_output_callback;
aurcbs_out.inputProcRefCon = stm;
r = AudioUnitSetProperty(stm->output_unit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
AU_OUT_BUS,
&aurcbs_out,
sizeof(aurcbs_out));
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback", r);
+ LOG("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback rv=%d", r);
return CUBEB_ERROR;
}
- audiounit_layout_init(&stm->output_unit, OUTPUT, &stm->output_stream_params);
+ audiounit_layout_init(stm, OUTPUT);
LOG("(%p) Output audiounit init successfully.", stm);
return CUBEB_OK;
}
static int
audiounit_setup_stream(cubeb_stream * stm)
{
@@ -1867,25 +1963,25 @@ audiounit_setup_stream(cubeb_stream * st
if (!stm->resampler) {
LOG("(%p) Could not create resampler.", stm);
return CUBEB_ERROR;
}
if (stm->input_unit != NULL) {
r = AudioUnitInitialize(stm->input_unit);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitInitialize/input", r);
+ LOG("AudioUnitInitialize/input rv=%d", r);
return CUBEB_ERROR;
}
}
if (stm->output_unit != NULL) {
r = AudioUnitInitialize(stm->output_unit);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitInitialize/output", r);
+ LOG("AudioUnitInitialize/output rv=%d", r);
return CUBEB_ERROR;
}
}
if (stm->input_unit && stm->output_unit) {
// According to the I/O hardware rate it is expected a specific pattern of callbacks
// for example is input is 44100 and output is 48000 we expected no more than 2
// out callback in a row.
@@ -2117,41 +2213,41 @@ audiounit_stream_get_latency(cubeb_strea
size = sizeof(unit_latency_sec);
r = AudioUnitGetProperty(stm->output_unit,
kAudioUnitProperty_Latency,
kAudioUnitScope_Global,
0,
&unit_latency_sec,
&size);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioUnitProperty_Latency", r);
+ LOG("AudioUnitGetProperty/kAudioUnitProperty_Latency rv=%d", r);
return CUBEB_ERROR;
}
size = sizeof(device_latency_frames);
r = AudioObjectGetPropertyData(output_device_id,
&latency_address,
0,
NULL,
&size,
&device_latency_frames);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitGetPropertyData/latency_frames", r);
+ LOG("AudioUnitGetPropertyData/latency_frames rv=%d", r);
return CUBEB_ERROR;
}
size = sizeof(device_safety_offset);
r = AudioObjectGetPropertyData(output_device_id,
&safety_offset_address,
0,
NULL,
&size,
&device_safety_offset);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitGetPropertyData/safety_offset", r);
+ LOG("AudioUnitGetPropertyData/safety_offset rv=%d", r);
return CUBEB_ERROR;
}
/* This part is fixed and depend on the stream parameter and the hardware. */
stm->hw_latency_frames =
static_cast<uint32_t>(unit_latency_sec * stm->output_desc.mSampleRate)
+ device_latency_frames
+ device_safety_offset;
@@ -2168,17 +2264,17 @@ int audiounit_stream_set_volume(cubeb_st
OSStatus r;
r = AudioUnitSetParameter(stm->output_unit,
kHALOutputParam_Volume,
kAudioUnitScope_Global,
0, volume, 0);
if (r != noErr) {
- PRINT_ERROR_CODE("AudioUnitSetParameter/kHALOutputParam_Volume", r);
+ LOG("AudioUnitSetParameter/kHALOutputParam_Volume rv=%d", r);
return CUBEB_ERROR;
}
return CUBEB_OK;
}
int audiounit_stream_set_panning(cubeb_stream * stm, float panning)
{
if (stm->output_desc.mChannelsPerFrame > 2) {
@@ -2524,17 +2620,17 @@ audiounit_create_device_from_hwdev(Audio
latency = audiounit_get_device_presentation_latency(devid, adr.mScope);
adr.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
size = sizeof(AudioValueRange);
if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &range) == noErr) {
ret->latency_lo = latency + range.mMinimum;
ret->latency_hi = latency + range.mMaximum;
} else {
- ret->latency_lo = 10 * ret->default_rate / 1000; /* Default to 10ms */
+ ret->latency_lo = 10 * ret->default_rate / 1000; /* Default to 10ms */
ret->latency_hi = 100 * ret->default_rate / 1000; /* Default to 100ms */
}
return ret;
}
static int
audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
@@ -2717,79 +2813,16 @@ int audiounit_register_device_collection
collection_changed_callback,
user_ptr);
} else {
ret = audiounit_remove_device_listener(context);
}
return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR;
}
-static cubeb_channel_layout
-audiounit_get_channel_layout(bool preferred)
-{
- OSStatus rv = noErr;
-
- // Get the default ouput unit
- AudioUnit output_unit;
- audiounit_create_unit(&output_unit, false, nullptr, 0);
-
- // Get the channel layout
- UInt32 size = 0;
- rv = AudioUnitGetPropertyInfo(output_unit,
- preferred ? kAudioDevicePropertyPreferredChannelLayout :
- kAudioUnitProperty_AudioChannelLayout,
- kAudioUnitScope_Output,
- AU_OUT_BUS,
- &size,
- nullptr);
- if (rv != noErr) {
- if (preferred) {
- PRINT_ERROR_CODE("AudioUnitGetPropertyInfo/kAudioDevicePropertyPreferredChannelLayout", rv);
- } else {
- PRINT_ERROR_CODE("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout", rv);
- }
- return CUBEB_LAYOUT_UNDEFINED;
- }
- assert(size > 0);
-
- auto_channel_layout layout(size);
- rv = AudioUnitGetProperty(output_unit,
- preferred ? kAudioDevicePropertyPreferredChannelLayout :
- kAudioUnitProperty_AudioChannelLayout,
- kAudioUnitScope_Output,
- AU_OUT_BUS,
- layout.get(),
- &size);
- if (rv != noErr) {
- if (preferred) {
- PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioDevicePropertyPreferredChannelLayout", rv);
- } else {
- PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout", rv);
- }
- return CUBEB_LAYOUT_UNDEFINED;
- }
-
- if (layout.get()->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
- // kAudioChannelLayoutTag_UseChannelBitmap
- // kAudioChannelLayoutTag_Mono
- // kAudioChannelLayoutTag_Stereo
- // ....
- LOG("Only handle UseChannelDescriptions for now.\n");
- return CUBEB_LAYOUT_UNDEFINED;
- }
-
- cubeb_channel_map cm;
- cm.channels = layout.get()->mNumberChannelDescriptions;
- for (UInt32 i = 0; i < layout.get()->mNumberChannelDescriptions; ++i) {
- cm.map[i] = channel_label_to_cubeb_channel(layout.get()->mChannelDescriptions[i].mChannelLabel);
- }
-
- return cubeb_channel_map_to_layout(&cm);
-}
-
cubeb_ops const audiounit_ops = {
/*.init =*/ audiounit_init,
/*.get_backend_id =*/ audiounit_get_backend_id,
/*.get_max_channel_count =*/ audiounit_get_max_channel_count,
/*.get_min_latency =*/ audiounit_get_min_latency,
/*.get_preferred_sample_rate =*/ audiounit_get_preferred_sample_rate,
/*.get_preferred_channel_layout =*/ audiounit_get_preferred_channel_layout,
/*.enumerate_devices =*/ audiounit_enumerate_devices,