diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a3f4fc2941..773921155e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -29,6 +29,11 @@ * Extrapolate current position during sleep with offload scheduling. * Add `Renderer.release()` and `AudioSink.release()` for releasing the resources at the end of player's lifecycle. + * Listen to audio capabilities changes in `DefaultAudioSink`. Add a + required parameter `context` in the constructor of `DefaultAudioSink`, + with which the `DefaultAudioSink` will register as the listener to the + `AudioCapabilitiesReceiver` and update its `audioCapabilities` property + when informed with a capabilities change. * DRM: * Reduce the visibility of several internal-only methods on `DefaultDrmSession` that aren't expected to be called from outside the diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java index 02a77a96e4..f3443e1307 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java @@ -26,7 +26,6 @@ import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.media3.common.util.Log; import androidx.media3.common.util.UnstableApi; -import androidx.media3.exoplayer.audio.AudioCapabilities; import androidx.media3.exoplayer.audio.AudioRendererEventListener; import androidx.media3.exoplayer.audio.AudioSink; import androidx.media3.exoplayer.audio.DefaultAudioSink; @@ -649,8 +648,7 @@ public class DefaultRenderersFactory implements RenderersFactory { boolean enableFloatOutput, boolean enableAudioTrackPlaybackParams, boolean enableOffload) { - return new DefaultAudioSink.Builder() - .setAudioCapabilities(AudioCapabilities.getCapabilities(context)) + return new DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode( diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java index ae2a4b27d7..859b98f215 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java @@ -17,13 +17,16 @@ package androidx.media3.exoplayer.audio; import static androidx.media3.common.audio.AudioProcessor.EMPTY_BUFFER; import static androidx.media3.common.util.Assertions.checkNotNull; +import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Util.constrainValue; import static androidx.media3.exoplayer.audio.AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES; +import static androidx.media3.exoplayer.audio.AudioCapabilities.getCapabilities; import static java.lang.Math.max; import static java.lang.Math.min; import static java.lang.annotation.ElementType.TYPE_USE; import android.annotation.SuppressLint; +import android.content.Context; import android.media.AudioDeviceInfo; import android.media.AudioFormat; import android.media.AudioManager; @@ -227,6 +230,7 @@ public final class DefaultAudioSink implements AudioSink { /** A builder to create {@link DefaultAudioSink} instances. */ public static final class Builder { + @Nullable private final Context context; private AudioCapabilities audioCapabilities; @Nullable private androidx.media3.common.audio.AudioProcessorChain audioProcessorChain; private boolean enableFloatOutput; @@ -235,19 +239,36 @@ public final class DefaultAudioSink implements AudioSink { AudioTrackBufferSizeProvider audioTrackBufferSizeProvider; @Nullable AudioOffloadListener audioOffloadListener; - /** Creates a new builder. */ + /** + * @deprecated Use {@link #Builder(Context)} instead. + */ + @Deprecated public Builder() { + this.context = null; audioCapabilities = DEFAULT_AUDIO_CAPABILITIES; offloadMode = OFFLOAD_MODE_DISABLED; audioTrackBufferSizeProvider = AudioTrackBufferSizeProvider.DEFAULT; } /** - * Sets audio capabilities for playback on this device. May be {@code null} if the default - * capabilities (no encoded audio passthrough support) should be assumed. + * Creates a new builder. * - *
Default is {@link AudioCapabilities#DEFAULT_AUDIO_CAPABILITIES}.
+ * @param context The {@link Context}.
*/
+ public Builder(Context context) {
+ this.context = context;
+ audioCapabilities = DEFAULT_AUDIO_CAPABILITIES;
+ offloadMode = OFFLOAD_MODE_DISABLED;
+ audioTrackBufferSizeProvider = AudioTrackBufferSizeProvider.DEFAULT;
+ }
+
+ /**
+ * @deprecated These {@linkplain AudioCapabilities audio capabilities} are only used in the
+ * absence of a {@linkplain Context context}. In the case when the {@code Context} is {@code
+ * null} and the {@code audioCapabilities} is not set to the {@code Builder}, the default
+ * capabilities (no encoded audio passthrough support) should be assumed.
+ */
+ @Deprecated
@CanIgnoreReturnValue
public Builder setAudioCapabilities(AudioCapabilities audioCapabilities) {
checkNotNull(audioCapabilities);
@@ -466,6 +487,7 @@ public final class DefaultAudioSink implements AudioSink {
@GuardedBy("releaseExecutorLock")
private static int pendingReleaseCount;
+ @Nullable private final Context context;
private final androidx.media3.common.audio.AudioProcessorChain audioProcessorChain;
private final boolean enableFloatOutput;
private final ChannelMappingAudioProcessor channelMappingAudioProcessor;
@@ -491,6 +513,7 @@ public final class DefaultAudioSink implements AudioSink {
private @MonotonicNonNull AudioProcessingPipeline audioProcessingPipeline;
@Nullable private AudioTrack audioTrack;
private AudioCapabilities audioCapabilities;
+ private @MonotonicNonNull AudioCapabilitiesReceiver audioCapabilitiesReceiver;
private AudioAttributes audioAttributes;
@Nullable private MediaPositionParameters afterDrainParameters;
@@ -529,10 +552,12 @@ public final class DefaultAudioSink implements AudioSink {
private long lastFeedElapsedRealtimeMs;
private boolean offloadDisabledUntilNextConfiguration;
private boolean isWaitingForOffloadEndOfStreamHandled;
+ @Nullable private Looper playbackLooper;
@RequiresNonNull("#1.audioProcessorChain")
private DefaultAudioSink(Builder builder) {
- audioCapabilities = builder.audioCapabilities;
+ context = builder.context;
+ audioCapabilities = context != null ? getCapabilities(context) : builder.audioCapabilities;
audioProcessorChain = builder.audioProcessorChain;
enableFloatOutput = Util.SDK_INT >= 21 && builder.enableFloatOutput;
preferAudioTrackPlaybackParams = Util.SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams;
@@ -599,7 +624,7 @@ public final class DefaultAudioSink implements AudioSink {
if (!offloadDisabledUntilNextConfiguration && useOffloadedPlayback(format, audioAttributes)) {
return SINK_FORMAT_SUPPORTED_DIRECTLY;
}
- if (audioCapabilities.isPassthroughPlaybackSupported(format)) {
+ if (getAudioCapabilities().isPassthroughPlaybackSupported(format)) {
return SINK_FORMAT_SUPPORTED_DIRECTLY;
}
return SINK_FORMAT_UNSUPPORTED;
@@ -692,7 +717,7 @@ public final class DefaultAudioSink implements AudioSink {
outputMode = OUTPUT_MODE_PASSTHROUGH;
@Nullable
Pair