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)
{
}