diff --git a/packages/video_player/video_player_platform_interface/CHANGELOG.md b/packages/video_player/video_player_platform_interface/CHANGELOG.md index 024cca4e3af..234067842ef 100644 --- a/packages/video_player/video_player_platform_interface/CHANGELOG.md +++ b/packages/video_player/video_player_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.6.0 + +* Adds `VideoAudioTrack` class and `getAudioTracks()`, `selectAudioTrack()`, `isAudioTrackSupportAvailable()` methods to platform interface for audio track management. + ## 6.5.0 * Adds a `setAllowBackgroundPlayback` method to dynamically control background playback. diff --git a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart index 1037e55ee82..226cb4f707f 100644 --- a/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart +++ b/packages/video_player/video_player_platform_interface/lib/video_player_platform_interface.dart @@ -128,6 +128,31 @@ abstract class VideoPlayerPlatform extends PlatformInterface { Future setWebOptions(int playerId, VideoPlayerWebOptions options) { throw UnimplementedError('setWebOptions() has not been implemented.'); } + + /// Gets the available audio tracks for the video. + Future> getAudioTracks(int playerId) { + throw UnimplementedError('getAudioTracks() has not been implemented.'); + } + + /// Selects which audio track is chosen for playback from its [trackId] + Future selectAudioTrack(int playerId, String trackId) { + throw UnimplementedError('selectAudioTrack() has not been implemented.'); + } + + /// Returns whether audio track selection is supported on this platform. + /// + /// This method allows developers to query at runtime whether the current + /// platform supports audio track selection functionality. This is useful + /// for platforms like web where audio track selection may not be available. + /// + /// Returns `true` if [getAudioTracks] and [selectAudioTrack] are supported, + /// `false` otherwise. + /// + /// The default implementation returns `false`. Platform implementations + /// should override this to return `true` if they support audio track selection. + bool isAudioTrackSupportAvailable() { + return false; + } } class _PlaceholderImplementation extends VideoPlayerPlatform {} @@ -536,3 +561,88 @@ class VideoCreationOptions { /// The type of view to be used for displaying the video player final VideoViewType viewType; } + +/// Represents an audio track in a video with its metadata. +@immutable +class VideoAudioTrack { + /// Constructs an instance of [VideoAudioTrack]. + const VideoAudioTrack({ + required this.id, + required this.label, + required this.language, + required this.isSelected, + this.bitrate, + this.sampleRate, + this.channelCount, + this.codec, + }); + + /// Unique identifier for the audio track. + final String id; + + /// Human-readable label for the track. + /// May be null if not available from the platform. + final String? label; + + /// Language code of the audio track (e.g., 'en', 'es', 'und'). + /// May be null if not available from the platform. + final String? language; + + /// Whether this track is currently selected. + final bool isSelected; + + /// Bitrate of the audio track in bits per second. + /// May be null if not available from the platform. + final int? bitrate; + + /// Sample rate of the audio track in Hz. + /// May be null if not available from the platform. + final int? sampleRate; + + /// Number of audio channels. + /// May be null if not available from the platform. + final int? channelCount; + + /// Audio codec used (e.g., 'aac', 'mp3', 'ac3'). + /// May be null if not available from the platform. + final String? codec; + + @override + bool operator ==(Object other) { + return identical(this, other) || + other is VideoAudioTrack && + runtimeType == other.runtimeType && + id == other.id && + label == other.label && + language == other.language && + isSelected == other.isSelected && + bitrate == other.bitrate && + sampleRate == other.sampleRate && + channelCount == other.channelCount && + codec == other.codec; + } + + @override + int get hashCode => Object.hash( + id, + label, + language, + isSelected, + bitrate, + sampleRate, + channelCount, + codec, + ); + + @override + String toString() => + 'VideoAudioTrack(' + 'id: $id, ' + 'label: $label, ' + 'language: $language, ' + 'isSelected: $isSelected, ' + 'bitrate: $bitrate, ' + 'sampleRate: $sampleRate, ' + 'channelCount: $channelCount, ' + 'codec: $codec)'; +} diff --git a/packages/video_player/video_player_platform_interface/test/video_player_platform_interface_test.dart b/packages/video_player/video_player_platform_interface/test/video_player_platform_interface_test.dart index ad5938afcee..2d920161ec9 100644 --- a/packages/video_player/video_player_platform_interface/test/video_player_platform_interface_test.dart +++ b/packages/video_player/video_player_platform_interface/test/video_player_platform_interface_test.dart @@ -19,4 +19,25 @@ void main() { throwsUnimplementedError, ); }); + + test('default implementation getAudioTracks throws unimplemented', () async { + await expectLater( + () => initialInstance.getAudioTracks(1), + throwsUnimplementedError, + ); + }); + + test( + 'default implementation selectAudioTrack throws unimplemented', + () async { + await expectLater( + () => initialInstance.selectAudioTrack(1, 'trackId'), + throwsUnimplementedError, + ); + }, + ); + + test('default implementation isAudioTrackSupportAvailable returns false', () { + expect(initialInstance.isAudioTrackSupportAvailable(), false); + }); }