From d520830eb0e9e9f53769c99151688ba37d647cab Mon Sep 17 00:00:00 2001
From: Tristan Roux
Date: Sun, 28 Apr 2019 17:10:37 +0200
Subject: [PATCH] Allowing seeking before creating the player. Loading the
duration of the songs before creating the player.
---
Opus/Code/Api/Services/MusicPlayer.cs | 314 +++++++++++++-------------
Opus/Code/DataStructure/Song.cs | 1 +
Opus/Code/UI/Views/Player.cs | 23 +-
3 files changed, 168 insertions(+), 170 deletions(-)
diff --git a/Opus/Code/Api/Services/MusicPlayer.cs b/Opus/Code/Api/Services/MusicPlayer.cs
index 30dcdce..3e8e5dc 100644
--- a/Opus/Code/Api/Services/MusicPlayer.cs
+++ b/Opus/Code/Api/Services/MusicPlayer.cs
@@ -239,7 +239,7 @@ namespace Opus.Api.Services
}
}
UseCastPlayer = RemotePlayer != null;
- player.PlayWhenReady = !UseCastPlayer;
+ //player.PlayWhenReady = !UseCastPlayer;
}
public void ChangeVolume(float volume)
@@ -248,129 +248,8 @@ namespace Opus.Api.Services
player.Volume = volume * (volumeDuked ? 0.2f : 1);
}
- public async void Play(string filePath, string title = null, string artist = null, string youtubeID = null, string thumbnailURI = null, bool isLive = false, DateTimeOffset? expireDate = null)
+ public void Prepare(Song song)
{
- isRunning = true;
- if (player == null)
- InitializeService();
-
- queue?.Clear();
- currentID = -1;
- Queue.instance?.Refresh();
- Home.instance?.RefreshQueue(false);
-
- Song song = null;
- if (title == null)
- song = await LocalManager.GetSong(filePath);
- else
- {
- song = new Song(title, artist, thumbnailURI, youtubeID, -1, -1, filePath, true);
- }
-
- song.IsLiveStream = isLive;
- isLiveStream = isLive;
-
- if (!UseCastPlayer)
- {
- if (mediaSession == null)
- {
- mediaSession = new MediaSessionCompat(Application.Context, "Opus");
- mediaSession.SetFlags(MediaSessionCompat.FlagHandlesMediaButtons | MediaSessionCompat.FlagHandlesTransportControls);
- PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder().SetActions(PlaybackStateCompat.ActionPlay | PlaybackStateCompat.ActionPause | PlaybackStateCompat.ActionSkipToNext | PlaybackStateCompat.ActionSkipToPrevious);
- mediaSession.SetPlaybackState(builder.Build());
- mediaSession.SetCallback(new HeadphonesActions());
- }
-
- DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(Application.Context, "Opus");
- IExtractorsFactory extractorFactory = new DefaultExtractorsFactory();
- Handler handler = new Handler();
-
- IMediaSource mediaSource = null;
- if (isLive)
- mediaSource = new HlsMediaSource(Uri.Parse(filePath), dataSourceFactory, handler, null);
- else if (title == null)
- mediaSource = new ExtractorMediaSource(Uri.FromFile(new Java.IO.File(filePath)), dataSourceFactory, extractorFactory, handler, null);
- else
- mediaSource = new ExtractorMediaSource(Uri.Parse(filePath), dataSourceFactory, extractorFactory, handler, null);
-
- AudioAttributes attributes = new AudioAttributes.Builder()
- .SetUsage(AudioUsageKind.Media)
- .SetContentType(AudioContentType.Music)
- .Build();
-
- if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
- {
- audioFocusRequest = new AudioFocusRequestClass.Builder(AudioFocus.Gain)
- .SetAudioAttributes(attributes)
- .SetAcceptsDelayedFocusGain(true)
- .SetWillPauseWhenDucked(true)
- .SetOnAudioFocusChangeListener(this)
- .Build();
- AudioFocusRequest audioFocus = audioManager.RequestAudioFocus(audioFocusRequest);
-
- if (audioFocus != AudioFocusRequest.Granted)
- {
- Console.WriteLine("Can't Get Audio Focus");
- return;
- }
- }
- else
- {
-#pragma warning disable CS0618 // Type or member is obsolete
-
- AudioManager am = (AudioManager)MainActivity.instance.GetSystemService(AudioService);
-
- AudioFocusRequest audioFocus = am.RequestAudioFocus(this, Stream.Music, AudioFocus.Gain);
-
- if (audioFocus != AudioFocusRequest.Granted)
- {
- Console.WriteLine("Can't Get Audio Focus");
- return;
- }
-#pragma warning restore CS0618
- }
-
- player.PlayWhenReady = true;
- player.Prepare(mediaSource, true, true);
- CreateNotification(song.Title, song.Artist, song.AlbumArt, song.Album);
- AddToQueue(song);
- currentID = CurrentID() + 1;
- }
- else
- {
- RemotePlayer.Load(GetMediaInfo(song), new MediaLoadOptions.Builder().SetAutoplay(true).Build());
- RemotePlayer.Play();
- queue = new List { song };
- currentID = 0;
- }
-
- autoPlay.Clear();
-
- SaveQueueSlot();
- Player.instance?.RefreshPlayer();
- Home.instance?.AddQueue();
- ParseNextSong();
- if (useAutoPlay)
- GenerateAutoPlay(false);
- }
-
- public async void Play(Song song, long progress = -1, bool addToQueue = true)
- {
- if (song.IsParsed != true)
- {
- await ParseSong(song, -1, true);
- return;
- }
-
- if (addToQueue)
- {
- queue?.Clear();
- currentID = -1;
- }
-
- isLiveStream = song.IsLiveStream;
-
- isRunning = true;
if (player == null)
InitializeService();
@@ -396,46 +275,121 @@ namespace Opus.Api.Services
mediaSource = new ExtractorMediaSource(Uri.FromFile(new Java.IO.File(song.Path)), dataSourceFactory, extractorFactory, handler, null);
else
mediaSource = new ExtractorMediaSource(Uri.Parse(song.Path), dataSourceFactory, extractorFactory, handler, null);
+ player.Prepare(mediaSource, true, true);
+ }
+ else
+ RemotePlayer.Load(GetMediaInfo(song), new MediaLoadOptions.Builder().SetAutoplay(true).Build());
+ }
- AudioAttributes attributes = new AudioAttributes.Builder()
+ public void RequestAudioFocus()
+ {
+ AudioAttributes attributes = new AudioAttributes.Builder()
.SetUsage(AudioUsageKind.Media)
.SetContentType(AudioContentType.Music)
.Build();
- if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
- {
- audioFocusRequest = new AudioFocusRequestClass.Builder(AudioFocus.Gain)
- .SetAudioAttributes(attributes)
- .SetAcceptsDelayedFocusGain(true)
- .SetWillPauseWhenDucked(true)
- .SetOnAudioFocusChangeListener(this)
- .Build();
- AudioFocusRequest audioFocus = audioManager.RequestAudioFocus(audioFocusRequest);
+ if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
+ {
+ audioFocusRequest = new AudioFocusRequestClass.Builder(AudioFocus.Gain)
+ .SetAudioAttributes(attributes)
+ .SetAcceptsDelayedFocusGain(true)
+ .SetWillPauseWhenDucked(true)
+ .SetOnAudioFocusChangeListener(this)
+ .Build();
+ AudioFocusRequest audioFocus = audioManager.RequestAudioFocus(audioFocusRequest);
- if (audioFocus != AudioFocusRequest.Granted)
- {
- Console.WriteLine("Can't Get Audio Focus");
- return;
- }
- }
- else
+ if (audioFocus != AudioFocusRequest.Granted)
{
+ Console.WriteLine("Can't Get Audio Focus");
+ return;
+ }
+ }
+ else
+ {
#pragma warning disable CS0618 // Type or member is obsolete
- AudioManager am = (AudioManager)MainActivity.instance.GetSystemService(AudioService);
+ AudioManager am = (AudioManager)MainActivity.instance.GetSystemService(AudioService);
- AudioFocusRequest audioFocus = am.RequestAudioFocus(this, Stream.Music, AudioFocus.Gain);
+ AudioFocusRequest audioFocus = am.RequestAudioFocus(this, Stream.Music, AudioFocus.Gain);
- if (audioFocus != AudioFocusRequest.Granted)
- {
- Console.WriteLine("Can't Get Audio Focus");
- return;
- }
-#pragma warning restore CS0618
+ if (audioFocus != AudioFocusRequest.Granted)
+ {
+ Console.WriteLine("Can't Get Audio Focus");
+ return;
}
+#pragma warning restore CS0618
+ }
+ }
+ public async void Play(string filePath, string title = null, string artist = null, string youtubeID = null, string thumbnailURI = null, bool isLive = false, DateTimeOffset? expireDate = null)
+ {
+ isRunning = true;
+ queue?.Clear();
+ currentID = -1;
+ Queue.instance?.Refresh();
+ Home.instance?.RefreshQueue(false);
+
+ Song song = null;
+ if (title == null)
+ song = await LocalManager.GetSong(filePath);
+ else
+ {
+ song = new Song(title, artist, thumbnailURI, youtubeID, -1, -1, filePath, true);
+ }
+
+ song.IsLiveStream = isLive;
+ isLiveStream = isLive;
+ Prepare(song);
+
+ if (!UseCastPlayer)
+ {
+ RequestAudioFocus();
+ player.PlayWhenReady = true;
+ CreateNotification(song.Title, song.Artist, song.AlbumArt, song.Album);
+ AddToQueue(song);
+ currentID = CurrentID() + 1;
+ }
+ else
+ {
+ RemotePlayer.Play();
+ queue = new List { song };
+ currentID = 0;
+ }
+
+ autoPlay.Clear();
+
+ SaveQueueSlot();
+ Player.instance?.RefreshPlayer();
+ Home.instance?.AddQueue();
+ ParseNextSong();
+ if (useAutoPlay)
+ GenerateAutoPlay(false);
+ }
+
+ public async void Play(Song song, long progress = -1, bool addToQueue = true)
+ {
+ if (song.IsParsed == false)
+ await ParseSong(song, -1);
+ else if (song.IsParsed == null)
+ {
+ await ParseSong(song, -1, true);
+ return;
+ }
+
+ if (addToQueue)
+ {
+ queue?.Clear();
+ currentID = -1;
+ }
+
+ isLiveStream = song.IsLiveStream;
+ isRunning = true;
+
+ Prepare(song);
+ if(!UseCastPlayer)
+ {
+ RequestAudioFocus();
player.PlayWhenReady = true;
- player.Prepare(mediaSource, true, true);
CreateNotification(song.Title, song.Artist, song.AlbumArt, song.Album);
if (progress != -1) //I'm seeking after the prepare because with some format, exoplayer's prepare reset the position
@@ -539,6 +493,7 @@ namespace Opus.Api.Services
song.Title = video.Title;
song.Artist = video.Author;
song.Album = await MainActivity.GetBestThumb(new string[] { video.Thumbnails.MaxResUrl, video.Thumbnails.StandardResUrl, video.Thumbnails.HighResUrl });
+ song.Duration = (int)video.Duration.TotalMilliseconds;
Player.instance?.RefreshPlayer();
if (startPlaybackWhenPosible)
@@ -1012,11 +967,11 @@ namespace Opus.Api.Services
Queue.instance?.NotifyItemInserted(queue.Count - 1);
}
- public void PlayPrevious()
+ public async void PlayPrevious()
{
Player.instance.playNext = false;
Player.instance.Buffering();
- if(CurrentPosition > Duration * 0.2f || CurrentID() - 1 < 0)
+ if(CurrentPosition > await Duration() * 0.2f || CurrentID() - 1 < 0)
{
if (player != null)
player.SeekTo(0);
@@ -1147,12 +1102,32 @@ namespace Opus.Api.Services
return currentID;
}
- public static void SeekTo(long positionMS)
+ public async static void SeekTo(long positionMS)
{
if (!UseCastPlayer)
- player.SeekTo(positionMS);
+ {
+ if (player != null)
+ player.SeekTo(positionMS);
+ else
+ {
+ Player.instance?.Buffering();
+
+ if(instance == null)
+ {
+ Intent intent = new Intent(MainActivity.instance, typeof(MusicPlayer));
+ MainActivity.instance.StartService(intent);
+
+ while (instance == null)
+ await Task.Delay(10);
+ }
+
+ instance.Play(await GetItem(), positionMS, false);
+ }
+ }
else
+ {
RemotePlayer.Seek(positionMS);
+ }
}
void AddSongToDataBase(Song item)
@@ -1303,15 +1278,33 @@ namespace Opus.Api.Services
}
}
- public static long Duration
+ public async static Task Duration()
{
- get
+ if(!UseCastPlayer)
+ return player == null ? (await GetItem()).Duration : (int)player.Duration;
+ else
+ return RemotePlayer == null ? (await GetItem()).Duration : (int)RemotePlayer.StreamDuration;
+ }
+
+ public async static Task LoadDuration()
+ {
+ int oldDur = await Duration();
+ if (oldDur < 10)
{
- if(!UseCastPlayer)
- return player == null ? 1 : player.Duration;
- else
- return RemotePlayer == null ? 1 : RemotePlayer.StreamDuration;
+ Song song = await GetItem();
+ if (song.IsYt && song.IsParsed != true)
+ await ParseSong(song);
+ else if(!song.IsYt)
+ {
+ MediaMetadataRetriever meta = new MediaMetadataRetriever();
+ await meta.SetDataSourceAsync(song.Path);
+ song.Duration = int.Parse(meta.ExtractMetadata(MetadataKey.Duration));
+ meta.Release();
+ }
+
+ return song.Duration;
}
+ return oldDur;
}
public static long CurrentPosition
@@ -1799,7 +1792,8 @@ namespace Opus.Api.Services
}
if(state == Com.Google.Android.Exoplayer2.Player.StateBuffering)
{
- Player.instance?.Buffering();
+ if(isRunning)
+ Player.instance?.Buffering();
}
if(state == Com.Google.Android.Exoplayer2.Player.StateReady)
{
diff --git a/Opus/Code/DataStructure/Song.cs b/Opus/Code/DataStructure/Song.cs
index ab200d0..d5155a0 100644
--- a/Opus/Code/DataStructure/Song.cs
+++ b/Opus/Code/DataStructure/Song.cs
@@ -26,6 +26,7 @@ namespace Opus.DataStructure
public bool? IsParsed { get; set; }
public bool IsYt { get; set; }
public DateTimeOffset? ExpireDate { get; set;}
+ public int Duration { get; set; }
public bool IsLiveStream = false;
public string TrackID;
diff --git a/Opus/Code/UI/Views/Player.cs b/Opus/Code/UI/Views/Player.cs
index 17253db..d75fff1 100644
--- a/Opus/Code/UI/Views/Player.cs
+++ b/Opus/Code/UI/Views/Player.cs
@@ -67,10 +67,10 @@ namespace Opus
albumArt = view.FindViewById(Resource.Id.playerAlbum);
timer = view.FindViewById(Resource.Id.timer);
bar = view.FindViewById(Resource.Id.songTimer);
- bar.ProgressChanged += (sender, e) =>
+ bar.ProgressChanged += async (sender, e) =>
{
if (!MusicPlayer.isLiveStream)
- timer.Text = string.Format("{0} | {1}", DurationToTimer(e.Progress), DurationToTimer((int)MusicPlayer.Duration));
+ timer.Text = string.Format("{0} | {1}", DurationToTimer(e.Progress), DurationToTimer(await MusicPlayer.Duration()));
};
bar.StartTrackingTouch += (sender, e) =>
{
@@ -207,9 +207,6 @@ namespace Opus
if (bar != null)
{
- while (MusicPlayer.Duration < 2)
- await Task.Delay(100);
-
if(spBar == null)
spBar = Activity.FindViewById(Resource.Id.spProgress);
@@ -223,12 +220,18 @@ namespace Opus
}
else
{
- bar.Max = (int)MusicPlayer.Duration;
- timer.Text = string.Format("{0} | {1}", DurationToTimer((int)MusicPlayer.CurrentPosition), DurationToTimer((int)MusicPlayer.Duration));
- spBar.Max = (int)MusicPlayer.Duration;
+ int duration = await MusicPlayer.Duration();
+ bar.Max = duration;
+ timer.Text = string.Format("{0} | {1}", DurationToTimer((int)MusicPlayer.CurrentPosition), DurationToTimer(duration));
+ spBar.Max = duration;
spBar.Progress = (int)MusicPlayer.CurrentPosition;
handler.PostDelayed(UpdateSeekBar, 1000);
+
+ int LoadedMax = (int)await MusicPlayer.LoadDuration();
+ bar.Max = LoadedMax;
+ spBar.Max = LoadedMax;
+ timer.Text = string.Format("{0} | {1}", DurationToTimer((int)MusicPlayer.CurrentPosition), DurationToTimer(LoadedMax));
}
}
}
@@ -290,7 +293,7 @@ namespace Opus
MainActivity.instance.SheetBehavior.State = BottomSheetBehavior.StateCollapsed;
}
- public void UpdateSeekBar()
+ public async void UpdateSeekBar()
{
if (!MusicPlayer.isRunning)
{
@@ -300,7 +303,7 @@ namespace Opus
if(MusicPlayer.autoUpdateSeekBar)
{
bar.Progress = (int)MusicPlayer.CurrentPosition;
- timer.Text = string.Format("{0} | {1}", DurationToTimer((int)MusicPlayer.CurrentPosition), DurationToTimer((int)MusicPlayer.Duration));
+ timer.Text = string.Format("{0} | {1}", DurationToTimer((int)MusicPlayer.CurrentPosition), DurationToTimer(await MusicPlayer.Duration()));
}
spBar.Progress = (int)MusicPlayer.CurrentPosition;
handler.PostDelayed(UpdateSeekBar, 100);