Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 48 additions & 77 deletions src/CommunityToolkit.Maui.MediaElement/Views/MediaManager.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -79,56 +81,6 @@ public void UpdateNotifications()
}
}

/// <summary>
/// Occurs when ExoPlayer changes the player state.
/// </summary>
/// <paramref name="playWhenReady">Indicates whether the player should start playing the media whenever the media is ready.</paramref>
/// <paramref name="playbackState">The state that the player has transitioned to.</paramref>
/// <remarks>
/// This is part of the <see cref="IPlayerListener"/> implementation.
/// While this method does not seem to have any references, it's invoked at runtime.
/// </remarks>
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);
}
}

/// <summary>
/// Creates the corresponding platform view of <see cref="MediaElement"/> on Android.
/// </summary>
Expand Down Expand Up @@ -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);
}

/// <summary>
/// Occurs when ExoPlayer changes the playback state.
/// </summary>
Expand All @@ -195,24 +157,41 @@ or PlaybackState.StateSkippingToQueueItem
/// </remarks>
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
Comment on lines +160 to +165
{
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);
Expand Down Expand Up @@ -352,6 +331,7 @@ protected virtual partial void PlatformStop()
protected virtual async partial ValueTask PlatformUpdateSource()
{
var hasSetSource = false;
hasMediaOpened = false;

if (Player is null)
{
Expand Down Expand Up @@ -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();
Comment on lines +400 to +402
}
}

Expand Down Expand Up @@ -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)
{
}
Expand All @@ -880,6 +848,9 @@ public void OnPlaybackSuppressionReasonChanged(int playbackSuppressionReason)
{
}

public void OnPlayerStateChanged(bool playWhenReady, int playbackState)
{
}
public void OnPlayerErrorChanged(PlaybackException? error)
{
}
Expand Down
Loading