diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index f97f9f1c5e41..f0ca386794cb 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,3 +1,10 @@ +## 2.12.0 + +* Routes video over AirPlay when an external screen is active, by setting + `usesExternalPlaybackWhileExternalScreenIsActive` on the `AVPlayer`. Selecting + an AirPlay route previously moved only the audio, leaving the video on the + device while the receiver showed a mirrored screen. + ## 2.11.0 * Implements `setPreventsDisplaySleepDuringVideoPlayback` using diff --git a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.swift b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.swift index 72bbe1e44658..f18954d9f65e 100644 --- a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.swift +++ b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.swift @@ -396,6 +396,23 @@ private let hlsAudioTestURI = #expect(player.player.preventsDisplaySleepDuringVideoPlayback == true) } + #if os(iOS) + @Test func externalPlaybackIsEnabledForAirPlay() { + let stubAVFactory = StubFVPAVFactory(player: AVPlayer()) + let player = FVPVideoPlayer( + playerItem: StubPlayerItem(), + avFactory: stubAVFactory, + viewProvider: StubViewProvider()) + + // usesExternalPlaybackWhileExternalScreenIsActive defaults to NO, which + // keeps the video on the device whenever an external screen is active. An + // AirPlay route then moves only the audio, and the receiver shows a + // mirrored screen rather than playing the stream itself. + #expect(player.player.allowsExternalPlayback == true) + #expect(player.player.usesExternalPlaybackWhileExternalScreenIsActive == true) + } + #endif + /// Sanity checks a video player playing the given URL with the actual AVPlayer. This is essentially /// a mini integration test of the player component. /// diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m index 316aa6237c25..86418642f7d6 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m @@ -145,6 +145,22 @@ - (instancetype)initWithPlayerItem:(NSObject *)item _player = [avFactory playerWithPlayerItem:item]; _player.actionAtItemEnd = AVPlayerActionAtItemEndNone; +#if TARGET_OS_IOS + // Allow the video to follow an AirPlay route to an external device. + // + // allowsExternalPlayback already defaults to YES, but + // usesExternalPlaybackWhileExternalScreenIsActive defaults to NO, so the + // player deliberately keeps the picture on the device whenever an external + // screen is active. The result is that selecting an AirPlay route changes the + // audio route while the video stays on the phone and the TV only receives a + // mirrored copy of the screen. + // + // Verified on an Apple TV: with both set, the receiver plays the stream + // itself and the local surface is released. + _player.allowsExternalPlayback = YES; + _player.usesExternalPlaybackWhileExternalScreenIsActive = YES; +#endif + // Configure output. AVVideoColorPropertiesKey must be declared on the output settings (not on // pixel buffer attributes, where AVFoundation silently ignores it) so that HDR sources are // tone-mapped to BT.709 SDR for the Flutter texture. diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index 9a1e29eab6d1..e0505a96ca8b 100644 --- a/packages/video_player/video_player_avfoundation/pubspec.yaml +++ b/packages/video_player/video_player_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_avfoundation description: iOS and macOS implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.11.0 +version: 2.12.0 environment: sdk: ^3.10.0