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