public override void HandleRequest(SeekGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } if (prevState.Equals(GroupStateType.Playing)) { ResumePlaying = true; } else if (prevState.Equals(GroupStateType.Paused)) { ResumePlaying = false; } // Sanitize PositionTicks. var ticks = context.SanitizePositionTicks(request.PositionTicks); // Seek. context.PositionTicks = ticks; context.LastActivity = DateTime.UtcNow; var command = context.NewSyncPlayCommand(SendCommandType.Seek); context.SendCommand(session, SyncPlayBroadcastType.AllGroup, command, cancellationToken); // Reset status of sessions and await for all Ready events. context.SetAllBuffering(true); // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); }
public virtual void HandleRequest(QueueGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { var result = context.AddToPlayQueue(request.ItemIds, request.Mode); if (!result) { _logger.LogError("Unable to add items to play queue in group {GroupId}.", context.GroupId.ToString()); return; } var reason = request.Mode switch { GroupQueueMode.QueueNext => PlayQueueUpdateReason.QueueNext, _ => PlayQueueUpdateReason.Queue }; var playQueueUpdate = context.GetPlayQueueUpdate(reason); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken); }
public override void HandleRequest(ReadyGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { SendStopCommand(context, prevState, session, cancellationToken); }
/// <inheritdoc /> public override void HandleRequest(PlayGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Change state. var waitingState = new WaitingGroupState(LoggerFactory); context.SetState(waitingState); waitingState.HandleRequest(request, context, Type, session, cancellationToken); }
/// <inheritdoc /> public override void HandleRequest(PauseGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Change state. var pausedState = new PausedGroupState(LoggerFactory); context.SetState(pausedState); pausedState.HandleRequest(request, context, Type, session, cancellationToken); }
public override void HandleRequest(PreviousItemGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } ResumePlaying = true; // Make sure the client knows the playing item, to avoid duplicate requests. if (!request.PlaylistItemId.Equals(context.PlayQueue.GetPlayingItemPlaylistId())) { _logger.LogDebug("Session {SessionId} provided the wrong playlist item for group {GroupId}.", session.Id, context.GroupId.ToString()); return; } var newItem = context.PreviousItemInQueue(); if (newItem) { // Send playing-queue update. var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.PreviousItem); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken); // Reset status of sessions and await for all Ready events. context.SetAllBuffering(true); } else { // Return to old state. IGroupState newState = prevState switch { GroupStateType.Playing => new PlayingGroupState(LoggerFactory), GroupStateType.Paused => new PausedGroupState(LoggerFactory), _ => new IdleGroupState(LoggerFactory) }; context.SetState(newState); _logger.LogDebug("No previous item available in group {GroupId}.", context.GroupId.ToString()); } }
/// <inheritdoc /> public override void HandleRequest(ReadyGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { if (prevState.Equals(Type)) { // Group was not waiting, make sure client has latest state. var command = context.NewSyncPlayCommand(SendCommandType.Unpause); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); } else if (prevState.Equals(GroupStateType.Waiting)) { // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); } }
/// <inheritdoc /> public abstract void SessionLeaving(IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken);
/// <inheritdoc /> public virtual void HandleRequest(SetPlaylistItemGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { var waitingState = new WaitingGroupState(LoggerFactory); context.SetState(waitingState); waitingState.HandleRequest(request, context, Type, session, cancellationToken); }
/// <inheritdoc /> public virtual void HandleRequest(PingGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Collected pings are used to account for network latency when unpausing playback. context.UpdatePing(session, request.Ping); }
/// <inheritdoc /> public virtual void HandleRequest(IgnoreWaitGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { context.SetIgnoreGroupWait(session, request.IgnoreWait); }
/// <inheritdoc /> public virtual void HandleRequest(SetShuffleModeGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { context.SetShuffleMode(request.Mode); var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.ShuffleMode); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken); }
/// <inheritdoc /> public override void HandleRequest(PauseGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { if (!prevState.Equals(Type)) { // Pause group and compute the media playback position. var currentTime = DateTime.UtcNow; var elapsedTime = currentTime - context.LastActivity; context.LastActivity = currentTime; // Elapsed time is negative if event happens // during the delay added to account for latency. // In this phase clients haven't started the playback yet. // In other words, LastActivity is in the future, // when playback unpause is supposed to happen. // Seek only if playback actually started. context.PositionTicks += Math.Max(elapsedTime.Ticks, 0); var command = context.NewSyncPlayCommand(SendCommandType.Pause); context.SendCommand(session, SyncPlayBroadcastType.AllGroup, command, cancellationToken); // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); } else { // Client got lost, sending current state. var command = context.NewSyncPlayCommand(SendCommandType.Pause); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); } }
/// <inheritdoc /> public override void HandleRequest(ReadyGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { if (prevState.Equals(Type)) { // Client got lost, sending current state. var command = context.NewSyncPlayCommand(SendCommandType.Pause); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); } else if (prevState.Equals(GroupStateType.Waiting)) { // Sending current state to all clients. var command = context.NewSyncPlayCommand(SendCommandType.Pause); context.SendCommand(session, SyncPlayBroadcastType.AllGroup, command, cancellationToken); // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); } }
public override void HandleRequest(BufferGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } // Make sure the client is playing the correct item. if (!request.PlaylistItemId.Equals(context.PlayQueue.GetPlayingItemPlaylistId())) { _logger.LogDebug("Session {SessionId} reported wrong playlist item in group {GroupId}.", session.Id, context.GroupId.ToString()); var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.SetCurrentItem); var updateSession = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.CurrentSession, updateSession, cancellationToken); context.SetBuffering(session, true); return; } if (prevState.Equals(GroupStateType.Playing)) { // Resume playback when all ready. ResumePlaying = true; context.SetBuffering(session, true); // Pause group and compute the media playback position. var currentTime = DateTime.UtcNow; var elapsedTime = currentTime - context.LastActivity; context.LastActivity = currentTime; // Elapsed time is negative if event happens // during the delay added to account for latency. // In this phase clients haven't started the playback yet. // In other words, LastActivity is in the future, // when playback unpause is supposed to happen. // Seek only if playback actually started. context.PositionTicks += Math.Max(elapsedTime.Ticks, 0); // Send pause command to all non-buffering sessions. var command = context.NewSyncPlayCommand(SendCommandType.Pause); context.SendCommand(session, SyncPlayBroadcastType.AllReady, command, cancellationToken); } else if (prevState.Equals(GroupStateType.Paused)) { // Don't resume playback when all ready. ResumePlaying = false; context.SetBuffering(session, true); // Send pause command to buffering session. var command = context.NewSyncPlayCommand(SendCommandType.Pause); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); } else if (prevState.Equals(GroupStateType.Waiting)) { // Another session is now buffering. context.SetBuffering(session, true); if (!ResumePlaying) { // Force update for this session that should be paused. var command = context.NewSyncPlayCommand(SendCommandType.Pause); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); } } // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); }
/// <inheritdoc /> public virtual void HandleRequest(RemoveFromPlaylistGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { var playingItemRemoved = context.RemoveFromPlayQueue(request.PlaylistItemIds); var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.RemoveItems); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken); if (playingItemRemoved && !context.PlayQueue.IsItemPlaying()) { _logger.LogDebug("Play queue in group {GroupId} is now empty.", context.GroupId.ToString()); IGroupState idleState = new IdleGroupState(LoggerFactory); context.SetState(idleState); var stopRequest = new StopGroupRequest(); idleState.HandleRequest(stopRequest, context, Type, session, cancellationToken); } }
public override void HandleRequest(ReadyGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } // Make sure the client is playing the correct item. if (!request.PlaylistItemId.Equals(context.PlayQueue.GetPlayingItemPlaylistId())) { _logger.LogDebug("Session {SessionId} reported wrong playlist item in group {GroupId}.", session.Id, context.GroupId.ToString()); var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.SetCurrentItem); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.CurrentSession, update, cancellationToken); context.SetBuffering(session, true); return; } // Compute elapsed time between the client reported time and now. // Elapsed time is used to estimate the client position when playback is unpaused. // Ideally, the request is received and handled without major delays. // However, to avoid waiting indefinitely when a client is not reporting a correct time, // the elapsed time is ignored after a certain threshold. var currentTime = DateTime.UtcNow; var elapsedTime = currentTime.Subtract(request.When); var timeSyncThresholdTicks = TimeSpan.FromMilliseconds(context.TimeSyncOffset).Ticks; if (Math.Abs(elapsedTime.Ticks) > timeSyncThresholdTicks) { _logger.LogWarning("Session {SessionId} is not time syncing properly. Ignoring elapsed time.", session.Id); elapsedTime = TimeSpan.Zero; } // Ignore elapsed time if client is paused. if (!request.IsPlaying) { elapsedTime = TimeSpan.Zero; } var requestTicks = context.SanitizePositionTicks(request.PositionTicks); var clientPosition = TimeSpan.FromTicks(requestTicks) + elapsedTime; var delayTicks = context.PositionTicks - clientPosition.Ticks; var maxPlaybackOffsetTicks = TimeSpan.FromMilliseconds(context.MaxPlaybackOffset).Ticks; _logger.LogDebug("Session {SessionId} is at {PositionTicks} (delay of {Delay} seconds) in group {GroupId}.", session.Id, clientPosition, TimeSpan.FromTicks(delayTicks).TotalSeconds, context.GroupId.ToString()); if (ResumePlaying) { // Handle case where session reported as ready but in reality // it has no clue of the real position nor the playback state. if (!request.IsPlaying && Math.Abs(delayTicks) > maxPlaybackOffsetTicks) { // Session not ready at all. context.SetBuffering(session, true); // Correcting session's position. var command = context.NewSyncPlayCommand(SendCommandType.Seek); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); _logger.LogWarning("Session {SessionId} got lost in time, correcting.", session.Id); return; } // Session is ready. context.SetBuffering(session, false); if (context.IsBuffering()) { // Others are still buffering, tell this client to pause when ready. var command = context.NewSyncPlayCommand(SendCommandType.Pause); command.When = currentTime.AddTicks(delayTicks); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); _logger.LogInformation("Session {SessionId} will pause when ready in {Delay} seconds. Group {GroupId} is waiting for all ready events.", session.Id, TimeSpan.FromTicks(delayTicks).TotalSeconds, context.GroupId.ToString()); } else { // If all ready, then start playback. // Let other clients resume as soon as the buffering client catches up. if (delayTicks > context.GetHighestPing() * 2 * TimeSpan.TicksPerMillisecond) { // Client that was buffering is recovering, notifying others to resume. context.LastActivity = currentTime.AddTicks(delayTicks); var command = context.NewSyncPlayCommand(SendCommandType.Unpause); var filter = SyncPlayBroadcastType.AllExceptCurrentSession; if (!request.IsPlaying) { filter = SyncPlayBroadcastType.AllGroup; } context.SendCommand(session, filter, command, cancellationToken); _logger.LogInformation("Session {SessionId} is recovering, group {GroupId} will resume in {Delay} seconds.", session.Id, context.GroupId.ToString(), TimeSpan.FromTicks(delayTicks).TotalSeconds); } else { // Client, that was buffering, resumed playback but did not update others in time. delayTicks = context.GetHighestPing() * 2 * TimeSpan.TicksPerMillisecond; delayTicks = Math.Max(delayTicks, context.DefaultPing); context.LastActivity = currentTime.AddTicks(delayTicks); var command = context.NewSyncPlayCommand(SendCommandType.Unpause); context.SendCommand(session, SyncPlayBroadcastType.AllGroup, command, cancellationToken); _logger.LogWarning("Session {SessionId} resumed playback, group {GroupId} has {Delay} seconds to recover.", session.Id, context.GroupId.ToString(), TimeSpan.FromTicks(delayTicks).TotalSeconds); } // Change state. var playingState = new PlayingGroupState(LoggerFactory); context.SetState(playingState); playingState.HandleRequest(request, context, Type, session, cancellationToken); } } else { // Check that session is really ready, tolerate player imperfections under a certain threshold. if (Math.Abs(context.PositionTicks - requestTicks) > maxPlaybackOffsetTicks) { // Session still not ready. context.SetBuffering(session, true); // Session is seeking to wrong position, correcting. var command = context.NewSyncPlayCommand(SendCommandType.Seek); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); _logger.LogWarning("Session {SessionId} is seeking to wrong position, correcting.", session.Id); return; } else { // Session is ready. context.SetBuffering(session, false); } if (!context.IsBuffering()) { _logger.LogDebug("Session {SessionId} is ready, group {GroupId} is ready.", session.Id, context.GroupId.ToString()); // Group is ready, returning to previous state. var pausedState = new PausedGroupState(LoggerFactory); context.SetState(pausedState); if (InitialState.Equals(GroupStateType.Playing)) { // Group went from playing to waiting state and a pause request occured while waiting. var pauseRequest = new PauseGroupRequest(); pausedState.HandleRequest(pauseRequest, context, Type, session, cancellationToken); } else if (InitialState.Equals(GroupStateType.Paused)) { pausedState.HandleRequest(request, context, Type, session, cancellationToken); } } } }
public override void HandleRequest(PlayGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } ResumePlaying = true; var setQueueStatus = context.SetPlayQueue(request.PlayingQueue, request.PlayingItemPosition, request.StartPositionTicks); if (!setQueueStatus) { _logger.LogError("Unable to set playing queue in group {GroupId}.", context.GroupId.ToString()); // Ignore request and return to previous state. IGroupState newState = prevState switch { GroupStateType.Playing => new PlayingGroupState(LoggerFactory), GroupStateType.Paused => new PausedGroupState(LoggerFactory), _ => new IdleGroupState(LoggerFactory) }; context.SetState(newState); return; } var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.NewPlaylist); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken); // Reset status of sessions and await for all Ready events. context.SetAllBuffering(true); _logger.LogDebug("Session {SessionId} set a new play queue in group {GroupId}.", session.Id, context.GroupId.ToString()); }
public override void HandleRequest(IgnoreWaitGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { context.SetIgnoreGroupWait(session, request.IgnoreWait); if (!context.IsBuffering()) { _logger.LogDebug("Ignoring session {SessionId}, group {GroupId} is ready.", session.Id, context.GroupId.ToString()); if (ResumePlaying) { // Client, that was buffering, stopped following playback. var playingState = new PlayingGroupState(LoggerFactory); context.SetState(playingState); var unpauseRequest = new UnpauseGroupRequest(); playingState.HandleRequest(unpauseRequest, context, Type, session, cancellationToken); } else { // Group is ready, returning to previous state. var pausedState = new PausedGroupState(LoggerFactory); context.SetState(pausedState); } } }
public override void HandleRequest(SetPlaylistItemGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } ResumePlaying = true; var result = context.SetPlayingItem(request.PlaylistItemId); if (result) { var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.SetCurrentItem); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken); // Reset status of sessions and await for all Ready events. context.SetAllBuffering(true); } else { // Return to old state. IGroupState newState = prevState switch { GroupStateType.Playing => new PlayingGroupState(LoggerFactory), GroupStateType.Paused => new PausedGroupState(LoggerFactory), _ => new IdleGroupState(LoggerFactory) }; context.SetState(newState); _logger.LogDebug("Unable to change current playing item in group {GroupId}.", context.GroupId.ToString()); } }
/// <inheritdoc /> public override void SessionLeaving(IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Do nothing. }
public override void HandleRequest(UnpauseGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } if (prevState.Equals(GroupStateType.Idle)) { ResumePlaying = true; context.RestartCurrentItem(); var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.NewPlaylist); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken); // Reset status of sessions and await for all Ready events. context.SetAllBuffering(true); _logger.LogDebug("Group {GroupId} is waiting for all ready events.", context.GroupId.ToString()); } else { if (ResumePlaying) { _logger.LogDebug("Forcing the playback to start in group {GroupId}. Group-wait is disabled until next state change.", context.GroupId.ToString()); // An Unpause request is forcing the playback to start, ignoring sessions that are not ready. context.SetAllBuffering(false); // Change state. var playingState = new PlayingGroupState(LoggerFactory) { IgnoreBuffering = true }; context.SetState(playingState); playingState.HandleRequest(request, context, Type, session, cancellationToken); } else { // Group would have gone to paused state, now will go to playing state when ready. ResumePlaying = true; // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); } } }
/// <inheritdoc /> public override void HandleRequest(UnpauseGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { if (!prevState.Equals(Type)) { // Pick a suitable time that accounts for latency. var delayMillis = Math.Max(context.GetHighestPing() * 2, context.DefaultPing); // Unpause group and set starting point in future. // Clients will start playback at LastActivity (datetime) from PositionTicks (playback position). // The added delay does not guarantee, of course, that the command will be received in time. // Playback synchronization will mainly happen client side. context.LastActivity = DateTime.UtcNow.AddMilliseconds(delayMillis); var command = context.NewSyncPlayCommand(SendCommandType.Unpause); context.SendCommand(session, SyncPlayBroadcastType.AllGroup, command, cancellationToken); // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); } else { // Client got lost, sending current state. var command = context.NewSyncPlayCommand(SendCommandType.Unpause); context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken); } }
public override void HandleRequest(PauseGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } // Wait for sessions to be ready, then switch to paused state. ResumePlaying = false; // Notify relevant state change event. SendGroupStateUpdate(context, request, session, cancellationToken); }
public virtual void HandleRequest(MovePlaylistItemGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { var result = context.MoveItemInPlayQueue(request.PlaylistItemId, request.NewIndex); if (!result) { _logger.LogError("Unable to move item in group {GroupId}.", context.GroupId.ToString()); return; } var playQueueUpdate = context.GetPlayQueueUpdate(PlayQueueUpdateReason.MoveItem); var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate); context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken); }
public override void HandleRequest(StopGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Save state if first event. if (!InitialStateSet) { InitialState = prevState; InitialStateSet = true; } // Change state. var idleState = new IdleGroupState(LoggerFactory); context.SetState(idleState); idleState.HandleRequest(request, context, Type, session, cancellationToken); }
public virtual void HandleRequest(NextItemGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { UnhandledRequest(request); }
public override void SessionJoined(IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { SendStopCommand(context, Type, session, cancellationToken); }