Remote playback almost working

This commit is contained in:
watsonb8 2019-11-03 23:17:34 -05:00
parent a13e491a7e
commit a537edd657
14 changed files with 296 additions and 136 deletions

View File

@ -1,54 +1,100 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project
Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<ProduceAssemblyReference>true</ProduceAssemblyReference> <ProduceAssemblyReference>true</ProduceAssemblyReference>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup
Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Xamarin.Forms" Version="3.6.0.264807" /> <PackageReference
<PackageReference Include="Xamarin.Essentials" Version="1.0.1" /> Include="Xamarin.Forms"
<PackageReference Include="Xamarin.Forms.DataGrid" Version="3.1.0" /> Version="3.6.0.264807"/>
<PackageReference Include="taglib-sharp-netstandard2.0" Version="2.1.0" /> <PackageReference
<PackageReference Include="LibVLCSharp.Forms" Version="3.0.0" /> Include="Xamarin.Essentials"
<PackageReference Include="VideoLAN.LibVLC.Mac" Version="3.1.3" /> Version="1.0.1"/>
<PackageReference Include="Grpc" Version="1.21.0" /> <PackageReference
<PackageReference Include="Grpc.Tools" Version="1.21.0" PrivateAssests="All" /> Include="Xamarin.Forms.DataGrid"
<PackageReference Include="Google.Protobuf" Version="3.8.0" /> Version="3.1.0"/>
<PackageReference Include="Xam.Plugins.Settings" Version="3.1.1" /> <PackageReference
<PackageReference Include="Sharpnado.Forms.HorizontalListView" Version="1.2.0" /> Include="taglib-sharp-netstandard2.0"
Version="2.1.0"/>
<PackageReference
Include="LibVLCSharp.Forms"
Version="3.0.0"/>
<PackageReference
Include="VideoLAN.LibVLC.Mac"
Version="3.1.3"/>
<PackageReference
Include="Grpc"
Version="1.21.0"/>
<PackageReference
Include="Grpc.Tools"
Version="1.21.0"
PrivateAssests="All"/>
<PackageReference
Include="Google.Protobuf"
Version="3.8.0"/>
<PackageReference
Include="Xam.Plugins.Settings"
Version="3.1.1"/>
<PackageReference
Include="Sharpnado.Forms.HorizontalListView"
Version="1.2.0"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Design\" /> <Folder
<Folder Include="Design\Components\" /> Include="Design\"/>
<Folder Include="Design\Views\" /> <Folder
<Folder Include="Design\Views\Songs\" /> Include="Design\Components\"/>
<Folder Include="Design\Views\MainView\" /> <Folder
<Folder Include="Design\Behaviors\" /> Include="Design\Views\"/>
<Folder Include="Design\Components\NavigationMenu\" /> <Folder
<Folder Include="Design\Views\Albums\" /> Include="Design\Views\Songs\"/>
<Folder Include="Design\Views\Artists\" /> <Folder
<Folder Include="Design\Views\Stations\" /> Include="Design\Views\MainView\"/>
<Folder Include="Utils\" /> <Folder
<Folder Include="Models\" /> Include="Design\Behaviors\"/>
<Folder Include="Services\" /> <Folder
<Folder Include="Design\Views\Party\" /> Include="Design\Components\NavigationMenu\"/>
<Folder Include="Design\Components\HostSelector\" /> <Folder
<Folder Include="Design\Components\MemberList\" /> Include="Design\Views\Albums\"/>
<Folder Include="Design\Components\Queue\" /> <Folder
<Folder Include="Design\Views\Profile\" /> Include="Design\Views\Artists\"/>
<Folder
Include="Design\Views\Stations\"/>
<Folder
Include="Utils\"/>
<Folder
Include="Models\"/>
<Folder
Include="Services\"/>
<Folder
Include="Design\Views\Party\"/>
<Folder
Include="Design\Components\HostSelector\"/>
<Folder
Include="Design\Components\MemberList\"/>
<Folder
Include="Design\Components\Queue\"/>
<Folder
Include="Design\Views\Profile\"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Design\Components\MusicPlayer\Player.xaml.cs"> <Compile
Update="Design\Components\MusicPlayer\Player.xaml.cs">
<DependentUpon>Player.xaml</DependentUpon> <DependentUpon>Player.xaml</DependentUpon>
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Protobuf Include="Proto\general.proto" /> <Protobuf
<Protobuf Include="Proto\party.proto" /> Include="Proto\general.proto"/>
<Protobuf Include="Proto\playback.proto" /> <Protobuf
<Protobuf Include="Proto\events.proto" /> Include="Proto\party.proto"/>
<Protobuf
Include="Proto\events.proto"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -12,6 +12,10 @@
HeaderHeight="40" HeaderHeight="40"
BorderColor="#CCCCCC" BorderColor="#CCCCCC"
HeaderBackground="#E0E6F8"> HeaderBackground="#E0E6F8">
<dg:DataGrid.GestureRecognizers>
<TapGestureRecognizer
NumberOfTapsRequired="2"/>
</dg:DataGrid.GestureRecognizers>
<dg:DataGrid.HeaderFontSize> <dg:DataGrid.HeaderFontSize>
<OnIdiom <OnIdiom
x:TypeArguments="x:Double"> x:TypeArguments="x:Double">

