Code refactoring for cleaner view model design

This commit is contained in:
watsonb8 2019-11-29 12:37:57 -05:00
parent 3398d145ac
commit 85ab39defd
15 changed files with 351 additions and 123 deletions

View File

@ -75,9 +75,9 @@ namespace Aurora.Design.Views
#endregion Player #endregion Player
#region Lifecycle #region Lifecycle
public virtual void OnActive() { } public virtual Task OnActive() { return Task.FromResult<object>(null); }
public virtual void OnInactive() { } public virtual Task OnInactive() { return Task.FromResult<object>(null); }
#endregion #endregion

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.ClientService.Events;
using Aurora.Services.PlayerService; using Aurora.Services.PlayerService;
using Aurora.Services.EventManager; using Aurora.Services.EventManager;
using Aurora.Models.Media; using Aurora.Models.Media;
@ -47,9 +48,6 @@ namespace Aurora.Design.Views.Party
PlayCommand = new Command(OnDoubleClickExecute, CanDoubleClickExecute); PlayCommand = new Command(OnDoubleClickExecute, CanDoubleClickExecute);
_client = ClientService.Instance; _client = ClientService.Instance;
//Hook up event handler
_client.EventReceived += this.OnEventReceived;
} }
~PartyViewModel() ~PartyViewModel()
@ -151,70 +149,100 @@ namespace Aurora.Design.Views.Party
#endregion Properties #endregion Properties
#region Events #region Events
public override void OnActive() /// <summary>
/// Called by framework when view becomes active
/// </summary>
/// <returns></returns>
public override async Task OnActive()
{ {
//TODO //TODO
//If in party subscribe to events if (this._state == PartyState.Hosting)
//If in party get events {
} await SubscribeToEvents();
}
public override void OnInactive() _client.OnMediaPaused += this.OnMediaPaused;
{ _client.OnMediaResumed += this.OnMediaResumed;
//TODO _client.OnNewMediaPlaying += this.OnNewMediaPlaying;
//unsubscribe _client.OnPartyMemberJoined += this.OnPartyMemberJoined;
//stop getting events _client.OnPartyMemberLeft += this.OnPartyMemberLeft;
} }
/// <summary> /// <summary>
/// An event handler for the client receiving update events /// Called by framework when view becomes inactive
/// </summary> /// </summary>
/// <param name="sender">The object that sent the event</param> /// <returns></returns>
/// <param name="eventArgs">The event arguments</param> public override async Task OnInactive()
public void OnEventReceived(object sender, EventReceivedEventArgs eventArgs)
{ {
switch (eventArgs.BaseEvent.DerivedEventCase) _client.StopEvents();
await UnsubscribeFromEvents();
//Stop event stream and un hook events
_client.OnMediaPaused -= this.OnMediaPaused;
_client.OnMediaResumed -= this.OnMediaResumed;
_client.OnNewMediaPlaying -= this.OnNewMediaPlaying;
_client.OnPartyMemberJoined -= this.OnPartyMemberJoined;
_client.OnPartyMemberLeft -= this.OnPartyMemberLeft;
}
/// <summary>
/// Remote media paused event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnMediaPaused(object sender, MediaPausedEventArgs args)
{
StopPlaying();
}
/// <summary>
/// Remote playing new media event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnNewMediaPlaying(object sender, NewMediaPlayingEventArgs args)
{
PlayFromBeginning(GetMediaFromQueue(args.Event.Media.Id));
}
/// <summary>
/// Remote resumed playing event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnMediaResumed(object sender, MediaResumedEventArgs args)
{
PlayResume();
}
/// <summary>
/// Member joined party event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnPartyMemberJoined(object sender, PartyMemberJoinedEventArgs args)
{
PartyMember member = new PartyMember
{ {
case BaseEvent.DerivedEventOneofCase.None: UserName = args.Event.Member.UserName,
{ Id = args.Event.Member.Id,
throw new InvalidOperationException(); IpAddress = args.Event.Member.IpAddress,
} Port = args.Event.Member.Port
case BaseEvent.DerivedEventOneofCase.PartyMemberJoinedEvent: };
{
PartyMemberJoinedEvent derivedEvent = eventArgs.BaseEvent.PartyMemberJoinedEvent;
PartyMember member = new PartyMember
{
UserName = derivedEvent.Member.UserName,
Id = derivedEvent.Member.Id,
IpAddress = derivedEvent.Member.IpAddress,
Port = derivedEvent.Member.Port
};
Members.Add(member); Members.Add(member);
}
break; /// <summary>
} /// Member left party event
case BaseEvent.DerivedEventOneofCase.PartyMemberLeftEvent: /// </summary>
{ /// <param name="sender"></param>
PartyMemberJoinedEvent derivedEvent = eventArgs.BaseEvent.PartyMemberJoinedEvent; /// <param name="args"></param>
var found = Members.Where(x => x.Id == derivedEvent.Member.Id); public void OnPartyMemberLeft(object sender, PartyMemberLeftEventArgs args)
foreach (PartyMember member in found) {
{ var found = Members.Where(x => x.Id == args.Event.Member.Id);
_members.Remove(member); foreach (PartyMember member in found)
} {
break; _members.Remove(member);
}
case BaseEvent.DerivedEventOneofCase.MediaPlayingEvent:
{
MediaPlayingEvent derivedEvent = eventArgs.BaseEvent.MediaPlayingEvent;
Play(derivedEvent);
break;
}
case BaseEvent.DerivedEventOneofCase.MediaPausedEvent:
{
MediaPausedEvent derivedEvent = eventArgs.BaseEvent.MediaPausedEvent;
StopPlaying();
break;
}
} }
} }
@ -274,17 +302,32 @@ namespace Aurora.Design.Views.Party
public override void OnPlayButtonExecute() public override void OnPlayButtonExecute()
{ {
_player.Play();
switch (_player.PlaybackState) switch (_player.PlaybackState)
{ {
case PlaybackState.Buffering: case PlaybackState.Buffering:
{ {
_player.Play(); //Fire play resume event
AudioMetadata meta = _selectedMedia.Metadata as AudioMetadata;
MediaResumedEvent mediaResumed = new MediaResumedEvent();
EventManager.Instance.FireEvent(new BaseEvent()
{
MediaResumedEvent = mediaResumed
});
break; break;
} }
case PlaybackState.Playing: case PlaybackState.Playing:
{ {
_player.Pause(); //Fire play stopped event
AudioMetadata meta = _selectedMedia.Metadata as AudioMetadata;
MediaPausedEvent mediaPaused = new MediaPausedEvent();
EventManager.Instance.FireEvent(new BaseEvent()
{
MediaPausedEvent = mediaPaused
});
break; break;
} }
} }
@ -310,8 +353,9 @@ namespace Aurora.Design.Views.Party
/// </summary> /// </summary>
public void OnDoubleClickExecute() public void OnDoubleClickExecute()
{ {
//Fire Playing event
AudioMetadata meta = _selectedMedia.Metadata as AudioMetadata; AudioMetadata meta = _selectedMedia.Metadata as AudioMetadata;
MediaPlayingEvent mediaPlaying = new MediaPlayingEvent() NewMediaPlayingEvent mediaPlaying = new NewMediaPlayingEvent()
{ {
Media = new RemoteMediaData() Media = new RemoteMediaData()
{ {
@ -324,7 +368,7 @@ namespace Aurora.Design.Views.Party
EventManager.Instance.FireEvent(new BaseEvent() EventManager.Instance.FireEvent(new BaseEvent()
{ {
MediaPlayingEvent = mediaPlaying NewMediaPlayingEvent = mediaPlaying
}); });
} }
@ -355,19 +399,7 @@ namespace Aurora.Design.Views.Party
RefreshMembers(); RefreshMembers();
//Subscribe to events //Subscribe to events
SubscribeRequest req = new SubscribeRequest(); await SubscribeToEvents();
req.EventTypes.Add(EventType.PartyMemberJoined);
req.EventTypes.Add(EventType.PartyMemberLeft);
req.EventTypes.Add(EventType.MediaPlaying);
req.EventTypes.Add(EventType.MediaStopped);
if (!string.IsNullOrWhiteSpace(SettingsService.Instance.ClientId))
{
req.ClientId = SettingsService.Instance.ClientId;
}
Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", SettingsService.Instance.ClientId));
_client.RemoteEventClient.SubscribeToEvents(req);
QueueResponse queueResponse = _client.RemotePartyClient.GetQueue(new Empty()); QueueResponse queueResponse = _client.RemotePartyClient.GetQueue(new Empty());
@ -403,19 +435,41 @@ namespace Aurora.Design.Views.Party
_client.StopEvents(); _client.StopEvents();
//Unsubscribe //Unsubscribe
UnsubscribeAllRequest unsubscribeReq = new UnsubscribeAllRequest(); await UnsubscribeFromEvents();
await _client.RemoteEventClient.UnsubscribeFromAllAsync(unsubscribeReq);
//Leave party //Leave party
LeavePartyRequest leaveReq = new LeavePartyRequest(); LeavePartyRequest leaveReq = new LeavePartyRequest();
await _client.RemotePartyClient.LeavePartyAsync(leaveReq); await _client.RemotePartyClient.LeavePartyAsync(leaveReq);
} }
private async Task SubscribeToEvents()
{
SubscribeRequest req = new SubscribeRequest();
req.EventTypes.Add(EventType.PartyMemberJoined);
req.EventTypes.Add(EventType.PartyMemberLeft);
req.EventTypes.Add(EventType.MediaPlaying);
req.EventTypes.Add(EventType.MediaStopped);
if (!string.IsNullOrWhiteSpace(SettingsService.Instance.ClientId))
{
req.ClientId = SettingsService.Instance.ClientId;
}
Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", SettingsService.Instance.ClientId));
await _client.RemoteEventClient.SubscribeToEventsAsync(req);
}
private async Task UnsubscribeFromEvents()
{
UnsubscribeAllRequest unsubscribeReq = new UnsubscribeAllRequest();
await _client.RemoteEventClient.UnsubscribeFromAllAsync(unsubscribeReq);
}
/// <summary> /// <summary>
/// Refresh members list. /// Refresh members list.
/// </summary> /// </summary>
private void RefreshMembers() private void RefreshMembers()
{ {
Members.Clear();
MembersResponse response = _client.RemotePartyClient.GetPartyMembers(new Empty()); MembersResponse response = _client.RemotePartyClient.GetPartyMembers(new Empty());
//Add members //Add members
foreach (PartyMember member in response.Members) foreach (PartyMember member in response.Members)
@ -431,17 +485,28 @@ namespace Aurora.Design.Views.Party
OnPropertyChanged("IsNotSelectingHost"); OnPropertyChanged("IsNotSelectingHost");
} }
private async void Play(MediaPlayingEvent args) private BaseMedia GetMediaFromQueue(string Id)
{ {
//TODO this design assumes all played music is in a queue if (_queue.Any((BaseMedia media) => media.Id == Id))
//TODO this is a slow design depending on size of queue
if (_queue.Any((BaseMedia media) => media.Id == args.Media.Id))
{ {
BaseMedia media = _queue.First((BaseMedia med) => med.Id == args.Media.Id); BaseMedia media = _queue.First((BaseMedia med) => med.Id == Id);
base.Media = media; return media;
await _player.LoadMedia(base.Media).ConfigureAwait(true);
_player.Play();
} }
else
{
return null;
}
}
private async void PlayFromBeginning(BaseMedia args)
{
base.Media = args;
await _player.LoadMedia(base.Media).ConfigureAwait(true);
_player.Play();
}
private void PlayResume()
{
_player.Play();
} }
private void StopPlaying() private void StopPlaying()

View File

@ -93,7 +93,6 @@ namespace Aurora.Design.Views.Songs
await _player.LoadMedia(base.Media).ConfigureAwait(true); await _player.LoadMedia(base.Media).ConfigureAwait(true);
} }
_player.Play();
switch (_player.PlaybackState) switch (_player.PlaybackState)
{ {
case PlaybackState.Buffering: case PlaybackState.Buffering:
@ -106,6 +105,11 @@ namespace Aurora.Design.Views.Songs
_player.Pause(); _player.Pause();
break; break;
} }
case PlaybackState.Stopped:
{
_player.Play();
break;
}
} }
} }

