diff options
author | wm4 <wm4@nowhere> | 2017-06-28 12:26:27 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2017-06-28 13:18:59 +0200 |
commit | c5a82f729bd09745488ef96fa7c76307c41c0073 (patch) | |
tree | b4b14a1252934679c6d8acf59ba145adb08342a0 /audio | |
parent | 0af561953a2a4b10b23367dccbc0c22730d69999 (diff) |
audio/out/pull: detect and log underflows
Mostly for debugging, I guess.
Diffstat (limited to 'audio')
-rw-r--r-- | audio/out/pull.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/audio/out/pull.c b/audio/out/pull.c index a656de6fdd..6da3825965 100644 --- a/audio/out/pull.c +++ b/audio/out/pull.c @@ -55,6 +55,13 @@ struct ao_pull_state { // AO_STATE_* atomic_int state; + // Set when the buffer is intentionally not fed anymore in PLAY state. + atomic_bool draining; + + // Set by the audio thread when an underflow was detected. + // It adds the number of samples. + atomic_int underflow; + // Device delay of the last written sample, in realtime. atomic_llong end_time_us; }; @@ -100,11 +107,20 @@ static int play(struct ao *ao, void **data, int samples, int flags) int state = atomic_load(&p->state); if (!IS_PLAYING(state)) { + atomic_store(&p->draining, false); + atomic_store(&p->underflow, 0); set_state(ao, AO_STATE_PLAY); if (!ao->stream_silence) ao->driver->resume(ao); } + bool draining = write_samples == samples && (flags & AOPLAY_FINAL_CHUNK); + atomic_store(&p->draining, draining); + + int underflow = atomic_fetch_and(&p->underflow, 0); + if (underflow) + MP_WARN(ao, "Audio underflow by %d samples.\n", underflow); + return write_samples; } @@ -135,6 +151,9 @@ int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us) int buffered_bytes = mp_ring_buffered(p->buffers[0]); bytes = MPMIN(buffered_bytes, full_bytes); + if (buffered_bytes < bytes && !atomic_load(&p->draining)) + atomic_fetch_add(&p->underflow, (bytes - buffered_bytes) / ao->sstride); + if (bytes > 0) atomic_store(&p->end_time_us, out_time_us); @@ -221,6 +240,7 @@ static void drain(struct ao *ao) struct ao_pull_state *p = ao->api_priv; int state = atomic_load(&p->state); if (IS_PLAYING(state)) { + atomic_store(&p->draining, true); // Wait for lower bound. mp_sleep_us(mp_ring_buffered(p->buffers[0]) / (double)ao->bps * 1e6); // And then poll for actual end. (Unfortunately, this code considers |