internal DataReceivedEventArgs(byte[] data, long startTime, long endTime, IManifestStream stream, IManifestTrack track) { StartTime = startTime; EndTime = endTime; Data = data; Stream = stream; Track = track; }
void UpdateSelectedTrack(TimeSpan position) { lock (bitrateLog) // make this is thread safe since the collection can be updated on a background thread. { foreach (var item in bitrateLog.ToList()) { if (item.TimeStamp <= position.Ticks) { bitrateLog.Remove(item); selectedTrack = item.Track; } else { break; } } } }
public void RefreshState(TimeSpan position) { Position = position; if (RefreshingState != null) { RefreshingState(this, new RefreshingStateEventArgs(position)); } IManifestTrack selectedTrack = null; lock (bitrateLog) // make this is thread safe since the collection can be updated on a background thread. { foreach (var item in bitrateLog.ToList()) { if (item.TimeStamp <= position.Ticks) { bitrateLog.Remove(item); selectedTrack = item.Track; } else { break; } } } if (selectedTrack != null) { CurrentBitrate = selectedTrack.Bitrate; CurrentWidth = selectedTrack.MaxWidth; CurrentHeight = selectedTrack.MaxHeight; var videoStream = VideoStream; LowestBitrate = videoStream.SelectedTracks.Min(t => t.Bitrate); HighestBitrate = videoStream.SelectedTracks.Max(t => t.Bitrate); if (StateChanged != null) { StateChanged(this, EventArgs.Empty); } } }
internal DataErrorEventArgs(Exception error, IManifestStream stream, IManifestTrack track) { Error = error; Stream = stream; Track = track; }
private async Task PollFragmentsAsync(IManifestStream stream, IManifestTrack track, CancellationToken cancellationToken) { try { var iter = stream.FirstInCurrentChunkList; var finished = false; ChunkInfo?chunkInfo = await stream.GetChunkInfoAsync(iter); cancellationToken.ThrowIfCancellationRequested(); do { try { // add small artificial delay if chunk is more than 1 minute away so we don't hog bandwidth if (chunkInfo.Value.ChunkTime > Position.Add(TimeSpan.FromMinutes(1)).Ticks) { await Task.Delay(ChunkCachePollingIntervalMilliseconds, cancellationToken); } var chunkData = (await stream.GetChunkDataAsync(iter, track)).ToArray(); cancellationToken.ThrowIfCancellationRequested(); var currentChunkInfo = chunkInfo.Value; if (iter.MoveNext()) { chunkInfo = await stream.GetChunkInfoAsync(iter); cancellationToken.ThrowIfCancellationRequested(); } else { chunkInfo = null; finished = true; } OnDataReceived(new DataReceivedEventArgs(chunkData, currentChunkInfo.ChunkTime, chunkInfo.HasValue ? chunkInfo.Value.ChunkTime : ActiveAdaptiveSource.Manifest.Duration, stream, track)); if (finished && IsLive) // for live situations, we need to keep checking { do { await Task.Delay(ChunkLivePollingIntervalMilliseconds, cancellationToken); // wait 1 second before checking again finished = !IsLive; // recheck in case EndOfLive occurred } while (!finished && !iter.MoveNext()); if (!finished) { chunkInfo = await stream.GetChunkInfoAsync(iter); cancellationToken.ThrowIfCancellationRequested(); } } } catch (OperationCanceledException) { throw; } catch (Exception ex) { OnDataError(new DataErrorEventArgs(ex, stream, track)); finished = true; } } while (!finished); } catch (OperationCanceledException) { throw; } catch (Exception ex) { OnDataError(new DataErrorEventArgs(ex, stream, track)); } }
public BitrateLogEntry(long timeStamp, IManifestTrack track) { TimeStamp = timeStamp; Track = track; }
public AudioStreamAttributes(IManifestTrack track) { this.track = track; }
public VideoTrackAttributes(IManifestTrack track) { this.track = track; }