PlayingGroupState.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using System;
  2. using System.Threading;
  3. using MediaBrowser.Controller.Session;
  4. using MediaBrowser.Model.SyncPlay;
  5. using Microsoft.Extensions.Logging;
  6. namespace MediaBrowser.Controller.SyncPlay
  7. {
  8. /// <summary>
  9. /// Class PlayingGroupState.
  10. /// </summary>
  11. /// <remarks>
  12. /// Class is not thread-safe, external locking is required when accessing methods.
  13. /// </remarks>
  14. public class PlayingGroupState : AbstractGroupState
  15. {
  16. /// <summary>
  17. /// Ignore requests for buffering.
  18. /// </summary>
  19. public bool IgnoreBuffering { get; set; }
  20. /// <summary>
  21. /// Default constructor.
  22. /// </summary>
  23. public PlayingGroupState(ILogger logger)
  24. : base(logger)
  25. {
  26. // Do nothing.
  27. }
  28. /// <inheritdoc />
  29. public override GroupState GetGroupState()
  30. {
  31. return GroupState.Playing;
  32. }
  33. /// <inheritdoc />
  34. public override void SessionJoined(ISyncPlayStateContext context, GroupState prevState, SessionInfo session, CancellationToken cancellationToken)
  35. {
  36. // Wait for session to be ready.
  37. var waitingState = new WaitingGroupState(_logger);
  38. context.SetState(waitingState);
  39. waitingState.SessionJoined(context, GetGroupState(), session, cancellationToken);
  40. }
  41. /// <inheritdoc />
  42. public override void SessionLeaving(ISyncPlayStateContext context, GroupState prevState, SessionInfo session, CancellationToken cancellationToken)
  43. {
  44. // Do nothing.
  45. }
  46. /// <inheritdoc />
  47. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, PlayGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  48. {
  49. // Change state.
  50. var waitingState = new WaitingGroupState(_logger);
  51. context.SetState(waitingState);
  52. waitingState.HandleRequest(context, GetGroupState(), request, session, cancellationToken);
  53. }
  54. /// <inheritdoc />
  55. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, UnpauseGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  56. {
  57. if (!prevState.Equals(GetGroupState()))
  58. {
  59. // Pick a suitable time that accounts for latency.
  60. var delayMillis = Math.Max(context.GetHighestPing() * 2, context.DefaultPing);
  61. // Unpause group and set starting point in future.
  62. // Clients will start playback at LastActivity (datetime) from PositionTicks (playback position).
  63. // The added delay does not guarantee, of course, that the command will be received in time.
  64. // Playback synchronization will mainly happen client side.
  65. context.LastActivity = DateTime.UtcNow.AddMilliseconds(
  66. delayMillis
  67. );
  68. var command = context.NewSyncPlayCommand(SendCommandType.Unpause);
  69. context.SendCommand(session, SyncPlayBroadcastType.AllGroup, command, cancellationToken);
  70. // Notify relevant state change event.
  71. SendGroupStateUpdate(context, request, session, cancellationToken);
  72. }
  73. else
  74. {
  75. // Client got lost, sending current state.
  76. var command = context.NewSyncPlayCommand(SendCommandType.Unpause);
  77. context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken);
  78. }
  79. }
  80. /// <inheritdoc />
  81. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, PauseGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  82. {
  83. // Change state.
  84. var pausedState = new PausedGroupState(_logger);
  85. context.SetState(pausedState);
  86. pausedState.HandleRequest(context, GetGroupState(), request, session, cancellationToken);
  87. }
  88. /// <inheritdoc />
  89. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, StopGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  90. {
  91. // Change state.
  92. var idleState = new IdleGroupState(_logger);
  93. context.SetState(idleState);
  94. idleState.HandleRequest(context, GetGroupState(), request, session, cancellationToken);
  95. }
  96. /// <inheritdoc />
  97. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, SeekGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  98. {
  99. // Change state.
  100. var waitingState = new WaitingGroupState(_logger);
  101. context.SetState(waitingState);
  102. waitingState.HandleRequest(context, GetGroupState(), request, session, cancellationToken);
  103. }
  104. /// <inheritdoc />
  105. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, BufferGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  106. {
  107. if (IgnoreBuffering)
  108. {
  109. return;
  110. }
  111. // Change state.
  112. var waitingState = new WaitingGroupState(_logger);
  113. context.SetState(waitingState);
  114. waitingState.HandleRequest(context, GetGroupState(), request, session, cancellationToken);
  115. }
  116. /// <inheritdoc />
  117. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, ReadyGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  118. {
  119. if (prevState.Equals(GetGroupState()))
  120. {
  121. // Group was not waiting, make sure client has latest state.
  122. var command = context.NewSyncPlayCommand(SendCommandType.Unpause);
  123. context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken);
  124. }
  125. else if (prevState.Equals(GroupState.Waiting))
  126. {
  127. // Notify relevant state change event.
  128. SendGroupStateUpdate(context, request, session, cancellationToken);
  129. }
  130. }
  131. /// <inheritdoc />
  132. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, NextTrackGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  133. {
  134. // Change state.
  135. var waitingState = new WaitingGroupState(_logger);
  136. context.SetState(waitingState);
  137. waitingState.HandleRequest(context, GetGroupState(), request, session, cancellationToken);
  138. }
  139. /// <inheritdoc />
  140. public override void HandleRequest(ISyncPlayStateContext context, GroupState prevState, PreviousTrackGroupRequest request, SessionInfo session, CancellationToken cancellationToken)
  141. {
  142. // Change state.
  143. var waitingState = new WaitingGroupState(_logger);
  144. context.SetState(waitingState);
  145. waitingState.HandleRequest(context, GetGroupState(), request, session, cancellationToken);
  146. }
  147. }
  148. }