< Summary - Jellyfin

Information
Class: Jellyfin.LiveTv.TunerHosts.LiveStream
Assembly: Jellyfin.LiveTv
File(s): /srv/git/jellyfin/src/Jellyfin.LiveTv/TunerHosts/LiveStream.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 43
Coverable lines: 43
Total lines: 176
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)0%620%
SetTempFilePath(...)100%210%
Open(...)100%210%
GetStream()0%620%
Dispose()100%210%
Dispose(...)0%2040%
TrySeek(...)0%620%

File(s)

/srv/git/jellyfin/src/Jellyfin.LiveTv/TunerHosts/LiveStream.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CA1711
 4#pragma warning disable CS1591
 5
 6using System;
 7using System.Globalization;
 8using System.IO;
 9using System.Threading;
 10using System.Threading.Tasks;
 11using MediaBrowser.Common.Configuration;
 12using MediaBrowser.Controller.Library;
 13using MediaBrowser.Model.Dto;
 14using MediaBrowser.Model.IO;
 15using MediaBrowser.Model.LiveTv;
 16using Microsoft.Extensions.Logging;
 17
 18namespace Jellyfin.LiveTv.TunerHosts
 19{
 20    public class LiveStream : ILiveStream
 21    {
 22        private readonly IConfigurationManager _configurationManager;
 23
 24        public LiveStream(
 25            MediaSourceInfo mediaSource,
 26            TunerHostInfo tuner,
 27            IFileSystem fileSystem,
 28            ILogger logger,
 29            IConfigurationManager configurationManager,
 30            IStreamHelper streamHelper)
 31        {
 032            OriginalMediaSource = mediaSource;
 33            FileSystem = fileSystem;
 034            MediaSource = mediaSource;
 35            Logger = logger;
 036            EnableStreamSharing = true;
 037            UniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
 38
 039            if (tuner is not null)
 40            {
 041                TunerHostId = tuner.Id;
 42            }
 43
 044            _configurationManager = configurationManager;
 45            StreamHelper = streamHelper;
 46
 047            ConsumerCount = 1;
 048            SetTempFilePath("ts");
 049        }
 50
 51        protected IFileSystem FileSystem { get; }
 52
 53        protected IStreamHelper StreamHelper { get; }
 54
 55        protected ILogger Logger { get; }
 56
 57        protected CancellationTokenSource LiveStreamCancellationTokenSource { get; } = new CancellationTokenSource();
 58
 59        protected string TempFilePath { get; set; }
 60
 61        public MediaSourceInfo OriginalMediaSource { get; set; }
 62
 63        public MediaSourceInfo MediaSource { get; set; }
 64
 65        public int ConsumerCount { get; set; }
 66
 67        public string OriginalStreamId { get; set; }
 68
 69        public bool EnableStreamSharing { get; set; }
 70
 71        public string UniqueId { get; }
 72
 73        public string TunerHostId { get; }
 74
 75        public DateTime DateOpened { get; protected set; }
 76
 77        protected void SetTempFilePath(string extension)
 78        {
 079            TempFilePath = Path.Combine(_configurationManager.GetTranscodePath(), UniqueId + "." + extension);
 080        }
 81
 82        public virtual Task Open(CancellationToken openCancellationToken)
 83        {
 084            DateOpened = DateTime.UtcNow;
 085            return Task.CompletedTask;
 86        }
 87
 88        public async Task Close()
 89        {
 90            EnableStreamSharing = false;
 91
 92            Logger.LogInformation("Closing {Type}", GetType().Name);
 93
 94            await LiveStreamCancellationTokenSource.CancelAsync().ConfigureAwait(false);
 95        }
 96
 97        public Stream GetStream()
 98        {
 099            var stream = new FileStream(
 0100                TempFilePath,
 0101                FileMode.Open,
 0102                FileAccess.Read,
 0103                FileShare.ReadWrite,
 0104                IODefaults.FileStreamBufferSize,
 0105                FileOptions.SequentialScan | FileOptions.Asynchronous);
 106
 0107            bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10;
 0108            if (seekFile)
 109            {
 0110                TrySeek(stream, -20000);
 111            }
 112
 0113            return stream;
 114        }
 115
 116        /// <inheritdoc />
 117        public void Dispose()
 118        {
 0119            Dispose(true);
 0120            GC.SuppressFinalize(this);
 0121        }
 122
 123        protected virtual void Dispose(bool dispose)
 124        {
 0125            if (dispose)
 126            {
 0127                LiveStreamCancellationTokenSource?.Dispose();
 128            }
 0129        }
 130
 131        protected async Task DeleteTempFiles(string path, int retryCount = 0)
 132        {
 133            if (retryCount == 0)
 134            {
 135                Logger.LogInformation("Deleting temp file {FilePath}", path);
 136            }
 137
 138            try
 139            {
 140                FileSystem.DeleteFile(path);
 141            }
 142            catch (Exception ex)
 143            {
 144                Logger.LogError(ex, "Error deleting file {FilePath}", path);
 145                if (retryCount <= 40)
 146                {
 147                    await Task.Delay(500).ConfigureAwait(false);
 148                    await DeleteTempFiles(path, retryCount + 1).ConfigureAwait(false);
 149                }
 150            }
 151        }
 152
 153        private void TrySeek(FileStream stream, long offset)
 154        {
 0155            if (!stream.CanSeek)
 156            {
 0157                return;
 158            }
 159
 160            try
 161            {
 0162                stream.Seek(offset, SeekOrigin.End);
 0163            }
 0164            catch (IOException)
 165            {
 0166            }
 0167            catch (ArgumentException)
 168            {
 0169            }
 0170            catch (Exception ex)
 171            {
 0172                Logger.LogError(ex, "Error seeking stream");
 0173            }
 0174        }
 175    }
 176}