Use device set for getDevicesForStream
Implemented through getDevicesForAttributes.
This change avoids device bit-mask aliasing.
Use a TreeSet for device set instead of
HashSet to unify with native handling.
Test: boot and check audio
Test: atest audiopolicy_tests
Test: atest AudioHostTest
Test: atest AudioServiceHostTest
Test: atest AudioManagerTest
Bug: 184944421
Bug: 220928984
Merged-In: Id382172f44f604de659de0bff52c0a28603d1e79
Change-Id: Id382172f44f604de659de0bff52c0a28603d1e79
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 90b272c..e781760 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -829,13 +829,6 @@
}
static jint
-android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
-{
- return (jint)deviceTypesToBitMask(
- AudioSystem::getDevicesForStream(static_cast<audio_stream_type_t>(stream)));
-}
-
-static jint
android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
{
return (jint) AudioSystem::getPrimaryOutputSamplingRate();
@@ -2959,7 +2952,6 @@
{"getMasterMono", "()Z", (void *)android_media_AudioSystem_getMasterMono},
{"setMasterBalance", "(F)I", (void *)android_media_AudioSystem_setMasterBalance},
{"getMasterBalance", "()F", (void *)android_media_AudioSystem_getMasterBalance},
- {"getDevicesForStream", "(I)I", (void *)android_media_AudioSystem_getDevicesForStream},
{"getPrimaryOutputSamplingRate", "()I",
(void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
{"getPrimaryOutputFrameCount", "()I",
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 6e695e6..ead2b1d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5625,27 +5625,33 @@
* Note that the information may be imprecise when the implementation
* cannot distinguish whether a particular device is enabled.
*
- * {@hide}
+ * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
+ * will have multi-bit device types.
+ * Prefer to use {@link #getDevicesForAttributes()} instead,
+ * noting that getDevicesForStream() has a few small discrepancies
+ * for better volume handling.
+ * @hide
*/
@UnsupportedAppUsage
+ @Deprecated
public int getDevicesForStream(int streamType) {
switch (streamType) {
- case STREAM_VOICE_CALL:
- case STREAM_SYSTEM:
- case STREAM_RING:
- case STREAM_MUSIC:
- case STREAM_ALARM:
- case STREAM_NOTIFICATION:
- case STREAM_DTMF:
- case STREAM_ACCESSIBILITY:
- final IAudioService service = getService();
- try {
- return service.getDevicesForStream(streamType);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- default:
- return 0;
+ case STREAM_VOICE_CALL:
+ case STREAM_SYSTEM:
+ case STREAM_RING:
+ case STREAM_MUSIC:
+ case STREAM_ALARM:
+ case STREAM_NOTIFICATION:
+ case STREAM_DTMF:
+ case STREAM_ACCESSIBILITY:
+ final IAudioService service = getService();
+ try {
+ return service.getDeviceMaskForStream(streamType);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ default:
+ return 0;
}
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 210f3e5..acb34b5 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -29,6 +29,7 @@
import android.media.audio.common.AidlConversion;
import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioProductStrategy;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
@@ -47,6 +48,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.TreeSet;
/* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
* TO UPDATE THE CORRESPONDING NATIVE GLUE AND AudioManager.java.
@@ -1655,9 +1657,63 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static native boolean getMasterMute();
- /** @hide */
+ /** @hide
+ * Only used (unsupported) for legacy apps.
+ * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
+ * will have multi-bit device types.
+ * Use {@link AudioManager#getDevicesForAttributes(AudioAttributes)} instead.
+ */
@UnsupportedAppUsage
- public static native int getDevicesForStream(int stream);
+ @Deprecated
+ public static int getDevicesForStream(int stream) {
+ final AudioAttributes attr =
+ AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(stream);
+ return getDeviceMaskFromSet(generateAudioDeviceTypesSet(
+ getDevicesForAttributes(attr, true /* forVolume */)));
+ }
+
+ /** @hide
+ * Conversion from a device set to a bit mask.
+ *
+ * Legacy compatibility method (use a device list instead of a bit mask).
+ * Conversion to bit mask skips multi-bit (S and later) internal device types
+ * (e.g. AudioSystem.DEVICE_OUT* or AudioManager.DEVICE_OUT*) for legacy
+ * compatibility reasons. Legacy apps will not understand these new device types
+ * and it will raise false matches with old device types.
+ */
+ public static int getDeviceMaskFromSet(@NonNull Set<Integer> deviceSet) {
+ int deviceMask = DEVICE_NONE; // zero.
+ int deviceInChecksum = DEVICE_BIT_IN;
+ for (Integer device : deviceSet) {
+ if ((device & (device - 1) & ~DEVICE_BIT_IN) != 0) {
+ Log.v(TAG, "getDeviceMaskFromSet skipping multi-bit device value " + device);
+ continue;
+ }
+ deviceMask |= device;
+ deviceInChecksum &= device;
+ }
+ // Validate that deviceSet is either ALL input devices or ALL output devices.
+ // We check that the "OR" of all the DEVICE_BIT_INs == the "AND" of all DEVICE_BIT_INs.
+ if (!deviceSet.isEmpty() && deviceInChecksum != (deviceMask & DEVICE_BIT_IN)) {
+ Log.e(TAG, "getDeviceMaskFromSet: Invalid set: " + deviceSetToString(deviceSet));
+ }
+ return deviceMask;
+ }
+
+ /** @hide */
+ @NonNull
+ public static String deviceSetToString(@NonNull Set<Integer> devices) {
+ int n = 0;
+ StringBuilder sb = new StringBuilder();
+ for (Integer device : devices) {
+ if (n++ > 0) {
+ sb.append(", ");
+ }
+ sb.append(AudioSystem.getDeviceName(device));
+ sb.append("(" + Integer.toHexString(device) + ")");
+ }
+ return sb.toString();
+ }
/**
* @hide
@@ -2252,18 +2308,15 @@
/**
* @hide
- * Return a set of audio device types from a bit mask audio device type, which may
+ * Return a set of audio device types from a list of audio device attributes, 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);
- }
+ @NonNull
+ public static Set<Integer> generateAudioDeviceTypesSet(
+ @NonNull List<AudioDeviceAttributes> deviceList) {
+ Set<Integer> deviceTypes = new TreeSet<>();
+ for (AudioDeviceAttributes device : deviceList) {
+ deviceTypes.add(device.getInternalType());
}
return deviceTypes;
}
@@ -2274,7 +2327,7 @@
*/
public static Set<Integer> intersectionAudioDeviceTypes(
@NonNull Set<Integer> a, @NonNull Set<Integer> b) {
- Set<Integer> intersection = new HashSet<>(a);
+ Set<Integer> intersection = new TreeSet<>(a);
intersection.retainAll(b);
return intersection;
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index d702eb9..fa3057a 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -360,7 +360,7 @@
boolean isMusicActive(in boolean remotely);
- int getDevicesForStream(in int streamType);
+ int getDeviceMaskForStream(in int streamType);
int[] getAvailableCommunicationDeviceIds();
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index ff7557a..270a61b 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1565,6 +1565,13 @@
private AtomicBoolean mMusicMuted = new AtomicBoolean(false);
+ private static <T> boolean hasIntersection(Set<T> a, Set<T> b) {
+ for (T e : a) {
+ if (b.contains(e)) return true;
+ }
+ return false;
+ }
+
boolean messageMutesMusic(int message) {
if (message == 0) {
return false;
@@ -1574,8 +1581,8 @@
|| message == MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT
|| message == MSG_L_A2DP_DEVICE_CONFIG_CHANGE)
&& AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)
- && mDeviceInventory.DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(
- mAudioService.getDevicesForStream(AudioSystem.STREAM_MUSIC))) {
+ && hasIntersection(mDeviceInventory.DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET,
+ mAudioService.getDeviceSetForStream(AudioSystem.STREAM_MUSIC))) {
return false;
}
return true;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 24dfa25..d606aba 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -195,6 +195,7 @@
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
+import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -1822,6 +1823,7 @@
}
// Check if device to be updated is routed for the given audio stream
+ // This may include devices such as SPEAKER_SAFE.
List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt(
new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build(),
true /* forVolume */);
@@ -3693,8 +3695,7 @@
int streamType = getBluetoothContextualVolumeStream(newMode);
- final Set<Integer> deviceTypes = AudioSystem.generateAudioDeviceTypesSet(
- mAudioSystem.getDevicesForStream(streamType));
+ final Set<Integer> deviceTypes = getDeviceSetForStreamDirect(streamType);
final Set<Integer> absVolumeMultiModeCaseDevices = AudioSystem.intersectionAudioDeviceTypes(
mAbsVolumeMultiModeCaseDevices, deviceTypes);
if (absVolumeMultiModeCaseDevices.isEmpty()) {
@@ -6258,55 +6259,104 @@
}
}
- /** only public for mocking/spying, do not call outside of AudioService */
+ /**
+ * Returns device associated with the stream volume.
+ *
+ * Only public for mocking/spying, do not call outside of AudioService.
+ * Device volume aliasing means DEVICE_OUT_SPEAKER may be returned for
+ * DEVICE_OUT_SPEAKER_SAFE.
+ */
@VisibleForTesting
public int getDeviceForStream(int stream) {
- int device = getDevicesForStreamInt(stream);
- if ((device & (device - 1)) != 0) {
+ return selectOneAudioDevice(getDeviceSetForStream(stream));
+ }
+
+ /*
+ * Must match native apm_extract_one_audio_device() used in getDeviceForVolume()
+ * or the wrong device volume may be adjusted.
+ */
+ private int selectOneAudioDevice(Set<Integer> deviceSet) {
+ if (deviceSet.isEmpty()) {
+ return AudioSystem.DEVICE_NONE;
+ } else if (deviceSet.size() == 1) {
+ return deviceSet.iterator().next();
+ } else {
// Multiple device selection is either:
// - speaker + one other device: give priority to speaker in this case.
// - one A2DP device + another device: happens with duplicated output. In this case
// retain the device on the A2DP output as the other must not correspond to an active
// selection if not the speaker.
// - 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) {
- device = AudioSystem.DEVICE_OUT_SPEAKER;
- } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
- // FIXME(b/184944421): DEVICE_OUT_HDMI_EARC has two bits set,
- // so it must be handled correctly as it aliases
- // with DEVICE_OUT_HDMI_ARC | DEVICE_OUT_EARPIECE.
- device = AudioSystem.DEVICE_OUT_HDMI_ARC;
- } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
- device = AudioSystem.DEVICE_OUT_SPDIF;
- } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
- device = AudioSystem.DEVICE_OUT_AUX_LINE;
+
+ if (deviceSet.contains(AudioSystem.DEVICE_OUT_SPEAKER)) {
+ return AudioSystem.DEVICE_OUT_SPEAKER;
+ } else if (deviceSet.contains(AudioSystem.DEVICE_OUT_SPEAKER_SAFE)) {
+ // Note: DEVICE_OUT_SPEAKER_SAFE not present in getDeviceSetForStreamDirect
+ return AudioSystem.DEVICE_OUT_SPEAKER_SAFE;
+ } else if (deviceSet.contains(AudioSystem.DEVICE_OUT_HDMI_ARC)) {
+ return AudioSystem.DEVICE_OUT_HDMI_ARC;
+ } else if (deviceSet.contains(AudioSystem.DEVICE_OUT_HDMI_EARC)) {
+ return AudioSystem.DEVICE_OUT_HDMI_EARC;
+ } else if (deviceSet.contains(AudioSystem.DEVICE_OUT_SPDIF)) {
+ return AudioSystem.DEVICE_OUT_SPDIF;
+ } else if (deviceSet.contains(AudioSystem.DEVICE_OUT_AUX_LINE)) {
+ return AudioSystem.DEVICE_OUT_AUX_LINE;
} else {
for (int deviceType : AudioSystem.DEVICE_OUT_ALL_A2DP_SET) {
- if ((deviceType & device) == deviceType) {
+ if (deviceSet.contains(deviceType)) {
return deviceType;
}
}
}
}
- return device;
+ Log.w(TAG, "selectOneAudioDevice returning DEVICE_NONE from invalid device combination "
+ + AudioSystem.deviceSetToString(deviceSet));
+ return AudioSystem.DEVICE_NONE;
}
/**
* @see AudioManager#getDevicesForStream(int)
+ * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
+ * will have multi-bit device types since S.
+ * Use {@link #getDevicesForAttributes()} instead.
*/
- public int getDevicesForStream(int streamType) {
+ @Override
+ @Deprecated
+ public int getDeviceMaskForStream(int streamType) {
ensureValidStreamType(streamType);
+ // no permission required
final long token = Binder.clearCallingIdentity();
try {
- return mAudioSystem.getDevicesForStream(streamType);
+ return AudioSystem.getDeviceMaskFromSet(
+ getDeviceSetForStreamDirect(streamType));
} finally {
Binder.restoreCallingIdentity(token);
}
}
- private int getDevicesForStreamInt(int stream) {
+ /**
+ * Returns the devices associated with a stream type.
+ *
+ * SPEAKER_SAFE will alias to SPEAKER.
+ */
+ @NonNull
+ private Set<Integer> getDeviceSetForStreamDirect(int stream) {
+ final AudioAttributes attr =
+ AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(stream);
+ Set<Integer> deviceSet =
+ AudioSystem.generateAudioDeviceTypesSet(
+ getDevicesForAttributesInt(attr, true /* forVolume */));
+ return deviceSet;
+ }
+
+ /**
+ * Returns a reference to the list of devices for the stream, do not modify.
+ *
+ * The device returned may be aliased to the actual device whose volume curve
+ * will be used. For example DEVICE_OUT_SPEAKER_SAFE aliases to DEVICE_OUT_SPEAKER.
+ */
+ @NonNull
+ public Set<Integer> getDeviceSetForStream(int stream) {
ensureValidStreamType(stream);
synchronized (VolumeStreamState.class) {
return mStreamStates[stream].observeDevicesForStream_syncVSS(true);
@@ -6318,11 +6368,10 @@
synchronized (VolumeStreamState.class) {
for (int stream = 0; stream < mStreamStates.length; stream++) {
if (stream != skipStream) {
- int devices = mStreamStates[stream].observeDevicesForStream_syncVSS(
- false /*checkOthers*/);
-
- Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices);
- for (Integer device : devicesSet) {
+ Set<Integer> deviceSet =
+ mStreamStates[stream].observeDevicesForStream_syncVSS(
+ false /*checkOthers*/);
+ for (Integer device : deviceSet) {
// Update volume states for devices routed for the stream
updateVolumeStates(device, stream,
"AudioService#onObserveDevicesForAllStreams");
@@ -6643,7 +6692,7 @@
&& DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice)
&& mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
&& mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
- && (newDevice & mAudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0) {
+ && getDeviceSetForStreamDirect(AudioSystem.STREAM_MUSIC).contains(newDevice)) {
if (DEBUG_VOL) {
Log.i(TAG, String.format("onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
newDevice, AudioSystem.getOutputDeviceName(newDevice)));
@@ -7031,7 +7080,7 @@
private boolean mIsMuted;
private boolean mIsMutedInternally;
private String mVolumeIndexSettingName;
- private int mObservedDevices;
+ @NonNull private Set<Integer> mObservedDeviceSet = new TreeSet<>();
private final SparseIntArray mIndexMap = new SparseIntArray(8) {
@Override
@@ -7098,17 +7147,30 @@
}
}
+ /**
+ * Returns a list of devices associated with the stream type.
+ *
+ * This is a reference to the local list, do not modify.
+ */
@GuardedBy("VolumeStreamState.class")
- public int observeDevicesForStream_syncVSS(boolean checkOthers) {
+ @NonNull
+ public Set<Integer> observeDevicesForStream_syncVSS(
+ boolean checkOthers) {
if (!mSystemServer.isPrivileged()) {
- return AudioSystem.DEVICE_NONE;
+ return new TreeSet<Integer>();
}
- final int devices = mAudioSystem.getDevicesForStream(mStreamType);
- if (devices == mObservedDevices) {
- return devices;
+ final Set<Integer> deviceSet =
+ getDeviceSetForStreamDirect(mStreamType);
+ if (deviceSet.equals(mObservedDeviceSet)) {
+ return mObservedDeviceSet;
}
- final int prevDevices = mObservedDevices;
- mObservedDevices = devices;
+
+ // Use legacy bit masks for message signalling.
+ // TODO(b/185386781): message needs update since it uses devices bit-mask.
+ final int devices = AudioSystem.getDeviceMaskFromSet(deviceSet);
+ final int prevDevices = AudioSystem.getDeviceMaskFromSet(mObservedDeviceSet);
+
+ mObservedDeviceSet = deviceSet;
if (checkOthers) {
// one stream's devices have changed, check the others
postObserveDevicesForAllStreams(mStreamType);
@@ -7124,7 +7186,7 @@
SENDMSG_QUEUE, prevDevices /*arg1*/, devices /*arg2*/,
// ok to send reference to this object, it is final
mStreamDevicesChanged /*obj*/, 0 /*delay*/);
- return devices;
+ return mObservedDeviceSet;
}
public @Nullable String getSettingNameForDevice(int device) {
@@ -7555,19 +7617,7 @@
}
pw.println();
pw.print(" Devices: ");
- final int devices = getDevicesForStreamInt(mStreamType);
- int device, i = 0, n = 0;
- // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
- // (the default device is not returned by getDevicesForStreamInt)
- while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
- if ((devices & device) != 0) {
- if (n++ > 0) {
- pw.print(", ");
- }
- pw.print(AudioSystem.getOutputDeviceName(device));
- }
- i++;
- }
+ pw.print(AudioSystem.deviceSetToString(getDeviceSetForStream(mStreamType)));
}
}
@@ -9324,7 +9374,9 @@
mDeviceBroker.setForceUse_Async(AudioSystem.FOR_HDMI_SYSTEM_AUDIO, config,
"setHdmiSystemAudioSupported");
}
- device = getDevicesForStreamInt(AudioSystem.STREAM_MUSIC);
+ // TODO(b/185386781): Update AudioManager API to use device list.
+ // So far, this value appears to be advisory for debug log.
+ device = getDeviceMaskForStream(AudioSystem.STREAM_MUSIC);
}
}
return device;
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 6ef8e87..1429b3c 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -52,15 +52,13 @@
* in measured methods
*/
private static final boolean ENABLE_GETDEVICES_STATS = false;
- private static final int NB_MEASUREMENTS = 2;
- private static final int METHOD_GETDEVICESFORSTREAM = 0;
- private static final int METHOD_GETDEVICESFORATTRIBUTES = 1;
+ private static final int NB_MEASUREMENTS = 1;
+ private static final int METHOD_GETDEVICESFORATTRIBUTES = 0;
private long[] mMethodTimeNs;
private int[] mMethodCallCounter;
- private String[] mMethodNames = {"getDevicesForStream", "getDevicesForAttributes"};
+ private String[] mMethodNames = {"getDevicesForAttributes"};
private static final boolean USE_CACHE_FOR_GETDEVICES = true;
- private ConcurrentHashMap<Integer, Integer> mDevicesForStreamCache;
private ConcurrentHashMap<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>>
mDevicesForAttrCache;
private int[] mMethodCacheHit;
@@ -113,8 +111,6 @@
sSingletonDefaultAdapter = new AudioSystemAdapter();
AudioSystem.setRoutingCallback(sSingletonDefaultAdapter);
if (USE_CACHE_FOR_GETDEVICES) {
- sSingletonDefaultAdapter.mDevicesForStreamCache =
- new ConcurrentHashMap<>(AudioSystem.getNumStreamTypes());
sSingletonDefaultAdapter.mDevicesForAttrCache =
new ConcurrentHashMap<>(AudioSystem.getNumStreamTypes());
sSingletonDefaultAdapter.mMethodCacheHit = new int[NB_MEASUREMENTS];
@@ -131,11 +127,6 @@
if (DEBUG_CACHE) {
Log.d(TAG, "---- clearing cache ----------");
}
- if (mDevicesForStreamCache != null) {
- synchronized (mDevicesForStreamCache) {
- mDevicesForStreamCache.clear();
- }
- }
if (mDevicesForAttrCache != null) {
synchronized (mDevicesForAttrCache) {
mDevicesForAttrCache.clear();
@@ -144,60 +135,6 @@
}
/**
- * Same as {@link AudioSystem#getDevicesForStream(int)}
- * @param stream a valid stream type
- * @return a mask of device types
- */
- public int getDevicesForStream(int stream) {
- if (!ENABLE_GETDEVICES_STATS) {
- return getDevicesForStreamImpl(stream);
- }
- mMethodCallCounter[METHOD_GETDEVICESFORSTREAM]++;
- final long startTime = SystemClock.uptimeNanos();
- final int res = getDevicesForStreamImpl(stream);
- mMethodTimeNs[METHOD_GETDEVICESFORSTREAM] += SystemClock.uptimeNanos() - startTime;
- return res;
- }
-
- private int getDevicesForStreamImpl(int stream) {
- if (USE_CACHE_FOR_GETDEVICES) {
- Integer res;
- synchronized (mDevicesForStreamCache) {
- res = mDevicesForStreamCache.get(stream);
- if (res == null) {
- res = AudioSystem.getDevicesForStream(stream);
- mDevicesForStreamCache.put(stream, res);
- if (DEBUG_CACHE) {
- Log.d(TAG, mMethodNames[METHOD_GETDEVICESFORSTREAM]
- + streamDeviceToDebugString(stream, res));
- }
- return res;
- }
- // cache hit
- mMethodCacheHit[METHOD_GETDEVICESFORSTREAM]++;
- if (DEBUG_CACHE) {
- final int real = AudioSystem.getDevicesForStream(stream);
- if (res == real) {
- Log.d(TAG, mMethodNames[METHOD_GETDEVICESFORSTREAM]
- + streamDeviceToDebugString(stream, res) + " CACHE");
- } else {
- Log.e(TAG, mMethodNames[METHOD_GETDEVICESFORSTREAM]
- + streamDeviceToDebugString(stream, res)
- + " CACHE ERROR real dev=0x" + Integer.toHexString(real));
- }
- }
- }
- return res;
- }
- // not using cache
- return AudioSystem.getDevicesForStream(stream);
- }
-
- private static String streamDeviceToDebugString(int stream, int dev) {
- return " stream=" + stream + " dev=0x" + Integer.toHexString(dev);
- }
-
- /**
* Same as {@link AudioSystem#getDevicesForAttributes(AudioAttributes)}
* @param attributes the attributes for which the routing is queried
* @return the devices that the stream with the given attributes would be routed to
@@ -253,12 +190,9 @@
}
private static String attrDeviceToDebugString(@NonNull AudioAttributes attr,
- @NonNull ArrayList<AudioDeviceAttributes> devices) {
- String ds = " attrUsage=" + attr.getSystemUsage();
- for (AudioDeviceAttributes ada : devices) {
- ds = ds.concat(" dev=0x" + Integer.toHexString(ada.getInternalType()));
- }
- return ds;
+ @NonNull List<AudioDeviceAttributes> devices) {
+ return " attrUsage=" + attr.getSystemUsage() + " "
+ + AudioSystem.deviceSetToString(AudioSystem.generateAudioDeviceTypesSet(devices));
}
/**
@@ -518,20 +452,23 @@
*/
public void dump(PrintWriter pw) {
pw.println("\nAudioSystemAdapter:");
- pw.println(" mDevicesForStreamCache:");
- if (mDevicesForStreamCache != null) {
- for (Integer stream : mDevicesForStreamCache.keySet()) {
- pw.println("\t stream:" + stream + " device:"
- + AudioSystem.getOutputDeviceName(mDevicesForStreamCache.get(stream)));
- }
- }
pw.println(" mDevicesForAttrCache:");
if (mDevicesForAttrCache != null) {
for (Map.Entry<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>>
entry : mDevicesForAttrCache.entrySet()) {
- pw.println("\t" + entry.getKey().first + " forVolume: " + entry.getKey().second);
- for (AudioDeviceAttributes devAttr : entry.getValue()) {
- pw.println("\t\t" + devAttr);
+ final AudioAttributes attributes = entry.getKey().first;
+ try {
+ final int stream = attributes.getVolumeControlStream();
+ pw.println("\t" + attributes + " forVolume: " + entry.getKey().second
+ + " stream: "
+ + AudioSystem.STREAM_NAMES[stream] + "(" + stream + ")");
+ for (AudioDeviceAttributes devAttr : entry.getValue()) {
+ pw.println("\t\t" + devAttr);
+ }
+ } catch (IllegalArgumentException e) {
+ // dump could fail if attributes do not map to a stream.
+ pw.println("\t dump failed for attributes: " + attributes);
+ Log.e(TAG, "dump failed", e);
}
}
}
@@ -545,7 +482,8 @@
+ ": counter=" + mMethodCallCounter[i]
+ " time(ms)=" + (mMethodTimeNs[i] / 1E6)
+ (USE_CACHE_FOR_GETDEVICES
- ? (" FScacheHit=" + mMethodCacheHit[METHOD_GETDEVICESFORSTREAM]) : ""));
+ ? (" FScacheHit=" + mMethodCacheHit[METHOD_GETDEVICESFORATTRIBUTES])
+ : ""));
}
pw.println("\n");
}