• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.audio;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.media.AudioAttributes;
22 import android.media.AudioDeviceAttributes;
23 import android.media.AudioMixerAttributes;
24 import android.media.AudioSystem;
25 import android.media.IDevicesForAttributesCallback;
26 import android.media.INativeAudioVolumeGroupCallback;
27 import android.media.ISoundDose;
28 import android.media.ISoundDoseCallback;
29 import android.media.audiopolicy.AudioMix;
30 import android.media.audiopolicy.AudioMixingRule;
31 import android.media.audiopolicy.Flags;
32 import android.os.IBinder;
33 import android.os.RemoteCallbackList;
34 import android.os.RemoteException;
35 import android.os.SystemClock;
36 import android.util.ArrayMap;
37 import android.util.Log;
38 import android.util.Pair;
39 
40 import com.android.internal.annotations.GuardedBy;
41 
42 import java.io.PrintWriter;
43 import java.time.Instant;
44 import java.time.ZoneId;
45 import java.time.format.DateTimeFormatter;
46 import java.util.ArrayList;
47 import java.util.Collections;
48 import java.util.List;
49 import java.util.Locale;
50 import java.util.Map;
51 import java.util.concurrent.ConcurrentHashMap;
52 
53 /**
54  * Provides an adapter to access functionality of the android.media.AudioSystem class for device
55  * related functionality.
56  * Use the "real" AudioSystem through the default adapter.
57  * Use the "always ok" adapter to avoid dealing with the APM behaviors during a test.
58  */
59 public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
60         AudioSystem.VolumeRangeInitRequestCallback {
61 
62     private static final String TAG = "AudioSystemAdapter";
63 
64     // initialized in factory getDefaultAdapter()
65     private static AudioSystemAdapter sSingletonDefaultAdapter;
66 
67     /**
68      * should be false by default unless enabling measurements of method call counts and time spent
69      * in measured methods
70      */
71     private static final boolean ENABLE_GETDEVICES_STATS = false;
72     private static final int NB_MEASUREMENTS = 1;
73     private static final int METHOD_GETDEVICESFORATTRIBUTES = 0;
74     private long[] mMethodTimeNs;
75     private int[] mMethodCallCounter;
76     private String[] mMethodNames = {"getDevicesForAttributes"};
77 
78     private static final boolean USE_CACHE_FOR_GETDEVICES = true;
79     private static final Object sDeviceCacheLock = new Object();
80     private ConcurrentHashMap<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>>
81             mLastDevicesForAttr = new ConcurrentHashMap<>();
82     @GuardedBy("sDeviceCacheLock")
83     private ConcurrentHashMap<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>>
84             mDevicesForAttrCache;
85     @GuardedBy("sDeviceCacheLock")
86     private long mDevicesForAttributesCacheClearTimeMs = System.currentTimeMillis();
87     private int[] mMethodCacheHit;
88     /**
89      * Map that stores all attributes + forVolume pairs that are registered for
90      * routing change callback. The key is the {@link IBinder} that corresponds
91      * to the remote callback.
92      */
93     private final ArrayMap<IBinder, List<Pair<AudioAttributes, Boolean>>> mRegisteredAttributesMap =
94             new ArrayMap<>();
95     private final RemoteCallbackList<IDevicesForAttributesCallback>
96             mDevicesForAttributesCallbacks = new RemoteCallbackList<>();
97 
98     private static final Object sRoutingListenerLock = new Object();
99     @GuardedBy("sRoutingListenerLock")
100     private static @Nullable OnRoutingUpdatedListener sRoutingListener;
101     private static final Object sVolRangeInitReqListenerLock = new Object();
102     @GuardedBy("sVolRangeInitReqListenerLock")
103     private static @Nullable OnVolRangeInitRequestListener sVolRangeInitReqListener;
104 
105     /**
106      * should be false except when trying to debug caching errors. When true, the value retrieved
107      * from the cache will be compared against the real queried value, which defeats the purpose of
108      * the cache in terms of performance.
109      */
110     private static final boolean DEBUG_CACHE = false;
111 
112     /**
113      * Implementation of AudioSystem.RoutingUpdateCallback
114      */
115     @Override
onRoutingUpdated()116     public void onRoutingUpdated() {
117         if (DEBUG_CACHE) {
118             Log.d(TAG, "---- onRoutingUpdated (from native) ----------");
119         }
120         invalidateRoutingCache();
121         final OnRoutingUpdatedListener listener;
122         synchronized (sRoutingListenerLock) {
123             listener = sRoutingListener;
124         }
125         if (listener != null) {
126             listener.onRoutingUpdatedFromNative();
127         }
128 
129         synchronized (mRegisteredAttributesMap) {
130             final int nbCallbacks = mDevicesForAttributesCallbacks.beginBroadcast();
131 
132             for (int i = 0; i < nbCallbacks; i++) {
133                 IDevicesForAttributesCallback cb =
134                         mDevicesForAttributesCallbacks.getBroadcastItem(i);
135                 List<Pair<AudioAttributes, Boolean>> attrList =
136                         mRegisteredAttributesMap.get(cb.asBinder());
137 
138                 if (attrList == null) {
139                     throw new IllegalStateException("Attribute list must not be null");
140                 }
141 
142                 for (Pair<AudioAttributes, Boolean> attr : attrList) {
143                     ArrayList<AudioDeviceAttributes> devices =
144                             getDevicesForAttributes(attr.first, attr.second);
145                     if (!mLastDevicesForAttr.containsKey(attr)
146                             || !sameDeviceList(devices, mLastDevicesForAttr.get(attr))) {
147                         try {
148                             cb.onDevicesForAttributesChanged(
149                                     attr.first, attr.second, devices);
150                         } catch (RemoteException e) { }
151                     }
152                 }
153             }
154             mDevicesForAttributesCallbacks.finishBroadcast();
155         }
156     }
157 
158     interface OnRoutingUpdatedListener {
onRoutingUpdatedFromNative()159         void onRoutingUpdatedFromNative();
160     }
161 
setRoutingListener(@ullable OnRoutingUpdatedListener listener)162     static void setRoutingListener(@Nullable OnRoutingUpdatedListener listener) {
163         synchronized (sRoutingListenerLock) {
164             sRoutingListener = listener;
165         }
166     }
167 
168     /**
169      * Empties the routing cache if enabled.
170      */
clearRoutingCache()171     public void clearRoutingCache() {
172         if (DEBUG_CACHE) {
173             Log.d(TAG, "---- routing cache clear (from java) ----------");
174         }
175         invalidateRoutingCache();
176     }
177 
178     /**
179      * @see AudioManager#addOnDevicesForAttributesChangedListener(
180      *      AudioAttributes, Executor, OnDevicesForAttributesChangedListener)
181      */
addOnDevicesForAttributesChangedListener(AudioAttributes attributes, boolean forVolume, @NonNull IDevicesForAttributesCallback listener)182     public void addOnDevicesForAttributesChangedListener(AudioAttributes attributes,
183             boolean forVolume, @NonNull IDevicesForAttributesCallback listener) {
184         List<Pair<AudioAttributes, Boolean>> res;
185         final Pair<AudioAttributes, Boolean> attr = new Pair(attributes, forVolume);
186         synchronized (mRegisteredAttributesMap) {
187             res = mRegisteredAttributesMap.get(listener.asBinder());
188             if (res == null) {
189                 res = new ArrayList<>();
190                 mRegisteredAttributesMap.put(listener.asBinder(), res);
191                 mDevicesForAttributesCallbacks.register(listener);
192             }
193 
194             if (!res.contains(attr)) {
195                 res.add(attr);
196             }
197         }
198 
199         // Make query on registration to populate cache
200         getDevicesForAttributes(attributes, forVolume);
201     }
202 
203     /**
204      * @see AudioManager#removeOnDevicesForAttributesChangedListener(
205      *      OnDevicesForAttributesChangedListener)
206      */
removeOnDevicesForAttributesChangedListener( @onNull IDevicesForAttributesCallback listener)207     public void removeOnDevicesForAttributesChangedListener(
208             @NonNull IDevicesForAttributesCallback listener) {
209         synchronized (mRegisteredAttributesMap) {
210             if (!mRegisteredAttributesMap.containsKey(listener.asBinder())) {
211                 Log.w(TAG, "listener to be removed is not found.");
212                 return;
213             }
214             mRegisteredAttributesMap.remove(listener.asBinder());
215             mDevicesForAttributesCallbacks.unregister(listener);
216         }
217     }
218 
219     /**
220      * Helper function to compare lists of {@link AudioDeviceAttributes}
221      * @return true if the two lists contains the same devices, false otherwise.
222      */
sameDeviceList(@onNull List<AudioDeviceAttributes> a, @NonNull List<AudioDeviceAttributes> b)223     private boolean sameDeviceList(@NonNull List<AudioDeviceAttributes> a,
224             @NonNull List<AudioDeviceAttributes> b) {
225         for (AudioDeviceAttributes device : a) {
226             if (!b.contains(device)) {
227                 return false;
228             }
229         }
230         for (AudioDeviceAttributes device : b) {
231             if (!a.contains(device)) {
232                 return false;
233             }
234         }
235         return true;
236     }
237 
238     /**
239      * Implementation of AudioSystem.VolumeRangeInitRequestCallback
240      */
241     @Override
onVolumeRangeInitializationRequested()242     public void onVolumeRangeInitializationRequested() {
243         final OnVolRangeInitRequestListener listener;
244         synchronized (sVolRangeInitReqListenerLock) {
245             listener = sVolRangeInitReqListener;
246         }
247         if (listener != null) {
248             listener.onVolumeRangeInitRequestFromNative();
249         }
250     }
251 
252     interface OnVolRangeInitRequestListener {
onVolumeRangeInitRequestFromNative()253         void onVolumeRangeInitRequestFromNative();
254     }
255 
setVolRangeInitReqListener(@ullable OnVolRangeInitRequestListener listener)256     static void setVolRangeInitReqListener(@Nullable OnVolRangeInitRequestListener listener) {
257         synchronized (sVolRangeInitReqListenerLock) {
258             sVolRangeInitReqListener = listener;
259         }
260     }
261 
262     /**
263      * Create a wrapper around the {@link AudioSystem} static methods, all functions are directly
264      * forwarded to the AudioSystem class.
265      * @return an adapter around AudioSystem
266      */
getDefaultAdapter()267     static final synchronized @NonNull AudioSystemAdapter getDefaultAdapter() {
268         if (sSingletonDefaultAdapter == null) {
269             sSingletonDefaultAdapter = new AudioSystemAdapter();
270             AudioSystem.setRoutingCallback(sSingletonDefaultAdapter);
271             AudioSystem.setVolumeRangeInitRequestCallback(sSingletonDefaultAdapter);
272             if (USE_CACHE_FOR_GETDEVICES) {
273                 synchronized (sDeviceCacheLock) {
274                     sSingletonDefaultAdapter.mDevicesForAttrCache =
275                             new ConcurrentHashMap<>(AudioSystem.getNumStreamTypes());
276                     sSingletonDefaultAdapter.mMethodCacheHit = new int[NB_MEASUREMENTS];
277                 }
278             }
279             if (ENABLE_GETDEVICES_STATS) {
280                 sSingletonDefaultAdapter.mMethodCallCounter = new int[NB_MEASUREMENTS];
281                 sSingletonDefaultAdapter.mMethodTimeNs = new long[NB_MEASUREMENTS];
282             }
283         }
284         return sSingletonDefaultAdapter;
285     }
286 
invalidateRoutingCache()287     private void invalidateRoutingCache() {
288         if (DEBUG_CACHE) {
289             Log.d(TAG, "---- clearing cache ----------");
290         }
291         synchronized (sDeviceCacheLock) {
292             if (mDevicesForAttrCache != null) {
293                 mDevicesForAttributesCacheClearTimeMs = System.currentTimeMillis();
294                 // Save latest cache to determine routing updates
295                 mLastDevicesForAttr.putAll(mDevicesForAttrCache);
296 
297                 mDevicesForAttrCache.clear();
298             }
299         }
300     }
301 
302     /**
303      * Same as {@link AudioSystem#getDevicesForAttributes(AudioAttributes)}
304      * @param attributes the attributes for which the routing is queried
305      * @return the devices that the stream with the given attributes would be routed to
306      */
getDevicesForAttributes( @onNull AudioAttributes attributes, boolean forVolume)307     public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
308             @NonNull AudioAttributes attributes, boolean forVolume) {
309         if (!ENABLE_GETDEVICES_STATS) {
310             return getDevicesForAttributesImpl(attributes, forVolume);
311         }
312         mMethodCallCounter[METHOD_GETDEVICESFORATTRIBUTES]++;
313         final long startTime = SystemClock.uptimeNanos();
314         final ArrayList<AudioDeviceAttributes> res = getDevicesForAttributesImpl(
315                 attributes, forVolume);
316         mMethodTimeNs[METHOD_GETDEVICESFORATTRIBUTES] += SystemClock.uptimeNanos() - startTime;
317         return res;
318     }
319 
getDevicesForAttributesImpl( @onNull AudioAttributes attributes, boolean forVolume)320     private @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesImpl(
321             @NonNull AudioAttributes attributes, boolean forVolume) {
322         if (USE_CACHE_FOR_GETDEVICES) {
323             ArrayList<AudioDeviceAttributes> res;
324             final Pair<AudioAttributes, Boolean> key = new Pair(attributes, forVolume);
325             synchronized (sDeviceCacheLock) {
326                 res = mDevicesForAttrCache.get(key);
327                 if (res == null) {
328                     res = AudioSystem.getDevicesForAttributes(attributes, forVolume);
329                     mDevicesForAttrCache.put(key, res);
330                     if (DEBUG_CACHE) {
331                         Log.d(TAG, mMethodNames[METHOD_GETDEVICESFORATTRIBUTES]
332                                 + attrDeviceToDebugString(attributes, res));
333                     }
334                     return res;
335                 }
336                 // cache hit
337                 mMethodCacheHit[METHOD_GETDEVICESFORATTRIBUTES]++;
338                 if (DEBUG_CACHE) {
339                     final ArrayList<AudioDeviceAttributes> real =
340                             AudioSystem.getDevicesForAttributes(attributes, forVolume);
341                     if (res.equals(real)) {
342                         Log.d(TAG, mMethodNames[METHOD_GETDEVICESFORATTRIBUTES]
343                                 + attrDeviceToDebugString(attributes, res) + " CACHE");
344                     } else {
345                         Log.e(TAG, mMethodNames[METHOD_GETDEVICESFORATTRIBUTES]
346                                 + attrDeviceToDebugString(attributes, res)
347                                 + " CACHE ERROR real:" + attrDeviceToDebugString(attributes, real));
348                     }
349                 }
350             }
351             return res;
352         }
353         // not using cache
354         return AudioSystem.getDevicesForAttributes(attributes, forVolume);
355     }
356 
attrDeviceToDebugString(@onNull AudioAttributes attr, @NonNull List<AudioDeviceAttributes> devices)357     private static String attrDeviceToDebugString(@NonNull AudioAttributes attr,
358             @NonNull List<AudioDeviceAttributes> devices) {
359         return " attrUsage=" + attr.getSystemUsage() + " "
360                 + AudioSystem.deviceSetToString(AudioSystem.generateAudioDeviceTypesSet(devices));
361     }
362 
363     /**
364      * Same as {@link AudioSystem#setDeviceConnectionState(AudioDeviceAttributes, int, int)}
365      * @param attributes
366      * @param state
367      * @param codecFormat
368      * @return
369      */
setDeviceConnectionState(AudioDeviceAttributes attributes, int state, int codecFormat, boolean deviceSwitch)370     public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
371             int codecFormat, boolean deviceSwitch) {
372         invalidateRoutingCache();
373         return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat, deviceSwitch);
374     }
375 
376     /**
377      * Same as {@link AudioSystem#getDeviceConnectionState(int, String)}
378      * @param device
379      * @param deviceAddress
380      * @return
381      */
getDeviceConnectionState(int device, String deviceAddress)382     public int getDeviceConnectionState(int device, String deviceAddress) {
383         return AudioSystem.getDeviceConnectionState(device, deviceAddress);
384     }
385 
386     /**
387      * Same as {@link AudioSystem#handleDeviceConfigChange(int, String, String, int)}
388      * @param device
389      * @param deviceAddress
390      * @param deviceName
391      * @param codecFormat
392      * @return
393      */
handleDeviceConfigChange(int device, String deviceAddress, String deviceName, int codecFormat)394     public int handleDeviceConfigChange(int device, String deviceAddress,
395                                                String deviceName, int codecFormat) {
396         invalidateRoutingCache();
397         return AudioSystem.handleDeviceConfigChange(device, deviceAddress, deviceName,
398                 codecFormat);
399     }
400 
401     /**
402      * Same as {@link AudioSystem#setDevicesRoleForStrategy(int, int, List)}
403      * @param strategy
404      * @param role
405      * @param devices
406      * @return
407      */
setDevicesRoleForStrategy(int strategy, int role, @NonNull List<AudioDeviceAttributes> devices)408     public int setDevicesRoleForStrategy(int strategy, int role,
409                                          @NonNull List<AudioDeviceAttributes> devices) {
410         invalidateRoutingCache();
411         return AudioSystem.setDevicesRoleForStrategy(strategy, role, devices);
412     }
413 
414     /**
415      * Same as {@link AudioSystem#removeDevicesRoleForStrategy(int, int, List)}
416      * @param strategy
417      * @param role
418      * @param devices
419      * @return
420      */
removeDevicesRoleForStrategy(int strategy, int role, @NonNull List<AudioDeviceAttributes> devices)421     public int removeDevicesRoleForStrategy(int strategy, int role,
422                                             @NonNull List<AudioDeviceAttributes> devices) {
423         invalidateRoutingCache();
424         return AudioSystem.removeDevicesRoleForStrategy(strategy, role, devices);
425     }
426 
427     /**
428      * Same as {@link AudioSystem#clearDevicesRoleForStrategy(int, int)}
429      * @param strategy
430      * @param role
431      * @return
432      */
clearDevicesRoleForStrategy(int strategy, int role)433     public int clearDevicesRoleForStrategy(int strategy, int role) {
434         invalidateRoutingCache();
435         return AudioSystem.clearDevicesRoleForStrategy(strategy, role);
436     }
437 
438     /**
439      * Same as (@link AudioSystem#setDevicesRoleForCapturePreset(int, List))
440      * @param capturePreset
441      * @param role
442      * @param devices
443      * @return
444      */
setDevicesRoleForCapturePreset(int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices)445     public int setDevicesRoleForCapturePreset(int capturePreset, int role,
446                                               @NonNull List<AudioDeviceAttributes> devices) {
447         invalidateRoutingCache();
448         return AudioSystem.setDevicesRoleForCapturePreset(capturePreset, role, devices);
449     }
450 
451     /**
452      * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int, List)}
453      * @param capturePreset
454      * @param role
455      * @param devicesToRemove
456      * @return
457      */
removeDevicesRoleForCapturePreset( int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove)458     public int removeDevicesRoleForCapturePreset(
459             int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) {
460         invalidateRoutingCache();
461         return AudioSystem.removeDevicesRoleForCapturePreset(capturePreset, role, devicesToRemove);
462     }
463 
464     /**
465      * Same as {@link AudioSystem#addDevicesRoleForCapturePreset(int, int, List)}
466      * @param capturePreset the capture preset to configure
467      * @param role the role of the devices
468      * @param devices the list of devices to be added as role for the given capture preset
469      * @return {@link #SUCCESS} if successfully added
470      */
addDevicesRoleForCapturePreset( int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices)471     public int addDevicesRoleForCapturePreset(
472             int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) {
473         invalidateRoutingCache();
474         return AudioSystem.addDevicesRoleForCapturePreset(capturePreset, role, devices);
475     }
476 
477     /**
478      * Same as {@link AudioSystem#}
479      * @param capturePreset
480      * @param role
481      * @return
482      */
clearDevicesRoleForCapturePreset(int capturePreset, int role)483     public int clearDevicesRoleForCapturePreset(int capturePreset, int role) {
484         invalidateRoutingCache();
485         return AudioSystem.clearDevicesRoleForCapturePreset(capturePreset, role);
486     }
487 
488     /**
489      * Same as {@link AudioSystem#setParameters(String)}
490      * @param keyValuePairs
491      * @return
492      */
setParameters(String keyValuePairs)493     public int setParameters(String keyValuePairs) {
494         invalidateRoutingCache();
495         return AudioSystem.setParameters(keyValuePairs);
496     }
497 
498     /**
499      * Same as {@link AudioSystem#isMicrophoneMuted()}}
500      * Checks whether the microphone mute is on or off.
501      * @return true if microphone is muted, false if it's not
502      */
isMicrophoneMuted()503     public boolean isMicrophoneMuted() {
504         return AudioSystem.isMicrophoneMuted();
505     }
506 
507     /**
508      * Same as {@link AudioSystem#muteMicrophone(boolean)}
509      * Sets the microphone mute on or off.
510      *
511      * @param on set <var>true</var> to mute the microphone;
512      *           <var>false</var> to turn mute off
513      * @return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR
514      */
muteMicrophone(boolean on)515     public int muteMicrophone(boolean on) {
516         return AudioSystem.muteMicrophone(on);
517     }
518 
519     /**
520      * Same as {@link AudioSystem#setCurrentImeUid(int)}
521      * Communicate UID of current InputMethodService to audio policy service.
522      */
setCurrentImeUid(int uid)523     public int setCurrentImeUid(int uid) {
524         return AudioSystem.setCurrentImeUid(uid);
525     }
526 
527     /**
528      * Same as {@link AudioSystem#isStreamActive(int, int)}
529      */
isStreamActive(int stream, int inPastMs)530     public boolean isStreamActive(int stream, int inPastMs) {
531         return AudioSystem.isStreamActive(stream, inPastMs);
532     }
533 
534     /**
535      * Same as {@link AudioSystem#isStreamActiveRemotely(int, int)}
536      * @param stream
537      * @param inPastMs
538      * @return
539      */
isStreamActiveRemotely(int stream, int inPastMs)540     public boolean isStreamActiveRemotely(int stream, int inPastMs) {
541         return AudioSystem.isStreamActiveRemotely(stream, inPastMs);
542     }
543 
544     /**
545      * Same as {@link AudioSystem#setStreamVolumeIndexAS(int, int, int)}
546      * @param stream
547      * @param index
548      * @param device
549      * @return
550      */
setStreamVolumeIndexAS(int stream, int index, boolean muted, int device)551     public int setStreamVolumeIndexAS(int stream, int index, boolean muted, int device) {
552         return AudioSystem.setStreamVolumeIndexAS(stream, index, muted, device);
553     }
554 
555     /** Same as {@link AudioSystem#setVolumeIndexForAttributes(AudioAttributes, int, int)} */
setVolumeIndexForAttributes(AudioAttributes attributes, int index, boolean muted, int device)556     public int setVolumeIndexForAttributes(AudioAttributes attributes, int index, boolean muted,
557             int device) {
558         return AudioSystem.setVolumeIndexForAttributes(attributes, index, muted, device);
559     }
560 
561     /**
562      * Same as {@link AudioSystem#setPhoneState(int, int)}
563      * @param state
564      * @param uid
565      * @return
566      */
setPhoneState(int state, int uid)567     public int setPhoneState(int state, int uid) {
568         invalidateRoutingCache();
569         return AudioSystem.setPhoneState(state, uid);
570     }
571 
572     /**
573      * Same as {@link AudioSystem#setAllowedCapturePolicy(int, int)}
574      * @param uid
575      * @param flags
576      * @return
577      */
setAllowedCapturePolicy(int uid, int flags)578     public int setAllowedCapturePolicy(int uid, int flags) {
579         return AudioSystem.setAllowedCapturePolicy(uid, flags);
580     }
581 
582     /**
583      * Same as {@link AudioSystem#setForceUse(int, int)}
584      * @param usage
585      * @param config
586      * @return
587      */
setForceUse(int usage, int config)588     public int setForceUse(int usage, int config) {
589         invalidateRoutingCache();
590         return AudioSystem.setForceUse(usage, config);
591     }
592 
593     /**
594      * Same as {@link AudioSystem#getForceUse(int)}
595      * @param usage
596      * @return
597      */
getForceUse(int usage)598     public int getForceUse(int usage) {
599         return AudioSystem.getForceUse(usage);
600     }
601 
602     /**
603      * Same as {@link AudioSystem#setDeviceAbsoluteVolumeEnabled(int, String, boolean, int)}
604      * @param nativeDeviceType the internal device type for which absolute volume is
605      *                         enabled/disabled
606      * @param address the address of the device for which absolute volume is enabled/disabled
607      * @param enabled whether the absolute volume is enabled/disabled
608      * @param streamToDriveAbs the stream that is controlling the absolute volume
609      * @return status of indicating the success of this operation
610      */
setDeviceAbsoluteVolumeEnabled(int nativeDeviceType, @NonNull String address, boolean enabled, int streamToDriveAbs)611     public int setDeviceAbsoluteVolumeEnabled(int nativeDeviceType, @NonNull String address,
612             boolean enabled, int streamToDriveAbs) {
613         return AudioSystem.setDeviceAbsoluteVolumeEnabled(nativeDeviceType, address, enabled,
614                 streamToDriveAbs);
615     }
616 
617     /**
618      * Same as {@link AudioSystem#registerPolicyMixes(ArrayList, boolean)}
619      * @param mixes
620      * @param register
621      * @return
622      */
registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register)623     public int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register) {
624         invalidateRoutingCache();
625         return AudioSystem.registerPolicyMixes(mixes, register);
626     }
627 
628     /**
629      * @return a list of AudioMixes that are registered in the audio policy manager.
630      */
getRegisteredPolicyMixes()631     public List<AudioMix> getRegisteredPolicyMixes() {
632         if (!Flags.audioMixTestApi()) {
633             return Collections.emptyList();
634         }
635 
636         List<AudioMix> audioMixes = new ArrayList<>();
637         int result = AudioSystem.getRegisteredPolicyMixes(audioMixes);
638         if (result != AudioSystem.SUCCESS) {
639             throw new IllegalStateException(
640                     "Cannot fetch registered policy mixes. Result: " + result);
641         }
642         return Collections.unmodifiableList(audioMixes);
643     }
644 
645     /**
646      * Update already {@link AudioMixingRule}-s for already registered {@link AudioMix}-es.
647      *
648      * @param mixes              - array of registered {@link AudioMix}-es to update.
649      * @param updatedMixingRules - array of {@link AudioMixingRule}-s corresponding to
650      *                           {@code mixesToUpdate} mixes. The array must be same size as
651      *                           {@code mixesToUpdate} and i-th {@link AudioMixingRule} must
652      *                           correspond to i-th {@link AudioMix} from mixesToUpdate array.
653      */
updateMixingRules(@onNull AudioMix[] mixes, @NonNull AudioMixingRule[] updatedMixingRules)654     public int updateMixingRules(@NonNull AudioMix[] mixes,
655             @NonNull AudioMixingRule[] updatedMixingRules) {
656         invalidateRoutingCache();
657         return AudioSystem.updatePolicyMixes(mixes, updatedMixingRules);
658     }
659 
660     /**
661      * Same as {@link AudioSystem#setUidDeviceAffinities(int, int[], String[])}
662      * @param uid
663      * @param types
664      * @param addresses
665      * @return
666      */
setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses)667     public int setUidDeviceAffinities(int uid, @NonNull int[] types,  @NonNull String[] addresses) {
668         invalidateRoutingCache();
669         return AudioSystem.setUidDeviceAffinities(uid, types, addresses);
670     }
671 
672     /**
673      * Same as {@link AudioSystem#removeUidDeviceAffinities(int)}
674      * @param uid
675      * @return
676      */
removeUidDeviceAffinities(int uid)677     public int removeUidDeviceAffinities(int uid) {
678         invalidateRoutingCache();
679         return AudioSystem.removeUidDeviceAffinities(uid);
680     }
681 
682     /**
683      * Same as {@link AudioSystem#setUserIdDeviceAffinities(int, int[], String[])}
684      * @param userId
685      * @param types
686      * @param addresses
687      * @return
688      */
setUserIdDeviceAffinities(int userId, @NonNull int[] types, @NonNull String[] addresses)689     public int setUserIdDeviceAffinities(int userId, @NonNull int[] types,
690             @NonNull String[] addresses) {
691         invalidateRoutingCache();
692         return AudioSystem.setUserIdDeviceAffinities(userId, types, addresses);
693     }
694 
695     /**
696      * Same as {@link AudioSystem#removeUserIdDeviceAffinities(int)}
697      * @param userId
698      * @return
699      */
removeUserIdDeviceAffinities(int userId)700     public int removeUserIdDeviceAffinities(int userId) {
701         invalidateRoutingCache();
702         return AudioSystem.removeUserIdDeviceAffinities(userId);
703     }
704 
705     /**
706      * Same as {@link AudioSystem#getSoundDoseInterface(ISoundDoseCallback)}
707      * @param callback
708      * @return
709      */
getSoundDoseInterface(ISoundDoseCallback callback)710     public ISoundDose getSoundDoseInterface(ISoundDoseCallback callback) {
711         return AudioSystem.getSoundDoseInterface(callback);
712     }
713 
714     /**
715      * Same as
716      * {@link AudioSystem#setPreferredMixerAttributes(
717      *        AudioAttributes, int, int, AudioMixerAttributes)}
718      * @param attributes
719      * @param mixerAttributes
720      * @param uid
721      * @param portId
722      * @return
723      */
setPreferredMixerAttributes( @onNull AudioAttributes attributes, int portId, int uid, @NonNull AudioMixerAttributes mixerAttributes)724     public int setPreferredMixerAttributes(
725             @NonNull AudioAttributes attributes,
726             int portId,
727             int uid,
728             @NonNull AudioMixerAttributes mixerAttributes) {
729         return AudioSystem.setPreferredMixerAttributes(attributes, portId, uid, mixerAttributes);
730     }
731 
732     /**
733      * Same as {@link AudioSystem#clearPreferredMixerAttributes(AudioAttributes, int, int)}
734      * @param attributes
735      * @param uid
736      * @param portId
737      * @return
738      */
clearPreferredMixerAttributes( @onNull AudioAttributes attributes, int portId, int uid)739     public int clearPreferredMixerAttributes(
740             @NonNull AudioAttributes attributes, int portId, int uid) {
741         return AudioSystem.clearPreferredMixerAttributes(attributes, portId, uid);
742     }
743 
744     /**
745      * Sets master mute state in audio flinger
746      * @param mute the mute state to set
747      * @return operation status
748      */
setMasterMute(boolean mute)749     public int setMasterMute(boolean mute) {
750         return AudioSystem.setMasterMute(mute);
751     }
752 
listenForSystemPropertyChange(String systemPropertyName, Runnable callback)753     public long listenForSystemPropertyChange(String systemPropertyName, Runnable callback) {
754         return AudioSystem.listenForSystemPropertyChange(systemPropertyName, callback);
755     }
756 
triggerSystemPropertyUpdate(long handle)757     public void triggerSystemPropertyUpdate(long handle) {
758         AudioSystem.triggerSystemPropertyUpdate(handle);
759     }
760 
761     /**
762      * Same as {@link AudioSystem#registerAudioVolumeGroupCallback(INativeAudioVolumeGroupCallback)}
763      * @param callback to register
764      * @return {@link #SUCCESS} if successfully registered.
765      *
766      * @hide
767      */
registerAudioVolumeGroupCallback(INativeAudioVolumeGroupCallback callback)768     public int registerAudioVolumeGroupCallback(INativeAudioVolumeGroupCallback callback) {
769         return AudioSystem.registerAudioVolumeGroupCallback(callback);
770     }
771 
772     /**
773      * Same as
774      * {@link AudioSystem#unregisterAudioVolumeGroupCallback(INativeAudioVolumeGroupCallback)}.
775      * @param callback to register
776      * @return {@link #SUCCESS} if successfully registered.
777      *
778      * @hide
779      */
unregisterAudioVolumeGroupCallback(INativeAudioVolumeGroupCallback callback)780     public int unregisterAudioVolumeGroupCallback(INativeAudioVolumeGroupCallback callback) {
781         return AudioSystem.unregisterAudioVolumeGroupCallback(callback);
782     }
783 
784     /**
785      * Part of AudioService dump
786      * @param pw
787      */
dump(PrintWriter pw)788     public void dump(PrintWriter pw) {
789         pw.println("\nAudioSystemAdapter:");
790         final DateTimeFormatter formatter = DateTimeFormatter
791                 .ofPattern("MM-dd HH:mm:ss:SSS")
792                 .withLocale(Locale.US)
793                 .withZone(ZoneId.systemDefault());
794         synchronized (sDeviceCacheLock) {
795             pw.println(" last cache clear time: " + formatter.format(
796                     Instant.ofEpochMilli(mDevicesForAttributesCacheClearTimeMs)));
797             pw.println(" mDevicesForAttrCache:");
798             if (mDevicesForAttrCache != null) {
799                 for (Map.Entry<Pair<AudioAttributes, Boolean>, ArrayList<AudioDeviceAttributes>>
800                         entry : mDevicesForAttrCache.entrySet()) {
801                     final AudioAttributes attributes = entry.getKey().first;
802                     try {
803                         final int stream = attributes.getVolumeControlStream();
804                         pw.println("\t" + attributes + " forVolume: " + entry.getKey().second
805                                 + " stream: "
806                                 + AudioSystem.STREAM_NAMES[stream] + "(" + stream + ")");
807                         for (AudioDeviceAttributes devAttr : entry.getValue()) {
808                             pw.println("\t\t" + devAttr);
809                         }
810                     } catch (IllegalArgumentException e) {
811                         // dump could fail if attributes do not map to a stream.
812                         pw.println("\t dump failed for attributes: " + attributes);
813                         Log.e(TAG, "dump failed", e);
814                     }
815                 }
816             }
817         }
818 
819         if (!ENABLE_GETDEVICES_STATS) {
820             // only stats in the rest of this dump
821             return;
822         }
823         for (int i = 0; i < NB_MEASUREMENTS; i++) {
824             pw.println(mMethodNames[i]
825                     + ": counter=" + mMethodCallCounter[i]
826                     + " time(ms)=" + (mMethodTimeNs[i] / 1E6)
827                     + (USE_CACHE_FOR_GETDEVICES
828                         ? (" FScacheHit=" + mMethodCacheHit[METHOD_GETDEVICESFORATTRIBUTES])
829                         : ""));
830         }
831         pw.println("\n");
832     }
833 }
834