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);