diff --git a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs index 86f569b0b8..a3c5a00ea8 100644 --- a/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs +++ b/src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs @@ -25,9 +25,11 @@ namespace CommunityToolkit.Maui.Core.Views; public partial class MediaManager : Java.Lang.Object, IPlayerListener { + const int idleState = 1; const int bufferState = 2; const int readyState = 3; const int endedState = 4; + bool hasMediaOpened = false; readonly HttpClient client = new(); readonly SemaphoreSlim seekToSemaphoreSlim = new(1, 1); @@ -79,56 +81,6 @@ public void UpdateNotifications() } } - /// - /// Occurs when ExoPlayer changes the player state. - /// - /// Indicates whether the player should start playing the media whenever the media is ready. - /// The state that the player has transitioned to. - /// - /// This is part of the implementation. - /// While this method does not seem to have any references, it's invoked at runtime. - /// - public void OnPlayerStateChanged(bool playWhenReady, int playbackState) - { - if (Player is null || MediaElement.Source is null) - { - return; - } - - var newState = playbackState switch - { - PlaybackState.StateFastForwarding - or PlaybackState.StateRewinding - or PlaybackState.StateSkippingToNext - or PlaybackState.StateSkippingToPrevious - or PlaybackState.StateSkippingToQueueItem - or PlaybackState.StatePlaying => playWhenReady - ? MediaElementState.Playing - : MediaElementState.Paused, - - PlaybackState.StatePaused => MediaElementState.Paused, - - PlaybackState.StateConnecting - or PlaybackState.StateBuffering => MediaElementState.Buffering, - - PlaybackState.StateNone => MediaElementState.None, - PlaybackState.StateStopped => MediaElement.CurrentState is not MediaElementState.Failed - ? MediaElementState.Stopped - : MediaElementState.Failed, - - PlaybackState.StateError => MediaElementState.Failed, - - _ => MediaElementState.None, - }; - - MediaElement.CurrentStateChanged(newState); - if (playbackState is readyState) - { - MediaElement.Duration = TimeSpan.FromMilliseconds(Player.Duration < 0 ? 0 : Player.Duration); - MediaElement.Position = TimeSpan.FromMilliseconds(Player.CurrentPosition < 0 ? 0 : Player.CurrentPosition); - } - } - /// /// Creates the corresponding platform view of on Android. /// @@ -185,6 +137,16 @@ or PlaybackState.StateSkippingToQueueItem return (Player, PlayerView); } + public void OnPlayWhenReadyChanged(bool playWhenReady, int reason) + { + if (!hasMediaOpened || Player is null || MediaElement.Source is null || Player.PlaybackState != readyState) + { + return; + } + + MediaElement.CurrentStateChanged(playWhenReady ? MediaElementState.Playing : MediaElementState.Paused); + } + /// /// Occurs when ExoPlayer changes the playback state. /// @@ -195,24 +157,41 @@ or PlaybackState.StateSkippingToQueueItem /// public void OnPlaybackStateChanged(int playbackState) { - if (MediaElement.Source is null) + if (MediaElement.Source is null || Player is null) { return; } - MediaElementState newState = MediaElement.CurrentState; - switch (playbackState) + MediaElementState newState = playbackState switch + { + idleState => MediaElement.CurrentState is not MediaElementState.Failed + ? MediaElementState.Stopped + : MediaElementState.Failed, + bufferState => MediaElementState.Buffering, + readyState => Player.PlayWhenReady + ? MediaElementState.Playing + : MediaElementState.Paused, + endedState => MediaElementState.Stopped, + _ => MediaElement.CurrentState + }; + + if (playbackState == readyState) + { + MediaElement.Duration = TimeSpan.FromMilliseconds(Player.Duration < 0 ? 0 : Player.Duration); + MediaElement.Position = TimeSpan.FromMilliseconds(Player.CurrentPosition < 0 ? 0 : Player.CurrentPosition); + + if (!hasMediaOpened && Player.PlayerError is null) + { + hasMediaOpened = true; + MediaElement.MediaOpened(); + } + + seekToTaskCompletionSource?.TrySetResult(); + } + + if (MediaElementState.Stopped == newState) { - case bufferState: - newState = MediaElementState.Buffering; - break; - case endedState: - newState = MediaElementState.Stopped; - MediaElement.MediaEnded(); - break; - case readyState: - seekToTaskCompletionSource?.TrySetResult(); - break; + MediaElement.MediaEnded(); } MediaElement.CurrentStateChanged(newState); @@ -352,6 +331,7 @@ protected virtual partial void PlatformStop() protected virtual async partial ValueTask PlatformUpdateSource() { var hasSetSource = false; + hasMediaOpened = false; if (Player is null) { @@ -417,17 +397,9 @@ protected virtual async partial ValueTask PlatformUpdateSource() hasSetSource = true; } - if (hasSetSource) + if (hasSetSource && isAndroidForegroundServiceEnabled) { - if (Player.PlayerError is null) - { - MediaElement.MediaOpened(); - } - - if (isAndroidForegroundServiceEnabled) - { - UpdateNotifications(); - } + UpdateNotifications(); } } @@ -868,10 +840,6 @@ public void OnMetadata(Metadata? metadata) { } - public void OnPlayWhenReadyChanged(bool playWhenReady, int reason) - { - } - public void OnPositionDiscontinuity(PlayerPositionInfo? oldPosition, PlayerPositionInfo? newPosition, int reason) { } @@ -880,6 +848,9 @@ public void OnPlaybackSuppressionReasonChanged(int playbackSuppressionReason) { } + public void OnPlayerStateChanged(bool playWhenReady, int playbackState) + { + } public void OnPlayerErrorChanged(PlaybackException? error) { }