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