diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index 1508c0bbfe22..42a8ea8b0a26 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.9.5 + +* Converts portions of the native code to Swift for improved maintainability. + ## 2.9.4 * Ensures that the display link does not continue requesting frames after a player is disposed. diff --git a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/TestClasses.swift b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/TestClasses.swift index 3856995b855c..2dbef61b2f45 100644 --- a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/TestClasses.swift +++ b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/TestClasses.swift @@ -4,7 +4,9 @@ import AVFoundation import Testing -import video_player_avfoundation +import video_player_avfoundation_objc + +@testable import video_player_avfoundation #if os(iOS) import Flutter @@ -249,7 +251,7 @@ final class StubFVPDisplayLink: NSObject, FVPDisplayLink { } } -final class StubFVPDisplayLinkFactory: NSObject, FVPDisplayLinkFactory { +final class StubFVPDisplayLinkFactory: DisplayLinkFactory { let displayLink = StubFVPDisplayLink() var fireDisplayLink: (() -> Void)? 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 c965a70a8430..7d776258c4cc 100644 --- a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.swift +++ b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.swift @@ -4,7 +4,8 @@ import AVFoundation import Testing -@preconcurrency import video_player_avfoundation +@preconcurrency @testable import video_player_avfoundation +import video_player_avfoundation_objc #if os(iOS) import Flutter @@ -41,32 +42,25 @@ private let hlsAudioTestURI = view.wantsLayer = true let viewProvider = StubViewProvider(view: view) #endif - let videoPlayerPlugin = createInitializedPlugin(viewProvider: viewProvider) + let videoPlayerPlugin = try createInitializedPlugin(viewProvider: viewProvider) - var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: mp4TestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: mp4TestURI, httpHeaders: [:])) let player = videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPTextureBasedVideoPlayer #expect(player.playerLayer.superlayer == view.layer) } - @Test func playerForPlatformViewDoesNotRegisterTexture() { + @Test func playerForPlatformViewDoesNotRegisterTexture() throws { let textureRegistry = TestTextureRegistry() let stubDisplayLinkFactory = StubFVPDisplayLinkFactory() - let videoPlayerPlugin = createInitializedPlugin( + let videoPlayerPlugin = try createInitializedPlugin( displayLinkFactory: stubDisplayLinkFactory, textureRegistry: textureRegistry) - var error: FlutterError? - videoPlayerPlugin.createPlatformViewPlayer( - with: FVPCreationOptions.make(withUri: hlsTestURI, httpHeaders: [:]), - error: &error) - #expect(error == nil) + _ = try videoPlayerPlugin.createPlatformViewPlayer( + options: CreationOptions(uri: hlsTestURI, httpHeaders: [:])) #expect(!textureRegistry.registeredTexture) } @@ -76,20 +70,17 @@ private let hlsAudioTestURI = let mockVideoOutput = TestPixelBufferSource() // Display link and frame updater wire-up is currently done in FVPVideoPlayerPlugin, so create // the player via the plugin instead of directly to include that logic in the test. - let videoPlayerPlugin = createInitializedPlugin( + let videoPlayerPlugin = try createInitializedPlugin( avFactory: StubFVPAVFactory(pixelBufferSource: mockVideoOutput), displayLinkFactory: stubDisplayLinkFactory) - var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: hlsTestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: hlsTestURI, httpHeaders: [:])) let player = videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPTextureBasedVideoPlayer // Ensure that the video playback is paused before seeking. + var error: FlutterError? player.pauseWithError(&error) #expect(error == nil) @@ -112,16 +103,12 @@ private let hlsAudioTestURI = @Test func initStartsDisplayLinkTemporarily() throws { let stubDisplayLinkFactory = StubFVPDisplayLinkFactory() let mockVideoOutput = TestPixelBufferSource() - let videoPlayerPlugin = createInitializedPlugin( + let videoPlayerPlugin = try createInitializedPlugin( avFactory: StubFVPAVFactory(pixelBufferSource: mockVideoOutput), displayLinkFactory: stubDisplayLinkFactory) - var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: hlsTestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: hlsTestURI, httpHeaders: [:])) // Init should start the display link temporarily. #expect(stubDisplayLinkFactory.displayLink.running) @@ -139,22 +126,20 @@ private let hlsAudioTestURI = #expect(!stubDisplayLinkFactory.displayLink.running) } - @Test func seekToWhilePlayingDoesNotStopDisplayLink() async { + @Test func seekToWhilePlayingDoesNotStopDisplayLink() async throws { let stubDisplayLinkFactory = StubFVPDisplayLinkFactory() let mockVideoOutput = TestPixelBufferSource() - let videoPlayerPlugin = createInitializedPlugin( + let videoPlayerPlugin = try createInitializedPlugin( avFactory: StubFVPAVFactory(pixelBufferSource: mockVideoOutput), displayLinkFactory: stubDisplayLinkFactory) - var error: FlutterError? - let identifiers = videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: hlsTestURI, httpHeaders: [:]), - error: &error) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: hlsTestURI, httpHeaders: [:])) let player = - videoPlayerPlugin.playersByIdentifier[identifiers!.playerId] as! FVPTextureBasedVideoPlayer + videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPTextureBasedVideoPlayer // Ensure that the video is playing before seeking. + var error: FlutterError? player.playWithError(&error) #expect(error == nil) @@ -172,21 +157,19 @@ private let hlsAudioTestURI = #expect(stubDisplayLinkFactory.displayLink.running) } - @Test func pauseWhileWaitingForFrameDoesNotStopDisplayLink() { + @Test func pauseWhileWaitingForFrameDoesNotStopDisplayLink() throws { let stubDisplayLinkFactory = StubFVPDisplayLinkFactory() // Display link and frame updater wire-up is currently done in FVPVideoPlayerPlugin, so create // the player via the plugin instead of directly to include that logic in the test. - let videoPlayerPlugin = createInitializedPlugin(displayLinkFactory: stubDisplayLinkFactory) + let videoPlayerPlugin = try createInitializedPlugin(displayLinkFactory: stubDisplayLinkFactory) - var error: FlutterError? - let identifiers = videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: hlsTestURI, httpHeaders: [:]), - error: &error) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: hlsTestURI, httpHeaders: [:])) let player = - videoPlayerPlugin.playersByIdentifier[identifiers!.playerId] as! FVPTextureBasedVideoPlayer + videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPTextureBasedVideoPlayer // Run a play/pause cycle to force the pause codepath to run completely. + var error: FlutterError? player.playWithError(&error) #expect(error == nil) player.pauseWithError(&error) @@ -196,20 +179,18 @@ private let hlsAudioTestURI = #expect(stubDisplayLinkFactory.displayLink.running) } - @Test func disposeWhilePlayingStopsDisplayLink() async { + @Test func disposeWhilePlayingStopsDisplayLink() async throws { let stubDisplayLinkFactory = StubFVPDisplayLinkFactory() let mockVideoOutput = TestPixelBufferSource() - let videoPlayerPlugin = createInitializedPlugin( + let videoPlayerPlugin = try createInitializedPlugin( avFactory: StubFVPAVFactory(pixelBufferSource: mockVideoOutput), displayLinkFactory: stubDisplayLinkFactory) var error: FlutterError? - let identifiers = videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: hlsTestURI, httpHeaders: [:]), - error: &error) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: hlsTestURI, httpHeaders: [:])) let player = - videoPlayerPlugin.playersByIdentifier[identifiers!.playerId] as! FVPTextureBasedVideoPlayer + videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPTextureBasedVideoPlayer player.playWithError(&error) #expect(error == nil) @@ -220,16 +201,13 @@ private let hlsAudioTestURI = } @Test func deregistersFromPlayer() throws { - let videoPlayerPlugin = createInitializedPlugin() + let videoPlayerPlugin = try createInitializedPlugin() - var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: mp4TestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) - let player = videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPVideoPlayer + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: mp4TestURI, httpHeaders: [:])) + let player = try #require(videoPlayerPlugin.playersByIdentifier[identifiers.playerId]) + var error: FlutterError? player.disposeWithError(&error) #expect(error == nil) #expect(videoPlayerPlugin.playersByIdentifier.count == 0) @@ -239,15 +217,11 @@ private let hlsAudioTestURI = // TODO(stuartmorgan): Rewrite this test to use stubs, instead of running for 10 // seconds with a real player and hoping to get buffer status updates. let realObjectFactory = FVPDefaultAVFactory() - let videoPlayerPlugin = createInitializedPlugin(avFactory: realObjectFactory) + let videoPlayerPlugin = try createInitializedPlugin(avFactory: realObjectFactory) - var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: mp4TestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) - let player = videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPVideoPlayer + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: mp4TestURI, httpHeaders: [:])) + let player = try #require(videoPlayerPlugin.playersByIdentifier[identifiers.playerId]) let avPlayer = player.player avPlayer.play() @@ -455,16 +429,13 @@ private let hlsAudioTestURI = // Autoreleasepool is needed to simulate conditions of FVPVideoPlayer deallocation. try autoreleasepool { - let videoPlayerPlugin = createInitializedPlugin(avFactory: realObjectFactory) + let videoPlayerPlugin = try createInitializedPlugin(avFactory: realObjectFactory) var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: mp4TestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: mp4TestURI, httpHeaders: [:])) - let player = videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPVideoPlayer + let player = try #require(videoPlayerPlugin.playersByIdentifier[identifiers.playerId]) weakPlayer = player avPlayer = player.player @@ -500,14 +471,10 @@ private let hlsAudioTestURI = // Autoreleasepool is needed to simulate conditions of FVPVideoPlayer deallocation. try autoreleasepool { - let videoPlayerPlugin = createInitializedPlugin(avFactory: StubFVPAVFactory()) + let videoPlayerPlugin = try createInitializedPlugin(avFactory: StubFVPAVFactory()) - var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: mp4TestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: mp4TestURI, httpHeaders: [:])) let player = videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPTextureBasedVideoPlayer @@ -515,8 +482,7 @@ private let hlsAudioTestURI = player.onTextureUnregistered(StubTexture()) - videoPlayerPlugin.initialize(&error) - #expect(error == nil) + try videoPlayerPlugin.initialize() } // Wait for the weak pointer to be invalidated, indicating that the player has been deallocated. @@ -531,16 +497,15 @@ private let hlsAudioTestURI = // No assertions needed. Lack of crash is a success. } - @Test func failedToLoadVideoEventShouldBeAlwaysSent() async { + @Test func failedToLoadVideoEventShouldBeAlwaysSent() async throws { // Use real objects to test a real failure flow. let realObjectFactory = FVPDefaultAVFactory() - let videoPlayerPlugin = createInitializedPlugin(avFactory: realObjectFactory) + let videoPlayerPlugin = try createInitializedPlugin(avFactory: realObjectFactory) - var error: FlutterError? - let identifiers = videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: "", httpHeaders: [:]), error: &error) - #expect(error == nil) - let player = videoPlayerPlugin.playersByIdentifier[identifiers!.playerId] as! FVPVideoPlayer + // Provide a URI that is a valid URI, but not a video, to trigger a failure inside AVPlayer. + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: "https://flutter.dev", httpHeaders: [:])) + let player = try #require(videoPlayerPlugin.playersByIdentifier[identifiers.playerId]) await withCheckedContinuation { continuation in // TODO(stuartmorgan): Update this test to instead use a mock listener, and add separate unit @@ -580,17 +545,13 @@ private let hlsAudioTestURI = let textureRegistry = TestTextureRegistry() let stubDisplayLinkFactory = StubFVPDisplayLinkFactory() let mockVideoOutput = TestPixelBufferSource() - let videoPlayerPlugin = createInitializedPlugin( + let videoPlayerPlugin = try createInitializedPlugin( avFactory: StubFVPAVFactory(pixelBufferSource: mockVideoOutput), displayLinkFactory: stubDisplayLinkFactory, textureRegistry: textureRegistry) - var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: mp4TestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: mp4TestURI, httpHeaders: [:])) let playerIdentifier = identifiers.playerId let player = videoPlayerPlugin.playersByIdentifier[playerIdentifier] as! FVPTextureBasedVideoPlayer @@ -614,15 +575,11 @@ private let hlsAudioTestURI = @Test func videoOutputIsAddedWhenAVPlayerIsInitialized() async throws { let realObjectFactory = FVPDefaultAVFactory() - let videoPlayerPlugin = createInitializedPlugin(avFactory: realObjectFactory) + let videoPlayerPlugin = try createInitializedPlugin(avFactory: realObjectFactory) - var error: FlutterError? - let identifiers = try #require( - videoPlayerPlugin.createTexturePlayer( - with: FVPCreationOptions.make(withUri: mp4TestURI, httpHeaders: [:]), - error: &error)) - #expect(error == nil) - let player = videoPlayerPlugin.playersByIdentifier[identifiers.playerId] as! FVPVideoPlayer + let identifiers = try videoPlayerPlugin.createTexturePlayer( + options: CreationOptions(uri: mp4TestURI, httpHeaders: [:])) + let player = try #require(videoPlayerPlugin.playersByIdentifier[identifiers.playerId]) let listener = StubEventListener() await withCheckedContinuation { continuation in @@ -636,33 +593,29 @@ private let hlsAudioTestURI = } #if os(iOS) - @Test func videoPlayerShouldNotOverwritePlayAndRecordNorDefaultToSpeaker() { + @Test func videoPlayerShouldNotOverwritePlayAndRecordNorDefaultToSpeaker() throws { let stubFactory = StubFVPAVFactory() let audioSession = TestAudioSession() stubFactory.audioSession = audioSession audioSession.category = .playAndRecord audioSession.categoryOptions = .defaultToSpeaker - let videoPlayerPlugin = createInitializedPlugin(avFactory: stubFactory) + let videoPlayerPlugin = try createInitializedPlugin(avFactory: stubFactory) - var error: FlutterError? - videoPlayerPlugin.setMixWithOthers(true, error: &error) - #expect(error == nil) + try videoPlayerPlugin.setMixWithOthers(true) #expect(audioSession.category == .playAndRecord) #expect(audioSession.categoryOptions.contains(.defaultToSpeaker)) #expect(audioSession.categoryOptions.contains(.mixWithOthers)) } - @Test func setMixWithOthersShouldNoOpWhenNoChangesAreRequired() { + @Test func setMixWithOthersShouldNoOpWhenNoChangesAreRequired() throws { let stubFactory = StubFVPAVFactory() let audioSession = TestAudioSession() stubFactory.audioSession = audioSession audioSession.category = .playAndRecord audioSession.categoryOptions = [.mixWithOthers, .defaultToSpeaker] - let videoPlayerPlugin = createInitializedPlugin(avFactory: stubFactory) + let videoPlayerPlugin = try createInitializedPlugin(avFactory: stubFactory) - var error: FlutterError? - videoPlayerPlugin.setMixWithOthers(true, error: &error) - #expect(error == nil) + try videoPlayerPlugin.setMixWithOthers(true) #expect(!audioSession.setCategoryCalled) } #endif @@ -808,22 +761,20 @@ private let hlsAudioTestURI = /// then initializes it. private func createInitializedPlugin( avFactory: FVPAVFactory = StubFVPAVFactory(), - displayLinkFactory: FVPDisplayLinkFactory = StubFVPDisplayLinkFactory(), + displayLinkFactory: DisplayLinkFactory = StubFVPDisplayLinkFactory(), binaryMessenger: FlutterBinaryMessenger = StubBinaryMessenger(), textureRegistry: FlutterTextureRegistry = TestTextureRegistry(), viewProvider: FVPViewProvider = StubViewProvider(), assetProvider: FVPAssetProvider = StubAssetProvider() - ) -> FVPVideoPlayerPlugin { - let plugin = FVPVideoPlayerPlugin( + ) throws -> VideoPlayerPlugin { + let plugin = VideoPlayerPlugin( avFactory: avFactory, displayLinkFactory: displayLinkFactory, binaryMessenger: binaryMessenger, textureRegistry: textureRegistry, viewProvider: viewProvider, assetProvider: assetProvider) - var error: FlutterError? - plugin.initialize(&error) - #expect(error == nil) + try plugin.initialize() return plugin } diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation.podspec b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation.podspec index ca7a63e97258..416a4461570c 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation.podspec +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation.podspec @@ -14,14 +14,18 @@ Downloaded by pub (not CocoaPods). s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } s.source = { :http => 'https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation' } s.documentation_url = 'https://pub.dev/packages/video_player' - s.source_files = 'video_player_avfoundation/Sources/video_player_avfoundation/**/*.{h,m}' + s.source_files = 'video_player_avfoundation/Sources/video_player_avfoundation{,_objc}/**/*.{h,m,swift}' s.ios.source_files = 'video_player_avfoundation/Sources/video_player_avfoundation_ios/*' s.osx.source_files = 'video_player_avfoundation/Sources/video_player_avfoundation_macos/*' - s.public_header_files = 'video_player_avfoundation/Sources/video_player_avfoundation/include/**/*.h' + s.public_header_files = 'video_player_avfoundation/Sources/video_player_avfoundation_objc/include/**/*.h' s.ios.dependency 'Flutter' s.osx.dependency 'FlutterMacOS' s.ios.deployment_target = '13.0' s.osx.deployment_target = '10.15' s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.xcconfig = { + 'LIBRARY_SEARCH_PATHS' => '$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', + 'LD_RUNPATH_SEARCH_PATHS' => '/usr/lib/swift', + } s.resource_bundles = {'video_player_avfoundation_privacy' => ['video_player_avfoundation/Sources/video_player_avfoundation/Resources/PrivacyInfo.xcprivacy']} end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Package.swift b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Package.swift index 821310e0e12b..54155f14693b 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Package.swift +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Package.swift @@ -20,11 +20,17 @@ let package = Package( .target( name: "video_player_avfoundation", dependencies: [ - .target(name: "video_player_avfoundation_ios", condition: .when(platforms: [.iOS])), - .target(name: "video_player_avfoundation_macos", condition: .when(platforms: [.macOS])), + "video_player_avfoundation_objc" ], resources: [ .process("Resources") + ] + ), + .target( + name: "video_player_avfoundation_objc", + dependencies: [ + .target(name: "video_player_avfoundation_ios", condition: .when(platforms: [.iOS])), + .target(name: "video_player_avfoundation_macos", condition: .when(platforms: [.macOS])), ], cSettings: [ .headerSearchPath("include/video_player_avfoundation") @@ -33,13 +39,15 @@ let package = Package( .target( name: "video_player_avfoundation_ios", cSettings: [ - .headerSearchPath("../video_player_avfoundation/include/video_player_avfoundation") + .headerSearchPath( + "../video_player_avfoundation_objc/include/video_player_avfoundation_objc") ] ), .target( name: "video_player_avfoundation_macos", cSettings: [ - .headerSearchPath("../video_player_avfoundation/include/video_player_avfoundation") + .headerSearchPath( + "../video_player_avfoundation_objc/include/video_player_avfoundation_objc") ] ), ] diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPNativeVideoViewFactory.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPNativeVideoViewFactory.m deleted file mode 100644 index 21d7c4bf6752..000000000000 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPNativeVideoViewFactory.m +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "../video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoViewFactory.h" - -#import "../video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoView.h" -#import "../video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h" -#import "../video_player_avfoundation/include/video_player_avfoundation/messages.g.h" - -@interface FVPNativeVideoViewFactory () -@property(nonatomic, strong) NSObject *messenger; -@property(nonatomic, copy) FVPVideoPlayer * (^playerByIdProvider)(NSNumber *); -@end - -@implementation FVPNativeVideoViewFactory - -- (instancetype)initWithMessenger:(NSObject *)messenger - playerByIdentifierProvider:(FVPVideoPlayer * (^)(NSNumber *))playerByIdProvider { - self = [super init]; - if (self) { - _messenger = messenger; - _playerByIdProvider = [playerByIdProvider copy]; - } - return self; -} - -#pragma mark - FlutterPlatformViewFactory - -#if TARGET_OS_OSX -- (NSView *)createWithViewIdentifier:(int64_t)viewIdentifier - arguments:(FVPPlatformVideoViewCreationParams *)args { -#else -- (NSObject *)createWithFrame:(CGRect)frame - viewIdentifier:(int64_t)viewIdentifier - arguments:(FVPPlatformVideoViewCreationParams *)args { -#endif - NSNumber *playerIdentifier = @(args.playerId); - FVPVideoPlayer *player = self.playerByIdProvider(playerIdentifier); - return [[FVPNativeVideoView alloc] initWithPlayer:player.player]; -} - -- (NSObject *)createArgsCodec { - return FVPGetMessagesCodec(); -} - -@end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m deleted file mode 100644 index a420e8397401..000000000000 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "./include/video_player_avfoundation/FVPVideoPlayerPlugin.h" -#import "./include/video_player_avfoundation/FVPVideoPlayerPlugin_Test.h" - -@import AVFoundation; - -#import "./include/video_player_avfoundation/FVPAVFactory.h" -#import "./include/video_player_avfoundation/FVPAssetProvider.h" -#import "./include/video_player_avfoundation/FVPDisplayLink.h" -#import "./include/video_player_avfoundation/FVPEventBridge.h" -#import "./include/video_player_avfoundation/FVPFrameUpdater.h" -#import "./include/video_player_avfoundation/FVPNativeVideoViewFactory.h" -#import "./include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h" -#import "./include/video_player_avfoundation/FVPVideoPlayer.h" -// Relative path is needed for messages.g.h. See -// https://github.com/flutter/packages/pull/6675/#discussion_r1591210702 -#import "./include/video_player_avfoundation/messages.g.h" - -/// Non-test implementation of the diplay link factory. -@interface FVPDefaultDisplayLinkFactory : NSObject -@end - -@implementation FVPDefaultDisplayLinkFactory -- (NSObject *)displayLinkWithViewProvider:(NSObject *)viewProvider - callback:(void (^)(void))callback { -#if TARGET_OS_IOS - return [[FVPCADisplayLink alloc] initWithViewProvider:viewProvider callback:callback]; -#else - if (@available(macOS 14.0, *)) { - return [[FVPCADisplayLink alloc] initWithViewProvider:viewProvider callback:callback]; - } - return [[FVPCoreVideoDisplayLink alloc] initWithViewProvider:viewProvider callback:callback]; -#endif -} - -@end - -#pragma mark - - -/// Non-test implementation of FVPAssetProvider, wrapping a Flutter plugin -/// registrar. -@interface FVPDefaultAssetProvider : NSObject -@property(weak, nonatomic) NSObject *registrar; - -- (instancetype)initWithRegistrar:(NSObject *)registrar; -@end - -@implementation FVPDefaultAssetProvider - -- (instancetype)initWithRegistrar:(NSObject *)registrar { - self = [super init]; - if (self) { - _registrar = registrar; - } - return self; -} - -- (NSString *)lookupKeyForAsset:(NSString *)asset { - return [self.registrar lookupKeyForAsset:asset]; -} - -- (NSString *)lookupKeyForAsset:(NSString *)asset fromPackage:(NSString *)package { - return [self.registrar lookupKeyForAsset:asset fromPackage:package]; -} - -@end - -#pragma mark - - -@interface FVPVideoPlayerPlugin () -@property(nonatomic, strong) NSObject *binaryMessenger; -@property(nonatomic, strong) NSObject *textureRegistry; -@property(nonatomic, strong) id displayLinkFactory; -@property(nonatomic, strong) id avFactory; -@property(nonatomic, strong) NSObject *viewProvider; -@property(nonatomic, strong) NSObject *assetProvider; -@property(nonatomic, assign) int64_t nextPlayerIdentifier; -@end - -@implementation FVPVideoPlayerPlugin -+ (void)registerWithRegistrar:(NSObject *)registrar { - FVPVideoPlayerPlugin *instance = [[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; - // Publish the instance so that it receives detachFromEngineForRegistrar:. - [registrar publish:instance]; - FVPNativeVideoViewFactory *factory = [[FVPNativeVideoViewFactory alloc] - initWithMessenger:registrar.messenger - playerByIdentifierProvider:^FVPVideoPlayer *(NSNumber *playerIdentifier) { - return instance->_playersByIdentifier[playerIdentifier]; - }]; - [registrar registerViewFactory:factory withId:@"plugins.flutter.dev/video_player_ios"]; - SetUpFVPAVFoundationVideoPlayerApi(registrar.messenger, instance); -} - -- (instancetype)initWithRegistrar:(NSObject *)registrar { - return [self initWithAVFactory:[[FVPDefaultAVFactory alloc] init] - displayLinkFactory:[[FVPDefaultDisplayLinkFactory alloc] init] - binaryMessenger:registrar.messenger - textureRegistry:registrar.textures - viewProvider:[[FVPDefaultViewProvider alloc] initWithRegistrar:registrar] - assetProvider:[[FVPDefaultAssetProvider alloc] initWithRegistrar:registrar]]; -} - -- (instancetype)initWithAVFactory:(id)avFactory - displayLinkFactory:(id)displayLinkFactory - binaryMessenger:(NSObject *)binaryMessenger - textureRegistry:(NSObject *)textureRegistry - viewProvider:(NSObject *)viewProvider - assetProvider:(NSObject *)assetProvider { - self = [super init]; - NSAssert(self, @"super init cannot be nil"); - _binaryMessenger = binaryMessenger; - _textureRegistry = textureRegistry; - _assetProvider = assetProvider; - _viewProvider = viewProvider; - _displayLinkFactory = displayLinkFactory ?: [[FVPDefaultDisplayLinkFactory alloc] init]; - _avFactory = avFactory ?: [[FVPDefaultAVFactory alloc] init]; - _playersByIdentifier = [NSMutableDictionary dictionaryWithCapacity:1]; - _nextPlayerIdentifier = 1; - return self; -} - -- (void)detachFromEngineForRegistrar:(NSObject *)registrar { - FlutterError *error; - for (FVPVideoPlayer *player in self.playersByIdentifier.allValues) { - // Remove the channel and texture cleanup, and the event listener, to ensure that the player - // doesn't message the engine that is no longer connected. - player.onDisposed = nil; - player.eventListener = nil; - [player disposeWithError:&error]; - } - [self.playersByIdentifier removeAllObjects]; - SetUpFVPAVFoundationVideoPlayerApi(registrar.messenger, nil); -} - -- (int64_t)configurePlayer:(FVPVideoPlayer *)player - withExtraDisposeHandler:(nullable void (^)(void))extraDisposeHandler { - int64_t playerIdentifier = self.nextPlayerIdentifier++; - self.playersByIdentifier[@(playerIdentifier)] = player; - - NSObject *messenger = self.binaryMessenger; - NSString *channelSuffix = [NSString stringWithFormat:@"%lld", playerIdentifier]; - // Set up the player-specific API handler, and its onDispose unregistration. - SetUpFVPVideoPlayerInstanceApiWithSuffix(messenger, player, channelSuffix); - __weak typeof(self) weakSelf = self; - player.onDisposed = ^() { - SetUpFVPVideoPlayerInstanceApiWithSuffix(messenger, nil, channelSuffix); - if (extraDisposeHandler) { - extraDisposeHandler(); - } - [weakSelf.playersByIdentifier removeObjectForKey:@(playerIdentifier)]; - }; - // Set up the event channel. - FVPEventBridge *eventBridge = [[FVPEventBridge alloc] - initWithMessenger:messenger - channelName:[NSString stringWithFormat:@"flutter.dev/videoPlayer/videoEvents%@", - channelSuffix]]; - player.eventListener = eventBridge; - - return playerIdentifier; -} - -// This function, although slightly modified, is also in camera_avfoundation. -// Both need to do the same thing and run on the same thread (for example main thread). -// Do not overwrite PlayAndRecord with Playback which causes inability to record -// audio, do not overwrite all options. -// Only change category if it is considered an upgrade which means it can only enable -// ability to play in silent mode or ability to record audio but never disables it, -// that could affect other plugins which depend on this global state. Only change -// category or options if there is change to prevent unnecessary lags and silence. -#if TARGET_OS_IOS -static void upgradeAudioSessionCategory(NSObject *session, - AVAudioSessionCategory requestedCategory, - AVAudioSessionCategoryOptions options, - AVAudioSessionCategoryOptions clearOptions) { - NSSet *playCategories = [NSSet - setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; - NSSet *recordCategories = - [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; - NSSet *requiredCategories = [NSSet setWithObjects:requestedCategory, session.category, nil]; - BOOL requiresPlay = [requiredCategories intersectsSet:playCategories]; - BOOL requiresRecord = [requiredCategories intersectsSet:recordCategories]; - if (requiresPlay && requiresRecord) { - requestedCategory = AVAudioSessionCategoryPlayAndRecord; - } else if (requiresPlay) { - requestedCategory = AVAudioSessionCategoryPlayback; - } else if (requiresRecord) { - requestedCategory = AVAudioSessionCategoryRecord; - } - options = (session.categoryOptions & ~clearOptions) | options; - if ([requestedCategory isEqualToString:session.category] && options == session.categoryOptions) { - return; - } - [session setCategory:requestedCategory withOptions:options error:nil]; -} -#endif - -- (void)initialize:(FlutterError *__autoreleasing *)error { -#if TARGET_OS_IOS - // Allow audio playback when the Ring/Silent switch is set to silent - upgradeAudioSessionCategory(self.avFactory.sharedAudioSession, AVAudioSessionCategoryPlayback, - /* options */ 0, - /* clearOptions */ 0); -#endif - - FlutterError *disposeError; - // Disposing a player removes it from the dictionary, so iterate over a copy. - NSArray *players = [self.playersByIdentifier.allValues copy]; - for (FVPVideoPlayer *player in players) { - [player disposeWithError:&disposeError]; - } - [self.playersByIdentifier removeAllObjects]; -} - -- (nullable NSNumber *)createPlatformViewPlayerWithOptions:(nonnull FVPCreationOptions *)options - error:(FlutterError **)error { - @try { - NSObject *item = [self playerItemWithCreationOptions:options]; - - // FVPVideoPlayer contains all required logic for platform views. - FVPVideoPlayer *player = [[FVPVideoPlayer alloc] initWithPlayerItem:item - avFactory:self.avFactory - viewProvider:self.viewProvider]; - - return @([self configurePlayer:player withExtraDisposeHandler:nil]); - } @catch (NSException *exception) { - *error = [FlutterError errorWithCode:@"video_player" message:exception.reason details:nil]; - return nil; - } -} - -- (nullable FVPTexturePlayerIds *)createTexturePlayerWithOptions: - (nonnull FVPCreationOptions *)options - error:(FlutterError **)error { - @try { - NSObject *item = [self playerItemWithCreationOptions:options]; - FVPFrameUpdater *frameUpdater = [[FVPFrameUpdater alloc] initWithRegistry:self.textureRegistry]; - NSObject *displayLink = - [self.displayLinkFactory displayLinkWithViewProvider:self.viewProvider - callback:^() { - [frameUpdater displayLinkFired]; - }]; - - FVPTextureBasedVideoPlayer *player = - [[FVPTextureBasedVideoPlayer alloc] initWithPlayerItem:item - frameUpdater:frameUpdater - displayLink:displayLink - avFactory:self.avFactory - viewProvider:self.viewProvider]; - - int64_t textureIdentifier = [self.textureRegistry registerTexture:player]; - [player setTextureIdentifier:textureIdentifier]; - __weak typeof(self) weakSelf = self; - int64_t playerIdentifier = [self configurePlayer:player - withExtraDisposeHandler:^() { - [weakSelf.textureRegistry unregisterTexture:textureIdentifier]; - }]; - return [FVPTexturePlayerIds makeWithPlayerId:playerIdentifier textureId:textureIdentifier]; - } @catch (NSException *exception) { - *error = [FlutterError errorWithCode:@"video_player" message:exception.reason details:nil]; - return nil; - } -} - -- (void)setMixWithOthers:(BOOL)mixWithOthers - error:(FlutterError *_Nullable __autoreleasing *)error { -#if TARGET_OS_OSX - // AVAudioSession doesn't exist on macOS, and audio always mixes, so just no-op. -#else - NSObject *session = self.avFactory.sharedAudioSession; - if (mixWithOthers) { - upgradeAudioSessionCategory(session, session.category, - /* options */ AVAudioSessionCategoryOptionMixWithOthers, - /* clearOptions */ 0); - } else { - upgradeAudioSessionCategory(session, session.category, /* options */ 0, - /* clearOptions */ AVAudioSessionCategoryOptionMixWithOthers); - } -#endif -} - -- (nullable NSString *)fileURLForAssetWithName:(NSString *)asset - package:(nullable NSString *)package - error:(FlutterError *_Nullable *_Nonnull)error { - NSString *resource = package == nil - ? [self.assetProvider lookupKeyForAsset:asset] - : [self.assetProvider lookupKeyForAsset:asset fromPackage:package]; - - NSString *path = [[NSBundle mainBundle] pathForResource:resource ofType:nil]; -#if TARGET_OS_OSX - // See https://github.com/flutter/flutter/issues/135302 - // TODO(stuartmorgan): Remove this if the asset APIs are adjusted to work better for macOS. - if (!path) { - path = [NSURL URLWithString:resource relativeToURL:NSBundle.mainBundle.bundleURL].path; - } -#endif - - if (!path) { - return nil; - } - return [NSURL fileURLWithPath:path].absoluteString; -} - -/// Returns the AVPlayerItem corresponding to the given player creation options. -- (nonnull NSObject *)playerItemWithCreationOptions: - (nonnull FVPCreationOptions *)options { - NSDictionary *headers = options.httpHeaders; - NSDictionary *itemOptions = - headers.count == 0 ? nil : @{@"AVURLAssetHTTPHeaderFieldsKey" : headers}; - NSObject *asset = [self.avFactory URLAssetWithURL:[NSURL URLWithString:options.uri] - options:itemOptions]; - return [self.avFactory playerItemWithAsset:asset]; -} - -@end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/NativeVideoViewFactory.swift b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/NativeVideoViewFactory.swift new file mode 100644 index 000000000000..f5dbaddd0843 --- /dev/null +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/NativeVideoViewFactory.swift @@ -0,0 +1,66 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif + +#if canImport(video_player_avfoundation_objc) + import video_player_avfoundation_objc +#endif + +/// A factory class responsible for creating native video views that can be embedded in a +/// Flutter app. +final class NativeVideoViewFactory: NSObject, FlutterPlatformViewFactory { + private let messenger: FlutterBinaryMessenger + private let playerByIdentifierProvider: (Int64) -> FVPVideoPlayer? + + /// Initializes a new instance of NativeVideoViewFactory with the given messenger and + /// a block that provides video players associated with their identifiers. + init( + messenger: FlutterBinaryMessenger, + playerByIdentifierProvider: @escaping (Int64) -> FVPVideoPlayer? + ) { + self.messenger = messenger + self.playerByIdentifierProvider = playerByIdentifierProvider + super.init() + } + + #if os(macOS) + func create( + withViewIdentifier viewIdentifier: Int64, + arguments: Any? + ) -> NSView { + return createNativeVideoView(arguments: arguments as! PlatformVideoViewCreationParams) + } + #elseif os(iOS) + func create( + withFrame frame: CGRect, + viewIdentifier: Int64, + arguments: Any? + ) -> FlutterPlatformView { + return createNativeVideoView(arguments: arguments as! PlatformVideoViewCreationParams) + } + #endif + + func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { + return VideoPlayerPluginMessagesPigeonCodec.shared + } + + /// Creates a native video view for the given arguments. + private func createNativeVideoView( + arguments args: PlatformVideoViewCreationParams + ) -> FVPNativeVideoView { + // The Dart code should never attempt to create a platform view for a player that doesn't exist, + // and there's no mechanism to report an error, so just force-unwrap. + let player = playerByIdentifierProvider(args.playerId)! + return FVPNativeVideoView(player: player.player) + } +} diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/VideoPlayerPlugin.swift b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/VideoPlayerPlugin.swift new file mode 100644 index 000000000000..951f3bcfed67 --- /dev/null +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/VideoPlayerPlugin.swift @@ -0,0 +1,323 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import AVFoundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif + +#if canImport(video_player_avfoundation_objc) + import video_player_avfoundation_objc +#endif + +// Protocol for an display link factory. Used for injecting display links in tests. +protocol DisplayLinkFactory { + func displayLink( + with viewProvider: FVPViewProvider, + callback: @escaping () -> Void + ) -> FVPDisplayLink +} + +/// Non-test implementation of the display link factory. +final class DefaultDisplayLinkFactory: DisplayLinkFactory { + func displayLink( + with viewProvider: FVPViewProvider, + callback: @escaping () -> Void + ) -> FVPDisplayLink { + #if os(iOS) + return FVPCADisplayLink(viewProvider: viewProvider, callback: callback) + #elseif os(macOS) + if #available(macOS 14.0, *) { + return FVPCADisplayLink(viewProvider: viewProvider, callback: callback) + } + return FVPCoreVideoDisplayLink(viewProvider: viewProvider, callback: callback) + #endif + } +} + +/// Non-test implementation of FVPAssetProvider, wrapping a Flutter plugin +/// registrar. +final class DefaultAssetProvider: NSObject, FVPAssetProvider { + private weak var registrar: FlutterPluginRegistrar? + + init(registrar: FlutterPluginRegistrar) { + self.registrar = registrar + super.init() + } + + func lookupKey(forAsset asset: String) -> String? { + return registrar?.lookupKey(forAsset: asset) + } + + func lookupKey(forAsset asset: String, fromPackage package: String) -> String? { + return registrar?.lookupKey(forAsset: asset, fromPackage: package) + } +} + +public final class VideoPlayerPlugin: NSObject, FlutterPlugin, AVFoundationVideoPlayerApi { + private let binaryMessenger: FlutterBinaryMessenger + private let textureRegistry: FlutterTextureRegistry + private let displayLinkFactory: DisplayLinkFactory + private let avFactory: FVPAVFactory + private let viewProvider: FVPViewProvider + private let assetProvider: FVPAssetProvider + private var nextPlayerIdentifier: Int64 = 1 + var playersByIdentifier: [Int64: FVPVideoPlayer] = [:] + + public static func register(with registrar: FlutterPluginRegistrar) { + let instance = VideoPlayerPlugin(registrar: registrar) + // Publish the instance so that it receives detachFromEngine. + registrar.publish(instance) + + #if os(iOS) + let messenger = registrar.messenger() + #else + let messenger = registrar.messenger + #endif + let factory = NativeVideoViewFactory( + messenger: messenger, + playerByIdentifierProvider: { + [weak instance] (playerIdentifier: Int64) -> FVPVideoPlayer? in + return instance?.playersByIdentifier[playerIdentifier] + } + ) + registrar.register(factory, withId: "plugins.flutter.dev/video_player_ios") + + AVFoundationVideoPlayerApiSetup.setUp(binaryMessenger: messenger, api: instance) + } + + convenience init(registrar: FlutterPluginRegistrar) { + #if os(iOS) + let messenger = registrar.messenger() + let textures = registrar.textures() + #else + let messenger = registrar.messenger + let textures = registrar.textures + #endif + self.init( + avFactory: FVPDefaultAVFactory(), + displayLinkFactory: DefaultDisplayLinkFactory(), + binaryMessenger: messenger, + textureRegistry: textures, + viewProvider: FVPDefaultViewProvider(registrar: registrar), + assetProvider: DefaultAssetProvider(registrar: registrar) + ) + } + + init( + avFactory: FVPAVFactory, + displayLinkFactory: DisplayLinkFactory, + binaryMessenger: FlutterBinaryMessenger, + textureRegistry: FlutterTextureRegistry, + viewProvider: FVPViewProvider, + assetProvider: FVPAssetProvider + ) { + self.binaryMessenger = binaryMessenger + self.textureRegistry = textureRegistry + self.assetProvider = assetProvider + self.viewProvider = viewProvider + self.displayLinkFactory = displayLinkFactory + self.avFactory = avFactory + super.init() + } + + public func detachFromEngine(for registrar: FlutterPluginRegistrar) { + for player in playersByIdentifier.values { + // Remove the channel and texture cleanup, and the event listener, to ensure that the player + // doesn't message the engine that is no longer connected. + player.onDisposed = nil + player.eventListener = nil + var error: FlutterError? + player.disposeWithError(&error) + } + playersByIdentifier.removeAll() + #if os(iOS) + let messenger = registrar.messenger() + #else + let messenger = registrar.messenger + #endif + AVFoundationVideoPlayerApiSetup.setUp(binaryMessenger: messenger, api: nil) + } + + func initialize() throws { + #if os(iOS) + // Allow audio playback when the Ring/Silent switch is set to silent + upgradeAudioSessionCategory( + session: avFactory.sharedAudioSession(), + requestedCategory: .playback, + options: [], + clearOptions: [] + ) + #endif + + for player in playersByIdentifier.values { + var error: FlutterError? + player.disposeWithError(&error) + } + playersByIdentifier.removeAll() + } + + func createPlatformViewPlayer(options params: CreationOptions) throws -> Int64 { + let item = try playerItem(with: params) + let player = FVPVideoPlayer(playerItem: item, avFactory: avFactory, viewProvider: viewProvider) + return configurePlayer(player, extraDisposeHandler: nil) + } + + func createTexturePlayer(options creationOptions: CreationOptions) throws -> TexturePlayerIds { + let item = try playerItem(with: creationOptions) + let frameUpdater = FVPFrameUpdater(registry: textureRegistry) + let displayLink = displayLinkFactory.displayLink(with: viewProvider) { + frameUpdater.displayLinkFired() + } + + let player = FVPTextureBasedVideoPlayer( + playerItem: item, + frameUpdater: frameUpdater, + displayLink: displayLink, + avFactory: avFactory, + viewProvider: viewProvider + ) + + let textureId = textureRegistry.register(player) + player.setTextureIdentifier(textureId) + + let playerId = configurePlayer(player) { [weak self] in + self?.textureRegistry.unregisterTexture(textureId) + } + + return TexturePlayerIds(playerId: playerId, textureId: textureId) + } + + func setMixWithOthers(_ mixWithOthers: Bool) throws { + #if os(iOS) + let session = avFactory.sharedAudioSession() + if mixWithOthers { + upgradeAudioSessionCategory( + session: session, + requestedCategory: session.category, + options: .mixWithOthers, + clearOptions: [] + ) + } else { + upgradeAudioSessionCategory( + session: session, + requestedCategory: session.category, + options: [], + clearOptions: .mixWithOthers + ) + } + #endif + // AVAudioSession doesn't exist on macOS, and audio always mixes, so just no-op. + } + + func fileURLForAsset(name asset: String, package: String?) throws -> String? { + let resource = + if let package = package { + assetProvider.lookupKey(forAsset: asset, fromPackage: package) + } else { + assetProvider.lookupKey(forAsset: asset) + } + + var path = Bundle.main.path(forResource: resource, ofType: nil) + #if os(macOS) + // See https://github.com/flutter/flutter/issues/135302 + // TODO(stuartmorgan): Remove this if the asset APIs are adjusted to work better for macOS. + if path == nil, let resource = resource { + path = URL(string: resource, relativeTo: Bundle.main.bundleURL)?.path + } + #endif + + guard let validPath = path else { + return nil + } + return URL(fileURLWithPath: validPath).absoluteString + } + + // MARK: - Private + + private func configurePlayer( + _ player: FVPVideoPlayer, + extraDisposeHandler: (() -> Void)? + ) -> Int64 { + let playerId = nextPlayerIdentifier + nextPlayerIdentifier += 1 + playersByIdentifier[playerId] = player + + let channelSuffix = "\(playerId)" + // Set up the player-specific API handler, and its onDispose unregistration. + SetUpFVPVideoPlayerInstanceApiWithSuffix(binaryMessenger, player, channelSuffix) + + player.onDisposed = { [weak self] in + guard let strongSelf = self else { return } + SetUpFVPVideoPlayerInstanceApiWithSuffix(strongSelf.binaryMessenger, nil, channelSuffix) + extraDisposeHandler?() + strongSelf.playersByIdentifier.removeValue(forKey: playerId) + } + + // Set up the event channel. + let eventBridge = FVPEventBridge( + messenger: binaryMessenger, + channelName: "flutter.dev/videoPlayer/videoEvents\(channelSuffix)" + ) + player.eventListener = eventBridge + + return playerId + } + + private func playerItem(with options: CreationOptions) throws -> FVPAVPlayerItem { + let headers = options.httpHeaders + let itemOptions = headers.isEmpty ? nil : ["AVURLAssetHTTPHeaderFieldsKey": headers] + guard let url = URL(string: options.uri) else { + throw PigeonError(code: "video_player", message: "Invalid URI", details: nil) + } + let asset = avFactory.urlAsset(with: url, options: itemOptions) + return avFactory.playerItem(with: asset) + } +} + +#if os(iOS) + // This function, although slightly modified, is also in camera_avfoundation. + // Both need to do the same thing and run on the same thread (for example main thread). + // Do not overwrite PlayAndRecord with Playback which causes inability to record + // audio, do not overwrite all options. + // Only change category if it is considered an upgrade which means it can only enable + // ability to play in silent mode or ability to record audio but never disables it, + // that could affect other plugins which depend on this global state. Only change + // category or options if there is change to prevent unnecessary lags and silence. + private func upgradeAudioSessionCategory( + session: FVPAVAudioSession, + requestedCategory: AVAudioSession.Category, + options: AVAudioSession.CategoryOptions, + clearOptions: AVAudioSession.CategoryOptions + ) { + let playCategories: Set = [.playback, .playAndRecord] + let recordCategories: Set = [.record, .playAndRecord] + let requiredCategories: Set = [requestedCategory, session.category] + + let requiresPlay = !requiredCategories.isDisjoint(with: playCategories) + let requiresRecord = !requiredCategories.isDisjoint(with: recordCategories) + + var finalCategory = requestedCategory + if requiresPlay && requiresRecord { + finalCategory = .playAndRecord + } else if requiresPlay { + finalCategory = .playback + } else if requiresRecord { + finalCategory = .record + } + + let newOptions = session.categoryOptions.subtracting(clearOptions).union(options) + + if finalCategory == session.category && newOptions == session.categoryOptions { + return + } + + try? session.setCategory(finalCategory, with: newOptions) + } +#endif diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/VideoPlayerPluginMessages.g.swift b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/VideoPlayerPluginMessages.g.swift new file mode 100644 index 000000000000..3cd23143abc7 --- /dev/null +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/VideoPlayerPluginMessages.g.swift @@ -0,0 +1,440 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +import Foundation + +#if os(iOS) + import Flutter +#elseif os(macOS) + import FlutterMacOS +#else + #error("Unsupported platform.") +#endif + +/// Error class for passing custom error details to Dart side. +final class PigeonError: Error { + let code: String + let message: String? + let details: Sendable? + + init(code: String, message: String?, details: Sendable?) { + self.code = code + self.message = message + self.details = details + } + + var localizedDescription: String { + return + "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" + } +} + +private func wrapResult(_ result: Any?) -> [Any?] { + return [result] +} + +private func wrapError(_ error: Any) -> [Any?] { + if let pigeonError = error as? PigeonError { + return [ + pigeonError.code, + pigeonError.message, + pigeonError.details, + ] + } + if let flutterError = error as? FlutterError { + return [ + flutterError.code, + flutterError.message, + flutterError.details, + ] + } + return [ + "\(error)", + "\(Swift.type(of: error))", + "Stacktrace: \(Thread.callStackSymbols)", + ] +} + +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + +private func nilOrValue(_ value: Any?) -> T? { + if value is NSNull { return nil } + return value as! T? +} + +private func doubleEqualsVideoPlayerPluginMessages(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashVideoPlayerPluginMessages(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + +func deepEqualsVideoPlayerPluginMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { + let cleanLhs = nilOrValue(lhs) as Any? + let cleanRhs = nilOrValue(rhs) as Any? + switch (cleanLhs, cleanRhs) { + case (nil, nil): + return true + + case (nil, _), (_, nil): + return false + + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: + return true + + case is (Void, Void): + return true + + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsVideoPlayerPluginMessages(element, rhsArray[index]) { + return false + } + } + return true + + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsVideoPlayerPluginMessages(element, rhsArray[index]) { + return false + } + } + return true + + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsVideoPlayerPluginMessages(lhsKey, rhsKey) { + if deepEqualsVideoPlayerPluginMessages(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsVideoPlayerPluginMessages(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + + default: + return false + } +} + +func deepHashVideoPlayerPluginMessages(value: Any?, hasher: inout Hasher) { + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashVideoPlayerPluginMessages(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashVideoPlayerPluginMessages(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashVideoPlayerPluginMessages(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashVideoPlayerPluginMessages(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashVideoPlayerPluginMessages(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) + } + } else { + hasher.combine(0) + } +} + +/// Information passed to the platform view creation. +/// +/// Generated class from Pigeon that represents data sent in messages. +struct PlatformVideoViewCreationParams: Hashable { + var playerId: Int64 + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> PlatformVideoViewCreationParams? { + let playerId = pigeonVar_list[0] as! Int64 + + return PlatformVideoViewCreationParams( + playerId: playerId + ) + } + func toList() -> [Any?] { + return [ + playerId + ] + } + static func == (lhs: PlatformVideoViewCreationParams, rhs: PlatformVideoViewCreationParams) + -> Bool + { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsVideoPlayerPluginMessages(lhs.playerId, rhs.playerId) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("PlatformVideoViewCreationParams") + deepHashVideoPlayerPluginMessages(value: playerId, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct CreationOptions: Hashable { + var uri: String + var httpHeaders: [String: String] + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> CreationOptions? { + let uri = pigeonVar_list[0] as! String + let httpHeaders = pigeonVar_list[1] as! [String: String] + + return CreationOptions( + uri: uri, + httpHeaders: httpHeaders + ) + } + func toList() -> [Any?] { + return [ + uri, + httpHeaders, + ] + } + static func == (lhs: CreationOptions, rhs: CreationOptions) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsVideoPlayerPluginMessages(lhs.uri, rhs.uri) + && deepEqualsVideoPlayerPluginMessages(lhs.httpHeaders, rhs.httpHeaders) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("CreationOptions") + deepHashVideoPlayerPluginMessages(value: uri, hasher: &hasher) + deepHashVideoPlayerPluginMessages(value: httpHeaders, hasher: &hasher) + } +} + +/// Generated class from Pigeon that represents data sent in messages. +struct TexturePlayerIds: Hashable { + var playerId: Int64 + var textureId: Int64 + + // swift-format-ignore: AlwaysUseLowerCamelCase + static func fromList(_ pigeonVar_list: [Any?]) -> TexturePlayerIds? { + let playerId = pigeonVar_list[0] as! Int64 + let textureId = pigeonVar_list[1] as! Int64 + + return TexturePlayerIds( + playerId: playerId, + textureId: textureId + ) + } + func toList() -> [Any?] { + return [ + playerId, + textureId, + ] + } + static func == (lhs: TexturePlayerIds, rhs: TexturePlayerIds) -> Bool { + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsVideoPlayerPluginMessages(lhs.playerId, rhs.playerId) + && deepEqualsVideoPlayerPluginMessages(lhs.textureId, rhs.textureId) + } + + func hash(into hasher: inout Hasher) { + hasher.combine("TexturePlayerIds") + deepHashVideoPlayerPluginMessages(value: playerId, hasher: &hasher) + deepHashVideoPlayerPluginMessages(value: textureId, hasher: &hasher) + } +} + +private class VideoPlayerPluginMessagesPigeonCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 129: + return PlatformVideoViewCreationParams.fromList(self.readValue() as! [Any?]) + case 130: + return CreationOptions.fromList(self.readValue() as! [Any?]) + case 131: + return TexturePlayerIds.fromList(self.readValue() as! [Any?]) + default: + return super.readValue(ofType: type) + } + } +} + +private class VideoPlayerPluginMessagesPigeonCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? PlatformVideoViewCreationParams { + super.writeByte(129) + super.writeValue(value.toList()) + } else if let value = value as? CreationOptions { + super.writeByte(130) + super.writeValue(value.toList()) + } else if let value = value as? TexturePlayerIds { + super.writeByte(131) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class VideoPlayerPluginMessagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return VideoPlayerPluginMessagesPigeonCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return VideoPlayerPluginMessagesPigeonCodecWriter(data: data) + } +} + +class VideoPlayerPluginMessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { + static let shared = VideoPlayerPluginMessagesPigeonCodec( + readerWriter: VideoPlayerPluginMessagesPigeonCodecReaderWriter()) +} + +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol AVFoundationVideoPlayerApi { + func initialize() throws + func createPlatformViewPlayer(options params: CreationOptions) throws -> Int64 + func createTexturePlayer(options creationOptions: CreationOptions) throws -> TexturePlayerIds + func setMixWithOthers(_ mixWithOthers: Bool) throws + func fileURLForAsset(name asset: String, package: String?) throws -> String? +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class AVFoundationVideoPlayerApiSetup { + static var codec: FlutterStandardMessageCodec { VideoPlayerPluginMessagesPigeonCodec.shared } + /// Sets up an instance of `AVFoundationVideoPlayerApi` to handle messages through the `binaryMessenger`. + static func setUp( + binaryMessenger: FlutterBinaryMessenger, api: AVFoundationVideoPlayerApi?, + messageChannelSuffix: String = "" + ) { + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + let initializeChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.initialize\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + initializeChannel.setMessageHandler { _, reply in + do { + try api.initialize() + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + initializeChannel.setMessageHandler(nil) + } + let createForPlatformViewChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.createForPlatformView\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + createForPlatformViewChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let paramsArg = args[0] as! CreationOptions + do { + let result = try api.createPlatformViewPlayer(options: paramsArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + createForPlatformViewChannel.setMessageHandler(nil) + } + let createForTextureViewChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.createForTextureView\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + createForTextureViewChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let creationOptionsArg = args[0] as! CreationOptions + do { + let result = try api.createTexturePlayer(options: creationOptionsArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + createForTextureViewChannel.setMessageHandler(nil) + } + let setMixWithOthersChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.setMixWithOthers\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setMixWithOthersChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let mixWithOthersArg = args[0] as! Bool + do { + try api.setMixWithOthers(mixWithOthersArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + setMixWithOthersChannel.setMessageHandler(nil) + } + let getAssetUrlChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.getAssetUrl\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + getAssetUrlChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let assetArg = args[0] as! String + let packageArg: String? = nilOrValue(args[1]) + do { + let result = try api.fileURLForAsset(name: assetArg, package: packageArg) + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + getAssetUrlChannel.setMessageHandler(nil) + } + } +} diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoViewFactory.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoViewFactory.h deleted file mode 100644 index d20d68e64993..000000000000 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoViewFactory.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@import Foundation; - -#import "FVPVideoPlayer.h" - -#if TARGET_OS_OSX -@import FlutterMacOS; -#else -@import Flutter; -#endif - -/// A factory class responsible for creating native video views that can be embedded in a -/// Flutter app. -@interface FVPNativeVideoViewFactory : NSObject -/// Initializes a new instance of FVPNativeVideoViewFactory with the given messenger and -/// a block that provides video players associated with their identifiers. -- (instancetype)initWithMessenger:(NSObject *)messenger - playerByIdentifierProvider:(FVPVideoPlayer * (^)(NSNumber *))playerByIdentifierProvider; -@end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin.h deleted file mode 100644 index 447d38731380..000000000000 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#if TARGET_OS_OSX -@import FlutterMacOS; -#else -@import Flutter; -#endif - -NS_ASSUME_NONNULL_BEGIN - -@interface FVPVideoPlayerPlugin : NSObject -- (instancetype)initWithRegistrar:(NSObject *)registrar; -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin_Test.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin_Test.h deleted file mode 100644 index b9ba034edc8d..000000000000 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin_Test.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "FVPVideoPlayerPlugin.h" - -#if TARGET_OS_OSX -@import FlutterMacOS; -#else -@import Flutter; -#endif - -#import "FVPAVFactory.h" -#import "FVPAssetProvider.h" -#import "FVPDisplayLink.h" -#import "FVPVideoPlayer.h" -#import "FVPViewProvider.h" -#import "messages.g.h" - -NS_ASSUME_NONNULL_BEGIN - -// Protocol for an AVPlayer instance factory. Used for injecting display links in tests. -@protocol FVPDisplayLinkFactory -- (NSObject *)displayLinkWithViewProvider:(NSObject *)viewProvider - callback:(void (^)(void))callback; -@end - -#pragma mark - - -@interface FVPVideoPlayerPlugin () - -@property(readonly, strong, nonatomic) - NSMutableDictionary *playersByIdentifier; - -- (instancetype)initWithAVFactory:(id)avFactory - displayLinkFactory:(id)displayLinkFactory - binaryMessenger:(NSObject *)binaryMessenger - textureRegistry:(NSObject *)textureRegistry - viewProvider:(NSObject *)viewProvider - assetProvider:(NSObject *)assetProvider; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_ios/FVPNativeVideoView.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_ios/FVPNativeVideoView.m index 6c20d144d5aa..606183241c8f 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_ios/FVPNativeVideoView.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_ios/FVPNativeVideoView.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "../video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoView.h" +#import "../video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPNativeVideoView.h" #import diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_macos/FVPCoreVideoDisplayLink.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_macos/FVPCoreVideoDisplayLink.m index 55c3a11996a5..f6b4241bba8a 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_macos/FVPCoreVideoDisplayLink.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_macos/FVPCoreVideoDisplayLink.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "../video_player_avfoundation/include/video_player_avfoundation/FVPDisplayLink.h" +#import "../video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPDisplayLink.h" #import #import diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_macos/FVPNativeVideoView.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_macos/FVPNativeVideoView.m index 78c68a8b0477..ec2a2a986552 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_macos/FVPNativeVideoView.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_macos/FVPNativeVideoView.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "../video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoView.h" +#import "../video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPNativeVideoView.h" #import #import diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/AVAssetTrackUtils.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/AVAssetTrackUtils.m similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/AVAssetTrackUtils.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/AVAssetTrackUtils.m diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPAVFactory.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPAVFactory.m similarity index 98% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPAVFactory.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPAVFactory.m index 4cee990adb1f..4053bd0dbaae 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPAVFactory.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPAVFactory.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "./include/video_player_avfoundation/FVPAVFactory.h" +#import "./include/video_player_avfoundation_objc/FVPAVFactory.h" @import AVFoundation; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPCADisplayLink.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPCADisplayLink.m similarity index 96% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPCADisplayLink.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPCADisplayLink.m index 3bfa0d63c313..ef5e96dc7d85 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPCADisplayLink.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPCADisplayLink.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "../video_player_avfoundation/include/video_player_avfoundation/FVPDisplayLink.h" +#import "../video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPDisplayLink.h" @import Foundation; @import QuartzCore; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPEventBridge.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPEventBridge.m similarity index 98% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPEventBridge.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPEventBridge.m index 0df3569da9bd..ba8fd756e4f0 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPEventBridge.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPEventBridge.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "./include/video_player_avfoundation/FVPEventBridge.h" +#import "./include/video_player_avfoundation_objc/FVPEventBridge.h" @import Foundation; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPFrameUpdater.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPFrameUpdater.m similarity index 88% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPFrameUpdater.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPFrameUpdater.m index 0800cae41306..745010c8bcba 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPFrameUpdater.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPFrameUpdater.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "./include/video_player_avfoundation/FVPFrameUpdater.h" +#import "./include/video_player_avfoundation_objc/FVPFrameUpdater.h" @implementation FVPFrameUpdater - (FVPFrameUpdater *)initWithRegistry:(NSObject *)registry { diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer.m similarity index 98% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer.m index 1419da4d7743..ee5034d29cf9 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer.m @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "./include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h" -#import "./include/video_player_avfoundation/FVPTextureBasedVideoPlayer_Test.h" +#import "./include/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer.h" +#import "./include/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer_Test.h" @interface FVPTextureBasedVideoPlayer () // The updater that drives callbacks to the engine to indicate that a new frame is ready. diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m similarity index 98% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m index 2270120378d5..04ce60e6a989 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPVideoPlayer.m @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "./include/video_player_avfoundation/FVPVideoPlayer.h" -#import "./include/video_player_avfoundation/FVPVideoPlayer_Internal.h" +#import "./include/video_player_avfoundation_objc/FVPVideoPlayer.h" +#import "./include/video_player_avfoundation_objc/FVPVideoPlayer_Internal.h" #import -#import "./include/video_player_avfoundation/AVAssetTrackUtils.h" +#import "./include/video_player_avfoundation_objc/AVAssetTrackUtils.h" static void *timeRangeContext = &timeRangeContext; static void *statusContext = &statusContext; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPViewProvider.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPViewProvider.m similarity index 91% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPViewProvider.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPViewProvider.m index f72f86927cd8..d9ac02d1beeb 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPViewProvider.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/FVPViewProvider.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "./include/video_player_avfoundation/FVPViewProvider.h" +#import "./include/video_player_avfoundation_objc/FVPViewProvider.h" #if TARGET_OS_OSX @import FlutterMacOS; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.m similarity index 54% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.m index abb8efbad50d..0c2cfc987374 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.m @@ -1,10 +1,10 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.7), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon -#import "./include/video_player_avfoundation/messages.g.h" +#import "./include/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.h" #if TARGET_OS_OSX @import FlutterMacOS; @@ -12,6 +12,97 @@ @import Flutter; #endif +static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { + if (a == b) { + return YES; + } + if (a == nil) { + return b == [NSNull null]; + } + if (b == nil) { + return a == [NSNull null]; + } + if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { + return + [a isEqual:b] || (isnan([(NSNumber *)a doubleValue]) && isnan([(NSNumber *)b doubleValue])); + } + if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { + NSArray *arrayA = (NSArray *)a; + NSArray *arrayB = (NSArray *)b; + if (arrayA.count != arrayB.count) { + return NO; + } + for (NSUInteger i = 0; i < arrayA.count; i++) { + if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { + return NO; + } + } + return YES; + } + if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictA = (NSDictionary *)a; + NSDictionary *dictB = (NSDictionary *)b; + if (dictA.count != dictB.count) { + return NO; + } + for (id keyA in dictA) { + id valueA = dictA[keyA]; + BOOL found = NO; + for (id keyB in dictB) { + if (FLTPigeonDeepEquals(keyA, keyB)) { + id valueB = dictB[keyB]; + if (FLTPigeonDeepEquals(valueA, valueB)) { + found = YES; + break; + } else { + return NO; + } + } + } + if (!found) { + return NO; + } + } + return YES; + } + return [a isEqual:b]; +} + +static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { + if (value == nil || value == (id)[NSNull null]) { + return 0; + } + if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double d = n.doubleValue; + if (isnan(d)) { + // Normalize NaN to a consistent hash. + return (NSUInteger)0x7FF8000000000000; + } + if (d == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + d = 0.0; + } + return @(d).hash; + } + if ([value isKindOfClass:[NSArray class]]) { + NSUInteger result = 1; + for (id item in (NSArray *)value) { + result = result * 31 + FLTPigeonDeepHash(item); + } + return result; + } + if ([value isKindOfClass:[NSDictionary class]]) { + NSUInteger result = 0; + NSDictionary *dict = (NSDictionary *)value; + for (id key in dict) { + result += ((FLTPigeonDeepHash(key) * 31) ^ FLTPigeonDeepHash(dict[key])); + } + return result; + } + return [value hash]; +} + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ @@ -26,102 +117,12 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { return (result == [NSNull null]) ? nil : result; } -@interface FVPPlatformVideoViewCreationParams () -+ (FVPPlatformVideoViewCreationParams *)fromList:(NSArray *)list; -+ (nullable FVPPlatformVideoViewCreationParams *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface FVPCreationOptions () -+ (FVPCreationOptions *)fromList:(NSArray *)list; -+ (nullable FVPCreationOptions *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - -@interface FVPTexturePlayerIds () -+ (FVPTexturePlayerIds *)fromList:(NSArray *)list; -+ (nullable FVPTexturePlayerIds *)nullableFromList:(NSArray *)list; -- (NSArray *)toList; -@end - @interface FVPMediaSelectionAudioTrackData () + (FVPMediaSelectionAudioTrackData *)fromList:(NSArray *)list; + (nullable FVPMediaSelectionAudioTrackData *)nullableFromList:(NSArray *)list; - (NSArray *)toList; @end -@implementation FVPPlatformVideoViewCreationParams -+ (instancetype)makeWithPlayerId:(NSInteger)playerId { - FVPPlatformVideoViewCreationParams *pigeonResult = - [[FVPPlatformVideoViewCreationParams alloc] init]; - pigeonResult.playerId = playerId; - return pigeonResult; -} -+ (FVPPlatformVideoViewCreationParams *)fromList:(NSArray *)list { - FVPPlatformVideoViewCreationParams *pigeonResult = - [[FVPPlatformVideoViewCreationParams alloc] init]; - pigeonResult.playerId = [GetNullableObjectAtIndex(list, 0) integerValue]; - return pigeonResult; -} -+ (nullable FVPPlatformVideoViewCreationParams *)nullableFromList:(NSArray *)list { - return (list) ? [FVPPlatformVideoViewCreationParams fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - @(self.playerId), - ]; -} -@end - -@implementation FVPCreationOptions -+ (instancetype)makeWithUri:(NSString *)uri - httpHeaders:(NSDictionary *)httpHeaders { - FVPCreationOptions *pigeonResult = [[FVPCreationOptions alloc] init]; - pigeonResult.uri = uri; - pigeonResult.httpHeaders = httpHeaders; - return pigeonResult; -} -+ (FVPCreationOptions *)fromList:(NSArray *)list { - FVPCreationOptions *pigeonResult = [[FVPCreationOptions alloc] init]; - pigeonResult.uri = GetNullableObjectAtIndex(list, 0); - pigeonResult.httpHeaders = GetNullableObjectAtIndex(list, 1); - return pigeonResult; -} -+ (nullable FVPCreationOptions *)nullableFromList:(NSArray *)list { - return (list) ? [FVPCreationOptions fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - self.uri ?: [NSNull null], - self.httpHeaders ?: [NSNull null], - ]; -} -@end - -@implementation FVPTexturePlayerIds -+ (instancetype)makeWithPlayerId:(NSInteger)playerId textureId:(NSInteger)textureId { - FVPTexturePlayerIds *pigeonResult = [[FVPTexturePlayerIds alloc] init]; - pigeonResult.playerId = playerId; - pigeonResult.textureId = textureId; - return pigeonResult; -} -+ (FVPTexturePlayerIds *)fromList:(NSArray *)list { - FVPTexturePlayerIds *pigeonResult = [[FVPTexturePlayerIds alloc] init]; - pigeonResult.playerId = [GetNullableObjectAtIndex(list, 0) integerValue]; - pigeonResult.textureId = [GetNullableObjectAtIndex(list, 1) integerValue]; - return pigeonResult; -} -+ (nullable FVPTexturePlayerIds *)nullableFromList:(NSArray *)list { - return (list) ? [FVPTexturePlayerIds fromList:list] : nil; -} -- (NSArray *)toList { - return @[ - @(self.playerId), - @(self.textureId), - ]; -} -@end - @implementation FVPMediaSelectionAudioTrackData + (instancetype)makeWithIndex:(NSInteger)index displayName:(nullable NSString *)displayName @@ -157,20 +158,37 @@ + (nullable FVPMediaSelectionAudioTrackData *)nullableFromList:(NSArray *)li self.commonMetadataTitle ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + FVPMediaSelectionAudioTrackData *other = (FVPMediaSelectionAudioTrackData *)object; + return self.index == other.index && FLTPigeonDeepEquals(self.displayName, other.displayName) && + FLTPigeonDeepEquals(self.languageCode, other.languageCode) && + self.isSelected == other.isSelected && + FLTPigeonDeepEquals(self.commonMetadataTitle, other.commonMetadataTitle); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + @(self.index).hash; + result = result * 31 + FLTPigeonDeepHash(self.displayName); + result = result * 31 + FLTPigeonDeepHash(self.languageCode); + result = result * 31 + @(self.isSelected).hash; + result = result * 31 + FLTPigeonDeepHash(self.commonMetadataTitle); + return result; +} @end -@interface FVPMessagesPigeonCodecReader : FlutterStandardReader +@interface FVPVideoPlayerInstanceMessagesPigeonCodecReader : FlutterStandardReader @end -@implementation FVPMessagesPigeonCodecReader +@implementation FVPVideoPlayerInstanceMessagesPigeonCodecReader - (nullable id)readValueOfType:(UInt8)type { switch (type) { case 129: - return [FVPPlatformVideoViewCreationParams fromList:[self readValue]]; - case 130: - return [FVPCreationOptions fromList:[self readValue]]; - case 131: - return [FVPTexturePlayerIds fromList:[self readValue]]; - case 132: return [FVPMediaSelectionAudioTrackData fromList:[self readValue]]; default: return [super readValueOfType:type]; @@ -178,182 +196,40 @@ - (nullable id)readValueOfType:(UInt8)type { } @end -@interface FVPMessagesPigeonCodecWriter : FlutterStandardWriter +@interface FVPVideoPlayerInstanceMessagesPigeonCodecWriter : FlutterStandardWriter @end -@implementation FVPMessagesPigeonCodecWriter +@implementation FVPVideoPlayerInstanceMessagesPigeonCodecWriter - (void)writeValue:(id)value { - if ([value isKindOfClass:[FVPPlatformVideoViewCreationParams class]]) { + if ([value isKindOfClass:[FVPMediaSelectionAudioTrackData class]]) { [self writeByte:129]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[FVPCreationOptions class]]) { - [self writeByte:130]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[FVPTexturePlayerIds class]]) { - [self writeByte:131]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[FVPMediaSelectionAudioTrackData class]]) { - [self writeByte:132]; - [self writeValue:[value toList]]; } else { [super writeValue:value]; } } @end -@interface FVPMessagesPigeonCodecReaderWriter : FlutterStandardReaderWriter +@interface FVPVideoPlayerInstanceMessagesPigeonCodecReaderWriter : FlutterStandardReaderWriter @end -@implementation FVPMessagesPigeonCodecReaderWriter +@implementation FVPVideoPlayerInstanceMessagesPigeonCodecReaderWriter - (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { - return [[FVPMessagesPigeonCodecWriter alloc] initWithData:data]; + return [[FVPVideoPlayerInstanceMessagesPigeonCodecWriter alloc] initWithData:data]; } - (FlutterStandardReader *)readerWithData:(NSData *)data { - return [[FVPMessagesPigeonCodecReader alloc] initWithData:data]; + return [[FVPVideoPlayerInstanceMessagesPigeonCodecReader alloc] initWithData:data]; } @end -NSObject *FVPGetMessagesCodec(void) { +NSObject *FVPGetVideoPlayerInstanceMessagesCodec(void) { static FlutterStandardMessageCodec *sSharedObject = nil; static dispatch_once_t sPred = 0; dispatch_once(&sPred, ^{ - FVPMessagesPigeonCodecReaderWriter *readerWriter = - [[FVPMessagesPigeonCodecReaderWriter alloc] init]; + FVPVideoPlayerInstanceMessagesPigeonCodecReaderWriter *readerWriter = + [[FVPVideoPlayerInstanceMessagesPigeonCodecReaderWriter alloc] init]; sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; }); return sSharedObject; } -void SetUpFVPAVFoundationVideoPlayerApi(id binaryMessenger, - NSObject *api) { - SetUpFVPAVFoundationVideoPlayerApiWithSuffix(binaryMessenger, api, @""); -} - -void SetUpFVPAVFoundationVideoPlayerApiWithSuffix(id binaryMessenger, - NSObject *api, - NSString *messageChannelSuffix) { - messageChannelSuffix = messageChannelSuffix.length > 0 - ? [NSString stringWithFormat:@".%@", messageChannelSuffix] - : @""; - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.video_player_avfoundation." - @"AVFoundationVideoPlayerApi.initialize", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(initialize:)], - @"FVPAVFoundationVideoPlayerApi api (%@) doesn't respond to @selector(initialize:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - FlutterError *error; - [api initialize:&error]; - callback(wrapResult(nil, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.video_player_avfoundation." - @"AVFoundationVideoPlayerApi.createForPlatformView", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(createPlatformViewPlayerWithOptions:error:)], - @"FVPAVFoundationVideoPlayerApi api (%@) doesn't respond to " - @"@selector(createPlatformViewPlayerWithOptions:error:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FVPCreationOptions *arg_params = GetNullableObjectAtIndex(args, 0); - FlutterError *error; - NSNumber *output = [api createPlatformViewPlayerWithOptions:arg_params error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.video_player_avfoundation." - @"AVFoundationVideoPlayerApi.createForTextureView", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(createTexturePlayerWithOptions:error:)], - @"FVPAVFoundationVideoPlayerApi api (%@) doesn't respond to " - @"@selector(createTexturePlayerWithOptions:error:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - FVPCreationOptions *arg_creationOptions = GetNullableObjectAtIndex(args, 0); - FlutterError *error; - FVPTexturePlayerIds *output = [api createTexturePlayerWithOptions:arg_creationOptions - error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.video_player_avfoundation." - @"AVFoundationVideoPlayerApi.setMixWithOthers", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(setMixWithOthers:error:)], - @"FVPAVFoundationVideoPlayerApi api (%@) doesn't respond to " - @"@selector(setMixWithOthers:error:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - BOOL arg_mixWithOthers = [GetNullableObjectAtIndex(args, 0) boolValue]; - FlutterError *error; - [api setMixWithOthers:arg_mixWithOthers error:&error]; - callback(wrapResult(nil, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } - { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.video_player_avfoundation." - @"AVFoundationVideoPlayerApi.getAssetUrl", - messageChannelSuffix] - binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; - if (api) { - NSCAssert([api respondsToSelector:@selector(fileURLForAssetWithName:package:error:)], - @"FVPAVFoundationVideoPlayerApi api (%@) doesn't respond to " - @"@selector(fileURLForAssetWithName:package:error:)", - api); - [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - NSArray *args = message; - NSString *arg_asset = GetNullableObjectAtIndex(args, 0); - NSString *arg_package = GetNullableObjectAtIndex(args, 1); - FlutterError *error; - NSString *output = [api fileURLForAssetWithName:arg_asset package:arg_package error:&error]; - callback(wrapResult(output, error)); - }]; - } else { - [channel setMessageHandler:nil]; - } - } -} void SetUpFVPVideoPlayerInstanceApi(id binaryMessenger, NSObject *api) { SetUpFVPVideoPlayerInstanceApiWithSuffix(binaryMessenger, api, @""); @@ -372,7 +248,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.setLooping", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert( [api respondsToSelector:@selector(setLooping:error:)], @@ -396,7 +272,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.setVolume", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert( [api respondsToSelector:@selector(setVolume:error:)], @@ -420,7 +296,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.setPlaybackSpeed", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert([api respondsToSelector:@selector(setPlaybackSpeed:error:)], @"FVPVideoPlayerInstanceApi api (%@) doesn't respond to " @@ -444,7 +320,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.play", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert([api respondsToSelector:@selector(playWithError:)], @"FVPVideoPlayerInstanceApi api (%@) doesn't respond to @selector(playWithError:)", @@ -465,7 +341,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.getPosition", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert([api respondsToSelector:@selector(position:)], @"FVPVideoPlayerInstanceApi api (%@) doesn't respond to @selector(position:)", api); @@ -485,7 +361,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.seekTo", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert( [api respondsToSelector:@selector(seekTo:completion:)], @@ -510,7 +386,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.pause", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert([api respondsToSelector:@selector(pauseWithError:)], @"FVPVideoPlayerInstanceApi api (%@) doesn't respond to @selector(pauseWithError:)", @@ -531,7 +407,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.dispose", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert( [api respondsToSelector:@selector(disposeWithError:)], @@ -553,7 +429,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.getAudioTracks", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert([api respondsToSelector:@selector(getAudioTracks:)], @"FVPVideoPlayerInstanceApi api (%@) doesn't respond to @selector(getAudioTracks:)", @@ -574,7 +450,7 @@ void SetUpFVPVideoPlayerInstanceApiWithSuffix(id binaryM @"VideoPlayerInstanceApi.selectAudioTrack", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FVPGetMessagesCodec()]; + codec:FVPGetVideoPlayerInstanceMessagesCodec()]; if (api) { NSCAssert([api respondsToSelector:@selector(selectAudioTrackAtIndex:error:)], @"FVPVideoPlayerInstanceApi api (%@) doesn't respond to " diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/AVAssetTrackUtils.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/AVAssetTrackUtils.h similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/AVAssetTrackUtils.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/AVAssetTrackUtils.h diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPAVFactory.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPAVFactory.h similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPAVFactory.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPAVFactory.h diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPAssetProvider.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPAssetProvider.h similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPAssetProvider.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPAssetProvider.h diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPDisplayLink.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPDisplayLink.h similarity index 97% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPDisplayLink.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPDisplayLink.h index 7646669069a4..3e4835b24aea 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPDisplayLink.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPDisplayLink.h @@ -6,6 +6,8 @@ #import "FVPViewProvider.h" +NS_ASSUME_NONNULL_BEGIN + // A cross-platform display link abstraction. @protocol FVPDisplayLink @@ -49,3 +51,5 @@ API_AVAILABLE(ios(4.0), macos(14.0)) @end #endif + +NS_ASSUME_NONNULL_END diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPEventBridge.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPEventBridge.h similarity index 93% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPEventBridge.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPEventBridge.h index 873361e53d2e..4205e89037e8 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPEventBridge.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPEventBridge.h @@ -6,6 +6,8 @@ #import "FVPVideoEventListener.h" +NS_ASSUME_NONNULL_BEGIN + #if TARGET_OS_OSX @import FlutterMacOS; #else @@ -20,3 +22,5 @@ channelName:(NSString *)channelName; @end + +NS_ASSUME_NONNULL_END diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPFrameUpdater.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPFrameUpdater.h similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPFrameUpdater.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPFrameUpdater.h diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoView.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPNativeVideoView.h similarity index 93% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoView.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPNativeVideoView.h index 627195470f6e..23aabe08214f 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPNativeVideoView.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPNativeVideoView.h @@ -10,6 +10,8 @@ @import Flutter; #endif +NS_ASSUME_NONNULL_BEGIN + /// A class used to create a native video view that can be embedded in a Flutter app. /// This class wraps an AVPlayer instance and displays its video content. #if TARGET_OS_IOS @@ -21,3 +23,5 @@ /// It creates a video view instance and sets the provided AVPlayer instance to it. - (instancetype)initWithPlayer:(AVPlayer *)player; @end + +NS_ASSUME_NONNULL_END diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer.h similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer.h diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer_Test.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer_Test.h similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer_Test.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPTextureBasedVideoPlayer_Test.h diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoEventListener.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPVideoEventListener.h similarity index 97% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoEventListener.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPVideoEventListener.h index a267adbb902b..4787b1111dbe 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoEventListener.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPVideoEventListener.h @@ -4,6 +4,8 @@ @import Foundation; +NS_ASSUME_NONNULL_BEGIN + /// Handles event/status callbacks from FVPVideoPlayer. /// /// This is an abstraction around the event channel to avoid coupling FVPVideoPlayer directly to @@ -30,3 +32,5 @@ /// Called when the video player has been disposed on the Dart side. - (void)videoPlayerWasDisposed; @end + +NS_ASSUME_NONNULL_END diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPVideoPlayer.h similarity index 92% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPVideoPlayer.h index 02954d7a3680..be10a3317e97 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPVideoPlayer.h @@ -4,7 +4,7 @@ @import AVFoundation; -#import "./messages.g.h" +#import "./VideoPlayerInstanceMessages.g.h" #import "FVPAVFactory.h" #import "FVPVideoEventListener.h" #import "FVPViewProvider.h" @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN /// FVPVideoPlayer manages video playback using AVPlayer. /// It provides methods for controlling playback, adjusting volume, and handling seeking. /// This class contains all functionalities needed to manage video playback in platform views and is -/// typically used alongside FVPNativeVideoViewFactory. If you need to display a video using a +/// typically used alongside NativeVideoViewFactory. If you need to display a video using a /// texture, use FVPTextureBasedVideoPlayer instead. @interface FVPVideoPlayer : NSObject /// The AVPlayer instance used for video playback. diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPVideoPlayer_Internal.h similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPVideoPlayer_Internal.h diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPViewProvider.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPViewProvider.h similarity index 100% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPViewProvider.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/FVPViewProvider.h diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.h similarity index 50% rename from packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h rename to packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.h index 3b2dd3952245..b06b0357d2a1 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.h @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.7), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon @import Foundation; @@ -13,36 +13,8 @@ NS_ASSUME_NONNULL_BEGIN -@class FVPPlatformVideoViewCreationParams; -@class FVPCreationOptions; -@class FVPTexturePlayerIds; @class FVPMediaSelectionAudioTrackData; -/// Information passed to the platform view creation. -@interface FVPPlatformVideoViewCreationParams : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithPlayerId:(NSInteger)playerId; -@property(nonatomic, assign) NSInteger playerId; -@end - -@interface FVPCreationOptions : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithUri:(NSString *)uri - httpHeaders:(NSDictionary *)httpHeaders; -@property(nonatomic, copy) NSString *uri; -@property(nonatomic, copy) NSDictionary *httpHeaders; -@end - -@interface FVPTexturePlayerIds : NSObject -/// `init` unavailable to enforce nonnull fields, see the `make` class method. -- (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithPlayerId:(NSInteger)playerId textureId:(NSInteger)textureId; -@property(nonatomic, assign) NSInteger playerId; -@property(nonatomic, assign) NSInteger textureId; -@end - /// Raw audio track data from AVMediaSelectionOption (for HLS streams). @interface FVPMediaSelectionAudioTrackData : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. @@ -60,30 +32,7 @@ NS_ASSUME_NONNULL_BEGIN @end /// The codec used by all APIs. -NSObject *FVPGetMessagesCodec(void); - -@protocol FVPAVFoundationVideoPlayerApi -- (void)initialize:(FlutterError *_Nullable *_Nonnull)error; -/// @return `nil` only when `error != nil`. -- (nullable NSNumber *)createPlatformViewPlayerWithOptions:(FVPCreationOptions *)params - error:(FlutterError *_Nullable *_Nonnull)error; -/// @return `nil` only when `error != nil`. -- (nullable FVPTexturePlayerIds *) - createTexturePlayerWithOptions:(FVPCreationOptions *)creationOptions - error:(FlutterError *_Nullable *_Nonnull)error; -- (void)setMixWithOthers:(BOOL)mixWithOthers error:(FlutterError *_Nullable *_Nonnull)error; -- (nullable NSString *)fileURLForAssetWithName:(NSString *)asset - package:(nullable NSString *)package - error:(FlutterError *_Nullable *_Nonnull)error; -@end - -extern void SetUpFVPAVFoundationVideoPlayerApi( - id binaryMessenger, - NSObject *_Nullable api); - -extern void SetUpFVPAVFoundationVideoPlayerApiWithSuffix( - id binaryMessenger, - NSObject *_Nullable api, NSString *messageChannelSuffix); +NSObject *FVPGetVideoPlayerInstanceMessagesCodec(void); @protocol FVPVideoPlayerInstanceApi - (void)setLooping:(BOOL)looping error:(FlutterError *_Nullable *_Nonnull)error; diff --git a/packages/video_player/video_player_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/video_player/video_player_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index a17db2baa66b..a047a7cbeb4d 100644 --- a/packages/video_player/video_player_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/video_player/video_player_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -53,8 +53,8 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3300E9FA2F69AA5200842B27 /* TestClasses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TestClasses.swift; path = ../../../darwin/RunnerTests/TestClasses.swift; sourceTree = ""; }; - 3300E9FB2F69AA5200842B27 /* VideoPlayerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = VideoPlayerTests.swift; path = ../../../darwin/RunnerTests/VideoPlayerTests.swift; sourceTree = ""; }; + 3300E9FA2F69AA5200842B27 /* TestClasses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TestClasses.swift; path = ../../darwin/RunnerTests/TestClasses.swift; sourceTree = SOURCE_ROOT; }; + 3300E9FB2F69AA5200842B27 /* VideoPlayerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = VideoPlayerTests.swift; path = ../../darwin/RunnerTests/VideoPlayerTests.swift; sourceTree = SOURCE_ROOT; }; 3300EA022F69AA9500842B27 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3300EA152F69AB0B00842B27 /* VideoPlayerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerUITests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; diff --git a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart index 6684d9c4c658..c9ab066711f0 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart @@ -8,7 +8,8 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; -import 'messages.g.dart'; +import 'video_player_instance_messages.g.dart'; +import 'video_player_plugin_messages.g.dart'; /// The non-test implementation of `_apiProvider`. VideoPlayerInstanceApi _productionApiProvider(int playerId) { diff --git a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart b/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart deleted file mode 100644 index 24644d8f42d0..000000000000 --- a/packages/video_player/video_player_avfoundation/lib/src/messages.g.dart +++ /dev/null @@ -1,681 +0,0 @@ -// Copyright 2013 The Flutter Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.7), do not edit directly. -// See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, omit_obvious_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers - -import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; - -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; -import 'package:flutter/services.dart'; - -PlatformException _createConnectionError(String channelName) { - return PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); -} - -bool _deepEquals(Object? a, Object? b) { - if (a is List && b is List) { - return a.length == b.length && - a.indexed.every( - ((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), - ); - } - if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); - } - return a == b; -} - -/// Information passed to the platform view creation. -class PlatformVideoViewCreationParams { - PlatformVideoViewCreationParams({required this.playerId}); - - int playerId; - - List _toList() { - return [playerId]; - } - - Object encode() { - return _toList(); - } - - static PlatformVideoViewCreationParams decode(Object result) { - result as List; - return PlatformVideoViewCreationParams(playerId: result[0]! as int); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! PlatformVideoViewCreationParams || - other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(encode(), other.encode()); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); -} - -class CreationOptions { - CreationOptions({required this.uri, required this.httpHeaders}); - - String uri; - - Map httpHeaders; - - List _toList() { - return [uri, httpHeaders]; - } - - Object encode() { - return _toList(); - } - - static CreationOptions decode(Object result) { - result as List; - return CreationOptions( - uri: result[0]! as String, - httpHeaders: (result[1] as Map?)! - .cast(), - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! CreationOptions || other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(encode(), other.encode()); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); -} - -class TexturePlayerIds { - TexturePlayerIds({required this.playerId, required this.textureId}); - - int playerId; - - int textureId; - - List _toList() { - return [playerId, textureId]; - } - - Object encode() { - return _toList(); - } - - static TexturePlayerIds decode(Object result) { - result as List; - return TexturePlayerIds( - playerId: result[0]! as int, - textureId: result[1]! as int, - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! TexturePlayerIds || other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(encode(), other.encode()); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); -} - -/// Raw audio track data from AVMediaSelectionOption (for HLS streams). -class MediaSelectionAudioTrackData { - MediaSelectionAudioTrackData({ - required this.index, - this.displayName, - this.languageCode, - required this.isSelected, - this.commonMetadataTitle, - }); - - int index; - - String? displayName; - - String? languageCode; - - bool isSelected; - - String? commonMetadataTitle; - - List _toList() { - return [ - index, - displayName, - languageCode, - isSelected, - commonMetadataTitle, - ]; - } - - Object encode() { - return _toList(); - } - - static MediaSelectionAudioTrackData decode(Object result) { - result as List; - return MediaSelectionAudioTrackData( - index: result[0]! as int, - displayName: result[1] as String?, - languageCode: result[2] as String?, - isSelected: result[3]! as bool, - commonMetadataTitle: result[4] as String?, - ); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is! MediaSelectionAudioTrackData || - other.runtimeType != runtimeType) { - return false; - } - if (identical(this, other)) { - return true; - } - return _deepEquals(encode(), other.encode()); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); -} - -class _PigeonCodec extends StandardMessageCodec { - const _PigeonCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is PlatformVideoViewCreationParams) { - buffer.putUint8(129); - writeValue(buffer, value.encode()); - } else if (value is CreationOptions) { - buffer.putUint8(130); - writeValue(buffer, value.encode()); - } else if (value is TexturePlayerIds) { - buffer.putUint8(131); - writeValue(buffer, value.encode()); - } else if (value is MediaSelectionAudioTrackData) { - buffer.putUint8(132); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 129: - return PlatformVideoViewCreationParams.decode(readValue(buffer)!); - case 130: - return CreationOptions.decode(readValue(buffer)!); - case 131: - return TexturePlayerIds.decode(readValue(buffer)!); - case 132: - return MediaSelectionAudioTrackData.decode(readValue(buffer)!); - default: - return super.readValueOfType(type, buffer); - } - } -} - -class AVFoundationVideoPlayerApi { - /// Constructor for [AVFoundationVideoPlayerApi]. The [binaryMessenger] named argument is - /// available for dependency injection. If it is left null, the default - /// BinaryMessenger will be used which routes to the host platform. - AVFoundationVideoPlayerApi({ - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty - ? '.$messageChannelSuffix' - : ''; - final BinaryMessenger? pigeonVar_binaryMessenger; - - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - final String pigeonVar_messageChannelSuffix; - - Future initialize() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.initialize$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future createForPlatformView(CreationOptions params) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.createForPlatformView$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [params], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } - } - - Future createForTextureView( - CreationOptions creationOptions, - ) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.createForTextureView$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [creationOptions], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as TexturePlayerIds?)!; - } - } - - Future setMixWithOthers(bool mixWithOthers) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.setMixWithOthers$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [mixWithOthers], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future getAssetUrl(String asset, String? package) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.getAssetUrl$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [asset, package], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return (pigeonVar_replyList[0] as String?); - } - } -} - -class VideoPlayerInstanceApi { - /// Constructor for [VideoPlayerInstanceApi]. The [binaryMessenger] named argument is - /// available for dependency injection. If it is left null, the default - /// BinaryMessenger will be used which routes to the host platform. - VideoPlayerInstanceApi({ - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty - ? '.$messageChannelSuffix' - : ''; - final BinaryMessenger? pigeonVar_binaryMessenger; - - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - final String pigeonVar_messageChannelSuffix; - - Future setLooping(bool looping) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.setLooping$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [looping], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future setVolume(double volume) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.setVolume$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [volume], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future setPlaybackSpeed(double speed) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.setPlaybackSpeed$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [speed], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future play() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.play$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future getPosition() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.getPosition$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } - } - - Future seekTo(int position) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.seekTo$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [position], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future pause() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.pause$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future dispose() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.dispose$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - Future> getAudioTracks() async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.getAudioTracks$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)! - .cast(); - } - } - - Future selectAudioTrack(int trackIndex) async { - final pigeonVar_channelName = - 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.selectAudioTrack$pigeonVar_messageChannelSuffix'; - final pigeonVar_channel = BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [trackIndex], - ); - final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } -} diff --git a/packages/video_player/video_player_avfoundation/lib/src/video_player_instance_messages.g.dart b/packages/video_player/video_player_avfoundation/lib/src/video_player_instance_messages.g.dart new file mode 100644 index 000000000000..c10d9f31a0ce --- /dev/null +++ b/packages/video_player/video_player_avfoundation/lib/src/video_player_instance_messages.g.dart @@ -0,0 +1,405 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List; + +import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; + +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; +} + +bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } + if (a is List && b is List) { + return a.length == b.length && + a.indexed.every( + ((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), + ); + } + if (a is Map && b is Map) { + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; + } + return a == b; +} + +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + +/// Raw audio track data from AVMediaSelectionOption (for HLS streams). +class MediaSelectionAudioTrackData { + MediaSelectionAudioTrackData({ + required this.index, + this.displayName, + this.languageCode, + required this.isSelected, + this.commonMetadataTitle, + }); + + int index; + + String? displayName; + + String? languageCode; + + bool isSelected; + + String? commonMetadataTitle; + + List _toList() { + return [ + index, + displayName, + languageCode, + isSelected, + commonMetadataTitle, + ]; + } + + Object encode() { + return _toList(); + } + + static MediaSelectionAudioTrackData decode(Object result) { + result as List; + return MediaSelectionAudioTrackData( + index: result[0]! as int, + displayName: result[1] as String?, + languageCode: result[2] as String?, + isSelected: result[3]! as bool, + commonMetadataTitle: result[4] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! MediaSelectionAudioTrackData || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(index, other.index) && + _deepEquals(displayName, other.displayName) && + _deepEquals(languageCode, other.languageCode) && + _deepEquals(isSelected, other.isSelected) && + _deepEquals(commonMetadataTitle, other.commonMetadataTitle); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is MediaSelectionAudioTrackData) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + return MediaSelectionAudioTrackData.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class VideoPlayerInstanceApi { + /// Constructor for [VideoPlayerInstanceApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + VideoPlayerInstanceApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future setLooping(bool looping) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.setLooping$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [looping], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future setVolume(double volume) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.setVolume$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [volume], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future setPlaybackSpeed(double speed) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.setPlaybackSpeed$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [speed], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future play() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.play$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future getPosition() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.getPosition$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; + } + + Future seekTo(int position) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.seekTo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [position], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future pause() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.pause$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future dispose() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.dispose$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future> getAudioTracks() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.getAudioTracks$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List) + .cast(); + } + + Future selectAudioTrack(int trackIndex) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.VideoPlayerInstanceApi.selectAudioTrack$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [trackIndex], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } +} diff --git a/packages/video_player/video_player_avfoundation/lib/src/video_player_plugin_messages.g.dart b/packages/video_player/video_player_avfoundation/lib/src/video_player_plugin_messages.g.dart new file mode 100644 index 000000000000..e1d4dbaa2136 --- /dev/null +++ b/packages/video_player/video_player_avfoundation/lib/src/video_player_plugin_messages.g.dart @@ -0,0 +1,377 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List; + +import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; + +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; +} + +bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } + if (a is List && b is List) { + return a.length == b.length && + a.indexed.every( + ((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), + ); + } + if (a is Map && b is Map) { + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; + } + return a == b; +} + +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + +/// Information passed to the platform view creation. +class PlatformVideoViewCreationParams { + PlatformVideoViewCreationParams({required this.playerId}); + + int playerId; + + List _toList() { + return [playerId]; + } + + Object encode() { + return _toList(); + } + + static PlatformVideoViewCreationParams decode(Object result) { + result as List; + return PlatformVideoViewCreationParams(playerId: result[0]! as int); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformVideoViewCreationParams || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(playerId, other.playerId); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class CreationOptions { + CreationOptions({required this.uri, required this.httpHeaders}); + + String uri; + + Map httpHeaders; + + List _toList() { + return [uri, httpHeaders]; + } + + Object encode() { + return _toList(); + } + + static CreationOptions decode(Object result) { + result as List; + return CreationOptions( + uri: result[0]! as String, + httpHeaders: (result[1]! as Map).cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! CreationOptions || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(uri, other.uri) && + _deepEquals(httpHeaders, other.httpHeaders); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class TexturePlayerIds { + TexturePlayerIds({required this.playerId, required this.textureId}); + + int playerId; + + int textureId; + + List _toList() { + return [playerId, textureId]; + } + + Object encode() { + return _toList(); + } + + static TexturePlayerIds decode(Object result) { + result as List; + return TexturePlayerIds( + playerId: result[0]! as int, + textureId: result[1]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! TexturePlayerIds || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(playerId, other.playerId) && + _deepEquals(textureId, other.textureId); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _deepHash([runtimeType, ..._toList()]); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is PlatformVideoViewCreationParams) { + buffer.putUint8(129); + writeValue(buffer, value.encode()); + } else if (value is CreationOptions) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is TexturePlayerIds) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + return PlatformVideoViewCreationParams.decode(readValue(buffer)!); + case 130: + return CreationOptions.decode(readValue(buffer)!); + case 131: + return TexturePlayerIds.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +class AVFoundationVideoPlayerApi { + /// Constructor for [AVFoundationVideoPlayerApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + AVFoundationVideoPlayerApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future initialize() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.initialize$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future createForPlatformView(CreationOptions params) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.createForPlatformView$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [params], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; + } + + Future createForTextureView( + CreationOptions creationOptions, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.createForTextureView$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [creationOptions], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as TexturePlayerIds; + } + + Future setMixWithOthers(bool mixWithOthers) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.setMixWithOthers$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [mixWithOthers], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + } + + Future getAssetUrl(String asset, String? package) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.getAssetUrl$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [asset, package], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as String?; + } +} diff --git a/packages/video_player/video_player_avfoundation/pigeons/messages.dart b/packages/video_player/video_player_avfoundation/pigeons/video_player_instance_messages.dart similarity index 51% rename from packages/video_player/video_player_avfoundation/pigeons/messages.dart rename to packages/video_player/video_player_avfoundation/pigeons/video_player_instance_messages.dart index f49b46005307..354d2357b7ca 100644 --- a/packages/video_player/video_player_avfoundation/pigeons/messages.dart +++ b/packages/video_player/video_player_avfoundation/pigeons/video_player_instance_messages.dart @@ -2,43 +2,25 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Contains player-instance-level APIs. + import 'package:pigeon/pigeon.dart'; @ConfigurePigeon( PigeonOptions( - dartOut: 'lib/src/messages.g.dart', + dartOut: 'lib/src/video_player_instance_messages.g.dart', objcHeaderOut: - 'darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/messages.g.h', + 'darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/include/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.h', objcSourceOut: - 'darwin/video_player_avfoundation/Sources/video_player_avfoundation/messages.g.m', + 'darwin/video_player_avfoundation/Sources/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.m', objcOptions: ObjcOptions( prefix: 'FVP', - headerIncludePath: './include/video_player_avfoundation/messages.g.h', + headerIncludePath: + './include/video_player_avfoundation_objc/VideoPlayerInstanceMessages.g.h', ), copyrightHeader: 'pigeons/copyright.txt', ), ) -/// Information passed to the platform view creation. -class PlatformVideoViewCreationParams { - const PlatformVideoViewCreationParams({required this.playerId}); - - final int playerId; -} - -class CreationOptions { - CreationOptions({required this.uri, required this.httpHeaders}); - - String uri; - Map httpHeaders; -} - -class TexturePlayerIds { - TexturePlayerIds({required this.playerId, required this.textureId}); - - final int playerId; - final int textureId; -} - /// Raw audio track data from AVMediaSelectionOption (for HLS streams). class MediaSelectionAudioTrackData { MediaSelectionAudioTrackData({ @@ -56,23 +38,6 @@ class MediaSelectionAudioTrackData { String? commonMetadataTitle; } -@HostApi() -abstract class AVFoundationVideoPlayerApi { - @ObjCSelector('initialize') - void initialize(); - // Creates a new player using a platform view for rendering and returns its - // ID. - @ObjCSelector('createPlatformViewPlayerWithOptions:') - int createForPlatformView(CreationOptions params); - // Creates a new player using a texture for rendering and returns its IDs. - @ObjCSelector('createTexturePlayerWithOptions:') - TexturePlayerIds createForTextureView(CreationOptions creationOptions); - @ObjCSelector('setMixWithOthers:') - void setMixWithOthers(bool mixWithOthers); - @ObjCSelector('fileURLForAssetWithName:package:') - String? getAssetUrl(String asset, String? package); -} - @HostApi() abstract class VideoPlayerInstanceApi { @ObjCSelector('setLooping:') diff --git a/packages/video_player/video_player_avfoundation/pigeons/video_player_plugin_messages.dart b/packages/video_player/video_player_avfoundation/pigeons/video_player_plugin_messages.dart new file mode 100644 index 000000000000..91f4fc80cbda --- /dev/null +++ b/packages/video_player/video_player_avfoundation/pigeons/video_player_plugin_messages.dart @@ -0,0 +1,52 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Contains plugin-class-level APIs. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartOut: 'lib/src/video_player_plugin_messages.g.dart', + swiftOut: + 'darwin/video_player_avfoundation/Sources/video_player_avfoundation/VideoPlayerPluginMessages.g.swift', + copyrightHeader: 'pigeons/copyright.txt', + ), +) +/// Information passed to the platform view creation. +class PlatformVideoViewCreationParams { + const PlatformVideoViewCreationParams({required this.playerId}); + + final int playerId; +} + +class CreationOptions { + CreationOptions({required this.uri, required this.httpHeaders}); + + String uri; + Map httpHeaders; +} + +class TexturePlayerIds { + TexturePlayerIds({required this.playerId, required this.textureId}); + + final int playerId; + final int textureId; +} + +@HostApi() +abstract class AVFoundationVideoPlayerApi { + void initialize(); + // Creates a new player using a platform view for rendering and returns its + // ID. + @SwiftFunction('createPlatformViewPlayer(options:)') + int createForPlatformView(CreationOptions params); + // Creates a new player using a texture for rendering and returns its IDs. + @SwiftFunction('createTexturePlayer(options:)') + TexturePlayerIds createForTextureView(CreationOptions creationOptions); + @SwiftFunction('setMixWithOthers(_:)') + void setMixWithOthers(bool mixWithOthers); + @SwiftFunction('fileURLForAsset(name:package:)') + String? getAssetUrl(String asset, String? package); +} diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index f14fefb73326..762d8d08eadd 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.9.4 +version: 2.9.5 environment: sdk: ^3.10.0 @@ -14,16 +14,17 @@ flutter: platforms: ios: dartPluginClass: AVFoundationVideoPlayer - pluginClass: FVPVideoPlayerPlugin + pluginClass: VideoPlayerPlugin sharedDarwinSource: true macos: dartPluginClass: AVFoundationVideoPlayer - pluginClass: FVPVideoPlayerPlugin + pluginClass: VideoPlayerPlugin sharedDarwinSource: true dependencies: flutter: sdk: flutter + meta: ^1.10.0 video_player_platform_interface: ^6.6.0 dev_dependencies: @@ -31,7 +32,7 @@ dev_dependencies: flutter_test: sdk: flutter mockito: ^5.4.4 - pigeon: ^26.1.7 + pigeon: ^26.3.4 topics: - video diff --git a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart index c16d5bcb08e9..dcec5e6ee107 100644 --- a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart +++ b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.dart @@ -7,7 +7,8 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:video_player_avfoundation/src/messages.g.dart'; +import 'package:video_player_avfoundation/src/video_player_instance_messages.g.dart'; +import 'package:video_player_avfoundation/src/video_player_plugin_messages.g.dart'; import 'package:video_player_avfoundation/video_player_avfoundation.dart'; import 'package:video_player_platform_interface/video_player_platform_interface.dart'; diff --git a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart index 8caf6ad8dc43..2871affc2596 100644 --- a/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart +++ b/packages/video_player/video_player_avfoundation/test/avfoundation_video_player_test.mocks.dart @@ -7,7 +7,10 @@ import 'dart:async' as _i4; import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/src/dummies.dart' as _i3; -import 'package:video_player_avfoundation/src/messages.g.dart' as _i2; +import 'package:video_player_avfoundation/src/video_player_instance_messages.g.dart' + as _i5; +import 'package:video_player_avfoundation/src/video_player_plugin_messages.g.dart' + as _i2; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -22,6 +25,7 @@ import 'package:video_player_avfoundation/src/messages.g.dart' as _i2; // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeTexturePlayerIds_0 extends _i1.SmartFake implements _i2.TexturePlayerIds { @@ -111,7 +115,7 @@ class MockAVFoundationVideoPlayerApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockVideoPlayerInstanceApi extends _i1.Mock - implements _i2.VideoPlayerInstanceApi { + implements _i5.VideoPlayerInstanceApi { @override String get pigeonVar_messageChannelSuffix => (super.noSuchMethod( @@ -198,4 +202,28 @@ class MockVideoPlayerInstanceApi extends _i1.Mock returnValueForMissingStub: _i4.Future.value(), ) as _i4.Future); + + @override + _i4.Future> getAudioTracks() => + (super.noSuchMethod( + Invocation.method(#getAudioTracks, []), + returnValue: + _i4.Future>.value( + <_i5.MediaSelectionAudioTrackData>[], + ), + returnValueForMissingStub: + _i4.Future>.value( + <_i5.MediaSelectionAudioTrackData>[], + ), + ) + as _i4.Future>); + + @override + _i4.Future selectAudioTrack(int? trackIndex) => + (super.noSuchMethod( + Invocation.method(#selectAudioTrack, [trackIndex]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); }