mirror of
https://github.com/zoriya/Opus.git
synced 2026-06-03 14:35:33 +00:00
Adding youtube play for chromecast. Automatically sync state.
This commit is contained in:
@@ -274,6 +274,7 @@
|
||||
<Compile Include="Resources\Portable Class\AddToPlaylistAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\AudioStopper.cs" />
|
||||
<Compile Include="Resources\Portable Class\Browse.cs" />
|
||||
<Compile Include="Resources\Portable Class\CastProvider.cs" />
|
||||
<Compile Include="Resources\Portable Class\ChannelAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\ChannelPreviewHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\CircleTransformation.cs" />
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<application android:allowBackup="true" android:label="MusicApp">
|
||||
<meta-data android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME" android:value="com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider" />
|
||||
<meta-data android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME" android:value="MusicApp.CastProvider" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,31 @@
|
||||
using Android.Content;
|
||||
using Android.Gms.Cast;
|
||||
using Android.Gms.Cast.Framework;
|
||||
using Android.Gms.Cast.Framework.Media;
|
||||
using Android.Runtime;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MusicApp
|
||||
{
|
||||
[Register("MusicApp/CastProvider")]
|
||||
public class CastProvider : Java.Lang.Object, IOptionsProvider
|
||||
{
|
||||
public CastOptions GetCastOptions(Context appContext)
|
||||
{
|
||||
//NotificationOptions notification = new NotificationOptions.Builder()
|
||||
// .
|
||||
//Customise (or disable) build in notification here.
|
||||
|
||||
CastOptions options = new CastOptions.Builder()
|
||||
.SetReceiverApplicationId(CastMediaControlIntent.DefaultMediaReceiverApplicationId)
|
||||
.SetStopReceiverApplicationWhenEndingSession(true)
|
||||
.Build();
|
||||
return options;
|
||||
}
|
||||
|
||||
public IList<SessionProvider> GetAdditionalSessionProviders(Context appContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
using Android.Content;
|
||||
using Android.Database;
|
||||
using Android.Gms.Cast;
|
||||
using Android.Gms.Cast.Framework;
|
||||
using Android.Gms.Cast.Framework.Media;
|
||||
using Android.Graphics;
|
||||
using Android.Media;
|
||||
using Android.OS;
|
||||
@@ -21,6 +23,7 @@ using Com.Google.Android.Exoplayer2.Source.Hls;
|
||||
using Com.Google.Android.Exoplayer2.Trackselection;
|
||||
using Com.Google.Android.Exoplayer2.Upstream;
|
||||
using Com.Google.Android.Exoplayer2.Util;
|
||||
using Java.Lang;
|
||||
using MusicApp.Resources.values;
|
||||
using SQLite;
|
||||
using Square.Picasso;
|
||||
@@ -39,12 +42,13 @@ using Uri = Android.Net.Uri;
|
||||
namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
[Service]
|
||||
public class MusicPlayer : Service, IPlayerEventListener, AudioManager.IOnAudioFocusChangeListener, CastPlayer.ISessionAvailabilityListener
|
||||
public class MusicPlayer : Service, IPlayerEventListener, AudioManager.IOnAudioFocusChangeListener, CastPlayer.ISessionAvailabilityListener, RemoteMediaClient.IListener, ISessionManagerListener
|
||||
{
|
||||
public static MusicPlayer instance;
|
||||
private static bool UseCastPlayer = false;
|
||||
public static SimpleExoPlayer player;
|
||||
private static CastPlayer CastPlayer;
|
||||
private static RemoteMediaClient RemoteMediaClient;
|
||||
public float volume;
|
||||
private static AudioStopper noisyReceiver;
|
||||
public static List<Song> queue = new List<Song>();
|
||||
@@ -187,6 +191,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
CastPlayer = new CastPlayer(MainActivity.CastContext);
|
||||
CastPlayer.SetSessionAvailabilityListener(this);
|
||||
CastPlayer.AddListener(this);
|
||||
RemoteMediaClient = MainActivity.CastContext.SessionManager.CurrentCastSession?.RemoteMediaClient;
|
||||
RemoteMediaClient?.AddListener(this);
|
||||
UseCastPlayer = CastPlayer.IsCastSessionAvailable;
|
||||
player.PlayWhenReady = !UseCastPlayer;
|
||||
}
|
||||
@@ -278,10 +284,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
else
|
||||
{
|
||||
CastPlayer.LoadItem(GetQueueItem(song), 0);
|
||||
CastPlayer.PlayWhenReady = true;
|
||||
}
|
||||
|
||||
isRunning = true;
|
||||
|
||||
if (addToQueue)
|
||||
{
|
||||
AddToQueue(song);
|
||||
@@ -378,6 +383,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
else
|
||||
{
|
||||
CastPlayer.LoadItem(GetQueueItem(song), 0);
|
||||
CastPlayer.PlayWhenReady = true;
|
||||
}
|
||||
|
||||
isRunning = true;
|
||||
@@ -669,16 +675,30 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
private void RandomizeQueue()
|
||||
{
|
||||
Random r = new Random();
|
||||
Song current = queue[CurrentID()];
|
||||
queue.RemoveAt(CurrentID());
|
||||
queue = queue.OrderBy(x => r.Next()).ToList();
|
||||
if (UseCastPlayer)
|
||||
{
|
||||
Timeline timeLine = CastPlayer.CurrentTimeline;
|
||||
for (int i = 0; i < timeLine.PeriodCount; i++)
|
||||
{
|
||||
Timeline.Period period = timeLine.GetPeriod(i, new Timeline.Period());
|
||||
CastPlayer.MoveItem((int)period.Id, new Random().Next(0, timeLine.PeriodCount));
|
||||
}
|
||||
|
||||
GetQueueFromCast();
|
||||
}
|
||||
else
|
||||
{
|
||||
Random r = new Random();
|
||||
Song current = queue[CurrentID()];
|
||||
queue.RemoveAt(CurrentID());
|
||||
queue = queue.OrderBy(x => r.Next()).ToList();
|
||||
|
||||
current.queueSlot = 0;
|
||||
currentID = 0;
|
||||
queue.Insert(0, current);
|
||||
}
|
||||
|
||||
current.queueSlot = 0;
|
||||
currentID = 0;
|
||||
queue.Insert(0, current);
|
||||
UpdateQueueSlots();
|
||||
|
||||
SaveQueueSlot();
|
||||
Player.instance?.UpdateNext();
|
||||
Queue.instance?.Refresh();
|
||||
@@ -700,6 +720,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
queue.Insert(song.queueSlot, song);
|
||||
UpdateQueueSlots();
|
||||
Home.instance?.RefreshQueue();
|
||||
|
||||
if(UseCastPlayer)
|
||||
CastPlayer.AddItems(GetQueueItem(song));
|
||||
}
|
||||
|
||||
public void AddToQueue(Song song)
|
||||
@@ -709,6 +732,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
queue.Insert(song.queueSlot, song);
|
||||
UpdateQueueSlots();
|
||||
Home.instance?.RefreshQueue();
|
||||
|
||||
if (UseCastPlayer)
|
||||
CastPlayer.AddItems(GetQueueItem(song));
|
||||
}
|
||||
|
||||
public void PlayLastInQueue(string filePath)
|
||||
@@ -720,6 +746,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
UpdateQueueItemDB(song);
|
||||
|
||||
Home.instance?.RefreshQueue();
|
||||
|
||||
if (UseCastPlayer)
|
||||
CastPlayer.AddItems(GetQueueItem(song));
|
||||
}
|
||||
|
||||
public void PlayLastInQueue(Song song)
|
||||
@@ -728,6 +757,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
queue.Add(song);
|
||||
UpdateQueueItemDB(song);
|
||||
Home.instance?.RefreshQueue();
|
||||
|
||||
if (UseCastPlayer)
|
||||
CastPlayer.AddItems(GetQueueItem(song));
|
||||
}
|
||||
|
||||
public void PlayLastInQueue(string filePath, string title, string artist, string youtubeID, string thumbnailURI, bool isLive = false)
|
||||
@@ -741,6 +773,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
queue.Add(song);
|
||||
UpdateQueueItemDB(song);
|
||||
Home.instance?.RefreshQueue();
|
||||
|
||||
if (UseCastPlayer)
|
||||
CastPlayer.AddItems(GetQueueItem(song));
|
||||
}
|
||||
|
||||
public void PlayPrevious()
|
||||
@@ -1125,7 +1160,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
icon = Picasso.With(Application.Context).Load(imageURI).Error(Resource.Drawable.MusicIcon).Placeholder(Resource.Drawable.MusicIcon).Transform(new RemoveBlackBorder(true)).Get();
|
||||
}
|
||||
catch (Exception)
|
||||
catch (System.Exception)
|
||||
{
|
||||
icon = Picasso.With(Application.Context).Load(Resource.Drawable.MusicIcon).Get();
|
||||
}
|
||||
@@ -1142,7 +1177,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
icon = Picasso.With(Application.Context).Load(iconURI).Error(Resource.Drawable.MusicIcon).Placeholder(Resource.Drawable.MusicIcon).NetworkPolicy(NetworkPolicy.Offline).Resize(400, 400).CenterCrop().Get();
|
||||
}
|
||||
catch (Exception)
|
||||
catch (System.Exception)
|
||||
{
|
||||
icon = Picasso.With(Application.Context).Load(Resource.Drawable.MusicIcon).Get();
|
||||
}
|
||||
@@ -1234,7 +1269,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
//notificationManager.Notify(notificationID, notification);
|
||||
|
||||
//StopForeground(false);
|
||||
CastPlayer.PlayWhenReady = false;
|
||||
//CastPlayer.PlayWhenReady = false;
|
||||
RemoteMediaClient.Pause();
|
||||
FrameLayout smallPlayer = MainActivity.instance.FindViewById<FrameLayout>(Resource.Id.smallPlayer);
|
||||
smallPlayer?.FindViewById<ImageButton>(Resource.Id.spPlay)?.SetImageResource(Resource.Drawable.Play);
|
||||
|
||||
@@ -1326,7 +1362,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
//StartForeground(notificationID, notification);
|
||||
|
||||
CastPlayer.PlayWhenReady = true;
|
||||
//CastPlayer.PlayWhenReady = true;
|
||||
RemoteMediaClient.Play();
|
||||
|
||||
FrameLayout smallPlayer = MainActivity.instance.FindViewById<FrameLayout>(Resource.Id.smallPlayer);
|
||||
smallPlayer?.FindViewById<ImageButton>(Resource.Id.spPlay)?.SetImageResource(Resource.Drawable.Pause);
|
||||
@@ -1350,6 +1387,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
MediaMetadata metadata = new MediaMetadata(MediaMetadata.MediaTypeMusicTrack);
|
||||
metadata.PutString(MediaMetadata.KeyTitle, song.Title);
|
||||
metadata.PutString(MediaMetadata.KeyArtist, song.Artist);
|
||||
//metadata.PutString(MediaMetadata.)
|
||||
metadata.AddImage(new Android.Gms.Common.Images.WebImage(Uri.Parse(song.Album), 1000, 1000));
|
||||
|
||||
MediaInfo mediaInfo = new MediaInfo.Builder(song.Path)
|
||||
@@ -1359,7 +1397,37 @@ namespace MusicApp.Resources.Portable_Class
|
||||
.Build();
|
||||
|
||||
return new MediaQueueItem.Builder(mediaInfo).Build();
|
||||
}
|
||||
}
|
||||
|
||||
private Song GetSongFromQueueItem(MediaQueueItem queueItem)
|
||||
{
|
||||
string title = queueItem.Media.Metadata.GetString(MediaMetadata.KeyTitle);
|
||||
string artist = queueItem.Media.Metadata.GetString(MediaMetadata.KeyArtist);
|
||||
string album = null;
|
||||
string youtubeID = null;
|
||||
long albumArt = 0;
|
||||
long id = 0;
|
||||
string path = queueItem.Media.ContentId;
|
||||
bool isYT = true;
|
||||
bool isParsed = true;
|
||||
return new Song(title, artist, album, youtubeID, albumArt, id, path, isYT, isParsed);
|
||||
}
|
||||
|
||||
public void GetQueueFromCast()
|
||||
{
|
||||
if (UseCastPlayer)
|
||||
{
|
||||
queue = new List<Song>();
|
||||
Timeline timeLine = CastPlayer.CurrentTimeline;
|
||||
for (int i = 0; i < timeLine.PeriodCount; i++)
|
||||
{
|
||||
Timeline.Period period = timeLine.GetPeriod(i, new Timeline.Period());
|
||||
MediaQueueItem item = CastPlayer.GetItem((int)period.Id);
|
||||
queue.Add(GetSongFromQueueItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
@@ -1497,12 +1565,119 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
player.Stop();
|
||||
}
|
||||
Player.instance.RefreshPlayer();
|
||||
}
|
||||
|
||||
public void OnCastSessionUnavailable()
|
||||
{
|
||||
UseCastPlayer = false;
|
||||
}
|
||||
|
||||
|
||||
//Remote media client calls
|
||||
|
||||
public void OnAdBreakStatusUpdated() { }
|
||||
|
||||
public void OnMetadataUpdated()
|
||||
{
|
||||
Console.WriteLine("&Metadata Updated");
|
||||
}
|
||||
|
||||
public void OnPreloadStatusUpdated()
|
||||
{
|
||||
Console.WriteLine("&Preload Status Updated");
|
||||
}
|
||||
|
||||
public void OnQueueStatusUpdated()
|
||||
{
|
||||
Console.WriteLine("&Queue status updated");
|
||||
}
|
||||
|
||||
public void OnSendingRemoteMediaRequest()
|
||||
{
|
||||
Console.WriteLine("&Sending Remote Media Request");
|
||||
}
|
||||
|
||||
public void OnStatusUpdated()
|
||||
{
|
||||
if (RemoteMediaClient.IsBuffering)
|
||||
Player.instance?.Buffering();
|
||||
else
|
||||
Player.instance?.Ready();
|
||||
|
||||
if (RemoteMediaClient.IsPaused)
|
||||
{
|
||||
isRunning = false;
|
||||
FrameLayout smallPlayer = MainActivity.instance.FindViewById<FrameLayout>(Resource.Id.smallPlayer);
|
||||
smallPlayer?.FindViewById<ImageButton>(Resource.Id.spPlay)?.SetImageResource(Resource.Drawable.Play);
|
||||
|
||||
if (Player.instance != null)
|
||||
{
|
||||
MainActivity.instance?.FindViewById<ImageButton>(Resource.Id.playButton)?.SetImageResource(Resource.Drawable.Play);
|
||||
Player.instance.handler?.PostDelayed(Player.instance.UpdateSeekBar, 1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isRunning = true;
|
||||
FrameLayout smallPlayer = MainActivity.instance.FindViewById<FrameLayout>(Resource.Id.smallPlayer);
|
||||
smallPlayer?.FindViewById<ImageButton>(Resource.Id.spPlay)?.SetImageResource(Resource.Drawable.Pause);
|
||||
|
||||
if (Player.instance != null)
|
||||
{
|
||||
MainActivity.instance?.FindViewById<ImageButton>(Resource.Id.playButton)?.SetImageResource(Resource.Drawable.Pause);
|
||||
Player.instance.handler?.PostDelayed(Player.instance.UpdateSeekBar, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//SessionManagerListener
|
||||
|
||||
//Should set the reference of the RemoteMediaClient here and handle remote loose.
|
||||
|
||||
public void OnSessionEnded(Java.Lang.Object session, int error)
|
||||
{
|
||||
Console.WriteLine("&Session Ended");
|
||||
SwitchRemote(null);
|
||||
}
|
||||
|
||||
public void OnSessionEnding(Java.Lang.Object session) { }
|
||||
|
||||
public void OnSessionResumeFailed(Java.Lang.Object session, int error) { }
|
||||
|
||||
public void OnSessionResumed(Java.Lang.Object session, bool wasSuspended)
|
||||
{
|
||||
Console.WriteLine("&Session Resumed");
|
||||
SwitchRemote(((CastSession)session).RemoteMediaClient);
|
||||
}
|
||||
|
||||
public void OnSessionResuming(Java.Lang.Object session, string sessionId) { }
|
||||
|
||||
public void OnSessionStartFailed(Java.Lang.Object session, int error) { }
|
||||
|
||||
public void OnSessionStarted(Java.Lang.Object session, string sessionId)
|
||||
{
|
||||
Console.WriteLine("&Session Started");
|
||||
SwitchRemote(((CastSession)session).RemoteMediaClient);
|
||||
}
|
||||
|
||||
public void OnSessionStarting(Java.Lang.Object session) { }
|
||||
|
||||
public void OnSessionSuspended(Java.Lang.Object session, int reason)
|
||||
{
|
||||
Console.WriteLine("&Session Suspended");
|
||||
SwitchRemote(null);
|
||||
}
|
||||
|
||||
private void SwitchRemote(RemoteMediaClient remoteClient)
|
||||
{
|
||||
if (RemoteMediaClient != null)
|
||||
RemoteMediaClient.RemoveListener(this);
|
||||
|
||||
RemoteMediaClient = remoteClient;
|
||||
if (RemoteMediaClient != null)
|
||||
RemoteMediaClient.AddListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
if (MusicPlayer.player != null && bar != null)
|
||||
{
|
||||
while (MusicPlayer.Duration < 1)
|
||||
while (MusicPlayer.Duration < 2)
|
||||
await Task.Delay(100);
|
||||
|
||||
if (current.IsLiveStream)
|
||||
@@ -340,14 +340,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
buffer.SetY(play.GetY());
|
||||
play.Visibility = ViewStates.Gone;
|
||||
|
||||
ProgressBar smallBuffer = MainActivity.instance.FindViewById<ProgressBar>(Resource.Id.spBuffer);
|
||||
ImageButton smallPlay = MainActivity.instance.FindViewById<ImageButton>(Resource.Id.spPlay);
|
||||
if(MainActivity.Theme == 1)
|
||||
smallBuffer.IndeterminateTintList = ColorStateList.ValueOf(Color.White);
|
||||
else
|
||||
smallBuffer.IndeterminateTintList = ColorStateList.ValueOf(Color.Black);
|
||||
smallBuffer.Visibility = ViewStates.Visible;
|
||||
smallPlay.Visibility = ViewStates.Invisible;
|
||||
MainActivity.instance.FindViewById<ProgressBar>(Resource.Id.spBuffer).Visibility = ViewStates.Visible;
|
||||
MainActivity.instance.FindViewById<ImageButton>(Resource.Id.spPlay).Visibility = ViewStates.Invisible;
|
||||
}
|
||||
|
||||
public void Error()
|
||||
@@ -620,6 +614,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
MainActivity.instance.FindViewById<ImageButton>(Resource.Id.spNext).ImageTintList = ColorStateList.ValueOf(Color.White);
|
||||
MainActivity.instance.FindViewById<ImageButton>(Resource.Id.spPlay).ImageTintList = ColorStateList.ValueOf(Color.White);
|
||||
MainActivity.instance.FindViewById<ImageButton>(Resource.Id.spLast).ImageTintList = ColorStateList.ValueOf(Color.White);
|
||||
MainActivity.instance.FindViewById<ProgressBar>(Resource.Id.spBuffer).IndeterminateTintList = ColorStateList.ValueOf(Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -627,6 +622,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
MainActivity.instance.FindViewById<ImageButton>(Resource.Id.spNext).ImageTintList = ColorStateList.ValueOf(Color.Black);
|
||||
MainActivity.instance.FindViewById<ImageButton>(Resource.Id.spPlay).ImageTintList = ColorStateList.ValueOf(Color.Black);
|
||||
MainActivity.instance.FindViewById<ImageButton>(Resource.Id.spLast).ImageTintList = ColorStateList.ValueOf(Color.Black);
|
||||
MainActivity.instance.FindViewById<ProgressBar>(Resource.Id.spBuffer).IndeterminateTintList = ColorStateList.ValueOf(Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user