Skip to content
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,31 @@ abstract class VideoPlayerPlatform extends PlatformInterface {
Future<void> setWebOptions(int playerId, VideoPlayerWebOptions options) {
throw UnimplementedError('setWebOptions() has not been implemented.');
}

/// Gets the available audio tracks for the video.
Future<List<VideoAudioTrack>> getAudioTracks(int playerId) {
throw UnimplementedError('getAudioTracks() has not been implemented.');
}

/// Selects which audio track is chosen for playback from its [trackId]
Future<void> 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 {}
Expand Down Expand Up @@ -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)';
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
}