aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs37
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs8
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs35
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs120
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs129
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs48
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs20
9 files changed, 131 insertions, 276 deletions
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 2d9ea5853..368053b9d 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -498,11 +498,17 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (!string.IsNullOrWhiteSpace(tunerChannel.TunerChannelId))
{
- var mappedTunerChannelId = GetMappedChannel(tunerChannel.TunerChannelId, mappings);
+ var tunerChannelId = tunerChannel.TunerChannelId;
+ if (tunerChannelId.IndexOf(".json.schedulesdirect.org", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ tunerChannelId = tunerChannelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I');
+ }
+
+ var mappedTunerChannelId = GetMappedChannel(tunerChannelId, mappings);
if (string.IsNullOrWhiteSpace(mappedTunerChannelId))
{
- mappedTunerChannelId = tunerChannel.TunerChannelId;
+ mappedTunerChannelId = tunerChannelId;
}
var channel = epgChannels.FirstOrDefault(i => string.Equals(mappedTunerChannelId, i.Id, StringComparison.OrdinalIgnoreCase));
@@ -644,8 +650,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public Task<string> CreateTimer(TimerInfo timer, CancellationToken cancellationToken)
{
- var existingTimer = _timerProvider.GetAll()
- .FirstOrDefault(i => string.Equals(timer.ProgramId, i.ProgramId, StringComparison.OrdinalIgnoreCase));
+ var existingTimer = string.IsNullOrWhiteSpace(timer.ProgramId) ?
+ null :
+ _timerProvider.GetTimerByProgramId(timer.ProgramId);
if (existingTimer != null)
{
@@ -724,10 +731,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return true;
}
- //if (string.Equals(i.SeriesId, info.SeriesId, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(info.SeriesId))
- //{
- // return true;
- //}
+ if (string.Equals(i.SeriesId, info.SeriesId, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(info.SeriesId))
+ {
+ return true;
+ }
return false;
})
@@ -740,7 +747,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
timer.SeriesTimerId = info.Id;
timer.IsManual = true;
- _timerProvider.AddOrUpdate(timer);
+ _timerProvider.AddOrUpdate(timer, false);
}
await UpdateTimersForSeriesTimer(epgData, info, true, false).ConfigureAwait(false);
@@ -2342,6 +2349,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (existingTimer == null)
{
+ existingTimer = string.IsNullOrWhiteSpace(timer.ProgramId)
+ ? null
+ : _timerProvider.GetTimerByProgramId(timer.ProgramId);
+ }
+
+ if (existingTimer == null)
+ {
if (ShouldCancelTimerForSeriesTimer(seriesTimer, timer))
{
timer.Status = RecordingStatus.Cancelled;
@@ -2354,9 +2368,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
else
{
- // Only update if not currently active
+ // Only update if not currently active - test both new timer and existing in case Id's are different
+ // Id's could be different if the timer was created manually prior to series timer creation
ActiveRecordingInfo activeRecordingInfo;
- if (!_activeRecordings.TryGetValue(timer.Id, out activeRecordingInfo))
+ if (!_activeRecordings.TryGetValue(timer.Id, out activeRecordingInfo) && !_activeRecordings.TryGetValue(existingTimer.Id, out activeRecordingInfo))
{
UpdateExistingTimerWithNewMetadata(existingTimer, timer);
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 0567bdfd9..6cc5b6920 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -163,7 +163,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
var inputModifiers = "-fflags +genpts -async 1 -vsync -1";
- var commandLineArgs = "-i \"{0}\"{5} {2} -map_metadata -1 -threads 0 {3}{4} -y \"{1}\"";
+ var commandLineArgs = "-i \"{0}\"{5} {2} -map_metadata -1 -threads 0 {3}{4}{6} -y \"{1}\"";
long startTimeTicks = 0;
//if (mediaSource.DateLiveStreamOpened.HasValue)
@@ -193,7 +193,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var subtitleArgs = CopySubtitles ? " -codec:s copy" : " -sn";
- commandLineArgs = string.Format(commandLineArgs, inputTempFile, targetFile, videoArgs, GetAudioArgs(mediaSource), subtitleArgs, durationParam);
+ var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ?
+ " -f mp4 -movflags frag_keyframe+empty_moov" :
+ string.Empty;
+
+ commandLineArgs = string.Format(commandLineArgs, inputTempFile, targetFile, videoArgs, GetAudioArgs(mediaSource), subtitleArgs, durationParam, outputParam);
return inputModifiers + " " + commandLineArgs;
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 35868d318..2eec3df8a 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -166,5 +166,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
return GetAll().FirstOrDefault(r => string.Equals(r.Id, id, StringComparison.OrdinalIgnoreCase));
}
+
+ public TimerInfo GetTimerByProgramId(string programId)
+ {
+ return GetAll().FirstOrDefault(r => string.Equals(r.ProgramId, programId, StringComparison.OrdinalIgnoreCase));
+ }
}
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 8406d44a7..b9e73b62e 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1078,25 +1078,28 @@ namespace Emby.Server.Implementations.LiveTv
var channel = GetInternalChannel(program.ChannelId);
- var channelUserdata = _userDataManager.GetUserData(userId, channel);
-
- if (channelUserdata.Likes ?? false)
- {
- score += 2;
- }
- else if (!(channelUserdata.Likes ?? true))
+ if (channel != null)
{
- score -= 2;
- }
+ var channelUserdata = _userDataManager.GetUserData(userId, channel);
- if (channelUserdata.IsFavorite)
- {
- score += 3;
- }
+ if (channelUserdata.Likes ?? false)
+ {
+ score += 2;
+ }
+ else if (!(channelUserdata.Likes ?? true))
+ {
+ score -= 2;
+ }
- if (factorChannelWatchCount)
- {
- score += channelUserdata.PlayCount;
+ if (channelUserdata.IsFavorite)
+ {
+ score += 3;
+ }
+
+ if (factorChannelWatchCount)
+ {
+ score += channelUserdata.PlayCount;
+ }
}
return score;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 02a6bf85d..17c57712e 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -275,6 +275,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public int HD { get; set; }
}
+ protected EncodingOptions GetEncodingOptions()
+ {
+ return Config.GetConfiguration<EncodingOptions>("encoding");
+ }
+
+ private string GetHdHrIdFromChannelId(string channelId)
+ {
+ return channelId.Split('_')[1];
+ }
+
private MediaSourceInfo GetMediaSource(TunerHostInfo info, string channelId, ChannelInfo channelInfo, string profile)
{
int? width = null;
@@ -362,14 +372,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
nal = "0";
}
- var url = GetApiUrl(info, true) + "/auto/v" + channelId;
-
- // If raw was used, the tuner doesn't support params
- if (!string.IsNullOrWhiteSpace(profile)
- && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
- {
- url += "?transcode=" + profile;
- }
+ var url = GetApiUrl(info, false);
var id = profile;
if (string.IsNullOrWhiteSpace(id))
@@ -381,92 +384,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var mediaSource = new MediaSourceInfo
{
Path = url,
- Protocol = MediaProtocol.Http,
- MediaStreams = new List<MediaStream>
- {
- new MediaStream
- {
- Type = MediaStreamType.Video,
- // Set the index to -1 because we don't know the exact index of the video stream within the container
- Index = -1,
- IsInterlaced = isInterlaced,
- Codec = videoCodec,
- Width = width,
- Height = height,
- BitRate = videoBitrate,
- NalLengthSize = nal
-
- },
- new MediaStream
- {
- Type = MediaStreamType.Audio,
- // Set the index to -1 because we don't know the exact index of the audio stream within the container
- Index = -1,
- Codec = audioCodec,
- BitRate = audioBitrate
- }
- },
- RequiresOpening = true,
- RequiresClosing = false,
- BufferMs = 0,
- Container = "ts",
- Id = id,
- SupportsDirectPlay = false,
- SupportsDirectStream = true,
- SupportsTranscoding = true,
- IsInfiniteStream = true
- };
-
- mediaSource.InferTotalBitrate();
-
- return mediaSource;
- }
-
- protected EncodingOptions GetEncodingOptions()
- {
- return Config.GetConfiguration<EncodingOptions>("encoding");
- }
-
- private string GetHdHrIdFromChannelId(string channelId)
- {
- return channelId.Split('_')[1];
- }
-
- private MediaSourceInfo GetLegacyMediaSource(TunerHostInfo info, string channelId, ChannelInfo channel)
- {
- int? width = null;
- int? height = null;
- bool isInterlaced = true;
- string videoCodec = null;
- string audioCodec = null;
-
- int? videoBitrate = null;
- int? audioBitrate = null;
-
- if (channel != null)
- {
- if (string.IsNullOrWhiteSpace(videoCodec))
- {
- videoCodec = channel.VideoCodec;
- }
- audioCodec = channel.AudioCodec;
- }
-
- // normalize
- if (string.Equals(videoCodec, "mpeg2", StringComparison.OrdinalIgnoreCase))
- {
- videoCodec = "mpeg2video";
- }
-
- string nal = null;
-
- var url = GetApiUrl(info, false);
- var id = channelId;
- id += "_" + url.GetMD5().ToString("N");
-
- var mediaSource = new MediaSourceInfo
- {
- Path = url,
Protocol = MediaProtocol.Udp,
MediaStreams = new List<MediaStream>
{
@@ -527,7 +444,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (isLegacyTuner)
{
- list.Add(GetLegacyMediaSource(info, hdhrId, channelInfo));
+ list.Add(GetMediaSource(info, hdhrId, channelInfo, "native"));
}
else
{
@@ -579,20 +496,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var hdhomerunChannel = channelInfo as HdHomerunChannelInfo;
+ var mediaSource = GetMediaSource(info, hdhrId, channelInfo, profile);
+ var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
+
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
{
- var mediaSource = GetLegacyMediaSource(info, hdhrId, channelInfo);
- var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
-
return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
}
else
{
- var mediaSource = GetMediaSource(info, hdhrId, channelInfo, profile);
- //var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
-
- return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
- //return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
+ //return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
+ return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index 867e07e87..92000a1b3 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -120,8 +120,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// send url to start streaming
await hdHomerunManager.StartStreaming(remoteAddress, localAddress, localPort, _channelCommands, _numTuners, cancellationToken).ConfigureAwait(false);
- var timeoutToken = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(5000).Token, cancellationToken).Token;
- var response = await udpClient.ReceiveAsync(timeoutToken).ConfigureAwait(false);
_logger.Info("Opened HDHR UDP stream from {0}", remoteAddress);
if (!cancellationToken.IsCancellationRequested)
@@ -132,8 +130,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
onStarted = () => openTaskCompletionSource.TrySetResult(true);
}
- var stream = new UdpClientStream(udpClient);
- await _multicastStream.CopyUntilCancelled(stream, onStarted, cancellationToken).ConfigureAwait(false);
+ await _multicastStream.CopyUntilCancelled(udpClient, onStarted, cancellationToken).ConfigureAwait(false);
}
}
catch (OperationCanceledException ex)
@@ -158,7 +155,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
await hdHomerunManager.StopStreaming().ConfigureAwait(false);
- udpClient.Dispose();
_liveStreamTaskCompletionSource.TrySetResult(true);
}
}
@@ -171,127 +167,4 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _multicastStream.CopyToAsync(stream);
}
}
-
- // This handles the ReadAsync function only of a Stream object
- // This is used to wrap a UDP socket into a stream for MulticastStream which only uses ReadAsync
- public class UdpClientStream : Stream
- {
- private static int RtpHeaderBytes = 12;
- private static int PacketSize = 1316;
- private readonly ISocket _udpClient;
- bool disposed;
-
- public UdpClientStream(ISocket udpClient) : base()
- {
- _udpClient = udpClient;
- }
-
- public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- if (buffer == null)
- throw new ArgumentNullException("buffer");
-
- if (offset + count < 0)
- throw new ArgumentOutOfRangeException("offset + count must not be negative", "offset+count");
-
- if (offset + count > buffer.Length)
- throw new ArgumentException("offset + count must not be greater than the length of buffer", "offset+count");
-
- if (disposed)
- throw new ObjectDisposedException(typeof(UdpClientStream).ToString());
-
- // This will always receive a 1328 packet size (PacketSize + RtpHeaderSize)
- // The RTP header will be stripped so see how many reads we need to make to fill the buffer.
- int numReads = count / PacketSize;
- int totalBytesRead = 0;
-
- for (int i = 0; i < numReads; ++i)
- {
- var data = await _udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
-
- var bytesRead = data.ReceivedBytes - RtpHeaderBytes;
-
- // remove rtp header
- Buffer.BlockCopy(data.Buffer, RtpHeaderBytes, buffer, offset, bytesRead);
- offset += bytesRead;
- totalBytesRead += bytesRead;
- }
- return totalBytesRead;
- }
-
- protected override void Dispose(bool disposing)
- {
- disposed = true;
- }
-
- public override bool CanRead
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public override bool CanSeek
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public override bool CanWrite
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public override long Length
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public override long Position
- {
- get
- {
- throw new NotImplementedException();
- }
-
- set
- {
- throw new NotImplementedException();
- }
- }
-
- public override void Flush()
- {
- throw new NotImplementedException();
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
-
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
- }
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index fe677f6fa..8c4b9bf60 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -144,11 +144,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
channel.TunerChannelId = string.IsNullOrWhiteSpace(tvgId) ? channelId : tvgId;
- if (!string.IsNullOrWhiteSpace(channel.TunerChannelId) && channel.TunerChannelId.IndexOf(".json.schedulesdirect.org", StringComparison.OrdinalIgnoreCase) != -1)
- {
- channel.TunerChannelId = channel.TunerChannelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I');
- }
-
var channelIdValues = new List<string>();
if (!string.IsNullOrWhiteSpace(channelId))
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
index 90ff36441..e3d0d1eba 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
@@ -7,6 +7,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
@@ -40,7 +41,52 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var allStreams = _outputStreams.ToList();
foreach (var stream in allStreams)
{
- stream.Value.Queue(copy);
+ stream.Value.Queue(copy, 0, copy.Length);
+ }
+
+ if (onStarted != null)
+ {
+ var onStartedCopy = onStarted;
+ onStarted = null;
+ Task.Run(onStartedCopy);
+ }
+ }
+
+ else
+ {
+ await Task.Delay(100).ConfigureAwait(false);
+ }
+ }
+ }
+
+ private static int RtpHeaderBytes = 12;
+ public async Task CopyUntilCancelled(ISocket udpClient, Action onStarted, CancellationToken cancellationToken)
+ {
+ _cancellationToken = cancellationToken;
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ var receiveToken = cancellationToken;
+
+ // On the first connection attempt, put a timeout to avoid being stuck indefinitely in the event of failure
+ if (onStarted != null)
+ {
+ receiveToken = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(5000).Token, cancellationToken).Token;
+ }
+
+ var data = await udpClient.ReceiveAsync(receiveToken).ConfigureAwait(false);
+ var bytesRead = data.ReceivedBytes - RtpHeaderBytes;
+
+ if (bytesRead > 0)
+ {
+ byte[] copy = new byte[bytesRead];
+ Buffer.BlockCopy(data.Buffer, RtpHeaderBytes, copy, 0, bytesRead);
+
+ var allStreams = _outputStreams.ToList();
+ foreach (var stream in allStreams)
+ {
+ //stream.Value.Queue(data.Buffer, RtpHeaderBytes, bytesRead);
+ stream.Value.Queue(copy, 0, copy.Length);
}
if (onStarted != null)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
index 7b48ce21a..27dd288a7 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
@@ -13,7 +13,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public class QueueStream
{
private readonly Stream _outputStream;
- private readonly ConcurrentQueue<byte[]> _queue = new ConcurrentQueue<byte[]>();
+ private readonly ConcurrentQueue<Tuple<byte[],int,int>> _queue = new ConcurrentQueue<Tuple<byte[], int, int>>();
private CancellationToken _cancellationToken;
public TaskCompletionSource<bool> TaskCompletion { get; private set; }
@@ -28,9 +28,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
TaskCompletion = new TaskCompletionSource<bool>();
}
- public void Queue(byte[] bytes)
+ public void Queue(byte[] bytes, int offset, int count)
{
- _queue.Enqueue(bytes);
+ _queue.Enqueue(new Tuple<byte[], int, int>(bytes, offset, count));
}
public void Start(CancellationToken cancellationToken)
@@ -39,12 +39,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
Task.Run(() => StartInternal());
}
- private byte[] Dequeue()
+ private Tuple<byte[], int, int> Dequeue()
{
- byte[] bytes;
- if (_queue.TryDequeue(out bytes))
+ Tuple<byte[], int, int> result;
+ if (_queue.TryDequeue(out result))
{
- return bytes;
+ return result;
}
return null;
@@ -58,10 +58,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
while (true)
{
- var bytes = Dequeue();
- if (bytes != null)
+ var result = Dequeue();
+ if (result != null)
{
- await _outputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+ await _outputStream.WriteAsync(result.Item1, result.Item2, result.Item3, cancellationToken).ConfigureAwait(false);
}
else
{