Browse Source

fix fallback on mirror channels (#2436)

pull/2432/head
Jason Dove 11 months ago committed by GitHub
parent
commit
9e111a103e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 1
      ErsatzTV.Application/ErsatzTV.Application.csproj
  3. 66
      ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
  4. 4
      ErsatzTV.sln

2
CHANGELOG.md

@ -48,6 +48,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -48,6 +48,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Block schedules: skip media items that will never fit in block duration
- Fix HLS playlist generation for clients that actually care about discontinuities (like hls.js)
- This should resolve most playback issues with built-in channel preview
- Fix deco dead air fallback selection and duration on mirror channels
- Fix fallback filler duration on mirror channels
## [25.6.0] - 2025-09-14
### Added

1
ErsatzTV.Application/ErsatzTV.Application.csproj

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Configurations>Debug;Release;Debug No Sync</Configurations>
</PropertyGroup>
<ItemGroup>

66
ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs

@ -42,6 +42,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -42,6 +42,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
private readonly IPlexPathReplacementService _plexPathReplacementService;
private readonly ISongVideoGenerator _songVideoGenerator;
private readonly ITelevisionRepository _televisionRepository;
private readonly bool _isDebugNoSync;
public GetPlayoutItemProcessByChannelNumberHandler(
IDbContextFactory<TvContext> dbContextFactory,
@ -77,6 +78,12 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -77,6 +78,12 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
_graphicsElementSelector = graphicsElementSelector;
_decoSelector = decoSelector;
_logger = logger;
#if DEBUG_NO_SYNC
_isDebugNoSync = true;
#else
_isDebugNoSync = false;
#endif
}
protected override async Task<Either<BaseError, PlayoutItemProcessModel>> GetProcess(
@ -233,7 +240,10 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -233,7 +240,10 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
.ThenInclude(i => i.Deco)
.ThenInclude(d => d.DecoWatermarks)
.ThenInclude(d => d.Watermark)
.SelectOneAsync(p => p.ChannelId, p => p.ChannelId == channel.Id, cancellationToken);
.SelectOneAsync(
p => p.ChannelId,
p => p.ChannelId == (channel.MirrorSourceChannelId ?? channel.Id),
cancellationToken);
foreach (Playout playout in maybePlayout)
{
@ -264,6 +274,35 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -264,6 +274,35 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
_logger.LogDebug(ex, "Failed to get playout item title");
}
DateTimeOffset start = playoutItemWithPath.PlayoutItem.StartOffset;
DateTimeOffset finish = playoutItemWithPath.PlayoutItem.FinishOffset;
TimeSpan inPoint = playoutItemWithPath.PlayoutItem.InPoint;
TimeSpan outPoint = playoutItemWithPath.PlayoutItem.OutPoint;
DateTimeOffset effectiveNow = request.StartAtZero ? start : now;
TimeSpan duration = finish - effectiveNow;
if (_isDebugNoSync)
{
Command doesNotExistProcess = await _ffmpegProcessService.ForError(
ffmpegPath,
channel,
duration,
$"DEBUG_NO_SYNC:\n{Mapper.GetDisplayTitle(playoutItemWithPath.PlayoutItem.MediaItem, Option<string>.None)}\nFrom: {start} To: {finish}",
request.HlsRealtime,
request.PtsOffset,
channel.FFmpegProfile.VaapiDisplay,
channel.FFmpegProfile.VaapiDriver,
channel.FFmpegProfile.VaapiDevice,
Optional(channel.FFmpegProfile.QsvExtraHardwareFrames));
return new PlayoutItemProcessModel(
doesNotExistProcess,
Option<GraphicsEngineContext>.None,
duration,
finish,
true);
}
MediaVersion version = playoutItemWithPath.PlayoutItem.MediaItem.GetHeadVersion();
string videoPath = playoutItemWithPath.Path;
@ -337,13 +376,6 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -337,13 +376,6 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
.GetValue<bool>(ConfigElementKey.FFmpegSaveReports, cancellationToken)
.Map(result => result.IfNone(false));
DateTimeOffset start = playoutItemWithPath.PlayoutItem.StartOffset;
DateTimeOffset finish = playoutItemWithPath.PlayoutItem.FinishOffset;
TimeSpan inPoint = playoutItemWithPath.PlayoutItem.InPoint;
TimeSpan outPoint = playoutItemWithPath.PlayoutItem.OutPoint;
DateTimeOffset effectiveNow = request.StartAtZero ? start : now;
TimeSpan duration = finish - effectiveNow;
_logger.LogDebug(
"S: {Start}, F: {Finish}, In: {InPoint}, Out: {OutPoint}, EffNow: {EffectiveNow}, Dur: {Duration}",
start,
@ -402,15 +434,17 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -402,15 +434,17 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
foreach (BaseError error in maybePlayoutItem.LeftToSeq())
{
Option<TimeSpan> maybeDuration = await dbContext.PlayoutItems
.Filter(pi => pi.Playout.ChannelId == channel.Id)
Option<DateTimeOffset> maybeNextStart = await dbContext.PlayoutItems
.Filter(pi => pi.Playout.ChannelId == (channel.MirrorSourceChannelId ?? channel.Id))
.Filter(pi => pi.Start > now.UtcDateTime)
.OrderBy(pi => pi.Start)
.FirstOrDefaultAsync(cancellationToken)
.Map(Optional)
.MapT(pi => pi.StartOffset - now);
.MapT(pi => pi.StartOffset);
DateTimeOffset finish = maybeDuration.Match(d => now.Add(d), () => now);
Option<TimeSpan> maybeDuration = maybeNextStart.Map(s => s - now);
DateTimeOffset finish = maybeNextStart.Match(s => s, () => now);
_logger.LogWarning(
"Error locating playout item {@Error}. Will display error from {Start} to {Finish}",
@ -623,7 +657,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -623,7 +657,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
MediaItem item = items[new Random().Next(items.Count)];
Option<TimeSpan> maybeDuration = await dbContext.PlayoutItems
.Filter(pi => pi.Playout.ChannelId == channel.Id)
.Filter(pi => pi.Playout.ChannelId == (channel.MirrorSourceChannelId ?? channel.Id))
.Filter(pi => pi.Start > now.UtcDateTime)
.OrderBy(pi => pi.Start)
.FirstOrDefaultAsync(cancellationToken)
@ -681,6 +715,12 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< @@ -681,6 +715,12 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
{
string path = await GetPlayoutItemPath(playoutItem, cancellationToken);
if (_isDebugNoSync)
{
// pretend it exists so we get a nice error message
return new PlayoutItemWithPath(playoutItem, path);
}
// check filesystem first
if (_localFileSystem.FileExists(path))
{

4
ErsatzTV.sln

@ -55,8 +55,8 @@ Global @@ -55,8 +55,8 @@ Global
{CBA93B70-0241-4A73-ABC6-A6E3976A6D7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBA93B70-0241-4A73-ABC6-A6E3976A6D7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CBA93B70-0241-4A73-ABC6-A6E3976A6D7C}.Release|Any CPU.Build.0 = Release|Any CPU
{CBA93B70-0241-4A73-ABC6-A6E3976A6D7C}.Debug No Sync|Any CPU.ActiveCfg = Debug|Any CPU
{CBA93B70-0241-4A73-ABC6-A6E3976A6D7C}.Debug No Sync|Any CPU.Build.0 = Debug|Any CPU
{CBA93B70-0241-4A73-ABC6-A6E3976A6D7C}.Debug No Sync|Any CPU.ActiveCfg = Debug No Sync|Any CPU
{CBA93B70-0241-4A73-ABC6-A6E3976A6D7C}.Debug No Sync|Any CPU.Build.0 = Debug No Sync|Any CPU
{CE7F1ACD-F286-4761-A7BC-A541A1E25C86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE7F1ACD-F286-4761-A7BC-A541A1E25C86}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE7F1ACD-F286-4761-A7BC-A541A1E25C86}.Release|Any CPU.ActiveCfg = Release|Any CPU

Loading…
Cancel
Save