1 /* 2 * Copyright (C) 2007 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 android.media; 18 19 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT; 20 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO; 21 import static android.content.Context.DEVICE_ID_DEFAULT; 22 import static android.media.audio.Flags.autoPublicVolumeApiHardening; 23 import static android.media.audio.Flags.automaticBtDeviceType; 24 import static android.media.audio.Flags.FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING; 25 import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API; 26 import static android.media.audio.Flags.FLAG_SUPPORTED_DEVICE_TYPES_API; 27 import static android.media.audiopolicy.Flags.FLAG_ENABLE_FADE_MANAGER_CONFIGURATION; 28 29 import android.Manifest; 30 import android.annotation.CallbackExecutor; 31 import android.annotation.FlaggedApi; 32 import android.annotation.IntDef; 33 import android.annotation.IntRange; 34 import android.annotation.NonNull; 35 import android.annotation.Nullable; 36 import android.annotation.RequiresPermission; 37 import android.annotation.SdkConstant; 38 import android.annotation.SdkConstant.SdkConstantType; 39 import android.annotation.SuppressLint; 40 import android.annotation.SystemApi; 41 import android.annotation.SystemService; 42 import android.annotation.TestApi; 43 import android.app.NotificationManager; 44 import android.app.PendingIntent; 45 import android.app.compat.CompatChanges; 46 import android.bluetooth.BluetoothCodecConfig; 47 import android.bluetooth.BluetoothDevice; 48 import android.bluetooth.BluetoothLeAudioCodecConfig; 49 import android.companion.virtual.VirtualDeviceManager; 50 import android.compat.annotation.ChangeId; 51 import android.compat.annotation.EnabledSince; 52 import android.compat.annotation.Overridable; 53 import android.compat.annotation.UnsupportedAppUsage; 54 import android.content.ComponentName; 55 import android.content.Context; 56 import android.content.Intent; 57 import android.content.pm.PackageManager; 58 import android.media.AudioAttributes.AttributeSystemUsage; 59 import android.media.CallbackUtil.ListenerInfo; 60 import android.media.audiopolicy.AudioPolicy; 61 import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; 62 import android.media.audiopolicy.AudioProductStrategy; 63 import android.media.audiopolicy.AudioVolumeGroup; 64 import android.media.audiopolicy.AudioVolumeGroupChangeHandler; 65 import android.media.projection.MediaProjection; 66 import android.media.session.MediaController; 67 import android.media.session.MediaSession; 68 import android.media.session.MediaSessionLegacyHelper; 69 import android.media.session.MediaSessionManager; 70 import android.net.Uri; 71 import android.os.Binder; 72 import android.os.Build; 73 import android.os.Handler; 74 import android.os.IBinder; 75 import android.os.Looper; 76 import android.os.Message; 77 import android.os.RemoteException; 78 import android.os.ServiceManager; 79 import android.os.SystemClock; 80 import android.os.UserHandle; 81 import android.provider.Settings; 82 import android.text.TextUtils; 83 import android.util.ArrayMap; 84 import android.util.IntArray; 85 import android.util.Log; 86 import android.util.Pair; 87 import android.view.KeyEvent; 88 89 import com.android.internal.annotations.GuardedBy; 90 import com.android.internal.util.Preconditions; 91 92 import java.io.IOException; 93 import java.lang.annotation.Retention; 94 import java.lang.annotation.RetentionPolicy; 95 import java.lang.ref.WeakReference; 96 import java.util.ArrayList; 97 import java.util.Arrays; 98 import java.util.Collections; 99 import java.util.HashMap; 100 import java.util.HashSet; 101 import java.util.Iterator; 102 import java.util.List; 103 import java.util.Map; 104 import java.util.Objects; 105 import java.util.Set; 106 import java.util.TreeMap; 107 import java.util.concurrent.ConcurrentHashMap; 108 import java.util.concurrent.Executor; 109 import java.util.concurrent.Executors; 110 import java.util.concurrent.TimeUnit; 111 112 /** 113 * AudioManager provides access to volume and ringer mode control. 114 */ 115 @SystemService(Context.AUDIO_SERVICE) 116 public class AudioManager { 117 118 private Context mOriginalContext; 119 private Context mApplicationContext; 120 private int mOriginalContextDeviceId = DEVICE_ID_DEFAULT; 121 private @Nullable VirtualDeviceManager mVirtualDeviceManager; // Lazy initialized. 122 private static final String TAG = "AudioManager"; 123 private static final boolean DEBUG = false; 124 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler(); 125 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler = 126 new AudioVolumeGroupChangeHandler(); 127 128 private static WeakReference<Context> sContext; 129 130 /** 131 * Broadcast intent, a hint for applications that audio is about to become 132 * 'noisy' due to a change in audio outputs. For example, this intent may 133 * be sent when a wired headset is unplugged, or when an A2DP audio 134 * sink is disconnected, and the audio system is about to automatically 135 * switch audio route to the speaker. Applications that are controlling 136 * audio streams may consider pausing, reducing volume or some other action 137 * on receipt of this intent so as not to surprise the user with audio 138 * from the speaker. 139 */ 140 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 141 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY"; 142 143 /** 144 * Sticky broadcast intent action indicating that the ringer mode has 145 * changed. Includes the new ringer mode. 146 * 147 * @see #EXTRA_RINGER_MODE 148 */ 149 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 150 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; 151 152 /** 153 * @hide 154 * Sticky broadcast intent action indicating that the internal ringer mode has 155 * changed. Includes the new ringer mode. 156 * 157 * @see #EXTRA_RINGER_MODE 158 */ 159 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 160 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION = 161 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION"; 162 163 /** 164 * The new ringer mode. 165 * 166 * @see #RINGER_MODE_CHANGED_ACTION 167 * @see #RINGER_MODE_NORMAL 168 * @see #RINGER_MODE_SILENT 169 * @see #RINGER_MODE_VIBRATE 170 */ 171 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE"; 172 173 /** 174 * Broadcast intent action indicating that the vibrate setting has 175 * changed. Includes the vibrate type and its new setting. 176 * 177 * @see #EXTRA_VIBRATE_TYPE 178 * @see #EXTRA_VIBRATE_SETTING 179 * @deprecated Applications should maintain their own vibrate policy based on 180 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 181 */ 182 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 183 public static final String VIBRATE_SETTING_CHANGED_ACTION = 184 "android.media.VIBRATE_SETTING_CHANGED"; 185 186 /** 187 * @hide Broadcast intent when the volume for a particular stream type changes. 188 * Includes the stream, the new volume and previous volumes. 189 * Notes: 190 * - for internal platform use only, do not make public, 191 * - never used for "remote" volume changes 192 * 193 * @see #EXTRA_VOLUME_STREAM_TYPE 194 * @see #EXTRA_VOLUME_STREAM_VALUE 195 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE 196 */ 197 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 198 @UnsupportedAppUsage 199 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"; 200 201 /** 202 * @hide Broadcast intent when the volume for a particular stream type changes. 203 * Includes the stream, the new volume and previous volumes. 204 * Notes: 205 * - for internal platform use only, do not make public, 206 * - never used for "remote" volume changes 207 * 208 * @see #EXTRA_VOLUME_STREAM_TYPE 209 * @see #EXTRA_VOLUME_STREAM_VALUE 210 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE 211 */ 212 @SystemApi 213 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 214 @SuppressLint("ActionValue") 215 public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION"; 216 217 /** 218 * @hide Broadcast intent when the devices for a particular stream type changes. 219 * Includes the stream, the new devices and previous devices. 220 * Notes: 221 * - for internal platform use only, do not make public, 222 * - never used for "remote" volume changes 223 * 224 * @see #EXTRA_VOLUME_STREAM_TYPE 225 * @see #EXTRA_VOLUME_STREAM_DEVICES 226 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES 227 * @see #getDevicesForStream 228 */ 229 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 230 public static final String STREAM_DEVICES_CHANGED_ACTION = 231 "android.media.STREAM_DEVICES_CHANGED_ACTION"; 232 233 /** 234 * @hide Broadcast intent when a stream mute state changes. 235 * Includes the stream that changed and the new mute state 236 * 237 * @see #EXTRA_VOLUME_STREAM_TYPE 238 * @see #EXTRA_STREAM_VOLUME_MUTED 239 */ 240 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 241 public static final String STREAM_MUTE_CHANGED_ACTION = 242 "android.media.STREAM_MUTE_CHANGED_ACTION"; 243 244 /** 245 * @hide Broadcast intent when the master mute state changes. 246 * Includes the the new volume 247 * 248 * @see #EXTRA_MASTER_VOLUME_MUTED 249 */ 250 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 251 public static final String MASTER_MUTE_CHANGED_ACTION = 252 "android.media.MASTER_MUTE_CHANGED_ACTION"; 253 254 /** 255 * The new vibrate setting for a particular type. 256 * 257 * @see #VIBRATE_SETTING_CHANGED_ACTION 258 * @see #EXTRA_VIBRATE_TYPE 259 * @see #VIBRATE_SETTING_ON 260 * @see #VIBRATE_SETTING_OFF 261 * @see #VIBRATE_SETTING_ONLY_SILENT 262 * @deprecated Applications should maintain their own vibrate policy based on 263 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 264 */ 265 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING"; 266 267 /** 268 * The vibrate type whose setting has changed. 269 * 270 * @see #VIBRATE_SETTING_CHANGED_ACTION 271 * @see #VIBRATE_TYPE_NOTIFICATION 272 * @see #VIBRATE_TYPE_RINGER 273 * @deprecated Applications should maintain their own vibrate policy based on 274 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 275 */ 276 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE"; 277 278 /** 279 * @hide The stream type for the volume changed intent. 280 */ 281 @SystemApi 282 @SuppressLint("ActionValue") 283 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE"; 284 285 /** 286 * @hide 287 * The stream type alias for the volume changed intent. 288 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream 289 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also 290 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices, 291 * {@link #STREAM_MUSIC} on others (e.g. a television). 292 */ 293 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS = 294 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS"; 295 296 /** 297 * @hide The volume associated with the stream for the volume changed intent. 298 */ 299 @SystemApi 300 @SuppressLint("ActionValue") 301 public static final String EXTRA_VOLUME_STREAM_VALUE = 302 "android.media.EXTRA_VOLUME_STREAM_VALUE"; 303 304 /** 305 * @hide The previous volume associated with the stream for the volume changed intent. 306 */ 307 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE = 308 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE"; 309 310 /** 311 * @hide The devices associated with the stream for the stream devices changed intent. 312 */ 313 public static final String EXTRA_VOLUME_STREAM_DEVICES = 314 "android.media.EXTRA_VOLUME_STREAM_DEVICES"; 315 316 /** 317 * @hide The previous devices associated with the stream for the stream devices changed intent. 318 */ 319 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES = 320 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES"; 321 322 /** 323 * @hide The new master volume mute state for the master mute changed intent. 324 * Value is boolean 325 */ 326 public static final String EXTRA_MASTER_VOLUME_MUTED = 327 "android.media.EXTRA_MASTER_VOLUME_MUTED"; 328 329 /** 330 * @hide The new stream volume mute state for the stream mute changed intent. 331 * Value is boolean 332 */ 333 public static final String EXTRA_STREAM_VOLUME_MUTED = 334 "android.media.EXTRA_STREAM_VOLUME_MUTED"; 335 336 /** 337 * Broadcast Action: Wired Headset plugged in or unplugged. 338 * 339 * You <em>cannot</em> receive this through components declared 340 * in manifests, only by explicitly registering for it with 341 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 342 * Context.registerReceiver()}. 343 * 344 * <p>The intent will have the following extra values: 345 * <ul> 346 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> 347 * <li><em>name</em> - Headset type, human readable string </li> 348 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li> 349 * </ul> 350 * </ul> 351 */ 352 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 353 public static final String ACTION_HEADSET_PLUG = 354 "android.intent.action.HEADSET_PLUG"; 355 356 /** 357 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged. 358 * 359 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE}, 360 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}. 361 * <p>It can only be received by explicitly registering for it with 362 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}. 363 */ 364 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 365 public static final String ACTION_HDMI_AUDIO_PLUG = 366 "android.media.action.HDMI_AUDIO_PLUG"; 367 368 /** 369 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in 370 * or unplugged. 371 * An integer value of 1 indicates a plugged-in state, 0 is unplugged. 372 */ 373 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE"; 374 375 /** 376 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels 377 * supported by the HDMI device. 378 * The corresponding integer value is only available when the device is plugged in (as expressed 379 * by {@link #EXTRA_AUDIO_PLUG_STATE}). 380 */ 381 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT"; 382 383 /** 384 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by 385 * the connected HDMI device. 386 * The corresponding array of encoding values is only available when the device is plugged in 387 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in 388 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use 389 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values. 390 */ 391 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS"; 392 393 /** Used to identify the volume of audio streams for phone calls */ 394 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL; 395 /** Used to identify the volume of audio streams for system sounds */ 396 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM; 397 /** Used to identify the volume of audio streams for the phone ring */ 398 public static final int STREAM_RING = AudioSystem.STREAM_RING; 399 /** Used to identify the volume of audio streams for music playback */ 400 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC; 401 /** Used to identify the volume of audio streams for alarms */ 402 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM; 403 /** Used to identify the volume of audio streams for notifications */ 404 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION; 405 /** @hide Used to identify the volume of audio streams for phone calls when connected 406 * to bluetooth */ 407 @SystemApi 408 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO; 409 /** @hide Used to identify the volume of audio streams for enforced system sounds 410 * in certain countries (e.g camera in Japan) */ 411 @UnsupportedAppUsage 412 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED; 413 /** Used to identify the volume of audio streams for DTMF Tones */ 414 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF; 415 /** @hide Used to identify the volume of audio streams exclusively transmitted through the 416 * speaker (TTS) of the device */ 417 @UnsupportedAppUsage 418 public static final int STREAM_TTS = AudioSystem.STREAM_TTS; 419 /** Used to identify the volume of audio streams for accessibility prompts */ 420 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY; 421 /** @hide Used to identify the volume of audio streams for virtual assistant */ 422 @SystemApi 423 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 424 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT; 425 426 /** Number of audio streams */ 427 /** 428 * @deprecated Do not iterate on volume stream type values. 429 */ 430 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS; 431 432 /** @hide */ 433 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL, 434 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC, 435 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION, 436 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY }; 437 438 /** @hide */ 439 @TestApi getPublicStreamTypes()440 public static final int[] getPublicStreamTypes() { 441 return PUBLIC_STREAM_TYPES; 442 } 443 444 /** 445 * Increase the ringer volume. 446 * 447 * @see #adjustVolume(int, int) 448 * @see #adjustStreamVolume(int, int, int) 449 */ 450 public static final int ADJUST_RAISE = 1; 451 452 /** 453 * Decrease the ringer volume. 454 * 455 * @see #adjustVolume(int, int) 456 * @see #adjustStreamVolume(int, int, int) 457 */ 458 public static final int ADJUST_LOWER = -1; 459 460 /** 461 * Maintain the previous ringer volume. This may be useful when needing to 462 * show the volume toast without actually modifying the volume. 463 * 464 * @see #adjustVolume(int, int) 465 * @see #adjustStreamVolume(int, int, int) 466 */ 467 public static final int ADJUST_SAME = 0; 468 469 /** 470 * Mute the volume. Has no effect if the stream is already muted. 471 * 472 * @see #adjustVolume(int, int) 473 * @see #adjustStreamVolume(int, int, int) 474 */ 475 public static final int ADJUST_MUTE = -100; 476 477 /** 478 * Unmute the volume. Has no effect if the stream is not muted. 479 * 480 * @see #adjustVolume(int, int) 481 * @see #adjustStreamVolume(int, int, int) 482 */ 483 public static final int ADJUST_UNMUTE = 100; 484 485 /** 486 * Toggle the mute state. If muted the stream will be unmuted. If not muted 487 * the stream will be muted. 488 * 489 * @see #adjustVolume(int, int) 490 * @see #adjustStreamVolume(int, int, int) 491 */ 492 public static final int ADJUST_TOGGLE_MUTE = 101; 493 494 /** @hide */ 495 @IntDef(flag = false, prefix = "ADJUST", value = { 496 ADJUST_RAISE, 497 ADJUST_LOWER, 498 ADJUST_SAME, 499 ADJUST_MUTE, 500 ADJUST_UNMUTE, 501 ADJUST_TOGGLE_MUTE } 502 ) 503 @Retention(RetentionPolicy.SOURCE) 504 public @interface VolumeAdjustment {} 505 506 /** @hide */ adjustToString(int adj)507 public static final String adjustToString(int adj) { 508 switch (adj) { 509 case ADJUST_RAISE: return "ADJUST_RAISE"; 510 case ADJUST_LOWER: return "ADJUST_LOWER"; 511 case ADJUST_SAME: return "ADJUST_SAME"; 512 case ADJUST_MUTE: return "ADJUST_MUTE"; 513 case ADJUST_UNMUTE: return "ADJUST_UNMUTE"; 514 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE"; 515 default: return new StringBuilder("unknown adjust mode ").append(adj).toString(); 516 } 517 } 518 519 // Flags should be powers of 2! 520 521 /** 522 * Show a toast containing the current volume. 523 * 524 * @see #adjustStreamVolume(int, int, int) 525 * @see #adjustVolume(int, int) 526 * @see #setStreamVolume(int, int, int) 527 * @see #setRingerMode(int) 528 */ 529 public static final int FLAG_SHOW_UI = 1 << 0; 530 531 /** 532 * Whether to include ringer modes as possible options when changing volume. 533 * For example, if true and volume level is 0 and the volume is adjusted 534 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or 535 * vibrate mode. 536 * <p> 537 * By default this is on for the ring stream. If this flag is included, 538 * this behavior will be present regardless of the stream type being 539 * affected by the ringer mode. 540 * 541 * @see #adjustVolume(int, int) 542 * @see #adjustStreamVolume(int, int, int) 543 */ 544 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1; 545 546 /** 547 * Whether to play a sound when changing the volume. 548 * <p> 549 * If this is given to {@link #adjustVolume(int, int)} or 550 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored 551 * in some cases (for example, the decided stream type is not 552 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted 553 * downward). 554 * 555 * @see #adjustStreamVolume(int, int, int) 556 * @see #adjustVolume(int, int) 557 * @see #setStreamVolume(int, int, int) 558 */ 559 public static final int FLAG_PLAY_SOUND = 1 << 2; 560 561 /** 562 * Removes any sounds/vibrate that may be in the queue, or are playing (related to 563 * changing volume). 564 */ 565 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3; 566 567 /** 568 * Whether to vibrate if going into the vibrate ringer mode. 569 */ 570 public static final int FLAG_VIBRATE = 1 << 4; 571 572 /** 573 * Indicates to VolumePanel that the volume slider should be disabled as user 574 * cannot change the stream volume 575 * @hide 576 */ 577 public static final int FLAG_FIXED_VOLUME = 1 << 5; 578 579 /** 580 * Indicates the volume set/adjust call is for Bluetooth absolute volume 581 * @hide 582 */ 583 @SystemApi 584 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6; 585 586 /** 587 * Adjusting the volume was prevented due to silent mode, display a hint in the UI. 588 * @hide 589 */ 590 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7; 591 592 /** 593 * Indicates the volume call is for Hdmi Cec system audio volume 594 * @hide 595 */ 596 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8; 597 598 /** 599 * Indicates that this should only be handled if media is actively playing. 600 * @hide 601 */ 602 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9; 603 604 /** 605 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders. 606 * @hide 607 */ 608 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10; 609 610 /** 611 * Adjusting the volume down from vibrated was prevented, display a hint in the UI. 612 * @hide 613 */ 614 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11; 615 616 /** 617 * Adjusting the volume due to a hardware key press. 618 * This flag can be used in the places in order to denote (or check) that a volume adjustment 619 * request is from a hardware key press. (e.g. {@link MediaController}). 620 * @hide 621 */ 622 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 623 public static final int FLAG_FROM_KEY = 1 << 12; 624 625 /** 626 * Indicates that an absolute volume controller is notifying AudioService of a change in the 627 * volume or mute status of an external audio system. 628 * @hide 629 */ 630 public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13; 631 632 /** @hide */ 633 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = { 634 ENCODED_SURROUND_OUTPUT_UNKNOWN, 635 ENCODED_SURROUND_OUTPUT_AUTO, 636 ENCODED_SURROUND_OUTPUT_NEVER, 637 ENCODED_SURROUND_OUTPUT_ALWAYS, 638 ENCODED_SURROUND_OUTPUT_MANUAL 639 }) 640 @Retention(RetentionPolicy.SOURCE) 641 public @interface EncodedSurroundOutputMode {} 642 643 /** 644 * The mode for surround sound formats is unknown. 645 */ 646 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1; 647 648 /** 649 * The surround sound formats are available for use if they are detected. This is the default 650 * mode. 651 */ 652 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0; 653 654 /** 655 * The surround sound formats are NEVER available, even if they are detected by the hardware. 656 * Those formats will not be reported. 657 */ 658 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1; 659 660 /** 661 * The surround sound formats are ALWAYS available, even if they are not detected by the 662 * hardware. Those formats will be reported as part of the HDMI output capability. 663 * Applications are then free to use either PCM or encoded output. 664 */ 665 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2; 666 667 /** 668 * Surround sound formats are available according to the choice of user, even if they are not 669 * detected by the hardware. Those formats will be reported as part of the HDMI output 670 * capability. Applications are then free to use either PCM or encoded output. 671 */ 672 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3; 673 674 /** 675 * @hide 676 * This list contains all the flags that can be used in internal APIs for volume 677 * related operations */ 678 @IntDef(flag = true, prefix = "FLAG", value = { 679 FLAG_SHOW_UI, 680 FLAG_ALLOW_RINGER_MODES, 681 FLAG_PLAY_SOUND, 682 FLAG_REMOVE_SOUND_AND_VIBRATE, 683 FLAG_VIBRATE, 684 FLAG_FIXED_VOLUME, 685 FLAG_BLUETOOTH_ABS_VOLUME, 686 FLAG_SHOW_SILENT_HINT, 687 FLAG_HDMI_SYSTEM_AUDIO_VOLUME, 688 FLAG_ACTIVE_MEDIA_ONLY, 689 FLAG_SHOW_UI_WARNINGS, 690 FLAG_SHOW_VIBRATE_HINT, 691 FLAG_FROM_KEY, 692 FLAG_ABSOLUTE_VOLUME, 693 }) 694 @Retention(RetentionPolicy.SOURCE) 695 // TODO(308698465) remove due to potential conflict with the new flags class 696 public @interface Flags {} 697 698 /** 699 * @hide 700 * This list contains all the flags that can be used in SDK-visible methods for volume 701 * related operations. 702 * See for instance {@link #adjustVolume(int, int)}, 703 * {@link #adjustStreamVolume(int, int, int)}, 704 * {@link #adjustSuggestedStreamVolume(int, int, int)}, 705 * {@link #adjustVolumeGroupVolume(int, int, int)}, 706 * {@link #setStreamVolume(int, int, int)} 707 * The list contains all volume flags, but the values commented out of the list are there for 708 * maintenance reasons (for when adding flags or changing their visibility), 709 * and to document why some are not in the list (hidden or SystemApi). */ 710 @IntDef(flag = true, prefix = "FLAG", value = { 711 FLAG_SHOW_UI, 712 FLAG_ALLOW_RINGER_MODES, 713 FLAG_PLAY_SOUND, 714 FLAG_REMOVE_SOUND_AND_VIBRATE, 715 FLAG_VIBRATE, 716 //FLAG_FIXED_VOLUME, removed due to @hide 717 //FLAG_BLUETOOTH_ABS_VOLUME, removed due to @SystemApi 718 //FLAG_SHOW_SILENT_HINT, removed due to @hide 719 //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide 720 //FLAG_ACTIVE_MEDIA_ONLY, removed due to @hide 721 //FLAG_SHOW_UI_WARNINGS, removed due to @hide 722 //FLAG_SHOW_VIBRATE_HINT, removed due to @hide 723 //FLAG_FROM_KEY, removed due to @SystemApi 724 //FLAG_ABSOLUTE_VOLUME, removed due to @hide 725 }) 726 @Retention(RetentionPolicy.SOURCE) 727 public @interface PublicVolumeFlags {} 728 729 /** 730 * @hide 731 * Like PublicVolumeFlags, but for all the flags that can be used in @SystemApi methods for 732 * volume related operations. 733 * See for instance {@link #setVolumeIndexForAttributes(AudioAttributes, int, int)}, 734 * {@link #setVolumeGroupVolumeIndex(int, int, int)}, 735 * {@link #setStreamVolumeForUid(int, int, int, String, int, int, int)}, 736 * {@link #adjustStreamVolumeForUid(int, int, int, String, int, int, int)}, 737 * {@link #adjustSuggestedStreamVolumeForUid(int, int, int, String, int, int, int)} 738 * The list contains all volume flags, but the values commented out of the list are there for 739 * maintenance reasons (for when adding flags or changing their visibility), 740 * and to document which hidden values are not in the list. */ 741 @IntDef(flag = true, prefix = "FLAG", value = { 742 FLAG_SHOW_UI, 743 FLAG_ALLOW_RINGER_MODES, 744 FLAG_PLAY_SOUND, 745 FLAG_REMOVE_SOUND_AND_VIBRATE, 746 FLAG_VIBRATE, 747 //FLAG_FIXED_VOLUME, removed due to @hide 748 FLAG_BLUETOOTH_ABS_VOLUME, 749 //FLAG_SHOW_SILENT_HINT, removed due to @hide 750 //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide 751 //FLAG_ACTIVE_MEDIA_ONLY, removed due to @hide 752 //FLAG_SHOW_UI_WARNINGS, removed due to @hide 753 //FLAG_SHOW_VIBRATE_HINT, removed due to @hide 754 FLAG_FROM_KEY, 755 //FLAG_ABSOLUTE_VOLUME, removed due to @hide 756 }) 757 @Retention(RetentionPolicy.SOURCE) 758 public @interface SystemVolumeFlags {} 759 760 // The iterator of TreeMap#entrySet() returns the entries in ascending key order. 761 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>(); 762 763 static { FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI")764 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI"); FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES")765 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES"); FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND")766 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND"); FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE")767 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE"); FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE")768 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE"); FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME")769 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME"); FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME")770 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME"); FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT")771 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT"); FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME")772 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME"); FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY")773 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY"); FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS")774 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS"); FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT")775 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT"); FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY")776 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY"); FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME")777 FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME"); 778 } 779 780 /** @hide */ flagsToString(int flags)781 public static String flagsToString(int flags) { 782 final StringBuilder sb = new StringBuilder(); 783 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) { 784 final int flag = entry.getKey(); 785 if ((flags & flag) != 0) { 786 if (sb.length() > 0) { 787 sb.append(','); 788 } 789 sb.append(entry.getValue()); 790 flags &= ~flag; 791 } 792 } 793 if (flags != 0) { 794 if (sb.length() > 0) { 795 sb.append(','); 796 } 797 sb.append(flags); 798 } 799 return sb.toString(); 800 } 801 802 /** 803 * Ringer mode that will be silent and will not vibrate. (This overrides the 804 * vibrate setting.) 805 * 806 * @see #setRingerMode(int) 807 * @see #getRingerMode() 808 */ 809 public static final int RINGER_MODE_SILENT = 0; 810 811 /** 812 * Ringer mode that will be silent and will vibrate. (This will cause the 813 * phone ringer to always vibrate, but the notification vibrate to only 814 * vibrate if set.) 815 * 816 * @see #setRingerMode(int) 817 * @see #getRingerMode() 818 */ 819 public static final int RINGER_MODE_VIBRATE = 1; 820 821 /** 822 * Ringer mode that may be audible and may vibrate. It will be audible if 823 * the volume before changing out of this mode was audible. It will vibrate 824 * if the vibrate setting is on. 825 * 826 * @see #setRingerMode(int) 827 * @see #getRingerMode() 828 */ 829 public static final int RINGER_MODE_NORMAL = 2; 830 831 /** 832 * Maximum valid ringer mode value. Values must start from 0 and be contiguous. 833 * @hide 834 */ 835 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL; 836 837 /** 838 * Vibrate type that corresponds to the ringer. 839 * 840 * @see #setVibrateSetting(int, int) 841 * @see #getVibrateSetting(int) 842 * @see #shouldVibrate(int) 843 * @deprecated Applications should maintain their own vibrate policy based on 844 * current ringer mode that can be queried via {@link #getRingerMode()}. 845 */ 846 public static final int VIBRATE_TYPE_RINGER = 0; 847 848 /** 849 * Vibrate type that corresponds to notifications. 850 * 851 * @see #setVibrateSetting(int, int) 852 * @see #getVibrateSetting(int) 853 * @see #shouldVibrate(int) 854 * @deprecated Applications should maintain their own vibrate policy based on 855 * current ringer mode that can be queried via {@link #getRingerMode()}. 856 */ 857 public static final int VIBRATE_TYPE_NOTIFICATION = 1; 858 859 /** 860 * Vibrate setting that suggests to never vibrate. 861 * 862 * @see #setVibrateSetting(int, int) 863 * @see #getVibrateSetting(int) 864 * @deprecated Applications should maintain their own vibrate policy based on 865 * current ringer mode that can be queried via {@link #getRingerMode()}. 866 */ 867 public static final int VIBRATE_SETTING_OFF = 0; 868 869 /** 870 * Vibrate setting that suggests to vibrate when possible. 871 * 872 * @see #setVibrateSetting(int, int) 873 * @see #getVibrateSetting(int) 874 * @deprecated Applications should maintain their own vibrate policy based on 875 * current ringer mode that can be queried via {@link #getRingerMode()}. 876 */ 877 public static final int VIBRATE_SETTING_ON = 1; 878 879 /** 880 * Vibrate setting that suggests to only vibrate when in the vibrate ringer 881 * mode. 882 * 883 * @see #setVibrateSetting(int, int) 884 * @see #getVibrateSetting(int) 885 * @deprecated Applications should maintain their own vibrate policy based on 886 * current ringer mode that can be queried via {@link #getRingerMode()}. 887 */ 888 public static final int VIBRATE_SETTING_ONLY_SILENT = 2; 889 890 /** 891 * Suggests using the default stream type. This may not be used in all 892 * places a stream type is needed. 893 */ 894 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE; 895 896 private static IAudioService sService; 897 898 /** 899 * @hide 900 * For test purposes only, will throw NPE with some methods that require a Context. 901 */ 902 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) AudioManager()903 public AudioManager() { 904 } 905 906 /** 907 * @hide 908 */ 909 @UnsupportedAppUsage AudioManager(Context context)910 public AudioManager(Context context) { 911 setContext(context); 912 initPlatform(); 913 } 914 getContext()915 private Context getContext() { 916 if (mApplicationContext == null) { 917 setContext(mOriginalContext); 918 } 919 if (mApplicationContext != null) { 920 return mApplicationContext; 921 } 922 return mOriginalContext; 923 } 924 setContext(Context context)925 private void setContext(Context context) { 926 if (context == null) { 927 return; 928 } 929 mOriginalContextDeviceId = context.getDeviceId(); 930 mApplicationContext = context.getApplicationContext(); 931 if (mApplicationContext != null) { 932 mOriginalContext = null; 933 } else { 934 mOriginalContext = context; 935 } 936 sContext = new WeakReference<>(context); 937 } 938 939 @UnsupportedAppUsage getService()940 static IAudioService getService() 941 { 942 if (sService != null) { 943 return sService; 944 } 945 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 946 sService = IAudioService.Stub.asInterface(b); 947 return sService; 948 } 949 getVirtualDeviceManager()950 private VirtualDeviceManager getVirtualDeviceManager() { 951 if (mVirtualDeviceManager != null) { 952 return mVirtualDeviceManager; 953 } 954 mVirtualDeviceManager = getContext().getSystemService(VirtualDeviceManager.class); 955 return mVirtualDeviceManager; 956 } 957 958 /** 959 * Sends a simulated key event for a media button. To simulate a key press, you must first send 960 * a KeyEvent built with a {@link KeyEvent#ACTION_DOWN} action, then another event with the 961 * {@link KeyEvent#ACTION_UP} action. 962 * 963 * <p>The key event will be sent to the current media key event consumer which registered with 964 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}. 965 * 966 * @param keyEvent a media session {@link KeyEvent}, as defined by {@link 967 * KeyEvent#isMediaSessionKey}. 968 */ dispatchMediaKeyEvent(KeyEvent keyEvent)969 public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 970 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 971 helper.sendMediaButtonEvent(keyEvent, false); 972 } 973 974 /** 975 * @hide 976 */ preDispatchKeyEvent(KeyEvent event, int stream)977 public void preDispatchKeyEvent(KeyEvent event, int stream) { 978 /* 979 * If the user hits another key within the play sound delay, then 980 * cancel the sound 981 */ 982 int keyCode = event.getKeyCode(); 983 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP 984 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE 985 && AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) { 986 /* 987 * The user has hit another key during the delay (e.g., 300ms) 988 * since the last volume key up, so cancel any sounds. 989 */ 990 adjustSuggestedStreamVolume(ADJUST_SAME, 991 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); 992 } 993 } 994 995 /** 996 * Indicates if the device implements a fixed volume policy. 997 * <p>Some devices may not have volume control and may operate at a fixed volume, 998 * and may not enable muting or changing the volume of audio streams. 999 * This method will return true on such devices. 1000 * <p>The following APIs have no effect when volume is fixed: 1001 * <ul> 1002 * <li> {@link #adjustVolume(int, int)} 1003 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)} 1004 * <li> {@link #adjustStreamVolume(int, int, int)} 1005 * <li> {@link #setStreamVolume(int, int, int)} 1006 * <li> {@link #setRingerMode(int)} 1007 * <li> {@link #setStreamSolo(int, boolean)} 1008 * <li> {@link #setStreamMute(int, boolean)} 1009 * </ul> 1010 */ isVolumeFixed()1011 public boolean isVolumeFixed() { 1012 boolean res = false; 1013 try { 1014 res = getService().isVolumeFixed(); 1015 } catch (RemoteException e) { 1016 Log.e(TAG, "Error querying isVolumeFixed", e); 1017 } 1018 return res; 1019 } 1020 1021 /** 1022 * Adjusts the volume of a particular stream by one step in a direction. 1023 * <p> 1024 * This method should only be used by applications that replace the platform-wide 1025 * management of audio settings or the main telephony application. 1026 * <p>This method has no effect if the device implements a fixed volume policy 1027 * as indicated by {@link #isVolumeFixed()}. 1028 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 1029 * unless the app has been granted Do Not Disturb Access. 1030 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1031 * 1032 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, 1033 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC}, 1034 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}. 1035 * @param direction The direction to adjust the volume. One of 1036 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 1037 * {@link #ADJUST_SAME}. 1038 * @param flags 1039 * @see #adjustVolume(int, int) 1040 * @see #setStreamVolume(int, int, int) 1041 * @throws SecurityException if the adjustment triggers a Do Not Disturb change 1042 * and the caller is not granted notification policy access. 1043 */ adjustStreamVolume(int streamType, int direction, @PublicVolumeFlags int flags)1044 public void adjustStreamVolume(int streamType, int direction, @PublicVolumeFlags int flags) { 1045 final IAudioService service = getService(); 1046 try { 1047 service.adjustStreamVolumeWithAttribution(streamType, direction, flags, 1048 getContext().getOpPackageName(), getContext().getAttributionTag()); 1049 } catch (RemoteException e) { 1050 throw e.rethrowFromSystemServer(); 1051 } 1052 } 1053 1054 /** 1055 * Adjusts the volume of the most relevant stream. For example, if a call is 1056 * active, it will have the highest priority regardless of if the in-call 1057 * screen is showing. Another example, if music is playing in the background 1058 * and a call is not active, the music stream will be adjusted. 1059 * <p> 1060 * This method should only be used by applications that replace the 1061 * platform-wide management of audio settings or the main telephony 1062 * application. 1063 * <p> 1064 * This method has no effect if the device implements a fixed volume policy 1065 * as indicated by {@link #isVolumeFixed()}. 1066 * 1067 * @param direction The direction to adjust the volume. One of 1068 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 1069 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 1070 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 1071 * @param flags 1072 * @see #adjustSuggestedStreamVolume(int, int, int) 1073 * @see #adjustStreamVolume(int, int, int) 1074 * @see #setStreamVolume(int, int, int) 1075 * @see #isVolumeFixed() 1076 */ adjustVolume(int direction, @PublicVolumeFlags int flags)1077 public void adjustVolume(int direction, @PublicVolumeFlags int flags) { 1078 if (applyAutoHardening()) { 1079 final IAudioService service = getService(); 1080 try { 1081 service.adjustVolume(direction, flags); 1082 } catch (RemoteException e) { 1083 throw e.rethrowFromSystemServer(); 1084 } 1085 } else { 1086 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 1087 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags); 1088 } 1089 } 1090 1091 /** 1092 * Adjusts the volume of the most relevant stream, or the given fallback 1093 * stream. 1094 * <p> 1095 * This method should only be used by applications that replace the 1096 * platform-wide management of audio settings or the main telephony 1097 * application. 1098 * <p> 1099 * This method has no effect if the device implements a fixed volume policy 1100 * as indicated by {@link #isVolumeFixed()}. 1101 * 1102 * @param direction The direction to adjust the volume. One of 1103 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 1104 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 1105 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 1106 * @param suggestedStreamType The stream type that will be used if there 1107 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is 1108 * valid here. 1109 * @param flags 1110 * @see #adjustVolume(int, int) 1111 * @see #adjustStreamVolume(int, int, int) 1112 * @see #setStreamVolume(int, int, int) 1113 * @see #isVolumeFixed() 1114 */ adjustSuggestedStreamVolume(int direction, int suggestedStreamType, @PublicVolumeFlags int flags)1115 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, 1116 @PublicVolumeFlags int flags) { 1117 if (applyAutoHardening()) { 1118 final IAudioService service = getService(); 1119 try { 1120 service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags); 1121 } catch (RemoteException e) { 1122 throw e.rethrowFromSystemServer(); 1123 } 1124 } else { 1125 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 1126 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags); 1127 } 1128 } 1129 1130 /** @hide */ 1131 @UnsupportedAppUsage 1132 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setMasterMute(boolean mute, int flags)1133 public void setMasterMute(boolean mute, int flags) { 1134 final IAudioService service = getService(); 1135 try { 1136 service.setMasterMute(mute, flags, getContext().getOpPackageName(), 1137 UserHandle.getCallingUserId(), getContext().getAttributionTag()); 1138 } catch (RemoteException e) { 1139 throw e.rethrowFromSystemServer(); 1140 } 1141 } 1142 1143 /** 1144 * Returns the current ringtone mode. 1145 * 1146 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL}, 1147 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. 1148 * @see #setRingerMode(int) 1149 */ getRingerMode()1150 public int getRingerMode() { 1151 final IAudioService service = getService(); 1152 try { 1153 return service.getRingerModeExternal(); 1154 } catch (RemoteException e) { 1155 throw e.rethrowFromSystemServer(); 1156 } 1157 } 1158 1159 /** 1160 * Returns the current user setting for ramping ringer on incoming phone call ringtone. 1161 * 1162 * @return true if the incoming phone call ringtone is configured to gradually increase its 1163 * volume, false otherwise. 1164 */ isRampingRingerEnabled()1165 public boolean isRampingRingerEnabled() { 1166 return Settings.System.getInt(getContext().getContentResolver(), 1167 Settings.System.APPLY_RAMPING_RINGER, 0) != 0; 1168 } 1169 1170 /** 1171 * Sets the flag for enabling ramping ringer on incoming phone call ringtone. 1172 * 1173 * @see #isRampingRingerEnabled() 1174 * @hide 1175 */ 1176 @TestApi setRampingRingerEnabled(boolean enabled)1177 public void setRampingRingerEnabled(boolean enabled) { 1178 Settings.System.putInt(getContext().getContentResolver(), 1179 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0); 1180 } 1181 1182 /** 1183 * Checks valid ringer mode values. 1184 * 1185 * @return true if the ringer mode indicated is valid, false otherwise. 1186 * 1187 * @see #setRingerMode(int) 1188 * @hide 1189 */ 1190 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isValidRingerMode(int ringerMode)1191 public static boolean isValidRingerMode(int ringerMode) { 1192 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) { 1193 return false; 1194 } 1195 final IAudioService service = getService(); 1196 try { 1197 return service.isValidRingerMode(ringerMode); 1198 } catch (RemoteException e) { 1199 throw e.rethrowFromSystemServer(); 1200 } 1201 } 1202 1203 /** 1204 * Returns the maximum volume index for a particular stream. 1205 * 1206 * @param streamType The stream type whose maximum volume index is returned. 1207 * @return The maximum valid volume index for the stream. 1208 * @see #getStreamVolume(int) 1209 */ getStreamMaxVolume(int streamType)1210 public int getStreamMaxVolume(int streamType) { 1211 final IAudioService service = getService(); 1212 try { 1213 return service.getStreamMaxVolume(streamType); 1214 } catch (RemoteException e) { 1215 throw e.rethrowFromSystemServer(); 1216 } 1217 } 1218 1219 /** 1220 * Returns the minimum volume index for a particular stream. 1221 * @param streamType The stream type whose minimum volume index is returned. Must be one of 1222 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, 1223 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, 1224 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}. 1225 * @return The minimum valid volume index for the stream. 1226 * @see #getStreamVolume(int) 1227 */ getStreamMinVolume(int streamType)1228 public int getStreamMinVolume(int streamType) { 1229 if (!isPublicStreamType(streamType)) { 1230 throw new IllegalArgumentException("Invalid stream type " + streamType); 1231 } 1232 return getStreamMinVolumeInt(streamType); 1233 } 1234 1235 /** 1236 * @hide 1237 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type. 1238 * @param streamType The stream type whose minimum volume index is returned. 1239 * @return The minimum valid volume index for the stream. 1240 * @see #getStreamVolume(int) 1241 */ 1242 @TestApi getStreamMinVolumeInt(int streamType)1243 public int getStreamMinVolumeInt(int streamType) { 1244 final IAudioService service = getService(); 1245 try { 1246 return service.getStreamMinVolume(streamType); 1247 } catch (RemoteException e) { 1248 throw e.rethrowFromSystemServer(); 1249 } 1250 } 1251 1252 /** 1253 * Returns the current volume index for a particular stream. 1254 * 1255 * @param streamType The stream type whose volume index is returned. 1256 * @return The current volume index for the stream. 1257 * @see #getStreamMaxVolume(int) 1258 * @see #setStreamVolume(int, int, int) 1259 */ getStreamVolume(int streamType)1260 public int getStreamVolume(int streamType) { 1261 final IAudioService service = getService(); 1262 try { 1263 return service.getStreamVolume(streamType); 1264 } catch (RemoteException e) { 1265 throw e.rethrowFromSystemServer(); 1266 } 1267 } 1268 1269 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h 1270 private static final float VOLUME_MIN_DB = -758.0f; 1271 1272 /** @hide */ 1273 @IntDef(flag = false, prefix = "STREAM", value = { 1274 STREAM_VOICE_CALL, 1275 STREAM_SYSTEM, 1276 STREAM_RING, 1277 STREAM_MUSIC, 1278 STREAM_ALARM, 1279 STREAM_NOTIFICATION, 1280 STREAM_DTMF, 1281 STREAM_ACCESSIBILITY } 1282 ) 1283 @Retention(RetentionPolicy.SOURCE) 1284 public @interface PublicStreamTypes {} 1285 1286 /** 1287 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on 1288 * the given type of audio output device. 1289 * @param streamType stream type for which the volume is queried. 1290 * @param index the volume index for which the volume is queried. The index value must be 1291 * between the minimum and maximum index values for the given stream type (see 1292 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}). 1293 * @param deviceType the type of audio output device for which volume is queried. 1294 * @return a volume expressed in dB. 1295 * A negative value indicates the audio signal is attenuated. A typical maximum value 1296 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is 1297 * reflected by a value of {@link Float#NEGATIVE_INFINITY}. 1298 */ getStreamVolumeDb(@ublicStreamTypes int streamType, int index, @AudioDeviceInfo.AudioDeviceTypeOut int deviceType)1299 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index, 1300 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { 1301 if (!isPublicStreamType(streamType)) { 1302 throw new IllegalArgumentException("Invalid stream type " + streamType); 1303 } 1304 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) { 1305 throw new IllegalArgumentException("Invalid stream volume index " + index); 1306 } 1307 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) { 1308 throw new IllegalArgumentException("Invalid audio output device type " + deviceType); 1309 } 1310 final float gain = AudioSystem.getStreamVolumeDB(streamType, index, 1311 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType)); 1312 if (gain <= VOLUME_MIN_DB) { 1313 return Float.NEGATIVE_INFINITY; 1314 } else { 1315 return gain; 1316 } 1317 } 1318 1319 /** 1320 * @hide 1321 * Checks whether a stream type is part of the public SDK 1322 * @param streamType 1323 * @return true if the stream type is available in SDK 1324 */ isPublicStreamType(int streamType)1325 public static boolean isPublicStreamType(int streamType) { 1326 switch (streamType) { 1327 case STREAM_VOICE_CALL: 1328 case STREAM_SYSTEM: 1329 case STREAM_RING: 1330 case STREAM_MUSIC: 1331 case STREAM_ALARM: 1332 case STREAM_NOTIFICATION: 1333 case STREAM_DTMF: 1334 case STREAM_ACCESSIBILITY: 1335 return true; 1336 default: 1337 return false; 1338 } 1339 } 1340 1341 /** 1342 * Get last audible volume before stream was muted. 1343 * 1344 * @hide 1345 */ 1346 @SystemApi 1347 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getLastAudibleStreamVolume(int streamType)1348 public int getLastAudibleStreamVolume(int streamType) { 1349 final IAudioService service = getService(); 1350 try { 1351 return service.getLastAudibleStreamVolume(streamType); 1352 } catch (RemoteException e) { 1353 throw e.rethrowFromSystemServer(); 1354 } 1355 } 1356 1357 /** 1358 * Get the stream type whose volume is driving the UI sounds volume. 1359 * UI sounds are screen lock/unlock, camera shutter, key clicks... 1360 * It is assumed that this stream type is also tied to ringer mode changes. 1361 * @hide 1362 */ getUiSoundsStreamType()1363 public int getUiSoundsStreamType() { 1364 final IAudioService service = getService(); 1365 try { 1366 return service.getUiSoundsStreamType(); 1367 } catch (RemoteException e) { 1368 throw e.rethrowFromSystemServer(); 1369 } 1370 } 1371 1372 /** 1373 * Sets the ringer mode. 1374 * <p> 1375 * Silent mode will mute the volume and will not vibrate. Vibrate mode will 1376 * mute the volume and vibrate. Normal mode will be audible and may vibrate 1377 * according to user settings. 1378 * <p>This method has no effect if the device implements a fixed volume policy 1379 * as indicated by {@link #isVolumeFixed()}. 1380 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 1381 * unless the app has been granted Do Not Disturb Access. 1382 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1383 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL}, 1384 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. 1385 * @see #getRingerMode() 1386 * @see #isVolumeFixed() 1387 */ setRingerMode(int ringerMode)1388 public void setRingerMode(int ringerMode) { 1389 if (!isValidRingerMode(ringerMode)) { 1390 return; 1391 } 1392 final IAudioService service = getService(); 1393 try { 1394 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName()); 1395 } catch (RemoteException e) { 1396 throw e.rethrowFromSystemServer(); 1397 } 1398 } 1399 1400 /** 1401 * Sets the volume index for a particular stream. 1402 * <p>This method has no effect if the device implements a fixed volume policy 1403 * as indicated by {@link #isVolumeFixed()}. 1404 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless 1405 * the app has been granted Do Not Disturb Access. 1406 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1407 * @param streamType The stream whose volume index should be set. 1408 * @param index The volume index to set. See 1409 * {@link #getStreamMaxVolume(int)} for the largest valid value. 1410 * @param flags 1411 * @see #getStreamMaxVolume(int) 1412 * @see #getStreamVolume(int) 1413 * @see #isVolumeFixed() 1414 * @throws SecurityException if the volume change triggers a Do Not Disturb change 1415 * and the caller is not granted notification policy access. 1416 */ setStreamVolume(int streamType, int index, @PublicVolumeFlags int flags)1417 public void setStreamVolume(int streamType, int index, @PublicVolumeFlags int flags) { 1418 final IAudioService service = getService(); 1419 try { 1420 service.setStreamVolumeWithAttribution(streamType, index, flags, 1421 getContext().getOpPackageName(), getContext().getAttributionTag()); 1422 } catch (RemoteException e) { 1423 throw e.rethrowFromSystemServer(); 1424 } 1425 } 1426 1427 /** 1428 * Sets the volume index for a particular {@link AudioAttributes}. 1429 * @param attr The {@link AudioAttributes} whose volume index should be set. 1430 * @param index The volume index to set. See 1431 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value 1432 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value. 1433 * @param flags 1434 * @see #getMaxVolumeIndexForAttributes(AudioAttributes) 1435 * @see #getMinVolumeIndexForAttributes(AudioAttributes) 1436 * @see #isVolumeFixed() 1437 * @hide 1438 */ 1439 @SystemApi 1440 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setVolumeIndexForAttributes(@onNull AudioAttributes attr, int index, @SystemVolumeFlags int flags)1441 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, 1442 @SystemVolumeFlags int flags) { 1443 Preconditions.checkNotNull(attr, "attr must not be null"); 1444 final IAudioService service = getService(); 1445 int groupId = getVolumeGroupIdForAttributes(attr); 1446 setVolumeGroupVolumeIndex(groupId, index, flags); 1447 } 1448 1449 /** 1450 * Returns the current volume index for a particular {@link AudioAttributes}. 1451 * 1452 * @param attr The {@link AudioAttributes} whose volume index is returned. 1453 * @return The current volume index for the stream. 1454 * @see #getMaxVolumeIndexForAttributes(AudioAttributes) 1455 * @see #getMinVolumeIndexForAttributes(AudioAttributes) 1456 * @see #setVolumeForAttributes(AudioAttributes, int, int) 1457 * @hide 1458 */ 1459 @SystemApi 1460 @IntRange(from = 0) 1461 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getVolumeIndexForAttributes(@onNull AudioAttributes attr)1462 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1463 Preconditions.checkNotNull(attr, "attr must not be null"); 1464 final IAudioService service = getService(); 1465 int groupId = getVolumeGroupIdForAttributes(attr); 1466 return getVolumeGroupVolumeIndex(groupId); 1467 } 1468 1469 /** 1470 * Returns the maximum volume index for a particular {@link AudioAttributes}. 1471 * 1472 * @param attr The {@link AudioAttributes} whose maximum volume index is returned. 1473 * @return The maximum valid volume index for the {@link AudioAttributes}. 1474 * @see #getVolumeIndexForAttributes(AudioAttributes) 1475 * @hide 1476 */ 1477 @SystemApi 1478 @IntRange(from = 0) 1479 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getMaxVolumeIndexForAttributes(@onNull AudioAttributes attr)1480 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1481 Preconditions.checkNotNull(attr, "attr must not be null"); 1482 final IAudioService service = getService(); 1483 int groupId = getVolumeGroupIdForAttributes(attr); 1484 return getVolumeGroupMaxVolumeIndex(groupId); 1485 } 1486 1487 /** 1488 * Returns the minimum volume index for a particular {@link AudioAttributes}. 1489 * 1490 * @param attr The {@link AudioAttributes} whose minimum volume index is returned. 1491 * @return The minimum valid volume index for the {@link AudioAttributes}. 1492 * @see #getVolumeIndexForAttributes(AudioAttributes) 1493 * @hide 1494 */ 1495 @SystemApi 1496 @IntRange(from = 0) 1497 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getMinVolumeIndexForAttributes(@onNull AudioAttributes attr)1498 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1499 Preconditions.checkNotNull(attr, "attr must not be null"); 1500 final IAudioService service = getService(); 1501 int groupId = getVolumeGroupIdForAttributes(attr); 1502 return getVolumeGroupMinVolumeIndex(groupId); 1503 } 1504 1505 /** 1506 * Returns the volume group id associated to the given {@link AudioAttributes}. 1507 * 1508 * @param attributes The {@link AudioAttributes} to consider. 1509 * @return audio volume group id supporting the given {@link AudioAttributes} if found, 1510 * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise. 1511 */ getVolumeGroupIdForAttributes(@onNull AudioAttributes attributes)1512 public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) { 1513 Preconditions.checkNotNull(attributes, "Audio Attributes must not be null"); 1514 return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes, 1515 /* fallbackOnDefault= */ true); 1516 } 1517 1518 /** 1519 * Sets the volume index for a particular group associated to given id. 1520 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} 1521 * to retrieve the volume group id supporting the given {@link AudioAttributes}. 1522 * 1523 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1524 * @param index The volume index to set. See 1525 * {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value 1526 * {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value. 1527 * @param flags 1528 * @hide 1529 */ 1530 @SystemApi 1531 @RequiresPermission(anyOf = { 1532 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 1533 android.Manifest.permission.MODIFY_AUDIO_ROUTING 1534 }) setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags)1535 public void setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags) { 1536 final IAudioService service = getService(); 1537 try { 1538 service.setVolumeGroupVolumeIndex(groupId, index, flags, 1539 getContext().getOpPackageName(), getContext().getAttributionTag()); 1540 } catch (RemoteException e) { 1541 throw e.rethrowFromSystemServer(); 1542 } 1543 } 1544 1545 /** 1546 * Returns the current volume index for a particular group associated to given id. 1547 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} 1548 * to retrieve the volume group id supporting the given {@link AudioAttributes}. 1549 * 1550 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1551 * @return The current volume index for the stream. 1552 * @hide 1553 */ 1554 @SystemApi 1555 @IntRange(from = 0) 1556 @RequiresPermission(anyOf = { 1557 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 1558 android.Manifest.permission.MODIFY_AUDIO_ROUTING 1559 }) getVolumeGroupVolumeIndex(int groupId)1560 public int getVolumeGroupVolumeIndex(int groupId) { 1561 final IAudioService service = getService(); 1562 try { 1563 return service.getVolumeGroupVolumeIndex(groupId); 1564 } catch (RemoteException e) { 1565 throw e.rethrowFromSystemServer(); 1566 } 1567 } 1568 1569 /** 1570 * Returns the maximum volume index for a particular group associated to given id. 1571 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} 1572 * to retrieve the volume group id supporting the given {@link AudioAttributes}. 1573 * 1574 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1575 * @return The maximum valid volume index for the {@link AudioAttributes}. 1576 * @hide 1577 */ 1578 @SystemApi 1579 @IntRange(from = 0) 1580 @RequiresPermission(anyOf = { 1581 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 1582 android.Manifest.permission.MODIFY_AUDIO_ROUTING 1583 }) getVolumeGroupMaxVolumeIndex(int groupId)1584 public int getVolumeGroupMaxVolumeIndex(int groupId) { 1585 final IAudioService service = getService(); 1586 try { 1587 return service.getVolumeGroupMaxVolumeIndex(groupId); 1588 } catch (RemoteException e) { 1589 throw e.rethrowFromSystemServer(); 1590 } 1591 } 1592 1593 /** 1594 * Returns the minimum volume index for a particular group associated to given id. 1595 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} 1596 * to retrieve the volume group id supporting the given {@link AudioAttributes}. 1597 * 1598 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1599 * @return The minimum valid volume index for the {@link AudioAttributes}. 1600 * @hide 1601 */ 1602 @SystemApi 1603 @IntRange(from = 0) 1604 @RequiresPermission(anyOf = { 1605 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 1606 android.Manifest.permission.MODIFY_AUDIO_ROUTING 1607 }) getVolumeGroupMinVolumeIndex(int groupId)1608 public int getVolumeGroupMinVolumeIndex(int groupId) { 1609 final IAudioService service = getService(); 1610 try { 1611 return service.getVolumeGroupMinVolumeIndex(groupId); 1612 } catch (RemoteException e) { 1613 throw e.rethrowFromSystemServer(); 1614 } 1615 } 1616 1617 /** 1618 * Adjusts the volume of a particular group associated to given id by one step in a direction. 1619 * <p> If the volume group is associated to a stream type, it fallbacks on 1620 * {@link #adjustStreamVolume(int, int, int)} for compatibility reason. 1621 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve 1622 * the volume group id supporting the given {@link AudioAttributes}. 1623 * 1624 * @param groupId of the audio volume group to consider. 1625 * @param direction The direction to adjust the volume. One of 1626 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 1627 * {@link #ADJUST_SAME}. 1628 * @param flags 1629 * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller 1630 * is not granted notification policy access. 1631 */ adjustVolumeGroupVolume(int groupId, int direction, @PublicVolumeFlags int flags)1632 public void adjustVolumeGroupVolume(int groupId, int direction, @PublicVolumeFlags int flags) { 1633 IAudioService service = getService(); 1634 try { 1635 service.adjustVolumeGroupVolume(groupId, direction, flags, 1636 getContext().getOpPackageName()); 1637 } catch (RemoteException e) { 1638 throw e.rethrowFromSystemServer(); 1639 } 1640 } 1641 1642 /** 1643 * Get last audible volume of the group associated to given id before it was muted. 1644 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve 1645 * the volume group id supporting the given {@link AudioAttributes}. 1646 * 1647 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1648 * @return current volume if not muted, volume before muted otherwise. 1649 * @hide 1650 */ 1651 @SystemApi 1652 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") 1653 @IntRange(from = 0) getLastAudibleVolumeForVolumeGroup(int groupId)1654 public int getLastAudibleVolumeForVolumeGroup(int groupId) { 1655 IAudioService service = getService(); 1656 try { 1657 return service.getLastAudibleVolumeForVolumeGroup(groupId); 1658 } catch (RemoteException e) { 1659 throw e.rethrowFromSystemServer(); 1660 } 1661 } 1662 1663 /** 1664 * Returns the current mute state for a particular volume group associated to the given id. 1665 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve 1666 * the volume group id supporting the given {@link AudioAttributes}. 1667 * 1668 * @param groupId of the audio volume group to consider. 1669 * @return The mute state for the given audio volume group id. 1670 * @see #adjustVolumeGroupVolume(int, int, int) 1671 */ isVolumeGroupMuted(int groupId)1672 public boolean isVolumeGroupMuted(int groupId) { 1673 IAudioService service = getService(); 1674 try { 1675 return service.isVolumeGroupMuted(groupId); 1676 } catch (RemoteException e) { 1677 throw e.rethrowFromSystemServer(); 1678 } 1679 } 1680 1681 /** 1682 * Set the system usages to be supported on this device. 1683 * @param systemUsages array of system usages to support {@link AttributeSystemUsage} 1684 * @hide 1685 */ 1686 @SystemApi 1687 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setSupportedSystemUsages(@onNull @ttributeSystemUsage int[] systemUsages)1688 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) { 1689 Objects.requireNonNull(systemUsages, "systemUsages must not be null"); 1690 final IAudioService service = getService(); 1691 try { 1692 service.setSupportedSystemUsages(systemUsages); 1693 } catch (RemoteException e) { 1694 throw e.rethrowFromSystemServer(); 1695 } 1696 } 1697 1698 /** 1699 * Get the system usages supported on this device. 1700 * @return array of supported system usages {@link AttributeSystemUsage} 1701 * @hide 1702 */ 1703 @SystemApi 1704 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getSupportedSystemUsages()1705 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() { 1706 final IAudioService service = getService(); 1707 try { 1708 return service.getSupportedSystemUsages(); 1709 } catch (RemoteException e) { 1710 throw e.rethrowFromSystemServer(); 1711 } 1712 } 1713 1714 /** 1715 * Solo or unsolo a particular stream. 1716 * <p> 1717 * Do not use. This method has been deprecated and is now a no-op. 1718 * {@link #requestAudioFocus} should be used for exclusive audio playback. 1719 * 1720 * @param streamType The stream to be soloed/unsoloed. 1721 * @param state The required solo state: true for solo ON, false for solo 1722 * OFF 1723 * @see #isVolumeFixed() 1724 * @deprecated Do not use. If you need exclusive audio playback use 1725 * {@link #requestAudioFocus}. 1726 */ 1727 @Deprecated setStreamSolo(int streamType, boolean state)1728 public void setStreamSolo(int streamType, boolean state) { 1729 Log.w(TAG, "setStreamSolo has been deprecated. Do not use."); 1730 } 1731 1732 /** 1733 * Mute or unmute an audio stream. 1734 * <p> 1735 * This method should only be used by applications that replace the 1736 * platform-wide management of audio settings or the main telephony 1737 * application. 1738 * <p> 1739 * This method has no effect if the device implements a fixed volume policy 1740 * as indicated by {@link #isVolumeFixed()}. 1741 * <p> 1742 * This method was deprecated in API level 22. Prior to API level 22 this 1743 * method had significantly different behavior and should be used carefully. 1744 * The following applies only to pre-22 platforms: 1745 * <ul> 1746 * <li>The mute command is protected against client process death: if a 1747 * process with an active mute request on a stream dies, this stream will be 1748 * unmuted automatically.</li> 1749 * <li>The mute requests for a given stream are cumulative: the AudioManager 1750 * can receive several mute requests from one or more clients and the stream 1751 * will be unmuted only when the same number of unmute requests are 1752 * received.</li> 1753 * <li>For a better user experience, applications MUST unmute a muted stream 1754 * in onPause() and mute is again in onResume() if appropriate.</li> 1755 * </ul> 1756 * 1757 * @param streamType The stream to be muted/unmuted. 1758 * @param state The required mute state: true for mute ON, false for mute 1759 * OFF 1760 * @see #isVolumeFixed() 1761 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with 1762 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead. 1763 */ 1764 @Deprecated setStreamMute(int streamType, boolean state)1765 public void setStreamMute(int streamType, boolean state) { 1766 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead."); 1767 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE; 1768 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 1769 adjustSuggestedStreamVolume(direction, streamType, 0); 1770 } else { 1771 adjustStreamVolume(streamType, direction, 0); 1772 } 1773 } 1774 1775 /** 1776 * Returns the current mute state for a particular stream. 1777 * 1778 * @param streamType The stream to get mute state for. 1779 * @return The mute state for the given stream. 1780 * @see #adjustStreamVolume(int, int, int) 1781 */ isStreamMute(int streamType)1782 public boolean isStreamMute(int streamType) { 1783 final IAudioService service = getService(); 1784 try { 1785 return service.isStreamMute(streamType); 1786 } catch (RemoteException e) { 1787 throw e.rethrowFromSystemServer(); 1788 } 1789 } 1790 1791 /** 1792 * get master mute state. 1793 * 1794 * @hide 1795 */ 1796 @UnsupportedAppUsage isMasterMute()1797 public boolean isMasterMute() { 1798 final IAudioService service = getService(); 1799 try { 1800 return service.isMasterMute(); 1801 } catch (RemoteException e) { 1802 throw e.rethrowFromSystemServer(); 1803 } 1804 } 1805 1806 /** 1807 * forces the stream controlled by hard volume keys 1808 * specifying streamType == -1 releases control to the 1809 * logic. 1810 * 1811 * @hide 1812 */ 1813 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) 1814 @UnsupportedAppUsage forceVolumeControlStream(int streamType)1815 public void forceVolumeControlStream(int streamType) { 1816 final IAudioService service = getService(); 1817 try { 1818 service.forceVolumeControlStream(streamType, mICallBack); 1819 } catch (RemoteException e) { 1820 throw e.rethrowFromSystemServer(); 1821 } 1822 } 1823 1824 /** 1825 * Returns whether a particular type should vibrate according to user 1826 * settings and the current ringer mode. 1827 * <p> 1828 * This shouldn't be needed by most clients that use notifications to 1829 * vibrate. The notification manager will not vibrate if the policy doesn't 1830 * allow it, so the client should always set a vibrate pattern and let the 1831 * notification manager control whether or not to actually vibrate. 1832 * 1833 * @param vibrateType The type of vibrate. One of 1834 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1835 * {@link #VIBRATE_TYPE_RINGER}. 1836 * @return Whether the type should vibrate at the instant this method is 1837 * called. 1838 * @see #setVibrateSetting(int, int) 1839 * @see #getVibrateSetting(int) 1840 * @deprecated Applications should maintain their own vibrate policy based on 1841 * current ringer mode that can be queried via {@link #getRingerMode()}. 1842 */ shouldVibrate(int vibrateType)1843 public boolean shouldVibrate(int vibrateType) { 1844 final IAudioService service = getService(); 1845 try { 1846 return service.shouldVibrate(vibrateType); 1847 } catch (RemoteException e) { 1848 throw e.rethrowFromSystemServer(); 1849 } 1850 } 1851 1852 /** 1853 * Returns whether the user's vibrate setting for a vibrate type. 1854 * <p> 1855 * This shouldn't be needed by most clients that want to vibrate, instead 1856 * see {@link #shouldVibrate(int)}. 1857 * 1858 * @param vibrateType The type of vibrate. One of 1859 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1860 * {@link #VIBRATE_TYPE_RINGER}. 1861 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON}, 1862 * {@link #VIBRATE_SETTING_OFF}, or 1863 * {@link #VIBRATE_SETTING_ONLY_SILENT}. 1864 * @see #setVibrateSetting(int, int) 1865 * @see #shouldVibrate(int) 1866 * @deprecated Applications should maintain their own vibrate policy based on 1867 * current ringer mode that can be queried via {@link #getRingerMode()}. 1868 */ getVibrateSetting(int vibrateType)1869 public int getVibrateSetting(int vibrateType) { 1870 final IAudioService service = getService(); 1871 try { 1872 return service.getVibrateSetting(vibrateType); 1873 } catch (RemoteException e) { 1874 throw e.rethrowFromSystemServer(); 1875 } 1876 } 1877 1878 /** 1879 * Sets the setting for when the vibrate type should vibrate. 1880 * <p> 1881 * This method should only be used by applications that replace the platform-wide 1882 * management of audio settings or the main telephony application. 1883 * 1884 * @param vibrateType The type of vibrate. One of 1885 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1886 * {@link #VIBRATE_TYPE_RINGER}. 1887 * @param vibrateSetting The vibrate setting, one of 1888 * {@link #VIBRATE_SETTING_ON}, 1889 * {@link #VIBRATE_SETTING_OFF}, or 1890 * {@link #VIBRATE_SETTING_ONLY_SILENT}. 1891 * @see #getVibrateSetting(int) 1892 * @see #shouldVibrate(int) 1893 * @deprecated Applications should maintain their own vibrate policy based on 1894 * current ringer mode that can be queried via {@link #getRingerMode()}. 1895 */ setVibrateSetting(int vibrateType, int vibrateSetting)1896 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 1897 final IAudioService service = getService(); 1898 try { 1899 service.setVibrateSetting(vibrateType, vibrateSetting); 1900 } catch (RemoteException e) { 1901 throw e.rethrowFromSystemServer(); 1902 } 1903 } 1904 1905 /** 1906 * Sets the speakerphone on or off. 1907 * <p> 1908 * This method should only be used by applications that replace the platform-wide 1909 * management of audio settings or the main telephony application. 1910 * 1911 * @param on set <var>true</var> to turn on speakerphone; 1912 * <var>false</var> to turn it off 1913 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} or 1914 * {@link AudioManager#clearCommunicationDevice()} instead. 1915 */ setSpeakerphoneOn(boolean on)1916 @Deprecated public void setSpeakerphoneOn(boolean on) { 1917 final IAudioService service = getService(); 1918 try { 1919 service.setSpeakerphoneOn(mICallBack, on); 1920 } catch (RemoteException e) { 1921 throw e.rethrowFromSystemServer(); 1922 } 1923 } 1924 1925 /** 1926 * Checks whether the speakerphone is on or off. 1927 * 1928 * @return true if speakerphone is on, false if it's off 1929 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead. 1930 */ isSpeakerphoneOn()1931 @Deprecated public boolean isSpeakerphoneOn() { 1932 final IAudioService service = getService(); 1933 try { 1934 return service.isSpeakerphoneOn(); 1935 } catch (RemoteException e) { 1936 throw e.rethrowFromSystemServer(); 1937 } 1938 } 1939 1940 /** 1941 * Specifies whether the audio played by this app may or may not be captured by other apps or 1942 * the system. 1943 * 1944 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}. 1945 * 1946 * There are multiple ways to set this policy: 1947 * <ul> 1948 * <li> for each track independently, see 1949 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li> 1950 * <li> application-wide at runtime, with this method </li> 1951 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application 1952 * manifest. </li> 1953 * </ul> 1954 * The most restrictive policy is always applied. 1955 * 1956 * See {@link AudioPlaybackCaptureConfiguration} for more details on 1957 * which audio signals can be captured. 1958 * 1959 * @param capturePolicy one of 1960 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, 1961 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, 1962 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. 1963 * @throws RuntimeException if the argument is not a valid value. 1964 */ setAllowedCapturePolicy(@udioAttributes.CapturePolicy int capturePolicy)1965 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) { 1966 // TODO: also pass the package in case multiple packages have the same UID 1967 final IAudioService service = getService(); 1968 try { 1969 int result = service.setAllowedCapturePolicy(capturePolicy); 1970 if (result != AudioSystem.AUDIO_STATUS_OK) { 1971 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); 1972 return; 1973 } 1974 } catch (RemoteException e) { 1975 throw e.rethrowFromSystemServer(); 1976 } 1977 } 1978 1979 /** 1980 * Return the capture policy. 1981 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or 1982 * the default if it was not called. 1983 */ 1984 @AudioAttributes.CapturePolicy getAllowedCapturePolicy()1985 public int getAllowedCapturePolicy() { 1986 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL; 1987 try { 1988 result = getService().getAllowedCapturePolicy(); 1989 } catch (RemoteException e) { 1990 Log.e(TAG, "Failed to query allowed capture policy: " + e); 1991 } 1992 return result; 1993 } 1994 1995 //==================================================================== 1996 // Audio Product Strategy routing 1997 1998 /** 1999 * @hide 2000 * Set the preferred device for a given strategy, i.e. the audio routing to be used by 2001 * this audio strategy. Note that the device may not be available at the time the preferred 2002 * device is set, but it will be used once made available. 2003 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting 2004 * this preference for this strategy.</p> 2005 * @param strategy the audio strategy whose routing will be affected 2006 * @param device the audio device to route to when available 2007 * @return true if the operation was successful, false otherwise 2008 */ 2009 @SystemApi 2010 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDeviceForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2011 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy, 2012 @NonNull AudioDeviceAttributes device) { 2013 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device)); 2014 } 2015 2016 /** 2017 * @hide 2018 * Removes the preferred audio device(s) previously set with 2019 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 2020 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}. 2021 * @param strategy the audio strategy whose routing will be affected 2022 * @return true if the operation was successful, false otherwise (invalid strategy, or no 2023 * device set for example) 2024 */ 2025 @SystemApi 2026 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removePreferredDeviceForStrategy(@onNull AudioProductStrategy strategy)2027 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) { 2028 Objects.requireNonNull(strategy); 2029 try { 2030 final int status = 2031 getService().removePreferredDevicesForStrategy(strategy.getId()); 2032 return status == AudioSystem.SUCCESS; 2033 } catch (RemoteException e) { 2034 throw e.rethrowFromSystemServer(); 2035 } 2036 } 2037 2038 /** 2039 * @hide 2040 * Return the preferred device for an audio strategy, previously set with 2041 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 2042 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 2043 * @param strategy the strategy to query 2044 * @return the preferred device for that strategy, if multiple devices are set as preferred 2045 * devices, the first one in the list will be returned. Null will be returned if none was 2046 * ever set or if the strategy is invalid 2047 */ 2048 @SystemApi 2049 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2050 @Nullable getPreferredDeviceForStrategy( @onNull AudioProductStrategy strategy)2051 public AudioDeviceAttributes getPreferredDeviceForStrategy( 2052 @NonNull AudioProductStrategy strategy) { 2053 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy); 2054 return devices.isEmpty() ? null : devices.get(0); 2055 } 2056 2057 /** 2058 * @hide 2059 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by 2060 * this audio strategy. Note that the devices may not be available at the time the preferred 2061 * devices is set, but it will be used once made available. 2062 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting 2063 * this preference for this strategy.</p> 2064 * Note that the list of devices is not a list ranked by preference, but a list of one or more 2065 * devices used simultaneously to output the same audio signal. 2066 * @param strategy the audio strategy whose routing will be affected 2067 * @param devices a non-empty list of the audio devices to route to when available 2068 * @return true if the operation was successful, false otherwise 2069 */ 2070 @SystemApi 2071 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDevicesForStrategy(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2072 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy, 2073 @NonNull List<AudioDeviceAttributes> devices) { 2074 Objects.requireNonNull(strategy); 2075 Objects.requireNonNull(devices); 2076 if (devices.isEmpty()) { 2077 throw new IllegalArgumentException( 2078 "Tried to set preferred devices for strategy with a empty list"); 2079 } 2080 for (AudioDeviceAttributes device : devices) { 2081 Objects.requireNonNull(device); 2082 } 2083 try { 2084 final int status = 2085 getService().setPreferredDevicesForStrategy(strategy.getId(), devices); 2086 return status == AudioSystem.SUCCESS; 2087 } catch (RemoteException e) { 2088 throw e.rethrowFromSystemServer(); 2089 } 2090 } 2091 2092 /** 2093 * @hide 2094 * Return the preferred devices for an audio strategy, previously set with 2095 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2096 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 2097 * @param strategy the strategy to query 2098 * @return list of the preferred devices for that strategy 2099 */ 2100 @SystemApi 2101 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2102 @NonNull getPreferredDevicesForStrategy( @onNull AudioProductStrategy strategy)2103 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy( 2104 @NonNull AudioProductStrategy strategy) { 2105 Objects.requireNonNull(strategy); 2106 try { 2107 return getService().getPreferredDevicesForStrategy(strategy.getId()); 2108 } catch (RemoteException e) { 2109 throw e.rethrowFromSystemServer(); 2110 } 2111 } 2112 2113 /** 2114 * @hide 2115 * Set a device as non-default for a given strategy, i.e. the audio routing to be avoided by 2116 * this audio strategy. 2117 * <p>Use 2118 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2119 * to cancel setting this preference for this strategy.</p> 2120 * @param strategy the audio strategy whose routing will be affected 2121 * @param device the audio device to not route to when available 2122 * @return true if the operation was successful, false otherwise 2123 */ 2124 @SystemApi 2125 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setDeviceAsNonDefaultForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2126 public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy, 2127 @NonNull AudioDeviceAttributes device) { 2128 Objects.requireNonNull(strategy); 2129 Objects.requireNonNull(device); 2130 try { 2131 final int status = 2132 getService().setDeviceAsNonDefaultForStrategy(strategy.getId(), device); 2133 return status == AudioSystem.SUCCESS; 2134 } catch (RemoteException e) { 2135 throw e.rethrowFromSystemServer(); 2136 } 2137 } 2138 2139 /** 2140 * @hide 2141 * Removes the audio device(s) from the non-default device list previously set with 2142 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2143 * @param strategy the audio strategy whose routing will be affected 2144 * @param device the audio device to remove from the non-default device list 2145 * @return true if the operation was successful, false otherwise (invalid strategy, or no 2146 * device set for example) 2147 */ 2148 @SystemApi 2149 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeDeviceAsNonDefaultForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2150 public boolean removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy, 2151 @NonNull AudioDeviceAttributes device) { 2152 Objects.requireNonNull(strategy); 2153 Objects.requireNonNull(device); 2154 try { 2155 final int status = 2156 getService().removeDeviceAsNonDefaultForStrategy(strategy.getId(), device); 2157 return status == AudioSystem.SUCCESS; 2158 } catch (RemoteException e) { 2159 throw e.rethrowFromSystemServer(); 2160 } 2161 } 2162 2163 /** 2164 * @hide 2165 * Gets the audio device(s) from the non-default device list previously set with 2166 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2167 * @param strategy the audio strategy to query 2168 * @return list of non-default devices for the strategy 2169 */ 2170 @SystemApi 2171 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2172 @NonNull getNonDefaultDevicesForStrategy( @onNull AudioProductStrategy strategy)2173 public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy( 2174 @NonNull AudioProductStrategy strategy) { 2175 Objects.requireNonNull(strategy); 2176 try { 2177 return getService().getNonDefaultDevicesForStrategy(strategy.getId()); 2178 } catch (RemoteException e) { 2179 throw e.rethrowFromSystemServer(); 2180 } 2181 } 2182 2183 /** 2184 * @hide 2185 * Interface to be notified of changes in the preferred audio device set for a given audio 2186 * strategy. 2187 * <p>Note that this listener will only be invoked whenever 2188 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 2189 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 2190 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in 2191 * preferred device. It will not be invoked directly after registration with 2192 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)} 2193 * to indicate which strategies had preferred devices at the time of registration.</p> 2194 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) 2195 * @see #removePreferredDeviceForStrategy(AudioProductStrategy) 2196 * @see #getPreferredDeviceForStrategy(AudioProductStrategy) 2197 * @deprecated use #OnPreferredDevicesForStrategyChangedListener 2198 */ 2199 @SystemApi 2200 @Deprecated 2201 public interface OnPreferredDeviceForStrategyChangedListener { 2202 /** 2203 * Called on the listener to indicate that the preferred audio device for the given 2204 * strategy has changed. 2205 * @param strategy the {@link AudioProductStrategy} whose preferred device changed 2206 * @param device <code>null</code> if the preferred device was removed, or the newly set 2207 * preferred audio device 2208 */ onPreferredDeviceForStrategyChanged(@onNull AudioProductStrategy strategy, @Nullable AudioDeviceAttributes device)2209 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy, 2210 @Nullable AudioDeviceAttributes device); 2211 } 2212 2213 /** 2214 * @hide 2215 * Interface to be notified of changes in the preferred audio devices set for a given audio 2216 * strategy. 2217 * <p>Note that this listener will only be invoked whenever 2218 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}, 2219 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}, 2220 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}, 2221 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2222 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in 2223 * preferred device(s). It will not be invoked directly after registration with 2224 * {@link #addOnPreferredDevicesForStrategyChangedListener( 2225 * Executor, OnPreferredDevicesForStrategyChangedListener)} 2226 * to indicate which strategies had preferred devices at the time of registration.</p> 2227 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) 2228 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List) 2229 * @see #removePreferredDeviceForStrategy(AudioProductStrategy) 2230 * @see #getPreferredDevicesForStrategy(AudioProductStrategy) 2231 */ 2232 @SystemApi 2233 public interface OnPreferredDevicesForStrategyChangedListener { 2234 /** 2235 * Called on the listener to indicate that the preferred audio devices for the given 2236 * strategy has changed. 2237 * @param strategy the {@link AudioProductStrategy} whose preferred device changed 2238 * @param devices a list of newly set preferred audio devices 2239 */ onPreferredDevicesForStrategyChanged(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2240 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy, 2241 @NonNull List<AudioDeviceAttributes> devices); 2242 } 2243 2244 /** 2245 * @hide 2246 * Adds a listener for being notified of changes to the strategy-preferred audio device. 2247 * @param executor 2248 * @param listener 2249 * @throws SecurityException if the caller doesn't hold the required permission 2250 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener( 2251 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead 2252 */ 2253 @SystemApi 2254 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2255 @Deprecated addOnPreferredDeviceForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDeviceForStrategyChangedListener listener)2256 public void addOnPreferredDeviceForStrategyChangedListener( 2257 @NonNull @CallbackExecutor Executor executor, 2258 @NonNull OnPreferredDeviceForStrategyChangedListener listener) 2259 throws SecurityException { 2260 // No-op, the method is deprecated. 2261 } 2262 2263 /** 2264 * @hide 2265 * Removes a previously added listener of changes to the strategy-preferred audio device. 2266 * @param listener 2267 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener( 2268 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead 2269 */ 2270 @SystemApi 2271 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2272 @Deprecated removeOnPreferredDeviceForStrategyChangedListener( @onNull OnPreferredDeviceForStrategyChangedListener listener)2273 public void removeOnPreferredDeviceForStrategyChangedListener( 2274 @NonNull OnPreferredDeviceForStrategyChangedListener listener) { 2275 // No-op, the method is deprecated. 2276 } 2277 2278 /** 2279 * @hide 2280 * Adds a listener for being notified of changes to the strategy-preferred audio device. 2281 * @param executor 2282 * @param listener 2283 * @throws SecurityException if the caller doesn't hold the required permission 2284 */ 2285 @SystemApi 2286 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) addOnPreferredDevicesForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDevicesForStrategyChangedListener listener)2287 public void addOnPreferredDevicesForStrategyChangedListener( 2288 @NonNull @CallbackExecutor Executor executor, 2289 @NonNull OnPreferredDevicesForStrategyChangedListener listener) 2290 throws SecurityException { 2291 Objects.requireNonNull(executor); 2292 Objects.requireNonNull(listener); 2293 mPrefDevListenerMgr.addListener( 2294 executor, listener, "addOnPreferredDevicesForStrategyChangedListener", 2295 () -> new StrategyPreferredDevicesDispatcherStub()); 2296 } 2297 2298 /** 2299 * @hide 2300 * Removes a previously added listener of changes to the strategy-preferred audio device. 2301 * @param listener 2302 */ 2303 @SystemApi 2304 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeOnPreferredDevicesForStrategyChangedListener( @onNull OnPreferredDevicesForStrategyChangedListener listener)2305 public void removeOnPreferredDevicesForStrategyChangedListener( 2306 @NonNull OnPreferredDevicesForStrategyChangedListener listener) { 2307 Objects.requireNonNull(listener); 2308 mPrefDevListenerMgr.removeListener( 2309 listener, "removeOnPreferredDevicesForStrategyChangedListener"); 2310 } 2311 2312 /** 2313 * @hide 2314 * Interface to be notified of changes in the non-default audio devices set for a given audio 2315 * strategy. 2316 * <p>Note that this listener will only be invoked whenever 2317 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}, 2318 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}, 2319 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}, 2320 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2321 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in 2322 * non-default device(s). It will not be invoked directly after registration with 2323 * {@link #addOnNonDefaultDevicesForStrategyChangedListener( 2324 * Executor, OnNonDefaultDevicesForStrategyChangedListener)} 2325 * to indicate which strategies had preferred devices at the time of registration.</p> 2326 * @see #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes) 2327 * @see #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes) 2328 */ 2329 @SystemApi 2330 public interface OnNonDefaultDevicesForStrategyChangedListener { 2331 /** 2332 * Called on the listener to indicate that the non-default audio devices for the given 2333 * strategy has changed. 2334 * @param strategy the {@link AudioProductStrategy} whose non-default device changed 2335 * @param devices a list of newly set non-default audio devices 2336 */ onNonDefaultDevicesForStrategyChanged(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2337 void onNonDefaultDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy, 2338 @NonNull List<AudioDeviceAttributes> devices); 2339 } 2340 2341 /** 2342 * @hide 2343 * Adds a listener for being notified of changes to the non-default audio devices for 2344 * strategies. 2345 * @param executor 2346 * @param listener 2347 * @throws SecurityException if the caller doesn't hold the required permission 2348 */ 2349 @SystemApi 2350 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) addOnNonDefaultDevicesForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)2351 public void addOnNonDefaultDevicesForStrategyChangedListener( 2352 @NonNull @CallbackExecutor Executor executor, 2353 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) 2354 throws SecurityException { 2355 Objects.requireNonNull(executor); 2356 Objects.requireNonNull(listener); 2357 2358 mNonDefDevListenerMgr.addListener( 2359 executor, listener, "addOnNonDefaultDevicesForStrategyChangedListener", 2360 () -> new StrategyNonDefaultDevicesDispatcherStub()); 2361 } 2362 2363 /** 2364 * @hide 2365 * Removes a previously added listener of changes to the non-default audio device for 2366 * strategies. 2367 * @param listener 2368 */ 2369 @SystemApi 2370 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeOnNonDefaultDevicesForStrategyChangedListener( @onNull OnNonDefaultDevicesForStrategyChangedListener listener)2371 public void removeOnNonDefaultDevicesForStrategyChangedListener( 2372 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) { 2373 Objects.requireNonNull(listener); 2374 mNonDefDevListenerMgr.removeListener( 2375 listener, "removeOnNonDefaultDevicesForStrategyChangedListener"); 2376 } 2377 2378 /** 2379 * Manages the OnPreferredDevicesForStrategyChangedListener listeners and the 2380 * StrategyPreferredDevicesDispatcherStub 2381 */ 2382 private final CallbackUtil.LazyListenerManager<OnPreferredDevicesForStrategyChangedListener> 2383 mPrefDevListenerMgr = new CallbackUtil.LazyListenerManager(); 2384 2385 /** 2386 * Manages the OnNonDefaultDevicesForStrategyChangedListener listeners and the 2387 * StrategyNonDefaultDevicesDispatcherStub 2388 */ 2389 private final CallbackUtil.LazyListenerManager<OnNonDefaultDevicesForStrategyChangedListener> 2390 mNonDefDevListenerMgr = new CallbackUtil.LazyListenerManager(); 2391 2392 private final class StrategyPreferredDevicesDispatcherStub 2393 extends IStrategyPreferredDevicesDispatcher.Stub 2394 implements CallbackUtil.DispatcherStub { 2395 2396 @Override dispatchPrefDevicesChanged(int strategyId, @NonNull List<AudioDeviceAttributes> devices)2397 public void dispatchPrefDevicesChanged(int strategyId, 2398 @NonNull List<AudioDeviceAttributes> devices) { 2399 final AudioProductStrategy strategy = 2400 AudioProductStrategy.getAudioProductStrategyWithId(strategyId); 2401 2402 mPrefDevListenerMgr.callListeners( 2403 (listener) -> listener.onPreferredDevicesForStrategyChanged(strategy, devices)); 2404 } 2405 2406 @Override register(boolean register)2407 public void register(boolean register) { 2408 try { 2409 if (register) { 2410 getService().registerStrategyPreferredDevicesDispatcher(this); 2411 } else { 2412 getService().unregisterStrategyPreferredDevicesDispatcher(this); 2413 } 2414 } catch (RemoteException e) { 2415 e.rethrowFromSystemServer(); 2416 } 2417 } 2418 } 2419 2420 private final class StrategyNonDefaultDevicesDispatcherStub 2421 extends IStrategyNonDefaultDevicesDispatcher.Stub 2422 implements CallbackUtil.DispatcherStub { 2423 2424 @Override dispatchNonDefDevicesChanged(int strategyId, @NonNull List<AudioDeviceAttributes> devices)2425 public void dispatchNonDefDevicesChanged(int strategyId, 2426 @NonNull List<AudioDeviceAttributes> devices) { 2427 final AudioProductStrategy strategy = 2428 AudioProductStrategy.getAudioProductStrategyWithId(strategyId); 2429 2430 mNonDefDevListenerMgr.callListeners( 2431 (listener) -> listener.onNonDefaultDevicesForStrategyChanged( 2432 strategy, devices)); 2433 } 2434 2435 @Override register(boolean register)2436 public void register(boolean register) { 2437 try { 2438 if (register) { 2439 getService().registerStrategyNonDefaultDevicesDispatcher(this); 2440 } else { 2441 getService().unregisterStrategyNonDefaultDevicesDispatcher(this); 2442 } 2443 } catch (RemoteException e) { 2444 e.rethrowFromSystemServer(); 2445 } 2446 } 2447 } 2448 2449 //==================================================================== 2450 // Audio Capture Preset routing 2451 2452 /** 2453 * @hide 2454 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by 2455 * this capture preset. Note that the device may not be available at the time the preferred 2456 * device is set, but it will be used once made available. 2457 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference 2458 * for this capture preset.</p> 2459 * @param capturePreset the audio capture preset whose routing will be affected 2460 * @param device the audio device to route to when available 2461 * @return true if the operation was successful, false otherwise 2462 */ 2463 @SystemApi 2464 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDeviceForCapturePreset(@ediaRecorder.SystemSource int capturePreset, @NonNull AudioDeviceAttributes device)2465 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset, 2466 @NonNull AudioDeviceAttributes device) { 2467 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device)); 2468 } 2469 2470 /** 2471 * @hide 2472 * Remove all the preferred audio devices previously set 2473 * @param capturePreset the audio capture preset whose routing will be affected 2474 * @return true if the operation was successful, false otherwise (invalid capture preset, or no 2475 * device set for example) 2476 */ 2477 @SystemApi 2478 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) clearPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset)2479 public boolean clearPreferredDevicesForCapturePreset( 2480 @MediaRecorder.SystemSource int capturePreset) { 2481 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2482 return false; 2483 } 2484 try { 2485 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset); 2486 return status == AudioSystem.SUCCESS; 2487 } catch (RemoteException e) { 2488 throw e.rethrowFromSystemServer(); 2489 } 2490 } 2491 2492 /** 2493 * @hide 2494 * Return the preferred devices for an audio capture preset, previously set with 2495 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} 2496 * @param capturePreset the capture preset to query 2497 * @return a list that contains preferred devices for that capture preset. 2498 */ 2499 @NonNull 2500 @SystemApi 2501 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset)2502 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset( 2503 @MediaRecorder.SystemSource int capturePreset) { 2504 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2505 return new ArrayList<AudioDeviceAttributes>(); 2506 } 2507 try { 2508 return getService().getPreferredDevicesForCapturePreset(capturePreset); 2509 } catch (RemoteException e) { 2510 throw e.rethrowFromSystemServer(); 2511 } 2512 } 2513 setPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset, @NonNull List<AudioDeviceAttributes> devices)2514 private boolean setPreferredDevicesForCapturePreset( 2515 @MediaRecorder.SystemSource int capturePreset, 2516 @NonNull List<AudioDeviceAttributes> devices) { 2517 Objects.requireNonNull(devices); 2518 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2519 return false; 2520 } 2521 if (devices.size() != 1) { 2522 throw new IllegalArgumentException( 2523 "Only support setting one preferred devices for capture preset"); 2524 } 2525 for (AudioDeviceAttributes device : devices) { 2526 Objects.requireNonNull(device); 2527 } 2528 try { 2529 final int status = 2530 getService().setPreferredDevicesForCapturePreset(capturePreset, devices); 2531 return status == AudioSystem.SUCCESS; 2532 } catch (RemoteException e) { 2533 throw e.rethrowFromSystemServer(); 2534 } 2535 } 2536 2537 /** 2538 * @hide 2539 * Interface to be notified of changes in the preferred audio devices set for a given capture 2540 * preset. 2541 * <p>Note that this listener will only be invoked whenever 2542 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or 2543 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in 2544 * preferred device. It will not be invoked directly after registration with 2545 * {@link #addOnPreferredDevicesForCapturePresetChangedListener( 2546 * Executor, OnPreferredDevicesForCapturePresetChangedListener)} 2547 * to indicate which strategies had preferred devices at the time of registration.</p> 2548 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes) 2549 * @see #clearPreferredDevicesForCapturePreset(int) 2550 * @see #getPreferredDevicesForCapturePreset(int) 2551 */ 2552 @SystemApi 2553 public interface OnPreferredDevicesForCapturePresetChangedListener { 2554 /** 2555 * Called on the listener to indicate that the preferred audio devices for the given 2556 * capture preset has changed. 2557 * @param capturePreset the capture preset whose preferred device changed 2558 * @param devices a list of newly set preferred audio devices 2559 */ onPreferredDevicesForCapturePresetChanged( @ediaRecorder.SystemSource int capturePreset, @NonNull List<AudioDeviceAttributes> devices)2560 void onPreferredDevicesForCapturePresetChanged( 2561 @MediaRecorder.SystemSource int capturePreset, 2562 @NonNull List<AudioDeviceAttributes> devices); 2563 } 2564 2565 /** 2566 * @hide 2567 * Adds a listener for being notified of changes to the capture-preset-preferred audio device. 2568 * @param executor 2569 * @param listener 2570 * @throws SecurityException if the caller doesn't hold the required permission 2571 */ 2572 @SystemApi 2573 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) addOnPreferredDevicesForCapturePresetChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)2574 public void addOnPreferredDevicesForCapturePresetChangedListener( 2575 @NonNull @CallbackExecutor Executor executor, 2576 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) 2577 throws SecurityException { 2578 Objects.requireNonNull(executor); 2579 Objects.requireNonNull(listener); 2580 int status = addOnDevRoleForCapturePresetChangedListener( 2581 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED); 2582 if (status == AudioSystem.ERROR) { 2583 // This must not happen 2584 throw new RuntimeException("Unknown error happened"); 2585 } 2586 if (status == AudioSystem.BAD_VALUE) { 2587 throw new IllegalArgumentException( 2588 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() " 2589 + "on a previously registered listener"); 2590 } 2591 } 2592 2593 /** 2594 * @hide 2595 * Removes a previously added listener of changes to the capture-preset-preferred audio device. 2596 * @param listener 2597 */ 2598 @SystemApi 2599 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeOnPreferredDevicesForCapturePresetChangedListener( @onNull OnPreferredDevicesForCapturePresetChangedListener listener)2600 public void removeOnPreferredDevicesForCapturePresetChangedListener( 2601 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) { 2602 Objects.requireNonNull(listener); 2603 int status = removeOnDevRoleForCapturePresetChangedListener( 2604 listener, AudioSystem.DEVICE_ROLE_PREFERRED); 2605 if (status == AudioSystem.ERROR) { 2606 // This must not happen 2607 throw new RuntimeException("Unknown error happened"); 2608 } 2609 if (status == AudioSystem.BAD_VALUE) { 2610 throw new IllegalArgumentException( 2611 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() " 2612 + "on an unregistered listener"); 2613 } 2614 } 2615 addOnDevRoleForCapturePresetChangedListener( @onNull @allbackExecutor Executor executor, @NonNull T listener, int deviceRole)2616 private <T> int addOnDevRoleForCapturePresetChangedListener( 2617 @NonNull @CallbackExecutor Executor executor, 2618 @NonNull T listener, int deviceRole) { 2619 Objects.requireNonNull(executor); 2620 Objects.requireNonNull(listener); 2621 DevRoleListeners<T> devRoleListeners = 2622 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); 2623 if (devRoleListeners == null) { 2624 return AudioSystem.ERROR; 2625 } 2626 synchronized (devRoleListeners.mDevRoleListenersLock) { 2627 if (devRoleListeners.hasDevRoleListener(listener)) { 2628 return AudioSystem.BAD_VALUE; 2629 } 2630 // lazy initialization of the list of device role listener 2631 if (devRoleListeners.mListenerInfos == null) { 2632 devRoleListeners.mListenerInfos = new ArrayList<>(); 2633 } 2634 final int oldCbCount = devRoleListeners.mListenerInfos.size(); 2635 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener)); 2636 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) { 2637 // register binder for callbacks 2638 synchronized (mDevRoleForCapturePresetListenersLock) { 2639 int deviceRoleListenerStatus = mDeviceRoleListenersStatus; 2640 mDeviceRoleListenersStatus |= (1 << deviceRole); 2641 if (deviceRoleListenerStatus != 0) { 2642 // There are already device role changed listeners active. 2643 return AudioSystem.SUCCESS; 2644 } 2645 if (mDevicesRoleForCapturePresetDispatcherStub == null) { 2646 mDevicesRoleForCapturePresetDispatcherStub = 2647 new CapturePresetDevicesRoleDispatcherStub(); 2648 } 2649 try { 2650 getService().registerCapturePresetDevicesRoleDispatcher( 2651 mDevicesRoleForCapturePresetDispatcherStub); 2652 } catch (RemoteException e) { 2653 throw e.rethrowFromSystemServer(); 2654 } 2655 } 2656 } 2657 } 2658 return AudioSystem.SUCCESS; 2659 } 2660 removeOnDevRoleForCapturePresetChangedListener( @onNull T listener, int deviceRole)2661 private <T> int removeOnDevRoleForCapturePresetChangedListener( 2662 @NonNull T listener, int deviceRole) { 2663 Objects.requireNonNull(listener); 2664 DevRoleListeners<T> devRoleListeners = 2665 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); 2666 if (devRoleListeners == null) { 2667 return AudioSystem.ERROR; 2668 } 2669 synchronized (devRoleListeners.mDevRoleListenersLock) { 2670 if (!devRoleListeners.removeDevRoleListener(listener)) { 2671 return AudioSystem.BAD_VALUE; 2672 } 2673 if (devRoleListeners.mListenerInfos.size() == 0) { 2674 // unregister binder for callbacks 2675 synchronized (mDevRoleForCapturePresetListenersLock) { 2676 mDeviceRoleListenersStatus ^= (1 << deviceRole); 2677 if (mDeviceRoleListenersStatus != 0) { 2678 // There are some other device role changed listeners active. 2679 return AudioSystem.SUCCESS; 2680 } 2681 try { 2682 getService().unregisterCapturePresetDevicesRoleDispatcher( 2683 mDevicesRoleForCapturePresetDispatcherStub); 2684 } catch (RemoteException e) { 2685 throw e.rethrowFromSystemServer(); 2686 } 2687 } 2688 } 2689 } 2690 return AudioSystem.SUCCESS; 2691 } 2692 2693 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of( 2694 AudioSystem.DEVICE_ROLE_PREFERRED, 2695 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>()); 2696 2697 private class DevRoleListenerInfo<T> { 2698 final @NonNull Executor mExecutor; 2699 final @NonNull T mListener; DevRoleListenerInfo(Executor executor, T listener)2700 DevRoleListenerInfo(Executor executor, T listener) { 2701 mExecutor = executor; 2702 mListener = listener; 2703 } 2704 } 2705 2706 private class DevRoleListeners<T> { 2707 private final Object mDevRoleListenersLock = new Object(); 2708 @GuardedBy("mDevRoleListenersLock") 2709 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos; 2710 2711 @GuardedBy("mDevRoleListenersLock") getDevRoleListenerInfo(T listener)2712 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) { 2713 if (mListenerInfos == null) { 2714 return null; 2715 } 2716 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) { 2717 if (listenerInfo.mListener == listener) { 2718 return listenerInfo; 2719 } 2720 } 2721 return null; 2722 } 2723 2724 @GuardedBy("mDevRoleListenersLock") hasDevRoleListener(T listener)2725 private boolean hasDevRoleListener(T listener) { 2726 return getDevRoleListenerInfo(listener) != null; 2727 } 2728 2729 @GuardedBy("mDevRoleListenersLock") removeDevRoleListener(T listener)2730 private boolean removeDevRoleListener(T listener) { 2731 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener); 2732 if (infoToRemove != null) { 2733 mListenerInfos.remove(infoToRemove); 2734 return true; 2735 } 2736 return false; 2737 } 2738 } 2739 2740 private final Object mDevRoleForCapturePresetListenersLock = new Object(); 2741 /** 2742 * Record if there is a listener added for device role change. If there is a listener added for 2743 * a specified device role change, the bit at position `1 << device_role` is set. 2744 */ 2745 @GuardedBy("mDevRoleForCapturePresetListenersLock") 2746 private int mDeviceRoleListenersStatus = 0; 2747 @GuardedBy("mDevRoleForCapturePresetListenersLock") 2748 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub; 2749 2750 private final class CapturePresetDevicesRoleDispatcherStub 2751 extends ICapturePresetDevicesRoleDispatcher.Stub { 2752 2753 @Override dispatchDevicesRoleChanged( int capturePreset, int role, List<AudioDeviceAttributes> devices)2754 public void dispatchDevicesRoleChanged( 2755 int capturePreset, int role, List<AudioDeviceAttributes> devices) { 2756 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role); 2757 if (listenersObj == null) { 2758 return; 2759 } 2760 switch (role) { 2761 case AudioSystem.DEVICE_ROLE_PREFERRED: { 2762 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener> 2763 listeners = 2764 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>) 2765 listenersObj; 2766 final ArrayList<DevRoleListenerInfo< 2767 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners; 2768 synchronized (listeners.mDevRoleListenersLock) { 2769 if (listeners.mListenerInfos.isEmpty()) { 2770 return; 2771 } 2772 prefDevListeners = (ArrayList<DevRoleListenerInfo< 2773 OnPreferredDevicesForCapturePresetChangedListener>>) 2774 listeners.mListenerInfos.clone(); 2775 } 2776 final long ident = Binder.clearCallingIdentity(); 2777 try { 2778 for (DevRoleListenerInfo< 2779 OnPreferredDevicesForCapturePresetChangedListener> info : 2780 prefDevListeners) { 2781 info.mExecutor.execute(() -> 2782 info.mListener.onPreferredDevicesForCapturePresetChanged( 2783 capturePreset, devices)); 2784 } 2785 } finally { 2786 Binder.restoreCallingIdentity(ident); 2787 } 2788 } break; 2789 default: 2790 break; 2791 } 2792 } 2793 } 2794 2795 //==================================================================== 2796 // Direct playback query 2797 2798 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}: 2799 direct playback not supported. */ 2800 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED; 2801 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}: 2802 direct offload playback supported. Compressed offload is a variant of direct playback. 2803 It is the feature that allows audio processing tasks to be done on the Android device but 2804 not on the application processor, instead, it is handled by dedicated hardware such as audio 2805 DSPs. That will allow the application processor to be idle as much as possible, which is 2806 good for power saving. Compressed offload playback supports 2807 {@link AudioTrack.StreamEventCallback} for event notifications. */ 2808 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED = 2809 AudioSystem.DIRECT_OFFLOAD_SUPPORTED; 2810 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}: 2811 direct offload playback supported with gapless transitions. Compressed offload is a variant 2812 of direct playback. It is the feature that allows audio processing tasks to be done on the 2813 Android device but not on the application processor, instead, it is handled by dedicated 2814 hardware such as audio DSPs. That will allow the application processor to be idle as much as 2815 possible, which is good for power saving. Compressed offload playback supports 2816 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions 2817 indicates the ability to play consecutive audio tracks without an audio silence in 2818 between. */ 2819 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED = 2820 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED; 2821 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}: 2822 direct playback supported. This value covers direct playback that is bitstream pass-through 2823 such as compressed pass-through. */ 2824 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED = 2825 AudioSystem.DIRECT_BITSTREAM_SUPPORTED; 2826 2827 /** @hide */ 2828 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = { 2829 DIRECT_PLAYBACK_NOT_SUPPORTED, 2830 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED, 2831 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED, 2832 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED} 2833 ) 2834 @Retention(RetentionPolicy.SOURCE) 2835 public @interface AudioDirectPlaybackMode {} 2836 2837 /** 2838 * Returns a bitfield representing the different forms of direct playback currently available 2839 * for a given audio format. 2840 * <p>Direct playback means that the audio stream is not altered by the framework. The audio 2841 * stream will not be resampled, volume scaled, downmixed or mixed with other content by 2842 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for 2843 * passthrough. 2844 * <p>Checking for direct support can help the app select the representation of audio content 2845 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver) 2846 * connected to it. Note that the provided stream can still be re-encoded or mixed with other 2847 * streams, if needed. 2848 * @param format the audio format (codec, sample rate, channels) being checked. 2849 * @param attributes the {@link AudioAttributes} to be used for playback 2850 * @return the direct playback mode available with given format and attributes. The returned 2851 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of 2852 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED}, 2853 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and 2854 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if 2855 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value, 2856 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too. 2857 */ 2858 @AudioDirectPlaybackMode getDirectPlaybackSupport(@onNull AudioFormat format, @NonNull AudioAttributes attributes)2859 public static int getDirectPlaybackSupport(@NonNull AudioFormat format, 2860 @NonNull AudioAttributes attributes) { 2861 Objects.requireNonNull(format); 2862 Objects.requireNonNull(attributes); 2863 return AudioSystem.getDirectPlaybackSupport(format, attributes); 2864 } 2865 2866 //==================================================================== 2867 // Offload query 2868 /** 2869 * Returns whether offloaded playback of an audio format is supported on the device. 2870 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream 2871 * is not competing with other software resources. In general, it is supported by dedicated 2872 * hardware, such as audio DSPs. 2873 * <p>Note that this query only provides information about the support of an audio format, 2874 * it does not indicate whether the resources necessary for the offloaded playback are 2875 * available at that instant. 2876 * @param format the audio format (codec, sample rate, channels) being checked. 2877 * @param attributes the {@link AudioAttributes} to be used for playback 2878 * @return true if the given audio format can be offloaded. 2879 */ isOffloadedPlaybackSupported(@onNull AudioFormat format, @NonNull AudioAttributes attributes)2880 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format, 2881 @NonNull AudioAttributes attributes) { 2882 if (format == null) { 2883 throw new NullPointerException("Illegal null AudioFormat"); 2884 } 2885 if (attributes == null) { 2886 throw new NullPointerException("Illegal null AudioAttributes"); 2887 } 2888 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED; 2889 } 2890 2891 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 2892 offload playback not supported */ 2893 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED; 2894 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 2895 offload playback supported */ 2896 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED; 2897 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 2898 offload playback supported with gapless transitions */ 2899 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED = 2900 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED; 2901 2902 /** @hide */ 2903 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = { 2904 PLAYBACK_OFFLOAD_NOT_SUPPORTED, 2905 PLAYBACK_OFFLOAD_SUPPORTED, 2906 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED } 2907 ) 2908 @Retention(RetentionPolicy.SOURCE) 2909 public @interface AudioOffloadMode {} 2910 2911 /** 2912 * Returns whether offloaded playback of an audio format is supported on the device or not and 2913 * when supported whether gapless transitions are possible or not. 2914 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream 2915 * is not competing with other software resources. In general, it is supported by dedicated 2916 * hardware, such as audio DSPs. 2917 * <p>Note that this query only provides information about the support of an audio format, 2918 * it does not indicate whether the resources necessary for the offloaded playback are 2919 * available at that instant. 2920 * @param format the audio format (codec, sample rate, channels) being checked. 2921 * @param attributes the {@link AudioAttributes} to be used for playback 2922 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported, 2923 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or 2924 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are 2925 * also supported. 2926 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead 2927 */ 2928 @Deprecated 2929 @AudioOffloadMode getPlaybackOffloadSupport(@onNull AudioFormat format, @NonNull AudioAttributes attributes)2930 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format, 2931 @NonNull AudioAttributes attributes) { 2932 if (format == null) { 2933 throw new NullPointerException("Illegal null AudioFormat"); 2934 } 2935 if (attributes == null) { 2936 throw new NullPointerException("Illegal null AudioAttributes"); 2937 } 2938 return AudioSystem.getOffloadSupport(format, attributes); 2939 } 2940 2941 //==================================================================== 2942 // Immersive audio 2943 2944 /** 2945 * Return a handle to the optional platform's {@link Spatializer} 2946 * @return the {@code Spatializer} instance. 2947 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect 2948 * on the platform 2949 */ getSpatializer()2950 public @NonNull Spatializer getSpatializer() { 2951 return new Spatializer(this); 2952 } 2953 2954 //==================================================================== 2955 // Bluetooth SCO control 2956 /** 2957 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 2958 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE} 2959 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED} 2960 * or {@link #SCO_AUDIO_STATE_CONNECTED} 2961 * 2962 * @see #startBluetoothSco() 2963 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead 2964 */ 2965 @Deprecated 2966 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2967 public static final String ACTION_SCO_AUDIO_STATE_CHANGED = 2968 "android.media.SCO_AUDIO_STATE_CHANGED"; 2969 2970 /** 2971 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 2972 * connection state has been updated. 2973 * <p>This intent has two extras: 2974 * <ul> 2975 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li> 2976 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li> 2977 * </ul> 2978 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of: 2979 * <ul> 2980 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li> 2981 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li> 2982 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li> 2983 * </ul> 2984 * @see #startBluetoothSco() 2985 */ 2986 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2987 public static final String ACTION_SCO_AUDIO_STATE_UPDATED = 2988 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED"; 2989 2990 /** 2991 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or 2992 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state. 2993 */ 2994 public static final String EXTRA_SCO_AUDIO_STATE = 2995 "android.media.extra.SCO_AUDIO_STATE"; 2996 2997 /** 2998 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous 2999 * bluetooth SCO connection state. 3000 */ 3001 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE = 3002 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"; 3003 3004 /** 3005 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 3006 * indicating that the SCO audio channel is not established 3007 */ 3008 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; 3009 /** 3010 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE} 3011 * indicating that the SCO audio channel is established 3012 */ 3013 public static final int SCO_AUDIO_STATE_CONNECTED = 1; 3014 /** 3015 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 3016 * indicating that the SCO audio channel is being established 3017 */ 3018 public static final int SCO_AUDIO_STATE_CONNECTING = 2; 3019 /** 3020 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that 3021 * there was an error trying to obtain the state 3022 */ 3023 public static final int SCO_AUDIO_STATE_ERROR = -1; 3024 3025 3026 /** 3027 * Indicates if current platform supports use of SCO for off call use cases. 3028 * Application wanted to use bluetooth SCO audio when the phone is not in call 3029 * must first call this method to make sure that the platform supports this 3030 * feature. 3031 * @return true if bluetooth SCO can be used for audio when not in call 3032 * false otherwise 3033 * @see #startBluetoothSco() 3034 */ isBluetoothScoAvailableOffCall()3035 public boolean isBluetoothScoAvailableOffCall() { 3036 return getContext().getResources().getBoolean( 3037 com.android.internal.R.bool.config_bluetooth_sco_off_call); 3038 } 3039 3040 /** 3041 * Start bluetooth SCO audio connection. 3042 * <p>Requires Permission: 3043 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}. 3044 * <p>This method can be used by applications wanting to send and received audio 3045 * to/from a bluetooth SCO headset while the phone is not in call. 3046 * <p>As the SCO connection establishment can take several seconds, 3047 * applications should not rely on the connection to be available when the method 3048 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} 3049 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}. 3050 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO 3051 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver 3052 * registration. If the state is already CONNECTED, no state change will be received via the 3053 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco() 3054 * so that the connection stays active in case the current initiator stops the connection. 3055 * <p>Unless the connection is already active as described above, the state will always 3056 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection 3057 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected). 3058 * <p>When finished with the SCO connection or if the establishment fails, the application must 3059 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection. 3060 * <p>Even if a SCO connection is established, the following restrictions apply on audio 3061 * output streams so that they can be routed to SCO headset: 3062 * <ul> 3063 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li> 3064 * <li> the format must be mono </li> 3065 * <li> the sampling must be 16kHz or 8kHz </li> 3066 * </ul> 3067 * <p>The following restrictions apply on input streams: 3068 * <ul> 3069 * <li> the format must be mono </li> 3070 * <li> the sampling must be 8kHz </li> 3071 * </ul> 3072 * <p>Note that the phone application always has the priority on the usage of the SCO 3073 * connection for telephony. If this method is called while the phone is in call 3074 * it will be ignored. Similarly, if a call is received or sent while an application 3075 * is using the SCO connection, the connection will be lost for the application and NOT 3076 * returned automatically when the call ends. 3077 * <p>NOTE: up to and including API version 3078 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual 3079 * voice call to the bluetooth headset. 3080 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio 3081 * connection is established. 3082 * @see #stopBluetoothSco() 3083 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 3084 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} instead. 3085 */ startBluetoothSco()3086 @Deprecated public void startBluetoothSco() { 3087 final IAudioService service = getService(); 3088 try { 3089 service.startBluetoothSco(mICallBack, 3090 getContext().getApplicationInfo().targetSdkVersion); 3091 } catch (RemoteException e) { 3092 throw e.rethrowFromSystemServer(); 3093 } 3094 } 3095 3096 /** 3097 * @hide 3098 * Start bluetooth SCO audio connection in virtual call mode. 3099 * <p>Requires Permission: 3100 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}. 3101 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode. 3102 * Telephony and communication applications (VoIP, Video Chat) should preferably select 3103 * virtual call mode. 3104 * Applications using voice input for search or commands should first try raw audio connection 3105 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of 3106 * failure. 3107 * @see #startBluetoothSco() 3108 * @see #stopBluetoothSco() 3109 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 3110 */ 3111 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) startBluetoothScoVirtualCall()3112 public void startBluetoothScoVirtualCall() { 3113 final IAudioService service = getService(); 3114 try { 3115 service.startBluetoothScoVirtualCall(mICallBack); 3116 } catch (RemoteException e) { 3117 throw e.rethrowFromSystemServer(); 3118 } 3119 } 3120 3121 /** 3122 * Stop bluetooth SCO audio connection. 3123 * <p>Requires Permission: 3124 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}. 3125 * <p>This method must be called by applications having requested the use of 3126 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO 3127 * connection or if connection fails. 3128 * @see #startBluetoothSco() 3129 * @deprecated Use {@link AudioManager#clearCommunicationDevice()} instead. 3130 */ 3131 // Also used for connections started with {@link #startBluetoothScoVirtualCall()} stopBluetoothSco()3132 @Deprecated public void stopBluetoothSco() { 3133 final IAudioService service = getService(); 3134 try { 3135 service.stopBluetoothSco(mICallBack); 3136 } catch (RemoteException e) { 3137 throw e.rethrowFromSystemServer(); 3138 } 3139 } 3140 3141 /** 3142 * Request use of Bluetooth SCO headset for communications. 3143 * <p> 3144 * This method should only be used by applications that replace the platform-wide 3145 * management of audio settings or the main telephony application. 3146 * 3147 * @param on set <var>true</var> to use bluetooth SCO for communications; 3148 * <var>false</var> to not use bluetooth SCO for communications 3149 */ setBluetoothScoOn(boolean on)3150 public void setBluetoothScoOn(boolean on){ 3151 final IAudioService service = getService(); 3152 try { 3153 service.setBluetoothScoOn(on); 3154 } catch (RemoteException e) { 3155 throw e.rethrowFromSystemServer(); 3156 } 3157 } 3158 3159 /** 3160 * Checks whether communications use Bluetooth SCO. 3161 * 3162 * @return true if SCO is used for communications; 3163 * false if otherwise 3164 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead. 3165 */ isBluetoothScoOn()3166 @Deprecated public boolean isBluetoothScoOn() { 3167 final IAudioService service = getService(); 3168 try { 3169 return service.isBluetoothScoOn(); 3170 } catch (RemoteException e) { 3171 throw e.rethrowFromSystemServer(); 3172 } 3173 } 3174 3175 /** 3176 * @deprecated Use {@link MediaRouter#selectRoute} instead. 3177 */ setBluetoothA2dpOn(boolean on)3178 @Deprecated public void setBluetoothA2dpOn(boolean on){ 3179 } 3180 3181 /** 3182 * Checks whether a Bluetooth A2DP audio peripheral is connected or not. 3183 * 3184 * @return true if a Bluetooth A2DP peripheral is connected 3185 * false if otherwise 3186 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 3187 */ isBluetoothA2dpOn()3188 public boolean isBluetoothA2dpOn() { 3189 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"") 3190 == AudioSystem.DEVICE_STATE_AVAILABLE) { 3191 return true; 3192 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"") 3193 == AudioSystem.DEVICE_STATE_AVAILABLE) { 3194 return true; 3195 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"") 3196 == AudioSystem.DEVICE_STATE_AVAILABLE) { 3197 return true; 3198 } 3199 return false; 3200 } 3201 3202 /** 3203 * Sets audio routing to the wired headset on or off. 3204 * 3205 * @param on set <var>true</var> to route audio to/from wired 3206 * headset; <var>false</var> disable wired headset audio 3207 * @deprecated Do not use. 3208 */ setWiredHeadsetOn(boolean on)3209 @Deprecated public void setWiredHeadsetOn(boolean on){ 3210 } 3211 3212 /** 3213 * Checks whether a wired headset is connected or not. 3214 * <p>This is not a valid indication that audio playback is 3215 * actually over the wired headset as audio routing depends on other conditions. 3216 * 3217 * @return true if a wired headset is connected. 3218 * false if otherwise 3219 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 3220 */ isWiredHeadsetOn()3221 public boolean isWiredHeadsetOn() { 3222 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"") 3223 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 3224 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"") 3225 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 3226 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "") 3227 == AudioSystem.DEVICE_STATE_UNAVAILABLE) { 3228 return false; 3229 } else { 3230 return true; 3231 } 3232 } 3233 3234 /** 3235 * Sets the microphone mute on or off. 3236 * <p> 3237 * This method should only be used by applications that replace the platform-wide 3238 * management of audio settings or the main telephony application. 3239 * 3240 * @param on set <var>true</var> to mute the microphone; 3241 * <var>false</var> to turn mute off 3242 */ setMicrophoneMute(boolean on)3243 public void setMicrophoneMute(boolean on) { 3244 final IAudioService service = getService(); 3245 try { 3246 service.setMicrophoneMute(on, getContext().getOpPackageName(), 3247 UserHandle.getCallingUserId(), getContext().getAttributionTag()); 3248 } catch (RemoteException e) { 3249 throw e.rethrowFromSystemServer(); 3250 } 3251 } 3252 3253 /** 3254 * @hide 3255 * Sets the microphone from switch mute on or off. 3256 * <p> 3257 * This method should only be used by InputManager to notify 3258 * Audio Subsystem about Microphone Mute switch state. 3259 * 3260 * @param on set <var>true</var> to mute the microphone; 3261 * <var>false</var> to turn mute off 3262 */ 3263 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setMicrophoneMuteFromSwitch(boolean on)3264 public void setMicrophoneMuteFromSwitch(boolean on) { 3265 final IAudioService service = getService(); 3266 try { 3267 service.setMicrophoneMuteFromSwitch(on); 3268 } catch (RemoteException e) { 3269 throw e.rethrowFromSystemServer(); 3270 } 3271 } 3272 3273 /** 3274 * Checks whether the microphone mute is on or off. 3275 * 3276 * @return true if microphone is muted, false if it's not 3277 */ isMicrophoneMute()3278 public boolean isMicrophoneMute() { 3279 final IAudioService service = getService(); 3280 try { 3281 return service.isMicrophoneMuted(); 3282 } catch (RemoteException e) { 3283 throw e.rethrowFromSystemServer(); 3284 } 3285 } 3286 3287 /** 3288 * Broadcast Action: microphone muting state changed. 3289 * 3290 * You <em>cannot</em> receive this through components declared 3291 * in manifests, only by explicitly registering for it with 3292 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 3293 * Context.registerReceiver()}. 3294 * 3295 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the 3296 * microphone is muted. 3297 */ 3298 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 3299 public static final String ACTION_MICROPHONE_MUTE_CHANGED = 3300 "android.media.action.MICROPHONE_MUTE_CHANGED"; 3301 3302 /** 3303 * Broadcast Action: speakerphone state changed. 3304 * 3305 * You <em>cannot</em> receive this through components declared 3306 * in manifests, only by explicitly registering for it with 3307 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 3308 * Context.registerReceiver()}. 3309 * 3310 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the 3311 * speakerphone functionality is enabled or not. 3312 */ 3313 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 3314 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = 3315 "android.media.action.SPEAKERPHONE_STATE_CHANGED"; 3316 3317 /** 3318 * Sets the audio mode. 3319 * <p> 3320 * The audio mode encompasses audio routing AND the behavior of 3321 * the telephony layer. Therefore this method should only be used by applications that 3322 * replace the platform-wide management of audio settings or the main telephony application. 3323 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony 3324 * application when it places a phone call, as it will cause signals from the radio layer 3325 * to feed the platform mixer. 3326 * 3327 * @param mode the requested audio mode. 3328 * Informs the HAL about the current audio state so that 3329 * it can route the audio appropriately. 3330 */ setMode(@udioMode int mode)3331 public void setMode(@AudioMode int mode) { 3332 final IAudioService service = getService(); 3333 try { 3334 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName()); 3335 } catch (RemoteException e) { 3336 throw e.rethrowFromSystemServer(); 3337 } 3338 } 3339 3340 /** 3341 * This change id controls use of audio modes for call audio redirection. 3342 * @hide 3343 */ 3344 @ChangeId 3345 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 3346 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id 3347 3348 /** 3349 * Returns the current audio mode. 3350 * 3351 * @return the current audio mode. 3352 */ 3353 @AudioMode getMode()3354 public int getMode() { 3355 final IAudioService service = getService(); 3356 try { 3357 int mode = service.getMode(); 3358 int sdk; 3359 try { 3360 sdk = getContext().getApplicationInfo().targetSdkVersion; 3361 } catch (NullPointerException e) { 3362 // some tests don't have a Context 3363 sdk = Build.VERSION.SDK_INT; 3364 } 3365 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) { 3366 mode = MODE_IN_CALL; 3367 } else if (mode == MODE_CALL_REDIRECT 3368 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) { 3369 mode = MODE_IN_CALL; 3370 } else if (mode == MODE_COMMUNICATION_REDIRECT 3371 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) { 3372 mode = MODE_IN_COMMUNICATION; 3373 } 3374 return mode; 3375 } catch (RemoteException e) { 3376 throw e.rethrowFromSystemServer(); 3377 } 3378 } 3379 3380 /** 3381 * Interface definition of a callback that is notified when the audio mode changes 3382 */ 3383 public interface OnModeChangedListener { 3384 /** 3385 * Called on the listener to indicate that the audio mode has changed 3386 * 3387 * @param mode The current audio mode 3388 */ onModeChanged(@udioMode int mode)3389 void onModeChanged(@AudioMode int mode); 3390 } 3391 3392 /** 3393 * manages the OnModeChangedListener listeners and the ModeDispatcherStub 3394 */ 3395 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr = 3396 new CallbackUtil.LazyListenerManager(); 3397 3398 3399 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub 3400 implements CallbackUtil.DispatcherStub { 3401 3402 @Override register(boolean register)3403 public void register(boolean register) { 3404 try { 3405 if (register) { 3406 getService().registerModeDispatcher(this); 3407 } else { 3408 getService().unregisterModeDispatcher(this); 3409 } 3410 } catch (RemoteException e) { 3411 e.rethrowFromSystemServer(); 3412 } 3413 } 3414 3415 @Override dispatchAudioModeChanged(int mode)3416 public void dispatchAudioModeChanged(int mode) { 3417 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode)); 3418 } 3419 } 3420 3421 /** 3422 * Adds a listener to be notified of changes to the audio mode. 3423 * See {@link #getMode()} 3424 * @param executor 3425 * @param listener 3426 */ addOnModeChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnModeChangedListener listener)3427 public void addOnModeChangedListener( 3428 @NonNull @CallbackExecutor Executor executor, 3429 @NonNull OnModeChangedListener listener) { 3430 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener", 3431 () -> new ModeDispatcherStub()); 3432 } 3433 3434 /** 3435 * Removes a previously added listener for changes to audio mode. 3436 * See {@link #getMode()} 3437 * @param listener 3438 */ removeOnModeChangedListener(@onNull OnModeChangedListener listener)3439 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) { 3440 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener"); 3441 } 3442 3443 /** 3444 * Indicates if the platform supports a special call screening and call monitoring mode. 3445 * <p> 3446 * When this mode is supported, it is possible to perform call screening and monitoring 3447 * functions while other use cases like music or movie playback are active. 3448 * <p> 3449 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in 3450 * call screening mode. 3451 * <p> 3452 * If call screening mode is not supported, setting mode to 3453 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by 3454 * {@link #getMode()}. 3455 * @return true if call screening mode is supported, false otherwise. 3456 */ isCallScreeningModeSupported()3457 public boolean isCallScreeningModeSupported() { 3458 final IAudioService service = getService(); 3459 try { 3460 return service.isCallScreeningModeSupported(); 3461 } catch (RemoteException e) { 3462 throw e.rethrowFromSystemServer(); 3463 } 3464 } 3465 3466 /* modes for setMode/getMode/setRoute/getRoute */ 3467 /** 3468 * Audio hardware modes. 3469 */ 3470 /** 3471 * Invalid audio mode. 3472 */ 3473 public static final int MODE_INVALID = AudioSystem.MODE_INVALID; 3474 /** 3475 * Current audio mode. Used to apply audio routing to current mode. 3476 */ 3477 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT; 3478 /** 3479 * Normal audio mode: not ringing and no call established. 3480 */ 3481 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL; 3482 /** 3483 * Ringing audio mode. An incoming is being signaled. 3484 */ 3485 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE; 3486 /** 3487 * In call audio mode. A telephony call is established. 3488 */ 3489 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL; 3490 /** 3491 * In communication audio mode. An audio/video chat or VoIP call is established. 3492 */ 3493 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION; 3494 /** 3495 * Call screening in progress. Call is connected and audio is accessible to call 3496 * screening applications but other audio use cases are still possible. 3497 */ 3498 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING; 3499 3500 /** 3501 * A telephony call is established and its audio is being redirected to another device. 3502 */ 3503 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT; 3504 3505 /** 3506 * An audio/video chat or VoIP call is established and its audio is being redirected to another 3507 * device. 3508 */ 3509 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT; 3510 3511 /** @hide */ 3512 @IntDef(flag = false, prefix = "MODE_", value = { 3513 MODE_NORMAL, 3514 MODE_RINGTONE, 3515 MODE_IN_CALL, 3516 MODE_IN_COMMUNICATION, 3517 MODE_CALL_SCREENING, 3518 MODE_CALL_REDIRECT, 3519 MODE_COMMUNICATION_REDIRECT} 3520 ) 3521 @Retention(RetentionPolicy.SOURCE) 3522 public @interface AudioMode {} 3523 3524 /* Routing bits for setRouting/getRouting API */ 3525 /** 3526 * Routing audio output to earpiece 3527 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3528 * setBluetoothScoOn() methods instead. 3529 */ 3530 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; 3531 /** 3532 * Routing audio output to speaker 3533 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3534 * setBluetoothScoOn() methods instead. 3535 */ 3536 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; 3537 /** 3538 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO} 3539 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3540 * setBluetoothScoOn() methods instead. 3541 */ 3542 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO; 3543 /** 3544 * Routing audio output to bluetooth SCO 3545 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3546 * setBluetoothScoOn() methods instead. 3547 */ 3548 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO; 3549 /** 3550 * Routing audio output to headset 3551 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3552 * setBluetoothScoOn() methods instead. 3553 */ 3554 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; 3555 /** 3556 * Routing audio output to bluetooth A2DP 3557 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3558 * setBluetoothScoOn() methods instead. 3559 */ 3560 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP; 3561 /** 3562 * Used for mask parameter of {@link #setRouting(int,int,int)}. 3563 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3564 * setBluetoothScoOn() methods instead. 3565 */ 3566 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; 3567 3568 /** 3569 * Sets the audio routing for a specified mode 3570 * 3571 * @param mode audio mode to change route. E.g., MODE_RINGTONE. 3572 * @param routes bit vector of routes requested, created from one or 3573 * more of ROUTE_xxx types. Set bits indicate that route should be on 3574 * @param mask bit vector of routes to change, created from one or more of 3575 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged 3576 * 3577 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3578 * setBluetoothScoOn() methods instead. 3579 */ 3580 @Deprecated setRouting(int mode, int routes, int mask)3581 public void setRouting(int mode, int routes, int mask) { 3582 } 3583 3584 /** 3585 * Returns the current audio routing bit vector for a specified mode. 3586 * 3587 * @param mode audio mode to get route (e.g., MODE_RINGTONE) 3588 * @return an audio route bit vector that can be compared with ROUTE_xxx 3589 * bits 3590 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(), 3591 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead. 3592 */ 3593 @Deprecated getRouting(int mode)3594 public int getRouting(int mode) { 3595 return -1; 3596 } 3597 3598 /** 3599 * Checks whether any music is active. 3600 * 3601 * @return true if any music tracks are active. 3602 */ isMusicActive()3603 public boolean isMusicActive() { 3604 final IAudioService service = getService(); 3605 try { 3606 return service.isMusicActive(false /*remotely*/); 3607 } catch (RemoteException e) { 3608 throw e.rethrowFromSystemServer(); 3609 } 3610 } 3611 3612 /** 3613 * @hide 3614 * Checks whether any music or media is actively playing on a remote device (e.g. wireless 3615 * display). Note that BT audio sinks are not considered remote devices. 3616 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device 3617 */ 3618 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isMusicActiveRemotely()3619 public boolean isMusicActiveRemotely() { 3620 final IAudioService service = getService(); 3621 try { 3622 return service.isMusicActive(true /*remotely*/); 3623 } catch (RemoteException e) { 3624 throw e.rethrowFromSystemServer(); 3625 } 3626 } 3627 3628 /** 3629 * @hide 3630 * Checks whether the current audio focus is exclusive. 3631 * @return true if the top of the audio focus stack requested focus 3632 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} 3633 */ isAudioFocusExclusive()3634 public boolean isAudioFocusExclusive() { 3635 final IAudioService service = getService(); 3636 try { 3637 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE; 3638 } catch (RemoteException e) { 3639 throw e.rethrowFromSystemServer(); 3640 } 3641 } 3642 3643 /** 3644 * Return a new audio session identifier not associated with any player or effect. 3645 * An audio session identifier is a system wide unique identifier for a set of audio streams 3646 * (one or more mixed together). 3647 * <p>The primary use of the audio session ID is to associate audio effects to audio players, 3648 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio 3649 * session ID will be applied to the mixed audio content of the players that share the same 3650 * audio session. 3651 * <p>This method can for instance be used when creating one of the 3652 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect, 3653 * or to specify a session for a speech synthesis utterance 3654 * in {@link android.speech.tts.TextToSpeech.Engine}. 3655 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the 3656 * system failed to generate a new session, a condition in which audio playback or recording 3657 * will subsequently fail as well. 3658 */ generateAudioSessionId()3659 public int generateAudioSessionId() { 3660 int session = AudioSystem.newAudioSessionId(); 3661 if (session > 0) { 3662 return session; 3663 } else { 3664 Log.e(TAG, "Failure to generate a new audio session ID"); 3665 return ERROR; 3666 } 3667 } 3668 3669 /** 3670 * A special audio session ID to indicate that the audio session ID isn't known and the 3671 * framework should generate a new value. This can be used when building a new 3672 * {@link AudioTrack} instance with 3673 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}. 3674 */ 3675 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE; 3676 3677 3678 /* 3679 * Sets a generic audio configuration parameter. The use of these parameters 3680 * are platform dependant, see libaudio 3681 * 3682 * ** Temporary interface - DO NOT USE 3683 * 3684 * TODO: Replace with a more generic key:value get/set mechanism 3685 * 3686 * param key name of parameter to set. Must not be null. 3687 * param value value of parameter. Must not be null. 3688 */ 3689 /** 3690 * @hide 3691 * @deprecated Use {@link #setParameters(String)} instead 3692 */ setParameter(String key, String value)3693 @Deprecated public void setParameter(String key, String value) { 3694 setParameters(key+"="+value); 3695 } 3696 3697 /** 3698 * Sets a variable number of parameter values to audio hardware. 3699 * 3700 * @param keyValuePairs list of parameters key value pairs in the form: 3701 * key1=value1;key2=value2;... 3702 * 3703 */ setParameters(String keyValuePairs)3704 public void setParameters(String keyValuePairs) { 3705 AudioSystem.setParameters(keyValuePairs); 3706 } 3707 3708 /** 3709 * @hide 3710 */ 3711 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3712 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setHfpEnabled(boolean enable)3713 public void setHfpEnabled(boolean enable) { 3714 AudioSystem.setParameters("hfp_enable=" + enable); 3715 } 3716 3717 /** 3718 * @hide 3719 */ 3720 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3721 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setHfpVolume(int volume)3722 public void setHfpVolume(int volume) { 3723 AudioSystem.setParameters("hfp_volume=" + volume); 3724 } 3725 3726 /** 3727 * @hide 3728 */ 3729 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3730 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setHfpSamplingRate(int rate)3731 public void setHfpSamplingRate(int rate) { 3732 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate); 3733 } 3734 3735 /** 3736 * @hide 3737 */ 3738 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3739 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setBluetoothHeadsetProperties(@onNull String name, boolean hasNrecEnabled, boolean hasWbsEnabled)3740 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled, 3741 boolean hasWbsEnabled) { 3742 AudioSystem.setParameters("bt_headset_name=" + name 3743 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off") 3744 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off")); 3745 } 3746 3747 /** 3748 * @hide 3749 */ 3750 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3751 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setA2dpSuspended(boolean enable)3752 public void setA2dpSuspended(boolean enable) { 3753 final IAudioService service = getService(); 3754 try { 3755 service.setA2dpSuspended(enable); 3756 } catch (RemoteException e) { 3757 throw e.rethrowFromSystemServer(); 3758 } 3759 } 3760 3761 /** 3762 * Suspends the use of LE Audio. 3763 * 3764 * @param enable {@code true} to suspend le audio, {@code false} to unsuspend 3765 * 3766 * @hide 3767 */ 3768 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3769 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setLeAudioSuspended(boolean enable)3770 public void setLeAudioSuspended(boolean enable) { 3771 final IAudioService service = getService(); 3772 try { 3773 service.setLeAudioSuspended(enable); 3774 } catch (RemoteException e) { 3775 throw e.rethrowFromSystemServer(); 3776 } 3777 } 3778 3779 /** 3780 * Gets a variable number of parameter values from audio hardware. 3781 * 3782 * @param keys list of parameters 3783 * @return list of parameters key value pairs in the form: 3784 * key1=value1;key2=value2;... 3785 */ getParameters(String keys)3786 public String getParameters(String keys) { 3787 return AudioSystem.getParameters(keys); 3788 } 3789 3790 /* Sound effect identifiers */ 3791 /** 3792 * Keyboard and direction pad click sound 3793 * @see #playSoundEffect(int) 3794 */ 3795 public static final int FX_KEY_CLICK = 0; 3796 /** 3797 * Focus has moved up 3798 * @see #playSoundEffect(int) 3799 */ 3800 public static final int FX_FOCUS_NAVIGATION_UP = 1; 3801 /** 3802 * Focus has moved down 3803 * @see #playSoundEffect(int) 3804 */ 3805 public static final int FX_FOCUS_NAVIGATION_DOWN = 2; 3806 /** 3807 * Focus has moved left 3808 * @see #playSoundEffect(int) 3809 */ 3810 public static final int FX_FOCUS_NAVIGATION_LEFT = 3; 3811 /** 3812 * Focus has moved right 3813 * @see #playSoundEffect(int) 3814 */ 3815 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; 3816 /** 3817 * IME standard keypress sound 3818 * @see #playSoundEffect(int) 3819 */ 3820 public static final int FX_KEYPRESS_STANDARD = 5; 3821 /** 3822 * IME spacebar keypress sound 3823 * @see #playSoundEffect(int) 3824 */ 3825 public static final int FX_KEYPRESS_SPACEBAR = 6; 3826 /** 3827 * IME delete keypress sound 3828 * @see #playSoundEffect(int) 3829 */ 3830 public static final int FX_KEYPRESS_DELETE = 7; 3831 /** 3832 * IME return_keypress sound 3833 * @see #playSoundEffect(int) 3834 */ 3835 public static final int FX_KEYPRESS_RETURN = 8; 3836 3837 /** 3838 * Invalid keypress sound 3839 * @see #playSoundEffect(int) 3840 */ 3841 public static final int FX_KEYPRESS_INVALID = 9; 3842 3843 /** 3844 * Back sound 3845 * @see #playSoundEffect(int) 3846 */ 3847 public static final int FX_BACK = 10; 3848 3849 /** 3850 * @hide Home sound 3851 * <p> 3852 * To be played by the framework when the home app becomes active if config_enableHomeSound is 3853 * set to true. This is currently only used on TV devices. 3854 * Note that this sound is only available if a sound file is specified in audio_assets.xml. 3855 * @see #playSoundEffect(int) 3856 */ 3857 public static final int FX_HOME = 11; 3858 3859 /** 3860 * @hide Navigation repeat sound 1 3861 * <p> 3862 * To be played by the framework when a focus navigation is repeatedly triggered 3863 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3864 * This is currently only used on TV devices. 3865 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3866 * @see #playSoundEffect(int) 3867 */ 3868 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12; 3869 3870 /** 3871 * @hide Navigation repeat sound 2 3872 * <p> 3873 * To be played by the framework when a focus navigation is repeatedly triggered 3874 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3875 * This is currently only used on TV devices. 3876 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3877 * @see #playSoundEffect(int) 3878 */ 3879 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13; 3880 3881 /** 3882 * @hide Navigation repeat sound 3 3883 * <p> 3884 * To be played by the framework when a focus navigation is repeatedly triggered 3885 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3886 * This is currently only used on TV devices. 3887 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3888 * @see #playSoundEffect(int) 3889 */ 3890 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14; 3891 3892 /** 3893 * @hide Navigation repeat sound 4 3894 * <p> 3895 * To be played by the framework when a focus navigation is repeatedly triggered 3896 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3897 * This is currently only used on TV devices. 3898 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3899 * @see #playSoundEffect(int) 3900 */ 3901 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15; 3902 3903 /** 3904 * @hide Number of sound effects 3905 */ 3906 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3907 public static final int NUM_SOUND_EFFECTS = 16; 3908 3909 /** @hide */ 3910 @IntDef(prefix = { "FX_" }, value = { 3911 FX_KEY_CLICK, 3912 FX_FOCUS_NAVIGATION_UP, 3913 FX_FOCUS_NAVIGATION_DOWN, 3914 FX_FOCUS_NAVIGATION_LEFT, 3915 FX_FOCUS_NAVIGATION_RIGHT, 3916 FX_KEYPRESS_STANDARD, 3917 FX_KEYPRESS_SPACEBAR, 3918 FX_KEYPRESS_DELETE, 3919 FX_KEYPRESS_RETURN, 3920 FX_KEYPRESS_INVALID, 3921 FX_BACK 3922 }) 3923 @Retention(RetentionPolicy.SOURCE) 3924 public @interface SystemSoundEffect {} 3925 3926 /** 3927 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects 3928 */ 3929 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4; 3930 3931 /** 3932 * @hide 3933 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[ 3934 * @return The id of a navigation repeat sound effect or -1 if out of bounds 3935 */ getNthNavigationRepeatSoundEffect(int n)3936 public static int getNthNavigationRepeatSoundEffect(int n) { 3937 switch (n) { 3938 case 0: 3939 return FX_FOCUS_NAVIGATION_REPEAT_1; 3940 case 1: 3941 return FX_FOCUS_NAVIGATION_REPEAT_2; 3942 case 2: 3943 return FX_FOCUS_NAVIGATION_REPEAT_3; 3944 case 3: 3945 return FX_FOCUS_NAVIGATION_REPEAT_4; 3946 default: 3947 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n); 3948 return -1; 3949 } 3950 } 3951 3952 /** 3953 * @hide 3954 */ setNavigationRepeatSoundEffectsEnabled(boolean enabled)3955 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) { 3956 try { 3957 getService().setNavigationRepeatSoundEffectsEnabled(enabled); 3958 } catch (RemoteException e) { 3959 3960 } 3961 } 3962 3963 /** 3964 * @hide 3965 * @return true if the navigation repeat sound effects are enabled 3966 */ areNavigationRepeatSoundEffectsEnabled()3967 public boolean areNavigationRepeatSoundEffectsEnabled() { 3968 try { 3969 return getService().areNavigationRepeatSoundEffectsEnabled(); 3970 } catch (RemoteException e) { 3971 throw e.rethrowFromSystemServer(); 3972 } 3973 } 3974 3975 /** 3976 * @hide 3977 * @param enabled 3978 */ setHomeSoundEffectEnabled(boolean enabled)3979 public void setHomeSoundEffectEnabled(boolean enabled) { 3980 try { 3981 getService().setHomeSoundEffectEnabled(enabled); 3982 } catch (RemoteException e) { 3983 3984 } 3985 } 3986 3987 /** 3988 * @hide 3989 * @return true if the home sound effect is enabled 3990 */ isHomeSoundEffectEnabled()3991 public boolean isHomeSoundEffectEnabled() { 3992 try { 3993 return getService().isHomeSoundEffectEnabled(); 3994 } catch (RemoteException e) { 3995 throw e.rethrowFromSystemServer(); 3996 } 3997 } 3998 3999 /** 4000 * Plays a sound effect (Key clicks, lid open/close...) 4001 * @param effectType The type of sound effect. 4002 * NOTE: This version uses the UI settings to determine 4003 * whether sounds are heard or not. 4004 */ playSoundEffect(@ystemSoundEffect int effectType)4005 public void playSoundEffect(@SystemSoundEffect int effectType) { 4006 playSoundEffect(effectType, UserHandle.USER_CURRENT); 4007 } 4008 4009 /** 4010 * Plays a sound effect (Key clicks, lid open/close...) 4011 * @param effectType The type of sound effect. 4012 * @param userId The current user to pull sound settings from 4013 * NOTE: This version uses the UI settings to determine 4014 * whether sounds are heard or not. 4015 * @hide 4016 */ playSoundEffect(@ystemSoundEffect int effectType, int userId)4017 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) { 4018 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 4019 return; 4020 } 4021 4022 if (delegateSoundEffectToVdm(effectType)) { 4023 return; 4024 } 4025 4026 final IAudioService service = getService(); 4027 try { 4028 service.playSoundEffect(effectType, userId); 4029 } catch (RemoteException e) { 4030 throw e.rethrowFromSystemServer(); 4031 } 4032 } 4033 4034 /** 4035 * Plays a sound effect (Key clicks, lid open/close...) 4036 * @param effectType The type of sound effect. 4037 * @param volume Sound effect volume. 4038 * The volume value is a raw scalar so UI controls should be scaled logarithmically. 4039 * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used. 4040 * NOTE: This version is for applications that have their own 4041 * settings panel for enabling and controlling volume. 4042 */ playSoundEffect(@ystemSoundEffect int effectType, float volume)4043 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) { 4044 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 4045 return; 4046 } 4047 4048 if (delegateSoundEffectToVdm(effectType)) { 4049 return; 4050 } 4051 4052 final IAudioService service = getService(); 4053 try { 4054 service.playSoundEffectVolume(effectType, volume); 4055 } catch (RemoteException e) { 4056 throw e.rethrowFromSystemServer(); 4057 } 4058 } 4059 4060 /** 4061 * Checks whether this {@link AudioManager} instance is associated with {@link VirtualDevice} 4062 * configured with custom device policy for audio. If there is such device, request to play 4063 * sound effect is forwarded to {@link VirtualDeviceManager}. 4064 * 4065 * @param effectType - The type of sound effect. 4066 * @return true if the request was forwarded to {@link VirtualDeviceManager} instance, 4067 * false otherwise. 4068 */ delegateSoundEffectToVdm(@ystemSoundEffect int effectType)4069 private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) { 4070 if (hasCustomPolicyVirtualDeviceContext()) { 4071 VirtualDeviceManager vdm = getVirtualDeviceManager(); 4072 vdm.playSoundEffect(mOriginalContextDeviceId, effectType); 4073 return true; 4074 } 4075 return false; 4076 } 4077 hasCustomPolicyVirtualDeviceContext()4078 private boolean hasCustomPolicyVirtualDeviceContext() { 4079 if (mOriginalContextDeviceId == DEVICE_ID_DEFAULT) { 4080 return false; 4081 } 4082 4083 VirtualDeviceManager vdm = getVirtualDeviceManager(); 4084 return vdm != null && vdm.getDevicePolicy(mOriginalContextDeviceId, POLICY_TYPE_AUDIO) 4085 != DEVICE_POLICY_DEFAULT; 4086 } 4087 4088 /** 4089 * Load Sound effects. 4090 * This method must be called when sound effects are enabled. 4091 */ loadSoundEffects()4092 public void loadSoundEffects() { 4093 final IAudioService service = getService(); 4094 try { 4095 service.loadSoundEffects(); 4096 } catch (RemoteException e) { 4097 throw e.rethrowFromSystemServer(); 4098 } 4099 } 4100 4101 /** 4102 * Unload Sound effects. 4103 * This method can be called to free some memory when 4104 * sound effects are disabled. 4105 */ unloadSoundEffects()4106 public void unloadSoundEffects() { 4107 final IAudioService service = getService(); 4108 try { 4109 service.unloadSoundEffects(); 4110 } catch (RemoteException e) { 4111 throw e.rethrowFromSystemServer(); 4112 } 4113 } 4114 4115 /** 4116 * @hide 4117 */ audioFocusToString(int focus)4118 public static String audioFocusToString(int focus) { 4119 switch (focus) { 4120 case AUDIOFOCUS_NONE: 4121 return "AUDIOFOCUS_NONE"; 4122 case AUDIOFOCUS_GAIN: 4123 return "AUDIOFOCUS_GAIN"; 4124 case AUDIOFOCUS_GAIN_TRANSIENT: 4125 return "AUDIOFOCUS_GAIN_TRANSIENT"; 4126 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 4127 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK"; 4128 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 4129 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE"; 4130 case AUDIOFOCUS_LOSS: 4131 return "AUDIOFOCUS_LOSS"; 4132 case AUDIOFOCUS_LOSS_TRANSIENT: 4133 return "AUDIOFOCUS_LOSS_TRANSIENT"; 4134 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK. 4135 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"; 4136 default: 4137 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")"; 4138 } 4139 } 4140 4141 /** 4142 * Used to indicate no audio focus has been gained or lost, or requested. 4143 */ 4144 public static final int AUDIOFOCUS_NONE = 0; 4145 4146 /** 4147 * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration. 4148 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4149 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 4150 */ 4151 public static final int AUDIOFOCUS_GAIN = 1; 4152 /** 4153 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short 4154 * amount of time. Examples of temporary changes are the playback of driving directions, or an 4155 * event notification. 4156 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4157 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 4158 */ 4159 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; 4160 /** 4161 * Used to indicate a temporary request of audio focus, anticipated to last a short 4162 * amount of time, and where it is acceptable for other audio applications to keep playing 4163 * after having lowered their output level (also referred to as "ducking"). 4164 * Examples of temporary changes are the playback of driving directions where playback of music 4165 * in the background is acceptable. 4166 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4167 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 4168 */ 4169 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; 4170 /** 4171 * Used to indicate a temporary request of audio focus, anticipated to last a short 4172 * amount of time, during which no other applications, or system components, should play 4173 * anything. Examples of exclusive and transient audio focus requests are voice 4174 * memo recording and speech recognition, during which the system shouldn't play any 4175 * notifications, and media playback should have paused. 4176 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 4177 */ 4178 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; 4179 /** 4180 * Used to indicate a loss of audio focus of unknown duration. 4181 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4182 */ 4183 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN; 4184 /** 4185 * Used to indicate a transient loss of audio focus. 4186 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4187 */ 4188 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT; 4189 /** 4190 * Used to indicate a transient loss of audio focus where the loser of the audio focus can 4191 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as 4192 * the new focus owner doesn't require others to be silent. 4193 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4194 */ 4195 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = 4196 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; 4197 4198 /** 4199 * Interface definition for a callback to be invoked when the audio focus of the system is 4200 * updated. 4201 */ 4202 public interface OnAudioFocusChangeListener { 4203 /** 4204 * Called on the listener to notify it the audio focus for this listener has been changed. 4205 * The focusChange value indicates whether the focus was gained, 4206 * whether the focus was lost, and whether that loss is transient, or whether the new focus 4207 * holder will hold it for an unknown amount of time. 4208 * When losing focus, listeners can use the focus change information to decide what 4209 * behavior to adopt when losing focus. A music player could for instance elect to lower 4210 * the volume of its music stream (duck) for transient focus losses, and pause otherwise. 4211 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN}, 4212 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT} 4213 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}. 4214 */ onAudioFocusChange(int focusChange)4215 public void onAudioFocusChange(int focusChange); 4216 } 4217 4218 /** 4219 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback 4220 */ 4221 private static class FocusRequestInfo { 4222 @NonNull final AudioFocusRequest mRequest; 4223 @Nullable final Handler mHandler; FocusRequestInfo(@onNull AudioFocusRequest afr, @Nullable Handler handler)4224 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) { 4225 mRequest = afr; 4226 mHandler = handler; 4227 } 4228 } 4229 4230 /** 4231 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack, 4232 * to actual listener objects. 4233 */ 4234 @UnsupportedAppUsage 4235 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap = 4236 new ConcurrentHashMap<String, FocusRequestInfo>(); 4237 findFocusRequestInfo(String id)4238 private FocusRequestInfo findFocusRequestInfo(String id) { 4239 return mAudioFocusIdListenerMap.get(id); 4240 } 4241 4242 /** 4243 * Handler for events (audio focus change, recording config change) coming from the 4244 * audio service. 4245 */ 4246 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate = 4247 new ServiceEventHandlerDelegate(null); 4248 4249 /** 4250 * Event types 4251 */ 4252 private final static int MSSG_FOCUS_CHANGE = 0; 4253 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1; 4254 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2; 4255 4256 /** 4257 * Helper class to handle the forwarding of audio service events to the appropriate listener 4258 */ 4259 private class ServiceEventHandlerDelegate { 4260 private final Handler mHandler; 4261 ServiceEventHandlerDelegate(Handler handler)4262 ServiceEventHandlerDelegate(Handler handler) { 4263 Looper looper; 4264 if (handler == null) { 4265 if ((looper = Looper.myLooper()) == null) { 4266 looper = Looper.getMainLooper(); 4267 } 4268 } else { 4269 looper = handler.getLooper(); 4270 } 4271 4272 if (looper != null) { 4273 // implement the event handler delegate to receive events from audio service 4274 mHandler = new Handler(looper) { 4275 @Override 4276 public void handleMessage(Message msg) { 4277 switch (msg.what) { 4278 case MSSG_FOCUS_CHANGE: { 4279 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj); 4280 if (fri != null) { 4281 final OnAudioFocusChangeListener listener = 4282 fri.mRequest.getOnAudioFocusChangeListener(); 4283 if (listener != null) { 4284 Log.d(TAG, "dispatching onAudioFocusChange(" 4285 + msg.arg1 + ") to " + msg.obj); 4286 listener.onAudioFocusChange(msg.arg1); 4287 } 4288 } 4289 } break; 4290 case MSSG_RECORDING_CONFIG_CHANGE: { 4291 final RecordConfigChangeCallbackData cbData = 4292 (RecordConfigChangeCallbackData) msg.obj; 4293 if (cbData.mCb != null) { 4294 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs); 4295 } 4296 } break; 4297 case MSSG_PLAYBACK_CONFIG_CHANGE: { 4298 final PlaybackConfigChangeCallbackData cbData = 4299 (PlaybackConfigChangeCallbackData) msg.obj; 4300 if (cbData.mCb != null) { 4301 if (DEBUG) { 4302 Log.d(TAG, "dispatching onPlaybackConfigChanged()"); 4303 } 4304 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs); 4305 } 4306 } break; 4307 default: 4308 Log.e(TAG, "Unknown event " + msg.what); 4309 } 4310 } 4311 }; 4312 } else { 4313 mHandler = null; 4314 } 4315 } 4316 getHandler()4317 Handler getHandler() { 4318 return mHandler; 4319 } 4320 } 4321 4322 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() { 4323 @Override 4324 public void dispatchAudioFocusChange(int focusChange, String id) { 4325 final FocusRequestInfo fri = findFocusRequestInfo(id); 4326 if (fri != null) { 4327 final OnAudioFocusChangeListener listener = 4328 fri.mRequest.getOnAudioFocusChangeListener(); 4329 if (listener != null) { 4330 final Handler h = (fri.mHandler == null) ? 4331 mServiceEventHandlerDelegate.getHandler() : fri.mHandler; 4332 final Message m = h.obtainMessage( 4333 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, 4334 id/*obj*/); 4335 h.sendMessage(m); 4336 } 4337 } 4338 } 4339 4340 @Override 4341 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) { 4342 synchronized (mFocusRequestsLock) { 4343 // TODO use generation counter as the key instead 4344 final BlockingFocusResultReceiver focusReceiver = 4345 mFocusRequestsAwaitingResult.remove(clientId); 4346 if (focusReceiver != null) { 4347 focusReceiver.notifyResult(requestResult); 4348 } else { 4349 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver"); 4350 } 4351 } 4352 } 4353 }; 4354 getIdForAudioFocusListener(OnAudioFocusChangeListener l)4355 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) { 4356 if (l == null) { 4357 return new String(this.toString()); 4358 } else { 4359 return new String(this.toString() + l.toString()); 4360 } 4361 } 4362 4363 /** 4364 * @hide 4365 * Registers a listener to be called when audio focus changes and keeps track of the associated 4366 * focus request (including Handler to use for the listener). 4367 * @param afr the full request parameters 4368 */ registerAudioFocusRequest(@onNull AudioFocusRequest afr)4369 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) { 4370 final Handler h = afr.getOnAudioFocusChangeListenerHandler(); 4371 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null : 4372 new ServiceEventHandlerDelegate(h).getHandler()); 4373 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 4374 mAudioFocusIdListenerMap.put(key, fri); 4375 } 4376 4377 /** 4378 * @hide 4379 * Causes the specified listener to not be called anymore when focus is gained or lost. 4380 * @param l the listener to unregister. 4381 */ unregisterAudioFocusRequest(OnAudioFocusChangeListener l)4382 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) { 4383 // remove locally 4384 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l)); 4385 } 4386 4387 4388 /** 4389 * A failed focus change request. 4390 */ 4391 public static final int AUDIOFOCUS_REQUEST_FAILED = 0; 4392 /** 4393 * A successful focus change request. 4394 */ 4395 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; 4396 /** 4397 * A focus change request whose granting is delayed: the request was successful, but the 4398 * requester will only be granted audio focus once the condition that prevented immediate 4399 * granting has ended. 4400 * See {@link #requestAudioFocus(AudioFocusRequest)} and 4401 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} 4402 */ 4403 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2; 4404 4405 /** @hide */ 4406 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = { 4407 AUDIOFOCUS_REQUEST_FAILED, 4408 AUDIOFOCUS_REQUEST_GRANTED, 4409 AUDIOFOCUS_REQUEST_DELAYED } 4410 ) 4411 @Retention(RetentionPolicy.SOURCE) 4412 public @interface FocusRequestResult {} 4413 4414 /** 4415 * @hide 4416 * code returned when a synchronous focus request on the client-side is to be blocked 4417 * until the external audio focus policy decides on the response for the client 4418 */ 4419 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100; 4420 4421 /** 4422 * Timeout duration in ms when waiting on an external focus policy for the result for a 4423 * focus request 4424 */ 4425 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 250; 4426 4427 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id"; 4428 4429 private final Object mFocusRequestsLock = new Object(); 4430 /** 4431 * Map of all receivers of focus request results, one per unresolved focus request. 4432 * Receivers are added before sending the request to the external focus policy, 4433 * and are removed either after receiving the result, or after the timeout. 4434 * This variable is lazily initialized. 4435 */ 4436 @GuardedBy("mFocusRequestsLock") 4437 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult; 4438 4439 4440 /** 4441 * Request audio focus. 4442 * Send a request to obtain the audio focus 4443 * @param l the listener to be notified of audio focus changes 4444 * @param streamType the main audio stream type affected by the focus request 4445 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 4446 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 4447 * for the playback of driving directions, or notifications sounds. 4448 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 4449 * the previous focus owner to keep playing if it ducks its audio output. 4450 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 4451 * that benefits from the system not playing disruptive sounds like notifications, for 4452 * usecases such as voice memo recording, or speech recognition. 4453 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 4454 * as the playback of a song or a video. 4455 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4456 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)} 4457 */ requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)4458 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) { 4459 PlayerBase.deprecateStreamTypeForPlayback(streamType, 4460 "AudioManager", "requestAudioFocus()"); 4461 int status = AUDIOFOCUS_REQUEST_FAILED; 4462 4463 try { 4464 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or 4465 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the 4466 // AUDIOFOCUS_FLAG_DELAY_OK flag 4467 status = requestAudioFocus(l, 4468 new AudioAttributes.Builder() 4469 .setInternalLegacyStreamType(streamType).build(), 4470 durationHint, 4471 0 /* flags, legacy behavior */); 4472 } catch (IllegalArgumentException e) { 4473 Log.e(TAG, "Audio focus request denied due to ", e); 4474 } 4475 4476 return status; 4477 } 4478 4479 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks 4480 /** 4481 * @hide 4482 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be 4483 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when 4484 * the system is in a state where focus cannot change, but be granted focus later when 4485 * this condition ends. 4486 */ 4487 @SystemApi 4488 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0; 4489 /** 4490 * @hide 4491 * Use this flag when requesting audio focus to indicate that the requester 4492 * will pause its media playback (if applicable) when losing audio focus with 4493 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking. 4494 * <br>On some platforms, the ducking may be handled without the application being aware of it 4495 * (i.e. it will not transiently lose focus). For applications that for instance play spoken 4496 * content, such as audio book or podcast players, ducking may never be acceptable, and will 4497 * thus always pause. This flag enables them to be declared as such whenever they request focus. 4498 */ 4499 @SystemApi 4500 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1; 4501 /** 4502 * @hide 4503 * Use this flag to lock audio focus so granting is temporarily disabled. 4504 * <br>This flag can only be used by owners of a registered 4505 * {@link android.media.audiopolicy.AudioPolicy} in 4506 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)} 4507 */ 4508 @SystemApi 4509 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2; 4510 4511 /** 4512 * @hide 4513 * flag set on test API calls, 4514 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}, 4515 */ 4516 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3; 4517 /** @hide */ 4518 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK 4519 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS; 4520 /** @hide */ 4521 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK 4522 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK; 4523 4524 /** 4525 * Request audio focus. 4526 * See the {@link AudioFocusRequest} for information about the options available to configure 4527 * your request, and notification of focus gain and loss. 4528 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is 4529 * requested. 4530 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4531 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4532 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus 4533 * is requested without building the {@link AudioFocusRequest} with 4534 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to 4535 * {@code true}. 4536 * @throws NullPointerException if passed a null argument 4537 */ requestAudioFocus(@onNull AudioFocusRequest focusRequest)4538 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) { 4539 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/); 4540 } 4541 4542 /** 4543 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 4544 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus 4545 * with {@link #requestAudioFocus(AudioFocusRequest)}. 4546 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4547 * @throws IllegalArgumentException if passed a null argument 4548 */ abandonAudioFocusRequest(@onNull AudioFocusRequest focusRequest)4549 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) { 4550 if (focusRequest == null) { 4551 throw new IllegalArgumentException("Illegal null AudioFocusRequest"); 4552 } 4553 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(), 4554 focusRequest.getAudioAttributes()); 4555 } 4556 4557 /** 4558 * @hide 4559 * Request audio focus. 4560 * Send a request to obtain the audio focus. This method differs from 4561 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express 4562 * that the requester accepts delayed grants of audio focus. 4563 * @param l the listener to be notified of audio focus changes. It is not allowed to be null 4564 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}. 4565 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 4566 * requesting audio focus. 4567 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 4568 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 4569 * for the playback of driving directions, or notifications sounds. 4570 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 4571 * the previous focus owner to keep playing if it ducks its audio output. 4572 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 4573 * that benefits from the system not playing disruptive sounds like notifications, for 4574 * usecases such as voice memo recording, or speech recognition. 4575 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 4576 * as the playback of a song or a video. 4577 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 4578 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}. 4579 * <br>Use 0 when not using any flags for the request, which behaves like 4580 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 4581 * focus is granted immediately, or the grant request fails because the system is in a 4582 * state where focus cannot change (e.g. a phone call). 4583 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4584 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4585 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested 4586 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag. 4587 * @throws IllegalArgumentException 4588 */ 4589 @SystemApi 4590 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags)4591 public int requestAudioFocus(OnAudioFocusChangeListener l, 4592 @NonNull AudioAttributes requestAttributes, 4593 int durationHint, 4594 int flags) throws IllegalArgumentException { 4595 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) { 4596 throw new IllegalArgumentException("Invalid flags 0x" 4597 + Integer.toHexString(flags).toUpperCase()); 4598 } 4599 return requestAudioFocus(l, requestAttributes, durationHint, 4600 flags & AUDIOFOCUS_FLAGS_APPS, 4601 null /* no AudioPolicy*/); 4602 } 4603 4604 /** 4605 * @hide 4606 * Request or lock audio focus. 4607 * This method is to be used by system components that have registered an 4608 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 4609 * so focus granting is temporarily disabled. 4610 * @param l see the description of the same parameter in 4611 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4612 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 4613 * requesting audio focus. 4614 * @param durationHint see the description of the same parameter in 4615 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4616 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 4617 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}. 4618 * <br>Use 0 when not using any flags for the request, which behaves like 4619 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 4620 * focus is granted immediately, or the grant request fails because the system is in a 4621 * state where focus cannot change (e.g. a phone call). 4622 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 4623 * focus, or null. 4624 * @return see the description of the same return value in 4625 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4626 * @throws IllegalArgumentException 4627 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)} 4628 */ 4629 @SystemApi 4630 @RequiresPermission(anyOf= { 4631 Manifest.permission.MODIFY_PHONE_STATE, 4632 Manifest.permission.MODIFY_AUDIO_ROUTING 4633 }) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags, AudioPolicy ap)4634 public int requestAudioFocus(OnAudioFocusChangeListener l, 4635 @NonNull AudioAttributes requestAttributes, 4636 int durationHint, 4637 int flags, 4638 AudioPolicy ap) throws IllegalArgumentException { 4639 // parameter checking 4640 if (requestAttributes == null) { 4641 throw new IllegalArgumentException("Illegal null AudioAttributes argument"); 4642 } 4643 if (!AudioFocusRequest.isValidFocusGain(durationHint)) { 4644 throw new IllegalArgumentException("Invalid duration hint"); 4645 } 4646 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) { 4647 throw new IllegalArgumentException("Illegal flags 0x" 4648 + Integer.toHexString(flags).toUpperCase()); 4649 } 4650 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) { 4651 throw new IllegalArgumentException( 4652 "Illegal null focus listener when flagged as accepting delayed focus grant"); 4653 } 4654 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4655 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) { 4656 throw new IllegalArgumentException( 4657 "Illegal null focus listener when flagged as pausing instead of ducking"); 4658 } 4659 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) { 4660 throw new IllegalArgumentException( 4661 "Illegal null audio policy when locking audio focus"); 4662 } 4663 4664 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint) 4665 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */) 4666 .setAudioAttributes(requestAttributes) 4667 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK) 4668 == AUDIOFOCUS_FLAG_DELAY_OK) 4669 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4670 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4671 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) 4672 .build(); 4673 return requestAudioFocus(afr, ap); 4674 } 4675 4676 /** 4677 * @hide 4678 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID. 4679 * Used to simulate conditions of the test, not the behavior of the focus requester under test. 4680 * @param afr the parameters of the request 4681 * @param clientFakeId the identifier of the AudioManager the client would be requesting from 4682 * @param clientFakeUid the UID of the client, here an arbitrary int, 4683 * doesn't have to be a real UID 4684 * @param clientTargetSdk the target SDK used by the client 4685 * @return return code indicating status of the request 4686 */ 4687 @TestApi 4688 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") requestAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk)4689 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr, 4690 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) { 4691 Objects.requireNonNull(afr); 4692 Objects.requireNonNull(clientFakeId); 4693 int status; 4694 BlockingFocusResultReceiver focusReceiver; 4695 synchronized (mFocusRequestsLock) { 4696 try { 4697 status = getService().requestAudioFocusForTest(afr.getAudioAttributes(), 4698 afr.getFocusGain(), 4699 mICallBack, 4700 mAudioFocusDispatcher, 4701 clientFakeId, "com.android.test.fakeclient", 4702 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST, 4703 clientFakeUid, clientTargetSdk); 4704 } catch (RemoteException e) { 4705 throw e.rethrowFromSystemServer(); 4706 } 4707 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) { 4708 // default path with no external focus policy 4709 return status; 4710 } 4711 4712 focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId); 4713 } 4714 4715 return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver); 4716 } 4717 4718 /** 4719 * @hide 4720 * Test API to abandon audio focus for an arbitrary client. 4721 * Used to simulate conditions of the test, not the behavior of the focus requester under test. 4722 * @param afr the parameters used for the request 4723 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client 4724 * would be requesting 4725 * @return return code indicating status of the request 4726 */ 4727 @TestApi 4728 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") abandonAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId)4729 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr, 4730 @NonNull String clientFakeId) { 4731 Objects.requireNonNull(afr); 4732 Objects.requireNonNull(clientFakeId); 4733 try { 4734 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher, 4735 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient"); 4736 } catch (RemoteException e) { 4737 throw e.rethrowFromSystemServer(); 4738 } 4739 } 4740 4741 /** 4742 * @hide 4743 * Return the duration of the fade out applied when a player of the given AudioAttributes 4744 * is losing audio focus 4745 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS} 4746 * @return a duration in ms, 0 indicates no fade out is applied 4747 */ 4748 @TestApi 4749 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFadeOutDurationOnFocusLossMillis(@onNull AudioAttributes aa)4750 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa) 4751 { 4752 Objects.requireNonNull(aa); 4753 try { 4754 return getService().getFadeOutDurationOnFocusLossMillis(aa); 4755 } catch (RemoteException e) { 4756 throw e.rethrowFromSystemServer(); 4757 } 4758 } 4759 4760 /** 4761 * @hide 4762 * Test method to return the list of UIDs currently marked as ducked because of their 4763 * audio focus status 4764 * @return the list of UIDs, can be empty when no app is being ducked. 4765 */ 4766 @TestApi 4767 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4768 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFocusDuckedUidsForTest()4769 public @NonNull List<Integer> getFocusDuckedUidsForTest() { 4770 try { 4771 return getService().getFocusDuckedUidsForTest(); 4772 } catch (RemoteException e) { 4773 throw e.rethrowFromSystemServer(); 4774 } 4775 } 4776 4777 /** 4778 * @hide 4779 * Test method to return the duration of the fade out applied on the players of a focus loser 4780 * @return the fade out duration in ms 4781 */ 4782 @TestApi 4783 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4784 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFocusFadeOutDurationForTest()4785 public long getFocusFadeOutDurationForTest() { 4786 try { 4787 return getService().getFocusFadeOutDurationForTest(); 4788 } catch (RemoteException e) { 4789 throw e.rethrowFromSystemServer(); 4790 } 4791 } 4792 4793 /** 4794 * @hide 4795 * Test method to return the length of time after a fade-out before the focus loser is unmuted 4796 * (and is faded back in). 4797 * @return the time gap after a fade-out completion on focus loss, and fade-in start in ms. 4798 */ 4799 @TestApi 4800 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4801 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFocusUnmuteDelayAfterFadeOutForTest()4802 public long getFocusUnmuteDelayAfterFadeOutForTest() { 4803 try { 4804 return getService().getFocusUnmuteDelayAfterFadeOutForTest(); 4805 } catch (RemoteException e) { 4806 throw e.rethrowFromSystemServer(); 4807 } 4808 } 4809 4810 /** 4811 * @hide 4812 * Test method to start preventing applications from requesting audio focus during a test, 4813 * which could interfere with the functionality/behavior under test. 4814 * Calling this method needs to be paired with a call to {@link #exitAudioFocusFreezeForTest} 4815 * when the testing is done. If this is not the case (e.g. in case of a test crash), 4816 * a death observer mechanism will ensure the system is not left in a bad state, but this should 4817 * not be relied on when implementing tests. 4818 * @param exemptedUids a list of UIDs that are exempt from the freeze. This would for instance 4819 * be those of the test runner and other players used in the test, or the "fake" UIDs used 4820 * for testing with {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}. 4821 * @return true if the focus freeze mode is successfully entered, false if there was an issue, 4822 * such as another freeze in place at the time of invocation. 4823 * A false result should result in a test failure as this would indicate the system is not 4824 * in a proper state with a predictable behavior for audio focus management. 4825 */ 4826 @TestApi 4827 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4828 @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") enterAudioFocusFreezeForTest(@onNull List<Integer> exemptedUids)4829 public boolean enterAudioFocusFreezeForTest(@NonNull List<Integer> exemptedUids) { 4830 Objects.requireNonNull(exemptedUids); 4831 try { 4832 final int[] uids = exemptedUids.stream().mapToInt(Integer::intValue).toArray(); 4833 return getService().enterAudioFocusFreezeForTest(mICallBack, uids); 4834 } catch (RemoteException e) { 4835 throw e.rethrowFromSystemServer(); 4836 } 4837 } 4838 4839 /** 4840 * @hide 4841 * Test method to end preventing applications from requesting audio focus during a test. 4842 * @return true if the focus freeze mode is successfully exited, false if there was an issue, 4843 * such as the freeze already having ended, or not started. 4844 */ 4845 @TestApi 4846 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4847 @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") exitAudioFocusFreezeForTest()4848 public boolean exitAudioFocusFreezeForTest() { 4849 try { 4850 return getService().exitAudioFocusFreezeForTest(mICallBack); 4851 } catch (RemoteException e) { 4852 throw e.rethrowFromSystemServer(); 4853 } 4854 } 4855 4856 /** 4857 * @hide 4858 * Request or lock audio focus. 4859 * This method is to be used by system components that have registered an 4860 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 4861 * so focus granting is temporarily disabled. 4862 * @param afr see the description of the same parameter in 4863 * {@link #requestAudioFocus(AudioFocusRequest)} 4864 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 4865 * focus, or null. 4866 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4867 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4868 * @throws NullPointerException if the AudioFocusRequest is null 4869 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy 4870 */ 4871 @SystemApi 4872 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) requestAudioFocus(@onNull AudioFocusRequest afr, @Nullable AudioPolicy ap)4873 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) { 4874 if (afr == null) { 4875 throw new NullPointerException("Illegal null AudioFocusRequest"); 4876 } 4877 // this can only be checked now, not during the creation of the AudioFocusRequest instance 4878 if (afr.locksFocus() && ap == null) { 4879 throw new IllegalArgumentException( 4880 "Illegal null audio policy when locking audio focus"); 4881 } 4882 4883 if (hasCustomPolicyVirtualDeviceContext()) { 4884 // If the focus request was made within context associated with VirtualDevice 4885 // configured with custom device policy for audio, bypass audio service focus handling. 4886 // The custom device policy for audio means that audio associated with this device 4887 // is likely rerouted to VirtualAudioDevice and playback on the VirtualAudioDevice 4888 // shouldn't affect non-virtual audio tracks (and vice versa). 4889 return AUDIOFOCUS_REQUEST_GRANTED; 4890 } 4891 4892 registerAudioFocusRequest(afr); 4893 final IAudioService service = getService(); 4894 final int status; 4895 int sdk; 4896 try { 4897 sdk = getContext().getApplicationInfo().targetSdkVersion; 4898 } catch (NullPointerException e) { 4899 // some tests don't have a Context 4900 sdk = Build.VERSION.SDK_INT; 4901 } 4902 4903 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 4904 BlockingFocusResultReceiver focusReceiver; 4905 synchronized (mFocusRequestsLock) { 4906 4907 try { 4908 // TODO status contains result and generation counter for ext policy 4909 status = service.requestAudioFocus(afr.getAudioAttributes(), 4910 afr.getFocusGain(), mICallBack, 4911 mAudioFocusDispatcher, 4912 clientId, 4913 getContext().getOpPackageName() /* package name */, 4914 getContext().getAttributionTag(), 4915 afr.getFlags(), 4916 ap != null ? ap.cb() : null, 4917 sdk); 4918 } catch (RemoteException e) { 4919 throw e.rethrowFromSystemServer(); 4920 } 4921 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) { 4922 // default path with no external focus policy 4923 return status; 4924 } 4925 focusReceiver = addClientIdToFocusReceiverLocked(clientId); 4926 } 4927 4928 return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver); 4929 } 4930 4931 @GuardedBy("mFocusRequestsLock") addClientIdToFocusReceiverLocked(String clientId)4932 private BlockingFocusResultReceiver addClientIdToFocusReceiverLocked(String clientId) { 4933 BlockingFocusResultReceiver focusReceiver; 4934 if (mFocusRequestsAwaitingResult == null) { 4935 mFocusRequestsAwaitingResult = 4936 new HashMap<String, BlockingFocusResultReceiver>(1); 4937 } 4938 focusReceiver = new BlockingFocusResultReceiver(clientId); 4939 mFocusRequestsAwaitingResult.put(clientId, focusReceiver); 4940 return focusReceiver; 4941 } 4942 handleExternalAudioPolicyWaitIfNeeded(String clientId, BlockingFocusResultReceiver focusReceiver)4943 private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId, 4944 BlockingFocusResultReceiver focusReceiver) { 4945 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS); 4946 if (DEBUG && !focusReceiver.receivedResult()) { 4947 Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded" 4948 + " response from ext policy timed out, denying request"); 4949 } 4950 4951 synchronized (mFocusRequestsLock) { 4952 mFocusRequestsAwaitingResult.remove(clientId); 4953 } 4954 return focusReceiver.requestResult(); 4955 } 4956 4957 // helper class that abstracts out the handling of spurious wakeups in Object.wait() 4958 private static final class SafeWaitObject { 4959 private boolean mQuit = false; 4960 safeNotify()4961 public void safeNotify() { 4962 synchronized (this) { 4963 mQuit = true; 4964 this.notify(); 4965 } 4966 } 4967 safeWait(long millis)4968 public void safeWait(long millis) throws InterruptedException { 4969 final long timeOutTime = java.lang.System.currentTimeMillis() + millis; 4970 synchronized (this) { 4971 while (!mQuit) { 4972 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis(); 4973 if (timeToWait <= 0) { 4974 break; 4975 } 4976 this.wait(timeToWait); 4977 } 4978 } 4979 } 4980 } 4981 4982 private static final class BlockingFocusResultReceiver { 4983 private final SafeWaitObject mLock = new SafeWaitObject(); 4984 @GuardedBy("mLock") 4985 private boolean mResultReceived = false; 4986 // request denied by default (e.g. timeout) 4987 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED; 4988 private final String mFocusClientId; 4989 BlockingFocusResultReceiver(String clientId)4990 BlockingFocusResultReceiver(String clientId) { 4991 mFocusClientId = clientId; 4992 } 4993 receivedResult()4994 boolean receivedResult() { return mResultReceived; } requestResult()4995 int requestResult() { return mFocusRequestResult; } 4996 notifyResult(int requestResult)4997 void notifyResult(int requestResult) { 4998 synchronized (mLock) { 4999 mResultReceived = true; 5000 mFocusRequestResult = requestResult; 5001 mLock.safeNotify(); 5002 } 5003 } 5004 waitForResult(long timeOutMs)5005 public void waitForResult(long timeOutMs) { 5006 synchronized (mLock) { 5007 if (mResultReceived) { 5008 // the result was received before waiting 5009 return; 5010 } 5011 try { 5012 mLock.safeWait(timeOutMs); 5013 } catch (InterruptedException e) { } 5014 } 5015 } 5016 } 5017 5018 /** 5019 * @hide 5020 * Used internally by telephony package to request audio focus. Will cause the focus request 5021 * to be associated with the "voice communication" identifier only used in AudioService 5022 * to identify this use case. 5023 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for 5024 * the establishment of the call 5025 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so 5026 * media applications resume after a call 5027 */ 5028 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) requestAudioFocusForCall(int streamType, int durationHint)5029 public void requestAudioFocusForCall(int streamType, int durationHint) { 5030 final IAudioService service = getService(); 5031 try { 5032 service.requestAudioFocus(new AudioAttributes.Builder() 5033 .setInternalLegacyStreamType(streamType).build(), 5034 durationHint, mICallBack, null, 5035 AudioSystem.IN_VOICE_COMM_FOCUS_ID, 5036 getContext().getOpPackageName(), 5037 getContext().getAttributionTag(), 5038 AUDIOFOCUS_FLAG_LOCK, 5039 null /* policy token */, 0 /* sdk n/a here*/); 5040 } catch (RemoteException e) { 5041 throw e.rethrowFromSystemServer(); 5042 } 5043 } 5044 5045 /** 5046 * @hide 5047 * Return the volume ramping time for a sound to be played after the given focus request, 5048 * and to play a sound of the given attributes 5049 * @param focusGain 5050 * @param attr 5051 * @return 5052 */ getFocusRampTimeMs(int focusGain, AudioAttributes attr)5053 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) { 5054 final IAudioService service = getService(); 5055 try { 5056 return service.getFocusRampTimeMs(focusGain, attr); 5057 } catch (RemoteException e) { 5058 throw e.rethrowFromSystemServer(); 5059 } 5060 } 5061 5062 /** 5063 * @hide 5064 * Set the result to the audio focus request received through 5065 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 5066 * @param afi the information about the focus requester 5067 * @param requestResult the result to the focus request to be passed to the requester 5068 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 5069 */ 5070 @SystemApi 5071 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setFocusRequestResult(@onNull AudioFocusInfo afi, @FocusRequestResult int requestResult, @NonNull AudioPolicy ap)5072 public void setFocusRequestResult(@NonNull AudioFocusInfo afi, 5073 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) { 5074 if (afi == null) { 5075 throw new IllegalArgumentException("Illegal null AudioFocusInfo"); 5076 } 5077 if (ap == null) { 5078 throw new IllegalArgumentException("Illegal null AudioPolicy"); 5079 } 5080 final IAudioService service = getService(); 5081 try { 5082 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb()); 5083 } catch (RemoteException e) { 5084 throw e.rethrowFromSystemServer(); 5085 } 5086 } 5087 5088 /** 5089 * @hide 5090 * Notifies an application with a focus listener of gain or loss of audio focus. 5091 * This method can only be used by owners of an {@link AudioPolicy} configured with 5092 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true. 5093 * @param afi the recipient of the focus change, that has previously requested audio focus, and 5094 * that was received by the {@code AudioPolicy} through 5095 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 5096 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN}, 5097 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or 5098 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}) 5099 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS}, 5100 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}, 5101 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}). 5102 * <br>For the focus gain, the change type should be the same as the app requested. 5103 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 5104 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or 5105 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or 5106 * if there was an error sending the request. 5107 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null. 5108 */ 5109 @SystemApi 5110 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) dispatchAudioFocusChange(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap)5111 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange, 5112 @NonNull AudioPolicy ap) { 5113 if (afi == null) { 5114 throw new NullPointerException("Illegal null AudioFocusInfo"); 5115 } 5116 if (ap == null) { 5117 throw new NullPointerException("Illegal null AudioPolicy"); 5118 } 5119 final IAudioService service = getService(); 5120 try { 5121 return service.dispatchFocusChange(afi, focusChange, ap.cb()); 5122 } catch (RemoteException e) { 5123 throw e.rethrowFromSystemServer(); 5124 } 5125 } 5126 5127 /** 5128 * Notifies an application with a focus listener of gain or loss of audio focus 5129 * 5130 * <p>This is similar to {@link #dispatchAudioFocusChange(AudioFocusInfo, int, AudioPolicy)} but 5131 * with additional functionality of fade. The players of the application with audio focus 5132 * change, provided they meet the active {@link FadeManagerConfiguration} requirements, are 5133 * faded before dispatching the callback to the application. For example, players of the 5134 * application losing audio focus will be faded out, whereas players of the application gaining 5135 * audio focus will be faded in, if needed. 5136 * 5137 * <p>The applicability of fade is decided against the supplied active {@link AudioFocusInfo}. 5138 * This list cannot be {@code null}. The list can be empty if no other active 5139 * {@link AudioFocusInfo} available at the time of the dispatch. 5140 * 5141 * <p>The {@link FadeManagerConfiguration} supplied here is prioritized over existing fade 5142 * configurations. If none supplied, either the {@link FadeManagerConfiguration} set through 5143 * {@link AudioPolicy} or the default will be used to determine the fade properties. 5144 * 5145 * <p>This method can only be used by owners of an {@link AudioPolicy} configured with 5146 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true. 5147 * 5148 * @param afi the recipient of the focus change, that has previously requested audio focus, and 5149 * that was received by the {@code AudioPolicy} through 5150 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)} 5151 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN}, 5152 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or 5153 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}) 5154 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS}, 5155 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}, 5156 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}). 5157 * <br>For the focus gain, the change type should be the same as the app requested 5158 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 5159 * @param otherActiveAfis active {@link AudioFocusInfo} that are granted audio focus at the time 5160 * of dispatch 5161 * @param transientFadeMgrConfig {@link FadeManagerConfiguration} that will be used for fading 5162 * players resulting from this dispatch. This is a transient configuration that is only 5163 * valid for this focus change and shall be discarded after processing this request. 5164 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener or if 5165 * there was an error sending the request, or {@link #AUDIOFOCUS_REQUEST_GRANTED} if the 5166 * dispatch was successfully sent, or {@link #AUDIOFOCUS_REQUEST_DELAYED} if 5167 * the request was successful but the dispatch of focus change was delayed due to a fade 5168 * operation. 5169 * @hide 5170 */ 5171 @FlaggedApi(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION) 5172 @SystemApi 5173 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) 5174 @FocusRequestResult dispatchAudioFocusChangeWithFade(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap, @NonNull List<AudioFocusInfo> otherActiveAfis, @Nullable FadeManagerConfiguration transientFadeMgrConfig)5175 public int dispatchAudioFocusChangeWithFade(@NonNull AudioFocusInfo afi, int focusChange, 5176 @NonNull AudioPolicy ap, @NonNull List<AudioFocusInfo> otherActiveAfis, 5177 @Nullable FadeManagerConfiguration transientFadeMgrConfig) { 5178 Objects.requireNonNull(afi, "AudioFocusInfo cannot be null"); 5179 Objects.requireNonNull(ap, "AudioPolicy cannot be null"); 5180 Objects.requireNonNull(otherActiveAfis, "Other active AudioFocusInfo list cannot be null"); 5181 5182 IAudioService service = getService(); 5183 try { 5184 return service.dispatchFocusChangeWithFade(afi, focusChange, ap.cb(), otherActiveAfis, 5185 transientFadeMgrConfig); 5186 } catch (RemoteException e) { 5187 throw e.rethrowFromSystemServer(); 5188 } 5189 } 5190 5191 /** 5192 * @hide 5193 * Used internally by telephony package to abandon audio focus, typically after a call or 5194 * when ringing ends and the call is rejected or not answered. 5195 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. 5196 */ 5197 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) abandonAudioFocusForCall()5198 public void abandonAudioFocusForCall() { 5199 final IAudioService service = getService(); 5200 try { 5201 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID, 5202 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName()); 5203 } catch (RemoteException e) { 5204 throw e.rethrowFromSystemServer(); 5205 } 5206 } 5207 5208 /** 5209 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 5210 * @param l the listener with which focus was requested. 5211 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 5212 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 5213 */ abandonAudioFocus(OnAudioFocusChangeListener l)5214 public int abandonAudioFocus(OnAudioFocusChangeListener l) { 5215 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/); 5216 } 5217 5218 /** 5219 * @hide 5220 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 5221 * @param l the listener with which focus was requested. 5222 * @param aa the {@link AudioAttributes} with which audio focus was requested 5223 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 5224 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 5225 */ 5226 @SystemApi 5227 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would 5228 // have been done by a matching requestAudioFocus abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa)5229 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) { 5230 if (hasCustomPolicyVirtualDeviceContext()) { 5231 // If this AudioManager instance is running within VirtualDevice context configured 5232 // with custom device policy for audio, the audio focus handling is bypassed. 5233 return AUDIOFOCUS_REQUEST_GRANTED; 5234 } 5235 unregisterAudioFocusRequest(l); 5236 final IAudioService service = getService(); 5237 try { 5238 return service.abandonAudioFocus(mAudioFocusDispatcher, 5239 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName()); 5240 } catch (RemoteException e) { 5241 throw e.rethrowFromSystemServer(); 5242 } 5243 } 5244 5245 //==================================================================== 5246 // Remote Control 5247 /** 5248 * Register a component to be the sole receiver of MEDIA_BUTTON intents. 5249 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 5250 * that will receive the media button intent. This broadcast receiver must be declared 5251 * in the application manifest. The package of the component must match that of 5252 * the context you're registering from. 5253 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 5254 */ 5255 @Deprecated registerMediaButtonEventReceiver(ComponentName eventReceiver)5256 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 5257 if (eventReceiver == null) { 5258 return; 5259 } 5260 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) { 5261 Log.e(TAG, "registerMediaButtonEventReceiver() error: " + 5262 "receiver and context package names don't match"); 5263 return; 5264 } 5265 // construct a PendingIntent for the media button and register it 5266 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 5267 // the associated intent will be handled by the component being registered 5268 mediaButtonIntent.setComponent(eventReceiver); 5269 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 5270 0/*requestCode, ignored*/, mediaButtonIntent, 5271 PendingIntent.FLAG_IMMUTABLE); 5272 registerMediaButtonIntent(pi, eventReceiver); 5273 } 5274 5275 /** 5276 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like 5277 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows 5278 * the buttons to go to any PendingIntent. Note that you should only use this form if 5279 * you know you will continue running for the full time until unregistering the 5280 * PendingIntent. 5281 * @param eventReceiver target that will receive media button intents. The PendingIntent 5282 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action 5283 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the 5284 * media button that was pressed. 5285 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 5286 */ 5287 @Deprecated registerMediaButtonEventReceiver(PendingIntent eventReceiver)5288 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) { 5289 if (eventReceiver == null) { 5290 return; 5291 } 5292 registerMediaButtonIntent(eventReceiver, null); 5293 } 5294 5295 /** 5296 * @hide 5297 * no-op if (pi == null) or (eventReceiver == null) 5298 */ registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver)5299 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) { 5300 if (pi == null) { 5301 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter"); 5302 return; 5303 } 5304 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 5305 helper.addMediaButtonListener(pi, eventReceiver, getContext()); 5306 } 5307 5308 /** 5309 * Unregister the receiver of MEDIA_BUTTON intents. 5310 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 5311 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}. 5312 * @deprecated Use {@link MediaSession} instead. 5313 */ 5314 @Deprecated unregisterMediaButtonEventReceiver(ComponentName eventReceiver)5315 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 5316 if (eventReceiver == null) { 5317 return; 5318 } 5319 // construct a PendingIntent for the media button and unregister it 5320 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 5321 // the associated intent will be handled by the component being registered 5322 mediaButtonIntent.setComponent(eventReceiver); 5323 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 5324 0/*requestCode, ignored*/, mediaButtonIntent, 5325 PendingIntent.FLAG_IMMUTABLE); 5326 unregisterMediaButtonIntent(pi); 5327 } 5328 5329 /** 5330 * Unregister the receiver of MEDIA_BUTTON intents. 5331 * @param eventReceiver same PendingIntent that was registed with 5332 * {@link #registerMediaButtonEventReceiver(PendingIntent)}. 5333 * @deprecated Use {@link MediaSession} instead. 5334 */ 5335 @Deprecated unregisterMediaButtonEventReceiver(PendingIntent eventReceiver)5336 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) { 5337 if (eventReceiver == null) { 5338 return; 5339 } 5340 unregisterMediaButtonIntent(eventReceiver); 5341 } 5342 5343 /** 5344 * @hide 5345 */ unregisterMediaButtonIntent(PendingIntent pi)5346 public void unregisterMediaButtonIntent(PendingIntent pi) { 5347 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 5348 helper.removeMediaButtonListener(pi); 5349 } 5350 5351 /** 5352 * Registers the remote control client for providing information to display on the remote 5353 * controls. 5354 * @param rcClient The remote control client from which remote controls will receive 5355 * information to display. 5356 * @see RemoteControlClient 5357 * @deprecated Use {@link MediaSession} instead. 5358 */ 5359 @Deprecated registerRemoteControlClient(RemoteControlClient rcClient)5360 public void registerRemoteControlClient(RemoteControlClient rcClient) { 5361 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 5362 return; 5363 } 5364 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 5365 } 5366 5367 /** 5368 * Unregisters the remote control client that was providing information to display on the 5369 * remote controls. 5370 * @param rcClient The remote control client to unregister. 5371 * @see #registerRemoteControlClient(RemoteControlClient) 5372 * @deprecated Use {@link MediaSession} instead. 5373 */ 5374 @Deprecated unregisterRemoteControlClient(RemoteControlClient rcClient)5375 public void unregisterRemoteControlClient(RemoteControlClient rcClient) { 5376 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 5377 return; 5378 } 5379 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 5380 } 5381 5382 /** 5383 * Registers a {@link RemoteController} instance for it to receive media 5384 * metadata updates and playback state information from applications using 5385 * {@link RemoteControlClient}, and control their playback. 5386 * <p> 5387 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be 5388 * one of the enabled notification listeners (see 5389 * {@link android.service.notification.NotificationListenerService}). 5390 * 5391 * @param rctlr the object to register. 5392 * @return true if the {@link RemoteController} was successfully registered, 5393 * false if an error occurred, due to an internal system error, or 5394 * insufficient permissions. 5395 * @deprecated Use 5396 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)} 5397 * and {@link MediaController} instead. 5398 */ 5399 @Deprecated registerRemoteController(RemoteController rctlr)5400 public boolean registerRemoteController(RemoteController rctlr) { 5401 if (rctlr == null) { 5402 return false; 5403 } 5404 rctlr.startListeningToSessions(); 5405 return true; 5406 } 5407 5408 /** 5409 * Unregisters a {@link RemoteController}, causing it to no longer receive 5410 * media metadata and playback state information, and no longer be capable 5411 * of controlling playback. 5412 * 5413 * @param rctlr the object to unregister. 5414 * @deprecated Use 5415 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)} 5416 * instead. 5417 */ 5418 @Deprecated unregisterRemoteController(RemoteController rctlr)5419 public void unregisterRemoteController(RemoteController rctlr) { 5420 if (rctlr == null) { 5421 return; 5422 } 5423 rctlr.stopListeningToSessions(); 5424 } 5425 5426 5427 //==================================================================== 5428 // Audio policy 5429 /** 5430 * @hide 5431 * Register the given {@link AudioPolicy}. 5432 * This call is synchronous and blocks until the registration process successfully completed 5433 * or failed to complete. 5434 * @param policy the non-null {@link AudioPolicy} to register. 5435 * @return {@link #ERROR} if there was an error communicating with the registration service 5436 * or if the user doesn't have the required 5437 * {@link Manifest.permission#MODIFY_AUDIO_ROUTING} permission, 5438 * {@link #SUCCESS} otherwise. 5439 */ 5440 @SystemApi 5441 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) registerAudioPolicy(@onNull AudioPolicy policy)5442 public int registerAudioPolicy(@NonNull AudioPolicy policy) { 5443 return registerAudioPolicyStatic(policy); 5444 } 5445 registerAudioPolicyStatic(@onNull AudioPolicy policy)5446 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) { 5447 if (policy == null) { 5448 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 5449 } 5450 final IAudioService service = getService(); 5451 try { 5452 MediaProjection projection = policy.getMediaProjection(); 5453 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), 5454 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(), 5455 policy.isVolumeController(), 5456 projection == null ? null : projection.getProjection(), 5457 policy.getAttributionSource()); 5458 if (regId == null) { 5459 return ERROR; 5460 } else { 5461 policy.setRegistration(regId); 5462 } 5463 // successful registration 5464 } catch (RemoteException e) { 5465 throw e.rethrowFromSystemServer(); 5466 } 5467 return SUCCESS; 5468 } 5469 5470 /** 5471 * @hide 5472 * Unregisters an {@link AudioPolicy} asynchronously. 5473 * @param policy the non-null {@link AudioPolicy} to unregister. 5474 */ 5475 @SystemApi 5476 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicyAsync(@onNull AudioPolicy policy)5477 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) { 5478 unregisterAudioPolicyAsyncStatic(policy); 5479 } 5480 unregisterAudioPolicyAsyncStatic(@onNull AudioPolicy policy)5481 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) { 5482 if (policy == null) { 5483 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 5484 } 5485 final IAudioService service = getService(); 5486 try { 5487 service.unregisterAudioPolicyAsync(policy.cb()); 5488 policy.reset(); 5489 } catch (RemoteException e) { 5490 throw e.rethrowFromSystemServer(); 5491 } 5492 } 5493 5494 /** 5495 * @hide 5496 * Unregisters an {@link AudioPolicy} synchronously. 5497 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects 5498 * associated with mixes of this policy. 5499 * @param policy the non-null {@link AudioPolicy} to unregister. 5500 */ 5501 @SystemApi 5502 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicy(@onNull AudioPolicy policy)5503 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) { 5504 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument"); 5505 final IAudioService service = getService(); 5506 try { 5507 policy.invalidateCaptorsAndInjectors(); 5508 service.unregisterAudioPolicy(policy.cb()); 5509 policy.reset(); 5510 } catch (RemoteException e) { 5511 throw e.rethrowFromSystemServer(); 5512 } 5513 } 5514 5515 /** 5516 * @hide 5517 * @return All currently registered audio policy mixes. 5518 */ 5519 @TestApi 5520 @FlaggedApi(android.media.audiopolicy.Flags.FLAG_AUDIO_MIX_TEST_API) 5521 @NonNull getRegisteredPolicyMixes()5522 public List<android.media.audiopolicy.AudioMix> getRegisteredPolicyMixes() { 5523 if (!android.media.audiopolicy.Flags.audioMixTestApi()) { 5524 return Collections.emptyList(); 5525 } 5526 5527 final IAudioService service = getService(); 5528 try { 5529 return service.getRegisteredPolicyMixes(); 5530 } catch (RemoteException e) { 5531 throw e.rethrowFromSystemServer(); 5532 } 5533 } 5534 5535 /** 5536 * @hide 5537 * @return true if an AudioPolicy was previously registered 5538 */ 5539 @TestApi hasRegisteredDynamicPolicy()5540 public boolean hasRegisteredDynamicPolicy() { 5541 final IAudioService service = getService(); 5542 try { 5543 return service.hasRegisteredDynamicPolicy(); 5544 } catch (RemoteException e) { 5545 throw e.rethrowFromSystemServer(); 5546 } 5547 } 5548 5549 //==================================================================== 5550 // Notification of playback activity & playback configuration 5551 /** 5552 * Interface for receiving update notifications about the playback activity on the system. 5553 * Extend this abstract class and register it with 5554 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)} 5555 * to be notified. 5556 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current 5557 * configuration. 5558 * @see AudioPlaybackConfiguration 5559 */ 5560 public static abstract class AudioPlaybackCallback { 5561 /** 5562 * Called whenever the playback activity and configuration has changed. 5563 * @param configs list containing the results of 5564 * {@link AudioManager#getActivePlaybackConfigurations()}. 5565 */ onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs)5566 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {} 5567 } 5568 5569 private static class AudioPlaybackCallbackInfo { 5570 final AudioPlaybackCallback mCb; 5571 final Handler mHandler; AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler)5572 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) { 5573 mCb = cb; 5574 mHandler = handler; 5575 } 5576 } 5577 5578 private final static class PlaybackConfigChangeCallbackData { 5579 final AudioPlaybackCallback mCb; 5580 final List<AudioPlaybackConfiguration> mConfigs; 5581 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, List<AudioPlaybackConfiguration> configs)5582 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, 5583 List<AudioPlaybackConfiguration> configs) { 5584 mCb = cb; 5585 mConfigs = configs; 5586 } 5587 } 5588 5589 /** 5590 * Register a callback to be notified of audio playback changes through 5591 * {@link AudioPlaybackCallback} 5592 * @param cb non-null callback to register 5593 * @param handler the {@link Handler} object for the thread on which to execute 5594 * the callback. If <code>null</code>, the {@link Handler} associated with the main 5595 * {@link Looper} will be used. 5596 */ registerAudioPlaybackCallback(@onNull AudioPlaybackCallback cb, @Nullable Handler handler)5597 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb, 5598 @Nullable Handler handler) 5599 { 5600 if (cb == null) { 5601 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 5602 } 5603 5604 synchronized(mPlaybackCallbackLock) { 5605 // lazy initialization of the list of playback callbacks 5606 if (mPlaybackCallbackList == null) { 5607 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>(); 5608 } 5609 final int oldCbCount = mPlaybackCallbackList.size(); 5610 if (!hasPlaybackCallback_sync(cb)) { 5611 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb, 5612 new ServiceEventHandlerDelegate(handler).getHandler())); 5613 final int newCbCount = mPlaybackCallbackList.size(); 5614 if ((oldCbCount == 0) && (newCbCount > 0)) { 5615 // register binder for callbacks 5616 try { 5617 getService().registerPlaybackCallback(mPlayCb); 5618 } catch (RemoteException e) { 5619 throw e.rethrowFromSystemServer(); 5620 } 5621 } 5622 } else { 5623 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously" 5624 + "registered callback"); 5625 } 5626 } 5627 } 5628 5629 /** 5630 * Unregister an audio playback callback previously registered with 5631 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 5632 * @param cb non-null callback to unregister 5633 */ unregisterAudioPlaybackCallback(@onNull AudioPlaybackCallback cb)5634 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) { 5635 if (cb == null) { 5636 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 5637 } 5638 synchronized(mPlaybackCallbackLock) { 5639 if (mPlaybackCallbackList == null) { 5640 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 5641 + " that was never registered"); 5642 return; 5643 } 5644 final int oldCbCount = mPlaybackCallbackList.size(); 5645 if (removePlaybackCallback_sync(cb)) { 5646 final int newCbCount = mPlaybackCallbackList.size(); 5647 if ((oldCbCount > 0) && (newCbCount == 0)) { 5648 // unregister binder for callbacks 5649 try { 5650 getService().unregisterPlaybackCallback(mPlayCb); 5651 } catch (RemoteException e) { 5652 throw e.rethrowFromSystemServer(); 5653 } 5654 } 5655 } else { 5656 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 5657 + " already unregistered or never registered"); 5658 } 5659 } 5660 } 5661 5662 /** 5663 * Returns the current active audio playback configurations of the device 5664 * @return a non-null list of playback configurations. An empty list indicates there is no 5665 * playback active when queried. 5666 * @see AudioPlaybackConfiguration 5667 */ getActivePlaybackConfigurations()5668 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() { 5669 final IAudioService service = getService(); 5670 try { 5671 return service.getActivePlaybackConfigurations(); 5672 } catch (RemoteException e) { 5673 throw e.rethrowFromSystemServer(); 5674 } 5675 } 5676 5677 /** 5678 * All operations on this list are sync'd on mPlaybackCallbackLock. 5679 * List is lazy-initialized in 5680 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 5681 * List can be null. 5682 */ 5683 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList; 5684 private final Object mPlaybackCallbackLock = new Object(); 5685 5686 /** 5687 * Must be called synchronized on mPlaybackCallbackLock 5688 */ hasPlaybackCallback_sync(@onNull AudioPlaybackCallback cb)5689 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 5690 if (mPlaybackCallbackList != null) { 5691 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 5692 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 5693 return true; 5694 } 5695 } 5696 } 5697 return false; 5698 } 5699 5700 /** 5701 * Must be called synchronized on mPlaybackCallbackLock 5702 */ removePlaybackCallback_sync(@onNull AudioPlaybackCallback cb)5703 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 5704 if (mPlaybackCallbackList != null) { 5705 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 5706 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 5707 mPlaybackCallbackList.remove(i); 5708 return true; 5709 } 5710 } 5711 } 5712 return false; 5713 } 5714 5715 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() { 5716 @Override 5717 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs, 5718 boolean flush) { 5719 if (flush) { 5720 Binder.flushPendingCommands(); 5721 } 5722 synchronized(mPlaybackCallbackLock) { 5723 if (mPlaybackCallbackList != null) { 5724 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 5725 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i); 5726 if (arci.mHandler != null) { 5727 final Message m = arci.mHandler.obtainMessage( 5728 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/, 5729 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 5730 arci.mHandler.sendMessage(m); 5731 } 5732 } 5733 } 5734 } 5735 } 5736 5737 }; 5738 5739 //==================================================================== 5740 // Notification of recording activity & recording configuration 5741 /** 5742 * Interface for receiving update notifications about the recording configuration. Extend 5743 * this abstract class and register it with 5744 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)} 5745 * to be notified. 5746 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current 5747 * configuration. 5748 * @see AudioRecordingConfiguration 5749 */ 5750 public static abstract class AudioRecordingCallback { 5751 /** 5752 * Called whenever the device recording configuration has changed. 5753 * @param configs list containing the results of 5754 * {@link AudioManager#getActiveRecordingConfigurations()}. 5755 */ onRecordingConfigChanged(List<AudioRecordingConfiguration> configs)5756 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {} 5757 } 5758 5759 private static class AudioRecordingCallbackInfo { 5760 final AudioRecordingCallback mCb; 5761 final Handler mHandler; AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler)5762 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) { 5763 mCb = cb; 5764 mHandler = handler; 5765 } 5766 } 5767 5768 private final static class RecordConfigChangeCallbackData { 5769 final AudioRecordingCallback mCb; 5770 final List<AudioRecordingConfiguration> mConfigs; 5771 RecordConfigChangeCallbackData(AudioRecordingCallback cb, List<AudioRecordingConfiguration> configs)5772 RecordConfigChangeCallbackData(AudioRecordingCallback cb, 5773 List<AudioRecordingConfiguration> configs) { 5774 mCb = cb; 5775 mConfigs = configs; 5776 } 5777 } 5778 5779 /** 5780 * Register a callback to be notified of audio recording changes through 5781 * {@link AudioRecordingCallback} 5782 * @param cb non-null callback to register 5783 * @param handler the {@link Handler} object for the thread on which to execute 5784 * the callback. If <code>null</code>, the {@link Handler} associated with the main 5785 * {@link Looper} will be used. 5786 */ registerAudioRecordingCallback(@onNull AudioRecordingCallback cb, @Nullable Handler handler)5787 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb, 5788 @Nullable Handler handler) 5789 { 5790 if (cb == null) { 5791 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 5792 } 5793 5794 synchronized(mRecordCallbackLock) { 5795 // lazy initialization of the list of recording callbacks 5796 if (mRecordCallbackList == null) { 5797 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>(); 5798 } 5799 final int oldCbCount = mRecordCallbackList.size(); 5800 if (!hasRecordCallback_sync(cb)) { 5801 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb, 5802 new ServiceEventHandlerDelegate(handler).getHandler())); 5803 final int newCbCount = mRecordCallbackList.size(); 5804 if ((oldCbCount == 0) && (newCbCount > 0)) { 5805 // register binder for callbacks 5806 final IAudioService service = getService(); 5807 try { 5808 service.registerRecordingCallback(mRecCb); 5809 } catch (RemoteException e) { 5810 throw e.rethrowFromSystemServer(); 5811 } 5812 } 5813 } else { 5814 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously" 5815 + "registered callback"); 5816 } 5817 } 5818 } 5819 5820 /** 5821 * Unregister an audio recording callback previously registered with 5822 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 5823 * @param cb non-null callback to unregister 5824 */ unregisterAudioRecordingCallback(@onNull AudioRecordingCallback cb)5825 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) { 5826 if (cb == null) { 5827 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 5828 } 5829 synchronized(mRecordCallbackLock) { 5830 if (mRecordCallbackList == null) { 5831 return; 5832 } 5833 final int oldCbCount = mRecordCallbackList.size(); 5834 if (removeRecordCallback_sync(cb)) { 5835 final int newCbCount = mRecordCallbackList.size(); 5836 if ((oldCbCount > 0) && (newCbCount == 0)) { 5837 // unregister binder for callbacks 5838 final IAudioService service = getService(); 5839 try { 5840 service.unregisterRecordingCallback(mRecCb); 5841 } catch (RemoteException e) { 5842 throw e.rethrowFromSystemServer(); 5843 } 5844 } 5845 } else { 5846 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback" 5847 + " already unregistered or never registered"); 5848 } 5849 } 5850 } 5851 5852 /** 5853 * Returns the current active audio recording configurations of the device. 5854 * @return a non-null list of recording configurations. An empty list indicates there is 5855 * no recording active when queried. 5856 * @see AudioRecordingConfiguration 5857 */ getActiveRecordingConfigurations()5858 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() { 5859 final IAudioService service = getService(); 5860 try { 5861 return service.getActiveRecordingConfigurations(); 5862 } catch (RemoteException e) { 5863 throw e.rethrowFromSystemServer(); 5864 } 5865 } 5866 5867 /** 5868 * constants for the recording events, to keep in sync 5869 * with frameworks/av/include/media/AudioPolicy.h 5870 */ 5871 /** @hide */ 5872 public static final int RECORD_CONFIG_EVENT_NONE = -1; 5873 /** @hide */ 5874 public static final int RECORD_CONFIG_EVENT_START = 0; 5875 /** @hide */ 5876 public static final int RECORD_CONFIG_EVENT_STOP = 1; 5877 /** @hide */ 5878 public static final int RECORD_CONFIG_EVENT_UPDATE = 2; 5879 /** @hide */ 5880 public static final int RECORD_CONFIG_EVENT_RELEASE = 3; 5881 /** 5882 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h 5883 */ 5884 /** @hide */ 5885 public static final int RECORD_RIID_INVALID = -1; 5886 /** @hide */ 5887 public static final int RECORDER_STATE_STARTED = 0; 5888 /** @hide */ 5889 public static final int RECORDER_STATE_STOPPED = 1; 5890 5891 /** 5892 * All operations on this list are sync'd on mRecordCallbackLock. 5893 * List is lazy-initialized in 5894 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 5895 * List can be null. 5896 */ 5897 private List<AudioRecordingCallbackInfo> mRecordCallbackList; 5898 private final Object mRecordCallbackLock = new Object(); 5899 5900 /** 5901 * Must be called synchronized on mRecordCallbackLock 5902 */ hasRecordCallback_sync(@onNull AudioRecordingCallback cb)5903 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 5904 if (mRecordCallbackList != null) { 5905 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5906 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 5907 return true; 5908 } 5909 } 5910 } 5911 return false; 5912 } 5913 5914 /** 5915 * Must be called synchronized on mRecordCallbackLock 5916 */ removeRecordCallback_sync(@onNull AudioRecordingCallback cb)5917 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 5918 if (mRecordCallbackList != null) { 5919 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5920 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 5921 mRecordCallbackList.remove(i); 5922 return true; 5923 } 5924 } 5925 } 5926 return false; 5927 } 5928 5929 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() { 5930 @Override 5931 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) { 5932 synchronized(mRecordCallbackLock) { 5933 if (mRecordCallbackList != null) { 5934 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5935 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i); 5936 if (arci.mHandler != null) { 5937 final Message m = arci.mHandler.obtainMessage( 5938 MSSG_RECORDING_CONFIG_CHANGE/*what*/, 5939 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 5940 arci.mHandler.sendMessage(m); 5941 } 5942 } 5943 } 5944 } 5945 } 5946 5947 }; 5948 5949 //===================================================================== 5950 5951 /** 5952 * @hide 5953 * Reload audio settings. This method is called by Settings backup 5954 * agent when audio settings are restored and causes the AudioService 5955 * to read and apply restored settings. 5956 */ 5957 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) reloadAudioSettings()5958 public void reloadAudioSettings() { 5959 final IAudioService service = getService(); 5960 try { 5961 service.reloadAudioSettings(); 5962 } catch (RemoteException e) { 5963 throw e.rethrowFromSystemServer(); 5964 } 5965 } 5966 5967 /** 5968 * {@hide} 5969 */ 5970 private final IBinder mICallBack = new Binder(); 5971 5972 /** 5973 * Checks whether the phone is in silent mode, with or without vibrate. 5974 * 5975 * @return true if phone is in silent mode, with or without vibrate. 5976 * 5977 * @see #getRingerMode() 5978 * 5979 * @hide pending API Council approval 5980 */ 5981 @UnsupportedAppUsage isSilentMode()5982 public boolean isSilentMode() { 5983 int ringerMode = getRingerMode(); 5984 boolean silentMode = 5985 (ringerMode == RINGER_MODE_SILENT) || 5986 (ringerMode == RINGER_MODE_VIBRATE); 5987 return silentMode; 5988 } 5989 5990 // This section re-defines new output device constants from AudioSystem, because the AudioSystem 5991 // class is not used by other parts of the framework, which instead use definitions and methods 5992 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService. 5993 5994 /** @hide 5995 * The audio device code for representing "no device." */ 5996 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE; 5997 /** @hide 5998 * The audio output device code for the small speaker at the front of the device used 5999 * when placing calls. Does not refer to an in-ear headphone without attached microphone, 6000 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a 6001 * {@link #DEVICE_OUT_WIRED_HEADPHONE}. 6002 */ 6003 @UnsupportedAppUsage 6004 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE; 6005 /** @hide 6006 * The audio output device code for the built-in speaker */ 6007 @UnsupportedAppUsage 6008 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER; 6009 /** @hide 6010 * The audio output device code for a wired headset with attached microphone */ 6011 @UnsupportedAppUsage 6012 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET; 6013 /** @hide 6014 * The audio output device code for a wired headphone without attached microphone */ 6015 @UnsupportedAppUsage 6016 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 6017 /** @hide 6018 * The audio output device code for a USB headphone with attached microphone */ 6019 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET; 6020 /** @hide 6021 * The audio output device code for generic Bluetooth SCO, for voice */ 6022 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 6023 /** @hide 6024 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and 6025 * Hands-Free Profile (HFP), for voice 6026 */ 6027 @UnsupportedAppUsage 6028 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 6029 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 6030 /** @hide 6031 * The audio output device code for Bluetooth SCO car audio, for voice */ 6032 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 6033 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 6034 /** @hide 6035 * The audio output device code for generic Bluetooth A2DP, for music */ 6036 @UnsupportedAppUsage 6037 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; 6038 /** @hide 6039 * The audio output device code for Bluetooth A2DP headphones, for music */ 6040 @UnsupportedAppUsage 6041 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 6042 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; 6043 /** @hide 6044 * The audio output device code for Bluetooth A2DP external speaker, for music */ 6045 @UnsupportedAppUsage 6046 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 6047 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; 6048 /** @hide 6049 * The audio output device code for S/PDIF (legacy) or HDMI 6050 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */ 6051 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL; 6052 /** @hide 6053 * The audio output device code for HDMI */ 6054 @UnsupportedAppUsage 6055 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI; 6056 /** @hide 6057 * The audio output device code for an analog wired headset attached via a 6058 * docking station 6059 */ 6060 @UnsupportedAppUsage 6061 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; 6062 /** @hide 6063 * The audio output device code for a digital wired headset attached via a 6064 * docking station 6065 */ 6066 @UnsupportedAppUsage 6067 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET; 6068 /** @hide 6069 * The audio output device code for a USB audio accessory. The accessory is in USB host 6070 * mode and the Android device in USB device mode 6071 */ 6072 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY; 6073 /** @hide 6074 * The audio output device code for a USB audio device. The device is in USB device 6075 * mode and the Android device in USB host mode 6076 */ 6077 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE; 6078 /** @hide 6079 * The audio output device code for projection output. 6080 */ 6081 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; 6082 /** @hide 6083 * The audio output device code the telephony voice TX path. 6084 */ 6085 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX; 6086 /** @hide 6087 * The audio output device code for an analog jack with line impedance detected. 6088 */ 6089 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE; 6090 /** @hide 6091 * The audio output device code for HDMI Audio Return Channel. 6092 */ 6093 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC; 6094 /** @hide 6095 * The audio output device code for HDMI enhanced Audio Return Channel. 6096 */ 6097 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC; 6098 /** @hide 6099 * The audio output device code for S/PDIF digital connection. 6100 */ 6101 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF; 6102 /** @hide 6103 * The audio output device code for built-in FM transmitter. 6104 */ 6105 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM; 6106 /** @hide 6107 * The audio output device code for echo reference injection point. 6108 */ 6109 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER; 6110 /** @hide 6111 * The audio output device code for a BLE audio headset. 6112 */ 6113 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET; 6114 /** @hide 6115 * The audio output device code for a BLE audio speaker. 6116 */ 6117 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER; 6118 /** @hide 6119 * The audio output device code for a BLE audio brodcast group. 6120 */ 6121 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST; 6122 /** @hide 6123 * This is not used as a returned value from {@link #getDevicesForStream}, but could be 6124 * used in the future in a set method to select whatever default device is chosen by the 6125 * platform-specific implementation. 6126 */ 6127 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT; 6128 6129 /** @hide 6130 * The audio input device code for default built-in microphone 6131 */ 6132 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC; 6133 /** @hide 6134 * The audio input device code for a Bluetooth SCO headset 6135 */ 6136 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 6137 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; 6138 /** @hide 6139 * The audio input device code for wired headset microphone 6140 */ 6141 public static final int DEVICE_IN_WIRED_HEADSET = 6142 AudioSystem.DEVICE_IN_WIRED_HEADSET; 6143 /** @hide 6144 * The audio input device code for HDMI 6145 */ 6146 public static final int DEVICE_IN_HDMI = 6147 AudioSystem.DEVICE_IN_HDMI; 6148 /** @hide 6149 * The audio input device code for HDMI ARC 6150 */ 6151 public static final int DEVICE_IN_HDMI_ARC = 6152 AudioSystem.DEVICE_IN_HDMI_ARC; 6153 6154 /** @hide 6155 * The audio input device code for HDMI EARC 6156 */ 6157 public static final int DEVICE_IN_HDMI_EARC = 6158 AudioSystem.DEVICE_IN_HDMI_EARC; 6159 6160 /** @hide 6161 * The audio input device code for telephony voice RX path 6162 */ 6163 public static final int DEVICE_IN_TELEPHONY_RX = 6164 AudioSystem.DEVICE_IN_TELEPHONY_RX; 6165 /** @hide 6166 * The audio input device code for built-in microphone pointing to the back 6167 */ 6168 public static final int DEVICE_IN_BACK_MIC = 6169 AudioSystem.DEVICE_IN_BACK_MIC; 6170 /** @hide 6171 * The audio input device code for analog from a docking station 6172 */ 6173 public static final int DEVICE_IN_ANLG_DOCK_HEADSET = 6174 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET; 6175 /** @hide 6176 * The audio input device code for digital from a docking station 6177 */ 6178 public static final int DEVICE_IN_DGTL_DOCK_HEADSET = 6179 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET; 6180 /** @hide 6181 * The audio input device code for a USB audio accessory. The accessory is in USB host 6182 * mode and the Android device in USB device mode 6183 */ 6184 public static final int DEVICE_IN_USB_ACCESSORY = 6185 AudioSystem.DEVICE_IN_USB_ACCESSORY; 6186 /** @hide 6187 * The audio input device code for a USB audio device. The device is in USB device 6188 * mode and the Android device in USB host mode 6189 */ 6190 public static final int DEVICE_IN_USB_DEVICE = 6191 AudioSystem.DEVICE_IN_USB_DEVICE; 6192 /** @hide 6193 * The audio input device code for a FM radio tuner 6194 */ 6195 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER; 6196 /** @hide 6197 * The audio input device code for a TV tuner 6198 */ 6199 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER; 6200 /** @hide 6201 * The audio input device code for an analog jack with line impedance detected 6202 */ 6203 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE; 6204 /** @hide 6205 * The audio input device code for a S/PDIF digital connection 6206 */ 6207 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF; 6208 /** @hide 6209 * The audio input device code for audio loopback 6210 */ 6211 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK; 6212 /** @hide 6213 * The audio input device code for an echo reference capture point. 6214 */ 6215 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE; 6216 /** @hide 6217 * The audio input device code for a BLE audio headset. 6218 */ 6219 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET; 6220 6221 /** 6222 * Return true if the device code corresponds to an output device. 6223 * @hide 6224 */ isOutputDevice(int device)6225 public static boolean isOutputDevice(int device) 6226 { 6227 return !AudioSystem.isInputDevice(device); 6228 } 6229 6230 /** 6231 * Return true if the device code corresponds to an input device. 6232 * @hide 6233 */ isInputDevice(int device)6234 public static boolean isInputDevice(int device) 6235 { 6236 return AudioSystem.isInputDevice(device); 6237 } 6238 6239 6240 /** 6241 * Return the enabled devices for the specified output stream type. 6242 * 6243 * @param streamType The stream type to query. One of 6244 * {@link #STREAM_VOICE_CALL}, 6245 * {@link #STREAM_SYSTEM}, 6246 * {@link #STREAM_RING}, 6247 * {@link #STREAM_MUSIC}, 6248 * {@link #STREAM_ALARM}, 6249 * {@link #STREAM_NOTIFICATION}, 6250 * {@link #STREAM_DTMF}, 6251 * {@link #STREAM_ACCESSIBILITY}. 6252 * 6253 * @return The bit-mask "or" of audio output device codes for all enabled devices on this 6254 * stream. Zero or more of 6255 * {@link #DEVICE_OUT_EARPIECE}, 6256 * {@link #DEVICE_OUT_SPEAKER}, 6257 * {@link #DEVICE_OUT_WIRED_HEADSET}, 6258 * {@link #DEVICE_OUT_WIRED_HEADPHONE}, 6259 * {@link #DEVICE_OUT_BLUETOOTH_SCO}, 6260 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET}, 6261 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT}, 6262 * {@link #DEVICE_OUT_BLUETOOTH_A2DP}, 6263 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}, 6264 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER}, 6265 * {@link #DEVICE_OUT_HDMI}, 6266 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET}, 6267 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}. 6268 * {@link #DEVICE_OUT_USB_ACCESSORY}. 6269 * {@link #DEVICE_OUT_USB_DEVICE}. 6270 * {@link #DEVICE_OUT_REMOTE_SUBMIX}. 6271 * {@link #DEVICE_OUT_TELEPHONY_TX}. 6272 * {@link #DEVICE_OUT_LINE}. 6273 * {@link #DEVICE_OUT_HDMI_ARC}. 6274 * {@link #DEVICE_OUT_HDMI_EARC}. 6275 * {@link #DEVICE_OUT_SPDIF}. 6276 * {@link #DEVICE_OUT_FM}. 6277 * {@link #DEVICE_OUT_DEFAULT} is not used here. 6278 * 6279 * The implementation may support additional device codes beyond those listed, so 6280 * the application should ignore any bits which it does not recognize. 6281 * Note that the information may be imprecise when the implementation 6282 * cannot distinguish whether a particular device is enabled. 6283 * 6284 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices 6285 * will have multi-bit device types. 6286 * Prefer to use {@link #getDevicesForAttributes()} instead, 6287 * noting that getDevicesForStream() has a few small discrepancies 6288 * for better volume handling. 6289 * @hide 6290 */ 6291 @UnsupportedAppUsage 6292 @Deprecated getDevicesForStream(int streamType)6293 public int getDevicesForStream(int streamType) { 6294 switch (streamType) { 6295 case STREAM_VOICE_CALL: 6296 case STREAM_SYSTEM: 6297 case STREAM_RING: 6298 case STREAM_MUSIC: 6299 case STREAM_ALARM: 6300 case STREAM_NOTIFICATION: 6301 case STREAM_DTMF: 6302 case STREAM_ACCESSIBILITY: 6303 final IAudioService service = getService(); 6304 try { 6305 return service.getDeviceMaskForStream(streamType); 6306 } catch (RemoteException e) { 6307 throw e.rethrowFromSystemServer(); 6308 } 6309 default: 6310 return 0; 6311 } 6312 } 6313 6314 /** 6315 * @hide 6316 * Get the audio devices that would be used for the routing of the given audio attributes. 6317 * @param attributes the {@link AudioAttributes} for which the routing is being queried 6318 * @return an empty list if there was an issue with the request, a list of audio devices 6319 * otherwise (typically one device, except for duplicated paths). 6320 */ 6321 @SystemApi 6322 @RequiresPermission(anyOf = { 6323 Manifest.permission.MODIFY_AUDIO_ROUTING, 6324 Manifest.permission.QUERY_AUDIO_STATE 6325 }) getDevicesForAttributes( @onNull AudioAttributes attributes)6326 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes( 6327 @NonNull AudioAttributes attributes) { 6328 Objects.requireNonNull(attributes); 6329 final IAudioService service = getService(); 6330 try { 6331 return service.getDevicesForAttributes(attributes); 6332 } catch (RemoteException e) { 6333 throw e.rethrowFromSystemServer(); 6334 } 6335 } 6336 6337 // Each listener corresponds to a unique callback stub because each listener can subscribe to 6338 // different AudioAttributes. 6339 private final ConcurrentHashMap<OnDevicesForAttributesChangedListener, 6340 IDevicesForAttributesCallbackStub> mDevicesForAttributesListenerToStub = 6341 new ConcurrentHashMap<>(); 6342 6343 private static final class IDevicesForAttributesCallbackStub 6344 extends IDevicesForAttributesCallback.Stub { 6345 ListenerInfo<OnDevicesForAttributesChangedListener> mInfo; 6346 IDevicesForAttributesCallbackStub(@onNull OnDevicesForAttributesChangedListener listener, @NonNull Executor executor)6347 IDevicesForAttributesCallbackStub(@NonNull OnDevicesForAttributesChangedListener listener, 6348 @NonNull Executor executor) { 6349 mInfo = new ListenerInfo<>(listener, executor); 6350 } 6351 register(boolean register, AudioAttributes attributes)6352 public void register(boolean register, AudioAttributes attributes) { 6353 try { 6354 if (register) { 6355 getService().addOnDevicesForAttributesChangedListener(attributes, this); 6356 } else { 6357 getService().removeOnDevicesForAttributesChangedListener(this); 6358 } 6359 } catch (RemoteException e) { 6360 throw e.rethrowFromSystemServer(); 6361 } 6362 } 6363 6364 @Override onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume, List<AudioDeviceAttributes> devices)6365 public void onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume, 6366 List<AudioDeviceAttributes> devices) { 6367 // forVolume is ignored. The case where it is `true` is not handled. 6368 mInfo.mExecutor.execute(() -> 6369 mInfo.mListener.onDevicesForAttributesChanged( 6370 attributes, devices)); 6371 } 6372 } 6373 6374 /** 6375 * @hide 6376 * Interface to be notified of when routing changes for the registered audio attributes. 6377 */ 6378 @SystemApi 6379 public interface OnDevicesForAttributesChangedListener { 6380 /** 6381 * Called on the listener to indicate that the audio devices for the given audio 6382 * attributes have changed. 6383 * @param attributes the {@link AudioAttributes} whose routing changed 6384 * @param devices a list of newly routed audio devices 6385 */ onDevicesForAttributesChanged(@onNull AudioAttributes attributes, @NonNull List<AudioDeviceAttributes> devices)6386 void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes, 6387 @NonNull List<AudioDeviceAttributes> devices); 6388 } 6389 6390 /** 6391 * @hide 6392 * Adds a listener for being notified of routing changes for the given {@link AudioAttributes}. 6393 * @param attributes the {@link AudioAttributes} to listen for routing changes 6394 * @param executor 6395 * @param listener 6396 */ 6397 @SystemApi 6398 @RequiresPermission(anyOf = { 6399 Manifest.permission.MODIFY_AUDIO_ROUTING, 6400 Manifest.permission.QUERY_AUDIO_STATE 6401 }) addOnDevicesForAttributesChangedListener(@onNull AudioAttributes attributes, @NonNull @CallbackExecutor Executor executor, @NonNull OnDevicesForAttributesChangedListener listener)6402 public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes, 6403 @NonNull @CallbackExecutor Executor executor, 6404 @NonNull OnDevicesForAttributesChangedListener listener) { 6405 Objects.requireNonNull(attributes); 6406 Objects.requireNonNull(executor); 6407 Objects.requireNonNull(listener); 6408 6409 synchronized (mDevicesForAttributesListenerToStub) { 6410 IDevicesForAttributesCallbackStub callbackStub = 6411 mDevicesForAttributesListenerToStub.get(listener); 6412 6413 if (callbackStub == null) { 6414 callbackStub = new IDevicesForAttributesCallbackStub(listener, executor); 6415 mDevicesForAttributesListenerToStub.put(listener, callbackStub); 6416 } 6417 6418 callbackStub.register(true, attributes); 6419 } 6420 } 6421 6422 /** 6423 * @hide 6424 * Removes a previously registered listener for being notified of routing changes for the given 6425 * {@link AudioAttributes}. 6426 * @param listener 6427 */ 6428 @SystemApi 6429 @RequiresPermission(anyOf = { 6430 Manifest.permission.MODIFY_AUDIO_ROUTING, 6431 Manifest.permission.QUERY_AUDIO_STATE 6432 }) removeOnDevicesForAttributesChangedListener( @onNull OnDevicesForAttributesChangedListener listener)6433 public void removeOnDevicesForAttributesChangedListener( 6434 @NonNull OnDevicesForAttributesChangedListener listener) { 6435 Objects.requireNonNull(listener); 6436 6437 synchronized (mDevicesForAttributesListenerToStub) { 6438 IDevicesForAttributesCallbackStub callbackStub = 6439 mDevicesForAttributesListenerToStub.get(listener); 6440 if (callbackStub != null) { 6441 callbackStub.register(false, null /* attributes */); 6442 } 6443 6444 mDevicesForAttributesListenerToStub.remove(listener); 6445 } 6446 } 6447 6448 /** 6449 * Get the audio devices that would be used for the routing of the given audio attributes. 6450 * These are the devices anticipated to play sound from an {@link AudioTrack} created with 6451 * the specified {@link AudioAttributes}. 6452 * The audio routing can change if audio devices are physically connected or disconnected or 6453 * concurrently through {@link AudioRouting} or {@link MediaRouter}. 6454 * @param attributes the {@link AudioAttributes} for which the routing is being queried 6455 * @return an empty list if there was an issue with the request, a list of 6456 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths). 6457 */ getAudioDevicesForAttributes( @onNull AudioAttributes attributes)6458 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes( 6459 @NonNull AudioAttributes attributes) { 6460 final List<AudioDeviceAttributes> devicesForAttributes; 6461 try { 6462 Objects.requireNonNull(attributes); 6463 final IAudioService service = getService(); 6464 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes); 6465 } catch (Exception e) { 6466 Log.i(TAG, "No audio devices available for specified attributes."); 6467 return Collections.emptyList(); 6468 } 6469 6470 // Map from AudioDeviceAttributes to AudioDeviceInfo 6471 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS); 6472 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>(); 6473 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) { 6474 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) { 6475 if (deviceForAttributes.getType() == deviceInfo.getType() 6476 && TextUtils.equals(deviceForAttributes.getAddress(), 6477 deviceInfo.getAddress())) { 6478 deviceInfosForAttributes.add(deviceInfo); 6479 } 6480 } 6481 } 6482 return Collections.unmodifiableList(deviceInfosForAttributes); 6483 } 6484 6485 /** 6486 * @hide 6487 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as 6488 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not 6489 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}. 6490 */ 6491 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1; 6492 /** 6493 * @hide 6494 * Volume behavior for an audio device where a software attenuation is applied 6495 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6496 */ 6497 @SystemApi 6498 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; 6499 /** 6500 * @hide 6501 * Volume behavior for an audio device where the volume is always set to provide no attenuation 6502 * nor gain (e.g. unit gain). 6503 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6504 */ 6505 @SystemApi 6506 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; 6507 /** 6508 * @hide 6509 * Volume behavior for an audio device where the volume is either set to muted, or to provide 6510 * no attenuation nor gain (e.g. unit gain). 6511 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6512 */ 6513 @SystemApi 6514 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; 6515 /** 6516 * @hide 6517 * Volume behavior for an audio device where no software attenuation is applied, and 6518 * the volume is kept synchronized between the host and the device itself through a 6519 * device-specific protocol such as BT AVRCP. 6520 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6521 */ 6522 @SystemApi 6523 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; 6524 /** 6525 * @hide 6526 * Volume behavior for an audio device where no software attenuation is applied, and 6527 * the volume is kept synchronized between the host and the device itself through a 6528 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g. 6529 * normal vs in phone call). 6530 * @see #setMode(int) 6531 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6532 */ 6533 @SystemApi 6534 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; 6535 6536 /** 6537 * @hide 6538 * A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set 6539 * the volume percentage of the audio device. Specifically, {@link #setStreamVolume} will have 6540 * no effect, or an unreliable effect. 6541 */ 6542 @SystemApi 6543 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5; 6544 6545 /** @hide */ 6546 @IntDef({ 6547 DEVICE_VOLUME_BEHAVIOR_VARIABLE, 6548 DEVICE_VOLUME_BEHAVIOR_FULL, 6549 DEVICE_VOLUME_BEHAVIOR_FIXED, 6550 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, 6551 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, 6552 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY, 6553 }) 6554 @Retention(RetentionPolicy.SOURCE) 6555 public @interface DeviceVolumeBehavior {} 6556 6557 /** @hide */ 6558 @IntDef({ 6559 DEVICE_VOLUME_BEHAVIOR_UNSET, 6560 DEVICE_VOLUME_BEHAVIOR_VARIABLE, 6561 DEVICE_VOLUME_BEHAVIOR_FULL, 6562 DEVICE_VOLUME_BEHAVIOR_FIXED, 6563 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, 6564 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, 6565 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY, 6566 }) 6567 @Retention(RetentionPolicy.SOURCE) 6568 public @interface DeviceVolumeBehaviorState {} 6569 6570 /** 6571 * Variants of absolute volume behavior that are set in {@link AudioDeviceVolumeManager}. 6572 * @hide 6573 */ 6574 @IntDef({ 6575 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, 6576 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY, 6577 }) 6578 @Retention(RetentionPolicy.SOURCE) 6579 public @interface AbsoluteDeviceVolumeBehavior {} 6580 6581 /** 6582 * @hide 6583 * Throws IAE on an invalid volume behavior value 6584 * @param volumeBehavior behavior value to check 6585 */ enforceValidVolumeBehavior(int volumeBehavior)6586 public static void enforceValidVolumeBehavior(int volumeBehavior) { 6587 switch (volumeBehavior) { 6588 case DEVICE_VOLUME_BEHAVIOR_VARIABLE: 6589 case DEVICE_VOLUME_BEHAVIOR_FULL: 6590 case DEVICE_VOLUME_BEHAVIOR_FIXED: 6591 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE: 6592 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE: 6593 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY: 6594 return; 6595 default: 6596 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior); 6597 } 6598 } 6599 6600 /** 6601 * @hide 6602 * Sets the volume behavior for an audio output device. 6603 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE 6604 * @see #DEVICE_VOLUME_BEHAVIOR_FULL 6605 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED 6606 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE 6607 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE 6608 * @param device the device to be affected 6609 * @param deviceVolumeBehavior one of the device behaviors 6610 */ 6611 @SystemApi 6612 @RequiresPermission(anyOf = { 6613 Manifest.permission.MODIFY_AUDIO_ROUTING, 6614 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED 6615 }) setDeviceVolumeBehavior(@onNull AudioDeviceAttributes device, @DeviceVolumeBehavior int deviceVolumeBehavior)6616 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device, 6617 @DeviceVolumeBehavior int deviceVolumeBehavior) { 6618 // verify arguments (validity of device type is enforced in server) 6619 Objects.requireNonNull(device); 6620 enforceValidVolumeBehavior(deviceVolumeBehavior); 6621 // communicate with service 6622 final IAudioService service = getService(); 6623 try { 6624 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior, 6625 mApplicationContext.getOpPackageName()); 6626 } catch (RemoteException e) { 6627 throw e.rethrowFromSystemServer(); 6628 } 6629 } 6630 6631 /** 6632 * @hide 6633 * Controls whether DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY may be returned by 6634 * getDeviceVolumeBehavior. If this is disabled, DEVICE_VOLUME_BEHAVIOR_FULL is returned 6635 * in its place. 6636 */ 6637 @ChangeId 6638 @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 6639 @Overridable 6640 public static final long RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 240663182L; 6641 6642 /** 6643 * @hide 6644 * Returns the volume device behavior for the given audio device 6645 * @param device the audio device 6646 * @return the volume behavior for the device 6647 */ 6648 @SystemApi 6649 @RequiresPermission(anyOf = { 6650 Manifest.permission.MODIFY_AUDIO_ROUTING, 6651 Manifest.permission.QUERY_AUDIO_STATE, 6652 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED 6653 }) 6654 public @DeviceVolumeBehavior getDeviceVolumeBehavior(@onNull AudioDeviceAttributes device)6655 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { 6656 // verify arguments (validity of device type is enforced in server) 6657 Objects.requireNonNull(device); 6658 // communicate with service 6659 final IAudioService service = getService(); 6660 try { 6661 int behavior = service.getDeviceVolumeBehavior(device); 6662 if (!CompatChanges.isChangeEnabled(RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) 6663 && behavior == DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) { 6664 return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL; 6665 } 6666 return behavior; 6667 } catch (RemoteException e) { 6668 throw e.rethrowFromSystemServer(); 6669 } 6670 } 6671 6672 /** 6673 * @hide 6674 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}. 6675 */ 6676 @TestApi 6677 @RequiresPermission(anyOf = { 6678 Manifest.permission.MODIFY_AUDIO_ROUTING, 6679 Manifest.permission.QUERY_AUDIO_STATE, 6680 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED 6681 }) isFullVolumeDevice()6682 public boolean isFullVolumeDevice() { 6683 final AudioAttributes attributes = new AudioAttributes.Builder() 6684 .setUsage(AudioAttributes.USAGE_MEDIA) 6685 .build(); 6686 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes); 6687 for (AudioDeviceAttributes device : devices) { 6688 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) { 6689 return true; 6690 } 6691 } 6692 return false; 6693 } 6694 6695 /** 6696 * Indicate wired accessory connection state change. 6697 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx) 6698 * @param state new connection state: 1 connected, 0 disconnected 6699 * @param name device name 6700 * {@hide} 6701 */ 6702 @UnsupportedAppUsage 6703 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setWiredDeviceConnectionState(int device, int state, String address, String name)6704 public void setWiredDeviceConnectionState(int device, int state, String address, String name) { 6705 AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name); 6706 setWiredDeviceConnectionState(attributes, state); 6707 } 6708 6709 /** 6710 * Indicate wired accessory connection state change and attributes. 6711 * @param state new connection state: 1 connected, 0 disconnected 6712 * @param attributes attributes of the connected device 6713 * {@hide} 6714 */ 6715 @UnsupportedAppUsage 6716 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state)6717 public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) { 6718 final IAudioService service = getService(); 6719 try { 6720 service.setWiredDeviceConnectionState(attributes, state, 6721 mApplicationContext.getOpPackageName()); 6722 } catch (RemoteException e) { 6723 throw e.rethrowFromSystemServer(); 6724 } 6725 } 6726 6727 /** 6728 * Indicate wired accessory connection state change. 6729 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect" 6730 * @param connected true for connected, false for disconnected 6731 * {@hide} 6732 */ 6733 @TestApi 6734 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setTestDeviceConnectionState(@onNull AudioDeviceAttributes device, boolean connected)6735 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device, 6736 boolean connected) { 6737 try { 6738 getService().setTestDeviceConnectionState(device, connected); 6739 } catch (RemoteException e) { 6740 throw e.rethrowFromSystemServer(); 6741 } 6742 } 6743 6744 /** 6745 * Indicate Bluetooth profile connection state change. 6746 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and 6747 * <code>previousDevice</code> 6748 * This operation is asynchronous. 6749 * 6750 * @param newDevice Bluetooth device connected or null if there is no new devices 6751 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected 6752 * devices 6753 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo} 6754 * {@hide} 6755 */ 6756 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 6757 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) handleBluetoothActiveDeviceChanged(@ullable BluetoothDevice newDevice, @Nullable BluetoothDevice previousDevice, @NonNull BluetoothProfileConnectionInfo info)6758 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice, 6759 @Nullable BluetoothDevice previousDevice, 6760 @NonNull BluetoothProfileConnectionInfo info) { 6761 final IAudioService service = getService(); 6762 try { 6763 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info); 6764 } catch (RemoteException e) { 6765 throw e.rethrowFromSystemServer(); 6766 } 6767 } 6768 6769 /** {@hide} */ getRingtonePlayer()6770 public IRingtonePlayer getRingtonePlayer() { 6771 try { 6772 return getService().getRingtonePlayer(); 6773 } catch (RemoteException e) { 6774 throw e.rethrowFromSystemServer(); 6775 } 6776 } 6777 6778 /** 6779 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate 6780 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps 6781 * should use this value as a default, and offer the user the option to override it. 6782 * The low latency output stream is typically either the device's primary output stream, 6783 * or another output stream with smaller buffers. 6784 */ 6785 // FIXME Deprecate 6786 public static final String PROPERTY_OUTPUT_SAMPLE_RATE = 6787 "android.media.property.OUTPUT_SAMPLE_RATE"; 6788 6789 /** 6790 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size 6791 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps 6792 * should use this value as a minimum, and offer the user the option to override it. 6793 * The low latency output stream is typically either the device's primary output stream, 6794 * or another output stream with smaller buffers. 6795 */ 6796 // FIXME Deprecate 6797 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = 6798 "android.media.property.OUTPUT_FRAMES_PER_BUFFER"; 6799 6800 /** 6801 * Used as a key for {@link #getProperty} to determine if the default microphone audio source 6802 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 6803 */ 6804 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = 6805 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND"; 6806 6807 /** 6808 * Used as a key for {@link #getProperty} to determine if the default speaker audio path 6809 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 6810 */ 6811 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = 6812 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND"; 6813 6814 /** 6815 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is 6816 * available and supported with the expected frequency range and level response. 6817 */ 6818 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = 6819 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED"; 6820 /** 6821 * Returns the value of the property with the specified key. 6822 * @param key One of the strings corresponding to a property key: either 6823 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE}, 6824 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER}, 6825 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND}, 6826 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or 6827 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}. 6828 * @return A string representing the associated value for that property key, 6829 * or null if there is no value for that key. 6830 */ getProperty(String key)6831 public String getProperty(String key) { 6832 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) { 6833 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate(); 6834 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null; 6835 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) { 6836 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount(); 6837 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null; 6838 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) { 6839 // Will throw a RuntimeException Resources.NotFoundException if this config value is 6840 // not found. 6841 return String.valueOf(getContext().getResources().getBoolean( 6842 com.android.internal.R.bool.config_supportMicNearUltrasound)); 6843 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) { 6844 return String.valueOf(getContext().getResources().getBoolean( 6845 com.android.internal.R.bool.config_supportSpeakerNearUltrasound)); 6846 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) { 6847 return String.valueOf(getContext().getResources().getBoolean( 6848 com.android.internal.R.bool.config_supportAudioSourceUnprocessed)); 6849 } else { 6850 // null or unknown key 6851 return null; 6852 } 6853 } 6854 6855 /** 6856 * @hide 6857 * Sets an additional audio output device delay in milliseconds. 6858 * 6859 * The additional output delay is a request to the output device to 6860 * delay audio presentation (generally with respect to video presentation for better 6861 * synchronization). 6862 * It may not be supported by all output devices, 6863 * and typically increases the audio latency by the amount of additional 6864 * audio delay requested. 6865 * 6866 * If additional audio delay is supported by an audio output device, 6867 * it is expected to be supported for all output streams (and configurations) 6868 * opened on that device. 6869 * 6870 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 6871 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0} 6872 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}. 6873 * @return true if successful, false if the device does not support output device delay 6874 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}. 6875 */ 6876 @SystemApi 6877 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setAdditionalOutputDeviceDelay( @onNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis)6878 public boolean setAdditionalOutputDeviceDelay( 6879 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) { 6880 Objects.requireNonNull(device); 6881 try { 6882 return getService().setAdditionalOutputDeviceDelay( 6883 new AudioDeviceAttributes(device), delayMillis); 6884 } catch (RemoteException e) { 6885 throw e.rethrowFromSystemServer(); 6886 } 6887 } 6888 6889 /** 6890 * @hide 6891 * Returns the current additional audio output device delay in milliseconds. 6892 * 6893 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 6894 * @return the additional output device delay. This is a non-negative number. 6895 * {@code 0} is returned if unsupported. 6896 */ 6897 @SystemApi 6898 @IntRange(from = 0) getAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)6899 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) { 6900 Objects.requireNonNull(device); 6901 try { 6902 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device)); 6903 } catch (RemoteException e) { 6904 throw e.rethrowFromSystemServer(); 6905 } 6906 } 6907 6908 /** 6909 * @hide 6910 * Returns the maximum additional audio output device delay in milliseconds. 6911 * 6912 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 6913 * @return the maximum output device delay in milliseconds that can be set. 6914 * This is a non-negative number 6915 * representing the additional audio delay supported for the device. 6916 * {@code 0} is returned if unsupported. 6917 */ 6918 @SystemApi 6919 @IntRange(from = 0) getMaxAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)6920 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) { 6921 Objects.requireNonNull(device); 6922 try { 6923 return getService().getMaxAdditionalOutputDeviceDelay( 6924 new AudioDeviceAttributes(device)); 6925 } catch (RemoteException e) { 6926 throw e.rethrowFromSystemServer(); 6927 } 6928 } 6929 6930 /** 6931 * Returns the estimated latency for the given stream type in milliseconds. 6932 * 6933 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need 6934 * a better solution. 6935 * @hide 6936 */ 6937 @UnsupportedAppUsage getOutputLatency(int streamType)6938 public int getOutputLatency(int streamType) { 6939 return AudioSystem.getOutputLatency(streamType); 6940 } 6941 6942 /** 6943 * Registers a global volume controller interface. Currently limited to SystemUI. 6944 * 6945 * @hide 6946 */ setVolumeController(IVolumeController controller)6947 public void setVolumeController(IVolumeController controller) { 6948 try { 6949 getService().setVolumeController(controller); 6950 } catch (RemoteException e) { 6951 throw e.rethrowFromSystemServer(); 6952 } 6953 } 6954 6955 /** 6956 * Returns the registered volume controller interface. 6957 * 6958 * @hide 6959 */ 6960 @Nullable getVolumeController()6961 public IVolumeController getVolumeController() { 6962 try { 6963 return getService().getVolumeController(); 6964 } catch (RemoteException e) { 6965 throw e.rethrowFromSystemServer(); 6966 } 6967 } 6968 6969 /** 6970 * Notify audio manager about volume controller visibility changes. 6971 * Currently limited to SystemUI. 6972 * 6973 * @hide 6974 */ notifyVolumeControllerVisible(IVolumeController controller, boolean visible)6975 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) { 6976 try { 6977 getService().notifyVolumeControllerVisible(controller, visible); 6978 } catch (RemoteException e) { 6979 throw e.rethrowFromSystemServer(); 6980 } 6981 } 6982 6983 /** 6984 * Only useful for volume controllers. 6985 * @hide 6986 */ isStreamAffectedByRingerMode(int streamType)6987 public boolean isStreamAffectedByRingerMode(int streamType) { 6988 try { 6989 return getService().isStreamAffectedByRingerMode(streamType); 6990 } catch (RemoteException e) { 6991 throw e.rethrowFromSystemServer(); 6992 } 6993 } 6994 6995 /** 6996 * Only useful for volume controllers. 6997 * @hide 6998 */ isStreamAffectedByMute(int streamType)6999 public boolean isStreamAffectedByMute(int streamType) { 7000 try { 7001 return getService().isStreamAffectedByMute(streamType); 7002 } catch (RemoteException e) { 7003 throw e.rethrowFromSystemServer(); 7004 } 7005 } 7006 7007 /** 7008 * Check whether a user can mute this stream type from a given UI element. 7009 * 7010 * <p>Only useful for volume controllers. 7011 * 7012 * @param streamType type of stream to check if it's mutable from UI 7013 * 7014 * @hide 7015 */ isStreamMutableByUi(int streamType)7016 public boolean isStreamMutableByUi(int streamType) { 7017 try { 7018 return getService().isStreamMutableByUi(streamType); 7019 } catch (RemoteException e) { 7020 throw e.rethrowFromSystemServer(); 7021 } 7022 } 7023 7024 /** 7025 * Only useful for volume controllers. 7026 * @hide 7027 */ disableSafeMediaVolume()7028 public void disableSafeMediaVolume() { 7029 try { 7030 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName()); 7031 } catch (RemoteException e) { 7032 throw e.rethrowFromSystemServer(); 7033 } 7034 } 7035 7036 /** 7037 * @hide 7038 * Lower media volume to RS1 interval 7039 */ lowerVolumeToRs1()7040 public void lowerVolumeToRs1() { 7041 try { 7042 getService().lowerVolumeToRs1(mApplicationContext.getOpPackageName()); 7043 } catch (RemoteException e) { 7044 throw e.rethrowFromSystemServer(); 7045 } 7046 } 7047 7048 /** 7049 * @hide 7050 * @return the RS2 upper bound used for momentary exposure warnings 7051 */ 7052 @TestApi 7053 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) getRs2Value()7054 public float getRs2Value() { 7055 try { 7056 return getService().getOutputRs2UpperBound(); 7057 } catch (RemoteException e) { 7058 throw e.rethrowFromSystemServer(); 7059 } 7060 } 7061 7062 /** 7063 * @hide 7064 * Sets the RS2 upper bound used for momentary exposure warnings 7065 */ 7066 @TestApi 7067 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setRs2Value(float rs2Value)7068 public void setRs2Value(float rs2Value) { 7069 try { 7070 getService().setOutputRs2UpperBound(rs2Value); 7071 } catch (RemoteException e) { 7072 throw e.rethrowFromSystemServer(); 7073 } 7074 } 7075 7076 /** 7077 * @hide 7078 * @return the current computed sound dose value 7079 */ 7080 @TestApi 7081 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) getCsd()7082 public float getCsd() { 7083 try { 7084 return getService().getCsd(); 7085 } catch (RemoteException e) { 7086 throw e.rethrowFromSystemServer(); 7087 } 7088 } 7089 7090 /** 7091 * @hide 7092 * Sets the computed sound dose value to {@code csd}. A negative value will 7093 * reset all the CSD related timeouts: after a momentary exposure warning and 7094 * before the momentary exposure reaches RS2 (see IEC62368-1 10.6.5) 7095 */ 7096 @TestApi 7097 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setCsd(float csd)7098 public void setCsd(float csd) { 7099 try { 7100 getService().setCsd(csd); 7101 } catch (RemoteException e) { 7102 throw e.rethrowFromSystemServer(); 7103 } 7104 } 7105 7106 /** 7107 * @hide 7108 * Forces the computation of MEL values (used for CSD) on framework level. This will have the 7109 * result of ignoring the MEL values computed on HAL level. Should only be used in testing 7110 * since this can affect the certification of a device with EN50332-3 regulation. 7111 */ 7112 @TestApi 7113 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) forceUseFrameworkMel(boolean useFrameworkMel)7114 public void forceUseFrameworkMel(boolean useFrameworkMel) { 7115 try { 7116 getService().forceUseFrameworkMel(useFrameworkMel); 7117 } catch (RemoteException e) { 7118 throw e.rethrowFromSystemServer(); 7119 } 7120 } 7121 7122 /** 7123 * @hide 7124 * Forces the computation of CSD on all output devices. 7125 */ 7126 @TestApi 7127 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices)7128 public void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) { 7129 try { 7130 getService().forceComputeCsdOnAllDevices(computeCsdOnAllDevices); 7131 } catch (RemoteException e) { 7132 throw e.rethrowFromSystemServer(); 7133 } 7134 } 7135 7136 /** 7137 * @hide 7138 * Returns whether CSD is enabled and supported by the current active audio module HAL. 7139 * This method will return {@code false) for setups in which CSD as a feature is available 7140 * (see {@link AudioManager#isCsdAsAFeatureAvailable()}) and not enabled (see 7141 * {@link AudioManager#isCsdAsAFeatureEnabled()}). 7142 */ 7143 @TestApi 7144 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isCsdEnabled()7145 public boolean isCsdEnabled() { 7146 try { 7147 return getService().isCsdEnabled(); 7148 } catch (RemoteException e) { 7149 throw e.rethrowFromSystemServer(); 7150 } 7151 } 7152 7153 /** 7154 * @hide 7155 * Returns whether CSD as a feature can be manipulated by a client. This method 7156 * returns {@code true} in countries where there isn't a safe hearing regulation 7157 * enforced. 7158 */ 7159 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isCsdAsAFeatureAvailable()7160 public boolean isCsdAsAFeatureAvailable() { 7161 try { 7162 return getService().isCsdAsAFeatureAvailable(); 7163 } catch (RemoteException e) { 7164 throw e.rethrowFromSystemServer(); 7165 } 7166 } 7167 7168 /** 7169 * @hide 7170 * Returns {@code true} if the client has enabled CSD. This function should only 7171 * be called if {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}. 7172 */ 7173 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isCsdAsAFeatureEnabled()7174 public boolean isCsdAsAFeatureEnabled() { 7175 try { 7176 return getService().isCsdAsAFeatureEnabled(); 7177 } catch (RemoteException e) { 7178 throw e.rethrowFromSystemServer(); 7179 } 7180 } 7181 7182 /** 7183 * @hide 7184 * Enables/disables the CSD feature. This function should only be called if 7185 * {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}. 7186 */ 7187 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setCsdAsAFeatureEnabled(boolean csdToggleValue)7188 public void setCsdAsAFeatureEnabled(boolean csdToggleValue) { 7189 try { 7190 getService().setCsdAsAFeatureEnabled(csdToggleValue); 7191 } catch (RemoteException e) { 7192 throw e.rethrowFromSystemServer(); 7193 } 7194 } 7195 7196 /** 7197 * @hide 7198 * Describes an audio device that has not been categorized with a specific 7199 * audio type. 7200 */ 7201 public static final int AUDIO_DEVICE_CATEGORY_UNKNOWN = 0; 7202 7203 /** 7204 * @hide 7205 * Describes an audio device which is categorized as something different. 7206 */ 7207 public static final int AUDIO_DEVICE_CATEGORY_OTHER = 1; 7208 7209 /** 7210 * @hide 7211 * Describes an audio device which was categorized as speakers. 7212 */ 7213 public static final int AUDIO_DEVICE_CATEGORY_SPEAKER = 2; 7214 7215 /** 7216 * @hide 7217 * Describes an audio device which was categorized as headphones. 7218 */ 7219 public static final int AUDIO_DEVICE_CATEGORY_HEADPHONES = 3; 7220 7221 /** 7222 * @hide 7223 * Describes an audio device which was categorized as car-kit. 7224 */ 7225 public static final int AUDIO_DEVICE_CATEGORY_CARKIT = 4; 7226 7227 /** 7228 * @hide 7229 * Describes an audio device which was categorized as watch. 7230 */ 7231 public static final int AUDIO_DEVICE_CATEGORY_WATCH = 5; 7232 7233 /** 7234 * @hide 7235 * Describes an audio device which was categorized as hearing aid. 7236 */ 7237 public static final int AUDIO_DEVICE_CATEGORY_HEARING_AID = 6; 7238 7239 /** 7240 * @hide 7241 * Describes an audio device which was categorized as receiver. 7242 */ 7243 public static final int AUDIO_DEVICE_CATEGORY_RECEIVER = 7; 7244 7245 /** @hide */ 7246 @IntDef(flag = false, prefix = "AUDIO_DEVICE_CATEGORY", value = { 7247 AUDIO_DEVICE_CATEGORY_UNKNOWN, 7248 AUDIO_DEVICE_CATEGORY_OTHER, 7249 AUDIO_DEVICE_CATEGORY_SPEAKER, 7250 AUDIO_DEVICE_CATEGORY_HEADPHONES, 7251 AUDIO_DEVICE_CATEGORY_CARKIT, 7252 AUDIO_DEVICE_CATEGORY_WATCH, 7253 AUDIO_DEVICE_CATEGORY_HEARING_AID, 7254 AUDIO_DEVICE_CATEGORY_RECEIVER } 7255 ) 7256 @Retention(RetentionPolicy.SOURCE) 7257 public @interface AudioDeviceCategory {} 7258 7259 /** @hide */ audioDeviceCategoryToString(int audioDeviceCategory)7260 public static String audioDeviceCategoryToString(int audioDeviceCategory) { 7261 switch (audioDeviceCategory) { 7262 case AUDIO_DEVICE_CATEGORY_UNKNOWN: return "AUDIO_DEVICE_CATEGORY_UNKNOWN"; 7263 case AUDIO_DEVICE_CATEGORY_OTHER: return "AUDIO_DEVICE_CATEGORY_OTHER"; 7264 case AUDIO_DEVICE_CATEGORY_SPEAKER: return "AUDIO_DEVICE_CATEGORY_SPEAKER"; 7265 case AUDIO_DEVICE_CATEGORY_HEADPHONES: return "AUDIO_DEVICE_CATEGORY_HEADPHONES"; 7266 case AUDIO_DEVICE_CATEGORY_CARKIT: return "AUDIO_DEVICE_CATEGORY_CARKIT"; 7267 case AUDIO_DEVICE_CATEGORY_WATCH: return "AUDIO_DEVICE_CATEGORY_WATCH"; 7268 case AUDIO_DEVICE_CATEGORY_HEARING_AID: return "AUDIO_DEVICE_CATEGORY_HEARING_AID"; 7269 case AUDIO_DEVICE_CATEGORY_RECEIVER: return "AUDIO_DEVICE_CATEGORY_RECEIVER"; 7270 default: 7271 return new StringBuilder("unknown AudioDeviceCategory ").append( 7272 audioDeviceCategory).toString(); 7273 } 7274 } 7275 7276 /** 7277 * @hide 7278 * Sets the audio device type of a Bluetooth device given its MAC address 7279 */ 7280 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setBluetoothAudioDeviceCategory_legacy(@onNull String address, boolean isBle, @AudioDeviceCategory int btAudioDeviceType)7281 public void setBluetoothAudioDeviceCategory_legacy(@NonNull String address, boolean isBle, 7282 @AudioDeviceCategory int btAudioDeviceType) { 7283 if (automaticBtDeviceType()) { 7284 // do nothing 7285 return; 7286 } 7287 try { 7288 getService().setBluetoothAudioDeviceCategory_legacy(address, isBle, btAudioDeviceType); 7289 } catch (RemoteException e) { 7290 throw e.rethrowFromSystemServer(); 7291 } 7292 } 7293 7294 /** 7295 * @hide 7296 * Gets the audio device type of a Bluetooth device given its MAC address 7297 */ 7298 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) 7299 @AudioDeviceCategory getBluetoothAudioDeviceCategory_legacy(@onNull String address, boolean isBle)7300 public int getBluetoothAudioDeviceCategory_legacy(@NonNull String address, boolean isBle) { 7301 if (automaticBtDeviceType()) { 7302 return AUDIO_DEVICE_CATEGORY_UNKNOWN; 7303 } 7304 try { 7305 return getService().getBluetoothAudioDeviceCategory_legacy(address, isBle); 7306 } catch (RemoteException e) { 7307 throw e.rethrowFromSystemServer(); 7308 } 7309 } 7310 7311 /** 7312 * @hide 7313 * Sets the audio device type of a Bluetooth device given its MAC address 7314 * 7315 * @return {@code true} if the device type was set successfully. If the 7316 * audio device type was automatically identified this method will 7317 * return {@code false}. 7318 */ 7319 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setBluetoothAudioDeviceCategory(@onNull String address, @AudioDeviceCategory int btAudioDeviceCategory)7320 public boolean setBluetoothAudioDeviceCategory(@NonNull String address, 7321 @AudioDeviceCategory int btAudioDeviceCategory) { 7322 if (!automaticBtDeviceType()) { 7323 return false; 7324 } 7325 try { 7326 return getService().setBluetoothAudioDeviceCategory(address, btAudioDeviceCategory); 7327 } catch (RemoteException e) { 7328 throw e.rethrowFromSystemServer(); 7329 } 7330 } 7331 7332 /** 7333 * @hide 7334 * Gets the audio device type of a Bluetooth device given its MAC address 7335 */ 7336 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) 7337 @AudioDeviceCategory getBluetoothAudioDeviceCategory(@onNull String address)7338 public int getBluetoothAudioDeviceCategory(@NonNull String address) { 7339 if (!automaticBtDeviceType()) { 7340 return AUDIO_DEVICE_CATEGORY_UNKNOWN; 7341 } 7342 try { 7343 return getService().getBluetoothAudioDeviceCategory(address); 7344 } catch (RemoteException e) { 7345 throw e.rethrowFromSystemServer(); 7346 } 7347 } 7348 7349 /** 7350 * @hide 7351 * Returns {@code true} if the audio device type of a Bluetooth device can 7352 * be automatically identified 7353 */ 7354 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isBluetoothAudioDeviceCategoryFixed(@onNull String address)7355 public boolean isBluetoothAudioDeviceCategoryFixed(@NonNull String address) { 7356 if (!automaticBtDeviceType()) { 7357 return false; 7358 } 7359 try { 7360 return getService().isBluetoothAudioDeviceCategoryFixed(address); 7361 } catch (RemoteException e) { 7362 throw e.rethrowFromSystemServer(); 7363 } 7364 } 7365 7366 /** 7367 * @hide 7368 * Sound dose warning at every 100% of dose during integration window 7369 */ 7370 public static final int CSD_WARNING_DOSE_REACHED_1X = 1; 7371 /** 7372 * @hide 7373 * Sound dose warning when 500% of dose is reached during integration window 7374 */ 7375 public static final int CSD_WARNING_DOSE_REPEATED_5X = 2; 7376 /** 7377 * @hide 7378 * Sound dose warning after a momentary exposure event 7379 */ 7380 public static final int CSD_WARNING_MOMENTARY_EXPOSURE = 3; 7381 /** 7382 * @hide 7383 * Sound dose warning at every 100% of dose during integration window 7384 */ 7385 public static final int CSD_WARNING_ACCUMULATION_START = 4; 7386 7387 /** @hide */ 7388 @IntDef(flag = false, value = { 7389 CSD_WARNING_DOSE_REACHED_1X, 7390 CSD_WARNING_DOSE_REPEATED_5X, 7391 CSD_WARNING_MOMENTARY_EXPOSURE, 7392 CSD_WARNING_ACCUMULATION_START } 7393 ) 7394 @Retention(RetentionPolicy.SOURCE) 7395 public @interface CsdWarning {} 7396 7397 /** 7398 * Only useful for volume controllers. 7399 * @hide 7400 */ 7401 @UnsupportedAppUsage setRingerModeInternal(int ringerMode)7402 public void setRingerModeInternal(int ringerMode) { 7403 try { 7404 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName()); 7405 } catch (RemoteException e) { 7406 throw e.rethrowFromSystemServer(); 7407 } 7408 } 7409 7410 /** 7411 * Only useful for volume controllers. 7412 * @hide 7413 */ 7414 @UnsupportedAppUsage getRingerModeInternal()7415 public int getRingerModeInternal() { 7416 try { 7417 return getService().getRingerModeInternal(); 7418 } catch (RemoteException e) { 7419 throw e.rethrowFromSystemServer(); 7420 } 7421 } 7422 7423 /** 7424 * Only useful for volume controllers. 7425 * @hide 7426 */ setVolumePolicy(VolumePolicy policy)7427 public void setVolumePolicy(VolumePolicy policy) { 7428 try { 7429 getService().setVolumePolicy(policy); 7430 } catch (RemoteException e) { 7431 throw e.rethrowFromSystemServer(); 7432 } 7433 } 7434 7435 /** 7436 * Set Hdmi Cec system audio mode. 7437 * 7438 * @param on whether to be on system audio mode 7439 * @return output device type. 0 (DEVICE_NONE) if failed to set device. 7440 * @hide 7441 */ setHdmiSystemAudioSupported(boolean on)7442 public int setHdmiSystemAudioSupported(boolean on) { 7443 try { 7444 return getService().setHdmiSystemAudioSupported(on); 7445 } catch (RemoteException e) { 7446 throw e.rethrowFromSystemServer(); 7447 } 7448 } 7449 7450 /** 7451 * Returns true if Hdmi Cec system audio mode is supported. 7452 * 7453 * @hide 7454 */ 7455 @SystemApi 7456 @SuppressLint("RequiresPermission") // FIXME is this still used? isHdmiSystemAudioSupported()7457 public boolean isHdmiSystemAudioSupported() { 7458 try { 7459 return getService().isHdmiSystemAudioSupported(); 7460 } catch (RemoteException e) { 7461 throw e.rethrowFromSystemServer(); 7462 } 7463 } 7464 7465 /** 7466 * Return codes for listAudioPorts(), createAudioPatch() ... 7467 */ 7468 7469 /** @hide */ 7470 @SystemApi 7471 public static final int SUCCESS = AudioSystem.SUCCESS; 7472 /** 7473 * A default error code. 7474 */ 7475 public static final int ERROR = AudioSystem.ERROR; 7476 /** @hide 7477 * CANDIDATE FOR PUBLIC API 7478 */ 7479 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE; 7480 /** @hide 7481 */ 7482 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION; 7483 /** @hide 7484 */ 7485 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED; 7486 /** @hide 7487 */ 7488 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT; 7489 /** 7490 * An error code indicating that the object reporting it is no longer valid and needs to 7491 * be recreated. 7492 */ 7493 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT; 7494 7495 /** 7496 * Returns a list of descriptors for all audio ports managed by the audio framework. 7497 * Audio ports are nodes in the audio framework or audio hardware that can be configured 7498 * or connected and disconnected with createAudioPatch() or releaseAudioPatch(). 7499 * See AudioPort for a list of attributes of each audio port. 7500 * @param ports An AudioPort ArrayList where the list will be returned. 7501 * @hide 7502 */ 7503 @UnsupportedAppUsage listAudioPorts(ArrayList<AudioPort> ports)7504 public static int listAudioPorts(ArrayList<AudioPort> ports) { 7505 return updateAudioPortCache(ports, null, null); 7506 } 7507 7508 /** 7509 * Returns a list of descriptors for all audio ports managed by the audio framework as 7510 * it was before the last update calback. 7511 * @param ports An AudioPort ArrayList where the list will be returned. 7512 * @hide 7513 */ listPreviousAudioPorts(ArrayList<AudioPort> ports)7514 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) { 7515 return updateAudioPortCache(null, null, ports); 7516 } 7517 7518 /** 7519 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort) 7520 * @see listAudioPorts(ArrayList<AudioPort>) 7521 * @hide 7522 */ listAudioDevicePorts(ArrayList<AudioDevicePort> devices)7523 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 7524 if (devices == null) { 7525 return ERROR_BAD_VALUE; 7526 } 7527 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 7528 int status = updateAudioPortCache(ports, null, null); 7529 if (status == SUCCESS) { 7530 filterDevicePorts(ports, devices); 7531 } 7532 return status; 7533 } 7534 7535 /** 7536 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort) 7537 * @see listPreviousAudioPorts(ArrayList<AudioPort>) 7538 * @hide 7539 */ listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices)7540 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 7541 if (devices == null) { 7542 return ERROR_BAD_VALUE; 7543 } 7544 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 7545 int status = updateAudioPortCache(null, null, ports); 7546 if (status == SUCCESS) { 7547 filterDevicePorts(ports, devices); 7548 } 7549 return status; 7550 } 7551 filterDevicePorts(ArrayList<AudioPort> ports, ArrayList<AudioDevicePort> devices)7552 private static void filterDevicePorts(ArrayList<AudioPort> ports, 7553 ArrayList<AudioDevicePort> devices) { 7554 devices.clear(); 7555 for (int i = 0; i < ports.size(); i++) { 7556 if (ports.get(i) instanceof AudioDevicePort) { 7557 devices.add((AudioDevicePort)ports.get(i)); 7558 } 7559 } 7560 } 7561 7562 /** 7563 * Create a connection between two or more devices. The framework will reject the request if 7564 * device types are not compatible or the implementation does not support the requested 7565 * configuration. 7566 * NOTE: current implementation is limited to one source and one sink per patch. 7567 * @param patch AudioPatch array where the newly created patch will be returned. 7568 * As input, if patch[0] is not null, the specified patch will be replaced by the 7569 * new patch created. This avoids calling releaseAudioPatch() when modifying a 7570 * patch and allows the implementation to optimize transitions. 7571 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE. 7572 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK. 7573 * 7574 * @return - {@link #SUCCESS} if connection is successful. 7575 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed. 7576 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported. 7577 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create 7578 * a patch. 7579 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 7580 * - {@link #ERROR} if patch cannot be connected for any other reason. 7581 * 7582 * patch[0] contains the newly created patch 7583 * @hide 7584 */ 7585 @UnsupportedAppUsage createAudioPatch(AudioPatch[] patch, AudioPortConfig[] sources, AudioPortConfig[] sinks)7586 public static int createAudioPatch(AudioPatch[] patch, 7587 AudioPortConfig[] sources, 7588 AudioPortConfig[] sinks) { 7589 return AudioSystem.createAudioPatch(patch, sources, sinks); 7590 } 7591 7592 /** 7593 * Releases an existing audio patch connection. 7594 * @param patch The audio patch to disconnect. 7595 * @return - {@link #SUCCESS} if disconnection is successful. 7596 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist. 7597 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release 7598 * a patch. 7599 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 7600 * - {@link #ERROR} if patch cannot be released for any other reason. 7601 * @hide 7602 */ 7603 @UnsupportedAppUsage releaseAudioPatch(AudioPatch patch)7604 public static int releaseAudioPatch(AudioPatch patch) { 7605 return AudioSystem.releaseAudioPatch(patch); 7606 } 7607 7608 /** 7609 * List all existing connections between audio ports. 7610 * @param patches An AudioPatch array where the list will be returned. 7611 * @hide 7612 */ 7613 @UnsupportedAppUsage listAudioPatches(ArrayList<AudioPatch> patches)7614 public static int listAudioPatches(ArrayList<AudioPatch> patches) { 7615 return updateAudioPortCache(null, patches, null); 7616 } 7617 7618 /** 7619 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by 7620 * AudioGain.buildConfig() 7621 * @hide 7622 */ setAudioPortGain(AudioPort port, AudioGainConfig gain)7623 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) { 7624 if (port == null || gain == null) { 7625 return ERROR_BAD_VALUE; 7626 } 7627 AudioPortConfig activeConfig = port.activeConfig(); 7628 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(), 7629 activeConfig.channelMask(), activeConfig.format(), gain); 7630 config.mConfigMask = AudioPortConfig.GAIN; 7631 return AudioSystem.setAudioPortConfig(config); 7632 } 7633 7634 /** 7635 * Listener registered by client to be notified upon new audio port connections, 7636 * disconnections or attributes update. 7637 * @hide 7638 */ 7639 public interface OnAudioPortUpdateListener { 7640 /** 7641 * Callback method called upon audio port list update. 7642 * @param portList the updated list of audio ports 7643 */ onAudioPortListUpdate(AudioPort[] portList)7644 public void onAudioPortListUpdate(AudioPort[] portList); 7645 7646 /** 7647 * Callback method called upon audio patch list update. 7648 * @param patchList the updated list of audio patches 7649 */ onAudioPatchListUpdate(AudioPatch[] patchList)7650 public void onAudioPatchListUpdate(AudioPatch[] patchList); 7651 7652 /** 7653 * Callback method called when the mediaserver dies 7654 */ onServiceDied()7655 public void onServiceDied(); 7656 } 7657 7658 /** 7659 * Register an audio port list update listener. 7660 * @hide 7661 */ 7662 @UnsupportedAppUsage registerAudioPortUpdateListener(OnAudioPortUpdateListener l)7663 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) { 7664 sAudioPortEventHandler.init(); 7665 sAudioPortEventHandler.registerListener(l); 7666 } 7667 7668 /** 7669 * Unregister an audio port list update listener. 7670 * @hide 7671 */ 7672 @UnsupportedAppUsage unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l)7673 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) { 7674 sAudioPortEventHandler.unregisterListener(l); 7675 } 7676 7677 // 7678 // AudioPort implementation 7679 // 7680 7681 private static final int AUDIOPORT_GENERATION_INIT = 0; 7682 private static Object sAudioPortGenerationLock = new Object(); 7683 @GuardedBy("sAudioPortGenerationLock") 7684 private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; 7685 private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>(); 7686 private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>(); 7687 private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>(); 7688 resetAudioPortGeneration()7689 static int resetAudioPortGeneration() { 7690 int generation; 7691 synchronized (sAudioPortGenerationLock) { 7692 generation = sAudioPortGeneration; 7693 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; 7694 } 7695 return generation; 7696 } 7697 updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, ArrayList<AudioPort> previousPorts)7698 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, 7699 ArrayList<AudioPort> previousPorts) { 7700 sAudioPortEventHandler.init(); 7701 synchronized (sAudioPortGenerationLock) { 7702 7703 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) { 7704 int[] patchGeneration = new int[1]; 7705 int[] portGeneration = new int[1]; 7706 int status; 7707 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>(); 7708 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>(); 7709 7710 do { 7711 newPorts.clear(); 7712 status = AudioSystem.listAudioPorts(newPorts, portGeneration); 7713 if (status != SUCCESS) { 7714 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed"); 7715 return status; 7716 } 7717 newPatches.clear(); 7718 status = AudioSystem.listAudioPatches(newPatches, patchGeneration); 7719 if (status != SUCCESS) { 7720 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed"); 7721 return status; 7722 } 7723 // Loop until patch generation is the same as port generation unless audio ports 7724 // and audio patches are not null. 7725 } while (patchGeneration[0] != portGeneration[0] 7726 && (ports == null || patches == null)); 7727 // If the patch generation doesn't equal port generation, return ERROR here in case 7728 // of mismatch between audio ports and audio patches. 7729 if (patchGeneration[0] != portGeneration[0]) { 7730 return ERROR; 7731 } 7732 7733 for (int i = 0; i < newPatches.size(); i++) { 7734 for (int j = 0; j < newPatches.get(i).sources().length; j++) { 7735 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j], 7736 newPorts); 7737 newPatches.get(i).sources()[j] = portCfg; 7738 } 7739 for (int j = 0; j < newPatches.get(i).sinks().length; j++) { 7740 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j], 7741 newPorts); 7742 newPatches.get(i).sinks()[j] = portCfg; 7743 } 7744 } 7745 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) { 7746 AudioPatch newPatch = i.next(); 7747 boolean hasInvalidPort = false; 7748 for (AudioPortConfig portCfg : newPatch.sources()) { 7749 if (portCfg == null) { 7750 hasInvalidPort = true; 7751 break; 7752 } 7753 } 7754 for (AudioPortConfig portCfg : newPatch.sinks()) { 7755 if (portCfg == null) { 7756 hasInvalidPort = true; 7757 break; 7758 } 7759 } 7760 if (hasInvalidPort) { 7761 // Temporarily remove patches with invalid ports. One who created the patch 7762 // is responsible for dealing with the port change. 7763 i.remove(); 7764 } 7765 } 7766 7767 sPreviousAudioPortsCached = sAudioPortsCached; 7768 sAudioPortsCached = newPorts; 7769 sAudioPatchesCached = newPatches; 7770 sAudioPortGeneration = portGeneration[0]; 7771 } 7772 if (ports != null) { 7773 ports.clear(); 7774 ports.addAll(sAudioPortsCached); 7775 } 7776 if (patches != null) { 7777 patches.clear(); 7778 patches.addAll(sAudioPatchesCached); 7779 } 7780 if (previousPorts != null) { 7781 previousPorts.clear(); 7782 previousPorts.addAll(sPreviousAudioPortsCached); 7783 } 7784 } 7785 return SUCCESS; 7786 } 7787 updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports)7788 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) { 7789 AudioPort port = portCfg.port(); 7790 int k; 7791 for (k = 0; k < ports.size(); k++) { 7792 // compare handles because the port returned by JNI is not of the correct 7793 // subclass 7794 if (ports.get(k).handle().equals(port.handle())) { 7795 port = ports.get(k); 7796 break; 7797 } 7798 } 7799 if (k == ports.size()) { 7800 // This can happen in case of stale audio patch referring to a removed device and is 7801 // handled by the caller. 7802 return null; 7803 } 7804 AudioGainConfig gainCfg = portCfg.gain(); 7805 if (gainCfg != null) { 7806 AudioGain gain = port.gain(gainCfg.index()); 7807 gainCfg = gain.buildConfig(gainCfg.mode(), 7808 gainCfg.channelMask(), 7809 gainCfg.values(), 7810 gainCfg.rampDurationMs()); 7811 } 7812 return port.buildConfig(portCfg.samplingRate(), 7813 portCfg.channelMask(), 7814 portCfg.format(), 7815 gainCfg); 7816 } 7817 7818 private OnAmPortUpdateListener mPortListener = null; 7819 7820 /** 7821 * The message sent to apps when the contents of the device list changes if they provide 7822 * a {@link Handler} object to {@link registerAudioDeviceCallback}. 7823 */ 7824 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0; 7825 private final static int MSG_DEVICES_DEVICES_ADDED = 1; 7826 private final static int MSG_DEVICES_DEVICES_REMOVED = 2; 7827 7828 /** 7829 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications. 7830 */ 7831 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks = 7832 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>(); 7833 7834 /** 7835 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter 7836 * the results list to only those device types they are interested in. 7837 */ 7838 /** 7839 * Specifies to the {@link AudioManager#getDevices(int)} method to include 7840 * source (i.e. input) audio devices. 7841 */ 7842 public static final int GET_DEVICES_INPUTS = 0x0001; 7843 7844 /** 7845 * Specifies to the {@link AudioManager#getDevices(int)} method to include 7846 * sink (i.e. output) audio devices. 7847 */ 7848 public static final int GET_DEVICES_OUTPUTS = 0x0002; 7849 7850 /** @hide */ 7851 @IntDef(flag = true, prefix = "GET_DEVICES", value = { 7852 GET_DEVICES_INPUTS, 7853 GET_DEVICES_OUTPUTS } 7854 ) 7855 @Retention(RetentionPolicy.SOURCE) 7856 public @interface AudioDeviceRole {} 7857 7858 /** 7859 * Specifies to the {@link AudioManager#getDevices(int)} method to include both 7860 * source and sink devices. 7861 */ 7862 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS; 7863 7864 /** 7865 * Determines if a given AudioDevicePort meets the specified filter criteria. 7866 * @param port The port to test. 7867 * @param flags A set of bitflags specifying the criteria to test. 7868 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS} 7869 **/ checkFlags(AudioDevicePort port, int flags)7870 private static boolean checkFlags(AudioDevicePort port, int flags) { 7871 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 || 7872 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0; 7873 } 7874 checkTypes(AudioDevicePort port)7875 private static boolean checkTypes(AudioDevicePort port) { 7876 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) != 7877 AudioDeviceInfo.TYPE_UNKNOWN; 7878 } 7879 7880 /** 7881 * Returns a Set of unique Integers corresponding to audio device type identifiers that can 7882 * <i>potentially</i> be connected to the system and meeting the criteria specified in the 7883 * <code>direction</code> parameter. 7884 * Note that this set contains {@link AudioDeviceInfo} device type identifiers for both devices 7885 * currently available <i>and</i> those that can be available if the user connects an audio 7886 * peripheral. Examples include TYPE_WIRED_HEADSET if the Android device supports an analog 7887 * headset jack or TYPE_USB_DEVICE if the Android device supports a USB host-mode port. 7888 * These are generally a superset of device type identifiers associated with the 7889 * AudioDeviceInfo objects returned from AudioManager.getDevices(). 7890 * @param direction The constant specifying whether input or output devices are queried. 7891 * @see #GET_DEVICES_OUTPUTS 7892 * @see #GET_DEVICES_INPUTS 7893 * @return A (possibly zero-length) Set of Integer objects corresponding to the audio 7894 * device types of devices supported by the implementation. 7895 * @throws IllegalArgumentException If an invalid direction constant is specified. 7896 */ 7897 @FlaggedApi(FLAG_SUPPORTED_DEVICE_TYPES_API) 7898 public @NonNull Set<Integer> getSupportedDeviceTypes(@udioDeviceRole int direction)7899 getSupportedDeviceTypes(@AudioDeviceRole int direction) { 7900 if (direction != GET_DEVICES_OUTPUTS && direction != GET_DEVICES_INPUTS) { 7901 throw new IllegalArgumentException("AudioManager.getSupportedDeviceTypes(0x" 7902 + Integer.toHexString(direction) + ") - Invalid."); 7903 } 7904 7905 IntArray internalDeviceTypes = new IntArray(); 7906 int status = AudioSystem.getSupportedDeviceTypes(direction, internalDeviceTypes); 7907 if (status != AudioManager.SUCCESS) { 7908 Log.e(TAG, "AudioManager.getSupportedDeviceTypes(" + direction + ") failed. status:" 7909 + status); 7910 } 7911 7912 // convert to external (AudioDeviceInfo.getType()) device IDs 7913 HashSet<Integer> externalDeviceTypes = new HashSet<Integer>(); 7914 for (int index = 0; index < internalDeviceTypes.size(); index++) { 7915 // Set will eliminate any duplicates which AudioSystem.getSupportedDeviceTypes() 7916 // returns 7917 externalDeviceTypes.add( 7918 AudioDeviceInfo.convertInternalDeviceToDeviceType( 7919 internalDeviceTypes.get(index))); 7920 } 7921 7922 return externalDeviceTypes; 7923 } 7924 7925 /** 7926 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices 7927 * currently connected to the system and meeting the criteria specified in the 7928 * <code>flags</code> parameter. 7929 * Notes that Android audio framework only support one device per device type. In that case, 7930 * if there are multiple audio device with the same device type connected to the Android device, 7931 * only the last reported device will be known by Android audio framework and returned by this 7932 * API. 7933 * @param flags A set of bitflags specifying the criteria to test. 7934 * @see #GET_DEVICES_OUTPUTS 7935 * @see #GET_DEVICES_INPUTS 7936 * @see #GET_DEVICES_ALL 7937 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 7938 */ getDevices(@udioDeviceRole int flags)7939 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) { 7940 return getDevicesStatic(flags); 7941 } 7942 7943 /** 7944 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo 7945 * objects from the current (internal) AudioDevicePort list. 7946 */ 7947 private static AudioDeviceInfo[] infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags)7948 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) { 7949 7950 // figure out how many AudioDeviceInfo we need space for... 7951 int numRecs = 0; 7952 for (AudioDevicePort port : ports) { 7953 if (checkTypes(port) && checkFlags(port, flags)) { 7954 numRecs++; 7955 } 7956 } 7957 7958 // Now load them up... 7959 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs]; 7960 int slot = 0; 7961 for (AudioDevicePort port : ports) { 7962 if (checkTypes(port) && checkFlags(port, flags)) { 7963 deviceList[slot++] = new AudioDeviceInfo(port); 7964 } 7965 } 7966 7967 return deviceList; 7968 } 7969 7970 /* 7971 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by 7972 * the add/remove callback mechanism to provide a list of the newly added or removed devices 7973 * rather than the whole list and make the app figure it out. 7974 * Note that calling this method with: 7975 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports. 7976 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports. 7977 */ calcListDeltas( ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags)7978 private static AudioDeviceInfo[] calcListDeltas( 7979 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) { 7980 7981 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>(); 7982 7983 AudioDevicePort cur_port = null; 7984 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) { 7985 boolean cur_port_found = false; 7986 cur_port = ports_B.get(cur_index); 7987 for (int prev_index = 0; 7988 prev_index < ports_A.size() && !cur_port_found; 7989 prev_index++) { 7990 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id()); 7991 } 7992 7993 if (!cur_port_found) { 7994 delta_ports.add(cur_port); 7995 } 7996 } 7997 7998 return infoListFromPortList(delta_ports, flags); 7999 } 8000 8001 /** 8002 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently 8003 * connected to the system and meeting the criteria specified in the <code>flags</code> 8004 * parameter. 8005 * This is an internal function. The public API front is getDevices(int). 8006 * @param flags A set of bitflags specifying the criteria to test. 8007 * @see #GET_DEVICES_OUTPUTS 8008 * @see #GET_DEVICES_INPUTS 8009 * @see #GET_DEVICES_ALL 8010 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 8011 * @hide 8012 */ getDevicesStatic(int flags)8013 public static AudioDeviceInfo[] getDevicesStatic(int flags) { 8014 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>(); 8015 int status = AudioManager.listAudioDevicePorts(ports); 8016 if (status != AudioManager.SUCCESS) { 8017 // fail and bail! 8018 return new AudioDeviceInfo[0]; // Always return an array. 8019 } 8020 8021 return infoListFromPortList(ports, flags); 8022 } 8023 8024 /** 8025 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID. 8026 * @param portId The audio port ID to look up for. 8027 * @param flags A set of bitflags specifying the criteria to test. 8028 * @see #GET_DEVICES_OUTPUTS 8029 * @see #GET_DEVICES_INPUTS 8030 * @see #GET_DEVICES_ALL 8031 * @return An AudioDeviceInfo or null if no device with matching port ID is found. 8032 * @hide 8033 */ getDeviceForPortId(int portId, int flags)8034 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) { 8035 if (portId == 0) { 8036 return null; 8037 } 8038 AudioDeviceInfo[] devices = getDevicesStatic(flags); 8039 for (AudioDeviceInfo device : devices) { 8040 if (device.getId() == portId) { 8041 return device; 8042 } 8043 } 8044 return null; 8045 } 8046 8047 /** 8048 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes 8049 * to the set of connected audio devices. 8050 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect 8051 * notifications. 8052 * @param handler Specifies the {@link Handler} object for the thread on which to execute 8053 * the callback. If <code>null</code>, the {@link Handler} associated with the main 8054 * {@link Looper} will be used. 8055 */ registerAudioDeviceCallback(AudioDeviceCallback callback, @Nullable Handler handler)8056 public void registerAudioDeviceCallback(AudioDeviceCallback callback, 8057 @Nullable Handler handler) { 8058 synchronized (mDeviceCallbacks) { 8059 if (callback != null && !mDeviceCallbacks.containsKey(callback)) { 8060 if (mDeviceCallbacks.size() == 0) { 8061 if (mPortListener == null) { 8062 mPortListener = new OnAmPortUpdateListener(); 8063 } 8064 registerAudioPortUpdateListener(mPortListener); 8065 } 8066 NativeEventHandlerDelegate delegate = 8067 new NativeEventHandlerDelegate(callback, handler); 8068 mDeviceCallbacks.put(callback, delegate); 8069 broadcastDeviceListChange_sync(delegate.getHandler()); 8070 } 8071 } 8072 } 8073 8074 /** 8075 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered 8076 * to receive notifications of changes to the set of connected audio devices. 8077 * @param callback The {@link AudioDeviceCallback} object that was previously registered 8078 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered. 8079 */ unregisterAudioDeviceCallback(AudioDeviceCallback callback)8080 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) { 8081 synchronized (mDeviceCallbacks) { 8082 if (mDeviceCallbacks.containsKey(callback)) { 8083 mDeviceCallbacks.remove(callback); 8084 if (mDeviceCallbacks.size() == 0) { 8085 unregisterAudioPortUpdateListener(mPortListener); 8086 } 8087 } 8088 } 8089 } 8090 8091 /** 8092 * Set port id for microphones by matching device type and address. 8093 * @hide 8094 */ setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones)8095 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) { 8096 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS); 8097 for (int i = microphones.size() - 1; i >= 0; i--) { 8098 boolean foundPortId = false; 8099 for (AudioDeviceInfo device : devices) { 8100 if (device.getPort().type() == microphones.get(i).getInternalDeviceType() 8101 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) { 8102 microphones.get(i).setId(device.getId()); 8103 foundPortId = true; 8104 break; 8105 } 8106 } 8107 if (!foundPortId) { 8108 Log.i(TAG, "Failed to find port id for device with type:" 8109 + microphones.get(i).getType() + " address:" 8110 + microphones.get(i).getAddress()); 8111 microphones.remove(i); 8112 } 8113 } 8114 } 8115 8116 /** 8117 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}. 8118 * @hide 8119 */ microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo)8120 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) { 8121 int deviceType = deviceInfo.getType(); 8122 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC 8123 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY 8124 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN 8125 : MicrophoneInfo.LOCATION_PERIPHERAL; 8126 MicrophoneInfo microphone = new MicrophoneInfo( 8127 deviceInfo.getPort().name() + deviceInfo.getId(), 8128 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation, 8129 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN, 8130 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN, 8131 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(), 8132 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN, 8133 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN); 8134 microphone.setId(deviceInfo.getId()); 8135 return microphone; 8136 } 8137 8138 /** 8139 * Add {@link MicrophoneInfo} by device information while filtering certain types. 8140 */ addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, HashSet<Integer> filterTypes)8141 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, 8142 HashSet<Integer> filterTypes) { 8143 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS); 8144 for (AudioDeviceInfo device : devices) { 8145 if (filterTypes.contains(device.getType())) { 8146 continue; 8147 } 8148 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device); 8149 microphones.add(microphone); 8150 } 8151 } 8152 8153 /** 8154 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics 8155 * of all available microphones. The list is empty when no microphones are available 8156 * on the device. An error during the query will result in an IOException being thrown. 8157 * 8158 * @return a list that contains all microphones' characteristics 8159 * @throws IOException if an error occurs. 8160 */ getMicrophones()8161 public List<MicrophoneInfo> getMicrophones() throws IOException { 8162 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>(); 8163 int status = AudioSystem.getMicrophones(microphones); 8164 HashSet<Integer> filterTypes = new HashSet<>(); 8165 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY); 8166 if (status != AudioManager.SUCCESS) { 8167 // fail and populate microphones with unknown characteristics by device information. 8168 if (status != AudioManager.ERROR_INVALID_OPERATION) { 8169 Log.e(TAG, "getMicrophones failed:" + status); 8170 } 8171 Log.i(TAG, "fallback on device info"); 8172 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 8173 return microphones; 8174 } 8175 setPortIdForMicrophones(microphones); 8176 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC); 8177 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 8178 return microphones; 8179 } 8180 8181 /** 8182 * Returns a list of audio formats that corresponds to encoding formats 8183 * supported on offload path for A2DP playback. 8184 * 8185 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats 8186 * supported for offload A2DP playback 8187 * @hide 8188 */ 8189 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) getHwOffloadFormatsSupportedForA2dp()8190 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() { 8191 ArrayList<Integer> formatsList = new ArrayList<>(); 8192 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>(); 8193 8194 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia( 8195 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList); 8196 if (status != AudioManager.SUCCESS) { 8197 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status); 8198 return codecConfigList; 8199 } 8200 8201 for (Integer format : formatsList) { 8202 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format); 8203 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) { 8204 codecConfigList.add( 8205 new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build()); 8206 } 8207 } 8208 return codecConfigList; 8209 } 8210 getHwOffloadFormatsSupportedForLeAudio( @udioSystem.BtOffloadDeviceType int deviceType)8211 private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio( 8212 @AudioSystem.BtOffloadDeviceType int deviceType) { 8213 ArrayList<Integer> formatsList = new ArrayList<>(); 8214 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>(); 8215 8216 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia( 8217 deviceType, formatsList); 8218 if (status != AudioManager.SUCCESS) { 8219 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status); 8220 return leAudioCodecConfigList; 8221 } 8222 8223 for (Integer format : formatsList) { 8224 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format); 8225 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) { 8226 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder() 8227 .setCodecType(btLeAudioCodec) 8228 .build()); 8229 } 8230 } 8231 return leAudioCodecConfigList; 8232 } 8233 8234 /** 8235 * Returns a list of audio formats that corresponds to encoding formats 8236 * supported on offload path for Le audio playback. 8237 * 8238 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats 8239 * supported for offload Le Audio playback 8240 * @hide 8241 */ 8242 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 8243 @NonNull getHwOffloadFormatsSupportedForLeAudio()8244 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() { 8245 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET); 8246 } 8247 8248 /** 8249 * Returns a list of audio formats that corresponds to encoding formats 8250 * supported on offload path for Le Broadcast playback. 8251 * 8252 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats 8253 * supported for offload Le Broadcast playback 8254 * @hide 8255 */ 8256 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 8257 @NonNull getHwOffloadFormatsSupportedForLeBroadcast()8258 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() { 8259 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST); 8260 } 8261 8262 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the 8263 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list 8264 // of the ports that exist at the time of the last notification. 8265 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>(); 8266 8267 /** 8268 * Internal method to compute and generate add/remove messages and then send to any 8269 * registered callbacks. Must be called synchronized on mDeviceCallbacks. 8270 */ broadcastDeviceListChange_sync(Handler handler)8271 private void broadcastDeviceListChange_sync(Handler handler) { 8272 int status; 8273 8274 // Get the new current set of ports 8275 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>(); 8276 status = AudioManager.listAudioDevicePorts(current_ports); 8277 if (status != AudioManager.SUCCESS) { 8278 return; 8279 } 8280 8281 if (handler != null) { 8282 // This is the callback for the registration, so send the current list 8283 AudioDeviceInfo[] deviceList = 8284 infoListFromPortList(current_ports, GET_DEVICES_ALL); 8285 handler.sendMessage( 8286 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList)); 8287 } else { 8288 AudioDeviceInfo[] added_devices = 8289 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL); 8290 AudioDeviceInfo[] removed_devices = 8291 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL); 8292 if (added_devices.length != 0 || removed_devices.length != 0) { 8293 for (int i = 0; i < mDeviceCallbacks.size(); i++) { 8294 handler = mDeviceCallbacks.valueAt(i).getHandler(); 8295 if (handler != null) { 8296 if (removed_devices.length != 0) { 8297 handler.sendMessage(Message.obtain(handler, 8298 MSG_DEVICES_DEVICES_REMOVED, 8299 removed_devices)); 8300 } 8301 if (added_devices.length != 0) { 8302 handler.sendMessage(Message.obtain(handler, 8303 MSG_DEVICES_DEVICES_ADDED, 8304 added_devices)); 8305 } 8306 } 8307 } 8308 } 8309 } 8310 8311 mPreviousPorts = current_ports; 8312 } 8313 8314 /** 8315 * Handles Port list update notifications from the AudioManager 8316 */ 8317 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener { 8318 static final String TAG = "OnAmPortUpdateListener"; onAudioPortListUpdate(AudioPort[] portList)8319 public void onAudioPortListUpdate(AudioPort[] portList) { 8320 synchronized (mDeviceCallbacks) { 8321 broadcastDeviceListChange_sync(null); 8322 } 8323 } 8324 8325 /** 8326 * Callback method called upon audio patch list update. 8327 * Note: We don't do anything with Patches at this time, so ignore this notification. 8328 * @param patchList the updated list of audio patches. 8329 */ onAudioPatchListUpdate(AudioPatch[] patchList)8330 public void onAudioPatchListUpdate(AudioPatch[] patchList) {} 8331 8332 /** 8333 * Callback method called when the mediaserver dies 8334 */ onServiceDied()8335 public void onServiceDied() { 8336 synchronized (mDeviceCallbacks) { 8337 broadcastDeviceListChange_sync(null); 8338 } 8339 } 8340 } 8341 8342 8343 /** 8344 * @hide 8345 * Abstract class to receive event notification about audioserver process state. 8346 */ 8347 @SystemApi 8348 public abstract static class AudioServerStateCallback { onAudioServerDown()8349 public void onAudioServerDown() { } onAudioServerUp()8350 public void onAudioServerUp() { } 8351 } 8352 8353 private Executor mAudioServerStateExec; 8354 private AudioServerStateCallback mAudioServerStateCb; 8355 private final Object mAudioServerStateCbLock = new Object(); 8356 8357 private final IAudioServerStateDispatcher mAudioServerStateDispatcher = 8358 new IAudioServerStateDispatcher.Stub() { 8359 @Override 8360 public void dispatchAudioServerStateChange(boolean state) { 8361 Executor exec; 8362 AudioServerStateCallback cb; 8363 8364 synchronized (mAudioServerStateCbLock) { 8365 exec = mAudioServerStateExec; 8366 cb = mAudioServerStateCb; 8367 } 8368 8369 if ((exec == null) || (cb == null)) { 8370 return; 8371 } 8372 if (state) { 8373 exec.execute(() -> cb.onAudioServerUp()); 8374 } else { 8375 exec.execute(() -> cb.onAudioServerDown()); 8376 } 8377 } 8378 }; 8379 8380 /** 8381 * @hide 8382 * Registers a callback for notification of audio server state changes. 8383 * @param executor {@link Executor} to handle the callbacks 8384 * @param stateCallback the callback to receive the audio server state changes 8385 * To remove the callabck, pass a null reference for both executor and stateCallback. 8386 */ 8387 @SystemApi setAudioServerStateCallback(@onNull Executor executor, @NonNull AudioServerStateCallback stateCallback)8388 public void setAudioServerStateCallback(@NonNull Executor executor, 8389 @NonNull AudioServerStateCallback stateCallback) { 8390 if (stateCallback == null) { 8391 throw new IllegalArgumentException("Illegal null AudioServerStateCallback"); 8392 } 8393 if (executor == null) { 8394 throw new IllegalArgumentException( 8395 "Illegal null Executor for the AudioServerStateCallback"); 8396 } 8397 8398 synchronized (mAudioServerStateCbLock) { 8399 if (mAudioServerStateCb != null) { 8400 throw new IllegalStateException( 8401 "setAudioServerStateCallback called with already registered callabck"); 8402 } 8403 final IAudioService service = getService(); 8404 try { 8405 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher); 8406 } catch (RemoteException e) { 8407 throw e.rethrowFromSystemServer(); 8408 } 8409 mAudioServerStateExec = executor; 8410 mAudioServerStateCb = stateCallback; 8411 } 8412 } 8413 8414 /** 8415 * @hide 8416 * Unregisters the callback for notification of audio server state changes. 8417 */ 8418 @SystemApi clearAudioServerStateCallback()8419 public void clearAudioServerStateCallback() { 8420 synchronized (mAudioServerStateCbLock) { 8421 if (mAudioServerStateCb != null) { 8422 final IAudioService service = getService(); 8423 try { 8424 service.unregisterAudioServerStateDispatcher( 8425 mAudioServerStateDispatcher); 8426 } catch (RemoteException e) { 8427 throw e.rethrowFromSystemServer(); 8428 } 8429 } 8430 mAudioServerStateExec = null; 8431 mAudioServerStateCb = null; 8432 } 8433 } 8434 8435 /** 8436 * @hide 8437 * Checks if native audioservice is running or not. 8438 * @return true if native audioservice runs, false otherwise. 8439 */ 8440 @SystemApi isAudioServerRunning()8441 public boolean isAudioServerRunning() { 8442 final IAudioService service = getService(); 8443 try { 8444 return service.isAudioServerRunning(); 8445 } catch (RemoteException e) { 8446 throw e.rethrowFromSystemServer(); 8447 } 8448 } 8449 8450 /** 8451 * Sets the surround sound mode. 8452 * 8453 * @return true if successful, otherwise false 8454 */ 8455 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setEncodedSurroundMode(@ncodedSurroundOutputMode int mode)8456 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) { 8457 try { 8458 return getService().setEncodedSurroundMode(mode); 8459 } catch (RemoteException e) { 8460 throw e.rethrowFromSystemServer(); 8461 } 8462 } 8463 8464 /** 8465 * Gets the surround sound mode. 8466 * 8467 * @return true if successful, otherwise false 8468 */ getEncodedSurroundMode()8469 public @EncodedSurroundOutputMode int getEncodedSurroundMode() { 8470 try { 8471 return getService().getEncodedSurroundMode( 8472 getContext().getApplicationInfo().targetSdkVersion); 8473 } catch (RemoteException e) { 8474 throw e.rethrowFromSystemServer(); 8475 } 8476 } 8477 8478 /** 8479 * @hide 8480 * Returns all surround formats. 8481 * @return a map where the key is a surround format and 8482 * the value indicates the surround format is enabled or not 8483 */ 8484 @TestApi 8485 @NonNull getSurroundFormats()8486 public Map<Integer, Boolean> getSurroundFormats() { 8487 try { 8488 return getService().getSurroundFormats(); 8489 } catch (RemoteException e) { 8490 throw e.rethrowFromSystemServer(); 8491 } 8492 } 8493 8494 /** 8495 * Sets and persists a certain surround format as enabled or not. 8496 * <p> 8497 * This API is called by TvSettings surround sound menu when user enables or disables a 8498 * surround sound format. This setting is persisted as global user setting. 8499 * Applications should revert their changes to surround sound settings unless they intend to 8500 * modify the global user settings across all apps. The framework does not auto-revert an 8501 * application's settings after a lifecycle event. Audio focus is not required to apply these 8502 * settings. 8503 * 8504 * @param enabled the required surround format state, true for enabled, false for disabled 8505 * @return true if successful, otherwise false 8506 */ 8507 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setSurroundFormatEnabled( @udioFormat.SurroundSoundEncoding int audioFormat, boolean enabled)8508 public boolean setSurroundFormatEnabled( 8509 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) { 8510 try { 8511 return getService().setSurroundFormatEnabled(audioFormat, enabled); 8512 } catch (RemoteException e) { 8513 throw e.rethrowFromSystemServer(); 8514 } 8515 } 8516 8517 /** 8518 * Gets whether a certain surround format is enabled or not. 8519 * @param audioFormat a surround format 8520 * 8521 * @return whether the required surround format is enabled 8522 */ isSurroundFormatEnabled(@udioFormat.SurroundSoundEncoding int audioFormat)8523 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) { 8524 try { 8525 return getService().isSurroundFormatEnabled(audioFormat); 8526 } catch (RemoteException e) { 8527 throw e.rethrowFromSystemServer(); 8528 } 8529 } 8530 8531 /** 8532 * @hide 8533 * Returns all surround formats that are reported by the connected HDMI device. 8534 * The return values are not affected by calling setSurroundFormatEnabled. 8535 * 8536 * @return a list of surround formats 8537 */ 8538 @TestApi 8539 @NonNull getReportedSurroundFormats()8540 public List<Integer> getReportedSurroundFormats() { 8541 try { 8542 return getService().getReportedSurroundFormats(); 8543 } catch (RemoteException e) { 8544 throw e.rethrowFromSystemServer(); 8545 } 8546 } 8547 8548 /** 8549 * Return if audio haptic coupled playback is supported or not. 8550 * 8551 * @return whether audio haptic playback supported. 8552 */ isHapticPlaybackSupported()8553 public static boolean isHapticPlaybackSupported() { 8554 return AudioSystem.isHapticPlaybackSupported(); 8555 } 8556 8557 /** 8558 * @hide 8559 * Indicates whether a platform supports the Ultrasound feature which covers the playback 8560 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the 8561 * usage will be 8562 * To start the Ultrasound playback: 8563 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}. 8564 * To start the Ultrasound capture: 8565 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}. 8566 * 8567 * @return whether the ultrasound feature is supported, true when platform supports both 8568 * Ultrasound playback and capture, false otherwise. 8569 */ 8570 @SystemApi 8571 @RequiresPermission(Manifest.permission.ACCESS_ULTRASOUND) isUltrasoundSupported()8572 public boolean isUltrasoundSupported() { 8573 try { 8574 return getService().isUltrasoundSupported(); 8575 } catch (RemoteException e) { 8576 throw e.rethrowFromSystemServer(); 8577 } 8578 } 8579 8580 /** 8581 * @hide 8582 * Indicates whether the platform supports capturing content from the hotword recognition 8583 * pipeline. To capture content of this type, create an AudioRecord with 8584 * {@link AudioRecord.Builder.setRequestHotwordStream(boolean, boolean)}. 8585 * @param lookbackAudio Query if the hotword stream additionally supports providing buffered 8586 * audio prior to stream open. 8587 * @return True if the platform supports capturing hotword content, and if lookbackAudio 8588 * is true, if it additionally supports capturing buffered hotword content prior to stream 8589 * open. False otherwise. 8590 */ 8591 @SystemApi 8592 @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD) isHotwordStreamSupported(boolean lookbackAudio)8593 public boolean isHotwordStreamSupported(boolean lookbackAudio) { 8594 try { 8595 return getService().isHotwordStreamSupported(lookbackAudio); 8596 } catch (RemoteException e) { 8597 return false; 8598 } 8599 } 8600 8601 /** 8602 * @hide 8603 * Introspection API to retrieve audio product strategies. 8604 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of 8605 * audio product strategies, which is indexed by a weakly typed index in order to be extended 8606 * by OEM without any needs of AOSP patches. 8607 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product 8608 * strategy refered either by its index or human readable string. It will allow clients 8609 * application to start streaming data using these {@link AudioAttributes} on the selected 8610 * device by Audio Policy Engine. 8611 * @return a (possibly zero-length) array of 8612 * {@see android.media.audiopolicy.AudioProductStrategy} objects. 8613 */ 8614 @SystemApi 8615 @NonNull 8616 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getAudioProductStrategies()8617 public static List<AudioProductStrategy> getAudioProductStrategies() { 8618 final IAudioService service = getService(); 8619 try { 8620 return service.getAudioProductStrategies(); 8621 } catch (RemoteException e) { 8622 throw e.rethrowFromSystemServer(); 8623 } 8624 } 8625 8626 /** 8627 * @hide 8628 * Introspection API to retrieve audio volume groups. 8629 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of 8630 * audio volume groups. 8631 * @return a (possibly zero-length) List of 8632 * {@see android.media.audiopolicy.AudioVolumeGroup} objects. 8633 */ 8634 @SystemApi 8635 @NonNull 8636 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 8637 // TODO also open to MODIFY_AUDIO_SETTINGS_PRIVILEGED b/341780042 getAudioVolumeGroups()8638 public static List<AudioVolumeGroup> getAudioVolumeGroups() { 8639 final IAudioService service = getService(); 8640 try { 8641 return service.getAudioVolumeGroups(); 8642 } catch (RemoteException e) { 8643 throw e.rethrowFromSystemServer(); 8644 } 8645 } 8646 8647 /** 8648 * @hide 8649 * Callback registered by client to be notified upon volume group change. 8650 */ 8651 @SystemApi 8652 public abstract static class VolumeGroupCallback { 8653 /** 8654 * Callback method called upon audio volume group change. 8655 * @param group the group for which the volume has changed 8656 */ onAudioVolumeGroupChanged(int group, int flags)8657 public void onAudioVolumeGroupChanged(int group, int flags) {} 8658 } 8659 8660 /** 8661 * @hide 8662 * Register an audio volume group change listener. 8663 * @param callback the {@link VolumeGroupCallback} to register 8664 */ 8665 @SystemApi registerVolumeGroupCallback( @onNull Executor executor, @NonNull VolumeGroupCallback callback)8666 public void registerVolumeGroupCallback( 8667 @NonNull Executor executor, 8668 @NonNull VolumeGroupCallback callback) { 8669 Preconditions.checkNotNull(executor, "executor must not be null"); 8670 Preconditions.checkNotNull(callback, "volume group change cb must not be null"); 8671 sAudioAudioVolumeGroupChangedHandler.init(); 8672 // TODO: make use of executor 8673 sAudioAudioVolumeGroupChangedHandler.registerListener(callback); 8674 } 8675 8676 /** 8677 * @hide 8678 * Unregister an audio volume group change listener. 8679 * @param callback the {@link VolumeGroupCallback} to unregister 8680 */ 8681 @SystemApi unregisterVolumeGroupCallback( @onNull VolumeGroupCallback callback)8682 public void unregisterVolumeGroupCallback( 8683 @NonNull VolumeGroupCallback callback) { 8684 Preconditions.checkNotNull(callback, "volume group change cb must not be null"); 8685 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback); 8686 } 8687 8688 /** 8689 * Return if an asset contains haptic channels or not. 8690 * 8691 * @param context the {@link Context} to resolve the uri. 8692 * @param uri the {@link Uri} of the asset. 8693 * @return true if the assert contains haptic channels. 8694 * @hide 8695 */ hasHapticChannelsImpl(@onNull Context context, @NonNull Uri uri)8696 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) { 8697 MediaExtractor extractor = new MediaExtractor(); 8698 try { 8699 extractor.setDataSource(context, uri, null); 8700 for (int i = 0; i < extractor.getTrackCount(); i++) { 8701 MediaFormat format = extractor.getTrackFormat(i); 8702 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) 8703 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) { 8704 return true; 8705 } 8706 } 8707 } catch (IOException e) { 8708 Log.e(TAG, "hasHapticChannels failure:" + e); 8709 } 8710 return false; 8711 } 8712 8713 /** 8714 * Return if an asset contains haptic channels or not. 8715 * 8716 * @param context the {@link Context} to resolve the uri. 8717 * @param uri the {@link Uri} of the asset. 8718 * @return true if the assert contains haptic channels. 8719 * @hide 8720 */ hasHapticChannels(@ullable Context context, @NonNull Uri uri)8721 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) { 8722 Objects.requireNonNull(uri); 8723 8724 if (context != null) { 8725 return hasHapticChannelsImpl(context, uri); 8726 } 8727 8728 Context cachedContext = sContext.get(); 8729 if (cachedContext != null) { 8730 if (DEBUG) { 8731 Log.d(TAG, "Try to use static context to query if having haptic channels"); 8732 } 8733 return hasHapticChannelsImpl(cachedContext, uri); 8734 } 8735 8736 // Try with audio service context, this may fail to get correct result. 8737 if (DEBUG) { 8738 Log.d(TAG, "Try to use audio service context to query if having haptic channels"); 8739 } 8740 try { 8741 return getService().hasHapticChannels(uri); 8742 } catch (RemoteException e) { 8743 throw e.rethrowFromSystemServer(); 8744 } 8745 } 8746 8747 /** 8748 * Set whether or not there is an active RTT call. 8749 * This method should be called by Telecom service. 8750 * @hide 8751 * TODO: make this a @SystemApi 8752 */ setRttEnabled(boolean rttEnabled)8753 public static void setRttEnabled(boolean rttEnabled) { 8754 try { 8755 getService().setRttEnabled(rttEnabled); 8756 } catch (RemoteException e) { 8757 throw e.rethrowFromSystemServer(); 8758 } 8759 } 8760 8761 /** 8762 * Adjusts the volume of the most relevant stream, or the given fallback 8763 * stream. 8764 * <p> 8765 * This method should only be used by applications that replace the 8766 * platform-wide management of audio settings or the main telephony 8767 * application. 8768 * <p> 8769 * This method has no effect if the device implements a fixed volume policy 8770 * as indicated by {@link #isVolumeFixed()}. 8771 * <p>This API checks if the caller has the necessary permissions based on the provided 8772 * component name, uid, and pid values. 8773 * See {@link #adjustSuggestedStreamVolume(int, int, int)}. 8774 * 8775 * @param suggestedStreamType The stream type that will be used if there 8776 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is 8777 * valid here. 8778 * @param direction The direction to adjust the volume. One of 8779 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 8780 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 8781 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 8782 * @param flags 8783 * @param packageName the package name of client application 8784 * @param uid the uid of client application 8785 * @param pid the pid of client application 8786 * @param targetSdkVersion the target sdk version of client application 8787 * @see #adjustVolume(int, int) 8788 * @see #adjustStreamVolume(int, int, int) 8789 * @see #setStreamVolume(int, int, int) 8790 * @see #isVolumeFixed() 8791 * 8792 * @hide 8793 */ 8794 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)8795 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, 8796 @SystemVolumeFlags int flags, 8797 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 8798 try { 8799 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags, 8800 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion); 8801 } catch (RemoteException e) { 8802 throw e.rethrowFromSystemServer(); 8803 } 8804 } 8805 8806 /** 8807 * Adjusts the volume of a particular stream by one step in a direction. 8808 * <p> 8809 * This method should only be used by applications that replace the platform-wide 8810 * management of audio settings or the main telephony application. 8811 * <p>This method has no effect if the device implements a fixed volume policy 8812 * as indicated by {@link #isVolumeFixed()}. 8813 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 8814 * unless the app has been granted Do Not Disturb Access. 8815 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 8816 * <p>This API checks if the caller has the necessary permissions based on the provided 8817 * component name, uid, and pid values. 8818 * See {@link #adjustStreamVolume(int, int, int)}. 8819 * 8820 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, 8821 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC}, 8822 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}. 8823 * @param direction The direction to adjust the volume. One of 8824 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 8825 * {@link #ADJUST_SAME}. 8826 * @param flags 8827 * @param packageName the package name of client application 8828 * @param uid the uid of client application 8829 * @param pid the pid of client application 8830 * @param targetSdkVersion the target sdk version of client application 8831 * @see #adjustVolume(int, int) 8832 * @see #setStreamVolume(int, int, int) 8833 * @throws SecurityException if the adjustment triggers a Do Not Disturb change 8834 * and the caller is not granted notification policy access. 8835 * 8836 * @hide 8837 */ 8838 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) adjustStreamVolumeForUid(int streamType, int direction, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)8839 public void adjustStreamVolumeForUid(int streamType, int direction, 8840 @SystemVolumeFlags int flags, 8841 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 8842 try { 8843 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid, 8844 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion); 8845 } catch (RemoteException e) { 8846 throw e.rethrowFromSystemServer(); 8847 } 8848 } 8849 8850 /** 8851 * Sets the volume index for a particular stream. 8852 * <p>This method has no effect if the device implements a fixed volume policy 8853 * as indicated by {@link #isVolumeFixed()}. 8854 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless 8855 * the app has been granted Do Not Disturb Access. 8856 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 8857 * <p>This API checks if the caller has the necessary permissions based on the provided 8858 * component name, uid, and pid values. 8859 * See {@link #setStreamVolume(int, int, int)}. 8860 * 8861 * @param streamType The stream whose volume index should be set. 8862 * @param index The volume index to set. See 8863 * {@link #getStreamMaxVolume(int)} for the largest valid value. 8864 * @param flags 8865 * @param packageName the package name of client application 8866 * @param uid the uid of client application 8867 * @param pid the pid of client application 8868 * @param targetSdkVersion the target sdk version of client application 8869 * @see #getStreamMaxVolume(int) 8870 * @see #getStreamVolume(int) 8871 * @see #isVolumeFixed() 8872 * @throws SecurityException if the volume change triggers a Do Not Disturb change 8873 * and the caller is not granted notification policy access. 8874 * 8875 * @hide 8876 */ 8877 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) setStreamVolumeForUid(int streamType, int index, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)8878 public void setStreamVolumeForUid(int streamType, int index, 8879 @SystemVolumeFlags int flags, 8880 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 8881 try { 8882 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid, 8883 UserHandle.getUserHandleForUid(uid), targetSdkVersion); 8884 } catch (RemoteException e) { 8885 throw e.rethrowFromSystemServer(); 8886 } 8887 } 8888 8889 8890 /** @hide 8891 * TODO: make this a @SystemApi */ 8892 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setMultiAudioFocusEnabled(boolean enabled)8893 public void setMultiAudioFocusEnabled(boolean enabled) { 8894 try { 8895 getService().setMultiAudioFocusEnabled(enabled); 8896 } catch (RemoteException e) { 8897 throw e.rethrowFromSystemServer(); 8898 } 8899 } 8900 8901 8902 /** 8903 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID. 8904 * For more details on Hardware A/V synchronization please refer to 8905 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/"> 8906 * media tunneling documentation</a>. 8907 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved. 8908 * @return the HW A/V sync ID for this audio session (an integer different from 0). 8909 * @throws UnsupportedOperationException if HW A/V synchronization is not supported. 8910 */ getAudioHwSyncForSession(int sessionId)8911 public int getAudioHwSyncForSession(int sessionId) { 8912 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId); 8913 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) { 8914 throw new UnsupportedOperationException("HW A/V synchronization is not supported."); 8915 } 8916 return hwSyncId; 8917 } 8918 8919 /** 8920 * Selects the audio device that should be used for communication use cases, for instance voice 8921 * or video calls. This method can be used by voice or video chat applications to select a 8922 * different audio device than the one selected by default by the platform. 8923 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by 8924 * {@link #getAvailableCommunicationDevices()}. Note that only devices in a sink role 8925 * (AKA output devices, see {@link AudioDeviceInfo#isSink()}) can be specified. The matching 8926 * source device is selected automatically by the platform. 8927 * <p>The selection is active as long as the requesting application process lives, until 8928 * {@link #clearCommunicationDevice} is called or until the device is disconnected. 8929 * It is therefore important for applications to clear the request when a call ends or the 8930 * the requesting activity or service is stopped or destroyed. 8931 * <p>In case of simultaneous requests by multiple applications the priority is given to the 8932 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the 8933 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode 8934 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main 8935 * telephony application with permission 8936 * {@link Manifest.permission#MODIFY_PHONE_STATE}. 8937 * <p> If the requested devices is not currently available, the request will be rejected and 8938 * the method will return false. 8939 * <p>This API replaces the following deprecated APIs: 8940 * <ul> 8941 * <li> {@link #startBluetoothSco()} 8942 * <li> {@link #stopBluetoothSco()} 8943 * <li> {@link #setSpeakerphoneOn(boolean)} 8944 * </ul> 8945 * <h4>Example</h4> 8946 * <p>The example below shows how to enable and disable speakerphone mode. 8947 * <pre class="prettyprint"> 8948 * // Get an AudioManager instance 8949 * AudioManager audioManager = Context.getSystemService(AudioManager.class); 8950 * AudioDeviceInfo speakerDevice = null; 8951 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); 8952 * for (AudioDeviceInfo device : devices) { 8953 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { 8954 * speakerDevice = device; 8955 * break; 8956 * } 8957 * } 8958 * if (speakerDevice != null) { 8959 * // Turn speakerphone ON. 8960 * boolean result = audioManager.setCommunicationDevice(speakerDevice); 8961 * if (!result) { 8962 * // Handle error. 8963 * } 8964 * // Turn speakerphone OFF. 8965 * audioManager.clearCommunicationDevice(); 8966 * } 8967 * </pre> 8968 * @param device the requested audio device. 8969 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise. 8970 * @throws IllegalArgumentException If an invalid device is specified. 8971 */ setCommunicationDevice(@onNull AudioDeviceInfo device)8972 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) { 8973 Objects.requireNonNull(device); 8974 try { 8975 if (device.getId() == 0) { 8976 Log.w(TAG, "setCommunicationDevice: device not found: " + device); 8977 return false; 8978 } 8979 return getService().setCommunicationDevice(mICallBack, device.getId()); 8980 } catch (RemoteException e) { 8981 throw e.rethrowFromSystemServer(); 8982 } 8983 } 8984 8985 /** 8986 * Cancels previous communication device selection made with 8987 * {@link #setCommunicationDevice(AudioDeviceInfo)}. 8988 */ clearCommunicationDevice()8989 public void clearCommunicationDevice() { 8990 try { 8991 getService().setCommunicationDevice(mICallBack, 0); 8992 } catch (RemoteException e) { 8993 throw e.rethrowFromSystemServer(); 8994 } 8995 } 8996 8997 /** 8998 * Returns currently selected audio device for communication. 8999 * <p>This API replaces the following deprecated APIs: 9000 * <ul> 9001 * <li> {@link #isBluetoothScoOn()} 9002 * <li> {@link #isSpeakerphoneOn()} 9003 * </ul> 9004 * @return an {@link AudioDeviceInfo} indicating which audio device is 9005 * currently selected for communication use cases. Can be null on platforms 9006 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. 9007 * is used. 9008 */ 9009 @Nullable getCommunicationDevice()9010 public AudioDeviceInfo getCommunicationDevice() { 9011 try { 9012 return getDeviceForPortId( 9013 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS); 9014 } catch (RemoteException e) { 9015 throw e.rethrowFromSystemServer(); 9016 } 9017 } 9018 9019 /** 9020 * Returns a list of audio devices that can be selected for communication use cases via 9021 * {@link #setCommunicationDevice(AudioDeviceInfo)}. 9022 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice(). 9023 */ 9024 @NonNull getAvailableCommunicationDevices()9025 public List<AudioDeviceInfo> getAvailableCommunicationDevices() { 9026 try { 9027 ArrayList<AudioDeviceInfo> devices = new ArrayList<>(); 9028 int[] portIds = getService().getAvailableCommunicationDeviceIds(); 9029 for (int portId : portIds) { 9030 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); 9031 if (device == null) { 9032 continue; 9033 } 9034 devices.add(device); 9035 } 9036 return devices; 9037 } catch (RemoteException e) { 9038 throw e.rethrowFromSystemServer(); 9039 } 9040 } 9041 9042 /** 9043 * Returns a list of direct {@link AudioProfile} that are supported for the specified 9044 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback 9045 * is possible. 9046 * 9047 * <p>Direct playback means that the audio stream is not resampled or downmixed 9048 * by the framework. Checking for direct support can help the app select the representation 9049 * of audio content that most closely matches the capabilities of the device and peripherals 9050 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded 9051 * or mixed with other streams, if needed. 9052 * <p>When using this information to inform your application which audio format to play, 9053 * query again whenever audio output devices change (see {@link AudioDeviceCallback}). 9054 * @param attributes a non-null {@link AudioAttributes} instance. 9055 * @return a list of {@link AudioProfile} 9056 */ 9057 @NonNull getDirectProfilesForAttributes(@onNull AudioAttributes attributes)9058 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) { 9059 Objects.requireNonNull(attributes); 9060 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>(); 9061 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList); 9062 if (status != SUCCESS) { 9063 Log.w(TAG, "getDirectProfilesForAttributes failed."); 9064 return new ArrayList<>(); 9065 } 9066 return audioProfilesList; 9067 } 9068 9069 /** 9070 * @hide 9071 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided. 9072 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, 9073 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. 9074 * The method will return null if no device of the provided type is connected. 9075 * If more than one device of the provided type is connected, an object corresponding to the 9076 * first device encountered in the enumeration list will be returned. 9077 * @param deviceType The device device for which an <code>AudioDeviceInfo</code> 9078 * object is queried. 9079 * @return An AudioDeviceInfo object or null if no device with the requested type is connected. 9080 * @throws IllegalArgumentException If an invalid device type is specified. 9081 */ 9082 @TestApi 9083 @Nullable getDeviceInfoFromType( @udioDeviceInfo.AudioDeviceTypeOut int deviceType)9084 public static AudioDeviceInfo getDeviceInfoFromType( 9085 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { 9086 return getDeviceInfoFromTypeAndAddress(deviceType, null); 9087 } 9088 9089 /** 9090 * @hide 9091 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and 9092 * address provided. 9093 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, 9094 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. 9095 * If a null address is provided, the matching will happen on the type only. 9096 * The method will return null if no device of the provided type and address is connected. 9097 * If more than one device of the provided type is connected, an object corresponding to the 9098 * first device encountered in the enumeration list will be returned. 9099 * @param type The device device for which an <code>AudioDeviceInfo</code> 9100 * object is queried. 9101 * @param address The device address for which an <code>AudioDeviceInfo</code> 9102 * object is queried or null if requesting match on type only. 9103 * @return An AudioDeviceInfo object or null if no matching device is connected. 9104 * @throws IllegalArgumentException If an invalid device type is specified. 9105 */ 9106 @Nullable getDeviceInfoFromTypeAndAddress( @udioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address)9107 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress( 9108 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) { 9109 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS); 9110 AudioDeviceInfo deviceForType = null; 9111 for (AudioDeviceInfo device : devices) { 9112 if (device.getType() == type) { 9113 deviceForType = device; 9114 if (address == null || address.equals(device.getAddress())) { 9115 return device; 9116 } 9117 } 9118 } 9119 return deviceForType; 9120 } 9121 9122 /** 9123 * Listener registered by client to be notified upon communication audio device change. 9124 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 9125 */ 9126 public interface OnCommunicationDeviceChangedListener { 9127 /** 9128 * Callback method called upon communication audio device change. 9129 * @param device the audio device requested for communication use cases. 9130 * Can be null on platforms not supporting 9131 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. 9132 */ onCommunicationDeviceChanged(@ullable AudioDeviceInfo device)9133 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device); 9134 } 9135 9136 /** 9137 * manages the OnCommunicationDeviceChangedListener listeners and the 9138 * CommunicationDeviceDispatcherStub 9139 */ 9140 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener> 9141 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager(); 9142 /** 9143 * Adds a listener for being notified of changes to the communication audio device. 9144 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 9145 * @param executor 9146 * @param listener 9147 */ addOnCommunicationDeviceChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnCommunicationDeviceChangedListener listener)9148 public void addOnCommunicationDeviceChangedListener( 9149 @NonNull @CallbackExecutor Executor executor, 9150 @NonNull OnCommunicationDeviceChangedListener listener) { 9151 mCommDeviceChangedListenerMgr.addListener( 9152 executor, listener, "addOnCommunicationDeviceChangedListener", 9153 () -> new CommunicationDeviceDispatcherStub()); 9154 } 9155 9156 /** 9157 * Removes a previously added listener of changes to the communication audio device. 9158 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 9159 * @param listener 9160 */ removeOnCommunicationDeviceChangedListener( @onNull OnCommunicationDeviceChangedListener listener)9161 public void removeOnCommunicationDeviceChangedListener( 9162 @NonNull OnCommunicationDeviceChangedListener listener) { 9163 mCommDeviceChangedListenerMgr.removeListener(listener, 9164 "removeOnCommunicationDeviceChangedListener"); 9165 } 9166 9167 private final class CommunicationDeviceDispatcherStub 9168 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub { 9169 9170 @Override register(boolean register)9171 public void register(boolean register) { 9172 try { 9173 if (register) { 9174 getService().registerCommunicationDeviceDispatcher(this); 9175 } else { 9176 getService().unregisterCommunicationDeviceDispatcher(this); 9177 } 9178 } catch (RemoteException e) { 9179 e.rethrowFromSystemServer(); 9180 } 9181 } 9182 9183 @Override dispatchCommunicationDeviceChanged(int portId)9184 public void dispatchCommunicationDeviceChanged(int portId) { 9185 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); 9186 mCommDeviceChangedListenerMgr.callListeners( 9187 (listener) -> listener.onCommunicationDeviceChanged(device)); 9188 } 9189 } 9190 9191 9192 /** 9193 * @hide 9194 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing 9195 * PSTN call. 9196 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain 9197 * an AudioTrack for call uplink audio injection and 9198 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain 9199 * an AudioRecord for call downlink audio extraction. 9200 * @return true if PSTN call audio is accessible, false otherwise. 9201 */ 9202 @TestApi 9203 @SystemApi 9204 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION) isPstnCallAudioInterceptable()9205 public boolean isPstnCallAudioInterceptable() { 9206 final IAudioService service = getService(); 9207 try { 9208 return service.isPstnCallAudioInterceptable(); 9209 } catch (RemoteException e) { 9210 throw e.rethrowFromSystemServer(); 9211 } 9212 } 9213 9214 /** @hide */ 9215 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = { 9216 CALL_REDIRECT_NONE, 9217 CALL_REDIRECT_PSTN, 9218 CALL_REDIRECT_VOIP } 9219 ) 9220 @Retention(RetentionPolicy.SOURCE) 9221 public @interface CallRedirectionMode {} 9222 9223 /** 9224 * Not used for call redirection 9225 * @hide 9226 */ 9227 public static final int CALL_REDIRECT_NONE = 0; 9228 /** 9229 * Used to redirect PSTN call 9230 * @hide 9231 */ 9232 public static final int CALL_REDIRECT_PSTN = 1; 9233 /** 9234 * Used to redirect VoIP call 9235 * @hide 9236 */ 9237 public static final int CALL_REDIRECT_VOIP = 2; 9238 9239 getCallRedirectMode()9240 private @CallRedirectionMode int getCallRedirectMode() { 9241 int mode = getMode(); 9242 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING 9243 || mode == MODE_CALL_REDIRECT) { 9244 return CALL_REDIRECT_PSTN; 9245 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) { 9246 return CALL_REDIRECT_VOIP; 9247 } 9248 return CALL_REDIRECT_NONE; 9249 } 9250 checkCallRedirectionFormat(AudioFormat format, boolean isOutput)9251 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) { 9252 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT 9253 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) { 9254 throw new UnsupportedOperationException(" Unsupported encoding "); 9255 } 9256 if (format.getSampleRate() < 8000 9257 || format.getSampleRate() > 48000) { 9258 throw new UnsupportedOperationException(" Unsupported sample rate "); 9259 } 9260 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO 9261 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) { 9262 throw new UnsupportedOperationException(" Unsupported output channel mask "); 9263 } 9264 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO 9265 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) { 9266 throw new UnsupportedOperationException(" Unsupported input channel mask "); 9267 } 9268 } 9269 9270 class CallIRedirectionClientInfo { 9271 public WeakReference trackOrRecord; 9272 public int redirectMode; 9273 } 9274 9275 private Object mCallRedirectionLock = new Object(); 9276 @GuardedBy("mCallRedirectionLock") 9277 private CallInjectionModeChangedListener mCallRedirectionModeListener; 9278 @GuardedBy("mCallRedirectionLock") 9279 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients; 9280 9281 /** 9282 * @hide 9283 * Returns an AudioTrack that can be used to inject audio to an active call uplink. 9284 * This can be used for functions like call screening or call audio redirection and is reserved 9285 * to system apps with privileged permission. 9286 * @param format the desired audio format for audio playback. 9287 * p>Formats accepted are: 9288 * <ul> 9289 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li> 9290 * <li><em>Channel mask</em> - Mono or Stereo </li> 9291 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li> 9292 * </ul> 9293 * 9294 * @return The AudioTrack used for audio injection 9295 * @throws NullPointerException if AudioFormat argument is null. 9296 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified. 9297 * @throws IllegalArgumentException if an invalid AudioFormat is specified. 9298 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing . 9299 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL, 9300 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT 9301 * or MODE_COMMUNICATION_REDIRECT. 9302 */ 9303 @TestApi 9304 @SystemApi 9305 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION) getCallUplinkInjectionAudioTrack(@onNull AudioFormat format)9306 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) { 9307 Objects.requireNonNull(format); 9308 checkCallRedirectionFormat(format, true /* isOutput */); 9309 9310 AudioTrack track = null; 9311 int redirectMode = getCallRedirectMode(); 9312 if (redirectMode == CALL_REDIRECT_NONE) { 9313 throw new IllegalStateException( 9314 " not available in mode " + AudioSystem.modeToString(getMode())); 9315 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) { 9316 throw new UnsupportedOperationException(" PSTN Call audio not accessible "); 9317 } 9318 9319 track = new AudioTrack.Builder() 9320 .setAudioAttributes(new AudioAttributes.Builder() 9321 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT) 9322 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) 9323 .build()) 9324 .setAudioFormat(format) 9325 .setCallRedirectionMode(redirectMode) 9326 .build(); 9327 9328 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) { 9329 synchronized (mCallRedirectionLock) { 9330 if (mCallRedirectionModeListener == null) { 9331 mCallRedirectionModeListener = new CallInjectionModeChangedListener(); 9332 try { 9333 addOnModeChangedListener( 9334 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener); 9335 } catch (Exception e) { 9336 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e); 9337 mCallRedirectionModeListener = null; 9338 throw new UnsupportedOperationException(" Cannot register mode listener "); 9339 } 9340 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>(); 9341 } 9342 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo(); 9343 info.redirectMode = redirectMode; 9344 info.trackOrRecord = new WeakReference<AudioTrack>(track); 9345 mCallIRedirectionClients.add(info); 9346 } 9347 } else { 9348 throw new UnsupportedOperationException(" Cannot create the AudioTrack"); 9349 } 9350 return track; 9351 } 9352 9353 /** 9354 * @hide 9355 * Returns an AudioRecord that can be used to extract audio from an active call downlink. 9356 * This can be used for functions like call screening or call audio redirection and is reserved 9357 * to system apps with privileged permission. 9358 * @param format the desired audio format for audio capture. 9359 *<p>Formats accepted are: 9360 * <ul> 9361 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li> 9362 * <li><em>Channel mask</em> - Mono or Stereo </li> 9363 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li> 9364 * </ul> 9365 * 9366 * @return The AudioRecord used for audio extraction 9367 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified. 9368 * @throws IllegalArgumentException if an invalid AudioFormat is specified. 9369 * @throws NullPointerException if AudioFormat argument is null. 9370 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing . 9371 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL, 9372 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT 9373 * or MODE_COMMUNICATION_REDIRECT. 9374 */ 9375 @TestApi 9376 @SystemApi 9377 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION) getCallDownlinkExtractionAudioRecord(@onNull AudioFormat format)9378 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) { 9379 Objects.requireNonNull(format); 9380 checkCallRedirectionFormat(format, false /* isOutput */); 9381 9382 AudioRecord record = null; 9383 int redirectMode = getCallRedirectMode(); 9384 if (redirectMode == CALL_REDIRECT_NONE) { 9385 throw new IllegalStateException( 9386 " not available in mode " + AudioSystem.modeToString(getMode())); 9387 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) { 9388 throw new UnsupportedOperationException(" PSTN Call audio not accessible "); 9389 } 9390 9391 record = new AudioRecord.Builder() 9392 .setAudioAttributes(new AudioAttributes.Builder() 9393 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK) 9394 .build()) 9395 .setAudioFormat(format) 9396 .setCallRedirectionMode(redirectMode) 9397 .build(); 9398 9399 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) { 9400 synchronized (mCallRedirectionLock) { 9401 if (mCallRedirectionModeListener == null) { 9402 mCallRedirectionModeListener = new CallInjectionModeChangedListener(); 9403 try { 9404 addOnModeChangedListener( 9405 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener); 9406 } catch (Exception e) { 9407 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e); 9408 mCallRedirectionModeListener = null; 9409 throw new UnsupportedOperationException(" Cannot register mode listener "); 9410 } 9411 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>(); 9412 } 9413 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo(); 9414 info.redirectMode = redirectMode; 9415 info.trackOrRecord = new WeakReference<AudioRecord>(record); 9416 mCallIRedirectionClients.add(info); 9417 } 9418 } else { 9419 throw new UnsupportedOperationException(" Cannot create the AudioRecord"); 9420 } 9421 return record; 9422 } 9423 9424 class CallInjectionModeChangedListener implements OnModeChangedListener { 9425 @Override onModeChanged(@udioMode int mode)9426 public void onModeChanged(@AudioMode int mode) { 9427 synchronized (mCallRedirectionLock) { 9428 final ArrayList<CallIRedirectionClientInfo> clientInfos = 9429 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone(); 9430 for (CallIRedirectionClientInfo info : clientInfos) { 9431 Object trackOrRecord = info.trackOrRecord.get(); 9432 if (trackOrRecord != null) { 9433 if ((info.redirectMode == CALL_REDIRECT_PSTN 9434 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING 9435 && mode != MODE_CALL_REDIRECT) 9436 || (info.redirectMode == CALL_REDIRECT_VOIP 9437 && mode != MODE_IN_COMMUNICATION 9438 && mode != MODE_COMMUNICATION_REDIRECT)) { 9439 if (trackOrRecord instanceof AudioTrack) { 9440 AudioTrack track = (AudioTrack) trackOrRecord; 9441 track.release(); 9442 } else { 9443 AudioRecord record = (AudioRecord) trackOrRecord; 9444 record.release(); 9445 } 9446 mCallIRedirectionClients.remove(info); 9447 } 9448 } 9449 } 9450 if (mCallIRedirectionClients.isEmpty()) { 9451 try { 9452 if (mCallRedirectionModeListener != null) { 9453 removeOnModeChangedListener(mCallRedirectionModeListener); 9454 } 9455 } catch (Exception e) { 9456 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e); 9457 } finally { 9458 mCallRedirectionModeListener = null; 9459 mCallIRedirectionClients = null; 9460 } 9461 } 9462 } 9463 } 9464 } 9465 9466 //--------------------------------------------------------- 9467 // audio device connection-dependent muting 9468 /** 9469 * @hide 9470 * Mute a set of playback use cases until a given audio device is connected. 9471 * Automatically unmute upon connection of the device, or after the given timeout, whichever 9472 * happens first. 9473 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example 9474 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the 9475 * device connects 9476 * @param device the audio device expected to connect within the timeout duration 9477 * @param timeout the maximum amount of time to wait for the device connection 9478 * @param timeUnit the unit for the timeout 9479 * @throws IllegalStateException when trying to issue the command while another is already in 9480 * progress and hasn't been cancelled by 9481 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See 9482 * {@link #getMutingExpectedDevice()} to check if a muting command is active. 9483 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback) 9484 */ 9485 @SystemApi 9486 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) muteAwaitConnection(@onNull int[] usagesToMute, @NonNull AudioDeviceAttributes device, long timeout, @NonNull TimeUnit timeUnit)9487 public void muteAwaitConnection(@NonNull int[] usagesToMute, 9488 @NonNull AudioDeviceAttributes device, 9489 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException { 9490 if (timeout <= 0) { 9491 throw new IllegalArgumentException("Timeout must be greater than 0"); 9492 } 9493 Objects.requireNonNull(usagesToMute); 9494 if (usagesToMute.length == 0) { 9495 throw new IllegalArgumentException("Array of usages to mute cannot be empty"); 9496 } 9497 Objects.requireNonNull(device); 9498 Objects.requireNonNull(timeUnit); 9499 try { 9500 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout)); 9501 } catch (RemoteException e) { 9502 throw e.rethrowFromSystemServer(); 9503 } 9504 } 9505 9506 /** 9507 * @hide 9508 * Query which audio device, if any, is causing some playback use cases to be muted until it 9509 * connects. 9510 * @return the audio device used in 9511 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null 9512 * if there is no active muting command (either because the muting command was not issued 9513 * or because it timed out) 9514 */ 9515 @SystemApi 9516 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getMutingExpectedDevice()9517 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() { 9518 try { 9519 return getService().getMutingExpectedDevice(); 9520 } catch (RemoteException e) { 9521 throw e.rethrowFromSystemServer(); 9522 } 9523 } 9524 9525 /** 9526 * @hide 9527 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)} 9528 * command. 9529 * @param device the device whose connection was expected when the {@code muteAwaitConnection} 9530 * command was issued. 9531 * @throws IllegalStateException when trying to issue the command for a device whose connection 9532 * is not anticipated by a previous call to 9533 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)} 9534 */ 9535 @SystemApi 9536 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) cancelMuteAwaitConnection(@onNull AudioDeviceAttributes device)9537 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device) 9538 throws IllegalStateException { 9539 Objects.requireNonNull(device); 9540 try { 9541 getService().cancelMuteAwaitConnection(device); 9542 } catch (RemoteException e) { 9543 throw e.rethrowFromSystemServer(); 9544 } 9545 } 9546 9547 /** 9548 * @hide 9549 * A callback class to receive events about the muting and unmuting of playback use cases 9550 * conditional on the upcoming connection of an audio device. 9551 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback) 9552 */ 9553 @SystemApi 9554 public abstract static class MuteAwaitConnectionCallback { 9555 9556 /** 9557 * An event where the expected audio device connected 9558 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[]) 9559 */ 9560 public static final int EVENT_CONNECTION = 1; 9561 /** 9562 * An event where the expected audio device failed connect before the timeout happened 9563 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[]) 9564 */ 9565 public static final int EVENT_TIMEOUT = 2; 9566 /** 9567 * An event where the {@code muteAwaitConnection()} command 9568 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)} 9569 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[]) 9570 */ 9571 public static final int EVENT_CANCEL = 3; 9572 9573 /** @hide */ 9574 @IntDef(flag = false, prefix = "EVENT_", value = { 9575 EVENT_CONNECTION, 9576 EVENT_TIMEOUT, 9577 EVENT_CANCEL } 9578 ) 9579 @Retention(RetentionPolicy.SOURCE) 9580 public @interface UnmuteEvent {} 9581 9582 /** 9583 * Called when a number of playback use cases are muted in response to a call to 9584 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}. 9585 * @param device the audio device whose connection is expected. Playback use cases are 9586 * unmuted when that device connects 9587 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected 9588 * playback use cases. 9589 */ onMutedUntilConnection( @onNull AudioDeviceAttributes device, @NonNull int[] mutedUsages)9590 public void onMutedUntilConnection( 9591 @NonNull AudioDeviceAttributes device, 9592 @NonNull int[] mutedUsages) {} 9593 9594 /** 9595 * Called when an event occurred that caused playback uses cases to be unmuted 9596 * @param unmuteEvent the nature of the event 9597 * @param device the device that was expected to connect 9598 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until 9599 * the event occurred 9600 */ onUnmutedEvent( @nmuteEvent int unmuteEvent, @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages)9601 public void onUnmutedEvent( 9602 @UnmuteEvent int unmuteEvent, 9603 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {} 9604 } 9605 9606 9607 /** 9608 * @hide 9609 * Register a callback to receive updates on the playback muting conditional on a specific 9610 * audio device connection. 9611 * @param executor the {@link Executor} handling the callback 9612 * @param callback the callback to register 9613 */ 9614 @SystemApi 9615 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) registerMuteAwaitConnectionCallback( @onNull @allbackExecutor Executor executor, @NonNull MuteAwaitConnectionCallback callback)9616 public void registerMuteAwaitConnectionCallback( 9617 @NonNull @CallbackExecutor Executor executor, 9618 @NonNull MuteAwaitConnectionCallback callback) { 9619 synchronized (mMuteAwaitConnectionListenerLock) { 9620 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>, 9621 MuteAwaitConnectionDispatcherStub> res = 9622 CallbackUtil.addListener("registerMuteAwaitConnectionCallback", 9623 executor, callback, mMuteAwaitConnectionListeners, 9624 mMuteAwaitConnDispatcherStub, 9625 () -> new MuteAwaitConnectionDispatcherStub(), 9626 stub -> stub.register(true)); 9627 mMuteAwaitConnectionListeners = res.first; 9628 mMuteAwaitConnDispatcherStub = res.second; 9629 } 9630 } 9631 9632 /** 9633 * @hide 9634 * Unregister a previously registered callback for playback muting conditional on device 9635 * connection. 9636 * @param callback the callback to unregister 9637 */ 9638 @SystemApi 9639 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterMuteAwaitConnectionCallback( @onNull MuteAwaitConnectionCallback callback)9640 public void unregisterMuteAwaitConnectionCallback( 9641 @NonNull MuteAwaitConnectionCallback callback) { 9642 synchronized (mMuteAwaitConnectionListenerLock) { 9643 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>, 9644 MuteAwaitConnectionDispatcherStub> res = 9645 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback", 9646 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub, 9647 stub -> stub.register(false)); 9648 mMuteAwaitConnectionListeners = res.first; 9649 mMuteAwaitConnDispatcherStub = res.second; 9650 } 9651 } 9652 9653 /** 9654 * Add UIDs that can be considered as assistant. 9655 * 9656 * @param assistantUids UIDs of the services that can be considered as assistant. 9657 * 9658 * @hide 9659 */ 9660 @SystemApi 9661 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) addAssistantServicesUids(@onNull int[] assistantUids)9662 public void addAssistantServicesUids(@NonNull int[] assistantUids) { 9663 try { 9664 getService().addAssistantServicesUids(assistantUids); 9665 } catch (RemoteException e) { 9666 throw e.rethrowFromSystemServer(); 9667 } 9668 } 9669 9670 /** 9671 * Remove UIDs that can be considered as assistant. 9672 * 9673 * @param assistantUids UIDs of the services that should be remove. 9674 * 9675 * @hide 9676 */ 9677 @SystemApi 9678 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeAssistantServicesUids(@onNull int[] assistantUids)9679 public void removeAssistantServicesUids(@NonNull int[] assistantUids) { 9680 try { 9681 getService().removeAssistantServicesUids(assistantUids); 9682 } catch (RemoteException e) { 9683 throw e.rethrowFromSystemServer(); 9684 } 9685 } 9686 9687 /** 9688 * Get the assistants UIDs that been added with the 9689 * {@link #addAssistantServicesUids(int[])} and not yet removed with 9690 * {@link #removeAssistantServicesUids(int[])} 9691 * 9692 * <p> Note that during native audioserver crash and after boot up the list of assistant 9693 * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant) 9694 * Just after user switch, the list of assistant will also reset to empty. 9695 * In both cases,The component's UID of the assistiant role or assistant setting will be 9696 * automitically added to the list by the audio service. 9697 * 9698 * @return array of assistants UIDs 9699 * 9700 * @hide 9701 */ 9702 @SystemApi 9703 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getAssistantServicesUids()9704 public @NonNull int[] getAssistantServicesUids() { 9705 try { 9706 int[] uids = getService().getAssistantServicesUids(); 9707 return Arrays.copyOf(uids, uids.length); 9708 } catch (RemoteException e) { 9709 throw e.rethrowFromSystemServer(); 9710 } 9711 } 9712 9713 /** 9714 * Sets UIDs that can be considered as active assistant. Calling the API with a new array will 9715 * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active. 9716 * In this manner calling the API with an empty array will remove all UIDs previously set. 9717 * 9718 * @param assistantUids UIDs of the services that can be considered active assistant. Can be 9719 * an empty array, for this no UID will be considered active. 9720 * 9721 * <p> Note that during audio service crash reset and after boot up the list of active assistant 9722 * UIDs will be reset to an empty list (i.e. no UID will be considered as an active assistant). 9723 * Just after user switch the list of active assistant will also reset to empty. 9724 * 9725 * @hide 9726 */ 9727 @SystemApi 9728 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setActiveAssistantServiceUids(@onNull int[] assistantUids)9729 public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) { 9730 try { 9731 getService().setActiveAssistantServiceUids(assistantUids); 9732 } catch (RemoteException e) { 9733 throw e.rethrowFromSystemServer(); 9734 } 9735 } 9736 9737 /** 9738 * Get active assistant UIDs last set with the 9739 * {@link #setActiveAssistantServiceUids(int[])} 9740 * 9741 * @return array of active assistants UIDs 9742 * 9743 * @hide 9744 */ 9745 @SystemApi 9746 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getActiveAssistantServicesUids()9747 public @NonNull int[] getActiveAssistantServicesUids() { 9748 try { 9749 int[] uids = getService().getActiveAssistantServiceUids(); 9750 return Arrays.copyOf(uids, uids.length); 9751 } catch (RemoteException e) { 9752 throw e.rethrowFromSystemServer(); 9753 } 9754 } 9755 9756 /** 9757 * Returns an {@link AudioHalVersionInfo} indicating the Audio Hal Version. If there is no audio 9758 * HAL found, null will be returned. 9759 * 9760 * @return @see @link #AudioHalVersionInfo The version of Audio HAL. 9761 * @hide 9762 */ 9763 @TestApi getHalVersion()9764 public static @Nullable AudioHalVersionInfo getHalVersion() { 9765 try { 9766 return getService().getHalVersion(); 9767 } catch (RemoteException e) { 9768 Log.e(TAG, "Error querying getHalVersion", e); 9769 throw e.rethrowFromSystemServer(); 9770 } 9771 } 9772 9773 //==================================================================== 9774 // Preferred mixer attributes 9775 9776 /** 9777 * Returns the {@link AudioMixerAttributes} that can be used to set as preferred mixer 9778 * attributes via {@link #setPreferredMixerAttributes( 9779 * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}. 9780 * <p>Note that only USB devices are guaranteed to expose configurable mixer attributes. An 9781 * empty list may be returned for all other types of devices as they may not allow dynamic 9782 * configuration. 9783 * 9784 * @param device the device to query 9785 * @return a list of {@link AudioMixerAttributes} that can be used as preferred mixer attributes 9786 * for the given device. 9787 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes) 9788 */ 9789 @NonNull getSupportedMixerAttributes(@onNull AudioDeviceInfo device)9790 public List<AudioMixerAttributes> getSupportedMixerAttributes(@NonNull AudioDeviceInfo device) { 9791 Objects.requireNonNull(device); 9792 List<AudioMixerAttributes> mixerAttrs = new ArrayList<>(); 9793 return (AudioSystem.getSupportedMixerAttributes(device.getId(), mixerAttrs) 9794 == AudioSystem.SUCCESS) ? mixerAttrs : new ArrayList<>(); 9795 } 9796 9797 /** 9798 * Configures the mixer attributes for a particular {@link AudioAttributes} over a given 9799 * {@link AudioDeviceInfo}. 9800 * <p>Call {@link #getSupportedMixerAttributes(AudioDeviceInfo)} to determine which mixer 9801 * attributes can be used with the given device. 9802 * <p>The ownership of preferred mixer attributes is recognized by uid. When a playback from the 9803 * same uid is routed to the given audio device when calling this API, the output mixer/stream 9804 * will be configured with the values previously set via this API. 9805 * <p>Use {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} 9806 * to cancel setting mixer attributes for this {@link AudioAttributes}. 9807 * 9808 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set. 9809 * Currently, only {@link AudioAttributes#USAGE_MEDIA} is supported. When 9810 * playing audio targeted at the given device, use the same attributes for 9811 * playback. 9812 * @param device the device to be routed. Currently, only USB device will be allowed. 9813 * @param mixerAttributes the preferred mixer attributes. When playing audio targeted at the 9814 * given device, use the same {@link AudioFormat} for both playback 9815 * and the mixer attributes. 9816 * @return true only if the preferred mixer attributes are set successfully. 9817 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 9818 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 9819 */ 9820 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS) setPreferredMixerAttributes(@onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device, @NonNull AudioMixerAttributes mixerAttributes)9821 public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes, 9822 @NonNull AudioDeviceInfo device, 9823 @NonNull AudioMixerAttributes mixerAttributes) { 9824 Objects.requireNonNull(attributes); 9825 Objects.requireNonNull(device); 9826 Objects.requireNonNull(mixerAttributes); 9827 try { 9828 final int status = getService().setPreferredMixerAttributes( 9829 attributes, device.getId(), mixerAttributes); 9830 return status == AudioSystem.SUCCESS; 9831 } catch (RemoteException e) { 9832 throw e.rethrowFromSystemServer(); 9833 } 9834 } 9835 9836 /** 9837 * Returns current preferred mixer attributes that is set via 9838 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)} 9839 * 9840 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set. 9841 * @param device the expected routing device 9842 * @return the preferred mixer attributes, which will be null when no preferred mixer attributes 9843 * have been set, or when they have been cleared. 9844 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes) 9845 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 9846 */ 9847 @Nullable getPreferredMixerAttributes( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device)9848 public AudioMixerAttributes getPreferredMixerAttributes( 9849 @NonNull AudioAttributes attributes, 9850 @NonNull AudioDeviceInfo device) { 9851 Objects.requireNonNull(attributes); 9852 Objects.requireNonNull(device); 9853 List<AudioMixerAttributes> mixerAttrList = new ArrayList<>(); 9854 int ret = AudioSystem.getPreferredMixerAttributes( 9855 attributes, device.getId(), mixerAttrList); 9856 if (ret == AudioSystem.SUCCESS) { 9857 return mixerAttrList.isEmpty() ? null : mixerAttrList.get(0); 9858 } else { 9859 Log.e(TAG, "Failed calling getPreferredMixerAttributes, ret=" + ret); 9860 return null; 9861 } 9862 } 9863 9864 /** 9865 * Clears the current preferred mixer attributes that were previously set via 9866 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)} 9867 * 9868 * @param attributes the {@link AudioAttributes} whose mixer attributes should be cleared. 9869 * @param device the expected routing device 9870 * @return true only if the preferred mixer attributes are removed successfully. 9871 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes) 9872 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 9873 */ 9874 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS) clearPreferredMixerAttributes( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device)9875 public boolean clearPreferredMixerAttributes( 9876 @NonNull AudioAttributes attributes, 9877 @NonNull AudioDeviceInfo device) { 9878 Objects.requireNonNull(attributes); 9879 Objects.requireNonNull(device); 9880 try { 9881 final int status = getService().clearPreferredMixerAttributes( 9882 attributes, device.getId()); 9883 return status == AudioSystem.SUCCESS; 9884 } catch (RemoteException e) { 9885 throw e.rethrowFromSystemServer(); 9886 } 9887 } 9888 9889 /** 9890 * Interface to be notified of changes in the preferred mixer attributes. 9891 * <p>Note that this listener will only be invoked whenever 9892 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)} 9893 * or {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} or device 9894 * disconnection causes a change in preferred mixer attributes. 9895 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes) 9896 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 9897 */ 9898 public interface OnPreferredMixerAttributesChangedListener { 9899 /** 9900 * Called on the listener to indicate that the preferred mixer attributes for the audio 9901 * attributes over the given device has changed. 9902 * 9903 * @param attributes the audio attributes for playback 9904 * @param device the targeted device 9905 * @param mixerAttributes the {@link AudioMixerAttributes} that contains information for 9906 * preferred mixer attributes or null if preferred mixer attributes 9907 * is cleared 9908 */ onPreferredMixerAttributesChanged( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device, @Nullable AudioMixerAttributes mixerAttributes)9909 void onPreferredMixerAttributesChanged( 9910 @NonNull AudioAttributes attributes, 9911 @NonNull AudioDeviceInfo device, 9912 @Nullable AudioMixerAttributes mixerAttributes); 9913 } 9914 9915 /** 9916 * Manage the {@link OnPreferredMixerAttributesChangedListener} listeners and the 9917 * {@link PreferredMixerAttributesDispatcherStub}. 9918 */ 9919 private final CallbackUtil.LazyListenerManager<OnPreferredMixerAttributesChangedListener> 9920 mPrefMixerAttributesListenerMgr = new CallbackUtil.LazyListenerManager(); 9921 9922 /** 9923 * Adds a listener for being notified of changes to the preferred mixer attributes. 9924 * @param executor the executor to execute the callback 9925 * @param listener the listener to be notified of changes in the preferred mixer attributes. 9926 */ addOnPreferredMixerAttributesChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredMixerAttributesChangedListener listener)9927 public void addOnPreferredMixerAttributesChangedListener( 9928 @NonNull @CallbackExecutor Executor executor, 9929 @NonNull OnPreferredMixerAttributesChangedListener listener) { 9930 Objects.requireNonNull(executor); 9931 Objects.requireNonNull(listener); 9932 mPrefMixerAttributesListenerMgr.addListener(executor, listener, 9933 "addOnPreferredMixerAttributesChangedListener", 9934 () -> new PreferredMixerAttributesDispatcherStub()); 9935 } 9936 9937 /** 9938 * Removes a previously added listener of changes to the preferred mixer attributes. 9939 * @param listener the listener to be notified of changes in the preferred mixer attributes, 9940 * which were added via {@link #addOnPreferredMixerAttributesChangedListener( 9941 * Executor, OnPreferredMixerAttributesChangedListener)}. 9942 */ removeOnPreferredMixerAttributesChangedListener( @onNull OnPreferredMixerAttributesChangedListener listener)9943 public void removeOnPreferredMixerAttributesChangedListener( 9944 @NonNull OnPreferredMixerAttributesChangedListener listener) { 9945 Objects.requireNonNull(listener); 9946 mPrefMixerAttributesListenerMgr.removeListener(listener, 9947 "removeOnPreferredMixerAttributesChangedListener"); 9948 } 9949 9950 private final class PreferredMixerAttributesDispatcherStub 9951 extends IPreferredMixerAttributesDispatcher.Stub 9952 implements CallbackUtil.DispatcherStub { 9953 9954 @Override register(boolean register)9955 public void register(boolean register) { 9956 try { 9957 if (register) { 9958 getService().registerPreferredMixerAttributesDispatcher(this); 9959 } else { 9960 getService().unregisterPreferredMixerAttributesDispatcher(this); 9961 } 9962 } catch (RemoteException e) { 9963 e.rethrowFromSystemServer(); 9964 } 9965 } 9966 9967 @Override dispatchPrefMixerAttributesChanged(@onNull AudioAttributes attr, int deviceId, @Nullable AudioMixerAttributes mixerAttr)9968 public void dispatchPrefMixerAttributesChanged(@NonNull AudioAttributes attr, 9969 int deviceId, 9970 @Nullable AudioMixerAttributes mixerAttr) { 9971 // TODO: If the device is disconnected, we may not be able to find the device with 9972 // given device id. We need a better to carry the device information via binder. 9973 AudioDeviceInfo device = getDeviceForPortId(deviceId, GET_DEVICES_OUTPUTS); 9974 if (device == null) { 9975 Log.d(TAG, "Drop preferred mixer attributes changed as the device(" 9976 + deviceId + ") is disconnected"); 9977 return; 9978 } 9979 mPrefMixerAttributesListenerMgr.callListeners( 9980 (listener) -> listener.onPreferredMixerAttributesChanged( 9981 attr, device, mixerAttr)); 9982 } 9983 } 9984 9985 /** 9986 * Requests if the implementation supports controlling the latency modes 9987 * over the Bluetooth A2DP or LE Audio links. 9988 * 9989 * @return true if supported, false otherwise 9990 * 9991 * @hide 9992 */ 9993 @SystemApi 9994 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) supportsBluetoothVariableLatency()9995 public boolean supportsBluetoothVariableLatency() { 9996 try { 9997 return getService().supportsBluetoothVariableLatency(); 9998 } catch (RemoteException e) { 9999 throw e.rethrowFromSystemServer(); 10000 } 10001 } 10002 10003 /** 10004 * Enables or disables the variable Bluetooth latency control mechanism in the 10005 * audio framework and the audio HAL. This does not apply to the latency mode control 10006 * on the spatializer output as this is a built-in feature. 10007 * 10008 * @hide 10009 */ 10010 @SystemApi 10011 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setBluetoothVariableLatencyEnabled(boolean enabled)10012 public void setBluetoothVariableLatencyEnabled(boolean enabled) { 10013 try { 10014 getService().setBluetoothVariableLatencyEnabled(enabled); 10015 } catch (RemoteException e) { 10016 throw e.rethrowFromSystemServer(); 10017 } 10018 } 10019 10020 /** 10021 * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled. 10022 * @hide 10023 */ 10024 @SystemApi 10025 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) isBluetoothVariableLatencyEnabled()10026 public boolean isBluetoothVariableLatencyEnabled() { 10027 try { 10028 return getService().isBluetoothVariableLatencyEnabled(); 10029 } catch (RemoteException e) { 10030 throw e.rethrowFromSystemServer(); 10031 } 10032 } 10033 10034 //==================================================================== 10035 // Stream aliasing changed listener, getter for stream alias or independent streams 10036 10037 /** 10038 * manages the stream aliasing listeners and StreamAliasingDispatcherStub 10039 */ 10040 private final CallbackUtil.LazyListenerManager<Runnable> mStreamAliasingListenerMgr = 10041 new CallbackUtil.LazyListenerManager(); 10042 10043 10044 final class StreamAliasingDispatcherStub extends IStreamAliasingDispatcher.Stub 10045 implements CallbackUtil.DispatcherStub { 10046 10047 @Override register(boolean register)10048 public void register(boolean register) { 10049 try { 10050 getService().registerStreamAliasingDispatcher(this, register); 10051 } catch (RemoteException e) { 10052 e.rethrowFromSystemServer(); 10053 } 10054 } 10055 10056 @Override dispatchStreamAliasingChanged()10057 public void dispatchStreamAliasingChanged() { 10058 mStreamAliasingListenerMgr.callListeners((listener) -> listener.run()); 10059 } 10060 } 10061 10062 /** 10063 * @hide 10064 * Adds a listener to be notified of changes to volume stream type aliasing. 10065 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)} 10066 * @param executor the Executor running the listener 10067 * @param onStreamAliasingChangedListener the listener to add for the aliasing changes 10068 */ 10069 @SystemApi 10070 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) addOnStreamAliasingChangedListener( @onNull @allbackExecutor Executor executor, @NonNull Runnable onStreamAliasingChangedListener)10071 public void addOnStreamAliasingChangedListener( 10072 @NonNull @CallbackExecutor Executor executor, 10073 @NonNull Runnable onStreamAliasingChangedListener) { 10074 mStreamAliasingListenerMgr.addListener(executor, onStreamAliasingChangedListener, 10075 "addOnStreamAliasingChangedListener", 10076 () -> new StreamAliasingDispatcherStub()); 10077 } 10078 10079 /** 10080 * @hide 10081 * Removes a previously added listener for changes to stream aliasing. 10082 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)} 10083 * @see #addOnStreamAliasingChangedListener(Executor, Runnable) 10084 * @param onStreamAliasingChangedListener the previously added listener of aliasing changes 10085 */ 10086 @SystemApi 10087 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) removeOnStreamAliasingChangedListener( @onNull Runnable onStreamAliasingChangedListener)10088 public void removeOnStreamAliasingChangedListener( 10089 @NonNull Runnable onStreamAliasingChangedListener) { 10090 mStreamAliasingListenerMgr.removeListener(onStreamAliasingChangedListener, 10091 "removeOnStreamAliasingChangedListener"); 10092 } 10093 10094 /** 10095 * @hide 10096 * Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING, 10097 * volumes will be updated in case of a change. 10098 * @param isAliased if true, STREAM_NOTIFICATION is aliased to STREAM_RING 10099 */ 10100 @TestApi 10101 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setNotifAliasRingForTest(boolean isAliased)10102 public void setNotifAliasRingForTest(boolean isAliased) { 10103 final IAudioService service = getService(); 10104 try { 10105 service.setNotifAliasRingForTest(isAliased); 10106 } catch (RemoteException e) { 10107 throw e.rethrowFromSystemServer(); 10108 } 10109 } 10110 10111 /** 10112 * @hide 10113 * Return the list of independent stream types for volume control. 10114 * A stream type is considered independent when the volume changes of that type do not 10115 * affect any other independent volume control stream type. 10116 * An independent stream type is its own alias when using {@link #getStreamTypeAlias(int)}. 10117 * @return list of independent stream types, where each value can be one of 10118 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, 10119 * {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, {@link #STREAM_NOTIFICATION}, 10120 * {@link #STREAM_DTMF} and {@link #STREAM_ACCESSIBILITY}. 10121 */ 10122 @SystemApi 10123 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) getIndependentStreamTypes()10124 public @NonNull List<Integer> getIndependentStreamTypes() { 10125 final IAudioService service = getService(); 10126 try { 10127 return service.getIndependentStreamTypes(); 10128 } catch (RemoteException e) { 10129 throw e.rethrowFromSystemServer(); 10130 } 10131 } 10132 10133 /** 10134 * @hide 10135 * Return the stream type that a given stream is aliased to. 10136 * A stream alias means that any change to the source stream will also be applied to the alias, 10137 * and vice-versa. 10138 * If a stream is independent (i.e. part of the stream types returned by 10139 * {@link #getIndependentStreamTypes()}), its alias is itself. 10140 * @param sourceStreamType the stream type to query for the alias. 10141 * @return the stream type the source type is aliased to. 10142 */ 10143 @SystemApi 10144 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) getStreamTypeAlias(@ublicStreamTypes int sourceStreamType)10145 public @PublicStreamTypes int getStreamTypeAlias(@PublicStreamTypes int sourceStreamType) { 10146 final IAudioService service = getService(); 10147 try { 10148 return service.getStreamTypeAlias(sourceStreamType); 10149 } catch (RemoteException e) { 10150 throw e.rethrowFromSystemServer(); 10151 } 10152 } 10153 10154 /** 10155 * @hide 10156 * Returns whether the system uses {@link AudioVolumeGroup} for volume control 10157 * @return true when volume control is performed through volume groups, false if it uses 10158 * stream types. 10159 */ 10160 @TestApi 10161 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isVolumeControlUsingVolumeGroups()10162 public boolean isVolumeControlUsingVolumeGroups() { 10163 final IAudioService service = getService(); 10164 try { 10165 return service.isVolumeControlUsingVolumeGroups(); 10166 } catch (RemoteException e) { 10167 throw e.rethrowFromSystemServer(); 10168 } 10169 } 10170 10171 /** 10172 * @hide 10173 * Checks whether a notification sound should be played or not, as reported by the state 10174 * of the audio framework. Querying whether playback should proceed is favored over 10175 * playing and letting the sound be muted or not. 10176 * @param aa the {@link AudioAttributes} of the notification about to maybe play 10177 * @return true if the audio framework state is such that the notification should be played 10178 * because at time of checking, and the notification will be heard, 10179 * false otherwise 10180 */ 10181 @TestApi 10182 @FlaggedApi(FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING) 10183 @RequiresPermission(android.Manifest.permission.QUERY_AUDIO_STATE) shouldNotificationSoundPlay(@onNull final AudioAttributes aa)10184 public boolean shouldNotificationSoundPlay(@NonNull final AudioAttributes aa) { 10185 final IAudioService service = getService(); 10186 try { 10187 return service.shouldNotificationSoundPlay(Objects.requireNonNull(aa)); 10188 } catch (RemoteException e) { 10189 throw e.rethrowFromSystemServer(); 10190 } 10191 } 10192 10193 //==================================================================== 10194 // Mute await connection 10195 10196 private final Object mMuteAwaitConnectionListenerLock = new Object(); 10197 10198 @GuardedBy("mMuteAwaitConnectionListenerLock") 10199 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>> 10200 mMuteAwaitConnectionListeners; 10201 10202 @GuardedBy("mMuteAwaitConnectionListenerLock") 10203 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub; 10204 10205 private final class MuteAwaitConnectionDispatcherStub 10206 extends IMuteAwaitConnectionCallback.Stub { register(boolean register)10207 public void register(boolean register) { 10208 try { 10209 getService().registerMuteAwaitConnectionDispatcher(this, register); 10210 } catch (RemoteException e) { 10211 throw e.rethrowFromSystemServer(); 10212 } 10213 } 10214 10215 @Override 10216 @SuppressLint("GuardedBy") // lock applied inside callListeners method dispatchOnMutedUntilConnection(AudioDeviceAttributes device, int[] mutedUsages)10217 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device, 10218 int[] mutedUsages) { 10219 CallbackUtil.callListeners(mMuteAwaitConnectionListeners, 10220 mMuteAwaitConnectionListenerLock, 10221 (listener) -> listener.onMutedUntilConnection(device, mutedUsages)); 10222 } 10223 10224 @Override 10225 @SuppressLint("GuardedBy") // lock applied inside callListeners method dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device, int[] mutedUsages)10226 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device, 10227 int[] mutedUsages) { 10228 CallbackUtil.callListeners(mMuteAwaitConnectionListeners, 10229 mMuteAwaitConnectionListenerLock, 10230 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages)); 10231 } 10232 } 10233 10234 //==================================================================== 10235 // Flag related utilities 10236 10237 private boolean mIsAutomotive = false; 10238 initPlatform()10239 private void initPlatform() { 10240 try { 10241 final Context context = getContext(); 10242 if (context != null) { 10243 mIsAutomotive = context.getPackageManager() 10244 .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 10245 } 10246 } catch (Exception e) { 10247 Log.e(TAG, "Error querying system feature for AUTOMOTIVE", e); 10248 } 10249 } 10250 applyAutoHardening()10251 private boolean applyAutoHardening() { 10252 if (mIsAutomotive && autoPublicVolumeApiHardening()) { 10253 return true; 10254 } 10255 return false; 10256 } 10257 10258 //--------------------------------------------------------- 10259 // Inner classes 10260 //-------------------- 10261 /** 10262 * Helper class to handle the forwarding of native events to the appropriate listener 10263 * (potentially) handled in a different thread. 10264 */ 10265 private class NativeEventHandlerDelegate { 10266 private final Handler mHandler; 10267 NativeEventHandlerDelegate(final AudioDeviceCallback callback, Handler handler)10268 NativeEventHandlerDelegate(final AudioDeviceCallback callback, 10269 Handler handler) { 10270 // find the looper for our new event handler 10271 Looper looper; 10272 if (handler != null) { 10273 looper = handler.getLooper(); 10274 } else { 10275 // no given handler, use the looper the addListener call was called in 10276 looper = Looper.getMainLooper(); 10277 } 10278 10279 // construct the event handler with this looper 10280 if (looper != null) { 10281 // implement the event handler delegate 10282 mHandler = new Handler(looper) { 10283 @Override 10284 public void handleMessage(Message msg) { 10285 switch(msg.what) { 10286 case MSG_DEVICES_CALLBACK_REGISTERED: 10287 case MSG_DEVICES_DEVICES_ADDED: 10288 if (callback != null) { 10289 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj); 10290 } 10291 break; 10292 10293 case MSG_DEVICES_DEVICES_REMOVED: 10294 if (callback != null) { 10295 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj); 10296 } 10297 break; 10298 10299 default: 10300 Log.e(TAG, "Unknown native event type: " + msg.what); 10301 break; 10302 } 10303 } 10304 }; 10305 } else { 10306 mHandler = null; 10307 } 10308 } 10309 getHandler()10310 Handler getHandler() { 10311 return mHandler; 10312 } 10313 } 10314 } 10315