#nullable disable using System; using System.Threading; using MediaBrowser.Controller.Session; using MediaBrowser.Controller.SyncPlay.PlaybackRequests; using MediaBrowser.Model.SyncPlay; using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.SyncPlay.GroupStates { /// /// Class PausedGroupState. /// /// /// Class is not thread-safe, external locking is required when accessing methods. /// public class PausedGroupState : AbstractGroupState { /// /// Initializes a new instance of the class. /// /// Instance of the interface. public PausedGroupState(ILoggerFactory loggerFactory) : base(loggerFactory) { } /// public override GroupStateType Type { get; } = GroupStateType.Paused; /// public override void SessionJoined(IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Wait for session to be ready. var waitingState = new WaitingGroupState(LoggerFactory); context.SetState(waitingState); waitingState.SessionJoined(context, Type, session, cancellationToken); } /// public override void SessionLeaving(IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Do nothing. } /// 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); } /// public override void HandleRequest(UnpauseGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Change state. var playingState = new PlayingGroupState(LoggerFactory); context.SetState(playingState); playingState.HandleRequest(request, context, Type, session, cancellationToken); } /// 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); } } /// public override void HandleRequest(StopGroupRequest request, IGroupStateContext context, GroupStateType prevState, SessionInfo session, CancellationToken cancellationToken) { // Change state. var idleState = new IdleGroupState(LoggerFactory); context.SetState(idleState); idleState.HandleRequest(request, context, Type, session, cancellationToken); } /// public override void HandleRequest(SeekGroupRequest 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); } /// public override void HandleRequest(BufferGroupRequest 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); } /// 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(NextItemGroupRequest 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); } /// public override void HandleRequest(PreviousItemGroupRequest 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); } } }