Use AudioAtributes when determining AudioCapabilities

The capabilities change depending on the attributes, so we should
pass down the actual attributes used during playback and update
the capabilities whenever these change.

PiperOrigin-RevId: 597197507
This commit is contained in:
tonihei 2024-01-10 03:15:25 -08:00 committed by Copybara-Service
parent 4fde35c9cc
commit 3596bc332d
3 changed files with 93 additions and 42 deletions

View File

@ -21,7 +21,6 @@ import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.media.AudioAttributes;
import android.media.AudioDeviceInfo; import android.media.AudioDeviceInfo;
import android.media.AudioFormat; import android.media.AudioFormat;
import android.media.AudioManager; import android.media.AudioManager;
@ -33,6 +32,7 @@ import androidx.annotation.DoNotInline;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
@ -58,6 +58,7 @@ public final class AudioCapabilities {
new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT); new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT);
/** Encodings supported when the device specifies external surround sound. */ /** Encodings supported when the device specifies external surround sound. */
@SuppressLint("InlinedApi") // Compile-time access to integer constants defined in API 21.
private static final ImmutableList<Integer> EXTERNAL_SURROUND_SOUND_ENCODINGS = private static final ImmutableList<Integer> EXTERNAL_SURROUND_SOUND_ENCODINGS =
ImmutableList.of( ImmutableList.of(
AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3); AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3);
@ -82,21 +83,33 @@ public final class AudioCapabilities {
private static final String EXTERNAL_SURROUND_SOUND_KEY = "external_surround_sound_enabled"; private static final String EXTERNAL_SURROUND_SOUND_KEY = "external_surround_sound_enabled";
/** /**
* Returns the current audio capabilities for the device. * @deprecated Use {@link #getCapabilities(Context, AudioAttributes)} instead.
*/
@Deprecated
public static AudioCapabilities getCapabilities(Context context) {
return getCapabilities(context, AudioAttributes.DEFAULT);
}
/**
* Returns the current audio capabilities.
* *
* @param context A context for obtaining the current audio capabilities. * @param context A context for obtaining the current audio capabilities.
* @param audioAttributes The {@link AudioAttributes} to obtain capabilities for.
* @return The current audio capabilities for the device. * @return The current audio capabilities for the device.
*/ */
@SuppressWarnings("InlinedApi") @SuppressWarnings("InlinedApi")
public static AudioCapabilities getCapabilities(Context context) { @SuppressLint("UnprotectedReceiver") // ACTION_HDMI_AUDIO_PLUG is protected since API 16
public static AudioCapabilities getCapabilities(
Context context, AudioAttributes audioAttributes) {
Intent intent = Intent intent =
context.registerReceiver( context.registerReceiver(
/* receiver= */ null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG)); /* receiver= */ null, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG));
return getCapabilities(context, intent); return getCapabilities(context, intent, audioAttributes);
} }
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
/* package */ static AudioCapabilities getCapabilities(Context context, @Nullable Intent intent) { /* package */ static AudioCapabilities getCapabilities(
Context context, @Nullable Intent intent, AudioAttributes audioAttributes) {
// If a connection to Bluetooth device is detected, we only return the minimum capabilities that // If a connection to Bluetooth device is detected, we only return the minimum capabilities that
// is supported by all the devices. // is supported by all the devices.
if (Util.SDK_INT >= 23 && Api23.isBluetoothConnected(context)) { if (Util.SDK_INT >= 23 && Api23.isBluetoothConnected(context)) {
@ -113,7 +126,7 @@ public final class AudioCapabilities {
// it on TV and automotive devices, which generally shouldn't support audio offload for surround // it on TV and automotive devices, which generally shouldn't support audio offload for surround
// encodings. // encodings.
if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) {
supportedEncodings.addAll(Api29.getDirectPlaybackSupportedEncodings()); supportedEncodings.addAll(Api29.getDirectPlaybackSupportedEncodings(audioAttributes));
return new AudioCapabilities( return new AudioCapabilities(
Ints.toArray(supportedEncodings.build()), DEFAULT_MAX_CHANNEL_COUNT); Ints.toArray(supportedEncodings.build()), DEFAULT_MAX_CHANNEL_COUNT);
} }
@ -155,8 +168,9 @@ public final class AudioCapabilities {
* Constructs new audio capabilities based on a set of supported encodings and a maximum channel * Constructs new audio capabilities based on a set of supported encodings and a maximum channel
* count. * count.
* *
* <p>Applications should generally call {@link #getCapabilities(Context)} to obtain an instance * <p>Applications should generally call {@link #getCapabilities(Context, AudioAttributes)} to
* based on the capabilities advertised by the platform, rather than calling this constructor. * obtain an instance based on the capabilities advertised by the platform, rather than calling
* this constructor.
* *
* @param supportedEncodings Supported audio encodings from {@link android.media.AudioFormat}'s * @param supportedEncodings Supported audio encodings from {@link android.media.AudioFormat}'s
* {@code ENCODING_*} constants. Passing {@code null} indicates that no encodings are * {@code ENCODING_*} constants. Passing {@code null} indicates that no encodings are
@ -188,22 +202,42 @@ public final class AudioCapabilities {
return maxChannelCount; return maxChannelCount;
} }
/** Returns whether the device can do passthrough playback for {@code format}. */ /**
* @deprecated Use {@link #isPassthroughPlaybackSupported(Format, AudioAttributes)} instead.
*/
@Deprecated
public boolean isPassthroughPlaybackSupported(Format format) { public boolean isPassthroughPlaybackSupported(Format format) {
return getEncodingAndChannelConfigForPassthrough(format) != null; return isPassthroughPlaybackSupported(format, AudioAttributes.DEFAULT);
}
/** Returns whether the device can do passthrough playback for {@code format}. */
public boolean isPassthroughPlaybackSupported(Format format, AudioAttributes audioAttributes) {
return getEncodingAndChannelConfigForPassthrough(format, audioAttributes) != null;
}
/**
* @deprecated Use {@link #getEncodingAndChannelConfigForPassthrough(Format, AudioAttributes)}
* instead.
*/
@Deprecated
@Nullable
public Pair<Integer, Integer> getEncodingAndChannelConfigForPassthrough(Format format) {
return getEncodingAndChannelConfigForPassthrough(format, AudioAttributes.DEFAULT);
} }
/** /**
* Returns the encoding and channel config to use when configuring an {@link AudioTrack} in * Returns the encoding and channel config to use when configuring an {@link AudioTrack} in
* passthrough mode for the specified {@link Format}. Returns {@code null} if passthrough of the * passthrough mode for the specified {@link Format} and {@link AudioAttributes}. Returns {@code
* format is unsupported. * null} if passthrough of the format is unsupported.
* *
* @param format The {@link Format}. * @param format The {@link Format}.
* @param audioAttributes The {@link AudioAttributes}.
* @return The encoding and channel config to use, or {@code null} if passthrough of the format is * @return The encoding and channel config to use, or {@code null} if passthrough of the format is
* unsupported. * unsupported.
*/ */
@Nullable @Nullable
public Pair<Integer, Integer> getEncodingAndChannelConfigForPassthrough(Format format) { public Pair<Integer, Integer> getEncodingAndChannelConfigForPassthrough(
Format format, AudioAttributes audioAttributes) {
@C.Encoding @C.Encoding
int encoding = MimeTypes.getEncoding(checkNotNull(format.sampleMimeType), format.codecs); int encoding = MimeTypes.getEncoding(checkNotNull(format.sampleMimeType), format.codecs);
// Check that this is an encoding known to work for passthrough. This avoids trying to use // Check that this is an encoding known to work for passthrough. This avoids trying to use
@ -231,7 +265,8 @@ public final class AudioCapabilities {
// For E-AC3 JOC, the format is object based so the format channel count is arbitrary. // For E-AC3 JOC, the format is object based so the format channel count is arbitrary.
int sampleRate = int sampleRate =
format.sampleRate != Format.NO_VALUE ? format.sampleRate : DEFAULT_SAMPLE_RATE_HZ; format.sampleRate != Format.NO_VALUE ? format.sampleRate : DEFAULT_SAMPLE_RATE_HZ;
channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); channelCount =
getMaxSupportedChannelCountForPassthrough(encoding, sampleRate, audioAttributes);
} else { } else {
channelCount = format.channelCount; channelCount = format.channelCount;
// Some DTS:X TVs reports ACTION_HDMI_AUDIO_PLUG.EXTRA_MAX_CHANNEL_COUNT as 8 // Some DTS:X TVs reports ACTION_HDMI_AUDIO_PLUG.EXTRA_MAX_CHANNEL_COUNT as 8
@ -288,12 +323,12 @@ public final class AudioCapabilities {
* encoding, or {@code 0} if the format is unsupported. * encoding, or {@code 0} if the format is unsupported.
*/ */
private static int getMaxSupportedChannelCountForPassthrough( private static int getMaxSupportedChannelCountForPassthrough(
@C.Encoding int encoding, int sampleRate) { @C.Encoding int encoding, int sampleRate, AudioAttributes audioAttributes) {
// From API 29 we can get the channel count from the platform, but before then there is no way // From API 29 we can get the channel count from the platform, but before then there is no way
// to query the platform so we assume the channel count matches the maximum channel count per // to query the platform so we assume the channel count matches the maximum channel count per
// audio encoding spec. // audio encoding spec.
if (Util.SDK_INT >= 29) { if (Util.SDK_INT >= 29) {
return Api29.getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); return Api29.getMaxSupportedChannelCountForPassthrough(encoding, sampleRate, audioAttributes);
} }
return checkNotNull(ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.getOrDefault(encoding, 0)); return checkNotNull(ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.getOrDefault(encoding, 0));
} }
@ -325,13 +360,13 @@ public final class AudioCapabilities {
private Api23() {} private Api23() {}
@DoNotInline @DoNotInline
public static final boolean isBluetoothConnected(Context context) { public static boolean isBluetoothConnected(Context context) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
AudioDeviceInfo[] audioDeviceInfos = AudioDeviceInfo[] audioDeviceInfos =
checkNotNull(audioManager).getDevices(AudioManager.GET_DEVICES_OUTPUTS); checkNotNull(audioManager).getDevices(AudioManager.GET_DEVICES_OUTPUTS);
ImmutableSet<Integer> allBluetoothDeviceTypesSet = getAllBluetoothDeviceTypes(); ImmutableSet<Integer> allBluetoothDeviceTypesSet = getAllBluetoothDeviceTypes();
for (int i = 0; i < audioDeviceInfos.length; i++) { for (AudioDeviceInfo audioDeviceInfo : audioDeviceInfos) {
if (allBluetoothDeviceTypesSet.contains(audioDeviceInfos[i].getType())) { if (allBluetoothDeviceTypesSet.contains(audioDeviceInfo.getType())) {
return true; return true;
} }
} }
@ -348,7 +383,7 @@ public final class AudioCapabilities {
* API 31. And the type {@link AudioDeviceInfo#TYPE_BLE_BROADCAST} is added from API 33. * API 31. And the type {@link AudioDeviceInfo#TYPE_BLE_BROADCAST} is added from API 33.
*/ */
@DoNotInline @DoNotInline
private static final ImmutableSet<Integer> getAllBluetoothDeviceTypes() { private static ImmutableSet<Integer> getAllBluetoothDeviceTypes() {
ImmutableSet.Builder<Integer> allBluetoothDeviceTypes = ImmutableSet.Builder<Integer> allBluetoothDeviceTypes =
new ImmutableSet.Builder<Integer>() new ImmutableSet.Builder<Integer>()
.add(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLUETOOTH_SCO); .add(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
@ -365,17 +400,12 @@ public final class AudioCapabilities {
@RequiresApi(29) @RequiresApi(29)
private static final class Api29 { private static final class Api29 {
private static final AudioAttributes DEFAULT_AUDIO_ATTRIBUTES =
new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)
.setFlags(0)
.build();
private Api29() {} private Api29() {}
@DoNotInline @DoNotInline
public static ImmutableList<Integer> getDirectPlaybackSupportedEncodings() { public static ImmutableList<Integer> getDirectPlaybackSupportedEncodings(
AudioAttributes audioAttributes) {
ImmutableList.Builder<Integer> supportedEncodingsListBuilder = ImmutableList.builder(); ImmutableList.Builder<Integer> supportedEncodingsListBuilder = ImmutableList.builder();
for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) {
if (Util.SDK_INT < Util.getApiLevelThatAudioFormatIntroducedAudioEncoding(encoding)) { if (Util.SDK_INT < Util.getApiLevelThatAudioFormatIntroducedAudioEncoding(encoding)) {
@ -388,7 +418,7 @@ public final class AudioCapabilities {
.setEncoding(encoding) .setEncoding(encoding)
.setSampleRate(DEFAULT_SAMPLE_RATE_HZ) .setSampleRate(DEFAULT_SAMPLE_RATE_HZ)
.build(), .build(),
DEFAULT_AUDIO_ATTRIBUTES)) { audioAttributes.getAudioAttributesV21().audioAttributes)) {
supportedEncodingsListBuilder.add(encoding); supportedEncodingsListBuilder.add(encoding);
} }
} }
@ -402,7 +432,7 @@ public final class AudioCapabilities {
*/ */
@DoNotInline @DoNotInline
public static int getMaxSupportedChannelCountForPassthrough( public static int getMaxSupportedChannelCountForPassthrough(
@C.Encoding int encoding, int sampleRate) { @C.Encoding int encoding, int sampleRate, AudioAttributes audioAttributes) {
// TODO(internal b/234351617): Query supported channel masks directly once it's supported, // TODO(internal b/234351617): Query supported channel masks directly once it's supported,
// see also b/25994457. // see also b/25994457.
for (int channelCount = DEFAULT_MAX_CHANNEL_COUNT; channelCount > 0; channelCount--) { for (int channelCount = DEFAULT_MAX_CHANNEL_COUNT; channelCount > 0; channelCount--) {
@ -416,7 +446,8 @@ public final class AudioCapabilities {
.setSampleRate(sampleRate) .setSampleRate(sampleRate)
.setChannelMask(channelConfig) .setChannelMask(channelConfig)
.build(); .build();
if (AudioTrack.isDirectPlaybackSupported(audioFormat, DEFAULT_AUDIO_ATTRIBUTES)) { if (AudioTrack.isDirectPlaybackSupported(
audioFormat, audioAttributes.getAudioAttributesV21().audioAttributes)) {
return channelCount; return channelCount;
} }
} }

View File

@ -31,6 +31,7 @@ import android.os.Handler;
import androidx.annotation.DoNotInline; import androidx.annotation.DoNotInline;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
@ -59,17 +60,21 @@ public final class AudioCapabilitiesReceiver {
@Nullable private final BroadcastReceiver hdmiAudioPlugBroadcastReceiver; @Nullable private final BroadcastReceiver hdmiAudioPlugBroadcastReceiver;
@Nullable private final ExternalSurroundSoundSettingObserver externalSurroundSoundSettingObserver; @Nullable private final ExternalSurroundSoundSettingObserver externalSurroundSoundSettingObserver;
@Nullable /* package */ AudioCapabilities audioCapabilities; @Nullable private AudioCapabilities audioCapabilities;
private AudioAttributes audioAttributes;
private boolean registered; private boolean registered;
/** /**
* @param context A context for registering the receiver. * @param context A context for registering the receiver.
* @param listener The listener to notify when audio capabilities change. * @param listener The listener to notify when audio capabilities change.
* @param audioAttributes The {@link AudioAttributes}.
*/ */
public AudioCapabilitiesReceiver(Context context, Listener listener) { public AudioCapabilitiesReceiver(
Context context, Listener listener, AudioAttributes audioAttributes) {
context = context.getApplicationContext(); context = context.getApplicationContext();
this.context = context; this.context = context;
this.listener = checkNotNull(listener); this.listener = checkNotNull(listener);
this.audioAttributes = audioAttributes;
handler = Util.createHandlerForCurrentOrMainLooper(); handler = Util.createHandlerForCurrentOrMainLooper();
audioDeviceCallback = Util.SDK_INT >= 23 ? new AudioDeviceCallbackV23() : null; audioDeviceCallback = Util.SDK_INT >= 23 ? new AudioDeviceCallbackV23() : null;
hdmiAudioPlugBroadcastReceiver = hdmiAudioPlugBroadcastReceiver =
@ -82,6 +87,16 @@ public final class AudioCapabilitiesReceiver {
: null; : null;
} }
/**
* Updates the {@link AudioAttributes} used by this instance.
*
* @param audioAttributes The {@link AudioAttributes}.
*/
public void setAudioAttributes(AudioAttributes audioAttributes) {
this.audioAttributes = audioAttributes;
onNewAudioCapabilities(AudioCapabilities.getCapabilities(context, audioAttributes));
}
/** /**
* Registers the receiver, meaning it will notify the listener when audio capability changes * Registers the receiver, meaning it will notify the listener when audio capability changes
* occur. The current audio capabilities will be returned. It is important to call {@link * occur. The current audio capabilities will be returned. It is important to call {@link
@ -111,7 +126,7 @@ public final class AudioCapabilitiesReceiver {
/* broadcastPermission= */ null, /* broadcastPermission= */ null,
handler); handler);
} }
audioCapabilities = AudioCapabilities.getCapabilities(context, stickyIntent); audioCapabilities = AudioCapabilities.getCapabilities(context, stickyIntent, audioAttributes);
return audioCapabilities; return audioCapabilities;
} }
@ -148,7 +163,7 @@ public final class AudioCapabilitiesReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (!isInitialStickyBroadcast()) { if (!isInitialStickyBroadcast()) {
onNewAudioCapabilities(AudioCapabilities.getCapabilities(context, intent)); onNewAudioCapabilities(AudioCapabilities.getCapabilities(context, intent, audioAttributes));
} }
} }
} }
@ -175,7 +190,7 @@ public final class AudioCapabilitiesReceiver {
@Override @Override
public void onChange(boolean selfChange) { public void onChange(boolean selfChange) {
onNewAudioCapabilities(AudioCapabilities.getCapabilities(context)); onNewAudioCapabilities(AudioCapabilities.getCapabilities(context, audioAttributes));
} }
} }
@ -183,12 +198,12 @@ public final class AudioCapabilitiesReceiver {
private final class AudioDeviceCallbackV23 extends AudioDeviceCallback { private final class AudioDeviceCallbackV23 extends AudioDeviceCallback {
@Override @Override
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) { public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
onNewAudioCapabilities(AudioCapabilities.getCapabilities(context)); onNewAudioCapabilities(AudioCapabilities.getCapabilities(context, audioAttributes));
} }
@Override @Override
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) { public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
onNewAudioCapabilities(AudioCapabilities.getCapabilities(context)); onNewAudioCapabilities(AudioCapabilities.getCapabilities(context, audioAttributes));
} }
} }

View File

@ -559,7 +559,9 @@ public final class DefaultAudioSink implements AudioSink {
@RequiresNonNull("#1.audioProcessorChain") @RequiresNonNull("#1.audioProcessorChain")
private DefaultAudioSink(Builder builder) { private DefaultAudioSink(Builder builder) {
context = builder.context; context = builder.context;
audioCapabilities = context != null ? getCapabilities(context) : builder.audioCapabilities; audioAttributes = AudioAttributes.DEFAULT;
audioCapabilities =
context != null ? getCapabilities(context, audioAttributes) : 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;
@ -576,7 +578,6 @@ public final class DefaultAudioSink implements AudioSink {
new ToInt16PcmAudioProcessor(), channelMappingAudioProcessor, trimmingAudioProcessor); new ToInt16PcmAudioProcessor(), channelMappingAudioProcessor, trimmingAudioProcessor);
toFloatPcmAvailableAudioProcessors = ImmutableList.of(new ToFloatPcmAudioProcessor()); toFloatPcmAvailableAudioProcessors = ImmutableList.of(new ToFloatPcmAudioProcessor());
volume = 1f; volume = 1f;
audioAttributes = AudioAttributes.DEFAULT;
audioSessionId = C.AUDIO_SESSION_ID_UNSET; audioSessionId = C.AUDIO_SESSION_ID_UNSET;
auxEffectInfo = new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, 0f); auxEffectInfo = new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, 0f);
mediaPositionParameters = mediaPositionParameters =
@ -630,7 +631,7 @@ public final class DefaultAudioSink implements AudioSink {
// guaranteed to support. // guaranteed to support.
return SINK_FORMAT_SUPPORTED_WITH_TRANSCODING; return SINK_FORMAT_SUPPORTED_WITH_TRANSCODING;
} }
if (audioCapabilities.isPassthroughPlaybackSupported(format)) { if (audioCapabilities.isPassthroughPlaybackSupported(format, audioAttributes)) {
return SINK_FORMAT_SUPPORTED_DIRECTLY; return SINK_FORMAT_SUPPORTED_DIRECTLY;
} }
return SINK_FORMAT_UNSUPPORTED; return SINK_FORMAT_UNSUPPORTED;
@ -736,7 +737,8 @@ 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); audioCapabilities.getEncodingAndChannelConfigForPassthrough(
inputFormat, audioAttributes);
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);
@ -1320,6 +1322,9 @@ public final class DefaultAudioSink implements AudioSink {
// The audio attributes are ignored in tunneling mode, so no need to reset. // The audio attributes are ignored in tunneling mode, so no need to reset.
return; return;
} }
if (audioCapabilitiesReceiver != null) {
audioCapabilitiesReceiver.setAudioAttributes(audioAttributes);
}
flush(); flush();
} }
@ -1711,7 +1716,7 @@ public final class DefaultAudioSink implements AudioSink {
// current (playback) thread as the constructor is not called in the playback thread. // current (playback) thread as the constructor is not called in the playback thread.
playbackLooper = Looper.myLooper(); playbackLooper = Looper.myLooper();
audioCapabilitiesReceiver = audioCapabilitiesReceiver =
new AudioCapabilitiesReceiver(context, this::onAudioCapabilitiesChanged); new AudioCapabilitiesReceiver(context, this::onAudioCapabilitiesChanged, audioAttributes);
audioCapabilities = audioCapabilitiesReceiver.register(); audioCapabilities = audioCapabilitiesReceiver.register();
} }
} }