Fix MaxActiveVideoStreams limit check to prevent transcoding before validation

Move video stream limit validation from SessionManager.OnPlaybackStart() to
DynamicHlsController.GetLiveHlsStream() before transcoding starts. This prevents
FFmpeg processes from starting when users exceed their concurrent video stream limits.
This commit is contained in:
Mahmoud Almontasser 2025-08-03 20:07:50 +02:00
parent 22783bbff1
commit 03125c8904
2 changed files with 28 additions and 22 deletions

View File

@ -755,27 +755,6 @@ namespace Emby.Server.Implementations.Session
? null
: GetNowPlayingItem(session, info.ItemId);
// Check video stream limits before allowing playback
if (libraryItem?.MediaType == MediaType.Video)
{
var sessionUsers = GetUsers(session);
foreach (var user in sessionUsers)
{
if (user.MaxActiveVideoStreams > 0)
{
var activeVideoStreams = Sessions.Count(s =>
s.UserId.Equals(user.Id) &&
s.NowPlayingItem?.MediaType == MediaType.Video);
_logger.LogInformation("Current/Max video streams for user {User}: {VideoStreams}/{MaxVideoStreams}", user.Username, activeVideoStreams, user.MaxActiveVideoStreams);
if (activeVideoStreams >= user.MaxActiveVideoStreams)
{
throw new MediaBrowser.Controller.Net.SecurityException($"User '{user.Username}' has reached their maximum number of concurrent video streams ({user.MaxActiveVideoStreams}).");
}
}
}
}
await UpdateNowPlayingItem(session, info, libraryItem, true).ConfigureAwait(false);
if (!string.IsNullOrEmpty(session.DeviceId) && info.PlayMethod != PlayMethod.Transcode)

View File

@ -19,6 +19,7 @@ using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Streaming;
using MediaBrowser.MediaEncoding.Encoder;
using MediaBrowser.Model.Configuration;
@ -60,6 +61,7 @@ public class DynamicHlsController : BaseJellyfinApiController
private readonly IDynamicHlsPlaylistGenerator _dynamicHlsPlaylistGenerator;
private readonly DynamicHlsHelper _dynamicHlsHelper;
private readonly EncodingOptions _encodingOptions;
private readonly ISessionManager _sessionManager;
/// <summary>
/// Initializes a new instance of the <see cref="DynamicHlsController"/> class.
@ -75,6 +77,7 @@ public class DynamicHlsController : BaseJellyfinApiController
/// <param name="dynamicHlsHelper">Instance of <see cref="DynamicHlsHelper"/>.</param>
/// <param name="encodingHelper">Instance of <see cref="EncodingHelper"/>.</param>
/// <param name="dynamicHlsPlaylistGenerator">Instance of <see cref="IDynamicHlsPlaylistGenerator"/>.</param>
/// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param>
public DynamicHlsController(
ILibraryManager libraryManager,
IUserManager userManager,
@ -86,7 +89,8 @@ public class DynamicHlsController : BaseJellyfinApiController
ILogger<DynamicHlsController> logger,
DynamicHlsHelper dynamicHlsHelper,
EncodingHelper encodingHelper,
IDynamicHlsPlaylistGenerator dynamicHlsPlaylistGenerator)
IDynamicHlsPlaylistGenerator dynamicHlsPlaylistGenerator,
ISessionManager sessionManager)
{
_libraryManager = libraryManager;
_userManager = userManager;
@ -99,6 +103,7 @@ public class DynamicHlsController : BaseJellyfinApiController
_dynamicHlsHelper = dynamicHlsHelper;
_encodingHelper = encodingHelper;
_dynamicHlsPlaylistGenerator = dynamicHlsPlaylistGenerator;
_sessionManager = sessionManager;
_encodingOptions = serverConfigurationManager.GetEncodingOptions();
}
@ -297,6 +302,28 @@ public class DynamicHlsController : BaseJellyfinApiController
cancellationToken)
.ConfigureAwait(false);
// Check video stream limits before starting transcoding
if (state.MediaSource?.VideoType is not null)
{
var userId = HttpContext.User.GetUserId();
if (!userId.IsEmpty())
{
var user = _userManager.GetUserById(userId);
if (user is not null && user.MaxActiveVideoStreams > 0)
{
var activeVideoStreams = _sessionManager.Sessions.Count(s =>
s.UserId.Equals(user.Id) &&
s.NowPlayingItem?.MediaType == MediaType.Video);
_logger.LogInformation("Current/Max video streams for user {User}: {VideoStreams}/{MaxVideoStreams}", user.Username, activeVideoStreams, user.MaxActiveVideoStreams);
if (activeVideoStreams >= user.MaxActiveVideoStreams)
{
throw new MediaBrowser.Controller.Net.SecurityException($"User '{user.Username}' has reached their maximum number of concurrent video streams ({user.MaxActiveVideoStreams}).");
}
}
}
}
TranscodingJob? job = null;
var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");