View File

@ -12,6 +12,10 @@ namespace Aurora.Design.Components.Queue
public Queue() public Queue()
{ {
InitializeComponent(); InitializeComponent();
this.QueueDataGrid.ItemSelected += (sender, e) =>
{
this.SelectedItem = e.SelectedItem;
};
} }
#region ItemsSource Property #region ItemsSource Property
@ -69,8 +73,7 @@ namespace Aurora.Design.Components.Queue
BindableProperty.Create(propertyName: "SelectedItem", BindableProperty.Create(propertyName: "SelectedItem",
returnType: typeof(object), returnType: typeof(object),
declaringType: typeof(Queue), declaringType: typeof(Queue),
defaultBindingMode: BindingMode.TwoWay, defaultBindingMode: BindingMode.TwoWay);
propertyChanged: OnSelectedItemChanged);
/// <summary> /// <summary>
/// Backing property for the SelectedItem property. /// Backing property for the SelectedItem property.
@ -88,22 +91,58 @@ namespace Aurora.Design.Components.Queue
} }
} }
/// <summary> /// <summary>
/// Handles selection change events. /// Bindable property for the item double clicked command
/// </summary> /// </summary>
/// <param name="bindable">The bindable object.</param> /// <param name=""SelectedItem""></param>
/// <param name="typeof(BaseMetadata"></param>
/// <returns></returns>
public static readonly BindableProperty ItemDoubleClickedProperty =
BindableProperty.Create(propertyName: "ItemDoubleClicked",
returnType: typeof(Command),
declaringType: typeof(Queue),
propertyChanged: OnDoubleClickPropertyChanged);
/// <summary>
/// Public backing property
/// </summary>
/// <value></value>
public Command ItemDoubleClicked
{
get
{
return (Command)GetValue(ItemDoubleClickedProperty);
}
set
{
SetValue(ItemDoubleClickedProperty, value);
}
}
/// <summary>
/// Event handler for double click property. Adds command execute handler.
/// </summary>
/// <param name="bindable"></param>
/// <param name="newValue"></param> /// <param name="newValue"></param>
/// <param name="oldValue"></param> /// <param name="oldValue"></param>
private static void OnSelectedItemChanged(BindableObject bindable, object newValue, object oldValue) private static void OnDoubleClickPropertyChanged(BindableObject bindable, object newValue, object oldValue)
{ {
Queue control = bindable as Queue; Queue control = bindable as Queue;
var queueDataGrid = control.FindByName("QueueDataGrid") as DataGrid; var queueDataGrid = control.FindByName("QueueDataGrid") as DataGrid;
IEnumerable<object> source = (IEnumerable<object>)queueDataGrid.ItemsSource; if (queueDataGrid.GestureRecognizers.Count > 0)
if (source.Contains(newValue))
{ {
queueDataGrid.SelectedItem = newValue; var gestureRecognizer = queueDataGrid.GestureRecognizers.First();
}
if (gestureRecognizer is TapGestureRecognizer)
{
TapGestureRecognizer tap = gestureRecognizer as TapGestureRecognizer;
tap.Tapped += (sender, e) =>
{
control.ItemDoubleClicked.Execute(null);
};
}
}
} }
} }
} }

View File

@ -24,7 +24,9 @@
<Label <Label
Text="Queue"/> Text="Queue"/>
<qu:Queue <qu:Queue
ItemsSource="{Binding Queue}"/> ItemsSource="{Binding Queue}"
SelectedItem="{Binding SelectedSong}"
ItemDoubleClicked="{Binding PlayCommand}"/>
</StackLayout> </StackLayout>
<hs:HostSelector <hs:HostSelector
Grid.Row="0" Grid.Row="0"

View File

@ -8,6 +8,7 @@ using Aurora.Proto.General;
using Aurora.Proto.Party; using Aurora.Proto.Party;
using Aurora.Proto.Events; using Aurora.Proto.Events;
using Aurora.Services.ClientService; using Aurora.Services.ClientService;
using Aurora.Services.PlayerService;
using Aurora.Models.Media; using Aurora.Models.Media;
namespace Aurora.Design.Views.Party namespace Aurora.Design.Views.Party
@ -24,8 +25,8 @@ namespace Aurora.Design.Views.Party
private PartyState _state; private PartyState _state;
private string _hostname; private string _hostname;
private ObservableCollection<PartyMember> _members; private ObservableCollection<PartyMember> _members;
private ObservableCollection<BaseMedia> _queue;
private ObservableCollection<RemoteMediaData> _queue; private BaseMedia _selectedSong;
public PartyViewModel() public PartyViewModel()
{ {
@ -33,10 +34,12 @@ namespace Aurora.Design.Views.Party
this.HostCommand = new Command(OnHostExecute, CanHostExecute); this.HostCommand = new Command(OnHostExecute, CanHostExecute);
_members = new ObservableCollection<PartyMember>(); _members = new ObservableCollection<PartyMember>();
_queue = new ObservableCollection<RemoteMediaData>(); _queue = new ObservableCollection<BaseMedia>();
SetState(PartyState.SelectingHost); SetState(PartyState.SelectingHost);
PlayCommand = new Command(PlayExecute);
//Hook up event handler //Hook up event handler
ClientService.Instance.EventReceived += this.OnEventReceived; ClientService.Instance.EventReceived += this.OnEventReceived;
} }
@ -70,7 +73,7 @@ namespace Aurora.Design.Views.Party
get { return _state != PartyState.SelectingHost; } get { return _state != PartyState.SelectingHost; }
} }
public ObservableCollection<RemoteMediaData> Queue public ObservableCollection<BaseMedia> Queue
{ {
get get
{ {
@ -94,6 +97,14 @@ namespace Aurora.Design.Views.Party
set { SetProperty(ref _hostname, value); } set { SetProperty(ref _hostname, value); }
} }
public BaseMedia SelectedSong
{
get { return _selectedSong; }
set { SetProperty(ref _selectedSong, value); }
}
public Command PlayCommand { get; private set; }
#endregion Properties #endregion Properties
#region Events #region Events
@ -209,9 +220,21 @@ namespace Aurora.Design.Views.Party
QueueResponse queueResponse = ClientService.Instance.RemotePartyClient.GetQueue(new Empty()); QueueResponse queueResponse = ClientService.Instance.RemotePartyClient.GetQueue(new Empty());
Queue.Clear(); Queue.Clear();
//Convert received data to remote audio models
foreach (RemoteMediaData data in queueResponse.MediaList) foreach (RemoteMediaData data in queueResponse.MediaList)
{ {
Queue.Add(data); //Assign received metadata (since this can't be aquired from a file)
AudioMetadata meta = new AudioMetadata();
meta.Title = data.Title;
meta.Album = data.Album;
meta.Artist = data.Artist;
meta.Duration = data.Duration;
RemoteAudio remote = new RemoteAudio(data.Id,
meta,
ClientService.Instance.RemotePartyClient);
Queue.Add(remote);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -245,6 +268,11 @@ namespace Aurora.Design.Views.Party
Members.Add(member); Members.Add(member);
} }
public void PlayExecute()
{
PlayerService.Instance.LoadMedia(_selectedSong);
PlayerService.Instance.Play();
}
#endregion Private Methods #endregion Private Methods
} }
} }