View File

@ -50,15 +50,20 @@ message BaseEvent {
oneof derivedEvent { oneof derivedEvent {
PartyMemberJoinedEvent partyMemberJoinedEvent = 3; PartyMemberJoinedEvent partyMemberJoinedEvent = 3;
PartyMemberLeftEvent partyMemberLeftEvent = 4; PartyMemberLeftEvent partyMemberLeftEvent = 4;
MediaPlayingEvent mediaPlayingEvent = 5; NewMediaPlayingEvent newMediaPlayingEvent = 5;
MediaPausedEvent mediaPausedEvent = 6; MediaPausedEvent mediaPausedEvent = 6;
MediaResumedEvent mediaResumedEvent = 7;
} }
} }
message MediaPlayingEvent { message NewMediaPlayingEvent {
Aurora.Proto.Party.RemoteMediaData media = 1; Aurora.Proto.Party.RemoteMediaData media = 1;
} }
message MediaResumedEvent {
Aurora.Proto.General.Empty empty = 1;
}
message MediaPausedEvent { message MediaPausedEvent {
Aurora.Proto.General.Empty empty = 1; Aurora.Proto.General.Empty empty = 1;
} }

View File

@ -34,6 +34,7 @@ namespace Aurora.RemoteImpl
Action<BaseEvent> callback = (BaseEvent bEvent) => Action<BaseEvent> callback = (BaseEvent bEvent) =>
{ {
Console.WriteLine(string.Format("SERVER - Event fired for peer: {0}", peerId)); Console.WriteLine(string.Format("SERVER - Event fired for peer: {0}", peerId));
//TODO need to remove callback if stream no longer exists IE. Client crashed or stopped
responseStream.WriteAsync(bEvent); responseStream.WriteAsync(bEvent);
}; };

