Change signature of ChunkSource.onChunkLoadError
A no-op change that changes the signature of the onChunkLoadError method of the ChunkSource. Implementors can get the exclusion duration directly from the LoadErrorHndlingPolicy instead of receiving it as an argument of the callback. PiperOrigin-RevId: 381102935
This commit is contained in:
parent
ed471fae96
commit
1cb4fb290f
@ -516,13 +516,9 @@ public class ChunkSampleStream<T extends ChunkSource>
|
|||||||
LoadErrorInfo loadErrorInfo =
|
LoadErrorInfo loadErrorInfo =
|
||||||
new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount);
|
new LoadErrorInfo(loadEventInfo, mediaLoadData, error, errorCount);
|
||||||
|
|
||||||
long exclusionDurationMs =
|
|
||||||
cancelable
|
|
||||||
? loadErrorHandlingPolicy.getExclusionDurationMsFor(
|
|
||||||
LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo)
|
|
||||||
: C.TIME_UNSET;
|
|
||||||
@Nullable LoadErrorAction loadErrorAction = null;
|
@Nullable LoadErrorAction loadErrorAction = null;
|
||||||
if (chunkSource.onChunkLoadError(loadable, cancelable, error, exclusionDurationMs)) {
|
if (chunkSource.onChunkLoadError(
|
||||||
|
loadable, cancelable, loadErrorInfo, loadErrorHandlingPolicy)) {
|
||||||
if (cancelable) {
|
if (cancelable) {
|
||||||
loadErrorAction = Loader.DONT_RETRY;
|
loadErrorAction = Loader.DONT_RETRY;
|
||||||
if (isMediaChunk) {
|
if (isMediaChunk) {
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.chunk;
|
package com.google.android.exoplayer2.source.chunk;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
|
||||||
import com.google.android.exoplayer2.SeekParameters;
|
import com.google.android.exoplayer2.SeekParameters;
|
||||||
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -104,15 +104,19 @@ public interface ChunkSource {
|
|||||||
*
|
*
|
||||||
* @param chunk The chunk whose load encountered the error.
|
* @param chunk The chunk whose load encountered the error.
|
||||||
* @param cancelable Whether the load can be canceled.
|
* @param cancelable Whether the load can be canceled.
|
||||||
* @param e The error.
|
* @param loadErrorInfo The load error info.
|
||||||
* @param exclusionDurationMs The duration for which the associated track may be excluded, or
|
* @param loadErrorHandlingPolicy The load error handling policy to customize the behaviour of
|
||||||
* {@link C#TIME_UNSET} if the track may not be excluded.
|
* handling the load error.
|
||||||
* @return Whether the load should be canceled so that a replacement chunk can be loaded instead.
|
* @return Whether the load should be canceled so that a replacement chunk can be loaded instead.
|
||||||
* Must be {@code false} if {@code cancelable} is {@code false}. If {@code true}, {@link
|
* Must be {@code false} if {@code cancelable} is {@code false}. If {@code true}, {@link
|
||||||
* #getNextChunk(long, long, List, ChunkHolder)} will be called to obtain the replacement
|
* #getNextChunk(long, long, List, ChunkHolder)} will be called to obtain the replacement
|
||||||
* chunk.
|
* chunk.
|
||||||
*/
|
*/
|
||||||
boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e, long exclusionDurationMs);
|
boolean onChunkLoadError(
|
||||||
|
Chunk chunk,
|
||||||
|
boolean cancelable,
|
||||||
|
LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo,
|
||||||
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy);
|
||||||
|
|
||||||
/** Releases any held resources. */
|
/** Releases any held resources. */
|
||||||
void release();
|
void release();
|
||||||
|
@ -46,6 +46,7 @@ import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
|||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException;
|
||||||
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
@ -455,7 +456,10 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onChunkLoadError(
|
public boolean onChunkLoadError(
|
||||||
Chunk chunk, boolean cancelable, Exception e, long exclusionDurationMs) {
|
Chunk chunk,
|
||||||
|
boolean cancelable,
|
||||||
|
LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo,
|
||||||
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||||
if (!cancelable) {
|
if (!cancelable) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -465,8 +469,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
// Workaround for missing segment at the end of the period
|
// Workaround for missing segment at the end of the period
|
||||||
if (!manifest.dynamic
|
if (!manifest.dynamic
|
||||||
&& chunk instanceof MediaChunk
|
&& chunk instanceof MediaChunk
|
||||||
&& e instanceof InvalidResponseCodeException
|
&& loadErrorInfo.exception instanceof InvalidResponseCodeException
|
||||||
&& ((InvalidResponseCodeException) e).responseCode == 404) {
|
&& ((InvalidResponseCodeException) loadErrorInfo.exception).responseCode == 404) {
|
||||||
RepresentationHolder representationHolder =
|
RepresentationHolder representationHolder =
|
||||||
representationHolders[trackSelection.indexOf(chunk.trackFormat)];
|
representationHolders[trackSelection.indexOf(chunk.trackFormat)];
|
||||||
long segmentCount = representationHolder.getSegmentCount();
|
long segmentCount = representationHolder.getSegmentCount();
|
||||||
@ -478,6 +482,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
long exclusionDurationMs =
|
||||||
|
loadErrorHandlingPolicy.getExclusionDurationMsFor(
|
||||||
|
LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo);
|
||||||
return exclusionDurationMs != C.TIME_UNSET
|
return exclusionDurationMs != C.TIME_UNSET
|
||||||
&& trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), exclusionDurationMs);
|
&& trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), exclusionDurationMs);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.dash;
|
package com.google.android.exoplayer2.source.dash;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -23,6 +24,8 @@ import androidx.test.core.app.ApplicationProvider;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
|
import com.google.android.exoplayer2.source.LoadEventInfo;
|
||||||
|
import com.google.android.exoplayer2.source.MediaLoadData;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor;
|
import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor;
|
||||||
import com.google.android.exoplayer2.source.chunk.ChunkHolder;
|
import com.google.android.exoplayer2.source.chunk.ChunkHolder;
|
||||||
@ -30,10 +33,18 @@ import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
|||||||
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
|
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
|
||||||
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||||
|
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||||
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
|
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
||||||
|
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||||
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import java.io.IOException;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.annotation.internal.DoNotInstrument;
|
import org.robolectric.annotation.internal.DoNotInstrument;
|
||||||
@ -132,4 +143,129 @@ public class DefaultDashChunkSourceTest {
|
|||||||
assertThat(output.chunk.dataSpec.flags & DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED)
|
assertThat(output.chunk.dataSpec.flags & DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED)
|
||||||
.isEqualTo(0);
|
.isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onChunkLoadError_trackExclusionEnabled_requestReplacementChunkAsLongAsAvailable()
|
||||||
|
throws Exception {
|
||||||
|
DefaultLoadErrorHandlingPolicy loadErrorHandlingPolicy =
|
||||||
|
new DefaultLoadErrorHandlingPolicy() {
|
||||||
|
@Override
|
||||||
|
public long getExclusionDurationMsFor(int fallbackType, LoadErrorInfo loadErrorInfo) {
|
||||||
|
// Try to exclude tracks only.
|
||||||
|
return fallbackType == FALLBACK_TYPE_LOCATION
|
||||||
|
? C.TIME_UNSET
|
||||||
|
: super.getExclusionDurationMsFor(fallbackType, loadErrorInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
int numberOfTracks = 2;
|
||||||
|
DashChunkSource chunkSource = createDashChunkSource(numberOfTracks);
|
||||||
|
ChunkHolder output = new ChunkHolder();
|
||||||
|
for (int i = 0; i < numberOfTracks; i++) {
|
||||||
|
chunkSource.getNextChunk(
|
||||||
|
/* playbackPositionUs= */ 0,
|
||||||
|
/* loadPositionUs= */ 0,
|
||||||
|
/* queue= */ ImmutableList.of(),
|
||||||
|
output);
|
||||||
|
|
||||||
|
boolean alternativeTrackAvailable =
|
||||||
|
chunkSource.onChunkLoadError(
|
||||||
|
checkNotNull(output.chunk),
|
||||||
|
/* cancelable= */ true,
|
||||||
|
createFakeLoadErrorInfo(
|
||||||
|
output.chunk.dataSpec, /* httpResponseCode= */ 404, /* errorCount= */ 1),
|
||||||
|
loadErrorHandlingPolicy);
|
||||||
|
|
||||||
|
// Expect true except for the last track remaining.
|
||||||
|
assertThat(alternativeTrackAvailable).isEqualTo(i != numberOfTracks - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onChunkLoadError_trackExclusionDisabled_neverRequestReplacementChunk()
|
||||||
|
throws Exception {
|
||||||
|
DefaultLoadErrorHandlingPolicy loadErrorHandlingPolicy =
|
||||||
|
new DefaultLoadErrorHandlingPolicy() {
|
||||||
|
@Override
|
||||||
|
public long getExclusionDurationMsFor(int fallbackType, LoadErrorInfo loadErrorInfo) {
|
||||||
|
// Never exclude, neither tracks nor locations.
|
||||||
|
return C.TIME_UNSET;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
DashChunkSource chunkSource = createDashChunkSource(/* numberOfTracks= */ 2);
|
||||||
|
ChunkHolder output = new ChunkHolder();
|
||||||
|
chunkSource.getNextChunk(
|
||||||
|
/* playbackPositionUs= */ 0,
|
||||||
|
/* loadPositionUs= */ 0,
|
||||||
|
/* queue= */ ImmutableList.of(),
|
||||||
|
output);
|
||||||
|
|
||||||
|
boolean alternativeTrackAvailable =
|
||||||
|
chunkSource.onChunkLoadError(
|
||||||
|
checkNotNull(output.chunk),
|
||||||
|
/* cancelable= */ true,
|
||||||
|
createFakeLoadErrorInfo(
|
||||||
|
output.chunk.dataSpec, /* httpResponseCode= */ 404, /* errorCount= */ 1),
|
||||||
|
loadErrorHandlingPolicy);
|
||||||
|
|
||||||
|
assertThat(alternativeTrackAvailable).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DashChunkSource createDashChunkSource(int numberOfTracks) throws IOException {
|
||||||
|
Assertions.checkArgument(numberOfTracks < 6);
|
||||||
|
DashManifest manifest =
|
||||||
|
new DashManifestParser()
|
||||||
|
.parse(
|
||||||
|
Uri.parse("https://example.com/test.mpd"),
|
||||||
|
TestUtil.getInputStream(
|
||||||
|
ApplicationProvider.getApplicationContext(), SAMPLE_MPD_VOD));
|
||||||
|
int[] adaptationSetIndices = new int[] {0};
|
||||||
|
int[] selectedTracks = new int[numberOfTracks];
|
||||||
|
Format[] formats = new Format[numberOfTracks];
|
||||||
|
for (int i = 0; i < numberOfTracks; i++) {
|
||||||
|
selectedTracks[i] = i;
|
||||||
|
formats[i] =
|
||||||
|
manifest
|
||||||
|
.getPeriod(0)
|
||||||
|
.adaptationSets
|
||||||
|
.get(adaptationSetIndices[0])
|
||||||
|
.representations
|
||||||
|
.get(i)
|
||||||
|
.format;
|
||||||
|
}
|
||||||
|
AdaptiveTrackSelection adaptiveTrackSelection =
|
||||||
|
new AdaptiveTrackSelection(
|
||||||
|
new TrackGroup(formats),
|
||||||
|
selectedTracks,
|
||||||
|
new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build());
|
||||||
|
return new DefaultDashChunkSource(
|
||||||
|
BundledChunkExtractor.FACTORY,
|
||||||
|
new LoaderErrorThrower.Dummy(),
|
||||||
|
manifest,
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* adaptationSetIndices= */ adaptationSetIndices,
|
||||||
|
adaptiveTrackSelection,
|
||||||
|
C.TRACK_TYPE_VIDEO,
|
||||||
|
new FakeDataSource(),
|
||||||
|
/* elapsedRealtimeOffsetMs= */ 0,
|
||||||
|
/* maxSegmentsPerLoad= */ 1,
|
||||||
|
/* enableEventMessageTrack= */ false,
|
||||||
|
/* closedCaptionFormats */ ImmutableList.of(),
|
||||||
|
/* playerTrackEmsgHandler= */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoadErrorHandlingPolicy.LoadErrorInfo createFakeLoadErrorInfo(
|
||||||
|
DataSpec dataSpec, int httpResponseCode, int errorCount) {
|
||||||
|
LoadEventInfo loadEventInfo =
|
||||||
|
new LoadEventInfo(/* loadTaskId= */ 0, dataSpec, SystemClock.elapsedRealtime());
|
||||||
|
MediaLoadData mediaLoadData = new MediaLoadData(C.DATA_TYPE_MEDIA);
|
||||||
|
HttpDataSource.InvalidResponseCodeException invalidResponseCodeException =
|
||||||
|
new HttpDataSource.InvalidResponseCodeException(
|
||||||
|
httpResponseCode,
|
||||||
|
/* responseMessage= */ null,
|
||||||
|
ImmutableMap.of(),
|
||||||
|
dataSpec,
|
||||||
|
new byte[0]);
|
||||||
|
return new LoadErrorHandlingPolicy.LoadErrorInfo(
|
||||||
|
loadEventInfo, mediaLoadData, invalidResponseCodeException, errorCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.
|
|||||||
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
@ -282,7 +283,13 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onChunkLoadError(
|
public boolean onChunkLoadError(
|
||||||
Chunk chunk, boolean cancelable, Exception e, long exclusionDurationMs) {
|
Chunk chunk,
|
||||||
|
boolean cancelable,
|
||||||
|
LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo,
|
||||||
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||||
|
long exclusionDurationMs =
|
||||||
|
loadErrorHandlingPolicy.getExclusionDurationMsFor(
|
||||||
|
LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK, loadErrorInfo);
|
||||||
return cancelable
|
return cancelable
|
||||||
&& exclusionDurationMs != C.TIME_UNSET
|
&& exclusionDurationMs != C.TIME_UNSET
|
||||||
&& trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), exclusionDurationMs);
|
&& trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), exclusionDurationMs);
|
||||||
|
@ -30,6 +30,7 @@ import com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment;
|
|||||||
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
|
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
@ -156,7 +157,10 @@ public class FakeChunkSource implements ChunkSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onChunkLoadError(
|
public boolean onChunkLoadError(
|
||||||
Chunk chunk, boolean cancelable, Exception e, long exclusionDurationMs) {
|
Chunk chunk,
|
||||||
|
boolean cancelable,
|
||||||
|
LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo,
|
||||||
|
LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user