using System; using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.PlaybackDtos; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; namespace Jellyfin.Api.Models.StreamingDtos { /// /// The stream state dto. /// public class StreamState : EncodingJobInfo, IDisposable { private readonly IMediaSourceManager _mediaSourceManager; private readonly TranscodingJobHelper _transcodingJobHelper; private bool _disposed; /// /// Initializes a new instance of the class. /// /// Instance of the interface. /// The . /// The singleton. public StreamState(IMediaSourceManager mediaSourceManager, TranscodingJobType transcodingType, TranscodingJobHelper transcodingJobHelper) : base(transcodingType) { _mediaSourceManager = mediaSourceManager; _transcodingJobHelper = transcodingJobHelper; } /// /// Gets or sets the requested url. /// public string? RequestedUrl { get; set; } // /// // /// Gets or sets the request. // /// // public StreamRequest Request // { // get => (StreamRequest)BaseRequest; // set // { // BaseRequest = value; // // IsVideoRequest = VideoRequest != null; // } // } /// /// Gets or sets the transcoding throttler. /// public TranscodingThrottler? TranscodingThrottler { get; set; } /// /// Gets the video request. /// public VideoStreamRequest VideoRequest => Request as VideoStreamRequest; /// /// Gets or sets the direct stream provicer. /// public IDirectStreamProvider? DirectStreamProvider { get; set; } /// /// Gets or sets the path to wait for. /// public string? WaitForPath { get; set; } /// /// Gets a value indicating whether the request outputs video. /// public bool IsOutputVideo => Request is VideoStreamRequest; /// /// Gets the segment length. /// public int SegmentLength { get { if (Request.SegmentLength.HasValue) { return Request.SegmentLength.Value; } if (EncodingHelper.IsCopyCodec(OutputVideoCodec)) { var userAgent = UserAgent ?? string.Empty; if (userAgent.IndexOf("AppleTV", StringComparison.OrdinalIgnoreCase) != -1 || userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1 || userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 || userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 || userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1) { if (IsSegmentedLiveStream) { return 6; } return 6; } if (IsSegmentedLiveStream) { return 3; } return 6; } return 3; } } /// /// Gets the minimum number of segments. /// public int MinSegments { get { if (Request.MinSegments.HasValue) { return Request.MinSegments.Value; } return SegmentLength >= 10 ? 2 : 3; } } /// /// Gets or sets the user agent. /// public string? UserAgent { get; set; } /// /// Gets or sets a value indicating whether to estimate the content length. /// public bool EstimateContentLength { get; set; } /// /// Gets or sets the transcode seek info. /// public TranscodeSeekInfo TranscodeSeekInfo { get; set; } /// /// Gets or sets a value indicating whether to enable dlna headers. /// public bool EnableDlnaHeaders { get; set; } /// /// Gets or sets the device profile. /// public DeviceProfile? DeviceProfile { get; set; } /// /// Gets or sets the transcoding job. /// public TranscodingJobDto? TranscodingJob { get; set; } /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// public override void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) { _transcodingJobHelper.ReportTranscodingProgress(TranscodingJob!, this, transcodingPosition, framerate, percentComplete, bytesTranscoded, bitRate); } /// /// Disposes the stream state. /// /// Whether the object is currently beeing disposed. protected virtual void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { // REVIEW: Is this the right place for this? if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Request.LiveStreamId) && !string.IsNullOrWhiteSpace(MediaSource.LiveStreamId)) { _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).GetAwaiter().GetResult(); } TranscodingThrottler?.Dispose(); } TranscodingThrottler = null; TranscodingJob = null; _disposed = true; } } }