Adding dependency injection
This commit is contained in:
parent
f8ad2f459e
commit
48d0ffa77d
@ -150,7 +150,7 @@
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces">
|
||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Linq.Async">
|
||||
<HintPath>..\packages\System.Linq.Async.4.0.0\lib\net461\System.Linq.Async.dll</HintPath>
|
||||
@ -164,6 +164,10 @@
|
||||
<Reference Include="CarouselView.FormsPlugin.Abstractions">
|
||||
<HintPath>..\packages\CarouselView.FormsPlugin.5.2.0\lib\netstandard2.0\CarouselView.FormsPlugin.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Autofac">
|
||||
<HintPath>..\packages\Autofac.5.0.0\lib\net461\Autofac.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="gtk-gui\gui.stetic">
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Autofac" version="5.0.0" targetFramework="net47" />
|
||||
<package id="CarouselView.FormsPlugin" version="5.2.0" targetFramework="net47" />
|
||||
<package id="DLToolkit.Forms.Controls.FlowListView" version="2.0.11" targetFramework="net47" />
|
||||
<package id="Google.Protobuf" version="3.10.1" targetFramework="net47" />
|
||||
@ -13,7 +14,7 @@
|
||||
<package id="LibVLCSharp.GTK" version="3.3.1" targetFramework="net47" />
|
||||
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net47" />
|
||||
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net47" />
|
||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.0.0" targetFramework="net47" />
|
||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.0" targetFramework="net47" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net47" />
|
||||
<package id="OpenTK" version="3.1.0" targetFramework="net47" />
|
||||
<package id="OpenTK.GLControl" version="3.0.1" targetFramework="net47" />
|
||||
|
@ -13,6 +13,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Grpc" Version="2.26.0" />
|
||||
<PackageReference Include="Autofac" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Remove="..\Aurora\Proto\general.proto" />
|
||||
|
29
Aurora.test/ControllerTests/MediaControllerTest.cs
Normal file
29
Aurora.test/ControllerTests/MediaControllerTest.cs
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<IPlayer>(new PlayerService()).SingleInstance();
|
||||
_builder.RegisterType<PlayerService>().As<IPlayer>().SingleInstance();
|
||||
_builder.RegisterType<SettingsService>().As<ISettingsService>().SingleInstance();
|
||||
_builder.RegisterType<ClientService>().As<IClientService>().SingleInstance();
|
||||
_builder.RegisterType<MainView>().SingleInstance();
|
||||
_builder.RegisterType<AlbumsViewModel>();
|
||||
_builder.RegisterType<ArtistsViewModel>();
|
||||
_builder.RegisterType<PartyViewModel>();
|
||||
_builder.RegisterType<ProfileViewModel>();
|
||||
_builder.RegisterType<SongsViewModel>();
|
||||
_builder.RegisterType<StationsViewModel>();
|
||||
|
||||
// _builder.RegisterInstance<ISettingsService>(new SettingsService()).SingleInstance();
|
||||
_container = _builder.Build();
|
||||
|
||||
MainPage = _container.Resolve<MainView>();
|
||||
}
|
||||
|
||||
public static IContainer Container
|
||||
{
|
||||
get { return _container; }
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
|
@ -23,6 +23,7 @@
|
||||
<PackageReference Include="Sharpnado.Forms.HorizontalListView" Version="1.3.0" />
|
||||
<PackageReference Include="DLToolkit.Forms.Controls.FlowListView" Version="2.0.11" />
|
||||
<PackageReference Include="CarouselView.FormsPlugin" Version="5.2.0" />
|
||||
<PackageReference Include="Autofac" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Design\" />
|
||||
|
@ -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<int, BaseViewModel> _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);
|
||||
}
|
||||
|
||||
|
@ -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<PartyMember> _members;
|
||||
private ObservableCollection<BaseMedia> _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<PartyMember>();
|
||||
_queue = new ObservableCollection<BaseMedia>();
|
||||
|
||||
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()
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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<Sync> 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<IPlayer>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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<ClientService>
|
||||
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<BaseEvent> eventStream = _remoteEventsClient
|
||||
.GetEvents(new EventsRequest { ClientId = SettingsService.Instance.ClientId }))
|
||||
.GetEvents(new EventsRequest { ClientId = this._settingsService.ClientId }))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
42
Aurora/Services/ClientService/IClientService.cs
Normal file
42
Aurora/Services/ClientService/IClientService.cs
Normal file
@ -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();
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronous function for processing events off of the event stream.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task GetEvents();
|
||||
|
||||
void StopEvents();
|
||||
}
|
||||
}
|
64
Aurora/Services/Player/IPlayer.cs
Normal file
64
Aurora/Services/Player/IPlayer.cs
Normal file
@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Event handler for changing playback states.
|
||||
/// </summary>
|
||||
event PlaybackStateChangedEventHandler PlaybackStateChanged;
|
||||
|
||||
event MediaChangedEventHandler MediaChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The state of playback
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
PlaybackState PlaybackState { get; }
|
||||
|
||||
bool IsLoaded { get; }
|
||||
|
||||
bool IsMediaLoaded(BaseMedia media);
|
||||
|
||||
BaseMedia CurrentMedia { get; }
|
||||
|
||||
float CurrentMediaPosition { get; }
|
||||
|
||||
long CurrentMediaLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Load media into the media player.
|
||||
/// </summary>
|
||||
/// <param name="media">Media to load</param>
|
||||
Task LoadMedia(BaseMedia media);
|
||||
|
||||
/// <summary>
|
||||
/// Play currently loaded media.
|
||||
/// </summary>
|
||||
void Play();
|
||||
|
||||
/// <summary>
|
||||
/// Pause currently loaded media.
|
||||
/// </summary>
|
||||
void Pause();
|
||||
|
||||
/// <summary>
|
||||
/// Stop currently loaded media.
|
||||
/// </summary>
|
||||
void Stop();
|
||||
|
||||
void Enqueue(BaseMedia song);
|
||||
|
||||
void Dequeue(BaseMedia song);
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
12
Aurora/Services/Player/PlaybackState.cs
Normal file
12
Aurora/Services/Player/PlaybackState.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace Aurora.Services.Player
|
||||
{
|
||||
public enum PlaybackState
|
||||
{
|
||||
Playing,
|
||||
Stopped,
|
||||
Buffering,
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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<PlayerService>
|
||||
public class PlayerService : BaseService<PlayerService>, IPlayer
|
||||
{
|
||||
private const long _ticksPerMillisecond = 10000;
|
||||
private BaseMedia _currentMedia;
|
@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
public enum PlaybackState
|
||||
{
|
||||
Playing,
|
||||
Stopped,
|
||||
Buffering,
|
||||
|
||||
}
|
38
Aurora/Services/Server/Controllers/Constructor.cs
Normal file
38
Aurora/Services/Server/Controllers/Constructor.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor for partial class
|
||||
/// </summary>
|
||||
public RemotePartyController(string partyName, string description)
|
||||
{
|
||||
this._startDateTime = DateTime.UtcNow;
|
||||
this._displayName = partyName;
|
||||
this._description = description;
|
||||
this._memberList = new SortedList<string, Member>();
|
||||
this._mediaList = new SortedList<string, Models.Media.BaseMedia>();
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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<string, BaseMedia> _mediaList;
|
||||
|
||||
public override Task<ListMediaResponse> 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> baseMedia = new List<BaseMedia>(_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<RemoteMedia> GetMedia(GetMediaRequest request, Grpc.Core.ServerCallContext context)
|
||||
public override Task<Media> 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<Media> CreateMedia(CreateMediaRequest request, Grpc.Core.ServerCallContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Task StreamMedia(StreamMediaRequest request, Grpc.Core.IServerStreamWriter<Proto.General.Chunk> responseStream, Grpc.Core.ServerCallContext context)
|
||||
public override Task<Empty> DeleteMedia(DeleteMediaRequest request, Grpc.Core.ServerCallContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Task SyncMedia(SyncMediaRequest request, Grpc.Core.IServerStreamWriter<Sync> responseStream, Grpc.Core.ServerCallContext context)
|
||||
public override async Task StreamMedia(StreamMediaRequest request, Grpc.Core.IServerStreamWriter<Proto.General.Chunk> 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<Sync> responseStream, Grpc.Core.ServerCallContext context)
|
||||
{
|
||||
bool continueSync = true;
|
||||
using (var scope = App.Container.BeginLifetimeScope())
|
||||
{
|
||||
IPlayer player = scope.Resolve<IPlayer>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Member> members = new List<Member>(_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);
|
||||
}
|
||||
|
@ -17,30 +17,6 @@ namespace Aurora.Services.Server.Controllers
|
||||
|
||||
private EventManager.EventManager _eventManager;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for partial class
|
||||
/// </summary>
|
||||
public RemotePartyController(string partyName, string description)
|
||||
{
|
||||
this._startDateTime = DateTime.UtcNow;
|
||||
this._displayName = partyName;
|
||||
this._description = description;
|
||||
this._memberList = new SortedList<string, Member>();
|
||||
|
||||
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<Party> GetParty(Proto.General.Empty request, Grpc.Core.ServerCallContext context)
|
||||
{
|
||||
Party party = new Party()
|
||||
|
@ -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<ServerService>
|
||||
{
|
||||
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<ISettingsService>();
|
||||
this._port = service.DefaultPort;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(host))
|
||||
{
|
||||
|
27
Aurora/Services/Settings/ISettingsService.cs
Normal file
27
Aurora/Services/Settings/ISettingsService.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using Plugin.Settings.Abstractions;
|
||||
|
||||
namespace Aurora.Services.Settings
|
||||
{
|
||||
public interface ISettingsService
|
||||
{
|
||||
ISettings AppSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's username. This is persisted.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default port to use. This is persisted.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
int DefaultPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current sessions clientId. This is assigned by the server. This is not persisted.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
string ClientId { get; set; }
|
||||
}
|
||||
}
|
@ -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<SettingsService>
|
||||
public class SettingsService : ISettingsService
|
||||
{
|
||||
private Lazy<ISettings> _appSettings;
|
||||
private string _usernameKey = "username";
|
Loading…
Reference in New Issue
Block a user