diff options
Diffstat (limited to 'Emby.Server.Implementations/Session/SessionManager.cs')
| -rw-r--r-- | Emby.Server.Implementations/Session/SessionManager.cs | 126 |
1 files changed, 104 insertions, 22 deletions
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 030da6f73..cf2ca047c 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -7,11 +7,13 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Entities; -using Jellyfin.Data.Entities.Security; +using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Data.Events; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Entities; +using Jellyfin.Database.Implementations.Entities.Security; +using Jellyfin.Database.Implementations.Enums; using Jellyfin.Extensions; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; @@ -62,6 +64,9 @@ namespace Emby.Server.Implementations.Session private readonly ConcurrentDictionary<string, SessionInfo> _activeConnections = new(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, string>> _activeLiveStreamSessions + = new(StringComparer.OrdinalIgnoreCase); + private Timer _idleTimer; private Timer _inactiveTimer; @@ -309,7 +314,7 @@ namespace Emby.Server.Implementations.Session _activeConnections.TryRemove(key, out _); if (!string.IsNullOrEmpty(session.PlayState?.LiveStreamId)) { - await _mediaSourceManager.CloseLiveStream(session.PlayState.LiveStreamId).ConfigureAwait(false); + await CloseLiveStreamIfNeededAsync(session.PlayState.LiveStreamId, session.Id).ConfigureAwait(false); } await OnSessionEnded(session).ConfigureAwait(false); @@ -317,6 +322,42 @@ namespace Emby.Server.Implementations.Session } /// <inheritdoc /> + public async Task CloseLiveStreamIfNeededAsync(string liveStreamId, string sessionIdOrPlaySessionId) + { + bool liveStreamNeedsToBeClosed = false; + + if (_activeLiveStreamSessions.TryGetValue(liveStreamId, out var activeSessionMappings)) + { + if (activeSessionMappings.TryRemove(sessionIdOrPlaySessionId, out var correspondingId)) + { + if (!string.IsNullOrEmpty(correspondingId)) + { + activeSessionMappings.TryRemove(correspondingId, out _); + } + + liveStreamNeedsToBeClosed = true; + } + + if (activeSessionMappings.IsEmpty) + { + _activeLiveStreamSessions.TryRemove(liveStreamId, out _); + } + } + + if (liveStreamNeedsToBeClosed) + { + try + { + await _mediaSourceManager.CloseLiveStream(liveStreamId).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error closing live stream"); + } + } + } + + /// <inheritdoc /> public async ValueTask ReportSessionEnded(string sessionId) { CheckDisposed(); @@ -343,6 +384,11 @@ namespace Emby.Server.Implementations.Session /// <returns>Task.</returns> private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem, bool updateLastCheckInTime) { + if (session is null) + { + return; + } + if (string.IsNullOrEmpty(info.MediaSourceId)) { info.MediaSourceId = info.ItemId.ToString("N", CultureInfo.InvariantCulture); @@ -410,7 +456,7 @@ namespace Emby.Server.Implementations.Session var nowPlayingQueue = info.NowPlayingQueue; - if (nowPlayingQueue?.Length > 0) + if (nowPlayingQueue?.Length > 0 && !nowPlayingQueue.SequenceEqual(session.NowPlayingQueue)) { session.NowPlayingQueue = nowPlayingQueue; @@ -428,6 +474,7 @@ namespace Emby.Server.Implementations.Session private void RemoveNowPlayingItem(SessionInfo session) { session.NowPlayingItem = null; + session.FullNowPlayingItem = null; session.PlayState = new PlayerStateInfo(); if (!string.IsNullOrEmpty(session.DeviceId)) @@ -462,13 +509,11 @@ namespace Emby.Server.Implementations.Session ArgumentException.ThrowIfNullOrEmpty(deviceId); var key = GetSessionKey(appName, deviceId); - - CheckDisposed(); - - if (!_activeConnections.TryGetValue(key, out var sessionInfo)) + SessionInfo newSession = CreateSessionInfo(key, appName, appVersion, deviceId, deviceName, remoteEndPoint, user); + SessionInfo sessionInfo = _activeConnections.GetOrAdd(key, newSession); + if (ReferenceEquals(newSession, sessionInfo)) { - sessionInfo = CreateSession(key, appName, appVersion, deviceId, deviceName, remoteEndPoint, user); - _activeConnections[key] = sessionInfo; + OnSessionStarted(newSession); } sessionInfo.UserId = user?.Id ?? Guid.Empty; @@ -492,7 +537,7 @@ namespace Emby.Server.Implementations.Session return sessionInfo; } - private SessionInfo CreateSession( + private SessionInfo CreateSessionInfo( string key, string appName, string appVersion, @@ -536,7 +581,6 @@ namespace Emby.Server.Implementations.Session sessionInfo.HasCustomDeviceName = true; } - OnSessionStarted(sessionInfo); return sessionInfo; } @@ -675,6 +719,11 @@ namespace Emby.Server.Implementations.Session private BaseItem GetNowPlayingItem(SessionInfo session, Guid itemId) { + if (session is null) + { + return null; + } + var item = session.FullNowPlayingItem; if (item is not null && item.Id.Equals(itemId)) { @@ -725,6 +774,11 @@ namespace Emby.Server.Implementations.Session } } + if (!string.IsNullOrEmpty(info.LiveStreamId)) + { + UpdateLiveStreamActiveSessionMappings(info.LiveStreamId, info.SessionId, info.PlaySessionId); + } + var eventArgs = new PlaybackStartEventArgs { Item = libraryItem, @@ -782,6 +836,32 @@ namespace Emby.Server.Implementations.Session return OnPlaybackProgress(info, false); } + private void UpdateLiveStreamActiveSessionMappings(string liveStreamId, string sessionId, string playSessionId) + { + var activeSessionMappings = _activeLiveStreamSessions.GetOrAdd(liveStreamId, _ => new ConcurrentDictionary<string, string>()); + + if (!string.IsNullOrEmpty(playSessionId)) + { + if (!activeSessionMappings.TryGetValue(sessionId, out var currentPlaySessionId) || currentPlaySessionId != playSessionId) + { + if (!string.IsNullOrEmpty(currentPlaySessionId)) + { + activeSessionMappings.TryRemove(currentPlaySessionId, out _); + } + + activeSessionMappings[sessionId] = playSessionId; + activeSessionMappings[playSessionId] = sessionId; + } + } + else + { + if (!activeSessionMappings.TryGetValue(sessionId, out _)) + { + activeSessionMappings[sessionId] = string.Empty; + } + } + } + /// <summary> /// Used to report playback progress for an item. /// </summary> @@ -794,7 +874,11 @@ namespace Emby.Server.Implementations.Session ArgumentNullException.ThrowIfNull(info); - var session = GetSession(info.SessionId); + var session = GetSession(info.SessionId, false); + if (session is null) + { + return; + } var libraryItem = info.ItemId.IsEmpty() ? null @@ -818,6 +902,11 @@ namespace Emby.Server.Implementations.Session } } + if (!string.IsNullOrEmpty(info.LiveStreamId)) + { + UpdateLiveStreamActiveSessionMappings(info.LiveStreamId, info.SessionId, info.PlaySessionId); + } + var eventArgs = new PlaybackProgressEventArgs { Item = libraryItem, @@ -1000,14 +1089,7 @@ namespace Emby.Server.Implementations.Session if (!string.IsNullOrEmpty(info.LiveStreamId)) { - try - { - await _mediaSourceManager.CloseLiveStream(info.LiveStreamId).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error closing live stream"); - } + await CloseLiveStreamIfNeededAsync(info.LiveStreamId, session.Id).ConfigureAwait(false); } var eventArgs = new PlaybackStopEventArgs @@ -1724,7 +1806,6 @@ namespace Emby.Server.Implementations.Session fields.Remove(ItemFields.DateLastSaved); fields.Remove(ItemFields.DisplayPreferencesId); fields.Remove(ItemFields.Etag); - fields.Remove(ItemFields.InheritedParentalRatingValue); fields.Remove(ItemFields.ItemCounts); fields.Remove(ItemFields.MediaSourceCount); fields.Remove(ItemFields.MediaStreams); @@ -2055,6 +2136,7 @@ namespace Emby.Server.Implementations.Session } _activeConnections.Clear(); + _activeLiveStreamSessions.Clear(); } } } |
