mpv-player / mpv-player/mpv

ao/pulse: ao_drain() hangs forever on LoongArch when PulseAudio underrun produces negative buf_diff

Open Beginner friendly
#17,651 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

os:linux
Dominant language
C
Stars
37k
Forks
3.5k
Avg merge
1d 10h
Merged PRs (30d)
22

Description

mpv Information
uos@uos-PC:~/proj/deepin-movie-reborn$ mpv --version
mpv 0.38.0 Copyright © 2000-2024 mpv/MPlayer/mplayer2 projects
libplacebo version: v6.338.2
FFmpeg version: 6.1.1-2deepin9
FFmpeg library versions:
   libavutil       58.29.100
   libavcodec      60.31.102
   libavformat     60.16.100
   libswscale      7.5.100
   libavfilter     9.12.100
   libswresample   4.12.100
Other Information
- Linux version:
- Kernel Version:
- GPU Model:
- Mesa/GPU Driver Version:
- Window Manager and Version:
- Source of mpv:
- Latest known working version:
- Issue started after the following happened:
Reproduction Steps
  1. Use a LoongArch64 machine with PulseAudio as the audio backend
  2. Play any video file to completion: mpv test.mp4
  3. Wait for playback to finish naturally (do not press q)
  4. Observe that the mpv process does not exit and hangs permanently
Expected Behavior

mpv exits cleanly after playback finishes.

Actual Behavior

mpv hangs permanently after playback ends. The process is frozen (0% CPU,
no response to input) and must be killed manually with SIGKILL.

Log File

Thread 11 (mpv core):
#6 ao_drain (ao=...) at ../audio/out/buffer.c:484
#7 uninit_audio_out (...) at ../player/audio.c:245
#8 idle_loop (...) at ../player/playloop.c:1308

Thread 19 (ao thread):
#3 mp_cond_timedwait (timeout=9223372036854775807 /* INT64_MAX */, ...)
at ../audio/out/buffer.c

Root cause analysis:

With prebuf=0 (set by mpv), PulseAudio documents that on underrun
read_index overtakes write_index. In get_delay_hackfixed():

int64_t latency = pa_bytes_to_usec(ti->write_index - ti->read_index, ss);

The subtraction produces a negative int64_t. Passing it to pa_bytes_to_usec()
(which takes uint64_t) triggers implicit conversion to ~2^64, producing a
latency on the order of 1e8 seconds. This flows into ao_drain():

mp_cond_timedwait(&p->wakeup, &p->lock,
                  MP_TIME_S_TO_NS(MPMAX(delay, 0) + 0.25))

MP_TIME_S_TO_NS(1e8) ≈ 1e17 ns, which exceeds the 1000-day threshold in
mp_cond_timedwait() (threads-posix.h), causing it to call pthread_cond_wait()
instead — an infinite wait.

On x86_64 this code path is never reached because underflow_cb() fires
and clears priv->playing before ao_drain() enters its wait loop, so
ao_drain() exits without calling get_delay_hackfixed(). On LoongArch,
underflow_cb() does not fire in time, exposing the overflow bug.

Fix: guard pa_bytes_to_usec() against negative input in get_delay_hackfixed().

Environment: LoongArch64, PulseAudio, mpv 0.38.0

Sample Files

No response

I carefully read all instruction and confirm that I did the following:
  • I tested and confirmed that the issue exists with the latest release version or newer.
  • I provided all required information including system and mpv version.
  • I produced the log file with the exact same set of files, parameters, and conditions used in "Reproduction Steps", with the addition of --log-file=output.txt.
  • I produced the log file while the behaviors described in "Actual Behavior" were actively observed.
  • I attached the full, untruncated log file.
  • I attached the backtrace in the case of a crash.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in audio/out/buffer.c at get_delay_hackfixed() and ao_drain(), then review the PulseAudio underrun behavior described in the issue. Check threads-posix.h to understand the timed-wait threshold. Done means playback exits normally on LoongArch64 after a PulseAudio underrun, without introducing an oversized delay or indefinite wait.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
audio-video-rtc
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.