13
0

ALSA: add locks to safely add/remove MIDI devices

Theoretically this could be lock-free by using a queue of device
ports to be added/remove in sync in the process-callback, but
realistically adding/removing devices doesn't have to be rt-safe.
This commit is contained in:
Robin Gareus 2019-01-14 22:07:51 +01:00
parent 8f9e63575f
commit 8b71967be9
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 26 additions and 2 deletions

View File

@ -78,6 +78,7 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
{
_instance_name = s_instance_name;
pthread_mutex_init (&_port_callback_mutex, 0);
pthread_mutex_init (&_device_port_mutex, 0);
_input_audio_device_info.valid = false;
_output_audio_device_info.valid = false;
@ -87,6 +88,7 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
AlsaAudioBackend::~AlsaAudioBackend ()
{
pthread_mutex_destroy (&_port_callback_mutex);
pthread_mutex_destroy (&_device_port_mutex);
}
/* AUDIOBACKEND API */
@ -474,6 +476,7 @@ AlsaAudioBackend::update_systemic_audio_latencies ()
void
AlsaAudioBackend::update_systemic_midi_latencies ()
{
pthread_mutex_lock (&_device_port_mutex);
uint32_t i = 0;
for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
assert (_rmidi_out.size() > i);
@ -495,6 +498,7 @@ AlsaAudioBackend::update_systemic_midi_latencies ()
lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency);
set_latency_range (*it, true, lr);
}
pthread_mutex_unlock (&_device_port_mutex);
update_latencies ();
}
@ -682,6 +686,7 @@ AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable
register_system_midi_ports(device);
} else {
// remove all ports provided by the given device
pthread_mutex_lock (&_device_port_mutex);
uint32_t i = 0;
for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end ();) {
assert (_rmidi_out.size() > i);
@ -705,6 +710,7 @@ AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable
_rmidi_in.erase (_rmidi_in.begin() + i);
delete rm;
}
pthread_mutex_unlock (&_device_port_mutex);
}
update_systemic_midi_latencies ();
}
@ -1540,12 +1546,14 @@ AlsaAudioBackend::update_system_port_latecies ()
(*it)->update_connected_latency (false);
}
pthread_mutex_lock (&_device_port_mutex);
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it) {
(*it)->update_connected_latency (true);
}
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
(*it)->update_connected_latency (false);
}
pthread_mutex_unlock (&_device_port_mutex);
for (AudioSlaves::iterator s = _slaves.begin (); s != _slaves.end (); ++s) {
if ((*s)->dead) {
@ -1648,7 +1656,9 @@ AlsaAudioBackend::register_system_midi_ports(const std::string device)
static_cast<AlsaMidiPort*>(p)->set_n_periods(_periods_per_cycle); // TODO check MIDI alignment
AlsaPort *ap = static_cast<AlsaPort*>(p);
ap->set_pretty_name (replace_name_io (i->first, false));
pthread_mutex_lock (&_device_port_mutex);
_system_midi_out.push_back (ap);
pthread_mutex_unlock (&_device_port_mutex);
_rmidi_out.push_back (mout);
}
}
@ -1687,7 +1697,9 @@ AlsaAudioBackend::register_system_midi_ports(const std::string device)
set_latency_range (p, false, lr);
AlsaPort *ap = static_cast<AlsaPort*>(p);
ap->set_pretty_name (replace_name_io (i->first, true));
pthread_mutex_lock (&_device_port_mutex);
_system_midi_in.push_back (ap);
pthread_mutex_unlock (&_device_port_mutex);
_rmidi_in.push_back (midin);
}
}
@ -2170,6 +2182,8 @@ AlsaAudioBackend::main_process_thread ()
}
}
/* only used when adding/removing MIDI device/system ports */
pthread_mutex_lock (&_device_port_mutex);
/* de-queue incoming midi*/
i = 0;
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
@ -2186,6 +2200,7 @@ AlsaAudioBackend::main_process_thread ()
}
rm->sync_time (clock1);
}
pthread_mutex_unlock (&_device_port_mutex);
for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
@ -2199,6 +2214,8 @@ AlsaAudioBackend::main_process_thread ()
return 0;
}
/* only used when adding/removing MIDI device/system ports */
pthread_mutex_lock (&_device_port_mutex);
for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
static_cast<AlsaMidiPort*>(*it)->next_period();
}
@ -2214,6 +2231,7 @@ AlsaAudioBackend::main_process_thread ()
rm->send_event (mit->timestamp (), mit->data (), mit->size ());
}
}
pthread_mutex_unlock (&_device_port_mutex);
/* write back audio */
i = 0;
@ -2265,6 +2283,7 @@ AlsaAudioBackend::main_process_thread ()
clock1 = g_get_monotonic_time();
uint32_t i = 0;
pthread_mutex_lock (&_device_port_mutex);
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
static_cast<AlsaMidiBuffer*>((*it)->get_buffer(0))->clear ();
AlsaMidiIn *rm = _rmidi_in.at(i);
@ -2280,6 +2299,7 @@ AlsaAudioBackend::main_process_thread ()
}
rm->sync_time (clock1);
}
pthread_mutex_unlock (&_device_port_mutex);
_last_process_start = 0;
if (engine.process_callback (_samples_per_period)) {
@ -2289,10 +2309,12 @@ AlsaAudioBackend::main_process_thread ()
}
// drop all outgoing MIDI messages
pthread_mutex_lock (&_device_port_mutex);
for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
void *bptr = (*it)->get_buffer(0);
midi_clear(bptr);
void *bptr = (*it)->get_buffer(0);
midi_clear(bptr);
}
pthread_mutex_unlock (&_device_port_mutex);
_dsp_load = 1.0;
reset_dll = true;

View File

@ -393,6 +393,8 @@ class AlsaAudioBackend : public AudioBackend {
pthread_t _midi_device_thread_id;
bool _midi_device_thread_active;
pthread_mutex_t _device_port_mutex;
/* processing */
float _dsp_load;
ARDOUR::DSPLoadCalculator _dsp_load_calc;