diff --git a/packages/video_player/video_player/lib/video_player.dart b/packages/video_player/video_player/lib/video_player.dart index afb6735bfecf..9adad683a403 100644 --- a/packages/video_player/video_player/lib/video_player.dart +++ b/packages/video_player/video_player/lib/video_player.dart @@ -857,6 +857,28 @@ class VideoPlayerController extends ValueNotifier { } } + /// 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. + /// + /// Example usage: + /// ```dart + /// if (await controller.isAudioTrackSupportAvailable()) { + /// final tracks = await controller.getAudioTracks(); + /// // Show audio track selection UI + /// } else { + /// // Hide audio track selection UI or show unsupported message + /// } + /// ``` + Future isAudioTrackSupportAvailable() async { + return _videoPlayerPlatform.isAudioTrackSupportAvailable(); + } + bool get _isDisposedOrNotInitialized => _isDisposed || !value.isInitialized; } diff --git a/packages/video_player/video_player/test/video_player_test.dart b/packages/video_player/video_player/test/video_player_test.dart index 0dda8ab93217..397664324bc4 100644 --- a/packages/video_player/video_player/test/video_player_test.dart +++ b/packages/video_player/video_player/test/video_player_test.dart @@ -120,6 +120,12 @@ class FakeController extends ValueNotifier selectedAudioTrackId = trackId; } + @override + Future isAudioTrackSupportAvailable() async { + // Return true for testing purposes + return true; + } + String? selectedAudioTrackId; } @@ -1852,5 +1858,11 @@ class FakeVideoPlayerPlatform extends VideoPlayerPlatform { selectedAudioTrackIds[playerId] = trackId; } + @override + Future isAudioTrackSupportAvailable() async { + calls.add('isAudioTrackSupportAvailable'); + return true; // Return true for testing purposes + } + final Map selectedAudioTrackIds = {}; } diff --git a/packages/video_player/video_player_android/lib/src/android_video_player.dart b/packages/video_player/video_player_android/lib/src/android_video_player.dart index 7ea0ead7a0c7..aee97b23f1b3 100644 --- a/packages/video_player/video_player_android/lib/src/android_video_player.dart +++ b/packages/video_player/video_player_android/lib/src/android_video_player.dart @@ -245,6 +245,12 @@ class AndroidVideoPlayer extends VideoPlayerPlatform { return _playerWith(id: playerId).selectAudioTrack(trackId); } + @override + Future isAudioTrackSupportAvailable() async { + // Android with ExoPlayer supports audio track selection + return true; + } + _PlayerInstance _playerWith({required int id}) { final _PlayerInstance? player = _players[id]; return player ?? (throw StateError('No active player with ID $id.')); diff --git a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart index c9b7e09eaa97..35564a2c1570 100644 --- a/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart +++ b/packages/video_player/video_player_avfoundation/lib/src/avfoundation_video_player.dart @@ -262,6 +262,12 @@ class AVFoundationVideoPlayer extends VideoPlayerPlatform { return _playerWith(id: playerId).selectAudioTrack(trackId); } + @override + Future isAudioTrackSupportAvailable() async { + // iOS/macOS with AVFoundation supports audio track selection + return true; + } + @override Widget buildView(int playerId) { return buildViewWithOptions(VideoViewOptions(playerId: playerId)); 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 32d4cc17e5e2..643fa50a036e 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 @@ -131,6 +131,18 @@ abstract class VideoPlayerPlatform extends PlatformInterface { 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. + Future isAudioTrackSupportAvailable() { + throw UnimplementedError('isAudioTrackSupportAvailable() has not been implemented.'); + } } class _PlaceholderImplementation extends VideoPlayerPlatform {} diff --git a/packages/video_player/video_player_web/example/pubspec.yaml b/packages/video_player/video_player_web/example/pubspec.yaml index e3bce6949901..c11ee9cfc8bb 100644 --- a/packages/video_player/video_player_web/example/pubspec.yaml +++ b/packages/video_player/video_player_web/example/pubspec.yaml @@ -18,3 +18,7 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + video_player_platform_interface: {path: ../../../../packages/video_player/video_player_platform_interface} diff --git a/packages/video_player/video_player_web/lib/video_player_web.dart b/packages/video_player/video_player_web/lib/video_player_web.dart index 5fdc71a8db56..bd54e63ec3ee 100644 --- a/packages/video_player/video_player_web/lib/video_player_web.dart +++ b/packages/video_player/video_player_web/lib/video_player_web.dart @@ -170,4 +170,22 @@ class VideoPlayerPlugin extends VideoPlayerPlatform { /// Sets the audio mode to mix with other sources (ignored). @override Future setMixWithOthers(bool mixWithOthers) => Future.value(); + + @override + Future> getAudioTracks(int playerId) async { + // Web platform does not support audio track selection + throw UnimplementedError('getAudioTracks() is not supported on web'); + } + + @override + Future selectAudioTrack(int playerId, String trackId) async { + // Web platform does not support audio track selection + throw UnimplementedError('selectAudioTrack() is not supported on web'); + } + + @override + Future isAudioTrackSupportAvailable() async { + // Web platform does not support audio track selection + return false; + } } diff --git a/packages/video_player/video_player_web/pubspec.yaml b/packages/video_player/video_player_web/pubspec.yaml index ca36ffe35ee6..d8ea9bd434ba 100644 --- a/packages/video_player/video_player_web/pubspec.yaml +++ b/packages/video_player/video_player_web/pubspec.yaml @@ -31,3 +31,7 @@ dev_dependencies: topics: - video - video-player +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + video_player_platform_interface: {path: ../../../packages/video_player/video_player_platform_interface}