Reselect track when renderer capabilities change
* Implement RendererCapabilities.Listener in DefaultTrackSelector. * Add new methods TrackSelector.invalidateForRendererCapabilitiesChange and TrackSelector.InvalidateListener.onRendererCapabilitiesChanged. * Add new field allowInvalidateSelectionsOnRendererCapabilitiesChange to DefaultTrackSelector.Parameter to allow opt-in of the renderer capabilities detection feature. * Add logics of triggering track reselection when renderer capabilities change. PiperOrigin-RevId: 529067433
This commit is contained in:
parent
eac26b1838
commit
480ff93f85
@ -66,6 +66,12 @@
|
|||||||
* Add Util methods `shouldShowPlayButton` and
|
* Add Util methods `shouldShowPlayButton` and
|
||||||
`handlePlayPauseButtonAction` to write custom UI elements with a
|
`handlePlayPauseButtonAction` to write custom UI elements with a
|
||||||
play/pause button.
|
play/pause button.
|
||||||
|
* Track selection:
|
||||||
|
* Add
|
||||||
|
`DefaultTrackSelector.Parameters.allowInvalidateSelectionsForRendererCapabilitiesChange`
|
||||||
|
which is disabled by default. When enabled, the `DefaultTrackSelector`
|
||||||
|
will trigger a new track selection when the renderer capabilities
|
||||||
|
changed.
|
||||||
* Audio:
|
* Audio:
|
||||||
* Fix bug where some playbacks fail when tunneling is enabled and
|
* Fix bug where some playbacks fail when tunneling is enabled and
|
||||||
`AudioProcessors` are active, e.g. for gapless trimming
|
`AudioProcessors` are active, e.g. for gapless trimming
|
||||||
@ -85,6 +91,9 @@
|
|||||||
`onRendererCapabilitiesChanged` events.
|
`onRendererCapabilitiesChanged` events.
|
||||||
* Add `ChannelMixingAudioProcessor` for applying scaling/mixing to audio
|
* Add `ChannelMixingAudioProcessor` for applying scaling/mixing to audio
|
||||||
channels.
|
channels.
|
||||||
|
* Add new int value `DISCARD_REASON_AUDIO_BYPASS_POSSIBLE` to
|
||||||
|
`DecoderDiscardReasons` to discard audio decoder when bypass mode is
|
||||||
|
possible after audio capabilities change.
|
||||||
* Metadata:
|
* Metadata:
|
||||||
* Deprecate `MediaMetadata.folderType` in favor of `isBrowsable` and
|
* Deprecate `MediaMetadata.folderType` in favor of `isBrowsable` and
|
||||||
`mediaType`.
|
`mediaType`.
|
||||||
|
@ -80,7 +80,8 @@ public final class DecoderReuseEvaluation {
|
|||||||
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED,
|
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED,
|
||||||
DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED,
|
DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED,
|
||||||
DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED,
|
DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED,
|
||||||
DISCARD_REASON_AUDIO_ENCODING_CHANGED
|
DISCARD_REASON_AUDIO_ENCODING_CHANGED,
|
||||||
|
DISCARD_REASON_AUDIO_BYPASS_POSSIBLE
|
||||||
})
|
})
|
||||||
public @interface DecoderDiscardReasons {}
|
public @interface DecoderDiscardReasons {}
|
||||||
|
|
||||||
@ -114,6 +115,8 @@ public final class DecoderReuseEvaluation {
|
|||||||
public static final int DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED = 1 << 13;
|
public static final int DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED = 1 << 13;
|
||||||
/** The audio encoding is changing. */
|
/** The audio encoding is changing. */
|
||||||
public static final int DISCARD_REASON_AUDIO_ENCODING_CHANGED = 1 << 14;
|
public static final int DISCARD_REASON_AUDIO_ENCODING_CHANGED = 1 << 14;
|
||||||
|
/** The audio bypass mode is possible. */
|
||||||
|
public static final int DISCARD_REASON_AUDIO_BYPASS_POSSIBLE = 1 << 15;
|
||||||
|
|
||||||
/** The name of the decoder. */
|
/** The name of the decoder. */
|
||||||
public final String decoderName;
|
public final String decoderName;
|
||||||
|
@ -165,6 +165,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
private static final int MSG_SET_PAUSE_AT_END_OF_WINDOW = 23;
|
private static final int MSG_SET_PAUSE_AT_END_OF_WINDOW = 23;
|
||||||
private static final int MSG_SET_OFFLOAD_SCHEDULING_ENABLED = 24;
|
private static final int MSG_SET_OFFLOAD_SCHEDULING_ENABLED = 24;
|
||||||
private static final int MSG_ATTEMPT_RENDERER_ERROR_RECOVERY = 25;
|
private static final int MSG_ATTEMPT_RENDERER_ERROR_RECOVERY = 25;
|
||||||
|
private static final int MSG_RENDERER_CAPABILITIES_CHANGED = 26;
|
||||||
|
|
||||||
private static final int ACTIVE_INTERVAL_MS = 10;
|
private static final int ACTIVE_INTERVAL_MS = 10;
|
||||||
private static final int IDLE_INTERVAL_MS = 1000;
|
private static final int IDLE_INTERVAL_MS = 1000;
|
||||||
@ -481,6 +482,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
handler.sendEmptyMessage(MSG_TRACK_SELECTION_INVALIDATED);
|
handler.sendEmptyMessage(MSG_TRACK_SELECTION_INVALIDATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRendererCapabilitiesChanged(Renderer renderer) {
|
||||||
|
handler.sendEmptyMessage(MSG_RENDERER_CAPABILITIES_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultMediaClock.PlaybackParametersListener implementation.
|
// DefaultMediaClock.PlaybackParametersListener implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -576,6 +582,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
case MSG_ATTEMPT_RENDERER_ERROR_RECOVERY:
|
case MSG_ATTEMPT_RENDERER_ERROR_RECOVERY:
|
||||||
attemptRendererErrorRecovery();
|
attemptRendererErrorRecovery();
|
||||||
break;
|
break;
|
||||||
|
case MSG_RENDERER_CAPABILITIES_CHANGED:
|
||||||
|
reselectTracksInternalAndSeek();
|
||||||
|
break;
|
||||||
case MSG_RELEASE:
|
case MSG_RELEASE:
|
||||||
releaseInternal();
|
releaseInternal();
|
||||||
// Return immediately to not send playback info updates after release.
|
// Return immediately to not send playback info updates after release.
|
||||||
|
@ -444,6 +444,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||||||
DecoderReuseEvaluation evaluation = codecInfo.canReuseCodec(oldFormat, newFormat);
|
DecoderReuseEvaluation evaluation = codecInfo.canReuseCodec(oldFormat, newFormat);
|
||||||
|
|
||||||
@DecoderDiscardReasons int discardReasons = evaluation.discardReasons;
|
@DecoderDiscardReasons int discardReasons = evaluation.discardReasons;
|
||||||
|
if (isBypassPossible(newFormat)) {
|
||||||
|
// We prefer direct audio playback so that for multi-channel tracks the audio is not downmixed
|
||||||
|
// to stereo.
|
||||||
|
discardReasons |= DecoderReuseEvaluation.DISCARD_REASON_AUDIO_BYPASS_POSSIBLE;
|
||||||
|
}
|
||||||
if (getCodecMaxInputSize(codecInfo, newFormat) > codecMaxInputSize) {
|
if (getCodecMaxInputSize(codecInfo, newFormat) > codecMaxInputSize) {
|
||||||
discardReasons |= DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED;
|
discardReasons |= DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED;
|
||||||
}
|
}
|
||||||
|
@ -491,7 +491,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceDrmSession == null && shouldUseBypass(inputFormat)) {
|
if (isBypassPossible(inputFormat)) {
|
||||||
initBypass(inputFormat);
|
initBypass(inputFormat);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -546,6 +546,19 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether buffers in the input format can be processed without a codec.
|
||||||
|
*
|
||||||
|
* <p>This method returns the possibility of bypass mode with checking both the renderer
|
||||||
|
* capabilities and DRM protection.
|
||||||
|
*
|
||||||
|
* @param format The input {@link Format}.
|
||||||
|
* @return Whether playback bypassing {@link MediaCodec} is possible.
|
||||||
|
*/
|
||||||
|
protected final boolean isBypassPossible(Format format) {
|
||||||
|
return sourceDrmSession == null && shouldUseBypass(inputFormat);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether buffers in the input format can be processed without a codec.
|
* Returns whether buffers in the input format can be processed without a codec.
|
||||||
*
|
*
|
||||||
|
@ -111,7 +111,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
* }</pre>
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public class DefaultTrackSelector extends MappingTrackSelector {
|
public class DefaultTrackSelector extends MappingTrackSelector
|
||||||
|
implements RendererCapabilities.Listener {
|
||||||
|
|
||||||
private static final String TAG = "DefaultTrackSelector";
|
private static final String TAG = "DefaultTrackSelector";
|
||||||
private static final String AUDIO_CHANNEL_COUNT_CONSTRAINTS_WARN_MESSAGE =
|
private static final String AUDIO_CHANNEL_COUNT_CONSTRAINTS_WARN_MESSAGE =
|
||||||
@ -758,6 +759,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
private boolean exceedRendererCapabilitiesIfNecessary;
|
private boolean exceedRendererCapabilitiesIfNecessary;
|
||||||
private boolean tunnelingEnabled;
|
private boolean tunnelingEnabled;
|
||||||
private boolean allowMultipleAdaptiveSelections;
|
private boolean allowMultipleAdaptiveSelections;
|
||||||
|
private boolean allowInvalidateSelectionsOnRendererCapabilitiesChange;
|
||||||
// Overrides
|
// Overrides
|
||||||
private final SparseArray<Map<TrackGroupArray, @NullableType SelectionOverride>>
|
private final SparseArray<Map<TrackGroupArray, @NullableType SelectionOverride>>
|
||||||
selectionOverrides;
|
selectionOverrides;
|
||||||
@ -814,6 +816,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
exceedRendererCapabilitiesIfNecessary = initialValues.exceedRendererCapabilitiesIfNecessary;
|
exceedRendererCapabilitiesIfNecessary = initialValues.exceedRendererCapabilitiesIfNecessary;
|
||||||
tunnelingEnabled = initialValues.tunnelingEnabled;
|
tunnelingEnabled = initialValues.tunnelingEnabled;
|
||||||
allowMultipleAdaptiveSelections = initialValues.allowMultipleAdaptiveSelections;
|
allowMultipleAdaptiveSelections = initialValues.allowMultipleAdaptiveSelections;
|
||||||
|
allowInvalidateSelectionsOnRendererCapabilitiesChange =
|
||||||
|
initialValues.allowInvalidateSelectionsOnRendererCapabilitiesChange;
|
||||||
// Overrides
|
// Overrides
|
||||||
selectionOverrides = cloneSelectionOverrides(initialValues.selectionOverrides);
|
selectionOverrides = cloneSelectionOverrides(initialValues.selectionOverrides);
|
||||||
rendererDisabledFlags = initialValues.rendererDisabledFlags.clone();
|
rendererDisabledFlags = initialValues.rendererDisabledFlags.clone();
|
||||||
@ -877,6 +881,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
bundle.getBoolean(
|
bundle.getBoolean(
|
||||||
Parameters.FIELD_ALLOW_MULTIPLE_ADAPTIVE_SELECTIONS,
|
Parameters.FIELD_ALLOW_MULTIPLE_ADAPTIVE_SELECTIONS,
|
||||||
defaultValue.allowMultipleAdaptiveSelections));
|
defaultValue.allowMultipleAdaptiveSelections));
|
||||||
|
setAllowInvalidateSelectionsOnRendererCapabilitiesChange(
|
||||||
|
bundle.getBoolean(
|
||||||
|
Parameters.FIELD_ALLOW_INVALIDATE_SELECTIONS_ON_RENDERER_CAPABILITIES_CHANGE,
|
||||||
|
defaultValue.allowInvalidateSelectionsOnRendererCapabilitiesChange));
|
||||||
// Overrides
|
// Overrides
|
||||||
selectionOverrides = new SparseArray<>();
|
selectionOverrides = new SparseArray<>();
|
||||||
setSelectionOverridesFromBundle(bundle);
|
setSelectionOverridesFromBundle(bundle);
|
||||||
@ -1290,6 +1298,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether to allow to invalidate selections on renderer capabilities change.
|
||||||
|
*
|
||||||
|
* @param allowInvalidateSelectionsOnRendererCapabilitiesChange Whether to allow to invalidate
|
||||||
|
* selections.
|
||||||
|
* @return This builder.
|
||||||
|
*/
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setAllowInvalidateSelectionsOnRendererCapabilitiesChange(
|
||||||
|
boolean allowInvalidateSelectionsOnRendererCapabilitiesChange) {
|
||||||
|
this.allowInvalidateSelectionsOnRendererCapabilitiesChange =
|
||||||
|
allowInvalidateSelectionsOnRendererCapabilitiesChange;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
@Override
|
@Override
|
||||||
public Builder addOverride(TrackSelectionOverride override) {
|
public Builder addOverride(TrackSelectionOverride override) {
|
||||||
@ -1547,6 +1570,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
exceedRendererCapabilitiesIfNecessary = true;
|
exceedRendererCapabilitiesIfNecessary = true;
|
||||||
tunnelingEnabled = false;
|
tunnelingEnabled = false;
|
||||||
allowMultipleAdaptiveSelections = true;
|
allowMultipleAdaptiveSelections = true;
|
||||||
|
allowInvalidateSelectionsOnRendererCapabilitiesChange = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SparseArray<Map<TrackGroupArray, @NullableType SelectionOverride>>
|
private static SparseArray<Map<TrackGroupArray, @NullableType SelectionOverride>>
|
||||||
@ -1719,6 +1743,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
*/
|
*/
|
||||||
public final boolean allowMultipleAdaptiveSelections;
|
public final boolean allowMultipleAdaptiveSelections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to allow to invalidate selections on renderer capabilities change. The default value
|
||||||
|
* is {@code false}.
|
||||||
|
*/
|
||||||
|
public final boolean allowInvalidateSelectionsOnRendererCapabilitiesChange;
|
||||||
|
|
||||||
// Overrides
|
// Overrides
|
||||||
private final SparseArray<Map<TrackGroupArray, @NullableType SelectionOverride>>
|
private final SparseArray<Map<TrackGroupArray, @NullableType SelectionOverride>>
|
||||||
selectionOverrides;
|
selectionOverrides;
|
||||||
@ -1743,6 +1773,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
exceedRendererCapabilitiesIfNecessary = builder.exceedRendererCapabilitiesIfNecessary;
|
exceedRendererCapabilitiesIfNecessary = builder.exceedRendererCapabilitiesIfNecessary;
|
||||||
tunnelingEnabled = builder.tunnelingEnabled;
|
tunnelingEnabled = builder.tunnelingEnabled;
|
||||||
allowMultipleAdaptiveSelections = builder.allowMultipleAdaptiveSelections;
|
allowMultipleAdaptiveSelections = builder.allowMultipleAdaptiveSelections;
|
||||||
|
allowInvalidateSelectionsOnRendererCapabilitiesChange =
|
||||||
|
builder.allowInvalidateSelectionsOnRendererCapabilitiesChange;
|
||||||
// Overrides
|
// Overrides
|
||||||
selectionOverrides = builder.selectionOverrides;
|
selectionOverrides = builder.selectionOverrides;
|
||||||
rendererDisabledFlags = builder.rendererDisabledFlags;
|
rendererDisabledFlags = builder.rendererDisabledFlags;
|
||||||
@ -1833,6 +1865,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
&& exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary
|
&& exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary
|
||||||
&& tunnelingEnabled == other.tunnelingEnabled
|
&& tunnelingEnabled == other.tunnelingEnabled
|
||||||
&& allowMultipleAdaptiveSelections == other.allowMultipleAdaptiveSelections
|
&& allowMultipleAdaptiveSelections == other.allowMultipleAdaptiveSelections
|
||||||
|
&& allowInvalidateSelectionsOnRendererCapabilitiesChange
|
||||||
|
== other.allowInvalidateSelectionsOnRendererCapabilitiesChange
|
||||||
// Overrides
|
// Overrides
|
||||||
&& areRendererDisabledFlagsEqual(rendererDisabledFlags, other.rendererDisabledFlags)
|
&& areRendererDisabledFlagsEqual(rendererDisabledFlags, other.rendererDisabledFlags)
|
||||||
&& areSelectionOverridesEqual(selectionOverrides, other.selectionOverrides);
|
&& areSelectionOverridesEqual(selectionOverrides, other.selectionOverrides);
|
||||||
@ -1858,6 +1892,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0);
|
result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0);
|
||||||
result = 31 * result + (tunnelingEnabled ? 1 : 0);
|
result = 31 * result + (tunnelingEnabled ? 1 : 0);
|
||||||
result = 31 * result + (allowMultipleAdaptiveSelections ? 1 : 0);
|
result = 31 * result + (allowMultipleAdaptiveSelections ? 1 : 0);
|
||||||
|
result = 31 * result + (allowInvalidateSelectionsOnRendererCapabilitiesChange ? 1 : 0);
|
||||||
// Overrides (omitted from hashCode).
|
// Overrides (omitted from hashCode).
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1898,6 +1933,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 15);
|
Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 15);
|
||||||
private static final String FIELD_CONSTRAIN_AUDIO_CHANNEL_COUNT_TO_DEVICE_CAPABILITIES =
|
private static final String FIELD_CONSTRAIN_AUDIO_CHANNEL_COUNT_TO_DEVICE_CAPABILITIES =
|
||||||
Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 16);
|
Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 16);
|
||||||
|
private static final String FIELD_ALLOW_INVALIDATE_SELECTIONS_ON_RENDERER_CAPABILITIES_CHANGE =
|
||||||
|
Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 17);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bundle toBundle() {
|
public Bundle toBundle() {
|
||||||
@ -1934,6 +1971,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
FIELD_EXCEED_RENDERER_CAPABILITIES_IF_NECESSARY, exceedRendererCapabilitiesIfNecessary);
|
FIELD_EXCEED_RENDERER_CAPABILITIES_IF_NECESSARY, exceedRendererCapabilitiesIfNecessary);
|
||||||
bundle.putBoolean(FIELD_TUNNELING_ENABLED, tunnelingEnabled);
|
bundle.putBoolean(FIELD_TUNNELING_ENABLED, tunnelingEnabled);
|
||||||
bundle.putBoolean(FIELD_ALLOW_MULTIPLE_ADAPTIVE_SELECTIONS, allowMultipleAdaptiveSelections);
|
bundle.putBoolean(FIELD_ALLOW_MULTIPLE_ADAPTIVE_SELECTIONS, allowMultipleAdaptiveSelections);
|
||||||
|
bundle.putBoolean(
|
||||||
|
FIELD_ALLOW_INVALIDATE_SELECTIONS_ON_RENDERER_CAPABILITIES_CHANGE,
|
||||||
|
allowInvalidateSelectionsOnRendererCapabilitiesChange);
|
||||||
|
|
||||||
putSelectionOverridesToBundle(bundle, selectionOverrides);
|
putSelectionOverridesToBundle(bundle, selectionOverrides);
|
||||||
// Only true values are put into rendererDisabledFlags.
|
// Only true values are put into rendererDisabledFlags.
|
||||||
@ -2360,6 +2400,19 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public RendererCapabilities.Listener getRendererCapabilitiesListener() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RendererCapabilities.Listener implementation.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRendererCapabilitiesChanged(Renderer renderer) {
|
||||||
|
maybeInvalidateForRendererCapabilitiesChange(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
// MappingTrackSelector implementation.
|
// MappingTrackSelector implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2772,6 +2825,16 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void maybeInvalidateForRendererCapabilitiesChange(Renderer renderer) {
|
||||||
|
boolean shouldInvalidate;
|
||||||
|
synchronized (lock) {
|
||||||
|
shouldInvalidate = parameters.allowInvalidateSelectionsOnRendererCapabilitiesChange;
|
||||||
|
}
|
||||||
|
if (shouldInvalidate) {
|
||||||
|
invalidateForRendererCapabilitiesChange(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Utility methods.
|
// Utility methods.
|
||||||
|
|
||||||
private static void applyTrackSelectionOverrides(
|
private static void applyTrackSelectionOverrides(
|
||||||
|
@ -102,6 +102,15 @@ public abstract class TrackSelector {
|
|||||||
* longer valid. May be called from any thread.
|
* longer valid. May be called from any thread.
|
||||||
*/
|
*/
|
||||||
void onTrackSelectionsInvalidated();
|
void onTrackSelectionsInvalidated();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by a {@link TrackSelector} to indicate that selections it has previously made may no
|
||||||
|
* longer be valid due to the renderer capabilities change. This method is called from playback
|
||||||
|
* thread.
|
||||||
|
*
|
||||||
|
* @param renderer The renderer whose capabilities changed.
|
||||||
|
*/
|
||||||
|
default void onRendererCapabilitiesChanged(Renderer renderer) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable private InvalidationListener listener;
|
@Nullable private InvalidationListener listener;
|
||||||
@ -207,6 +216,18 @@ public abstract class TrackSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls {@link InvalidationListener#onRendererCapabilitiesChanged(Renderer)} to invalidate all
|
||||||
|
* previously generated track selections because a renderer's capabilities have changed.
|
||||||
|
*
|
||||||
|
* @param renderer The renderer whose capabilities changed.
|
||||||
|
*/
|
||||||
|
protected final void invalidateForRendererCapabilitiesChange(Renderer renderer) {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onRendererCapabilitiesChanged(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a bandwidth meter which can be used by track selections to select tracks. Must only be
|
* Returns a bandwidth meter which can be used by track selections to select tracks. Must only be
|
||||||
* called when the track selector is {@linkplain #init(InvalidationListener, BandwidthMeter)
|
* called when the track selector is {@linkplain #init(InvalidationListener, BandwidthMeter)
|
||||||
|
@ -28,6 +28,7 @@ import static androidx.media3.exoplayer.RendererCapabilities.HARDWARE_ACCELERATI
|
|||||||
import static androidx.media3.exoplayer.RendererCapabilities.TUNNELING_NOT_SUPPORTED;
|
import static androidx.media3.exoplayer.RendererCapabilities.TUNNELING_NOT_SUPPORTED;
|
||||||
import static androidx.media3.exoplayer.RendererConfiguration.DEFAULT;
|
import static androidx.media3.exoplayer.RendererConfiguration.DEFAULT;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@ -44,17 +45,21 @@ import androidx.media3.common.TrackGroup;
|
|||||||
import androidx.media3.common.TrackSelectionOverride;
|
import androidx.media3.common.TrackSelectionOverride;
|
||||||
import androidx.media3.common.TrackSelectionParameters;
|
import androidx.media3.common.TrackSelectionParameters;
|
||||||
import androidx.media3.common.Tracks;
|
import androidx.media3.common.Tracks;
|
||||||
|
import androidx.media3.common.util.HandlerWrapper;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.exoplayer.ExoPlaybackException;
|
import androidx.media3.exoplayer.ExoPlaybackException;
|
||||||
|
import androidx.media3.exoplayer.Renderer;
|
||||||
import androidx.media3.exoplayer.RendererCapabilities;
|
import androidx.media3.exoplayer.RendererCapabilities;
|
||||||
import androidx.media3.exoplayer.RendererCapabilities.Capabilities;
|
import androidx.media3.exoplayer.RendererCapabilities.Capabilities;
|
||||||
import androidx.media3.exoplayer.RendererConfiguration;
|
import androidx.media3.exoplayer.RendererConfiguration;
|
||||||
|
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
||||||
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
|
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
|
||||||
import androidx.media3.exoplayer.source.TrackGroupArray;
|
import androidx.media3.exoplayer.source.TrackGroupArray;
|
||||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector.Parameters;
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector.Parameters;
|
||||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector.SelectionOverride;
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector.SelectionOverride;
|
||||||
import androidx.media3.exoplayer.trackselection.TrackSelector.InvalidationListener;
|
import androidx.media3.exoplayer.trackselection.TrackSelector.InvalidationListener;
|
||||||
import androidx.media3.exoplayer.upstream.BandwidthMeter;
|
import androidx.media3.exoplayer.upstream.BandwidthMeter;
|
||||||
|
import androidx.media3.test.utils.FakeAudioRenderer;
|
||||||
import androidx.media3.test.utils.FakeTimeline;
|
import androidx.media3.test.utils.FakeTimeline;
|
||||||
import androidx.media3.test.utils.TestUtil;
|
import androidx.media3.test.utils.TestUtil;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@ -2454,6 +2459,36 @@ public final class DefaultTrackSelectorTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onRendererCapabilitiesChangedWithDefaultParameters_notNotifyInvalidateListener() {
|
||||||
|
Renderer renderer =
|
||||||
|
new FakeAudioRenderer(
|
||||||
|
/* handler= */ mock(HandlerWrapper.class),
|
||||||
|
/* eventListener= */ mock(AudioRendererEventListener.class));
|
||||||
|
|
||||||
|
trackSelector.onRendererCapabilitiesChanged(renderer);
|
||||||
|
|
||||||
|
verify(invalidationListener, never()).onRendererCapabilitiesChanged(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onRendererCapabilitiesChangedWithInvalidateSelectionsForRendererCapabilitiesChangeEnabled_notifyInvalidateListener() {
|
||||||
|
trackSelector.setParameters(
|
||||||
|
defaultParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setAllowInvalidateSelectionsOnRendererCapabilitiesChange(true)
|
||||||
|
.build());
|
||||||
|
Renderer renderer =
|
||||||
|
new FakeAudioRenderer(
|
||||||
|
/* handler= */ mock(HandlerWrapper.class),
|
||||||
|
/* eventListener= */ mock(AudioRendererEventListener.class));
|
||||||
|
|
||||||
|
trackSelector.onRendererCapabilitiesChanged(renderer);
|
||||||
|
|
||||||
|
verify(invalidationListener).onRendererCapabilitiesChanged(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
private static void assertSelections(TrackSelectorResult result, TrackSelection[] expected) {
|
private static void assertSelections(TrackSelectorResult result, TrackSelection[] expected) {
|
||||||
assertThat(result.length).isEqualTo(expected.length);
|
assertThat(result.length).isEqualTo(expected.length);
|
||||||
for (int i = 0; i < expected.length; i++) {
|
for (int i = 0; i < expected.length; i++) {
|
||||||
@ -2574,6 +2609,7 @@ public final class DefaultTrackSelectorTest {
|
|||||||
.setExceedRendererCapabilitiesIfNecessary(false)
|
.setExceedRendererCapabilitiesIfNecessary(false)
|
||||||
.setTunnelingEnabled(true)
|
.setTunnelingEnabled(true)
|
||||||
.setAllowMultipleAdaptiveSelections(true)
|
.setAllowMultipleAdaptiveSelections(true)
|
||||||
|
.setAllowInvalidateSelectionsOnRendererCapabilitiesChange(false)
|
||||||
.setSelectionOverride(
|
.setSelectionOverride(
|
||||||
/* rendererIndex= */ 2,
|
/* rendererIndex= */ 2,
|
||||||
new TrackGroupArray(VIDEO_TRACK_GROUP),
|
new TrackGroupArray(VIDEO_TRACK_GROUP),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user