public download_m3u8File_parts_parallel_params_t(DownloadPartsAndSaveInputParams ip) : this() { mc = ip.mc; m3u8File = ip.m3u8File; cts = ip.Cts; requestStepAction = ip.RequestStepAction; responseStepAction = ip.ResponseStepAction; maxDegreeOfParallelism = ip.MaxDegreeOfParallelism; }
public download_m3u8File_parts_parallel_params_t(DownloadPartsAndSaveInputParams ip) : this() { mc = ip.mc; m3u8File = ip.m3u8File; cts = ip.Cts; waitIfPausedEvent = ip.WaitIfPausedEvent; waitingIfPaused = ip.WaitingIfPaused; requestStepAction = ip.RequestStepAction; responseStepAction = ip.ResponseStepAction; maxDegreeOfParallelism = ip.MaxDegreeOfParallelism; useCrossAppInstanceDegreeOfParallelism = ip.UseCrossAppInstanceDegreeOfParallelism; }
private static IEnumerable <m3u8_part_ts> download_m3u8File_parts_parallel(DownloadPartsAndSaveInputParams ip) { var ct = (ip.Cts?.Token).GetValueOrDefault(CancellationToken.None); var m3u8File = ip.m3u8File; var baseAddress = m3u8File.BaseAddress; var totalPatrs = m3u8File.Parts.Count; var successReceivedPartCount = 0; var failedReceivedPartCount = 0; ip.ResponseStepAction?.Invoke(new ResponseStepActionParams(totalPatrs)); var expectedPartNumber = m3u8File.Parts.FirstOrDefault().OrderNumber; var maxPartNumber = m3u8File.Parts.LastOrDefault().OrderNumber; var sourceQueue = new Queue <m3u8_part_ts>(m3u8File.Parts); var downloadPartsSet = new SortedSet <m3u8_part_ts>(default(m3u8_part_ts.comparer)); using (var innerCts = new CancellationTokenSource()) using (var joinedCts = CancellationTokenSource.CreateLinkedTokenSource(ct, innerCts.Token)) using (var canExtractPartEvent = new AutoResetEvent(false)) { //-1-// var task_download = Task.Run(() => { for (var n = 1; sourceQueue.Count != 0; n++) { #region [.check 'waitIfPausedEvent'.] if (!ip.WaitIfPausedEvent.IsSet) { ip.WaitingIfPaused?.Invoke(); ip.WaitIfPausedEvent.Wait(joinedCts.Token); } #endregion ip.DownloadThreadsSemaphore.Wait(/*ct*/ joinedCts.Token); var part = sourceQueue.Dequeue(); var rq = RequestStepActionParams.CreateSuccess(totalPatrs, n, part); ip.RequestStepAction?.Invoke(rq); ip.mc.DownloadPart(part, baseAddress, /*ct*/ joinedCts.Token) .ContinueWith(continuationTask => { var rsp = new ResponseStepActionParams(totalPatrs); if (continuationTask.IsFaulted) { Interlocked.Increment(ref expectedPartNumber); part.SetError(continuationTask.Exception); rsp.SuccessReceivedPartCount = successReceivedPartCount; rsp.FailedReceivedPartCount = Interlocked.Increment(ref failedReceivedPartCount); rsp.Part = part; ip.ResponseStepAction?.Invoke(rsp); innerCts.Cancel(); } else if (!continuationTask.IsCanceled) { var downloadPart = continuationTask.Result; if (downloadPart.Error != null) { rsp.SuccessReceivedPartCount = successReceivedPartCount; rsp.FailedReceivedPartCount = Interlocked.Increment(ref failedReceivedPartCount); } else { rsp.SuccessReceivedPartCount = Interlocked.Increment(ref successReceivedPartCount); rsp.FailedReceivedPartCount = failedReceivedPartCount; rsp.BytesLength = downloadPart.Bytes.Length; } rsp.Part = downloadPart; ip.ResponseStepAction?.Invoke(rsp); lock ( downloadPartsSet ) { downloadPartsSet.Add(downloadPart); canExtractPartEvent.Set(); } } }, /*ct*/ joinedCts.Token); } }, /*ct*/ joinedCts.Token); //-2-// for (var localReadyParts = new Queue <m3u8_part_ts>(Math.Min(0x1000, ip.MaxDegreeOfParallelism)); expectedPartNumber <= maxPartNumber;) { var idx = WaitHandle.WaitAny(new[] { canExtractPartEvent /*0*/, /*ct*/ joinedCts.Token.WaitHandle /*1*/, }); if (idx == 1) //[ct.IsCancellationRequested := 1] { break; } if (idx != 0) //[canExtractPartEvent := 0] { continue; } lock ( downloadPartsSet ) { for ( ; downloadPartsSet.Count != 0;) { var min_part = downloadPartsSet.Min; if (expectedPartNumber == min_part.OrderNumber) { downloadPartsSet.Remove(min_part); Interlocked.Increment(ref expectedPartNumber); ip.DownloadThreadsSemaphore.Release(); localReadyParts.Enqueue(min_part); } else { break; } } } for ( ; localReadyParts.Count != 0;) { var part = localReadyParts.Dequeue(); yield return(part); } } //-3.0-// if (innerCts.IsCancellationRequested) { throw (new m3u8_Exception("Canceled after part download error")); } //-3-// task_download.Wait(); } //-4-// ct.ThrowIfCancellationRequested(); }