#include <glibmm.h>
#include "coreaudio_pcmio.h"
+using namespace ARDOUR;
+
+/* abstraction for deprecated CoreAudio */
+
+static OSStatus GetPropertyWrapper (
+ AudioDeviceID id, UInt32 elem, bool input, AudioDevicePropertyID prop, UInt32* size, void * data)
+{
+#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress property_address;
+ property_address.mSelector = prop;
+ switch (prop) {
+ case kAudioDevicePropertyBufferFrameSize:
+ case kAudioDevicePropertyBufferFrameSizeRange:
+ property_address.mScope = kAudioObjectPropertyScopeGlobal;
+ break;
+ default:
+ property_address.mScope = input ? kAudioDevicePropertyScopeInput: kAudioDevicePropertyScopeOutput;
+ break;
+ }
+ property_address.mElement = kAudioObjectPropertyElementMaster;
+ return AudioObjectGetPropertyData(id, &property_address, elem, NULL, size, data);
+#else
+ return AudioDeviceGetProperty(id, elem, input, prop, size, data);
+#endif
+}
+
+static OSStatus SetPropertyWrapper (
+ AudioDeviceID id, const AudioTimeStamp* when, UInt32 chn, bool input, AudioDevicePropertyID prop, UInt32 size, void * data)
+{
+#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress property_address;
+ property_address.mSelector = prop;
+ property_address.mScope = input ? kAudioDevicePropertyScopeInput: kAudioDevicePropertyScopeOutput;
+ property_address.mElement = kAudioObjectPropertyElementMaster;
+ return AudioObjectSetPropertyData (id, &property_address, 0, NULL, size, data);
+#else
+ return AudioDeviceSetProperty (id, when, chn, input, prop, size, data);
+#endif
+}
+
+static OSStatus GetHardwarePropertyInfoWrapper (AudioDevicePropertyID prop, UInt32* size)
+{
+#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress property_address;
+ property_address.mSelector = prop;
+ property_address.mScope = kAudioObjectPropertyScopeGlobal;
+ property_address.mElement = kAudioObjectPropertyElementMaster;
+ return AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &property_address, 0, NULL, size);
+#else
+ Boolean outWritable;
+ return AudioHardwareGetPropertyInfo(prop, size, &outWritable);
+#endif
+}
+
+static OSStatus GetHardwarePropertyWrapper (AudioDevicePropertyID prop, UInt32* size, void *d)
+{
+#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress property_address;
+ property_address.mSelector = prop;
+ property_address.mScope = kAudioObjectPropertyScopeGlobal;
+ property_address.mElement = kAudioObjectPropertyElementMaster;
+ return AudioObjectGetPropertyData(kAudioObjectSystemObject, &property_address, 0, NULL, size, d);
+#else
+ return AudioHardwareGetProperty (prop, size, d);
+#endif
+}
+
+static OSStatus GetPropertyInfoWrapper (AudioDeviceID id, UInt32 elem, bool input, AudioDevicePropertyID prop, UInt32* size)
+{
+#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress property_address;
+ property_address.mSelector = prop;
+ property_address.mScope = input ? kAudioDevicePropertyScopeInput: kAudioDevicePropertyScopeOutput;
+ property_address.mElement = elem;
+ return AudioObjectGetPropertyDataSize(id, &property_address, 0, NULL, size);
+#else
+ Boolean outWritable;
+ return AudioDeviceGetPropertyInfo(id, elem, input, prop, size, &outWritable);
+#endif
+}
+
+static OSStatus GetDeviceNameFromID(AudioDeviceID id, char* name)
+{
+ UInt32 size = 256;
+ return GetPropertyWrapper (id, 0, 0, kAudioDevicePropertyDeviceName, &size, name);
+}
+
+static CFStringRef GetDeviceName(AudioDeviceID id)
+{
+ UInt32 size = sizeof(CFStringRef);
+ CFStringRef UIname;
+ OSStatus err = GetPropertyWrapper (id, 0, 0, kAudioDevicePropertyDeviceUID, &size, &UIname);
+ return (err == noErr) ? UIname : NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "coreaudio_pcmio_aggregate.cc"
+
+/* callbacks */
+
#ifdef COREAUDIO_108
-static OSStatus hardwarePropertyChangeCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) {
+
+static OSStatus property_callback_ptr (AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) {
CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
- self->hwPropertyChange();
+ for (UInt32 i = 0; i < inNumberAddresses; ++i) {
+ switch (inAddresses[i].mSelector) {
+ case kAudioHardwarePropertyDevices:
+ self->hw_changed_callback();
+ break;
+ case kAudioDeviceProcessorOverload:
+ self->xrun_callback();
+ break;
+ case kAudioDevicePropertyBufferFrameSize:
+ self->buffer_size_callback();
+ break;
+ case kAudioDevicePropertyNominalSampleRate:
+ self->sample_rate_callback();
+ break;
+ default:
+ break;
+ }
+ }
return noErr;
}
+
#else
-static OSStatus hardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* arg) {
+
+static OSStatus hw_changed_callback_ptr (AudioHardwarePropertyID inPropertyID, void* arg) {
if (inPropertyID == kAudioHardwarePropertyDevices) {
CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
- self->hwPropertyChange();
+ self->hw_changed_callback();
}
return noErr;
}
+
+static OSStatus property_callback_ptr (
+ AudioDeviceID inDevice,
+ UInt32 inChannel,
+ Boolean isInput,
+ AudioDevicePropertyID inPropertyID,
+ void* inClientData)
+{
+ CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inClientData);
+ switch (inPropertyID) {
+ case kAudioDeviceProcessorOverload:
+ d->xrun_callback();
+ break;
+ case kAudioDevicePropertyBufferFrameSize:
+ d->buffer_size_callback();
+ break;
+ case kAudioDevicePropertyNominalSampleRate:
+ d->sample_rate_callback();
+ break;
+ }
+ return noErr;
+}
+
+#endif
+
+static OSStatus render_callback_ptr (
+ void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData)
+{
+ CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inRefCon);
+ return d->render_callback(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
+}
+
+
+static OSStatus add_listener (AudioDeviceID id, AudioDevicePropertyID selector, void *arg) {
+#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress property_address;
+ property_address.mSelector = selector;
+ property_address.mScope = kAudioObjectPropertyScopeGlobal;
+ property_address.mElement = 0;
+ return AudioObjectAddPropertyListener(id, &property_address, property_callback_ptr, arg);
+#else
+ return AudioDeviceAddPropertyListener(id, 0, true, selector, property_callback_ptr, arg);
#endif
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
CoreAudioPCM::CoreAudioPCM ()
: _auhal (0)
, _device_ids (0)
, _input_audio_buffer_list (0)
+ , _active_device_id (0)
+ , _aggregate_device_id (0)
+ , _aggregate_plugin_id (0)
, _state (-1)
, _capture_channels (0)
, _playback_channels (0)
, _process_callback (0)
, _error_callback (0)
, _hw_changed_callback (0)
+ , _xrun_callback (0)
+ , _buffer_size_callback (0)
+ , _sample_rate_callback (0)
, _device_ins (0)
, _device_outs (0)
{
AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioHardwarePropertyDevices };
AudioObjectSetPropertyData (kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
- AudioObjectPropertyAddress prop;
- prop.mSelector = kAudioHardwarePropertyDevices;
- prop.mScope = kAudioObjectPropertyScopeGlobal;
- prop.mElement = 0;
- AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, hardwarePropertyChangeCallback, this);
+ property.mSelector = kAudioHardwarePropertyDevices;
+ property.mScope = kAudioObjectPropertyScopeGlobal;
+ property.mElement = 0;
+ AudioObjectAddPropertyListener(kAudioObjectSystemObject, &property, property_callback_ptr, this);
#else
- AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, hardwarePropertyChangeCallback, this);
+ AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, hw_changed_callback_ptr, this);
#endif
}
prop.mSelector = kAudioHardwarePropertyDevices;
prop.mScope = kAudioObjectPropertyScopeGlobal;
prop.mElement = 0;
- AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &hardwarePropertyChangeCallback, this);
+ AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &property_callback_ptr, this);
#else
- AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, hardwarePropertyChangeCallback);
+ AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, hw_changed_callback_ptr);
#endif
free(_input_audio_buffer_list);
pthread_mutex_destroy (&_discovery_lock);
void
-CoreAudioPCM::hwPropertyChange() {
+CoreAudioPCM::hw_changed_callback() {
+#ifndef NDEBUG
+ printf("CoreAudio HW change..\n");
+#endif
discover();
- // TODO Filter events..
if (_hw_changed_callback) {
_hw_changed_callback(_hw_changed_arg);
}
return -1;
}
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
- property_address.mScope = kAudioDevicePropertyScopeOutput;
- property_address.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectGetPropertyDataSize(_device_ids[device_id], &property_address, 0, NULL, &size);
-#else
- err = AudioDeviceGetPropertyInfo(_device_ids[device_id], 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &size, NULL);
-#endif
+ err = GetPropertyInfoWrapper (_device_ids[device_id], 0, false, kAudioDevicePropertyAvailableNominalSampleRates, &size);
if (err != kAudioHardwareNoError) {
return -1;
}
- int numRates = size / sizeof(AudioValueRange);
+ uint32_t numRates = size / sizeof(AudioValueRange);
AudioValueRange* supportedRates = new AudioValueRange[numRates];
-#ifdef COREAUDIO_108
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, supportedRates);
-#else
- err = AudioDeviceGetProperty(_device_ids[device_id], 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &size, supportedRates);
-#endif
+ err = GetPropertyWrapper (_device_ids[device_id], 0, false, kAudioDevicePropertyAvailableNominalSampleRates, &size, supportedRates);
if (err != kAudioHardwareNoError) {
delete [] supportedRates;
AudioValueRange supportedRange;
size = sizeof (AudioValueRange);
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &supportedRange);
-#else
- err = AudioDeviceGetProperty(_device_ids[device_id], 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &size, &supportedRange);
-#endif
-
- if (err != kAudioHardwareNoError) {
+ err = GetPropertyWrapper (_device_ids[device_id], 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &size, &supportedRange);
+ if (err != noErr) {
return -1;
}
}
/* query number of inputs */
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyStreamConfiguration;
- property_address.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
- err = AudioObjectGetPropertyDataSize(_device_ids[device_id], &property_address, 0, NULL, &size);
- if (kAudioHardwareNoError != err) {
- fprintf(stderr, "CoreaAudioPCM: kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
- return 0;
- }
-
- bufferList = (AudioBufferList *)(malloc(size));
- assert(bufferList);
- if (!bufferList) { fprintf(stderr, "OUT OF MEMORY\n"); return 0; }
-
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, bufferList);
-
-#else
- err = AudioDeviceGetPropertyInfo (_device_ids[device_id], 0, input ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT, kAudioDevicePropertyStreamConfiguration, &size, NULL);
+ err = GetPropertyInfoWrapper (_device_ids[device_id], 0, input, kAudioDevicePropertyStreamConfiguration, &size);
if (kAudioHardwareNoError != err) {
- fprintf(stderr, "CoreaAudioPCM: kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
+ fprintf(stderr, "CoreaAudioPCM: kAudioDevicePropertyStreamConfiguration failed\n");
return 0;
}
bufferList = (AudioBufferList *)(malloc(size));
assert(bufferList);
if (!bufferList) { fprintf(stderr, "OUT OF MEMORY\n"); return 0; }
-
bufferList->mNumberBuffers = 0;
- err = AudioDeviceGetProperty(_device_ids[device_id], 0, input ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT, kAudioDevicePropertyStreamConfiguration, &size, bufferList);
-#endif
+ err = GetPropertyWrapper (_device_ids[device_id], 0, input, kAudioDevicePropertyStreamConfiguration, &size, bufferList);
if(kAudioHardwareNoError != err) {
- fprintf(stderr, "CoreaAudioPCM: kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
+ fprintf(stderr, "CoreaAudioPCM: kAudioDevicePropertyStreamConfiguration failed\n");
free(bufferList);
return 0;
}
}
void
-CoreAudioPCM::get_stream_latencies(uint32 device_id, bool input, std::vector<uint32>& latencies)
+CoreAudioPCM::get_stream_latencies(uint32_t device_id, bool input, std::vector<uint32_t>& latencies)
{
OSStatus err;
UInt32 size = 0;
return;
}
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyStreams;
- property_address.mScope = input ? kAudioDevicePropertyScopeInput: kAudioDevicePropertyScopeOutput;
- property_address.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectGetPropertyDataSize(_device_ids[device_id], &property_address, 0, NULL, &size);
-#else
- Boolean outWritable;
- const int elem = input ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT;
- err = AudioDeviceGetPropertyInfo(_device_ids[device_id], 0, elem, kAudioDevicePropertyStreams, &size, &outWritable);
-#endif
- if (err != noErr) {
- return;
- }
+ err = GetPropertyInfoWrapper (_device_ids[device_id], 0, input, kAudioDevicePropertyStreams, &size);
+ if (err != noErr) { return; }
- uint32 stream_count = size / sizeof(UInt32);
+ uint32_t stream_count = size / sizeof(UInt32);
AudioStreamID streamIDs[stream_count];
-#ifdef COREAUDIO_108
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &streamIDs);
-#else
- err = AudioDeviceGetProperty(_device_ids[device_id], 0, elem, kAudioDevicePropertyStreams, &size, streamIDs);
-#endif
+ err = GetPropertyWrapper (_device_ids[device_id], 0, input, kAudioDevicePropertyStreams, &size, &streamIDs);
if (err != noErr) {
fprintf(stderr, "GetStreamLatencies kAudioDevicePropertyStreams\n");
return;
}
- for (uint32 i = 0; i < stream_count; i++) {
+ for (uint32_t i = 0; i < stream_count; i++) {
UInt32 stream_latency;
size = sizeof(UInt32);
#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress property_address;
property_address.mSelector = kAudioDevicePropertyStreams;
+ property_address.mScope = input ? kAudioDevicePropertyScopeInput: kAudioDevicePropertyScopeOutput;
+ property_address.mElement = i; // ??
err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &stream_latency);
#else
- err = AudioStreamGetProperty(streamIDs[i], elem, kAudioStreamPropertyLatency, &size, &stream_latency);
+ err = AudioStreamGetProperty(streamIDs[i], input, kAudioStreamPropertyLatency, &size, &stream_latency);
#endif
if (err != noErr) {
fprintf(stderr, "GetStreamLatencies kAudioStreamPropertyLatency\n");
return;
}
#ifndef NDEBUG
- printf("Stream %d latency: %d\n", i, stream_latency);
+ printf(" ^ Stream %u latency: %u\n", (unsigned int)i, (unsigned int)stream_latency);
#endif
latencies.push_back(stream_latency);
}
}
uint32_t
-CoreAudioPCM::get_latency(uint32 device_id, bool input)
+CoreAudioPCM::get_latency(uint32_t device_id, bool input)
{
OSStatus err;
- uint32 latency = 0;
+ uint32_t latency = 0;
UInt32 size = sizeof(UInt32);
UInt32 lat0 = 0;
UInt32 latS = 0;
return 0;
}
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyLatency;
- property_address.mScope = input? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
- property_address.mElement = 0;
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &lat0);
-#else
- const int elem = input ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT;
- err = AudioDeviceGetProperty(_device_ids[device_id], 0, elem, kAudioDevicePropertyLatency, &size, &lat0);
-#endif
+ err = GetPropertyWrapper (_device_ids[device_id], 0, input, kAudioDevicePropertyLatency, &size, &lat0);
if (err != kAudioHardwareNoError) {
fprintf(stderr, "GetLatency kAudioDevicePropertyLatency\n");
}
-#ifdef COREAUDIO_108
- property_address.mSelector = kAudioDevicePropertySafetyOffset;
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &latS);
-#else
- err = AudioDeviceGetProperty(_device_ids[device_id], 0, elem, kAudioDevicePropertySafetyOffset, &size, &latS);
-#endif
+ err = GetPropertyWrapper (_device_ids[device_id], 0, input, kAudioDevicePropertySafetyOffset, &size, &latS);
if (err != kAudioHardwareNoError) {
fprintf(stderr, "GetLatency kAudioDevicePropertySafetyOffset\n");
}
#ifndef NDEBUG
- printf("Base Latency systemic+safetyoffset = %d+%d\n", lat0, latS);
+ printf("%s Latency systemic+safetyoffset = %u + %u\n",
+ input ? "Input" : "Output", (unsigned int)lat0, (unsigned int)latS);
#endif
latency = lat0 + latS;
uint32_t max_stream_latency = 0;
- std::vector<uint32> stream_latencies;
+ std::vector<uint32_t> stream_latencies;
get_stream_latencies(device_id, input, stream_latencies);
for (size_t i = 0; i < stream_latencies.size(); ++i) {
max_stream_latency = std::max(max_stream_latency, stream_latencies[i]);
return latency;
}
+uint32_t
+CoreAudioPCM::get_latency(bool input)
+{
+ if (_active_device_id == 0) {
+ return 0;
+ }
+ return get_latency (_active_device_id, input);
+}
+uint32_t
+CoreAudioPCM::current_buffer_size_id(AudioDeviceID id) {
+ UInt32 buffer_size;
+ UInt32 size = sizeof(UInt32);
+ OSStatus err;
+ err = GetPropertyWrapper (id, 0, 0, kAudioDevicePropertyBufferFrameSize, &size, &buffer_size);
+ if (err != noErr) {
+ return _samples_per_period;
+ }
+ return buffer_size;
+}
float
-CoreAudioPCM::current_sample_rate(uint32 device_id, bool input) {
+CoreAudioPCM::current_sample_rate_id(AudioDeviceID id, bool input) {
OSStatus err;
UInt32 size = 0;
-
- if (device_id >= _n_devices) {
- return -1;
- }
-
- float sample_rate = 0;
-
Float64 rate;
size = sizeof (rate);
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyNominalSampleRate;
- property_address.mScope = input ? kAudioDevicePropertyScopeInput: kAudioDevicePropertyScopeOutput;
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &rate);
-#else
- err = AudioDeviceGetPropertyInfo(_device_ids[device_id], 0, input ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT, kAudioDevicePropertyNominalSampleRate, &size, &rate);
-#endif
-
- if (err == kAudioHardwareNoError) {
- sample_rate = rate;
+ err = GetPropertyWrapper(id, 0, input, kAudioDevicePropertyNominalSampleRate, &size, &rate);
+ if (err == noErr) {
+ return rate;
}
+ return 0;
+}
- // prefer input, if vailable
-
-#ifdef COREAUDIO_108
- property_address.mSelector = kAudioDevicePropertyNominalSampleRate;
- property_address.mScope = kAudioDevicePropertyScopeInput;
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &rate);
-#else
- err = AudioDeviceGetPropertyInfo(_device_ids[device_id], 0, AUHAL_INPUT_ELEMENT, kAudioDevicePropertyNominalSampleRate, &size, &rate);
-#endif
-
- if (err == kAudioHardwareNoError) {
- sample_rate = rate;
+float
+CoreAudioPCM::current_sample_rate(uint32_t device_id, bool input) {
+ if (device_id >= _n_devices) {
+ return -1;
}
+ return current_sample_rate_id(_device_ids[device_id], input);
+}
- return sample_rate;
+float
+CoreAudioPCM::sample_rate() {
+ if (_active_device_id == 0) {
+ return 0;
+ }
+ return current_sample_rate_id(_active_device_id, _playback_channels > 0 ? false : true);
}
int
-CoreAudioPCM::set_device_sample_rate (uint32 device_id, float rate, bool input)
+CoreAudioPCM::set_device_sample_rate_id (AudioDeviceID id, float rate, bool input)
{
std::vector<int>::iterator intIter;
OSStatus err;
UInt32 size = 0;
- if (current_sample_rate(device_id, input) == rate) {
+ if (current_sample_rate_id(id, input) == rate) {
return 0;
}
Float64 newNominalRate = rate;
size = sizeof (Float64);
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyNominalSampleRate;
- property_address.mScope = input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
- property_address.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectSetPropertyData (_device_ids[device_id], &property_address, 0, NULL, size, &newNominalRate);
-#else
- err = AudioDeviceSetProperty(_device_ids[device_id], NULL, 0, input ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT, kAudioDevicePropertyNominalSampleRate, size, &newNominalRate);
-#endif
+ err = SetPropertyWrapper(id, NULL, 0, input, kAudioDevicePropertyNominalSampleRate, size, &newNominalRate);
if (err != noErr) {
fprintf(stderr, "CoreAudioPCM: failed to set samplerate\n");
return 0;
int timeout = 3000; // 3 sec
while (--timeout > 0) {
- if (current_sample_rate(device_id) == rate) {
+ if (current_sample_rate_id(id, input) == rate) {
break;
}
Glib::usleep (1000);
return 0;
}
+int
+CoreAudioPCM::set_device_sample_rate (uint32_t device_id, float rate, bool input)
+{
+ if (device_id >= _n_devices) {
+ return 0;
+ }
+ return set_device_sample_rate_id(_device_ids[device_id], rate, input);
+}
+
void
CoreAudioPCM::discover()
{
}
_devices.clear();
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioHardwarePropertyDevices;
- property_address.mScope = kAudioObjectPropertyScopeGlobal;
- property_address.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &property_address, 0, NULL, &size);
-#else
- err = AudioHardwareGetPropertyInfo (kAudioHardwarePropertyDevices, &size, NULL);
-#endif
+ err = GetHardwarePropertyInfoWrapper (kAudioHardwarePropertyDevices, &size);
_n_devices = size / sizeof (AudioDeviceID);
size = _n_devices * sizeof (AudioDeviceID);
return;
}
-
-#ifdef COREAUDIO_108
- property_address.mSelector = kAudioHardwarePropertyDevices;
- err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property_address, 0, NULL, &size, _device_ids);
-#else
- err = AudioHardwareGetProperty (kAudioHardwarePropertyDevices, &size, _device_ids);
-#endif
+ err = GetHardwarePropertyWrapper (kAudioHardwarePropertyDevices, &size, _device_ids);
for (size_t idx = 0; idx < _n_devices; ++idx) {
size = 64;
char deviceName[64];
-#ifdef COREAUDIO_108
- property_address.mSelector = kAudioDevicePropertyDeviceName;
- property_address.mScope = kAudioDevicePropertyScopeOutput;
- err = AudioObjectGetPropertyData(_device_ids[idx], &property_address, 0, NULL, &size, deviceName);
-#else
- err = AudioDeviceGetProperty(_device_ids[idx], 0, 0, kAudioDevicePropertyDeviceName, &size, deviceName);
-#endif
+ err = GetPropertyWrapper (_device_ids[idx], 0, 0, kAudioDevicePropertyDeviceName, &size, deviceName);
if (kAudioHardwareNoError != err) {
- fprintf(stderr, "CoreAudioPCM: device name query failed: %i\n", err);
+ fprintf(stderr, "CoreAudioPCM: device name query failed\n");
continue;
}
_device_ins[idx] = inputChannelCount;
_device_outs[idx] = outputChannelCount;
#ifndef NDEBUG
- printf("CoreAudio Device: #%ld '%s' in:%d out:%d\n", idx, deviceName, inputChannelCount, outputChannelCount);
+ printf("CoreAudio Device: #%ld (id:%lu) '%s' in:%u out:%u\n", idx,
+ (long unsigned int)_device_ids[idx],
+ deviceName,
+ (unsigned int)inputChannelCount, (unsigned int)outputChannelCount);
#endif
- if (outputChannelCount > 0 && inputChannelCount > 0) {
+ if (outputChannelCount > 0 || inputChannelCount > 0) {
_devices.insert (std::pair<size_t, std::string> (idx, dn));
}
+ if (inputChannelCount > 0) {
+ _input_devices.insert (std::pair<size_t, std::string> (idx, dn));
+ }
+ if (outputChannelCount > 0) {
+ _output_devices.insert (std::pair<size_t, std::string> (idx, dn));
+ }
+ if (outputChannelCount > 0 && inputChannelCount > 0) {
+ _duplex_devices.insert (std::pair<size_t, std::string> (idx, dn));
+ }
}
}
pthread_mutex_unlock (&_discovery_lock);
}
+void
+CoreAudioPCM::xrun_callback ()
+{
+#ifndef NDEBUG
+ printf("Coreaudio XRUN\n");
+#endif
+ if (_xrun_callback) {
+ _xrun_callback(_xrun_arg);
+ }
+}
+
+void
+CoreAudioPCM::buffer_size_callback ()
+{
+ _samples_per_period = current_buffer_size_id(_active_device_id);
+
+ if (_buffer_size_callback) {
+ _buffer_size_callback(_buffer_size_arg);
+ }
+}
+
+void
+CoreAudioPCM::sample_rate_callback ()
+{
+#ifndef NDEBUG
+ printf("Sample Rate Changed!\n");
+#endif
+ if (_sample_rate_callback) {
+ _sample_rate_callback(_sample_rate_arg);
+ }
+}
+
void
CoreAudioPCM::pcm_stop ()
{
if (!_auhal) return;
AudioOutputUnitStop(_auhal);
+ if (_state == 0) {
+#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress prop;
+ prop.mScope = kAudioObjectPropertyScopeGlobal;
+ prop.mElement = 0;
+ if (_active_device_id > 0) {
+ prop.mSelector = kAudioDeviceProcessorOverload;
+ AudioObjectRemovePropertyListener(_active_device_id, &prop, &property_callback_ptr, this);
+ prop.mSelector = kAudioDevicePropertyBufferFrameSize;
+ AudioObjectRemovePropertyListener(_active_device_id, &prop, &property_callback_ptr, this);
+ prop.mSelector = kAudioDevicePropertyNominalSampleRate;
+ AudioObjectRemovePropertyListener(_active_device_id, &prop, &property_callback_ptr, this);
+ }
+#else
+ if (_active_device_id > 0) {
+ AudioDeviceRemovePropertyListener(_active_device_id, 0, true, kAudioDeviceProcessorOverload, property_callback_ptr);
+ AudioDeviceRemovePropertyListener(_active_device_id, 0, true, kAudioDevicePropertyBufferFrameSize, property_callback_ptr);
+ AudioDeviceRemovePropertyListener(_active_device_id, 0, true, kAudioDevicePropertyNominalSampleRate, property_callback_ptr);
+ }
+#endif
+ }
+ if (_aggregate_plugin_id) {
+ destroy_aggregate_device();
+ discover();
+ }
+
AudioUnitUninitialize(_auhal);
#ifdef COREAUDIO_108
AudioComponentInstanceDispose(_auhal);
_state = -1;
_capture_channels = 0;
_playback_channels = 0;
+ _aggregate_plugin_id = 0;
+ _aggregate_device_id = 0;
+ _active_device_id = 0;
free(_input_audio_buffer_list);
_input_audio_buffer_list = 0;
_error_callback = 0;
_process_callback = 0;
+ _xrun_callback = 0;
}
#ifndef NDEBUG
static void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
{
printf ("- - - - - - - - - - - - - - - - - - - -\n");
- printf (" Sample Rate:%f", inDesc->mSampleRate);
- printf (" Format ID:%.*s\n", (int)sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
- printf (" Format Flags:%X\n", inDesc->mFormatFlags);
- printf (" Bytes per Packet:%d\n", inDesc->mBytesPerPacket);
- printf (" Frames per Packet:%d\n", inDesc->mFramesPerPacket);
- printf (" Bytes per Frame:%d\n", inDesc->mBytesPerFrame);
- printf (" Channels per Frame:%d\n", inDesc->mChannelsPerFrame);
- printf (" Bits per Channel:%d\n", inDesc->mBitsPerChannel);
+ printf (" Sample Rate:%.2f", inDesc->mSampleRate);
+ printf (" Format ID:%.*s\n", (int)sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
+ printf (" Format Flags:%X\n", (unsigned int)inDesc->mFormatFlags);
+ printf (" Bytes per Packet:%d\n", (int)inDesc->mBytesPerPacket);
+ printf (" Frames per Packet:%d\n", (int)inDesc->mFramesPerPacket);
+ printf (" Bytes per Frame:%d\n", (int)inDesc->mBytesPerFrame);
+ printf (" Channels per Frame:%d\n", (int)inDesc->mChannelsPerFrame);
+ printf (" Bits per Channel:%d\n", (int)inDesc->mBitsPerChannel);
printf ("- - - - - - - - - - - - - - - - - - - -\n");
}
#endif
-static OSStatus render_callback_ptr (
- void* inRefCon,
- AudioUnitRenderActionFlags* ioActionFlags,
- const AudioTimeStamp* inTimeStamp,
- UInt32 inBusNumber,
- UInt32 inNumberFrames,
- AudioBufferList* ioData)
+int
+CoreAudioPCM::set_device_buffer_size_id (AudioDeviceID id, uint32_t samples_per_period)
{
- CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inRefCon);
- return d->render_callback(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
+ OSStatus err;
+ UInt32 uint32val;
+
+ uint32val = samples_per_period;
+ err = SetPropertyWrapper(id, NULL, 0, true, kAudioDevicePropertyBufferFrameSize, sizeof(UInt32), &uint32val);
+ if (err != noErr) { return -1; }
+ err = SetPropertyWrapper(id, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, sizeof(UInt32), &uint32val);
+ if (err != noErr) { return -1; }
+ return 0;
}
+int
+CoreAudioPCM::set_samples_per_period (uint32_t n_samples)
+{
+ if (_state != 0 || _active_device_id == 0) {
+ return -1;
+ }
+ set_device_buffer_size_id (_active_device_id, n_samples);
+ return 0;
+}
int
CoreAudioPCM::pcm_start (
uint32_t device_id_in, uint32_t device_id_out,
uint32_t sample_rate, uint32_t samples_per_period,
- int (process_callback (void*)), void *process_arg)
+ int (process_callback (void*, const uint32_t, const uint64_t)), void *process_arg)
{
assert(_device_ids);
std::string errorMsg;
- _state = -2;
+ _state = -99;
- if (device_id_out >= _n_devices || device_id_in >= _n_devices) {
+ // "None" = UINT32_MAX
+ if (device_id_out >= _n_devices && device_id_in >= _n_devices) {
return -1;
}
+ pthread_mutex_lock (&_discovery_lock);
+
_process_callback = process_callback;
_process_arg = process_arg;
- _max_samples_per_period = samples_per_period;
+ _samples_per_period = samples_per_period;
_cur_samples_per_period = 0;
+ _active_device_id = 0;
+ _capture_channels = 0;
+ _playback_channels = 0;
+
+ const uint32_t chn_in = (device_id_in < _n_devices ? _device_ins[device_id_in] : 0) + ((device_id_out != device_id_in && device_id_out < _n_devices) ? _device_ins[device_id_out] : 0);
+ const uint32_t chn_out =(device_id_out < _n_devices ? _device_outs[device_id_out] : 0) + ((device_id_out != device_id_in && device_id_in < _n_devices) ? _device_outs[device_id_in] : 0);
+
+ assert (chn_in > 0 || chn_out > 0);
ComponentResult err;
UInt32 uint32val;
+ UInt32 size;
+ AudioDeviceID device_id;
AudioStreamBasicDescription srcFormat, dstFormat;
+#ifndef COREAUDIO_108
+ ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
+ Component HALOutput = FindNextComponent(NULL, &cd);
+ if (!HALOutput) { errorMsg="FindNextComponent"; _state = -2; goto error; }
+
+ err = OpenAComponent(HALOutput, &_auhal);
+ if (err != noErr) { errorMsg="OpenAComponent"; _state = -2; goto error; }
+#else
AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
- if (!HALOutput) { errorMsg="AudioComponentFindNext"; goto error; }
+ if (!HALOutput) { errorMsg="AudioComponentFindNext"; _state = -2; goto error; }
err = AudioComponentInstanceNew(HALOutput, &_auhal);
- if (err != noErr) { errorMsg="AudioComponentInstanceNew"; goto error; }
+ if (err != noErr) { errorMsg="AudioComponentInstanceNew"; _state = -2; goto error; }
+#endif
err = AudioUnitInitialize(_auhal);
- if (err != noErr) { errorMsg="AudioUnitInitialize"; goto error; }
+ if (err != noErr) { errorMsg="AudioUnitInitialize"; _state = -3; goto error; }
- // explicitly change samplerate of the device
+ // explicitly change samplerate of the devices, TODO allow separate rates with aggregates
if (set_device_sample_rate(device_id_in, sample_rate, true)) {
- errorMsg="Failed to set SampleRate, Capture Device"; goto error;
+ errorMsg="Failed to set SampleRate, Capture Device"; _state = -4; goto error;
}
if (set_device_sample_rate(device_id_out, sample_rate, false)) {
- errorMsg="Failed to set SampleRate, Playback Device"; goto error;
+ errorMsg="Failed to set SampleRate, Playback Device"; _state = -4; goto error;
}
// explicitly request device buffer size
- uint32val = samples_per_period;
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyBufferFrameSize;
- property_address.mScope = kAudioDevicePropertyScopeInput;
- property_address.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectSetPropertyData (_device_ids[device_id_in], &property_address, 0, NULL, sizeof(UInt32), &uint32val);
- if (err != noErr) { errorMsg="kAudioDevicePropertyBufferFrameSize, Input"; goto error; }
+ if (device_id_in < _n_devices && set_device_buffer_size_id(_device_ids[device_id_in], samples_per_period)) {
+ errorMsg="kAudioDevicePropertyBufferFrameSize, Input"; _state = -5; goto error;
+ }
+ if (device_id_out < _n_devices && set_device_buffer_size_id(_device_ids[device_id_out], samples_per_period)) {
+ errorMsg="kAudioDevicePropertyBufferFrameSize, Output"; _state = -5; goto error;
+ }
- property_address.mScope = kAudioDevicePropertyScopeOutput;
- err = AudioObjectSetPropertyData (_device_ids[device_id_out], &property_address, 0, NULL, sizeof(UInt32), &uint32val);
- if (err != noErr) { errorMsg="kAudioDevicePropertyBufferFrameSize, Output"; goto error; }
-#else
- err = AudioDeviceSetProperty(_device_ids[device_id_in], NULL, 0, AUHAL_INPUT_ELEMENT, kAudioDevicePropertyBufferFrameSize, sizeof(UInt32), &uint32val);
- if (err != noErr) { errorMsg="kAudioDevicePropertyBufferFrameSize, Input"; goto error; }
- err = AudioDeviceSetProperty(_device_ids[device_id_out], NULL, 0, AUHAL_OUTPUT_ELEMENT, kAudioDevicePropertyBufferFrameSize, sizeof(UInt32), &uint32val);
- if (err != noErr) { errorMsg="kAudioDevicePropertyBufferFrameSize, Output"; goto error; }
-#endif
+ // create aggregate device..
+ if (device_id_in < _n_devices && device_id_out < _n_devices && _device_ids[device_id_in] != _device_ids[device_id_out]) {
+ if (0 == create_aggregate_device(_device_ids[device_id_in], _device_ids[device_id_out], sample_rate, &_aggregate_device_id)) {
+ device_id = _aggregate_device_id;
+ } else {
+ _aggregate_device_id = 0;
+ _aggregate_plugin_id = 0;
+ errorMsg="Cannot create Aggregate Device"; _state = -12; goto error;
+ }
+ } else if (device_id_out < _n_devices) {
+ device_id = _device_ids[device_id_out];
+ } else {
+ assert (device_id_in < _n_devices);
+ device_id = _device_ids[device_id_in];
+ }
- uint32val = 1;
- err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, AUHAL_INPUT_ELEMENT, &uint32val, sizeof(UInt32));
- if (err != noErr) { errorMsg="kAudioOutputUnitProperty_EnableIO, Input"; goto error; }
- uint32val = 1;
- err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, AUHAL_OUTPUT_ELEMENT, &uint32val, sizeof(UInt32));
- if (err != noErr) { errorMsg="kAudioOutputUnitProperty_EnableIO, Output"; goto error; }
-
- err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT, &_device_ids[device_id_out], sizeof(AudioDeviceID));
- if (err != noErr) { errorMsg="kAudioOutputUnitProperty_CurrentDevice, Output"; goto error; }
-
- err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT, &_device_ids[device_id_in], sizeof(AudioDeviceID));
- if (err != noErr) { errorMsg="kAudioOutputUnitProperty_CurrentDevice, Input"; goto error; }
-
- // Set buffer size
- err = AudioUnitSetProperty(_auhal, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT, (UInt32*)&_max_samples_per_period, sizeof(UInt32));
- if (err != noErr) { errorMsg="kAudioUnitProperty_MaximumFramesPerSlice, Input"; goto error; }
- err = AudioUnitSetProperty(_auhal, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT, (UInt32*)&_max_samples_per_period, sizeof(UInt32));
- if (err != noErr) { errorMsg="kAudioUnitProperty_MaximumFramesPerSlice, Output"; goto error; }
-
- // set sample format
- srcFormat.mSampleRate = sample_rate;
- srcFormat.mFormatID = kAudioFormatLinearPCM;
- srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
- srcFormat.mBytesPerPacket = sizeof(float);
- srcFormat.mFramesPerPacket = 1;
- srcFormat.mBytesPerFrame = sizeof(float);
- srcFormat.mChannelsPerFrame = _device_ins[device_id_in];
- srcFormat.mBitsPerChannel = 32;
+ if (device_id_out != device_id_in) {
+ assert(_aggregate_device_id > 0 || device_id_in >= _n_devices || device_id_out >= _n_devices);
+ }
-#if 0
- property_address = { kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster };
- err = AudioObjectSetPropertyData (_device_ids[device_id_in], &property_address, 0, NULL, sizeof(AudioStreamBasicDescription), &srcFormat);
-#else
- err = AudioUnitSetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, AUHAL_INPUT_ELEMENT, &srcFormat, sizeof(AudioStreamBasicDescription));
-#endif
- if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat, Output"; goto error; }
+ // enableIO to progress further
+ uint32val = (chn_in > 0) ? 1 : 0;
+ err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, AUHAL_INPUT_ELEMENT, &uint32val, sizeof(UInt32));
+ if (err != noErr) { errorMsg="kAudioOutputUnitProperty_EnableIO, Input"; _state = -7; goto error; }
- dstFormat.mSampleRate = sample_rate;
- dstFormat.mFormatID = kAudioFormatLinearPCM;
- dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
- dstFormat.mBytesPerPacket = sizeof(float);
- dstFormat.mFramesPerPacket = 1;
- dstFormat.mBytesPerFrame = sizeof(float);
- dstFormat.mChannelsPerFrame = _device_outs[device_id_out];
- dstFormat.mBitsPerChannel = 32;
+ uint32val = (chn_out > 0) ? 1 : 0;
+ err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, AUHAL_OUTPUT_ELEMENT, &uint32val, sizeof(UInt32));
+ if (err != noErr) { errorMsg="kAudioOutputUnitProperty_EnableIO, Output"; _state = -7; goto error; }
+
+ err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &device_id, sizeof(AudioDeviceID));
+ if (err != noErr) { errorMsg="kAudioOutputUnitProperty_CurrentDevice, Input"; _state = -7; goto error; }
+
+ if (chn_in > 0) {
+ // set sample format
+ srcFormat.mSampleRate = sample_rate;
+ srcFormat.mFormatID = kAudioFormatLinearPCM;
+ srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
+ srcFormat.mBytesPerPacket = sizeof(float);
+ srcFormat.mFramesPerPacket = 1;
+ srcFormat.mBytesPerFrame = sizeof(float);
+ srcFormat.mChannelsPerFrame = chn_in;
+ srcFormat.mBitsPerChannel = 32;
+
+ err = AudioUnitSetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, AUHAL_INPUT_ELEMENT, &srcFormat, sizeof(AudioStreamBasicDescription));
+ if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat, Output"; _state = -6; goto error; }
+
+ err = AudioUnitSetProperty(_auhal, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, AUHAL_INPUT_ELEMENT, (UInt32*)&_samples_per_period, sizeof(UInt32));
+ if (err != noErr) { errorMsg="kAudioUnitProperty_MaximumFramesPerSlice, Input"; _state = -6; goto error; }
+ }
-#if 0
- property_address = { kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput, 0 };
- err = AudioObjectSetPropertyData (_device_ids[device_id_out], &property_address, 0, NULL, sizeof(AudioStreamBasicDescription), &dstFormat);
-#else
- err = AudioUnitSetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, AUHAL_OUTPUT_ELEMENT, &dstFormat, sizeof(AudioStreamBasicDescription));
-#endif
- if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat Input"; goto error; }
+ if (chn_out > 0) {
+ dstFormat.mSampleRate = sample_rate;
+ dstFormat.mFormatID = kAudioFormatLinearPCM;
+ dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
+ dstFormat.mBytesPerPacket = sizeof(float);
+ dstFormat.mFramesPerPacket = 1;
+ dstFormat.mBytesPerFrame = sizeof(float);
+ dstFormat.mChannelsPerFrame = chn_out;
+ dstFormat.mBitsPerChannel = 32;
+
+ err = AudioUnitSetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, AUHAL_OUTPUT_ELEMENT, &dstFormat, sizeof(AudioStreamBasicDescription));
+ if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat Input"; _state = -5; goto error; }
+
+ err = AudioUnitSetProperty(_auhal, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT, (UInt32*)&_samples_per_period, sizeof(UInt32));
+ if (err != noErr) { errorMsg="kAudioUnitProperty_MaximumFramesPerSlice, Output"; _state = -5; goto error; }
+ }
- UInt32 size;
- size = sizeof(AudioStreamBasicDescription);
- err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, AUHAL_INPUT_ELEMENT, &srcFormat, &size);
- if (err != noErr) { errorMsg="Get kAudioUnitProperty_StreamFormat, Output"; goto error; }
- _capture_channels = srcFormat.mChannelsPerFrame;
+ /* read back stream descriptions */
+ if (chn_in > 0) {
+ size = sizeof(AudioStreamBasicDescription);
+ err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, AUHAL_INPUT_ELEMENT, &srcFormat, &size);
+ if (err != noErr) { errorMsg="Get kAudioUnitProperty_StreamFormat, Output"; _state = -5; goto error; }
+ _capture_channels = srcFormat.mChannelsPerFrame;
#ifndef NDEBUG
- PrintStreamDesc(&srcFormat);
+ PrintStreamDesc(&srcFormat);
#endif
+ }
- size = sizeof(AudioStreamBasicDescription);
- err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, AUHAL_OUTPUT_ELEMENT, &dstFormat, &size);
- if (err != noErr) { errorMsg="Get kAudioUnitProperty_StreamFormat, Input"; goto error; }
- _playback_channels = dstFormat.mChannelsPerFrame;
+ if (chn_out > 0) {
+ size = sizeof(AudioStreamBasicDescription);
+ err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, AUHAL_OUTPUT_ELEMENT, &dstFormat, &size);
+ if (err != noErr) { errorMsg="Get kAudioUnitProperty_StreamFormat, Input"; _state = -5; goto error; }
+ _playback_channels = dstFormat.mChannelsPerFrame;
#ifndef NDEBUG
- PrintStreamDesc(&dstFormat);
+ PrintStreamDesc(&dstFormat);
#endif
+ }
+
+ /* prepare buffers for input */
+ if (_capture_channels > 0) {
+ _input_audio_buffer_list = (AudioBufferList*)malloc(sizeof(AudioBufferList) + (_capture_channels - 1) * sizeof(AudioBuffer));
+ assert(_input_audio_buffer_list);
+ if (!_input_audio_buffer_list) { errorMsg="Out of Memory."; _state = -8; goto error; }
+ }
+
+ _active_device_id = device_id;
+
+ // add Listeners
+ err = add_listener (_active_device_id, kAudioDeviceProcessorOverload, this);
+ if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Listen"; _state = -9; goto error; }
- _input_audio_buffer_list = (AudioBufferList*)malloc(sizeof(UInt32) + _capture_channels * sizeof(AudioBuffer));
- assert(_input_audio_buffer_list);
- if (!_input_audio_buffer_list) { errorMsg="Out of Memory."; goto error; }
+ err = add_listener (_active_device_id, kAudioDevicePropertyBufferFrameSize, this);
+ if (err != noErr) { errorMsg="kAudioDevicePropertyBufferFrameSize, Listen"; _state = -9; goto error; }
- // Setup callbacks
+ err = add_listener (_active_device_id, kAudioDevicePropertyNominalSampleRate, this);
+ if (err != noErr) { errorMsg="kAudioDevicePropertyNominalSampleRate, Listen"; _state = -9; goto error; }
+
+ _samples_per_period = current_buffer_size_id(_active_device_id);
+
+ // Setup callback
AURenderCallbackStruct renderCallback;
memset (&renderCallback, 0, sizeof (renderCallback));
renderCallback.inputProc = render_callback_ptr;
renderCallback.inputProcRefCon = this;
- err = AudioUnitSetProperty(_auhal,
- kAudioUnitProperty_SetRenderCallback,
- kAudioUnitScope_Output, AUHAL_OUTPUT_ELEMENT,
- &renderCallback, sizeof (renderCallback));
- if (err != noErr) { errorMsg="kAudioUnitProperty_SetRenderCallback"; goto error; }
+ if (_playback_channels == 0) {
+ err = AudioUnitSetProperty(_auhal,
+ kAudioOutputUnitProperty_SetInputCallback,
+ kAudioUnitScope_Output, 1,
+ &renderCallback, sizeof (renderCallback));
+ } else {
+ err = AudioUnitSetProperty(_auhal,
+ kAudioUnitProperty_SetRenderCallback,
+ kAudioUnitScope_Output, 0,
+ &renderCallback, sizeof (renderCallback));
+ }
+
+ if (err != noErr) { errorMsg="kAudioUnitProperty_SetRenderCallback"; _state = -10; goto error; }
+ /* setup complete, now get going.. */
if (AudioOutputUnitStart(_auhal) == noErr) {
_input_names.clear();
_output_names.clear();
- cache_port_names( device_id_in, true);
- cache_port_names( device_id_out, false);
+ cache_port_names (device_id, true);
+ cache_port_names (device_id, false);
_state = 0;
+ pthread_mutex_unlock (&_discovery_lock);
+
+ // kick device
+ if (set_device_buffer_size_id(_active_device_id, samples_per_period)) {
+ errorMsg="kAudioDevicePropertyBufferFrameSize"; _state = -11; goto error;
+ }
+
return 0;
}
error:
+ assert (_state != 0);
char *rv = (char*)&err;
fprintf(stderr, "CoreaudioPCM Error: %c%c%c%c %s\n", rv[0], rv[1], rv[2], rv[3], errorMsg.c_str());
pcm_stop();
- _state = -3;
+ _active_device_id = 0;
+ pthread_mutex_unlock (&_discovery_lock);
return -1;
}
void
-CoreAudioPCM::cache_port_names(uint32 device_id, bool input)
+CoreAudioPCM::cache_port_names(AudioDeviceID id, bool input)
{
uint32_t n_chn;
- assert (device_id < _n_devices);
if (input) {
n_chn = _capture_channels;
AudioObjectPropertyAddress property_address;
property_address.mSelector = kAudioObjectPropertyElementName;
property_address.mScope = input ? kAudioDevicePropertyScopeInput: kAudioDevicePropertyScopeOutput;
-#else
- const int elem = input ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT;
#endif
for (uint32_t c = 0; c < n_chn; ++c) {
#ifdef COREAUDIO_108
property_address.mElement = c + 1;
- err = AudioObjectGetPropertyDataSize(_device_ids[device_id], &property_address, 0, NULL, &size);
+ err = AudioObjectGetPropertyDataSize(id, &property_address, 0, NULL, &size);
#else
- err = AudioDeviceGetPropertyInfo (_device_ids[device_id], c + 1, elem,
+ err = AudioDeviceGetPropertyInfo (id, c + 1, input,
kAudioDevicePropertyChannelNameCFString,
&size,
NULL);
if (err == kAudioHardwareNoError) {
#ifdef COREAUDIO_108
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, c + 1, NULL, &size, &name);
+ err = AudioObjectGetPropertyData(id, &property_address, c + 1, NULL, &size, &name);
#else
- err = AudioDeviceGetProperty (_device_ids[device_id], c + 1, elem,
+ err = AudioDeviceGetProperty (id, c + 1, input,
kAudioDevicePropertyChannelNameCFString,
&size,
&name);
#endif
}
-
+
bool decoded = false;
char* cstr_name = 0;
if (err == kAudioHardwareNoError) {
decoded = CFStringGetCString(name, cstr_name, maxSize, kCFStringEncodingUTF8);
}
- ss << (c + 1) << " - ";
+ ss << (c + 1);
if (cstr_name && decoded && (0 != std::strlen(cstr_name) ) ) {
- ss << cstr_name;
- } else {
- if (input) {
- ss << "Input " << (c + 1);
- } else {
- ss << "Output " << (c + 1);
- }
+ ss << " - " << cstr_name;
}
-
+#if 0
printf("%s %d Name: %s\n", input ? "Input" : "Output", c+1, ss.str().c_str());
+#endif
if (input) {
_input_names.push_back (ss.str());
}
std::string
-CoreAudioPCM::cached_port_name(uint32 port, bool input) const
+CoreAudioPCM::cached_port_name(uint32_t port, bool input) const
{
if (_state != 0) { return ""; }
if (input) {
- if (port > _input_names.size()) {
+ if (port >= _input_names.size()) {
return "";
}
return _input_names[port];
} else {
- if (port > _output_names.size()) {
+ if (port >= _output_names.size()) {
return "";
}
return _output_names[port];
UInt32 inNumberFrames,
AudioBufferList* ioData)
{
- OSStatus retVal = 0;
+ OSStatus retVal = kAudioHardwareNoError;
- assert(_max_samples_per_period >= inNumberFrames);
- assert(ioData->mNumberBuffers = _playback_channels);
+ if (_samples_per_period < inNumberFrames) {
+#ifndef NDEBUG
+ printf("samples per period exceeds configured value, cycle skipped (%u < %u)\n",
+ (unsigned int)_samples_per_period, (unsigned int)inNumberFrames);
+#endif
+ for (uint32_t i = 0; _playback_channels > 0 && i < ioData->mNumberBuffers; ++i) {
+ float* ob = (float*) ioData->mBuffers[i].mData;
+ memset(ob, 0, sizeof(float) * inNumberFrames);
+ }
+ return noErr;
+ }
+
+ assert(_playback_channels == 0 || ioData->mNumberBuffers == _playback_channels);
+ UInt64 cur_cycle_start = AudioGetCurrentHostTime ();
_cur_samples_per_period = inNumberFrames;
+ if (_capture_channels > 0) {
+ _input_audio_buffer_list->mNumberBuffers = _capture_channels;
+ for (uint32_t i = 0; i < _capture_channels; ++i) {
+ _input_audio_buffer_list->mBuffers[i].mNumberChannels = 1;
+ _input_audio_buffer_list->mBuffers[i].mDataByteSize = inNumberFrames * sizeof(float);
+ _input_audio_buffer_list->mBuffers[i].mData = NULL;
+ }
- _input_audio_buffer_list->mNumberBuffers = _capture_channels;
- for (uint32_t i = 0; i < _capture_channels; ++i) {
- _input_audio_buffer_list->mBuffers[i].mNumberChannels = 1;
- _input_audio_buffer_list->mBuffers[i].mDataByteSize = inNumberFrames * sizeof(float);
- _input_audio_buffer_list->mBuffers[i].mData = NULL;
+ retVal = AudioUnitRender(_auhal, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, _input_audio_buffer_list);
}
- retVal = AudioUnitRender(_auhal, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, _input_audio_buffer_list);
-
if (retVal != kAudioHardwareNoError) {
#if 0
char *rv = (char*)&retVal;
int rv = -1;
if (_process_callback) {
- rv = _process_callback(_process_arg);
+ rv = _process_callback(_process_arg, inNumberFrames, cur_cycle_start);
}
_in_process = false;
- if (rv != 0) {
+ if (rv != 0 && _playback_channels > 0) {
// clear output
for (uint32_t i = 0; i < ioData->mNumberBuffers; ++i) {
float* ob = (float*) ioData->mBuffers[i].mData;
return -1;
}
- assert(_output_audio_buffer_list->mNumberBuffers > chn);
+ assert(_output_audio_buffer_list && _output_audio_buffer_list->mNumberBuffers > chn);
memcpy((void*)_output_audio_buffer_list->mBuffers[chn].mData, (void*)output, sizeof(float) * n_samples);
return 0;
}
UInt32 size = sizeof (config_app);
OSStatus err;
-#ifdef COREAUDIO_108
- AudioObjectPropertyAddress property_address;
- property_address.mSelector = kAudioDevicePropertyConfigurationApplication;
- property_address.mScope = kAudioDevicePropertyScopeOutput;
- property_address.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &config_app);
-#else
- err = AudioDeviceGetProperty(_device_ids[device_id], 0, 0, kAudioDevicePropertyConfigurationApplication, &size, &config_app);
-#endif
+ err = GetPropertyWrapper(_device_ids[device_id], 0, false, kAudioDevicePropertyConfigurationApplication, &size, &config_app);
if (kAudioHardwareNoError != err) {
return;
}