Skip to content

Commit

Permalink
Refactor Queue for repeat, shuffle and more
Browse files Browse the repository at this point in the history
  • Loading branch information
martijn00 committed Sep 25, 2019
1 parent 740ed1b commit 5111e23
Show file tree
Hide file tree
Showing 23 changed files with 228 additions and 263 deletions.
2 changes: 1 addition & 1 deletion MediaManager.Forms/Xaml/PlayNextExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public class PlayNextExtension : MediaExtensionBase
public PlayNextExtension()
: base()
{
MediaManager.Queue.CollectionChanged += (s, e) => RaiseCanExecuteChanged();
MediaManager.Queue.QueueChanged += (s, e) => RaiseCanExecuteChanged();
}

protected override bool CanExecute() =>
Expand Down
2 changes: 1 addition & 1 deletion MediaManager.Forms/Xaml/PlayPreviousExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public class PlayPreviousExtension : MediaExtensionBase
public PlayPreviousExtension()
: base()
{
MediaManager.Queue.CollectionChanged += (s, e) => RaiseCanExecuteChanged();
MediaManager.Queue.QueueChanged += (s, e) => RaiseCanExecuteChanged();
}

protected override bool CanExecute() =>
Expand Down
46 changes: 46 additions & 0 deletions MediaManager/CollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;

namespace MediaManager
{
public static class CollectionExtensions
{
public static int[] GetShuffleExchanges(int size, int key)
{
int[] exchanges = new int[size - 1];
var rand = new Random(key);
for (int i = size - 1; i > 0; i--)
{
int n = rand.Next(i + 1);
exchanges[size - 1 - i] = n;
}
return exchanges;
}

public static void Shuffle<T>(this IList<T> list, int key)
{
int size = list.Count;
var exchanges = GetShuffleExchanges(size, key);
for (int i = size - 1; i > 0; i--)
{
int n = exchanges[size - 1 - i];
var tmp = list[i];
list[i] = list[n];
list[n] = tmp;
}
}

public static void DeShuffle<T>(this IList<T> list, int key)
{
int size = list.Count;
var exchanges = GetShuffleExchanges(size, key);
for (int i = 1; i < size; i++)
{
int n = exchanges[size - i - 1];
var tmp = list[i];
list[i] = list[n];
list[n] = tmp;
}
}
}
}
24 changes: 16 additions & 8 deletions MediaManager/MediaManagerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,20 @@ internal set
public abstract TimeSpan Position { get; }
public abstract TimeSpan Duration { get; }
public abstract float Speed { get; set; }
public abstract RepeatMode RepeatMode { get; set; }
public abstract bool KeepScreenOn { get; set; }

private RepeatMode _repeatMode = RepeatMode.Off;
public virtual RepeatMode RepeatMode
{
get => _repeatMode;
set => SetProperty(ref _repeatMode, value);
}

private ShuffleMode _shuffleMode = ShuffleMode.Off;
public virtual ShuffleMode ShuffleMode
{
get => Queue.ShuffleMode;
set => Queue.ShuffleMode = value;
get => _shuffleMode;
set => SetProperty(ref _shuffleMode, value);
}

private bool _clearQueueOnPlay = true;
Expand Down Expand Up @@ -290,24 +297,25 @@ public virtual async Task<bool> PlayNext()
{
mediaItem = Queue.Current;
}
else if (RepeatMode == RepeatMode.All && !Queue.HasNext())
// If we repeat all and there is no next in the Queue, we go back to the first
else if (RepeatMode == RepeatMode.All && !Queue.HasNext)
{
mediaItem = Queue.First();
}
// Otherwise we try to play the next media item in the queue
else if (Queue.HasNext())
else if (Queue.HasNext)
{
mediaItem = Queue.NextItem;
mediaItem = Queue.Next;
}

return await PlayQueueItem(mediaItem);
}

public virtual async Task<bool> PlayPrevious()
{
if (Queue.HasPrevious())
if (Queue.HasPrevious)
{
return await PlayQueueItem(Queue.PreviousItem);
return await PlayQueueItem(Queue.Previous);
}
return false;
}
Expand Down
51 changes: 27 additions & 24 deletions MediaManager/Platforms/Android/MediaManagerImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,49 +236,48 @@ public override async Task<bool> PlayNext()
{
await EnsureInit();

if (Player.NextWindowIndex == Player.CurrentWindowIndex)
// If we repeat just the single media item, we do that first
if (RepeatMode == RepeatMode.One)
{
await SeekTo(TimeSpan.FromSeconds(0));
return true;
}

if (Player.NextWindowIndex == -1)
// If we repeat all and there is no next in the Queue, we go back to the first
else if (RepeatMode == RepeatMode.All && !Queue.HasNext)
{
return false;
var mediaItem = Queue.First();
return await PlayQueueItem(mediaItem);
}

MediaController.GetTransportControls().SkipToNext();

return true;
// Otherwise we try to play the next media item in the queue
else if (Queue.HasNext)
{
MediaController.GetTransportControls().SkipToNext();
return true;
}
return false;
}

