summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2018-11-08 14:29:04 +0100
committerMax Kellermann <max@musicpd.org>2018-11-11 12:37:29 +0100
commitfee75dc766995d9946af03b40861f19412b5edd9 (patch)
tree242adc4b5e923f637cfc1df9ca3c38dd54094856
parentba5c856f154fcfbbb6643e32e020c1c3bc2e8feb (diff)
{output,mixer}/alsa: use snd_pcm_poll_descriptors_revents()
This call was missing, causing very high CPU usage when the ALSA output plugin was used with dmix. Closes #391
-rw-r--r--NEWS1
-rw-r--r--src/input/plugins/AlsaInputPlugin.cxx2
-rw-r--r--src/lib/alsa/NonBlock.cxx48
-rw-r--r--src/lib/alsa/NonBlock.hxx12
-rw-r--r--src/mixer/plugins/AlsaMixerPlugin.cxx2
-rw-r--r--src/output/plugins/AlsaOutputPlugin.cxx2
6 files changed, 67 insertions, 0 deletions
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<Mutex> 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<Mutex> lock(mutex);