ao_avfoundation: stop requesting media while paused - #18390
ao_avfoundation: stop requesting media while paused#18390aliceisjustplaying wants to merge 1 commit into
Conversation
The AVSampleBufferAudioRenderer callback remained registered when the synchronizer rate was set to zero. If its queue was empty when playback was paused, AVFoundation immediately invoked the callback again after ao_read_data returned no samples, consuming a full CPU core. Stop requesting media data before pausing and register the callback again when playback resumes. This balances the request/stop lifecycle and prevents the empty renderer from busy-looping.
Why should it do that?
Busylooping any time the player is paused would've resulted in far more noise about it, considering we haven't heard about this issue at all yet, is this a MacOS regression? |
| struct priv *p = ao->priv; | ||
|
|
||
| if (paused) { | ||
| [p->renderer stopRequestingMediaData]; |
There was a problem hiding this comment.
I know we use this property elsewhere in the AO too, but this is deprecated https://developer.apple.com/documentation/avfoundation/avsamplebufferaudiorenderer/stoprequestingmediadata()
It can't be the case that avoiding busylooping necessitates the use of a deprecated property
|
I also find it strange that there is no noise about it, but I tested this both on the macOS 27 beta but also on macOS 26 now and I can reproduce it, Updated the PR description. Looking into the deprecated property. |
|
@llyyr it's deprecated for swift but not objc, and as far as i can tell apple's website is just simply wrong about this Xcode 27 SDK, #if defined(__swift__)
API_DEPRECATED("Cancel the receiver's Task instead", macos(10.13, 27.0), ...)
#else
API_AVAILABLE(macos(10.13), ...)
#endif
|
Summary
Stop
AVSampleBufferAudioRendererfrom requesting media data while mpv is paused, then register the request callback again when playback resumes.Root cause
set_pauseset the render synchronizer rate to zero but left the media-data request active. If the renderer had no queued audio,ao_read_datareturned no samples while paused. AVFoundation still considered the renderer ready for more data and immediately invoked the callback again, creating a busy loop on theavfoundation eventqueue.The callback request now stops before the rate changes to zero. Resuming sets the rate back to one and registers a new callback, keeping the request and stop lifecycle balanced.
Observed failure
A paused mpv 0.41.0 process consistently consumed one full CPU core while its playback, decoder, demuxer, video-output, and Lua threads slept. A process sample showed the active thread in this stack:
The process-level signal stayed consistent across repeated measurements:
Verification
meson compile -C buildgit diff --check origin/master...HEADao=avfoundation, completed five pause/resume cycles, and left the player pausedAdditional macOS 26 runtime verification:
e7191f2a65) and PR commit (4df03a9b22) on macOS 26.6.2 (25G83), arm64paused_cpu=77.4; a three-second sample recorded 2,266 samples onDispatchQueue: avfoundation event, including 1,610 in-[AVMediaDataRequester _requestMediaDataIfReady]paused_cpu=0.1;requestMediaDataIfReadywas absent from the sample; resume and re-pause measured0.0%CPUThis build configuration defines no automated tests. The behavior depends on the macOS AVFoundation runtime, so the verification exercises the real audio output.
AI/LLM disclosure
OpenAI Codex with GPT-5.6 Sol (high) assisted with diagnosis, implementation, testing, and drafting this pull request. I understand the change and take full responsibility for it, including its licensing under the file's existing LGPLv2.1+ terms. I will participate in review with human-written responses.