Commit 85b61adb by andrewlewis Committed by Oliver Woodman

Call onPrepared/onSourceInfoRefreshed on the playback thread.

HlsSampleStreamWrapper and ExtractorMediaPeriod would call
onPrepared/onSourceInfoRefreshed from their loading threads. That was
problematic for ConcatenatingMediaSource and MergingMediaSource, which assume
that their callbacks are called on the same thread (iterating through timelines
from all sources and updating pendingTimelineSources respectively). This change
makes them post calls to the callbacks on the playback thread.

Generally, implementing a composite MediaSource is easier if
MediaPeriod.Callback's methods are all called on the same (playback) thread, so
this change makes that part of its contract.

Also post onContinueLoadingRequested from ExtractingLoadable because
MergingMediaPeriod.onContinueLoadingRequested reads trackGroups written on the
playback thread.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=134407280
parent eaf82188
...@@ -66,6 +66,9 @@ import java.util.Arrays; ...@@ -66,6 +66,9 @@ import java.util.Arrays;
private final Loader loader; private final Loader loader;
private final ExtractorHolder extractorHolder; private final ExtractorHolder extractorHolder;
private final ConditionVariable loadCondition; private final ConditionVariable loadCondition;
private final Runnable maybeFinishPrepareRunnable;
private final Runnable onContinueLoadingRequestedRunnable;
private final Handler handler;
private SeekMap seekMap; private SeekMap seekMap;
private boolean tracksBuilt; private boolean tracksBuilt;
...@@ -85,6 +88,7 @@ import java.util.Arrays; ...@@ -85,6 +88,7 @@ import java.util.Arrays;
private int extractedSamplesCountAtStartOfLoad; private int extractedSamplesCountAtStartOfLoad;
private boolean loadingFinished; private boolean loadingFinished;
private boolean released;
/** /**
* @param uri The {@link Uri} of the media stream. * @param uri The {@link Uri} of the media stream.
...@@ -100,7 +104,7 @@ import java.util.Arrays; ...@@ -100,7 +104,7 @@ import java.util.Arrays;
public ExtractorMediaPeriod(Uri uri, DataSource dataSource, Extractor[] extractors, public ExtractorMediaPeriod(Uri uri, DataSource dataSource, Extractor[] extractors,
int minLoadableRetryCount, Handler eventHandler, int minLoadableRetryCount, Handler eventHandler,
ExtractorMediaSource.EventListener eventListener, MediaSource.Listener sourceListener, ExtractorMediaSource.EventListener eventListener, MediaSource.Listener sourceListener,
Callback callback, Allocator allocator) { final Callback callback, Allocator allocator) {
this.uri = uri; this.uri = uri;
this.dataSource = dataSource; this.dataSource = dataSource;
this.minLoadableRetryCount = minLoadableRetryCount; this.minLoadableRetryCount = minLoadableRetryCount;
...@@ -112,6 +116,21 @@ import java.util.Arrays; ...@@ -112,6 +116,21 @@ import java.util.Arrays;
loader = new Loader("Loader:ExtractorMediaPeriod"); loader = new Loader("Loader:ExtractorMediaPeriod");
extractorHolder = new ExtractorHolder(extractors, this); extractorHolder = new ExtractorHolder(extractors, this);
loadCondition = new ConditionVariable(); loadCondition = new ConditionVariable();
maybeFinishPrepareRunnable = new Runnable() {
@Override
public void run() {
maybeFinishPrepare();
}
};
onContinueLoadingRequestedRunnable = new Runnable() {
@Override
public void run() {
if (!released) {
callback.onContinueLoadingRequested(ExtractorMediaPeriod.this);
}
}
};
handler = new Handler();
pendingResetPositionUs = C.TIME_UNSET; pendingResetPositionUs = C.TIME_UNSET;
sampleQueues = new DefaultTrackOutput[0]; sampleQueues = new DefaultTrackOutput[0];
...@@ -126,11 +145,13 @@ import java.util.Arrays; ...@@ -126,11 +145,13 @@ import java.util.Arrays;
@Override @Override
public void run() { public void run() {
extractorHolder.release(); extractorHolder.release();
for (DefaultTrackOutput sampleQueue : sampleQueues) {
sampleQueue.disable();
}
} }
}); });
for (DefaultTrackOutput sampleQueue : sampleQueues) { handler.removeCallbacksAndMessages(null);
sampleQueue.disable(); released = true;
}
} }
@Override @Override
...@@ -330,7 +351,7 @@ import java.util.Arrays; ...@@ -330,7 +351,7 @@ import java.util.Arrays;
return madeProgress ? Loader.RETRY_RESET_ERROR_COUNT : Loader.RETRY; return madeProgress ? Loader.RETRY_RESET_ERROR_COUNT : Loader.RETRY;
} }
// ExtractorOutput implementation. // ExtractorOutput implementation. Called by the loading thread.
@Override @Override
public TrackOutput track(int id) { public TrackOutput track(int id) {
...@@ -344,26 +365,26 @@ import java.util.Arrays; ...@@ -344,26 +365,26 @@ import java.util.Arrays;
@Override @Override
public void endTracks() { public void endTracks() {
tracksBuilt = true; tracksBuilt = true;
maybeFinishPrepare(); handler.post(maybeFinishPrepareRunnable);
} }
@Override @Override
public void seekMap(SeekMap seekMap) { public void seekMap(SeekMap seekMap) {
this.seekMap = seekMap; this.seekMap = seekMap;
maybeFinishPrepare(); handler.post(maybeFinishPrepareRunnable);
} }
// UpstreamFormatChangedListener implementation // UpstreamFormatChangedListener implementation. Called by the loading thread.
@Override @Override
public void onUpstreamFormatChanged(Format format) { public void onUpstreamFormatChanged(Format format) {
maybeFinishPrepare(); handler.post(maybeFinishPrepareRunnable);
} }
// Internal methods. // Internal methods.
private void maybeFinishPrepare() { private void maybeFinishPrepare() {
if (prepared || seekMap == null || !tracksBuilt) { if (released || prepared || seekMap == null || !tracksBuilt) {
return; return;
} }
for (DefaultTrackOutput sampleQueue : sampleQueues) { for (DefaultTrackOutput sampleQueue : sampleQueues) {
...@@ -576,7 +597,7 @@ import java.util.Arrays; ...@@ -576,7 +597,7 @@ import java.util.Arrays;
if (input.getPosition() > position + CONTINUE_LOADING_CHECK_INTERVAL_BYTES) { if (input.getPosition() > position + CONTINUE_LOADING_CHECK_INTERVAL_BYTES) {
position = input.getPosition(); position = input.getPosition();
loadCondition.close(); loadCondition.close();
callback.onContinueLoadingRequested(ExtractorMediaPeriod.this); handler.post(onContinueLoadingRequestedRunnable);
} }
} }
} finally { } finally {
......
...@@ -32,7 +32,7 @@ public interface MediaPeriod extends SequenceableLoader { ...@@ -32,7 +32,7 @@ public interface MediaPeriod extends SequenceableLoader {
/** /**
* Called when preparation completes. * Called when preparation completes.
* <p> * <p>
* May be called from any thread. After invoking this method, the {@link MediaPeriod} can expect * Called on the playback thread. After invoking this method, the {@link MediaPeriod} can expect
* for {@link #selectTracks(TrackSelection[], boolean[], SampleStream[], boolean[], long)} to be * for {@link #selectTracks(TrackSelection[], boolean[], SampleStream[], boolean[], long)} to be
* called with the initial track selection. * called with the initial track selection.
* *
......
...@@ -29,7 +29,7 @@ public interface SequenceableLoader { ...@@ -29,7 +29,7 @@ public interface SequenceableLoader {
/** /**
* Called by the loader to indicate that it wishes for its {@link #continueLoading(long)} method * Called by the loader to indicate that it wishes for its {@link #continueLoading(long)} method
* to be called when it can continue to load data. * to be called when it can continue to load data. Called on the playback thread.
*/ */
void onContinueLoadingRequested(T source); void onContinueLoadingRequested(T source);
......
...@@ -62,6 +62,7 @@ import java.util.List; ...@@ -62,6 +62,7 @@ import java.util.List;
private final Handler continueLoadingHandler; private final Handler continueLoadingHandler;
private final Loader manifestFetcher; private final Loader manifestFetcher;
private final long preparePositionUs; private final long preparePositionUs;
private final Runnable continueLoadingRunnable;
private int pendingPrepareCount; private int pendingPrepareCount;
private HlsPlaylist playlist; private HlsPlaylist playlist;
...@@ -72,7 +73,6 @@ import java.util.List; ...@@ -72,7 +73,6 @@ import java.util.List;
private HlsSampleStreamWrapper[] sampleStreamWrappers; private HlsSampleStreamWrapper[] sampleStreamWrappers;
private HlsSampleStreamWrapper[] enabledSampleStreamWrappers; private HlsSampleStreamWrapper[] enabledSampleStreamWrappers;
private CompositeSequenceableLoader sequenceableLoader; private CompositeSequenceableLoader sequenceableLoader;
private Runnable continueLoadingRunnable;
public HlsMediaPeriod(Uri manifestUri, DataSource.Factory dataSourceFactory, public HlsMediaPeriod(Uri manifestUri, DataSource.Factory dataSourceFactory,
int minLoadableRetryCount, EventDispatcher eventDispatcher, int minLoadableRetryCount, EventDispatcher eventDispatcher,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.hls; package com.google.android.exoplayer2.source.hls;
import android.os.Handler;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.SparseArray; import android.util.SparseArray;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
...@@ -81,13 +82,15 @@ import java.util.LinkedList; ...@@ -81,13 +82,15 @@ import java.util.LinkedList;
private final HlsChunkSource.HlsChunkHolder nextChunkHolder; private final HlsChunkSource.HlsChunkHolder nextChunkHolder;
private final SparseArray<DefaultTrackOutput> sampleQueues; private final SparseArray<DefaultTrackOutput> sampleQueues;
private final LinkedList<HlsMediaChunk> mediaChunks; private final LinkedList<HlsMediaChunk> mediaChunks;
private final Runnable maybeFinishPrepareRunnable;
private final Handler handler;
private volatile boolean sampleQueuesBuilt; private boolean sampleQueuesBuilt;
private boolean prepared; private boolean prepared;
private int enabledTrackCount; private int enabledTrackCount;
private Format downstreamTrackFormat; private Format downstreamTrackFormat;
private int upstreamChunkUid; private int upstreamChunkUid;
private boolean released;
// Tracks are complicated in HLS. See documentation of buildTracks for details. // Tracks are complicated in HLS. See documentation of buildTracks for details.
// Indexed by track (as exposed by this source). // Indexed by track (as exposed by this source).
...@@ -130,6 +133,13 @@ import java.util.LinkedList; ...@@ -130,6 +133,13 @@ import java.util.LinkedList;
nextChunkHolder = new HlsChunkSource.HlsChunkHolder(); nextChunkHolder = new HlsChunkSource.HlsChunkHolder();
sampleQueues = new SparseArray<>(); sampleQueues = new SparseArray<>();
mediaChunks = new LinkedList<>(); mediaChunks = new LinkedList<>();
maybeFinishPrepareRunnable = new Runnable() {
@Override
public void run() {
maybeFinishPrepare();
}
};
handler = new Handler();
lastSeekPositionUs = positionUs; lastSeekPositionUs = positionUs;
pendingResetPositionUs = positionUs; pendingResetPositionUs = positionUs;
} }
...@@ -255,6 +265,8 @@ import java.util.LinkedList; ...@@ -255,6 +265,8 @@ import java.util.LinkedList;
sampleQueues.valueAt(i).disable(); sampleQueues.valueAt(i).disable();
} }
loader.release(); loader.release();
handler.removeCallbacksAndMessages(null);
released = true;
} }
public long getLargestQueuedTimestampUs() { public long getLargestQueuedTimestampUs() {
...@@ -464,7 +476,7 @@ import java.util.LinkedList; ...@@ -464,7 +476,7 @@ import java.util.LinkedList;
@Override @Override
public void endTracks() { public void endTracks() {
sampleQueuesBuilt = true; sampleQueuesBuilt = true;
maybeFinishPrepare(); handler.post(maybeFinishPrepareRunnable);
} }
@Override @Override
...@@ -472,17 +484,17 @@ import java.util.LinkedList; ...@@ -472,17 +484,17 @@ import java.util.LinkedList;
// Do nothing. // Do nothing.
} }
// UpstreamFormatChangedListener implementation. // UpstreamFormatChangedListener implementation. Called by the loading thread.
@Override @Override
public void onUpstreamFormatChanged(Format format) { public void onUpstreamFormatChanged(Format format) {
maybeFinishPrepare(); handler.post(maybeFinishPrepareRunnable);
} }
// Internal methods. // Internal methods.
private void maybeFinishPrepare() { private void maybeFinishPrepare() {
if (prepared || !sampleQueuesBuilt) { if (released || prepared || !sampleQueuesBuilt) {
return; return;
} }
int sampleQueueCount = sampleQueues.size(); int sampleQueueCount = sampleQueues.size();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment