diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java index f609ad7191..6ba7bb7294 100644 --- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java +++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java @@ -239,12 +239,12 @@ import java.util.concurrent.atomic.AtomicInteger; return false; } } catch (ExoPlaybackException e) { - Log.e(TAG, "Internal track renderer error.", e); + Log.e(TAG, "Renderer error.", e); eventHandler.obtainMessage(MSG_ERROR, e).sendToTarget(); stopInternal(); return true; } catch (IOException e) { - Log.e(TAG, "Source track renderer error.", e); + Log.e(TAG, "Source error.", e); eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForSource(e)).sendToTarget(); stopInternal(); return true; diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSource.java b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSource.java index 528c3557d1..d12d4354bb 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkSource.java @@ -84,4 +84,11 @@ public interface ChunkSource { */ boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e); + /** + * Releases the source. + *

+ * This method should be called when the source is no longer required. + */ + void release(); + } diff --git a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkTrackStream.java b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkTrackStream.java index 1b6366aa6c..2af1f4c1bb 100644 --- a/library/src/main/java/com/google/android/exoplayer/chunk/ChunkTrackStream.java +++ b/library/src/main/java/com/google/android/exoplayer/chunk/ChunkTrackStream.java @@ -37,10 +37,11 @@ import java.util.List; /** * A {@link TrackStream} that loads media in {@link Chunk}s, obtained from a {@link ChunkSource}. */ -public class ChunkTrackStream implements TrackStream, Loader.Callback { +public class ChunkTrackStream implements TrackStream, + Loader.Callback { private final Loader loader; - private final ChunkSource chunkSource; + private final T chunkSource; private final int minLoadableRetryCount; private final LinkedList mediaChunks; private final List readOnlyMediaChunks; @@ -72,7 +73,7 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback { * @param minLoadableRetryCount The minimum number of times that the source should retry a load * before propagating an error. */ - public ChunkTrackStream(ChunkSource chunkSource, LoadControl loadControl, + public ChunkTrackStream(T chunkSource, LoadControl loadControl, int bufferSizeContribution, long positionUs, Handler eventHandler, ChunkTrackStreamEventListener eventListener, int eventSourceId, int minLoadableRetryCount) { this.chunkSource = chunkSource; @@ -109,6 +110,15 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback { } } + /** + * Returns the {@link ChunkSource} used by this stream. + * + * @return The {@link ChunkSource}. + */ + public T getChunkSource() { + return chunkSource; + } + /** * Returns an estimate of the position up to which data is buffered. * @@ -160,6 +170,7 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback { * This method should be called when the stream is no longer required. */ public void release() { + chunkSource.release(); loadControl.unregister(this); if (loader.isLoading()) { loader.cancelLoading(); @@ -181,7 +192,9 @@ public class ChunkTrackStream implements TrackStream, Loader.Callback { @Override public void maybeThrowError() throws IOException { loader.maybeThrowError(); - chunkSource.maybeThrowError(); + if (!loader.isLoading()) { + chunkSource.maybeThrowError(); + } } @Override diff --git a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java index 7ed8a46e4d..6a10bb970e 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/DashChunkSource.java @@ -42,6 +42,7 @@ import com.google.android.exoplayer.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer.extractor.mp4.FragmentedMp4Extractor; import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSpec; +import com.google.android.exoplayer.upstream.Loader; import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.Util; @@ -56,6 +57,7 @@ import java.util.List; */ public class DashChunkSource implements ChunkSource { + private final Loader manifestLoader; private final int adaptationSetIndex; private final TrackGroup trackGroup; private final RepresentationHolder[] representationHolders; @@ -72,6 +74,7 @@ public class DashChunkSource implements ChunkSource { private IOException fatalError; /** + * @param manifestLoader The {@link Loader} being used to load manifests. * @param manifest The initial manifest. * @param adaptationSetIndex The index of the adaptation set in the manifest. * @param trackGroup The track group corresponding to the adaptation set. @@ -82,9 +85,10 @@ public class DashChunkSource implements ChunkSource { * server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified * as the server's unix time minus the local elapsed time. It unknown, set to 0. */ - public DashChunkSource(MediaPresentationDescription manifest, int adaptationSetIndex, - TrackGroup trackGroup, int[] tracks, DataSource dataSource, + public DashChunkSource(Loader manifestLoader, MediaPresentationDescription manifest, + int adaptationSetIndex, TrackGroup trackGroup, int[] tracks, DataSource dataSource, FormatEvaluator adaptiveFormatEvaluator, long elapsedRealtimeOffsetMs) { + this.manifestLoader = manifestLoader; this.manifest = manifest; this.adaptationSetIndex = adaptationSetIndex; this.trackGroup = trackGroup; @@ -131,18 +135,14 @@ public class DashChunkSource implements ChunkSource { } } - public void release() { - if (adaptiveFormatEvaluator != null) { - adaptiveFormatEvaluator.disable(); - } - } - // ChunkSource implementation. @Override public void maybeThrowError() throws IOException { if (fatalError != null) { throw fatalError; + } else { + manifestLoader.maybeThrowError(); } } @@ -273,6 +273,13 @@ public class DashChunkSource implements ChunkSource { return false; } + @Override + public void release() { + if (adaptiveFormatEvaluator != null) { + adaptiveFormatEvaluator.disable(); + } + } + // Private methods. private long getNowUnixTimeUs() { diff --git a/library/src/main/java/com/google/android/exoplayer/dash/DashSampleSource.java b/library/src/main/java/com/google/android/exoplayer/dash/DashSampleSource.java index bc7d7e550e..584d3522d7 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/DashSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/DashSampleSource.java @@ -47,7 +47,6 @@ import android.net.Uri; import android.os.Handler; import android.os.SystemClock; import android.util.Log; -import android.util.Pair; import java.io.BufferedReader; import java.io.IOException; @@ -93,9 +92,7 @@ public final class DashSampleSource implements SampleSource { private int[] trackGroupAdaptationSetIndices; private boolean pendingReset; private long lastSeekPositionUs; - - private DashChunkSource[] chunkSources; - private ChunkTrackStream[] trackStreams; + private ChunkTrackStream[] trackStreams; public DashSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory, BandwidthMeter bandwidthMeter, Handler eventHandler, @@ -110,8 +107,7 @@ public final class DashSampleSource implements SampleSource { dataSource = dataSourceFactory.createDataSource(); manifestParser = new MediaPresentationDescriptionParser(); manifestCallback = new ManifestCallback(); - chunkSources = new DashChunkSource[0]; - trackStreams = new ChunkTrackStream[0]; + trackStreams = newTrackStreamArray(0); } @Override @@ -140,18 +136,15 @@ public final class DashSampleSource implements SampleSource { public TrackStream[] selectTracks(List oldStreams, List newSelections, long positionUs) { int newEnabledSourceCount = trackStreams.length + newSelections.size() - oldStreams.size(); - DashChunkSource[] newChunkSources = new DashChunkSource[newEnabledSourceCount]; - ChunkTrackStream[] newTrackStreams = new ChunkTrackStream[newEnabledSourceCount]; + ChunkTrackStream[] newTrackStreams = + newTrackStreamArray(newEnabledSourceCount); int newEnabledSourceIndex = 0; // Iterate over currently enabled streams, either releasing them or adding them to the new list. - for (int i = 0; i < trackStreams.length; i++) { - ChunkTrackStream trackStream = trackStreams[i]; + for (ChunkTrackStream trackStream : trackStreams) { if (oldStreams.contains(trackStream)) { - chunkSources[i].release(); trackStream.release(); } else { - newChunkSources[newEnabledSourceIndex] = chunkSources[i]; newTrackStreams[newEnabledSourceIndex++] = trackStream; } } @@ -159,14 +152,11 @@ public final class DashSampleSource implements SampleSource { // Instantiate and return new streams. TrackStream[] streamsToReturn = new TrackStream[newSelections.size()]; for (int i = 0; i < newSelections.size(); i++) { - Pair trackComponents = - buildTrackStream(newSelections.get(i), positionUs); - newChunkSources[newEnabledSourceIndex] = trackComponents.first; - newTrackStreams[newEnabledSourceIndex++] = trackComponents.second; - streamsToReturn[i] = trackComponents.second; + newTrackStreams[newEnabledSourceIndex] = buildTrackStream(newSelections.get(i), positionUs); + streamsToReturn[i] = newTrackStreams[newEnabledSourceIndex]; + newEnabledSourceIndex++; } - chunkSources = newChunkSources; trackStreams = newTrackStreams; return streamsToReturn; } @@ -187,7 +177,7 @@ public final class DashSampleSource implements SampleSource { startLoadingManifest(); } } - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { trackStream.continueBuffering(positionUs); } } @@ -196,7 +186,7 @@ public final class DashSampleSource implements SampleSource { public long readReset() { if (pendingReset) { pendingReset = false; - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { trackStream.setReadingEnabled(true); } return lastSeekPositionUs; @@ -207,7 +197,7 @@ public final class DashSampleSource implements SampleSource { @Override public long getBufferedPositionUs() { long bufferedPositionUs = Long.MAX_VALUE; - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { long rendererBufferedPositionUs = trackStream.getBufferedPositionUs(); if (rendererBufferedPositionUs != C.END_OF_SOURCE_US) { bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs); @@ -220,7 +210,7 @@ public final class DashSampleSource implements SampleSource { public void seekToUs(long positionUs) { lastSeekPositionUs = positionUs; pendingReset = true; - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { trackStream.setReadingEnabled(false); trackStream.seekToUs(positionUs); } @@ -229,10 +219,7 @@ public final class DashSampleSource implements SampleSource { @Override public void release() { loader.release(); - for (DashChunkSource chunkSource : chunkSources) { - chunkSource.release(); - } - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { trackStream.release(); } } @@ -254,8 +241,8 @@ public final class DashSampleSource implements SampleSource { prepared = true; } } else { - for (DashChunkSource chunkSource : chunkSources) { - chunkSource.updateManifest(manifest); + for (ChunkTrackStream trackStream : trackStreams) { + trackStream.getChunkSource().updateManifest(manifest); } } } @@ -337,7 +324,7 @@ public final class DashSampleSource implements SampleSource { trackGroups = new TrackGroupArray(trackGroupArray); } - private Pair buildTrackStream(TrackSelection selection, + private ChunkTrackStream buildTrackStream(TrackSelection selection, long positionUs) { int[] selectedTracks = selection.getTracks(); FormatEvaluator adaptiveEvaluator = selectedTracks.length > 1 @@ -348,14 +335,17 @@ public final class DashSampleSource implements SampleSource { int adaptationSetType = adaptationSet.type; int bufferSize = Util.getDefaultBufferSize(adaptationSetType); DataSource dataSource = dataSourceFactory.createDataSource(bandwidthMeter); - DashChunkSource chunkSource = new DashChunkSource(manifest, adaptationSetIndex, + DashChunkSource chunkSource = new DashChunkSource(loader, manifest, adaptationSetIndex, trackGroups.get(selection.group), selectedTracks, dataSource, adaptiveEvaluator, elapsedRealtimeOffset); - ChunkTrackStream trackStream = new ChunkTrackStream(chunkSource, loadControl, bufferSize, - positionUs, eventHandler, eventListener, adaptationSetType, MIN_LOADABLE_RETRY_COUNT); - return Pair.create(chunkSource, trackStream); + return new ChunkTrackStream<>(chunkSource, loadControl, bufferSize, positionUs, eventHandler, + eventListener, adaptationSetType, MIN_LOADABLE_RETRY_COUNT); } + @SuppressWarnings("unchecked") + private static ChunkTrackStream[] newTrackStreamArray(int length) { + return new ChunkTrackStream[length]; + } private final class ManifestCallback implements Loader.Callback> { diff --git a/library/src/main/java/com/google/android/exoplayer/hls/HlsTrackStreamWrapper.java b/library/src/main/java/com/google/android/exoplayer/hls/HlsTrackStreamWrapper.java index efdb53273a..01c211da50 100644 --- a/library/src/main/java/com/google/android/exoplayer/hls/HlsTrackStreamWrapper.java +++ b/library/src/main/java/com/google/android/exoplayer/hls/HlsTrackStreamWrapper.java @@ -93,7 +93,7 @@ import java.util.List; * @param bufferSizeContribution The contribution of this source to the media buffer, in bytes. * @param muxedAudioFormat If HLS master playlist indicates that the stream contains muxed audio, * this is the audio {@link Format} as defined by the playlist. - * @param muxedAudioFormat If HLS master playlist indicates that the stream contains muxed + * @param muxedCaptionFormat If HLS master playlist indicates that the stream contains muxed * captions, this is the audio {@link Format} as defined by the playlist. * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be * null if delivery of events is not required. diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java index 086cfdcdea..f5d7097aae 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingChunkSource.java @@ -34,6 +34,7 @@ import com.google.android.exoplayer.extractor.mp4.TrackEncryptionBox; import com.google.android.exoplayer.smoothstreaming.SmoothStreamingManifest.StreamElement; import com.google.android.exoplayer.upstream.DataSource; import com.google.android.exoplayer.upstream.DataSpec; +import com.google.android.exoplayer.upstream.Loader; import android.net.Uri; import android.text.TextUtils; @@ -47,6 +48,7 @@ import java.util.List; */ public class SmoothStreamingChunkSource implements ChunkSource { + private final Loader manifestLoader; private final int elementIndex; private final TrackGroup trackGroup; private final ChunkExtractorWrapper[] extractorWrappers; @@ -63,6 +65,7 @@ public class SmoothStreamingChunkSource implements ChunkSource { private IOException fatalError; /** + * @param manifestLoader The {@link Loader} being used to load manifests. * @param manifest The initial manifest. * @param elementIndex The index of the stream element in the manifest. * @param trackGroup The track group corresponding to the stream element. @@ -71,9 +74,10 @@ public class SmoothStreamingChunkSource implements ChunkSource { * @param adaptiveFormatEvaluator For adaptive tracks, selects from the available formats. * @param trackEncryptionBoxes Track encryption boxes for the stream. */ - public SmoothStreamingChunkSource(SmoothStreamingManifest manifest, int elementIndex, - TrackGroup trackGroup, int[] tracks, DataSource dataSource, + public SmoothStreamingChunkSource(Loader manifestLoader, SmoothStreamingManifest manifest, + int elementIndex, TrackGroup trackGroup, int[] tracks, DataSource dataSource, FormatEvaluator adaptiveFormatEvaluator, TrackEncryptionBox[] trackEncryptionBoxes) { + this.manifestLoader = manifestLoader; this.manifest = manifest; this.elementIndex = elementIndex; this.trackGroup = trackGroup; @@ -135,18 +139,14 @@ public class SmoothStreamingChunkSource implements ChunkSource { return needManifestRefresh; } - public void release() { - if (adaptiveFormatEvaluator != null) { - adaptiveFormatEvaluator.disable(); - } - } - // ChunkSource implementation. @Override public void maybeThrowError() throws IOException { if (fatalError != null) { throw fatalError; + } else { + manifestLoader.maybeThrowError(); } } @@ -233,6 +233,13 @@ public class SmoothStreamingChunkSource implements ChunkSource { return false; } + @Override + public void release() { + if (adaptiveFormatEvaluator != null) { + adaptiveFormatEvaluator.disable(); + } + } + // Private methods. /** diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingSampleSource.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingSampleSource.java index 36b1d2fbd8..f4e4e7abd4 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingSampleSource.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingSampleSource.java @@ -44,7 +44,6 @@ import android.net.Uri; import android.os.Handler; import android.os.SystemClock; import android.util.Base64; -import android.util.Pair; import java.io.IOException; import java.util.Arrays; @@ -85,8 +84,7 @@ public final class SmoothStreamingSampleSource implements SampleSource, private boolean pendingReset; private long lastSeekPositionUs; - private SmoothStreamingChunkSource[] chunkSources; - private ChunkTrackStream[] trackStreams; + private ChunkTrackStream[] trackStreams; public SmoothStreamingSampleSource(Uri manifestUri, DataSourceFactory dataSourceFactory, BandwidthMeter bandwidthMeter, Handler eventHandler, @@ -97,11 +95,8 @@ public final class SmoothStreamingSampleSource implements SampleSource, this.bandwidthMeter = bandwidthMeter; this.eventHandler = eventHandler; this.eventListener = eventListener; - loadControl = new DefaultLoadControl(new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE)); - chunkSources = new SmoothStreamingChunkSource[0]; - trackStreams = new ChunkTrackStream[0]; - + trackStreams = newTrackStreamArray(0); manifestDataSource = dataSourceFactory.createDataSource(); manifestParser = new SmoothStreamingManifestParser(); manifestLoader = new Loader("Loader:Manifest"); @@ -133,19 +128,15 @@ public final class SmoothStreamingSampleSource implements SampleSource, public TrackStream[] selectTracks(List oldStreams, List newSelections, long positionUs) { int newEnabledSourceCount = trackStreams.length + newSelections.size() - oldStreams.size(); - SmoothStreamingChunkSource[] newChunkSources = - new SmoothStreamingChunkSource[newEnabledSourceCount]; - ChunkTrackStream[] newTrackStreams = new ChunkTrackStream[newEnabledSourceCount]; + ChunkTrackStream[] newTrackStreams = + newTrackStreamArray(newEnabledSourceCount); int newEnabledSourceIndex = 0; // Iterate over currently enabled streams, either releasing them or adding them to the new list. - for (int i = 0; i < trackStreams.length; i++) { - ChunkTrackStream trackStream = trackStreams[i]; + for (ChunkTrackStream trackStream : trackStreams) { if (oldStreams.contains(trackStream)) { - chunkSources[i].release(); trackStream.release(); } else { - newChunkSources[newEnabledSourceIndex] = chunkSources[i]; newTrackStreams[newEnabledSourceIndex++] = trackStream; } } @@ -153,14 +144,11 @@ public final class SmoothStreamingSampleSource implements SampleSource, // Instantiate and return new streams. TrackStream[] streamsToReturn = new TrackStream[newSelections.size()]; for (int i = 0; i < newSelections.size(); i++) { - Pair trackComponents = - buildTrackStream(newSelections.get(i), positionUs); - newChunkSources[newEnabledSourceIndex] = trackComponents.first; - newTrackStreams[newEnabledSourceIndex++] = trackComponents.second; - streamsToReturn[i] = trackComponents.second; + newTrackStreams[newEnabledSourceIndex] = buildTrackStream(newSelections.get(i), positionUs); + streamsToReturn[i] = newTrackStreams[newEnabledSourceIndex]; + newEnabledSourceIndex++; } - chunkSources = newChunkSources; trackStreams = newTrackStreams; return streamsToReturn; } @@ -170,15 +158,15 @@ public final class SmoothStreamingSampleSource implements SampleSource, if (manifest.isLive) { if (!manifestLoader.isLoading() && SystemClock.elapsedRealtime() > manifestLoadTimestamp + MINIMUM_MANIFEST_REFRESH_PERIOD_MS) { - for (SmoothStreamingChunkSource chunkSource : chunkSources) { - if (chunkSource.needManifestRefresh()) { + for (ChunkTrackStream trackStream : trackStreams) { + if (trackStream.getChunkSource().needManifestRefresh()) { startLoadingManifest(); break; } } } } - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { trackStream.continueBuffering(positionUs); } } @@ -187,7 +175,7 @@ public final class SmoothStreamingSampleSource implements SampleSource, public long readReset() { if (pendingReset) { pendingReset = false; - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { trackStream.setReadingEnabled(true); } return lastSeekPositionUs; @@ -198,7 +186,7 @@ public final class SmoothStreamingSampleSource implements SampleSource, @Override public long getBufferedPositionUs() { long bufferedPositionUs = Long.MAX_VALUE; - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { long rendererBufferedPositionUs = trackStream.getBufferedPositionUs(); if (rendererBufferedPositionUs != C.END_OF_SOURCE_US) { bufferedPositionUs = Math.min(bufferedPositionUs, rendererBufferedPositionUs); @@ -211,7 +199,7 @@ public final class SmoothStreamingSampleSource implements SampleSource, public void seekToUs(long positionUs) { lastSeekPositionUs = positionUs; pendingReset = true; - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { trackStream.setReadingEnabled(false); trackStream.seekToUs(positionUs); } @@ -220,10 +208,7 @@ public final class SmoothStreamingSampleSource implements SampleSource, @Override public void release() { manifestLoader.release(); - for (SmoothStreamingChunkSource chunkSource : chunkSources) { - chunkSource.release(); - } - for (ChunkTrackStream trackStream : trackStreams) { + for (ChunkTrackStream trackStream : trackStreams) { trackStream.release(); } } @@ -245,8 +230,8 @@ public final class SmoothStreamingSampleSource implements SampleSource, } prepared = true; } else { - for (SmoothStreamingChunkSource chunkSource : chunkSources) { - chunkSource.updateManifest(manifest); + for (ChunkTrackStream trackStream : trackStreams) { + trackStream.getChunkSource().updateManifest(manifest); } } } @@ -291,8 +276,8 @@ public final class SmoothStreamingSampleSource implements SampleSource, trackGroups = new TrackGroupArray(trackGroupArray); } - private Pair buildTrackStream( - TrackSelection selection, long positionUs) { + private ChunkTrackStream buildTrackStream(TrackSelection selection, + long positionUs) { int[] selectedTracks = selection.getTracks(); FormatEvaluator adaptiveEvaluator = selectedTracks.length > 1 ? new AdaptiveEvaluator(bandwidthMeter) : null; @@ -301,12 +286,16 @@ public final class SmoothStreamingSampleSource implements SampleSource, int streamElementType = streamElement.type; int bufferSize = Util.getDefaultBufferSize(streamElementType); DataSource dataSource = dataSourceFactory.createDataSource(bandwidthMeter); - SmoothStreamingChunkSource chunkSource = new SmoothStreamingChunkSource(manifest, - streamElementIndex, trackGroups.get(selection.group), selectedTracks, dataSource, + SmoothStreamingChunkSource chunkSource = new SmoothStreamingChunkSource(manifestLoader, + manifest, streamElementIndex, trackGroups.get(selection.group), selectedTracks, dataSource, adaptiveEvaluator, trackEncryptionBoxes); - ChunkTrackStream trackStream = new ChunkTrackStream(chunkSource, loadControl, bufferSize, - positionUs, eventHandler, eventListener, streamElementType, MIN_LOADABLE_RETRY_COUNT); - return Pair.create(chunkSource, trackStream); + return new ChunkTrackStream<>(chunkSource, loadControl, bufferSize, positionUs, eventHandler, + eventListener, streamElementType, MIN_LOADABLE_RETRY_COUNT); + } + + @SuppressWarnings("unchecked") + private static ChunkTrackStream[] newTrackStreamArray(int length) { + return new ChunkTrackStream[length]; } private static byte[] getProtectionElementKeyId(byte[] initData) {