CoreAudio: subscribe to device-alive property

This notifies the user about device disconnect and properly
shuts down the backend.
This commit is contained in:
Robin Gareus 2023-04-22 19:33:03 +02:00
parent 65c81feb5e
commit a7ca4cf8a1
4 changed files with 60 additions and 6 deletions

View File

@ -60,6 +60,12 @@ static void error_callback_ptr (void *arg)
d->error_callback();
}
static void halted_callback_ptr (void *arg)
{
CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg);
d->halted_callback();
}
static void xrun_callback_ptr (void *arg)
{
CoreAudioBackend *d = static_cast<CoreAudioBackend*> (arg);
@ -544,6 +550,7 @@ CoreAudioBackend::_start (bool for_latency_measurement)
_last_process_start = 0;
_pcmio->set_error_callback (error_callback_ptr, this);
_pcmio->set_halted_callback (halted_callback_ptr, this);
_pcmio->set_buffer_size_callback (buffer_size_callback_ptr, this);
_pcmio->set_sample_rate_callback (sample_rate_callback_ptr, this);
@ -1521,16 +1528,31 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos
}
void
CoreAudioBackend::error_callback ()
CoreAudioBackend::unset_callbacks ()
{
_pcmio->set_error_callback (NULL, NULL);
_pcmio->set_halted_callback (NULL, NULL);
_pcmio->set_sample_rate_callback (NULL, NULL);
_pcmio->set_xrun_callback (NULL, NULL);
_midiio->set_port_changed_callback(NULL, NULL);
}
void
CoreAudioBackend::error_callback ()
{
unset_callbacks ();
engine.halted_callback("CoreAudio Process aborted.");
_active_ca = false;
}
void
CoreAudioBackend::halted_callback ()
{
unset_callbacks ();
engine.halted_callback("Audio device was disconnected or shut down.");
stop ();
}
void
CoreAudioBackend::xrun_callback ()
{
@ -1558,10 +1580,7 @@ CoreAudioBackend::sample_rate_callback ()
#endif
return;
}
_pcmio->set_error_callback (NULL, NULL);
_pcmio->set_sample_rate_callback (NULL, NULL);
_pcmio->set_xrun_callback (NULL, NULL);
_midiio->set_port_changed_callback(NULL, NULL);
unset_callbacks ();
engine.halted_callback("Sample Rate Changed.");
stop();
}

View File

@ -234,6 +234,7 @@ class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl {
// really private, but needing static access:
int process_callback(uint32_t, uint64_t);
void error_callback();
void halted_callback();
void xrun_callback();
void buffer_size_callback();
void sample_rate_callback();
@ -371,6 +372,8 @@ class CoreAudioBackend : public AudioBackend, public PortEngineSharedImpl {
enum DeviceFilter { All, Input, Output, Duplex };
uint32_t name_to_id(std::string, DeviceFilter filter = All) const;
void unset_callbacks ();
/* processing */
float _dsp_load;
ARDOUR::DSPLoadCalculator _dsp_load_calc;

View File

@ -139,6 +139,9 @@ static OSStatus property_callback_ptr (AudioObjectID inObjectID, UInt32 inNumber
case kAudioDevicePropertyNominalSampleRate:
self->sample_rate_callback();
break;
case kAudioDevicePropertyDeviceIsAlive:
self->halted_callback();
break;
default:
break;
}
@ -222,6 +225,7 @@ CoreAudioPCM::CoreAudioPCM ()
, _n_devices (0)
, _process_callback (0)
, _error_callback (0)
, _halted_callback (0)
, _hw_changed_callback (0)
, _xrun_callback (0)
, _buffer_size_callback (0)
@ -266,7 +270,6 @@ CoreAudioPCM::~CoreAudioPCM ()
pthread_mutex_destroy (&_discovery_lock);
}
void
CoreAudioPCM::hw_changed_callback() {
#ifndef NDEBUG
@ -278,6 +281,15 @@ CoreAudioPCM::hw_changed_callback() {
}
}
void
CoreAudioPCM::halted_callback() {
#ifndef NDEBUG
printf("CoreAudio halted callback..\n");
#endif
if (_halted_callback) {
_halted_callback(_halted_arg);
}
}
int
CoreAudioPCM::available_sample_rates(uint32_t device_id, std::vector<float>& sampleRates)
@ -711,12 +723,15 @@ CoreAudioPCM::pcm_stop ()
AudioObjectRemovePropertyListener(_active_device_id, &prop, &property_callback_ptr, this);
prop.mSelector = kAudioDevicePropertyNominalSampleRate;
AudioObjectRemovePropertyListener(_active_device_id, &prop, &property_callback_ptr, this);
prop.mSelector = kAudioDevicePropertyDeviceIsAlive;
AudioObjectRemovePropertyListener(_active_device_id, &prop, &property_callback_ptr, this);
}
#else
if (_active_device_id > 0) {
AudioDeviceRemovePropertyListener(_active_device_id, 0, true, kAudioDeviceProcessorOverload, property_callback_ptr);
AudioDeviceRemovePropertyListener(_active_device_id, 0, true, kAudioDevicePropertyBufferFrameSize, property_callback_ptr);
AudioDeviceRemovePropertyListener(_active_device_id, 0, true, kAudioDevicePropertyNominalSampleRate, property_callback_ptr);
AudioDeviceRemovePropertyListener(_active_device_id, 0, true, kAudioDevicePropertyDeviceIsAlive, property_callback_ptr);
}
#endif
}
@ -746,6 +761,7 @@ CoreAudioPCM::pcm_stop ()
_output_names.clear();
_error_callback = 0;
_halted_callback = 0;
_process_callback = 0;
_xrun_callback = 0;
}
@ -973,6 +989,10 @@ CoreAudioPCM::pcm_start (
err = add_listener (_active_device_id, kAudioDevicePropertyNominalSampleRate, this);
if (err != noErr) { errorMsg="kAudioDevicePropertyNominalSampleRate, Listen"; _state = -9; goto error; }
err = add_listener (_active_device_id, kAudioDevicePropertyDeviceIsAlive, this);
if (err != noErr) { errorMsg="kAudioDevicePropertyNominalSampleRate, Listen"; _state = -9; goto error; }
_samples_per_period = current_buffer_size_id(_active_device_id);
// Setup callback

View File

@ -101,6 +101,14 @@ public:
_error_arg = error_arg;
}
void set_halted_callback (
void ( halted_callback (void*)),
void * halted_arg
) {
_halted_callback = halted_callback;
_halted_arg = halted_arg;
}
void set_hw_changed_callback (
void ( callback (void*)),
void * arg
@ -148,6 +156,7 @@ public:
void buffer_size_callback ();
void sample_rate_callback ();
void hw_changed_callback ();
void halted_callback ();
private:
float current_sample_rate_id (AudioDeviceID id, bool input);
@ -192,6 +201,9 @@ private:
void (* _error_callback) (void*);
void * _error_arg;
void (* _halted_callback) (void*);
void * _halted_arg;
void (* _hw_changed_callback) (void*);
void * _hw_changed_arg;