Fix crash when unplugging USB DAC

This commit is contained in:
badaix 2020-06-03 10:22:39 +02:00
parent b2bf4f2bfe
commit 535e78ff94
2 changed files with 24 additions and 9 deletions

View file

@ -104,18 +104,21 @@ void AlsaPlayer::setHardwareVolume(double volume, bool muted)
catch (const std::exception& e) catch (const std::exception& e)
{ {
LOG(ERROR, LOG_TAG) << "Exception: " << e.what() << "\n"; LOG(ERROR, LOG_TAG) << "Exception: " << e.what() << "\n";
uninitMixer();
} }
} }
bool AlsaPlayer::getHardwareVolume(double& volume, bool& muted) bool AlsaPlayer::getHardwareVolume(double& volume, bool& muted)
{ {
long vol;
int err = 0;
std::lock_guard<std::recursive_mutex> lock(mutex_);
try try
{ {
std::lock_guard<std::recursive_mutex> lock(mutex_);
if (elem_ == nullptr)
throw SnapException("Mixer not initialized");
long vol;
int err = 0;
while (snd_mixer_handle_events(mixer_) > 0) while (snd_mixer_handle_events(mixer_) > 0)
this_thread::sleep_for(1us); this_thread::sleep_for(1us);
long minv, maxv; long minv, maxv;
@ -163,11 +166,15 @@ void AlsaPlayer::waitForEvent()
sd_.async_wait(boost::asio::posix::stream_descriptor::wait_read, [this](const boost::system::error_code& ec) { sd_.async_wait(boost::asio::posix::stream_descriptor::wait_read, [this](const boost::system::error_code& ec) {
if (ec) if (ec)
{ {
// TODO: fd is "Bad" after unplugging/plugging USB DAC, i.e. after init/uninit/init cycle
LOG(DEBUG, LOG_TAG) << "waitForEvent error: " << ec.message() << "\n"; LOG(DEBUG, LOG_TAG) << "waitForEvent error: " << ec.message() << "\n";
return; return;
} }
std::lock_guard<std::recursive_mutex> lock(mutex_); std::lock_guard<std::recursive_mutex> lock(mutex_);
if (ctl_ == nullptr)
return;
unsigned short revents; unsigned short revents;
snd_ctl_poll_descriptors_revents(ctl_, fd_.get(), 1, &revents); snd_ctl_poll_descriptors_revents(ctl_, fd_.get(), 1, &revents);
if (revents & POLLIN || (revents == 0)) if (revents & POLLIN || (revents == 0))
@ -212,15 +219,20 @@ void AlsaPlayer::initMixer()
if (settings_.mixer.mode != ClientSettings::Mixer::Mode::hardware) if (settings_.mixer.mode != ClientSettings::Mixer::Mode::hardware)
return; return;
LOG(DEBUG, LOG_TAG) << "initMixer\n";
std::lock_guard<std::recursive_mutex> lock(mutex_); std::lock_guard<std::recursive_mutex> lock(mutex_);
int err; int err;
if ((err = snd_ctl_open(&ctl_, mixer_device_.c_str(), SND_CTL_READONLY)) < 0) if ((err = snd_ctl_open(&ctl_, mixer_device_.c_str(), SND_CTL_READONLY)) < 0)
throw SnapException("Can't open control for " + mixer_device_ + ", error: " + snd_strerror(err)); throw SnapException("Can't open control for " + mixer_device_ + ", error: " + snd_strerror(err));
if ((err = snd_ctl_subscribe_events(ctl_, 1)) < 0) if ((err = snd_ctl_subscribe_events(ctl_, 1)) < 0)
throw SnapException("Can't subscribe for events for " + mixer_device_ + ", error: " + snd_strerror(err)); throw SnapException("Can't subscribe for events for " + mixer_device_ + ", error: " + snd_strerror(err));
fd_ = std::make_unique<pollfd>(); fd_ = std::unique_ptr<pollfd, std::function<void(pollfd*)>>(new pollfd(), [](pollfd* p) {
close(p->fd);
delete p;
});
err = snd_ctl_poll_descriptors(ctl_, fd_.get(), 1); err = snd_ctl_poll_descriptors(ctl_, fd_.get(), 1);
LOG(DEBUG, LOG_TAG) << "Filled " << err << " poll descriptors, poll descriptor count: " << snd_ctl_poll_descriptors_count(ctl_) << "\n"; LOG(DEBUG, LOG_TAG) << "Filled " << err << " poll descriptors, poll descriptor count: " << snd_ctl_poll_descriptors_count(ctl_) << ", fd: " << fd_->fd
<< "\n";
snd_mixer_selem_id_t* sid; snd_mixer_selem_id_t* sid;
snd_mixer_selem_id_alloca(&sid); snd_mixer_selem_id_alloca(&sid);
@ -387,14 +399,16 @@ void AlsaPlayer::uninitAlsa(bool uninit_mixer)
void AlsaPlayer::uninitMixer() void AlsaPlayer::uninitMixer()
{ {
if (settings_.mixer.mode != ClientSettings::Mixer::Mode::hardware)
return;
LOG(DEBUG, LOG_TAG) << "uninitMixer\n";
std::lock_guard<std::recursive_mutex> lock(mutex_); std::lock_guard<std::recursive_mutex> lock(mutex_);
if (sd_.is_open()) if (sd_.is_open())
{ {
boost::system::error_code ec; boost::system::error_code ec;
sd_.cancel(ec); sd_.cancel(ec);
} }
// std::lock_guard<std::mutex> lock(mutex_);
if (ctl_ != nullptr) if (ctl_ != nullptr)
{ {
snd_ctl_close(ctl_); snd_ctl_close(ctl_);
@ -405,6 +419,7 @@ void AlsaPlayer::uninitMixer()
snd_mixer_close(mixer_); snd_mixer_close(mixer_);
mixer_ = nullptr; mixer_ = nullptr;
} }
fd_ = nullptr;
elem_ = nullptr; elem_ = nullptr;
} }

View file

@ -66,7 +66,7 @@ private:
std::string mixer_name_; std::string mixer_name_;
std::string mixer_device_; std::string mixer_device_;
std::unique_ptr<pollfd> fd_; std::unique_ptr<pollfd, std::function<void(pollfd*)>> fd_;
std::vector<char> buffer_; std::vector<char> buffer_;
snd_pcm_uframes_t frames_; snd_pcm_uframes_t frames_;
boost::asio::posix::stream_descriptor sd_; boost::asio::posix::stream_descriptor sd_;