View File

@ -15,7 +15,7 @@ namespace Aurora.Models.Media
} }
#region Properties #region Properties
public string Id { get; private set; } public string Id { get; protected set; }
#endregion Properties #endregion Properties

View File

@ -0,0 +1,83 @@
using System;
using System.IO;
using System.Threading;
using Aurora.Proto.Party;
using Aurora.Proto.General;
namespace Aurora.Models.Media
{
public class RemoteAudio : BaseMedia
{
private RemotePartyService.RemotePartyServiceClient _client;
private CancellationTokenSource _cancellationTokenSource;
#region Constructor
public RemoteAudio(string id, RemotePartyService.RemotePartyServiceClient client)
{
this.Id = id;
this._client = client;
_cancellationTokenSource = new CancellationTokenSource();
}
public RemoteAudio(string id, AudioMetadata metadata, RemotePartyService.RemotePartyServiceClient client)
{
this.Id = id;
this._client = client;
this.Metadata = metadata;
_cancellationTokenSource = new CancellationTokenSource();
}
#endregion Constructor
#region Properties
public override BaseMetadata Metadata { get; protected set; }
public override MediaTypeEnum MediaType
{
get { return MediaTypeEnum.Audio; }
}
#endregion Properties
/// <summary>
/// Override load method.
/// </summary>
public override async void Load()
{
this.DataStream = new MemoryStream();
using (var call = _client.GetSongStream(new SongRequest() { Id = this.Id }))
{
while (await call.ResponseStream.MoveNext(_cancellationTokenSource.Token))
{
Chunk chunk = call.ResponseStream.Current;
byte[] buffer = chunk.Content.ToByteArray();
await this.DataStream.WriteAsync(buffer, 0, buffer.Length, _cancellationTokenSource.Token);
Console.WriteLine(string.Format("Wrote byte chunk of size {0} to output stream", buffer.Length));
}
Console.WriteLine("Done receiving stream");
}
base.Load();
}
/// <summary>
/// Override unload method
/// </summary>
public override void Unload()
{
if (!_cancellationTokenSource.IsCancellationRequested)
{
_cancellationTokenSource.Cancel();
//Wait for cancellation
WaitHandle.WaitAny(new[] { _cancellationTokenSource.Token.WaitHandle });
}
base.Unload();
}
}
}

View File

