summaryrefslogtreecommitdiffstats
path: root/audio/out
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-05-11 19:00:05 +0200
committerwm4 <wm4@nowhere>2014-05-11 19:00:05 +0200
commit665c8b59be236a1dbe3dff12afc36946ca825830 (patch)
tree8cb8970b788425595d733e9b2d6c3f10f2bed459 /audio/out
parentfd56e2dbe6aefb637af222e111d052c507883c7d (diff)
downloadmpv-665c8b59be236a1dbe3dff12afc36946ca825830.tar.bz2
mpv-665c8b59be236a1dbe3dff12afc36946ca825830.tar.xz
audio/out: avoid wakeup feedback loop
When the audio buffer went low, but could not be refilled yet, it could happen that the AO playback thread and the decode thread could enter a wakeup feedback loop, causing up to 100% CPU usage doing nothing. This happened because the decoder thread would wake up the AO thread when writing 0 bytes of newly decoded data, and the AO thread in reaction wakes up the decoder thread after writing 0 bytes to the AO buffer. Fix this by waking up the decoder thread only if data was actually played or queued. (This will still cause some redundant wakeups, but will eventually settle down, reducing CPU usage close to ideal.)
Diffstat (limited to 'audio/out')
-rw-r--r--audio/out/push.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/audio/out/push.c b/audio/out/push.c
index 225b8b22d2..8ec8ba28ca 100644
--- a/audio/out/push.c
+++ b/audio/out/push.c
@@ -49,6 +49,7 @@ struct ao_push_state {
struct mp_audio_buffer *buffer;
+ bool newdata;
bool terminate;
bool playing;
@@ -185,6 +186,8 @@ static int play(struct ao *ao, void **data, int samples, int flags)
audio.planes[n] = data[n];
audio.samples = write_samples;
mp_audio_buffer_append(p->buffer, &audio);
+ if (write_samples > 0)
+ p->newdata = true;
p->final_chunk = !!(flags & AOPLAY_FINAL_CHUNK);
p->playing = true;
@@ -216,8 +219,10 @@ static int ao_play_data(struct ao *ao)
MP_WARN(ao, "Audio device returned non-sense value.\n");
r = data.samples;
}
- if (r > 0)
+ if (r > 0) {
mp_audio_buffer_skip(p->buffer, r);
+ p->newdata = false;
+ }
if (p->final_chunk && mp_audio_buffer_samples(p->buffer) == 0) {
p->playing = false;
p->expected_end_time = mp_time_sec() + AO_EOF_DELAY + 0.25; // + margin
@@ -256,7 +261,7 @@ static void *playthread(void *arg)
}
// Half of the buffer played -> wakeup playback thread to get more.
double min_wait = ao->device_buffer / (double)ao->samplerate;
- if (timeout <= min_wait / 2 + 0.001)
+ if (timeout <= min_wait / 2 + 0.001 && !p->newdata)
mp_input_wakeup(ao->input_ctx);
// Avoid wasting CPU - this assumes ao_play_data() usually fills the
// audio buffer as far as possible, so even if the device buffer