diff options
author | Robin Gareus <robin@gareus.org> | 2015-03-06 03:21:47 +0100 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2015-03-06 06:24:56 +0100 |
commit | 6b87e706ebcc8fb45f8ae5b978b661f1912d1f9c (patch) | |
tree | a2cfd1088c87df2ff21fcedce4217e6199a6fd5f | |
parent | 408090adce65f6a23e1e4b7afbd26f0cd6177e88 (diff) |
cont’d work on the coreaudio backend & cleanup
-rw-r--r-- | libs/backends/coreaudio/coreaudio_backend.cc | 121 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_backend.h | 11 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_pcmio.cc | 841 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_pcmio.h | 50 | ||||
-rw-r--r-- | libs/backends/coreaudio/coremidi_io.cc | 94 | ||||
-rw-r--r-- | libs/backends/coreaudio/coremidi_io.h | 23 | ||||
-rw-r--r-- | libs/backends/coreaudio/wscript | 3 |
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"), ¬ifyProc, this, &_midiClient); + err = MIDIClientCreate(CFSTR("Ardour"), ¬ifyProc, 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'] |