diff options
author | Robin Gareus <robin@gareus.org> | 2015-03-06 21:26:07 +0100 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2015-03-06 23:26:05 +0100 |
commit | 13bad670facd14ab63dccb8b1a0f1c7b8498e6bf (patch) | |
tree | 231987bfd57d21c5fe23e1fd35b9557102c7c709 | |
parent | 3b941fc0fa23d5612497a99771676ac70fdd10ad (diff) |
more ongoing work on the coreaudio backend
* audio port names
* latency compensation
* xrun reporting
* various fixes and cleanup
-rw-r--r-- | libs/backends/coreaudio/coreaudio_backend.cc | 76 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_backend.h | 1 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_pcmio.cc | 145 | ||||
-rw-r--r-- | libs/backends/coreaudio/coreaudio_pcmio.h | 18 |
4 files changed, 173 insertions, 67 deletions
diff --git a/libs/backends/coreaudio/coreaudio_backend.cc b/libs/backends/coreaudio/coreaudio_backend.cc index fd03ddea50..31ee9636e1 100644 --- a/libs/backends/coreaudio/coreaudio_backend.cc +++ b/libs/backends/coreaudio/coreaudio_backend.cc @@ -42,12 +42,32 @@ std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_audio_device_status; std::vector<AudioBackend::DeviceStatus> CoreAudioBackend::_midi_device_status; +/* static class instance access */ static void hw_changed_callback_ptr (void *arg) { CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg); d->hw_changed_callback(); } +static void error_callback_ptr (void *arg) +{ + CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg); + d->error_callback(); +} + +static void xrun_callback_ptr (void *arg) +{ + CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg); + d->xrun_callback(); +} + +static void midi_port_change (void *arg) +{ + CoreAudioBackend *d = static_cast<CoreAudioBackend *>(arg); + d->coremidi_rediscover (); +} + + CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info) : AudioBackend (e, info) , _run (false) @@ -386,18 +406,6 @@ static int process_callback_ptr (void *arg) return d->process_callback(); } -static void error_callback_ptr (void *arg) -{ - CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg); - d->error_callback(); -} - -static void midi_port_change (void *arg) -{ - CoreAudioBackend *d = static_cast<CoreAudioBackend *>(arg); - d->coremidi_rediscover (); -} - int CoreAudioBackend::_start (bool for_latency_measurement) { @@ -463,13 +471,13 @@ CoreAudioBackend::_start (bool for_latency_measurement) _samples_per_period = _pcmio->sample_per_period(); PBD::warning << _("CoreAudioBackend: samples per period does not match.") << endmsg; } +#endif - if (_pcmio->samplerate() != _samplerate) { - _samplerate = _pcmio->samplerate(); + if (_pcmio->current_sample_rate(name_to_id(_audio_device)) != _samplerate) { + _samplerate = _pcmio->current_sample_rate(name_to_id(_audio_device)); engine.sample_rate_change (_samplerate); PBD::warning << _("CoreAudioBackend: sample rate does not match.") << endmsg; } -#endif _measure_latency = for_latency_measurement; @@ -531,6 +539,7 @@ CoreAudioBackend::_start (bool for_latency_measurement) return -1; } _preinit = false; + _pcmio->set_xrun_callback (xrun_callback_ptr, this); return 0; } @@ -856,31 +865,34 @@ 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 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; + const uint32_t coreaudio_reported_input_latency = _pcmio->get_latency(name_to_id(_audio_device), true); + const uint32_t coreaudio_reported_output_latency = _pcmio->get_latency(name_to_id(_audio_device), false); + +#ifndef NDEBUG + printf("COREAUDIO LATENCY: i:%d, o:%d\n", + coreaudio_reported_input_latency, + coreaudio_reported_output_latency); +#endif + /* audio ports */ - lr.min = lr.max = _samples_per_period + (_measure_latency ? 0 : _systemic_audio_input_latency); - for (int i = 1; i <= a_ins; ++i) { + lr.min = lr.max = _samples_per_period + coreaudio_reported_input_latency + (_measure_latency ? 0 : _systemic_audio_input_latency); + for (int i = 0; i < a_ins; ++i) { char tmp[64]; - snprintf(tmp, sizeof(tmp), "system:capture_%d", i); + snprintf(tmp, sizeof(tmp), "system:capture_%s", _pcmio->cached_port_name(i, true).c_str()); PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal)); if (!p) return -1; set_latency_range (p, false, lr); _system_inputs.push_back(static_cast<CoreBackendPort*>(p)); } - lr.min = lr.max = _samples_per_period + (_measure_latency ? 0 : _systemic_audio_output_latency); - for (int i = 1; i <= a_out; ++i) { + lr.min = lr.max = _samples_per_period + coreaudio_reported_output_latency + (_measure_latency ? 0 : _systemic_audio_output_latency); + for (int i = 0; i < a_out; ++i) { char tmp[64]; - snprintf(tmp, sizeof(tmp), "system:playback_%d", i); + snprintf(tmp, sizeof(tmp), "system:playback_%s", _pcmio->cached_port_name(i, false).c_str()); PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal)); if (!p) return -1; set_latency_range (p, true, lr); @@ -1434,7 +1446,7 @@ CoreAudioBackend::process_callback () /* get audio */ i = 0; - for (std::vector<CoreBackendPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) { + for (std::vector<CoreBackendPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++i) { _pcmio->get_capture_channel (i, (float*)((*it)->get_buffer(n_samples)), n_samples); } @@ -1480,8 +1492,6 @@ CoreAudioBackend::process_callback () const int64_t elapsed_time = clock2 - clock1; _dsp_load = elapsed_time / (float) nominal_time; - //engine.Xrun (); // TODO, if any - /* port-connection change */ post_process(); pthread_mutex_unlock (&_process_callback_mutex); @@ -1496,6 +1506,12 @@ CoreAudioBackend::error_callback () } void +CoreAudioBackend::xrun_callback () +{ + engine.Xrun (); +} + +void CoreAudioBackend::hw_changed_callback () { _reinit_thread_callback = true; diff --git a/libs/backends/coreaudio/coreaudio_backend.h b/libs/backends/coreaudio/coreaudio_backend.h index 5e243656ea..715c067efc 100644 --- a/libs/backends/coreaudio/coreaudio_backend.h +++ b/libs/backends/coreaudio/coreaudio_backend.h @@ -214,6 +214,7 @@ class CoreAudioBackend : public AudioBackend { // really private, but needing static access: int process_callback(); void error_callback(); + void xrun_callback(); void hw_changed_callback(); protected: diff --git a/libs/backends/coreaudio/coreaudio_pcmio.cc b/libs/backends/coreaudio/coreaudio_pcmio.cc index 29207d4ffa..7f9322bc1f 100644 --- a/libs/backends/coreaudio/coreaudio_pcmio.cc +++ b/libs/backends/coreaudio/coreaudio_pcmio.cc @@ -20,25 +20,60 @@ #include "coreaudio_pcmio.h" #ifdef COREAUDIO_108 -static OSStatus hardwarePropertyChangeCallback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) { +static OSStatus hw_changed_callback_ptr(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) { CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg); - self->hwPropertyChange(); + self->hw_changed_callback(); return noErr; } #else -static OSStatus hardwarePropertyChangeCallback (AudioHardwarePropertyID inPropertyID, void* arg) { +static OSStatus hw_changed_callback_ptr (AudioHardwarePropertyID inPropertyID, void* arg) { if (inPropertyID == kAudioHardwarePropertyDevices) { CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg); - self->hwPropertyChange(); + self->hw_changed_callback(); } return noErr; } #endif +#ifdef COREAUDIO_108 +static OSStatus xrun_callback_ptr(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* arg) { + CoreAudioPCM * self = static_cast<CoreAudioPCM*>(arg); + self->xrun_callback(); + return noErr; +} +#else +static OSStatus xrun_callback_ptr( + AudioDeviceID inDevice, + UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + void* inClientData) +{ + CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inClientData); + d->xrun_callback(); + return noErr; +} +#endif + +static OSStatus render_callback_ptr ( + void* inRefCon, + AudioUnitRenderActionFlags* ioActionFlags, + const AudioTimeStamp* inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList* ioData) +{ + CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inRefCon); + return d->render_callback(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); +} + + CoreAudioPCM::CoreAudioPCM () : _auhal (0) , _device_ids (0) , _input_audio_buffer_list (0) + , _active_input (0) + , _active_output (0) , _state (-1) , _capture_channels (0) , _playback_channels (0) @@ -47,6 +82,7 @@ CoreAudioPCM::CoreAudioPCM () , _process_callback (0) , _error_callback (0) , _hw_changed_callback (0) + , _xrun_callback (0) , _device_ins (0) , _device_outs (0) { @@ -61,9 +97,9 @@ CoreAudioPCM::CoreAudioPCM () prop.mSelector = kAudioHardwarePropertyDevices; prop.mScope = kAudioObjectPropertyScopeGlobal; prop.mElement = 0; - AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, hardwarePropertyChangeCallback, this); + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, hw_changed_callback_ptr, this); #else - AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, hardwarePropertyChangeCallback, this); + AudioHardwareAddPropertyListener (kAudioHardwarePropertyDevices, hw_changed_callback_ptr, this); #endif } @@ -80,9 +116,9 @@ CoreAudioPCM::~CoreAudioPCM () prop.mSelector = kAudioHardwarePropertyDevices; prop.mScope = kAudioObjectPropertyScopeGlobal; prop.mElement = 0; - AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &hardwarePropertyChangeCallback, this); + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &hw_changed_callback_ptr, this); #else - AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, hardwarePropertyChangeCallback); + AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, hw_changed_callback_ptr); #endif free(_input_audio_buffer_list); pthread_mutex_destroy (&_discovery_lock); @@ -90,7 +126,8 @@ CoreAudioPCM::~CoreAudioPCM () void -CoreAudioPCM::hwPropertyChange() { +CoreAudioPCM::hw_changed_callback() { + printf("CHANGE..\n"); discover(); // TODO Filter events.. if (_hw_changed_callback) { @@ -305,7 +342,7 @@ CoreAudioPCM::get_stream_latencies(uint32 device_id, bool input, std::vector<uin return; } #ifndef NDEBUG - printf("Stream %d latency: %d\n", i, stream_latency); + printf(" ^ Stream %d latency: %d\n", i, stream_latency); #endif latencies.push_back(stream_latency); } @@ -349,7 +386,8 @@ CoreAudioPCM::get_latency(uint32 device_id, bool input) } #ifndef NDEBUG - printf("Base Latency systemic+safetyoffset = %d+%d\n", lat0, latS); + printf("%s Latency systemic+safetyoffset = %d + %d\n", + input ? "Input" : "Output", lat0, latS); #endif latency = lat0 + latS; @@ -543,11 +581,40 @@ CoreAudioPCM::discover() } void +CoreAudioPCM::xrun_callback () +{ +#ifndef NDEBUG + printf("Coreaudio XRUN\n"); +#endif + if (_xrun_callback) { + _xrun_callback(_xrun_arg); + } +} + +void CoreAudioPCM::pcm_stop () { if (!_auhal) return; AudioOutputUnitStop(_auhal); + if (_state == 0) { +#ifdef COREAUDIO_108 + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioDeviceProcessorOverload; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = 0; + if (_active_output > 0) { + AudioObjectRemovePropertyListener(_active_input, &prop, &xrun_callback_ptr, this); + } + if (_active_input > 0 && _active_output != _active_input) { + AudioObjectRemovePropertyListener(_active_output, &prop, &xrun_callback_ptr, this); + } +#else + AudioDeviceRemovePropertyListener(_active_input, 0 , true, kAudioDeviceProcessorOverload, xrun_callback_ptr); + AudioDeviceRemovePropertyListener(_active_output, 0 , false, kAudioDeviceProcessorOverload, xrun_callback_ptr); +#endif + } + AudioUnitUninitialize(_auhal); #ifdef COREAUDIO_108 AudioComponentInstanceDispose(_auhal); @@ -567,6 +634,7 @@ CoreAudioPCM::pcm_stop () _error_callback = 0; _process_callback = 0; + _xrun_callback = 0; } #ifndef NDEBUG @@ -585,20 +653,6 @@ static void PrintStreamDesc (AudioStreamBasicDescription *inDesc) } #endif -static OSStatus render_callback_ptr ( - void* inRefCon, - AudioUnitRenderActionFlags* ioActionFlags, - const AudioTimeStamp* inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList* ioData) -{ - CoreAudioPCM * d = static_cast<CoreAudioPCM*> (inRefCon); - return d->render_callback(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); -} - - - int CoreAudioPCM::pcm_start ( uint32_t device_id_in, uint32_t device_id_out, @@ -618,6 +672,7 @@ CoreAudioPCM::pcm_start ( _process_arg = process_arg; _max_samples_per_period = samples_per_period; _cur_samples_per_period = 0; + _active_input = _active_output = 0; ComponentResult err; UInt32 uint32val; @@ -715,6 +770,7 @@ CoreAudioPCM::pcm_start ( #endif if (err != noErr) { errorMsg="kAudioUnitProperty_StreamFormat Input"; goto error; } + /* read back stream descriptions */ UInt32 size; size = sizeof(AudioStreamBasicDescription); err = AudioUnitGetProperty(_auhal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, AUHAL_INPUT_ELEMENT, &srcFormat, &size); @@ -733,10 +789,32 @@ CoreAudioPCM::pcm_start ( PrintStreamDesc(&dstFormat); #endif + /* prepare buffers for input */ _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; } + _active_input = _device_ids[device_id_in]; + _active_output = _device_ids[device_id_out]; + +#ifdef COREAUDIO_108 + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioDeviceProcessorOverload; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = 0; + AudioObjectAddPropertyListener(_active_output, &prop, xrun_callback_ptr, this); + if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Output"; goto error; } + if (_active_input != _active_output) { + AudioObjectAddPropertyListener(_active_input, &prop, xrun_callback_ptr, this); + if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Input"; goto error; } + } +#else + err = AudioDeviceAddPropertyListener(_device_ids[device_id_out], 0 , false, kAudioDeviceProcessorOverload, xrun_callback_ptr, this); + if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Output"; goto error; } + err = AudioDeviceAddPropertyListener(_device_ids[device_id_in], 0 , true, kAudioDeviceProcessorOverload, xrun_callback_ptr, this); + if (err != noErr) { errorMsg="kAudioDeviceProcessorOverload, Input"; goto error; } +#endif + // Setup callbacks AURenderCallbackStruct renderCallback; memset (&renderCallback, 0, sizeof (renderCallback)); @@ -748,6 +826,7 @@ CoreAudioPCM::pcm_start ( &renderCallback, sizeof (renderCallback)); if (err != noErr) { errorMsg="kAudioUnitProperty_SetRenderCallback"; goto error; } + /* setup complete, now get going.. */ if (AudioOutputUnitStart(_auhal) == noErr) { _input_names.clear(); _output_names.clear(); @@ -762,6 +841,7 @@ error: fprintf(stderr, "CoreaudioPCM Error: %c%c%c%c %s\n", rv[0], rv[1], rv[2], rv[3], errorMsg.c_str()); pcm_stop(); _state = -3; + _active_input = _active_output = 0; return -1; } @@ -810,7 +890,7 @@ CoreAudioPCM::cache_port_names(uint32 device_id, bool input) &name); #endif } - + bool decoded = false; char* cstr_name = 0; if (err == kAudioHardwareNoError) { @@ -820,19 +900,14 @@ CoreAudioPCM::cache_port_names(uint32 device_id, bool input) decoded = CFStringGetCString(name, cstr_name, maxSize, kCFStringEncodingUTF8); } - ss << (c + 1) << " - "; + ss << (c + 1); if (cstr_name && decoded && (0 != std::strlen(cstr_name) ) ) { - ss << cstr_name; - } else { - if (input) { - ss << "Input " << (c + 1); - } else { - ss << "Output " << (c + 1); - } + ss << " - " << cstr_name; } - +#if 0 printf("%s %d Name: %s\n", input ? "Input" : "Output", c+1, ss.str().c_str()); +#endif if (input) { _input_names.push_back (ss.str()); diff --git a/libs/backends/coreaudio/coreaudio_pcmio.h b/libs/backends/coreaudio/coreaudio_pcmio.h index b249dedbf3..6bb3d08356 100644 --- a/libs/backends/coreaudio/coreaudio_pcmio.h +++ b/libs/backends/coreaudio/coreaudio_pcmio.h @@ -64,7 +64,6 @@ public: void * process_arg ); - // TODO: combine callbacks below, add a enum type void set_error_callback ( void ( error_callback (void*)), void * error_arg @@ -80,6 +79,13 @@ public: _hw_changed_callback = callback; _hw_changed_arg = arg; } + void set_xrun_callback ( + void ( callback (void*)), + void * arg + ) { + _xrun_callback = callback; + _xrun_arg = arg; + } // must be called from process_callback; int get_capture_channel (uint32_t chn, float *input, uint32_t n_samples); @@ -94,7 +100,8 @@ public: UInt32 inNumberFrames, AudioBufferList* ioData); - void hwPropertyChange(); + void xrun_callback (); + void hw_changed_callback (); private: int set_device_sample_rate (uint32 device_id, float rate, bool input); @@ -106,6 +113,9 @@ private: AudioBufferList* _input_audio_buffer_list; AudioBufferList* _output_audio_buffer_list; + AudioDeviceID _active_input; + AudioDeviceID _active_output; + int _state; uint32_t _max_samples_per_period; @@ -124,6 +134,10 @@ private: void (* _hw_changed_callback) (void*); void * _hw_changed_arg; + void (* _xrun_callback) (void*); + void * _xrun_arg; + + // TODO proper device info struct std::map<size_t, std::string> _devices; uint32_t * _device_ins; |