@ -10,6 +10,7 @@ service RemotePartyService {
rpc LeaveParty(LeavePartyRequest) returns (LeavePartyResponse); rpc LeaveParty(LeavePartyRequest) returns (LeavePartyResponse);
rpc GetPartyMembers(Aurora.Proto.General.Empty) returns (MembersResponse); rpc GetPartyMembers(Aurora.Proto.General.Empty) returns (MembersResponse);
rpc GetQueue(Aurora.Proto.General.Empty) returns (QueueResponse); rpc GetQueue(Aurora.Proto.General.Empty) returns (QueueResponse);
rpc GetSongStream(SongRequest) returns (stream Aurora.Proto.General.Chunk) {};
} }
message JoinPartyRequest { message JoinPartyRequest {
@ -49,8 +50,13 @@ message QueueResponse{
} }
message RemoteMediaData { message RemoteMediaData {
string title = 1; string id = 1;
string artist = 2; string title = 2;
string album = 3; string artist = 3;
string duration = 4; string album = 4;
string duration = 5;
}
message SongRequest {
string id = 1;
} }

View File

@ -1,21 +0,0 @@
syntax = "proto3";
package Aurora.Proto.Playback;
import "Proto/general.proto";
service RemotePlaybackService {
//Playback Service
rpc GetPartyStream(Aurora.Proto.General.Empty) returns (stream Aurora.Proto.General.Chunk) {};
}
enum TransferStatusCode {
Unknown = 0;
Ok = 1;
Failed = 2;
}
message TransferStatus {
string Message = 1;
TransferStatusCode Code = 2;
}

View File

@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Aurora.Proto.Party; using Aurora.Proto.Party;
using Aurora.Proto.Events; using Aurora.Proto.Events;
using Aurora.Proto.General;
using Aurora.Services.EventManager; using Aurora.Services.EventManager;
using Aurora.Services; using Aurora.Services;
using Aurora.Models.Media; using Aurora.Models.Media;
@ -104,7 +105,11 @@ namespace Aurora.RemoteImpl
metadata = media.Metadata as AudioMetadata; metadata = media.Metadata as AudioMetadata;
RemoteMediaData data = new RemoteMediaData(); RemoteMediaData data = new RemoteMediaData();
data.Title = metadata.Title == null ? metadata.Title : ""; data.Id = media.Id;
if (metadata.Title != null)
{
data.Title = metadata.Title;
}
if (metadata.Artist != null) if (metadata.Artist != null)
{ {
data.Artist = metadata.Artist; data.Artist = metadata.Artist;
@ -130,5 +135,24 @@ namespace Aurora.RemoteImpl
return Task.FromResult(mediaList); return Task.FromResult(mediaList);
} }
public override async Task GetSongStream(SongRequest request,
Grpc.Core.IServerStreamWriter<Chunk> responseStream,
Grpc.Core.ServerCallContext context)
{
BaseMedia song = LibraryService.Instance.GetSong(request.Id);
song.Load();
//Send stream
Console.WriteLine("Begin sending file");
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = song.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");
}
} }
} }

View File

@ -1,39 +0,0 @@
using System;
using System.Threading.Tasks;
using System.IO;
using Aurora.Proto.Playback;
using Aurora.Proto.General;
using Aurora.Models;
namespace Aurora.RemoteImpl
{
public class RemotePlaybackServiceImpl : RemotePlaybackService.RemotePlaybackServiceBase
{
public RemotePlaybackServiceImpl()
{
}
public override Task GetPartyStream(Empty empty,
Grpc.Core.IServerStreamWriter<Chunk> responseStream,
Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException("Working on it");
// //Send stream
// string cwd = Directory.GetCurrentDirectory();
// using (FileStream fs = System.IO.File.OpenRead(Path.Combine(cwd, request.FileName)))
// {
// Console.WriteLine("Begin sending file");
// byte[] buffer = new byte[2048]; // read in chunks of 2KB
// int bytesRead;
// while ((bytesRead = fs.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");
// };
}
}
}

View File

