mirror of
https://github.com/androidx/media.git
synced 2025-05-07 23:50:44 +08:00
DownloadHelper: propagate errors to callback
When downlading an adaptive asset, if an ExoPlaybackException happens during track selection, the player raises an UnsupportedOperationException which is not handled gracefully and can crash the app main thread. This change catches the error and forwards it to DownloadHelper.Callback.onPrepareError() as an IOException. PiperOrigin-RevId: 443015332
This commit is contained in:
parent
d1f8e96d9c
commit
63052e1a7c
@ -622,9 +622,13 @@ public final class DownloadHelper {
|
|||||||
*/
|
*/
|
||||||
public void replaceTrackSelections(
|
public void replaceTrackSelections(
|
||||||
int periodIndex, TrackSelectionParameters trackSelectionParameters) {
|
int periodIndex, TrackSelectionParameters trackSelectionParameters) {
|
||||||
assertPreparedWithMedia();
|
try {
|
||||||
clearTrackSelections(periodIndex);
|
assertPreparedWithMedia();
|
||||||
addTrackSelectionInternal(periodIndex, trackSelectionParameters);
|
clearTrackSelections(periodIndex);
|
||||||
|
addTrackSelectionInternal(periodIndex, trackSelectionParameters);
|
||||||
|
} catch (ExoPlaybackException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -637,8 +641,12 @@ public final class DownloadHelper {
|
|||||||
*/
|
*/
|
||||||
public void addTrackSelection(
|
public void addTrackSelection(
|
||||||
int periodIndex, TrackSelectionParameters trackSelectionParameters) {
|
int periodIndex, TrackSelectionParameters trackSelectionParameters) {
|
||||||
assertPreparedWithMedia();
|
try {
|
||||||
addTrackSelectionInternal(periodIndex, trackSelectionParameters);
|
assertPreparedWithMedia();
|
||||||
|
addTrackSelectionInternal(periodIndex, trackSelectionParameters);
|
||||||
|
} catch (ExoPlaybackException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -650,27 +658,31 @@ public final class DownloadHelper {
|
|||||||
* selection, as IETF BCP 47 conformant tags.
|
* selection, as IETF BCP 47 conformant tags.
|
||||||
*/
|
*/
|
||||||
public void addAudioLanguagesToSelection(String... languages) {
|
public void addAudioLanguagesToSelection(String... languages) {
|
||||||
assertPreparedWithMedia();
|
try {
|
||||||
|
assertPreparedWithMedia();
|
||||||
|
|
||||||
TrackSelectionParameters.Builder parametersBuilder =
|
TrackSelectionParameters.Builder parametersBuilder =
|
||||||
DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_CONTEXT.buildUpon();
|
DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_CONTEXT.buildUpon();
|
||||||
// Prefer highest supported bitrate for downloads.
|
// Prefer highest supported bitrate for downloads.
|
||||||
parametersBuilder.setForceHighestSupportedBitrate(true);
|
parametersBuilder.setForceHighestSupportedBitrate(true);
|
||||||
// Disable all non-audio track types supported by the renderers.
|
// Disable all non-audio track types supported by the renderers.
|
||||||
for (RendererCapabilities capabilities : rendererCapabilities) {
|
for (RendererCapabilities capabilities : rendererCapabilities) {
|
||||||
@C.TrackType int trackType = capabilities.getTrackType();
|
@C.TrackType int trackType = capabilities.getTrackType();
|
||||||
parametersBuilder.setTrackTypeDisabled(
|
parametersBuilder.setTrackTypeDisabled(
|
||||||
trackType, /* disabled= */ trackType != C.TRACK_TYPE_AUDIO);
|
trackType, /* disabled= */ trackType != C.TRACK_TYPE_AUDIO);
|
||||||
}
|
|
||||||
|
|
||||||
// Add a track selection to each period for each of the languages.
|
|
||||||
int periodCount = getPeriodCount();
|
|
||||||
for (String language : languages) {
|
|
||||||
TrackSelectionParameters parameters =
|
|
||||||
parametersBuilder.setPreferredAudioLanguage(language).build();
|
|
||||||
for (int periodIndex = 0; periodIndex < periodCount; periodIndex++) {
|
|
||||||
addTrackSelectionInternal(periodIndex, parameters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a track selection to each period for each of the languages.
|
||||||
|
int periodCount = getPeriodCount();
|
||||||
|
for (String language : languages) {
|
||||||
|
TrackSelectionParameters parameters =
|
||||||
|
parametersBuilder.setPreferredAudioLanguage(language).build();
|
||||||
|
for (int periodIndex = 0; periodIndex < periodCount; periodIndex++) {
|
||||||
|
addTrackSelectionInternal(periodIndex, parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ExoPlaybackException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,28 +698,32 @@ public final class DownloadHelper {
|
|||||||
*/
|
*/
|
||||||
public void addTextLanguagesToSelection(
|
public void addTextLanguagesToSelection(
|
||||||
boolean selectUndeterminedTextLanguage, String... languages) {
|
boolean selectUndeterminedTextLanguage, String... languages) {
|
||||||
assertPreparedWithMedia();
|
try {
|
||||||
|
assertPreparedWithMedia();
|
||||||
|
|
||||||
TrackSelectionParameters.Builder parametersBuilder =
|
TrackSelectionParameters.Builder parametersBuilder =
|
||||||
DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_CONTEXT.buildUpon();
|
DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_CONTEXT.buildUpon();
|
||||||
parametersBuilder.setSelectUndeterminedTextLanguage(selectUndeterminedTextLanguage);
|
parametersBuilder.setSelectUndeterminedTextLanguage(selectUndeterminedTextLanguage);
|
||||||
// Prefer highest supported bitrate for downloads.
|
// Prefer highest supported bitrate for downloads.
|
||||||
parametersBuilder.setForceHighestSupportedBitrate(true);
|
parametersBuilder.setForceHighestSupportedBitrate(true);
|
||||||
// Disable all non-text track types supported by the renderers.
|
// Disable all non-text track types supported by the renderers.
|
||||||
for (RendererCapabilities capabilities : rendererCapabilities) {
|
for (RendererCapabilities capabilities : rendererCapabilities) {
|
||||||
@C.TrackType int trackType = capabilities.getTrackType();
|
@C.TrackType int trackType = capabilities.getTrackType();
|
||||||
parametersBuilder.setTrackTypeDisabled(
|
parametersBuilder.setTrackTypeDisabled(
|
||||||
trackType, /* disabled= */ trackType != C.TRACK_TYPE_TEXT);
|
trackType, /* disabled= */ trackType != C.TRACK_TYPE_TEXT);
|
||||||
}
|
|
||||||
|
|
||||||
// Add a track selection to each period for each of the languages.
|
|
||||||
int periodCount = getPeriodCount();
|
|
||||||
for (String language : languages) {
|
|
||||||
TrackSelectionParameters parameters =
|
|
||||||
parametersBuilder.setPreferredTextLanguage(language).build();
|
|
||||||
for (int periodIndex = 0; periodIndex < periodCount; periodIndex++) {
|
|
||||||
addTrackSelectionInternal(periodIndex, parameters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a track selection to each period for each of the languages.
|
||||||
|
int periodCount = getPeriodCount();
|
||||||
|
for (String language : languages) {
|
||||||
|
TrackSelectionParameters parameters =
|
||||||
|
parametersBuilder.setPreferredTextLanguage(language).build();
|
||||||
|
for (int periodIndex = 0; periodIndex < periodCount; periodIndex++) {
|
||||||
|
addTrackSelectionInternal(periodIndex, parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ExoPlaybackException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,19 +743,24 @@ public final class DownloadHelper {
|
|||||||
int rendererIndex,
|
int rendererIndex,
|
||||||
DefaultTrackSelector.Parameters trackSelectorParameters,
|
DefaultTrackSelector.Parameters trackSelectorParameters,
|
||||||
List<SelectionOverride> overrides) {
|
List<SelectionOverride> overrides) {
|
||||||
assertPreparedWithMedia();
|
try {
|
||||||
DefaultTrackSelector.ParametersBuilder builder = trackSelectorParameters.buildUpon();
|
assertPreparedWithMedia();
|
||||||
for (int i = 0; i < mappedTrackInfos[periodIndex].getRendererCount(); i++) {
|
DefaultTrackSelector.ParametersBuilder builder = trackSelectorParameters.buildUpon();
|
||||||
builder.setRendererDisabled(/* rendererIndex= */ i, /* disabled= */ i != rendererIndex);
|
for (int i = 0; i < mappedTrackInfos[periodIndex].getRendererCount(); i++) {
|
||||||
}
|
builder.setRendererDisabled(/* rendererIndex= */ i, /* disabled= */ i != rendererIndex);
|
||||||
if (overrides.isEmpty()) {
|
|
||||||
addTrackSelectionInternal(periodIndex, builder.build());
|
|
||||||
} else {
|
|
||||||
TrackGroupArray trackGroupArray = mappedTrackInfos[periodIndex].getTrackGroups(rendererIndex);
|
|
||||||
for (int i = 0; i < overrides.size(); i++) {
|
|
||||||
builder.setSelectionOverride(rendererIndex, trackGroupArray, overrides.get(i));
|
|
||||||
addTrackSelectionInternal(periodIndex, builder.build());
|
|
||||||
}
|
}
|
||||||
|
if (overrides.isEmpty()) {
|
||||||
|
addTrackSelectionInternal(periodIndex, builder.build());
|
||||||
|
} else {
|
||||||
|
TrackGroupArray trackGroupArray =
|
||||||
|
mappedTrackInfos[periodIndex].getTrackGroups(rendererIndex);
|
||||||
|
for (int i = 0; i < overrides.size(); i++) {
|
||||||
|
builder.setSelectionOverride(rendererIndex, trackGroupArray, overrides.get(i));
|
||||||
|
addTrackSelectionInternal(periodIndex, builder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ExoPlaybackException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,7 +818,8 @@ public final class DownloadHelper {
|
|||||||
"mediaPreparer.timeline"
|
"mediaPreparer.timeline"
|
||||||
})
|
})
|
||||||
private void addTrackSelectionInternal(
|
private void addTrackSelectionInternal(
|
||||||
int periodIndex, TrackSelectionParameters trackSelectionParameters) {
|
int periodIndex, TrackSelectionParameters trackSelectionParameters)
|
||||||
|
throws ExoPlaybackException {
|
||||||
trackSelector.setParameters(trackSelectionParameters);
|
trackSelector.setParameters(trackSelectionParameters);
|
||||||
runTrackSelection(periodIndex);
|
runTrackSelection(periodIndex);
|
||||||
// TrackSelectionParameters can contain multiple overrides for each track type. The track
|
// TrackSelectionParameters can contain multiple overrides for each track type. The track
|
||||||
@ -812,7 +834,7 @@ public final class DownloadHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") // Initialization of array of Lists.
|
@SuppressWarnings("unchecked") // Initialization of array of Lists.
|
||||||
private void onMediaPrepared() {
|
private void onMediaPrepared() throws ExoPlaybackException {
|
||||||
checkNotNull(mediaPreparer);
|
checkNotNull(mediaPreparer);
|
||||||
checkNotNull(mediaPreparer.mediaPeriods);
|
checkNotNull(mediaPreparer.mediaPeriods);
|
||||||
checkNotNull(mediaPreparer.timeline);
|
checkNotNull(mediaPreparer.timeline);
|
||||||
@ -882,52 +904,47 @@ public final class DownloadHelper {
|
|||||||
"mediaPreparer",
|
"mediaPreparer",
|
||||||
"mediaPreparer.timeline"
|
"mediaPreparer.timeline"
|
||||||
})
|
})
|
||||||
private TrackSelectorResult runTrackSelection(int periodIndex) {
|
private TrackSelectorResult runTrackSelection(int periodIndex) throws ExoPlaybackException {
|
||||||
try {
|
TrackSelectorResult trackSelectorResult =
|
||||||
TrackSelectorResult trackSelectorResult =
|
trackSelector.selectTracks(
|
||||||
trackSelector.selectTracks(
|
rendererCapabilities,
|
||||||
rendererCapabilities,
|
trackGroupArrays[periodIndex],
|
||||||
trackGroupArrays[periodIndex],
|
new MediaPeriodId(mediaPreparer.timeline.getUidOfPeriod(periodIndex)),
|
||||||
new MediaPeriodId(mediaPreparer.timeline.getUidOfPeriod(periodIndex)),
|
mediaPreparer.timeline);
|
||||||
mediaPreparer.timeline);
|
for (int i = 0; i < trackSelectorResult.length; i++) {
|
||||||
for (int i = 0; i < trackSelectorResult.length; i++) {
|
@Nullable ExoTrackSelection newSelection = trackSelectorResult.selections[i];
|
||||||
@Nullable ExoTrackSelection newSelection = trackSelectorResult.selections[i];
|
if (newSelection == null) {
|
||||||
if (newSelection == null) {
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
List<ExoTrackSelection> existingSelectionList =
|
||||||
List<ExoTrackSelection> existingSelectionList =
|
trackSelectionsByPeriodAndRenderer[periodIndex][i];
|
||||||
trackSelectionsByPeriodAndRenderer[periodIndex][i];
|
boolean mergedWithExistingSelection = false;
|
||||||
boolean mergedWithExistingSelection = false;
|
for (int j = 0; j < existingSelectionList.size(); j++) {
|
||||||
for (int j = 0; j < existingSelectionList.size(); j++) {
|
ExoTrackSelection existingSelection = existingSelectionList.get(j);
|
||||||
ExoTrackSelection existingSelection = existingSelectionList.get(j);
|
if (existingSelection.getTrackGroup().equals(newSelection.getTrackGroup())) {
|
||||||
if (existingSelection.getTrackGroup().equals(newSelection.getTrackGroup())) {
|
// Merge with existing selection.
|
||||||
// Merge with existing selection.
|
scratchSet.clear();
|
||||||
scratchSet.clear();
|
for (int k = 0; k < existingSelection.length(); k++) {
|
||||||
for (int k = 0; k < existingSelection.length(); k++) {
|
scratchSet.put(existingSelection.getIndexInTrackGroup(k), 0);
|
||||||
scratchSet.put(existingSelection.getIndexInTrackGroup(k), 0);
|
|
||||||
}
|
|
||||||
for (int k = 0; k < newSelection.length(); k++) {
|
|
||||||
scratchSet.put(newSelection.getIndexInTrackGroup(k), 0);
|
|
||||||
}
|
|
||||||
int[] mergedTracks = new int[scratchSet.size()];
|
|
||||||
for (int k = 0; k < scratchSet.size(); k++) {
|
|
||||||
mergedTracks[k] = scratchSet.keyAt(k);
|
|
||||||
}
|
|
||||||
existingSelectionList.set(
|
|
||||||
j, new DownloadTrackSelection(existingSelection.getTrackGroup(), mergedTracks));
|
|
||||||
mergedWithExistingSelection = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
for (int k = 0; k < newSelection.length(); k++) {
|
||||||
if (!mergedWithExistingSelection) {
|
scratchSet.put(newSelection.getIndexInTrackGroup(k), 0);
|
||||||
existingSelectionList.add(newSelection);
|
}
|
||||||
|
int[] mergedTracks = new int[scratchSet.size()];
|
||||||
|
for (int k = 0; k < scratchSet.size(); k++) {
|
||||||
|
mergedTracks[k] = scratchSet.keyAt(k);
|
||||||
|
}
|
||||||
|
existingSelectionList.set(
|
||||||
|
j, new DownloadTrackSelection(existingSelection.getTrackGroup(), mergedTracks));
|
||||||
|
mergedWithExistingSelection = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return trackSelectorResult;
|
if (!mergedWithExistingSelection) {
|
||||||
} catch (ExoPlaybackException e) {
|
existingSelectionList.add(newSelection);
|
||||||
// DefaultTrackSelector does not throw exceptions during track selection.
|
}
|
||||||
throw new UnsupportedOperationException(e);
|
|
||||||
}
|
}
|
||||||
|
return trackSelectorResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaSource createMediaSourceInternal(
|
private static MediaSource createMediaSourceInternal(
|
||||||
@ -1098,7 +1115,14 @@ public final class DownloadHelper {
|
|||||||
}
|
}
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case DOWNLOAD_HELPER_CALLBACK_MESSAGE_PREPARED:
|
case DOWNLOAD_HELPER_CALLBACK_MESSAGE_PREPARED:
|
||||||
downloadHelper.onMediaPrepared();
|
try {
|
||||||
|
downloadHelper.onMediaPrepared();
|
||||||
|
} catch (ExoPlaybackException e) {
|
||||||
|
downloadHelperHandler
|
||||||
|
.obtainMessage(
|
||||||
|
DOWNLOAD_HELPER_CALLBACK_MESSAGE_FAILED, /* obj= */ new IOException(e))
|
||||||
|
.sendToTarget();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
case DOWNLOAD_HELPER_CALLBACK_MESSAGE_FAILED:
|
case DOWNLOAD_HELPER_CALLBACK_MESSAGE_FAILED:
|
||||||
release();
|
release();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user