CoreAudio fwheelin’ state-machine cleanup etc.
This commit is contained in:
parent
95558b5878
commit
2657992ebb
@ -105,6 +105,8 @@ CoreAudioBackend::CoreAudioBackend (AudioEngine& e, AudioBackendInfo& info)
|
||||
_instance_name = s_instance_name;
|
||||
pthread_mutex_init (&_port_callback_mutex, 0);
|
||||
pthread_mutex_init (&_process_callback_mutex, 0);
|
||||
pthread_mutex_init (&_freewheel_mutex, 0);
|
||||
pthread_cond_init (&_freewheel_signal, 0);
|
||||
|
||||
_pcmio = new CoreAudioPCM ();
|
||||
_midiio = new CoreMidiIo ();
|
||||
@ -119,6 +121,8 @@ CoreAudioBackend::~CoreAudioBackend ()
|
||||
delete _midiio; _midiio = 0;
|
||||
pthread_mutex_destroy (&_port_callback_mutex);
|
||||
pthread_mutex_destroy (&_process_callback_mutex);
|
||||
pthread_mutex_destroy (&_freewheel_mutex);
|
||||
pthread_cond_destroy (&_freewheel_signal);
|
||||
}
|
||||
|
||||
/* AUDIOBACKEND API */
|
||||
@ -502,7 +506,7 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||
if (_midi_driver_option == _("CoreMidi")) {
|
||||
_midiio->set_enabled(true);
|
||||
_midiio->set_port_changed_callback(midi_port_change, this);
|
||||
_midiio->start();
|
||||
_midiio->start(); // triggers port discovery, callback coremidi_rediscover()
|
||||
}
|
||||
|
||||
if (register_system_audio_ports()) {
|
||||
@ -520,8 +524,6 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||
return -1;
|
||||
}
|
||||
|
||||
engine.reconnect_ports ();
|
||||
|
||||
if (pthread_create (&_freeewheel_thread, NULL, pthread_freewheel, this))
|
||||
{
|
||||
PBD::error << _("CoreAudioBackend: failed to create process thread.") << endmsg;
|
||||
@ -553,8 +555,16 @@ CoreAudioBackend::_start (bool for_latency_measurement)
|
||||
_run = false;
|
||||
return -1;
|
||||
}
|
||||
_preinit = false;
|
||||
|
||||
engine.reconnect_ports ();
|
||||
|
||||
// force an initial registration_callback() & latency re-compute
|
||||
_port_change_flag = true;
|
||||
pre_process ();
|
||||
|
||||
// all systems go.
|
||||
_pcmio->set_xrun_callback (xrun_callback_ptr, this);
|
||||
_preinit = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -572,6 +582,10 @@ CoreAudioBackend::stop ()
|
||||
_midiio->set_port_changed_callback(NULL, NULL);
|
||||
_midiio->stop();
|
||||
|
||||
pthread_mutex_lock (&_freewheel_mutex);
|
||||
pthread_cond_signal (&_freewheel_signal);
|
||||
pthread_mutex_unlock (&_freewheel_mutex);
|
||||
|
||||
if (pthread_join (_freeewheel_thread, &status)) {
|
||||
PBD::error << _("CoreAudioBackend: failed to terminate.") << endmsg;
|
||||
return -1;
|
||||
@ -592,6 +606,11 @@ CoreAudioBackend::freewheel (bool onoff)
|
||||
return 0;
|
||||
}
|
||||
_freewheeling = onoff;
|
||||
// wake up freewheeling thread
|
||||
if (0 == pthread_mutex_trylock (&_freewheel_mutex)) {
|
||||
pthread_cond_signal (&_freewheel_signal);
|
||||
pthread_mutex_unlock (&_freewheel_mutex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -882,8 +901,8 @@ CoreAudioBackend::register_system_audio_ports()
|
||||
{
|
||||
LatencyRange lr;
|
||||
|
||||
const int a_ins = _n_inputs;
|
||||
const int a_out = _n_outputs;
|
||||
const uint32_t a_ins = _n_inputs;
|
||||
const uint32_t a_out = _n_outputs;
|
||||
|
||||
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);
|
||||
@ -896,7 +915,7 @@ CoreAudioBackend::register_system_audio_ports()
|
||||
|
||||
/* audio ports */
|
||||
lr.min = lr.max = coreaudio_reported_input_latency + (_measure_latency ? 0 : _systemic_audio_input_latency);
|
||||
for (int i = 0; i < a_ins; ++i) {
|
||||
for (uint32_t i = 0; i < a_ins; ++i) {
|
||||
char tmp[64];
|
||||
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));
|
||||
@ -906,7 +925,7 @@ CoreAudioBackend::register_system_audio_ports()
|
||||
}
|
||||
|
||||
lr.min = lr.max = coreaudio_reported_output_latency + (_measure_latency ? 0 : _systemic_audio_output_latency);
|
||||
for (int i = 0; i < a_out; ++i) {
|
||||
for (uint32_t i = 0; i < a_out; ++i) {
|
||||
char tmp[64];
|
||||
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));
|
||||
@ -1357,7 +1376,7 @@ CoreAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
|
||||
}
|
||||
|
||||
void
|
||||
CoreAudioBackend::post_process ()
|
||||
CoreAudioBackend::pre_process ()
|
||||
{
|
||||
bool connections_changed = false;
|
||||
bool ports_changed = false;
|
||||
@ -1394,38 +1413,63 @@ CoreAudioBackend::freewheel_thread ()
|
||||
{
|
||||
_active_fw = true;
|
||||
bool first_run = false;
|
||||
/* Freewheeling - use for export. The first call to
|
||||
* engine.process_callback() after engine.freewheel_callback will
|
||||
* if the first export cycle.
|
||||
* For reliable precise export timing, the calls need to be in sync.
|
||||
*
|
||||
* Furthermore we need to make sure the registered process thread
|
||||
* is correct.
|
||||
*
|
||||
* _freewheeling = GUI thread state as set by ::freewheel()
|
||||
* _freewheel = in sync here (export thread)
|
||||
*/
|
||||
pthread_mutex_lock (&_freewheel_mutex);
|
||||
while (_run) {
|
||||
// check if we should run,
|
||||
if (_freewheeling != _freewheel) {
|
||||
if (!_freewheeling) {
|
||||
// handshake w/ coreaudio
|
||||
_reinit_thread_callback = true;
|
||||
_freewheel_ack = false;
|
||||
// prepare leaving freewheeling mode
|
||||
_freewheel = false; // first mark as disabled
|
||||
_reinit_thread_callback = true; // hand over _main_thread
|
||||
_freewheel_ack = false; // prepare next handshake
|
||||
_midiio->set_enabled(true);
|
||||
} else {
|
||||
first_run = true;
|
||||
_freewheel = true;
|
||||
}
|
||||
|
||||
engine.freewheel_callback (_freewheeling);
|
||||
first_run = true;
|
||||
_freewheel = _freewheeling;
|
||||
}
|
||||
|
||||
if (!_freewheel || !_freewheel_ack) {
|
||||
// TODO use a pthread sync/sleep
|
||||
Glib::usleep(200000);
|
||||
// wait for a change, we use a timed wait to
|
||||
// terminate early in case some error sets _run = 0
|
||||
struct timeval tv;
|
||||
struct timespec ts;
|
||||
gettimeofday (&tv, NULL);
|
||||
ts.tv_sec = tv.tv_sec + 3;
|
||||
ts.tv_nsec = 0;
|
||||
pthread_cond_timedwait (&_freewheel_signal, &_freewheel_mutex, &ts);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (first_run) {
|
||||
// tell the engine we're ready to GO.
|
||||
engine.freewheel_callback (_freewheeling);
|
||||
first_run = false;
|
||||
_main_thread = pthread_self();
|
||||
AudioEngine::thread_init_callback (this);
|
||||
_midiio->set_enabled(false);
|
||||
}
|
||||
|
||||
post_process();
|
||||
// process port updates first in every cycle.
|
||||
pre_process();
|
||||
|
||||
// prevent coreaudio device changes
|
||||
pthread_mutex_lock (&_process_callback_mutex);
|
||||
// Freewheelin'
|
||||
|
||||
/* Freewheelin' */
|
||||
|
||||
// clear input buffers
|
||||
for (std::vector<CoreBackendPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
|
||||
memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
|
||||
}
|
||||
@ -1443,9 +1487,12 @@ CoreAudioBackend::freewheel_thread ()
|
||||
Glib::usleep (100); // don't hog cpu
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&_freewheel_mutex);
|
||||
|
||||
_active_fw = false;
|
||||
|
||||
if (_run) {
|
||||
// engine.process_callback() returner error
|
||||
engine.halted_callback("CoreAudio Freehweeling aborted.");
|
||||
}
|
||||
return 0;
|
||||
@ -1460,14 +1507,21 @@ CoreAudioBackend::process_callback ()
|
||||
_active_ca = true;
|
||||
|
||||
if (_run && _freewheel && !_freewheel_ack) {
|
||||
_freewheel_ack = true;
|
||||
// acknowledge freewheeling; hand-over thread ID
|
||||
pthread_mutex_lock (&_freewheel_mutex);
|
||||
if (_freewheel) _freewheel_ack = true;
|
||||
pthread_cond_signal (&_freewheel_signal);
|
||||
pthread_mutex_unlock (&_freewheel_mutex);
|
||||
}
|
||||
|
||||
if (!_run || _freewheel || _preinit) {
|
||||
// NB if we return 1, the output is
|
||||
// zeroed by the coreaudio callback
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pthread_mutex_trylock (&_process_callback_mutex)) {
|
||||
// block while devices are added/removed
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1475,13 +1529,10 @@ CoreAudioBackend::process_callback ()
|
||||
_reinit_thread_callback = false;
|
||||
_main_thread = pthread_self();
|
||||
AudioEngine::thread_init_callback (this);
|
||||
|
||||
manager.registration_callback();
|
||||
manager.graph_order_callback();
|
||||
}
|
||||
|
||||
/* port-connection change */
|
||||
post_process();
|
||||
pre_process();
|
||||
|
||||
const uint32_t n_samples = _pcmio->n_samples();
|
||||
|
||||
|
@ -300,7 +300,7 @@ class CoreAudioBackend : public AudioBackend {
|
||||
void* get_buffer (PortHandle, pframes_t);
|
||||
|
||||
void* freewheel_thread ();
|
||||
void post_process ();
|
||||
void pre_process ();
|
||||
void coremidi_rediscover ();
|
||||
|
||||
private:
|
||||
@ -317,8 +317,12 @@ class CoreAudioBackend : public AudioBackend {
|
||||
bool _freewheel_ack;
|
||||
bool _reinit_thread_callback;
|
||||
bool _measure_latency;
|
||||
|
||||
pthread_mutex_t _process_callback_mutex;
|
||||
|
||||
pthread_mutex_t _freewheel_mutex;
|
||||
pthread_cond_t _freewheel_signal;
|
||||
|
||||
static std::vector<std::string> _midi_options;
|
||||
static std::vector<AudioBackend::DeviceStatus> _audio_device_status;
|
||||
static std::vector<AudioBackend::DeviceStatus> _midi_device_status;
|
||||
|
Loading…
Reference in New Issue
Block a user