From afa73e6bcb997089e154a9d9edb2f49bafeb7ee2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Tue, 7 Jul 2026 23:51:34 +0200 Subject: [PATCH] Prefer avfoundation AO on macOS 27 to avoid mpv hotplug listener crash On macOS 27 beta, mpv's coreaudio AO fails to initialize (channel layout set rejected with paramErr -50). The existing ao=coreaudio,avfoundation fallback restored audio, but exposed an mpv bug: init() registers a HAL hotplug listener (AudioObjectAddPropertyListener on the system object, with the raw ao pointer as user data) before the step that fails, and the coreaudio_error path never unregisters it. mpv then frees the ao and falls back to avfoundation, leaving a dangling listener per playback start. The next audio device change (AirPods connect, sleep/wake device republish) invokes the listener with the freed pointer and crashes with a use-after-free SIGSEGV on the HALC_ProxyNotification Call Listener Queue (observed in build 262; faulting address was reused "texture_" shader string memory). Gate the AO order by OS version: on macOS 27+ use avfoundation,coreaudio so the failing coreaudio init never runs; older macOS keeps the native coreaudio first with avfoundation as fallback. Update the read-only defaults mirror in MPV options settings to match. --- Yattee/Services/Player/MPV/MPVClient.swift | 17 ++++++++++++----- .../Views/Settings/MPVOptionsSettingsView.swift | 6 +++++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Yattee/Services/Player/MPV/MPVClient.swift b/Yattee/Services/Player/MPV/MPVClient.swift index e0958f87..ac8b1a15 100644 --- a/Yattee/Services/Player/MPV/MPVClient.swift +++ b/Yattee/Services/Player/MPV/MPVClient.swift @@ -463,11 +463,18 @@ final class MPVClient: @unchecked Sendable { #elseif os(macOS) // coreaudio is the native macOS AO, but on macOS 27 beta it fails to // initialize ("unable to set the input channel layout on the audio - // unit … -50"), leaving playback silent. Add avfoundation - // (AVSampleBufferAudioRenderer) as a fallback so mpv self-heals: older - // macOS keeps using coreaudio, and where coreaudio can't open the - // device mpv drops to avfoundation instead of playing no sound. - setOptionSync("ao", "coreaudio,avfoundation") + // unit … -50"), leaving playback silent. Worse, mpv's coreaudio AO + // registers a HAL hotplug listener before the step that fails and its + // init-failure path never unregisters it, so every failed init leaves + // a dangling listener that crashes (use-after-free) on the next audio + // device change. On macOS 27+ put avfoundation first so the failing + // coreaudio init never runs; older macOS keeps native coreaudio with + // avfoundation as fallback. + if ProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 27 { + setOptionSync("ao", "avfoundation,coreaudio") + } else { + setOptionSync("ao", "coreaudio,avfoundation") + } #endif // Cache settings for network streams diff --git a/Yattee/Views/Settings/MPVOptionsSettingsView.swift b/Yattee/Views/Settings/MPVOptionsSettingsView.swift index 3bfbd44f..ee31a357 100644 --- a/Yattee/Views/Settings/MPVOptionsSettingsView.swift +++ b/Yattee/Views/Settings/MPVOptionsSettingsView.swift @@ -123,7 +123,11 @@ private struct DefaultOptionsSection: View { #if os(iOS) || os(tvOS) options.append(("ao", "audiounit")) #else - options.append(("ao", "coreaudio,avfoundation")) + if ProcessInfo.processInfo.operatingSystemVersion.majorVersion >= 27 { + options.append(("ao", "avfoundation,coreaudio")) + } else { + options.append(("ao", "coreaudio,avfoundation")) + } #endif options.append(("cache", "yes"))