diff --git a/Aurora.gtk/Aurora.gtk.csproj b/Aurora.gtk/Aurora.gtk.csproj
index 34acb22..d80583a 100644
--- a/Aurora.gtk/Aurora.gtk.csproj
+++ b/Aurora.gtk/Aurora.gtk.csproj
@@ -150,7 +150,7 @@
..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
- ..\packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
+ ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
..\packages\System.Linq.Async.4.0.0\lib\net461\System.Linq.Async.dll
@@ -164,6 +164,10 @@
..\packages\CarouselView.FormsPlugin.5.2.0\lib\netstandard2.0\CarouselView.FormsPlugin.Abstractions.dll
+
+ ..\packages\Autofac.5.0.0\lib\net461\Autofac.dll
+
+
diff --git a/Aurora.gtk/packages.config b/Aurora.gtk/packages.config
index 652707f..45a8c07 100644
--- a/Aurora.gtk/packages.config
+++ b/Aurora.gtk/packages.config
@@ -1,5 +1,6 @@
+
@@ -13,7 +14,7 @@
-
+
diff --git a/Aurora.test/Aurora.test.csproj b/Aurora.test/Aurora.test.csproj
index 9b7378f..8aafe1a 100644
--- a/Aurora.test/Aurora.test.csproj
+++ b/Aurora.test/Aurora.test.csproj
@@ -13,6 +13,7 @@
all
+
diff --git a/Aurora.test/ControllerTests/MediaControllerTest.cs b/Aurora.test/ControllerTests/MediaControllerTest.cs
new file mode 100644
index 0000000..902b672
--- /dev/null
+++ b/Aurora.test/ControllerTests/MediaControllerTest.cs
@@ -0,0 +1,29 @@
+using NUnit.Framework;
+using Aurora.Proto.PartyV2;
+using Aurora.Services.Server;
+using Grpc.Core;
+using System.Threading.Tasks;
+using System.Linq;
+
+namespace Aurora.test.ControllerTests
+{
+ public class MediaControllerTests
+ {
+ private RemotePartyService.RemotePartyServiceClient _remotePartyService;
+ private Channel _channel;
+ [SetUp]
+ public void Setup()
+ {
+ ServerService.Instance.Start("testParty", "asdf");
+ _channel = new Channel(string.Format("{0}:{1}", ServerService.GetLocalIPAddress(), 8080), ChannelCredentials.Insecure);
+ _remotePartyService = new RemotePartyService.RemotePartyServiceClient(_channel);
+ }
+
+ [TearDown]
+ public async Task TearDown()
+ {
+ await ServerService.Instance.Stop();
+ await _channel.ShutdownAsync();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Aurora.test/ControllerTests/MembersControllerTest.cs b/Aurora.test/ControllerTests/MembersControllerTest.cs
index d9122d5..0671801 100644
--- a/Aurora.test/ControllerTests/MembersControllerTest.cs
+++ b/Aurora.test/ControllerTests/MembersControllerTest.cs
@@ -139,5 +139,50 @@ namespace Aurora.test.ControllerTests
Assert.AreEqual(resp.Members.Count, 5);
Assert.False(resp.Members.Any(member => member.UserName == "Ke$sha"));
}
+
+ static object[] PagingCases =
+ {
+ new object[] {"Tupac", "Aubrey Grahm", "Beyonce Knowls", "Ke$ha", "A$ap Ferg", "asdf", "sdfa", "dfas", "fasd"},
+ };
+
+ [Test]
+ [TestCaseSource("PagingCases")]
+ public void MemberPagingTest(object[] members)
+ {
+ foreach (string name in members)
+ {
+ Member member = _remotePartyService.CreateMember(new CreateMemberRequest()
+ {
+ Parent = "party1",
+ Member = new Member()
+ {
+ UserName = name
+ }
+ });
+
+ Assert.NotNull(member);
+ }
+
+ //List members
+ ListMembersResponse resp = _remotePartyService.ListMembers(new ListMembersRequest()
+ {
+ Parent = "party1",
+ PageSize = 2,
+ });
+
+ string nextPageToken = resp.NextPageToken;
+
+ Assert.AreEqual(resp.Members.Count, 2);
+
+ //List members
+ resp = _remotePartyService.ListMembers(new ListMembersRequest()
+ {
+ Parent = "party1",
+ PageSize = 2,
+ PageToken = nextPageToken,
+ });
+
+ Assert.AreEqual(resp.Members.Count, 2);
+ }
}
}
\ No newline at end of file
diff --git a/Aurora/App.xaml.cs b/Aurora/App.xaml.cs
index cc5f24c..ca655b9 100644
--- a/Aurora/App.xaml.cs
+++ b/Aurora/App.xaml.cs
@@ -1,19 +1,51 @@
using System;
using Aurora.Design.Views.Main;
+using Aurora.Design.Views.Albums;
+using Aurora.Design.Views.Artists;
+using Aurora.Design.Views.Party;
+using Aurora.Design.Views.Profile;
+using Aurora.Design.Views.Songs;
+using Aurora.Design.Views.Stations;
+using Aurora.Services.ClientService;
+using Autofac;
using LibVLCSharp.Shared;
using Xamarin.Forms;
-using Xamarin.Forms.Xaml;
+using Aurora.Services.Player;
+using Aurora.Services.Settings;
namespace Aurora
{
public partial class App : Application
{
+ private static IContainer _container;
public App()
{
InitializeComponent();
Core.Initialize();
- MainPage = new MainView();
+ //Register DI
+ ContainerBuilder _builder = new ContainerBuilder();
+ // _builder.RegisterInstance(new PlayerService()).SingleInstance();
+ _builder.RegisterType().As().SingleInstance();
+ _builder.RegisterType().As().SingleInstance();
+ _builder.RegisterType().As().SingleInstance();
+ _builder.RegisterType().SingleInstance();
+ _builder.RegisterType();
+ _builder.RegisterType();
+ _builder.RegisterType();
+ _builder.RegisterType();
+ _builder.RegisterType();
+ _builder.RegisterType();
+
+ // _builder.RegisterInstance(new SettingsService()).SingleInstance();
+ _container = _builder.Build();
+
+ MainPage = _container.Resolve();
+ }
+
+ public static IContainer Container
+ {
+ get { return _container; }
}
protected override void OnStart()
diff --git a/Aurora/Aurora.csproj b/Aurora/Aurora.csproj
index 2301ec8..85cc85a 100644
--- a/Aurora/Aurora.csproj
+++ b/Aurora/Aurora.csproj
@@ -23,6 +23,7 @@
+
diff --git a/Aurora/Design/Views/MainView/MainView.xaml.cs b/Aurora/Design/Views/MainView/MainView.xaml.cs
index a008571..67d7f16 100644
--- a/Aurora/Design/Views/MainView/MainView.xaml.cs
+++ b/Aurora/Design/Views/MainView/MainView.xaml.cs
@@ -9,8 +9,8 @@ using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Aurora.Models.Media;
using Aurora.Design.Components.MediaPlayer;
-using Aurora.Services.PlayerService;
-using System.Threading;
+using Aurora.Services.Player;
+using Autofac;
namespace Aurora.Design.Views.Main
{
@@ -38,10 +38,10 @@ namespace Aurora.Design.Views.Main
private Dictionary _viewModels;
private BaseViewModel _lastViewModel;
private Player _playerComponent;
- private PlayerService _playerService;
+ private IPlayer _playerService;
private ContentPresenter _viewContent;
- public MainView()
+ public MainView(IPlayer player)
{
InitializeComponent();
BindingContext = new MainViewModel();
@@ -50,7 +50,7 @@ namespace Aurora.Design.Views.Main
_playerComponent = Player;
_viewContent = (ContentPresenter)Content.FindByName("ViewContent");
- _playerService = PlayerService.Instance;
+ _playerService = player;
MasterPage.ListView.ItemSelected += OnNavItemSelected;
@@ -89,7 +89,7 @@ namespace Aurora.Design.Views.Main
}
//Instantiate new view model
- vm = (BaseViewModel)Activator.CreateInstance(item.TargetViewModelType);
+ vm = (BaseViewModel)App.Container.Resolve(item.TargetViewModelType); //Activator.CreateInstance(item.TargetViewModelType);
_viewModels.Add(item.Id, vm);
}
@@ -135,7 +135,7 @@ namespace Aurora.Design.Views.Main
else
{
//Instantiate new view model
- vm = (BaseViewModel)Activator.CreateInstance(firstNavItem.TargetViewModelType);
+ vm = (BaseViewModel)App.Container.Resolve(firstNavItem.TargetViewModelType); //(BaseViewModel)Activator.CreateInstance(firstNavItem.TargetViewModelType);
_viewModels.Add(firstNavItem.Id, vm);
}
diff --git a/Aurora/Design/Views/Party/PartyViewModel.cs b/Aurora/Design/Views/Party/PartyViewModel.cs
index b9daa6d..be1e970 100644
--- a/Aurora/Design/Views/Party/PartyViewModel.cs
+++ b/Aurora/Design/Views/Party/PartyViewModel.cs
@@ -9,10 +9,11 @@ using Aurora.Proto.Party;
using Aurora.Proto.Events;
using Aurora.Services.ClientService;
using Aurora.Services.ClientService.Events;
-using Aurora.Services.PlayerService;
+using Aurora.Services.Player;
using Aurora.Services.EventManager;
using Aurora.Models.Media;
using Aurora.Design.Views.Party.NewPartyDialog;
+using Aurora.Services.Settings;
namespace Aurora.Design.Views.Party
{
@@ -32,22 +33,25 @@ namespace Aurora.Design.Views.Party
private ObservableCollection _members;
private ObservableCollection _queue;
private BaseMedia _selectedMedia;
- private ClientService _client;
+ private IClientService _client;
+ private ISettingsService _settingsService;
private int _selectedTabIndex;
- public PartyViewModel()
+ public PartyViewModel(ISettingsService settingsService, IClientService clientService)
{
_members = new ObservableCollection();
_queue = new ObservableCollection();
+ this._settingsService = settingsService;
+
SetState(PartyState.SelectingHost);
PlayCommand = new Command(OnDoubleClickCommandExecute, CanDoubleClickCommandExecute);
LeavePartyCommand = new Command(OnLeavePartyCommandExecute, CanLeavePartyCommandExecute);
- _client = ClientService.Instance;
+ _client = clientService;
_client.OnMediaPaused += this.OnRemoteMediaPaused;
_client.OnMediaResumed += this.OnRemoteMediaResumed;
@@ -245,7 +249,7 @@ namespace Aurora.Design.Views.Party
private async void OnJoinCommandExecute()
{
SetState(PartyState.Connecting);
- _client.Start(_hostname, SettingsService.Instance.DefaultPort.ToString());
+ _client.Start(_hostname, this._settingsService.DefaultPort.ToString());
await JoinParty(false);
//TODO add cancellation token
@@ -272,7 +276,7 @@ namespace Aurora.Design.Views.Party
ServerService.Instance.Start();
string localHost = ServerService.GetLocalIPAddress();
_client.IsHost = true;
- _client.Start(localHost, SettingsService.Instance.DefaultPort.ToString());
+ _client.Start(localHost, this._settingsService.DefaultPort.ToString());
await JoinParty(true);
@@ -387,10 +391,10 @@ namespace Aurora.Design.Views.Party
{
JoinPartyResponse resp = await _client.RemotePartyClient.JoinPartyAsync(new JoinPartyRequest
{
- UserName = SettingsService.Instance.Username,
+ UserName = this._settingsService.Username,
});
- SettingsService.Instance.ClientId = resp.ClientId;
+ this._settingsService.ClientId = resp.ClientId;
RefreshMembers();
@@ -447,13 +451,13 @@ namespace Aurora.Design.Views.Party
req.EventTypes.Add(EventType.PartyMemberLeft);
req.EventTypes.Add(EventType.MediaPlaying);
req.EventTypes.Add(EventType.MediaStopped);
- if (!string.IsNullOrWhiteSpace(SettingsService.Instance.ClientId))
+ if (!string.IsNullOrWhiteSpace(this._settingsService.ClientId))
{
- req.ClientId = SettingsService.Instance.ClientId;
+ req.ClientId = this._settingsService.ClientId;
}
- Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", SettingsService.Instance.ClientId));
+ Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", this._settingsService.ClientId));
await _client.RemoteEventClient.SubscribeToEventsAsync(req);
}
private async Task UnsubscribeFromEvents()
diff --git a/Aurora/Design/Views/Profile/ProfileViewModel.cs b/Aurora/Design/Views/Profile/ProfileViewModel.cs
index b71e876..ac86be5 100644
--- a/Aurora/Design/Views/Profile/ProfileViewModel.cs
+++ b/Aurora/Design/Views/Profile/ProfileViewModel.cs
@@ -1,32 +1,34 @@
using System;
-using Aurora.Services;
+using Aurora.Services.Settings;
namespace Aurora.Design.Views.Profile
{
public class ProfileViewModel : BaseViewModel
{
+ private ISettingsService _settingsService;
- public ProfileViewModel()
+ public ProfileViewModel(ISettingsService settingsService)
{
+ this._settingsService = settingsService;
}
public string Username
{
- get { return SettingsService.Instance.Username; }
+ get { return this._settingsService.Username; }
set
{
- SettingsService.Instance.Username = value;
+ this._settingsService.Username = value;
OnPropertyChanged("Username");
}
}
public string Port
{
- get { return SettingsService.Instance.DefaultPort.ToString(); }
+ get { return this._settingsService.DefaultPort.ToString(); }
set
{
Int32.TryParse(value, out int portNum);
- SettingsService.Instance.DefaultPort = portNum;
+ this._settingsService.DefaultPort = portNum;
OnPropertyChanged("Port");
}
}
diff --git a/Aurora/Proto/party.v2.proto b/Aurora/Proto/party.v2.proto
index 52efeee..3b7532d 100644
--- a/Aurora/Proto/party.v2.proto
+++ b/Aurora/Proto/party.v2.proto
@@ -44,7 +44,13 @@ service RemotePartyService {
rpc ListMedia(ListMediaRequest) returns (ListMediaResponse);
//Get
- rpc GetMedia(GetMediaRequest) returns (RemoteMedia);
+ rpc GetMedia(GetMediaRequest) returns (Media);
+
+ //Create
+ rpc CreateMedia(CreateMediaRequest) returns (Media);
+
+ //Delete
+ rpc DeleteMedia(DeleteMediaRequest) returns (Aurora.Proto.General.Empty) {};
//CUSTOM: Stream
rpc StreamMedia(StreamMediaRequest) returns (stream Aurora.Proto.General.Chunk) {};
@@ -97,7 +103,10 @@ message Member {
//Resource name of the party member to be returned (Added by server)
string name = 1;
string userName = 2;
+
+ //Added by server
string ipAddress = 3;
+
//Added by server
google.protobuf.Timestamp addedOn = 4;
}
@@ -134,7 +143,7 @@ message DeleteMemberRequest {
string name = 1;
}
-message RemoteMedia {
+message Media {
//Resource name of the remote media object
string name = 1;
string title = 2;
@@ -151,7 +160,7 @@ message ListMediaRequest {
}
message ListMediaResponse {
- repeated RemoteMedia media = 1;
+ repeated Media media = 1;
string nextPageToken = 3;
}
@@ -160,6 +169,17 @@ message GetMediaRequest {
string name = 1;
}
+message CreateMediaRequest {
+ //Resource name of the parent collection of the member to be created (The party)
+ string parent = 1;
+ Media media = 2;
+}
+
+message DeleteMediaRequest {
+ //Resource name of the member to be deleted
+ string name = 1;
+}
+
message StreamMediaRequest {
//Resource name of the media requested
string name = 1;
@@ -199,7 +219,7 @@ message BaseEvent {
}
message NewMediaPlayingEvent {
- RemoteMedia media = 1;
+ Media media = 1;
}
message MediaResumedEvent {
diff --git a/Aurora/RemoteImpl/RemoteSyncImpl.cs b/Aurora/RemoteImpl/RemoteSyncImpl.cs
index eddaac0..1b32902 100644
--- a/Aurora/RemoteImpl/RemoteSyncImpl.cs
+++ b/Aurora/RemoteImpl/RemoteSyncImpl.cs
@@ -2,7 +2,9 @@ using System;
using System.Threading.Tasks;
using Aurora.Proto.Sync;
using Aurora.Proto.General;
-using Aurora.Services.PlayerService;
+using Aurora.Services.Player;
+using Aurora;
+using Autofac;
namespace Aurora.RemoteImpl
{
@@ -19,31 +21,36 @@ namespace Aurora.RemoteImpl
Grpc.Core.IServerStreamWriter responseStream,
Grpc.Core.ServerCallContext context)
{
- bool continueSync = true;
- string currentId = PlayerService.Instance.CurrentMedia.Id;
- MediaChangedEventHandler mediaChanged = (sender, e) =>
+ using (var scope = App.Container.BeginLifetimeScope())
{
- if (e.NewId != currentId)
+ IPlayer player = scope.Resolve();
+ bool continueSync = true;
+ string currentId = player.CurrentMedia.Id;
+ MediaChangedEventHandler mediaChanged = (sender, e) =>
{
- continueSync = false;
- }
- };
-
- PlayerService.Instance.MediaChanged += mediaChanged;
-
- while (continueSync)
- {
- float length = PlayerService.Instance.CurrentMediaLength;
-
- Sync sync = new Sync()
- {
- TrackPosition = PlayerService.Instance.CurrentMediaPosition,
- ServerTimeTicks = Utils.TimeUtils.GetNetworkTime().DateTime.Ticks
+ if (e.NewId != currentId)
+ {
+ continueSync = false;
+ }
};
- await responseStream.WriteAsync(sync);
- Console.WriteLine("Sent Sync");
- await Task.Delay(5000);
+
+ player.MediaChanged += mediaChanged;
+
+ while (continueSync)
+ {
+ float length = player.CurrentMediaLength;
+
+ Sync sync = new Sync()
+ {
+ TrackPosition = player.CurrentMediaPosition,
+ ServerTimeTicks = Utils.TimeUtils.GetNetworkTime().DateTime.Ticks
+ };
+ await responseStream.WriteAsync(sync);
+ Console.WriteLine("Sent Sync");
+ await Task.Delay(5000);
+ }
}
+
}
}
}
\ No newline at end of file
diff --git a/Aurora/Services/ClientService/ClientService.cs b/Aurora/Services/ClientService/ClientService.cs
index a3c0c58..3b69d25 100644
--- a/Aurora/Services/ClientService/ClientService.cs
+++ b/Aurora/Services/ClientService/ClientService.cs
@@ -8,11 +8,12 @@ using Aurora.Proto.Playback;
using Aurora.Proto.Sync;
using Aurora.Services.ClientService.Events;
using System.Collections.Generic;
+using Aurora.Services.Settings;
namespace Aurora.Services.ClientService
{
- public class ClientService : BaseService
+ public class ClientService : IClientService
{
private RemotePartyService.RemotePartyServiceClient _remotePartyClient;
private RemoteEventService.RemoteEventServiceClient _remoteEventsClient;
@@ -20,17 +21,19 @@ namespace Aurora.Services.ClientService
private RemoteSyncService.RemoteSyncServiceClient _remoteSyncClient;
private Channel _channel;
- CancellationTokenSource _eventCancellationTokenSource;
+ private CancellationTokenSource _eventCancellationTokenSource;
+ private ISettingsService _settingsService;
- public ClientService()
+ public ClientService(ISettingsService settingsService)
{
+ this._settingsService = settingsService;
}
- public MediaPausedEventHandler OnMediaPaused;
- public NewMediaPlayingEventHandler OnNewMediaPlaying;
- public PartyMemberJoinedEventHandler OnPartyMemberJoined;
- public PartyMemberLeftEventHandler OnPartyMemberLeft;
- public MediaResumedEventHandler OnMediaResumed;
+ public MediaPausedEventHandler OnMediaPaused { get; set; }
+ public NewMediaPlayingEventHandler OnNewMediaPlaying { get; set; }
+ public PartyMemberJoinedEventHandler OnPartyMemberJoined { get; set; }
+ public PartyMemberLeftEventHandler OnPartyMemberLeft { get; set; }
+ public MediaResumedEventHandler OnMediaResumed { get; set; }
public RemotePartyService.RemotePartyServiceClient RemotePartyClient
{
@@ -94,10 +97,10 @@ namespace Aurora.Services.ClientService
public async Task GetEvents()
{
_eventCancellationTokenSource = new CancellationTokenSource();
- string clientId = SettingsService.Instance.ClientId;
+ string clientId = this._settingsService.ClientId;
Console.WriteLine(string.Format("CLIENT {0} - GetEvents called from client with id", clientId));
using (AsyncServerStreamingCall eventStream = _remoteEventsClient
- .GetEvents(new EventsRequest { ClientId = SettingsService.Instance.ClientId }))
+ .GetEvents(new EventsRequest { ClientId = this._settingsService.ClientId }))
{
try
{
diff --git a/Aurora/Services/ClientService/IClientService.cs b/Aurora/Services/ClientService/IClientService.cs
new file mode 100644
index 0000000..ec116c1
--- /dev/null
+++ b/Aurora/Services/ClientService/IClientService.cs
@@ -0,0 +1,42 @@
+using Aurora.Services.ClientService.Events;
+using Aurora.Proto.Events;
+using Aurora.Proto.Party;
+using Aurora.Proto.Playback;
+using Aurora.Proto.Sync;
+using System.Threading.Tasks;
+
+namespace Aurora.Services.ClientService
+{
+ public interface IClientService
+ {
+ MediaPausedEventHandler OnMediaPaused { get; set; }
+ NewMediaPlayingEventHandler OnNewMediaPlaying { get; set; }
+ PartyMemberJoinedEventHandler OnPartyMemberJoined { get; set; }
+ PartyMemberLeftEventHandler OnPartyMemberLeft { get; set; }
+ MediaResumedEventHandler OnMediaResumed { get; set; }
+
+ RemotePartyService.RemotePartyServiceClient RemotePartyClient { get; }
+
+ RemoteEventService.RemoteEventServiceClient RemoteEventClient { get; }
+
+ RemotePlaybackService.RemotePlaybackServiceClient RemotePlaybackClient { get; }
+
+ RemoteSyncService.RemoteSyncServiceClient RemoteSyncClient { get; }
+
+ bool IsStarted { get; }
+
+ bool IsHost { get; set; }
+
+ void Start(string hostname, string port);
+
+ void Close();
+
+ ///
+ /// Asynchronous function for processing events off of the event stream.
+ ///
+ ///
+ Task GetEvents();
+
+ void StopEvents();
+ }
+}
\ No newline at end of file
diff --git a/Aurora/Services/Player/IPlayer.cs b/Aurora/Services/Player/IPlayer.cs
new file mode 100644
index 0000000..8fde035
--- /dev/null
+++ b/Aurora/Services/Player/IPlayer.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Threading.Tasks;
+using System.Threading;
+using Grpc.Core;
+using Aurora.Models.Media;
+using Aurora.Proto.Sync;
+using LibVLCSharp.Shared;
+
+namespace Aurora.Services.Player
+{
+
+ public interface IPlayer
+ {
+
+ ///
+ /// Event handler for changing playback states.
+ ///
+ event PlaybackStateChangedEventHandler PlaybackStateChanged;
+
+ event MediaChangedEventHandler MediaChanged;
+
+ ///
+ /// The state of playback
+ ///
+ ///
+ PlaybackState PlaybackState { get; }
+
+ bool IsLoaded { get; }
+
+ bool IsMediaLoaded(BaseMedia media);
+
+ BaseMedia CurrentMedia { get; }
+
+ float CurrentMediaPosition { get; }
+
+ long CurrentMediaLength { get; }
+
+ ///
+ /// Load media into the media player.
+ ///
+ /// Media to load
+ Task LoadMedia(BaseMedia media);
+
+ ///
+ /// Play currently loaded media.
+ ///
+ void Play();
+
+ ///
+ /// Pause currently loaded media.
+ ///
+ void Pause();
+
+ ///
+ /// Stop currently loaded media.
+ ///
+ void Stop();
+
+ void Enqueue(BaseMedia song);
+
+ void Dequeue(BaseMedia song);
+
+ }
+}
diff --git a/Aurora/Services/PlayerService/MediaChangedEvent.cs b/Aurora/Services/Player/MediaChangedEvent.cs
similarity index 92%
rename from Aurora/Services/PlayerService/MediaChangedEvent.cs
rename to Aurora/Services/Player/MediaChangedEvent.cs
index e78ce14..a598c9a 100644
--- a/Aurora/Services/PlayerService/MediaChangedEvent.cs
+++ b/Aurora/Services/Player/MediaChangedEvent.cs
@@ -1,7 +1,7 @@
using System;
using Aurora.Models.Media;
-namespace Aurora.Services.PlayerService
+namespace Aurora.Services.Player
{
public delegate void MediaChangedEventHandler(object source, MediaChangedEventArgs e);
diff --git a/Aurora/Services/Player/PlaybackState.cs b/Aurora/Services/Player/PlaybackState.cs
new file mode 100644
index 0000000..aed0ad7
--- /dev/null
+++ b/Aurora/Services/Player/PlaybackState.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Aurora.Services.Player
+{
+ public enum PlaybackState
+ {
+ Playing,
+ Stopped,
+ Buffering,
+
+ }
+}
diff --git a/Aurora/Services/PlayerService/PlaybackStateChangedEvent.cs b/Aurora/Services/Player/PlaybackStateChangedEvent.cs
similarity index 92%
rename from Aurora/Services/PlayerService/PlaybackStateChangedEvent.cs
rename to Aurora/Services/Player/PlaybackStateChangedEvent.cs
index 2decee4..a07cf7a 100644
--- a/Aurora/Services/PlayerService/PlaybackStateChangedEvent.cs
+++ b/Aurora/Services/Player/PlaybackStateChangedEvent.cs
@@ -1,7 +1,7 @@
using System;
using Aurora.Models.Media;
-namespace Aurora.Services.PlayerService
+namespace Aurora.Services.Player
{
public delegate void PlaybackStateChangedEventHandler(object source, PlaybackStateChangedEventArgs e);
diff --git a/Aurora/Services/PlayerService/PlayerService.cs b/Aurora/Services/Player/PlayerService.cs
similarity index 98%
rename from Aurora/Services/PlayerService/PlayerService.cs
rename to Aurora/Services/Player/PlayerService.cs
index 9c18a46..bf85e4e 100644
--- a/Aurora/Services/PlayerService/PlayerService.cs
+++ b/Aurora/Services/Player/PlayerService.cs
@@ -6,10 +6,10 @@ using Aurora.Models.Media;
using Aurora.Proto.Sync;
using LibVLCSharp.Shared;
-namespace Aurora.Services.PlayerService
+namespace Aurora.Services.Player
{
- public class PlayerService : BaseService
+ public class PlayerService : BaseService, IPlayer
{
private const long _ticksPerMillisecond = 10000;
private BaseMedia _currentMedia;
diff --git a/Aurora/Services/PlayerService/PlaybackState.cs b/Aurora/Services/PlayerService/PlaybackState.cs
deleted file mode 100644
index 37c6773..0000000
--- a/Aurora/Services/PlayerService/PlaybackState.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System;
-
-public enum PlaybackState
-{
- Playing,
- Stopped,
- Buffering,
-
-}
\ No newline at end of file
diff --git a/Aurora/Services/Server/Controllers/Constructor.cs b/Aurora/Services/Server/Controllers/Constructor.cs
new file mode 100644
index 0000000..5bdb63c
--- /dev/null
+++ b/Aurora/Services/Server/Controllers/Constructor.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Aurora.Proto.PartyV2;
+
+namespace Aurora.Services.Server.Controllers
+{
+ public partial class RemotePartyController : RemotePartyService.RemotePartyServiceBase
+ {
+ ///
+ /// Constructor for partial class
+ ///
+ public RemotePartyController(string partyName, string description)
+ {
+ this._startDateTime = DateTime.UtcNow;
+ this._displayName = partyName;
+ this._description = description;
+ this._memberList = new SortedList();
+ this._mediaList = new SortedList();
+
+ string userName = "testUser";
+
+ this._eventManager = new EventManager.EventManager();
+
+ this._hostMember = new Member()
+ {
+ Name = GetNewMemberResourceName(_partyResourceName, ServerService.GetLocalIPAddress(), userName),
+ UserName = userName,
+ IpAddress = ServerService.GetLocalIPAddress(),
+ };
+
+ this._memberList.Add(_hostMember.Name, _hostMember);
+
+ //Add media from library
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Aurora/Services/Server/Controllers/MediaController.cs b/Aurora/Services/Server/Controllers/MediaController.cs
index 7af204e..cb35f5b 100644
--- a/Aurora/Services/Server/Controllers/MediaController.cs
+++ b/Aurora/Services/Server/Controllers/MediaController.cs
@@ -1,29 +1,158 @@
using System;
using System.Threading.Tasks;
+using System.Collections.Generic;
using Aurora.Proto.PartyV2;
+using Aurora.Models.Media;
+using Aurora.Proto.General;
+using Aurora.Services.Player;
+using Autofac;
namespace Aurora.Services.Server.Controllers
{
public partial class RemotePartyController : RemotePartyService.RemotePartyServiceBase
{
+ private SortedList _mediaList;
+
public override Task ListMedia(ListMediaRequest request, Grpc.Core.ServerCallContext context)
{
- throw new NotImplementedException();
+ ListMediaResponse resp = new ListMediaResponse();
+
+ int startIdx = 0;
+ if (!string.IsNullOrEmpty(request.PageToken))
+ {
+ startIdx = _memberList.IndexOfKey(request.PageToken) + 1;
+ }
+
+ int pageSize = request.PageSize;
+
+ if (pageSize > _mediaList.Count)
+ {
+ pageSize = _mediaList.Count;
+ }
+
+ //Gather page
+ List baseMedia = new List(_mediaList.Values);
+ foreach (BaseMedia media in baseMedia)
+ {
+ if (media.Metadata is AudioMetadata)
+ {
+ AudioMetadata meta = media.Metadata as AudioMetadata;
+ resp.Media.Add(new Media()
+ {
+ Name = media.Id,
+ Title = meta.Title,
+ Album = meta.Album,
+ Artist = meta.Artist,
+ Duration = meta.Duration
+ });
+ }
+ }
+
+ resp.NextPageToken = resp.Media[resp.Media.Count - 1].Name;
+ return Task.FromResult(resp);
}
- public override Task GetMedia(GetMediaRequest request, Grpc.Core.ServerCallContext context)
+ public override Task GetMedia(GetMediaRequest request, Grpc.Core.ServerCallContext context)
+ {
+ _mediaList.TryGetValue(request.Name, out BaseMedia baseMedia);
+
+ if (baseMedia == null)
+ {
+ throw new KeyNotFoundException();
+ }
+
+ Media media = new Media();
+ if (baseMedia.Metadata != null && baseMedia.Metadata is AudioMetadata)
+ {
+ AudioMetadata metadata = baseMedia.Metadata as AudioMetadata;
+ media.Name = baseMedia.Id;
+ media.Title = metadata.Title;
+ media.Artist = metadata.Artist;
+ media.Album = metadata.Album;
+ }
+
+ return Task.FromResult(media);
+ }
+
+ public override Task CreateMedia(CreateMediaRequest request, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
}
- public override Task StreamMedia(StreamMediaRequest request, Grpc.Core.IServerStreamWriter responseStream, Grpc.Core.ServerCallContext context)
+ public override Task DeleteMedia(DeleteMediaRequest request, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
}
- public override Task SyncMedia(SyncMediaRequest request, Grpc.Core.IServerStreamWriter responseStream, Grpc.Core.ServerCallContext context)
+ public override async Task StreamMedia(StreamMediaRequest request, Grpc.Core.IServerStreamWriter responseStream, Grpc.Core.ServerCallContext context)
{
- throw new NotImplementedException();
+ BaseMedia originalSong = LibraryService.Instance.GetSong(request.Name);
+ if (!(originalSong is LocalAudio))
+ {
+ return;
+ }
+
+ //Copy media object to not interfere with other threads
+ LocalAudio songCopy = new LocalAudio((LocalAudio)originalSong);
+
+ try
+ {
+ //Load only if not already loaded. (Multiple clients may be requesting media)
+ if (!songCopy.IsLoaded)
+ {
+ await songCopy.Load();
+ }
+
+ //Send stream
+ Console.WriteLine("Begin sending file");
+ byte[] buffer = new byte[2048]; // read in chunks of 2KB
+ int bytesRead;
+ while ((bytesRead = songCopy.DataStream.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ Google.Protobuf.ByteString bufferByteString = Google.Protobuf.ByteString.CopyFrom(buffer);
+ await responseStream.WriteAsync(new Chunk { Content = bufferByteString });
+ }
+ Console.WriteLine("Done sending file");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Exception caught while sending audio file: " + ex.Message);
+ }
+ }
+
+ public override async Task SyncMedia(SyncMediaRequest request, Grpc.Core.IServerStreamWriter responseStream, Grpc.Core.ServerCallContext context)
+ {
+ bool continueSync = true;
+ using (var scope = App.Container.BeginLifetimeScope())
+ {
+ IPlayer player = scope.Resolve();
+
+ string currentId = player.CurrentMedia.Id;
+ MediaChangedEventHandler mediaChanged = (sender, e) =>
+ {
+ if (e.NewId != currentId)
+ {
+ continueSync = false;
+ }
+ };
+
+ player.MediaChanged += mediaChanged;
+
+ while (continueSync)
+ {
+ float length = player.CurrentMediaLength;
+
+ Sync sync = new Sync()
+ {
+ TrackPosition = player.CurrentMediaPosition,
+ ServerTimeTicks = Utils.TimeUtils.GetNetworkTime().DateTime.Ticks
+ };
+ await responseStream.WriteAsync(sync);
+ Console.WriteLine("Sent Sync");
+ await Task.Delay(5000);
+ }
+ }
+
}
}
}
\ No newline at end of file
diff --git a/Aurora/Services/Server/Controllers/MemberController.cs b/Aurora/Services/Server/Controllers/MemberController.cs
index 2dbc70c..02b4a65 100644
--- a/Aurora/Services/Server/Controllers/MemberController.cs
+++ b/Aurora/Services/Server/Controllers/MemberController.cs
@@ -25,19 +25,21 @@ namespace Aurora.Services.Server.Controllers
startIdx = _memberList.IndexOfKey(request.PageToken) + 1;
}
+ int pageSize = request.PageSize;
+
//Assign pageSize
- if (request.PageSize > _memberList.Count)
+ if (pageSize > _memberList.Count)
{
- request.PageSize = _memberList.Count;
+ pageSize = _memberList.Count;
}
//Gather page
List members = new List(_memberList.Values);
- resp.Members.AddRange(members.GetRange(startIdx, request.PageSize));
+ resp.Members.AddRange(members.GetRange(startIdx, pageSize));
//Set next page token
- resp.NextPageToken = resp.Members[(startIdx + request.PageSize) - 1].Name;
+ resp.NextPageToken = resp.Members[resp.Members.Count - 1].Name;
return Task.FromResult(resp);
}
diff --git a/Aurora/Services/Server/Controllers/PartyController.cs b/Aurora/Services/Server/Controllers/PartyController.cs
index 1ee14ea..d8ad019 100644
--- a/Aurora/Services/Server/Controllers/PartyController.cs
+++ b/Aurora/Services/Server/Controllers/PartyController.cs
@@ -17,30 +17,6 @@ namespace Aurora.Services.Server.Controllers
private EventManager.EventManager _eventManager;
- ///
- /// Constructor for partial class
- ///
- public RemotePartyController(string partyName, string description)
- {
- this._startDateTime = DateTime.UtcNow;
- this._displayName = partyName;
- this._description = description;
- this._memberList = new SortedList();
-
- string userName = "testUser";
-
- this._eventManager = new EventManager.EventManager();
-
- this._hostMember = new Member()
- {
- Name = GetNewMemberResourceName(_partyResourceName, ServerService.GetLocalIPAddress(), userName),
- UserName = userName,
- IpAddress = ServerService.GetLocalIPAddress(),
- };
-
- this._memberList.Add(_hostMember.Name, _hostMember);
- }
-
public override Task GetParty(Proto.General.Empty request, Grpc.Core.ServerCallContext context)
{
Party party = new Party()
diff --git a/Aurora/Services/ServerService.cs b/Aurora/Services/ServerService.cs
index 3205ea1..8d2c0ac 100644
--- a/Aurora/Services/ServerService.cs
+++ b/Aurora/Services/ServerService.cs
@@ -8,13 +8,14 @@ using Aurora.Proto.Events;
using Aurora.Proto.Party;
using Aurora.Proto.Playback;
using Aurora.Proto.Sync;
-
+using Aurora.Services.Settings;
+using Autofac;
namespace Aurora.Services
{
public class ServerService : BaseService
{
- private int _port = SettingsService.Instance.DefaultPort;
+ private int _port;
private string _hostname;
private Grpc.Core.Server _server;
@@ -30,6 +31,11 @@ namespace Aurora.Services
public ServerService()
{
string host = GetLocalIPAddress();
+ using (var scope = App.Container.BeginLifetimeScope())
+ {
+ var service = scope.Resolve();
+ this._port = service.DefaultPort;
+ }
if (string.IsNullOrWhiteSpace(host))
{
diff --git a/Aurora/Services/Settings/ISettingsService.cs b/Aurora/Services/Settings/ISettingsService.cs
new file mode 100644
index 0000000..ddb0816
--- /dev/null
+++ b/Aurora/Services/Settings/ISettingsService.cs
@@ -0,0 +1,27 @@
+using Plugin.Settings.Abstractions;
+
+namespace Aurora.Services.Settings
+{
+ public interface ISettingsService
+ {
+ ISettings AppSettings { get; set; }
+
+ ///
+ /// The user's username. This is persisted.
+ ///
+ ///
+ string Username { get; set; }
+
+ ///
+ /// The default port to use. This is persisted.
+ ///
+ ///
+ int DefaultPort { get; set; }
+
+ ///
+ /// The current sessions clientId. This is assigned by the server. This is not persisted.
+ ///
+ ///
+ string ClientId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Aurora/Services/SettingsService.cs b/Aurora/Services/Settings/SettingsService.cs
similarity index 95%
rename from Aurora/Services/SettingsService.cs
rename to Aurora/Services/Settings/SettingsService.cs
index ae8c768..485f63c 100644
--- a/Aurora/Services/SettingsService.cs
+++ b/Aurora/Services/Settings/SettingsService.cs
@@ -3,9 +3,9 @@ using System.Threading;
using Plugin.Settings;
using Plugin.Settings.Abstractions;
-namespace Aurora.Services
+namespace Aurora.Services.Settings
{
- public class SettingsService : BaseService
+ public class SettingsService : ISettingsService
{
private Lazy _appSettings;
private string _usernameKey = "username";