View File

@ -6,9 +6,12 @@ using Aurora.Proto.Events;
using Aurora.Proto.Party; using Aurora.Proto.Party;
using Aurora.Proto.Playback; using Aurora.Proto.Playback;
using Aurora.Proto.Sync; using Aurora.Proto.Sync;
using Aurora.Services.ClientService.Events;
using System.Collections.Generic;
namespace Aurora.Services.ClientService namespace Aurora.Services.ClientService
{ {
public class ClientService : BaseService<ClientService> public class ClientService : BaseService<ClientService>
{ {
private RemotePartyService.RemotePartyServiceClient _remotePartyClient; private RemotePartyService.RemotePartyServiceClient _remotePartyClient;
@ -23,7 +26,11 @@ namespace Aurora.Services.ClientService
{ {
} }
public EventReceivedEventHandler EventReceived; public MediaPausedEventHandler OnMediaPaused;
public NewMediaPlayingEventHandler OnNewMediaPlaying;
public PartyMemberJoinedEventHandler OnPartyMemberJoined;
public PartyMemberLeftEventHandler OnPartyMemberLeft;
public MediaResumedEventHandler OnMediaResumed;
public RemotePartyService.RemotePartyServiceClient RemotePartyClient public RemotePartyService.RemotePartyServiceClient RemotePartyClient
{ {
@ -99,16 +106,36 @@ namespace Aurora.Services.ClientService
while (!_eventCancellationTokenSource.Token.IsCancellationRequested && while (!_eventCancellationTokenSource.Token.IsCancellationRequested &&
await eventStream.ResponseStream.MoveNext(_eventCancellationTokenSource.Token)) await eventStream.ResponseStream.MoveNext(_eventCancellationTokenSource.Token))
{ {
BaseEvent e = new BaseEvent(eventStream.ResponseStream.Current); try
if (this.EventReceived != null)
{ {
this.EventReceived.Invoke(this, new EventReceivedEventArgs(e)); BaseEvent e = new BaseEvent(eventStream.ResponseStream.Current);
Dictionary<BaseEvent.DerivedEventOneofCase, EventInfo> events = new Dictionary<BaseEvent.DerivedEventOneofCase, EventInfo>()
{
{BaseEvent.DerivedEventOneofCase.MediaPausedEvent, new EventInfo(this.OnMediaPaused, typeof(MediaPausedEventArgs))},
{BaseEvent.DerivedEventOneofCase.MediaResumedEvent, new EventInfo(this.OnMediaResumed, typeof(MediaResumedEventArgs))},
{BaseEvent.DerivedEventOneofCase.NewMediaPlayingEvent, new EventInfo(this.OnNewMediaPlaying, typeof(NewMediaPlayingEventArgs))},
{BaseEvent.DerivedEventOneofCase.PartyMemberJoinedEvent, new EventInfo(this.OnPartyMemberJoined, typeof(PartyMemberJoinedEventArgs))},
{BaseEvent.DerivedEventOneofCase.PartyMemberLeftEvent, new EventInfo(this.OnPartyMemberLeft, typeof(PartyMemberLeftEventArgs))}
};
events.TryGetValue(e.DerivedEventCase, out EventInfo eventInfo);
if (eventInfo != null && eventInfo.Handler != null)
{
eventInfo.Handler.DynamicInvoke(new object[] { this, Activator.CreateInstance(eventInfo.ArgsType, new object[] { e }) });
}
} }
catch (Exception ex)
{
Console.WriteLine("Exception while parsing event ---" + ex.Message);
}
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine(string.Format("EXCEPTION --- " + ex.Message)); Console.WriteLine(string.Format("EXCEPTION while parsing events --- " + ex.Message));
} }
} }
} }

View File

@ -0,0 +1,25 @@
using System;
using System.Threading.Tasks;
using System.Threading;
using Grpc.Core;
using Aurora.Proto.Events;
using Aurora.Proto.Party;
using Aurora.Proto.Playback;
using Aurora.Proto.Sync;
using Aurora.Services.ClientService.Events;
using System.Collections.Generic;
namespace Aurora.Services.ClientService
{
public class EventInfo
{
public EventInfo(Delegate handler, Type argsType)
{
this.Handler = handler;
ArgsType = argsType;
}
public Delegate Handler { get; private set; }
public Type ArgsType { get; private set; }
}
}

View File

@ -1,16 +0,0 @@
using System;
using Aurora.Proto.Events;
namespace Aurora.Services.ClientService
{
public delegate void EventReceivedEventHandler(object sender, EventReceivedEventArgs e);
public class EventReceivedEventArgs
{
public BaseEvent BaseEvent { get; private set; }
public EventReceivedEventArgs(BaseEvent e)
{
BaseEvent = e;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using Aurora.Proto.Events;
namespace Aurora.Services.ClientService.Events
{
public delegate void MediaPausedEventHandler(object sender, MediaPausedEventArgs e);
public class MediaPausedEventArgs
{
public MediaPausedEvent Event { get; private set; }
public MediaPausedEventArgs(BaseEvent e)
{
Event = e.MediaPausedEvent;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using Aurora.Proto.Events;
namespace Aurora.Services.ClientService
{
public delegate void MediaResumedEventHandler(object sender, MediaResumedEventArgs e);
public class MediaResumedEventArgs
{
public MediaResumedEvent Event { get; private set; }
public MediaResumedEventArgs(BaseEvent e)
{
Event = e.MediaResumedEvent;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using Aurora.Proto.Events;
namespace Aurora.Services.ClientService.Events
{
public delegate void NewMediaPlayingEventHandler(object sender, NewMediaPlayingEventArgs e);
public class NewMediaPlayingEventArgs
{
public NewMediaPlayingEvent Event { get; private set; }
public NewMediaPlayingEventArgs(BaseEvent e)
{
Event = e.NewMediaPlayingEvent;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using Aurora.Proto.Events;
namespace Aurora.Services.ClientService.Events
{
public delegate void PartyMemberJoinedEventHandler(object sender, PartyMemberJoinedEventArgs e);
public class PartyMemberJoinedEventArgs
{
public PartyMemberJoinedEvent Event { get; private set; }
public PartyMemberJoinedEventArgs(BaseEvent e)
{
Event = e.PartyMemberJoinedEvent;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
using Aurora.Proto.Events;
namespace Aurora.Services.ClientService.Events
{
public delegate void PartyMemberLeftEventHandler(object sender, PartyMemberLeftEventArgs e);
public class PartyMemberLeftEventArgs
{
public PartyMemberLeftEvent Event { get; private set; }
public PartyMemberLeftEventArgs(BaseEvent e)
{
Event = e.PartyMemberLeftEvent;
}
}
}

View File

@ -1,16 +1,9 @@
using System; using System;
using System.IO;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Google.Protobuf.Reflection;
using Aurora.Proto.Events; using Aurora.Proto.Events;
using Aurora.Models;
namespace Aurora.Services.EventManager namespace Aurora.Services.EventManager
{ {
@ -183,8 +176,6 @@ namespace Aurora.Services.EventManager
{ {
foreach (KeyValuePair<string, List<EventType>> pair in _subscriptionList) foreach (KeyValuePair<string, List<EventType>> pair in _subscriptionList)
{ {
Console.WriteLine("SERVER - Invoking action for client: " + pair.Key);
Task.Delay(1000); Task.Delay(1000);
//If action list contains an action for id, invoke //If action list contains an action for id, invoke
if (actionsCopy.ContainsKey(pair.Key)) if (actionsCopy.ContainsKey(pair.Key))

View File

@ -4,6 +4,8 @@ using System.Threading;
using Grpc.Core; using Grpc.Core;
using Aurora.Models.Media; using Aurora.Models.Media;
using Aurora.Proto.Sync; using Aurora.Proto.Sync;
using Aurora.Proto.Events;
using Aurora.Proto.Party;
using LibVLCSharp.Shared; using LibVLCSharp.Shared;
namespace Aurora.Services.PlayerService namespace Aurora.Services.PlayerService
@ -110,14 +112,14 @@ namespace Aurora.Services.PlayerService
RemoteAudio media = _currentMedia as RemoteAudio; RemoteAudio media = _currentMedia as RemoteAudio;
if (!media.FromHost) if (!media.FromHost)
{ {
RemoteSyncService.RemoteSyncServiceClient _remoteSyncClient = media.RemoteSyncClient; RemoteSyncService.RemoteSyncServiceClient remoteSyncClient = media.RemoteSyncClient;
//Sync playback in a separate task //Sync playback in a separate task
//Task completes when host stops syncing (when a song is complete) //Task completes when host stops syncing (when a song is complete)
Task syncTask = new Task(async () => Task syncTask = new Task(async () =>
{ {
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
using (AsyncServerStreamingCall<Sync> syncStream = _remoteSyncClient using (AsyncServerStreamingCall<Sync> syncStream = remoteSyncClient
.GetMediaSync(new Proto.General.Empty())) .GetMediaSync(new Proto.General.Empty()))
{ {
try try
@ -154,6 +156,7 @@ namespace Aurora.Services.PlayerService
}); });
syncTask.Start(); syncTask.Start();
// Task syncTask = Task.Run(() => Sync(remoteSyncClient));
} }
} }
@ -163,6 +166,50 @@ namespace Aurora.Services.PlayerService
} }
} }
/// <summary>
/// Async method to synchronize music playback with host
/// </summary>
/// <param name="remoteSyncClient"></param>
/// <returns></returns>
private async Task Sync(RemoteSyncService.RemoteSyncServiceClient remoteSyncClient)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
using (AsyncServerStreamingCall<Sync> syncStream = remoteSyncClient
.GetMediaSync(new Proto.General.Empty()))
{
try
{
while (await syncStream.ResponseStream.MoveNext(cancellationTokenSource.Token))
{
Sync sync = new Sync(syncStream.ResponseStream.Current);
if (sync != null)
{
//Adjust position based on sync
DateTime localTime = Utils.TimeUtils.GetNetworkTime();
//Get offset converted to milliseconds
float offset = ((localTime.Ticks - sync.ServerTime) * 100) / (1000 * 1000);
float length = CurrentMediaLength;
float newPosition = (sync.TrackTime + offset) / length;
//Adjust position if greater than 10 percent difference
float oldPosition = _mediaPlayer.Position;
if (newPosition - oldPosition > 0.001 ||
newPosition - oldPosition < -0.001)
{
_mediaPlayer.Position = newPosition;
Console.WriteLine("Audio synced");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception caught while attempting to sync: " + ex.Message);
}
}
}
/// <summary> /// <summary>
/// Pause currently loaded media. /// Pause currently loaded media.
/// </summary> /// </summary>
@ -191,7 +238,6 @@ namespace Aurora.Services.PlayerService
{ {
PlaybackStateChanged.Invoke(this, new PlaybackStateChangedEventArgs(oldState, _state)); PlaybackStateChanged.Invoke(this, new PlaybackStateChangedEventArgs(oldState, _state));
} }
} }
public void Enqueue(BaseMedia song) public void Enqueue(BaseMedia song)