-
Notifications
You must be signed in to change notification settings - Fork 3.5k
feat(ios): add audio track selection support for AVFoundation #10313
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?
feat(ios): add audio track selection support for AVFoundation #10313
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 audio track selection support for AVFoundation, enabling users to retrieve and select audio tracks from both HLS streams and regular video files. The changes include modifications to the CHANGELOG, platform-specific code (ObjC, Swift), example app, and test files. The minimum supported SDK versions have been updated, and new methods (getAudioTracks(), selectAudioTrack()) have been implemented. The code adheres to the repository's style guide, focusing on objective summaries and using code as the source of truth.
|
|
||
| * Updates minimum supported version to iOS 13 and macOS 10.15. | ||
| * Updates minimum supported SDK version to Flutter 3.35/Dart 3.9. | ||
| * Implements `getAudioTracks()` and `selectAudioTrack()` methods. |
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.
packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation.podspec
Outdated
Show resolved
Hide resolved
packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Package.swift
Outdated
Show resolved
Hide resolved
| // Skip nil options | ||
| if (!option || [option isKindOfClass:[NSNull class]]) { | ||
| continue; |
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.
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.
+1, why are we checking against NSNull or checking if the option is nil?
| } | ||
| // For asset tracks, we don't have a direct way to select them in AVFoundation | ||
| // This would require more complex track selection logic that's not commonly used |
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.
packages/video_player/video_player_avfoundation/example/ios/Flutter/AppFrameworkInfo.plist
Outdated
Show resolved
Hide resolved
packages/video_player/video_player_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj
Outdated
Show resolved
Hide resolved
packages/video_player/video_player_avfoundation/example/macos/Podfile
Outdated
Show resolved
Hide resolved
packages/video_player/video_player_avfoundation/example/macos/Runner.xcodeproj/project.pbxproj
Outdated
Show resolved
Hide resolved
| assets: | ||
| - assets/flutter-mark-square-64.png | ||
| - assets/Butterfly-209.mp4 | ||
| # FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. |
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.
Per the repository style guide, the review agent should not comment about dependency_overrides sections in pubspec.yaml files that have a comment starting with: "FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE." 1
Style Guide References
Footnotes
- Added getAudioTracks() method supporting both HLS media selection and regular asset tracks - Added selectAudioTrack() method with support for both track selection mechanisms - Included comprehensive test coverage for audio track functionality with edge cases
4784bd8 to
459e7f8
Compare
- Update iOS minimum deployment target from 12.0 to 13.0 - Update macOS minimum deployment target from 10.14 to 10.15 - Add CocoaPods framework embedding build phases to Xcode projects
|
@LongCatIsLooong @tarrinneal could you please review this PR |
This comment was marked as off-topic.
This comment was marked as off-topic.
|
any update on this ? 🙏🏻 |
|
🥲 |
Sorry, I've been out as my wife is recovering from surgery. I'll try to get to this in the next couple days. |
|
(just started reviewing this, I'll finish doing the review tomorrow, sorry for the delay I was working on a bugfix). |
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.
So far I've only looked at the objective-c implementation.
My biggest question: why is it required to drop down to lower-level AVAssetTrack stuff? I went to read a little about media selection group and my understanding is that it should be sufficient for most user-facing use cases. What are the use cases for the tracks information?
Additionally, track loading is lazy and asynchronous according to the documentation. I don't see logic that handles the asynchronism.
| // First, try to get tracks from media selection (for HLS streams) | ||
| AVMediaSelectionGroup *audioGroup = | ||
| [asset mediaSelectionGroupForMediaCharacteristic:AVMediaCharacteristicAudible]; | ||
| if (audioGroup && audioGroup.options.count > 0) { |
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:
| if (audioGroup && audioGroup.options.count > 0) { | |
| if (audioGroup.options.count > 0) { |
| NSMutableArray<FVPMediaSelectionAudioTrackData *> *mediaSelectionTracks = | ||
| [[NSMutableArray alloc] init]; | ||
| AVMediaSelectionOption *currentSelection = nil; | ||
| if (@available(iOS 11.0, macOS 10.13, *)) { |
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.
I thought the plugin's lowest supported iOS version is 13.0 so we don't have to resort to the deprecated API?
| // Skip nil options | ||
| if (!option || [option isKindOfClass:[NSNull class]]) { | ||
| continue; |
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.
+1, why are we checking against NSNull or checking if the option is nil?
| [AVMetadataItem metadataItemsFromArray:option.commonMetadata | ||
| withKey:AVMetadataCommonKeyTitle | ||
| keySpace:AVMetadataKeySpaceCommon]; | ||
| if (titleItems.count > 0 && titleItems.firstObject.stringValue) { |
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: is if isn't needed? firstObject returns nil if the array is empty according to documentation.
| commonMetadataTitle = titleItems.firstObject.stringValue; | ||
| } | ||
|
|
||
| BOOL isSelected = (currentSelection == option) || [currentSelection isEqual:option]; |
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.
Isn't [currentSelection isEqual:option] sufficient?
|
|
||
| // Validate that we have a valid format description object | ||
| if (formatDescObj && [formatDescObj respondsToSelector:@selector(self)]) { | ||
| NSString *className = NSStringFromClass([formatDescObj 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.
Still, I don't understand the purpose of this if condition and code in the block. The implementation seems to be very hacky.
| } | ||
| } @catch (NSException *exception) { | ||
| // Handle any exceptions from format description parsing gracefully | ||
| // This ensures the method continues to work even with mock objects or invalid data |
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.
I don't think we should add test-aware / test-specific logic to production code.
| trackId:(NSInteger)trackId | ||
| error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { | ||
| AVPlayerItem *currentItem = _player.currentItem; | ||
| if (!currentItem || !currentItem.asset) { |
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.
Should this be an error? Attempting to select an audio track while the current item is nil violates the contract I think?
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.
Actually, can currentItem be nil in FVVideoPlayer? The documentation says asset can't be nil: https://developer.apple.com/documentation/avfoundation/avplayeritem/asset
|
|
||
| AVAsset *asset = currentItem.asset; | ||
|
|
||
| // Check if this is a media selection track (for HLS streams) |
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.
My understanding is that media selection isn't only for HLS streams. Most container formats support them.
| // Check if this is a media selection track (for HLS streams) | ||
| if ([trackType isEqualToString:@"mediaSelection"]) { | ||
| // Validate that we have cached options and the trackId (index) is valid | ||
| if (_cachedAudioSelectionOptions && trackId >= 0 && |
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.
What happens if there was no cache?
AVFoundation Platform PR for : #9925
Pre-Review Checklist
[shared_preferences]pubspec.yamlwith 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.mdto 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].///).