private TimeSpan CalculateDownloadTimeout(Segment segment) { if (!IsDynamic) { return(TimeSpan.MaxValue); } var timeout = timeBufferDepthDefault; var averageThroughput = throughputHistory.GetAverageThroughput(); if (averageThroughput > 0 && currentRepresentation.Bandwidth.HasValue && segment.Period != null) { var bandwidth = currentRepresentation.Bandwidth.Value; var duration = segment.Period.Duration.TotalSeconds; var segmentSize = bandwidth * duration; var calculatedTimeNeeded = TimeSpan.FromSeconds(segmentSize / averageThroughput * 1.5); var docParams = currentStreams.GetDocumentParameters(); if (docParams == null) { throw new ArgumentNullException("currentStreams.GetDocumentParameters() returns null"); } var manifestMinBufferDepth = docParams.Document.MinBufferTime ?? TimeSpan.Zero; timeout = calculatedTimeNeeded > manifestMinBufferDepth ? calculatedTimeNeeded : manifestMinBufferDepth; } return(timeout); }
/// <summary> /// Swaps updated representation based on Manifest Reload. /// Updates segment information and base segment ID for the stream. /// </summary> /// <returns>bool. True. Representations were swapped. False otherwise</returns> private void SwapRepresentation() { // Exchange updated representation with "null". On subsequent calls, this will be an indication // that there is no new representations. var newRep = Interlocked.Exchange(ref newRepresentation, null); // Update internals with new representation if exists. if (newRep == null) { return; } initStreamBytes.Clear(); currentRepresentation = newRep; currentStreams = currentRepresentation.Segments; var docParams = currentStreams.GetDocumentParameters(); if (docParams == null) { throw new ArgumentNullException("currentStreams.GetDocumentParameters() returns null"); } currentStreamDuration = IsDynamic ? docParams.Document.MediaPresentationDuration : currentStreams.Duration; if (lastDownloadSegmentTimeRange == null) { currentSegmentId = currentRepresentation.Segments.StartSegmentId(); firstSegmentClock = currentStreams.SegmentTimeRange(currentSegmentId).Start; LogInfo($"Rep. Swap. Start Seg: [{currentSegmentId}]"); return; } var newSeg = currentStreams.NextSegmentId(lastDownloadSegmentTimeRange.Start); string message; if (newSeg.HasValue) { var segmentTimeRange = currentStreams.SegmentTimeRange(newSeg); message = $"Updated Seg: [{newSeg}]/({segmentTimeRange?.Start}-{segmentTimeRange?.Duration})"; } else { message = "Not Found. Setting segment to null"; } LogInfo( $"Rep. Swap. Last Seg: {currentSegmentId}/{lastDownloadSegmentTimeRange.Start}-{lastDownloadSegmentTimeRange.Duration} {message}"); currentSegmentId = newSeg; LogInfo("Representations swapped."); }
public void Start(bool initReloadRequired) { SwapRepresentation(); if (currentRepresentation == null) { throw new Exception("currentRepresentation has not been set"); } initInProgress = true; initDataDuration = currentStreams.GetDocumentParameters().Document.MinBufferTime ?? MinimumBufferTime; initSegmentReloadRequired = initReloadRequired; LogInfo("DashClient start: " + dataRequest.Duration); if (cancellationTokenSource == null || cancellationTokenSource?.IsCancellationRequested == true) { cancellationTokenSource?.Dispose(); cancellationTokenSource = new CancellationTokenSource(); } bufferTime = currentTime; if (currentSegmentId.HasValue == false) { currentSegmentId = currentRepresentation.AlignedStartSegmentID; } if (!trimOffset.HasValue) { trimOffset = currentRepresentation.AlignedTrimOffset; } if (currentStreams.InitSegment == null) { initInProgress = false; } downloadCompletedSubject.OnNext(Unit.Default); }