@ -4,7 +4,6 @@ using System.Threading;
using Grpc.Core; using Grpc.Core;
using Aurora.Proto.Events; using Aurora.Proto.Events;
using Aurora.Proto.Party; using Aurora.Proto.Party;
using Aurora.Proto.Playback;
using Aurora.Services.ClientService; using Aurora.Services.ClientService;
namespace Aurora.Services.ClientService namespace Aurora.Services.ClientService
@ -12,7 +11,6 @@ namespace Aurora.Services.ClientService
public class ClientService : BaseService<ClientService> public class ClientService : BaseService<ClientService>
{ {
private RemotePartyService.RemotePartyServiceClient _remotePartyClient; private RemotePartyService.RemotePartyServiceClient _remotePartyClient;
private RemotePlaybackService.RemotePlaybackServiceClient _remotePlaybackClient;
private RemoteEventService.RemoteEventServiceClient _remoteEventsClient; private RemoteEventService.RemoteEventServiceClient _remoteEventsClient;
private Channel _channel; private Channel _channel;
CancellationTokenSource _eventCancellationTokenSource; CancellationTokenSource _eventCancellationTokenSource;
@ -32,14 +30,6 @@ namespace Aurora.Services.ClientService
} }
} }
public RemotePlaybackService.RemotePlaybackServiceClient RemotePlaybackServiceClient
{
get
{
return _remotePlaybackClient;
}
}
public RemoteEventService.RemoteEventServiceClient RemoteEventClient public RemoteEventService.RemoteEventServiceClient RemoteEventClient
{ {
get { return _remoteEventsClient; } get { return _remoteEventsClient; }
@ -50,8 +40,7 @@ namespace Aurora.Services.ClientService
get get
{ {
return _remoteEventsClient != null && return _remoteEventsClient != null &&
_remotePartyClient != null && _remotePartyClient != null;
_remotePlaybackClient != null;
} }
} }
@ -60,7 +49,6 @@ namespace Aurora.Services.ClientService
_channel = new Channel(string.Format("{0}:{1}", hostname, port), ChannelCredentials.Insecure); _channel = new Channel(string.Format("{0}:{1}", hostname, port), ChannelCredentials.Insecure);
_remotePartyClient = new RemotePartyService.RemotePartyServiceClient(_channel); _remotePartyClient = new RemotePartyService.RemotePartyServiceClient(_channel);
_remotePlaybackClient = new RemotePlaybackService.RemotePlaybackServiceClient(_channel);
_remoteEventsClient = new RemoteEventService.RemoteEventServiceClient(_channel); _remoteEventsClient = new RemoteEventService.RemoteEventServiceClient(_channel);
//Assign but don't start task //Assign but don't start task
@ -73,7 +61,6 @@ namespace Aurora.Services.ClientService
await _channel.ShutdownAsync(); await _channel.ShutdownAsync();
_remotePartyClient = null; _remotePartyClient = null;
_remotePlaybackClient = null;
_remoteEventsClient = null; _remoteEventsClient = null;
} }

View File

@ -37,6 +37,12 @@ namespace Aurora.Services
return collection; return collection;
} }
public BaseMedia GetSong(string Id)
{
_library.TryGetValue(Id, out BaseMedia song);
return song;
}
/// <summary> /// <summary>
/// Loads library from files. /// Loads library from files.
/// </summary> /// </summary>

View File

@ -6,7 +6,6 @@ using Grpc.Core;
using Aurora.RemoteImpl; using Aurora.RemoteImpl;
using Aurora.Proto.Events; using Aurora.Proto.Events;
using Aurora.Proto.Party; using Aurora.Proto.Party;
using Aurora.Proto.Playback;
namespace Aurora.Services namespace Aurora.Services
@ -19,7 +18,6 @@ namespace Aurora.Services
//Implementation class declarations //Implementation class declarations
RemotePartyServiceImpl _remotePartyServiceImpl; RemotePartyServiceImpl _remotePartyServiceImpl;
RemotePlaybackServiceImpl _remotePlaybackImpl;
RemoteEventServiceImpl _remoteEventImpl; RemoteEventServiceImpl _remoteEventImpl;
/// <summary> /// <summary>
@ -58,7 +56,6 @@ namespace Aurora.Services
{ {
return (_remoteEventImpl != null && return (_remoteEventImpl != null &&
_remotePartyServiceImpl != null && _remotePartyServiceImpl != null &&
_remotePlaybackImpl != null &&
_server != null); _server != null);
} }
} }
@ -78,12 +75,10 @@ namespace Aurora.Services
{ {
//Construct implementations //Construct implementations
_remotePartyServiceImpl = new RemotePartyServiceImpl(); _remotePartyServiceImpl = new RemotePartyServiceImpl();
_remotePlaybackImpl = new RemotePlaybackServiceImpl();
_remoteEventImpl = new RemoteEventServiceImpl(); _remoteEventImpl = new RemoteEventServiceImpl();
// Register grpc RemoteService with singleton server service // Register grpc RemoteService with singleton server service
RegisterService(RemotePartyService.BindService(_remotePartyServiceImpl)); RegisterService(RemotePartyService.BindService(_remotePartyServiceImpl));
RegisterService(RemotePlaybackService.BindService(_remotePlaybackImpl));
RegisterService(RemoteEventService.BindService(_remoteEventImpl)); RegisterService(RemoteEventService.BindService(_remoteEventImpl));
} }
_server.Start(); _server.Start();