fix(macos): fall back to AVFoundation audio when CoreAudio fails to open

On macOS 27 beta, CoreAudio rejects ao_coreaudio's channel-layout setup
with paramErr (-50), and since 2.14.0 pinned ao=coreaudio as the only
output, the failed init left every video playing with no audio and no
selectable audio track. Append avfoundation as the fallback, mirroring
upstream mpv's macOS probe order: every format still opens through the
HAL-backed CoreAudio path when it works, and the fallback only engages
when CoreAudio's init fails outright.

close #1964
This commit is contained in:
edde746
2026-08-16 22:40:53 +02:00
parent 9dd8aa4679
commit e47b4e0a73
2 changed files with 10 additions and 6 deletions
+8 -4
View File
@@ -102,10 +102,14 @@ class MpvPlayerCore: MpvPlayerCoreBase {
}
override func configurePlatformMpvOptions(mpv: OpaquePointer) {
// Keep every macOS format on CoreAudio's HAL-backed path. This deliberately
// gives up AVFoundation spatialization so PCM and compressed streams share
// the same stable output implementation.
checkError(mpv_set_option_string(mpv, "ao", "coreaudio"))
// CoreAudio first: every format normally plays through the one HAL-backed
// timing path, deliberately giving up AVFoundation spatialization. The
// avfoundation fallback mirrors upstream mpv's macOS probe order and only
// engages when CoreAudio's init fails outright — macOS 27 beta rejects
// ao_coreaudio's channel-layout setup with paramErr (-50), and a
// single-entry ao list would turn that into playback with no audio at
// all (#1964).
checkError(mpv_set_option_string(mpv, "ao", "coreaudio,avfoundation"))
}
func reattachMetalLayer() {
+2 -2
View File
@@ -128,7 +128,7 @@ final class MpvPlayerContractTests: XCTestCase {
XCTAssertFalse(core.isPaused, "The accepted pause write must commit before completion")
}
func testMacOSVideoCoreUsesCoreAudioOutput() {
func testMacOSVideoCoreUsesCoreAudioWithAVFoundationFallback() {
guard let mpv = mpv_create() else {
return XCTFail("mpv_create failed")
}
@@ -151,7 +151,7 @@ final class MpvPlayerContractTests: XCTestCase {
mpv_get_property_string(mpv, $0)
}
defer { mpv_free(optionValue) }
XCTAssertEqual(optionValue.map { String(cString: $0) }, "coreaudio")
XCTAssertEqual(optionValue.map { String(cString: $0) }, "coreaudio,avfoundation")
}
func testPauseIntentUpdatesCacheBeforeAsyncWriteCompletes() {