Browse Source

maintain stream continuity after playout reset (#868)

* maintain stream continuity after playout reset

* maintain continuity after error streams
pull/871/head
Jason Dove 4 years ago committed by GitHub
parent
commit
5003e80500
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 30
      ErsatzTV.Application/Streaming/HlsSessionWorker.cs
  3. 1
      ErsatzTV.sln.DotSettings

2
CHANGELOG.md

@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Fixed
- Maintain stream continuity when playout is rebuilt for a channel that is actively being streamed
## [0.6.2-beta] - 2022-06-18
### Fixed

30
ErsatzTV.Application/Streaming/HlsSessionWorker.cs

@ -27,8 +27,10 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -27,8 +27,10 @@ public class HlsSessionWorker : IHlsSessionWorker
private readonly object _sync = new();
private string _channelNumber;
private bool _firstProcess;
private bool _hasWrittenSegments;
private DateTimeOffset _lastAccess;
private DateTimeOffset _lastDelete = DateTimeOffset.MinValue;
private bool _seekNextItem;
private Option<int> _targetFramerate;
private Timer _timer;
private DateTimeOffset _transcodedUntil;
@ -86,7 +88,11 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -86,7 +88,11 @@ public class HlsSessionWorker : IHlsSessionWorker
}
}
public void PlayoutUpdated() => _firstProcess = true;
public void PlayoutUpdated()
{
_firstProcess = true;
_seekNextItem = true;
}
public async Task Run(string channelNumber, TimeSpan idleTimeout, CancellationToken incomingCancellationToken)
{
@ -203,7 +209,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -203,7 +209,7 @@ public class HlsSessionWorker : IHlsSessionWorker
IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
long ptsOffset = await GetPtsOffset(mediator, _channelNumber, _firstProcess, cancellationToken);
long ptsOffset = await GetPtsOffset(mediator, _channelNumber, cancellationToken);
// _logger.LogInformation("PTS offset: {PtsOffset}", ptsOffset);
var request = new GetPlayoutItemProcessByChannelNumber(
@ -250,6 +256,13 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -250,6 +256,13 @@ public class HlsSessionWorker : IHlsSessionWorker
_logger.LogInformation("HLS process has completed for channel {Channel}", _channelNumber);
_transcodedUntil = processModel.Until;
_firstProcess = false;
if (_seekNextItem)
{
_firstProcess = true;
_seekNextItem = false;
}
_hasWrittenSegments = true;
return true;
}
else
@ -294,6 +307,14 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -294,6 +307,14 @@ public class HlsSessionWorker : IHlsSessionWorker
if (commandResult.ExitCode == 0)
{
_firstProcess = false;
if (_seekNextItem)
{
_firstProcess = true;
_seekNextItem = false;
}
_hasWrittenSegments = true;
return true;
}
}
@ -392,7 +413,6 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -392,7 +413,6 @@ public class HlsSessionWorker : IHlsSessionWorker
private async Task<long> GetPtsOffset(
IMediator mediator,
string channelNumber,
bool firstProcess,
CancellationToken cancellationToken)
{
await Slim.WaitAsync(cancellationToken);
@ -400,8 +420,8 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -400,8 +420,8 @@ public class HlsSessionWorker : IHlsSessionWorker
{
long result = 0;
// the first process always starts at zero
if (firstProcess)
// if we haven't yet written any segments, start at zero
if (!_hasWrittenSegments)
{
return result;
}

1
ErsatzTV.sln.DotSettings

@ -61,6 +61,7 @@ @@ -61,6 +61,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=showtitle/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=strm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Trakt/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=transcoded/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=tvdb/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=tvshow/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=uniqueid/@EntryIndexedValue">True</s:Boolean>

Loading…
Cancel
Save