1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.audio; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.bluetooth.BluetoothA2dp; 21 import android.bluetooth.BluetoothDevice; 22 import android.bluetooth.BluetoothHeadset; 23 import android.bluetooth.BluetoothHearingAid; 24 import android.bluetooth.BluetoothProfile; 25 import android.content.ContentResolver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.media.AudioAttributes; 29 import android.media.AudioDeviceAttributes; 30 import android.media.AudioDeviceInfo; 31 import android.media.AudioManager; 32 import android.media.AudioRoutesInfo; 33 import android.media.AudioSystem; 34 import android.media.IAudioRoutesObserver; 35 import android.media.ICapturePresetDevicesRoleDispatcher; 36 import android.media.ICommunicationDeviceDispatcher; 37 import android.media.IStrategyPreferredDevicesDispatcher; 38 import android.media.MediaMetrics; 39 import android.media.audiopolicy.AudioProductStrategy; 40 import android.os.Binder; 41 import android.os.Handler; 42 import android.os.IBinder; 43 import android.os.Looper; 44 import android.os.Message; 45 import android.os.PowerManager; 46 import android.os.RemoteCallbackList; 47 import android.os.RemoteException; 48 import android.os.SystemClock; 49 import android.os.UserHandle; 50 import android.text.TextUtils; 51 import android.util.Log; 52 import android.util.PrintWriterPrinter; 53 54 import com.android.internal.annotations.GuardedBy; 55 56 import java.io.PrintWriter; 57 import java.util.Arrays; 58 import java.util.HashSet; 59 import java.util.LinkedList; 60 import java.util.List; 61 import java.util.NoSuchElementException; 62 import java.util.Set; 63 import java.util.concurrent.atomic.AtomicBoolean; 64 65 66 /** @hide */ 67 /*package*/ final class AudioDeviceBroker { 68 69 private static final String TAG = "AS.AudioDeviceBroker"; 70 71 private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s 72 73 /*package*/ static final int BTA2DP_DOCK_TIMEOUT_MS = 8000; 74 // Timeout for connection to bluetooth headset service 75 /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 76 77 // Delay before checking it music should be unmuted after processing an A2DP message 78 private static final int BTA2DP_MUTE_CHECK_DELAY_MS = 100; 79 80 private final @NonNull AudioService mAudioService; 81 private final @NonNull Context mContext; 82 83 /** ID for Communication strategy retrieved form audio policy manager */ 84 private int mCommunicationStrategyId = -1; 85 /** Active communication device reported by audio policy manager */ 86 private AudioDeviceInfo mActiveCommunicationDevice; 87 /** Last preferred device set for communication strategy */ 88 private AudioDeviceAttributes mPreferredCommunicationDevice; 89 90 // Manages all connected devices, only ever accessed on the message loop 91 private final AudioDeviceInventory mDeviceInventory; 92 // Manages notifications to BT service 93 private final BtHelper mBtHelper; 94 // Adapter for system_server-reserved operations 95 private final SystemServerAdapter mSystemServer; 96 97 98 //------------------------------------------------------------------- 99 // we use a different lock than mDeviceStateLock so as not to create 100 // lock contention between enqueueing a message and handling them 101 private static final Object sLastDeviceConnectionMsgTimeLock = new Object(); 102 @GuardedBy("sLastDeviceConnectionMsgTimeLock") 103 private static long sLastDeviceConnectMsgTime = 0; 104 105 // General lock to be taken whenever the state of the audio devices is to be checked or changed 106 private final Object mDeviceStateLock = new Object(); 107 108 // Request to override default use of A2DP for media. 109 @GuardedBy("mDeviceStateLock") 110 private boolean mBluetoothA2dpEnabled; 111 112 // lock always taken when accessing AudioService.mSetModeDeathHandlers 113 // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055 114 /*package*/ final Object mSetModeLock = new Object(); 115 116 /** PID of current audio mode owner communicated by AudioService */ 117 private int mModeOwnerPid = 0; 118 119 //------------------------------------------------------------------- AudioDeviceBroker(@onNull Context context, @NonNull AudioService service)120 /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) { 121 mContext = context; 122 mAudioService = service; 123 mBtHelper = new BtHelper(this); 124 mDeviceInventory = new AudioDeviceInventory(this); 125 mSystemServer = SystemServerAdapter.getDefaultAdapter(mContext); 126 127 init(); 128 } 129 130 /** for test purposes only, inject AudioDeviceInventory and adapter for operations running 131 * in system_server */ AudioDeviceBroker(@onNull Context context, @NonNull AudioService service, @NonNull AudioDeviceInventory mockDeviceInventory, @NonNull SystemServerAdapter mockSystemServer)132 AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service, 133 @NonNull AudioDeviceInventory mockDeviceInventory, 134 @NonNull SystemServerAdapter mockSystemServer) { 135 mContext = context; 136 mAudioService = service; 137 mBtHelper = new BtHelper(this); 138 mDeviceInventory = mockDeviceInventory; 139 mSystemServer = mockSystemServer; 140 141 init(); 142 } 143 initCommunicationStrategyId()144 private void initCommunicationStrategyId() { 145 List<AudioProductStrategy> strategies = AudioProductStrategy.getAudioProductStrategies(); 146 for (AudioProductStrategy strategy : strategies) { 147 if (strategy.getAudioAttributesForLegacyStreamType(AudioSystem.STREAM_VOICE_CALL) 148 != null) { 149 mCommunicationStrategyId = strategy.getId(); 150 return; 151 } 152 } 153 mCommunicationStrategyId = -1; 154 } 155 init()156 private void init() { 157 setupMessaging(mContext); 158 159 initCommunicationStrategyId(); 160 mPreferredCommunicationDevice = null; 161 updateActiveCommunicationDevice(); 162 163 mSystemServer.registerUserStartedReceiver(mContext); 164 } 165 getContext()166 /*package*/ Context getContext() { 167 return mContext; 168 } 169 170 //--------------------------------------------------------------------- 171 // Communication from AudioService 172 // All methods are asynchronous and never block 173 // All permission checks are done in AudioService, all incoming calls are considered "safe" 174 // All post* methods are asynchronous 175 onSystemReady()176 /*package*/ void onSystemReady() { 177 synchronized (mSetModeLock) { 178 synchronized (mDeviceStateLock) { 179 mModeOwnerPid = mAudioService.getModeOwnerPid(); 180 mBtHelper.onSystemReady(); 181 } 182 } 183 } 184 onAudioServerDied()185 /*package*/ void onAudioServerDied() { 186 // restore devices 187 sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE); 188 } 189 setForceUse_Async(int useCase, int config, String eventSource)190 /*package*/ void setForceUse_Async(int useCase, int config, String eventSource) { 191 sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE, 192 useCase, config, eventSource); 193 } 194 toggleHdmiIfConnected_Async()195 /*package*/ void toggleHdmiIfConnected_Async() { 196 sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE); 197 } 198 disconnectAllBluetoothProfiles()199 /*package*/ void disconnectAllBluetoothProfiles() { 200 synchronized (mDeviceStateLock) { 201 mBtHelper.disconnectAllBluetoothProfiles(); 202 } 203 } 204 205 /** 206 * Handle BluetoothHeadset intents where the action is one of 207 * {@link BluetoothHeadset#ACTION_ACTIVE_DEVICE_CHANGED} or 208 * {@link BluetoothHeadset#ACTION_AUDIO_STATE_CHANGED}. 209 * @param intent 210 */ receiveBtEvent(@onNull Intent intent)211 /*package*/ void receiveBtEvent(@NonNull Intent intent) { 212 synchronized (mSetModeLock) { 213 synchronized (mDeviceStateLock) { 214 mBtHelper.receiveBtEvent(intent); 215 } 216 } 217 } 218 setBluetoothA2dpOn_Async(boolean on, String source)219 /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) { 220 synchronized (mDeviceStateLock) { 221 if (mBluetoothA2dpEnabled == on) { 222 return; 223 } 224 mBluetoothA2dpEnabled = on; 225 mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE); 226 sendIILMsgNoDelay(MSG_IIL_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE, 227 AudioSystem.FOR_MEDIA, 228 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, 229 source); 230 } 231 } 232 233 /** 234 * Turns speakerphone on/off 235 * @param on 236 * @param eventSource for logging purposes 237 */ setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource)238 /*package*/ void setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource) { 239 240 if (AudioService.DEBUG_COMM_RTE) { 241 Log.v(TAG, "setSpeakerphoneOn, on: " + on + " pid: " + pid); 242 } 243 244 synchronized (mSetModeLock) { 245 synchronized (mDeviceStateLock) { 246 AudioDeviceAttributes device = null; 247 if (on) { 248 device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""); 249 } else { 250 CommunicationRouteClient client = getCommunicationRouteClientForPid(pid); 251 if (client == null || !client.requestsSpeakerphone()) { 252 return; 253 } 254 } 255 setCommunicationRouteForClient( 256 cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource); 257 } 258 } 259 } 260 261 /** 262 * Select device for use for communication use cases. 263 * @param cb Client binder for death detection 264 * @param pid Client pid 265 * @param device Device selected or null to unselect. 266 * @param eventSource for logging purposes 267 */ setCommunicationDevice( IBinder cb, int pid, AudioDeviceInfo device, String eventSource)268 /*package*/ boolean setCommunicationDevice( 269 IBinder cb, int pid, AudioDeviceInfo device, String eventSource) { 270 271 if (AudioService.DEBUG_COMM_RTE) { 272 Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid); 273 } 274 275 synchronized (mSetModeLock) { 276 synchronized (mDeviceStateLock) { 277 AudioDeviceAttributes deviceAttr = null; 278 if (device != null) { 279 deviceAttr = new AudioDeviceAttributes(device); 280 } else { 281 CommunicationRouteClient client = getCommunicationRouteClientForPid(pid); 282 if (client == null) { 283 return false; 284 } 285 } 286 setCommunicationRouteForClient( 287 cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource); 288 } 289 } 290 return true; 291 } 292 293 @GuardedBy("mDeviceStateLock") setCommunicationRouteForClient( IBinder cb, int pid, AudioDeviceAttributes device, int scoAudioMode, String eventSource)294 /*package*/ void setCommunicationRouteForClient( 295 IBinder cb, int pid, AudioDeviceAttributes device, 296 int scoAudioMode, String eventSource) { 297 298 if (AudioService.DEBUG_COMM_RTE) { 299 Log.v(TAG, "setCommunicationRouteForClient: device: " + device); 300 } 301 AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( 302 "setCommunicationRouteForClient for pid: " + pid 303 + " device: " + device 304 + " from API: " + eventSource)).printLog(TAG)); 305 306 final boolean wasBtScoRequested = isBluetoothScoRequested(); 307 CommunicationRouteClient client; 308 309 310 // Save previous client route in case of failure to start BT SCO audio 311 AudioDeviceAttributes prevClientDevice = null; 312 client = getCommunicationRouteClientForPid(pid); 313 if (client != null) { 314 prevClientDevice = client.getDevice(); 315 } 316 317 if (device != null) { 318 client = addCommunicationRouteClient(cb, pid, device); 319 if (client == null) { 320 Log.w(TAG, "setCommunicationRouteForClient: could not add client for pid: " 321 + pid + " and device: " + device); 322 } 323 } else { 324 client = removeCommunicationRouteClient(cb, true); 325 } 326 if (client == null) { 327 return; 328 } 329 330 boolean isBtScoRequested = isBluetoothScoRequested(); 331 if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive())) { 332 if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) { 333 Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for pid: " 334 + pid); 335 // clean up or restore previous client selection 336 if (prevClientDevice != null) { 337 addCommunicationRouteClient(cb, pid, prevClientDevice); 338 } else { 339 removeCommunicationRouteClient(cb, true); 340 } 341 postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 342 } 343 } else if (!isBtScoRequested && wasBtScoRequested) { 344 mBtHelper.stopBluetoothSco(eventSource); 345 } 346 347 sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); 348 } 349 350 /** 351 * Returns the device currently requested for communication use case. 352 * If the current audio mode owner is in the communication route client list, 353 * use this preference. 354 * Otherwise use first client's preference (first client corresponds to latest request). 355 * null is returned if no client is in the list. 356 * @return AudioDeviceAttributes the requested device for communication. 357 */ 358 359 @GuardedBy("mDeviceStateLock") requestedCommunicationDevice()360 private AudioDeviceAttributes requestedCommunicationDevice() { 361 AudioDeviceAttributes device = null; 362 for (CommunicationRouteClient cl : mCommunicationRouteClients) { 363 if (cl.getPid() == mModeOwnerPid) { 364 device = cl.getDevice(); 365 } 366 } 367 if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) { 368 device = mCommunicationRouteClients.get(0).getDevice(); 369 } 370 371 if (AudioService.DEBUG_COMM_RTE) { 372 Log.v(TAG, "requestedCommunicationDevice, device: " 373 + device + " mode owner pid: " + mModeOwnerPid); 374 } 375 return device; 376 } 377 378 /** 379 * Returns the device currently requested for communication use case. 380 * @return AudioDeviceInfo the requested device for communication. 381 */ getCommunicationDevice()382 /* package */ AudioDeviceInfo getCommunicationDevice() { 383 synchronized (mDeviceStateLock) { 384 updateActiveCommunicationDevice(); 385 return mActiveCommunicationDevice; 386 } 387 } 388 389 /** 390 * Updates currently active communication device (mActiveCommunicationDevice). 391 */ 392 @GuardedBy("mDeviceStateLock") updateActiveCommunicationDevice()393 void updateActiveCommunicationDevice() { 394 AudioDeviceAttributes device = preferredCommunicationDevice(); 395 if (device == null) { 396 AudioAttributes attr = 397 AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( 398 AudioSystem.STREAM_VOICE_CALL); 399 List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr); 400 if (devices.isEmpty()) { 401 if (mAudioService.isPlatformVoice()) { 402 Log.w(TAG, 403 "updateActiveCommunicationDevice(): no device for phone strategy"); 404 } 405 mActiveCommunicationDevice = null; 406 return; 407 } 408 device = devices.get(0); 409 } 410 mActiveCommunicationDevice = AudioManager.getDeviceInfoFromTypeAndAddress( 411 device.getType(), device.getAddress()); 412 } 413 414 /** 415 * Indicates if the device which type is passed as argument is currently resquested to be used 416 * for communication. 417 * @param deviceType the device type the query applies to. 418 * @return true if this device type is requested for communication. 419 */ isDeviceRequestedForCommunication(int deviceType)420 private boolean isDeviceRequestedForCommunication(int deviceType) { 421 synchronized (mDeviceStateLock) { 422 AudioDeviceAttributes device = requestedCommunicationDevice(); 423 return device != null && device.getType() == deviceType; 424 } 425 } 426 427 /** 428 * Indicates if the device which type is passed as argument is currently either resquested 429 * to be used for communication or selected for an other reason (e.g bluetooth SCO audio 430 * is active for SCO device). 431 * @param deviceType the device type the query applies to. 432 * @return true if this device type is requested for communication. 433 */ isDeviceOnForCommunication(int deviceType)434 private boolean isDeviceOnForCommunication(int deviceType) { 435 synchronized (mDeviceStateLock) { 436 AudioDeviceAttributes device = preferredCommunicationDevice(); 437 return device != null && device.getType() == deviceType; 438 } 439 } 440 441 /** 442 * Indicates if the device which type is passed as argument is active for communication. 443 * Active means not only currently used by audio policy manager for communication strategy 444 * but also explicitly requested for use by communication strategy. 445 * @param deviceType the device type the query applies to. 446 * @return true if this device type is requested for communication. 447 */ isDeviceActiveForCommunication(int deviceType)448 private boolean isDeviceActiveForCommunication(int deviceType) { 449 return mActiveCommunicationDevice != null 450 && mActiveCommunicationDevice.getType() == deviceType 451 && mPreferredCommunicationDevice != null 452 && mPreferredCommunicationDevice.getType() == deviceType; 453 } 454 455 /** 456 * Helper method on top of isDeviceRequestedForCommunication() indicating if 457 * speakerphone ON is currently requested or not. 458 * @return true if speakerphone ON requested, false otherwise. 459 */ isSpeakerphoneRequested()460 private boolean isSpeakerphoneRequested() { 461 return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 462 } 463 464 /** 465 * Indicates if preferred route selection for communication is speakerphone. 466 * @return true if speakerphone is active, false otherwise. 467 */ isSpeakerphoneOn()468 /*package*/ boolean isSpeakerphoneOn() { 469 return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 470 } 471 isSpeakerphoneActive()472 private boolean isSpeakerphoneActive() { 473 return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 474 } 475 476 /** 477 * Helper method on top of isDeviceRequestedForCommunication() indicating if 478 * Bluetooth SCO ON is currently requested or not. 479 * @return true if Bluetooth SCO ON is requested, false otherwise. 480 */ isBluetoothScoRequested()481 /*package*/ boolean isBluetoothScoRequested() { 482 return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); 483 } 484 485 /** 486 * Indicates if preferred route selection for communication is Bluetooth SCO. 487 * @return true if Bluetooth SCO is preferred , false otherwise. 488 */ isBluetoothScoOn()489 /*package*/ boolean isBluetoothScoOn() { 490 return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); 491 } 492 isBluetoothScoActive()493 /*package*/ boolean isBluetoothScoActive() { 494 return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); 495 } 496 setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state, String address, String name, String caller)497 /*package*/ void setWiredDeviceConnectionState(int type, 498 @AudioService.ConnectionState int state, String address, String name, 499 String caller) { 500 //TODO move logging here just like in setBluetooth* methods 501 synchronized (mDeviceStateLock) { 502 mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller); 503 } 504 } 505 506 /*package*/ static final class BtDeviceConnectionInfo { 507 final @NonNull BluetoothDevice mDevice; 508 final @AudioService.BtProfileConnectionState int mState; 509 final int mProfile; 510 final boolean mSupprNoisy; 511 final int mVolume; 512 BtDeviceConnectionInfo(@onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int vol)513 BtDeviceConnectionInfo(@NonNull BluetoothDevice device, 514 @AudioService.BtProfileConnectionState int state, 515 int profile, boolean suppressNoisyIntent, int vol) { 516 mDevice = device; 517 mState = state; 518 mProfile = profile; 519 mSupprNoisy = suppressNoisyIntent; 520 mVolume = vol; 521 } 522 BtDeviceConnectionInfo(@onNull BtDeviceConnectionInfo info)523 BtDeviceConnectionInfo(@NonNull BtDeviceConnectionInfo info) { 524 mDevice = info.mDevice; 525 mState = info.mState; 526 mProfile = info.mProfile; 527 mSupprNoisy = info.mSupprNoisy; 528 mVolume = info.mVolume; 529 } 530 531 // redefine equality op so we can match messages intended for this device 532 @Override equals(Object o)533 public boolean equals(Object o) { 534 if (o == null) { 535 return false; 536 } 537 if (this == o) { 538 return true; 539 } 540 if (o instanceof BtDeviceConnectionInfo) { 541 return mDevice.equals(((BtDeviceConnectionInfo) o).mDevice); 542 } 543 return false; 544 } 545 546 @Override toString()547 public String toString() { 548 return "BtDeviceConnectionInfo dev=" + mDevice.toString(); 549 } 550 } 551 552 /** 553 * will block on mDeviceStateLock, which is held during an A2DP (dis) connection 554 * not just a simple message post 555 * @param info struct with the (dis)connection information 556 */ queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( @onNull BtDeviceConnectionInfo info)557 /*package*/ void queueBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( 558 @NonNull BtDeviceConnectionInfo info) { 559 final String name = TextUtils.emptyIfNull(info.mDevice.getName()); 560 new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR 561 + "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent") 562 .set(MediaMetrics.Property.STATE, info.mState == BluetoothProfile.STATE_CONNECTED 563 ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) 564 .set(MediaMetrics.Property.INDEX, info.mVolume) 565 .set(MediaMetrics.Property.NAME, name) 566 .record(); 567 568 // operations of removing and posting messages related to A2DP device state change must be 569 // mutually exclusive 570 synchronized (mDeviceStateLock) { 571 // when receiving a request to change the connection state of a device, this last 572 // request is the source of truth, so cancel all previous requests that are already in 573 // the handler 574 removeScheduledA2dpEvents(info.mDevice); 575 576 sendLMsgNoDelay( 577 info.mState == BluetoothProfile.STATE_CONNECTED 578 ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION 579 : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, 580 SENDMSG_QUEUE, info); 581 } 582 } 583 584 /** remove all previously scheduled connection and state change events for the given device */ 585 @GuardedBy("mDeviceStateLock") removeScheduledA2dpEvents(@onNull BluetoothDevice device)586 private void removeScheduledA2dpEvents(@NonNull BluetoothDevice device) { 587 mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, device); 588 589 final BtDeviceConnectionInfo connectionInfoToRemove = new BtDeviceConnectionInfo(device, 590 // the next parameters of the constructor will be ignored when finding the message 591 // to remove as the equality of the message's object is tested on the device itself 592 // (see BtDeviceConnectionInfo.equals() method override) 593 BluetoothProfile.STATE_CONNECTED, 0, false, -1); 594 mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, 595 connectionInfoToRemove); 596 mBrokerHandler.removeEqualMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION, 597 connectionInfoToRemove); 598 599 final BtHelper.BluetoothA2dpDeviceInfo devInfoToRemove = 600 new BtHelper.BluetoothA2dpDeviceInfo(device); 601 mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, 602 devInfoToRemove); 603 mBrokerHandler.removeEqualMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, 604 devInfoToRemove); 605 mBrokerHandler.removeEqualMessages(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, 606 devInfoToRemove); 607 } 608 609 private static final class HearingAidDeviceConnectionInfo { 610 final @NonNull BluetoothDevice mDevice; 611 final @AudioService.BtProfileConnectionState int mState; 612 final boolean mSupprNoisy; 613 final int mMusicDevice; 614 final @NonNull String mEventSource; 615 HearingAidDeviceConnectionInfo(@onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource)616 HearingAidDeviceConnectionInfo(@NonNull BluetoothDevice device, 617 @AudioService.BtProfileConnectionState int state, 618 boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) { 619 mDevice = device; 620 mState = state; 621 mSupprNoisy = suppressNoisyIntent; 622 mMusicDevice = musicDevice; 623 mEventSource = eventSource; 624 } 625 } 626 postBluetoothHearingAidDeviceConnectionState( @onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource)627 /*package*/ void postBluetoothHearingAidDeviceConnectionState( 628 @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, 629 boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) { 630 final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo( 631 device, state, suppressNoisyIntent, musicDevice, eventSource); 632 sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); 633 } 634 635 636 /** 637 * Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn(). 638 */ 639 private boolean mBluetoothScoOn; 640 setBluetoothScoOn(boolean on, String eventSource)641 /*package*/ void setBluetoothScoOn(boolean on, String eventSource) { 642 if (AudioService.DEBUG_COMM_RTE) { 643 Log.v(TAG, "setBluetoothScoOn: " + on + " " + eventSource); 644 } 645 synchronized (mDeviceStateLock) { 646 mBluetoothScoOn = on; 647 sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource); 648 } 649 } 650 startWatchingRoutes(IAudioRoutesObserver observer)651 /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { 652 synchronized (mDeviceStateLock) { 653 return mDeviceInventory.startWatchingRoutes(observer); 654 } 655 } 656 getCurAudioRoutes()657 /*package*/ AudioRoutesInfo getCurAudioRoutes() { 658 synchronized (mDeviceStateLock) { 659 return mDeviceInventory.getCurAudioRoutes(); 660 } 661 } 662 isAvrcpAbsoluteVolumeSupported()663 /*package*/ boolean isAvrcpAbsoluteVolumeSupported() { 664 synchronized (mDeviceStateLock) { 665 return mBtHelper.isAvrcpAbsoluteVolumeSupported(); 666 } 667 } 668 isBluetoothA2dpOn()669 /*package*/ boolean isBluetoothA2dpOn() { 670 synchronized (mDeviceStateLock) { 671 return mBluetoothA2dpEnabled; 672 } 673 } 674 postSetAvrcpAbsoluteVolumeIndex(int index)675 /*package*/ void postSetAvrcpAbsoluteVolumeIndex(int index) { 676 sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index); 677 } 678 postSetHearingAidVolumeIndex(int index, int streamType)679 /*package*/ void postSetHearingAidVolumeIndex(int index, int streamType) { 680 sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType); 681 } 682 postSetModeOwnerPid(int pid, int mode)683 /*package*/ void postSetModeOwnerPid(int pid, int mode) { 684 sendIIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid, mode); 685 } 686 postBluetoothA2dpDeviceConfigChange(@onNull BluetoothDevice device)687 /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) { 688 sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device); 689 } 690 startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode, @NonNull String eventSource)691 /*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode, 692 @NonNull String eventSource) { 693 694 if (AudioService.DEBUG_COMM_RTE) { 695 Log.v(TAG, "startBluetoothScoForClient_Sync, pid: " + pid); 696 } 697 698 synchronized (mSetModeLock) { 699 synchronized (mDeviceStateLock) { 700 AudioDeviceAttributes device = 701 new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""); 702 setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource); 703 } 704 } 705 } 706 stopBluetoothScoForClient( IBinder cb, int pid, @NonNull String eventSource)707 /*package*/ void stopBluetoothScoForClient( 708 IBinder cb, int pid, @NonNull String eventSource) { 709 710 if (AudioService.DEBUG_COMM_RTE) { 711 Log.v(TAG, "stopBluetoothScoForClient_Sync, pid: " + pid); 712 } 713 714 synchronized (mSetModeLock) { 715 synchronized (mDeviceStateLock) { 716 CommunicationRouteClient client = getCommunicationRouteClientForPid(pid); 717 if (client == null || !client.requestsBluetoothSco()) { 718 return; 719 } 720 setCommunicationRouteForClient( 721 cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource); 722 } 723 } 724 } 725 setPreferredDevicesForStrategySync(int strategy, @NonNull List<AudioDeviceAttributes> devices)726 /*package*/ int setPreferredDevicesForStrategySync(int strategy, 727 @NonNull List<AudioDeviceAttributes> devices) { 728 return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices); 729 } 730 postSetPreferredDevicesForStrategy(int strategy, @NonNull List<AudioDeviceAttributes> devices)731 /*package*/ void postSetPreferredDevicesForStrategy(int strategy, 732 @NonNull List<AudioDeviceAttributes> devices) { 733 sendILMsgNoDelay(MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy, devices); 734 } 735 removePreferredDevicesForStrategySync(int strategy)736 /*package*/ int removePreferredDevicesForStrategySync(int strategy) { 737 return mDeviceInventory.removePreferredDevicesForStrategySync(strategy); 738 } 739 postRemovePreferredDevicesForStrategy(int strategy)740 /*package*/ void postRemovePreferredDevicesForStrategy(int strategy) { 741 sendIMsgNoDelay(MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy); 742 } 743 registerStrategyPreferredDevicesDispatcher( @onNull IStrategyPreferredDevicesDispatcher dispatcher)744 /*package*/ void registerStrategyPreferredDevicesDispatcher( 745 @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { 746 mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher); 747 } 748 unregisterStrategyPreferredDevicesDispatcher( @onNull IStrategyPreferredDevicesDispatcher dispatcher)749 /*package*/ void unregisterStrategyPreferredDevicesDispatcher( 750 @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { 751 mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher); 752 } 753 setPreferredDevicesForCapturePresetSync(int capturePreset, @NonNull List<AudioDeviceAttributes> devices)754 /*package*/ int setPreferredDevicesForCapturePresetSync(int capturePreset, 755 @NonNull List<AudioDeviceAttributes> devices) { 756 return mDeviceInventory.setPreferredDevicesForCapturePresetSync(capturePreset, devices); 757 } 758 clearPreferredDevicesForCapturePresetSync(int capturePreset)759 /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) { 760 return mDeviceInventory.clearPreferredDevicesForCapturePresetSync(capturePreset); 761 } 762 registerCapturePresetDevicesRoleDispatcher( @onNull ICapturePresetDevicesRoleDispatcher dispatcher)763 /*package*/ void registerCapturePresetDevicesRoleDispatcher( 764 @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) { 765 mDeviceInventory.registerCapturePresetDevicesRoleDispatcher(dispatcher); 766 } 767 unregisterCapturePresetDevicesRoleDispatcher( @onNull ICapturePresetDevicesRoleDispatcher dispatcher)768 /*package*/ void unregisterCapturePresetDevicesRoleDispatcher( 769 @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) { 770 mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher); 771 } 772 registerCommunicationDeviceDispatcher( @onNull ICommunicationDeviceDispatcher dispatcher)773 /*package*/ void registerCommunicationDeviceDispatcher( 774 @NonNull ICommunicationDeviceDispatcher dispatcher) { 775 mCommDevDispatchers.register(dispatcher); 776 } 777 unregisterCommunicationDeviceDispatcher( @onNull ICommunicationDeviceDispatcher dispatcher)778 /*package*/ void unregisterCommunicationDeviceDispatcher( 779 @NonNull ICommunicationDeviceDispatcher dispatcher) { 780 mCommDevDispatchers.unregister(dispatcher); 781 } 782 783 // Monitoring of communication device 784 final RemoteCallbackList<ICommunicationDeviceDispatcher> mCommDevDispatchers = 785 new RemoteCallbackList<ICommunicationDeviceDispatcher>(); 786 787 // portId of the device currently selected for communication: avoids broadcasting changes 788 // when same communication route is applied 789 @GuardedBy("mDeviceStateLock") 790 int mCurCommunicationPortId = -1; 791 792 @GuardedBy("mDeviceStateLock") dispatchCommunicationDevice()793 private void dispatchCommunicationDevice() { 794 int portId = (mActiveCommunicationDevice == null) ? 0 795 : mActiveCommunicationDevice.getId(); 796 if (portId == mCurCommunicationPortId) { 797 return; 798 } 799 mCurCommunicationPortId = portId; 800 801 final int nbDispatchers = mCommDevDispatchers.beginBroadcast(); 802 for (int i = 0; i < nbDispatchers; i++) { 803 try { 804 mCommDevDispatchers.getBroadcastItem(i) 805 .dispatchCommunicationDeviceChanged(portId); 806 } catch (RemoteException e) { 807 } 808 } 809 mCommDevDispatchers.finishBroadcast(); 810 } 811 812 //--------------------------------------------------------------------- 813 // Communication with (to) AudioService 814 //TODO check whether the AudioService methods are candidates to move here postAccessoryPlugMediaUnmute(int device)815 /*package*/ void postAccessoryPlugMediaUnmute(int device) { 816 mAudioService.postAccessoryPlugMediaUnmute(device); 817 } 818 getVssVolumeForDevice(int streamType, int device)819 /*package*/ int getVssVolumeForDevice(int streamType, int device) { 820 return mAudioService.getVssVolumeForDevice(streamType, device); 821 } 822 getDeviceForStream(int streamType)823 /*package*/ int getDeviceForStream(int streamType) { 824 return mAudioService.getDeviceForStream(streamType); 825 } 826 postApplyVolumeOnDevice(int streamType, int device, String caller)827 /*package*/ void postApplyVolumeOnDevice(int streamType, int device, String caller) { 828 mAudioService.postApplyVolumeOnDevice(streamType, device, caller); 829 } 830 postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, String caller)831 /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, 832 String caller) { 833 mAudioService.postSetVolumeIndexOnDevice(streamType, vssVolIndex, device, caller); 834 } 835 postObserveDevicesForAllStreams()836 /*packages*/ void postObserveDevicesForAllStreams() { 837 mAudioService.postObserveDevicesForAllStreams(); 838 } 839 isInCommunication()840 /*package*/ boolean isInCommunication() { 841 return mAudioService.isInCommunication(); 842 } 843 hasMediaDynamicPolicy()844 /*package*/ boolean hasMediaDynamicPolicy() { 845 return mAudioService.hasMediaDynamicPolicy(); 846 } 847 getContentResolver()848 /*package*/ ContentResolver getContentResolver() { 849 return mAudioService.getContentResolver(); 850 } 851 checkMusicActive(int deviceType, String caller)852 /*package*/ void checkMusicActive(int deviceType, String caller) { 853 mAudioService.checkMusicActive(deviceType, caller); 854 } 855 checkVolumeCecOnHdmiConnection( @udioService.ConnectionState int state, String caller)856 /*package*/ void checkVolumeCecOnHdmiConnection( 857 @AudioService.ConnectionState int state, String caller) { 858 mAudioService.postCheckVolumeCecOnHdmiConnection(state, caller); 859 } 860 hasAudioFocusUsers()861 /*package*/ boolean hasAudioFocusUsers() { 862 return mAudioService.hasAudioFocusUsers(); 863 } 864 865 //--------------------------------------------------------------------- 866 // Message handling on behalf of helper classes postBroadcastScoConnectionState(int state)867 /*package*/ void postBroadcastScoConnectionState(int state) { 868 sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state); 869 } 870 postBroadcastBecomingNoisy()871 /*package*/ void postBroadcastBecomingNoisy() { 872 sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE); 873 } 874 875 @GuardedBy("mDeviceStateLock") postA2dpSinkConnection(@udioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay)876 /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state, 877 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { 878 sendILMsg(state == BluetoothA2dp.STATE_CONNECTED 879 ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED 880 : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, 881 SENDMSG_QUEUE, 882 state, btDeviceInfo, delay); 883 } 884 postA2dpSourceConnection(@udioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay)885 /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state, 886 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { 887 sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, 888 state, btDeviceInfo, delay); 889 } 890 postSetWiredDeviceConnectionState( AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay)891 /*package*/ void postSetWiredDeviceConnectionState( 892 AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) { 893 sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay); 894 } 895 postSetHearingAidConnectionState( @udioService.BtProfileConnectionState int state, @NonNull BluetoothDevice device, int delay)896 /*package*/ void postSetHearingAidConnectionState( 897 @AudioService.BtProfileConnectionState int state, 898 @NonNull BluetoothDevice device, int delay) { 899 sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE, 900 state, 901 device, 902 delay); 903 } 904 postDisconnectA2dp()905 /*package*/ void postDisconnectA2dp() { 906 sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE); 907 } 908 postDisconnectA2dpSink()909 /*package*/ void postDisconnectA2dpSink() { 910 sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE); 911 } 912 postDisconnectHearingAid()913 /*package*/ void postDisconnectHearingAid() { 914 sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE); 915 } 916 postDisconnectHeadset()917 /*package*/ void postDisconnectHeadset() { 918 sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE); 919 } 920 postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile)921 /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) { 922 sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile); 923 } 924 postBtA2dpSinkProfileConnected(BluetoothProfile profile)925 /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) { 926 sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile); 927 } 928 postBtHeasetProfileConnected(BluetoothHeadset headsetProfile)929 /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) { 930 sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile); 931 } 932 postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile)933 /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) { 934 sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE, 935 hearingAidProfile); 936 } 937 postCommunicationRouteClientDied(CommunicationRouteClient client)938 /*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) { 939 sendLMsgNoDelay(MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED, SENDMSG_QUEUE, client); 940 } 941 postSaveSetPreferredDevicesForStrategy(int strategy, List<AudioDeviceAttributes> devices)942 /*package*/ void postSaveSetPreferredDevicesForStrategy(int strategy, 943 List<AudioDeviceAttributes> devices) 944 { 945 sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy, devices); 946 } 947 postSaveRemovePreferredDevicesForStrategy(int strategy)948 /*package*/ void postSaveRemovePreferredDevicesForStrategy(int strategy) { 949 sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy); 950 } 951 postSaveSetPreferredDevicesForCapturePreset( int capturePreset, List<AudioDeviceAttributes> devices)952 /*package*/ void postSaveSetPreferredDevicesForCapturePreset( 953 int capturePreset, List<AudioDeviceAttributes> devices) { 954 sendILMsgNoDelay( 955 MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset, devices); 956 } 957 postSaveClearPreferredDevicesForCapturePreset(int capturePreset)958 /*package*/ void postSaveClearPreferredDevicesForCapturePreset(int capturePreset) { 959 sendIMsgNoDelay( 960 MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset); 961 } 962 963 //--------------------------------------------------------------------- 964 // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory) 965 // only call from a "handle"* method or "on"* method 966 967 // Handles request to override default use of A2DP for media. 968 //@GuardedBy("mConnectedDevices") setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source)969 /*package*/ void setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source) { 970 // for logging only 971 final String eventSource = new StringBuilder("setBluetoothA2dpOn(").append(on) 972 .append(") from u/pid:").append(Binder.getCallingUid()).append("/") 973 .append(Binder.getCallingPid()).append(" src:").append(source).toString(); 974 975 synchronized (mDeviceStateLock) { 976 mBluetoothA2dpEnabled = on; 977 mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE); 978 onSetForceUse( 979 AudioSystem.FOR_MEDIA, 980 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, 981 fromA2dp, 982 eventSource); 983 } 984 } 985 handleDeviceConnection(boolean connect, int device, String address, String deviceName)986 /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address, 987 String deviceName) { 988 synchronized (mDeviceStateLock) { 989 return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName); 990 } 991 } 992 postSetA2dpSourceConnectionState(@luetoothProfile.BtProfileState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo)993 /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state, 994 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { 995 final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0; 996 sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state, 997 btDeviceInfo); 998 } 999 handleFailureToConnectToBtHeadsetService(int delay)1000 /*package*/ void handleFailureToConnectToBtHeadsetService(int delay) { 1001 sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay); 1002 } 1003 handleCancelFailureToConnectToBtHeadsetService()1004 /*package*/ void handleCancelFailureToConnectToBtHeadsetService() { 1005 mBrokerHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); 1006 } 1007 postReportNewRoutes(boolean fromA2dp)1008 /*package*/ void postReportNewRoutes(boolean fromA2dp) { 1009 sendMsgNoDelay(fromA2dp ? MSG_REPORT_NEW_ROUTES_A2DP : MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP); 1010 } 1011 postA2dpActiveDeviceChange( @onNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo)1012 /*package*/ void postA2dpActiveDeviceChange( 1013 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { 1014 sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo); 1015 } 1016 1017 // must be called synchronized on mConnectedDevices hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice)1018 /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) { 1019 final BtHelper.BluetoothA2dpDeviceInfo devInfoToCheck = 1020 new BtHelper.BluetoothA2dpDeviceInfo(btDevice); 1021 return (mBrokerHandler.hasEqualMessages( 1022 MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, devInfoToCheck) 1023 || mBrokerHandler.hasEqualMessages( 1024 MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, devInfoToCheck)); 1025 } 1026 setA2dpTimeout(String address, int a2dpCodec, int delayMs)1027 /*package*/ void setA2dpTimeout(String address, int a2dpCodec, int delayMs) { 1028 sendILMsg(MSG_IL_BTA2DP_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs); 1029 } 1030 setAvrcpAbsoluteVolumeSupported(boolean supported)1031 /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) { 1032 synchronized (mDeviceStateLock) { 1033 mBtHelper.setAvrcpAbsoluteVolumeSupported(supported); 1034 } 1035 } 1036 clearAvrcpAbsoluteVolumeSupported()1037 /*package*/ void clearAvrcpAbsoluteVolumeSupported() { 1038 setAvrcpAbsoluteVolumeSupported(false); 1039 mAudioService.setAvrcpAbsoluteVolumeSupported(false); 1040 } 1041 getBluetoothA2dpEnabled()1042 /*package*/ boolean getBluetoothA2dpEnabled() { 1043 synchronized (mDeviceStateLock) { 1044 return mBluetoothA2dpEnabled; 1045 } 1046 } 1047 getA2dpCodec(@onNull BluetoothDevice device)1048 /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) { 1049 synchronized (mDeviceStateLock) { 1050 return mBtHelper.getA2dpCodec(device); 1051 } 1052 } 1053 broadcastStickyIntentToCurrentProfileGroup(Intent intent)1054 /*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) { 1055 mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent); 1056 } 1057 dump(PrintWriter pw, String prefix)1058 /*package*/ void dump(PrintWriter pw, String prefix) { 1059 if (mBrokerHandler != null) { 1060 pw.println(prefix + "Message handler (watch for unhandled messages):"); 1061 mBrokerHandler.dump(new PrintWriterPrinter(pw), prefix + " "); 1062 } else { 1063 pw.println("Message handler is null"); 1064 } 1065 1066 mDeviceInventory.dump(pw, prefix); 1067 1068 pw.println("\n" + prefix + "Communication route clients:"); 1069 mCommunicationRouteClients.forEach((cl) -> { 1070 pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " 1071 + cl.getDevice() + " cb: " + cl.getBinder()); }); 1072 1073 pw.println("\n" + prefix + "Computed Preferred communication device: " 1074 + preferredCommunicationDevice()); 1075 pw.println("\n" + prefix + "Applied Preferred communication device: " 1076 + mPreferredCommunicationDevice); 1077 pw.println(prefix + "Active communication device: " 1078 + ((mActiveCommunicationDevice == null) ? "None" 1079 : new AudioDeviceAttributes(mActiveCommunicationDevice))); 1080 1081 pw.println(prefix + "mCommunicationStrategyId: " 1082 + mCommunicationStrategyId); 1083 1084 pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid); 1085 1086 mBtHelper.dump(pw, prefix); 1087 } 1088 1089 //--------------------------------------------------------------------- 1090 // Internal handling of messages 1091 // These methods are ALL synchronous, in response to message handling in BrokerHandler 1092 // Blocking in any of those will block the message queue 1093 onSetForceUse(int useCase, int config, boolean fromA2dp, String eventSource)1094 private void onSetForceUse(int useCase, int config, boolean fromA2dp, String eventSource) { 1095 if (useCase == AudioSystem.FOR_MEDIA) { 1096 postReportNewRoutes(fromA2dp); 1097 } 1098 AudioService.sForceUseLogger.log( 1099 new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource)); 1100 new MediaMetrics.Item(MediaMetrics.Name.AUDIO_FORCE_USE + MediaMetrics.SEPARATOR 1101 + AudioSystem.forceUseUsageToString(useCase)) 1102 .set(MediaMetrics.Property.EVENT, "onSetForceUse") 1103 .set(MediaMetrics.Property.FORCE_USE_DUE_TO, eventSource) 1104 .set(MediaMetrics.Property.FORCE_USE_MODE, 1105 AudioSystem.forceUseConfigToString(config)) 1106 .record(); 1107 1108 if (AudioService.DEBUG_COMM_RTE) { 1109 Log.v(TAG, "onSetForceUse(useCase<" + useCase + ">, config<" + config + ">, fromA2dp<" 1110 + fromA2dp + ">, eventSource<" + eventSource + ">)"); 1111 } 1112 AudioSystem.setForceUse(useCase, config); 1113 } 1114 onSendBecomingNoisyIntent()1115 private void onSendBecomingNoisyIntent() { 1116 AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( 1117 "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG)); 1118 mSystemServer.sendDeviceBecomingNoisyIntent(); 1119 } 1120 1121 //--------------------------------------------------------------------- 1122 // Message handling 1123 private BrokerHandler mBrokerHandler; 1124 private BrokerThread mBrokerThread; 1125 private PowerManager.WakeLock mBrokerEventWakeLock; 1126 setupMessaging(Context ctxt)1127 private void setupMessaging(Context ctxt) { 1128 final PowerManager pm = (PowerManager) ctxt.getSystemService(Context.POWER_SERVICE); 1129 mBrokerEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 1130 "handleAudioDeviceEvent"); 1131 mBrokerThread = new BrokerThread(); 1132 mBrokerThread.start(); 1133 waitForBrokerHandlerCreation(); 1134 } 1135 waitForBrokerHandlerCreation()1136 private void waitForBrokerHandlerCreation() { 1137 synchronized (this) { 1138 while (mBrokerHandler == null) { 1139 try { 1140 wait(); 1141 } catch (InterruptedException e) { 1142 Log.e(TAG, "Interruption while waiting on BrokerHandler"); 1143 } 1144 } 1145 } 1146 } 1147 1148 /** Class that handles the device broker's message queue */ 1149 private class BrokerThread extends Thread { BrokerThread()1150 BrokerThread() { 1151 super("AudioDeviceBroker"); 1152 } 1153 1154 @Override run()1155 public void run() { 1156 // Set this thread up so the handler will work on it 1157 Looper.prepare(); 1158 1159 synchronized (AudioDeviceBroker.this) { 1160 mBrokerHandler = new BrokerHandler(); 1161 1162 // Notify that the handler has been created 1163 AudioDeviceBroker.this.notify(); 1164 } 1165 1166 Looper.loop(); 1167 } 1168 } 1169 1170 /** Class that handles the message queue */ 1171 private class BrokerHandler extends Handler { 1172 1173 @Override handleMessage(Message msg)1174 public void handleMessage(Message msg) { 1175 switch (msg.what) { 1176 case MSG_RESTORE_DEVICES: 1177 synchronized (mSetModeLock) { 1178 synchronized (mDeviceStateLock) { 1179 initCommunicationStrategyId(); 1180 updateActiveCommunicationDevice(); 1181 mDeviceInventory.onRestoreDevices(); 1182 mBtHelper.onAudioServerDiedRestoreA2dp(); 1183 onUpdateCommunicationRoute("MSG_RESTORE_DEVICES"); 1184 } 1185 } 1186 break; 1187 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 1188 synchronized (mDeviceStateLock) { 1189 mDeviceInventory.onSetWiredDeviceConnectionState( 1190 (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj); 1191 } 1192 break; 1193 case MSG_I_BROADCAST_BT_CONNECTION_STATE: 1194 synchronized (mDeviceStateLock) { 1195 mBtHelper.onBroadcastScoConnectionState(msg.arg1); 1196 } 1197 break; 1198 case MSG_IIL_SET_FORCE_USE: // intended fall-through 1199 case MSG_IIL_SET_FORCE_BT_A2DP_USE: 1200 onSetForceUse(msg.arg1, msg.arg2, 1201 (msg.what == MSG_IIL_SET_FORCE_BT_A2DP_USE), (String) msg.obj); 1202 break; 1203 case MSG_REPORT_NEW_ROUTES: 1204 case MSG_REPORT_NEW_ROUTES_A2DP: 1205 synchronized (mDeviceStateLock) { 1206 mDeviceInventory.onReportNewRoutes(); 1207 } 1208 break; 1209 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: 1210 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: 1211 synchronized (mDeviceStateLock) { 1212 mDeviceInventory.onSetA2dpSinkConnectionState( 1213 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); 1214 } 1215 break; 1216 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: 1217 synchronized (mDeviceStateLock) { 1218 mDeviceInventory.onSetA2dpSourceConnectionState( 1219 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); 1220 } 1221 break; 1222 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: 1223 synchronized (mDeviceStateLock) { 1224 mDeviceInventory.onSetHearingAidConnectionState( 1225 (BluetoothDevice) msg.obj, msg.arg1, 1226 mAudioService.getHearingAidStreamType()); 1227 } 1228 break; 1229 case MSG_BT_HEADSET_CNCT_FAILED: 1230 synchronized (mSetModeLock) { 1231 synchronized (mDeviceStateLock) { 1232 mBtHelper.resetBluetoothSco(); 1233 } 1234 } 1235 break; 1236 case MSG_IL_BTA2DP_TIMEOUT: 1237 // msg.obj == address of BTA2DP device 1238 synchronized (mDeviceStateLock) { 1239 mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1); 1240 } 1241 break; 1242 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: 1243 final int a2dpCodec; 1244 final BluetoothDevice btDevice = (BluetoothDevice) msg.obj; 1245 synchronized (mDeviceStateLock) { 1246 a2dpCodec = mBtHelper.getA2dpCodec(btDevice); 1247 // TODO: name of method being called on AudioDeviceInventory is currently 1248 // misleading (config change vs active device change), to be 1249 // reconciliated once the BT side has been updated. 1250 mDeviceInventory.onBluetoothA2dpActiveDeviceChange( 1251 new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec), 1252 BtHelper.EVENT_DEVICE_CONFIG_CHANGE); 1253 } 1254 break; 1255 case MSG_BROADCAST_AUDIO_BECOMING_NOISY: 1256 onSendBecomingNoisyIntent(); 1257 break; 1258 case MSG_II_SET_HEARING_AID_VOLUME: 1259 synchronized (mDeviceStateLock) { 1260 mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2); 1261 } 1262 break; 1263 case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME: 1264 synchronized (mDeviceStateLock) { 1265 mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); 1266 } 1267 break; 1268 case MSG_I_SET_MODE_OWNER_PID: 1269 synchronized (mSetModeLock) { 1270 synchronized (mDeviceStateLock) { 1271 mModeOwnerPid = msg.arg1; 1272 if (msg.arg2 != AudioSystem.MODE_RINGTONE) { 1273 onUpdateCommunicationRoute("setNewModeOwner"); 1274 } 1275 } 1276 } 1277 break; 1278 case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED: 1279 synchronized (mSetModeLock) { 1280 synchronized (mDeviceStateLock) { 1281 onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj); 1282 } 1283 } 1284 break; 1285 case MSG_L_UPDATE_COMMUNICATION_ROUTE: 1286 synchronized (mSetModeLock) { 1287 synchronized (mDeviceStateLock) { 1288 onUpdateCommunicationRoute((String) msg.obj); 1289 } 1290 } 1291 break; 1292 case MSG_TOGGLE_HDMI: 1293 synchronized (mDeviceStateLock) { 1294 mDeviceInventory.onToggleHdmi(); 1295 } 1296 break; 1297 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: 1298 synchronized (mDeviceStateLock) { 1299 mDeviceInventory.onBluetoothA2dpActiveDeviceChange( 1300 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, 1301 BtHelper.EVENT_ACTIVE_DEVICE_CHANGE); 1302 } 1303 break; 1304 case MSG_DISCONNECT_A2DP: 1305 synchronized (mDeviceStateLock) { 1306 mDeviceInventory.disconnectA2dp(); 1307 } 1308 break; 1309 case MSG_DISCONNECT_A2DP_SINK: 1310 synchronized (mDeviceStateLock) { 1311 mDeviceInventory.disconnectA2dpSink(); 1312 } 1313 break; 1314 case MSG_DISCONNECT_BT_HEARING_AID: 1315 synchronized (mDeviceStateLock) { 1316 mDeviceInventory.disconnectHearingAid(); 1317 } 1318 break; 1319 case MSG_DISCONNECT_BT_HEADSET: 1320 synchronized (mSetModeLock) { 1321 synchronized (mDeviceStateLock) { 1322 mBtHelper.disconnectHeadset(); 1323 } 1324 } 1325 break; 1326 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: 1327 synchronized (mDeviceStateLock) { 1328 mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj); 1329 } 1330 break; 1331 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK: 1332 synchronized (mDeviceStateLock) { 1333 mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj); 1334 } 1335 break; 1336 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID: 1337 synchronized (mDeviceStateLock) { 1338 mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj); 1339 } 1340 break; 1341 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: 1342 synchronized (mSetModeLock) { 1343 synchronized (mDeviceStateLock) { 1344 mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); 1345 } 1346 } 1347 break; 1348 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: 1349 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: { 1350 final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj; 1351 AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( 1352 "msg: setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent " 1353 + " state=" + info.mState 1354 // only querying address as this is the only readily available 1355 // field on the device 1356 + " addr=" + info.mDevice.getAddress() 1357 + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy 1358 + " vol=" + info.mVolume)).printLog(TAG)); 1359 synchronized (mDeviceStateLock) { 1360 mDeviceInventory.setBluetoothA2dpDeviceConnectionState( 1361 info.mDevice, info.mState, info.mProfile, info.mSupprNoisy, 1362 AudioSystem.DEVICE_NONE, info.mVolume); 1363 } 1364 } break; 1365 case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: { 1366 final HearingAidDeviceConnectionInfo info = 1367 (HearingAidDeviceConnectionInfo) msg.obj; 1368 AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( 1369 "msg: setHearingAidDeviceConnectionState state=" + info.mState 1370 + " addr=" + info.mDevice.getAddress() 1371 + " supprNoisy=" + info.mSupprNoisy 1372 + " src=" + info.mEventSource)).printLog(TAG)); 1373 synchronized (mDeviceStateLock) { 1374 mDeviceInventory.setBluetoothHearingAidDeviceConnectionState( 1375 info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); 1376 } 1377 } break; 1378 case MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY: { 1379 final int strategy = msg.arg1; 1380 final List<AudioDeviceAttributes> devices = 1381 (List<AudioDeviceAttributes>) msg.obj; 1382 mDeviceInventory.onSaveSetPreferredDevices(strategy, devices); 1383 } break; 1384 case MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY: { 1385 final int strategy = msg.arg1; 1386 mDeviceInventory.onSaveRemovePreferredDevices(strategy); 1387 } break; 1388 case MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY: { 1389 final int strategy = msg.arg1; 1390 final List<AudioDeviceAttributes> devices = 1391 (List<AudioDeviceAttributes>) msg.obj; 1392 setPreferredDevicesForStrategySync(strategy, devices); 1393 if (strategy == mCommunicationStrategyId) { 1394 onUpdatePhoneStrategyDevice(devices.isEmpty() ? null : devices.get(0)); 1395 } 1396 } break; 1397 case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: { 1398 final int strategy = msg.arg1; 1399 removePreferredDevicesForStrategySync(strategy); 1400 if (strategy == mCommunicationStrategyId) { 1401 onUpdatePhoneStrategyDevice(null); 1402 } 1403 } break; 1404 case MSG_CHECK_MUTE_MUSIC: 1405 checkMessagesMuteMusic(0); 1406 break; 1407 case MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET: { 1408 final int capturePreset = msg.arg1; 1409 final List<AudioDeviceAttributes> devices = 1410 (List<AudioDeviceAttributes>) msg.obj; 1411 mDeviceInventory.onSaveSetPreferredDevicesForCapturePreset( 1412 capturePreset, devices); 1413 } break; 1414 case MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET: { 1415 final int capturePreset = msg.arg1; 1416 mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset); 1417 } break; 1418 default: 1419 Log.wtf(TAG, "Invalid message " + msg.what); 1420 } 1421 1422 // Give some time to Bluetooth service to post a connection message 1423 // in case of active device switch 1424 if (MESSAGES_MUTE_MUSIC.contains(msg.what)) { 1425 sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, BTA2DP_MUTE_CHECK_DELAY_MS); 1426 } 1427 1428 if (isMessageHandledUnderWakelock(msg.what)) { 1429 try { 1430 mBrokerEventWakeLock.release(); 1431 } catch (Exception e) { 1432 Log.e(TAG, "Exception releasing wakelock", e); 1433 } 1434 } 1435 } 1436 } 1437 1438 // List of all messages. If a message has be handled under wakelock, add it to 1439 // the isMessageHandledUnderWakelock(int) method 1440 // Naming of msg indicates arguments, using JNI argument grammar 1441 // (e.g. II indicates two int args, IL indicates int and Obj arg) 1442 private static final int MSG_RESTORE_DEVICES = 1; 1443 private static final int MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE = 2; 1444 private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3; 1445 private static final int MSG_IIL_SET_FORCE_USE = 4; 1446 private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5; 1447 private static final int MSG_TOGGLE_HDMI = 6; 1448 private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7; 1449 private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8; 1450 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; 1451 private static final int MSG_IL_BTA2DP_TIMEOUT = 10; 1452 1453 // process change of A2DP device configuration, obj is BluetoothDevice 1454 private static final int MSG_L_A2DP_DEVICE_CONFIG_CHANGE = 11; 1455 1456 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12; 1457 private static final int MSG_REPORT_NEW_ROUTES = 13; 1458 private static final int MSG_II_SET_HEARING_AID_VOLUME = 14; 1459 private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15; 1460 private static final int MSG_I_SET_MODE_OWNER_PID = 16; 1461 1462 // process active A2DP device change, obj is BtHelper.BluetoothA2dpDeviceInfo 1463 private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18; 1464 1465 private static final int MSG_DISCONNECT_A2DP = 19; 1466 private static final int MSG_DISCONNECT_A2DP_SINK = 20; 1467 private static final int MSG_DISCONNECT_BT_HEARING_AID = 21; 1468 private static final int MSG_DISCONNECT_BT_HEADSET = 22; 1469 private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23; 1470 private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24; 1471 private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25; 1472 private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26; 1473 1474 // process change of state, obj is BtHelper.BluetoothA2dpDeviceInfo 1475 private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27; 1476 private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28; 1477 1478 // process external command to (dis)connect an A2DP device, obj is BtDeviceConnectionInfo 1479 private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29; 1480 private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30; 1481 1482 // process external command to (dis)connect a hearing aid device 1483 private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31; 1484 1485 private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY = 32; 1486 private static final int MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY = 33; 1487 1488 private static final int MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED = 34; 1489 private static final int MSG_CHECK_MUTE_MUSIC = 35; 1490 private static final int MSG_REPORT_NEW_ROUTES_A2DP = 36; 1491 1492 private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET = 37; 1493 private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38; 1494 1495 private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39; 1496 private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40; 1497 private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41; 1498 isMessageHandledUnderWakelock(int msgId)1499 private static boolean isMessageHandledUnderWakelock(int msgId) { 1500 switch(msgId) { 1501 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 1502 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: 1503 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: 1504 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: 1505 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: 1506 case MSG_IL_BTA2DP_TIMEOUT: 1507 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: 1508 case MSG_TOGGLE_HDMI: 1509 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: 1510 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: 1511 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: 1512 case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: 1513 case MSG_CHECK_MUTE_MUSIC: 1514 return true; 1515 default: 1516 return false; 1517 } 1518 } 1519 1520 // Message helper methods 1521 1522 // sendMsg() flags 1523 /** If the msg is already queued, replace it with this one. */ 1524 private static final int SENDMSG_REPLACE = 0; 1525 /** If the msg is already queued, ignore this one and leave the old. */ 1526 private static final int SENDMSG_NOOP = 1; 1527 /** If the msg is already queued, queue this one and leave the old. */ 1528 private static final int SENDMSG_QUEUE = 2; 1529 sendMsg(int msg, int existingMsgPolicy, int delay)1530 private void sendMsg(int msg, int existingMsgPolicy, int delay) { 1531 sendIILMsg(msg, existingMsgPolicy, 0, 0, null, delay); 1532 } 1533 sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay)1534 private void sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay) { 1535 sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, delay); 1536 } 1537 sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay)1538 private void sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay) { 1539 sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, delay); 1540 } 1541 sendIMsg(int msg, int existingMsgPolicy, int arg, int delay)1542 private void sendIMsg(int msg, int existingMsgPolicy, int arg, int delay) { 1543 sendIILMsg(msg, existingMsgPolicy, arg, 0, null, delay); 1544 } 1545 sendMsgNoDelay(int msg, int existingMsgPolicy)1546 private void sendMsgNoDelay(int msg, int existingMsgPolicy) { 1547 sendIILMsg(msg, existingMsgPolicy, 0, 0, null, 0); 1548 } 1549 sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg)1550 private void sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg) { 1551 sendIILMsg(msg, existingMsgPolicy, arg, 0, null, 0); 1552 } 1553 sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2)1554 private void sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2) { 1555 sendIILMsg(msg, existingMsgPolicy, arg1, arg2, null, 0); 1556 } 1557 sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj)1558 private void sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj) { 1559 sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, 0); 1560 } 1561 sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj)1562 private void sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj) { 1563 sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, 0); 1564 } 1565 sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj)1566 private void sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj) { 1567 sendIILMsg(msg, existingMsgPolicy, arg1, arg2, obj, 0); 1568 } 1569 sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)1570 private void sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, 1571 int delay) { 1572 if (existingMsgPolicy == SENDMSG_REPLACE) { 1573 mBrokerHandler.removeMessages(msg); 1574 } else if (existingMsgPolicy == SENDMSG_NOOP && mBrokerHandler.hasMessages(msg)) { 1575 return; 1576 } 1577 1578 if (isMessageHandledUnderWakelock(msg)) { 1579 final long identity = Binder.clearCallingIdentity(); 1580 try { 1581 mBrokerEventWakeLock.acquire(BROKER_WAKELOCK_TIMEOUT_MS); 1582 } catch (Exception e) { 1583 Log.e(TAG, "Exception acquiring wakelock", e); 1584 } 1585 Binder.restoreCallingIdentity(identity); 1586 } 1587 1588 if (MESSAGES_MUTE_MUSIC.contains(msg)) { 1589 checkMessagesMuteMusic(msg); 1590 } 1591 1592 synchronized (sLastDeviceConnectionMsgTimeLock) { 1593 long time = SystemClock.uptimeMillis() + delay; 1594 1595 switch (msg) { 1596 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: 1597 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: 1598 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: 1599 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: 1600 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 1601 case MSG_IL_BTA2DP_TIMEOUT: 1602 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: 1603 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: 1604 if (sLastDeviceConnectMsgTime >= time) { 1605 // add a little delay to make sure messages are ordered as expected 1606 time = sLastDeviceConnectMsgTime + 30; 1607 } 1608 sLastDeviceConnectMsgTime = time; 1609 break; 1610 default: 1611 break; 1612 } 1613 mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), 1614 time); 1615 } 1616 } 1617 1618 /** List of messages for which music is muted while processing is pending */ 1619 private static final Set<Integer> MESSAGES_MUTE_MUSIC; 1620 static { 1621 MESSAGES_MUTE_MUSIC = new HashSet<>(); 1622 MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED); 1623 MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED); 1624 MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE); 1625 MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE); 1626 MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION); 1627 MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION); 1628 MESSAGES_MUTE_MUSIC.add(MSG_IIL_SET_FORCE_BT_A2DP_USE); 1629 MESSAGES_MUTE_MUSIC.add(MSG_REPORT_NEW_ROUTES_A2DP); 1630 } 1631 1632 private AtomicBoolean mMusicMuted = new AtomicBoolean(false); 1633 1634 /** Mutes or unmutes music according to pending A2DP messages */ checkMessagesMuteMusic(int message)1635 private void checkMessagesMuteMusic(int message) { 1636 boolean mute = message != 0; 1637 if (!mute) { 1638 for (int msg : MESSAGES_MUTE_MUSIC) { 1639 if (mBrokerHandler.hasMessages(msg)) { 1640 mute = true; 1641 break; 1642 } 1643 } 1644 } 1645 1646 if (mute != mMusicMuted.getAndSet(mute)) { 1647 mAudioService.setMusicMute(mute); 1648 } 1649 } 1650 1651 // List of applications requesting a specific route for communication. 1652 @GuardedBy("mDeviceStateLock") 1653 private final @NonNull LinkedList<CommunicationRouteClient> mCommunicationRouteClients = 1654 new LinkedList<CommunicationRouteClient>(); 1655 1656 private class CommunicationRouteClient implements IBinder.DeathRecipient { 1657 private final IBinder mCb; 1658 private final int mPid; 1659 private AudioDeviceAttributes mDevice; 1660 CommunicationRouteClient(IBinder cb, int pid, AudioDeviceAttributes device)1661 CommunicationRouteClient(IBinder cb, int pid, AudioDeviceAttributes device) { 1662 mCb = cb; 1663 mPid = pid; 1664 mDevice = device; 1665 } 1666 registerDeathRecipient()1667 public boolean registerDeathRecipient() { 1668 boolean status = false; 1669 try { 1670 mCb.linkToDeath(this, 0); 1671 status = true; 1672 } catch (RemoteException e) { 1673 Log.w(TAG, "CommunicationRouteClient could not link to " + mCb + " binder death"); 1674 } 1675 return status; 1676 } 1677 unregisterDeathRecipient()1678 public void unregisterDeathRecipient() { 1679 try { 1680 mCb.unlinkToDeath(this, 0); 1681 } catch (NoSuchElementException e) { 1682 Log.w(TAG, "CommunicationRouteClient could not not unregistered to binder"); 1683 } 1684 } 1685 1686 @Override binderDied()1687 public void binderDied() { 1688 postCommunicationRouteClientDied(this); 1689 } 1690 getBinder()1691 IBinder getBinder() { 1692 return mCb; 1693 } 1694 getPid()1695 int getPid() { 1696 return mPid; 1697 } 1698 getDevice()1699 AudioDeviceAttributes getDevice() { 1700 return mDevice; 1701 } 1702 requestsBluetoothSco()1703 boolean requestsBluetoothSco() { 1704 return mDevice != null 1705 && mDevice.getType() 1706 == AudioDeviceInfo.TYPE_BLUETOOTH_SCO; 1707 } 1708 requestsSpeakerphone()1709 boolean requestsSpeakerphone() { 1710 return mDevice != null 1711 && mDevice.getType() 1712 == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER; 1713 } 1714 } 1715 1716 // @GuardedBy("mSetModeLock") 1717 @GuardedBy("mDeviceStateLock") onCommunicationRouteClientDied(CommunicationRouteClient client)1718 private void onCommunicationRouteClientDied(CommunicationRouteClient client) { 1719 if (client == null) { 1720 return; 1721 } 1722 Log.w(TAG, "Communication client died"); 1723 setCommunicationRouteForClient( 1724 client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED, 1725 "onCommunicationRouteClientDied"); 1726 } 1727 1728 /** 1729 * Determines which preferred device for phone strategy should be sent to audio policy manager 1730 * as a function of current SCO audio activation state and active communication route requests. 1731 * SCO audio state has the highest priority as it can result from external activation by 1732 * telephony service. 1733 * @return selected forced usage for communication. 1734 */ 1735 @GuardedBy("mDeviceStateLock") preferredCommunicationDevice()1736 @Nullable private AudioDeviceAttributes preferredCommunicationDevice() { 1737 boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn(); 1738 if (btSCoOn) { 1739 // Use the SCO device known to BtHelper so that it matches exactly 1740 // what has been communicated to audio policy manager. The device 1741 // returned by requestedCommunicationDevice() can be a dummy SCO device if legacy 1742 // APIs are used to start SCO audio. 1743 AudioDeviceAttributes device = mBtHelper.getHeadsetAudioDevice(); 1744 if (device != null) { 1745 return device; 1746 } 1747 } 1748 AudioDeviceAttributes device = requestedCommunicationDevice(); 1749 if (device == null || device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { 1750 // Do not indicate BT SCO selection if SCO is requested but SCO is not ON 1751 return null; 1752 } 1753 return device; 1754 } 1755 1756 /** 1757 * Configures audio policy manager and audio HAL according to active communication route. 1758 * Always called from message Handler. 1759 */ 1760 // @GuardedBy("mSetModeLock") 1761 @GuardedBy("mDeviceStateLock") onUpdateCommunicationRoute(String eventSource)1762 private void onUpdateCommunicationRoute(String eventSource) { 1763 AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice(); 1764 if (AudioService.DEBUG_COMM_RTE) { 1765 Log.v(TAG, "onUpdateCommunicationRoute, preferredCommunicationDevice: " 1766 + preferredCommunicationDevice + " eventSource: " + eventSource); 1767 } 1768 AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( 1769 "onUpdateCommunicationRoute, preferredCommunicationDevice: " 1770 + preferredCommunicationDevice + " eventSource: " + eventSource))); 1771 1772 if (preferredCommunicationDevice == null 1773 || preferredCommunicationDevice.getType() != AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { 1774 AudioSystem.setParameters("BT_SCO=off"); 1775 } else { 1776 AudioSystem.setParameters("BT_SCO=on"); 1777 } 1778 if (preferredCommunicationDevice == null) { 1779 postRemovePreferredDevicesForStrategy(mCommunicationStrategyId); 1780 } else { 1781 postSetPreferredDevicesForStrategy( 1782 mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice)); 1783 } 1784 } 1785 onUpdatePhoneStrategyDevice(AudioDeviceAttributes device)1786 private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) { 1787 synchronized (mSetModeLock) { 1788 synchronized (mDeviceStateLock) { 1789 boolean wasSpeakerphoneActive = isSpeakerphoneActive(); 1790 mPreferredCommunicationDevice = device; 1791 updateActiveCommunicationDevice(); 1792 if (wasSpeakerphoneActive != isSpeakerphoneActive()) { 1793 try { 1794 mContext.sendBroadcastAsUser( 1795 new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) 1796 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 1797 UserHandle.ALL); 1798 } catch (Exception e) { 1799 Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e); 1800 } 1801 } 1802 mAudioService.postUpdateRingerModeServiceInt(); 1803 dispatchCommunicationDevice(); 1804 } 1805 } 1806 } 1807 removeCommunicationRouteClient( IBinder cb, boolean unregister)1808 private CommunicationRouteClient removeCommunicationRouteClient( 1809 IBinder cb, boolean unregister) { 1810 for (CommunicationRouteClient cl : mCommunicationRouteClients) { 1811 if (cl.getBinder() == cb) { 1812 if (unregister) { 1813 cl.unregisterDeathRecipient(); 1814 } 1815 mCommunicationRouteClients.remove(cl); 1816 return cl; 1817 } 1818 } 1819 return null; 1820 } 1821 1822 @GuardedBy("mDeviceStateLock") addCommunicationRouteClient( IBinder cb, int pid, AudioDeviceAttributes device)1823 private CommunicationRouteClient addCommunicationRouteClient( 1824 IBinder cb, int pid, AudioDeviceAttributes device) { 1825 // always insert new request at first position 1826 removeCommunicationRouteClient(cb, true); 1827 CommunicationRouteClient client = new CommunicationRouteClient(cb, pid, device); 1828 if (client.registerDeathRecipient()) { 1829 mCommunicationRouteClients.add(0, client); 1830 return client; 1831 } 1832 return null; 1833 } 1834 1835 @GuardedBy("mDeviceStateLock") getCommunicationRouteClientForPid(int pid)1836 private CommunicationRouteClient getCommunicationRouteClientForPid(int pid) { 1837 for (CommunicationRouteClient cl : mCommunicationRouteClients) { 1838 if (cl.getPid() == pid) { 1839 return cl; 1840 } 1841 } 1842 return null; 1843 } 1844 } 1845