summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2015-03-06 03:21:47 +0100
committerRobin Gareus <robin@gareus.org>2015-03-06 06:24:56 +0100
commit6b87e706ebcc8fb45f8ae5b978b661f1912d1f9c (patch)
treea2cfd1088c87df2ff21fcedce4217e6199a6fd5f
parent408090adce65f6a23e1e4b7afbd26f0cd6177e88 (diff)
cont’d work on the coreaudio backend & cleanup
-rw-r--r--libs/backends/coreaudio/coreaudio_backend.cc121
-rw-r--r--libs/backends/coreaudio/coreaudio_backend.h11
-rw-r--r--libs/backends/coreaudio/coreaudio_pcmio.cc841
-rw-r--r--libs/backends/coreaudio/coreaudio_pcmio.h50
-rw-r--r--libs/backends/coreaudio/coremidi_io.cc94
-rw-r--r--libs/backends/coreaudio/coremidi_io.h23
-rw-r--r--libs/backends/coreaudio/wscript3
7 files changed, 839 insertions, 304 deletions
diff --git a/libs/backends/coreaudio/coreaudio_backend.cc b/libs/backends/coreaudio/coreaudio_backend.cc
index 80f532c313..f4add45ac9 100644
--- a/libs/backends/coreaudio/coreaudio_backend.cc
+++ b/libs/backends/coreaudio/coreaudio_backend.cc
@@ -41,6 +41,13 @@ std::vector<std::string> CoreAudioBackend::_midi_options;
std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_audio_device_status;
std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_midi_device_status;
+
+static void hw_changed_callback_ptr (void *arg)
+{
+ CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg);
+ d->hw_changed_callback();
+}
+
CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info)
: AudioBackend (e, info)
, _run (false)
@@ -70,6 +77,7 @@ CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info)
_pcmio = new CoreAudioPCM ();
_midiio = new CoreMidiIo ();
+ _pcmio->set_hw_changed_callback (hw_changed_callback_ptr, this);
_pcmio->discover();
_midiio->discover();
}
@@ -114,25 +122,16 @@ CoreAudioBackend::enumerate_devices () const
std::vector<float>
CoreAudioBackend::available_sample_rates (const std::string&) const
{
- // TODO ask _pcmio for available rates
std::vector<float> sr;
- sr.push_back (44100.0);
- sr.push_back (48000.0);
+ _pcmio->available_sample_rates(name_to_id(_audio_device), sr);
return sr;
}
std::vector<uint32_t>
CoreAudioBackend::available_buffer_sizes (const std::string&) const
{
- // TODO ask _pcmio for available rates
std::vector<uint32_t> bs;
- bs.push_back (64);
- bs.push_back (128);
- bs.push_back (256);
- bs.push_back (512);
- bs.push_back (1024);
- bs.push_back (2048);
- bs.push_back (4096);
+ _pcmio->available_buffer_sizes(name_to_id(_audio_device), bs);
return bs;
}
@@ -164,6 +163,8 @@ int
CoreAudioBackend::set_device_name (const std::string& d)
{
_audio_device = d;
+ const float sr = _pcmio->current_sample_rate(name_to_id(_audio_device));
+ if (sr > 0) { set_sample_rate(sr); }
return 0;
}
@@ -171,6 +172,7 @@ int
CoreAudioBackend::set_sample_rate (float sr)
{
if (sr <= 0) { return -1; }
+ // TODO check if it's in the list of valid SR
_samplerate = sr;
engine.sample_rate_change (sr);
return 0;
@@ -363,6 +365,12 @@ CoreAudioBackend::midi_device_enabled (std::string const device) const
return nfo->enabled;
}
+void
+CoreAudioBackend::launch_control_app ()
+{
+ _pcmio->launch_control_app(name_to_id(_audio_device));
+}
+
/* State Control */
static void * pthread_freewheel (void *arg)
@@ -391,7 +399,6 @@ static void midi_port_change (void *arg)
d->coremidi_rediscover ();
}
-
int
CoreAudioBackend::_start (bool for_latency_measurement)
{
@@ -414,21 +421,7 @@ CoreAudioBackend::_start (bool for_latency_measurement)
_ports.clear();
}
-#if 0
- assert(_rmidi_in.size() == 0);
- assert(_rmidi_out.size() == 0);
-#endif
-
- uint32_t device_id = UINT32_MAX;
- std::map<size_t, std::string> devices;
- _pcmio->device_list(devices);
-
- for (std::map<size_t, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
- if (i->second == _audio_device) {
- device_id = i->first;
- break;
- }
- }
+ uint32_t device_id = name_to_id(_audio_device);
assert(_active_ca == false);
assert(_active_fw == false);
@@ -485,11 +478,8 @@ CoreAudioBackend::_start (bool for_latency_measurement)
_run = true;
_port_change_flag = false;
- printf("MIDI: %s\n", _midi_driver_option.c_str());
-
if (_midi_driver_option == _("CoreMidi")) {
- //register_system_midi_ports();
- _midiio->setPortChangedCallback(midi_port_change, this);
+ _midiio->set_port_changed_callback(midi_port_change, this);
_midiio->discover();
}
@@ -510,7 +500,6 @@ CoreAudioBackend::_start (bool for_latency_measurement)
engine.reconnect_ports ();
-
if (pthread_create (&_freeewheel_thread, NULL, pthread_freewheel, this))
{
PBD::error << _("CoreAudioBackend: failed to create process thread.") << endmsg;
@@ -523,13 +512,11 @@ CoreAudioBackend::_start (bool for_latency_measurement)
while ((!_active_ca || !_active_fw) && --timeout > 0) { Glib::usleep (1000); }
if (timeout == 0) {
- printf("CoreAudioBackend: failed to start.");
PBD::error << _("CoreAudioBackend: failed to start.") << endmsg;
}
if (!_active_fw) {
PBD::error << _("CoreAudioBackend: failed to start freewheeling thread.") << endmsg;
- printf("CoreAudioBackend: fw .\n");
_run = false;
_pcmio->pcm_stop();
unregister_ports();
@@ -539,7 +526,6 @@ CoreAudioBackend::_start (bool for_latency_measurement)
}
if (!_active_ca) {
- printf("CoreAudioBackend: ca .\n");
PBD::error << _("CoreAudioBackend: failed to start coreaudio.") << endmsg;
stop();
_run = false;
@@ -560,28 +546,13 @@ CoreAudioBackend::stop ()
_run = false;
_pcmio->pcm_stop();
- _midiio->setPortChangedCallback(NULL, NULL);
+ _midiio->set_port_changed_callback(NULL, NULL);
if (pthread_join (_freeewheel_thread, &status)) {
PBD::error << _("CoreAudioBackend: failed to terminate.") << endmsg;
return -1;
}
-#if 0
- while (!_rmidi_out.empty ()) {
- CoreMidiIO *m = _rmidi_out.back ();
- m->stop();
- _rmidi_out.pop_back ();
- delete m;
- }
- while (!_rmidi_in.empty ()) {
- CoreMidiIO *m = _rmidi_in.back ();
- m->stop();
- _rmidi_in.pop_back ();
- delete m;
- }
-#endif
-
unregister_ports();
_active_ca = false;
@@ -637,6 +608,20 @@ CoreAudioBackend::samples_since_cycle_start ()
return 0;
}
+uint32_t
+CoreAudioBackend::name_to_id(std::string device_name) const {
+ uint32_t device_id = UINT32_MAX;
+ std::map<size_t, std::string> devices;
+ _pcmio->device_list(devices);
+
+ for (std::map<size_t, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
+ if (i->second == device_name) {
+ device_id = i->first;
+ break;
+ }
+ }
+ return device_id;
+}
void *
CoreAudioBackend::coreaudio_process_thread (void *arg)
@@ -872,8 +857,12 @@ int
CoreAudioBackend::register_system_audio_ports()
{
LatencyRange lr;
+ printf("COREAUDIO LATENCY: i:%d, o:%d\n",
+ _pcmio->get_latency(name_to_id(_audio_device), true),
+ _pcmio->get_latency(name_to_id(_audio_device), false));
- // TODO ask _pcmio for port latencies
+ //TODO set latencies
+ //TODO query port names
const int a_ins = _n_inputs > 0 ? _n_inputs : 2;
const int a_out = _n_outputs > 0 ? _n_outputs : 2;
@@ -907,6 +896,7 @@ CoreAudioBackend::register_system_midi_ports()
int midi_ins = _system_midi_out.size();
int midi_outs = _system_midi_in.size();
+ //TODO query port names
for (uint32_t i = midi_ins; i < _midiio->n_midi_outputs(); ++i) {
char tmp[64];
snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++midi_ins);
@@ -917,7 +907,6 @@ CoreAudioBackend::register_system_midi_ports()
LatencyRange lr;
lr.min = lr.max = _samples_per_period; // TODO add per-port midi-systemic latency
set_latency_range (p, false, lr);
- //static_cast<CoreMidiPort*>(p)->set_n_periods(2);
_system_midi_out.push_back(static_cast<CoreBackendPort*>(p));
}
@@ -931,7 +920,6 @@ CoreAudioBackend::register_system_midi_ports()
LatencyRange lr;
lr.min = lr.max = _samples_per_period; // TODO add per-port midi-systemic latency
set_latency_range (p, false, lr);
- //static_cast<CoreMidiPort*>(p)->set_n_periods(2);
_system_midi_in.push_back(static_cast<CoreBackendPort*>(p));
}
@@ -946,6 +934,8 @@ CoreAudioBackend::coremidi_rediscover()
pthread_mutex_lock (&_process_callback_mutex);
+ // TODO maintain device-specific connections, rather
+ // than re-map.
while (_system_midi_out.size() > _midiio->n_midi_outputs()) {
CoreBackendPort* p = _system_midi_out.back();
_system_midi_out.pop_back();
@@ -961,7 +951,6 @@ CoreAudioBackend::coremidi_rediscover()
register_system_midi_ports();
_port_change_flag = true;
- _reinit_thread_callback = true; // XXX, rather hook into _pcmio's hardwarePropertyChangeCallback
pthread_mutex_unlock (&_process_callback_mutex);
}
@@ -1404,7 +1393,6 @@ CoreAudioBackend::process_callback ()
}
if (_reinit_thread_callback || _main_thread != pthread_self()) {
- printf("REINIT THREAD\n");
_reinit_thread_callback = false;
_main_thread = pthread_self();
AudioEngine::thread_init_callback (this);
@@ -1417,6 +1405,7 @@ CoreAudioBackend::process_callback ()
#if 0 // here in RT callback ?? XXX
if (_samples_per_period != n_samples) {
+ printf("CoreAudio Adjust SPP %zu -> %d\n", _samples_per_period, n_samples);
_samples_per_period = n_samples;
engine.buffer_size_change (_samples_per_period);
// TODO update latencies
@@ -1428,7 +1417,7 @@ CoreAudioBackend::process_callback ()
clock1 = g_get_monotonic_time();
- // TODO get midi
+ /* get midi */
i=0;
for (std::vector<CoreBackendPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
CoreMidiBuffer* mbuf = static_cast<CoreMidiBuffer*>((*it)->get_buffer(0));
@@ -1465,12 +1454,12 @@ CoreAudioBackend::process_callback ()
return -1;
}
- // mixdown midi
+ /* mixdown midi */
for (std::vector<CoreBackendPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
- //static_cast<CoreMidiPort*>(*it)->next_period();
static_cast<CoreMidiPort*>(*it)->get_buffer(0);
}
- // queue outgoing midi
+
+ /* queue outgoing midi */
i = 0;
for (std::vector<CoreBackendPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
const CoreMidiBuffer *src = static_cast<const CoreMidiPort*>(*it)->const_buffer();
@@ -1487,15 +1476,14 @@ CoreAudioBackend::process_callback ()
_processed_samples += n_samples;
- // calc DSP load.
-
+ /* calc DSP load. */
clock2 = g_get_monotonic_time();
const int64_t elapsed_time = clock2 - clock1;
_dsp_load = elapsed_time / (float) nominal_time;
//engine.Xrun (); // TODO, if any
- // port-connection change
+ /* port-connection change */
post_process();
pthread_mutex_unlock (&_process_callback_mutex);
return 0;
@@ -1504,11 +1492,16 @@ CoreAudioBackend::process_callback ()
void
CoreAudioBackend::error_callback ()
{
- printf("ERROR CALLBACK\n");
_pcmio->set_error_callback (NULL, NULL);
engine.halted_callback("CoreAudio Process aborted.");
}
+void
+CoreAudioBackend::hw_changed_callback ()
+{
+ _reinit_thread_callback = true;
+ engine.request_device_list_update();
+}
/******************************************************************************/
diff --git a/libs/backends/coreaudio/coreaudio_backend.h b/libs/backends/coreaudio/coreaudio_backend.h
index 0460e57476..5e243656ea 100644
--- a/libs/backends/coreaudio/coreaudio_backend.h
+++ b/libs/backends/coreaudio/coreaudio_backend.h
@@ -199,8 +199,8 @@ class CoreAudioBackend : public AudioBackend {
bool can_set_systemic_midi_latencies () const { return false; /* XXX */}
/* External control app */
- std::string control_app_name () const { return std::string (); }
- void launch_control_app () {}
+ std::string control_app_name () const { return std::string ("Apple"); }
+ void launch_control_app ();
/* MIDI */
std::vector<std::string> enumerate_midi_options () const;
@@ -214,6 +214,7 @@ class CoreAudioBackend : public AudioBackend {
// really private, but needing static access:
int process_callback();
void error_callback();
+ void hw_changed_callback();
protected:
/* State Control */
@@ -333,6 +334,9 @@ class CoreAudioBackend : public AudioBackend {
uint32_t _systemic_audio_input_latency;
uint32_t _systemic_audio_output_latency;
+ /* coreaudio specific */
+ uint32_t name_to_id(std::string) const;
+
/* midi settings */
struct CoreMidiDeviceInfo {
bool enabled;
@@ -380,9 +384,6 @@ class CoreAudioBackend : public AudioBackend {
std::vector<CoreBackendPort *> _system_midi_in;
std::vector<CoreBackendPort *> _system_midi_out;
- //std::vector<CoreMidiOut *> _rmidi_out;
- //std::vector<CoreMidiIn *> _rmidi_in;
-
struct PortConnectData {
std::string a;
std::string b;
diff --git a/libs/backends/coreaudio/coreaudio_pcmio.cc b/libs/backends/coreaudio/coreaudio_pcmio.cc
index a1615d8583..29207d4ffa 100644
--- a/libs/backends/coreaudio/coreaudio_pcmio.cc
+++ b/libs/backends/coreaudio/coreaudio_pcmio.cc
@@ -16,10 +16,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <glibmm.h>
#include "coreaudio_pcmio.h"
-#include <string>
-
+#ifdef COREAUDIO_108
+static OSStatus hardwarePropertyChangeCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) {
+ CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
+ self->hwPropertyChange();
+ return noErr;
+}
+#else
static OSStatus hardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* arg) {
if (inPropertyID == kAudioHardwarePropertyDevices) {
CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg);
@@ -27,27 +33,38 @@ static OSStatus hardwarePropertyChangeCallback (AudioHardwarePropertyID inProper
}
return noErr;
}
+#endif
CoreAudioPCM::CoreAudioPCM ()
: _auhal (0)
- , _deviceIDs (0)
- , _inputAudioBufferList (0)
+ , _device_ids (0)
+ , _input_audio_buffer_list (0)
, _state (-1)
, _capture_channels (0)
, _playback_channels (0)
, _in_process (false)
- , _numDevices (0)
+ , _n_devices (0)
, _process_callback (0)
, _error_callback (0)
+ , _hw_changed_callback (0)
, _device_ins (0)
, _device_outs (0)
{
-#ifdef COREAUDIO_108 // TODO
+ pthread_mutex_init (&_discovery_lock, 0);
+
+#ifdef COREAUDIO_108
CFRunLoopRef theRunLoop = NULL;
AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioHardwarePropertyDevices };
AudioObjectSetPropertyData (kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
-#endif
+
+ AudioObjectPropertyAddress prop;
+ prop.mSelector = kAudioHardwarePropertyDevices;
+ prop.mScope = kAudioObjectPropertyScopeGlobal;
+ prop.mElement = 0;
+ AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, hardwarePropertyChangeCallback, this);
+#else
AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, hardwarePropertyChangeCallback, this);
+#endif
}
CoreAudioPCM::~CoreAudioPCM ()
@@ -55,179 +72,479 @@ CoreAudioPCM::~CoreAudioPCM ()
if (_state == 0) {
pcm_stop();
}
- delete _deviceIDs;
+ delete _device_ids;
free(_device_ins);
free(_device_outs);
+#ifdef COREAUDIO_108
+ AudioObjectPropertyAddress prop;
+ prop.mSelector = kAudioHardwarePropertyDevices;
+ prop.mScope = kAudioObjectPropertyScopeGlobal;
+ prop.mElement = 0;
+ AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &hardwarePropertyChangeCallback, this);
+#else
AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, hardwarePropertyChangeCallback);
- free(_inputAudioBufferList);
+#endif
+ free(_input_audio_buffer_list);
+ pthread_mutex_destroy (&_discovery_lock);
}
void
CoreAudioPCM::hwPropertyChange() {
- printf("hardwarePropertyChangeCallback\n");
discover();
+ // TODO Filter events..
+ if (_hw_changed_callback) {
+ _hw_changed_callback(_hw_changed_arg);
+ }
}
-void
-CoreAudioPCM::discover() {
- OSStatus err;
- UInt32 propSize = 0;
- // TODO trymutex lock.
+int
+CoreAudioPCM::available_sample_rates(uint32_t device_id, std::vector<float>& sampleRates)
+{
+ OSStatus err;
+ UInt32 size = 0;
+ sampleRates.clear();
- if (_deviceIDs) {
- delete _deviceIDs; _deviceIDs = 0;
- free(_device_ins); _device_ins = 0;
- free(_device_outs); _device_outs = 0;
+ if (device_id >= _n_devices) {
+ return -1;
}
- _devices.clear();
#ifdef COREAUDIO_108
- AudioObjectPropertyAddress propertyAddress;
- propertyAddress.mSelector = kAudioHardwarePropertyDevices;
- propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
- propertyAddress.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propSize);
+ 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 = AudioHardwareGetPropertyInfo (kAudioHardwarePropertyDevices, &propSize, NULL);
+ err = AudioDeviceGetPropertyInfo(_device_ids[device_id], 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &size, NULL);
#endif
- _numDevices = propSize / sizeof (AudioDeviceID);
- propSize = _numDevices * sizeof (AudioDeviceID);
+ if (err != kAudioHardwareNoError) {
+ return -1;
+ }
- _deviceIDs = new AudioDeviceID[_numDevices];
- _device_ins = (uint32_t*) calloc(_numDevices, sizeof(uint32_t));
- _device_outs = (uint32_t*) calloc(_numDevices, sizeof(uint32_t));
+ int numRates = size / sizeof(AudioValueRange);
+ AudioValueRange* supportedRates = new AudioValueRange[numRates];
#ifdef COREAUDIO_108
- propertyAddress.mSelector = kAudioHardwarePropertyDevices;
- err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propSize, _deviceIDs);
+ err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, supportedRates);
#else
- err = AudioHardwareGetProperty (kAudioHardwarePropertyDevices, &propSize, _deviceIDs);
+ err = AudioDeviceGetProperty(_device_ids[device_id], 0, 0, kAudioDevicePropertyAvailableNominalSampleRates, &size, supportedRates);
#endif
- for (size_t deviceIndex = 0; deviceIndex < _numDevices; deviceIndex++) {
- propSize = 64;
- char deviceName[64];
+ if (err != kAudioHardwareNoError) {
+ delete [] supportedRates;
+ return -1;
+ }
+
+ static const float ardourRates[] = { 8000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0};
+
+ for(uint32_t i = 0; i < sizeof(ardourRates)/sizeof(float); ++i) {
+ for(uint32_t j = 0; j < numRates; ++j) {
+ if ((supportedRates[j].mMinimum <= ardourRates[i]) &&
+ (supportedRates[j].mMaximum >= ardourRates[i])) {
+ sampleRates.push_back (ardourRates[i]);
+ break;
+ }
+ }
+ }
+
+ delete [] supportedRates;
+ return 0;
+}
+
+int
+CoreAudioPCM::available_buffer_sizes(uint32_t device_id, std::vector<uint32_t>& bufferSizes)
+{
+ OSStatus err;
+ UInt32 size = 0;
+ bufferSizes.clear();
+
+ if (device_id >= _n_devices) {
+ return -1;
+ }
+
+ AudioValueRange supportedRange;
+ size = sizeof (AudioValueRange);
+
#ifdef COREAUDIO_108
- propertyAddress.mSelector = kAudioDevicePropertyDeviceName;
- propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
- err = AudioObjectGetPropertyData(_deviceIDs[deviceIndex], &propertyAddress, 0, NULL, &propSize, deviceName);
+ AudioObjectPropertyAddress property_address;
+ property_address.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
+ err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &supportedRange);
#else
- err = AudioDeviceGetProperty(_deviceIDs[deviceIndex], 0, 0, kAudioDevicePropertyDeviceName, &propSize, deviceName);
+ err = AudioDeviceGetProperty(_device_ids[device_id], 0, 0, kAudioDevicePropertyBufferFrameSizeRange, &size, &supportedRange);
#endif
- if (kAudioHardwareNoError != err) {
- fprintf(stderr, "device name query failed: %i\n", err);
- continue;
+ if (err != kAudioHardwareNoError) {
+ return -1;
+ }
+
+ static const uint32_t ardourSizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
+
+ for(uint32_t i = 0; i < sizeof(ardourSizes)/sizeof(uint32_t); ++i) {
+ if ((supportedRange.mMinimum <= ardourSizes[i]) &&
+ (supportedRange.mMaximum >= ardourSizes[i])) {
+ bufferSizes.push_back (ardourSizes[i]);
}
+ }
- UInt32 size;
- UInt32 outputChannelCount = 0;
- UInt32 inputChannelCount = 0;
- AudioBufferList *bufferList = NULL;
+ if (bufferSizes.empty()) {
+ bufferSizes.push_back ((uint32_t)supportedRange.mMinimum);
+ bufferSizes.push_back ((uint32_t)supportedRange.mMaximum);
+ }
+ return 0;
+}
- /* query number of inputs */
+uint32_t
+CoreAudioPCM::available_channels(uint32_t device_id, bool input)
+{
+ OSStatus err;
+ UInt32 size = 0;
+ AudioBufferList *bufferList = NULL;
+ uint32_t channel_count = 0;
+
+ if (device_id >= _n_devices) {
+ return 0;
+ }
+
+ /* query number of inputs */
#ifdef COREAUDIO_108
- size = 0;
- propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
- propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
- err = AudioObjectGetPropertyDataSize(_deviceIDs[deviceIndex], &propertyAddress, 0, NULL, &size);
- if (kAudioHardwareNoError != err) {
- fprintf(stderr, "kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
- continue;
- }
+ 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"); break; }
+ bufferList = (AudioBufferList *)(malloc(size));
+ assert(bufferList);
+ if (!bufferList) { fprintf(stderr, "OUT OF MEMORY\n"); return 0; }
- err = AudioObjectGetPropertyData(_deviceIDs[deviceIndex], &propertyAddress, 0, NULL, &size, bufferList);
+ err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, bufferList);
#else
- err = AudioDeviceGetPropertyInfo (_deviceIDs[deviceIndex], 0, AUHAL_OUTPUT_ELEMENT, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
- if (kAudioHardwareNoError != err) {
- fprintf(stderr, "kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
- continue;
- }
- bufferList = (AudioBufferList *)(malloc(size));
- assert(bufferList);
- if (!bufferList) { fprintf(stderr, "OUT OF MEMORY\n"); break; }
+ err = AudioDeviceGetPropertyInfo (_device_ids[device_id], 0, input ? AUHAL_INPUT_ELEMENT : AUHAL_OUTPUT_ELEMENT, kAudioDevicePropertyStreamConfiguration, &size, NULL);
+ if (kAudioHardwareNoError != err) {
+ fprintf(stderr, "CoreaAudioPCM: kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
+ return 0;
+ }
- bufferList->mNumberBuffers = 0;
- err = AudioDeviceGetProperty(_deviceIDs[deviceIndex], 0, AUHAL_OUTPUT_ELEMENT, kAudioDevicePropertyStreamConfiguration, &size, bufferList);
+ 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
- if(kAudioHardwareNoError != err) {
- fprintf(stderr, "kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
- free(bufferList);
- continue;
- }
- for(UInt32 j = 0; j < bufferList->mNumberBuffers; ++j) {
- outputChannelCount += bufferList->mBuffers[j].mNumberChannels;
- }
+ if(kAudioHardwareNoError != err) {
+ fprintf(stderr, "CoreaAudioPCM: kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
free(bufferList);
+ return 0;
+ }
+ for(UInt32 j = 0; j < bufferList->mNumberBuffers; ++j) {
+ channel_count += bufferList->mBuffers[j].mNumberChannels;
+ }
+ free(bufferList);
+ return channel_count;
+}
+
+void
+CoreAudioPCM::get_stream_latencies(uint32 device_id, bool input, std::vector<uint32>& latencies)
+{
+ OSStatus err;
+ UInt32 size = 0;
+
+ if (device_id >= _n_devices) {
+ return;
+ }
- /* query number of inputs */
#ifdef COREAUDIO_108
- size = 0;
- propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
- propertyAddress.mScope = kAudioDevicePropertyScopeInput;
- err = AudioObjectGetPropertyDataSize(_deviceIDs[deviceIndex], &propertyAddress, 0, NULL, &size);
- if (kAudioHardwareNoError != err) {
- fprintf(stderr, "kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
- continue;
- }
+ 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;
+ }
- bufferList = (AudioBufferList *)(malloc(size));
- assert(bufferList);
- if (!bufferList) { fprintf(stderr, "OUT OF MEMORY\n"); break; }
+ uint32 stream_count = size / sizeof(UInt32);
+ AudioStreamID streamIDs[stream_count];
- err = AudioObjectGetPropertyData(_deviceIDs[deviceIndex], &propertyAddress, 0, NULL, &size, bufferList);
+#ifdef COREAUDIO_108
+ err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &streamIDs);
#else
- err = AudioDeviceGetPropertyInfo (_deviceIDs[deviceIndex], 0, AUHAL_INPUT_ELEMENT, kAudioDevicePropertyStreamConfiguration, &propSize, NULL);
- if (kAudioHardwareNoError != err) {
- fprintf(stderr, "kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
- continue;
- }
- bufferList = (AudioBufferList *)(malloc(size));
- assert(bufferList);
- if (!bufferList) { fprintf(stderr, "OUT OF MEMORY\n"); break; }
+ err = AudioDeviceGetProperty(_device_ids[device_id], 0, elem, kAudioDevicePropertyStreams, &size, streamIDs);
+#endif
+ if (err != noErr) {
+ fprintf(stderr, "GetStreamLatencies kAudioDevicePropertyStreams\n");
+ return;
+ }
- bufferList->mNumberBuffers = 0;
- err = AudioDeviceGetProperty(_deviceIDs[deviceIndex], 0, AUHAL_INPUT_ELEMENT, kAudioDevicePropertyStreamConfiguration, &size, bufferList);
+ for (uint32 i = 0; i < stream_count; i++) {
+ UInt32 stream_latency;
+ size = sizeof(UInt32);
+#ifdef COREAUDIO_108
+ property_address.mSelector = kAudioDevicePropertyStreams;
+ err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, 0, NULL, &size, &stream_latency);
+#else
+ err = AudioStreamGetProperty(streamIDs[i], elem, kAudioStreamPropertyLatency, &size, &stream_latency);
#endif
- if(kAudioHardwareNoError != err) {
- fprintf(stderr, "kAudioDevicePropertyStreamConfiguration failed: %i\n", err);
- free(bufferList);
- continue;
+ if (err != noErr) {
+ fprintf(stderr, "GetStreamLatencies kAudioStreamPropertyLatency\n");
+ return;
}
+#ifndef NDEBUG
+ printf("Stream %d latency: %d\n", i, stream_latency);
+#endif
+ latencies.push_back(stream_latency);
+ }
+}
+
+uint32_t
+CoreAudioPCM::get_latency(uint32 device_id, bool input)
+{
+ OSStatus err;
+ uint32 latency = 0;
+ UInt32 size = sizeof(UInt32);
+ UInt32 lat0 = 0;
+ UInt32 latS = 0;
+
+ if (device_id >= _n_devices) {
+ 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
+ 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
+ if (err != kAudioHardwareNoError) {
+ fprintf(stderr, "GetLatency kAudioDevicePropertySafetyOffset\n");
+ }
+
+#ifndef NDEBUG
+ printf("Base Latency systemic+safetyoffset = %d+%d\n", lat0, latS);
+#endif
+ latency = lat0 + latS;
+
+ uint32_t max_stream_latency = 0;
+ std::vector<uint32> 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]);
+ }
+ latency += max_stream_latency;
+
+ return latency;
+}
+
+
+
+
+float
+CoreAudioPCM::current_sample_rate(uint32 device_id, bool input) {
+ OSStatus err;
+ UInt32 size = 0;
+
+ if (device_id >= _n_devices) {
+ return -1;
+ }
+
+ float sample_rate = 0;
+
+ Float64 rate;
+ size = sizeof (rate);
- for(UInt32 j = 0; j < bufferList->mNumberBuffers; ++j) {
- inputChannelCount += bufferList->mBuffers[j].mNumberChannels;
+#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;
+ }
+
+ // 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;
+ }
+
+ return sample_rate;
+}
+
+int
+CoreAudioPCM::set_device_sample_rate (uint32 device_id, float rate, bool input)
+{
+ std::vector<int>::iterator intIter;
+ OSStatus err;
+ UInt32 size = 0;
+
+ if (current_sample_rate(device_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
+ 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) {
+ break;
}
- free(bufferList);
+ Glib::usleep (1000);
+ }
+ fprintf(stderr, "CoreAudioPCM: CoreAudio: Setting SampleRate took %d ms.\n", (3000 - timeout));
+
+ if (timeout == 0) {
+ fprintf(stderr, "CoreAudioPCM: CoreAudio: Setting SampleRate timed out.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+CoreAudioPCM::discover()
+{
+ OSStatus err;
+ UInt32 size = 0;
+
+ if (pthread_mutex_trylock (&_discovery_lock)) {
+ return;
+ }
+
+ if (_device_ids) {
+ delete _device_ids; _device_ids = 0;
+ free(_device_ins); _device_ins = 0;
+ free(_device_outs); _device_outs = 0;
+ }
+ _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
+
+ _n_devices = size / sizeof (AudioDeviceID);
+ size = _n_devices * sizeof (AudioDeviceID);
+
+ _device_ids = new AudioDeviceID[_n_devices];
+ _device_ins = (uint32_t*) calloc(_n_devices, sizeof(uint32_t));
+ _device_outs = (uint32_t*) calloc(_n_devices, sizeof(uint32_t));
+
+ assert(_device_ins && _device_outs && _device_ids);
+ if (!_device_ins || !_device_ins || !_device_ids) {
+ fprintf(stderr, "OUT OF MEMORY\n");
+ _device_ids = 0;
+ _device_ins = 0;
+ _device_outs = 0;
+ pthread_mutex_unlock (&_discovery_lock);
+ 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
+
+ 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
+
+ if (kAudioHardwareNoError != err) {
+ fprintf(stderr, "CoreAudioPCM: device name query failed: %i\n", err);
+ continue;
+ }
+
+ UInt32 inputChannelCount = available_channels(idx, true);
+ UInt32 outputChannelCount = available_channels(idx, false);
+
{
std::string dn = deviceName;
- _device_ins[deviceIndex] = inputChannelCount;
- _device_outs[deviceIndex] = outputChannelCount;
- printf("CoreAudio Device: #%ld '%s' in:%d out:%d\n", deviceIndex, deviceName, inputChannelCount, outputChannelCount);
+ _device_ins[idx] = inputChannelCount;
+ _device_outs[idx] = outputChannelCount;
+#ifndef NDEBUG
+ printf("CoreAudio Device: #%ld '%s' in:%d out:%d\n", idx, deviceName, inputChannelCount, outputChannelCount);
+#endif
if (outputChannelCount > 0 && inputChannelCount > 0) {
- _devices.insert (std::pair<size_t, std::string> (deviceIndex, dn));
+ _devices.insert (std::pair<size_t, std::string> (idx, dn));
}
}
}
+ pthread_mutex_unlock (&_discovery_lock);
}
void
CoreAudioPCM::pcm_stop ()
{
- printf("CoreAudioPCM::pcm_stop\n");
if (!_auhal) return;
AudioOutputUnitStop(_auhal);
@@ -242,8 +559,11 @@ CoreAudioPCM::pcm_stop ()
_capture_channels = 0;
_playback_channels = 0;
- free(_inputAudioBufferList);
- _inputAudioBufferList = 0;
+ free(_input_audio_buffer_list);
+ _input_audio_buffer_list = 0;
+
+ _input_names.clear();
+ _output_names.clear();
_error_callback = 0;
_process_callback = 0;
@@ -252,16 +572,16 @@ CoreAudioPCM::pcm_stop ()
#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 ("- - - - - - - - - - - - - - - - - - - -\n");
+ 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 ("- - - - - - - - - - - - - - - - - - - -\n");
}
#endif
@@ -286,10 +606,11 @@ CoreAudioPCM::pcm_start (
int (process_callback (void*)), void *process_arg)
{
- assert(_deviceIDs);
+ assert(_device_ids);
+ std::string errorMsg;
_state = -2;
- if (device_id_out >= _numDevices || device_id_in >= _numDevices) {
+ if (device_id_out >= _n_devices || device_id_in >= _n_devices) {
return -1;
}
@@ -299,38 +620,65 @@ CoreAudioPCM::pcm_start (
_cur_samples_per_period = 0;
ComponentResult err;
- UInt32 enableIO;
+ UInt32 uint32val;
AudioStreamBasicDescription srcFormat, dstFormat;
-
+
AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
- if (!HALOutput) { goto error; }
+ if (!HALOutput) { errorMsg="AudioComponentFindNext"; goto error; }
err = AudioComponentInstanceNew(HALOutput, &_auhal);
- if (err != noErr) { goto error; }
+ if (err != noErr) { errorMsg="AudioComponentInstanceNew"; goto error; }
err = AudioUnitInitialize(_auhal);
- if (err != noErr) { goto error; }
+ if (err != noErr) { errorMsg="AudioUnitInitialize"; goto error; }
- enableIO = 1;
- err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, AUHAL_INPUT_ELEMENT, &enableIO, sizeof(enableIO));
- if (err != noErr) { goto error; }
- enableIO = 1;
- err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, AUHAL_OUTPUT_ELEMENT, &enableIO, sizeof(enableIO));
- if (err != noErr) { goto error; }
+ // explicitly change samplerate of the device
+ if (set_device_sample_rate(device_id_in, sample_rate, true)) {
+ errorMsg="Failed to set SampleRate, Capture Device"; goto error;
+ }
+ if (set_device_sample_rate(device_id_out, sample_rate, false)) {
+ errorMsg="Failed to set SampleRate, Playback Device"; goto error;
+ }
- err = AudioUnitSetProperty(_auhal, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, AUHAL_OUTPUT_ELEMENT, &_deviceIDs[device_id_out], sizeof(AudioDeviceID));
- if (err != noErr) { 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; }
+
+ 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
+
+ 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_INPUT_ELEMENT, &_deviceIDs[device_id_in], sizeof(AudioDeviceID));
- if (err != noErr) { 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) { goto error; }
+ 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) { goto error; }
-
+ if (err != noErr) { errorMsg="kAudioUnitProperty_MaximumFramesPerSlice, Output"; goto error; }
// set sample format
srcFormat.mSampleRate = sample_rate;
@@ -342,8 +690,13 @@ CoreAudioPCM::pcm_start (
srcFormat.mChannelsPerFrame = _device_ins[device_id_in];
srcFormat.mBitsPerChannel = 32;
+#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));
- if (err != noErr) { goto error; }
+#endif
+ if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat, Output"; goto error; }
dstFormat.mSampleRate = sample_rate;
dstFormat.mFormatID = kAudioFormatLinearPCM;
@@ -354,13 +707,18 @@ CoreAudioPCM::pcm_start (
dstFormat.mChannelsPerFrame = _device_outs[device_id_out];
dstFormat.mBitsPerChannel = 32;
+#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));
- if (err != noErr) { goto error; }
+#endif
+ if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat Input"; goto error; }
UInt32 size;
size = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, AUHAL_INPUT_ELEMENT, &srcFormat, &size);
- if (err != noErr) { goto error; }
+ if (err != noErr) { errorMsg="Get kAudioUnitProperty_StreamFormat, Output"; goto error; }
_capture_channels = srcFormat.mChannelsPerFrame;
#ifndef NDEBUG
PrintStreamDesc(&srcFormat);
@@ -368,14 +726,16 @@ CoreAudioPCM::pcm_start (
size = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, AUHAL_OUTPUT_ELEMENT, &dstFormat, &size);
- if (err != noErr) { goto error; }
+ if (err != noErr) { errorMsg="Get kAudioUnitProperty_StreamFormat, Input"; goto error; }
_playback_channels = dstFormat.mChannelsPerFrame;
#ifndef NDEBUG
PrintStreamDesc(&dstFormat);
#endif
- _inputAudioBufferList = (AudioBufferList*)malloc(sizeof(UInt32) + _capture_channels * sizeof(AudioBuffer));
+ _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; }
// Setup callbacks
AURenderCallbackStruct renderCallback;
@@ -386,22 +746,125 @@ CoreAudioPCM::pcm_start (
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Output, AUHAL_OUTPUT_ELEMENT,
&renderCallback, sizeof (renderCallback));
- if (err != noErr) { goto error; }
-
- printf("SETUP OK..\n");
+ if (err != noErr) { errorMsg="kAudioUnitProperty_SetRenderCallback"; goto error; }
if (AudioOutputUnitStart(_auhal) == noErr) {
- printf("Coreaudio Started..\n");
+ _input_names.clear();
+ _output_names.clear();
+ cache_port_names( device_id_in, true);
+ cache_port_names( device_id_out, false);
_state = 0;
return 0;
}
error:
+ 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;
return -1;
}
+void
+CoreAudioPCM::cache_port_names(uint32 device_id, bool input)
+{
+ uint32_t n_chn;
+ assert (device_id < _n_devices);
+
+ if (input) {
+ n_chn = _capture_channels;
+ } else {
+ n_chn = _playback_channels;;
+ }
+#ifdef COREAUDIO_108
+ 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) {
+ CFStringRef name = NULL;
+ std::stringstream ss;
+ UInt32 size = 0;
+ OSStatus err;
+
+#ifdef COREAUDIO_108
+ property_address.mElement = c + 1;
+ err = AudioObjectGetPropertyDataSize(_device_ids[device_id], &property_address, 0, NULL, &size);
+#else
+ err = AudioDeviceGetPropertyInfo (_device_ids[device_id], c + 1, elem,
+ kAudioDevicePropertyChannelNameCFString,
+ &size,
+ NULL);
+#endif
+
+ if (err == kAudioHardwareNoError) {
+#ifdef COREAUDIO_108
+ err = AudioObjectGetPropertyData(_device_ids[device_id], &property_address, c + 1, NULL, &size, &name);
+#else
+ err = AudioDeviceGetProperty (_device_ids[device_id], c + 1, elem,
+ kAudioDevicePropertyChannelNameCFString,
+ &size,
+ &name);
+#endif
+ }
+
+ bool decoded = false;
+ char* cstr_name = 0;
+ if (err == kAudioHardwareNoError) {
+ CFIndex length = CFStringGetLength(name);
+ CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
+ cstr_name = new char[maxSize];
+ decoded = CFStringGetCString(name, cstr_name, maxSize, kCFStringEncodingUTF8);
+ }
+
+ 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);
+ }
+ }
+
+ printf("%s %d Name: %s\n", input ? "Input" : "Output", c+1, ss.str().c_str());
+
+ if (input) {
+ _input_names.push_back (ss.str());
+ } else {
+ _output_names.push_back (ss.str());
+ }
+
+ if (name) {
+ CFRelease (name);
+ }
+ delete [] cstr_name;
+ }
+}
+
+std::string
+CoreAudioPCM::cached_port_name(uint32 port, bool input) const
+{
+ if (_state != 0) { return ""; }
+
+ if (input) {
+ if (port > _input_names.size()) {
+ return "";
+ }
+ return _input_names[port];
+ } else {
+ if (port > _output_names.size()) {
+ return "";
+ }
+ return _output_names[port];
+ }
+}
+
OSStatus
CoreAudioPCM::render_callback (
@@ -419,25 +882,27 @@ CoreAudioPCM::render_callback (
_cur_samples_per_period = inNumberFrames;
- _inputAudioBufferList->mNumberBuffers = _capture_channels;
- for (int i = 0; i < _capture_channels; ++i) {
- _inputAudioBufferList->mBuffers[i].mNumberChannels = 1;
- _inputAudioBufferList->mBuffers[i].mDataByteSize = inNumberFrames * sizeof(float);
- _inputAudioBufferList->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, _inputAudioBufferList);
+ retVal = AudioUnitRender(_auhal, ioActionFlags, inTimeStamp, AUHAL_INPUT_ELEMENT, inNumberFrames, _input_audio_buffer_list);
- if (retVal != kAudioHardwareNoError) {
+ if (retVal != kAudioHardwareNoError) {
+#if 0
char *rv = (char*)&retVal;
printf("ERR %c%c%c%c\n", rv[0], rv[1], rv[2], rv[3]);
+#endif
if (_error_callback) {
_error_callback(_error_arg);
}
return retVal;
}
- _outputAudioBufferList = ioData;
+ _output_audio_buffer_list = ioData;
_in_process = true;
@@ -451,7 +916,7 @@ CoreAudioPCM::render_callback (
if (rv != 0) {
// clear output
- for (int i = 0; i < ioData->mNumberBuffers; ++i) {
+ for (uint32_t i = 0; i < ioData->mNumberBuffers; ++i) {
float* ob = (float*) ioData->mBuffers[i].mData;
memset(ob, 0, sizeof(float) * inNumberFrames);
}
@@ -465,8 +930,8 @@ CoreAudioPCM::get_capture_channel (uint32_t chn, float *input, uint32_t n_sample
if (!_in_process || chn > _capture_channels || n_samples > _cur_samples_per_period) {
return -1;
}
- assert(_inputAudioBufferList->mNumberBuffers > chn);
- memcpy((void*)input, (void*)_inputAudioBufferList->mBuffers[chn].mData, sizeof(float) * n_samples);
+ assert(_input_audio_buffer_list->mNumberBuffers > chn);
+ memcpy((void*)input, (void*)_input_audio_buffer_list->mBuffers[chn].mData, sizeof(float) * n_samples);
return 0;
}
@@ -477,7 +942,47 @@ CoreAudioPCM::set_playback_channel (uint32_t chn, const float *output, uint32_t
return -1;
}
- assert(_outputAudioBufferList->mNumberBuffers > chn);
- memcpy((void*)_outputAudioBufferList->mBuffers[chn].mData, (void*)output, sizeof(float) * n_samples);
+ assert(_output_audio_buffer_list->mNumberBuffers > chn);
+ memcpy((void*)_output_audio_buffer_list->mBuffers[chn].mData, (void*)output, sizeof(float) * n_samples);
return 0;
}
+
+
+void
+CoreAudioPCM::launch_control_app (uint32_t device_id)
+{
+ if (device_id >= _n_devices) {
+ return;
+ }
+
+ CFStringRef config_app = NULL;
+ 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
+ if (kAudioHardwareNoError != err) {
+ return;
+ }
+
+ FSRef appFSRef;
+ if (noErr == LSFindApplicationForInfo(kLSUnknownCreator, config_app, NULL, &appFSRef, NULL)) {
+ LSOpenFSRef(&appFSRef, NULL);
+ } else {
+ // open default AudioMIDISetup if device app is not found
+ CFStringRef audioMidiSetup = CFStringCreateWithCString(kCFAllocatorDefault, "com.apple.audio.AudioMIDISetup", kCFStringEncodingMacRoman);
+ if (noErr == LSFindApplicationForInfo(kLSUnknownCreator, audioMidiSetup, NULL, &appFSRef, NULL)) {
+ LSOpenFSRef(&appFSRef, NULL);
+ }
+ }
+ if (config_app) {
+ CFRelease (config_app);
+ }
+}
diff --git a/libs/backends/coreaudio/coreaudio_pcmio.h b/libs/backends/coreaudio/coreaudio_pcmio.h
index 179f1aec02..b249dedbf3 100644
--- a/libs/backends/coreaudio/coreaudio_pcmio.h
+++ b/libs/backends/coreaudio/coreaudio_pcmio.h
@@ -24,6 +24,7 @@
#include <AudioToolbox/AudioToolbox.h>
#include <map>
+#include <vector>
#include <string>
#define AUHAL_OUTPUT_ELEMENT 0
@@ -43,6 +44,16 @@ public:
void discover();
void device_list(std::map<size_t, std::string> &devices) const { devices = _devices;}
+ int available_sample_rates (uint32_t device_id, std::vector<float>& sampleRates);
+ int available_buffer_sizes (uint32_t device_id, std::vector<uint32_t>& sampleRates);
+ uint32_t available_channels (uint32_t device_id, bool input);
+ float current_sample_rate(uint32 device_id, bool input = false);
+ uint32_t get_latency(uint32 device_id, bool input);
+
+ std::string cached_port_name(uint32_t portnum, bool input) const;
+
+ void launch_control_app (uint32_t device_id);
+
void pcm_stop (void);
int pcm_start (
uint32_t input_device,
@@ -53,13 +64,22 @@ public:
void * process_arg
);
+ // TODO: combine callbacks below, add a enum type
void set_error_callback (
void ( error_callback (void*)),
void * error_arg
- ) {
- _error_callback = error_callback;
- _error_arg = error_arg;
- }
+ ) {
+ _error_callback = error_callback;
+ _error_arg = error_arg;
+ }
+
+ void set_hw_changed_callback (
+ void ( callback (void*)),
+ void * arg
+ ) {
+ _hw_changed_callback = callback;
+ _hw_changed_arg = arg;
+ }
// must be called from process_callback;
int get_capture_channel (uint32_t chn, float *input, uint32_t n_samples);
@@ -74,13 +94,17 @@ public:
UInt32 inNumberFrames,
AudioBufferList* ioData);
- void hwPropertyChange();
+ void hwPropertyChange();
private:
+ int set_device_sample_rate (uint32 device_id, float rate, bool input);
+ void get_stream_latencies(uint32 device_id, bool input, std::vector<uint32>& latencies);
+ void cache_port_names(uint32 device_id, bool input);
+
AudioUnit _auhal;
- AudioDeviceID* _deviceIDs;
- AudioBufferList* _inputAudioBufferList;
- AudioBufferList* _outputAudioBufferList;
+ AudioDeviceID* _device_ids;
+ AudioBufferList* _input_audio_buffer_list;
+ AudioBufferList* _output_audio_buffer_list;
int _state;
@@ -89,7 +113,7 @@ private:
uint32_t _capture_channels;
uint32_t _playback_channels;
bool _in_process;
- size_t _numDevices;
+ size_t _n_devices;
int (* _process_callback) (void*);
void * _process_arg;
@@ -97,9 +121,15 @@ private:
void (* _error_callback) (void*);
void * _error_arg;
+ void (* _hw_changed_callback) (void*);
+ void * _hw_changed_arg;
+
+ // TODO proper device info struct
std::map<size_t, std::string> _devices;
- // TODO proper device info struct
uint32_t * _device_ins;
uint32_t * _device_outs;
+ std::vector<std::string> _input_names;
+ std::vector<std::string> _output_names;
+ pthread_mutex_t _discovery_lock;
};
diff --git a/libs/backends/coreaudio/coremidi_io.cc b/libs/backends/coreaudio/coremidi_io.cc
index 9ded1f4e6a..750fd76e55 100644
--- a/libs/backends/coreaudio/coremidi_io.cc
+++ b/libs/backends/coreaudio/coremidi_io.cc
@@ -40,12 +40,12 @@ static void midiInputCallback(const MIDIPacketList *list, void *procRef, void *s
CoreMidiIo::CoreMidiIo()
- : _midiClient (0)
- , _inputEndPoints (0)
- , _outputEndPoints (0)
- , _inputPorts (0)
- , _outputPorts (0)
- , _inputQueue (0)
+ : _midi_client (0)
+ , _input_endpoints (0)
+ , _output_endpoints (0)
+ , _input_ports (0)
+ , _output_ports (0)
+ , _input_queue (0)
, _rb (0)
, _n_midi_in (0)
, _n_midi_out (0)
@@ -55,7 +55,7 @@ CoreMidiIo::CoreMidiIo()
, _changed_arg (0)
{
OSStatus err;
- err = MIDIClientCreate(CFSTR("Ardour"), &notifyProc, this, &_midiClient);
+ err = MIDIClientCreate(CFSTR("Ardour"), &notifyProc, this, &_midi_client);
if (noErr != err) {
fprintf(stderr, "Creating Midi Client failed\n");
}
@@ -65,7 +65,7 @@ CoreMidiIo::CoreMidiIo()
CoreMidiIo::~CoreMidiIo()
{
cleanup();
- MIDIClientDispose(_midiClient); _midiClient = 0;
+ MIDIClientDispose(_midi_client); _midi_client = 0;
}
void
@@ -73,19 +73,19 @@ CoreMidiIo::cleanup()
{
_active = false;
for (uint32_t i = 0 ; i < _n_midi_in ; ++i) {
- MIDIPortDispose(_inputPorts[i]);
- _inputQueue[i].clear();
+ MIDIPortDispose(_input_ports[i]);
+ _input_queue[i].clear();
delete _rb[i];
}
for (uint32_t i = 0 ; i < _n_midi_out ; ++i) {
- MIDIPortDispose(_outputPorts[i]);
+ MIDIPortDispose(_output_ports[i]);
}
- free(_inputPorts); _inputPorts = 0;
- free(_inputEndPoints); _inputEndPoints = 0;
- free(_inputQueue); _inputQueue = 0;
- free(_outputPorts); _outputPorts = 0;
- free(_outputEndPoints); _outputEndPoints = 0;
+ free(_input_ports); _input_ports = 0;
+ free(_input_endpoints); _input_endpoints = 0;
+ free(_input_queue); _input_queue = 0;
+ free(_output_ports); _output_ports = 0;
+ free(_output_endpoints); _output_endpoints = 0;
free(_rb); _rb = 0;
_n_midi_in = 0;
@@ -103,37 +103,37 @@ CoreMidiIo::notify_proc(const MIDINotification *message)
{
switch(message->messageID) {
case kMIDIMsgSetupChanged:
- printf("kMIDIMsgSetupChanged\n");
+ /* this one catches all of the added/removed/changed below */
+ //printf("kMIDIMsgSetupChanged\n");
discover();
break;
case kMIDIMsgObjectAdded:
{
- const MIDIObjectAddRemoveNotification *n = (const MIDIObjectAddRemoveNotification*) message;
- printf("kMIDIMsgObjectAdded\n");
+ //const MIDIObjectAddRemoveNotification *n = (const MIDIObjectAddRemoveNotification*) message;
+ //printf("kMIDIMsgObjectAdded\n");
}
break;
case kMIDIMsgObjectRemoved:
{
- const MIDIObjectAddRemoveNotification *n = (const MIDIObjectAddRemoveNotification*) message;
- printf("kMIDIMsgObjectRemoved\n");
+ //const MIDIObjectAddRemoveNotification *n = (const MIDIObjectAddRemoveNotification*) message;
+ //printf("kMIDIMsgObjectRemoved\n");
}
break;
case kMIDIMsgPropertyChanged:
{
- const MIDIObjectPropertyChangeNotification *n = (const MIDIObjectPropertyChangeNotification*) message;
- printf("kMIDIMsgObjectRemoved\n");
+ //const MIDIObjectPropertyChangeNotification *n = (const MIDIObjectPropertyChangeNotification*) message;
+ //printf("kMIDIMsgObjectRemoved\n");
}
break;
case kMIDIMsgThruConnectionsChanged:
- printf("kMIDIMsgThruConnectionsChanged\n");
+ //printf("kMIDIMsgThruConnectionsChanged\n");
break;
case kMIDIMsgSerialPortOwnerChanged:
- printf("kMIDIMsgSerialPortOwnerChanged\n");
+ //printf("kMIDIMsgSerialPortOwnerChanged\n");
break;
case kMIDIMsgIOError:
- printf("kMIDIMsgIOError\n");
- cleanup();
- //discover();
+ fprintf(stderr, "kMIDIMsgIOError\n");
+ discover();
break;
}
}
@@ -150,19 +150,19 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin
MIDIPacket packet;
size_t rv = _rb[port]->read((uint8_t*)&packet, sizeof(MIDIPacket));
assert(rv == sizeof(MIDIPacket));
- _inputQueue[port].push_back(boost::shared_ptr<CoreMIDIPacket>(new _CoreMIDIPacket (&packet)));
+ _input_queue[port].push_back(boost::shared_ptr<CoreMIDIPacket>(new _CoreMIDIPacket (&packet)));
}
UInt64 start = _time_at_cycle_start;
UInt64 end = AudioConvertNanosToHostTime(AudioConvertHostTimeToNanos(_time_at_cycle_start) + cycle_time_us * 1e3);
- for (CoreMIDIQueue::iterator it = _inputQueue[port].begin (); it != _inputQueue[port].end (); ) {
+ for (CoreMIDIQueue::iterator it = _input_queue[port].begin (); it != _input_queue[port].end (); ) {
if ((*it)->timeStamp < end) {
if ((*it)->timeStamp < start) {
uint64_t dt = AudioConvertHostTimeToNanos(start - (*it)->timeStamp);
//printf("Stale Midi Event dt:%.2fms\n", dt * 1e-6);
if (dt > 1e-4) { // 100ms, maybe too large
- it = _inputQueue[port].erase(it);
+ it = _input_queue[port].erase(it);
continue;
}
time = 0;
@@ -173,7 +173,7 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin
if (s > 0) {
memcpy(d, (*it)->data, s);
}
- _inputQueue[port].erase(it);
+ _input_queue[port].erase(it);
return s;
}
++it;
@@ -204,7 +204,7 @@ CoreMidiIo::send_event (uint32_t port, double reltime_us, const uint8_t *d, cons
assert(s < 256);
memcpy(mp->data, d, s);
- MIDISend(_outputPorts[port], _outputEndPoints[port], &pl);
+ MIDISend(_output_ports[port], _output_endpoints[port], &pl);
return 0;
}
@@ -213,20 +213,20 @@ CoreMidiIo::discover()
{
cleanup();
- assert(!_active && _midiClient);
+ assert(!_active && _midi_client);
ItemCount srcCount = MIDIGetNumberOfSources();
ItemCount dstCount = MIDIGetNumberOfDestinations();
if (srcCount > 0) {
- _inputPorts = (MIDIPortRef *) malloc (srcCount * sizeof(MIDIPortRef));
- _inputEndPoints = (MIDIEndpointRef*) malloc (srcCount * sizeof(MIDIEndpointRef));
- _inputQueue = (CoreMIDIQueue*) calloc (srcCount, sizeof(CoreMIDIQueue));
+ _input_ports = (MIDIPortRef *) malloc (srcCount * sizeof(MIDIPortRef));
+ _input_endpoints = (MIDIEndpointRef*) malloc (srcCount * sizeof(MIDIEndpointRef));
+ _input_queue = (CoreMIDIQueue*) calloc (srcCount, sizeof(CoreMIDIQueue));
_rb = (RingBuffer<uint8_t> **) malloc (srcCount * sizeof(RingBuffer<uint8_t>*));
}
if (dstCount > 0) {
- _outputPorts = (MIDIPortRef *) malloc (dstCount * sizeof(MIDIPortRef));
- _outputEndPoints = (MIDIEndpointRef*) malloc (dstCount * sizeof(MIDIEndpointRef));
+ _output_ports = (MIDIPortRef *) malloc (dstCount * sizeof(MIDIPortRef));
+ _output_endpoints = (MIDIEndpointRef*) malloc (dstCount * sizeof(MIDIEndpointRef));
}
for (ItemCount i = 0; i < srcCount; i++) {
@@ -235,17 +235,18 @@ CoreMidiIo::discover()
CFStringRef port_name;
port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("midi_capture_%lu"), i);
- err = MIDIInputPortCreate (_midiClient, port_name, midiInputCallback, this, &_inputPorts[_n_midi_in]);
+ err = MIDIInputPortCreate (_midi_client, port_name, midiInputCallback, this, &_input_ports[_n_midi_in]);
if (noErr != err) {
fprintf(stderr, "Cannot create Midi Output\n");
// TODO handle errors
continue;
}
+ // TODO get device name/ID
_rb[_n_midi_in] = new RingBuffer<uint8_t>(1024 * sizeof(MIDIPacket));
- _inputQueue[_n_midi_in] = CoreMIDIQueue();
- MIDIPortConnectSource(_inputPorts[_n_midi_in], src, (void*) _rb[_n_midi_in]);
+ _input_queue[_n_midi_in] = CoreMIDIQueue();
+ MIDIPortConnectSource(_input_ports[_n_midi_in], src, (void*) _rb[_n_midi_in]);
CFRelease(port_name);
- _inputEndPoints[_n_midi_in] = src;
+ _input_endpoints[_n_midi_in] = src;
++_n_midi_in;
}
@@ -255,15 +256,16 @@ CoreMidiIo::discover()
port_name = CFStringCreateWithFormat(NULL, NULL, CFSTR("midi_playback_%lu"), i);
OSStatus err;
- err = MIDIOutputPortCreate (_midiClient, port_name, &_outputPorts[_n_midi_out]);
+ err = MIDIOutputPortCreate (_midi_client, port_name, &_output_ports[_n_midi_out]);
if (noErr != err) {
fprintf(stderr, "Cannot create Midi Output\n");
// TODO handle errors
continue;
}
- MIDIPortConnectSource(_outputPorts[_n_midi_out], dst, NULL);
+ // TODO get device name/ID
+ MIDIPortConnectSource(_output_ports[_n_midi_out], dst, NULL);
CFRelease(port_name);
- _outputEndPoints[_n_midi_out] = dst;
+ _output_endpoints[_n_midi_out] = dst;
++_n_midi_out;
}
diff --git a/libs/backends/coreaudio/coremidi_io.h b/libs/backends/coreaudio/coremidi_io.h
index 312b9d171e..9edc77aa9d 100644
--- a/libs/backends/coreaudio/coremidi_io.h
+++ b/libs/backends/coreaudio/coremidi_io.h
@@ -76,7 +76,7 @@ public:
void notify_proc (const MIDINotification *message);
- void setPortChangedCallback (void (changed_callback (void*)), void *arg) {
+ void set_port_changed_callback (void (changed_callback (void*)), void *arg) {
_changed_callback = changed_callback;
_changed_arg = arg;
}
@@ -84,19 +84,20 @@ public:
private:
void cleanup ();
- MIDIClientRef _midiClient;
- MIDIEndpointRef * _inputEndPoints;
- MIDIEndpointRef * _outputEndPoints;
- MIDIPortRef * _inputPorts;
- MIDIPortRef * _outputPorts;
- CoreMIDIQueue * _inputQueue;
+ MIDIClientRef _midi_client;
+ MIDIEndpointRef * _input_endpoints;
+ MIDIEndpointRef * _output_endpoints;
+ MIDIPortRef * _input_ports;
+ MIDIPortRef * _output_ports;
+ CoreMIDIQueue * _input_queue;
+
RingBuffer<uint8_t> ** _rb;
- uint32_t _n_midi_in;
- uint32_t _n_midi_out;
+ uint32_t _n_midi_in;
+ uint32_t _n_midi_out;
- MIDITimeStamp _time_at_cycle_start;
- bool _active;
+ MIDITimeStamp _time_at_cycle_start;
+ bool _active;
void (* _changed_callback) (void*);
void * _changed_arg;
diff --git a/libs/backends/coreaudio/wscript b/libs/backends/coreaudio/wscript
index b0e6f4af12..99d9e66f69 100644
--- a/libs/backends/coreaudio/wscript
+++ b/libs/backends/coreaudio/wscript
@@ -31,3 +31,6 @@ def build(bld):
obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
'ARDOURBACKEND_DLL_EXPORTS', 'COREAUDIO_108'
]
+
+ # OSX 10.6 or later
+ obj.defines += ['COREAUDIO_108']