@Override public void maybeThrowError() throws IOException { if (fatalError != null) { throw fatalError; } else { manifestFetcher.maybeThrowError(); } }
@Override public void enable(int track) { enabledTrack = tracks.get(track); if (enabledTrack.isAdaptive()) { adaptiveFormatEvaluator.enable(); } if (manifestFetcher != null) { manifestFetcher.enable(); } }
@Override public void disable(List<? extends MediaChunk> queue) { if (enabledTrack.isAdaptive()) { adaptiveFormatEvaluator.disable(); } if (manifestFetcher != null) { manifestFetcher.disable(); } evaluation.format = null; fatalError = null; }
@Override public void continueBuffering(long playbackPositionUs) { if (manifestFetcher == null || !currentManifest.isLive || fatalError != null) { return; } SmoothStreamingManifest newManifest = manifestFetcher.getManifest(); if (currentManifest != newManifest && newManifest != null) { StreamElement currentElement = currentManifest.streamElements[enabledTrack.elementIndex]; int currentElementChunkCount = currentElement.chunkCount; StreamElement newElement = newManifest.streamElements[enabledTrack.elementIndex]; if (currentElementChunkCount == 0 || newElement.chunkCount == 0) { // There's no overlap between the old and new elements because at least one is empty. currentManifestChunkOffset += currentElementChunkCount; } else { long currentElementEndTimeUs = currentElement.getStartTimeUs(currentElementChunkCount - 1) + currentElement.getChunkDurationUs(currentElementChunkCount - 1); long newElementStartTimeUs = newElement.getStartTimeUs(0); if (currentElementEndTimeUs <= newElementStartTimeUs) { // There's no overlap between the old and new elements. currentManifestChunkOffset += currentElementChunkCount; } else { // The new element overlaps with the old one. currentManifestChunkOffset += currentElement.getChunkIndex(newElementStartTimeUs); } } currentManifest = newManifest; needManifestRefresh = false; } if (needManifestRefresh && (SystemClock.elapsedRealtime() > manifestFetcher.getManifestLoadStartTimestamp() + MINIMUM_MANIFEST_REFRESH_PERIOD_MS)) { manifestFetcher.requestRefresh(); } }
/** * Constructor to use for live streaming. * * <p>May also be used for fixed duration content, in which case the call is equivalent to calling * the other constructor, passing {@code manifestFetcher.getManifest()} is the first argument. * * @param manifestFetcher A fetcher for the manifest, which must have already successfully * completed an initial load. * @param trackSelector Selects tracks from the manifest to be exposed by this source. * @param dataSource A {@link DataSource} suitable for loading the media data. * @param adaptiveFormatEvaluator For adaptive tracks, selects from the available formats. * @param liveEdgeLatencyMs For live streams, the number of milliseconds that the playback should * lag behind the "live edge" (i.e. the end of the most recently defined media in the * manifest). Choosing a small value will minimize latency introduced by the player, however * note that the value sets an upper bound on the length of media that the player can buffer. * Hence a small value may increase the probability of rebuffering and playback failures. */ public SmoothStreamingChunkSource( ManifestFetcher<SmoothStreamingManifest> manifestFetcher, SmoothStreamingTrackSelector trackSelector, DataSource dataSource, FormatEvaluator adaptiveFormatEvaluator, long liveEdgeLatencyMs) { this( manifestFetcher, manifestFetcher.getManifest(), trackSelector, dataSource, adaptiveFormatEvaluator, liveEdgeLatencyMs); }