diff --git a/NEWS b/NEWS index b943b71d2..91a932e78 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ ver 0.21.2 (not yet released) - ffmpeg: require FFmpeg 3.1 or later - ffmpeg: fix broken sound with certain codecs * output + - alsa: fix high CPU usage with dmix - httpd: fix two crash bugs * mixer - alsa: fix more rounding errors diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx index 801a16fd0..29578ebc8 100644 --- a/src/input/plugins/AlsaInputPlugin.cxx +++ b/src/input/plugins/AlsaInputPlugin.cxx @@ -185,6 +185,8 @@ AlsaInputStream::PrepareSockets() noexcept void AlsaInputStream::DispatchSockets() noexcept { + non_block.DispatchSockets(*this, capture_handle); + const std::lock_guard protect(mutex); auto w = PrepareWriteBuffer(); diff --git a/src/lib/alsa/NonBlock.cxx b/src/lib/alsa/NonBlock.cxx index 589def151..5b6667302 100644 --- a/src/lib/alsa/NonBlock.cxx +++ b/src/lib/alsa/NonBlock.cxx @@ -49,6 +49,30 @@ AlsaNonBlockPcm::PrepareSockets(MultiSocketMonitor &m, snd_pcm_t *pcm) return std::chrono::steady_clock::duration(-1); } +void +AlsaNonBlockPcm::DispatchSockets(MultiSocketMonitor &m, + snd_pcm_t *pcm) noexcept +{ + int count = snd_pcm_poll_descriptors_count(pcm); + if (count <= 0) + return; + + const auto pfds = pfd_buffer.Get(count), end = pfds + count; + + auto *i = pfds; + m.ForEachReturnedEvent([&i, end](SocketDescriptor s, unsigned events){ + if (i >= end) + return; + + i->fd = s.Get(); + i->events = i->revents = events; + ++i; + }); + + unsigned short dummy; + snd_pcm_poll_descriptors_revents(pcm, pfds, i - pfds, &dummy); +} + std::chrono::steady_clock::duration AlsaNonBlockMixer::PrepareSockets(MultiSocketMonitor &m, snd_mixer_t *mixer) noexcept { @@ -67,3 +91,27 @@ AlsaNonBlockMixer::PrepareSockets(MultiSocketMonitor &m, snd_mixer_t *mixer) noe m.ReplaceSocketList(pfds, count); return std::chrono::steady_clock::duration(-1); } + +void +AlsaNonBlockMixer::DispatchSockets(MultiSocketMonitor &m, + snd_mixer_t *mixer) noexcept +{ + int count = snd_mixer_poll_descriptors_count(mixer); + if (count <= 0) + return; + + const auto pfds = pfd_buffer.Get(count), end = pfds + count; + + auto *i = pfds; + m.ForEachReturnedEvent([&i, end](SocketDescriptor s, unsigned events){ + if (i >= end) + return; + + i->fd = s.Get(); + i->events = i->revents = events; + ++i; + }); + + unsigned short dummy; + snd_mixer_poll_descriptors_revents(mixer, pfds, i - pfds, &dummy); +} diff --git a/src/lib/alsa/NonBlock.hxx b/src/lib/alsa/NonBlock.hxx index 8d6e42458..8e9e2c7f2 100644 --- a/src/lib/alsa/NonBlock.hxx +++ b/src/lib/alsa/NonBlock.hxx @@ -42,6 +42,12 @@ public: */ std::chrono::steady_clock::duration PrepareSockets(MultiSocketMonitor &m, snd_pcm_t *pcm); + + /** + * Wrapper for snd_pcm_poll_descriptors_revents(), to be + * called from MultiSocketMonitor::DispatchSockets(). + */ + void DispatchSockets(MultiSocketMonitor &m, snd_pcm_t *pcm) noexcept; }; /** @@ -54,6 +60,12 @@ class AlsaNonBlockMixer { public: std::chrono::steady_clock::duration PrepareSockets(MultiSocketMonitor &m, snd_mixer_t *mixer) noexcept; + + /** + * Wrapper for snd_mixer_poll_descriptors_revents(), to be + * called from MultiSocketMonitor::DispatchSockets(). + */ + void DispatchSockets(MultiSocketMonitor &m, snd_mixer_t *mixer) noexcept; }; #endif diff --git a/src/mixer/plugins/AlsaMixerPlugin.cxx b/src/mixer/plugins/AlsaMixerPlugin.cxx index dbc74d941..f6f8bf290 100644 --- a/src/mixer/plugins/AlsaMixerPlugin.cxx +++ b/src/mixer/plugins/AlsaMixerPlugin.cxx @@ -117,6 +117,8 @@ AlsaMixerMonitor::DispatchSockets() noexcept { assert(mixer != nullptr); + non_block.DispatchSockets(*this, mixer); + int err = snd_mixer_handle_events(mixer); if (err < 0) { FormatError(alsa_mixer_domain, diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx index 02b3dfe86..8d875ed26 100644 --- a/src/output/plugins/AlsaOutputPlugin.cxx +++ b/src/output/plugins/AlsaOutputPlugin.cxx @@ -889,6 +889,8 @@ AlsaOutput::PrepareSockets() noexcept void AlsaOutput::DispatchSockets() noexcept try { + non_block.DispatchSockets(*this, pcm); + { const std::lock_guard lock(mutex);