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
{
/// <summary>
/// Class PausedGroupState.
/// </summary>
/// <remarks>
/// Class is not thread-safe, external locking is required when accessing methods.
/// </remarks>
public class PausedGroupState : AbstractGroupState
{
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger < PausedGroupState > _logger ;
/// <summary>
/// Initializes a new instance of the <see cref="PausedGroupState"/> class.
/// </summary>
/// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
public PausedGroupState ( ILoggerFactory loggerFactory )
: base ( loggerFactory )
{
_logger = LoggerFactory . CreateLogger < PausedGroupState > ( ) ;
}
/// <inheritdoc />
public override GroupStateType Type { get ; } = GroupStateType . Paused ;
/// <inheritdoc />
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 ) ;
}
/// <inheritdoc />
public override void SessionLeaving ( IGroupStateContext context , GroupStateType prevState , SessionInfo session , CancellationToken cancellationToken )
{
// Do nothing.
}
/// <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 ( 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 ) ;
}
/// <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 ( 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 ) ;
}
/// <inheritdoc />
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 ) ;
}
/// <inheritdoc />
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 ) ;
}
/// <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 ) ;
}
}
/// <inheritdoc />
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 ) ;
}
/// <inheritdoc />
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 ) ;
}
}
}