summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-11-24 20:50:09 +0100
committerwm4 <wm4@nowhere>2016-11-24 20:52:15 +0100
commitc03a67c37c149134a25d400a62b7706386136379 (patch)
tree782ff6f79e6f343b29e6d8eaa9005df93ae87af3
parent48a7c4be3a8ea97ddc2150c20b5cf4db4f1b8e85 (diff)
downloadmpv-c03a67c37c149134a25d400a62b7706386136379.tar.bz2
mpv-c03a67c37c149134a25d400a62b7706386136379.tar.xz
audio/out/push: play silence on --audio-stream-silence
Until now, this was only implemented for ao_alsa and AOs not using push.c. ao_alsa.c relied on enabling funny underrun semantics for avoiding resets on lower levels, while other AOs using push.c didn't do anything. Change this and at least make push.c copy silent data to the AO. This still isn't perfect as keeping track of how much silence was played when seems complex, so we don't do it. The consequence is that frame-stepping will essentially randomize the A/V offset (it'll recover immediately when unpausing, but still ugly). Also, in order to empty the currently buffered audio on seeks etc., we still call ao_driver->reset and so on, so the AO driver will still need to handle this specially. The intent is to make behavior with ALSA less weird (for one we can remove the code in ao_alsa.c that tries to trigger an initial underflow). Also might help with #3754.
-rw-r--r--audio/out/ao_alsa.c6
-rw-r--r--audio/out/push.c41
2 files changed, 34 insertions, 13 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 201557697d..91c8e2d3fc 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -845,12 +845,6 @@ static int init_device(struct ao *ao, int mode)
ao->device_buffer = p->buffersize;
- // ao_alsa implements this by relying on underrun behavior (no data means
- // underrun, during which silence is played). Trigger by playing some
- // initial silence.
- if (ao->stream_silence)
- ao_play_silence(ao, p->outburst);
-
return 0;
alsa_error:
diff --git a/audio/out/push.c b/audio/out/push.c
index 555a7867da..a4a6808d7f 100644
--- a/audio/out/push.c
+++ b/audio/out/push.c
@@ -49,6 +49,8 @@ struct ao_push_state {
struct mp_audio_buffer *buffer;
+ struct mp_audio *silence;
+
bool terminate;
bool wait_on_ao;
bool still_playing;
@@ -259,15 +261,38 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return write_samples;
}
+static void ao_get_silence(struct ao *ao, struct mp_audio *data, int size)
+{
+ struct ao_push_state *p = ao->api_priv;
+ if (!p->silence) {
+ p->silence = talloc_zero(p, struct mp_audio);
+ mp_audio_set_format(p->silence, ao->format);
+ mp_audio_set_channels(p->silence, &ao->channels);
+ p->silence->rate = ao->samplerate;
+ }
+ if (p->silence->samples < size) {
+ mp_audio_realloc_min(p->silence, size);
+ p->silence->samples = size;
+ mp_audio_fill_silence(p->silence, 0, size);
+ }
+ *data = *p->silence;
+ data->samples = size;
+}
+
// called locked
static void ao_play_data(struct ao *ao)
{
struct ao_push_state *p = ao->api_priv;
- struct mp_audio data;
- mp_audio_buffer_peek(p->buffer, &data);
- int max = data.samples;
int space = ao->driver->get_space(ao);
+ bool play_silence = p->paused || (ao->stream_silence && !p->still_playing);
space = MPMAX(space, 0);
+ struct mp_audio data;
+ if (play_silence) {
+ ao_get_silence(ao, &data, space);
+ } else {
+ mp_audio_buffer_peek(p->buffer, &data);
+ }
+ int max = data.samples;
if (data.samples > space)
data.samples = space;
int flags = 0;
@@ -289,7 +314,8 @@ static void ao_play_data(struct ao *ao)
MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n");
r = max;
}
- mp_audio_buffer_skip(p->buffer, r);
+ if (!play_silence)
+ mp_audio_buffer_skip(p->buffer, r);
if (r > 0)
p->expected_end_time = 0;
// Nothing written, but more input data than space - this must mean the
@@ -300,7 +326,7 @@ static void ao_play_data(struct ao *ao)
// Wait until space becomes available. Also wait if we actually wrote data,
// so the AO wakes us up properly if it needs more data.
p->wait_on_ao = space == 0 || r > 0 || stuck;
- p->still_playing |= r > 0;
+ p->still_playing |= r > 0 && !play_silence;
// If we just filled the AO completely (r == space), don't refill for a
// while. Prevents wakeup feedback with byte-granular AOs.
int needed = unlocked_get_space(ao);
@@ -319,12 +345,13 @@ static void *playthread(void *arg)
mpthread_set_name("ao");
pthread_mutex_lock(&p->lock);
while (!p->terminate) {
- if (!p->paused)
+ bool playing = !p->paused || ao->stream_silence;
+ if (playing)
ao_play_data(ao);
if (!p->need_wakeup) {
MP_STATS(ao, "start audio wait");
- if (!p->wait_on_ao || p->paused) {
+ if (!p->wait_on_ao || !playing) {
// Avoid busy waiting, because the audio API will still report
// that it needs new data, even if we're not ready yet, or if
// get_space() decides that the amount of audio buffered in the