Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/video_player/video_player/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 2.12.0

* Forwards `VideoPlayerOptions.preferredAudioLanguage` during player creation so platform implementations can apply the preferred audio language per player instance.
* Updates minimum supported SDK version to Flutter 3.38/Dart 3.10.

## 2.11.1
Expand Down
8 changes: 8 additions & 0 deletions packages/video_player/video_player/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ dev_dependencies:
path_provider: ^2.0.6
test: any

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
video_player_android: {path: ../../../../packages/video_player/video_player_android}
video_player_avfoundation: {path: ../../../../packages/video_player/video_player_avfoundation}
video_player_platform_interface: {path: ../../../../packages/video_player/video_player_platform_interface}

flutter:
uses-material-design: true
assets:
Expand All @@ -35,3 +42,4 @@ flutter:
- assets/bumble_bee_captions.srt
- assets/bumble_bee_captions.vtt
- assets/Audio.mp3
- assets/multi_audio.mp4
1 change: 1 addition & 0 deletions packages/video_player/video_player/lib/video_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ class VideoPlayerController extends ValueNotifier<VideoPlayerValue> {
final creationOptions = platform_interface.VideoCreationOptions(
dataSource: dataSourceDescription,
viewType: viewType,
videoPlayerOptions: videoPlayerOptions
);

if (videoPlayerOptions?.mixWithOthers != null) {
Expand Down
8 changes: 7 additions & 1 deletion packages/video_player/video_player/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for displaying inline video with other Flutter
widgets on Android, iOS, macOS and web.
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.11.1
version: 2.12.0

environment:
sdk: ^3.10.0
Expand Down Expand Up @@ -39,3 +39,9 @@ dev_dependencies:
topics:
- video
- video-player
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
video_player_android: {path: ../../../packages/video_player/video_player_android}
video_player_avfoundation: {path: ../../../packages/video_player/video_player_avfoundation}
video_player_platform_interface: {path: ../../../packages/video_player/video_player_platform_interface}
18 changes: 18 additions & 0 deletions packages/video_player/video_player/test/video_player_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1754,6 +1754,22 @@ void main() {
expect(controller.videoPlayerOptions!.mixWithOthers, true);
});

test('preferredAudioLanguage is forwarded to createWithOptions', () async {
final controller = VideoPlayerController.networkUrl(
_localhostUri,
videoPlayerOptions: VideoPlayerOptions(preferredAudioLanguage: 'es'),
);
addTearDown(controller.dispose);

await controller.initialize();

expect(fakeVideoPlayerPlatform.creationOptions.length, 1);
expect(
fakeVideoPlayerPlatform.creationOptions[0].videoPlayerOptions?.preferredAudioLanguage,
'es',
);
});

test('true allowBackgroundPlayback continues playback', () async {
final controller = VideoPlayerController.networkUrl(
_localhostUri,
Expand Down Expand Up @@ -1899,6 +1915,7 @@ class FakeVideoPlayerPlatform extends VideoPlayerPlatform {
List<String> calls = <String>[];
List<DataSource> dataSources = <DataSource>[];
List<VideoViewType> viewTypes = <VideoViewType>[];
List<VideoCreationOptions> creationOptions = <VideoCreationOptions>[];
final Map<int, StreamController<VideoEvent>> streams = <int, StreamController<VideoEvent>>{};
bool forceInitError = false;
int nextPlayerId = 0;
Expand Down Expand Up @@ -1943,6 +1960,7 @@ class FakeVideoPlayerPlatform extends VideoPlayerPlatform {
}
dataSources.add(options.dataSource);
viewTypes.add(options.viewType);
creationOptions.add(options);
return nextPlayerId++;
}

Expand Down
4 changes: 4 additions & 0 deletions packages/video_player/video_player_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.12.0

* Adds support for setting a preferred audio language during player creation via `VideoPlayerOptions.preferredAudioLanguage`.

## 2.11.0

* Adds `backBufferDurationMs` to `CreationOptions` to configure ExoPlayer `DefaultLoadControl` back buffer duration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public VideoPlayer(
exoPlayer.prepare();
exoPlayer.addListener(createExoPlayerEventListener(exoPlayer, surfaceProducer));
setAudioAttributes(exoPlayer, options.mixWithOthers);
setPreferredAudioLanguage(exoPlayer, options.preferredAudioLanguage);
}

public void setDisposeHandler(@Nullable DisposeHandler handler) {
Expand Down Expand Up @@ -447,6 +448,18 @@ public void selectVideoTrack(long groupIndex, long trackIndex) {
trackSelector.buildUponParameters().setOverrideForType(override).build());
}

private static void setPreferredAudioLanguage(
ExoPlayer exoPlayer, String preferredAudioLanguage) {
if (preferredAudioLanguage != null) {
exoPlayer.setTrackSelectionParameters(
exoPlayer
.getTrackSelectionParameters()
.buildUpon()
.setPreferredAudioLanguage(preferredAudioLanguage)
.build());
}
}

public void dispose() {
isDisposed = true;
mainHandler.removeCallbacksAndMessages(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

public class VideoPlayerOptions {
public boolean mixWithOthers;
@Nullable public String preferredAudioLanguage;

/**
* The duration of the back buffer in milliseconds, used to configure ExoPlayer's load control.
Expand All @@ -21,5 +22,6 @@ public VideoPlayerOptions() {}
public VideoPlayerOptions(@NonNull VideoPlayerOptions other) {
this.mixWithOthers = other.mixWithOthers;
this.backBufferDurationMs = other.backBufferDurationMs;
this.preferredAudioLanguage = other.preferredAudioLanguage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ flutter:
assets:
- assets/flutter-mark-square-64.png
- assets/Butterfly-209.mp4
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
video_player_platform_interface: {path: ../../../../packages/video_player/video_player_platform_interface}
6 changes: 5 additions & 1 deletion packages/video_player/video_player_android/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: video_player_android
description: Android implementation of the video_player plugin.
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.11.0
version: 2.12.0

environment:
sdk: ^3.12.0
Expand Down Expand Up @@ -33,3 +33,7 @@ dev_dependencies:
topics:
- video
- video-player
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
video_player_platform_interface: {path: ../../../packages/video_player/video_player_platform_interface}
4 changes: 4 additions & 0 deletions packages/video_player/video_player_avfoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.11.1

* Adds support for setting a preferred audio language during player creation via `VideoPlayerOptions.preferredAudioLanguage`.

## 2.11.0

* Implements `setPreventsDisplaySleepDuringVideoPlayback` using
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ public final class VideoPlayerPlugin: NSObject, FlutterPlugin, AVFoundationVideo
func createPlatformViewPlayer(options params: CreationOptions) throws -> Int64 {
let item = try playerItem(with: params)
let player = FVPVideoPlayer(playerItem: item, avFactory: avFactory, viewProvider: viewProvider)
player.preferredAudioLanguage = params.preferredAudioLanguage
return configurePlayer(player, extraDisposeHandler: nil)
}

Expand All @@ -183,6 +184,7 @@ public final class VideoPlayerPlugin: NSObject, FlutterPlugin, AVFoundationVideo
avFactory: avFactory,
viewProvider: viewProvider
)
player.preferredAudioLanguage = creationOptions.preferredAudioLanguage

let textureId = textureRegistry.register(player)
player.setTextureIdentifier(textureId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private func doubleEqualsVideoPlayerPluginMessages(_ lhs: Double, _ rhs: Double)

private func doubleHashVideoPlayerPluginMessages(_ value: Double, _ hasher: inout Hasher) {
if value.isNaN {
hasher.combine(0x7FF8_0000_0000_0000)
hasher.combine(0x7FF8000000000000)
} else {
// Normalize -0.0 to 0.0
hasher.combine(value == 0 ? 0 : value)
Expand Down Expand Up @@ -176,12 +176,14 @@ func deepHashVideoPlayerPluginMessages(value: Any?, hasher: inout Hasher) {
}
}


/// 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
Expand All @@ -195,9 +197,7 @@ struct PlatformVideoViewCreationParams: Hashable {
playerId
]
}
static func == (lhs: PlatformVideoViewCreationParams, rhs: PlatformVideoViewCreationParams)
-> Bool
{
static func == (lhs: PlatformVideoViewCreationParams, rhs: PlatformVideoViewCreationParams) -> Bool {
if Swift.type(of: lhs) != Swift.type(of: rhs) {
return false
}
Expand All @@ -214,35 +214,40 @@ struct PlatformVideoViewCreationParams: Hashable {
struct CreationOptions: Hashable {
var uri: String
var httpHeaders: [String: String]
var preferredAudioLanguage: String? = nil


// 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]
let preferredAudioLanguage: String? = nilOrValue(pigeonVar_list[2])

return CreationOptions(
uri: uri,
httpHeaders: httpHeaders
httpHeaders: httpHeaders,
preferredAudioLanguage: preferredAudioLanguage
)
}
func toList() -> [Any?] {
return [
uri,
httpHeaders,
preferredAudioLanguage,
]
}
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)
return deepEqualsVideoPlayerPluginMessages(lhs.uri, rhs.uri) && deepEqualsVideoPlayerPluginMessages(lhs.httpHeaders, rhs.httpHeaders) && deepEqualsVideoPlayerPluginMessages(lhs.preferredAudioLanguage, rhs.preferredAudioLanguage)
}

func hash(into hasher: inout Hasher) {
hasher.combine("CreationOptions")
deepHashVideoPlayerPluginMessages(value: uri, hasher: &hasher)
deepHashVideoPlayerPluginMessages(value: httpHeaders, hasher: &hasher)
deepHashVideoPlayerPluginMessages(value: preferredAudioLanguage, hasher: &hasher)
}
}

Expand All @@ -251,6 +256,7 @@ 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
Expand All @@ -271,8 +277,7 @@ struct TexturePlayerIds: Hashable {
if Swift.type(of: lhs) != Swift.type(of: rhs) {
return false
}
return deepEqualsVideoPlayerPluginMessages(lhs.playerId, rhs.playerId)
&& deepEqualsVideoPlayerPluginMessages(lhs.textureId, rhs.textureId)
return deepEqualsVideoPlayerPluginMessages(lhs.playerId, rhs.playerId) && deepEqualsVideoPlayerPluginMessages(lhs.textureId, rhs.textureId)
}

func hash(into hasher: inout Hasher) {
Expand Down Expand Up @@ -325,8 +330,7 @@ private class VideoPlayerPluginMessagesPigeonCodecReaderWriter: FlutterStandardR
}

class VideoPlayerPluginMessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable {
static let shared = VideoPlayerPluginMessagesPigeonCodec(
readerWriter: VideoPlayerPluginMessagesPigeonCodecReaderWriter())
static let shared = VideoPlayerPluginMessagesPigeonCodec(readerWriter: VideoPlayerPluginMessagesPigeonCodecReaderWriter())
}

/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
Expand All @@ -342,15 +346,9 @@ protocol AVFoundationVideoPlayerApi {
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 = ""
) {
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)
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 {
Expand All @@ -363,10 +361,7 @@ class AVFoundationVideoPlayerApiSetup {
} else {
initializeChannel.setMessageHandler(nil)
}
let createForPlatformViewChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.createForPlatformView\(channelSuffix)",
binaryMessenger: binaryMessenger, codec: codec)
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?]
Expand All @@ -381,10 +376,7 @@ class AVFoundationVideoPlayerApiSetup {
} else {
createForPlatformViewChannel.setMessageHandler(nil)
}
let createForTextureViewChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.createForTextureView\(channelSuffix)",
binaryMessenger: binaryMessenger, codec: codec)
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?]
Expand All @@ -399,10 +391,7 @@ class AVFoundationVideoPlayerApiSetup {
} else {
createForTextureViewChannel.setMessageHandler(nil)
}
let setMixWithOthersChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.setMixWithOthers\(channelSuffix)",
binaryMessenger: binaryMessenger, codec: codec)
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?]
Expand All @@ -417,10 +406,7 @@ class AVFoundationVideoPlayerApiSetup {
} else {
setMixWithOthersChannel.setMessageHandler(nil)
}
let getAssetUrlChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.video_player_avfoundation.AVFoundationVideoPlayerApi.getAssetUrl\(channelSuffix)",
binaryMessenger: binaryMessenger, codec: codec)
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?]
Expand Down
Loading