MPVKit 1.0.15 bounded how far ahead ao_avfoundation enqueues PCM on macOS —
about 450ms of queue against the renderer's own ~1.7s — and disarms the feed
between refills, re-arming from a half-bound timer. 2.10 is the first release
to carry it: the AO pin went 1.0.12 to 1.0.16 over that release. #1711 reports
macOS audio skipping roughly every half second on 2.10 that 2.9.1 does not
have, and that bound is the only change to this path in the window, so restore
the renderer-owned depth 2.9.1 shipped. The option documents 0 as exactly that.
The AO itself stays. allowedAudioSpatializationFormats is a property of
AVSampleBufferAudioRenderer, and the compressed E-AC3 JOC sink lives there
too, while ao_coreaudio drives the HAL device and exposes no spatialization
control at all — CoreAudio is the fallback, not an alternative.
The cost is the latency the bound was added to remove: mpv multiplies --volume
into the samples as it hands them over, so a volume change stays inaudible
until the renderer queue drains. That is 2.9.1's behaviour, and the fix for it
belongs to the AO's gain domain rather than to how far ahead it may buffer.
Verified against the pinned MPVKit 1.0.16 libmpv on macOS: both option writes
are accepted, playback lands on ao_avfoundation and advances at 0.997x real
time. Runner's native suite passes.
Detection now runs off the UI isolate and covers every platform where
the answer can be trusted.
Availability was a plain platform check, so Linux always listed VLC, mpv
and Celluloid, macOS always listed VLC and IINA, and Windows always
listed VLC and PotPlayer whether or not any of them existed. Each player
now has a detector that asks exactly the question its launcher asks:
`sh -c 'command -v'` for PATH launches so the kernel performs the
executable check, NSWorkspace/Launch Services for `open -a`, `where.exe`
plus the concrete install paths for Windows VLC, and the registered URL
handler for PotPlayer and the iOS players.
Detection is asynchronous and memoised behind KnownPlayers.probe rather
than a Process.runSync in a static initialiser, which forked three
shells on the UI isolate during ExternalPlayerScreen.build. It is
prewarmed from startup, fails open when a probe throws, and keeps the
selected player listed when a detector misses it so a false negative
cannot leave the list with nothing selected.
iOS and tvOS gained LSApplicationQueriesSchemes entries for vlc and
infuse. Without them canOpenURL returns false for both schemes, so
_launchUrlScheme was already refusing to hand off to either player.
Android keeps the platform check: package visibility needs native
declarations, and a wrong answer there hides a working player.
When the display/system sleeps with a video paused, the window server
stops completing CAMetalLayer presents and mpv's MoltenVK swapchain wedges,
pinning one core at 100% until the app exits. occlusionState does not
reliably change on display sleep, so observe NSWorkspace screensDidSleep/
Wake to hide the metal layer (and drop the playback activity) while dark,
restoring on wake with a forced redraw when paused to avoid a stale frame.
Pairs with MPVKit v1.0.10, which gates libmpv presentation on the layer's
hidden state (check_visible) so presents actually stop while hidden.
Audio-only mpv core on every platform (dedicated
com.plezy/mpv_audio_player channels): parameterized android/windows/
linux mpv plugins and a new apple MpvAudioPlayerCore, all skipping
video/window paths (vid=no, audio-display=no, gapless-audio=weak).
MusicPlaybackService drives an in-memory queue with shuffle/repeat,
file-loaded-event gapless arming (property edges coalesce and the
android bridge drops them), per-track progress reporting, OS media
controls, audio focus, sleep timer, and error auto-skip.
PlaybackCoordinator enforces one live native player: starting video
disposes the audio core first.
- Remove vulkan-swap-mode mailbox (continuous GPU rendering even when paused)
- End playback activity assertion on pause, restore on play
- Fix PerformanceStatsService persistent frame callback leak