Commit f85d4d28 authored by Max Kellermann's avatar Max Kellermann

output/alsa: work around dmix non-blocking snd_pcm_drain() bug

See code comment. Bug was reported against MPD, but it's really an alsa-lib bug. https://bugs.musicpd.org/view.php?id=4662
parent b4e4bdcd
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "AlsaOutputPlugin.hxx" #include "AlsaOutputPlugin.hxx"
#include "lib/alsa/NonBlock.hxx" #include "lib/alsa/NonBlock.hxx"
#include "lib/alsa/Version.hxx"
#include "../OutputAPI.hxx" #include "../OutputAPI.hxx"
#include "../Wrapper.hxx" #include "../Wrapper.hxx"
#include "mixer/MixerList.hxx" #include "mixer/MixerList.hxx"
...@@ -108,6 +109,17 @@ class AlsaOutput final ...@@ -108,6 +109,17 @@ class AlsaOutput final
snd_pcm_uframes_t period_frames; snd_pcm_uframes_t period_frames;
/** /**
* Is this a buggy alsa-lib version, which needs a workaround
* for the snd_pcm_drain() bug always returning -EAGAIN? See
* alsa-lib commits fdc898d41135 and e4377b16454f for details.
* This bug was fixed in alsa-lib version 1.1.4.
*
* The workaround is to re-enable blocking mode for the
* snd_pcm_drain() call.
*/
bool work_around_drain_bug;
/**
* After Open(), has this output been activated by a Play() * After Open(), has this output been activated by a Play()
* command? * command?
*/ */
...@@ -988,6 +1000,19 @@ AlsaOutput::SetupOrDop(AudioFormat &audio_format, PcmExport::Params &params) ...@@ -988,6 +1000,19 @@ AlsaOutput::SetupOrDop(AudioFormat &audio_format, PcmExport::Params &params)
#endif #endif
} }
static constexpr bool
MaybeDmix(snd_pcm_type_t type)
{
return type == SND_PCM_TYPE_DMIX || type == SND_PCM_TYPE_PLUG;
}
gcc_pure
static bool
MaybeDmix(snd_pcm_t *pcm)
{
return MaybeDmix(snd_pcm_type(pcm));
}
inline void inline void
AlsaOutput::Open(AudioFormat &audio_format) AlsaOutput::Open(AudioFormat &audio_format)
{ {
...@@ -1012,6 +1037,9 @@ AlsaOutput::Open(AudioFormat &audio_format) ...@@ -1012,6 +1037,9 @@ AlsaOutput::Open(AudioFormat &audio_format)
GetDevice())); GetDevice()));
} }
work_around_drain_bug = MaybeDmix(pcm) &&
GetRuntimeAlsaVersion() < MakeAlsaVersion(1, 1, 4);
snd_pcm_nonblock(pcm, 1); snd_pcm_nonblock(pcm, 1);
#ifdef ENABLE_DSD #ifdef ENABLE_DSD
...@@ -1117,6 +1145,14 @@ AlsaOutput::DrainInternal() ...@@ -1117,6 +1145,14 @@ AlsaOutput::DrainInternal()
} }
/* .. and finally drain the ALSA hardware buffer */ /* .. and finally drain the ALSA hardware buffer */
if (work_around_drain_bug) {
snd_pcm_nonblock(pcm, 0);
bool result = snd_pcm_drain(pcm) != -EAGAIN;
snd_pcm_nonblock(pcm, 1);
return result;
}
return snd_pcm_drain(pcm) != -EAGAIN; return snd_pcm_drain(pcm) != -EAGAIN;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment