Merge "Refactor audio device type in audio frameworks."

This commit is contained in:
Treehugger Robot
2019-12-06 17:26:20 +00:00
committed by Gerrit Code Review
3 changed files with 279 additions and 176 deletions

View File

@@ -30,7 +30,9 @@ import android.util.Log;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
/* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET /* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
* TO UPDATE THE CORRESPONDING NATIVE GLUE AND AudioManager.java. * TO UPDATE THE CORRESPONDING NATIVE GLUE AND AudioManager.java.
@@ -541,51 +543,75 @@ public class AudioSystem
public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT; public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | // Deprecated in R because multiple device types are no longer accessed as a bit mask.
DEVICE_OUT_SPEAKER | // Removing this will get lint warning about changing hidden apis.
DEVICE_OUT_WIRED_HEADSET |
DEVICE_OUT_WIRED_HEADPHONE |
DEVICE_OUT_BLUETOOTH_SCO |
DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
DEVICE_OUT_HDMI |
DEVICE_OUT_ANLG_DOCK_HEADSET |
DEVICE_OUT_DGTL_DOCK_HEADSET |
DEVICE_OUT_USB_ACCESSORY |
DEVICE_OUT_USB_DEVICE |
DEVICE_OUT_REMOTE_SUBMIX |
DEVICE_OUT_TELEPHONY_TX |
DEVICE_OUT_LINE |
DEVICE_OUT_HDMI_ARC |
DEVICE_OUT_SPDIF |
DEVICE_OUT_FM |
DEVICE_OUT_AUX_LINE |
DEVICE_OUT_SPEAKER_SAFE |
DEVICE_OUT_IP |
DEVICE_OUT_BUS |
DEVICE_OUT_PROXY |
DEVICE_OUT_USB_HEADSET |
DEVICE_OUT_HEARING_AID |
DEVICE_OUT_DEFAULT);
public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
public static final int DEVICE_OUT_ALL_SCO = (DEVICE_OUT_BLUETOOTH_SCO |
DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
@UnsupportedAppUsage @UnsupportedAppUsage
public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY | public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
DEVICE_OUT_USB_DEVICE | DEVICE_OUT_USB_DEVICE |
DEVICE_OUT_USB_HEADSET); DEVICE_OUT_USB_HEADSET);
public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_AUX_LINE |
DEVICE_OUT_HDMI_ARC | public static final Set<Integer> DEVICE_OUT_ALL_SET;
DEVICE_OUT_SPDIF); public static final Set<Integer> DEVICE_OUT_ALL_A2DP_SET;
public static final int DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER = public static final Set<Integer> DEVICE_OUT_ALL_SCO_SET;
(DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO | public static final Set<Integer> DEVICE_OUT_ALL_USB_SET;
DEVICE_OUT_SPEAKER); public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET;
public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET;
static {
DEVICE_OUT_ALL_SET = new HashSet<>();
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_EARPIECE);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADSET);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADPHONE);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_ANLG_DOCK_HEADSET);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DGTL_DOCK_HEADSET);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_ACCESSORY);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_DEVICE);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_REMOTE_SUBMIX);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_TELEPHONY_TX);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_LINE);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI_ARC);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPDIF);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_FM);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_AUX_LINE);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER_SAFE);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_IP);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BUS);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_PROXY);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_HEADSET);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HEARING_AID);
DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DEFAULT);
DEVICE_OUT_ALL_A2DP_SET = new HashSet<>();
DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP);
DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES);
DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
DEVICE_OUT_ALL_SCO_SET = new HashSet<>();
DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO);
DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
DEVICE_OUT_ALL_USB_SET = new HashSet<>();
DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_ACCESSORY);
DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_DEVICE);
DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_HEADSET);
DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET = new HashSet<>();
DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_AUX_LINE);
DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_HDMI_ARC);
DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_SPDIF);
DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET = new HashSet<>();
DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.addAll(DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET);
DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.add(DEVICE_OUT_SPEAKER);
}
// input devices // input devices
@UnsupportedAppUsage @UnsupportedAppUsage
@@ -633,37 +659,47 @@ public class AudioSystem
@UnsupportedAppUsage @UnsupportedAppUsage
public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT; public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | public static final Set<Integer> DEVICE_IN_ALL_SET;
DEVICE_IN_AMBIENT | public static final Set<Integer> DEVICE_IN_ALL_SCO_SET;
DEVICE_IN_BUILTIN_MIC | public static final Set<Integer> DEVICE_IN_ALL_USB_SET;
DEVICE_IN_BLUETOOTH_SCO_HEADSET | static {
DEVICE_IN_WIRED_HEADSET | DEVICE_IN_ALL_SET = new HashSet<>();
DEVICE_IN_HDMI | DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION);
DEVICE_IN_TELEPHONY_RX | DEVICE_IN_ALL_SET.add(DEVICE_IN_AMBIENT);
DEVICE_IN_BACK_MIC | DEVICE_IN_ALL_SET.add(DEVICE_IN_BUILTIN_MIC);
DEVICE_IN_REMOTE_SUBMIX | DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET);
DEVICE_IN_ANLG_DOCK_HEADSET | DEVICE_IN_ALL_SET.add(DEVICE_IN_WIRED_HEADSET);
DEVICE_IN_DGTL_DOCK_HEADSET | DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI);
DEVICE_IN_USB_ACCESSORY | DEVICE_IN_ALL_SET.add(DEVICE_IN_TELEPHONY_RX);
DEVICE_IN_USB_DEVICE | DEVICE_IN_ALL_SET.add(DEVICE_IN_BACK_MIC);
DEVICE_IN_FM_TUNER | DEVICE_IN_ALL_SET.add(DEVICE_IN_REMOTE_SUBMIX);
DEVICE_IN_TV_TUNER | DEVICE_IN_ALL_SET.add(DEVICE_IN_ANLG_DOCK_HEADSET);
DEVICE_IN_LINE | DEVICE_IN_ALL_SET.add(DEVICE_IN_DGTL_DOCK_HEADSET);
DEVICE_IN_SPDIF | DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_ACCESSORY);
DEVICE_IN_BLUETOOTH_A2DP | DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_DEVICE);
DEVICE_IN_LOOPBACK | DEVICE_IN_ALL_SET.add(DEVICE_IN_FM_TUNER);
DEVICE_IN_IP | DEVICE_IN_ALL_SET.add(DEVICE_IN_TV_TUNER);
DEVICE_IN_BUS | DEVICE_IN_ALL_SET.add(DEVICE_IN_LINE);
DEVICE_IN_PROXY | DEVICE_IN_ALL_SET.add(DEVICE_IN_SPDIF);
DEVICE_IN_USB_HEADSET | DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_A2DP);
DEVICE_IN_BLUETOOTH_BLE | DEVICE_IN_ALL_SET.add(DEVICE_IN_LOOPBACK);
DEVICE_IN_HDMI_ARC | DEVICE_IN_ALL_SET.add(DEVICE_IN_IP);
DEVICE_IN_ECHO_REFERENCE | DEVICE_IN_ALL_SET.add(DEVICE_IN_BUS);
DEVICE_IN_DEFAULT); DEVICE_IN_ALL_SET.add(DEVICE_IN_PROXY);
public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET; DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_HEADSET);
public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY | DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_BLE);
DEVICE_IN_USB_DEVICE | DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI_ARC);
DEVICE_IN_USB_HEADSET); DEVICE_IN_ALL_SET.add(DEVICE_IN_ECHO_REFERENCE);
DEVICE_IN_ALL_SET.add(DEVICE_IN_DEFAULT);
DEVICE_IN_ALL_SCO_SET = new HashSet<>();
DEVICE_IN_ALL_SCO_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET);
DEVICE_IN_ALL_USB_SET = new HashSet<>();
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY);
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE);
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
}
// device states, must match AudioSystem::device_connection_state // device states, must match AudioSystem::device_connection_state
@UnsupportedAppUsage @UnsupportedAppUsage
@@ -1222,6 +1258,40 @@ public class AudioSystem
return getPlatformType(context) == PLATFORM_TELEVISION || forceSingleVolume; return getPlatformType(context) == PLATFORM_TELEVISION || forceSingleVolume;
} }
/**
* Return a set of audio device types from a bit mask audio device type, which may
* represent multiple audio device types.
* FIXME: Remove this when getting ride of bit mask usage of audio device types.
*/
public static Set<Integer> generateAudioDeviceTypesSet(int types) {
Set<Integer> deviceTypes = new HashSet<>();
Set<Integer> allDeviceTypes =
(types & DEVICE_BIT_IN) == 0 ? DEVICE_OUT_ALL_SET : DEVICE_IN_ALL_SET;
for (int deviceType : allDeviceTypes) {
if ((types & deviceType) == deviceType) {
deviceTypes.add(deviceType);
}
}
return deviceTypes;
}
/**
* Return the intersection of two audio device types collections.
*/
public static Set<Integer> intersectionAudioDeviceTypes(
@NonNull Set<Integer> a, @NonNull Set<Integer> b) {
Set<Integer> intersection = new HashSet<>(a);
intersection.retainAll(b);
return intersection;
}
/**
* Return true if the audio device types collection only contains the given device type.
*/
public static boolean isSingleAudioDeviceType(@NonNull Set<Integer> types, int type) {
return types.size() == 1 && types.contains(type);
}
public static final int DEFAULT_MUTE_STREAMS_AFFECTED = public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
(1 << STREAM_MUSIC) | (1 << STREAM_MUSIC) |
(1 << STREAM_RING) | (1 << STREAM_RING) |

View File

@@ -44,6 +44,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/** /**
* Class to manage the inventory of all connected devices. * Class to manage the inventory of all connected devices.
@@ -372,9 +374,14 @@ public class AudioDeviceInventory {
mDeviceBroker.postObserveDevicesForAllStreams(); mDeviceBroker.postObserveDevicesForAllStreams();
} }
private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG = private static final Set<Integer> DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET;
AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE static {
| AudioSystem.DEVICE_OUT_LINE | AudioSystem.DEVICE_OUT_ALL_USB; DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET = new HashSet<>();
DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE);
DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
}
/*package*/ void onSetWiredDeviceConnectionState( /*package*/ void onSetWiredDeviceConnectionState(
AudioDeviceInventory.WiredDeviceConnectionState wdcs) { AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
@@ -382,7 +389,7 @@ public class AudioDeviceInventory {
synchronized (mConnectedDevices) { synchronized (mConnectedDevices) {
if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED) if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
&& ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) { && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
mDeviceBroker.setBluetoothA2dpOnInt(true, mDeviceBroker.setBluetoothA2dpOnInt(true,
"onSetWiredDeviceConnectionState state DISCONNECTED"); "onSetWiredDeviceConnectionState state DISCONNECTED");
} }
@@ -393,7 +400,7 @@ public class AudioDeviceInventory {
return; return;
} }
if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) { if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
if ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) { if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
mDeviceBroker.setBluetoothA2dpOnInt(false, mDeviceBroker.setBluetoothA2dpOnInt(false,
"onSetWiredDeviceConnectionState state not DISCONNECTED"); "onSetWiredDeviceConnectionState state not DISCONNECTED");
} }
@@ -764,13 +771,19 @@ public class AudioDeviceInventory {
// - none of these devices are connected anymore after one is disconnected AND // - none of these devices are connected anymore after one is disconnected AND
// - the device being disconnected is actually used for music. // - the device being disconnected is actually used for music.
// Access synchronized on mConnectedDevices // Access synchronized on mConnectedDevices
private int mBecomingNoisyIntentDevices = private static final Set<Integer> BECOMING_NOISY_INTENT_DEVICES_SET;
AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE static {
| AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI BECOMING_NOISY_INTENT_DEVICES_SET = new HashSet<>();
| AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
| AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
| AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HDMI);
| AudioSystem.DEVICE_OUT_HEARING_AID; BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
}
// must be called before removing the device from mConnectedDevices // must be called before removing the device from mConnectedDevices
// musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
@@ -781,16 +794,16 @@ public class AudioDeviceInventory {
if (state != AudioService.CONNECTION_STATE_DISCONNECTED) { if (state != AudioService.CONNECTION_STATE_DISCONNECTED) {
return 0; return 0;
} }
if ((device & mBecomingNoisyIntentDevices) == 0) { if (!BECOMING_NOISY_INTENT_DEVICES_SET.contains(device)) {
return 0; return 0;
} }
int delay = 0; int delay = 0;
int devices = 0; Set<Integer> devices = new HashSet<>();
for (int i = 0; i < mConnectedDevices.size(); i++) { for (int i = 0; i < mConnectedDevices.size(); i++) {
int dev = mConnectedDevices.valueAt(i).mDeviceType; int dev = mConnectedDevices.valueAt(i).mDeviceType;
if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
&& ((dev & mBecomingNoisyIntentDevices) != 0)) { && BECOMING_NOISY_INTENT_DEVICES_SET.contains(dev)) {
devices |= dev; devices.add(dev);
} }
} }
if (musicDevice == AudioSystem.DEVICE_NONE) { if (musicDevice == AudioSystem.DEVICE_NONE) {
@@ -801,8 +814,9 @@ public class AudioDeviceInventory {
// because music routing is altered in this case. // because music routing is altered in this case.
// also checks whether media routing if affected by a dynamic policy or mirroring // also checks whether media routing if affected by a dynamic policy or mirroring
if (((device == musicDevice) || mDeviceBroker.isInCommunication()) if (((device == musicDevice) || mDeviceBroker.isInCommunication())
&& (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy() && AudioSystem.isSingleAudioDeviceType(devices, device)
&& ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) { && !mDeviceBroker.hasMediaDynamicPolicy()
&& (musicDevice != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)) {
if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/) if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)
&& !mDeviceBroker.hasAudioFocusUsers()) { && !mDeviceBroker.hasAudioFocusUsers()) {
// no media playback, not a "becoming noisy" situation, otherwise it could cause // no media playback, not a "becoming noisy" situation, otherwise it could cause

View File

@@ -147,6 +147,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -501,18 +502,20 @@ public class AudioService extends IAudioService.Stub
private volatile IRingtonePlayer mRingtonePlayer; private volatile IRingtonePlayer mRingtonePlayer;
// Devices for which the volume is fixed (volume is either max or muted) // Devices for which the volume is fixed (volume is either max or muted)
int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | Set<Integer> mFixedVolumeDevices = new HashSet<>(Arrays.asList(
AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | AudioSystem.DEVICE_OUT_HDMI,
AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
AudioSystem.DEVICE_OUT_HDMI_ARC | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
AudioSystem.DEVICE_OUT_SPDIF | AudioSystem.DEVICE_OUT_HDMI_ARC,
AudioSystem.DEVICE_OUT_AUX_LINE; AudioSystem.DEVICE_OUT_SPDIF,
AudioSystem.DEVICE_OUT_AUX_LINE));
// Devices for which the volume is always max, no volume panel // Devices for which the volume is always max, no volume panel
int mFullVolumeDevices = 0; Set<Integer> mFullVolumeDevices = new HashSet<>();
// Devices for the which use the "absolute volume" concept (framework sends audio signal // Devices for the which use the "absolute volume" concept (framework sends audio signal
// full scale, and volume control separately) and can be used for multiple use cases reflected // full scale, and volume control separately) and can be used for multiple use cases reflected
// by the audio mode (e.g. media playback in MODE_NORMAL, and phone calls in MODE_IN_CALL). // by the audio mode (e.g. media playback in MODE_NORMAL, and phone calls in MODE_IN_CALL).
int mAbsVolumeMultiModeCaseDevices = AudioSystem.DEVICE_OUT_HEARING_AID; Set<Integer> mAbsVolumeMultiModeCaseDevices = new HashSet<>(
Arrays.asList(AudioSystem.DEVICE_OUT_HEARING_AID));
private final boolean mMonitorRotation; private final boolean mMonitorRotation;
@@ -863,13 +866,14 @@ public class AudioService extends IAudioService.Stub
} }
mHdmiTvClient = mHdmiManager.getTvClient(); mHdmiTvClient = mHdmiManager.getTvClient();
if (mHdmiTvClient != null) { if (mHdmiTvClient != null) {
mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER; mFixedVolumeDevices.removeAll(
AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET);
} }
mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
if (mHdmiPlaybackClient != null) { if (mHdmiPlaybackClient != null) {
// not a television: HDMI output will be always at max // not a television: HDMI output will be always at max
mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI);
mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI);
} }
mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient(); mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient();
} }
@@ -1126,7 +1130,7 @@ public class AudioService extends IAudioService.Stub
@AudioService.ConnectionState int state, String caller) { @AudioService.ConnectionState int state, String caller) {
if (state == AudioService.CONNECTION_STATE_CONNECTED) { if (state == AudioService.CONNECTION_STATE_CONNECTED) {
// DEVICE_OUT_HDMI is now connected // DEVICE_OUT_HDMI is now connected
if ((AudioSystem.DEVICE_OUT_HDMI & mSafeMediaVolumeDevices) != 0) { if (mSafeMediaVolumeDevices.contains(AudioSystem.DEVICE_OUT_HDMI)) {
sendMsg(mAudioHandler, sendMsg(mAudioHandler,
MSG_CHECK_MUSIC_ACTIVE, MSG_CHECK_MUSIC_ACTIVE,
SENDMSG_REPLACE, SENDMSG_REPLACE,
@@ -1757,8 +1761,8 @@ public class AudioService extends IAudioService.Stub
// skip a2dp absolute volume control request when the device // skip a2dp absolute volume control request when the device
// is not an a2dp device // is not an a2dp device
if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 && if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
(flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) { && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
return; return;
} }
@@ -1779,14 +1783,14 @@ public class AudioService extends IAudioService.Stub
flags &= ~AudioManager.FLAG_FIXED_VOLUME; flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
((device & mFixedVolumeDevices) != 0)) { mFixedVolumeDevices.contains(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME; flags |= AudioManager.FLAG_FIXED_VOLUME;
// Always toggle between max safe volume and 0 for fixed volume devices where safe // Always toggle between max safe volume and 0 for fixed volume devices where safe
// volume is enforced, and max and 0 for the others. // volume is enforced, and max and 0 for the others.
// This is simulated by stepping by the full allowed volume range // This is simulated by stepping by the full allowed volume range
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
(device & mSafeMediaVolumeDevices) != 0) { mSafeMediaVolumeDevices.contains(device)) {
step = safeMediaVolumeIndex(device); step = safeMediaVolumeIndex(device);
} else { } else {
step = streamState.getMaxIndex(); step = streamState.getMaxIndex();
@@ -1856,7 +1860,7 @@ public class AudioService extends IAudioService.Stub
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex); Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
mVolumeController.postDisplaySafeVolumeWarning(flags); mVolumeController.postDisplaySafeVolumeWarning(flags);
} else if (((device & mFullVolumeDevices) == 0) } else if (!mFullVolumeDevices.contains(device)
&& (streamState.adjustIndex(direction * step, device, caller) && (streamState.adjustIndex(direction * step, device, caller)
|| streamState.mIsMuted)) { || streamState.mIsMuted)) {
// Post message to set system volume (it in turn will post a // Post message to set system volume (it in turn will post a
@@ -1885,9 +1889,9 @@ public class AudioService extends IAudioService.Stub
int newIndex = mStreamStates[streamType].getIndex(device); int newIndex = mStreamStates[streamType].getIndex(device);
// Check if volume update should be send to AVRCP // Check if volume update should be send to AVRCP
if (streamTypeAlias == AudioSystem.STREAM_MUSIC && if (streamTypeAlias == AudioSystem.STREAM_MUSIC
(device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
(flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) { if (DEBUG_VOL) {
Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index=" Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
+ newIndex + "stream=" + streamType); + newIndex + "stream=" + streamType);
@@ -1896,7 +1900,7 @@ public class AudioService extends IAudioService.Stub
} }
// Check if volume update should be send to Hearing Aid // Check if volume update should be send to Hearing Aid
if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
// only modify the hearing aid attenuation when the stream to modify matches // only modify the hearing aid attenuation when the stream to modify matches
// the one expected by the hearing aid // the one expected by the hearing aid
if (streamType == getHearingAidStreamType()) { if (streamType == getHearingAidStreamType()) {
@@ -1918,7 +1922,7 @@ public class AudioService extends IAudioService.Stub
if (mHdmiCecSink if (mHdmiCecSink
&& streamTypeAlias == AudioSystem.STREAM_MUSIC && streamTypeAlias == AudioSystem.STREAM_MUSIC
// vol change on a full volume device // vol change on a full volume device
&& ((device & mFullVolumeDevices) != 0)) { && mFullVolumeDevices.contains(device)) {
int keyCode = KeyEvent.KEYCODE_UNKNOWN; int keyCode = KeyEvent.KEYCODE_UNKNOWN;
switch (direction) { switch (direction) {
case AudioManager.ADJUST_RAISE: case AudioManager.ADJUST_RAISE:
@@ -2286,13 +2290,17 @@ public class AudioService extends IAudioService.Stub
int streamType = getHearingAidStreamType(newMode); int streamType = getHearingAidStreamType(newMode);
final int device = AudioSystem.getDevicesForStream(streamType); final Set<Integer> deviceTypes = AudioSystem.generateAudioDeviceTypesSet(
if ((device & mAbsVolumeMultiModeCaseDevices) == 0) { AudioSystem.getDevicesForStream(streamType));
final Set<Integer> absVolumeMultiModeCaseDevices = AudioSystem.intersectionAudioDeviceTypes(
mAbsVolumeMultiModeCaseDevices, deviceTypes);
if (absVolumeMultiModeCaseDevices.isEmpty()) {
return; return;
} }
// handling of specific interfaces goes here: // handling of specific interfaces goes here:
if ((device & mAbsVolumeMultiModeCaseDevices) == AudioSystem.DEVICE_OUT_HEARING_AID) { if (AudioSystem.isSingleAudioDeviceType(
absVolumeMultiModeCaseDevices, AudioSystem.DEVICE_OUT_HEARING_AID)) {
final int index = getStreamVolume(streamType); final int index = getStreamVolume(streamType);
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_MODE_CHANGE_HEARING_AID, sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_MODE_CHANGE_HEARING_AID,
newMode, streamType, index)); newMode, streamType, index));
@@ -2319,8 +2327,8 @@ public class AudioService extends IAudioService.Stub
// skip a2dp absolute volume control request when the device // skip a2dp absolute volume control request when the device
// is not an a2dp device // is not an a2dp device
if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 && if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
(flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) { && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
return; return;
} }
// If we are being called by the system (e.g. hardware keys) check for current user // If we are being called by the system (e.g. hardware keys) check for current user
@@ -2352,7 +2360,7 @@ public class AudioService extends IAudioService.Stub
index = rescaleIndex(index * 10, streamType, streamTypeAlias); index = rescaleIndex(index * 10, streamType, streamTypeAlias);
if (streamTypeAlias == AudioSystem.STREAM_MUSIC if (streamTypeAlias == AudioSystem.STREAM_MUSIC
&& (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) { if (DEBUG_VOL) {
Log.d(TAG, "setStreamVolume postSetAvrcpAbsoluteVolumeIndex index=" + index Log.d(TAG, "setStreamVolume postSetAvrcpAbsoluteVolumeIndex index=" + index
@@ -2361,7 +2369,7 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10); mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
} }
if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0 if (device == AudioSystem.DEVICE_OUT_HEARING_AID
&& streamType == getHearingAidStreamType()) { && streamType == getHearingAidStreamType()) {
Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
+ " stream=" + streamType); + " stream=" + streamType);
@@ -2374,13 +2382,13 @@ public class AudioService extends IAudioService.Stub
flags &= ~AudioManager.FLAG_FIXED_VOLUME; flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
((device & mFixedVolumeDevices) != 0)) { mFixedVolumeDevices.contains(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME; flags |= AudioManager.FLAG_FIXED_VOLUME;
// volume is either 0 or max allowed for fixed volume devices // volume is either 0 or max allowed for fixed volume devices
if (index != 0) { if (index != 0) {
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
(device & mSafeMediaVolumeDevices) != 0) { mSafeMediaVolumeDevices.contains(device)) {
index = safeMediaVolumeIndex(device); index = safeMediaVolumeIndex(device);
} else { } else {
index = streamState.getMaxIndex(); index = streamState.getMaxIndex();
@@ -2563,7 +2571,7 @@ public class AudioService extends IAudioService.Stub
if (streamType == AudioSystem.STREAM_MUSIC) { if (streamType == AudioSystem.STREAM_MUSIC) {
flags = updateFlagsForTvPlatform(flags); flags = updateFlagsForTvPlatform(flags);
if ((device & mFullVolumeDevices) != 0) { if (mFullVolumeDevices.contains(device)) {
flags &= ~AudioManager.FLAG_SHOW_UI; flags &= ~AudioManager.FLAG_SHOW_UI;
} }
} }
@@ -2609,7 +2617,7 @@ public class AudioService extends IAudioService.Stub
int device, int device,
boolean force, boolean force,
String caller) { String caller) {
if ((device & mFullVolumeDevices) != 0) { if (mFullVolumeDevices.contains(device)) {
return; return;
} }
VolumeStreamState streamState = mStreamStates[streamType]; VolumeStreamState streamState = mStreamStates[streamType];
@@ -2726,8 +2734,8 @@ public class AudioService extends IAudioService.Stub
if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) { if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb)); mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
if (mRmtSbmxFullVolRefCount == 0) { if (mRmtSbmxFullVolRefCount == 0) {
mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; mFixedVolumeDevices.add(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
applyRequired = true; applyRequired = true;
} }
mRmtSbmxFullVolRefCount++; mRmtSbmxFullVolRefCount++;
@@ -2736,8 +2744,8 @@ public class AudioService extends IAudioService.Stub
if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) { if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
mRmtSbmxFullVolRefCount--; mRmtSbmxFullVolRefCount--;
if (mRmtSbmxFullVolRefCount == 0) { if (mRmtSbmxFullVolRefCount == 0) {
mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
applyRequired = true; applyRequired = true;
} }
} }
@@ -2822,7 +2830,7 @@ public class AudioService extends IAudioService.Stub
index = 0; index = 0;
} }
if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) && if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
(device & mFixedVolumeDevices) != 0) { mFixedVolumeDevices.contains(device)) {
index = mStreamStates[streamType].getMaxIndex(); index = mStreamStates[streamType].getMaxIndex();
} }
return (index + 5) / 10; return (index + 5) / 10;
@@ -3680,7 +3688,7 @@ public class AudioService extends IAudioService.Stub
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) { if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
int device = getDeviceForStream(AudioSystem.STREAM_MUSIC); int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
if ((device & mSafeMediaVolumeDevices) != 0) { if (mSafeMediaVolumeDevices.contains(device)) {
sendMsg(mAudioHandler, sendMsg(mAudioHandler,
MSG_CHECK_MUSIC_ACTIVE, MSG_CHECK_MUSIC_ACTIVE,
SENDMSG_REPLACE, SENDMSG_REPLACE,
@@ -4221,6 +4229,8 @@ public class AudioService extends IAudioService.Stub
// retain the device on the A2DP output as the other must not correspond to an active // retain the device on the A2DP output as the other must not correspond to an active
// selection if not the speaker. // selection if not the speaker.
// - HDMI-CEC system audio mode only output: give priority to available item in order. // - HDMI-CEC system audio mode only output: give priority to available item in order.
// FIXME: Haven't applied audio device type refactor to this API
// as it is going to be deprecated.
if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
device = AudioSystem.DEVICE_OUT_SPEAKER; device = AudioSystem.DEVICE_OUT_SPEAKER;
} else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) { } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
@@ -4230,7 +4240,11 @@ public class AudioService extends IAudioService.Stub
} else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) { } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
device = AudioSystem.DEVICE_OUT_AUX_LINE; device = AudioSystem.DEVICE_OUT_AUX_LINE;
} else { } else {
device &= AudioSystem.DEVICE_OUT_ALL_A2DP; for (int deviceType : AudioSystem.DEVICE_OUT_ALL_A2DP_SET) {
if ((deviceType & device) == deviceType) {
return deviceType;
}
}
} }
} }
return device; return device;
@@ -4363,12 +4377,16 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device); mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
} }
private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG = private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET;
AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE | static {
AudioSystem.DEVICE_OUT_LINE | DEVICE_MEDIA_UNMUTED_ON_PLUG_SET = new HashSet<>();
AudioSystem.DEVICE_OUT_ALL_A2DP | DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
AudioSystem.DEVICE_OUT_ALL_USB | DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
AudioSystem.DEVICE_OUT_HDMI; DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE);
DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_HDMI);
}
/** only public for mocking/spying, do not call outside of AudioService */ /** only public for mocking/spying, do not call outside of AudioService */
@VisibleForTesting @VisibleForTesting
@@ -4384,7 +4402,7 @@ public class AudioService extends IAudioService.Stub
} }
if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
&& (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0 && DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice)
&& mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
&& mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0 && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
&& (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0) { && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0) {
@@ -4513,14 +4531,7 @@ public class AudioService extends IAudioService.Stub
} }
} }
synchronized (VolumeStreamState.class) { synchronized (VolumeStreamState.class) {
int remainingDevices = AudioSystem.DEVICE_OUT_ALL; for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
for (int i = 0; remainingDevices != 0; i++) {
int device = (1 << i);
if ((device & remainingDevices) == 0) {
continue;
}
remainingDevices &= ~device;
// retrieve current volume for device // retrieve current volume for device
// if no volume stored for current stream and device, use default volume if default // if no volume stored for current stream and device, use default volume if default
@@ -4580,11 +4591,12 @@ public class AudioService extends IAudioService.Stub
int index; int index;
if (mIsMuted) { if (mIsMuted) {
index = 0; index = 0;
} else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && isAvrcpAbsVolSupported) { } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& isAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} else if ((device & mFullVolumeDevices) != 0) { } else if (mFullVolumeDevices.contains(device)) {
index = (mIndexMax + 5)/10; index = (mIndexMax + 5)/10;
} else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10; index = (mIndexMax + 5)/10;
} else { } else {
index = (getIndex(device) + 5)/10; index = (getIndex(device) + 5)/10;
@@ -4602,12 +4614,12 @@ public class AudioService extends IAudioService.Stub
if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
if (mIsMuted) { if (mIsMuted) {
index = 0; index = 0;
} else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
isAvrcpAbsVolSupported) { && isAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
} else if ((device & mFullVolumeDevices) != 0) { } else if (mFullVolumeDevices.contains(device)) {
index = (mIndexMax + 5)/10; index = (mIndexMax + 5)/10;
} else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10; index = (mIndexMax + 5)/10;
} else { } else {
index = (mIndexMap.valueAt(i) + 5)/10; index = (mIndexMap.valueAt(i) + 5)/10;
@@ -4668,7 +4680,7 @@ public class AudioService extends IAudioService.Stub
&& device == AudioSystem.DEVICE_OUT_SPEAKER) { && device == AudioSystem.DEVICE_OUT_SPEAKER) {
for (int i = 0; i < mIndexMap.size(); i++) { for (int i = 0; i < mIndexMap.size(); i++) {
int otherDevice = mIndexMap.keyAt(i); int otherDevice = mIndexMap.keyAt(i);
if ((otherDevice & AudioSystem.DEVICE_OUT_ALL_SCO) != 0) { if (AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(otherDevice)) {
mIndexMap.put(otherDevice, index); mIndexMap.put(otherDevice, index);
} }
} }
@@ -4806,8 +4818,8 @@ public class AudioService extends IAudioService.Stub
for (int i = 0; i < mIndexMap.size(); i++) { for (int i = 0; i < mIndexMap.size(); i++) {
int device = mIndexMap.keyAt(i); int device = mIndexMap.keyAt(i);
int index = mIndexMap.valueAt(i); int index = mIndexMap.valueAt(i);
if (((device & mFullVolumeDevices) != 0) if (mFullVolumeDevices.contains(device)
|| (((device & mFixedVolumeDevices) != 0) && index != 0)) { || (mFixedVolumeDevices.contains(device) && index != 0)) {
mIndexMap.put(device, mIndexMax); mIndexMap.put(device, mIndexMax);
} }
applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported); applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);
@@ -4978,7 +4990,7 @@ public class AudioService extends IAudioService.Stub
// that may have a different device selected // that may have a different device selected
int streamDevice = getDeviceForStream(streamType); int streamDevice = getDeviceForStream(streamType);
if ((device != streamDevice) && isAvrcpAbsVolSupported if ((device != streamDevice) && isAvrcpAbsVolSupported
&& ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) { && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {
mStreamStates[streamType].applyDeviceVolume_syncVSS(device, mStreamStates[streamType].applyDeviceVolume_syncVSS(device,
isAvrcpAbsVolSupported); isAvrcpAbsVolSupported);
} }
@@ -5307,7 +5319,7 @@ public class AudioService extends IAudioService.Stub
} }
/*package*/ void checkMusicActive(int deviceType, String caller) { /*package*/ void checkMusicActive(int deviceType, String caller) {
if ((deviceType & mSafeMediaVolumeDevices) != 0) { if (mSafeMediaVolumeDevices.contains(deviceType)) {
sendMsg(mAudioHandler, sendMsg(mAudioHandler,
MSG_CHECK_MUSIC_ACTIVE, MSG_CHECK_MUSIC_ACTIVE,
SENDMSG_REPLACE, SENDMSG_REPLACE,
@@ -5753,9 +5765,9 @@ public class AudioService extends IAudioService.Stub
// the headset is compliant to EN 60950 with a max loudness of 100dB SPL. // the headset is compliant to EN 60950 with a max loudness of 100dB SPL.
private int mSafeUsbMediaVolumeIndex; private int mSafeUsbMediaVolumeIndex;
// mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced, // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
/*package*/ final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET /*package*/ final Set<Integer> mSafeMediaVolumeDevices = new HashSet<>(
| AudioSystem.DEVICE_OUT_WIRED_HEADPHONE Arrays.asList(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
| AudioSystem.DEVICE_OUT_USB_HEADSET; AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, AudioSystem.DEVICE_OUT_USB_HEADSET));
// mMusicActiveMs is the cumulative time of music activity since safe volume was disabled. // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
// When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
// automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS. // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
@@ -5765,7 +5777,7 @@ public class AudioService extends IAudioService.Stub
private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
private int safeMediaVolumeIndex(int device) { private int safeMediaVolumeIndex(int device) {
if ((device & mSafeMediaVolumeDevices) == 0) { if (!mSafeMediaVolumeDevices.contains(device)) {
return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]; return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
} }
if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) { if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
@@ -5800,14 +5812,9 @@ public class AudioService extends IAudioService.Stub
private void enforceSafeMediaVolume(String caller) { private void enforceSafeMediaVolume(String caller) {
VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC]; VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
int devices = mSafeMediaVolumeDevices; Set<Integer> devices = mSafeMediaVolumeDevices;
int i = 0;
while (devices != 0) { for (int device : devices) {
int device = 1 << i++;
if ((device & devices) == 0) {
continue;
}
int index = streamState.getIndex(device); int index = streamState.getIndex(device);
if (index > safeMediaVolumeIndex(device)) { if (index > safeMediaVolumeIndex(device)) {
streamState.setIndex(safeMediaVolumeIndex(device), device, caller); streamState.setIndex(safeMediaVolumeIndex(device), device, caller);
@@ -5819,16 +5826,15 @@ public class AudioService extends IAudioService.Stub
streamState, streamState,
0); 0);
} }
devices &= ~device;
} }
} }
private boolean checkSafeMediaVolume(int streamType, int index, int device) { private boolean checkSafeMediaVolume(int streamType, int index, int device) {
synchronized (mSafeMediaVolumeStateLock) { synchronized (mSafeMediaVolumeStateLock) {
if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) && if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)
(mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) && && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC)
((device & mSafeMediaVolumeDevices) != 0) && && (mSafeMediaVolumeDevices.contains(device))
(index > safeMediaVolumeIndex(device))) { && (index > safeMediaVolumeIndex(device))) {
return false; return false;
} }
return true; return true;
@@ -5869,14 +5875,14 @@ public class AudioService extends IAudioService.Stub
if (DEBUG_VOL) { if (DEBUG_VOL) {
Log.d(TAG, "CEC sink: setting HDMI as full vol device"); Log.d(TAG, "CEC sink: setting HDMI as full vol device");
} }
mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI);
} else { } else {
if (DEBUG_VOL) { if (DEBUG_VOL) {
Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device"); Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
} }
// Android TV devices without CEC service apply software volume on // Android TV devices without CEC service apply software volume on
// HDMI output // HDMI output
mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI);
} }
checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
@@ -6097,6 +6103,19 @@ public class AudioService extends IAudioService.Stub
pw.println(); pw.println();
} }
private String dumpDeviceTypes(@NonNull Set<Integer> deviceTypes) {
Iterator<Integer> it = deviceTypes.iterator();
if (!it.hasNext()) {
return "";
}
final StringBuilder sb = new StringBuilder();
sb.append("0x" + Integer.toHexString(it.next()));
while (it.hasNext()) {
sb.append("," + "0x" + Integer.toHexString(it.next()));
}
return sb.toString();
}
@Override @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -6133,7 +6152,7 @@ public class AudioService extends IAudioService.Stub
pw.println(mDeviceBroker.isAvrcpAbsoluteVolumeSupported()); pw.println(mDeviceBroker.isAvrcpAbsoluteVolumeSupported());
pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume); pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume);
pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume); pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume);
pw.print(" mFixedVolumeDevices=0x"); pw.println(Integer.toHexString(mFixedVolumeDevices)); pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
pw.print(" mHdmiCecSink="); pw.println(mHdmiCecSink); pw.print(" mHdmiCecSink="); pw.println(mHdmiCecSink);
pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient); pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient); pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);