-
Notifications
You must be signed in to change notification settings - Fork 3.5k
[video_player] Adds audio track metadata fetching and audio track selection feature #9925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a valuable feature for fetching and selecting audio tracks in the video_player package. The changes are comprehensive, touching the platform interface, Android (ExoPlayer) and iOS (AVFoundation) implementations, and adding a new demo screen.
My review has identified several critical and high-severity issues that should be addressed:
- The new native unit tests for both Android and iOS appear to be broken due to type mismatches and incorrect method calls, and will not compile in their current state.
- The Dart implementation code for both Android and iOS contains unsafe null assertions on data coming from the native side, which could lead to runtime crashes.
- The Android implementation has been updated to use a milestone version of Gradle, which is not recommended for production packages.
- The new audio track selection feature has not been implemented for the web platform, which will lead to
UnimplementedError
on web. - There is a minor issue in the new example app where
context
is used after anawait
without checking if the widget is still mounted.
Addressing these points will significantly improve the robustness and completeness of this new feature.
...deo_player_android/android/src/test/java/io/flutter/plugins/videoplayer/AudioTracksTest.java
Outdated
Show resolved
Hide resolved
packages/video_player/video_player_avfoundation/darwin/RunnerTests/AudioTracksTests.m
Outdated
Show resolved
Hide resolved
packages/video_player/video_player_android/android/gradle/wrapper/gradle-wrapper.properties
Outdated
Show resolved
Hide resolved
packages/video_player/video_player_android/lib/src/android_video_player.dart
Outdated
Show resolved
Hide resolved
packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart
Outdated
Show resolved
Hide resolved
packages/video_player/video_player/example/lib/audio_tracks_demo.dart
Outdated
Show resolved
Hide resolved
…oPlayer async updates
… fix format builders
I updated native andorid tests and ran the tests and verified that all native android tests are passing. |
fix(ios): fixed tests
@stuartmorgan-g @ash2moon can you please comment on this PR and lemme know if there are any concerns ? |
any update on this PR ? |
From triage: ping @tarrinneal @ash2moon @LongCatIsLooong @hellohuanlin for review @nateshmbhat Apologies for the delay; things have been unusually busy recently. A couple of high-level notes while you are waiting for full reviews:
|
This comment was marked as duplicate.
This comment was marked as duplicate.
@@ -1,5 +1,6 @@ | |||
## NEXT | |||
|
|||
* Implements `getAudioTracks()` and `selectAudioTrack()` methods for iOS/macOS using AVFoundation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uber nit: the package is called video_player_avfoundation
so I think the ios/macOS and AVFoundation part seems redundant.
|
||
// Sample video URLs with multiple audio tracks | ||
final List<String> _sampleVideos = <String>[ | ||
'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to use existing videos hosted in the flutter/samples repo (see the other demos), or do they not have tracks? I'm not sure what licenses these samples use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be a const
right?
try { | ||
await _controller?.dispose(); | ||
|
||
_controller = VideoPlayerController.networkUrl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: here and everywhere (especially in _loadAudioTracks
): consider using a local var so you don't have to use !
to force unwrap the controller every time.
|
||
// Add a small delay to allow ExoPlayer to process the track selection change | ||
// This is needed because ExoPlayer's track selection update is asynchronous | ||
await Future<void>.delayed(const Duration(milliseconds: 100)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm this could be a major source of flakiness. Shouldn't selectAudioTrack
completes the future only after the new tracks becomes ready?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, a major source of user errors if this isn't documented (still I would prefer that we hide the ugliness within our implementation so the user doesn't have to worry about that).
// Reload tracks to update selection status | ||
await _loadAudioTracks(); | ||
|
||
if (!mounted) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is also needed whenever you want to call setState
I think?
AVMediaSelectionOption *option = audioGroup.options[i]; | ||
|
||
// Skip nil options | ||
if (!option || [option isKindOfClass:[NSNull class]]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the first nil
check doesn't seem to be needed?
|
||
NSString *displayName = option.displayName; | ||
if (!displayName || displayName.length == 0) { | ||
displayName = [NSString stringWithFormat:@"Audio Track %ld", (long)(i + 1)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the implementation have to provide a fallback name?
|
||
NSString *languageCode = @"und"; | ||
if (option.locale) { | ||
languageCode = option.locale.languageCode ?: @"und"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: NSString* languageCode = option.locale.languageCode ?: @"und";
, without the if?
} | ||
|
||
NSString *commonMetadataTitle = nil; | ||
for (AVMetadataItem *item in option.commonMetadata) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the API documentation recommends filtering using a different method: https://developer.apple.com/documentation/avfoundation/avmediaselectionoption/commonmetadata?language=objc#Discussion
|
||
// Only attempt format description parsing in production (non-test) environments | ||
// Skip entirely if we detect any mock objects or test environment indicators | ||
NSString *trackClassName = NSStringFromClass([track class]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the behavior different in production and tests? I think that defeats the purpose of testing if the logic is different for tests?
Description
This PR adds comprehensive audio track retrieval and selection support to the video_player package, enabling developers to access detailed information about available audio tracks and switch between them during playback.
Changes Made
Core Features
VideoAudioTrack
model with comprehensive metadata fields:id
,label
,language
,isSelected
,bitrate
,sampleRate
,channelCount
,codec
VideoPlayerController
to expose audio track functionalityPlatform Implementations
getCurrentTracks()
APITrackSelectionOverride
with proper error handlingAVAssetTrack
for regular videosAVMediaSelectionGroup
for adaptive streamsTechnical Infrastructure
AudioTrackMessage
,ExoPlayerAudioTrackData
,AssetAudioTrackData
,MediaSelectionAudioTrackData
,NativeAudioTrackData
Demo Features
Related Issues
#59437 - Add audio track metadata support to video_player
Testing
Breaking Changes
None - all changes are additive and backward compatible.
Pre-Review Checklist
[video_player]
pubspec.yaml
with an appropriate new version according to the [pub versioning philosophy], or I have commented below to indicate which [version change exemption] this PR falls under[^1].CHANGELOG.md
to add a description of the change, [following repository CHANGELOG style], or I have commented below to indicate which [CHANGELOG exemption] this PR falls under[^1].///
).