ao/pulse: fix ao_drain hang when underrun makes buf_diff negative#17652
ao/pulse: fix ao_drain hang when underrun makes buf_diff negative#17652dengzhongyuan365-dev wants to merge 1 commit intompv-player:masterfrom
Conversation
bf0e808 to
13ff797
Compare
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
13ff797 to
928d398
Compare
|
@Dudemanguy |
|
Do you have an easy way to reproduce this problem? |
But,the code logic also presents computational problems. If an overflow occurs, it can cause subsequent stuttering, ultimately leading to the mpv freezing. |
|
@Dudemanguy Are there any other concerns? |
|
Nothing. Someone just needs to find the time to actually verify the bug and the fix. |
ok,there is
Thread 11 (Thread 1083849.1083884 "core"): |
|
So I can actually pretty easily reproduce what seems to be the issue here (mpv inexplicably freezing for no apparent reason) by just seeking around. It only happens with pulseaudio so at least it appears the be the problem described. This PR doesn't fix it for me though. I'm not sure if the root cause is correct but it's something to do with pulse. |
|
@Dudemanguy My commit fixes one specific, well-defined root-cause point: when PulseAudio latency hacks are enabled, get_delay_hackfixed() estimates the main-buffer delay using (write_index - read_index). With prebuf=0 and an underrun, read_index can overtake write_index, making the difference negative; passing that into pa_bytes_to_usec() (which takes a uint64_t) overflows into a huge latency value, which in turn pushes ao_drain() into an infinite wait. The PR targets exactly this overflow chain. You mentioned that it still freezes even with --no-pulse-latency-hacks (i.e. no behavior change). That suggests there is another entry point that can push ao_drain() into the same infinite wait — namely the non-hacks latency path (pa_stream_get_latency / get_delay_pulse) still returning abnormal/unavailable latency around seek/underrun. My PR does not cover that path, so it wouldn’t improve your case. Next, I’ll try to reproduce it using your “seek around repeatedly” scenario and then dig further into the actual root cause: specifically, what PulseAudio returns on the non-hacks path (NODATA? negative flag? extreme values?), and why that causes ao_drain()’s wait to go out of control. Once that’s understood, I’ll propose a targeted fix (rather than just papering over the hang with clamps/timeouts). |
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