From: Steinar H. Gunderson Date: Sat, 10 Sep 2016 14:42:46 +0000 (+0200) Subject: If a dead device comes back, put it into the right slot. X-Git-Tag: 1.4.0~56 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=e4c99b681aceb0d960f1d56acc9dafc83643854b If a dead device comes back, put it into the right slot. This fulfills one of the basic goals of hotplug, namely that a sound card can disappear (ie., lost cable), be replugged and then safely come back without any manual intervention. --- diff --git a/alsa_input.cpp b/alsa_input.cpp index cf9c69f..78faaf3 100644 --- a/alsa_input.cpp +++ b/alsa_input.cpp @@ -450,16 +450,24 @@ ALSAPool::ProbeResult ALSAPool::probe_device_once(unsigned card_index, unsigned snd_ctl_card_info_alloca(&card_info); snd_ctl_card_info(ctl, card_info); - lock_guard lock(mu); - unsigned internal_dev_index = find_free_device_index(); - devices[internal_dev_index].address = address; - devices[internal_dev_index].name = snd_ctl_card_info_get_name(card_info); - devices[internal_dev_index].info = snd_pcm_info_get_name(pcm_info); - devices[internal_dev_index].num_channels = num_channels; - devices[internal_dev_index].state = Device::State::READY; + string name = snd_ctl_card_info_get_name(card_info); + string info = snd_pcm_info_get_name(pcm_info); + + unsigned internal_dev_index; + { + lock_guard lock(mu); + internal_dev_index = find_free_device_index(name, info, num_channels, address); + devices[internal_dev_index].address = address; + devices[internal_dev_index].name = name; + devices[internal_dev_index].info = info; + devices[internal_dev_index].num_channels = num_channels; + // Note: Purposefully does not overwrite held. + } fprintf(stderr, "%s: Probed successfully.\n", address); + reset_device(internal_dev_index); // Restarts it if it is held (ie., we just replaced a dead card). + return ALSAPool::ProbeResult::SUCCESS; } @@ -570,16 +578,47 @@ void ALSAPool::set_card_state(unsigned index, ALSAPool::Device::State state) ; } -unsigned ALSAPool::find_free_device_index() +unsigned ALSAPool::find_free_device_index(const string &name, const string &info, unsigned num_channels, const string &address) { + // First try to find an exact match on a dead card. + for (unsigned i = 0; i < devices.size(); ++i) { + if (devices[i].state == Device::State::DEAD && + devices[i].address == address && + devices[i].name == name && + devices[i].info == info && + devices[i].num_channels == num_channels) { + devices[i].state = Device::State::READY; + return i; + } + } + + // Then try to find a match on everything but the address + // (probably that devices were plugged back in a different order). + // If we have two cards that are equal, this might get them mixed up, + // but we don't have anything better. + for (unsigned i = 0; i < devices.size(); ++i) { + if (devices[i].state == Device::State::DEAD && + devices[i].name == name && + devices[i].info == info && + devices[i].num_channels == num_channels) { + devices[i].state = Device::State::READY; + return i; + } + } + + // OK, so we didn't find a match; see if there are any empty slots. for (unsigned i = 0; i < devices.size(); ++i) { if (devices[i].state == Device::State::EMPTY) { devices[i].state = Device::State::READY; + devices[i].held = false; return i; } } + + // Failing that, we just insert the new device at the end. Device new_dev; new_dev.state = Device::State::READY; + new_dev.held = false; devices.push_back(new_dev); inputs.emplace_back(nullptr); return devices.size() - 1; diff --git a/alsa_input.h b/alsa_input.h index a93b984..4638e4b 100644 --- a/alsa_input.h +++ b/alsa_input.h @@ -184,7 +184,10 @@ private: // Must be called with held. Will allocate a new entry if needed. // The returned entry will be set to READY state. - unsigned find_free_device_index(); + unsigned find_free_device_index(const std::string &name, + const std::string &info, + unsigned num_channels, + const std::string &address); friend class ALSAInput; };