public override async Task<bool> PlayPrevious()
{
await EnsureInit();

if (Player.PreviousWindowIndex == Player.CurrentWindowIndex)
if (Queue.HasPrevious)
{
await SeekTo(TimeSpan.FromSeconds(0));
MediaController.GetTransportControls().SkipToPrevious();
return true;
}

if (Player.PreviousWindowIndex == -1)
{
return false;
}

MediaController.GetTransportControls().SkipToPrevious();

return true;
return false;
}

public override async Task<bool> PlayQueueItem(IMediaItem mediaItem)
{
await EnsureInit();

if (!Queue.Contains(mediaItem))
if (mediaItem == null || !Queue.Contains(mediaItem))
return false;

Queue.CurrentIndex = Queue.IndexOf(mediaItem);

MediaController.GetTransportControls().SkipToQueueItem(Queue.IndexOf(mediaItem));
return true;
}
Expand All @@ -291,6 +290,8 @@ public override async Task<bool> PlayQueueItem(int index)
if (mediaItem == null)
return false;

Queue.CurrentIndex = index;

MediaController.GetTransportControls().SkipToQueueItem(index);
return true;
}
Expand All @@ -313,25 +314,27 @@ public override RepeatMode RepeatMode
{
get
{
return (RepeatMode)MediaController?.RepeatMode;
return base.RepeatMode;
}
set
{
base.RepeatMode = value;
MediaController?.GetTransportControls()?.SetRepeatMode((int)value);
MediaSession.SetRepeatMode((int)value);
OnPropertyChanged();
MediaSession?.SetRepeatMode((int)value);
}
}

public override ShuffleMode ShuffleMode
{
get
{
return (ShuffleMode)MediaController?.ShuffleMode;
return base.ShuffleMode;
}
set
{
base.ShuffleMode = value;
MediaController?.GetTransportControls()?.SetShuffleMode((int)value);
MediaSession?.SetShuffleMode((int)value);
}
}

Expand Down
6 changes: 2 additions & 4 deletions MediaManager/Platforms/Android/Player/AndroidMediaPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,11 @@ protected virtual void Initialize()
},
OnTracksChangedImpl = (trackGroups, trackSelections) =>
{
var mediaItem = MediaManager.Queue.Current;
BeforePlaying?.Invoke(this, new MediaPlayerEventArgs(mediaItem, this));
BeforePlaying?.Invoke(this, new MediaPlayerEventArgs(MediaManager.Queue.Current, this));

MediaManager.Queue.CurrentIndex = Player.CurrentWindowIndex;
MediaManager.OnMediaItemChanged(this, new MediaItemEventArgs(mediaItem));

AfterPlaying?.Invoke(this, new MediaPlayerEventArgs(mediaItem, this));
AfterPlaying?.Invoke(this, new MediaPlayerEventArgs(MediaManager.Queue.Current, this));
},
OnPlayerStateChangedImpl = (bool playWhenReady, int playbackState) =>
{
Expand Down
6 changes: 1 addition & 5 deletions MediaManager/Platforms/Android/Player/PlaybackPreparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,7 @@ public void OnCommand(IPlayer p0, string p1, Bundle p2, ResultReceiver p3)

public void OnPrepare()
{
_mediaSource.Clear();

var mediaItems = MediaManager.Queue.Select(x => x.ToMediaSource()).ToList();
_mediaSource.AddMediaSources(mediaItems);

// _mediaSource is filled through the QueueDataAdapter
_player.Prepare(_mediaSource);

//Only in case of Prepare set PlayWhenReady to true because we use this to load in the whole queue
Expand Down
10 changes: 5 additions & 5 deletions MediaManager/Platforms/Android/Queue/QueueDataAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Android.Support.V4.Media;
using Com.Google.Android.Exoplayer2.Ext.Mediasession;
using Com.Google.Android.Exoplayer2.Source;
using MediaManager.Library;
using MediaManager.Platforms.Android.Media;

namespace MediaManager.Platforms.Android.Queue
Expand All @@ -16,7 +17,7 @@ public class QueueDataAdapter : Java.Lang.Object, TimelineQueueEditor.IQueueData
public QueueDataAdapter(ConcatenatingMediaSource mediaSource)
{
_mediaSource = mediaSource;
//_mediaManager.MediaQueue.CollectionChanged += MediaQueue_CollectionChanged;
MediaManager.Queue.MediaItems.CollectionChanged += MediaQueue_CollectionChanged;
}

protected QueueDataAdapter(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer)
Expand All @@ -42,14 +43,13 @@ public void Remove(int index)
{
MediaManager.Queue.RemoveAt(index);
}
//TODO: Find out if queue also need to get picked up on changes. Maybe when people add items directly to the queue while playing already.
/*

private void MediaQueue_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
if (_mediaSource.Size != _mediaManager.MediaQueue.Count)
if (_mediaSource.Size != MediaManager.Queue.Count)
{
for (int i = e.NewItems.Count - 1; i >= 0; i--)
{
Expand Down Expand Up @@ -95,6 +95,6 @@ private void MediaQueue_CollectionChanged(object sender, System.Collections.Spec
_mediaSource.Clear();
break;
}
}*/
}
}
}
29 changes: 0 additions & 29 deletions MediaManager/Platforms/Apple/AppleMediaManagerBase.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
using System;
using System.Linq;
using AVFoundation;
using MediaManager.Media;
using MediaManager.Notifications;
using MediaManager.Platforms.Apple.Media;
using MediaManager.Platforms.Apple.Notifications;
using MediaManager.Platforms.Apple.Player;
using MediaManager.Platforms.Apple.Volume;
using MediaManager.Playback;
using MediaManager.Player;
using MediaManager.Queue;
using MediaManager.Volume;

