diff --git a/macos/Runner/MpvPlayer/MpvPlayerCore.swift b/macos/Runner/MpvPlayer/MpvPlayerCore.swift index 2dd360385..119c47cbc 100644 --- a/macos/Runner/MpvPlayer/MpvPlayerCore.swift +++ b/macos/Runner/MpvPlayer/MpvPlayerCore.swift @@ -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() { diff --git a/macos/RunnerTests/RunnerTests.swift b/macos/RunnerTests/RunnerTests.swift index bde419155..5236d998d 100644 --- a/macos/RunnerTests/RunnerTests.swift +++ b/macos/RunnerTests/RunnerTests.swift @@ -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() {