From a90348740d574d960a6cd5961cfc477100ddaba5 Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Wed, 6 Sep 2023 20:01:58 -0500 Subject: [PATCH] fix subsequent hls session work ahead (#1419) --- CHANGELOG.md | 2 +- .../Streaming/HlsSessionWorker.cs | 20 +++++++++++++++---- ...layoutItemProcessByChannelNumberHandler.cs | 4 ++-- ErsatzTV/Controllers/ArtworkController.cs | 15 ++++++++------ 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44e4535a6..298c65934 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix adding alternate schedule ### Changed -- Optimize transcoding session to only work ahead (at max speed) for 2 minutes before throttling to realtime +- Optimize transcoding session to only work ahead (at max speed) for 3 minutes before throttling to realtime - This should *greatly* reduce cpu/gpu use when joining a channel, particularly with long content - Allow manually editing (typing) schedule item fixed start time - Use different control for editing schedule item duration, and allow 24-hour duration diff --git a/ErsatzTV.Application/Streaming/HlsSessionWorker.cs b/ErsatzTV.Application/Streaming/HlsSessionWorker.cs index 67e3a1550..93fc11657 100644 --- a/ErsatzTV.Application/Streaming/HlsSessionWorker.cs +++ b/ErsatzTV.Application/Streaming/HlsSessionWorker.cs @@ -19,6 +19,8 @@ namespace ErsatzTV.Application.Streaming; public class HlsSessionWorker : IHlsSessionWorker { + public static readonly TimeSpan WorkAheadDuration = TimeSpan.FromMinutes(3); + private static readonly SemaphoreSlim Slim = new(1, 1); private static int _workAheadCount; private readonly IMediator _mediator; @@ -269,17 +271,27 @@ public class HlsSessionWorker : IHlsSessionWorker { Interlocked.Increment(ref _workAheadCount); _logger.LogInformation("HLS segmenter will work ahead for channel {Channel}", _channelNumber); + + HlsSessionState nextState = _state switch + { + HlsSessionState.SeekAndRealtime => HlsSessionState.SeekAndWorkAhead, + HlsSessionState.ZeroAndRealtime => HlsSessionState.ZeroAndWorkAhead, + _ => _state + }; + + if (nextState != _state) + { + _logger.LogDebug("HLS session state accelerating {Last} => {Next}", _state, nextState); + _state = nextState; + } } else { _logger.LogInformation( "HLS segmenter will NOT work ahead for channel {Channel}", _channelNumber); - } - // throttle to realtime if needed - if (realtime) - { + // throttle to realtime if needed HlsSessionState nextState = _state switch { HlsSessionState.SeekAndWorkAhead => HlsSessionState.SeekAndRealtime, diff --git a/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs b/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs index f3417084f..317e18321 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs @@ -182,9 +182,9 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< // _logger.LogDebug("PRE Start: {Start}, Finish {Finish}", start, finish); // _logger.LogDebug("PRE in: {In}, out: {Out}", inPoint, outPoint); - if (!request.HlsRealtime && duration > TimeSpan.FromMinutes(2)) + if (!request.HlsRealtime && duration > HlsSessionWorker.WorkAheadDuration) { - finish = effectiveNow + TimeSpan.FromMinutes(2); + finish = effectiveNow + HlsSessionWorker.WorkAheadDuration; outPoint = finish - start + inPoint; isComplete = false; diff --git a/ErsatzTV/Controllers/ArtworkController.cs b/ErsatzTV/Controllers/ArtworkController.cs index 662c0d926..8b82ec557 100644 --- a/ErsatzTV/Controllers/ArtworkController.cs +++ b/ErsatzTV/Controllers/ArtworkController.cs @@ -138,9 +138,9 @@ public class ArtworkController : ControllerBase CancellationToken cancellationToken) { #if DEBUG_NO_SYNC + await Task.CompletedTask; return NotFound(); -#endif - +#else Either connectionParameters = await _mediator.Send(new GetPlexConnectionParameters(plexMediaSourceId), cancellationToken); @@ -165,14 +165,15 @@ public class ArtworkController : ControllerBase stream, response.Content.Headers.ContentType?.MediaType ?? "image/jpeg"); }); +#endif } private async Task GetJellyfinArtwork(string path, CancellationToken cancellationToken) { #if DEBUG_NO_SYNC + await Task.CompletedTask; return NotFound(); -#endif - +#else Either connectionParameters = await _mediator.Send(new GetJellyfinConnectionParameters(), cancellationToken); @@ -196,14 +197,15 @@ public class ArtworkController : ControllerBase stream, response.Content.Headers.ContentType?.MediaType ?? "image/jpeg"); }); +#endif } private async Task GetEmbyArtwork(string path, CancellationToken cancellationToken) { #if DEBUG_NO_SYNC + await Task.CompletedTask; return NotFound(); -#endif - +#else Either connectionParameters = await _mediator.Send(new GetEmbyConnectionParameters(), cancellationToken); @@ -227,5 +229,6 @@ public class ArtworkController : ControllerBase stream, response.Content.Headers.ContentType?.MediaType ?? "image/jpeg"); }); +#endif } }