namespace MediaManager
Expand Down Expand Up @@ -119,31 +116,5 @@ public override float Speed
Player.Rate = value;
}
}

public override RepeatMode RepeatMode
{
get => AppleMediaPlayer.RepeatMode;
set
{
if (AppleMediaPlayer.RepeatMode != value)
{
AppleMediaPlayer.RepeatMode = value;
OnPropertyChanged(nameof(RepeatMode));
}
}
}

public override ShuffleMode ShuffleMode
{
get => base.ShuffleMode;
set
{
if (base.ShuffleMode != value)
{
base.ShuffleMode = value;
OnPropertyChanged(nameof(ShuffleMode));
}
}
}
}
}
23 changes: 0 additions & 23 deletions MediaManager/Platforms/Apple/Player/AppleMediaPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using MediaManager.Library;
using MediaManager.Media;
using MediaManager.Platforms.Apple.Playback;
using MediaManager.Playback;
using MediaManager.Player;

namespace MediaManager.Platforms.Apple.Player
Expand All @@ -33,17 +32,6 @@ public AVQueuePlayer Player
set => SetProperty(ref _player, value);
}

#region RepeatMode

private RepeatMode _repeatMode;
public virtual RepeatMode RepeatMode
{
get => _repeatMode;
set => SetProperty(ref _repeatMode, value);
}

#endregion

private NSObject didFinishPlayingObserver;
private NSObject itemFailedToPlayToEndTimeObserver;
private NSObject errorObserver;
Expand Down Expand Up @@ -169,16 +157,6 @@ private async void DidFinishPlaying(NSNotification obj)
{
await Stop();
}
else if (RepeatMode == RepeatMode.All && MediaManager.Queue.Any())
{
MediaManager.Queue.CurrentIndex = 0;
await MediaManager.PlayQueueItem(MediaManager.Queue.Current);
}
else if (RepeatMode == RepeatMode.One && MediaManager.Queue.Any())
{
MediaManager.Queue.CurrentIndex = MediaManager.Queue.CurrentIndex - 1;
await MediaManager.PlayQueueItem(MediaManager.Queue.Current);
}
}

public override Task Pause()
Expand All @@ -195,7 +173,6 @@ public override async Task Play(IMediaItem mediaItem)

Player.ActionAtItemEnd = AVPlayerActionAtItemEnd.None;
Player.ReplaceCurrentItemWithPlayerItem(item);
MediaManager.OnMediaItemChanged(this, new MediaItemEventArgs(mediaItem));
await Play();

AfterPlaying?.Invoke(this, new MediaPlayerEventArgs(mediaItem, this));
Expand Down
Loading

0 comments on commit 5111e23

Please sign in to comment.