cont’d work on the coreaudio backend & cleanup
authorRobin Gareus <robin@gareus.org>
Fri, 6 Mar 2015 02:21:47 +0000 (03:21 +0100)
committerRobin Gareus <robin@gareus.org>
Fri, 6 Mar 2015 05:24:56 +0000 (06:24 +0100)
libs/backends/coreaudio/coreaudio_backend.cc
libs/backends/coreaudio/coreaudio_backend.h
libs/backends/coreaudio/coreaudio_pcmio.cc
libs/backends/coreaudio/coreaudio_pcmio.h
libs/backends/coreaudio/coremidi_io.cc
libs/backends/coreaudio/coremidi_io.h
libs/backends/coreaudio/wscript

index 80f532c313f7ab67afdf6c87052860c7e90c3a37..f4add45ac91726046c1e9aab64a441a5c08ed532 100644 (file)
@@ -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();
+}
 
 /******************************************************************************/
 
index 0460e57476b7531cc761fb38dca090d9a8250166..5e243656ead78ba7e4b7d7025b9b0dadc19afdbe 100644 (file)
@@ -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;
index a1615d8583eebd2bffaf49122e5125aa03619edb..29207d4ffa1c8032d25a6f2d99d068d5f5ef1b23 100644 (file)
  * 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);
+       }
+}
index 179f1aec02b51c9c42fe53cc281c7814d7708a7b..b249dedbf3cbe89de9abe76bca877dea926c4ff0 100644 (file)
@@ -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;
 };
index 9ded1f4e6a120a461eec8659fd61b75f9b9fe49e..750fd76e55bf5ef84b85d91038229ab75033fe44 100644 (file)
@@ -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;
        }
 
index 312b9d171e0a1bf7db7abe7c96c1467c80afc1c5..9edc77aa9d9e1f18e47bea61aede43a2b9b5d44e 100644 (file)
@@ -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;
index b0e6f4af121f9e1b05b3d9fdabccd79a97863bfe..99d9e66f69f2b9fe4426482ff229c14ae98dd0e7 100644 (file)
@@ -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']