private static async void DispatcherTimerOnTick(object sender, EventArgs eventArgs) { if (_apiClient == null || BackgroundAudioPlayer.Instance.PlayerState != PlayState.Playing) { return; } try { var track = BackgroundAudioPlayer.Instance.Track; var info = new PlaybackProgressInfo { ItemId = track.Tag, //UserId = _apiClient.CurrentUserId, PositionTicks = BackgroundAudioPlayer.Instance.Position.Ticks, IsMuted = false, IsPaused = false }; await _apiClient.ReportPlaybackProgressAsync(info); } catch (HttpException ex) { _logger.FatalException("DispatcherTimerOnTick()", ex); } }
/// <summary> /// Updates the now playing item id. /// </summary> /// <param name="session">The session.</param> /// <param name="info">The information.</param> /// <param name="libraryItem">The library item.</param> private void UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem) { var runtimeTicks = libraryItem.RunTimeTicks; if (string.IsNullOrWhiteSpace(info.MediaSourceId)) { info.MediaSourceId = info.ItemId; } if (!string.Equals(info.ItemId, info.MediaSourceId) && !string.IsNullOrWhiteSpace(info.MediaSourceId)) { runtimeTicks = _libraryManager.GetItemById(new Guid(info.MediaSourceId)).RunTimeTicks; } if (!string.IsNullOrWhiteSpace(info.ItemId)) { info.Item = GetItemInfo(libraryItem, runtimeTicks); } session.NowPlayingItem = info.Item; session.LastActivityDate = DateTime.UtcNow; session.PlayState.IsPaused = info.IsPaused; session.PlayState.PositionTicks = info.PositionTicks; session.PlayState.MediaSourceId = info.MediaSourceId; session.PlayState.CanSeek = info.CanSeek; session.PlayState.IsMuted = info.IsMuted; session.PlayState.VolumeLevel = info.VolumeLevel; session.PlayState.AudioStreamIndex = info.AudioStreamIndex; session.PlayState.SubtitleStreamIndex = info.SubtitleStreamIndex; session.PlayState.PlayMethod = info.PlayMethod; }
/// <summary> /// Used to report playback progress for an item /// </summary> /// <param name="info">The info.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentOutOfRangeException">positionTicks</exception> public async Task OnPlaybackProgress(PlaybackProgressInfo info) { if (info == null) { throw new ArgumentNullException("info"); } var session = GetSession(info.SessionId); var libraryItem = string.IsNullOrWhiteSpace(info.ItemId) ? null : _libraryManager.GetItemById(new Guid(info.ItemId)); UpdateNowPlayingItem(session, info, libraryItem); var users = GetUsers(session); if (libraryItem != null) { var key = libraryItem.GetUserDataKey(); foreach (var user in users) { await OnPlaybackProgress(user.Id, key, libraryItem, info.PositionTicks).ConfigureAwait(false); } } EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs { Item = libraryItem, Users = users, PlaybackPositionTicks = session.PlayState.PositionTicks, MediaSourceId = session.PlayState.MediaSourceId }, _logger); }
/// <summary> /// Timers the callback. /// </summary> /// <param name="state">The state.</param> private async void TimerCallback(object state) { var item = _mediaPlayer.CurrentMedia; if (item == null) { return; } var info = new PlaybackProgressInfo { //SessionId = _sessionManager //Item = item, ItemId = item.Id, //MediaSourceId = string.Empty, IsMuted = _playback.IsMuted, IsPaused = _mediaPlayer.PlayState == PlayState.Paused, PositionTicks = _mediaPlayer.CurrentPositionTicks, CanSeek = _mediaPlayer.CanSeek, AudioStreamIndex = _mediaPlayer.CurrentAudioStreamIndex, SubtitleStreamIndex = _mediaPlayer.CurrentSubtitleStreamIndex, VolumeLevel = (_mediaPlayer.PlayState != PlayState.Idle) ? (int?)_playback.Volume : null, PlayMethod = PlayMethod.DirectPlay, // todo remove hard coding }; try { await _apiClient.ReportPlaybackProgressAsync(info); } catch (Exception ex) { _logger.ErrorException("Error sending playback progress checking for {0}", ex, item.Name); } }
/// <summary> /// Used to report playback progress for an item /// </summary> /// <param name="info">The info.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentOutOfRangeException">positionTicks</exception> public async Task OnPlaybackProgress(PlaybackProgressInfo info) { if (info == null) { throw new ArgumentNullException("info"); } if (info.PositionTicks.HasValue && info.PositionTicks.Value < 0) { throw new ArgumentOutOfRangeException("positionTicks"); } var session = Sessions.First(i => i.Id.Equals(info.SessionId)); UpdateNowPlayingItem(session, info.Item, info.IsPaused, info.IsMuted, info.PositionTicks); var key = info.Item.GetUserDataKey(); var users = GetUsers(session); foreach (var user in users) { await OnPlaybackProgress(user.Id, key, info.Item, info.PositionTicks).ConfigureAwait(false); } EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs { Item = info.Item, Users = users, PlaybackPositionTicks = info.PositionTicks }, _logger); }
private async void TimerOnTick(object sender, EventArgs eventArgs) { try { var totalTicks = _startPositionTicks + PlayedVideoDuration.Ticks; Log.Info("Sending current runtime [{0}] to the server", totalTicks); var info = new PlaybackProgressInfo { ItemId = _itemId, IsMuted = false, IsPaused = false, PositionTicks = totalTicks }; await _playbackManager.ReportPlaybackProgress(info, _streamInfo, false, ApiClient); SetPlaybackTicks(totalTicks); } catch (HttpException ex) { Utils.HandleHttpException("TimerOnTick()", ex, NavigationService, Log); } }
/// <summary> /// Reports playback progress /// </summary> /// <param name="info">The information.</param> /// <param name="isOffline">if set to <c>true</c> [is offline].</param> /// <param name="apiClient">The current apiClient. It can be null if offline</param> /// <returns>Task.</returns> public async Task ReportPlaybackProgress(PlaybackProgressInfo info, bool isOffline, IApiClient apiClient) { if (!isOffline) { await apiClient.ReportPlaybackProgressAsync(info).ConfigureAwait(false); } }
public async Task <ActionResult> ReportPlaybackProgress([FromBody] PlaybackProgressInfo playbackProgressInfo) { playbackProgressInfo.PlayMethod = ValidatePlayMethod(playbackProgressInfo.PlayMethod, playbackProgressInfo.PlaySessionId); playbackProgressInfo.SessionId = RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id; await _sessionManager.OnPlaybackProgress(playbackProgressInfo).ConfigureAwait(false); return(NoContent()); }
/// <summary> /// Reports the playback progress. /// </summary> /// <param name="message">The message.</param> private void OnPlaybackProgress(WebSocketMessageInfo message) { var session = GetSessionFromMessage(message); if (session != null && session.UserId.HasValue) { var vals = message.Data.Split('|'); var itemId = vals[0]; long?positionTicks = null; if (vals.Length > 1) { long pos; if (long.TryParse(vals[1], out pos)) { positionTicks = pos; } } var isPaused = vals.Length > 2 && string.Equals(vals[2], "true", StringComparison.OrdinalIgnoreCase); var isMuted = vals.Length > 3 && string.Equals(vals[3], "true", StringComparison.OrdinalIgnoreCase); var info = new PlaybackProgressInfo { ItemId = itemId, PositionTicks = positionTicks, IsMuted = isMuted, IsPaused = isPaused, SessionId = session.Id }; if (vals.Length > 4) { info.MediaSourceId = vals[4]; } if (vals.Length > 5 && !string.IsNullOrWhiteSpace(vals[5])) { info.VolumeLevel = int.Parse(vals[5], _usCulture); } if (vals.Length > 5 && !string.IsNullOrWhiteSpace(vals[6])) { info.AudioStreamIndex = int.Parse(vals[6], _usCulture); } if (vals.Length > 7 && !string.IsNullOrWhiteSpace(vals[7])) { info.SubtitleStreamIndex = int.Parse(vals[7], _usCulture); } _sessionManager.OnPlaybackProgress(info); } }
public async Task UpdatePlaybackStatus(string mediaSourceId, TimeSpan position) { PlaybackProgressInfo data = new PlaybackProgressInfo(); if (Guid.TryParse(mediaSourceId, out Guid itemId)) { data.ItemId = itemId; } data.MediaSourceId = mediaSourceId; data.PositionTicks = position.Ticks; await DoPost("Sessions/Playing/Progress", data); }
/// <summary> /// Reports playback progress /// </summary> /// <param name="info">The information.</param> /// <param name="streamInfo">The stream information.</param> /// <param name="isOffline">if set to <c>true</c> [is offline].</param> /// <param name="apiClient">The current apiClient. It can be null if offline</param> /// <returns>Task.</returns> public async Task ReportPlaybackProgress(PlaybackProgressInfo info, StreamInfo streamInfo, bool isOffline, IApiClient apiClient) { if (!isOffline) { if (streamInfo != null) { info.PlaySessionId = streamInfo.PlaySessionId; if (streamInfo.MediaSource != null) { info.LiveStreamId = streamInfo.MediaSource.LiveStreamId; } } await apiClient.ReportPlaybackProgressAsync(info).ConfigureAwait(false); } }
/// <summary> /// Posts the specified request. /// </summary> /// <param name="request">The request.</param> public void Post(OnPlaybackProgress request) { var user = _userManager.GetUserById(request.UserId); var item = _dtoService.GetItemByDtoId(request.Id, user.Id); var info = new PlaybackProgressInfo { Item = item, PositionTicks = request.PositionTicks, IsMuted = request.IsMuted, IsPaused = request.IsPaused, SessionId = GetSession().Id }; var task = _sessionManager.OnPlaybackProgress(info); Task.WaitAll(task); }
public async Task <ActionResult> OnPlaybackProgress( [FromRoute, Required] Guid userId, [FromRoute, Required] Guid itemId, [FromQuery] string?mediaSourceId, [FromQuery] long?positionTicks, [FromQuery] int?audioStreamIndex, [FromQuery] int?subtitleStreamIndex, [FromQuery] int?volumeLevel, [FromQuery] PlayMethod?playMethod, [FromQuery] string?liveStreamId, [FromQuery] string?playSessionId, [FromQuery] RepeatMode?repeatMode, [FromQuery] bool isPaused = false, [FromQuery] bool isMuted = false) { var playbackProgressInfo = new PlaybackProgressInfo { ItemId = itemId, PositionTicks = positionTicks, IsMuted = isMuted, IsPaused = isPaused, MediaSourceId = mediaSourceId, AudioStreamIndex = audioStreamIndex, SubtitleStreamIndex = subtitleStreamIndex, VolumeLevel = volumeLevel, PlayMethod = playMethod ?? PlayMethod.Transcode, PlaySessionId = playSessionId, LiveStreamId = liveStreamId, RepeatMode = repeatMode ?? RepeatMode.RepeatNone }; playbackProgressInfo.PlayMethod = ValidatePlayMethod(playbackProgressInfo.PlayMethod, playbackProgressInfo.PlaySessionId); playbackProgressInfo.SessionId = await RequestHelpers.GetSessionId(_sessionManager, _authContext, Request).ConfigureAwait(false); await _sessionManager.OnPlaybackProgress(playbackProgressInfo).ConfigureAwait(false); return(NoContent()); }
/// <summary> /// Reports the playback progress. /// </summary> /// <param name="message">The message.</param> private void ReportPlaybackProgress(WebSocketMessageInfo message) { var session = GetSessionFromMessage(message); if (session != null && session.User != null) { var vals = message.Data.Split('|'); var item = _dtoService.GetItemByDtoId(vals[0]); long?positionTicks = null; if (vals.Length > 1) { long pos; if (long.TryParse(vals[1], out pos)) { positionTicks = pos; } } var isPaused = vals.Length > 2 && string.Equals(vals[2], "true", StringComparison.OrdinalIgnoreCase); var isMuted = vals.Length > 3 && string.Equals(vals[3], "true", StringComparison.OrdinalIgnoreCase); var info = new PlaybackProgressInfo { Item = item, PositionTicks = positionTicks, IsMuted = isMuted, IsPaused = isPaused, SessionId = session.Id }; _sessionManager.OnPlaybackProgress(info); } }
/// <summary> /// Used to report playback progress for an item /// </summary> /// <param name="info">The info.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentOutOfRangeException">positionTicks</exception> public async Task OnPlaybackProgress(PlaybackProgressInfo info) { if (info == null) { throw new ArgumentNullException("info"); } if (info.PositionTicks.HasValue && info.PositionTicks.Value < 0) { throw new ArgumentOutOfRangeException("positionTicks"); } var session = Sessions.First(i => i.Id.Equals(info.SessionId)); UpdateNowPlayingItem(session, info.Item, info.IsPaused, info.IsMuted, info.PositionTicks); var key = info.Item.GetUserDataKey(); var user = session.User; if (info.PositionTicks.HasValue) { var data = _userDataRepository.GetUserData(user.Id, key); UpdatePlayState(info.Item, data, info.PositionTicks.Value); await _userDataRepository.SaveUserData(user.Id, info.Item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false); } EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs { Item = info.Item, User = user, PlaybackPositionTicks = info.PositionTicks }, _logger); }
/// <summary> /// Used to report playback progress for an item /// </summary> /// <param name="info">The info.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.ArgumentOutOfRangeException">positionTicks</exception> public async Task OnPlaybackProgress(PlaybackProgressInfo info) { if (info == null) { throw new ArgumentNullException("info"); } var session = GetSession(info.SessionId); var libraryItem = string.IsNullOrWhiteSpace(info.ItemId) ? null : _libraryManager.GetItemById(new Guid(info.ItemId)); UpdateNowPlayingItem(session, info, libraryItem); var users = GetUsers(session); if (libraryItem != null) { var key = libraryItem.GetUserDataKey(); foreach (var user in users) { await OnPlaybackProgress(user.Id, key, libraryItem, info.PositionTicks).ConfigureAwait(false); } } EventHelper.FireEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs { Item = libraryItem, Users = users, PlaybackPositionTicks = session.PlayState.PositionTicks, MediaSourceId = session.PlayState.MediaSourceId, MediaInfo = info.Item, DeviceName = session.DeviceName, ClientName = session.Client, DeviceId = session.DeviceId }, _logger); }
/// <summary> /// Updates the now playing item id. /// </summary> /// <param name="session">The session.</param> /// <param name="info">The information.</param> /// <param name="libraryItem">The library item.</param> private void UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem) { var runtimeTicks = libraryItem == null ? null : libraryItem.RunTimeTicks; if (string.IsNullOrWhiteSpace(info.MediaSourceId)) { info.MediaSourceId = info.ItemId; } if (!string.Equals(info.ItemId, info.MediaSourceId) && !string.IsNullOrWhiteSpace(info.MediaSourceId)) { runtimeTicks = _libraryManager.GetItemById(new Guid(info.MediaSourceId)).RunTimeTicks; } if (!string.IsNullOrWhiteSpace(info.ItemId) && libraryItem != null) { var current = session.NowPlayingItem; if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase)) { info.Item = GetItemInfo(libraryItem, libraryItem, info.MediaSourceId); } else { info.Item = current; } info.Item.RunTimeTicks = runtimeTicks; } session.NowPlayingItem = info.Item; session.LastActivityDate = DateTime.UtcNow; session.PlayState.IsPaused = info.IsPaused; session.PlayState.PositionTicks = info.PositionTicks; session.PlayState.MediaSourceId = info.MediaSourceId; session.PlayState.CanSeek = info.CanSeek; session.PlayState.IsMuted = info.IsMuted; session.PlayState.VolumeLevel = info.VolumeLevel; session.PlayState.AudioStreamIndex = info.AudioStreamIndex; session.PlayState.SubtitleStreamIndex = info.SubtitleStreamIndex; session.PlayState.PlayMethod = info.PlayMethod; }
public override void WireMessages() { Messenger.Default.Register <VideoMessage>(this, m => { PlaylistItems = null; switch (m.PlayerSourceType) { case PlayerSourceType.Video: if (m.VideoItem != null) { SelectedItem = m.VideoItem; PlaylistItems = null; } break; case PlayerSourceType.Recording: if (m.VideoItem != null) { RecordingItem = m.VideoItem; PlaylistItems = null; } break; case PlayerSourceType.Programme: if (m.VideoItem != null) { ProgrammeItem = m.VideoItem; PlaylistItems = null; } break; case PlayerSourceType.Playlist: PlaylistItems = m.VideoPlaylists; SelectedItem = m.VideoItem; break; } PlayerSourceType = m.PlayerSourceType; _isResume = m.IsResume; _startPositionTicks = m.ResumeTicks ?? 0; }); Messenger.Default.Register <NotificationMessage>(this, async m => { if (m.Notification.Equals(Constants.Messages.SetResumeMsg)) { _isResume = true; } if (m.Notification.Equals(Constants.Messages.SendVideoTimeToServerMsg)) { try { var totalTicks = _startPositionTicks + PlayedVideoDuration.Ticks; Log.Info("Sending current runtime [{0}] to the server", totalTicks); var info = new PlaybackStopInfo { ItemId = _itemId, PositionTicks = totalTicks }; await _playbackManager.ReportPlaybackStopped(info, _streamInfo, App.ServerInfo.Id, AuthenticationService.Current.LoggedInUserId, false, ApiClient); SetPlaybackTicks(totalTicks); if (_timer != null && _timer.IsEnabled) { _timer.Stop(); } Messenger.Default.Send(new NotificationMessage(_itemId, totalTicks, Constants.Messages.RefreshResumeMsg)); } catch (HttpException ex) { Utils.HandleHttpException("SendVideoTimeToServer", ex, NavigationService, Log); } if (!PlaylistItems.IsNullOrEmpty()) { var index = PlaylistItems.IndexOf(SelectedItem); if (index >= 0 && index < PlaylistItems.Count - 1) { SelectedItem = PlaylistItems[index + 1]; await InitiatePlayback(false); } } } if (m.Notification.Equals(Constants.Messages.VideoStateChangedMsg)) { try { var totalTicks = _startPositionTicks + PlayedVideoDuration.Ticks; var isPaused = m.Sender != null && (bool)m.Sender; if (_timer != null) { if (isPaused) { if (_timer.IsEnabled) { _timer.Stop(); } } else { if (!_timer.IsEnabled) { _timer.Start(); } } } Log.Info("Sending current runtime [{0}] to the server", totalTicks); var info = new PlaybackProgressInfo { IsMuted = false, ItemId = _itemId, PositionTicks = totalTicks, IsPaused = isPaused }; await ApiClient.ReportPlaybackProgressAsync(info); SetPlaybackTicks(totalTicks); } catch (HttpException ex) { Utils.HandleHttpException("VideoStateChanged", ex, NavigationService, Log); } } }); }
/// <summary> /// Reports the playback progress. /// </summary> /// <param name="message">The message.</param> private void OnPlaybackProgress(WebSocketMessageInfo message) { var session = GetSessionFromMessage(message); if (session != null && session.UserId.HasValue) { var vals = message.Data.Split('|'); var itemId = vals[0]; long? positionTicks = null; if (vals.Length > 1) { long pos; if (long.TryParse(vals[1], out pos)) { positionTicks = pos; } } var isPaused = vals.Length > 2 && string.Equals(vals[2], "true", StringComparison.OrdinalIgnoreCase); var isMuted = vals.Length > 3 && string.Equals(vals[3], "true", StringComparison.OrdinalIgnoreCase); var info = new PlaybackProgressInfo { ItemId = itemId, PositionTicks = positionTicks, IsMuted = isMuted, IsPaused = isPaused, SessionId = session.Id }; if (vals.Length > 4) { info.MediaSourceId = vals[4]; } if (vals.Length > 5 && !string.IsNullOrWhiteSpace(vals[5])) { info.VolumeLevel = int.Parse(vals[5], _usCulture); } if (vals.Length > 5 && !string.IsNullOrWhiteSpace(vals[6])) { info.AudioStreamIndex = int.Parse(vals[6], _usCulture); } if (vals.Length > 7 && !string.IsNullOrWhiteSpace(vals[7])) { info.SubtitleStreamIndex = int.Parse(vals[7], _usCulture); } _sessionManager.OnPlaybackProgress(info); } }
private void ReportEmbyStatus() { //used to report position on stop - by the time the reporter polls, the player might have closed already //long lastPosition = 0; //when MPC-HC is loading a file, its state is None; //before playback starts properly, newer versions of MPC-HC may also report Paused or even Stopped //This flag prevents the reporter from terminating before the player loads the file bool startedPlaying = false; var stopwatch = new Stopwatch(); log.Debug("ProgressReporter thread starting"); for (;;) { stopwatch.Start(); var status = player.GetPlayerStatus(); if (!startedPlaying) { startedPlaying = status.State == PlayerState.Playing; } else { if (status.State == PlayerState.Stopped) { log.Info("MPC-HC is no longer playing"); var stopInfo = new PlaybackStopInfo { ItemId = itemId, PositionTicks = status.Position * Utils.EmbyTicksPerMs }; Utils.IgnoreExceptions(() => embyClient.ReportPlaybackStoppedAsync(stopInfo).Wait()); OnPlayerStopped(EventArgs.Empty); log.Info("Progress reporter terminating"); return; } var progressInfo = new PlaybackProgressInfo { CanSeek = player.CanSeek(), IsPaused = status.State == PlayerState.Paused, IsMuted = status.Muted, ItemId = itemId, PlayMethod = PlayMethod.DirectPlay, PositionTicks = status.Position * Utils.EmbyTicksPerMs, VolumeLevel = status.VolumeLevel, RepeatMode = RepeatMode.RepeatNone }; Utils.IgnoreExceptions(() => embyClient.ReportPlaybackProgressAsync(progressInfo).Wait()); //lastPosition = status.Position; } stopwatch.Stop(); int sleepTime = reportPeriod - (int)stopwatch.ElapsedMilliseconds; log.DebugFormat("Status report took {0}ms.", stopwatch.ElapsedMilliseconds); lock (monitor) { if (stop) { break; } if (sleepTime > 0) { Monitor.Wait(monitor, sleepTime); } if (stop) { break; } } stopwatch.Reset(); } }