Skip to content

Commit 13ff797

Browse files
ao/pulse: fix ao_drain hang when underrun makes buf_diff negative
With prebuf=0, on underrun read_index overtakes write_index, making buf_diff negative. Passing it to pa_bytes_to_usec() (uint64_t) overflows and causes ao_drain() to hang forever via an infinite mp_cond_timedwait(). Fixes: 17651
1 parent 1a545fa commit 13ff797

1 file changed

Lines changed: 10 additions & 2 deletions

File tree

audio/out/ao_pulse.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -584,8 +584,16 @@ static double get_delay_hackfixed(struct ao *ao)
584584
GENERIC_ERR_MSG("pa_stream_get_sample_spec() failed");
585585
return 0;
586586
}
587-
// data left in PulseAudio's main buffers (not written to sink yet)
588-
int64_t latency = pa_bytes_to_usec(ti->write_index - ti->read_index, ss);
587+
// data left in PulseAudio's main buffers (not written to sink yet).
588+
// With prebuf=0 (which mpv sets), PulseAudio documents that on underrun
589+
// read_index overtakes write_index, making the difference negative.
590+
// Passing a negative int64_t to pa_bytes_to_usec() (which takes uint64_t)
591+
// causes implicit conversion to a huge value, which then overflows
592+
// MP_TIME_S_TO_NS() to INT64_MAX, making mp_cond_timedwait() call
593+
// pthread_cond_wait() instead of pthread_cond_timedwait(), resulting in
594+
// ao_drain() hanging forever (observed on LoongArch + PulseAudio).
595+
int64_t buf_diff = ti->write_index - ti->read_index;
596+
int64_t latency = buf_diff > 0 ? (int64_t)pa_bytes_to_usec((uint64_t)buf_diff, ss) : 0;
589597
// since this info may be from a while ago, playback has progressed since
590598
latency -= ti->transport_usec;
591599
// data already moved from buffers to sink, but not played yet

0 commit comments

Comments
 (0)