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.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SdkConstant; 24 import android.annotation.SdkConstant.SdkConstantType; 25 import android.annotation.SuppressLint; 26 import android.annotation.SystemApi; 27 import android.annotation.SystemService; 28 import android.app.NotificationManager; 29 import android.app.PendingIntent; 30 import android.bluetooth.BluetoothDevice; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.media.audiopolicy.AudioPolicy; 35 import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; 36 import android.media.session.MediaController; 37 import android.media.session.MediaSession; 38 import android.media.session.MediaSessionLegacyHelper; 39 import android.media.session.MediaSessionManager; 40 import android.os.Binder; 41 import android.os.Build; 42 import android.os.Handler; 43 import android.os.IBinder; 44 import android.os.Looper; 45 import android.os.Message; 46 import android.os.Process; 47 import android.os.RemoteException; 48 import android.os.ServiceManager; 49 import android.os.SystemClock; 50 import android.os.UserHandle; 51 import android.provider.Settings; 52 import android.text.TextUtils; 53 import android.util.ArrayMap; 54 import android.util.Log; 55 import android.util.Pair; 56 import android.util.Slog; 57 import android.view.KeyEvent; 58 59 import com.android.internal.annotations.GuardedBy; 60 61 import java.io.IOException; 62 import java.lang.annotation.Retention; 63 import java.lang.annotation.RetentionPolicy; 64 import java.util.ArrayList; 65 import java.util.HashMap; 66 import java.util.HashSet; 67 import java.util.Iterator; 68 import java.util.List; 69 import java.util.Map; 70 import java.util.concurrent.ConcurrentHashMap; 71 import java.util.concurrent.Executor; 72 73 74 /** 75 * AudioManager provides access to volume and ringer mode control. 76 */ 77 @SystemService(Context.AUDIO_SERVICE) 78 public class AudioManager { 79 80 private Context mOriginalContext; 81 private Context mApplicationContext; 82 private long mVolumeKeyUpTime; 83 private final boolean mUseVolumeKeySounds; 84 private final boolean mUseFixedVolume; 85 private static final String TAG = "AudioManager"; 86 private static final boolean DEBUG = false; 87 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler(); 88 89 /** 90 * Broadcast intent, a hint for applications that audio is about to become 91 * 'noisy' due to a change in audio outputs. For example, this intent may 92 * be sent when a wired headset is unplugged, or when an A2DP audio 93 * sink is disconnected, and the audio system is about to automatically 94 * switch audio route to the speaker. Applications that are controlling 95 * audio streams may consider pausing, reducing volume or some other action 96 * on receipt of this intent so as not to surprise the user with audio 97 * from the speaker. 98 */ 99 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 100 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY"; 101 102 /** 103 * Sticky broadcast intent action indicating that the ringer mode has 104 * changed. Includes the new ringer mode. 105 * 106 * @see #EXTRA_RINGER_MODE 107 */ 108 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 109 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; 110 111 /** 112 * @hide 113 * Sticky broadcast intent action indicating that the internal ringer mode has 114 * changed. Includes the new ringer mode. 115 * 116 * @see #EXTRA_RINGER_MODE 117 */ 118 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 119 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION = 120 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION"; 121 122 /** 123 * The new ringer mode. 124 * 125 * @see #RINGER_MODE_CHANGED_ACTION 126 * @see #RINGER_MODE_NORMAL 127 * @see #RINGER_MODE_SILENT 128 * @see #RINGER_MODE_VIBRATE 129 */ 130 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE"; 131 132 /** 133 * Broadcast intent action indicating that the vibrate setting has 134 * changed. Includes the vibrate type and its new setting. 135 * 136 * @see #EXTRA_VIBRATE_TYPE 137 * @see #EXTRA_VIBRATE_SETTING 138 * @deprecated Applications should maintain their own vibrate policy based on 139 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 140 */ 141 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 142 public static final String VIBRATE_SETTING_CHANGED_ACTION = 143 "android.media.VIBRATE_SETTING_CHANGED"; 144 145 /** 146 * @hide Broadcast intent when the volume for a particular stream type changes. 147 * Includes the stream, the new volume and previous volumes. 148 * Notes: 149 * - for internal platform use only, do not make public, 150 * - never used for "remote" volume changes 151 * 152 * @see #EXTRA_VOLUME_STREAM_TYPE 153 * @see #EXTRA_VOLUME_STREAM_VALUE 154 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE 155 */ 156 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 157 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"; 158 159 /** 160 * @hide Broadcast intent when the devices for a particular stream type changes. 161 * Includes the stream, the new devices and previous devices. 162 * Notes: 163 * - for internal platform use only, do not make public, 164 * - never used for "remote" volume changes 165 * 166 * @see #EXTRA_VOLUME_STREAM_TYPE 167 * @see #EXTRA_VOLUME_STREAM_DEVICES 168 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES 169 * @see #getDevicesForStream 170 */ 171 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 172 public static final String STREAM_DEVICES_CHANGED_ACTION = 173 "android.media.STREAM_DEVICES_CHANGED_ACTION"; 174 175 /** 176 * @hide Broadcast intent when a stream mute state changes. 177 * Includes the stream that changed and the new mute state 178 * 179 * @see #EXTRA_VOLUME_STREAM_TYPE 180 * @see #EXTRA_STREAM_VOLUME_MUTED 181 */ 182 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 183 public static final String STREAM_MUTE_CHANGED_ACTION = 184 "android.media.STREAM_MUTE_CHANGED_ACTION"; 185 186 /** 187 * @hide Broadcast intent when the master mute state changes. 188 * Includes the the new volume 189 * 190 * @see #EXTRA_MASTER_VOLUME_MUTED 191 */ 192 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 193 public static final String MASTER_MUTE_CHANGED_ACTION = 194 "android.media.MASTER_MUTE_CHANGED_ACTION"; 195 196 /** 197 * The new vibrate setting for a particular type. 198 * 199 * @see #VIBRATE_SETTING_CHANGED_ACTION 200 * @see #EXTRA_VIBRATE_TYPE 201 * @see #VIBRATE_SETTING_ON 202 * @see #VIBRATE_SETTING_OFF 203 * @see #VIBRATE_SETTING_ONLY_SILENT 204 * @deprecated Applications should maintain their own vibrate policy based on 205 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 206 */ 207 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING"; 208 209 /** 210 * The vibrate type whose setting has changed. 211 * 212 * @see #VIBRATE_SETTING_CHANGED_ACTION 213 * @see #VIBRATE_TYPE_NOTIFICATION 214 * @see #VIBRATE_TYPE_RINGER 215 * @deprecated Applications should maintain their own vibrate policy based on 216 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 217 */ 218 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE"; 219 220 /** 221 * @hide The stream type for the volume changed intent. 222 */ 223 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE"; 224 225 /** 226 * @hide 227 * The stream type alias for the volume changed intent. 228 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream 229 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also 230 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices, 231 * {@link #STREAM_MUSIC} on others (e.g. a television). 232 */ 233 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS = 234 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS"; 235 236 /** 237 * @hide The volume associated with the stream for the volume changed intent. 238 */ 239 public static final String EXTRA_VOLUME_STREAM_VALUE = 240 "android.media.EXTRA_VOLUME_STREAM_VALUE"; 241 242 /** 243 * @hide The previous volume associated with the stream for the volume changed intent. 244 */ 245 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE = 246 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE"; 247 248 /** 249 * @hide The devices associated with the stream for the stream devices changed intent. 250 */ 251 public static final String EXTRA_VOLUME_STREAM_DEVICES = 252 "android.media.EXTRA_VOLUME_STREAM_DEVICES"; 253 254 /** 255 * @hide The previous devices associated with the stream for the stream devices changed intent. 256 */ 257 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES = 258 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES"; 259 260 /** 261 * @hide The new master volume mute state for the master mute changed intent. 262 * Value is boolean 263 */ 264 public static final String EXTRA_MASTER_VOLUME_MUTED = 265 "android.media.EXTRA_MASTER_VOLUME_MUTED"; 266 267 /** 268 * @hide The new stream volume mute state for the stream mute changed intent. 269 * Value is boolean 270 */ 271 public static final String EXTRA_STREAM_VOLUME_MUTED = 272 "android.media.EXTRA_STREAM_VOLUME_MUTED"; 273 274 /** 275 * Broadcast Action: Wired Headset plugged in or unplugged. 276 * 277 * You <em>cannot</em> receive this through components declared 278 * in manifests, only by explicitly registering for it with 279 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 280 * Context.registerReceiver()}. 281 * 282 * <p>The intent will have the following extra values: 283 * <ul> 284 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> 285 * <li><em>name</em> - Headset type, human readable string </li> 286 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li> 287 * </ul> 288 * </ul> 289 */ 290 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 291 public static final String ACTION_HEADSET_PLUG = 292 "android.intent.action.HEADSET_PLUG"; 293 294 /** 295 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged. 296 * 297 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE}, 298 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}. 299 * <p>It can only be received by explicitly registering for it with 300 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}. 301 */ 302 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 303 public static final String ACTION_HDMI_AUDIO_PLUG = 304 "android.media.action.HDMI_AUDIO_PLUG"; 305 306 /** 307 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in 308 * or unplugged. 309 * An integer value of 1 indicates a plugged-in state, 0 is unplugged. 310 */ 311 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE"; 312 313 /** 314 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels 315 * supported by the HDMI device. 316 * The corresponding integer value is only available when the device is plugged in (as expressed 317 * by {@link #EXTRA_AUDIO_PLUG_STATE}). 318 */ 319 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT"; 320 321 /** 322 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by 323 * the connected HDMI device. 324 * The corresponding array of encoding values is only available when the device is plugged in 325 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in 326 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use 327 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values. 328 */ 329 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS"; 330 331 /** Used to identify the volume of audio streams for phone calls */ 332 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL; 333 /** Used to identify the volume of audio streams for system sounds */ 334 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM; 335 /** Used to identify the volume of audio streams for the phone ring */ 336 public static final int STREAM_RING = AudioSystem.STREAM_RING; 337 /** Used to identify the volume of audio streams for music playback */ 338 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC; 339 /** Used to identify the volume of audio streams for alarms */ 340 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM; 341 /** Used to identify the volume of audio streams for notifications */ 342 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION; 343 /** @hide Used to identify the volume of audio streams for phone calls when connected 344 * to bluetooth */ 345 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO; 346 /** @hide Used to identify the volume of audio streams for enforced system sounds 347 * in certain countries (e.g camera in Japan) */ 348 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED; 349 /** Used to identify the volume of audio streams for DTMF Tones */ 350 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF; 351 /** @hide Used to identify the volume of audio streams exclusively transmitted through the 352 * speaker (TTS) of the device */ 353 public static final int STREAM_TTS = AudioSystem.STREAM_TTS; 354 /** Used to identify the volume of audio streams for accessibility prompts */ 355 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY; 356 357 /** Number of audio streams */ 358 /** 359 * @deprecated Do not iterate on volume stream type values. 360 */ 361 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS; 362 363 /** 364 * Increase the ringer volume. 365 * 366 * @see #adjustVolume(int, int) 367 * @see #adjustStreamVolume(int, int, int) 368 */ 369 public static final int ADJUST_RAISE = 1; 370 371 /** 372 * Decrease the ringer volume. 373 * 374 * @see #adjustVolume(int, int) 375 * @see #adjustStreamVolume(int, int, int) 376 */ 377 public static final int ADJUST_LOWER = -1; 378 379 /** 380 * Maintain the previous ringer volume. This may be useful when needing to 381 * show the volume toast without actually modifying the volume. 382 * 383 * @see #adjustVolume(int, int) 384 * @see #adjustStreamVolume(int, int, int) 385 */ 386 public static final int ADJUST_SAME = 0; 387 388 /** 389 * Mute the volume. Has no effect if the stream is already muted. 390 * 391 * @see #adjustVolume(int, int) 392 * @see #adjustStreamVolume(int, int, int) 393 */ 394 public static final int ADJUST_MUTE = -100; 395 396 /** 397 * Unmute the volume. Has no effect if the stream is not muted. 398 * 399 * @see #adjustVolume(int, int) 400 * @see #adjustStreamVolume(int, int, int) 401 */ 402 public static final int ADJUST_UNMUTE = 100; 403 404 /** 405 * Toggle the mute state. If muted the stream will be unmuted. If not muted 406 * the stream will be muted. 407 * 408 * @see #adjustVolume(int, int) 409 * @see #adjustStreamVolume(int, int, int) 410 */ 411 public static final int ADJUST_TOGGLE_MUTE = 101; 412 413 /** @hide */ 414 @IntDef(flag = false, prefix = "ADJUST", value = { 415 ADJUST_RAISE, 416 ADJUST_LOWER, 417 ADJUST_SAME, 418 ADJUST_MUTE, 419 ADJUST_UNMUTE, 420 ADJUST_TOGGLE_MUTE } 421 ) 422 @Retention(RetentionPolicy.SOURCE) 423 public @interface VolumeAdjustment {} 424 425 /** @hide */ adjustToString(int adj)426 public static final String adjustToString(int adj) { 427 switch (adj) { 428 case ADJUST_RAISE: return "ADJUST_RAISE"; 429 case ADJUST_LOWER: return "ADJUST_LOWER"; 430 case ADJUST_SAME: return "ADJUST_SAME"; 431 case ADJUST_MUTE: return "ADJUST_MUTE"; 432 case ADJUST_UNMUTE: return "ADJUST_UNMUTE"; 433 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE"; 434 default: return new StringBuilder("unknown adjust mode ").append(adj).toString(); 435 } 436 } 437 438 // Flags should be powers of 2! 439 440 /** 441 * Show a toast containing the current volume. 442 * 443 * @see #adjustStreamVolume(int, int, int) 444 * @see #adjustVolume(int, int) 445 * @see #setStreamVolume(int, int, int) 446 * @see #setRingerMode(int) 447 */ 448 public static final int FLAG_SHOW_UI = 1 << 0; 449 450 /** 451 * Whether to include ringer modes as possible options when changing volume. 452 * For example, if true and volume level is 0 and the volume is adjusted 453 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or 454 * vibrate mode. 455 * <p> 456 * By default this is on for the ring stream. If this flag is included, 457 * this behavior will be present regardless of the stream type being 458 * affected by the ringer mode. 459 * 460 * @see #adjustVolume(int, int) 461 * @see #adjustStreamVolume(int, int, int) 462 */ 463 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1; 464 465 /** 466 * Whether to play a sound when changing the volume. 467 * <p> 468 * If this is given to {@link #adjustVolume(int, int)} or 469 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored 470 * in some cases (for example, the decided stream type is not 471 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted 472 * downward). 473 * 474 * @see #adjustStreamVolume(int, int, int) 475 * @see #adjustVolume(int, int) 476 * @see #setStreamVolume(int, int, int) 477 */ 478 public static final int FLAG_PLAY_SOUND = 1 << 2; 479 480 /** 481 * Removes any sounds/vibrate that may be in the queue, or are playing (related to 482 * changing volume). 483 */ 484 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3; 485 486 /** 487 * Whether to vibrate if going into the vibrate ringer mode. 488 */ 489 public static final int FLAG_VIBRATE = 1 << 4; 490 491 /** 492 * Indicates to VolumePanel that the volume slider should be disabled as user 493 * cannot change the stream volume 494 * @hide 495 */ 496 public static final int FLAG_FIXED_VOLUME = 1 << 5; 497 498 /** 499 * Indicates the volume set/adjust call is for Bluetooth absolute volume 500 * @hide 501 */ 502 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6; 503 504 /** 505 * Adjusting the volume was prevented due to silent mode, display a hint in the UI. 506 * @hide 507 */ 508 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7; 509 510 /** 511 * Indicates the volume call is for Hdmi Cec system audio volume 512 * @hide 513 */ 514 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8; 515 516 /** 517 * Indicates that this should only be handled if media is actively playing. 518 * @hide 519 */ 520 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9; 521 522 /** 523 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders. 524 * @hide 525 */ 526 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10; 527 528 /** 529 * Adjusting the volume down from vibrated was prevented, display a hint in the UI. 530 * @hide 531 */ 532 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11; 533 534 /** 535 * Adjusting the volume due to a hardware key press. 536 * @hide 537 */ 538 public static final int FLAG_FROM_KEY = 1 << 12; 539 540 private static final String[] FLAG_NAMES = { 541 "FLAG_SHOW_UI", 542 "FLAG_ALLOW_RINGER_MODES", 543 "FLAG_PLAY_SOUND", 544 "FLAG_REMOVE_SOUND_AND_VIBRATE", 545 "FLAG_VIBRATE", 546 "FLAG_FIXED_VOLUME", 547 "FLAG_BLUETOOTH_ABS_VOLUME", 548 "FLAG_SHOW_SILENT_HINT", 549 "FLAG_HDMI_SYSTEM_AUDIO_VOLUME", 550 "FLAG_ACTIVE_MEDIA_ONLY", 551 "FLAG_SHOW_UI_WARNINGS", 552 "FLAG_SHOW_VIBRATE_HINT", 553 "FLAG_FROM_KEY", 554 }; 555 556 /** @hide */ flagsToString(int flags)557 public static String flagsToString(int flags) { 558 final StringBuilder sb = new StringBuilder(); 559 for (int i = 0; i < FLAG_NAMES.length; i++) { 560 final int flag = 1 << i; 561 if ((flags & flag) != 0) { 562 if (sb.length() > 0) { 563 sb.append(','); 564 } 565 sb.append(FLAG_NAMES[i]); 566 flags &= ~flag; 567 } 568 } 569 if (flags != 0) { 570 if (sb.length() > 0) { 571 sb.append(','); 572 } 573 sb.append(flags); 574 } 575 return sb.toString(); 576 } 577 578 /** 579 * Ringer mode that will be silent and will not vibrate. (This overrides the 580 * vibrate setting.) 581 * 582 * @see #setRingerMode(int) 583 * @see #getRingerMode() 584 */ 585 public static final int RINGER_MODE_SILENT = 0; 586 587 /** 588 * Ringer mode that will be silent and will vibrate. (This will cause the 589 * phone ringer to always vibrate, but the notification vibrate to only 590 * vibrate if set.) 591 * 592 * @see #setRingerMode(int) 593 * @see #getRingerMode() 594 */ 595 public static final int RINGER_MODE_VIBRATE = 1; 596 597 /** 598 * Ringer mode that may be audible and may vibrate. It will be audible if 599 * the volume before changing out of this mode was audible. It will vibrate 600 * if the vibrate setting is on. 601 * 602 * @see #setRingerMode(int) 603 * @see #getRingerMode() 604 */ 605 public static final int RINGER_MODE_NORMAL = 2; 606 607 /** 608 * Maximum valid ringer mode value. Values must start from 0 and be contiguous. 609 * @hide 610 */ 611 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL; 612 613 /** 614 * Vibrate type that corresponds to the ringer. 615 * 616 * @see #setVibrateSetting(int, int) 617 * @see #getVibrateSetting(int) 618 * @see #shouldVibrate(int) 619 * @deprecated Applications should maintain their own vibrate policy based on 620 * current ringer mode that can be queried via {@link #getRingerMode()}. 621 */ 622 public static final int VIBRATE_TYPE_RINGER = 0; 623 624 /** 625 * Vibrate type that corresponds to notifications. 626 * 627 * @see #setVibrateSetting(int, int) 628 * @see #getVibrateSetting(int) 629 * @see #shouldVibrate(int) 630 * @deprecated Applications should maintain their own vibrate policy based on 631 * current ringer mode that can be queried via {@link #getRingerMode()}. 632 */ 633 public static final int VIBRATE_TYPE_NOTIFICATION = 1; 634 635 /** 636 * Vibrate setting that suggests to never vibrate. 637 * 638 * @see #setVibrateSetting(int, int) 639 * @see #getVibrateSetting(int) 640 * @deprecated Applications should maintain their own vibrate policy based on 641 * current ringer mode that can be queried via {@link #getRingerMode()}. 642 */ 643 public static final int VIBRATE_SETTING_OFF = 0; 644 645 /** 646 * Vibrate setting that suggests to vibrate when possible. 647 * 648 * @see #setVibrateSetting(int, int) 649 * @see #getVibrateSetting(int) 650 * @deprecated Applications should maintain their own vibrate policy based on 651 * current ringer mode that can be queried via {@link #getRingerMode()}. 652 */ 653 public static final int VIBRATE_SETTING_ON = 1; 654 655 /** 656 * Vibrate setting that suggests to only vibrate when in the vibrate ringer 657 * mode. 658 * 659 * @see #setVibrateSetting(int, int) 660 * @see #getVibrateSetting(int) 661 * @deprecated Applications should maintain their own vibrate policy based on 662 * current ringer mode that can be queried via {@link #getRingerMode()}. 663 */ 664 public static final int VIBRATE_SETTING_ONLY_SILENT = 2; 665 666 /** 667 * Suggests using the default stream type. This may not be used in all 668 * places a stream type is needed. 669 */ 670 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE; 671 672 private static IAudioService sService; 673 674 /** 675 * @hide 676 * For test purposes only, will throw NPE with some methods that require a Context. 677 */ AudioManager()678 public AudioManager() { 679 mUseVolumeKeySounds = true; 680 mUseFixedVolume = false; 681 } 682 683 /** 684 * @hide 685 */ AudioManager(Context context)686 public AudioManager(Context context) { 687 setContext(context); 688 mUseVolumeKeySounds = getContext().getResources().getBoolean( 689 com.android.internal.R.bool.config_useVolumeKeySounds); 690 mUseFixedVolume = getContext().getResources().getBoolean( 691 com.android.internal.R.bool.config_useFixedVolume); 692 } 693 getContext()694 private Context getContext() { 695 if (mApplicationContext == null) { 696 setContext(mOriginalContext); 697 } 698 if (mApplicationContext != null) { 699 return mApplicationContext; 700 } 701 return mOriginalContext; 702 } 703 setContext(Context context)704 private void setContext(Context context) { 705 mApplicationContext = context.getApplicationContext(); 706 if (mApplicationContext != null) { 707 mOriginalContext = null; 708 } else { 709 mOriginalContext = context; 710 } 711 } 712 getService()713 private static IAudioService getService() 714 { 715 if (sService != null) { 716 return sService; 717 } 718 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 719 sService = IAudioService.Stub.asInterface(b); 720 return sService; 721 } 722 723 /** 724 * Sends a simulated key event for a media button. 725 * To simulate a key press, you must first send a KeyEvent built with a 726 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP} 727 * action. 728 * <p>The key event will be sent to the current media key event consumer which registered with 729 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}. 730 * @param keyEvent a {@link KeyEvent} instance whose key code is one of 731 * {@link KeyEvent#KEYCODE_MUTE}, 732 * {@link KeyEvent#KEYCODE_HEADSETHOOK}, 733 * {@link KeyEvent#KEYCODE_MEDIA_PLAY}, 734 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE}, 735 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE}, 736 * {@link KeyEvent#KEYCODE_MEDIA_STOP}, 737 * {@link KeyEvent#KEYCODE_MEDIA_NEXT}, 738 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS}, 739 * {@link KeyEvent#KEYCODE_MEDIA_REWIND}, 740 * {@link KeyEvent#KEYCODE_MEDIA_RECORD}, 741 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD}, 742 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE}, 743 * {@link KeyEvent#KEYCODE_MEDIA_EJECT}, 744 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}. 745 */ dispatchMediaKeyEvent(KeyEvent keyEvent)746 public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 747 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 748 helper.sendMediaButtonEvent(keyEvent, false); 749 } 750 751 /** 752 * @hide 753 */ preDispatchKeyEvent(KeyEvent event, int stream)754 public void preDispatchKeyEvent(KeyEvent event, int stream) { 755 /* 756 * If the user hits another key within the play sound delay, then 757 * cancel the sound 758 */ 759 int keyCode = event.getKeyCode(); 760 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP 761 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE 762 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) { 763 /* 764 * The user has hit another key during the delay (e.g., 300ms) 765 * since the last volume key up, so cancel any sounds. 766 */ 767 adjustSuggestedStreamVolume(ADJUST_SAME, 768 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); 769 } 770 } 771 772 /** 773 * Indicates if the device implements a fixed volume policy. 774 * <p>Some devices may not have volume control and may operate at a fixed volume, 775 * and may not enable muting or changing the volume of audio streams. 776 * This method will return true on such devices. 777 * <p>The following APIs have no effect when volume is fixed: 778 * <ul> 779 * <li> {@link #adjustVolume(int, int)} 780 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)} 781 * <li> {@link #adjustStreamVolume(int, int, int)} 782 * <li> {@link #setStreamVolume(int, int, int)} 783 * <li> {@link #setRingerMode(int)} 784 * <li> {@link #setStreamSolo(int, boolean)} 785 * <li> {@link #setStreamMute(int, boolean)} 786 * </ul> 787 */ isVolumeFixed()788 public boolean isVolumeFixed() { 789 return mUseFixedVolume; 790 } 791 792 /** 793 * Adjusts the volume of a particular stream by one step in a direction. 794 * <p> 795 * This method should only be used by applications that replace the platform-wide 796 * management of audio settings or the main telephony application. 797 * 798 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, 799 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC}, 800 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}. 801 * @param direction The direction to adjust the volume. One of 802 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 803 * {@link #ADJUST_SAME}. 804 * @param flags One or more flags. 805 * @see #adjustVolume(int, int) 806 * @see #setStreamVolume(int, int, int) 807 */ adjustStreamVolume(int streamType, int direction, int flags)808 public void adjustStreamVolume(int streamType, int direction, int flags) { 809 final IAudioService service = getService(); 810 try { 811 service.adjustStreamVolume(streamType, direction, flags, 812 getContext().getOpPackageName()); 813 } catch (RemoteException e) { 814 throw e.rethrowFromSystemServer(); 815 } 816 } 817 818 /** 819 * Adjusts the volume of the most relevant stream. For example, if a call is 820 * active, it will have the highest priority regardless of if the in-call 821 * screen is showing. Another example, if music is playing in the background 822 * and a call is not active, the music stream will be adjusted. 823 * <p> 824 * This method should only be used by applications that replace the 825 * platform-wide management of audio settings or the main telephony 826 * application. 827 * <p> 828 * This method has no effect if the device implements a fixed volume policy 829 * as indicated by {@link #isVolumeFixed()}. 830 * 831 * @param direction The direction to adjust the volume. One of 832 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 833 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 834 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 835 * @param flags One or more flags. 836 * @see #adjustSuggestedStreamVolume(int, int, int) 837 * @see #adjustStreamVolume(int, int, int) 838 * @see #setStreamVolume(int, int, int) 839 * @see #isVolumeFixed() 840 */ adjustVolume(int direction, int flags)841 public void adjustVolume(int direction, int flags) { 842 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 843 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags); 844 } 845 846 /** 847 * Adjusts the volume of the most relevant stream, or the given fallback 848 * stream. 849 * <p> 850 * This method should only be used by applications that replace the 851 * platform-wide management of audio settings or the main telephony 852 * application. 853 * <p> 854 * This method has no effect if the device implements a fixed volume policy 855 * as indicated by {@link #isVolumeFixed()}. 856 * 857 * @param direction The direction to adjust the volume. One of 858 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 859 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 860 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 861 * @param suggestedStreamType The stream type that will be used if there 862 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is 863 * valid here. 864 * @param flags One or more flags. 865 * @see #adjustVolume(int, int) 866 * @see #adjustStreamVolume(int, int, int) 867 * @see #setStreamVolume(int, int, int) 868 * @see #isVolumeFixed() 869 */ adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags)870 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 871 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 872 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags); 873 } 874 875 /** @hide */ setMasterMute(boolean mute, int flags)876 public void setMasterMute(boolean mute, int flags) { 877 final IAudioService service = getService(); 878 try { 879 service.setMasterMute(mute, flags, getContext().getOpPackageName(), 880 UserHandle.getCallingUserId()); 881 } catch (RemoteException e) { 882 throw e.rethrowFromSystemServer(); 883 } 884 } 885 886 /** 887 * Returns the current ringtone mode. 888 * 889 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL}, 890 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. 891 * @see #setRingerMode(int) 892 */ getRingerMode()893 public int getRingerMode() { 894 final IAudioService service = getService(); 895 try { 896 return service.getRingerModeExternal(); 897 } catch (RemoteException e) { 898 throw e.rethrowFromSystemServer(); 899 } 900 } 901 902 /** 903 * Checks valid ringer mode values. 904 * 905 * @return true if the ringer mode indicated is valid, false otherwise. 906 * 907 * @see #setRingerMode(int) 908 * @hide 909 */ isValidRingerMode(int ringerMode)910 public static boolean isValidRingerMode(int ringerMode) { 911 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) { 912 return false; 913 } 914 final IAudioService service = getService(); 915 try { 916 return service.isValidRingerMode(ringerMode); 917 } catch (RemoteException e) { 918 throw e.rethrowFromSystemServer(); 919 } 920 } 921 922 /** 923 * Returns the maximum volume index for a particular stream. 924 * 925 * @param streamType The stream type whose maximum volume index is returned. 926 * @return The maximum valid volume index for the stream. 927 * @see #getStreamVolume(int) 928 */ getStreamMaxVolume(int streamType)929 public int getStreamMaxVolume(int streamType) { 930 final IAudioService service = getService(); 931 try { 932 return service.getStreamMaxVolume(streamType); 933 } catch (RemoteException e) { 934 throw e.rethrowFromSystemServer(); 935 } 936 } 937 938 /** 939 * Returns the minimum volume index for a particular stream. 940 * @param streamType The stream type whose minimum volume index is returned. Must be one of 941 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, 942 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, 943 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}. 944 * @return The minimum valid volume index for the stream. 945 * @see #getStreamVolume(int) 946 */ getStreamMinVolume(int streamType)947 public int getStreamMinVolume(int streamType) { 948 if (!isPublicStreamType(streamType)) { 949 throw new IllegalArgumentException("Invalid stream type " + streamType); 950 } 951 return getStreamMinVolumeInt(streamType); 952 } 953 954 /** 955 * @hide 956 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type. 957 * @param streamType The stream type whose minimum volume index is returned. 958 * @return The minimum valid volume index for the stream. 959 * @see #getStreamVolume(int) 960 */ getStreamMinVolumeInt(int streamType)961 public int getStreamMinVolumeInt(int streamType) { 962 final IAudioService service = getService(); 963 try { 964 return service.getStreamMinVolume(streamType); 965 } catch (RemoteException e) { 966 throw e.rethrowFromSystemServer(); 967 } 968 } 969 970 /** 971 * Returns the current volume index for a particular stream. 972 * 973 * @param streamType The stream type whose volume index is returned. 974 * @return The current volume index for the stream. 975 * @see #getStreamMaxVolume(int) 976 * @see #setStreamVolume(int, int, int) 977 */ getStreamVolume(int streamType)978 public int getStreamVolume(int streamType) { 979 final IAudioService service = getService(); 980 try { 981 return service.getStreamVolume(streamType); 982 } catch (RemoteException e) { 983 throw e.rethrowFromSystemServer(); 984 } 985 } 986 987 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h 988 private static final float VOLUME_MIN_DB = -758.0f; 989 990 /** @hide */ 991 @IntDef(flag = false, prefix = "STREAM", value = { 992 STREAM_VOICE_CALL, 993 STREAM_SYSTEM, 994 STREAM_RING, 995 STREAM_MUSIC, 996 STREAM_ALARM, 997 STREAM_NOTIFICATION, 998 STREAM_DTMF, 999 STREAM_ACCESSIBILITY } 1000 ) 1001 @Retention(RetentionPolicy.SOURCE) 1002 public @interface PublicStreamTypes {} 1003 1004 /** 1005 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on 1006 * the given type of audio output device. 1007 * @param streamType stream type for which the volume is queried. 1008 * @param index the volume index for which the volume is queried. The index value must be 1009 * between the minimum and maximum index values for the given stream type (see 1010 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}). 1011 * @param deviceType the type of audio output device for which volume is queried. 1012 * @return a volume expressed in dB. 1013 * A negative value indicates the audio signal is attenuated. A typical maximum value 1014 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is 1015 * reflected by a value of {@link Float#NEGATIVE_INFINITY}. 1016 */ getStreamVolumeDb(@ublicStreamTypes int streamType, int index, @AudioDeviceInfo.AudioDeviceTypeOut int deviceType)1017 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index, 1018 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { 1019 if (!isPublicStreamType(streamType)) { 1020 throw new IllegalArgumentException("Invalid stream type " + streamType); 1021 } 1022 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) { 1023 throw new IllegalArgumentException("Invalid stream volume index " + index); 1024 } 1025 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) { 1026 throw new IllegalArgumentException("Invalid audio output device type " + deviceType); 1027 } 1028 final float gain = AudioSystem.getStreamVolumeDB(streamType, index, 1029 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType)); 1030 if (gain <= VOLUME_MIN_DB) { 1031 return Float.NEGATIVE_INFINITY; 1032 } else { 1033 return gain; 1034 } 1035 } 1036 isPublicStreamType(int streamType)1037 private static boolean isPublicStreamType(int streamType) { 1038 switch (streamType) { 1039 case STREAM_VOICE_CALL: 1040 case STREAM_SYSTEM: 1041 case STREAM_RING: 1042 case STREAM_MUSIC: 1043 case STREAM_ALARM: 1044 case STREAM_NOTIFICATION: 1045 case STREAM_DTMF: 1046 case STREAM_ACCESSIBILITY: 1047 return true; 1048 default: 1049 return false; 1050 } 1051 } 1052 1053 /** 1054 * Get last audible volume before stream was muted. 1055 * 1056 * @hide 1057 */ getLastAudibleStreamVolume(int streamType)1058 public int getLastAudibleStreamVolume(int streamType) { 1059 final IAudioService service = getService(); 1060 try { 1061 return service.getLastAudibleStreamVolume(streamType); 1062 } catch (RemoteException e) { 1063 throw e.rethrowFromSystemServer(); 1064 } 1065 } 1066 1067 /** 1068 * Get the stream type whose volume is driving the UI sounds volume. 1069 * UI sounds are screen lock/unlock, camera shutter, key clicks... 1070 * It is assumed that this stream type is also tied to ringer mode changes. 1071 * @hide 1072 */ getUiSoundsStreamType()1073 public int getUiSoundsStreamType() { 1074 final IAudioService service = getService(); 1075 try { 1076 return service.getUiSoundsStreamType(); 1077 } catch (RemoteException e) { 1078 throw e.rethrowFromSystemServer(); 1079 } 1080 } 1081 1082 /** 1083 * Sets the ringer mode. 1084 * <p> 1085 * Silent mode will mute the volume and will not vibrate. Vibrate mode will 1086 * mute the volume and vibrate. Normal mode will be audible and may vibrate 1087 * according to user settings. 1088 * <p>This method has no effect if the device implements a fixed volume policy 1089 * as indicated by {@link #isVolumeFixed()}. 1090 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 1091 * unless the app has been granted Do Not Disturb Access. 1092 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1093 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL}, 1094 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. 1095 * @see #getRingerMode() 1096 * @see #isVolumeFixed() 1097 */ setRingerMode(int ringerMode)1098 public void setRingerMode(int ringerMode) { 1099 if (!isValidRingerMode(ringerMode)) { 1100 return; 1101 } 1102 final IAudioService service = getService(); 1103 try { 1104 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName()); 1105 } catch (RemoteException e) { 1106 throw e.rethrowFromSystemServer(); 1107 } 1108 } 1109 1110 /** 1111 * Sets the volume index for a particular stream. 1112 * <p>This method has no effect if the device implements a fixed volume policy 1113 * as indicated by {@link #isVolumeFixed()}. 1114 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless 1115 * the app has been granted Do Not Disturb Access. 1116 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1117 * @param streamType The stream whose volume index should be set. 1118 * @param index The volume index to set. See 1119 * {@link #getStreamMaxVolume(int)} for the largest valid value. 1120 * @param flags One or more flags. 1121 * @see #getStreamMaxVolume(int) 1122 * @see #getStreamVolume(int) 1123 * @see #isVolumeFixed() 1124 */ setStreamVolume(int streamType, int index, int flags)1125 public void setStreamVolume(int streamType, int index, int flags) { 1126 final IAudioService service = getService(); 1127 try { 1128 service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName()); 1129 } catch (RemoteException e) { 1130 throw e.rethrowFromSystemServer(); 1131 } 1132 } 1133 1134 /** 1135 * Solo or unsolo a particular stream. 1136 * <p> 1137 * Do not use. This method has been deprecated and is now a no-op. 1138 * {@link #requestAudioFocus} should be used for exclusive audio playback. 1139 * 1140 * @param streamType The stream to be soloed/unsoloed. 1141 * @param state The required solo state: true for solo ON, false for solo 1142 * OFF 1143 * @see #isVolumeFixed() 1144 * @deprecated Do not use. If you need exclusive audio playback use 1145 * {@link #requestAudioFocus}. 1146 */ 1147 @Deprecated setStreamSolo(int streamType, boolean state)1148 public void setStreamSolo(int streamType, boolean state) { 1149 Log.w(TAG, "setStreamSolo has been deprecated. Do not use."); 1150 } 1151 1152 /** 1153 * Mute or unmute an audio stream. 1154 * <p> 1155 * This method should only be used by applications that replace the 1156 * platform-wide management of audio settings or the main telephony 1157 * application. 1158 * <p> 1159 * This method has no effect if the device implements a fixed volume policy 1160 * as indicated by {@link #isVolumeFixed()}. 1161 * <p> 1162 * This method was deprecated in API level 22. Prior to API level 22 this 1163 * method had significantly different behavior and should be used carefully. 1164 * The following applies only to pre-22 platforms: 1165 * <ul> 1166 * <li>The mute command is protected against client process death: if a 1167 * process with an active mute request on a stream dies, this stream will be 1168 * unmuted automatically.</li> 1169 * <li>The mute requests for a given stream are cumulative: the AudioManager 1170 * can receive several mute requests from one or more clients and the stream 1171 * will be unmuted only when the same number of unmute requests are 1172 * received.</li> 1173 * <li>For a better user experience, applications MUST unmute a muted stream 1174 * in onPause() and mute is again in onResume() if appropriate.</li> 1175 * </ul> 1176 * 1177 * @param streamType The stream to be muted/unmuted. 1178 * @param state The required mute state: true for mute ON, false for mute 1179 * OFF 1180 * @see #isVolumeFixed() 1181 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with 1182 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead. 1183 */ 1184 @Deprecated setStreamMute(int streamType, boolean state)1185 public void setStreamMute(int streamType, boolean state) { 1186 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead."); 1187 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE; 1188 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 1189 adjustSuggestedStreamVolume(direction, streamType, 0); 1190 } else { 1191 adjustStreamVolume(streamType, direction, 0); 1192 } 1193 } 1194 1195 /** 1196 * Returns the current mute state for a particular stream. 1197 * 1198 * @param streamType The stream to get mute state for. 1199 * @return The mute state for the given stream. 1200 * @see #adjustStreamVolume(int, int, int) 1201 */ isStreamMute(int streamType)1202 public boolean isStreamMute(int streamType) { 1203 final IAudioService service = getService(); 1204 try { 1205 return service.isStreamMute(streamType); 1206 } catch (RemoteException e) { 1207 throw e.rethrowFromSystemServer(); 1208 } 1209 } 1210 1211 /** 1212 * get master mute state. 1213 * 1214 * @hide 1215 */ isMasterMute()1216 public boolean isMasterMute() { 1217 final IAudioService service = getService(); 1218 try { 1219 return service.isMasterMute(); 1220 } catch (RemoteException e) { 1221 throw e.rethrowFromSystemServer(); 1222 } 1223 } 1224 1225 /** 1226 * forces the stream controlled by hard volume keys 1227 * specifying streamType == -1 releases control to the 1228 * logic. 1229 * 1230 * @hide 1231 */ forceVolumeControlStream(int streamType)1232 public void forceVolumeControlStream(int streamType) { 1233 final IAudioService service = getService(); 1234 try { 1235 service.forceVolumeControlStream(streamType, mICallBack); 1236 } catch (RemoteException e) { 1237 throw e.rethrowFromSystemServer(); 1238 } 1239 } 1240 1241 /** 1242 * Returns whether a particular type should vibrate according to user 1243 * settings and the current ringer mode. 1244 * <p> 1245 * This shouldn't be needed by most clients that use notifications to 1246 * vibrate. The notification manager will not vibrate if the policy doesn't 1247 * allow it, so the client should always set a vibrate pattern and let the 1248 * notification manager control whether or not to actually vibrate. 1249 * 1250 * @param vibrateType The type of vibrate. One of 1251 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1252 * {@link #VIBRATE_TYPE_RINGER}. 1253 * @return Whether the type should vibrate at the instant this method is 1254 * called. 1255 * @see #setVibrateSetting(int, int) 1256 * @see #getVibrateSetting(int) 1257 * @deprecated Applications should maintain their own vibrate policy based on 1258 * current ringer mode that can be queried via {@link #getRingerMode()}. 1259 */ shouldVibrate(int vibrateType)1260 public boolean shouldVibrate(int vibrateType) { 1261 final IAudioService service = getService(); 1262 try { 1263 return service.shouldVibrate(vibrateType); 1264 } catch (RemoteException e) { 1265 throw e.rethrowFromSystemServer(); 1266 } 1267 } 1268 1269 /** 1270 * Returns whether the user's vibrate setting for a vibrate type. 1271 * <p> 1272 * This shouldn't be needed by most clients that want to vibrate, instead 1273 * see {@link #shouldVibrate(int)}. 1274 * 1275 * @param vibrateType The type of vibrate. One of 1276 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1277 * {@link #VIBRATE_TYPE_RINGER}. 1278 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON}, 1279 * {@link #VIBRATE_SETTING_OFF}, or 1280 * {@link #VIBRATE_SETTING_ONLY_SILENT}. 1281 * @see #setVibrateSetting(int, int) 1282 * @see #shouldVibrate(int) 1283 * @deprecated Applications should maintain their own vibrate policy based on 1284 * current ringer mode that can be queried via {@link #getRingerMode()}. 1285 */ getVibrateSetting(int vibrateType)1286 public int getVibrateSetting(int vibrateType) { 1287 final IAudioService service = getService(); 1288 try { 1289 return service.getVibrateSetting(vibrateType); 1290 } catch (RemoteException e) { 1291 throw e.rethrowFromSystemServer(); 1292 } 1293 } 1294 1295 /** 1296 * Sets the setting for when the vibrate type should vibrate. 1297 * <p> 1298 * This method should only be used by applications that replace the platform-wide 1299 * management of audio settings or the main telephony application. 1300 * 1301 * @param vibrateType The type of vibrate. One of 1302 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1303 * {@link #VIBRATE_TYPE_RINGER}. 1304 * @param vibrateSetting The vibrate setting, one of 1305 * {@link #VIBRATE_SETTING_ON}, 1306 * {@link #VIBRATE_SETTING_OFF}, or 1307 * {@link #VIBRATE_SETTING_ONLY_SILENT}. 1308 * @see #getVibrateSetting(int) 1309 * @see #shouldVibrate(int) 1310 * @deprecated Applications should maintain their own vibrate policy based on 1311 * current ringer mode that can be queried via {@link #getRingerMode()}. 1312 */ setVibrateSetting(int vibrateType, int vibrateSetting)1313 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 1314 final IAudioService service = getService(); 1315 try { 1316 service.setVibrateSetting(vibrateType, vibrateSetting); 1317 } catch (RemoteException e) { 1318 throw e.rethrowFromSystemServer(); 1319 } 1320 } 1321 1322 /** 1323 * Sets the speakerphone on or off. 1324 * <p> 1325 * This method should only be used by applications that replace the platform-wide 1326 * management of audio settings or the main telephony application. 1327 * 1328 * @param on set <var>true</var> to turn on speakerphone; 1329 * <var>false</var> to turn it off 1330 */ setSpeakerphoneOn(boolean on)1331 public void setSpeakerphoneOn(boolean on){ 1332 final IAudioService service = getService(); 1333 try { 1334 service.setSpeakerphoneOn(on); 1335 } catch (RemoteException e) { 1336 throw e.rethrowFromSystemServer(); 1337 } 1338 } 1339 1340 /** 1341 * Checks whether the speakerphone is on or off. 1342 * 1343 * @return true if speakerphone is on, false if it's off 1344 */ isSpeakerphoneOn()1345 public boolean isSpeakerphoneOn() { 1346 final IAudioService service = getService(); 1347 try { 1348 return service.isSpeakerphoneOn(); 1349 } catch (RemoteException e) { 1350 throw e.rethrowFromSystemServer(); 1351 } 1352 } 1353 1354 //==================================================================== 1355 // Offload query 1356 /** 1357 * @hide 1358 * Returns whether offloaded playback of an audio format is supported on the device. 1359 * Offloaded playback is where the decoding of an audio stream is not competing with other 1360 * software resources. In general, it is supported by dedicated hardware, such as audio DSPs. 1361 * @param format the audio format (codec, sample rate, channels) being checked. 1362 * @return true if the given audio format can be offloaded. 1363 */ isOffloadedPlaybackSupported(@onNull AudioFormat format)1364 public boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format) { 1365 return AudioSystem.isOffloadSupported(format); 1366 } 1367 1368 //==================================================================== 1369 // Bluetooth SCO control 1370 /** 1371 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 1372 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE} 1373 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED} 1374 * or {@link #SCO_AUDIO_STATE_CONNECTED} 1375 * 1376 * @see #startBluetoothSco() 1377 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead 1378 */ 1379 @Deprecated 1380 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1381 public static final String ACTION_SCO_AUDIO_STATE_CHANGED = 1382 "android.media.SCO_AUDIO_STATE_CHANGED"; 1383 1384 /** 1385 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 1386 * connection state has been updated. 1387 * <p>This intent has two extras: 1388 * <ul> 1389 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li> 1390 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li> 1391 * </ul> 1392 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of: 1393 * <ul> 1394 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li> 1395 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li> 1396 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li> 1397 * </ul> 1398 * @see #startBluetoothSco() 1399 */ 1400 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1401 public static final String ACTION_SCO_AUDIO_STATE_UPDATED = 1402 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED"; 1403 1404 /** 1405 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or 1406 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state. 1407 */ 1408 public static final String EXTRA_SCO_AUDIO_STATE = 1409 "android.media.extra.SCO_AUDIO_STATE"; 1410 1411 /** 1412 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous 1413 * bluetooth SCO connection state. 1414 */ 1415 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE = 1416 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"; 1417 1418 /** 1419 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 1420 * indicating that the SCO audio channel is not established 1421 */ 1422 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; 1423 /** 1424 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE} 1425 * indicating that the SCO audio channel is established 1426 */ 1427 public static final int SCO_AUDIO_STATE_CONNECTED = 1; 1428 /** 1429 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 1430 * indicating that the SCO audio channel is being established 1431 */ 1432 public static final int SCO_AUDIO_STATE_CONNECTING = 2; 1433 /** 1434 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that 1435 * there was an error trying to obtain the state 1436 */ 1437 public static final int SCO_AUDIO_STATE_ERROR = -1; 1438 1439 1440 /** 1441 * Indicates if current platform supports use of SCO for off call use cases. 1442 * Application wanted to use bluetooth SCO audio when the phone is not in call 1443 * must first call this method to make sure that the platform supports this 1444 * feature. 1445 * @return true if bluetooth SCO can be used for audio when not in call 1446 * false otherwise 1447 * @see #startBluetoothSco() 1448 */ isBluetoothScoAvailableOffCall()1449 public boolean isBluetoothScoAvailableOffCall() { 1450 return getContext().getResources().getBoolean( 1451 com.android.internal.R.bool.config_bluetooth_sco_off_call); 1452 } 1453 1454 /** 1455 * Start bluetooth SCO audio connection. 1456 * <p>Requires Permission: 1457 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 1458 * <p>This method can be used by applications wanting to send and received audio 1459 * to/from a bluetooth SCO headset while the phone is not in call. 1460 * <p>As the SCO connection establishment can take several seconds, 1461 * applications should not rely on the connection to be available when the method 1462 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} 1463 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}. 1464 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO 1465 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver 1466 * registration. If the state is already CONNECTED, no state change will be received via the 1467 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco() 1468 * so that the connection stays active in case the current initiator stops the connection. 1469 * <p>Unless the connection is already active as described above, the state will always 1470 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection 1471 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected). 1472 * <p>When finished with the SCO connection or if the establishment fails, the application must 1473 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection. 1474 * <p>Even if a SCO connection is established, the following restrictions apply on audio 1475 * output streams so that they can be routed to SCO headset: 1476 * <ul> 1477 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li> 1478 * <li> the format must be mono </li> 1479 * <li> the sampling must be 16kHz or 8kHz </li> 1480 * </ul> 1481 * <p>The following restrictions apply on input streams: 1482 * <ul> 1483 * <li> the format must be mono </li> 1484 * <li> the sampling must be 8kHz </li> 1485 * </ul> 1486 * <p>Note that the phone application always has the priority on the usage of the SCO 1487 * connection for telephony. If this method is called while the phone is in call 1488 * it will be ignored. Similarly, if a call is received or sent while an application 1489 * is using the SCO connection, the connection will be lost for the application and NOT 1490 * returned automatically when the call ends. 1491 * <p>NOTE: up to and including API version 1492 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual 1493 * voice call to the bluetooth headset. 1494 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio 1495 * connection is established. 1496 * @see #stopBluetoothSco() 1497 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 1498 */ startBluetoothSco()1499 public void startBluetoothSco(){ 1500 final IAudioService service = getService(); 1501 try { 1502 service.startBluetoothSco(mICallBack, 1503 getContext().getApplicationInfo().targetSdkVersion); 1504 } catch (RemoteException e) { 1505 throw e.rethrowFromSystemServer(); 1506 } 1507 } 1508 1509 /** 1510 * @hide 1511 * Start bluetooth SCO audio connection in virtual call mode. 1512 * <p>Requires Permission: 1513 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 1514 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode. 1515 * Telephony and communication applications (VoIP, Video Chat) should preferably select 1516 * virtual call mode. 1517 * Applications using voice input for search or commands should first try raw audio connection 1518 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of 1519 * failure. 1520 * @see #startBluetoothSco() 1521 * @see #stopBluetoothSco() 1522 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 1523 */ startBluetoothScoVirtualCall()1524 public void startBluetoothScoVirtualCall() { 1525 final IAudioService service = getService(); 1526 try { 1527 service.startBluetoothScoVirtualCall(mICallBack); 1528 } catch (RemoteException e) { 1529 throw e.rethrowFromSystemServer(); 1530 } 1531 } 1532 1533 /** 1534 * Stop bluetooth SCO audio connection. 1535 * <p>Requires Permission: 1536 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 1537 * <p>This method must be called by applications having requested the use of 1538 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO 1539 * connection or if connection fails. 1540 * @see #startBluetoothSco() 1541 */ 1542 // Also used for connections started with {@link #startBluetoothScoVirtualCall()} stopBluetoothSco()1543 public void stopBluetoothSco(){ 1544 final IAudioService service = getService(); 1545 try { 1546 service.stopBluetoothSco(mICallBack); 1547 } catch (RemoteException e) { 1548 throw e.rethrowFromSystemServer(); 1549 } 1550 } 1551 1552 /** 1553 * Request use of Bluetooth SCO headset for communications. 1554 * <p> 1555 * This method should only be used by applications that replace the platform-wide 1556 * management of audio settings or the main telephony application. 1557 * 1558 * @param on set <var>true</var> to use bluetooth SCO for communications; 1559 * <var>false</var> to not use bluetooth SCO for communications 1560 */ setBluetoothScoOn(boolean on)1561 public void setBluetoothScoOn(boolean on){ 1562 final IAudioService service = getService(); 1563 try { 1564 service.setBluetoothScoOn(on); 1565 } catch (RemoteException e) { 1566 throw e.rethrowFromSystemServer(); 1567 } 1568 } 1569 1570 /** 1571 * Checks whether communications use Bluetooth SCO. 1572 * 1573 * @return true if SCO is used for communications; 1574 * false if otherwise 1575 */ isBluetoothScoOn()1576 public boolean isBluetoothScoOn() { 1577 final IAudioService service = getService(); 1578 try { 1579 return service.isBluetoothScoOn(); 1580 } catch (RemoteException e) { 1581 throw e.rethrowFromSystemServer(); 1582 } 1583 } 1584 1585 /** 1586 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth 1587 * headset; <var>false</var> disable A2DP audio 1588 * @deprecated Do not use. 1589 */ setBluetoothA2dpOn(boolean on)1590 @Deprecated public void setBluetoothA2dpOn(boolean on){ 1591 } 1592 1593 /** 1594 * Checks whether a Bluetooth A2DP audio peripheral is connected or not. 1595 * 1596 * @return true if a Bluetooth A2DP peripheral is connected 1597 * false if otherwise 1598 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 1599 */ isBluetoothA2dpOn()1600 public boolean isBluetoothA2dpOn() { 1601 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"") 1602 == AudioSystem.DEVICE_STATE_AVAILABLE) { 1603 return true; 1604 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"") 1605 == AudioSystem.DEVICE_STATE_AVAILABLE) { 1606 return true; 1607 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"") 1608 == AudioSystem.DEVICE_STATE_AVAILABLE) { 1609 return true; 1610 } 1611 return false; 1612 } 1613 1614 /** 1615 * Sets audio routing to the wired headset on or off. 1616 * 1617 * @param on set <var>true</var> to route audio to/from wired 1618 * headset; <var>false</var> disable wired headset audio 1619 * @deprecated Do not use. 1620 */ setWiredHeadsetOn(boolean on)1621 @Deprecated public void setWiredHeadsetOn(boolean on){ 1622 } 1623 1624 /** 1625 * Checks whether a wired headset is connected or not. 1626 * <p>This is not a valid indication that audio playback is 1627 * actually over the wired headset as audio routing depends on other conditions. 1628 * 1629 * @return true if a wired headset is connected. 1630 * false if otherwise 1631 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 1632 */ isWiredHeadsetOn()1633 public boolean isWiredHeadsetOn() { 1634 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"") 1635 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 1636 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"") 1637 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 1638 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "") 1639 == AudioSystem.DEVICE_STATE_UNAVAILABLE) { 1640 return false; 1641 } else { 1642 return true; 1643 } 1644 } 1645 1646 /** 1647 * Sets the microphone mute on or off. 1648 * <p> 1649 * This method should only be used by applications that replace the platform-wide 1650 * management of audio settings or the main telephony application. 1651 * 1652 * @param on set <var>true</var> to mute the microphone; 1653 * <var>false</var> to turn mute off 1654 */ setMicrophoneMute(boolean on)1655 public void setMicrophoneMute(boolean on) { 1656 final IAudioService service = getService(); 1657 try { 1658 service.setMicrophoneMute(on, getContext().getOpPackageName(), 1659 UserHandle.getCallingUserId()); 1660 } catch (RemoteException e) { 1661 throw e.rethrowFromSystemServer(); 1662 } 1663 } 1664 1665 /** 1666 * Checks whether the microphone mute is on or off. 1667 * 1668 * @return true if microphone is muted, false if it's not 1669 */ isMicrophoneMute()1670 public boolean isMicrophoneMute() { 1671 return AudioSystem.isMicrophoneMuted(); 1672 } 1673 1674 /** 1675 * Broadcast Action: microphone muting state changed. 1676 * 1677 * You <em>cannot</em> receive this through components declared 1678 * in manifests, only by explicitly registering for it with 1679 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 1680 * Context.registerReceiver()}. 1681 * 1682 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the 1683 * microphone is muted. 1684 */ 1685 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1686 public static final String ACTION_MICROPHONE_MUTE_CHANGED = 1687 "android.media.action.MICROPHONE_MUTE_CHANGED"; 1688 1689 /** 1690 * Sets the audio mode. 1691 * <p> 1692 * The audio mode encompasses audio routing AND the behavior of 1693 * the telephony layer. Therefore this method should only be used by applications that 1694 * replace the platform-wide management of audio settings or the main telephony application. 1695 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony 1696 * application when it places a phone call, as it will cause signals from the radio layer 1697 * to feed the platform mixer. 1698 * 1699 * @param mode the requested audio mode ({@link #MODE_NORMAL}, {@link #MODE_RINGTONE}, 1700 * {@link #MODE_IN_CALL} or {@link #MODE_IN_COMMUNICATION}). 1701 * Informs the HAL about the current audio state so that 1702 * it can route the audio appropriately. 1703 */ setMode(int mode)1704 public void setMode(int mode) { 1705 final IAudioService service = getService(); 1706 try { 1707 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName()); 1708 } catch (RemoteException e) { 1709 throw e.rethrowFromSystemServer(); 1710 } 1711 } 1712 1713 /** 1714 * Returns the current audio mode. 1715 * 1716 * @return the current audio mode ({@link #MODE_NORMAL}, {@link #MODE_RINGTONE}, 1717 * {@link #MODE_IN_CALL} or {@link #MODE_IN_COMMUNICATION}). 1718 * Returns the current current audio state from the HAL. 1719 */ getMode()1720 public int getMode() { 1721 final IAudioService service = getService(); 1722 try { 1723 return service.getMode(); 1724 } catch (RemoteException e) { 1725 throw e.rethrowFromSystemServer(); 1726 } 1727 } 1728 1729 /* modes for setMode/getMode/setRoute/getRoute */ 1730 /** 1731 * Audio harware modes. 1732 */ 1733 /** 1734 * Invalid audio mode. 1735 */ 1736 public static final int MODE_INVALID = AudioSystem.MODE_INVALID; 1737 /** 1738 * Current audio mode. Used to apply audio routing to current mode. 1739 */ 1740 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT; 1741 /** 1742 * Normal audio mode: not ringing and no call established. 1743 */ 1744 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL; 1745 /** 1746 * Ringing audio mode. An incoming is being signaled. 1747 */ 1748 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE; 1749 /** 1750 * In call audio mode. A telephony call is established. 1751 */ 1752 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL; 1753 /** 1754 * In communication audio mode. An audio/video chat or VoIP call is established. 1755 */ 1756 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION; 1757 1758 /* Routing bits for setRouting/getRouting API */ 1759 /** 1760 * Routing audio output to earpiece 1761 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 1762 * setBluetoothScoOn() methods instead. 1763 */ 1764 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; 1765 /** 1766 * Routing audio output to speaker 1767 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 1768 * setBluetoothScoOn() methods instead. 1769 */ 1770 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; 1771 /** 1772 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO} 1773 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 1774 * setBluetoothScoOn() methods instead. 1775 */ 1776 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO; 1777 /** 1778 * Routing audio output to bluetooth SCO 1779 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 1780 * setBluetoothScoOn() methods instead. 1781 */ 1782 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO; 1783 /** 1784 * Routing audio output to headset 1785 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 1786 * setBluetoothScoOn() methods instead. 1787 */ 1788 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; 1789 /** 1790 * Routing audio output to bluetooth A2DP 1791 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 1792 * setBluetoothScoOn() methods instead. 1793 */ 1794 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP; 1795 /** 1796 * Used for mask parameter of {@link #setRouting(int,int,int)}. 1797 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 1798 * setBluetoothScoOn() methods instead. 1799 */ 1800 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; 1801 1802 /** 1803 * Sets the audio routing for a specified mode 1804 * 1805 * @param mode audio mode to change route. E.g., MODE_RINGTONE. 1806 * @param routes bit vector of routes requested, created from one or 1807 * more of ROUTE_xxx types. Set bits indicate that route should be on 1808 * @param mask bit vector of routes to change, created from one or more of 1809 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged 1810 * 1811 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 1812 * setBluetoothScoOn() methods instead. 1813 */ 1814 @Deprecated setRouting(int mode, int routes, int mask)1815 public void setRouting(int mode, int routes, int mask) { 1816 } 1817 1818 /** 1819 * Returns the current audio routing bit vector for a specified mode. 1820 * 1821 * @param mode audio mode to get route (e.g., MODE_RINGTONE) 1822 * @return an audio route bit vector that can be compared with ROUTE_xxx 1823 * bits 1824 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(), 1825 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead. 1826 */ 1827 @Deprecated getRouting(int mode)1828 public int getRouting(int mode) { 1829 return -1; 1830 } 1831 1832 /** 1833 * Checks whether any music is active. 1834 * 1835 * @return true if any music tracks are active. 1836 */ isMusicActive()1837 public boolean isMusicActive() { 1838 return AudioSystem.isStreamActive(STREAM_MUSIC, 0); 1839 } 1840 1841 /** 1842 * @hide 1843 * Checks whether any music or media is actively playing on a remote device (e.g. wireless 1844 * display). Note that BT audio sinks are not considered remote devices. 1845 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device 1846 */ isMusicActiveRemotely()1847 public boolean isMusicActiveRemotely() { 1848 return AudioSystem.isStreamActiveRemotely(STREAM_MUSIC, 0); 1849 } 1850 1851 /** 1852 * @hide 1853 * Checks whether the current audio focus is exclusive. 1854 * @return true if the top of the audio focus stack requested focus 1855 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} 1856 */ isAudioFocusExclusive()1857 public boolean isAudioFocusExclusive() { 1858 final IAudioService service = getService(); 1859 try { 1860 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE; 1861 } catch (RemoteException e) { 1862 throw e.rethrowFromSystemServer(); 1863 } 1864 } 1865 1866 /** 1867 * Return a new audio session identifier not associated with any player or effect. 1868 * An audio session identifier is a system wide unique identifier for a set of audio streams 1869 * (one or more mixed together). 1870 * <p>The primary use of the audio session ID is to associate audio effects to audio players, 1871 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio 1872 * session ID will be applied to the mixed audio content of the players that share the same 1873 * audio session. 1874 * <p>This method can for instance be used when creating one of the 1875 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect, 1876 * or to specify a session for a speech synthesis utterance 1877 * in {@link android.speech.tts.TextToSpeech.Engine}. 1878 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the 1879 * system failed to generate a new session, a condition in which audio playback or recording 1880 * will subsequently fail as well. 1881 */ generateAudioSessionId()1882 public int generateAudioSessionId() { 1883 int session = AudioSystem.newAudioSessionId(); 1884 if (session > 0) { 1885 return session; 1886 } else { 1887 Log.e(TAG, "Failure to generate a new audio session ID"); 1888 return ERROR; 1889 } 1890 } 1891 1892 /** 1893 * A special audio session ID to indicate that the audio session ID isn't known and the 1894 * framework should generate a new value. This can be used when building a new 1895 * {@link AudioTrack} instance with 1896 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}. 1897 */ 1898 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE; 1899 1900 1901 /* 1902 * Sets a generic audio configuration parameter. The use of these parameters 1903 * are platform dependant, see libaudio 1904 * 1905 * ** Temporary interface - DO NOT USE 1906 * 1907 * TODO: Replace with a more generic key:value get/set mechanism 1908 * 1909 * param key name of parameter to set. Must not be null. 1910 * param value value of parameter. Must not be null. 1911 */ 1912 /** 1913 * @hide 1914 * @deprecated Use {@link #setParameters(String)} instead 1915 */ setParameter(String key, String value)1916 @Deprecated public void setParameter(String key, String value) { 1917 setParameters(key+"="+value); 1918 } 1919 1920 /** 1921 * Sets a variable number of parameter values to audio hardware. 1922 * 1923 * @param keyValuePairs list of parameters key value pairs in the form: 1924 * key1=value1;key2=value2;... 1925 * 1926 */ setParameters(String keyValuePairs)1927 public void setParameters(String keyValuePairs) { 1928 AudioSystem.setParameters(keyValuePairs); 1929 } 1930 1931 /** 1932 * Gets a variable number of parameter values from audio hardware. 1933 * 1934 * @param keys list of parameters 1935 * @return list of parameters key value pairs in the form: 1936 * key1=value1;key2=value2;... 1937 */ getParameters(String keys)1938 public String getParameters(String keys) { 1939 return AudioSystem.getParameters(keys); 1940 } 1941 1942 /* Sound effect identifiers */ 1943 /** 1944 * Keyboard and direction pad click sound 1945 * @see #playSoundEffect(int) 1946 */ 1947 public static final int FX_KEY_CLICK = 0; 1948 /** 1949 * Focus has moved up 1950 * @see #playSoundEffect(int) 1951 */ 1952 public static final int FX_FOCUS_NAVIGATION_UP = 1; 1953 /** 1954 * Focus has moved down 1955 * @see #playSoundEffect(int) 1956 */ 1957 public static final int FX_FOCUS_NAVIGATION_DOWN = 2; 1958 /** 1959 * Focus has moved left 1960 * @see #playSoundEffect(int) 1961 */ 1962 public static final int FX_FOCUS_NAVIGATION_LEFT = 3; 1963 /** 1964 * Focus has moved right 1965 * @see #playSoundEffect(int) 1966 */ 1967 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; 1968 /** 1969 * IME standard keypress sound 1970 * @see #playSoundEffect(int) 1971 */ 1972 public static final int FX_KEYPRESS_STANDARD = 5; 1973 /** 1974 * IME spacebar keypress sound 1975 * @see #playSoundEffect(int) 1976 */ 1977 public static final int FX_KEYPRESS_SPACEBAR = 6; 1978 /** 1979 * IME delete keypress sound 1980 * @see #playSoundEffect(int) 1981 */ 1982 public static final int FX_KEYPRESS_DELETE = 7; 1983 /** 1984 * IME return_keypress sound 1985 * @see #playSoundEffect(int) 1986 */ 1987 public static final int FX_KEYPRESS_RETURN = 8; 1988 1989 /** 1990 * Invalid keypress sound 1991 * @see #playSoundEffect(int) 1992 */ 1993 public static final int FX_KEYPRESS_INVALID = 9; 1994 /** 1995 * @hide Number of sound effects 1996 */ 1997 public static final int NUM_SOUND_EFFECTS = 10; 1998 1999 /** 2000 * Plays a sound effect (Key clicks, lid open/close...) 2001 * @param effectType The type of sound effect. One of 2002 * {@link #FX_KEY_CLICK}, 2003 * {@link #FX_FOCUS_NAVIGATION_UP}, 2004 * {@link #FX_FOCUS_NAVIGATION_DOWN}, 2005 * {@link #FX_FOCUS_NAVIGATION_LEFT}, 2006 * {@link #FX_FOCUS_NAVIGATION_RIGHT}, 2007 * {@link #FX_KEYPRESS_STANDARD}, 2008 * {@link #FX_KEYPRESS_SPACEBAR}, 2009 * {@link #FX_KEYPRESS_DELETE}, 2010 * {@link #FX_KEYPRESS_RETURN}, 2011 * {@link #FX_KEYPRESS_INVALID}, 2012 * NOTE: This version uses the UI settings to determine 2013 * whether sounds are heard or not. 2014 */ playSoundEffect(int effectType)2015 public void playSoundEffect(int effectType) { 2016 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 2017 return; 2018 } 2019 2020 if (!querySoundEffectsEnabled(Process.myUserHandle().getIdentifier())) { 2021 return; 2022 } 2023 2024 final IAudioService service = getService(); 2025 try { 2026 service.playSoundEffect(effectType); 2027 } catch (RemoteException e) { 2028 throw e.rethrowFromSystemServer(); 2029 } 2030 } 2031 2032 /** 2033 * Plays a sound effect (Key clicks, lid open/close...) 2034 * @param effectType The type of sound effect. One of 2035 * {@link #FX_KEY_CLICK}, 2036 * {@link #FX_FOCUS_NAVIGATION_UP}, 2037 * {@link #FX_FOCUS_NAVIGATION_DOWN}, 2038 * {@link #FX_FOCUS_NAVIGATION_LEFT}, 2039 * {@link #FX_FOCUS_NAVIGATION_RIGHT}, 2040 * {@link #FX_KEYPRESS_STANDARD}, 2041 * {@link #FX_KEYPRESS_SPACEBAR}, 2042 * {@link #FX_KEYPRESS_DELETE}, 2043 * {@link #FX_KEYPRESS_RETURN}, 2044 * {@link #FX_KEYPRESS_INVALID}, 2045 * @param userId The current user to pull sound settings from 2046 * NOTE: This version uses the UI settings to determine 2047 * whether sounds are heard or not. 2048 * @hide 2049 */ playSoundEffect(int effectType, int userId)2050 public void playSoundEffect(int effectType, int userId) { 2051 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 2052 return; 2053 } 2054 2055 if (!querySoundEffectsEnabled(userId)) { 2056 return; 2057 } 2058 2059 final IAudioService service = getService(); 2060 try { 2061 service.playSoundEffect(effectType); 2062 } catch (RemoteException e) { 2063 throw e.rethrowFromSystemServer(); 2064 } 2065 } 2066 2067 /** 2068 * Plays a sound effect (Key clicks, lid open/close...) 2069 * @param effectType The type of sound effect. One of 2070 * {@link #FX_KEY_CLICK}, 2071 * {@link #FX_FOCUS_NAVIGATION_UP}, 2072 * {@link #FX_FOCUS_NAVIGATION_DOWN}, 2073 * {@link #FX_FOCUS_NAVIGATION_LEFT}, 2074 * {@link #FX_FOCUS_NAVIGATION_RIGHT}, 2075 * {@link #FX_KEYPRESS_STANDARD}, 2076 * {@link #FX_KEYPRESS_SPACEBAR}, 2077 * {@link #FX_KEYPRESS_DELETE}, 2078 * {@link #FX_KEYPRESS_RETURN}, 2079 * {@link #FX_KEYPRESS_INVALID}, 2080 * @param volume Sound effect volume. 2081 * The volume value is a raw scalar so UI controls should be scaled logarithmically. 2082 * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used. 2083 * NOTE: This version is for applications that have their own 2084 * settings panel for enabling and controlling volume. 2085 */ playSoundEffect(int effectType, float volume)2086 public void playSoundEffect(int effectType, float volume) { 2087 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 2088 return; 2089 } 2090 2091 final IAudioService service = getService(); 2092 try { 2093 service.playSoundEffectVolume(effectType, volume); 2094 } catch (RemoteException e) { 2095 throw e.rethrowFromSystemServer(); 2096 } 2097 } 2098 2099 /** 2100 * Settings has an in memory cache, so this is fast. 2101 */ querySoundEffectsEnabled(int user)2102 private boolean querySoundEffectsEnabled(int user) { 2103 return Settings.System.getIntForUser(getContext().getContentResolver(), 2104 Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0; 2105 } 2106 2107 /** 2108 * Load Sound effects. 2109 * This method must be called when sound effects are enabled. 2110 */ loadSoundEffects()2111 public void loadSoundEffects() { 2112 final IAudioService service = getService(); 2113 try { 2114 service.loadSoundEffects(); 2115 } catch (RemoteException e) { 2116 throw e.rethrowFromSystemServer(); 2117 } 2118 } 2119 2120 /** 2121 * Unload Sound effects. 2122 * This method can be called to free some memory when 2123 * sound effects are disabled. 2124 */ unloadSoundEffects()2125 public void unloadSoundEffects() { 2126 final IAudioService service = getService(); 2127 try { 2128 service.unloadSoundEffects(); 2129 } catch (RemoteException e) { 2130 throw e.rethrowFromSystemServer(); 2131 } 2132 } 2133 2134 /** 2135 * Used to indicate no audio focus has been gained or lost, or requested. 2136 */ 2137 public static final int AUDIOFOCUS_NONE = 0; 2138 2139 /** 2140 * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration. 2141 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 2142 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 2143 */ 2144 public static final int AUDIOFOCUS_GAIN = 1; 2145 /** 2146 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short 2147 * amount of time. Examples of temporary changes are the playback of driving directions, or an 2148 * event notification. 2149 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 2150 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 2151 */ 2152 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; 2153 /** 2154 * Used to indicate a temporary request of audio focus, anticipated to last a short 2155 * amount of time, and where it is acceptable for other audio applications to keep playing 2156 * after having lowered their output level (also referred to as "ducking"). 2157 * Examples of temporary changes are the playback of driving directions where playback of music 2158 * in the background is acceptable. 2159 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 2160 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 2161 */ 2162 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; 2163 /** 2164 * Used to indicate a temporary request of audio focus, anticipated to last a short 2165 * amount of time, during which no other applications, or system components, should play 2166 * anything. Examples of exclusive and transient audio focus requests are voice 2167 * memo recording and speech recognition, during which the system shouldn't play any 2168 * notifications, and media playback should have paused. 2169 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 2170 */ 2171 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; 2172 /** 2173 * Used to indicate a loss of audio focus of unknown duration. 2174 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 2175 */ 2176 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN; 2177 /** 2178 * Used to indicate a transient loss of audio focus. 2179 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 2180 */ 2181 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT; 2182 /** 2183 * Used to indicate a transient loss of audio focus where the loser of the audio focus can 2184 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as 2185 * the new focus owner doesn't require others to be silent. 2186 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 2187 */ 2188 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = 2189 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; 2190 2191 /** 2192 * Interface definition for a callback to be invoked when the audio focus of the system is 2193 * updated. 2194 */ 2195 public interface OnAudioFocusChangeListener { 2196 /** 2197 * Called on the listener to notify it the audio focus for this listener has been changed. 2198 * The focusChange value indicates whether the focus was gained, 2199 * whether the focus was lost, and whether that loss is transient, or whether the new focus 2200 * holder will hold it for an unknown amount of time. 2201 * When losing focus, listeners can use the focus change information to decide what 2202 * behavior to adopt when losing focus. A music player could for instance elect to lower 2203 * the volume of its music stream (duck) for transient focus losses, and pause otherwise. 2204 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN}, 2205 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT} 2206 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}. 2207 */ onAudioFocusChange(int focusChange)2208 public void onAudioFocusChange(int focusChange); 2209 } 2210 2211 /** 2212 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback 2213 */ 2214 private static class FocusRequestInfo { 2215 @NonNull final AudioFocusRequest mRequest; 2216 @Nullable final Handler mHandler; FocusRequestInfo(@onNull AudioFocusRequest afr, @Nullable Handler handler)2217 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) { 2218 mRequest = afr; 2219 mHandler = handler; 2220 } 2221 } 2222 2223 /** 2224 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack, 2225 * to actual listener objects. 2226 */ 2227 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap = 2228 new ConcurrentHashMap<String, FocusRequestInfo>(); 2229 findFocusRequestInfo(String id)2230 private FocusRequestInfo findFocusRequestInfo(String id) { 2231 return mAudioFocusIdListenerMap.get(id); 2232 } 2233 2234 /** 2235 * Handler for events (audio focus change, recording config change) coming from the 2236 * audio service. 2237 */ 2238 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate = 2239 new ServiceEventHandlerDelegate(null); 2240 2241 /** 2242 * Event types 2243 */ 2244 private final static int MSSG_FOCUS_CHANGE = 0; 2245 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1; 2246 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2; 2247 2248 /** 2249 * Helper class to handle the forwarding of audio service events to the appropriate listener 2250 */ 2251 private class ServiceEventHandlerDelegate { 2252 private final Handler mHandler; 2253 ServiceEventHandlerDelegate(Handler handler)2254 ServiceEventHandlerDelegate(Handler handler) { 2255 Looper looper; 2256 if (handler == null) { 2257 if ((looper = Looper.myLooper()) == null) { 2258 looper = Looper.getMainLooper(); 2259 } 2260 } else { 2261 looper = handler.getLooper(); 2262 } 2263 2264 if (looper != null) { 2265 // implement the event handler delegate to receive events from audio service 2266 mHandler = new Handler(looper) { 2267 @Override 2268 public void handleMessage(Message msg) { 2269 switch (msg.what) { 2270 case MSSG_FOCUS_CHANGE: { 2271 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj); 2272 if (fri != null) { 2273 final OnAudioFocusChangeListener listener = 2274 fri.mRequest.getOnAudioFocusChangeListener(); 2275 if (listener != null) { 2276 Log.d(TAG, "dispatching onAudioFocusChange(" 2277 + msg.arg1 + ") to " + msg.obj); 2278 listener.onAudioFocusChange(msg.arg1); 2279 } 2280 } 2281 } break; 2282 case MSSG_RECORDING_CONFIG_CHANGE: { 2283 final RecordConfigChangeCallbackData cbData = 2284 (RecordConfigChangeCallbackData) msg.obj; 2285 if (cbData.mCb != null) { 2286 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs); 2287 } 2288 } break; 2289 case MSSG_PLAYBACK_CONFIG_CHANGE: { 2290 final PlaybackConfigChangeCallbackData cbData = 2291 (PlaybackConfigChangeCallbackData) msg.obj; 2292 if (cbData.mCb != null) { 2293 if (DEBUG) { 2294 Log.d(TAG, "dispatching onPlaybackConfigChanged()"); 2295 } 2296 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs); 2297 } 2298 } break; 2299 default: 2300 Log.e(TAG, "Unknown event " + msg.what); 2301 } 2302 } 2303 }; 2304 } else { 2305 mHandler = null; 2306 } 2307 } 2308 getHandler()2309 Handler getHandler() { 2310 return mHandler; 2311 } 2312 } 2313 2314 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() { 2315 @Override 2316 public void dispatchAudioFocusChange(int focusChange, String id) { 2317 final FocusRequestInfo fri = findFocusRequestInfo(id); 2318 if (fri != null) { 2319 final OnAudioFocusChangeListener listener = 2320 fri.mRequest.getOnAudioFocusChangeListener(); 2321 if (listener != null) { 2322 final Handler h = (fri.mHandler == null) ? 2323 mServiceEventHandlerDelegate.getHandler() : fri.mHandler; 2324 final Message m = h.obtainMessage( 2325 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, 2326 id/*obj*/); 2327 h.sendMessage(m); 2328 } 2329 } 2330 } 2331 2332 @Override 2333 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) { 2334 synchronized (mFocusRequestsLock) { 2335 // TODO use generation counter as the key instead 2336 final BlockingFocusResultReceiver focusReceiver = 2337 mFocusRequestsAwaitingResult.remove(clientId); 2338 if (focusReceiver != null) { 2339 focusReceiver.notifyResult(requestResult); 2340 } else { 2341 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver"); 2342 } 2343 } 2344 } 2345 }; 2346 getIdForAudioFocusListener(OnAudioFocusChangeListener l)2347 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) { 2348 if (l == null) { 2349 return new String(this.toString()); 2350 } else { 2351 return new String(this.toString() + l.toString()); 2352 } 2353 } 2354 2355 /** 2356 * @hide 2357 * Registers a listener to be called when audio focus changes and keeps track of the associated 2358 * focus request (including Handler to use for the listener). 2359 * @param afr the full request parameters 2360 */ registerAudioFocusRequest(@onNull AudioFocusRequest afr)2361 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) { 2362 final Handler h = afr.getOnAudioFocusChangeListenerHandler(); 2363 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null : 2364 new ServiceEventHandlerDelegate(h).getHandler()); 2365 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 2366 mAudioFocusIdListenerMap.put(key, fri); 2367 } 2368 2369 /** 2370 * @hide 2371 * Causes the specified listener to not be called anymore when focus is gained or lost. 2372 * @param l the listener to unregister. 2373 */ unregisterAudioFocusRequest(OnAudioFocusChangeListener l)2374 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) { 2375 // remove locally 2376 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l)); 2377 } 2378 2379 2380 /** 2381 * A failed focus change request. 2382 */ 2383 public static final int AUDIOFOCUS_REQUEST_FAILED = 0; 2384 /** 2385 * A successful focus change request. 2386 */ 2387 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; 2388 /** 2389 * A focus change request whose granting is delayed: the request was successful, but the 2390 * requester will only be granted audio focus once the condition that prevented immediate 2391 * granting has ended. 2392 * See {@link #requestAudioFocus(AudioFocusRequest)} and 2393 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} 2394 */ 2395 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2; 2396 2397 /** @hide */ 2398 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = { 2399 AUDIOFOCUS_REQUEST_FAILED, 2400 AUDIOFOCUS_REQUEST_GRANTED, 2401 AUDIOFOCUS_REQUEST_DELAYED } 2402 ) 2403 @Retention(RetentionPolicy.SOURCE) 2404 public @interface FocusRequestResult {} 2405 2406 /** 2407 * @hide 2408 * code returned when a synchronous focus request on the client-side is to be blocked 2409 * until the external audio focus policy decides on the response for the client 2410 */ 2411 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100; 2412 2413 /** 2414 * Timeout duration in ms when waiting on an external focus policy for the result for a 2415 * focus request 2416 */ 2417 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200; 2418 2419 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id"; 2420 2421 private final Object mFocusRequestsLock = new Object(); 2422 /** 2423 * Map of all receivers of focus request results, one per unresolved focus request. 2424 * Receivers are added before sending the request to the external focus policy, 2425 * and are removed either after receiving the result, or after the timeout. 2426 * This variable is lazily initialized. 2427 */ 2428 @GuardedBy("mFocusRequestsLock") 2429 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult; 2430 2431 2432 /** 2433 * Request audio focus. 2434 * Send a request to obtain the audio focus 2435 * @param l the listener to be notified of audio focus changes 2436 * @param streamType the main audio stream type affected by the focus request 2437 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 2438 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 2439 * for the playback of driving directions, or notifications sounds. 2440 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 2441 * the previous focus owner to keep playing if it ducks its audio output. 2442 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 2443 * that benefits from the system not playing disruptive sounds like notifications, for 2444 * usecases such as voice memo recording, or speech recognition. 2445 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 2446 * as the playback of a song or a video. 2447 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 2448 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)} 2449 */ requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)2450 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) { 2451 PlayerBase.deprecateStreamTypeForPlayback(streamType, 2452 "AudioManager", "requestAudioFocus()"); 2453 int status = AUDIOFOCUS_REQUEST_FAILED; 2454 2455 try { 2456 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or 2457 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the 2458 // AUDIOFOCUS_FLAG_DELAY_OK flag 2459 status = requestAudioFocus(l, 2460 new AudioAttributes.Builder() 2461 .setInternalLegacyStreamType(streamType).build(), 2462 durationHint, 2463 0 /* flags, legacy behavior */); 2464 } catch (IllegalArgumentException e) { 2465 Log.e(TAG, "Audio focus request denied due to ", e); 2466 } 2467 2468 return status; 2469 } 2470 2471 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks 2472 /** 2473 * @hide 2474 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be 2475 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when 2476 * the system is in a state where focus cannot change, but be granted focus later when 2477 * this condition ends. 2478 */ 2479 @SystemApi 2480 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0; 2481 /** 2482 * @hide 2483 * Use this flag when requesting audio focus to indicate that the requester 2484 * will pause its media playback (if applicable) when losing audio focus with 2485 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking. 2486 * <br>On some platforms, the ducking may be handled without the application being aware of it 2487 * (i.e. it will not transiently lose focus). For applications that for instance play spoken 2488 * content, such as audio book or podcast players, ducking may never be acceptable, and will 2489 * thus always pause. This flag enables them to be declared as such whenever they request focus. 2490 */ 2491 @SystemApi 2492 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1; 2493 /** 2494 * @hide 2495 * Use this flag to lock audio focus so granting is temporarily disabled. 2496 * <br>This flag can only be used by owners of a registered 2497 * {@link android.media.audiopolicy.AudioPolicy} in 2498 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)} 2499 */ 2500 @SystemApi 2501 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2; 2502 /** @hide */ 2503 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK 2504 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS; 2505 /** @hide */ 2506 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK 2507 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK; 2508 2509 /** 2510 * Request audio focus. 2511 * See the {@link AudioFocusRequest} for information about the options available to configure 2512 * your request, and notification of focus gain and loss. 2513 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is 2514 * requested. 2515 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 2516 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 2517 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus 2518 * is requested without building the {@link AudioFocusRequest} with 2519 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to 2520 * {@code true}. 2521 * @throws NullPointerException if passed a null argument 2522 */ requestAudioFocus(@onNull AudioFocusRequest focusRequest)2523 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) { 2524 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/); 2525 } 2526 2527 /** 2528 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 2529 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus 2530 * with {@link #requestAudioFocus(AudioFocusRequest)}. 2531 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 2532 * @throws IllegalArgumentException if passed a null argument 2533 */ abandonAudioFocusRequest(@onNull AudioFocusRequest focusRequest)2534 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) { 2535 if (focusRequest == null) { 2536 throw new IllegalArgumentException("Illegal null AudioFocusRequest"); 2537 } 2538 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(), 2539 focusRequest.getAudioAttributes()); 2540 } 2541 2542 /** 2543 * @hide 2544 * Request audio focus. 2545 * Send a request to obtain the audio focus. This method differs from 2546 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express 2547 * that the requester accepts delayed grants of audio focus. 2548 * @param l the listener to be notified of audio focus changes. It is not allowed to be null 2549 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}. 2550 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 2551 * requesting audio focus. 2552 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 2553 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 2554 * for the playback of driving directions, or notifications sounds. 2555 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 2556 * the previous focus owner to keep playing if it ducks its audio output. 2557 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 2558 * that benefits from the system not playing disruptive sounds like notifications, for 2559 * usecases such as voice memo recording, or speech recognition. 2560 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 2561 * as the playback of a song or a video. 2562 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 2563 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}. 2564 * <br>Use 0 when not using any flags for the request, which behaves like 2565 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 2566 * focus is granted immediately, or the grant request fails because the system is in a 2567 * state where focus cannot change (e.g. a phone call). 2568 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 2569 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 2570 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested 2571 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag. 2572 * @throws IllegalArgumentException 2573 */ 2574 @SystemApi 2575 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags)2576 public int requestAudioFocus(OnAudioFocusChangeListener l, 2577 @NonNull AudioAttributes requestAttributes, 2578 int durationHint, 2579 int flags) throws IllegalArgumentException { 2580 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) { 2581 throw new IllegalArgumentException("Invalid flags 0x" 2582 + Integer.toHexString(flags).toUpperCase()); 2583 } 2584 return requestAudioFocus(l, requestAttributes, durationHint, 2585 flags & AUDIOFOCUS_FLAGS_APPS, 2586 null /* no AudioPolicy*/); 2587 } 2588 2589 /** 2590 * @hide 2591 * Request or lock audio focus. 2592 * This method is to be used by system components that have registered an 2593 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 2594 * so focus granting is temporarily disabled. 2595 * @param l see the description of the same parameter in 2596 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 2597 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 2598 * requesting audio focus. 2599 * @param durationHint see the description of the same parameter in 2600 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 2601 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 2602 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}. 2603 * <br>Use 0 when not using any flags for the request, which behaves like 2604 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 2605 * focus is granted immediately, or the grant request fails because the system is in a 2606 * state where focus cannot change (e.g. a phone call). 2607 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 2608 * focus, or null. 2609 * @return see the description of the same return value in 2610 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 2611 * @throws IllegalArgumentException 2612 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)} 2613 */ 2614 @SystemApi 2615 @RequiresPermission(anyOf= { 2616 android.Manifest.permission.MODIFY_PHONE_STATE, 2617 android.Manifest.permission.MODIFY_AUDIO_ROUTING 2618 }) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags, AudioPolicy ap)2619 public int requestAudioFocus(OnAudioFocusChangeListener l, 2620 @NonNull AudioAttributes requestAttributes, 2621 int durationHint, 2622 int flags, 2623 AudioPolicy ap) throws IllegalArgumentException { 2624 // parameter checking 2625 if (requestAttributes == null) { 2626 throw new IllegalArgumentException("Illegal null AudioAttributes argument"); 2627 } 2628 if (!AudioFocusRequest.isValidFocusGain(durationHint)) { 2629 throw new IllegalArgumentException("Invalid duration hint"); 2630 } 2631 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) { 2632 throw new IllegalArgumentException("Illegal flags 0x" 2633 + Integer.toHexString(flags).toUpperCase()); 2634 } 2635 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) { 2636 throw new IllegalArgumentException( 2637 "Illegal null focus listener when flagged as accepting delayed focus grant"); 2638 } 2639 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 2640 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) { 2641 throw new IllegalArgumentException( 2642 "Illegal null focus listener when flagged as pausing instead of ducking"); 2643 } 2644 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) { 2645 throw new IllegalArgumentException( 2646 "Illegal null audio policy when locking audio focus"); 2647 } 2648 2649 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint) 2650 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */) 2651 .setAudioAttributes(requestAttributes) 2652 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK) 2653 == AUDIOFOCUS_FLAG_DELAY_OK) 2654 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 2655 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 2656 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) 2657 .build(); 2658 return requestAudioFocus(afr, ap); 2659 } 2660 2661 /** 2662 * @hide 2663 * Request or lock audio focus. 2664 * This method is to be used by system components that have registered an 2665 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 2666 * so focus granting is temporarily disabled. 2667 * @param afr see the description of the same parameter in 2668 * {@link #requestAudioFocus(AudioFocusRequest)} 2669 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 2670 * focus, or null. 2671 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 2672 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 2673 * @throws NullPointerException if the AudioFocusRequest is null 2674 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy 2675 */ 2676 @SystemApi 2677 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) requestAudioFocus(@onNull AudioFocusRequest afr, @Nullable AudioPolicy ap)2678 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) { 2679 if (afr == null) { 2680 throw new NullPointerException("Illegal null AudioFocusRequest"); 2681 } 2682 // this can only be checked now, not during the creation of the AudioFocusRequest instance 2683 if (afr.locksFocus() && ap == null) { 2684 throw new IllegalArgumentException( 2685 "Illegal null audio policy when locking audio focus"); 2686 } 2687 registerAudioFocusRequest(afr); 2688 final IAudioService service = getService(); 2689 final int status; 2690 int sdk; 2691 try { 2692 sdk = getContext().getApplicationInfo().targetSdkVersion; 2693 } catch (NullPointerException e) { 2694 // some tests don't have a Context 2695 sdk = Build.VERSION.SDK_INT; 2696 } 2697 2698 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 2699 final BlockingFocusResultReceiver focusReceiver; 2700 synchronized (mFocusRequestsLock) { 2701 try { 2702 // TODO status contains result and generation counter for ext policy 2703 status = service.requestAudioFocus(afr.getAudioAttributes(), 2704 afr.getFocusGain(), mICallBack, 2705 mAudioFocusDispatcher, 2706 clientId, 2707 getContext().getOpPackageName() /* package name */, afr.getFlags(), 2708 ap != null ? ap.cb() : null, 2709 sdk); 2710 } catch (RemoteException e) { 2711 throw e.rethrowFromSystemServer(); 2712 } 2713 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) { 2714 // default path with no external focus policy 2715 return status; 2716 } 2717 if (mFocusRequestsAwaitingResult == null) { 2718 mFocusRequestsAwaitingResult = 2719 new HashMap<String, BlockingFocusResultReceiver>(1); 2720 } 2721 focusReceiver = new BlockingFocusResultReceiver(clientId); 2722 mFocusRequestsAwaitingResult.put(clientId, focusReceiver); 2723 } 2724 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS); 2725 if (DEBUG && !focusReceiver.receivedResult()) { 2726 Log.e(TAG, "requestAudio response from ext policy timed out, denying request"); 2727 } 2728 synchronized (mFocusRequestsLock) { 2729 mFocusRequestsAwaitingResult.remove(clientId); 2730 } 2731 return focusReceiver.requestResult(); 2732 } 2733 2734 // helper class that abstracts out the handling of spurious wakeups in Object.wait() 2735 private static final class SafeWaitObject { 2736 private boolean mQuit = false; 2737 safeNotify()2738 public void safeNotify() { 2739 synchronized (this) { 2740 mQuit = true; 2741 this.notify(); 2742 } 2743 } 2744 safeWait(long millis)2745 public void safeWait(long millis) throws InterruptedException { 2746 final long timeOutTime = java.lang.System.currentTimeMillis() + millis; 2747 synchronized (this) { 2748 while (!mQuit) { 2749 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis(); 2750 if (timeToWait < 0) { break; } 2751 this.wait(timeToWait); 2752 } 2753 } 2754 } 2755 } 2756 2757 private static final class BlockingFocusResultReceiver { 2758 private final SafeWaitObject mLock = new SafeWaitObject(); 2759 @GuardedBy("mLock") 2760 private boolean mResultReceived = false; 2761 // request denied by default (e.g. timeout) 2762 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED; 2763 private final String mFocusClientId; 2764 BlockingFocusResultReceiver(String clientId)2765 BlockingFocusResultReceiver(String clientId) { 2766 mFocusClientId = clientId; 2767 } 2768 receivedResult()2769 boolean receivedResult() { return mResultReceived; } requestResult()2770 int requestResult() { return mFocusRequestResult; } 2771 notifyResult(int requestResult)2772 void notifyResult(int requestResult) { 2773 synchronized (mLock) { 2774 mResultReceived = true; 2775 mFocusRequestResult = requestResult; 2776 mLock.safeNotify(); 2777 } 2778 } 2779 waitForResult(long timeOutMs)2780 public void waitForResult(long timeOutMs) { 2781 synchronized (mLock) { 2782 if (mResultReceived) { 2783 // the result was received before waiting 2784 return; 2785 } 2786 try { 2787 mLock.safeWait(timeOutMs); 2788 } catch (InterruptedException e) { } 2789 } 2790 } 2791 } 2792 2793 /** 2794 * @hide 2795 * Used internally by telephony package to request audio focus. Will cause the focus request 2796 * to be associated with the "voice communication" identifier only used in AudioService 2797 * to identify this use case. 2798 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for 2799 * the establishment of the call 2800 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so 2801 * media applications resume after a call 2802 */ requestAudioFocusForCall(int streamType, int durationHint)2803 public void requestAudioFocusForCall(int streamType, int durationHint) { 2804 final IAudioService service = getService(); 2805 try { 2806 service.requestAudioFocus(new AudioAttributes.Builder() 2807 .setInternalLegacyStreamType(streamType).build(), 2808 durationHint, mICallBack, null, 2809 AudioSystem.IN_VOICE_COMM_FOCUS_ID, 2810 getContext().getOpPackageName(), 2811 AUDIOFOCUS_FLAG_LOCK, 2812 null /* policy token */, 0 /* sdk n/a here*/); 2813 } catch (RemoteException e) { 2814 throw e.rethrowFromSystemServer(); 2815 } 2816 } 2817 2818 /** 2819 * @hide 2820 * Return the volume ramping time for a sound to be played after the given focus request, 2821 * and to play a sound of the given attributes 2822 * @param focusGain 2823 * @param attr 2824 * @return 2825 */ getFocusRampTimeMs(int focusGain, AudioAttributes attr)2826 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) { 2827 final IAudioService service = getService(); 2828 try { 2829 return service.getFocusRampTimeMs(focusGain, attr); 2830 } catch (RemoteException e) { 2831 throw e.rethrowFromSystemServer(); 2832 } 2833 } 2834 2835 /** 2836 * @hide 2837 * Set the result to the audio focus request received through 2838 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 2839 * @param afi the information about the focus requester 2840 * @param requestResult the result to the focus request to be passed to the requester 2841 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 2842 */ 2843 @SystemApi 2844 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setFocusRequestResult(@onNull AudioFocusInfo afi, @FocusRequestResult int requestResult, @NonNull AudioPolicy ap)2845 public void setFocusRequestResult(@NonNull AudioFocusInfo afi, 2846 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) { 2847 if (afi == null) { 2848 throw new IllegalArgumentException("Illegal null AudioFocusInfo"); 2849 } 2850 if (ap == null) { 2851 throw new IllegalArgumentException("Illegal null AudioPolicy"); 2852 } 2853 final IAudioService service = getService(); 2854 try { 2855 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb()); 2856 } catch (RemoteException e) { 2857 throw e.rethrowFromSystemServer(); 2858 } 2859 } 2860 2861 /** 2862 * @hide 2863 * Notifies an application with a focus listener of gain or loss of audio focus. 2864 * This method can only be used by owners of an {@link AudioPolicy} configured with 2865 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true. 2866 * @param afi the recipient of the focus change, that has previously requested audio focus, and 2867 * that was received by the {@code AudioPolicy} through 2868 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 2869 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN}, 2870 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or 2871 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}) 2872 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS}, 2873 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}, 2874 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}). 2875 * <br>For the focus gain, the change type should be the same as the app requested. 2876 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 2877 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or 2878 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or 2879 * if there was an error sending the request. 2880 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null. 2881 */ 2882 @SystemApi 2883 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) dispatchAudioFocusChange(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap)2884 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange, 2885 @NonNull AudioPolicy ap) { 2886 if (afi == null) { 2887 throw new NullPointerException("Illegal null AudioFocusInfo"); 2888 } 2889 if (ap == null) { 2890 throw new NullPointerException("Illegal null AudioPolicy"); 2891 } 2892 final IAudioService service = getService(); 2893 try { 2894 return service.dispatchFocusChange(afi, focusChange, ap.cb()); 2895 } catch (RemoteException e) { 2896 throw e.rethrowFromSystemServer(); 2897 } 2898 } 2899 2900 /** 2901 * @hide 2902 * Used internally by telephony package to abandon audio focus, typically after a call or 2903 * when ringing ends and the call is rejected or not answered. 2904 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. 2905 */ abandonAudioFocusForCall()2906 public void abandonAudioFocusForCall() { 2907 final IAudioService service = getService(); 2908 try { 2909 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID, 2910 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName()); 2911 } catch (RemoteException e) { 2912 throw e.rethrowFromSystemServer(); 2913 } 2914 } 2915 2916 /** 2917 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 2918 * @param l the listener with which focus was requested. 2919 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 2920 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 2921 */ abandonAudioFocus(OnAudioFocusChangeListener l)2922 public int abandonAudioFocus(OnAudioFocusChangeListener l) { 2923 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/); 2924 } 2925 2926 /** 2927 * @hide 2928 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 2929 * @param l the listener with which focus was requested. 2930 * @param aa the {@link AudioAttributes} with which audio focus was requested 2931 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 2932 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 2933 */ 2934 @SystemApi 2935 @SuppressLint("Doclava125") // no permission enforcement, but only "undoes" what would have been 2936 // done by a matching requestAudioFocus abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa)2937 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) { 2938 int status = AUDIOFOCUS_REQUEST_FAILED; 2939 unregisterAudioFocusRequest(l); 2940 final IAudioService service = getService(); 2941 try { 2942 status = service.abandonAudioFocus(mAudioFocusDispatcher, 2943 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName()); 2944 } catch (RemoteException e) { 2945 throw e.rethrowFromSystemServer(); 2946 } 2947 return status; 2948 } 2949 2950 //==================================================================== 2951 // Remote Control 2952 /** 2953 * Register a component to be the sole receiver of MEDIA_BUTTON intents. 2954 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 2955 * that will receive the media button intent. This broadcast receiver must be declared 2956 * in the application manifest. The package of the component must match that of 2957 * the context you're registering from. 2958 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 2959 */ 2960 @Deprecated registerMediaButtonEventReceiver(ComponentName eventReceiver)2961 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 2962 if (eventReceiver == null) { 2963 return; 2964 } 2965 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) { 2966 Log.e(TAG, "registerMediaButtonEventReceiver() error: " + 2967 "receiver and context package names don't match"); 2968 return; 2969 } 2970 // construct a PendingIntent for the media button and register it 2971 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 2972 // the associated intent will be handled by the component being registered 2973 mediaButtonIntent.setComponent(eventReceiver); 2974 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 2975 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); 2976 registerMediaButtonIntent(pi, eventReceiver); 2977 } 2978 2979 /** 2980 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like 2981 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows 2982 * the buttons to go to any PendingIntent. Note that you should only use this form if 2983 * you know you will continue running for the full time until unregistering the 2984 * PendingIntent. 2985 * @param eventReceiver target that will receive media button intents. The PendingIntent 2986 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action 2987 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the 2988 * media button that was pressed. 2989 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 2990 */ 2991 @Deprecated registerMediaButtonEventReceiver(PendingIntent eventReceiver)2992 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) { 2993 if (eventReceiver == null) { 2994 return; 2995 } 2996 registerMediaButtonIntent(eventReceiver, null); 2997 } 2998 2999 /** 3000 * @hide 3001 * no-op if (pi == null) or (eventReceiver == null) 3002 */ registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver)3003 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) { 3004 if (pi == null) { 3005 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter"); 3006 return; 3007 } 3008 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 3009 helper.addMediaButtonListener(pi, eventReceiver, getContext()); 3010 } 3011 3012 /** 3013 * Unregister the receiver of MEDIA_BUTTON intents. 3014 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 3015 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}. 3016 * @deprecated Use {@link MediaSession} instead. 3017 */ 3018 @Deprecated unregisterMediaButtonEventReceiver(ComponentName eventReceiver)3019 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 3020 if (eventReceiver == null) { 3021 return; 3022 } 3023 // construct a PendingIntent for the media button and unregister it 3024 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 3025 // the associated intent will be handled by the component being registered 3026 mediaButtonIntent.setComponent(eventReceiver); 3027 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 3028 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); 3029 unregisterMediaButtonIntent(pi); 3030 } 3031 3032 /** 3033 * Unregister the receiver of MEDIA_BUTTON intents. 3034 * @param eventReceiver same PendingIntent that was registed with 3035 * {@link #registerMediaButtonEventReceiver(PendingIntent)}. 3036 * @deprecated Use {@link MediaSession} instead. 3037 */ 3038 @Deprecated unregisterMediaButtonEventReceiver(PendingIntent eventReceiver)3039 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) { 3040 if (eventReceiver == null) { 3041 return; 3042 } 3043 unregisterMediaButtonIntent(eventReceiver); 3044 } 3045 3046 /** 3047 * @hide 3048 */ unregisterMediaButtonIntent(PendingIntent pi)3049 public void unregisterMediaButtonIntent(PendingIntent pi) { 3050 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 3051 helper.removeMediaButtonListener(pi); 3052 } 3053 3054 /** 3055 * Registers the remote control client for providing information to display on the remote 3056 * controls. 3057 * @param rcClient The remote control client from which remote controls will receive 3058 * information to display. 3059 * @see RemoteControlClient 3060 * @deprecated Use {@link MediaSession} instead. 3061 */ 3062 @Deprecated registerRemoteControlClient(RemoteControlClient rcClient)3063 public void registerRemoteControlClient(RemoteControlClient rcClient) { 3064 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 3065 return; 3066 } 3067 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 3068 } 3069 3070 /** 3071 * Unregisters the remote control client that was providing information to display on the 3072 * remote controls. 3073 * @param rcClient The remote control client to unregister. 3074 * @see #registerRemoteControlClient(RemoteControlClient) 3075 * @deprecated Use {@link MediaSession} instead. 3076 */ 3077 @Deprecated unregisterRemoteControlClient(RemoteControlClient rcClient)3078 public void unregisterRemoteControlClient(RemoteControlClient rcClient) { 3079 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 3080 return; 3081 } 3082 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 3083 } 3084 3085 /** 3086 * Registers a {@link RemoteController} instance for it to receive media 3087 * metadata updates and playback state information from applications using 3088 * {@link RemoteControlClient}, and control their playback. 3089 * <p> 3090 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be 3091 * one of the enabled notification listeners (see 3092 * {@link android.service.notification.NotificationListenerService}). 3093 * 3094 * @param rctlr the object to register. 3095 * @return true if the {@link RemoteController} was successfully registered, 3096 * false if an error occurred, due to an internal system error, or 3097 * insufficient permissions. 3098 * @deprecated Use 3099 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)} 3100 * and {@link MediaController} instead. 3101 */ 3102 @Deprecated registerRemoteController(RemoteController rctlr)3103 public boolean registerRemoteController(RemoteController rctlr) { 3104 if (rctlr == null) { 3105 return false; 3106 } 3107 rctlr.startListeningToSessions(); 3108 return true; 3109 } 3110 3111 /** 3112 * Unregisters a {@link RemoteController}, causing it to no longer receive 3113 * media metadata and playback state information, and no longer be capable 3114 * of controlling playback. 3115 * 3116 * @param rctlr the object to unregister. 3117 * @deprecated Use 3118 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)} 3119 * instead. 3120 */ 3121 @Deprecated unregisterRemoteController(RemoteController rctlr)3122 public void unregisterRemoteController(RemoteController rctlr) { 3123 if (rctlr == null) { 3124 return; 3125 } 3126 rctlr.stopListeningToSessions(); 3127 } 3128 3129 3130 //==================================================================== 3131 // Audio policy 3132 /** 3133 * @hide 3134 * Register the given {@link AudioPolicy}. 3135 * This call is synchronous and blocks until the registration process successfully completed 3136 * or failed to complete. 3137 * @param policy the non-null {@link AudioPolicy} to register. 3138 * @return {@link #ERROR} if there was an error communicating with the registration service 3139 * or if the user doesn't have the required 3140 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission, 3141 * {@link #SUCCESS} otherwise. 3142 */ 3143 @SystemApi 3144 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) registerAudioPolicy(@onNull AudioPolicy policy)3145 public int registerAudioPolicy(@NonNull AudioPolicy policy) { 3146 if (policy == null) { 3147 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 3148 } 3149 final IAudioService service = getService(); 3150 try { 3151 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), 3152 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController()); 3153 if (regId == null) { 3154 return ERROR; 3155 } else { 3156 policy.setRegistration(regId); 3157 } 3158 // successful registration 3159 } catch (RemoteException e) { 3160 throw e.rethrowFromSystemServer(); 3161 } 3162 return SUCCESS; 3163 } 3164 3165 /** 3166 * @hide 3167 * @param policy the non-null {@link AudioPolicy} to unregister. 3168 */ 3169 @SystemApi 3170 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicyAsync(@onNull AudioPolicy policy)3171 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) { 3172 if (policy == null) { 3173 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 3174 } 3175 final IAudioService service = getService(); 3176 try { 3177 service.unregisterAudioPolicyAsync(policy.cb()); 3178 policy.setRegistration(null); 3179 } catch (RemoteException e) { 3180 throw e.rethrowFromSystemServer(); 3181 } 3182 } 3183 3184 //==================================================================== 3185 // Notification of playback activity & playback configuration 3186 /** 3187 * Interface for receiving update notifications about the playback activity on the system. 3188 * Extend this abstract class and register it with 3189 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)} 3190 * to be notified. 3191 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current 3192 * configuration. 3193 * @see AudioPlaybackConfiguration 3194 */ 3195 public static abstract class AudioPlaybackCallback { 3196 /** 3197 * Called whenever the playback activity and configuration has changed. 3198 * @param configs list containing the results of 3199 * {@link AudioManager#getActivePlaybackConfigurations()}. 3200 */ onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs)3201 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {} 3202 } 3203 3204 private static class AudioPlaybackCallbackInfo { 3205 final AudioPlaybackCallback mCb; 3206 final Handler mHandler; AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler)3207 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) { 3208 mCb = cb; 3209 mHandler = handler; 3210 } 3211 } 3212 3213 private final static class PlaybackConfigChangeCallbackData { 3214 final AudioPlaybackCallback mCb; 3215 final List<AudioPlaybackConfiguration> mConfigs; 3216 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, List<AudioPlaybackConfiguration> configs)3217 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, 3218 List<AudioPlaybackConfiguration> configs) { 3219 mCb = cb; 3220 mConfigs = configs; 3221 } 3222 } 3223 3224 /** 3225 * Register a callback to be notified of audio playback changes through 3226 * {@link AudioPlaybackCallback} 3227 * @param cb non-null callback to register 3228 * @param handler the {@link Handler} object for the thread on which to execute 3229 * the callback. If <code>null</code>, the {@link Handler} associated with the main 3230 * {@link Looper} will be used. 3231 */ registerAudioPlaybackCallback(@onNull AudioPlaybackCallback cb, Handler handler)3232 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb, Handler handler) 3233 { 3234 if (cb == null) { 3235 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 3236 } 3237 3238 synchronized(mPlaybackCallbackLock) { 3239 // lazy initialization of the list of playback callbacks 3240 if (mPlaybackCallbackList == null) { 3241 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>(); 3242 } 3243 final int oldCbCount = mPlaybackCallbackList.size(); 3244 if (!hasPlaybackCallback_sync(cb)) { 3245 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb, 3246 new ServiceEventHandlerDelegate(handler).getHandler())); 3247 final int newCbCount = mPlaybackCallbackList.size(); 3248 if ((oldCbCount == 0) && (newCbCount > 0)) { 3249 // register binder for callbacks 3250 try { 3251 getService().registerPlaybackCallback(mPlayCb); 3252 } catch (RemoteException e) { 3253 throw e.rethrowFromSystemServer(); 3254 } 3255 } 3256 } else { 3257 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously" 3258 + "registered callback"); 3259 } 3260 } 3261 } 3262 3263 /** 3264 * Unregister an audio playback callback previously registered with 3265 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 3266 * @param cb non-null callback to unregister 3267 */ unregisterAudioPlaybackCallback(@onNull AudioPlaybackCallback cb)3268 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) { 3269 if (cb == null) { 3270 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 3271 } 3272 synchronized(mPlaybackCallbackLock) { 3273 if (mPlaybackCallbackList == null) { 3274 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 3275 + " that was never registered"); 3276 return; 3277 } 3278 final int oldCbCount = mPlaybackCallbackList.size(); 3279 if (removePlaybackCallback_sync(cb)) { 3280 final int newCbCount = mPlaybackCallbackList.size(); 3281 if ((oldCbCount > 0) && (newCbCount == 0)) { 3282 // unregister binder for callbacks 3283 try { 3284 getService().unregisterPlaybackCallback(mPlayCb); 3285 } catch (RemoteException e) { 3286 throw e.rethrowFromSystemServer(); 3287 } 3288 } 3289 } else { 3290 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 3291 + " already unregistered or never registered"); 3292 } 3293 } 3294 } 3295 3296 /** 3297 * Returns the current active audio playback configurations of the device 3298 * @return a non-null list of playback configurations. An empty list indicates there is no 3299 * playback active when queried. 3300 * @see AudioPlaybackConfiguration 3301 */ getActivePlaybackConfigurations()3302 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() { 3303 final IAudioService service = getService(); 3304 try { 3305 return service.getActivePlaybackConfigurations(); 3306 } catch (RemoteException e) { 3307 throw e.rethrowFromSystemServer(); 3308 } 3309 } 3310 3311 /** 3312 * All operations on this list are sync'd on mPlaybackCallbackLock. 3313 * List is lazy-initialized in 3314 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 3315 * List can be null. 3316 */ 3317 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList; 3318 private final Object mPlaybackCallbackLock = new Object(); 3319 3320 /** 3321 * Must be called synchronized on mPlaybackCallbackLock 3322 */ hasPlaybackCallback_sync(@onNull AudioPlaybackCallback cb)3323 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 3324 if (mPlaybackCallbackList != null) { 3325 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 3326 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 3327 return true; 3328 } 3329 } 3330 } 3331 return false; 3332 } 3333 3334 /** 3335 * Must be called synchronized on mPlaybackCallbackLock 3336 */ removePlaybackCallback_sync(@onNull AudioPlaybackCallback cb)3337 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 3338 if (mPlaybackCallbackList != null) { 3339 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 3340 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 3341 mPlaybackCallbackList.remove(i); 3342 return true; 3343 } 3344 } 3345 } 3346 return false; 3347 } 3348 3349 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() { 3350 @Override 3351 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs, 3352 boolean flush) { 3353 if (flush) { 3354 Binder.flushPendingCommands(); 3355 } 3356 synchronized(mPlaybackCallbackLock) { 3357 if (mPlaybackCallbackList != null) { 3358 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 3359 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i); 3360 if (arci.mHandler != null) { 3361 final Message m = arci.mHandler.obtainMessage( 3362 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/, 3363 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 3364 arci.mHandler.sendMessage(m); 3365 } 3366 } 3367 } 3368 } 3369 } 3370 3371 }; 3372 3373 //==================================================================== 3374 // Notification of recording activity & recording configuration 3375 /** 3376 * Interface for receiving update notifications about the recording configuration. Extend 3377 * this abstract class and register it with 3378 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)} 3379 * to be notified. 3380 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current 3381 * configuration. 3382 * @see AudioRecordingConfiguration 3383 */ 3384 public static abstract class AudioRecordingCallback { 3385 /** 3386 * Called whenever the device recording configuration has changed. 3387 * @param configs list containing the results of 3388 * {@link AudioManager#getActiveRecordingConfigurations()}. 3389 */ onRecordingConfigChanged(List<AudioRecordingConfiguration> configs)3390 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {} 3391 } 3392 3393 private static class AudioRecordingCallbackInfo { 3394 final AudioRecordingCallback mCb; 3395 final Handler mHandler; AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler)3396 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) { 3397 mCb = cb; 3398 mHandler = handler; 3399 } 3400 } 3401 3402 private final static class RecordConfigChangeCallbackData { 3403 final AudioRecordingCallback mCb; 3404 final List<AudioRecordingConfiguration> mConfigs; 3405 RecordConfigChangeCallbackData(AudioRecordingCallback cb, List<AudioRecordingConfiguration> configs)3406 RecordConfigChangeCallbackData(AudioRecordingCallback cb, 3407 List<AudioRecordingConfiguration> configs) { 3408 mCb = cb; 3409 mConfigs = configs; 3410 } 3411 } 3412 3413 /** 3414 * Register a callback to be notified of audio recording changes through 3415 * {@link AudioRecordingCallback} 3416 * @param cb non-null callback to register 3417 * @param handler the {@link Handler} object for the thread on which to execute 3418 * the callback. If <code>null</code>, the {@link Handler} associated with the main 3419 * {@link Looper} will be used. 3420 */ registerAudioRecordingCallback(@onNull AudioRecordingCallback cb, Handler handler)3421 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb, Handler handler) 3422 { 3423 if (cb == null) { 3424 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 3425 } 3426 3427 synchronized(mRecordCallbackLock) { 3428 // lazy initialization of the list of recording callbacks 3429 if (mRecordCallbackList == null) { 3430 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>(); 3431 } 3432 final int oldCbCount = mRecordCallbackList.size(); 3433 if (!hasRecordCallback_sync(cb)) { 3434 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb, 3435 new ServiceEventHandlerDelegate(handler).getHandler())); 3436 final int newCbCount = mRecordCallbackList.size(); 3437 if ((oldCbCount == 0) && (newCbCount > 0)) { 3438 // register binder for callbacks 3439 final IAudioService service = getService(); 3440 try { 3441 service.registerRecordingCallback(mRecCb); 3442 } catch (RemoteException e) { 3443 throw e.rethrowFromSystemServer(); 3444 } 3445 } 3446 } else { 3447 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously" 3448 + "registered callback"); 3449 } 3450 } 3451 } 3452 3453 /** 3454 * Unregister an audio recording callback previously registered with 3455 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 3456 * @param cb non-null callback to unregister 3457 */ unregisterAudioRecordingCallback(@onNull AudioRecordingCallback cb)3458 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) { 3459 if (cb == null) { 3460 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 3461 } 3462 synchronized(mRecordCallbackLock) { 3463 if (mRecordCallbackList == null) { 3464 return; 3465 } 3466 final int oldCbCount = mRecordCallbackList.size(); 3467 if (removeRecordCallback_sync(cb)) { 3468 final int newCbCount = mRecordCallbackList.size(); 3469 if ((oldCbCount > 0) && (newCbCount == 0)) { 3470 // unregister binder for callbacks 3471 final IAudioService service = getService(); 3472 try { 3473 service.unregisterRecordingCallback(mRecCb); 3474 } catch (RemoteException e) { 3475 throw e.rethrowFromSystemServer(); 3476 } 3477 } 3478 } else { 3479 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback" 3480 + " already unregistered or never registered"); 3481 } 3482 } 3483 } 3484 3485 /** 3486 * Returns the current active audio recording configurations of the device. 3487 * @return a non-null list of recording configurations. An empty list indicates there is 3488 * no recording active when queried. 3489 * @see AudioRecordingConfiguration 3490 */ getActiveRecordingConfigurations()3491 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() { 3492 final IAudioService service = getService(); 3493 try { 3494 return service.getActiveRecordingConfigurations(); 3495 } catch (RemoteException e) { 3496 throw e.rethrowFromSystemServer(); 3497 } 3498 } 3499 3500 /** 3501 * constants for the recording events, to keep in sync 3502 * with frameworks/av/include/media/AudioPolicy.h 3503 */ 3504 /** @hide */ 3505 public final static int RECORD_CONFIG_EVENT_START = 1; 3506 /** @hide */ 3507 public final static int RECORD_CONFIG_EVENT_STOP = 0; 3508 3509 /** 3510 * All operations on this list are sync'd on mRecordCallbackLock. 3511 * List is lazy-initialized in 3512 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 3513 * List can be null. 3514 */ 3515 private List<AudioRecordingCallbackInfo> mRecordCallbackList; 3516 private final Object mRecordCallbackLock = new Object(); 3517 3518 /** 3519 * Must be called synchronized on mRecordCallbackLock 3520 */ hasRecordCallback_sync(@onNull AudioRecordingCallback cb)3521 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 3522 if (mRecordCallbackList != null) { 3523 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 3524 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 3525 return true; 3526 } 3527 } 3528 } 3529 return false; 3530 } 3531 3532 /** 3533 * Must be called synchronized on mRecordCallbackLock 3534 */ removeRecordCallback_sync(@onNull AudioRecordingCallback cb)3535 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 3536 if (mRecordCallbackList != null) { 3537 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 3538 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 3539 mRecordCallbackList.remove(i); 3540 return true; 3541 } 3542 } 3543 } 3544 return false; 3545 } 3546 3547 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() { 3548 @Override 3549 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) { 3550 synchronized(mRecordCallbackLock) { 3551 if (mRecordCallbackList != null) { 3552 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 3553 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i); 3554 if (arci.mHandler != null) { 3555 final Message m = arci.mHandler.obtainMessage( 3556 MSSG_RECORDING_CONFIG_CHANGE/*what*/, 3557 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 3558 arci.mHandler.sendMessage(m); 3559 } 3560 } 3561 } 3562 } 3563 } 3564 3565 }; 3566 3567 //===================================================================== 3568 3569 /** 3570 * @hide 3571 * Reload audio settings. This method is called by Settings backup 3572 * agent when audio settings are restored and causes the AudioService 3573 * to read and apply restored settings. 3574 */ reloadAudioSettings()3575 public void reloadAudioSettings() { 3576 final IAudioService service = getService(); 3577 try { 3578 service.reloadAudioSettings(); 3579 } catch (RemoteException e) { 3580 throw e.rethrowFromSystemServer(); 3581 } 3582 } 3583 3584 /** 3585 * @hide 3586 * Notifies AudioService that it is connected to an A2DP device that supports absolute volume, 3587 * so that AudioService can send volume change events to the A2DP device, rather than handling 3588 * them. 3589 */ avrcpSupportsAbsoluteVolume(String address, boolean support)3590 public void avrcpSupportsAbsoluteVolume(String address, boolean support) { 3591 final IAudioService service = getService(); 3592 try { 3593 service.avrcpSupportsAbsoluteVolume(address, support); 3594 } catch (RemoteException e) { 3595 throw e.rethrowFromSystemServer(); 3596 } 3597 } 3598 3599 /** 3600 * {@hide} 3601 */ 3602 private final IBinder mICallBack = new Binder(); 3603 3604 /** 3605 * Checks whether the phone is in silent mode, with or without vibrate. 3606 * 3607 * @return true if phone is in silent mode, with or without vibrate. 3608 * 3609 * @see #getRingerMode() 3610 * 3611 * @hide pending API Council approval 3612 */ isSilentMode()3613 public boolean isSilentMode() { 3614 int ringerMode = getRingerMode(); 3615 boolean silentMode = 3616 (ringerMode == RINGER_MODE_SILENT) || 3617 (ringerMode == RINGER_MODE_VIBRATE); 3618 return silentMode; 3619 } 3620 3621 // This section re-defines new output device constants from AudioSystem, because the AudioSystem 3622 // class is not used by other parts of the framework, which instead use definitions and methods 3623 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService. 3624 3625 /** @hide 3626 * The audio device code for representing "no device." */ 3627 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE; 3628 /** @hide 3629 * The audio output device code for the small speaker at the front of the device used 3630 * when placing calls. Does not refer to an in-ear headphone without attached microphone, 3631 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a 3632 * {@link #DEVICE_OUT_WIRED_HEADPHONE}. 3633 */ 3634 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE; 3635 /** @hide 3636 * The audio output device code for the built-in speaker */ 3637 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER; 3638 /** @hide 3639 * The audio output device code for a wired headset with attached microphone */ 3640 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET; 3641 /** @hide 3642 * The audio output device code for a wired headphone without attached microphone */ 3643 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 3644 /** @hide 3645 * The audio output device code for a USB headphone with attached microphone */ 3646 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET; 3647 /** @hide 3648 * The audio output device code for generic Bluetooth SCO, for voice */ 3649 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 3650 /** @hide 3651 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and 3652 * Hands-Free Profile (HFP), for voice 3653 */ 3654 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 3655 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 3656 /** @hide 3657 * The audio output device code for Bluetooth SCO car audio, for voice */ 3658 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 3659 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 3660 /** @hide 3661 * The audio output device code for generic Bluetooth A2DP, for music */ 3662 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; 3663 /** @hide 3664 * The audio output device code for Bluetooth A2DP headphones, for music */ 3665 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 3666 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; 3667 /** @hide 3668 * The audio output device code for Bluetooth A2DP external speaker, for music */ 3669 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 3670 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; 3671 /** @hide 3672 * The audio output device code for S/PDIF (legacy) or HDMI 3673 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */ 3674 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL; 3675 /** @hide 3676 * The audio output device code for HDMI */ 3677 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI; 3678 /** @hide 3679 * The audio output device code for an analog wired headset attached via a 3680 * docking station 3681 */ 3682 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; 3683 /** @hide 3684 * The audio output device code for a digital wired headset attached via a 3685 * docking station 3686 */ 3687 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET; 3688 /** @hide 3689 * The audio output device code for a USB audio accessory. The accessory is in USB host 3690 * mode and the Android device in USB device mode 3691 */ 3692 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY; 3693 /** @hide 3694 * The audio output device code for a USB audio device. The device is in USB device 3695 * mode and the Android device in USB host mode 3696 */ 3697 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE; 3698 /** @hide 3699 * The audio output device code for projection output. 3700 */ 3701 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; 3702 /** @hide 3703 * The audio output device code the telephony voice TX path. 3704 */ 3705 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX; 3706 /** @hide 3707 * The audio output device code for an analog jack with line impedance detected. 3708 */ 3709 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE; 3710 /** @hide 3711 * The audio output device code for HDMI Audio Return Channel. 3712 */ 3713 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC; 3714 /** @hide 3715 * The audio output device code for S/PDIF digital connection. 3716 */ 3717 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF; 3718 /** @hide 3719 * The audio output device code for built-in FM transmitter. 3720 */ 3721 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM; 3722 /** @hide 3723 * This is not used as a returned value from {@link #getDevicesForStream}, but could be 3724 * used in the future in a set method to select whatever default device is chosen by the 3725 * platform-specific implementation. 3726 */ 3727 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT; 3728 3729 /** @hide 3730 * The audio input device code for default built-in microphone 3731 */ 3732 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC; 3733 /** @hide 3734 * The audio input device code for a Bluetooth SCO headset 3735 */ 3736 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 3737 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; 3738 /** @hide 3739 * The audio input device code for wired headset microphone 3740 */ 3741 public static final int DEVICE_IN_WIRED_HEADSET = 3742 AudioSystem.DEVICE_IN_WIRED_HEADSET; 3743 /** @hide 3744 * The audio input device code for HDMI 3745 */ 3746 public static final int DEVICE_IN_HDMI = 3747 AudioSystem.DEVICE_IN_HDMI; 3748 /** @hide 3749 * The audio input device code for telephony voice RX path 3750 */ 3751 public static final int DEVICE_IN_TELEPHONY_RX = 3752 AudioSystem.DEVICE_IN_TELEPHONY_RX; 3753 /** @hide 3754 * The audio input device code for built-in microphone pointing to the back 3755 */ 3756 public static final int DEVICE_IN_BACK_MIC = 3757 AudioSystem.DEVICE_IN_BACK_MIC; 3758 /** @hide 3759 * The audio input device code for analog from a docking station 3760 */ 3761 public static final int DEVICE_IN_ANLG_DOCK_HEADSET = 3762 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET; 3763 /** @hide 3764 * The audio input device code for digital from a docking station 3765 */ 3766 public static final int DEVICE_IN_DGTL_DOCK_HEADSET = 3767 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET; 3768 /** @hide 3769 * The audio input device code for a USB audio accessory. The accessory is in USB host 3770 * mode and the Android device in USB device mode 3771 */ 3772 public static final int DEVICE_IN_USB_ACCESSORY = 3773 AudioSystem.DEVICE_IN_USB_ACCESSORY; 3774 /** @hide 3775 * The audio input device code for a USB audio device. The device is in USB device 3776 * mode and the Android device in USB host mode 3777 */ 3778 public static final int DEVICE_IN_USB_DEVICE = 3779 AudioSystem.DEVICE_IN_USB_DEVICE; 3780 /** @hide 3781 * The audio input device code for a FM radio tuner 3782 */ 3783 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER; 3784 /** @hide 3785 * The audio input device code for a TV tuner 3786 */ 3787 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER; 3788 /** @hide 3789 * The audio input device code for an analog jack with line impedance detected 3790 */ 3791 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE; 3792 /** @hide 3793 * The audio input device code for a S/PDIF digital connection 3794 */ 3795 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF; 3796 /** @hide 3797 * The audio input device code for audio loopback 3798 */ 3799 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK; 3800 3801 /** 3802 * Return true if the device code corresponds to an output device. 3803 * @hide 3804 */ isOutputDevice(int device)3805 public static boolean isOutputDevice(int device) 3806 { 3807 return (device & AudioSystem.DEVICE_BIT_IN) == 0; 3808 } 3809 3810 /** 3811 * Return true if the device code corresponds to an input device. 3812 * @hide 3813 */ isInputDevice(int device)3814 public static boolean isInputDevice(int device) 3815 { 3816 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN; 3817 } 3818 3819 3820 /** 3821 * Return the enabled devices for the specified output stream type. 3822 * 3823 * @param streamType The stream type to query. One of 3824 * {@link #STREAM_VOICE_CALL}, 3825 * {@link #STREAM_SYSTEM}, 3826 * {@link #STREAM_RING}, 3827 * {@link #STREAM_MUSIC}, 3828 * {@link #STREAM_ALARM}, 3829 * {@link #STREAM_NOTIFICATION}, 3830 * {@link #STREAM_DTMF}, 3831 * {@link #STREAM_ACCESSIBILITY}. 3832 * 3833 * @return The bit-mask "or" of audio output device codes for all enabled devices on this 3834 * stream. Zero or more of 3835 * {@link #DEVICE_OUT_EARPIECE}, 3836 * {@link #DEVICE_OUT_SPEAKER}, 3837 * {@link #DEVICE_OUT_WIRED_HEADSET}, 3838 * {@link #DEVICE_OUT_WIRED_HEADPHONE}, 3839 * {@link #DEVICE_OUT_BLUETOOTH_SCO}, 3840 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET}, 3841 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT}, 3842 * {@link #DEVICE_OUT_BLUETOOTH_A2DP}, 3843 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}, 3844 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER}, 3845 * {@link #DEVICE_OUT_HDMI}, 3846 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET}, 3847 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}. 3848 * {@link #DEVICE_OUT_USB_ACCESSORY}. 3849 * {@link #DEVICE_OUT_USB_DEVICE}. 3850 * {@link #DEVICE_OUT_REMOTE_SUBMIX}. 3851 * {@link #DEVICE_OUT_TELEPHONY_TX}. 3852 * {@link #DEVICE_OUT_LINE}. 3853 * {@link #DEVICE_OUT_HDMI_ARC}. 3854 * {@link #DEVICE_OUT_SPDIF}. 3855 * {@link #DEVICE_OUT_FM}. 3856 * {@link #DEVICE_OUT_DEFAULT} is not used here. 3857 * 3858 * The implementation may support additional device codes beyond those listed, so 3859 * the application should ignore any bits which it does not recognize. 3860 * Note that the information may be imprecise when the implementation 3861 * cannot distinguish whether a particular device is enabled. 3862 * 3863 * {@hide} 3864 */ getDevicesForStream(int streamType)3865 public int getDevicesForStream(int streamType) { 3866 switch (streamType) { 3867 case STREAM_VOICE_CALL: 3868 case STREAM_SYSTEM: 3869 case STREAM_RING: 3870 case STREAM_MUSIC: 3871 case STREAM_ALARM: 3872 case STREAM_NOTIFICATION: 3873 case STREAM_DTMF: 3874 case STREAM_ACCESSIBILITY: 3875 return AudioSystem.getDevicesForStream(streamType); 3876 default: 3877 return 0; 3878 } 3879 } 3880 3881 /** 3882 * Indicate wired accessory connection state change. 3883 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx) 3884 * @param state new connection state: 1 connected, 0 disconnected 3885 * @param name device name 3886 * {@hide} 3887 */ setWiredDeviceConnectionState(int type, int state, String address, String name)3888 public void setWiredDeviceConnectionState(int type, int state, String address, String name) { 3889 final IAudioService service = getService(); 3890 try { 3891 service.setWiredDeviceConnectionState(type, state, address, name, 3892 mApplicationContext.getOpPackageName()); 3893 } catch (RemoteException e) { 3894 throw e.rethrowFromSystemServer(); 3895 } 3896 } 3897 3898 /** 3899 * Indicate Hearing Aid connection state change. 3900 * @param device Bluetooth device connected/disconnected 3901 * @param state new connection state (BluetoothProfile.STATE_xxx) 3902 * {@hide} 3903 */ setHearingAidDeviceConnectionState(BluetoothDevice device, int state)3904 public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state) { 3905 final IAudioService service = getService(); 3906 try { 3907 service.setHearingAidDeviceConnectionState(device, state); 3908 } catch (RemoteException e) { 3909 throw e.rethrowFromSystemServer(); 3910 } 3911 } 3912 3913 /** 3914 * Indicate A2DP source or sink connection state change. 3915 * @param device Bluetooth device connected/disconnected 3916 * @param state new connection state (BluetoothProfile.STATE_xxx) 3917 * @param profile profile for the A2DP device 3918 * (either {@link android.bluetooth.BluetoothProfile.A2DP} or 3919 * {@link android.bluetooth.BluetoothProfile.A2DP_SINK}) 3920 * @return a delay in ms that the caller should wait before broadcasting 3921 * BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent. 3922 * {@hide} 3923 */ setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)3924 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, 3925 int profile) { 3926 final IAudioService service = getService(); 3927 int delay = 0; 3928 try { 3929 delay = service.setBluetoothA2dpDeviceConnectionState(device, state, profile); 3930 } catch (RemoteException e) { 3931 throw e.rethrowFromSystemServer(); 3932 } 3933 return delay; 3934 } 3935 3936 /** 3937 * Indicate A2DP source or sink connection state change and eventually suppress 3938 * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent. 3939 * @param device Bluetooth device connected/disconnected 3940 * @param state new connection state (BluetoothProfile.STATE_xxx) 3941 * @param profile profile for the A2DP device 3942 * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting. 3943 * (either {@link android.bluetooth.BluetoothProfile.A2DP} or 3944 * {@link android.bluetooth.BluetoothProfile.A2DP_SINK}) 3945 * @param suppressNoisyIntent if true the 3946 * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. 3947 * @return a delay in ms that the caller should wait before broadcasting 3948 * BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent. 3949 * {@hide} 3950 */ setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)3951 public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( 3952 BluetoothDevice device, int state, int profile, 3953 boolean suppressNoisyIntent, int a2dpVolume) { 3954 final IAudioService service = getService(); 3955 int delay = 0; 3956 try { 3957 delay = service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, 3958 state, profile, suppressNoisyIntent, a2dpVolume); 3959 } catch (RemoteException e) { 3960 throw e.rethrowFromSystemServer(); 3961 } 3962 return delay; 3963 } 3964 3965 /** 3966 * Indicate A2DP device configuration has changed. 3967 * @param device Bluetooth device whose configuration has changed. 3968 * {@hide} 3969 */ handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)3970 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) { 3971 final IAudioService service = getService(); 3972 try { 3973 service.handleBluetoothA2dpDeviceConfigChange(device); 3974 } catch (RemoteException e) { 3975 throw e.rethrowFromSystemServer(); 3976 } 3977 } 3978 3979 /** {@hide} */ getRingtonePlayer()3980 public IRingtonePlayer getRingtonePlayer() { 3981 try { 3982 return getService().getRingtonePlayer(); 3983 } catch (RemoteException e) { 3984 throw e.rethrowFromSystemServer(); 3985 } 3986 } 3987 3988 /** 3989 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate 3990 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps 3991 * should use this value as a default, and offer the user the option to override it. 3992 * The low latency output stream is typically either the device's primary output stream, 3993 * or another output stream with smaller buffers. 3994 */ 3995 // FIXME Deprecate 3996 public static final String PROPERTY_OUTPUT_SAMPLE_RATE = 3997 "android.media.property.OUTPUT_SAMPLE_RATE"; 3998 3999 /** 4000 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size 4001 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps 4002 * should use this value as a minimum, and offer the user the option to override it. 4003 * The low latency output stream is typically either the device's primary output stream, 4004 * or another output stream with smaller buffers. 4005 */ 4006 // FIXME Deprecate 4007 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = 4008 "android.media.property.OUTPUT_FRAMES_PER_BUFFER"; 4009 4010 /** 4011 * Used as a key for {@link #getProperty} to determine if the default microphone audio source 4012 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 4013 */ 4014 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = 4015 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND"; 4016 4017 /** 4018 * Used as a key for {@link #getProperty} to determine if the default speaker audio path 4019 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 4020 */ 4021 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = 4022 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND"; 4023 4024 /** 4025 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is 4026 * available and supported with the expected frequency range and level response. 4027 */ 4028 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = 4029 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED"; 4030 /** 4031 * Returns the value of the property with the specified key. 4032 * @param key One of the strings corresponding to a property key: either 4033 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE}, 4034 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER}, 4035 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND}, 4036 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or 4037 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}. 4038 * @return A string representing the associated value for that property key, 4039 * or null if there is no value for that key. 4040 */ getProperty(String key)4041 public String getProperty(String key) { 4042 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) { 4043 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate(); 4044 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null; 4045 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) { 4046 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount(); 4047 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null; 4048 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) { 4049 // Will throw a RuntimeException Resources.NotFoundException if this config value is 4050 // not found. 4051 return String.valueOf(getContext().getResources().getBoolean( 4052 com.android.internal.R.bool.config_supportMicNearUltrasound)); 4053 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) { 4054 return String.valueOf(getContext().getResources().getBoolean( 4055 com.android.internal.R.bool.config_supportSpeakerNearUltrasound)); 4056 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) { 4057 return String.valueOf(getContext().getResources().getBoolean( 4058 com.android.internal.R.bool.config_supportAudioSourceUnprocessed)); 4059 } else { 4060 // null or unknown key 4061 return null; 4062 } 4063 } 4064 4065 /** 4066 * Returns the estimated latency for the given stream type in milliseconds. 4067 * 4068 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need 4069 * a better solution. 4070 * @hide 4071 */ getOutputLatency(int streamType)4072 public int getOutputLatency(int streamType) { 4073 return AudioSystem.getOutputLatency(streamType); 4074 } 4075 4076 /** 4077 * Registers a global volume controller interface. Currently limited to SystemUI. 4078 * 4079 * @hide 4080 */ setVolumeController(IVolumeController controller)4081 public void setVolumeController(IVolumeController controller) { 4082 try { 4083 getService().setVolumeController(controller); 4084 } catch (RemoteException e) { 4085 throw e.rethrowFromSystemServer(); 4086 } 4087 } 4088 4089 /** 4090 * Notify audio manager about volume controller visibility changes. 4091 * Currently limited to SystemUI. 4092 * 4093 * @hide 4094 */ notifyVolumeControllerVisible(IVolumeController controller, boolean visible)4095 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) { 4096 try { 4097 getService().notifyVolumeControllerVisible(controller, visible); 4098 } catch (RemoteException e) { 4099 throw e.rethrowFromSystemServer(); 4100 } 4101 } 4102 4103 /** 4104 * Only useful for volume controllers. 4105 * @hide 4106 */ isStreamAffectedByRingerMode(int streamType)4107 public boolean isStreamAffectedByRingerMode(int streamType) { 4108 try { 4109 return getService().isStreamAffectedByRingerMode(streamType); 4110 } catch (RemoteException e) { 4111 throw e.rethrowFromSystemServer(); 4112 } 4113 } 4114 4115 /** 4116 * Only useful for volume controllers. 4117 * @hide 4118 */ isStreamAffectedByMute(int streamType)4119 public boolean isStreamAffectedByMute(int streamType) { 4120 try { 4121 return getService().isStreamAffectedByMute(streamType); 4122 } catch (RemoteException e) { 4123 throw e.rethrowFromSystemServer(); 4124 } 4125 } 4126 4127 /** 4128 * Only useful for volume controllers. 4129 * @hide 4130 */ disableSafeMediaVolume()4131 public void disableSafeMediaVolume() { 4132 try { 4133 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName()); 4134 } catch (RemoteException e) { 4135 throw e.rethrowFromSystemServer(); 4136 } 4137 } 4138 4139 /** 4140 * Only useful for volume controllers. 4141 * @hide 4142 */ setRingerModeInternal(int ringerMode)4143 public void setRingerModeInternal(int ringerMode) { 4144 try { 4145 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName()); 4146 } catch (RemoteException e) { 4147 throw e.rethrowFromSystemServer(); 4148 } 4149 } 4150 4151 /** 4152 * Only useful for volume controllers. 4153 * @hide 4154 */ getRingerModeInternal()4155 public int getRingerModeInternal() { 4156 try { 4157 return getService().getRingerModeInternal(); 4158 } catch (RemoteException e) { 4159 throw e.rethrowFromSystemServer(); 4160 } 4161 } 4162 4163 /** 4164 * Only useful for volume controllers. 4165 * @hide 4166 */ setVolumePolicy(VolumePolicy policy)4167 public void setVolumePolicy(VolumePolicy policy) { 4168 try { 4169 getService().setVolumePolicy(policy); 4170 } catch (RemoteException e) { 4171 throw e.rethrowFromSystemServer(); 4172 } 4173 } 4174 4175 /** 4176 * Set Hdmi Cec system audio mode. 4177 * 4178 * @param on whether to be on system audio mode 4179 * @return output device type. 0 (DEVICE_NONE) if failed to set device. 4180 * @hide 4181 */ setHdmiSystemAudioSupported(boolean on)4182 public int setHdmiSystemAudioSupported(boolean on) { 4183 try { 4184 return getService().setHdmiSystemAudioSupported(on); 4185 } catch (RemoteException e) { 4186 throw e.rethrowFromSystemServer(); 4187 } 4188 } 4189 4190 /** 4191 * Returns true if Hdmi Cec system audio mode is supported. 4192 * 4193 * @hide 4194 */ 4195 @SystemApi 4196 @SuppressLint("Doclava125") // FIXME is this still used? isHdmiSystemAudioSupported()4197 public boolean isHdmiSystemAudioSupported() { 4198 try { 4199 return getService().isHdmiSystemAudioSupported(); 4200 } catch (RemoteException e) { 4201 throw e.rethrowFromSystemServer(); 4202 } 4203 } 4204 4205 /** 4206 * Return codes for listAudioPorts(), createAudioPatch() ... 4207 */ 4208 4209 /** @hide 4210 * CANDIDATE FOR PUBLIC API 4211 */ 4212 public static final int SUCCESS = AudioSystem.SUCCESS; 4213 /** 4214 * A default error code. 4215 */ 4216 public static final int ERROR = AudioSystem.ERROR; 4217 /** @hide 4218 * CANDIDATE FOR PUBLIC API 4219 */ 4220 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE; 4221 /** @hide 4222 */ 4223 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION; 4224 /** @hide 4225 */ 4226 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED; 4227 /** @hide 4228 */ 4229 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT; 4230 /** 4231 * An error code indicating that the object reporting it is no longer valid and needs to 4232 * be recreated. 4233 */ 4234 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT; 4235 4236 /** 4237 * Returns a list of descriptors for all audio ports managed by the audio framework. 4238 * Audio ports are nodes in the audio framework or audio hardware that can be configured 4239 * or connected and disconnected with createAudioPatch() or releaseAudioPatch(). 4240 * See AudioPort for a list of attributes of each audio port. 4241 * @param ports An AudioPort ArrayList where the list will be returned. 4242 * @hide 4243 */ listAudioPorts(ArrayList<AudioPort> ports)4244 public static int listAudioPorts(ArrayList<AudioPort> ports) { 4245 return updateAudioPortCache(ports, null, null); 4246 } 4247 4248 /** 4249 * Returns a list of descriptors for all audio ports managed by the audio framework as 4250 * it was before the last update calback. 4251 * @param ports An AudioPort ArrayList where the list will be returned. 4252 * @hide 4253 */ listPreviousAudioPorts(ArrayList<AudioPort> ports)4254 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) { 4255 return updateAudioPortCache(null, null, ports); 4256 } 4257 4258 /** 4259 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort) 4260 * @see listAudioPorts(ArrayList<AudioPort>) 4261 * @hide 4262 */ listAudioDevicePorts(ArrayList<AudioDevicePort> devices)4263 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 4264 if (devices == null) { 4265 return ERROR_BAD_VALUE; 4266 } 4267 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 4268 int status = updateAudioPortCache(ports, null, null); 4269 if (status == SUCCESS) { 4270 filterDevicePorts(ports, devices); 4271 } 4272 return status; 4273 } 4274 4275 /** 4276 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort) 4277 * @see listPreviousAudioPorts(ArrayList<AudioPort>) 4278 * @hide 4279 */ listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices)4280 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 4281 if (devices == null) { 4282 return ERROR_BAD_VALUE; 4283 } 4284 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 4285 int status = updateAudioPortCache(null, null, ports); 4286 if (status == SUCCESS) { 4287 filterDevicePorts(ports, devices); 4288 } 4289 return status; 4290 } 4291 filterDevicePorts(ArrayList<AudioPort> ports, ArrayList<AudioDevicePort> devices)4292 private static void filterDevicePorts(ArrayList<AudioPort> ports, 4293 ArrayList<AudioDevicePort> devices) { 4294 devices.clear(); 4295 for (int i = 0; i < ports.size(); i++) { 4296 if (ports.get(i) instanceof AudioDevicePort) { 4297 devices.add((AudioDevicePort)ports.get(i)); 4298 } 4299 } 4300 } 4301 4302 /** 4303 * Create a connection between two or more devices. The framework will reject the request if 4304 * device types are not compatible or the implementation does not support the requested 4305 * configuration. 4306 * NOTE: current implementation is limited to one source and one sink per patch. 4307 * @param patch AudioPatch array where the newly created patch will be returned. 4308 * As input, if patch[0] is not null, the specified patch will be replaced by the 4309 * new patch created. This avoids calling releaseAudioPatch() when modifying a 4310 * patch and allows the implementation to optimize transitions. 4311 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE. 4312 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK. 4313 * 4314 * @return - {@link #SUCCESS} if connection is successful. 4315 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed. 4316 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported. 4317 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create 4318 * a patch. 4319 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 4320 * - {@link #ERROR} if patch cannot be connected for any other reason. 4321 * 4322 * patch[0] contains the newly created patch 4323 * @hide 4324 */ createAudioPatch(AudioPatch[] patch, AudioPortConfig[] sources, AudioPortConfig[] sinks)4325 public static int createAudioPatch(AudioPatch[] patch, 4326 AudioPortConfig[] sources, 4327 AudioPortConfig[] sinks) { 4328 return AudioSystem.createAudioPatch(patch, sources, sinks); 4329 } 4330 4331 /** 4332 * Releases an existing audio patch connection. 4333 * @param patch The audio patch to disconnect. 4334 * @return - {@link #SUCCESS} if disconnection is successful. 4335 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist. 4336 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release 4337 * a patch. 4338 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 4339 * - {@link #ERROR} if patch cannot be released for any other reason. 4340 * @hide 4341 */ releaseAudioPatch(AudioPatch patch)4342 public static int releaseAudioPatch(AudioPatch patch) { 4343 return AudioSystem.releaseAudioPatch(patch); 4344 } 4345 4346 /** 4347 * List all existing connections between audio ports. 4348 * @param patches An AudioPatch array where the list will be returned. 4349 * @hide 4350 */ listAudioPatches(ArrayList<AudioPatch> patches)4351 public static int listAudioPatches(ArrayList<AudioPatch> patches) { 4352 return updateAudioPortCache(null, patches, null); 4353 } 4354 4355 /** 4356 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by 4357 * AudioGain.buildConfig() 4358 * @hide 4359 */ setAudioPortGain(AudioPort port, AudioGainConfig gain)4360 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) { 4361 if (port == null || gain == null) { 4362 return ERROR_BAD_VALUE; 4363 } 4364 AudioPortConfig activeConfig = port.activeConfig(); 4365 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(), 4366 activeConfig.channelMask(), activeConfig.format(), gain); 4367 config.mConfigMask = AudioPortConfig.GAIN; 4368 return AudioSystem.setAudioPortConfig(config); 4369 } 4370 4371 /** 4372 * Listener registered by client to be notified upon new audio port connections, 4373 * disconnections or attributes update. 4374 * @hide 4375 */ 4376 public interface OnAudioPortUpdateListener { 4377 /** 4378 * Callback method called upon audio port list update. 4379 * @param portList the updated list of audio ports 4380 */ onAudioPortListUpdate(AudioPort[] portList)4381 public void onAudioPortListUpdate(AudioPort[] portList); 4382 4383 /** 4384 * Callback method called upon audio patch list update. 4385 * @param patchList the updated list of audio patches 4386 */ onAudioPatchListUpdate(AudioPatch[] patchList)4387 public void onAudioPatchListUpdate(AudioPatch[] patchList); 4388 4389 /** 4390 * Callback method called when the mediaserver dies 4391 */ onServiceDied()4392 public void onServiceDied(); 4393 } 4394 4395 /** 4396 * Register an audio port list update listener. 4397 * @hide 4398 */ registerAudioPortUpdateListener(OnAudioPortUpdateListener l)4399 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) { 4400 sAudioPortEventHandler.init(); 4401 sAudioPortEventHandler.registerListener(l); 4402 } 4403 4404 /** 4405 * Unregister an audio port list update listener. 4406 * @hide 4407 */ unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l)4408 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) { 4409 sAudioPortEventHandler.unregisterListener(l); 4410 } 4411 4412 // 4413 // AudioPort implementation 4414 // 4415 4416 static final int AUDIOPORT_GENERATION_INIT = 0; 4417 static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT); 4418 static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>(); 4419 static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>(); 4420 static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>(); 4421 resetAudioPortGeneration()4422 static int resetAudioPortGeneration() { 4423 int generation; 4424 synchronized (sAudioPortGeneration) { 4425 generation = sAudioPortGeneration; 4426 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; 4427 } 4428 return generation; 4429 } 4430 updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, ArrayList<AudioPort> previousPorts)4431 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, 4432 ArrayList<AudioPort> previousPorts) { 4433 sAudioPortEventHandler.init(); 4434 synchronized (sAudioPortGeneration) { 4435 4436 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) { 4437 int[] patchGeneration = new int[1]; 4438 int[] portGeneration = new int[1]; 4439 int status; 4440 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>(); 4441 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>(); 4442 4443 do { 4444 newPorts.clear(); 4445 status = AudioSystem.listAudioPorts(newPorts, portGeneration); 4446 if (status != SUCCESS) { 4447 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed"); 4448 return status; 4449 } 4450 newPatches.clear(); 4451 status = AudioSystem.listAudioPatches(newPatches, patchGeneration); 4452 if (status != SUCCESS) { 4453 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed"); 4454 return status; 4455 } 4456 // Loop until patch generation is the same as port generation unless audio ports 4457 // and audio patches are not null. 4458 } while (patchGeneration[0] != portGeneration[0] 4459 && (ports == null || patches == null)); 4460 // If the patch generation doesn't equal port generation, return ERROR here in case 4461 // of mismatch between audio ports and audio patches. 4462 if (patchGeneration[0] != portGeneration[0]) { 4463 return ERROR; 4464 } 4465 4466 for (int i = 0; i < newPatches.size(); i++) { 4467 for (int j = 0; j < newPatches.get(i).sources().length; j++) { 4468 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j], 4469 newPorts); 4470 newPatches.get(i).sources()[j] = portCfg; 4471 } 4472 for (int j = 0; j < newPatches.get(i).sinks().length; j++) { 4473 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j], 4474 newPorts); 4475 newPatches.get(i).sinks()[j] = portCfg; 4476 } 4477 } 4478 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) { 4479 AudioPatch newPatch = i.next(); 4480 boolean hasInvalidPort = false; 4481 for (AudioPortConfig portCfg : newPatch.sources()) { 4482 if (portCfg == null) { 4483 hasInvalidPort = true; 4484 break; 4485 } 4486 } 4487 for (AudioPortConfig portCfg : newPatch.sinks()) { 4488 if (portCfg == null) { 4489 hasInvalidPort = true; 4490 break; 4491 } 4492 } 4493 if (hasInvalidPort) { 4494 // Temporarily remove patches with invalid ports. One who created the patch 4495 // is responsible for dealing with the port change. 4496 i.remove(); 4497 } 4498 } 4499 4500 sPreviousAudioPortsCached = sAudioPortsCached; 4501 sAudioPortsCached = newPorts; 4502 sAudioPatchesCached = newPatches; 4503 sAudioPortGeneration = portGeneration[0]; 4504 } 4505 if (ports != null) { 4506 ports.clear(); 4507 ports.addAll(sAudioPortsCached); 4508 } 4509 if (patches != null) { 4510 patches.clear(); 4511 patches.addAll(sAudioPatchesCached); 4512 } 4513 if (previousPorts != null) { 4514 previousPorts.clear(); 4515 previousPorts.addAll(sPreviousAudioPortsCached); 4516 } 4517 } 4518 return SUCCESS; 4519 } 4520 updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports)4521 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) { 4522 AudioPort port = portCfg.port(); 4523 int k; 4524 for (k = 0; k < ports.size(); k++) { 4525 // compare handles because the port returned by JNI is not of the correct 4526 // subclass 4527 if (ports.get(k).handle().equals(port.handle())) { 4528 port = ports.get(k); 4529 break; 4530 } 4531 } 4532 if (k == ports.size()) { 4533 // this hould never happen 4534 Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id()); 4535 return null; 4536 } 4537 AudioGainConfig gainCfg = portCfg.gain(); 4538 if (gainCfg != null) { 4539 AudioGain gain = port.gain(gainCfg.index()); 4540 gainCfg = gain.buildConfig(gainCfg.mode(), 4541 gainCfg.channelMask(), 4542 gainCfg.values(), 4543 gainCfg.rampDurationMs()); 4544 } 4545 return port.buildConfig(portCfg.samplingRate(), 4546 portCfg.channelMask(), 4547 portCfg.format(), 4548 gainCfg); 4549 } 4550 4551 private OnAmPortUpdateListener mPortListener = null; 4552 4553 /** 4554 * The message sent to apps when the contents of the device list changes if they provide 4555 * a {#link Handler} object to addOnAudioDeviceConnectionListener(). 4556 */ 4557 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0; 4558 private final static int MSG_DEVICES_DEVICES_ADDED = 1; 4559 private final static int MSG_DEVICES_DEVICES_REMOVED = 2; 4560 4561 /** 4562 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications. 4563 */ 4564 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks = 4565 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>(); 4566 4567 /** 4568 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter 4569 * the results list to only those device types they are interested in. 4570 */ 4571 /** 4572 * Specifies to the {@link AudioManager#getDevices(int)} method to include 4573 * source (i.e. input) audio devices. 4574 */ 4575 public static final int GET_DEVICES_INPUTS = 0x0001; 4576 4577 /** 4578 * Specifies to the {@link AudioManager#getDevices(int)} method to include 4579 * sink (i.e. output) audio devices. 4580 */ 4581 public static final int GET_DEVICES_OUTPUTS = 0x0002; 4582 4583 /** 4584 * Specifies to the {@link AudioManager#getDevices(int)} method to include both 4585 * source and sink devices. 4586 */ 4587 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS; 4588 4589 /** 4590 * Determines if a given AudioDevicePort meets the specified filter criteria. 4591 * @param port The port to test. 4592 * @param flags A set of bitflags specifying the criteria to test. 4593 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS} 4594 **/ checkFlags(AudioDevicePort port, int flags)4595 private static boolean checkFlags(AudioDevicePort port, int flags) { 4596 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 || 4597 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0; 4598 } 4599 checkTypes(AudioDevicePort port)4600 private static boolean checkTypes(AudioDevicePort port) { 4601 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) != 4602 AudioDeviceInfo.TYPE_UNKNOWN; 4603 } 4604 4605 /** 4606 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices 4607 * currently connected to the system and meeting the criteria specified in the 4608 * <code>flags</code> parameter. 4609 * @param flags A set of bitflags specifying the criteria to test. 4610 * @see #GET_DEVICES_OUTPUTS 4611 * @see #GET_DEVICES_INPUTS 4612 * @see #GET_DEVICES_ALL 4613 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 4614 */ getDevices(int flags)4615 public AudioDeviceInfo[] getDevices(int flags) { 4616 return getDevicesStatic(flags); 4617 } 4618 4619 /** 4620 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo 4621 * objects from the current (internal) AudioDevicePort list. 4622 */ 4623 private static AudioDeviceInfo[] infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags)4624 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) { 4625 4626 // figure out how many AudioDeviceInfo we need space for... 4627 int numRecs = 0; 4628 for (AudioDevicePort port : ports) { 4629 if (checkTypes(port) && checkFlags(port, flags)) { 4630 numRecs++; 4631 } 4632 } 4633 4634 // Now load them up... 4635 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs]; 4636 int slot = 0; 4637 for (AudioDevicePort port : ports) { 4638 if (checkTypes(port) && checkFlags(port, flags)) { 4639 deviceList[slot++] = new AudioDeviceInfo(port); 4640 } 4641 } 4642 4643 return deviceList; 4644 } 4645 4646 /* 4647 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by 4648 * the add/remove callback mechanism to provide a list of the newly added or removed devices 4649 * rather than the whole list and make the app figure it out. 4650 * Note that calling this method with: 4651 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports. 4652 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports. 4653 */ calcListDeltas( ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags)4654 private static AudioDeviceInfo[] calcListDeltas( 4655 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) { 4656 4657 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>(); 4658 4659 AudioDevicePort cur_port = null; 4660 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) { 4661 boolean cur_port_found = false; 4662 cur_port = ports_B.get(cur_index); 4663 for (int prev_index = 0; 4664 prev_index < ports_A.size() && !cur_port_found; 4665 prev_index++) { 4666 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id()); 4667 } 4668 4669 if (!cur_port_found) { 4670 delta_ports.add(cur_port); 4671 } 4672 } 4673 4674 return infoListFromPortList(delta_ports, flags); 4675 } 4676 4677 /** 4678 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently 4679 * connected to the system and meeting the criteria specified in the <code>flags</code> 4680 * parameter. 4681 * This is an internal function. The public API front is getDevices(int). 4682 * @param flags A set of bitflags specifying the criteria to test. 4683 * @see #GET_DEVICES_OUTPUTS 4684 * @see #GET_DEVICES_INPUTS 4685 * @see #GET_DEVICES_ALL 4686 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 4687 * @hide 4688 */ getDevicesStatic(int flags)4689 public static AudioDeviceInfo[] getDevicesStatic(int flags) { 4690 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>(); 4691 int status = AudioManager.listAudioDevicePorts(ports); 4692 if (status != AudioManager.SUCCESS) { 4693 // fail and bail! 4694 return new AudioDeviceInfo[0]; // Always return an array. 4695 } 4696 4697 return infoListFromPortList(ports, flags); 4698 } 4699 4700 /** 4701 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes 4702 * to the set of connected audio devices. 4703 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect 4704 * notifications. 4705 * @param handler Specifies the {@link Handler} object for the thread on which to execute 4706 * the callback. If <code>null</code>, the {@link Handler} associated with the main 4707 * {@link Looper} will be used. 4708 */ registerAudioDeviceCallback(AudioDeviceCallback callback, android.os.Handler handler)4709 public void registerAudioDeviceCallback(AudioDeviceCallback callback, 4710 android.os.Handler handler) { 4711 synchronized (mDeviceCallbacks) { 4712 if (callback != null && !mDeviceCallbacks.containsKey(callback)) { 4713 if (mDeviceCallbacks.size() == 0) { 4714 if (mPortListener == null) { 4715 mPortListener = new OnAmPortUpdateListener(); 4716 } 4717 registerAudioPortUpdateListener(mPortListener); 4718 } 4719 NativeEventHandlerDelegate delegate = 4720 new NativeEventHandlerDelegate(callback, handler); 4721 mDeviceCallbacks.put(callback, delegate); 4722 broadcastDeviceListChange_sync(delegate.getHandler()); 4723 } 4724 } 4725 } 4726 4727 /** 4728 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered 4729 * to receive notifications of changes to the set of connected audio devices. 4730 * @param callback The {@link AudioDeviceCallback} object that was previously registered 4731 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered. 4732 */ unregisterAudioDeviceCallback(AudioDeviceCallback callback)4733 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) { 4734 synchronized (mDeviceCallbacks) { 4735 if (mDeviceCallbacks.containsKey(callback)) { 4736 mDeviceCallbacks.remove(callback); 4737 if (mDeviceCallbacks.size() == 0) { 4738 unregisterAudioPortUpdateListener(mPortListener); 4739 } 4740 } 4741 } 4742 } 4743 4744 /** 4745 * Set port id for microphones by matching device type and address. 4746 * @hide 4747 */ setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones)4748 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) { 4749 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS); 4750 for (int i = microphones.size() - 1; i >= 0; i--) { 4751 boolean foundPortId = false; 4752 for (AudioDeviceInfo device : devices) { 4753 if (device.getPort().type() == microphones.get(i).getInternalDeviceType() 4754 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) { 4755 microphones.get(i).setId(device.getId()); 4756 foundPortId = true; 4757 break; 4758 } 4759 } 4760 if (!foundPortId) { 4761 Log.i(TAG, "Failed to find port id for device with type:" 4762 + microphones.get(i).getType() + " address:" 4763 + microphones.get(i).getAddress()); 4764 microphones.remove(i); 4765 } 4766 } 4767 } 4768 4769 /** 4770 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}. 4771 * @hide 4772 */ microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo)4773 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) { 4774 int deviceType = deviceInfo.getType(); 4775 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC 4776 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY 4777 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN 4778 : MicrophoneInfo.LOCATION_PERIPHERAL; 4779 MicrophoneInfo microphone = new MicrophoneInfo( 4780 deviceInfo.getPort().name() + deviceInfo.getId(), 4781 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation, 4782 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN, 4783 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN, 4784 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(), 4785 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN, 4786 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN); 4787 microphone.setId(deviceInfo.getId()); 4788 return microphone; 4789 } 4790 4791 /** 4792 * Add {@link MicrophoneInfo} by device information while filtering certain types. 4793 */ addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, HashSet<Integer> filterTypes)4794 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, 4795 HashSet<Integer> filterTypes) { 4796 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS); 4797 for (AudioDeviceInfo device : devices) { 4798 if (filterTypes.contains(device.getType())) { 4799 continue; 4800 } 4801 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device); 4802 microphones.add(microphone); 4803 } 4804 } 4805 4806 /** 4807 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics 4808 * of all available microphones. The list is empty when no microphones are available 4809 * on the device. An error during the query will result in an IOException being thrown. 4810 * 4811 * @return a list that contains all microphones' characteristics 4812 * @throws IOException if an error occurs. 4813 */ getMicrophones()4814 public List<MicrophoneInfo> getMicrophones() throws IOException { 4815 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>(); 4816 int status = AudioSystem.getMicrophones(microphones); 4817 HashSet<Integer> filterTypes = new HashSet<>(); 4818 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY); 4819 if (status != AudioManager.SUCCESS) { 4820 // fail and populate microphones with unknown characteristics by device information. 4821 if (status != AudioManager.ERROR_INVALID_OPERATION) { 4822 Log.e(TAG, "getMicrophones failed:" + status); 4823 } 4824 Log.i(TAG, "fallback on device info"); 4825 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 4826 return microphones; 4827 } 4828 setPortIdForMicrophones(microphones); 4829 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC); 4830 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 4831 return microphones; 4832 } 4833 4834 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the 4835 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list 4836 // of the ports that exist at the time of the last notification. 4837 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>(); 4838 4839 /** 4840 * Internal method to compute and generate add/remove messages and then send to any 4841 * registered callbacks. Must be called synchronized on mDeviceCallbacks. 4842 */ broadcastDeviceListChange_sync(Handler handler)4843 private void broadcastDeviceListChange_sync(Handler handler) { 4844 int status; 4845 4846 // Get the new current set of ports 4847 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>(); 4848 status = AudioManager.listAudioDevicePorts(current_ports); 4849 if (status != AudioManager.SUCCESS) { 4850 return; 4851 } 4852 4853 if (handler != null) { 4854 // This is the callback for the registration, so send the current list 4855 AudioDeviceInfo[] deviceList = 4856 infoListFromPortList(current_ports, GET_DEVICES_ALL); 4857 handler.sendMessage( 4858 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList)); 4859 } else { 4860 AudioDeviceInfo[] added_devices = 4861 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL); 4862 AudioDeviceInfo[] removed_devices = 4863 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL); 4864 if (added_devices.length != 0 || removed_devices.length != 0) { 4865 for (int i = 0; i < mDeviceCallbacks.size(); i++) { 4866 handler = mDeviceCallbacks.valueAt(i).getHandler(); 4867 if (handler != null) { 4868 if (removed_devices.length != 0) { 4869 handler.sendMessage(Message.obtain(handler, 4870 MSG_DEVICES_DEVICES_REMOVED, 4871 removed_devices)); 4872 } 4873 if (added_devices.length != 0) { 4874 handler.sendMessage(Message.obtain(handler, 4875 MSG_DEVICES_DEVICES_ADDED, 4876 added_devices)); 4877 } 4878 } 4879 } 4880 } 4881 } 4882 4883 mPreviousPorts = current_ports; 4884 } 4885 4886 /** 4887 * Handles Port list update notifications from the AudioManager 4888 */ 4889 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener { 4890 static final String TAG = "OnAmPortUpdateListener"; onAudioPortListUpdate(AudioPort[] portList)4891 public void onAudioPortListUpdate(AudioPort[] portList) { 4892 synchronized (mDeviceCallbacks) { 4893 broadcastDeviceListChange_sync(null); 4894 } 4895 } 4896 4897 /** 4898 * Callback method called upon audio patch list update. 4899 * Note: We don't do anything with Patches at this time, so ignore this notification. 4900 * @param patchList the updated list of audio patches. 4901 */ onAudioPatchListUpdate(AudioPatch[] patchList)4902 public void onAudioPatchListUpdate(AudioPatch[] patchList) {} 4903 4904 /** 4905 * Callback method called when the mediaserver dies 4906 */ onServiceDied()4907 public void onServiceDied() { 4908 synchronized (mDeviceCallbacks) { 4909 broadcastDeviceListChange_sync(null); 4910 } 4911 } 4912 } 4913 4914 4915 /** 4916 * @hide 4917 * Abstract class to receive event notification about audioserver process state. 4918 */ 4919 @SystemApi 4920 public abstract static class AudioServerStateCallback { onAudioServerDown()4921 public void onAudioServerDown() { } onAudioServerUp()4922 public void onAudioServerUp() { } 4923 } 4924 4925 private Executor mAudioServerStateExec; 4926 private AudioServerStateCallback mAudioServerStateCb; 4927 private final Object mAudioServerStateCbLock = new Object(); 4928 4929 private final IAudioServerStateDispatcher mAudioServerStateDispatcher = 4930 new IAudioServerStateDispatcher.Stub() { 4931 @Override 4932 public void dispatchAudioServerStateChange(boolean state) { 4933 Executor exec; 4934 AudioServerStateCallback cb; 4935 4936 synchronized (mAudioServerStateCbLock) { 4937 exec = mAudioServerStateExec; 4938 cb = mAudioServerStateCb; 4939 } 4940 4941 if ((exec == null) || (cb == null)) { 4942 return; 4943 } 4944 if (state) { 4945 exec.execute(() -> cb.onAudioServerUp()); 4946 } else { 4947 exec.execute(() -> cb.onAudioServerDown()); 4948 } 4949 } 4950 }; 4951 4952 /** 4953 * @hide 4954 * Registers a callback for notification of audio server state changes. 4955 * @param executor {@link Executor} to handle the callbacks 4956 * @param stateCallback the callback to receive the audio server state changes 4957 * To remove the callabck, pass a null reference for both executor and stateCallback. 4958 */ 4959 @SystemApi setAudioServerStateCallback(@onNull Executor executor, @NonNull AudioServerStateCallback stateCallback)4960 public void setAudioServerStateCallback(@NonNull Executor executor, 4961 @NonNull AudioServerStateCallback stateCallback) { 4962 if (stateCallback == null) { 4963 throw new IllegalArgumentException("Illegal null AudioServerStateCallback"); 4964 } 4965 if (executor == null) { 4966 throw new IllegalArgumentException( 4967 "Illegal null Executor for the AudioServerStateCallback"); 4968 } 4969 4970 synchronized (mAudioServerStateCbLock) { 4971 if (mAudioServerStateCb != null) { 4972 throw new IllegalStateException( 4973 "setAudioServerStateCallback called with already registered callabck"); 4974 } 4975 final IAudioService service = getService(); 4976 try { 4977 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher); 4978 } catch (RemoteException e) { 4979 throw e.rethrowFromSystemServer(); 4980 } 4981 mAudioServerStateExec = executor; 4982 mAudioServerStateCb = stateCallback; 4983 } 4984 } 4985 4986 /** 4987 * @hide 4988 * Unregisters the callback for notification of audio server state changes. 4989 */ 4990 @SystemApi clearAudioServerStateCallback()4991 public void clearAudioServerStateCallback() { 4992 synchronized (mAudioServerStateCbLock) { 4993 if (mAudioServerStateCb != null) { 4994 final IAudioService service = getService(); 4995 try { 4996 service.unregisterAudioServerStateDispatcher( 4997 mAudioServerStateDispatcher); 4998 } catch (RemoteException e) { 4999 throw e.rethrowFromSystemServer(); 5000 } 5001 } 5002 mAudioServerStateExec = null; 5003 mAudioServerStateCb = null; 5004 } 5005 } 5006 5007 /** 5008 * @hide 5009 * Checks if native audioservice is running or not. 5010 * @return true if native audioservice runs, false otherwise. 5011 */ 5012 @SystemApi isAudioServerRunning()5013 public boolean isAudioServerRunning() { 5014 final IAudioService service = getService(); 5015 try { 5016 return service.isAudioServerRunning(); 5017 } catch (RemoteException e) { 5018 throw e.rethrowFromSystemServer(); 5019 } 5020 } 5021 5022 /** 5023 * @hide 5024 * Returns all surround formats. 5025 * @return a map where the key is a surround format and 5026 * the value indicates the surround format is enabled or not 5027 */ getSurroundFormats()5028 public Map<Integer, Boolean> getSurroundFormats() { 5029 Map<Integer, Boolean> surroundFormats = new HashMap<>(); 5030 int status = AudioSystem.getSurroundFormats(surroundFormats, false); 5031 if (status != AudioManager.SUCCESS) { 5032 // fail and bail! 5033 Log.e(TAG, "getSurroundFormats failed:" + status); 5034 return new HashMap<Integer, Boolean>(); // Always return a map. 5035 } 5036 return surroundFormats; 5037 } 5038 5039 /** 5040 * @hide 5041 * Set a certain surround format as enabled or not. 5042 * @param audioFormat a surround format, the value is one of 5043 * {@link AudioFormat#ENCODING_AC3}, {@link AudioFormat#ENCODING_E_AC3}, 5044 * {@link AudioFormat#ENCODING_DTS}, {@link AudioFormat#ENCODING_DTS_HD}, 5045 * {@link AudioFormat#ENCODING_AAC_LC}, {@link AudioFormat#ENCODING_DOLBY_TRUEHD}, 5046 * {@link AudioFormat#ENCODING_E_AC3_JOC}. Once {@link AudioFormat#ENCODING_AAC_LC} is 5047 * set as enabled, {@link AudioFormat#ENCODING_AAC_LC}, 5048 * {@link AudioFormat#ENCODING_AAC_HE_V1}, {@link AudioFormat#ENCODING_AAC_HE_V2}, 5049 * {@link AudioFormat#ENCODING_AAC_ELD}, {@link AudioFormat#ENCODING_AAC_XHE} are 5050 * all enabled. 5051 * @param enabled the required surround format state, true for enabled, false for disabled 5052 * @return true if successful, otherwise false 5053 */ setSurroundFormatEnabled( @udioFormat.SurroundSoundEncoding int audioFormat, boolean enabled)5054 public boolean setSurroundFormatEnabled( 5055 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) { 5056 int status = AudioSystem.setSurroundFormatEnabled(audioFormat, enabled); 5057 return status == AudioManager.SUCCESS; 5058 } 5059 5060 /** 5061 * @hide 5062 * Returns all surround formats that are reported by the connected HDMI device. 5063 * The keys are not affected by calling setSurroundFormatEnabled(), and the values 5064 * are not affected by calling setSurroundFormatEnabled() when in AUTO mode. 5065 * This information can used to show the AUTO setting for SurroundSound. 5066 * 5067 * @return a map where the key is a surround format and 5068 * the value indicates the surround format is enabled or not 5069 */ getReportedSurroundFormats()5070 public Map<Integer, Boolean> getReportedSurroundFormats() { 5071 Map<Integer, Boolean> reportedSurroundFormats = new HashMap<>(); 5072 int status = AudioSystem.getSurroundFormats(reportedSurroundFormats, true); 5073 if (status != AudioManager.SUCCESS) { 5074 // fail and bail! 5075 Log.e(TAG, "getReportedSurroundFormats failed:" + status); 5076 return new HashMap<Integer, Boolean>(); // Always return a map. 5077 } 5078 return reportedSurroundFormats; 5079 } 5080 5081 5082 //--------------------------------------------------------- 5083 // Inner classes 5084 //-------------------- 5085 /** 5086 * Helper class to handle the forwarding of native events to the appropriate listener 5087 * (potentially) handled in a different thread. 5088 */ 5089 private class NativeEventHandlerDelegate { 5090 private final Handler mHandler; 5091 NativeEventHandlerDelegate(final AudioDeviceCallback callback, Handler handler)5092 NativeEventHandlerDelegate(final AudioDeviceCallback callback, 5093 Handler handler) { 5094 // find the looper for our new event handler 5095 Looper looper; 5096 if (handler != null) { 5097 looper = handler.getLooper(); 5098 } else { 5099 // no given handler, use the looper the addListener call was called in 5100 looper = Looper.getMainLooper(); 5101 } 5102 5103 // construct the event handler with this looper 5104 if (looper != null) { 5105 // implement the event handler delegate 5106 mHandler = new Handler(looper) { 5107 @Override 5108 public void handleMessage(Message msg) { 5109 switch(msg.what) { 5110 case MSG_DEVICES_CALLBACK_REGISTERED: 5111 case MSG_DEVICES_DEVICES_ADDED: 5112 if (callback != null) { 5113 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj); 5114 } 5115 break; 5116 5117 case MSG_DEVICES_DEVICES_REMOVED: 5118 if (callback != null) { 5119 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj); 5120 } 5121 break; 5122 5123 default: 5124 Log.e(TAG, "Unknown native event type: " + msg.what); 5125 break; 5126 } 5127 } 5128 }; 5129 } else { 5130 mHandler = null; 5131 } 5132 } 5133 getHandler()5134 Handler getHandler() { 5135 return mHandler; 5136 } 5137 } 5138 } 5139