Loading media/java/android/media/AudioManager.java +27 −5 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.Context.DEVICE_ID_DEFAULT; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import static android.media.audio.Flags.automaticBtDeviceType; import static android.media.audio.Flags.cacheGetStreamMinMaxVolume; import static android.media.audio.Flags.cacheGetStreamVolume; import static android.media.audio.Flags.FLAG_DEPRECATE_STREAM_BT_SCO; import static android.media.audio.Flags.FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING; import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API; Loading Loading @@ -1241,7 +1242,12 @@ public class AudioManager { * @hide **/ public static final String VOLUME_MAX_CACHING_API = "getStreamMaxVolume"; private static final int VOLUME_MIN_MAX_CACHING_SIZE = 16; /** * API string for caching the volume for each stream * @hide **/ public static final String VOLUME_CACHING_API = "getStreamVolume"; private static final int VOLUME_CACHING_SIZE = 16; private final IpcDataCache.QueryHandler<VolumeCacheQuery, Integer> mVolQuery = new IpcDataCache.QueryHandler<>() { Loading @@ -1252,6 +1258,7 @@ public class AudioManager { return switch (query.queryCommand) { case QUERY_VOL_MIN -> service.getStreamMinVolume(query.stream); case QUERY_VOL_MAX -> service.getStreamMaxVolume(query.stream); case QUERY_VOL -> service.getStreamVolume(query.stream); default -> { Log.w(TAG, "Not a valid volume cache query: " + query); yield null; Loading @@ -1265,29 +1272,40 @@ public class AudioManager { }; private final IpcDataCache<VolumeCacheQuery, Integer> mVolMinCache = new IpcDataCache<>(VOLUME_MIN_MAX_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, VOLUME_MIN_CACHING_API, VOLUME_MIN_CACHING_API, mVolQuery); private final IpcDataCache<VolumeCacheQuery, Integer> mVolMaxCache = new IpcDataCache<>(VOLUME_MIN_MAX_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, VOLUME_MAX_CACHING_API, VOLUME_MAX_CACHING_API, mVolQuery); private final IpcDataCache<VolumeCacheQuery, Integer> mVolCache = new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, VOLUME_CACHING_API, VOLUME_CACHING_API, mVolQuery); /** * Used to invalidate the cache for the given API * @hide **/ public static void clearVolumeCache(String api) { if (cacheGetStreamMinMaxVolume()) { if (cacheGetStreamMinMaxVolume() && (VOLUME_MAX_CACHING_API.equals(api) || VOLUME_MIN_CACHING_API.equals(api))) { IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, api); } else if (cacheGetStreamVolume() && VOLUME_CACHING_API.equals(api)) { IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, api); } else { Log.w(TAG, "invalid clearVolumeCache for api " + api); } } private static final int QUERY_VOL_MIN = 1; private static final int QUERY_VOL_MAX = 2; private static final int QUERY_VOL = 3; /** @hide */ @IntDef(prefix = "QUERY_VOL", value = { QUERY_VOL_MIN, QUERY_VOL_MAX} QUERY_VOL_MAX, QUERY_VOL} ) @Retention(RetentionPolicy.SOURCE) private @interface QueryVolCommand {} Loading @@ -1297,6 +1315,7 @@ public class AudioManager { return switch (queryCommand) { case QUERY_VOL_MIN -> "getStreamMinVolume"; case QUERY_VOL_MAX -> "getStreamMaxVolume"; case QUERY_VOL -> "getStreamVolume"; default -> "invalid command"; }; } Loading Loading @@ -1373,6 +1392,9 @@ public class AudioManager { * @see #setStreamVolume(int, int, int) */ public int getStreamVolume(int streamType) { if (cacheGetStreamVolume()) { return mVolCache.query(new VolumeCacheQuery(streamType, QUERY_VOL)); } final IAudioService service = getService(); try { return service.getStreamVolume(streamType); Loading media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java +24 −12 Original line number Diff line number Diff line Loading @@ -67,6 +67,17 @@ public class AudioManagerTest { private AudioManager mAudioManager; private static final int[] PUBLIC_STREAM_TYPES = { STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC, STREAM_ALARM, STREAM_NOTIFICATION, STREAM_DTMF, STREAM_ACCESSIBILITY, }; @Rule public final AudioVolumesTestRule rule = new AudioVolumesTestRule(); Loading Loading @@ -226,18 +237,8 @@ public class AudioManagerTest { public void getStreamMinMaxVolume_consistentWithAs() throws Exception { IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); IAudioService service = IAudioService.Stub.asInterface(b); final int[] streamTypes = { STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC, STREAM_ALARM, STREAM_NOTIFICATION, STREAM_DTMF, STREAM_ACCESSIBILITY, }; for (int streamType : streamTypes) { for (int streamType : PUBLIC_STREAM_TYPES) { assertEquals(service.getStreamMinVolume(streamType), mAudioManager.getStreamMinVolume(streamType)); assertEquals(service.getStreamMaxVolume(streamType), Loading @@ -245,6 +246,17 @@ public class AudioManagerTest { } } @Test public void getStreamVolume_consistentWithAs() throws Exception { IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); IAudioService service = IAudioService.Stub.asInterface(b); for (int streamType : PUBLIC_STREAM_TYPES) { assertEquals(service.getStreamVolume(streamType), mAudioManager.getStreamVolume(streamType)); } } //----------------------------------------------------------------- // Test Volume per Attributes setter/getters //----------------------------------------------------------------- Loading services/core/java/com/android/server/audio/AudioManagerShellCommand.java +13 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,8 @@ class AudioManagerShellCommand extends ShellCommand { return getMinVolume(); case "get-max-volume": return getMaxVolume(); case "get-stream-volume": return getStreamVolume(); case "set-device-volume": return setDeviceVolume(); case "adj-mute": Loading Loading @@ -114,6 +116,8 @@ class AudioManagerShellCommand extends ShellCommand { pw.println(" Gets the min volume for STREAM_TYPE"); pw.println(" get-max-volume STREAM_TYPE"); pw.println(" Gets the max volume for STREAM_TYPE"); pw.println(" get-stream-volume STREAM_TYPE"); pw.println(" Gets the volume for STREAM_TYPE"); pw.println(" set-device-volume STREAM_TYPE VOLUME_INDEX NATIVE_DEVICE_TYPE"); pw.println(" Sets for NATIVE_DEVICE_TYPE the STREAM_TYPE volume to VOLUME_INDEX"); pw.println(" adj-mute STREAM_TYPE"); Loading Loading @@ -322,6 +326,15 @@ class AudioManagerShellCommand extends ShellCommand { return 0; } private int getStreamVolume() { final Context context = mService.mContext; final AudioManager am = context.getSystemService(AudioManager.class); final int stream = readIntArg(); final int result = am.getStreamVolume(stream); getOutPrintWriter().println("AudioManager.getStreamVolume(" + stream + ") -> " + result); return 0; } private int setDeviceVolume() { final Context context = mService.mContext; final AudioDeviceVolumeManager advm = (AudioDeviceVolumeManager) context.getSystemService( Loading services/core/java/com/android/server/audio/AudioService.java +39 −2 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import static android.media.AudioManager.STREAM_SYSTEM; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import static android.media.audio.Flags.automaticBtDeviceType; import static android.media.audio.Flags.cacheGetStreamMinMaxVolume; import static android.media.audio.Flags.cacheGetStreamVolume; import static android.media.audio.Flags.concurrentAudioRecordBypassPermission; import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency; import static android.media.audio.Flags.focusFreezeTestApi; Loading Loading @@ -1910,6 +1911,12 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.onRoutingUpdated(); } checkMuteAwaitConnection(); if (cacheGetStreamVolume()) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after routing update"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } } //----------------------------------------------------------------- Loading Loading @@ -4988,6 +4995,8 @@ public class AudioService extends IAudioService.Stub + concurrentAudioRecordBypassPermission()); pw.println("\tandroid.media.audio.Flags.cacheGetStreamMinMaxVolume:" + cacheGetStreamMinMaxVolume()); pw.println("\tandroid.media.audio.Flags.cacheGetStreamVolume:" + cacheGetStreamVolume()); } private void dumpAudioMode(PrintWriter pw) { Loading Loading @@ -7054,6 +7063,13 @@ public class AudioService extends IAudioService.Stub streamState.mIsMuted = false; } } if (cacheGetStreamVolume()) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after possibly changing mute in readAudioSettings"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } } readVolumeGroupsSettings(userSwitch); Loading Loading @@ -9274,11 +9290,23 @@ public class AudioService extends IAudioService.Stub public void put(int key, int value) { super.put(key, value); record("put", key, value); if (cacheGetStreamVolume()) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after update index map"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } } @Override public void setValueAt(int index, int value) { super.setValueAt(index, value); record("setValueAt", keyAt(index), value); if (cacheGetStreamVolume()) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after update index map"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } } // Record all changes in the VolumeStreamState Loading Loading @@ -10008,8 +10036,9 @@ public class AudioService extends IAudioService.Stub * @return true if the mute state was changed */ public boolean mute(boolean state, boolean apply, String src) { boolean changed; synchronized (VolumeStreamState.class) { boolean changed = state != mIsMuted; changed = state != mIsMuted; if (changed) { sMuteLogger.enqueue( new AudioServiceEvents.StreamMuteEvent(mStreamType, state, src)); Loading @@ -10027,8 +10056,16 @@ public class AudioService extends IAudioService.Stub doMute(); } } return changed; } if (cacheGetStreamVolume() && changed) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after changing mute state"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } return changed; } public void doMute() { Loading Loading
media/java/android/media/AudioManager.java +27 −5 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.Context.DEVICE_ID_DEFAULT; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import static android.media.audio.Flags.automaticBtDeviceType; import static android.media.audio.Flags.cacheGetStreamMinMaxVolume; import static android.media.audio.Flags.cacheGetStreamVolume; import static android.media.audio.Flags.FLAG_DEPRECATE_STREAM_BT_SCO; import static android.media.audio.Flags.FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING; import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API; Loading Loading @@ -1241,7 +1242,12 @@ public class AudioManager { * @hide **/ public static final String VOLUME_MAX_CACHING_API = "getStreamMaxVolume"; private static final int VOLUME_MIN_MAX_CACHING_SIZE = 16; /** * API string for caching the volume for each stream * @hide **/ public static final String VOLUME_CACHING_API = "getStreamVolume"; private static final int VOLUME_CACHING_SIZE = 16; private final IpcDataCache.QueryHandler<VolumeCacheQuery, Integer> mVolQuery = new IpcDataCache.QueryHandler<>() { Loading @@ -1252,6 +1258,7 @@ public class AudioManager { return switch (query.queryCommand) { case QUERY_VOL_MIN -> service.getStreamMinVolume(query.stream); case QUERY_VOL_MAX -> service.getStreamMaxVolume(query.stream); case QUERY_VOL -> service.getStreamVolume(query.stream); default -> { Log.w(TAG, "Not a valid volume cache query: " + query); yield null; Loading @@ -1265,29 +1272,40 @@ public class AudioManager { }; private final IpcDataCache<VolumeCacheQuery, Integer> mVolMinCache = new IpcDataCache<>(VOLUME_MIN_MAX_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, VOLUME_MIN_CACHING_API, VOLUME_MIN_CACHING_API, mVolQuery); private final IpcDataCache<VolumeCacheQuery, Integer> mVolMaxCache = new IpcDataCache<>(VOLUME_MIN_MAX_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, VOLUME_MAX_CACHING_API, VOLUME_MAX_CACHING_API, mVolQuery); private final IpcDataCache<VolumeCacheQuery, Integer> mVolCache = new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, VOLUME_CACHING_API, VOLUME_CACHING_API, mVolQuery); /** * Used to invalidate the cache for the given API * @hide **/ public static void clearVolumeCache(String api) { if (cacheGetStreamMinMaxVolume()) { if (cacheGetStreamMinMaxVolume() && (VOLUME_MAX_CACHING_API.equals(api) || VOLUME_MIN_CACHING_API.equals(api))) { IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, api); } else if (cacheGetStreamVolume() && VOLUME_CACHING_API.equals(api)) { IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, api); } else { Log.w(TAG, "invalid clearVolumeCache for api " + api); } } private static final int QUERY_VOL_MIN = 1; private static final int QUERY_VOL_MAX = 2; private static final int QUERY_VOL = 3; /** @hide */ @IntDef(prefix = "QUERY_VOL", value = { QUERY_VOL_MIN, QUERY_VOL_MAX} QUERY_VOL_MAX, QUERY_VOL} ) @Retention(RetentionPolicy.SOURCE) private @interface QueryVolCommand {} Loading @@ -1297,6 +1315,7 @@ public class AudioManager { return switch (queryCommand) { case QUERY_VOL_MIN -> "getStreamMinVolume"; case QUERY_VOL_MAX -> "getStreamMaxVolume"; case QUERY_VOL -> "getStreamVolume"; default -> "invalid command"; }; } Loading Loading @@ -1373,6 +1392,9 @@ public class AudioManager { * @see #setStreamVolume(int, int, int) */ public int getStreamVolume(int streamType) { if (cacheGetStreamVolume()) { return mVolCache.query(new VolumeCacheQuery(streamType, QUERY_VOL)); } final IAudioService service = getService(); try { return service.getStreamVolume(streamType); Loading
media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java +24 −12 Original line number Diff line number Diff line Loading @@ -67,6 +67,17 @@ public class AudioManagerTest { private AudioManager mAudioManager; private static final int[] PUBLIC_STREAM_TYPES = { STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC, STREAM_ALARM, STREAM_NOTIFICATION, STREAM_DTMF, STREAM_ACCESSIBILITY, }; @Rule public final AudioVolumesTestRule rule = new AudioVolumesTestRule(); Loading Loading @@ -226,18 +237,8 @@ public class AudioManagerTest { public void getStreamMinMaxVolume_consistentWithAs() throws Exception { IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); IAudioService service = IAudioService.Stub.asInterface(b); final int[] streamTypes = { STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING, STREAM_MUSIC, STREAM_ALARM, STREAM_NOTIFICATION, STREAM_DTMF, STREAM_ACCESSIBILITY, }; for (int streamType : streamTypes) { for (int streamType : PUBLIC_STREAM_TYPES) { assertEquals(service.getStreamMinVolume(streamType), mAudioManager.getStreamMinVolume(streamType)); assertEquals(service.getStreamMaxVolume(streamType), Loading @@ -245,6 +246,17 @@ public class AudioManagerTest { } } @Test public void getStreamVolume_consistentWithAs() throws Exception { IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); IAudioService service = IAudioService.Stub.asInterface(b); for (int streamType : PUBLIC_STREAM_TYPES) { assertEquals(service.getStreamVolume(streamType), mAudioManager.getStreamVolume(streamType)); } } //----------------------------------------------------------------- // Test Volume per Attributes setter/getters //----------------------------------------------------------------- Loading
services/core/java/com/android/server/audio/AudioManagerShellCommand.java +13 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,8 @@ class AudioManagerShellCommand extends ShellCommand { return getMinVolume(); case "get-max-volume": return getMaxVolume(); case "get-stream-volume": return getStreamVolume(); case "set-device-volume": return setDeviceVolume(); case "adj-mute": Loading Loading @@ -114,6 +116,8 @@ class AudioManagerShellCommand extends ShellCommand { pw.println(" Gets the min volume for STREAM_TYPE"); pw.println(" get-max-volume STREAM_TYPE"); pw.println(" Gets the max volume for STREAM_TYPE"); pw.println(" get-stream-volume STREAM_TYPE"); pw.println(" Gets the volume for STREAM_TYPE"); pw.println(" set-device-volume STREAM_TYPE VOLUME_INDEX NATIVE_DEVICE_TYPE"); pw.println(" Sets for NATIVE_DEVICE_TYPE the STREAM_TYPE volume to VOLUME_INDEX"); pw.println(" adj-mute STREAM_TYPE"); Loading Loading @@ -322,6 +326,15 @@ class AudioManagerShellCommand extends ShellCommand { return 0; } private int getStreamVolume() { final Context context = mService.mContext; final AudioManager am = context.getSystemService(AudioManager.class); final int stream = readIntArg(); final int result = am.getStreamVolume(stream); getOutPrintWriter().println("AudioManager.getStreamVolume(" + stream + ") -> " + result); return 0; } private int setDeviceVolume() { final Context context = mService.mContext; final AudioDeviceVolumeManager advm = (AudioDeviceVolumeManager) context.getSystemService( Loading
services/core/java/com/android/server/audio/AudioService.java +39 −2 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import static android.media.AudioManager.STREAM_SYSTEM; import static android.media.audio.Flags.autoPublicVolumeApiHardening; import static android.media.audio.Flags.automaticBtDeviceType; import static android.media.audio.Flags.cacheGetStreamMinMaxVolume; import static android.media.audio.Flags.cacheGetStreamVolume; import static android.media.audio.Flags.concurrentAudioRecordBypassPermission; import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency; import static android.media.audio.Flags.focusFreezeTestApi; Loading Loading @@ -1910,6 +1911,12 @@ public class AudioService extends IAudioService.Stub mSpatializerHelper.onRoutingUpdated(); } checkMuteAwaitConnection(); if (cacheGetStreamVolume()) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after routing update"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } } //----------------------------------------------------------------- Loading Loading @@ -4988,6 +4995,8 @@ public class AudioService extends IAudioService.Stub + concurrentAudioRecordBypassPermission()); pw.println("\tandroid.media.audio.Flags.cacheGetStreamMinMaxVolume:" + cacheGetStreamMinMaxVolume()); pw.println("\tandroid.media.audio.Flags.cacheGetStreamVolume:" + cacheGetStreamVolume()); } private void dumpAudioMode(PrintWriter pw) { Loading Loading @@ -7054,6 +7063,13 @@ public class AudioService extends IAudioService.Stub streamState.mIsMuted = false; } } if (cacheGetStreamVolume()) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after possibly changing mute in readAudioSettings"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } } readVolumeGroupsSettings(userSwitch); Loading Loading @@ -9274,11 +9290,23 @@ public class AudioService extends IAudioService.Stub public void put(int key, int value) { super.put(key, value); record("put", key, value); if (cacheGetStreamVolume()) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after update index map"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } } @Override public void setValueAt(int index, int value) { super.setValueAt(index, value); record("setValueAt", keyAt(index), value); if (cacheGetStreamVolume()) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after update index map"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } } // Record all changes in the VolumeStreamState Loading Loading @@ -10008,8 +10036,9 @@ public class AudioService extends IAudioService.Stub * @return true if the mute state was changed */ public boolean mute(boolean state, boolean apply, String src) { boolean changed; synchronized (VolumeStreamState.class) { boolean changed = state != mIsMuted; changed = state != mIsMuted; if (changed) { sMuteLogger.enqueue( new AudioServiceEvents.StreamMuteEvent(mStreamType, state, src)); Loading @@ -10027,8 +10056,16 @@ public class AudioService extends IAudioService.Stub doMute(); } } return changed; } if (cacheGetStreamVolume() && changed) { if (DEBUG_VOL) { Log.d(TAG, "Clear volume cache after changing mute state"); } AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API); } return changed; } public void doMute() { Loading