diff --git a/daemon/src/audio/alsa/alsalayer.cpp b/daemon/src/audio/alsa/alsalayer.cpp index 6a0fd0c86cd6ac7b538f5d7ef4a027a7e2f5b8d5..56b1ae2a4cc285451f86690a485addbe0370ffc6 100644 --- a/daemon/src/audio/alsa/alsalayer.cpp +++ b/daemon/src/audio/alsa/alsalayer.cpp @@ -101,11 +101,20 @@ AlsaLayer::~AlsaLayer (void) closePlaybackStream(); } +// Retry approach taken from pa_linux_alsa.c, part of PortAudio bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stream_t stream) { - int err = snd_pcm_open(pcm, dev.c_str(),stream, 0); + static const int MAX_RETRIES = 100; + int err = snd_pcm_open(pcm, dev.c_str(), stream, 0); + // Retry if busy, since dmix plugin may not have released the device yet + for (int tries = 0; tries < MAX_RETRIES and err == -EBUSY; ++tries) { + usleep(10000); + err = snd_pcm_open(pcm, dev.c_str(), stream, 0); + } + if (err < 0) { - _error("Alsa: couldn't open device %s : %s", dev.c_str(), snd_strerror(err)); + _error("Alsa: couldn't open device %s : %s", dev.c_str(), + snd_strerror(err)); return false; } @@ -141,9 +150,8 @@ AlsaLayer::startStream (void) if (not is_capture_open_) { is_capture_open_ = openDevice(&captureHandle_, pcmc, SND_PCM_STREAM_CAPTURE); - if (not is_capture_open_) { + if (not is_capture_open_) Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_CAPTURE_DEVICE); - } } if (not is_playback_open_) { diff --git a/daemon/src/audio/alsa/alsalayer.h b/daemon/src/audio/alsa/alsalayer.h index 9c14a1e6c2abc8e39a86f0543ac076975c3de385..a406667a0075926c1fdb9a05a0bb68cba05e5a70 100644 --- a/daemon/src/audio/alsa/alsalayer.h +++ b/daemon/src/audio/alsa/alsalayer.h @@ -146,6 +146,11 @@ class AlsaLayer : public AudioLayer private: + /** + * Calls snd_pcm_open and retries if device is busy, since dmix plugin + * will often hold on to a device temporarily after it has been opened + * and closed. + */ bool openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stream_t stream); /** diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 6e7c93b38128451f61e9e7227baa73b5ca1dccff..11713224eda502f61d321476c0270ae5c271d2da 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -1994,6 +1994,7 @@ void ManagerImpl::setAudioPlugin (const std::string& audioPlugin) // Recreate audio driver with new settings delete _audiodriver; _audiodriver = new AlsaLayer; + assert(preferences.getAudioApi() == ALSA_API_STR); if (wasStarted) _audiodriver->startStream(); @@ -2033,6 +2034,7 @@ void ManagerImpl::setAudioDevice (const int index, int streamType) // Recreate audio driver with new settings delete _audiodriver; _audiodriver = new AlsaLayer; + assert(preferences.getAudioApi() == ALSA_API_STR); if (wasStarted) _audiodriver->startStream();