Loading core/jni/android_media_AudioSystem.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ static struct { static struct { jmethodID postDynPolicyEventFromNative; jmethodID postRecordConfigEventFromNative; jmethodID postRoutingUpdatedFromNative; } gAudioPolicyEventHandlerMethods; static struct { jmethodID add; } gListMethods; Loading Loading @@ -539,6 +540,21 @@ android_media_AudioSystem_recording_callback(int event, env->DeleteLocalRef(jEffects); } static void android_media_AudioSystem_routing_callback() { JNIEnv *env = AndroidRuntime::getJNIEnv(); // callback into java jclass clazz = env->FindClass(kClassPathName); if (env == NULL) { return; } env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postRoutingUpdatedFromNative); env->DeleteLocalRef(clazz); } static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name, jint codec) Loading Loading @@ -1894,6 +1910,12 @@ android_media_AudioSystem_registerRecordingCallback(JNIEnv *env, jobject thiz) AudioSystem::setRecordConfigCallback(android_media_AudioSystem_recording_callback); } static void android_media_AudioSystem_registerRoutingCallback(JNIEnv *env, jobject thiz) { AudioSystem::setRoutingCallback(android_media_AudioSystem_routing_callback); } static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, Loading Loading @@ -2579,6 +2601,8 @@ static const JNINativeMethod gMethods[] = (void *)android_media_AudioSystem_registerDynPolicyCallback}, {"native_register_recording_callback", "()V", (void *)android_media_AudioSystem_registerRecordingCallback}, {"native_register_routing_callback", "()V", (void *)android_media_AudioSystem_registerRoutingCallback}, {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady}, {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB}, {"native_get_offload_support", "(IIIII)I", Loading Loading @@ -2762,6 +2786,9 @@ int register_android_media_AudioSystem(JNIEnv *env) gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative = GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), "recordingCallbackFromNative", "(IIIIIIZ[I[Landroid/media/audiofx/AudioEffect$Descriptor;[Landroid/media/audiofx/AudioEffect$Descriptor;I)V"); gAudioPolicyEventHandlerMethods.postRoutingUpdatedFromNative = GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), "routingCallbackFromNative", "()V"); jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); Loading media/java/android/media/AudioSystem.java +40 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,8 @@ import android.telephony.TelephonyManager; import android.util.Log; import android.util.Pair; import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; Loading Loading @@ -712,6 +714,42 @@ public class AudioSystem } } /** * @hide * Handles events from the audio policy manager about routing events */ public interface RoutingUpdateCallback { /** * Callback to notify a routing update event occurred */ void onRoutingUpdated(); } @GuardedBy("AudioSystem.class") private static RoutingUpdateCallback sRoutingUpdateCallback; /** @hide */ public static void setRoutingCallback(RoutingUpdateCallback cb) { synchronized (AudioSystem.class) { sRoutingUpdateCallback = cb; native_register_routing_callback(); } } private static void routingCallbackFromNative() { final RoutingUpdateCallback cb; synchronized (AudioSystem.class) { cb = sRoutingUpdateCallback; } //### Log.i(TAG, "#################### update"); if (cb == null) { Log.e(TAG, "routing update from APM was not captured"); return; } cb.onRoutingUpdated(); } /* * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...) * Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h Loading Loading @@ -1597,6 +1635,8 @@ public class AudioSystem private static native final void native_register_dynamic_policy_callback(); // declare this instance as having a recording configuration update callback handler private static native final void native_register_recording_callback(); // declare this instance as having a routing update callback handler private static native void native_register_routing_callback(); // must be kept in sync with value in include/system/audio.h /** @hide */ public static final int AUDIO_HW_SYNC_INVALID = 0; Loading services/core/java/com/android/server/audio/AudioService.java +4 −0 Original line number Diff line number Diff line Loading @@ -3467,6 +3467,8 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#getStreamVolume(int) */ public int getStreamVolume(int streamType) { ensureValidStreamType(streamType); Log.e(TAG, "AudioSystem.getDevicesForStream In AudioService from u/pid" + Binder.getCallingUid() + "/" + Binder.getCallingPid()); int device = getDeviceForStream(streamType); synchronized (VolumeStreamState.class) { int index = mStreamStates[streamType].getIndex(device); Loading Loading @@ -7951,6 +7953,8 @@ public class AudioService extends IAudioService.Stub protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; mAudioSystem.dump(pw); sLifecycleLogger.dump(pw); if (mAudioHandler != null) { pw.println("\nMessage handler (watch for unhandled messages):"); Loading services/core/java/com/android/server/audio/AudioSystemAdapter.java +157 −4 Original line number Diff line number Diff line Loading @@ -21,9 +21,13 @@ import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioSystem; import android.media.audiopolicy.AudioMix; import android.os.SystemClock; import android.util.Log; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; /** * Provides an adapter to access functionality of the android.media.AudioSystem class for device Loading @@ -31,15 +35,79 @@ import java.util.List; * Use the "real" AudioSystem through the default adapter. * Use the "always ok" adapter to avoid dealing with the APM behaviors during a test. */ public class AudioSystemAdapter { public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { private static final String TAG = "AudioSystemAdapter"; // initialized in factory getDefaultAdapter() private static AudioSystemAdapter sSingletonDefaultAdapter; /** * should be false by default unless enabling measurements of method call counts and time spent * 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 long[] mMethodTimeNs; private int[] mMethodCallCounter; private String[] mMethodNames = {"getDevicesForStream", "getDevicesForAttributes"}; private static final boolean USE_CACHE_FOR_GETDEVICES = true; private ConcurrentHashMap<Integer, Integer> mDevicesForStreamCache; private int[] mMethodCacheHit; /** * should be false except when trying to debug caching errors. When true, the value retrieved * from the cache will be compared against the real queried value, which defeats the purpose of * the cache in terms of performance. */ private static final boolean DEBUG_CACHE = false; /** * Implementation of AudioSystem.RoutingUpdateCallback */ @Override public void onRoutingUpdated() { if (DEBUG_CACHE) { Log.d(TAG, "---- onRoutingUpdated (from native) ----------"); } invalidateRoutingCache(); } /** * Create a wrapper around the {@link AudioSystem} static methods, all functions are directly * forwarded to the AudioSystem class. * @return an adapter around AudioSystem */ static final @NonNull AudioSystemAdapter getDefaultAdapter() { return new AudioSystemAdapter(); static final synchronized @NonNull AudioSystemAdapter getDefaultAdapter() { if (sSingletonDefaultAdapter == null) { sSingletonDefaultAdapter = new AudioSystemAdapter(); AudioSystem.setRoutingCallback(sSingletonDefaultAdapter); if (USE_CACHE_FOR_GETDEVICES) { sSingletonDefaultAdapter.mDevicesForStreamCache = new ConcurrentHashMap<Integer, Integer>(AudioSystem.getNumStreamTypes()); sSingletonDefaultAdapter.mMethodCacheHit = new int[NB_MEASUREMENTS]; } if (ENABLE_GETDEVICES_STATS) { sSingletonDefaultAdapter.mMethodCallCounter = new int[NB_MEASUREMENTS]; sSingletonDefaultAdapter.mMethodTimeNs = new long[NB_MEASUREMENTS]; } } return sSingletonDefaultAdapter; } private void invalidateRoutingCache() { if (DEBUG_CACHE) { Log.d(TAG, "---- clearing cache ----------"); } if (mDevicesForStreamCache == null) { return; } synchronized (mDevicesForStreamCache) { mDevicesForStreamCache.clear(); } } /** Loading @@ -48,6 +116,44 @@ public class AudioSystemAdapter { * @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, " stream=" + stream + " dev=0x" + Integer.toHexString(res)); } return res; } // cache hit mMethodCacheHit[METHOD_GETDEVICESFORSTREAM]++; if (DEBUG_CACHE) { final int real = AudioSystem.getDevicesForStream(stream); if (res == real) { Log.d(TAG, " stream=" + stream + " dev=0x" + Integer.toHexString(res) + " CACHE"); } else { Log.e(TAG, " stream=" + stream + " dev=0x" + Integer.toHexString(res) + " CACHE ERROR real dev=0x" + Integer.toHexString(real)); } } } return res; } return AudioSystem.getDevicesForStream(stream); } Loading @@ -58,6 +164,19 @@ public class AudioSystemAdapter { */ public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes( @NonNull AudioAttributes attributes) { if (!ENABLE_GETDEVICES_STATS) { return getDevicesForAttributesImpl(attributes); } mMethodCallCounter[METHOD_GETDEVICESFORATTRIBUTES]++; final long startTime = SystemClock.uptimeNanos(); final ArrayList<AudioDeviceAttributes> res = getDevicesForAttributesImpl(attributes); mMethodTimeNs[METHOD_GETDEVICESFORATTRIBUTES] += SystemClock.uptimeNanos() - startTime; return res; } private @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesImpl( @NonNull AudioAttributes attributes) { // TODO implement caching for attributes-based routing return AudioSystem.getDevicesForAttributes(attributes); } Loading @@ -72,6 +191,7 @@ public class AudioSystemAdapter { */ public int setDeviceConnectionState(int device, int state, String deviceAddress, String deviceName, int codecFormat) { invalidateRoutingCache(); return AudioSystem.setDeviceConnectionState(device, state, deviceAddress, deviceName, codecFormat); } Loading @@ -96,6 +216,7 @@ public class AudioSystemAdapter { */ public int handleDeviceConfigChange(int device, String deviceAddress, String deviceName, int codecFormat) { invalidateRoutingCache(); return AudioSystem.handleDeviceConfigChange(device, deviceAddress, deviceName, codecFormat); } Loading @@ -109,6 +230,7 @@ public class AudioSystemAdapter { */ public int setDevicesRoleForStrategy(int strategy, int role, @NonNull List<AudioDeviceAttributes> devices) { invalidateRoutingCache(); return AudioSystem.setDevicesRoleForStrategy(strategy, role, devices); } Loading @@ -119,6 +241,7 @@ public class AudioSystemAdapter { * @return */ public int removeDevicesRoleForStrategy(int strategy, int role) { invalidateRoutingCache(); return AudioSystem.removeDevicesRoleForStrategy(strategy, role); } Loading @@ -131,11 +254,12 @@ public class AudioSystemAdapter { */ public int setDevicesRoleForCapturePreset(int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { invalidateRoutingCache(); return AudioSystem.setDevicesRoleForCapturePreset(capturePreset, role, devices); } /** * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int)} * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, int[], String[])} * @param capturePreset * @param role * @param devicesToRemove Loading @@ -143,6 +267,7 @@ public class AudioSystemAdapter { */ public int removeDevicesRoleForCapturePreset( int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) { invalidateRoutingCache(); return AudioSystem.removeDevicesRoleForCapturePreset(capturePreset, role, devicesToRemove); } Loading @@ -153,6 +278,7 @@ public class AudioSystemAdapter { * @return */ public int clearDevicesRoleForCapturePreset(int capturePreset, int role) { invalidateRoutingCache(); return AudioSystem.clearDevicesRoleForCapturePreset(capturePreset, role); } Loading Loading @@ -218,6 +344,7 @@ public class AudioSystemAdapter { * @return */ public int setPhoneState(int state, int uid) { invalidateRoutingCache(); return AudioSystem.setPhoneState(state, uid); } Loading @@ -238,6 +365,7 @@ public class AudioSystemAdapter { * @return */ public int setForceUse(int usage, int config) { invalidateRoutingCache(); return AudioSystem.setForceUse(usage, config); } Loading @@ -257,6 +385,7 @@ public class AudioSystemAdapter { * @return */ public int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register) { invalidateRoutingCache(); return AudioSystem.registerPolicyMixes(mixes, register); } Loading @@ -268,6 +397,7 @@ public class AudioSystemAdapter { * @return */ public int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) { invalidateRoutingCache(); return AudioSystem.setUidDeviceAffinities(uid, types, addresses); } Loading @@ -277,6 +407,7 @@ public class AudioSystemAdapter { * @return */ public int removeUidDeviceAffinities(int uid) { invalidateRoutingCache(); return AudioSystem.removeUidDeviceAffinities(uid); } Loading @@ -289,6 +420,7 @@ public class AudioSystemAdapter { */ public int setUserIdDeviceAffinities(int userId, @NonNull int[] types, @NonNull String[] addresses) { invalidateRoutingCache(); return AudioSystem.setUserIdDeviceAffinities(userId, types, addresses); } Loading @@ -298,6 +430,27 @@ public class AudioSystemAdapter { * @return */ public int removeUserIdDeviceAffinities(int userId) { invalidateRoutingCache(); return AudioSystem.removeUserIdDeviceAffinities(userId); } /** * Part of AudioService dump * @param pw */ public void dump(PrintWriter pw) { if (!ENABLE_GETDEVICES_STATS) { // only stats in this dump return; } pw.println("\nAudioSystemAdapter:"); for (int i = 0; i < NB_MEASUREMENTS; i++) { pw.println(mMethodNames[i] + ": counter=" + mMethodCallCounter[i] + " time(ms)=" + (mMethodTimeNs[i] / 1E6) + (USE_CACHE_FOR_GETDEVICES ? (" FScacheHit=" + mMethodCacheHit[METHOD_GETDEVICESFORSTREAM]) : "")); } pw.println("\n"); } } Loading
core/jni/android_media_AudioSystem.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ static struct { static struct { jmethodID postDynPolicyEventFromNative; jmethodID postRecordConfigEventFromNative; jmethodID postRoutingUpdatedFromNative; } gAudioPolicyEventHandlerMethods; static struct { jmethodID add; } gListMethods; Loading Loading @@ -539,6 +540,21 @@ android_media_AudioSystem_recording_callback(int event, env->DeleteLocalRef(jEffects); } static void android_media_AudioSystem_routing_callback() { JNIEnv *env = AndroidRuntime::getJNIEnv(); // callback into java jclass clazz = env->FindClass(kClassPathName); if (env == NULL) { return; } env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postRoutingUpdatedFromNative); env->DeleteLocalRef(clazz); } static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name, jint codec) Loading Loading @@ -1894,6 +1910,12 @@ android_media_AudioSystem_registerRecordingCallback(JNIEnv *env, jobject thiz) AudioSystem::setRecordConfigCallback(android_media_AudioSystem_recording_callback); } static void android_media_AudioSystem_registerRoutingCallback(JNIEnv *env, jobject thiz) { AudioSystem::setRoutingCallback(android_media_AudioSystem_routing_callback); } static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, Loading Loading @@ -2579,6 +2601,8 @@ static const JNINativeMethod gMethods[] = (void *)android_media_AudioSystem_registerDynPolicyCallback}, {"native_register_recording_callback", "()V", (void *)android_media_AudioSystem_registerRecordingCallback}, {"native_register_routing_callback", "()V", (void *)android_media_AudioSystem_registerRoutingCallback}, {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady}, {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB}, {"native_get_offload_support", "(IIIII)I", Loading Loading @@ -2762,6 +2786,9 @@ int register_android_media_AudioSystem(JNIEnv *env) gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative = GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), "recordingCallbackFromNative", "(IIIIIIZ[I[Landroid/media/audiofx/AudioEffect$Descriptor;[Landroid/media/audiofx/AudioEffect$Descriptor;I)V"); gAudioPolicyEventHandlerMethods.postRoutingUpdatedFromNative = GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), "routingCallbackFromNative", "()V"); jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); Loading
media/java/android/media/AudioSystem.java +40 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,8 @@ import android.telephony.TelephonyManager; import android.util.Log; import android.util.Pair; import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; Loading Loading @@ -712,6 +714,42 @@ public class AudioSystem } } /** * @hide * Handles events from the audio policy manager about routing events */ public interface RoutingUpdateCallback { /** * Callback to notify a routing update event occurred */ void onRoutingUpdated(); } @GuardedBy("AudioSystem.class") private static RoutingUpdateCallback sRoutingUpdateCallback; /** @hide */ public static void setRoutingCallback(RoutingUpdateCallback cb) { synchronized (AudioSystem.class) { sRoutingUpdateCallback = cb; native_register_routing_callback(); } } private static void routingCallbackFromNative() { final RoutingUpdateCallback cb; synchronized (AudioSystem.class) { cb = sRoutingUpdateCallback; } //### Log.i(TAG, "#################### update"); if (cb == null) { Log.e(TAG, "routing update from APM was not captured"); return; } cb.onRoutingUpdated(); } /* * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...) * Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h Loading Loading @@ -1597,6 +1635,8 @@ public class AudioSystem private static native final void native_register_dynamic_policy_callback(); // declare this instance as having a recording configuration update callback handler private static native final void native_register_recording_callback(); // declare this instance as having a routing update callback handler private static native void native_register_routing_callback(); // must be kept in sync with value in include/system/audio.h /** @hide */ public static final int AUDIO_HW_SYNC_INVALID = 0; Loading
services/core/java/com/android/server/audio/AudioService.java +4 −0 Original line number Diff line number Diff line Loading @@ -3467,6 +3467,8 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#getStreamVolume(int) */ public int getStreamVolume(int streamType) { ensureValidStreamType(streamType); Log.e(TAG, "AudioSystem.getDevicesForStream In AudioService from u/pid" + Binder.getCallingUid() + "/" + Binder.getCallingPid()); int device = getDeviceForStream(streamType); synchronized (VolumeStreamState.class) { int index = mStreamStates[streamType].getIndex(device); Loading Loading @@ -7951,6 +7953,8 @@ public class AudioService extends IAudioService.Stub protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; mAudioSystem.dump(pw); sLifecycleLogger.dump(pw); if (mAudioHandler != null) { pw.println("\nMessage handler (watch for unhandled messages):"); Loading
services/core/java/com/android/server/audio/AudioSystemAdapter.java +157 −4 Original line number Diff line number Diff line Loading @@ -21,9 +21,13 @@ import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioSystem; import android.media.audiopolicy.AudioMix; import android.os.SystemClock; import android.util.Log; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; /** * Provides an adapter to access functionality of the android.media.AudioSystem class for device Loading @@ -31,15 +35,79 @@ import java.util.List; * Use the "real" AudioSystem through the default adapter. * Use the "always ok" adapter to avoid dealing with the APM behaviors during a test. */ public class AudioSystemAdapter { public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback { private static final String TAG = "AudioSystemAdapter"; // initialized in factory getDefaultAdapter() private static AudioSystemAdapter sSingletonDefaultAdapter; /** * should be false by default unless enabling measurements of method call counts and time spent * 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 long[] mMethodTimeNs; private int[] mMethodCallCounter; private String[] mMethodNames = {"getDevicesForStream", "getDevicesForAttributes"}; private static final boolean USE_CACHE_FOR_GETDEVICES = true; private ConcurrentHashMap<Integer, Integer> mDevicesForStreamCache; private int[] mMethodCacheHit; /** * should be false except when trying to debug caching errors. When true, the value retrieved * from the cache will be compared against the real queried value, which defeats the purpose of * the cache in terms of performance. */ private static final boolean DEBUG_CACHE = false; /** * Implementation of AudioSystem.RoutingUpdateCallback */ @Override public void onRoutingUpdated() { if (DEBUG_CACHE) { Log.d(TAG, "---- onRoutingUpdated (from native) ----------"); } invalidateRoutingCache(); } /** * Create a wrapper around the {@link AudioSystem} static methods, all functions are directly * forwarded to the AudioSystem class. * @return an adapter around AudioSystem */ static final @NonNull AudioSystemAdapter getDefaultAdapter() { return new AudioSystemAdapter(); static final synchronized @NonNull AudioSystemAdapter getDefaultAdapter() { if (sSingletonDefaultAdapter == null) { sSingletonDefaultAdapter = new AudioSystemAdapter(); AudioSystem.setRoutingCallback(sSingletonDefaultAdapter); if (USE_CACHE_FOR_GETDEVICES) { sSingletonDefaultAdapter.mDevicesForStreamCache = new ConcurrentHashMap<Integer, Integer>(AudioSystem.getNumStreamTypes()); sSingletonDefaultAdapter.mMethodCacheHit = new int[NB_MEASUREMENTS]; } if (ENABLE_GETDEVICES_STATS) { sSingletonDefaultAdapter.mMethodCallCounter = new int[NB_MEASUREMENTS]; sSingletonDefaultAdapter.mMethodTimeNs = new long[NB_MEASUREMENTS]; } } return sSingletonDefaultAdapter; } private void invalidateRoutingCache() { if (DEBUG_CACHE) { Log.d(TAG, "---- clearing cache ----------"); } if (mDevicesForStreamCache == null) { return; } synchronized (mDevicesForStreamCache) { mDevicesForStreamCache.clear(); } } /** Loading @@ -48,6 +116,44 @@ public class AudioSystemAdapter { * @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, " stream=" + stream + " dev=0x" + Integer.toHexString(res)); } return res; } // cache hit mMethodCacheHit[METHOD_GETDEVICESFORSTREAM]++; if (DEBUG_CACHE) { final int real = AudioSystem.getDevicesForStream(stream); if (res == real) { Log.d(TAG, " stream=" + stream + " dev=0x" + Integer.toHexString(res) + " CACHE"); } else { Log.e(TAG, " stream=" + stream + " dev=0x" + Integer.toHexString(res) + " CACHE ERROR real dev=0x" + Integer.toHexString(real)); } } } return res; } return AudioSystem.getDevicesForStream(stream); } Loading @@ -58,6 +164,19 @@ public class AudioSystemAdapter { */ public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes( @NonNull AudioAttributes attributes) { if (!ENABLE_GETDEVICES_STATS) { return getDevicesForAttributesImpl(attributes); } mMethodCallCounter[METHOD_GETDEVICESFORATTRIBUTES]++; final long startTime = SystemClock.uptimeNanos(); final ArrayList<AudioDeviceAttributes> res = getDevicesForAttributesImpl(attributes); mMethodTimeNs[METHOD_GETDEVICESFORATTRIBUTES] += SystemClock.uptimeNanos() - startTime; return res; } private @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesImpl( @NonNull AudioAttributes attributes) { // TODO implement caching for attributes-based routing return AudioSystem.getDevicesForAttributes(attributes); } Loading @@ -72,6 +191,7 @@ public class AudioSystemAdapter { */ public int setDeviceConnectionState(int device, int state, String deviceAddress, String deviceName, int codecFormat) { invalidateRoutingCache(); return AudioSystem.setDeviceConnectionState(device, state, deviceAddress, deviceName, codecFormat); } Loading @@ -96,6 +216,7 @@ public class AudioSystemAdapter { */ public int handleDeviceConfigChange(int device, String deviceAddress, String deviceName, int codecFormat) { invalidateRoutingCache(); return AudioSystem.handleDeviceConfigChange(device, deviceAddress, deviceName, codecFormat); } Loading @@ -109,6 +230,7 @@ public class AudioSystemAdapter { */ public int setDevicesRoleForStrategy(int strategy, int role, @NonNull List<AudioDeviceAttributes> devices) { invalidateRoutingCache(); return AudioSystem.setDevicesRoleForStrategy(strategy, role, devices); } Loading @@ -119,6 +241,7 @@ public class AudioSystemAdapter { * @return */ public int removeDevicesRoleForStrategy(int strategy, int role) { invalidateRoutingCache(); return AudioSystem.removeDevicesRoleForStrategy(strategy, role); } Loading @@ -131,11 +254,12 @@ public class AudioSystemAdapter { */ public int setDevicesRoleForCapturePreset(int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { invalidateRoutingCache(); return AudioSystem.setDevicesRoleForCapturePreset(capturePreset, role, devices); } /** * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int)} * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, int[], String[])} * @param capturePreset * @param role * @param devicesToRemove Loading @@ -143,6 +267,7 @@ public class AudioSystemAdapter { */ public int removeDevicesRoleForCapturePreset( int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) { invalidateRoutingCache(); return AudioSystem.removeDevicesRoleForCapturePreset(capturePreset, role, devicesToRemove); } Loading @@ -153,6 +278,7 @@ public class AudioSystemAdapter { * @return */ public int clearDevicesRoleForCapturePreset(int capturePreset, int role) { invalidateRoutingCache(); return AudioSystem.clearDevicesRoleForCapturePreset(capturePreset, role); } Loading Loading @@ -218,6 +344,7 @@ public class AudioSystemAdapter { * @return */ public int setPhoneState(int state, int uid) { invalidateRoutingCache(); return AudioSystem.setPhoneState(state, uid); } Loading @@ -238,6 +365,7 @@ public class AudioSystemAdapter { * @return */ public int setForceUse(int usage, int config) { invalidateRoutingCache(); return AudioSystem.setForceUse(usage, config); } Loading @@ -257,6 +385,7 @@ public class AudioSystemAdapter { * @return */ public int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register) { invalidateRoutingCache(); return AudioSystem.registerPolicyMixes(mixes, register); } Loading @@ -268,6 +397,7 @@ public class AudioSystemAdapter { * @return */ public int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) { invalidateRoutingCache(); return AudioSystem.setUidDeviceAffinities(uid, types, addresses); } Loading @@ -277,6 +407,7 @@ public class AudioSystemAdapter { * @return */ public int removeUidDeviceAffinities(int uid) { invalidateRoutingCache(); return AudioSystem.removeUidDeviceAffinities(uid); } Loading @@ -289,6 +420,7 @@ public class AudioSystemAdapter { */ public int setUserIdDeviceAffinities(int userId, @NonNull int[] types, @NonNull String[] addresses) { invalidateRoutingCache(); return AudioSystem.setUserIdDeviceAffinities(userId, types, addresses); } Loading @@ -298,6 +430,27 @@ public class AudioSystemAdapter { * @return */ public int removeUserIdDeviceAffinities(int userId) { invalidateRoutingCache(); return AudioSystem.removeUserIdDeviceAffinities(userId); } /** * Part of AudioService dump * @param pw */ public void dump(PrintWriter pw) { if (!ENABLE_GETDEVICES_STATS) { // only stats in this dump return; } pw.println("\nAudioSystemAdapter:"); for (int i = 0; i < NB_MEASUREMENTS; i++) { pw.println(mMethodNames[i] + ": counter=" + mMethodCallCounter[i] + " time(ms)=" + (mMethodTimeNs[i] / 1E6) + (USE_CACHE_FOR_GETDEVICES ? (" FScacheHit=" + mMethodCacheHit[METHOD_GETDEVICESFORSTREAM]) : "")); } pw.println("\n"); } }