/// <summary> /// Runs the read task which keeps a packet buffer as full as possible. /// It reports on DownloadProgress by enqueueing an update to the property /// in order to avoid any kind of disruption to this thread caused by the UI thread. /// </summary> internal void RunPacketReadingWorker() { try { // Holds the packet count for each read cycle var packetsRead = new MediaTypeDictionary <int>(); // State variables for media types var t = MediaType.None; // Store Container in local variable to prevent NullReferenceException // when dispose occurs sametime with read cycle var mediaContainer = Container; var main = mediaContainer.Components.Main.MediaType; var auxs = mediaContainer.Components.MediaTypes.Where(c => c != main && (c == MediaType.Audio || c == MediaType.Video)).ToArray(); var all = auxs.Union(new[] { main }).ToArray(); // State variables for bytes read (give-up condition) var startBytesRead = 0UL; var currentBytesRead = 0UL; // Worker logic begins here while (IsTaskCancellationPending == false) { // Enter a read cycle SeekingDone?.WaitOne(); // Enter a packet reading cycle PacketReadingCycle?.Reset(); if (CanReadMorePackets && mediaContainer.Components.PacketBufferLength < DownloadCacheLength) { // Initialize Packets read to 0 for each component and state variables foreach (var k in mediaContainer.Components.MediaTypes) { packetsRead[k] = 0; } startBytesRead = mediaContainer.Components.TotalBytesRead; currentBytesRead = 0UL; // Start to perform the read loop while (CanReadMorePackets) { // Perform a packet read. t will hold the packet type. t = mediaContainer.Read(); // Discard packets that we don't need (i.e. MediaType == None) if (mediaContainer.Components.MediaTypes.Contains(t) == false) { continue; } // Update the packet count for the components packetsRead[t] += 1; // Ensure we have read at least some packets from main and auxiliary streams. if (packetsRead.Where(k => all.Contains(k.Key)).All(c => c.Value > 0)) { break; } // The give-up condition is that in spite of efforts to read at least one of each, // we could not find the required packet types. currentBytesRead = mediaContainer.Components.TotalBytesRead - startBytesRead; if (currentBytesRead > (ulong)DownloadCacheLength) { break; } } } // finish the reading cycle. PacketReadingCycle?.Set(); // Wait some if we have a full packet buffer or we are unable to read more packets (i.e. EOF). if (mediaContainer.Components.PacketBufferLength >= DownloadCacheLength || CanReadMorePackets == false || currentBytesRead <= 0) { Task.Delay(1).GetAwaiter().GetResult(); } } } catch (ThreadAbortException) { } finally { // Always exit notifying the reading cycle is done. PacketReadingCycle?.Set(); } }
/// <summary> /// Runs the read task which keeps a packet buffer as full as possible. /// It reports on DownloadProgress by enqueueing an update to the property /// in order to avoid any kind of disruption to this thread caused by the UI thread. /// </summary> internal void RunPacketReadingWorker() { // Holds the packet count for each read cycle var packetsRead = new MediaTypeDictionary <int>(); // State variables for media types var t = MediaType.None; // Store Container in local variable to prevent NullReferenceException // when dispose occurs sametime with read cycle var mediaContainer = Container; var main = mediaContainer.Components.Main.MediaType; var auxs = mediaContainer.Components.MediaTypes.FundamentalAuxsFor(main); var all = main.JoinMediaTypes(auxs); try { // Worker logic begins here while (IsTaskCancellationPending == false) { // Wait for seeking to be done. SeekingDone.WaitOne(); // Enter a packet reading cycle PacketReadingCycle.Reset(); // Initialize Packets read to 0 for each component and state variables foreach (var k in mediaContainer.Components.MediaTypes) { packetsRead[k] = 0; } // Start to perform the read loop // NOTE: Disrupting the packet reader causes errors in UPD streams. Disrupt as little as possible while (CanReadMorePackets && ShouldReadMorePackets && IsTaskCancellationPending == false) { // Perform a packet read. t will hold the packet type. t = mediaContainer.Read(); // Discard packets that we don't need (i.e. MediaType == None) if (mediaContainer.Components.MediaTypes.HasMediaType(t) == false) { continue; } // Update the packet count for the components packetsRead[t] += 1; // Ensure we have read at least some packets from main and auxiliary streams. if (packetsRead.FundamentalsGreaterThan(0)) { break; } } // finish the reading cycle. PacketReadingCycle.Set(); // Don't evaluate a pause condition if we are seeking if (SeekingDone.IsSet() == false) { continue; } // Wait some if we have a full packet buffer or we are unable to read more packets (i.e. EOF). if (ShouldReadMorePackets == false || CanReadMorePackets == false || packetsRead.GetSum() <= 0) { Task.Delay(1).GetAwaiter().GetResult(); } } } catch (ThreadAbortException) { /* swallow */ } catch { if (!IsDisposed) { throw; } } finally { // Always exit notifying the reading cycle is done. PacketReadingCycle.Set(); } }