mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
DefaultTrackSelector: Constrain audio channel count
The track selector will select multi-channel formats when those can be spatialized, otherwise the selector will prefer stereo/mono audio tracks. When the device supports audio spatialization (Android 12L+), the DefaultTrackSelector will monitor for changes in the platform Spatializer and trigger a new track selection upon a Spatializer change event. Devices with a `television` UI mode are excluded from audio channel count constraints. #minor-release PiperOrigin-RevId: 453957269 (cherry picked from commit e2f0fd76730fd4042e8b2226300e5173b0179dc1)
This commit is contained in:
parent
74fbf0171f
commit
0fd24c2fa3
@ -39,6 +39,24 @@
|
|||||||
`DefaultTrackSelector.Parameters.buildUpon` to return
|
`DefaultTrackSelector.Parameters.buildUpon` to return
|
||||||
`DefaultTrackSelector.Parameters.Builder` instead of the deprecated
|
`DefaultTrackSelector.Parameters.Builder` instead of the deprecated
|
||||||
`DefaultTrackSelector.ParametersBuilder`.
|
`DefaultTrackSelector.ParametersBuilder`.
|
||||||
|
* Add
|
||||||
|
`DefaultTrackSelector.Parameters.constrainAudioChannelCountToDeviceCapabilities`.
|
||||||
|
which is enabled by default. When enabled, the `DefaultTrackSelector`
|
||||||
|
will prefer audio tracks whose channel count does not exceed the device
|
||||||
|
output capabilities. On handheld devices, the `DefaultTrackSelector`
|
||||||
|
will prefer stereo/mono over multichannel audio formats, unless the
|
||||||
|
multichannel format can be
|
||||||
|
[Spatialized](https://developer.android.com/reference/android/media/Spatializer)
|
||||||
|
(Android 12L+) or is a Dolby surround sound format. In addition, on
|
||||||
|
devices that support audio spatialization, the `DefaultTrackSelector`
|
||||||
|
will monitor for changes in the
|
||||||
|
[Spatializer properties](https://developer.android.com/reference/android/media/Spatializer.OnSpatializerStateChangedListener)
|
||||||
|
and trigger a new track selection upon these. Devices with a
|
||||||
|
`television`
|
||||||
|
[UI mode](https://developer.android.com/guide/topics/resources/providing-resources#UiModeQualifier)
|
||||||
|
are excluded from these constraints and the format with the highest
|
||||||
|
channel count will be preferred. To enable this feature, the
|
||||||
|
`DefaultTrackSelector` instance must be constructed with a `Context`.
|
||||||
* Video:
|
* Video:
|
||||||
* Rename `DummySurface` to `PlaceholderSurface`.
|
* Rename `DummySurface` to `PlaceholderSurface`.
|
||||||
* Add AV1 support to the `MediaCodecVideoRenderer.getCodecMaxInputSize`.
|
* Add AV1 support to the `MediaCodecVideoRenderer.getCodecMaxInputSize`.
|
||||||
@ -171,6 +189,8 @@
|
|||||||
`DEFAULT_TRACK_SELECTOR_PARAMETERS` constants. Use
|
`DEFAULT_TRACK_SELECTOR_PARAMETERS` constants. Use
|
||||||
`getDefaultTrackSelectorParameters(Context)` instead when possible, and
|
`getDefaultTrackSelectorParameters(Context)` instead when possible, and
|
||||||
`DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_CONTEXT` otherwise.
|
`DEFAULT_TRACK_SELECTOR_PARAMETERS_WITHOUT_CONTEXT` otherwise.
|
||||||
|
* Remove constructor `DefaultTrackSelector(ExoTrackSelection.Factory)`.
|
||||||
|
Use `DefaultTrackSelector(Context, ExoTrackSelection.Factory)` instead.
|
||||||
|
|
||||||
### 1.0.0-alpha03 (2022-03-14)
|
### 1.0.0-alpha03 (2022-03-14)
|
||||||
|
|
||||||
|
@ -380,6 +380,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
deviceInfo = createDeviceInfo(streamVolumeManager);
|
deviceInfo = createDeviceInfo(streamVolumeManager);
|
||||||
videoSize = VideoSize.UNKNOWN;
|
videoSize = VideoSize.UNKNOWN;
|
||||||
|
|
||||||
|
trackSelector.setAudioAttributes(audioAttributes);
|
||||||
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_AUDIO_SESSION_ID, audioSessionId);
|
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_AUDIO_SESSION_ID, audioSessionId);
|
||||||
sendRendererMessage(TRACK_TYPE_VIDEO, MSG_SET_AUDIO_SESSION_ID, audioSessionId);
|
sendRendererMessage(TRACK_TYPE_VIDEO, MSG_SET_AUDIO_SESSION_ID, audioSessionId);
|
||||||
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_AUDIO_ATTRIBUTES, audioAttributes);
|
sendRendererMessage(TRACK_TYPE_AUDIO, MSG_SET_AUDIO_ATTRIBUTES, audioAttributes);
|
||||||
@ -1375,6 +1376,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
audioFocusManager.setAudioAttributes(handleAudioFocus ? newAudioAttributes : null);
|
audioFocusManager.setAudioAttributes(handleAudioFocus ? newAudioAttributes : null);
|
||||||
|
trackSelector.setAudioAttributes(newAudioAttributes);
|
||||||
boolean playWhenReady = getPlayWhenReady();
|
boolean playWhenReady = getPlayWhenReady();
|
||||||
@AudioFocusManager.PlayerCommand
|
@AudioFocusManager.PlayerCommand
|
||||||
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
|
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
|
||||||
|
@ -110,6 +110,7 @@ public final class DownloadHelper {
|
|||||||
DefaultTrackSelector.Parameters.DEFAULT_WITHOUT_CONTEXT
|
DefaultTrackSelector.Parameters.DEFAULT_WITHOUT_CONTEXT
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.setForceHighestSupportedBitrate(true)
|
.setForceHighestSupportedBitrate(true)
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
/** Returns the default parameters used for track selection for downloading. */
|
/** Returns the default parameters used for track selection for downloading. */
|
||||||
@ -117,6 +118,7 @@ public final class DownloadHelper {
|
|||||||
return DefaultTrackSelector.Parameters.getDefaults(context)
|
return DefaultTrackSelector.Parameters.getDefaults(context)
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.setForceHighestSupportedBitrate(true)
|
.setForceHighestSupportedBitrate(true)
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,19 +15,29 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.exoplayer.trackselection;
|
package androidx.media3.exoplayer.trackselection;
|
||||||
|
|
||||||
|
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||||
|
import static androidx.media3.common.util.Util.castNonNull;
|
||||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||||
import static java.util.Collections.max;
|
import static java.util.Collections.max;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
import android.media.AudioFormat;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.Spatializer;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.SparseBooleanArray;
|
import android.util.SparseBooleanArray;
|
||||||
|
import androidx.annotation.GuardedBy;
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
import androidx.media3.common.AudioAttributes;
|
||||||
import androidx.media3.common.Bundleable;
|
import androidx.media3.common.Bundleable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.C.FormatSupport;
|
import androidx.media3.common.C.FormatSupport;
|
||||||
@ -40,6 +50,7 @@ import androidx.media3.common.TrackSelectionOverride;
|
|||||||
import androidx.media3.common.TrackSelectionParameters;
|
import androidx.media3.common.TrackSelectionParameters;
|
||||||
import androidx.media3.common.util.Assertions;
|
import androidx.media3.common.util.Assertions;
|
||||||
import androidx.media3.common.util.BundleableUtil;
|
import androidx.media3.common.util.BundleableUtil;
|
||||||
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.exoplayer.ExoPlaybackException;
|
import androidx.media3.exoplayer.ExoPlaybackException;
|
||||||
@ -50,6 +61,7 @@ import androidx.media3.exoplayer.RendererCapabilities.Capabilities;
|
|||||||
import androidx.media3.exoplayer.RendererConfiguration;
|
import androidx.media3.exoplayer.RendererConfiguration;
|
||||||
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 com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.ComparisonChain;
|
import com.google.common.collect.ComparisonChain;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Ordering;
|
import com.google.common.collect.Ordering;
|
||||||
@ -65,7 +77,6 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,6 +112,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
@UnstableApi
|
@UnstableApi
|
||||||
public class DefaultTrackSelector extends MappingTrackSelector {
|
public class DefaultTrackSelector extends MappingTrackSelector {
|
||||||
|
|
||||||
|
private static final String TAG = "DefaultTrackSelector";
|
||||||
|
private static final String AUDIO_CHANNEL_COUNT_CONSTRAINTS_WARN_MESSAGE =
|
||||||
|
"Audio channel count constraints cannot be applied without reference to Context. Build the"
|
||||||
|
+ " track selector instance with one of the non-deprecated constructors that take a"
|
||||||
|
+ " Context argument.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link Parameters.Builder} instead.
|
* @deprecated Use {@link Parameters.Builder} instead.
|
||||||
*/
|
*/
|
||||||
@ -680,6 +697,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
private boolean allowAudioMixedSampleRateAdaptiveness;
|
private boolean allowAudioMixedSampleRateAdaptiveness;
|
||||||
private boolean allowAudioMixedChannelCountAdaptiveness;
|
private boolean allowAudioMixedChannelCountAdaptiveness;
|
||||||
private boolean allowAudioMixedDecoderSupportAdaptiveness;
|
private boolean allowAudioMixedDecoderSupportAdaptiveness;
|
||||||
|
private boolean constrainAudioChannelCountToDeviceCapabilities;
|
||||||
// General
|
// General
|
||||||
private boolean exceedRendererCapabilitiesIfNecessary;
|
private boolean exceedRendererCapabilitiesIfNecessary;
|
||||||
private boolean tunnelingEnabled;
|
private boolean tunnelingEnabled;
|
||||||
@ -734,6 +752,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
initialValues.allowAudioMixedChannelCountAdaptiveness;
|
initialValues.allowAudioMixedChannelCountAdaptiveness;
|
||||||
allowAudioMixedDecoderSupportAdaptiveness =
|
allowAudioMixedDecoderSupportAdaptiveness =
|
||||||
initialValues.allowAudioMixedDecoderSupportAdaptiveness;
|
initialValues.allowAudioMixedDecoderSupportAdaptiveness;
|
||||||
|
constrainAudioChannelCountToDeviceCapabilities =
|
||||||
|
initialValues.constrainAudioChannelCountToDeviceCapabilities;
|
||||||
// General
|
// General
|
||||||
exceedRendererCapabilitiesIfNecessary = initialValues.exceedRendererCapabilitiesIfNecessary;
|
exceedRendererCapabilitiesIfNecessary = initialValues.exceedRendererCapabilitiesIfNecessary;
|
||||||
tunnelingEnabled = initialValues.tunnelingEnabled;
|
tunnelingEnabled = initialValues.tunnelingEnabled;
|
||||||
@ -746,6 +766,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
@SuppressWarnings("method.invocation") // Only setter are invoked.
|
@SuppressWarnings("method.invocation") // Only setter are invoked.
|
||||||
private Builder(Bundle bundle) {
|
private Builder(Bundle bundle) {
|
||||||
super(bundle);
|
super(bundle);
|
||||||
|
init();
|
||||||
Parameters defaultValue = Parameters.DEFAULT_WITHOUT_CONTEXT;
|
Parameters defaultValue = Parameters.DEFAULT_WITHOUT_CONTEXT;
|
||||||
// Video
|
// Video
|
||||||
setExceedVideoConstraintsIfNecessary(
|
setExceedVideoConstraintsIfNecessary(
|
||||||
@ -788,6 +809,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
Parameters.keyForField(
|
Parameters.keyForField(
|
||||||
Parameters.FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS),
|
Parameters.FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS),
|
||||||
defaultValue.allowAudioMixedDecoderSupportAdaptiveness));
|
defaultValue.allowAudioMixedDecoderSupportAdaptiveness));
|
||||||
|
setConstrainAudioChannelCountToDeviceCapabilities(
|
||||||
|
bundle.getBoolean(
|
||||||
|
Parameters.keyForField(
|
||||||
|
Parameters.FIELD_CONSTRAIN_AUDIO_CHANNEL_COUNT_TO_DEVICE_CAPABILITIES),
|
||||||
|
defaultValue.constrainAudioChannelCountToDeviceCapabilities));
|
||||||
// General
|
// General
|
||||||
setExceedRendererCapabilitiesIfNecessary(
|
setExceedRendererCapabilitiesIfNecessary(
|
||||||
bundle.getBoolean(
|
bundle.getBoolean(
|
||||||
@ -1082,6 +1108,36 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to only select audio tracks with channel counts that don't exceed the device's
|
||||||
|
* output capabilities. The default value is {@code true}.
|
||||||
|
*
|
||||||
|
* <p>When enabled, the track selector will prefer stereo/mono audio tracks over multichannel
|
||||||
|
* if the audio cannot be spatialized or the device is outputting stereo audio. For example,
|
||||||
|
* on a mobile device that outputs non-spatialized audio to its speakers. Dolby surround sound
|
||||||
|
* formats are excluded from these constraints because some Dolby decoders are known to
|
||||||
|
* spatialize multichannel audio on Android OS versions that don't support the {@link
|
||||||
|
* Spatializer} API.
|
||||||
|
*
|
||||||
|
* <p>For devices with Android 12L+ that support {@linkplain Spatializer audio
|
||||||
|
* spatialization}, when this is enabled the track selector will trigger a new track selection
|
||||||
|
* everytime a change in {@linkplain Spatializer.OnSpatializerStateChangedListener
|
||||||
|
* spatialization properties} is detected.
|
||||||
|
*
|
||||||
|
* <p>The constraints do not apply on devices with <a
|
||||||
|
* href="https://developer.android.com/guide/topics/resources/providing-resources#UiModeQualifier">{@code
|
||||||
|
* television} UI mode</a>.
|
||||||
|
*
|
||||||
|
* <p>The constraints do not apply when the track selector is created without a reference to a
|
||||||
|
* {@link Context} via the deprecated {@link
|
||||||
|
* DefaultTrackSelector#DefaultTrackSelector(TrackSelectionParameters,
|
||||||
|
* ExoTrackSelection.Factory)} constructor.
|
||||||
|
*/
|
||||||
|
public Builder setConstrainAudioChannelCountToDeviceCapabilities(boolean enabled) {
|
||||||
|
constrainAudioChannelCountToDeviceCapabilities = enabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1381,6 +1437,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
allowAudioMixedSampleRateAdaptiveness = false;
|
allowAudioMixedSampleRateAdaptiveness = false;
|
||||||
allowAudioMixedChannelCountAdaptiveness = false;
|
allowAudioMixedChannelCountAdaptiveness = false;
|
||||||
allowAudioMixedDecoderSupportAdaptiveness = false;
|
allowAudioMixedDecoderSupportAdaptiveness = false;
|
||||||
|
constrainAudioChannelCountToDeviceCapabilities = true;
|
||||||
// General
|
// General
|
||||||
exceedRendererCapabilitiesIfNecessary = true;
|
exceedRendererCapabilitiesIfNecessary = true;
|
||||||
tunnelingEnabled = false;
|
tunnelingEnabled = false;
|
||||||
@ -1475,6 +1532,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Video
|
// Video
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to exceed the {@link #maxVideoWidth}, {@link #maxVideoHeight} and {@link
|
* Whether to exceed the {@link #maxVideoWidth}, {@link #maxVideoHeight} and {@link
|
||||||
* #maxVideoBitrate} constraints when no selection can be made otherwise. The default value is
|
* #maxVideoBitrate} constraints when no selection can be made otherwise. The default value is
|
||||||
@ -1499,6 +1557,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
* RendererCapabilities.HardwareAccelerationSupport}.
|
* RendererCapabilities.HardwareAccelerationSupport}.
|
||||||
*/
|
*/
|
||||||
public final boolean allowVideoMixedDecoderSupportAdaptiveness;
|
public final boolean allowVideoMixedDecoderSupportAdaptiveness;
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to exceed the {@link #maxAudioChannelCount} and {@link #maxAudioBitrate} constraints
|
* Whether to exceed the {@link #maxAudioChannelCount} and {@link #maxAudioBitrate} constraints
|
||||||
* when no selection can be made otherwise. The default value is {@code true}.
|
* when no selection can be made otherwise. The default value is {@code true}.
|
||||||
@ -1526,6 +1587,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
* RendererCapabilities.HardwareAccelerationSupport}.
|
* RendererCapabilities.HardwareAccelerationSupport}.
|
||||||
*/
|
*/
|
||||||
public final boolean allowAudioMixedDecoderSupportAdaptiveness;
|
public final boolean allowAudioMixedDecoderSupportAdaptiveness;
|
||||||
|
/**
|
||||||
|
* Whether to constrain audio track selection so that the selected track's channel count does
|
||||||
|
* not exceed the device's output capabilities. The default value is {@code true}.
|
||||||
|
*/
|
||||||
|
public final boolean constrainAudioChannelCountToDeviceCapabilities;
|
||||||
|
|
||||||
|
// General
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to exceed renderer capabilities when no selection can be made otherwise.
|
* Whether to exceed renderer capabilities when no selection can be made otherwise.
|
||||||
*
|
*
|
||||||
@ -1566,6 +1635,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
allowAudioMixedSampleRateAdaptiveness = builder.allowAudioMixedSampleRateAdaptiveness;
|
allowAudioMixedSampleRateAdaptiveness = builder.allowAudioMixedSampleRateAdaptiveness;
|
||||||
allowAudioMixedChannelCountAdaptiveness = builder.allowAudioMixedChannelCountAdaptiveness;
|
allowAudioMixedChannelCountAdaptiveness = builder.allowAudioMixedChannelCountAdaptiveness;
|
||||||
allowAudioMixedDecoderSupportAdaptiveness = builder.allowAudioMixedDecoderSupportAdaptiveness;
|
allowAudioMixedDecoderSupportAdaptiveness = builder.allowAudioMixedDecoderSupportAdaptiveness;
|
||||||
|
constrainAudioChannelCountToDeviceCapabilities =
|
||||||
|
builder.constrainAudioChannelCountToDeviceCapabilities;
|
||||||
// General
|
// General
|
||||||
exceedRendererCapabilitiesIfNecessary = builder.exceedRendererCapabilitiesIfNecessary;
|
exceedRendererCapabilitiesIfNecessary = builder.exceedRendererCapabilitiesIfNecessary;
|
||||||
tunnelingEnabled = builder.tunnelingEnabled;
|
tunnelingEnabled = builder.tunnelingEnabled;
|
||||||
@ -1654,6 +1725,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
== other.allowAudioMixedChannelCountAdaptiveness
|
== other.allowAudioMixedChannelCountAdaptiveness
|
||||||
&& allowAudioMixedDecoderSupportAdaptiveness
|
&& allowAudioMixedDecoderSupportAdaptiveness
|
||||||
== other.allowAudioMixedDecoderSupportAdaptiveness
|
== other.allowAudioMixedDecoderSupportAdaptiveness
|
||||||
|
&& constrainAudioChannelCountToDeviceCapabilities
|
||||||
|
== other.constrainAudioChannelCountToDeviceCapabilities
|
||||||
// General
|
// General
|
||||||
&& exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary
|
&& exceedRendererCapabilitiesIfNecessary == other.exceedRendererCapabilitiesIfNecessary
|
||||||
&& tunnelingEnabled == other.tunnelingEnabled
|
&& tunnelingEnabled == other.tunnelingEnabled
|
||||||
@ -1678,6 +1751,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0);
|
result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0);
|
||||||
result = 31 * result + (allowAudioMixedChannelCountAdaptiveness ? 1 : 0);
|
result = 31 * result + (allowAudioMixedChannelCountAdaptiveness ? 1 : 0);
|
||||||
result = 31 * result + (allowAudioMixedDecoderSupportAdaptiveness ? 1 : 0);
|
result = 31 * result + (allowAudioMixedDecoderSupportAdaptiveness ? 1 : 0);
|
||||||
|
result = 31 * result + (constrainAudioChannelCountToDeviceCapabilities ? 1 : 0);
|
||||||
// General
|
// General
|
||||||
result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0);
|
result = 31 * result + (exceedRendererCapabilitiesIfNecessary ? 1 : 0);
|
||||||
result = 31 * result + (tunnelingEnabled ? 1 : 0);
|
result = 31 * result + (tunnelingEnabled ? 1 : 0);
|
||||||
@ -1712,6 +1786,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
FIELD_CUSTOM_ID_BASE + 14;
|
FIELD_CUSTOM_ID_BASE + 14;
|
||||||
private static final int FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS =
|
private static final int FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS =
|
||||||
FIELD_CUSTOM_ID_BASE + 15;
|
FIELD_CUSTOM_ID_BASE + 15;
|
||||||
|
private static final int FIELD_CONSTRAIN_AUDIO_CHANNEL_COUNT_TO_DEVICE_CAPABILITIES =
|
||||||
|
FIELD_CUSTOM_ID_BASE + 16;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bundle toBundle() {
|
public Bundle toBundle() {
|
||||||
@ -1746,6 +1822,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
bundle.putBoolean(
|
bundle.putBoolean(
|
||||||
keyForField(FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS),
|
keyForField(FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS),
|
||||||
allowAudioMixedDecoderSupportAdaptiveness);
|
allowAudioMixedDecoderSupportAdaptiveness);
|
||||||
|
bundle.putBoolean(
|
||||||
|
keyForField(FIELD_CONSTRAIN_AUDIO_CHANNEL_COUNT_TO_DEVICE_CAPABILITIES),
|
||||||
|
constrainAudioChannelCountToDeviceCapabilities);
|
||||||
// General
|
// General
|
||||||
bundle.putBoolean(
|
bundle.putBoolean(
|
||||||
keyForField(FIELD_EXCEED_RENDERER_CAPABILITIES_IF_NECESSARY),
|
keyForField(FIELD_EXCEED_RENDERER_CAPABILITIES_IF_NECESSARY),
|
||||||
@ -2004,8 +2083,20 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
/** Ordering where all elements are equal. */
|
/** Ordering where all elements are equal. */
|
||||||
private static final Ordering<Integer> NO_ORDER = Ordering.from((first, second) -> 0);
|
private static final Ordering<Integer> NO_ORDER = Ordering.from((first, second) -> 0);
|
||||||
|
|
||||||
|
private final Object lock;
|
||||||
|
@Nullable public final Context context;
|
||||||
private final ExoTrackSelection.Factory trackSelectionFactory;
|
private final ExoTrackSelection.Factory trackSelectionFactory;
|
||||||
private final AtomicReference<Parameters> parametersReference;
|
private final boolean deviceIsTV;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private Parameters parameters;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
@Nullable
|
||||||
|
private SpatializerWrapperV32 spatializer;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private AudioAttributes audioAttributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #DefaultTrackSelector(Context)} instead.
|
* @deprecated Use {@link #DefaultTrackSelector(Context)} instead.
|
||||||
@ -2015,14 +2106,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
this(Parameters.DEFAULT_WITHOUT_CONTEXT, new AdaptiveTrackSelection.Factory());
|
this(Parameters.DEFAULT_WITHOUT_CONTEXT, new AdaptiveTrackSelection.Factory());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link #DefaultTrackSelector(Context, ExoTrackSelection.Factory)}.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public DefaultTrackSelector(ExoTrackSelection.Factory trackSelectionFactory) {
|
|
||||||
this(Parameters.DEFAULT_WITHOUT_CONTEXT, trackSelectionFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context Any {@link Context}.
|
* @param context Any {@link Context}.
|
||||||
*/
|
*/
|
||||||
@ -2035,26 +2118,88 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
* @param trackSelectionFactory A factory for {@link ExoTrackSelection}s.
|
* @param trackSelectionFactory A factory for {@link ExoTrackSelection}s.
|
||||||
*/
|
*/
|
||||||
public DefaultTrackSelector(Context context, ExoTrackSelection.Factory trackSelectionFactory) {
|
public DefaultTrackSelector(Context context, ExoTrackSelection.Factory trackSelectionFactory) {
|
||||||
this(Parameters.getDefaults(context), trackSelectionFactory);
|
this(context, Parameters.getDefaults(context), trackSelectionFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param context Any {@link Context}.
|
||||||
|
* @param parameters Initial {@link TrackSelectionParameters}.
|
||||||
|
*/
|
||||||
|
public DefaultTrackSelector(Context context, TrackSelectionParameters parameters) {
|
||||||
|
this(context, parameters, new AdaptiveTrackSelection.Factory());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #DefaultTrackSelector(Context, TrackSelectionParameters,
|
||||||
|
* ExoTrackSelection.Factory)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public DefaultTrackSelector(
|
||||||
|
TrackSelectionParameters parameters, ExoTrackSelection.Factory trackSelectionFactory) {
|
||||||
|
this(parameters, trackSelectionFactory, /* context= */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context Any {@link Context}.
|
||||||
* @param parameters Initial {@link TrackSelectionParameters}.
|
* @param parameters Initial {@link TrackSelectionParameters}.
|
||||||
* @param trackSelectionFactory A factory for {@link ExoTrackSelection}s.
|
* @param trackSelectionFactory A factory for {@link ExoTrackSelection}s.
|
||||||
*/
|
*/
|
||||||
public DefaultTrackSelector(
|
public DefaultTrackSelector(
|
||||||
TrackSelectionParameters parameters, ExoTrackSelection.Factory trackSelectionFactory) {
|
Context context,
|
||||||
|
TrackSelectionParameters parameters,
|
||||||
|
ExoTrackSelection.Factory trackSelectionFactory) {
|
||||||
|
this(parameters, trackSelectionFactory, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exists for backwards compatibility so that the deprecated constructor {@link
|
||||||
|
* #DefaultTrackSelector(TrackSelectionParameters, ExoTrackSelection.Factory)} can initialize
|
||||||
|
* {@code context} with {@code null} while we don't have a public constructor with a {@code
|
||||||
|
* Nullable context}.
|
||||||
|
*
|
||||||
|
* @param context Any {@link Context}.
|
||||||
|
* @param parameters Initial {@link TrackSelectionParameters}.
|
||||||
|
* @param trackSelectionFactory A factory for {@link ExoTrackSelection}s.
|
||||||
|
*/
|
||||||
|
private DefaultTrackSelector(
|
||||||
|
TrackSelectionParameters parameters,
|
||||||
|
ExoTrackSelection.Factory trackSelectionFactory,
|
||||||
|
@Nullable Context context) {
|
||||||
|
this.lock = new Object();
|
||||||
|
this.context = context != null ? context.getApplicationContext() : null;
|
||||||
this.trackSelectionFactory = trackSelectionFactory;
|
this.trackSelectionFactory = trackSelectionFactory;
|
||||||
parametersReference =
|
if (parameters instanceof Parameters) {
|
||||||
new AtomicReference<>(
|
this.parameters = (Parameters) parameters;
|
||||||
parameters instanceof Parameters
|
} else {
|
||||||
? (Parameters) parameters
|
Parameters defaultParameters =
|
||||||
: Parameters.DEFAULT_WITHOUT_CONTEXT.buildUpon().set(parameters).build());
|
context == null ? Parameters.DEFAULT_WITHOUT_CONTEXT : Parameters.getDefaults(context);
|
||||||
|
this.parameters = defaultParameters.buildUpon().set(parameters).build();
|
||||||
|
}
|
||||||
|
this.audioAttributes = AudioAttributes.DEFAULT;
|
||||||
|
this.deviceIsTV = context != null && Util.isTv(context);
|
||||||
|
if (!deviceIsTV && context != null && Util.SDK_INT >= 32) {
|
||||||
|
spatializer = SpatializerWrapperV32.tryCreateInstance(context);
|
||||||
|
}
|
||||||
|
if (this.parameters.constrainAudioChannelCountToDeviceCapabilities && context == null) {
|
||||||
|
Log.w(TAG, AUDIO_CHANNEL_COUNT_CONSTRAINTS_WARN_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
synchronized (lock) {
|
||||||
|
if (Util.SDK_INT >= 32 && spatializer != null) {
|
||||||
|
spatializer.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Parameters getParameters() {
|
public Parameters getParameters() {
|
||||||
return parametersReference.get();
|
synchronized (lock) {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -2068,11 +2213,22 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
setParametersInternal((Parameters) parameters);
|
setParametersInternal((Parameters) parameters);
|
||||||
}
|
}
|
||||||
// Only add the fields of `TrackSelectionParameters` to `parameters`.
|
// Only add the fields of `TrackSelectionParameters` to `parameters`.
|
||||||
Parameters mergedParameters =
|
Parameters mergedParameters = new Parameters.Builder(getParameters()).set(parameters).build();
|
||||||
new Parameters.Builder(parametersReference.get()).set(parameters).build();
|
|
||||||
setParametersInternal(mergedParameters);
|
setParametersInternal(mergedParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAudioAttributes(AudioAttributes audioAttributes) {
|
||||||
|
boolean audioAttributesChanged;
|
||||||
|
synchronized (lock) {
|
||||||
|
audioAttributesChanged = !this.audioAttributes.equals(audioAttributes);
|
||||||
|
this.audioAttributes = audioAttributes;
|
||||||
|
}
|
||||||
|
if (audioAttributesChanged) {
|
||||||
|
maybeInvalidateForAudioChannelCountConstraints();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #setParameters(Parameters.Builder)} instead.
|
* @deprecated Use {@link #setParameters(Parameters.Builder)} instead.
|
||||||
*/
|
*/
|
||||||
@ -2103,7 +2259,16 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
*/
|
*/
|
||||||
private void setParametersInternal(Parameters parameters) {
|
private void setParametersInternal(Parameters parameters) {
|
||||||
Assertions.checkNotNull(parameters);
|
Assertions.checkNotNull(parameters);
|
||||||
if (!parametersReference.getAndSet(parameters).equals(parameters)) {
|
boolean parametersChanged;
|
||||||
|
synchronized (lock) {
|
||||||
|
parametersChanged = !this.parameters.equals(parameters);
|
||||||
|
this.parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parametersChanged) {
|
||||||
|
if (parameters.constrainAudioChannelCountToDeviceCapabilities && context == null) {
|
||||||
|
Log.w(TAG, AUDIO_CHANNEL_COUNT_CONSTRAINTS_WARN_MESSAGE);
|
||||||
|
}
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2119,22 +2284,33 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
MediaPeriodId mediaPeriodId,
|
MediaPeriodId mediaPeriodId,
|
||||||
Timeline timeline)
|
Timeline timeline)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
Parameters params = parametersReference.get();
|
Parameters parameters;
|
||||||
|
synchronized (lock) {
|
||||||
|
parameters = this.parameters;
|
||||||
|
if (parameters.constrainAudioChannelCountToDeviceCapabilities
|
||||||
|
&& Util.SDK_INT >= 32
|
||||||
|
&& spatializer != null) {
|
||||||
|
// Initialize the spatializer now so we can get a reference to the playback looper with
|
||||||
|
// Looper.myLooper().
|
||||||
|
spatializer.ensureInitialized(this, checkStateNotNull(Looper.myLooper()));
|
||||||
|
}
|
||||||
|
}
|
||||||
int rendererCount = mappedTrackInfo.getRendererCount();
|
int rendererCount = mappedTrackInfo.getRendererCount();
|
||||||
ExoTrackSelection.@NullableType Definition[] definitions =
|
ExoTrackSelection.@NullableType Definition[] definitions =
|
||||||
selectAllTracks(
|
selectAllTracks(
|
||||||
mappedTrackInfo,
|
mappedTrackInfo,
|
||||||
rendererFormatSupports,
|
rendererFormatSupports,
|
||||||
rendererMixedMimeTypeAdaptationSupports,
|
rendererMixedMimeTypeAdaptationSupports,
|
||||||
params);
|
parameters);
|
||||||
|
|
||||||
applyTrackSelectionOverrides(mappedTrackInfo, params, definitions);
|
applyTrackSelectionOverrides(mappedTrackInfo, parameters, definitions);
|
||||||
applyLegacyRendererOverrides(mappedTrackInfo, params, definitions);
|
applyLegacyRendererOverrides(mappedTrackInfo, parameters, definitions);
|
||||||
|
|
||||||
// Disable renderers if needed.
|
// Disable renderers if needed.
|
||||||
for (int i = 0; i < rendererCount; i++) {
|
for (int i = 0; i < rendererCount; i++) {
|
||||||
@C.TrackType int rendererType = mappedTrackInfo.getRendererType(i);
|
@C.TrackType int rendererType = mappedTrackInfo.getRendererType(i);
|
||||||
if (params.getRendererDisabled(i) || params.disabledTrackTypes.contains(rendererType)) {
|
if (parameters.getRendererDisabled(i)
|
||||||
|
|| parameters.disabledTrackTypes.contains(rendererType)) {
|
||||||
definitions[i] = null;
|
definitions[i] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2151,7 +2327,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
for (int i = 0; i < rendererCount; i++) {
|
for (int i = 0; i < rendererCount; i++) {
|
||||||
@C.TrackType int rendererType = mappedTrackInfo.getRendererType(i);
|
@C.TrackType int rendererType = mappedTrackInfo.getRendererType(i);
|
||||||
boolean forceRendererDisabled =
|
boolean forceRendererDisabled =
|
||||||
params.getRendererDisabled(i) || params.disabledTrackTypes.contains(rendererType);
|
parameters.getRendererDisabled(i) || parameters.disabledTrackTypes.contains(rendererType);
|
||||||
boolean rendererEnabled =
|
boolean rendererEnabled =
|
||||||
!forceRendererDisabled
|
!forceRendererDisabled
|
||||||
&& (mappedTrackInfo.getRendererType(i) == C.TRACK_TYPE_NONE
|
&& (mappedTrackInfo.getRendererType(i) == C.TRACK_TYPE_NONE
|
||||||
@ -2160,7 +2336,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure audio and video renderers to use tunneling if appropriate.
|
// Configure audio and video renderers to use tunneling if appropriate.
|
||||||
if (params.tunnelingEnabled) {
|
if (parameters.tunnelingEnabled) {
|
||||||
maybeConfigureRenderersForTunneling(
|
maybeConfigureRenderersForTunneling(
|
||||||
mappedTrackInfo, rendererFormatSupports, rendererConfigurations, rendererTrackSelections);
|
mappedTrackInfo, rendererFormatSupports, rendererConfigurations, rendererTrackSelections);
|
||||||
}
|
}
|
||||||
@ -2316,10 +2492,50 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
rendererFormatSupports,
|
rendererFormatSupports,
|
||||||
(int rendererIndex, TrackGroup group, @Capabilities int[] support) ->
|
(int rendererIndex, TrackGroup group, @Capabilities int[] support) ->
|
||||||
AudioTrackInfo.createForTrackGroup(
|
AudioTrackInfo.createForTrackGroup(
|
||||||
rendererIndex, group, params, support, hasVideoRendererWithMappedTracksFinal),
|
rendererIndex,
|
||||||
|
group,
|
||||||
|
params,
|
||||||
|
support,
|
||||||
|
hasVideoRendererWithMappedTracksFinal,
|
||||||
|
this::isAudioFormatWithinAudioChannelCountConstraints),
|
||||||
AudioTrackInfo::compareSelections);
|
AudioTrackInfo::compareSelections);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether an audio format is within the audio channel count constraints.
|
||||||
|
*
|
||||||
|
* <p>This method returns {@code true} if one of the following holds:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Audio channel count constraints are not applicable (all formats are considered within
|
||||||
|
* constraints).
|
||||||
|
* <li>The device has a <a
|
||||||
|
* href="https://developer.android.com/guide/topics/resources/providing-resources#UiModeQualifier">{@code
|
||||||
|
* television} UI mode</a>.
|
||||||
|
* <li>{@code format} has up to 2 channels.
|
||||||
|
* <li>The device does not support audio spatialization and the format is {@linkplain
|
||||||
|
* #isDolbyAudio(Format) a Dolby one}.
|
||||||
|
* <li>Audio spatialization is applicable and {@code format} can be spatialized.
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
private boolean isAudioFormatWithinAudioChannelCountConstraints(Format format) {
|
||||||
|
synchronized (lock) {
|
||||||
|
return !parameters.constrainAudioChannelCountToDeviceCapabilities
|
||||||
|
|| deviceIsTV
|
||||||
|
|| format.channelCount <= 2
|
||||||
|
|| (isDolbyAudio(format)
|
||||||
|
&& (Util.SDK_INT < 32
|
||||||
|
|| spatializer == null
|
||||||
|
|| !spatializer.isSpatializationSupported()))
|
||||||
|
|| (Util.SDK_INT >= 32
|
||||||
|
&& spatializer != null
|
||||||
|
&& spatializer.isSpatializationSupported()
|
||||||
|
&& spatializer.isAvailable()
|
||||||
|
&& spatializer.isEnabled()
|
||||||
|
&& spatializer.canBeSpatialized(audioAttributes, format));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Text track selection implementation.
|
// Text track selection implementation.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2453,6 +2669,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
firstTrackInfo.rendererIndex);
|
firstTrackInfo.rendererIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void maybeInvalidateForAudioChannelCountConstraints() {
|
||||||
|
boolean shouldInvalidate;
|
||||||
|
synchronized (lock) {
|
||||||
|
shouldInvalidate =
|
||||||
|
parameters.constrainAudioChannelCountToDeviceCapabilities
|
||||||
|
&& !deviceIsTV
|
||||||
|
&& Util.SDK_INT >= 32
|
||||||
|
&& spatializer != null
|
||||||
|
&& spatializer.isSpatializationSupported();
|
||||||
|
}
|
||||||
|
if (shouldInvalidate) {
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Utility methods.
|
// Utility methods.
|
||||||
|
|
||||||
private static void applyTrackSelectionOverrides(
|
private static void applyTrackSelectionOverrides(
|
||||||
@ -2777,6 +3008,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isDolbyAudio(Format format) {
|
||||||
|
if (format.sampleMimeType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (format.sampleMimeType) {
|
||||||
|
case MimeTypes.AUDIO_AC3:
|
||||||
|
case MimeTypes.AUDIO_E_AC3:
|
||||||
|
case MimeTypes.AUDIO_E_AC3_JOC:
|
||||||
|
case MimeTypes.AUDIO_AC4:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Base class for track selection information of a {@link Format}. */
|
/** Base class for track selection information of a {@link Format}. */
|
||||||
private abstract static class TrackInfo<T extends TrackInfo<T>> {
|
private abstract static class TrackInfo<T extends TrackInfo<T>> {
|
||||||
/** Factory for {@link TrackInfo} implementations for a given {@link TrackGroup}. */
|
/** Factory for {@link TrackInfo} implementations for a given {@link TrackGroup}. */
|
||||||
@ -3026,7 +3272,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
TrackGroup trackGroup,
|
TrackGroup trackGroup,
|
||||||
Parameters params,
|
Parameters params,
|
||||||
@Capabilities int[] formatSupport,
|
@Capabilities int[] formatSupport,
|
||||||
boolean hasMappedVideoTracks) {
|
boolean hasMappedVideoTracks,
|
||||||
|
Predicate<Format> withinAudioChannelCountConstraints) {
|
||||||
ImmutableList.Builder<AudioTrackInfo> listBuilder = ImmutableList.builder();
|
ImmutableList.Builder<AudioTrackInfo> listBuilder = ImmutableList.builder();
|
||||||
for (int i = 0; i < trackGroup.length; i++) {
|
for (int i = 0; i < trackGroup.length; i++) {
|
||||||
listBuilder.add(
|
listBuilder.add(
|
||||||
@ -3036,7 +3283,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
/* trackIndex= */ i,
|
/* trackIndex= */ i,
|
||||||
params,
|
params,
|
||||||
formatSupport[i],
|
formatSupport[i],
|
||||||
hasMappedVideoTracks));
|
hasMappedVideoTracks,
|
||||||
|
withinAudioChannelCountConstraints));
|
||||||
}
|
}
|
||||||
return listBuilder.build();
|
return listBuilder.build();
|
||||||
}
|
}
|
||||||
@ -3066,7 +3314,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
int trackIndex,
|
int trackIndex,
|
||||||
Parameters parameters,
|
Parameters parameters,
|
||||||
@Capabilities int formatSupport,
|
@Capabilities int formatSupport,
|
||||||
boolean hasMappedVideoTracks) {
|
boolean hasMappedVideoTracks,
|
||||||
|
Predicate<Format> withinAudioChannelCountConstraints) {
|
||||||
super(rendererIndex, trackGroup, trackIndex);
|
super(rendererIndex, trackGroup, trackIndex);
|
||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
this.language = normalizeUndeterminedLanguageToNull(format.language);
|
this.language = normalizeUndeterminedLanguageToNull(format.language);
|
||||||
@ -3098,7 +3347,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
isWithinConstraints =
|
isWithinConstraints =
|
||||||
(format.bitrate == Format.NO_VALUE || format.bitrate <= parameters.maxAudioBitrate)
|
(format.bitrate == Format.NO_VALUE || format.bitrate <= parameters.maxAudioBitrate)
|
||||||
&& (format.channelCount == Format.NO_VALUE
|
&& (format.channelCount == Format.NO_VALUE
|
||||||
|| format.channelCount <= parameters.maxAudioChannelCount);
|
|| format.channelCount <= parameters.maxAudioChannelCount)
|
||||||
|
&& withinAudioChannelCountConstraints.apply(format);
|
||||||
String[] localeLanguages = Util.getSystemLanguageCodes();
|
String[] localeLanguages = Util.getSystemLanguageCodes();
|
||||||
int bestLocaleMatchIndex = Integer.MAX_VALUE;
|
int bestLocaleMatchIndex = Integer.MAX_VALUE;
|
||||||
int bestLocaleMatchScore = 0;
|
int bestLocaleMatchScore = 0;
|
||||||
@ -3375,4 +3625,85 @@ public class DefaultTrackSelector extends MappingTrackSelector {
|
|||||||
.result();
|
.result();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the {@link Spatializer} in order to encapsulate its APIs within an inner class, to avoid
|
||||||
|
* runtime linking on devices with {@code API < 32}.
|
||||||
|
*/
|
||||||
|
@RequiresApi(32)
|
||||||
|
private static class SpatializerWrapperV32 {
|
||||||
|
|
||||||
|
private final Spatializer spatializer;
|
||||||
|
private final boolean spatializationSupported;
|
||||||
|
|
||||||
|
@Nullable private Handler handler;
|
||||||
|
@Nullable private Spatializer.OnSpatializerStateChangedListener listener;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static SpatializerWrapperV32 tryCreateInstance(Context context) {
|
||||||
|
@Nullable
|
||||||
|
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
return audioManager == null ? null : new SpatializerWrapperV32(audioManager.getSpatializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpatializerWrapperV32(Spatializer spatializer) {
|
||||||
|
this.spatializer = spatializer;
|
||||||
|
this.spatializationSupported =
|
||||||
|
spatializer.getImmersiveAudioLevel() != Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ensureInitialized(DefaultTrackSelector defaultTrackSelector, Looper looper) {
|
||||||
|
if (listener != null || handler != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.listener =
|
||||||
|
new Spatializer.OnSpatializerStateChangedListener() {
|
||||||
|
@Override
|
||||||
|
public void onSpatializerEnabledChanged(Spatializer spatializer, boolean enabled) {
|
||||||
|
defaultTrackSelector.maybeInvalidateForAudioChannelCountConstraints();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSpatializerAvailableChanged(Spatializer spatializer, boolean available) {
|
||||||
|
defaultTrackSelector.maybeInvalidateForAudioChannelCountConstraints();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.handler = new Handler(looper);
|
||||||
|
spatializer.addOnSpatializerStateChangedListener(handler::post, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSpatializationSupported() {
|
||||||
|
return spatializationSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return spatializer.isAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return spatializer.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canBeSpatialized(AudioAttributes audioAttributes, Format format) {
|
||||||
|
AudioFormat.Builder builder =
|
||||||
|
new AudioFormat.Builder()
|
||||||
|
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
|
||||||
|
.setChannelMask(Util.getAudioTrackChannelConfig(format.channelCount));
|
||||||
|
if (format.sampleRate != Format.NO_VALUE) {
|
||||||
|
builder.setSampleRate(format.sampleRate);
|
||||||
|
}
|
||||||
|
return spatializer.canBeSpatialized(
|
||||||
|
audioAttributes.getAudioAttributesV21().audioAttributes, builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
if (listener == null || handler == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spatializer.removeOnSpatializerStateChangedListener(listener);
|
||||||
|
castNonNull(handler).removeCallbacksAndMessages(/* token= */ null);
|
||||||
|
handler = null;
|
||||||
|
listener = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,9 @@ package androidx.media3.exoplayer.trackselection;
|
|||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||||
|
|
||||||
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.media3.common.AudioAttributes;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.common.Timeline;
|
import androidx.media3.common.Timeline;
|
||||||
import androidx.media3.common.TrackSelectionParameters;
|
import androidx.media3.common.TrackSelectionParameters;
|
||||||
@ -112,7 +114,8 @@ public abstract class TrackSelector {
|
|||||||
* it has previously made are no longer valid.
|
* it has previously made are no longer valid.
|
||||||
* @param bandwidthMeter A bandwidth meter which can be used by track selections to select tracks.
|
* @param bandwidthMeter A bandwidth meter which can be used by track selections to select tracks.
|
||||||
*/
|
*/
|
||||||
public final void init(InvalidationListener listener, BandwidthMeter bandwidthMeter) {
|
@CallSuper
|
||||||
|
public void init(InvalidationListener listener, BandwidthMeter bandwidthMeter) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.bandwidthMeter = bandwidthMeter;
|
this.bandwidthMeter = bandwidthMeter;
|
||||||
}
|
}
|
||||||
@ -121,9 +124,10 @@ public abstract class TrackSelector {
|
|||||||
* Called by the player to release the selector. The selector cannot be used until {@link
|
* Called by the player to release the selector. The selector cannot be used until {@link
|
||||||
* #init(InvalidationListener, BandwidthMeter)} is called again.
|
* #init(InvalidationListener, BandwidthMeter)} is called again.
|
||||||
*/
|
*/
|
||||||
public final void release() {
|
@CallSuper
|
||||||
this.listener = null;
|
public void release() {
|
||||||
this.bandwidthMeter = null;
|
listener = null;
|
||||||
|
bandwidthMeter = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,6 +182,11 @@ public abstract class TrackSelector {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Called by the player to set the {@link AudioAttributes} that will be used for playback. */
|
||||||
|
public void setAudioAttributes(AudioAttributes audioAttributes) {
|
||||||
|
// Default implementation is no-op.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls {@link InvalidationListener#onTrackSelectionsInvalidated()} to invalidate all previously
|
* Calls {@link InvalidationListener#onTrackSelectionsInvalidated()} to invalidate all previously
|
||||||
* generated track selections.
|
* generated track selections.
|
||||||
|
@ -31,9 +31,9 @@ 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;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.MockitoAnnotations.initMocks;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.media.Spatializer;
|
||||||
import androidx.media3.common.Bundleable;
|
import androidx.media3.common.Bundleable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
@ -68,14 +68,19 @@ import java.util.Map;
|
|||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
|
|
||||||
/** Unit tests for {@link DefaultTrackSelector}. */
|
/** Unit tests for {@link DefaultTrackSelector}. */
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public final class DefaultTrackSelectorTest {
|
public final class DefaultTrackSelectorTest {
|
||||||
|
|
||||||
|
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||||
|
|
||||||
private static final RendererCapabilities ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES =
|
private static final RendererCapabilities ALL_AUDIO_FORMAT_SUPPORTED_RENDERER_CAPABILITIES =
|
||||||
new FakeRendererCapabilities(C.TRACK_TYPE_AUDIO);
|
new FakeRendererCapabilities(C.TRACK_TYPE_AUDIO);
|
||||||
private static final RendererCapabilities ALL_TEXT_FORMAT_SUPPORTED_RENDERER_CAPABILITIES =
|
private static final RendererCapabilities ALL_TEXT_FORMAT_SUPPORTED_RENDERER_CAPABILITIES =
|
||||||
@ -142,7 +147,6 @@ public final class DefaultTrackSelectorTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
initMocks(this);
|
|
||||||
when(bandwidthMeter.getBitrateEstimate()).thenReturn(1000000L);
|
when(bandwidthMeter.getBitrateEstimate()).thenReturn(1000000L);
|
||||||
Context context = ApplicationProvider.getApplicationContext();
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
defaultParameters = Parameters.getDefaults(context);
|
defaultParameters = Parameters.getDefaults(context);
|
||||||
@ -877,11 +881,18 @@ public final class DefaultTrackSelectorTest {
|
|||||||
* are the same, and tracks are within renderer's capabilities.
|
* are the same, and tracks are within renderer's capabilities.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void selectTracksWithinCapabilitiesSelectHigherNumChannel() throws Exception {
|
public void
|
||||||
|
selectTracks_audioChannelCountConstraintsDisabledAndTracksWithinCapabilities_selectHigherNumChannel()
|
||||||
|
throws Exception {
|
||||||
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
|
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
|
||||||
Format higherChannelFormat = formatBuilder.setChannelCount(6).build();
|
Format higherChannelFormat = formatBuilder.setChannelCount(6).build();
|
||||||
Format lowerChannelFormat = formatBuilder.setChannelCount(2).build();
|
Format lowerChannelFormat = formatBuilder.setChannelCount(2).build();
|
||||||
TrackGroupArray trackGroups = wrapFormats(higherChannelFormat, lowerChannelFormat);
|
TrackGroupArray trackGroups = wrapFormats(higherChannelFormat, lowerChannelFormat);
|
||||||
|
trackSelector.setParameters(
|
||||||
|
trackSelector
|
||||||
|
.buildUponParameters()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
|
.build());
|
||||||
|
|
||||||
TrackSelectorResult result =
|
TrackSelectorResult result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
@ -957,11 +968,13 @@ public final class DefaultTrackSelectorTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that track selector will prefer audio tracks with higher channel count over tracks with
|
* Tests that track selector will prefer audio tracks with higher channel count over tracks with
|
||||||
* higher sample rate when other factors are the same, and tracks are within renderer's
|
* higher sample rate when audio channel count constraints are disabled, other factors are the
|
||||||
* capabilities.
|
* same, and tracks are within renderer's capabilities.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void selectTracksPreferHigherNumChannelBeforeSampleRate() throws Exception {
|
public void
|
||||||
|
selectTracks_audioChannelCountConstraintsDisabled_preferHigherNumChannelBeforeSampleRate()
|
||||||
|
throws Exception {
|
||||||
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
|
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
|
||||||
Format higherChannelLowerSampleRateFormat =
|
Format higherChannelLowerSampleRateFormat =
|
||||||
formatBuilder.setChannelCount(6).setSampleRate(22050).build();
|
formatBuilder.setChannelCount(6).setSampleRate(22050).build();
|
||||||
@ -969,6 +982,11 @@ public final class DefaultTrackSelectorTest {
|
|||||||
formatBuilder.setChannelCount(2).setSampleRate(44100).build();
|
formatBuilder.setChannelCount(2).setSampleRate(44100).build();
|
||||||
TrackGroupArray trackGroups =
|
TrackGroupArray trackGroups =
|
||||||
wrapFormats(higherChannelLowerSampleRateFormat, lowerChannelHigherSampleRateFormat);
|
wrapFormats(higherChannelLowerSampleRateFormat, lowerChannelHigherSampleRateFormat);
|
||||||
|
trackSelector.setParameters(
|
||||||
|
trackSelector
|
||||||
|
.buildUponParameters()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
|
.build());
|
||||||
|
|
||||||
TrackSelectorResult result =
|
TrackSelectorResult result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
@ -1454,8 +1472,66 @@ public final class DefaultTrackSelectorTest {
|
|||||||
assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 0, 1);
|
assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following test is subject to the execution context. It currently runs on SDK 30 and the
|
||||||
|
* environment matches a handheld device ({@link Util#isTv(Context)} returns {@code false}) and
|
||||||
|
* there is no {@link android.media.Spatializer}. If the execution environment upgrades, the test
|
||||||
|
* may start failing depending on how the Robolectric Spatializer behaves. If the test starts
|
||||||
|
* failing, and Robolectric offers a shadow Spatializer whose behavior can be controlled, revise
|
||||||
|
* this test so that the Spatializer cannot spatialize the multichannel format. Also add tests
|
||||||
|
* where the Spatializer can spatialize multichannel formats and the track selector picks a
|
||||||
|
* multichannel format.
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void selectTracks_multipleAudioTracks_selectsAllTracksInBestConfigurationOnly()
|
public void selectTracks_stereoAndMultichannelAACTracks_selectsStereo()
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
Format stereoAudioFormat = AUDIO_FORMAT.buildUpon().setChannelCount(2).setId("0").build();
|
||||||
|
Format multichannelAudioFormat = AUDIO_FORMAT.buildUpon().setChannelCount(6).setId("1").build();
|
||||||
|
TrackGroupArray trackGroups = singleTrackGroup(stereoAudioFormat, multichannelAudioFormat);
|
||||||
|
|
||||||
|
TrackSelectorResult result =
|
||||||
|
trackSelector.selectTracks(
|
||||||
|
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
||||||
|
|
||||||
|
assertThat(result.length).isEqualTo(1);
|
||||||
|
assertThat(result.selections[0].getSelectedFormat()).isSameInstanceAs(stereoAudioFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following test is subject to the execution context. It currently runs on SDK 30 and the
|
||||||
|
* environment matches a handheld device ({@link Util#isTv(Context)} returns {@code false}) and
|
||||||
|
* there is no {@link android.media.Spatializer}. If the execution environment upgrades, the test
|
||||||
|
* may start failing depending on how the Robolectric Spatializer behaves. If the test starts
|
||||||
|
* failing, and Robolectric offers a shadow Spatializer whose behavior can be controlled, revise
|
||||||
|
* this test so that the Spatializer does not support spatialization ({@link
|
||||||
|
* Spatializer#getImmersiveAudioLevel()} returns {@link
|
||||||
|
* Spatializer#SPATIALIZER_IMMERSIVE_LEVEL_NONE}).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
selectTracks_withAACStereoAndDolbyMultichannelTrackWithinCapabilities_selectsDolbyMultichannelTrack()
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
Format stereoAudioFormat = AUDIO_FORMAT.buildUpon().setChannelCount(2).setId("0").build();
|
||||||
|
Format multichannelAudioFormat =
|
||||||
|
AUDIO_FORMAT
|
||||||
|
.buildUpon()
|
||||||
|
.setSampleMimeType(MimeTypes.AUDIO_AC3)
|
||||||
|
.setChannelCount(6)
|
||||||
|
.setId("1")
|
||||||
|
.build();
|
||||||
|
TrackGroupArray trackGroups = singleTrackGroup(stereoAudioFormat, multichannelAudioFormat);
|
||||||
|
|
||||||
|
TrackSelectorResult result =
|
||||||
|
trackSelector.selectTracks(
|
||||||
|
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
||||||
|
|
||||||
|
assertThat(result.length).isEqualTo(1);
|
||||||
|
assertThat(result.selections[0].getSelectedFormat()).isSameInstanceAs(multichannelAudioFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
selectTracks_audioChannelCountConstraintsDisabledAndMultipleAudioTracks_selectsAllTracksInBestConfigurationOnly()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
TrackGroupArray trackGroups =
|
TrackGroupArray trackGroups =
|
||||||
singleTrackGroup(
|
singleTrackGroup(
|
||||||
@ -1476,6 +1552,10 @@ public final class DefaultTrackSelectorTest {
|
|||||||
/* channelCount= */ 6,
|
/* channelCount= */ 6,
|
||||||
MimeTypes.AUDIO_AAC,
|
MimeTypes.AUDIO_AAC,
|
||||||
/* sampleRate= */ 44100));
|
/* sampleRate= */ 44100));
|
||||||
|
trackSelector.setParameters(
|
||||||
|
trackSelector
|
||||||
|
.buildUponParameters()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false));
|
||||||
|
|
||||||
TrackSelectorResult result =
|
TrackSelectorResult result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
@ -1568,10 +1648,17 @@ public final class DefaultTrackSelectorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectTracksWithMultipleAudioTracksWithMixedChannelCounts() throws Exception {
|
public void
|
||||||
|
selectTracks_audioChannelCountConstraintsDisabledAndMultipleAudioTracksWithMixedChannelCounts()
|
||||||
|
throws Exception {
|
||||||
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
|
Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
|
||||||
Format stereoAudioFormat = formatBuilder.setChannelCount(2).build();
|
Format stereoAudioFormat = formatBuilder.setChannelCount(2).build();
|
||||||
Format surroundAudioFormat = formatBuilder.setChannelCount(5).build();
|
Format surroundAudioFormat = formatBuilder.setChannelCount(5).build();
|
||||||
|
trackSelector.setParameters(
|
||||||
|
trackSelector
|
||||||
|
.buildUponParameters()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
|
.build());
|
||||||
|
|
||||||
// Should not adapt between different channel counts, so we expect a fixed selection containing
|
// Should not adapt between different channel counts, so we expect a fixed selection containing
|
||||||
// the track with more channels.
|
// the track with more channels.
|
||||||
@ -1592,7 +1679,11 @@ public final class DefaultTrackSelectorTest {
|
|||||||
|
|
||||||
// If we constrain the channel count to 4 we expect a fixed selection containing the track with
|
// If we constrain the channel count to 4 we expect a fixed selection containing the track with
|
||||||
// fewer channels.
|
// fewer channels.
|
||||||
trackSelector.setParameters(defaultParameters.buildUpon().setMaxAudioChannelCount(4));
|
trackSelector.setParameters(
|
||||||
|
defaultParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
|
.setMaxAudioChannelCount(4));
|
||||||
result =
|
result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
||||||
@ -1601,7 +1692,11 @@ public final class DefaultTrackSelectorTest {
|
|||||||
|
|
||||||
// If we constrain the channel count to 2 we expect a fixed selection containing the track with
|
// If we constrain the channel count to 2 we expect a fixed selection containing the track with
|
||||||
// fewer channels.
|
// fewer channels.
|
||||||
trackSelector.setParameters(defaultParameters.buildUpon().setMaxAudioChannelCount(2));
|
trackSelector.setParameters(
|
||||||
|
defaultParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
|
.setMaxAudioChannelCount(2));
|
||||||
result =
|
result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
||||||
@ -1610,7 +1705,11 @@ public final class DefaultTrackSelectorTest {
|
|||||||
|
|
||||||
// If we constrain the channel count to 1 we expect a fixed selection containing the track with
|
// If we constrain the channel count to 1 we expect a fixed selection containing the track with
|
||||||
// fewer channels.
|
// fewer channels.
|
||||||
trackSelector.setParameters(defaultParameters.buildUpon().setMaxAudioChannelCount(1));
|
trackSelector.setParameters(
|
||||||
|
defaultParameters
|
||||||
|
.buildUpon()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
|
.setMaxAudioChannelCount(1));
|
||||||
result =
|
result =
|
||||||
trackSelector.selectTracks(
|
trackSelector.selectTracks(
|
||||||
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
new RendererCapabilities[] {AUDIO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
|
||||||
@ -1621,6 +1720,7 @@ public final class DefaultTrackSelectorTest {
|
|||||||
trackSelector.setParameters(
|
trackSelector.setParameters(
|
||||||
defaultParameters
|
defaultParameters
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
.setMaxAudioChannelCount(1)
|
.setMaxAudioChannelCount(1)
|
||||||
.setExceedAudioConstraintsIfNecessary(false));
|
.setExceedAudioConstraintsIfNecessary(false));
|
||||||
result =
|
result =
|
||||||
@ -2399,6 +2499,7 @@ public final class DefaultTrackSelectorTest {
|
|||||||
.setAllowAudioMixedChannelCountAdaptiveness(true)
|
.setAllowAudioMixedChannelCountAdaptiveness(true)
|
||||||
.setAllowAudioMixedDecoderSupportAdaptiveness(false)
|
.setAllowAudioMixedDecoderSupportAdaptiveness(false)
|
||||||
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AC3, MimeTypes.AUDIO_E_AC3)
|
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AC3, MimeTypes.AUDIO_E_AC3)
|
||||||
|
.setConstrainAudioChannelCountToDeviceCapabilities(false)
|
||||||
// Text
|
// Text
|
||||||
.setPreferredTextLanguages("de", "en")
|
.setPreferredTextLanguages("de", "en")
|
||||||
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
|
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user