From c60103df64104459883f1244363cc9cd39187545 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 6 Apr 2014 13:53:23 -0400 Subject: chromecast updates --- .../Session/SessionManager.cs | 267 +++++++++++++++++++-- .../Session/SessionWebSocketListener.cs | 30 ++- .../Session/WebSocketController.cs | 12 + 3 files changed, 283 insertions(+), 26 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Session') diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 62f04e841..6452d5ac7 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1,8 +1,12 @@ -using MediaBrowser.Common.Events; +using System.IO; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Session; @@ -42,6 +46,8 @@ namespace MediaBrowser.Server.Implementations.Session private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; private readonly IMusicManager _musicManager; + private readonly IDtoService _dtoService; + private readonly IImageProcessor _imageProcessor; /// /// Gets or sets the configuration manager. @@ -68,6 +74,10 @@ namespace MediaBrowser.Server.Implementations.Session /// public event EventHandler PlaybackStopped; + public event EventHandler SessionStarted; + + public event EventHandler SessionEnded; + private IEnumerable _sessionFactories = new List(); private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1); @@ -80,7 +90,7 @@ namespace MediaBrowser.Server.Implementations.Session /// The logger. /// The user repository. /// The library manager. - public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager) + public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor) { _userDataRepository = userDataRepository; _configurationManager = configurationManager; @@ -89,6 +99,8 @@ namespace MediaBrowser.Server.Implementations.Session _libraryManager = libraryManager; _userManager = userManager; _musicManager = musicManager; + _dtoService = dtoService; + _imageProcessor = imageProcessor; } /// @@ -109,6 +121,47 @@ namespace MediaBrowser.Server.Implementations.Session get { return _activeConnections.Values.OrderByDescending(c => c.LastActivityDate).ToList(); } } + private void OnSessionStarted(SessionInfo info) + { + EventHelper.QueueEventIfNotNull(SessionStarted, this, new SessionEventArgs + { + SessionInfo = info + + }, _logger); + } + + private async void OnSessionEnded(SessionInfo info) + { + try + { + await SendSessionEndedNotification(info, CancellationToken.None).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error in SendSessionEndedNotification", ex); + } + + EventHelper.QueueEventIfNotNull(SessionEnded, this, new SessionEventArgs + { + SessionInfo = info + + }, _logger); + + var disposable = info.SessionController as IDisposable; + + if (disposable != null) + { + try + { + disposable.Dispose(); + } + catch (Exception ex) + { + _logger.ErrorException("Error disposing session controller", ex); + } + } + } + /// /// Logs the user activity. /// @@ -194,19 +247,7 @@ namespace MediaBrowser.Server.Implementations.Session if (_activeConnections.TryRemove(key, out removed)) { - var disposable = removed.SessionController as IDisposable; - - if (disposable != null) - { - try - { - disposable.Dispose(); - } - catch (Exception ex) - { - _logger.ErrorException("Error disposing session controller", ex); - } - } + OnSessionEnded(removed); } } finally @@ -222,11 +263,9 @@ namespace MediaBrowser.Server.Implementations.Session /// The item. /// The media version identifier. /// if set to true [is paused]. - /// if set to true [is muted]. /// The current position ticks. - private void UpdateNowPlayingItem(SessionInfo session, BaseItem item, string mediaSourceId, bool isPaused, bool isMuted, long? currentPositionTicks = null) + private void UpdateNowPlayingItem(SessionInfo session, BaseItem item, string mediaSourceId, bool isPaused, long? currentPositionTicks = null) { - session.IsMuted = isMuted; session.IsPaused = isPaused; session.NowPlayingPositionTicks = currentPositionTicks; session.NowPlayingItem = item; @@ -291,12 +330,19 @@ namespace MediaBrowser.Server.Implementations.Session try { - var connection = _activeConnections.GetOrAdd(key, keyName => new SessionInfo + var connection = _activeConnections.GetOrAdd(key, keyName => { - Client = clientType, - DeviceId = deviceId, - ApplicationVersion = appVersion, - Id = Guid.NewGuid() + var sessionInfo = new SessionInfo + { + Client = clientType, + DeviceId = deviceId, + ApplicationVersion = appVersion, + Id = Guid.NewGuid() + }; + + OnSessionStarted(sessionInfo); + + return sessionInfo; }); connection.DeviceName = deviceName; @@ -372,11 +418,14 @@ namespace MediaBrowser.Server.Implementations.Session var mediaSourceId = GetMediaSourceId(item, info.MediaSourceId); - UpdateNowPlayingItem(session, item, mediaSourceId, false, false); + UpdateNowPlayingItem(session, item, mediaSourceId, false); session.CanSeek = info.CanSeek; session.QueueableMediaTypes = info.QueueableMediaTypes; + session.NowPlayingAudioStreamIndex = info.AudioStreamIndex; + session.NowPlayingSubtitleStreamIndex = info.SubtitleStreamIndex; + var key = item.GetUserDataKey(); var users = GetUsers(session); @@ -442,7 +491,12 @@ namespace MediaBrowser.Server.Implementations.Session var mediaSourceId = GetMediaSourceId(info.Item, info.MediaSourceId); - UpdateNowPlayingItem(session, info.Item, mediaSourceId, info.IsPaused, info.IsMuted, info.PositionTicks); + UpdateNowPlayingItem(session, info.Item, mediaSourceId, info.IsPaused, info.PositionTicks); + + session.IsMuted = info.IsMuted; + session.VolumeLevel = info.VolumeLevel; + session.NowPlayingAudioStreamIndex = info.AudioStreamIndex; + session.NowPlayingSubtitleStreamIndex = info.SubtitleStreamIndex; var key = info.Item.GetUserDataKey(); @@ -919,6 +973,27 @@ namespace MediaBrowser.Server.Implementations.Session } + public Task SendSessionEndedNotification(SessionInfo sessionInfo, CancellationToken cancellationToken) + { + var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null).ToList(); + var dto = GetSessionInfoDto(sessionInfo); + + var tasks = sessions.Select(session => Task.Run(async () => + { + try + { + await session.SessionController.SendSessionEndedNotification(dto, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error in SendSessionEndedNotification.", ex); + } + + }, cancellationToken)); + + return Task.WhenAll(tasks); + } + /// /// Adds the additional user. /// @@ -1017,5 +1092,147 @@ namespace MediaBrowser.Server.Implementations.Session session.PlayableMediaTypes = capabilities.PlayableMediaTypes; session.SupportedCommands = capabilities.SupportedCommands; } + + public SessionInfoDto GetSessionInfoDto(SessionInfo session) + { + var dto = new SessionInfoDto + { + Client = session.Client, + DeviceId = session.DeviceId, + DeviceName = session.DeviceName, + Id = session.Id.ToString("N"), + LastActivityDate = session.LastActivityDate, + NowPlayingPositionTicks = session.NowPlayingPositionTicks, + SupportsRemoteControl = session.SupportsRemoteControl, + IsPaused = session.IsPaused, + IsMuted = session.IsMuted, + NowViewingContext = session.NowViewingContext, + NowViewingItemId = session.NowViewingItemId, + NowViewingItemName = session.NowViewingItemName, + NowViewingItemType = session.NowViewingItemType, + ApplicationVersion = session.ApplicationVersion, + CanSeek = session.CanSeek, + QueueableMediaTypes = session.QueueableMediaTypes, + PlayableMediaTypes = session.PlayableMediaTypes, + RemoteEndPoint = session.RemoteEndPoint, + AdditionalUsers = session.AdditionalUsers, + SupportedCommands = session.SupportedCommands, + NowPlayingAudioStreamIndex = session.NowPlayingAudioStreamIndex, + NowPlayingSubtitleStreamIndex = session.NowPlayingSubtitleStreamIndex, + UserName = session.UserName, + VolumeLevel = session.VolumeLevel + }; + + if (session.NowPlayingItem != null) + { + dto.NowPlayingItem = GetNowPlayingInfo(session.NowPlayingItem, session.NowPlayingMediaSourceId, session.NowPlayingRunTimeTicks); + } + + if (session.UserId.HasValue) + { + dto.UserId = session.UserId.Value.ToString("N"); + } + + return dto; + } + + /// + /// Converts a BaseItem to a BaseItemInfo + /// + /// The item. + /// The media version identifier. + /// The now playing runtime ticks. + /// BaseItemInfo. + /// item + private BaseItemInfo GetNowPlayingInfo(BaseItem item, string mediaSourceId, long? nowPlayingRuntimeTicks) + { + if (item == null) + { + throw new ArgumentNullException("item"); + } + + var info = new BaseItemInfo + { + Id = GetDtoId(item), + Name = item.Name, + MediaType = item.MediaType, + Type = item.GetClientTypeName(), + RunTimeTicks = nowPlayingRuntimeTicks, + MediaSourceId = mediaSourceId + }; + + info.PrimaryImageTag = GetImageCacheTag(item, ImageType.Primary); + + var backropItem = item.HasImage(ImageType.Backdrop) ? item : null; + + var thumbItem = item.HasImage(ImageType.Thumb) ? item : null; + + if (thumbItem == null) + { + var episode = item as Episode; + + if (episode != null) + { + var series = episode.Series; + + if (series != null && series.HasImage(ImageType.Thumb)) + { + thumbItem = series; + } + } + } + + if (backropItem == null) + { + var episode = item as Episode; + + if (episode != null) + { + var series = episode.Series; + + if (series != null && series.HasImage(ImageType.Backdrop)) + { + backropItem = series; + } + } + } + + if (thumbItem == null) + { + thumbItem = item.Parents.FirstOrDefault(i => i.HasImage(ImageType.Thumb)); + } + + if (thumbItem != null) + { + info.ThumbImageTag = GetImageCacheTag(thumbItem, ImageType.Thumb); + info.ThumbItemId = GetDtoId(thumbItem); + } + + if (thumbItem != null) + { + info.BackdropImageTag = GetImageCacheTag(backropItem, ImageType.Backdrop); + info.BackdropItemId = GetDtoId(backropItem); + } + + return info; + } + + private Guid? GetImageCacheTag(BaseItem item, ImageType type) + { + try + { + return _imageProcessor.GetImageCacheTag(item, type); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting {0} image info", ex, type); + return null; + } + } + + private string GetDtoId(BaseItem item) + { + return _dtoService.GetDtoId(item); + } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs index fe32e2328..0ed94db8c 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Net; +using System.Globalization; +using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Session; @@ -187,6 +188,8 @@ namespace MediaBrowser.Server.Implementations.Session return result; } + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + /// /// Reports the playback start. /// @@ -228,6 +231,16 @@ namespace MediaBrowser.Server.Implementations.Session info.MediaSourceId = vals[3]; } + if (vals.Length > 4 && !string.IsNullOrWhiteSpace(vals[4])) + { + info.AudioStreamIndex = int.Parse(vals[4], _usCulture); + } + + if (vals.Length > 5 && !string.IsNullOrWhiteSpace(vals[5])) + { + info.SubtitleStreamIndex = int.Parse(vals[5], _usCulture); + } + _sessionManager.OnPlaybackStart(info); } } @@ -275,6 +288,21 @@ namespace MediaBrowser.Server.Implementations.Session 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); } } diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs index 3bb84fa0e..17a3594d8 100644 --- a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs +++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs @@ -198,5 +198,17 @@ namespace MediaBrowser.Server.Implementations.Session }, cancellationToken); } + + public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken) + { + var socket = GetActiveSocket(); + + return socket.SendAsync(new WebSocketMessage + { + MessageType = "SessionEnded", + Data = sessionInfo + + }, cancellationToken); + } } } -- cgit v1.2.3