mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Rollback of 26aee812d5
*** Original commit ***
Rollback of 6109a0eb62
*** Original commit ***
Intercept audio capabilities change in `DefaultAudioSink`
***
***
PiperOrigin-RevId: 520619600
This commit is contained in:
parent
43ad45dbef
commit
cb578fcf25
3 changed files with 66 additions and 10 deletions
|
|
@ -29,6 +29,11 @@
|
||||||
* Extrapolate current position during sleep with offload scheduling.
|
* Extrapolate current position during sleep with offload scheduling.
|
||||||
* Add `Renderer.release()` and `AudioSink.release()` for releasing the
|
* Add `Renderer.release()` and `AudioSink.release()` for releasing the
|
||||||
resources at the end of player's lifecycle.
|
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:
|
* DRM:
|
||||||
* Reduce the visibility of several internal-only methods on
|
* Reduce the visibility of several internal-only methods on
|
||||||
`DefaultDrmSession` that aren't expected to be called from outside the
|
`DefaultDrmSession` that aren't expected to be called from outside the
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.util.Log;
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.exoplayer.audio.AudioCapabilities;
|
|
||||||
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
||||||
import androidx.media3.exoplayer.audio.AudioSink;
|
import androidx.media3.exoplayer.audio.AudioSink;
|
||||||
import androidx.media3.exoplayer.audio.DefaultAudioSink;
|
import androidx.media3.exoplayer.audio.DefaultAudioSink;
|
||||||
|
|
@ -649,8 +648,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
||||||
boolean enableFloatOutput,
|
boolean enableFloatOutput,
|
||||||
boolean enableAudioTrackPlaybackParams,
|
boolean enableAudioTrackPlaybackParams,
|
||||||
boolean enableOffload) {
|
boolean enableOffload) {
|
||||||
return new DefaultAudioSink.Builder()
|
return new DefaultAudioSink.Builder(context)
|
||||||
.setAudioCapabilities(AudioCapabilities.getCapabilities(context))
|
|
||||||
.setEnableFloatOutput(enableFloatOutput)
|
.setEnableFloatOutput(enableFloatOutput)
|
||||||
.setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams)
|
.setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams)
|
||||||
.setOffloadMode(
|
.setOffloadMode(
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,16 @@ package androidx.media3.exoplayer.audio;
|
||||||
|
|
||||||
import static androidx.media3.common.audio.AudioProcessor.EMPTY_BUFFER;
|
import static androidx.media3.common.audio.AudioProcessor.EMPTY_BUFFER;
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
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.common.util.Util.constrainValue;
|
||||||
import static androidx.media3.exoplayer.audio.AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES;
|
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.max;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
import android.media.AudioDeviceInfo;
|
import android.media.AudioDeviceInfo;
|
||||||
import android.media.AudioFormat;
|
import android.media.AudioFormat;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
|
@ -227,6 +230,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
/** A builder to create {@link DefaultAudioSink} instances. */
|
/** A builder to create {@link DefaultAudioSink} instances. */
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
|
|
||||||
|
@Nullable private final Context context;
|
||||||
private AudioCapabilities audioCapabilities;
|
private AudioCapabilities audioCapabilities;
|
||||||
@Nullable private androidx.media3.common.audio.AudioProcessorChain audioProcessorChain;
|
@Nullable private androidx.media3.common.audio.AudioProcessorChain audioProcessorChain;
|
||||||
private boolean enableFloatOutput;
|
private boolean enableFloatOutput;
|
||||||
|
|
@ -235,19 +239,36 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
AudioTrackBufferSizeProvider audioTrackBufferSizeProvider;
|
AudioTrackBufferSizeProvider audioTrackBufferSizeProvider;
|
||||||
@Nullable AudioOffloadListener audioOffloadListener;
|
@Nullable AudioOffloadListener audioOffloadListener;
|
||||||
|
|
||||||
/** Creates a new builder. */
|
/**
|
||||||
|
* @deprecated Use {@link #Builder(Context)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public Builder() {
|
public Builder() {
|
||||||
|
this.context = null;
|
||||||
audioCapabilities = DEFAULT_AUDIO_CAPABILITIES;
|
audioCapabilities = DEFAULT_AUDIO_CAPABILITIES;
|
||||||
offloadMode = OFFLOAD_MODE_DISABLED;
|
offloadMode = OFFLOAD_MODE_DISABLED;
|
||||||
audioTrackBufferSizeProvider = AudioTrackBufferSizeProvider.DEFAULT;
|
audioTrackBufferSizeProvider = AudioTrackBufferSizeProvider.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets audio capabilities for playback on this device. May be {@code null} if the default
|
* Creates a new builder.
|
||||||
* capabilities (no encoded audio passthrough support) should be assumed.
|
|
||||||
*
|
*
|
||||||
* <p>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
|
@CanIgnoreReturnValue
|
||||||
public Builder setAudioCapabilities(AudioCapabilities audioCapabilities) {
|
public Builder setAudioCapabilities(AudioCapabilities audioCapabilities) {
|
||||||
checkNotNull(audioCapabilities);
|
checkNotNull(audioCapabilities);
|
||||||
|
|
@ -466,6 +487,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
@GuardedBy("releaseExecutorLock")
|
@GuardedBy("releaseExecutorLock")
|
||||||
private static int pendingReleaseCount;
|
private static int pendingReleaseCount;
|
||||||
|
|
||||||
|
@Nullable private final Context context;
|
||||||
private final androidx.media3.common.audio.AudioProcessorChain audioProcessorChain;
|
private final androidx.media3.common.audio.AudioProcessorChain audioProcessorChain;
|
||||||
private final boolean enableFloatOutput;
|
private final boolean enableFloatOutput;
|
||||||
private final ChannelMappingAudioProcessor channelMappingAudioProcessor;
|
private final ChannelMappingAudioProcessor channelMappingAudioProcessor;
|
||||||
|
|
@ -491,6 +513,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
private @MonotonicNonNull AudioProcessingPipeline audioProcessingPipeline;
|
private @MonotonicNonNull AudioProcessingPipeline audioProcessingPipeline;
|
||||||
@Nullable private AudioTrack audioTrack;
|
@Nullable private AudioTrack audioTrack;
|
||||||
private AudioCapabilities audioCapabilities;
|
private AudioCapabilities audioCapabilities;
|
||||||
|
private @MonotonicNonNull AudioCapabilitiesReceiver audioCapabilitiesReceiver;
|
||||||
|
|
||||||
private AudioAttributes audioAttributes;
|
private AudioAttributes audioAttributes;
|
||||||
@Nullable private MediaPositionParameters afterDrainParameters;
|
@Nullable private MediaPositionParameters afterDrainParameters;
|
||||||
|
|
@ -529,10 +552,12 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
private long lastFeedElapsedRealtimeMs;
|
private long lastFeedElapsedRealtimeMs;
|
||||||
private boolean offloadDisabledUntilNextConfiguration;
|
private boolean offloadDisabledUntilNextConfiguration;
|
||||||
private boolean isWaitingForOffloadEndOfStreamHandled;
|
private boolean isWaitingForOffloadEndOfStreamHandled;
|
||||||
|
@Nullable private Looper playbackLooper;
|
||||||
|
|
||||||
@RequiresNonNull("#1.audioProcessorChain")
|
@RequiresNonNull("#1.audioProcessorChain")
|
||||||
private DefaultAudioSink(Builder builder) {
|
private DefaultAudioSink(Builder builder) {
|
||||||
audioCapabilities = builder.audioCapabilities;
|
context = builder.context;
|
||||||
|
audioCapabilities = context != null ? getCapabilities(context) : builder.audioCapabilities;
|
||||||
audioProcessorChain = builder.audioProcessorChain;
|
audioProcessorChain = builder.audioProcessorChain;
|
||||||
enableFloatOutput = Util.SDK_INT >= 21 && builder.enableFloatOutput;
|
enableFloatOutput = Util.SDK_INT >= 21 && builder.enableFloatOutput;
|
||||||
preferAudioTrackPlaybackParams = Util.SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams;
|
preferAudioTrackPlaybackParams = Util.SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams;
|
||||||
|
|
@ -599,7 +624,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
if (!offloadDisabledUntilNextConfiguration && useOffloadedPlayback(format, audioAttributes)) {
|
if (!offloadDisabledUntilNextConfiguration && useOffloadedPlayback(format, audioAttributes)) {
|
||||||
return SINK_FORMAT_SUPPORTED_DIRECTLY;
|
return SINK_FORMAT_SUPPORTED_DIRECTLY;
|
||||||
}
|
}
|
||||||
if (audioCapabilities.isPassthroughPlaybackSupported(format)) {
|
if (getAudioCapabilities().isPassthroughPlaybackSupported(format)) {
|
||||||
return SINK_FORMAT_SUPPORTED_DIRECTLY;
|
return SINK_FORMAT_SUPPORTED_DIRECTLY;
|
||||||
}
|
}
|
||||||
return SINK_FORMAT_UNSUPPORTED;
|
return SINK_FORMAT_UNSUPPORTED;
|
||||||
|
|
@ -692,7 +717,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
outputMode = OUTPUT_MODE_PASSTHROUGH;
|
outputMode = OUTPUT_MODE_PASSTHROUGH;
|
||||||
@Nullable
|
@Nullable
|
||||||
Pair<Integer, Integer> encodingAndChannelConfig =
|
Pair<Integer, Integer> encodingAndChannelConfig =
|
||||||
audioCapabilities.getEncodingAndChannelConfigForPassthrough(inputFormat);
|
getAudioCapabilities().getEncodingAndChannelConfigForPassthrough(inputFormat);
|
||||||
if (encodingAndChannelConfig == null) {
|
if (encodingAndChannelConfig == null) {
|
||||||
throw new ConfigurationException(
|
throw new ConfigurationException(
|
||||||
"Unable to configure passthrough for: " + inputFormat, inputFormat);
|
"Unable to configure passthrough for: " + inputFormat, inputFormat);
|
||||||
|
|
@ -1431,6 +1456,22 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
offloadDisabledUntilNextConfiguration = false;
|
offloadDisabledUntilNextConfiguration = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
if (audioCapabilitiesReceiver != null) {
|
||||||
|
audioCapabilitiesReceiver.unregister();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AudioCapabilitiesReceiver.Listener implementation.
|
||||||
|
|
||||||
|
public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) {
|
||||||
|
checkState(playbackLooper == Looper.myLooper());
|
||||||
|
if (!audioCapabilities.equals(getAudioCapabilities())) {
|
||||||
|
this.audioCapabilities = audioCapabilities;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
private void resetSinkStateForFlush() {
|
private void resetSinkStateForFlush() {
|
||||||
|
|
@ -1646,6 +1687,18 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AudioCapabilities getAudioCapabilities() {
|
||||||
|
if (audioCapabilitiesReceiver == null && context != null) {
|
||||||
|
// Must be lazily initialized to receive audio capabilities receiver listener event on the
|
||||||
|
// current (playback) thread as the constructor is not called in the playback thread.
|
||||||
|
playbackLooper = Looper.myLooper();
|
||||||
|
audioCapabilitiesReceiver =
|
||||||
|
new AudioCapabilitiesReceiver(context, this::onAudioCapabilitiesChanged);
|
||||||
|
audioCapabilities = audioCapabilitiesReceiver.register();
|
||||||
|
}
|
||||||
|
return audioCapabilities;
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(29)
|
@RequiresApi(29)
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
private int getOffloadedPlaybackSupport(
|
private int getOffloadedPlaybackSupport(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue