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