Skip to content

Conversation

@nateshmbhat
Copy link
Contributor

  • Implemented getAudioTracks() method to retrieve available audio tracks from both HLS streams and regular video files

AVFoundation Platform PR for : #9925

Pre-Review Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] page, which explains my responsibilities.
  • I read and followed the [relevant style guides] and ran [the auto-formatter].
  • I signed the [CLA].
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I [linked to at least one issue that this PR fixes] in the description above.
  • I updated 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].
  • I updated 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].
  • I updated/added any relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or I have commented below to indicate which [test exemption] this PR falls under[^1].
  • All existing and new tests are passing.

Copy link

@gemini-code-assist gemini-code-assist bot left a 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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

It's great to see the new features documented in the changelog. However, consider adding a bit more detail about the specific use cases or benefits of these methods for developers.

Comment on lines +498 to +507
// Skip nil options
if (!option || [option isKindOfClass:[NSNull class]]) {
continue;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Consider adding a comment explaining why nil options are skipped. This will help future developers understand the logic behind this check.

Copy link
Contributor

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?

Comment on lines +679 to +681
}
// 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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add a comment explaining why direct selection isn't possible and what the limitations are. This will help future developers understand the current implementation and potential areas for improvement.

assets:
- assets/flutter-mark-square-64.png
- assets/Butterfly-209.mp4
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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

  1. 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." (link)

@stuartmorgan-g stuartmorgan-g added the triage-ios Should be looked at in iOS triage label Oct 28, 2025
- 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
@nateshmbhat nateshmbhat force-pushed the 28-oct-platform-avfoundation branch from 4784bd8 to 459e7f8 Compare November 7, 2025 16:32
@nateshmbhat nateshmbhat changed the title feat(video): add audio track selection support for AVFoundation feat(ios): add audio track selection support for AVFoundation Nov 7, 2025
- 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
@nateshmbhat
Copy link
Contributor Author

@LongCatIsLooong @tarrinneal could you please review this PR

@nateshmbhat

This comment was marked as off-topic.

@nateshmbhat
Copy link
Contributor Author

nateshmbhat commented Nov 19, 2025

any update on this ? 🙏🏻
@tarrinneal @LongCatIsLooong

@nateshmbhat
Copy link
Contributor Author

🥲

@tarrinneal
Copy link
Contributor

🥲

Sorry, I've been out as my wife is recovering from surgery. I'll try to get to this in the next couple days.

@LongCatIsLooong
Copy link
Contributor

(just started reviewing this, I'll finish doing the review tomorrow, sorry for the delay I was working on a bugfix).

Copy link
Contributor

@LongCatIsLooong LongCatIsLooong left a 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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
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, *)) {
Copy link
Contributor

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?

Comment on lines +498 to +507
// Skip nil options
if (!option || [option isKindOfClass:[NSNull class]]) {
continue;
Copy link
Contributor

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) {
Copy link
Contributor

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];
Copy link
Contributor

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]);
Copy link
Contributor

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
Copy link
Contributor

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) {
Copy link
Contributor

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?

Copy link
Contributor

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)
Copy link
Contributor

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 &&
Copy link
Contributor

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants