diff options
4 files changed, 103 insertions, 19 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index aa3dbda374be..71013f7f4e34 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -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; @@ -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<>() { @@ -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; @@ -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 {} @@ -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"; }; } @@ -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); diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java index 017a1029d35c..209734ca4a53 100644 --- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java +++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioManagerTest.java @@ -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(); @@ -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), @@ -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 //----------------------------------------------------------------- diff --git a/services/core/java/com/android/server/audio/AudioManagerShellCommand.java b/services/core/java/com/android/server/audio/AudioManagerShellCommand.java index c35f4fca6edd..fece7a899f0a 100644 --- a/services/core/java/com/android/server/audio/AudioManagerShellCommand.java +++ b/services/core/java/com/android/server/audio/AudioManagerShellCommand.java @@ -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": @@ -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"); @@ -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( diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 1baded86705e..ddce8c7051ea 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -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; @@ -1890,6 +1891,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); + } } //----------------------------------------------------------------- @@ -4968,6 +4975,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) { @@ -7034,6 +7043,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); @@ -9254,11 +9270,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 @@ -9988,8 +10016,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)); @@ -10007,8 +10036,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() { |