1 /****************************************************************************** 2 * 3 * Copyright 2004-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 /****************************************************************************** 20 * 21 * This is the advanced audio/video call-out function implementation for 22 * BTIF. 23 * 24 ******************************************************************************/ 25 26 #include <mutex> 27 28 #include <base/bind.h> 29 #include <base/logging.h> 30 #include <string.h> 31 32 #include "bt_target.h" 33 34 #include "a2dp_api.h" 35 #include "a2dp_sbc.h" 36 #include "bta_av_api.h" 37 #include "bta_av_ci.h" 38 #include "bta_av_co.h" 39 #include "bta_sys.h" 40 41 #include "btif_av.h" 42 #include "btif_av_co.h" 43 #include "btif_util.h" 44 #include "osi/include/osi.h" 45 #include "osi/include/properties.h" 46 47 // Macro to retrieve the number of elements in a statically allocated array 48 #define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a) / sizeof((__a)[0])) 49 50 // Macro to convert BTA AV audio handle to index and vice versa 51 #define BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle) \ 52 (((bta_av_handle) & (~BTA_AV_CHNL_MSK)) - 1) 53 #define BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(index) \ 54 (((index) + 1) | BTA_AV_CHNL_AUDIO) 55 56 class BtaAvCoSep { 57 public: 58 BtaAvCoSep() 59 : sep_info_idx(0), seid(0), codec_caps{}, num_protect(0), protect_info{} { 60 Reset(); 61 } 62 63 /** 64 * Reset the state. 65 */ 66 void Reset() { 67 sep_info_idx = 0; 68 seid = 0; 69 memset(codec_caps, 0, sizeof(codec_caps)); 70 num_protect = 0; 71 memset(protect_info, 0, sizeof(protect_info)); 72 } 73 74 uint8_t sep_info_idx; // Local SEP index (in BTA tables) 75 uint8_t seid; // Peer SEP index (in peer tables) 76 uint8_t codec_caps[AVDT_CODEC_SIZE]; // Peer SEP codec capabilities 77 uint8_t num_protect; // Peer SEP number of CP elements 78 uint8_t protect_info[AVDT_CP_INFO_LEN]; // Peer SEP content protection info 79 }; 80 81 class BtaAvCoPeer { 82 public: 83 BtaAvCoPeer() 84 : addr(RawAddress::kEmpty), 85 num_sinks(0), 86 num_sources(0), 87 num_seps(0), 88 num_rx_sinks(0), 89 num_rx_sources(0), 90 num_sup_sinks(0), 91 num_sup_sources(0), 92 p_sink(nullptr), 93 p_source(nullptr), 94 codec_config{}, 95 acceptor(false), 96 reconfig_needed(false), 97 opened(false), 98 mtu(0), 99 uuid_to_connect(0), 100 bta_av_handle_(0), 101 codecs_(nullptr), 102 content_protect_active_(false) { 103 Reset(0); 104 } 105 106 /** 107 * Initialize the state. 108 * 109 * @param codec_priorities the codec priorities to use for the initialization 110 */ 111 void Init(const std::vector<btav_a2dp_codec_config_t>& codec_priorities); 112 113 /** 114 * Reset the state. 115 * 116 * @param bta_av_handle the BTA AV handle to use 117 */ 118 void Reset(tBTA_AV_HNDL bta_av_handle); 119 120 /** 121 * Get the BTA AV handle. 122 * 123 * @return the BTA AV handle 124 */ 125 tBTA_AV_HNDL BtaAvHandle() const { return bta_av_handle_; } 126 127 /** 128 * Get the A2DP codecs. 129 * 130 * @return the A2DP codecs 131 */ 132 A2dpCodecs* GetCodecs() { return codecs_; } 133 134 bool ContentProtectActive() const { return content_protect_active_; } 135 void SetContentProtectActive(bool cp_active) { 136 content_protect_active_ = cp_active; 137 } 138 139 RawAddress addr; // Peer address 140 BtaAvCoSep sinks[BTAV_A2DP_CODEC_INDEX_MAX]; // Supported sinks 141 BtaAvCoSep sources[BTAV_A2DP_CODEC_INDEX_MAX]; // Supported sources 142 uint8_t num_sinks; // Total number of sinks at peer 143 uint8_t num_sources; // Total number of sources at peer 144 uint8_t num_seps; // Total number of SEPs at peer 145 uint8_t num_rx_sinks; // Number of received sinks 146 uint8_t num_rx_sources; // Number of received sources 147 uint8_t num_sup_sinks; // Number of supported sinks 148 uint8_t num_sup_sources; // Number of supported sources 149 const BtaAvCoSep* p_sink; // Currently selected sink 150 const BtaAvCoSep* p_source; // Currently selected source 151 uint8_t codec_config[AVDT_CODEC_SIZE]; // Current codec configuration 152 bool acceptor; // True if acceptor 153 bool reconfig_needed; // True if reconfiguration is needed 154 bool opened; // True if opened 155 uint16_t mtu; // Maximum Transmit Unit size 156 uint16_t uuid_to_connect; // UUID of peer device 157 158 private: 159 tBTA_AV_HNDL bta_av_handle_; // BTA AV handle to use 160 A2dpCodecs* codecs_; // Locally supported codecs 161 bool content_protect_active_; // True if Content Protect is active 162 }; 163 164 class BtaAvCo { 165 public: 166 BtaAvCo(bool content_protect_enabled) 167 : active_peer_(nullptr), 168 codec_config_{}, 169 content_protect_enabled_(content_protect_enabled), 170 content_protect_flag_(0) { 171 Reset(); 172 } 173 174 /** 175 * Initialize the state. 176 * 177 * @param codec_priorities the codec priorities to use for the initialization 178 */ 179 void Init(const std::vector<btav_a2dp_codec_config_t>& codec_priorities); 180 181 /** 182 * Checks whether a codec is supported. 183 * 184 * @param codec_index the index of the codec to check 185 * @return true if the codec is supported, otherwise false 186 */ 187 bool IsSupportedCodec(btav_a2dp_codec_index_t codec_index); 188 189 /** 190 * Get the current codec configuration for the active peer. 191 * 192 * @return the current codec configuration if found, otherwise nullptr 193 */ 194 A2dpCodecConfig* GetActivePeerCurrentCodec(); 195 196 /** 197 * Get the current codec configuration for a peer. 198 * 199 * @param peer_address the peer address 200 * @return the current codec configuration if found, otherwise nullptr 201 */ 202 A2dpCodecConfig* GetPeerCurrentCodec(const RawAddress& peer_address); 203 204 /** 205 * Find the peer UUID for a given BTA AV handle. 206 * 207 * @param bta_av_handle the BTA AV handle to use 208 * @return the peer UUID if found, otherwise 0 209 */ 210 uint16_t FindPeerUuid(tBTA_AV_HNDL bta_av_handle); 211 212 /** 213 * Process the AVDTP discovery result: number of Stream End Points (SEP) 214 * found during the AVDTP stream discovery process. 215 * 216 * @param bta_av_handle the BTA AV handle to identify the peer 217 * @param peer_address the peer address 218 * @param num_seps the number of discovered SEPs 219 * @param num_sinks number of discovered Sink SEPs 220 * @param num_sources number of discovered Source SEPs 221 * @param uuid_local local UUID 222 */ 223 void ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle, 224 const RawAddress& peer_address, uint8_t num_seps, 225 uint8_t num_sinks, uint8_t num_sources, 226 uint16_t uuid_local); 227 228 /** 229 * Process retrieved codec configuration and content protection from 230 * Peer Sink SEP. 231 * 232 * @param bta_av_handle the BTA AV handle to identify the peer 233 * @param peer_address the peer address 234 * @param p_codec_info the peer sink capability filled-in by the caller. 235 * On success, it will contain the current codec configuration for the peer. 236 * @param p_sep_info_idx the peer SEP index for the corresponding peer 237 * sink capability filled-in by the caller. On success, it will contain 238 * the SEP index for the current codec configuration for the peer. 239 * @param seid the peer SEP index in peer tables 240 * @param p_num_protect the peer SEP number of content protection elements 241 * filled-in by the caller. On success, it will contain the SEP number of 242 * content protection elements for the current codec configuration for the 243 * peer. 244 * @param p_protect_info the peer SEP content protection info filled-in by 245 * the caller. On success, it will contain the SEP content protection info 246 * for the current codec configuration for the peer. 247 * @return A2DP_SUCCESS on success, otherwise A2DP_FAIL 248 */ 249 tA2DP_STATUS ProcessSourceGetConfig(tBTA_AV_HNDL bta_av_handle, 250 const RawAddress& peer_address, 251 uint8_t* p_codec_info, 252 uint8_t* p_sep_info_idx, uint8_t seid, 253 uint8_t* p_num_protect, 254 uint8_t* p_protect_info); 255 256 /** 257 * Process retrieved codec configuration and content protection from 258 * Peer Source SEP. 259 * 260 * @param bta_av_handle the BTA AV handle to identify the peer 261 * @param peer_address the peer address 262 * @param p_codec_info the peer source capability filled-in by the caller. 263 * On success, it will contain the current codec configuration for the peer. 264 * @param p_sep_info_idx the peer SEP index for the corresponding peer 265 * source capability filled-in by the caller. On success, it will contain 266 * the SEP index for the current codec configuration for the peer. 267 * @param seid the peer SEP index in peer tables 268 * @param p_num_protect the peer SEP number of content protection elements 269 * filled-in by the caller. On success, it will contain the SEP number of 270 * content protection elements for the current codec configuration for the 271 * peer. 272 * @param p_protect_info the peer SEP content protection info filled-in by 273 * the caller. On success, it will contain the SEP content protection info 274 * for the current codec configuration for the peer. 275 * @return A2DP_SUCCESS on success, otherwise A2DP_FAIL 276 */ 277 tA2DP_STATUS ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, 278 const RawAddress& peer_address, 279 uint8_t* p_codec_info, 280 uint8_t* p_sep_info_idx, uint8_t seid, 281 uint8_t* p_num_protect, 282 uint8_t* p_protect_info); 283 284 /** 285 * Process AVDTP Set Config to set the codec and content protection 286 * configuration of the audio stream. 287 * 288 * @param bta_av_handle the BTA AV handle to identify the peer 289 * @param peer_address the peer address 290 * @param p_codec_info the codec configuration to set 291 * @param seid stream endpoint ID of stream initiating the operation 292 * @param peer_address the peer address 293 * @param num_protect the peer SEP number of content protection elements 294 * @param p_protect_info the peer SEP conntent protection info 295 * @param t_local_sep the local SEP: AVDT_TSEP_SRC or AVDT_TSEP_SNK 296 * @param avdt_handle the AVDTP handle 297 */ 298 void ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, 299 const RawAddress& peer_address, 300 const uint8_t* p_codec_info, uint8_t seid, 301 uint8_t num_protect, const uint8_t* p_protect_info, 302 uint8_t t_local_sep, uint8_t avdt_handle); 303 304 /** 305 * Process AVDTP Open when the stream connection is opened. 306 * 307 * @param bta_av_handle the BTA AV handle to identify the peer 308 * @param peer_address the peer address 309 * @param mtu the MTU of the connection 310 */ 311 void ProcessOpen(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, 312 uint16_t mtu); 313 314 /** 315 * Process AVDTP Close when the stream connection is closed. 316 * 317 * @param bta_av_handle the BTA AV handle to identify the peer 318 * @param peer_address the peer address 319 */ 320 void ProcessClose(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address); 321 322 /** 323 * Process AVDTP Start when the audio data streaming is started. 324 * 325 * @param bta_av_handle the BTA AV handle to identify the peer 326 * @param peer_address the peer address 327 * @param p_codec_info the codec configuration 328 * @param p_no_rtp_header on return, set to true if the audio data packets 329 * should not contain RTP header 330 */ 331 void ProcessStart(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, 332 const uint8_t* p_codec_info, bool* p_no_rtp_header); 333 334 /** 335 * Process AVDTP Stop when the audio data streaming is stopped. 336 * 337 * @param bta_av_handle the BTA AV handle to identify the peer 338 * @param peer_address the peer address 339 */ 340 void ProcessStop(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address); 341 342 /** 343 * Get the next encoded audio data packet to send. 344 * 345 * @param p_codec_info the codec configuration 346 * @param p_timestamp on return, set to the timestamp of the data packet 347 * @return the next encoded data packet or nullptr if no encoded data to send 348 */ 349 BT_HDR* GetNextSourceDataPacket(const uint8_t* p_codec_info, 350 uint32_t* p_timestamp); 351 352 /** 353 * An audio packet has been dropped. 354 * This signal can be used by the encoder to reduce the encoder bit rate 355 * setting. 356 * 357 * @param bta_av_handle the BTA AV handle to identify the peer 358 * @param peer_address the peer address 359 */ 360 void DataPacketWasDropped(tBTA_AV_HNDL bta_av_handle, 361 const RawAddress& peer_address); 362 363 /** 364 * Process AVDTP Audio Delay when the initial delay report is received by 365 * the Source. 366 * 367 * @param bta_av_handle the BTA AV handle to identify the peer 368 * @param peer_address the peer address 369 * @param delay the reported delay in 1/10th of a millisecond 370 */ 371 void ProcessAudioDelay(tBTA_AV_HNDL bta_av_handle, 372 const RawAddress& peer_address, uint16_t delay); 373 374 /** 375 * Update the MTU of the audio data connection. 376 * 377 * @param bta_av_handle the BTA AV handle to identify the peer 378 * @param peer_address the peer address 379 * @param mtu the new MTU of the audio data connection 380 */ 381 void UpdateMtu(tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, 382 uint16_t mtu); 383 384 /** 385 * Set the active peer. 386 * 387 * @param peer_address the peer address 388 * @return true on success, otherwise false 389 */ 390 bool SetActivePeer(const RawAddress& peer_address); 391 392 /** 393 * Get the encoder parameters for a peer. 394 * 395 * @param peer_address the peer address 396 * @param p_peer_params on return, set to the peer's encoder parameters 397 */ 398 void GetPeerEncoderParameters(const RawAddress& peer_address, 399 tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params); 400 401 /** 402 * Get the Source encoder interface for the current codec. 403 * 404 * @return the Source encoder interface for the current codec 405 */ 406 const tA2DP_ENCODER_INTERFACE* GetSourceEncoderInterface(); 407 408 /** 409 * Get the Sink decoder interface for the current codec. 410 * 411 * @return the Sink decoder interface for the current codec 412 */ 413 const tA2DP_DECODER_INTERFACE* GetSinkDecoderInterface(); 414 415 /** 416 * Set the codec user configuration. 417 * 418 * @param peer_address the peer address 419 * @param codec_user_config the codec user configuration to set 420 * @param p_restart_output if there is a change in the encoder configuration 421 * that requires restarting of the A2DP connection, flag |p_restart_output| 422 * will be set to true. 423 * @return true on success, otherwise false 424 */ 425 bool SetCodecUserConfig(const RawAddress& peer_address, 426 const btav_a2dp_codec_config_t& codec_user_config, 427 bool* p_restart_output); 428 429 /** 430 * Set the codec audio configuration. 431 * 432 * @param codec_audio_config the codec audio configuration to set 433 * @return true on success, otherwise false 434 */ 435 bool SetCodecAudioConfig(const btav_a2dp_codec_config_t& codec_audio_config); 436 437 /** 438 * Report the source codec state for a peer 439 * 440 * @param p_peer the peer to report 441 * @return true on success, otherwise false 442 */ 443 bool ReportSourceCodecState(BtaAvCoPeer* p_peer); 444 445 /** 446 * Report the sink codec state for a peer 447 * 448 * @param p_peer the peer to report 449 * @return true on success, otherwise false 450 */ 451 bool ReportSinkCodecState(BtaAvCoPeer* p_peer); 452 453 /** 454 * Get the content protection flag. 455 * 456 * @return the content protection flag. It should be one of the following: 457 * AVDT_CP_SCMS_COPY_NEVER, AVDT_CP_SCMS_COPY_ONCE, AVDT_CP_SCMS_COPY_FREE 458 */ 459 uint8_t ContentProtectFlag() const { return content_protect_flag_; } 460 461 /** 462 * Set the content protection flag. 463 * 464 * @param cp_flag the content protection flag. It should be one of the 465 * following: 466 * AVDT_CP_SCMS_COPY_NEVER, AVDT_CP_SCMS_COPY_ONCE, AVDT_CP_SCMS_COPY_FREE 467 * NOTE: If Content Protection is not enabled on the system, then 468 * the only acceptable vailue is AVDT_CP_SCMS_COPY_FREE. 469 */ 470 void SetContentProtectFlag(uint8_t cp_flag) { 471 if (!ContentProtectEnabled() && (cp_flag != AVDT_CP_SCMS_COPY_FREE)) { 472 return; 473 } 474 content_protect_flag_ = cp_flag; 475 } 476 477 /** 478 * Dump debug-related information. 479 * 480 * @param fd the file descritor to use for writing the ASCII formatted 481 * information 482 */ 483 void DebugDump(int fd); 484 485 /** 486 * Find the peer entry for a given peer address. 487 * 488 * @param peer_address the peer address to use 489 * @return the peer entry if found, otherwise nullptr 490 */ 491 BtaAvCoPeer* FindPeer(const RawAddress& peer_address); 492 493 /** 494 * Find the peer Sink SEP entry for a given codec index. 495 * 496 * @param p_peer the peer to use 497 * @param codec_index the codec index to use 498 * @return the peer Sink SEP for the codec index if found, otherwise nullptr 499 */ 500 BtaAvCoSep* FindPeerSink(BtaAvCoPeer* p_peer, 501 btav_a2dp_codec_index_t codec_index); 502 503 /** 504 * Find the peer Source SEP entry for a given codec index. 505 * 506 * @param p_peer the peer to use 507 * @param codec_config the codec index to use 508 * @return the peer Source SEP for the codec index if found, otherwise nullptr 509 */ 510 BtaAvCoSep* FindPeerSource(BtaAvCoPeer* p_peer, 511 btav_a2dp_codec_index_t codec_index); 512 513 private: 514 /** 515 * Reset the state. 516 */ 517 void Reset(); 518 519 /** 520 * Find the peer entry for a given BTA AV handle. 521 * 522 * @param bta_av_handle the BTA AV handle to use 523 * @return the peer entry if found, otherwise nullptr 524 */ 525 BtaAvCoPeer* FindPeer(tBTA_AV_HNDL bta_av_handle); 526 527 /** 528 * Find the peer entry for a given BTA AV handle and update it with the 529 * peer address. 530 * 531 * @param bta_av_handle the BTA AV handle to use 532 * @param peer_address the peer address 533 * @return the peer entry if found, otherwise nullptr 534 */ 535 BtaAvCoPeer* FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle, 536 const RawAddress& peer_address); 537 538 /** 539 * Select the Source codec configuration based on peer codec support. 540 * 541 * Furthermore, the local state for the remaining non-selected codecs is 542 * updated to reflect whether the codec is selectable. 543 * 544 * @param p_peer the peer to use 545 * @return a pointer to the corresponding SEP Sink entry on success, 546 * otherwise nullptr 547 */ 548 const BtaAvCoSep* SelectSourceCodec(BtaAvCoPeer* p_peer); 549 550 /** 551 * Select the Sink codec configuration based on peer codec support. 552 * 553 * Furthermore, the local state for the remaining non-selected codecs is 554 * updated to reflect whether the codec is selectable. 555 * 556 * @param p_peer the peer to use 557 * @return a pointer to the corresponding SEP Source entry on success, 558 * otherwise nullptr 559 */ 560 const BtaAvCoSep* SelectSinkCodec(BtaAvCoPeer* p_peer); 561 562 /** 563 * Save new codec configuration. 564 * 565 * @param p_peer the peer to use 566 * @param new_codec_config the new codec configuration to use 567 * @param num_protect the number of content protection elements 568 * @param p_protect_info the content protection info to use 569 */ 570 void SaveNewCodecConfig(BtaAvCoPeer* p_peer, const uint8_t* new_codec_config, 571 uint8_t num_protect, const uint8_t* p_protect_info); 572 573 /** 574 * Set the Over-The-Air preferred codec configuration. 575 * 576 * The OTA prefered codec configuration is ignored if the current 577 * codec configuration contains explicit user configuration, or if the 578 * codec configuration for the same codec contains explicit user 579 * configuration. 580 * 581 * @param p_peer is the peer device that sent the OTA codec configuration 582 * @param p_ota_codec_config contains the received OTA A2DP codec 583 * configuration from the remote peer. Note: this is not the peer codec 584 * capability, but the codec configuration that the peer would like to use. 585 * @param num_protect is the number of content protection methods to use 586 * @param p_protect_info contains the content protection information to use. 587 * @param p_restart_output if there is a change in the encoder configuration 588 * that requires restarting of the A2DP connection, flag |p_restart_output| 589 * is set to true. 590 * @return true on success, otherwise false 591 */ 592 bool SetCodecOtaConfig(BtaAvCoPeer* p_peer, const uint8_t* p_ota_codec_config, 593 uint8_t num_protect, const uint8_t* p_protect_info, 594 bool* p_restart_output); 595 596 /** 597 * Update all selectable Source codecs with the corresponding codec 598 * information from a Sink peer. 599 * 600 * @param p_peer the peer Sink SEP to use 601 * @return the number of codecs that have been updated 602 */ 603 size_t UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer); 604 605 /** 606 * Update a selectable Source codec with the corresponding codec information 607 * from a Sink peer. 608 * 609 * @param codec_config the codec config info to identify the codec to update 610 * @param p_peer the peer Sink SEP to use 611 * @return true if the codec is updated, otherwise false 612 */ 613 bool UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config, 614 BtaAvCoPeer* p_peer); 615 616 /** 617 * Update all selectable Sink codecs with the corresponding codec 618 * information from a Source peer. 619 * 620 * @param p_peer the peer Source SEP to use 621 * @return the number of codecs that have been updated 622 */ 623 size_t UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer); 624 625 /** 626 * Update a selectable Sink codec with the corresponding codec information 627 * from a Source peer. 628 * 629 * @param codec_config the codec config info to identify the codec to update 630 * @param p_peer the peer Source SEP to use 631 * @return true if the codec is updated, otherwise false 632 */ 633 bool UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config, 634 BtaAvCoPeer* p_peer); 635 636 /** 637 * Attempt to select Source codec configuration for a Sink peer. 638 * 639 * @param codec_config the codec configuration to use 640 * @param p_peer the Sink peer to use 641 * @return a pointer to the corresponding SEP Sink entry on success, 642 * otnerwise nullptr 643 */ 644 const BtaAvCoSep* AttemptSourceCodecSelection( 645 const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer); 646 647 /** 648 * Attempt to select Sink codec configuration for a Source peer. 649 * 650 * @param codec_config the codec configuration to use 651 * @param p_peer the Source peer to use 652 * @return a pointer to the corresponding SEP Source entry on success, 653 * otnerwise nullptr 654 */ 655 const BtaAvCoSep* AttemptSinkCodecSelection( 656 const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer); 657 658 /** 659 * Check if a peer SEP has content protection enabled. 660 * 661 * @param p_sep the peer SEP to check 662 * @return true if the peer SEP has content protection enabled, 663 * otherwise false 664 */ 665 bool AudioSepHasContentProtection(const BtaAvCoSep* p_sep); 666 667 /** 668 * Check if a content protection service is SCMS-T. 669 * 670 * @param p_orotect_info the content protection info to check 671 * @return true if the Contention Protection in @param p_protect_info 672 * is SCMS-T, otherwise false 673 */ 674 static bool ContentProtectIsScmst(const uint8_t* p_protect_info); 675 676 /** 677 * Check if audio protect info contains SCMS-T Content Protection. 678 * 679 * @param num_protect number of protect schemes 680 * @param p_protect_info the protect info to check 681 * @return true if @param p_protect_info contains SCMS-T, otherwise false 682 */ 683 static bool AudioProtectHasScmst(uint8_t num_protect, 684 const uint8_t* p_protect_info); 685 686 bool ContentProtectEnabled() const { return content_protect_enabled_; } 687 688 std::recursive_mutex codec_lock_; // Protect access to the codec state 689 std::vector<btav_a2dp_codec_config_t> codec_priorities_; // Configured 690 BtaAvCoPeer peers_[BTA_AV_NUM_STRS]; // Connected peer information 691 BtaAvCoPeer* active_peer_; // The current active peer 692 uint8_t codec_config_[AVDT_CODEC_SIZE]; // Current codec configuration 693 const bool content_protect_enabled_; // True if Content Protect is enabled 694 uint8_t content_protect_flag_; // Content Protect flag 695 }; 696 697 // SCMS-T protect info 698 const uint8_t bta_av_co_cp_scmst[AVDT_CP_INFO_LEN] = {0x02, 0x02, 0x00}; 699 700 // Control block instance 701 #if (BTA_AV_CO_CP_SCMS_T == TRUE) 702 static const bool kContentProtectEnabled = true; 703 #else 704 static const bool kContentProtectEnabled = false; 705 #endif 706 static BtaAvCo bta_av_co_cb(kContentProtectEnabled); 707 708 void BtaAvCoPeer::Init( 709 const std::vector<btav_a2dp_codec_config_t>& codec_priorities) { 710 Reset(bta_av_handle_); 711 // Reset the current config 712 codecs_ = new A2dpCodecs(codec_priorities); 713 codecs_->init(); 714 A2DP_InitDefaultCodec(codec_config); 715 } 716 717 void BtaAvCoPeer::Reset(tBTA_AV_HNDL bta_av_handle) { 718 addr = RawAddress::kEmpty; 719 for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(sinks); i++) { 720 BtaAvCoSep& sink = sinks[i]; 721 sink.Reset(); 722 } 723 for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(sources); i++) { 724 BtaAvCoSep& source = sources[i]; 725 source.Reset(); 726 } 727 num_sinks = 0; 728 num_sources = 0; 729 num_seps = 0; 730 num_rx_sinks = 0; 731 num_rx_sources = 0; 732 num_sup_sinks = 0; 733 num_sup_sources = 0; 734 p_sink = nullptr; 735 p_source = nullptr; 736 memset(codec_config, 0, sizeof(codec_config)); 737 acceptor = false; 738 reconfig_needed = false; 739 opened = false; 740 mtu = 0; 741 uuid_to_connect = 0; 742 743 bta_av_handle_ = bta_av_handle; 744 delete codecs_; 745 codecs_ = nullptr; 746 content_protect_active_ = false; 747 } 748 749 void BtaAvCo::Init( 750 const std::vector<btav_a2dp_codec_config_t>& codec_priorities) { 751 APPL_TRACE_DEBUG("%s", __func__); 752 753 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 754 755 // Reset the control block 756 Reset(); 757 codec_priorities_ = codec_priorities; 758 759 for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { 760 BtaAvCoPeer* p_peer = &peers_[i]; 761 p_peer->Init(codec_priorities); 762 } 763 } 764 765 void BtaAvCo::Reset() { 766 codec_priorities_.clear(); 767 active_peer_ = nullptr; 768 content_protect_flag_ = 0; 769 memset(codec_config_, 0, sizeof(codec_config_)); 770 771 if (ContentProtectEnabled()) { 772 SetContentProtectFlag(AVDT_CP_SCMS_COPY_NEVER); 773 } else { 774 SetContentProtectFlag(AVDT_CP_SCMS_COPY_FREE); 775 } 776 777 // Reset the peers and initialize the handles 778 for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { 779 BtaAvCoPeer* p_peer = &peers_[i]; 780 p_peer->Reset(BTA_AV_CO_AUDIO_INDEX_TO_HANDLE(i)); 781 } 782 } 783 784 bool BtaAvCo::IsSupportedCodec(btav_a2dp_codec_index_t codec_index) { 785 // All peer state is initialized with the same local codec config, 786 // hence we check only the first peer. 787 A2dpCodecs* codecs = peers_[0].GetCodecs(); 788 CHECK(codecs != nullptr); 789 return codecs->isSupportedCodec(codec_index); 790 } 791 792 A2dpCodecConfig* BtaAvCo::GetActivePeerCurrentCodec() { 793 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 794 795 if (active_peer_ == nullptr || active_peer_->GetCodecs() == nullptr) { 796 return nullptr; 797 } 798 return active_peer_->GetCodecs()->getCurrentCodecConfig(); 799 } 800 801 A2dpCodecConfig* BtaAvCo::GetPeerCurrentCodec(const RawAddress& peer_address) { 802 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 803 804 BtaAvCoPeer* peer = FindPeer(peer_address); 805 if (peer == nullptr || peer->GetCodecs() == nullptr) { 806 return nullptr; 807 } 808 return peer->GetCodecs()->getCurrentCodecConfig(); 809 } 810 811 BtaAvCoPeer* BtaAvCo::FindPeer(const RawAddress& peer_address) { 812 for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { 813 BtaAvCoPeer* p_peer = &peers_[i]; 814 if (p_peer->addr == peer_address) { 815 return p_peer; 816 } 817 } 818 return nullptr; 819 } 820 821 BtaAvCoPeer* BtaAvCo::FindPeer(tBTA_AV_HNDL bta_av_handle) { 822 uint8_t index; 823 824 index = BTA_AV_CO_AUDIO_HANDLE_TO_INDEX(bta_av_handle); 825 826 APPL_TRACE_DEBUG("%s: bta_av_handle = 0x%x index = %d", __func__, 827 bta_av_handle, index); 828 829 // Sanity check 830 if (index >= BTA_AV_CO_NUM_ELEMENTS(peers_)) { 831 APPL_TRACE_ERROR( 832 "%s: peer index %d for BTA AV handle 0x%x is out of bounds", __func__, 833 index, bta_av_handle); 834 return nullptr; 835 } 836 837 return &peers_[index]; 838 } 839 840 BtaAvCoPeer* BtaAvCo::FindPeerAndUpdate(tBTA_AV_HNDL bta_av_handle, 841 const RawAddress& peer_address) { 842 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle = 0x%x", __func__, 843 peer_address.ToString().c_str(), bta_av_handle); 844 845 BtaAvCoPeer* p_peer = FindPeer(bta_av_handle); 846 if (p_peer == nullptr) { 847 APPL_TRACE_ERROR("%s: peer entry for BTA AV handle 0x%x peer %s not found", 848 __func__, bta_av_handle, peer_address.ToString().c_str()); 849 return nullptr; 850 } 851 852 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle = 0x%x previous address %s", 853 __func__, peer_address.ToString().c_str(), bta_av_handle, 854 p_peer->addr.ToString().c_str()); 855 p_peer->addr = peer_address; 856 return p_peer; 857 } 858 859 uint16_t BtaAvCo::FindPeerUuid(tBTA_AV_HNDL bta_av_handle) { 860 BtaAvCoPeer* p_peer = FindPeer(bta_av_handle); 861 if (p_peer == nullptr) { 862 return 0; 863 } 864 return p_peer->uuid_to_connect; 865 } 866 867 void BtaAvCo::ProcessDiscoveryResult(tBTA_AV_HNDL bta_av_handle, 868 const RawAddress& peer_address, 869 uint8_t num_seps, uint8_t num_sinks, 870 uint8_t num_sources, uint16_t uuid_local) { 871 APPL_TRACE_DEBUG( 872 "%s: peer %s bta_av_handle:0x%x num_seps:%d num_sinks:%d num_sources:%d", 873 __func__, peer_address.ToString().c_str(), bta_av_handle, num_seps, 874 num_sinks, num_sources); 875 876 // Find the peer 877 BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); 878 if (p_peer == nullptr) { 879 APPL_TRACE_ERROR( 880 "%s: could not find peer entry for bta_av_handle 0x%x peer %s", 881 __func__, bta_av_handle, peer_address.ToString().c_str()); 882 return; 883 } 884 885 /* Sanity check : this should never happen */ 886 if (p_peer->opened) { 887 APPL_TRACE_ERROR("%s: peer %s already opened", __func__, 888 peer_address.ToString().c_str()); 889 } 890 891 /* Copy the discovery results */ 892 p_peer->addr = peer_address; 893 p_peer->num_sinks = num_sinks; 894 p_peer->num_sources = num_sources; 895 p_peer->num_seps = num_seps; 896 p_peer->num_rx_sinks = 0; 897 p_peer->num_rx_sources = 0; 898 p_peer->num_sup_sinks = 0; 899 p_peer->num_sup_sources = 0; 900 if (uuid_local == UUID_SERVCLASS_AUDIO_SINK) { 901 p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SOURCE; 902 } else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE) { 903 p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SINK; 904 } 905 } 906 907 tA2DP_STATUS BtaAvCo::ProcessSourceGetConfig( 908 tBTA_AV_HNDL bta_av_handle, const RawAddress& peer_address, 909 uint8_t* p_codec_info, uint8_t* p_sep_info_idx, uint8_t seid, 910 uint8_t* p_num_protect, uint8_t* p_protect_info) { 911 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle:0x%x codec:%s seid:%d", __func__, 912 peer_address.ToString().c_str(), bta_av_handle, 913 A2DP_CodecName(p_codec_info), seid); 914 APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", 915 __func__, *p_num_protect, p_protect_info[0], 916 p_protect_info[1], p_protect_info[2]); 917 APPL_TRACE_DEBUG("%s: codec: %s", __func__, 918 A2DP_CodecInfoString(p_codec_info).c_str()); 919 920 // Find the peer 921 BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); 922 if (p_peer == nullptr) { 923 APPL_TRACE_ERROR( 924 "%s: could not find peer entry for bta_av_handle 0x%x peer %s", 925 __func__, bta_av_handle, peer_address.ToString().c_str()); 926 return A2DP_FAIL; 927 } 928 APPL_TRACE_DEBUG("%s: peer(o=%d, n_sinks=%d, n_rx_sinks=%d, n_sup_sinks=%d)", 929 __func__, p_peer->opened, p_peer->num_sinks, 930 p_peer->num_rx_sinks, p_peer->num_sup_sinks); 931 932 p_peer->num_rx_sinks++; 933 934 // Check the peer's Sink codec 935 if (A2DP_IsPeerSinkCodecValid(p_codec_info)) { 936 // If there is room for a new one 937 if (p_peer->num_sup_sinks < BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks)) { 938 BtaAvCoSep* p_sink = &p_peer->sinks[p_peer->num_sup_sinks++]; 939 940 APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__, 941 p_codec_info[1], p_codec_info[2], p_codec_info[3], 942 p_codec_info[4], p_codec_info[5], p_codec_info[6]); 943 944 memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE); 945 p_sink->sep_info_idx = *p_sep_info_idx; 946 p_sink->seid = seid; 947 p_sink->num_protect = *p_num_protect; 948 memcpy(p_sink->protect_info, p_protect_info, AVDT_CP_INFO_LEN); 949 } else { 950 APPL_TRACE_ERROR("%s: peer %s : no more room for Sink info", __func__, 951 p_peer->addr.ToString().c_str()); 952 } 953 } 954 955 // Check if this is the last Sink get capabilities or all supported codec 956 // capabilities are retrieved. 957 if ((p_peer->num_rx_sinks != p_peer->num_sinks) && 958 (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) { 959 return A2DP_FAIL; 960 } 961 APPL_TRACE_DEBUG("%s: last Sink codec reached for peer %s (local %s)", 962 __func__, p_peer->addr.ToString().c_str(), 963 p_peer->acceptor ? "acceptor" : "initiator"); 964 965 // Select the Source codec 966 const BtaAvCoSep* p_sink = nullptr; 967 if (p_peer->acceptor) { 968 UpdateAllSelectableSourceCodecs(p_peer); 969 if (p_peer->p_sink == nullptr) { 970 // Update the selected codec 971 p_peer->p_sink = 972 FindPeerSink(p_peer, A2DP_SourceCodecIndex(p_peer->codec_config)); 973 } 974 p_sink = p_peer->p_sink; 975 if (p_sink == nullptr) { 976 APPL_TRACE_ERROR("%s: cannot find the selected codec for peer %s", 977 __func__, p_peer->addr.ToString().c_str()); 978 return A2DP_FAIL; 979 } 980 } else { 981 if (btif_av_peer_prefers_mandatory_codec(p_peer->addr)) { 982 // Apply user preferred codec directly before first codec selected. 983 p_sink = FindPeerSink(p_peer, BTAV_A2DP_CODEC_INDEX_SOURCE_SBC); 984 if (p_sink != nullptr) { 985 APPL_TRACE_API("%s: mandatory codec preferred for peer %s", __func__, 986 p_peer->addr.ToString().c_str()); 987 btav_a2dp_codec_config_t high_priority_mandatory{ 988 .codec_type = BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, 989 .codec_priority = BTAV_A2DP_CODEC_PRIORITY_HIGHEST, 990 // Using default settings for those untouched fields 991 }; 992 uint8_t result_codec_config[AVDT_CODEC_SIZE]; 993 bool restart_input = false; 994 bool restart_output = false; 995 bool config_updated = false; 996 tA2DP_ENCODER_INIT_PEER_PARAMS peer_params; 997 GetPeerEncoderParameters(p_peer->addr, &peer_params); 998 p_peer->GetCodecs()->setCodecUserConfig( 999 high_priority_mandatory, &peer_params, p_sink->codec_caps, 1000 result_codec_config, &restart_input, &restart_output, 1001 &config_updated); 1002 } else { 1003 APPL_TRACE_WARNING("%s: mandatory codec not found for peer %s", 1004 __func__, p_peer->addr.ToString().c_str()); 1005 } 1006 } 1007 p_sink = SelectSourceCodec(p_peer); 1008 if (p_sink == nullptr) { 1009 APPL_TRACE_ERROR("%s: cannot set up codec for peer %s", __func__, 1010 p_peer->addr.ToString().c_str()); 1011 return A2DP_FAIL; 1012 } 1013 } 1014 1015 // By default, no content protection 1016 *p_num_protect = 0; 1017 if (ContentProtectEnabled() && p_peer->ContentProtectActive()) { 1018 *p_num_protect = AVDT_CP_INFO_LEN; 1019 memcpy(p_protect_info, bta_av_co_cp_scmst, AVDT_CP_INFO_LEN); 1020 } 1021 1022 // If acceptor -> reconfig otherwise reply for configuration 1023 *p_sep_info_idx = p_sink->sep_info_idx; 1024 APPL_TRACE_EVENT("%s: peer %s acceptor:%s reconfig_needed:%s", __func__, 1025 p_peer->addr.ToString().c_str(), 1026 (p_peer->acceptor) ? "true" : "false", 1027 (p_peer->reconfig_needed) ? "true" : "false"); 1028 if (p_peer->acceptor) { 1029 if (p_peer->reconfig_needed) { 1030 APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__, 1031 bta_av_handle, p_peer->addr.ToString().c_str()); 1032 BTA_AvReconfig(bta_av_handle, true, p_sink->sep_info_idx, 1033 p_peer->codec_config, *p_num_protect, bta_av_co_cp_scmst); 1034 } 1035 } else { 1036 memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE); 1037 } 1038 1039 // report this peer selectable codecs after retrieved all its capabilities. 1040 LOG(INFO) << __func__ << ": retrieved " << +p_peer->num_rx_sinks 1041 << " capabilities from peer " << p_peer->addr; 1042 ReportSourceCodecState(p_peer); 1043 1044 return A2DP_SUCCESS; 1045 } 1046 1047 tA2DP_STATUS BtaAvCo::ProcessSinkGetConfig(tBTA_AV_HNDL bta_av_handle, 1048 const RawAddress& peer_address, 1049 uint8_t* p_codec_info, 1050 uint8_t* p_sep_info_idx, 1051 uint8_t seid, uint8_t* p_num_protect, 1052 uint8_t* p_protect_info) { 1053 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 1054 1055 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle:0x%x codec:%s seid:%d", __func__, 1056 peer_address.ToString().c_str(), bta_av_handle, 1057 A2DP_CodecName(p_codec_info), seid); 1058 APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", 1059 __func__, *p_num_protect, p_protect_info[0], 1060 p_protect_info[1], p_protect_info[2]); 1061 APPL_TRACE_DEBUG("%s: codec: %s", __func__, 1062 A2DP_CodecInfoString(p_codec_info).c_str()); 1063 1064 // Find the peer 1065 BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); 1066 if (p_peer == nullptr) { 1067 APPL_TRACE_ERROR( 1068 "%s: could not find peer entry for bta_av_handle 0x%x peer %s", 1069 __func__, bta_av_handle, peer_address.ToString().c_str()); 1070 return A2DP_FAIL; 1071 } 1072 APPL_TRACE_DEBUG( 1073 "%s: peer %s found (o=%d, n_sources=%d, n_rx_sources=%d, " 1074 "n_sup_sources=%d)", 1075 __func__, p_peer->addr.ToString().c_str(), p_peer->opened, 1076 p_peer->num_sources, p_peer->num_rx_sources, p_peer->num_sup_sources); 1077 1078 p_peer->num_rx_sources++; 1079 1080 // Check the peer's Source codec 1081 if (A2DP_IsPeerSourceCodecValid(p_codec_info)) { 1082 // If there is room for a new one 1083 if (p_peer->num_sup_sources < BTA_AV_CO_NUM_ELEMENTS(p_peer->sources)) { 1084 BtaAvCoSep* p_source = &p_peer->sources[p_peer->num_sup_sources++]; 1085 1086 APPL_TRACE_DEBUG("%s: saved caps[%x:%x:%x:%x:%x:%x]", __func__, 1087 p_codec_info[1], p_codec_info[2], p_codec_info[3], 1088 p_codec_info[4], p_codec_info[5], p_codec_info[6]); 1089 1090 memcpy(p_source->codec_caps, p_codec_info, AVDT_CODEC_SIZE); 1091 p_source->sep_info_idx = *p_sep_info_idx; 1092 p_source->seid = seid; 1093 p_source->num_protect = *p_num_protect; 1094 memcpy(p_source->protect_info, p_protect_info, AVDT_CP_INFO_LEN); 1095 } else { 1096 APPL_TRACE_ERROR("%s: peer %s : no more room for Source info", __func__, 1097 p_peer->addr.ToString().c_str()); 1098 } 1099 } 1100 1101 // Check if this is the last Source get capabilities or all supported codec 1102 // capabilities are retrieved. 1103 if ((p_peer->num_rx_sources != p_peer->num_sources) && 1104 (p_peer->num_sup_sources != BTA_AV_CO_NUM_ELEMENTS(p_peer->sources))) { 1105 return A2DP_FAIL; 1106 } 1107 APPL_TRACE_DEBUG("%s: last Source codec reached for peer %s", __func__, 1108 p_peer->addr.ToString().c_str()); 1109 1110 // Select the Sink codec 1111 const BtaAvCoSep* p_source = nullptr; 1112 if (p_peer->acceptor) { 1113 UpdateAllSelectableSinkCodecs(p_peer); 1114 if (p_peer->p_source == nullptr) { 1115 // Update the selected codec 1116 p_peer->p_source = 1117 FindPeerSource(p_peer, A2DP_SinkCodecIndex(p_peer->codec_config)); 1118 } 1119 p_source = p_peer->p_source; 1120 if (p_source == nullptr) { 1121 APPL_TRACE_ERROR("%s: cannot find the selected codec for peer %s", 1122 __func__, p_peer->addr.ToString().c_str()); 1123 return A2DP_FAIL; 1124 } 1125 } else { 1126 p_source = SelectSinkCodec(p_peer); 1127 if (p_source == nullptr) { 1128 APPL_TRACE_ERROR("%s: cannot set up codec for the peer %s", __func__, 1129 p_peer->addr.ToString().c_str()); 1130 return A2DP_FAIL; 1131 } 1132 } 1133 1134 // By default, no content protection 1135 *p_num_protect = 0; 1136 if (ContentProtectEnabled() && p_peer->ContentProtectActive()) { 1137 *p_num_protect = AVDT_CP_INFO_LEN; 1138 memcpy(p_protect_info, bta_av_co_cp_scmst, AVDT_CP_INFO_LEN); 1139 } 1140 1141 // If acceptor -> reconfig otherwise reply for configuration 1142 *p_sep_info_idx = p_source->sep_info_idx; 1143 APPL_TRACE_EVENT("%s: peer %s acceptor:%s reconfig_needed:%s", __func__, 1144 p_peer->addr.ToString().c_str(), 1145 (p_peer->acceptor) ? "true" : "false", 1146 (p_peer->reconfig_needed) ? "true" : "false"); 1147 if (p_peer->acceptor) { 1148 if (p_peer->reconfig_needed) { 1149 APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x) for peer %s", __func__, 1150 bta_av_handle, p_peer->addr.ToString().c_str()); 1151 BTA_AvReconfig(bta_av_handle, true, p_source->sep_info_idx, 1152 p_peer->codec_config, *p_num_protect, bta_av_co_cp_scmst); 1153 } 1154 } else { 1155 memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE); 1156 } 1157 1158 return A2DP_SUCCESS; 1159 } 1160 1161 void BtaAvCo::ProcessSetConfig(tBTA_AV_HNDL bta_av_handle, 1162 UNUSED_ATTR const RawAddress& peer_address, 1163 const uint8_t* p_codec_info, 1164 UNUSED_ATTR uint8_t seid, uint8_t num_protect, 1165 const uint8_t* p_protect_info, 1166 uint8_t t_local_sep, uint8_t avdt_handle) { 1167 tA2DP_STATUS status = A2DP_SUCCESS; 1168 uint8_t category = A2DP_SUCCESS; 1169 bool reconfig_needed = false; 1170 1171 APPL_TRACE_DEBUG( 1172 "%s: bta_av_handle=0x%x peer_address=%s seid=%d " 1173 "num_protect=%d t_local_sep=%d avdt_handle=%d", 1174 __func__, bta_av_handle, peer_address.ToString().c_str(), seid, 1175 num_protect, t_local_sep, avdt_handle); 1176 APPL_TRACE_DEBUG("%s: p_codec_info[%x:%x:%x:%x:%x:%x]", __func__, 1177 p_codec_info[1], p_codec_info[2], p_codec_info[3], 1178 p_codec_info[4], p_codec_info[5], p_codec_info[6]); 1179 APPL_TRACE_DEBUG("%s: num_protect:0x%02x protect_info:0x%02x%02x%02x", 1180 __func__, num_protect, p_protect_info[0], p_protect_info[1], 1181 p_protect_info[2]); 1182 APPL_TRACE_DEBUG("%s: codec: %s", __func__, 1183 A2DP_CodecInfoString(p_codec_info).c_str()); 1184 1185 // Find the peer 1186 BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); 1187 if (p_peer == nullptr) { 1188 APPL_TRACE_ERROR( 1189 "%s: could not find peer entry for bta_av_handle 0x%x peer %s", 1190 __func__, bta_av_handle, peer_address.ToString().c_str()); 1191 // Call call-in rejecting the configuration 1192 bta_av_ci_setconfig(bta_av_handle, A2DP_BUSY, AVDT_ASC_CODEC, 0, nullptr, 1193 false, avdt_handle); 1194 return; 1195 } 1196 1197 APPL_TRACE_DEBUG( 1198 "%s: peer %s found (o=%d, n_sinks=%d, n_rx_sinks=%d, " 1199 "n_sup_sinks=%d)", 1200 __func__, p_peer->addr.ToString().c_str(), p_peer->opened, 1201 p_peer->num_sinks, p_peer->num_rx_sinks, p_peer->num_sup_sinks); 1202 1203 // Sanity check: should not be opened at this point 1204 if (p_peer->opened) { 1205 APPL_TRACE_ERROR("%s: peer %s already in use", __func__, 1206 p_peer->addr.ToString().c_str()); 1207 } 1208 1209 if (num_protect != 0) { 1210 if (ContentProtectEnabled()) { 1211 if ((num_protect != 1) || 1212 !BtaAvCo::ContentProtectIsScmst(p_protect_info)) { 1213 APPL_TRACE_ERROR("%s: wrong CP configuration for peer %s", __func__, 1214 p_peer->addr.ToString().c_str()); 1215 status = A2DP_BAD_CP_TYPE; 1216 category = AVDT_ASC_PROTECT; 1217 } 1218 } else { 1219 // Do not support content protection for the time being 1220 APPL_TRACE_ERROR("%s: wrong CP configuration for peer %s", __func__, 1221 p_peer->addr.ToString().c_str()); 1222 status = A2DP_BAD_CP_TYPE; 1223 category = AVDT_ASC_PROTECT; 1224 } 1225 } 1226 1227 if (status == A2DP_SUCCESS) { 1228 bool codec_config_supported = false; 1229 1230 if (t_local_sep == AVDT_TSEP_SNK) { 1231 APPL_TRACE_DEBUG("%s: peer %s is A2DP Source", __func__, 1232 p_peer->addr.ToString().c_str()); 1233 codec_config_supported = A2DP_IsSinkCodecSupported(p_codec_info); 1234 if (codec_config_supported) { 1235 // If Peer is Source, and our config subset matches with what is 1236 // requested by peer, then just accept what peer wants. 1237 SaveNewCodecConfig(p_peer, p_codec_info, num_protect, p_protect_info); 1238 } 1239 } 1240 if (t_local_sep == AVDT_TSEP_SRC) { 1241 APPL_TRACE_DEBUG("%s: peer %s is A2DP SINK", __func__, 1242 p_peer->addr.ToString().c_str()); 1243 // Ignore the restart_output flag: accepting the remote device's 1244 // codec selection should not trigger codec reconfiguration. 1245 bool dummy_restart_output = false; 1246 if ((p_peer->GetCodecs() == nullptr) || 1247 !SetCodecOtaConfig(p_peer, p_codec_info, num_protect, p_protect_info, 1248 &dummy_restart_output)) { 1249 APPL_TRACE_ERROR("%s: cannot set source codec %s for peer %s", __func__, 1250 A2DP_CodecName(p_codec_info), 1251 p_peer->addr.ToString().c_str()); 1252 } else { 1253 codec_config_supported = true; 1254 // Check if reconfiguration is needed 1255 if (((num_protect == 1) && !p_peer->ContentProtectActive())) { 1256 reconfig_needed = true; 1257 } 1258 } 1259 } 1260 1261 // Check if codec configuration is supported 1262 if (!codec_config_supported) { 1263 category = AVDT_ASC_CODEC; 1264 status = A2DP_WRONG_CODEC; 1265 } 1266 } 1267 1268 if (status != A2DP_SUCCESS) { 1269 APPL_TRACE_DEBUG("%s: peer %s reject s=%d c=%d", __func__, 1270 p_peer->addr.ToString().c_str(), status, category); 1271 // Call call-in rejecting the configuration 1272 bta_av_ci_setconfig(bta_av_handle, status, category, 0, nullptr, false, 1273 avdt_handle); 1274 return; 1275 } 1276 1277 // Mark that this is an acceptor peer 1278 p_peer->acceptor = true; 1279 p_peer->reconfig_needed = reconfig_needed; 1280 APPL_TRACE_DEBUG("%s: peer %s accept reconf=%d", __func__, 1281 p_peer->addr.ToString().c_str(), reconfig_needed); 1282 // Call call-in accepting the configuration 1283 bta_av_ci_setconfig(bta_av_handle, A2DP_SUCCESS, A2DP_SUCCESS, 0, nullptr, 1284 reconfig_needed, avdt_handle); 1285 } 1286 1287 void BtaAvCo::ProcessOpen(tBTA_AV_HNDL bta_av_handle, 1288 const RawAddress& peer_address, uint16_t mtu) { 1289 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x mtu:%d", __func__, 1290 peer_address.ToString().c_str(), bta_av_handle, mtu); 1291 1292 // Find the peer 1293 BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); 1294 if (p_peer == nullptr) { 1295 APPL_TRACE_ERROR( 1296 "%s: could not find peer entry for bta_av_handle 0x%x peer %s", 1297 __func__, bta_av_handle, peer_address.ToString().c_str()); 1298 return; 1299 } 1300 p_peer->opened = true; 1301 p_peer->mtu = mtu; 1302 1303 // The first connected peer becomes the active peer 1304 if (active_peer_ == nullptr) { 1305 active_peer_ = p_peer; 1306 } 1307 } 1308 1309 void BtaAvCo::ProcessClose(tBTA_AV_HNDL bta_av_handle, 1310 const RawAddress& peer_address) { 1311 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__, 1312 peer_address.ToString().c_str(), bta_av_handle); 1313 btif_av_reset_audio_delay(); 1314 1315 // Find the peer 1316 BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); 1317 if (p_peer == nullptr) { 1318 APPL_TRACE_ERROR( 1319 "%s: could not find peer entry for bta_av_handle 0x%x peer %s", 1320 __func__, bta_av_handle, peer_address.ToString().c_str()); 1321 return; 1322 } 1323 // Reset the active peer 1324 if (active_peer_ == p_peer) { 1325 active_peer_ = nullptr; 1326 } 1327 // Mark the peer closed and clean the peer info 1328 p_peer->Init(codec_priorities_); 1329 } 1330 1331 void BtaAvCo::ProcessStart(tBTA_AV_HNDL bta_av_handle, 1332 const RawAddress& peer_address, 1333 const uint8_t* p_codec_info, bool* p_no_rtp_header) { 1334 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__, 1335 peer_address.ToString().c_str(), bta_av_handle); 1336 1337 // Find the peer 1338 BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); 1339 if (p_peer == nullptr) { 1340 APPL_TRACE_ERROR( 1341 "%s: could not find peer entry for bta_av_handle 0x%x peer %s", 1342 __func__, bta_av_handle, peer_address.ToString().c_str()); 1343 return; 1344 } 1345 1346 bool add_rtp_header = 1347 A2DP_UsesRtpHeader(p_peer->ContentProtectActive(), p_codec_info); 1348 1349 APPL_TRACE_DEBUG("%s: bta_av_handle: 0x%x add_rtp_header: %s", __func__, 1350 bta_av_handle, add_rtp_header ? "true" : "false"); 1351 *p_no_rtp_header = !add_rtp_header; 1352 } 1353 1354 void BtaAvCo::ProcessStop(tBTA_AV_HNDL bta_av_handle, 1355 const RawAddress& peer_address) { 1356 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x", __func__, 1357 peer_address.ToString().c_str(), bta_av_handle); 1358 // Nothing to do 1359 } 1360 1361 BT_HDR* BtaAvCo::GetNextSourceDataPacket(const uint8_t* p_codec_info, 1362 uint32_t* p_timestamp) { 1363 BT_HDR* p_buf; 1364 1365 APPL_TRACE_DEBUG("%s: codec: %s", __func__, A2DP_CodecName(p_codec_info)); 1366 1367 p_buf = btif_a2dp_source_audio_readbuf(); 1368 if (p_buf == nullptr) return nullptr; 1369 1370 /* 1371 * Retrieve the timestamp information from the media packet, 1372 * and set up the packet header. 1373 * 1374 * In media packet, the following information is available: 1375 * p_buf->layer_specific : number of audio frames in the packet 1376 * p_buf->word[0] : timestamp 1377 */ 1378 if (!A2DP_GetPacketTimestamp(p_codec_info, (const uint8_t*)(p_buf + 1), 1379 p_timestamp) || 1380 !A2DP_BuildCodecHeader(p_codec_info, p_buf, p_buf->layer_specific)) { 1381 APPL_TRACE_ERROR("%s: unsupported codec type (%d)", __func__, 1382 A2DP_GetCodecType(p_codec_info)); 1383 } 1384 1385 if (ContentProtectEnabled() && (active_peer_ != nullptr) && 1386 active_peer_->ContentProtectActive()) { 1387 p_buf->len++; 1388 p_buf->offset--; 1389 uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset; 1390 *p = ContentProtectFlag(); 1391 } 1392 1393 return p_buf; 1394 } 1395 1396 void BtaAvCo::DataPacketWasDropped(tBTA_AV_HNDL bta_av_handle, 1397 const RawAddress& peer_address) { 1398 APPL_TRACE_ERROR("%s: peer %s dropped audio packet on handle 0x%x", __func__, 1399 peer_address.ToString().c_str(), bta_av_handle); 1400 } 1401 1402 void BtaAvCo::ProcessAudioDelay(tBTA_AV_HNDL bta_av_handle, 1403 const RawAddress& peer_address, 1404 uint16_t delay) { 1405 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle: 0x%x delay:0x%x", __func__, 1406 peer_address.ToString().c_str(), bta_av_handle, delay); 1407 1408 btif_av_set_audio_delay(peer_address, delay); 1409 } 1410 1411 void BtaAvCo::UpdateMtu(tBTA_AV_HNDL bta_av_handle, 1412 const RawAddress& peer_address, uint16_t mtu) { 1413 LOG(INFO) << __func__ << ": peer " << peer_address 1414 << " bta_av_handle: " << loghex(bta_av_handle) << " mtu: " << mtu; 1415 1416 // Find the peer 1417 BtaAvCoPeer* p_peer = FindPeerAndUpdate(bta_av_handle, peer_address); 1418 if (p_peer == nullptr) { 1419 LOG(ERROR) << __func__ << ": could not find peer entry for bta_av_handle " 1420 << loghex(bta_av_handle) << " peer " << peer_address; 1421 return; 1422 } 1423 p_peer->mtu = mtu; 1424 } 1425 1426 bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) { 1427 VLOG(1) << __func__ << ": peer_address=" << peer_address; 1428 1429 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 1430 1431 if (peer_address.IsEmpty()) { 1432 // Reset the active peer; 1433 active_peer_ = nullptr; 1434 memset(codec_config_, 0, sizeof(codec_config_)); 1435 return true; 1436 } 1437 1438 // Find the peer 1439 BtaAvCoPeer* p_peer = FindPeer(peer_address); 1440 if (p_peer == nullptr) { 1441 return false; 1442 } 1443 1444 active_peer_ = p_peer; 1445 memcpy(codec_config_, active_peer_->codec_config, AVDT_CODEC_SIZE); 1446 LOG(INFO) << __func__ << ": codec = " << A2DP_CodecInfoString(codec_config_); 1447 // report the selected codec configuration of this new active peer. 1448 ReportSourceCodecState(active_peer_); 1449 return true; 1450 } 1451 1452 void BtaAvCo::GetPeerEncoderParameters( 1453 const RawAddress& peer_address, 1454 tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) { 1455 uint16_t min_mtu = 0xFFFF; 1456 CHECK(p_peer_params != nullptr) << "Peer address " << peer_address; 1457 1458 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 1459 1460 // Compute the MTU 1461 for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { 1462 const BtaAvCoPeer* p_peer = &peers_[i]; 1463 if (!p_peer->opened) continue; 1464 if (p_peer->addr != peer_address) continue; 1465 if (p_peer->mtu < min_mtu) min_mtu = p_peer->mtu; 1466 } 1467 p_peer_params->peer_mtu = min_mtu; 1468 p_peer_params->is_peer_edr = btif_av_is_peer_edr(peer_address); 1469 p_peer_params->peer_supports_3mbps = 1470 btif_av_peer_supports_3mbps(peer_address); 1471 APPL_TRACE_DEBUG( 1472 "%s: peer_address=%s peer_mtu=%d is_peer_edr=%s peer_supports_3mbps=%s", 1473 __func__, peer_address.ToString().c_str(), p_peer_params->peer_mtu, 1474 logbool(p_peer_params->is_peer_edr).c_str(), 1475 logbool(p_peer_params->peer_supports_3mbps).c_str()); 1476 } 1477 1478 const tA2DP_ENCODER_INTERFACE* BtaAvCo::GetSourceEncoderInterface() { 1479 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 1480 1481 return A2DP_GetEncoderInterface(codec_config_); 1482 } 1483 1484 const tA2DP_DECODER_INTERFACE* BtaAvCo::GetSinkDecoderInterface() { 1485 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 1486 1487 return A2DP_GetDecoderInterface(codec_config_); 1488 } 1489 1490 bool BtaAvCo::SetCodecUserConfig( 1491 const RawAddress& peer_address, 1492 const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output) { 1493 uint8_t result_codec_config[AVDT_CODEC_SIZE]; 1494 const BtaAvCoSep* p_sink = nullptr; 1495 bool restart_input = false; 1496 bool restart_output = false; 1497 bool config_updated = false; 1498 bool success = true; 1499 1500 VLOG(1) << __func__ << ": peer_address=" << peer_address 1501 << " codec_user_config={" << codec_user_config.ToString() << "}"; 1502 1503 *p_restart_output = false; 1504 1505 BtaAvCoPeer* p_peer = FindPeer(peer_address); 1506 if (p_peer == nullptr) { 1507 LOG(ERROR) << __func__ << ": cannot find peer " << peer_address 1508 << " to configure"; 1509 success = false; 1510 goto done; 1511 } 1512 1513 // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities 1514 if ((p_peer->num_rx_sinks != p_peer->num_sinks) && 1515 (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) { 1516 LOG(WARNING) << __func__ << ": peer " << p_peer->addr 1517 << " : not all peer's capabilities have been retrieved"; 1518 success = false; 1519 goto done; 1520 } 1521 1522 // Find the peer SEP codec to use 1523 if (codec_user_config.codec_type < BTAV_A2DP_CODEC_INDEX_MAX) { 1524 p_sink = FindPeerSink(p_peer, codec_user_config.codec_type); 1525 } else { 1526 // Use the current sink codec 1527 p_sink = p_peer->p_sink; 1528 } 1529 if (p_sink == nullptr) { 1530 LOG(ERROR) << __func__ << ": peer " << p_peer->addr 1531 << " : cannot find peer SEP to configure for codec type " 1532 << codec_user_config.codec_type; 1533 success = false; 1534 goto done; 1535 } 1536 1537 tA2DP_ENCODER_INIT_PEER_PARAMS peer_params; 1538 GetPeerEncoderParameters(p_peer->addr, &peer_params); 1539 if (!p_peer->GetCodecs()->setCodecUserConfig( 1540 codec_user_config, &peer_params, p_sink->codec_caps, 1541 result_codec_config, &restart_input, &restart_output, 1542 &config_updated)) { 1543 success = false; 1544 goto done; 1545 } 1546 1547 if (restart_output) { 1548 uint8_t num_protect = 0; 1549 if (ContentProtectEnabled() && p_peer->ContentProtectActive()) { 1550 num_protect = AVDT_CP_INFO_LEN; 1551 } 1552 1553 p_sink = SelectSourceCodec(p_peer); 1554 if (p_sink == nullptr) { 1555 LOG(ERROR) << __func__ << ": peer " << p_peer->addr 1556 << " : cannot set up codec for the peer SINK"; 1557 success = false; 1558 goto done; 1559 } 1560 1561 p_peer->acceptor = false; 1562 VLOG(1) << __func__ << ": call BTA_AvReconfig(" 1563 << loghex(p_peer->BtaAvHandle()) << ")"; 1564 BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx, 1565 p_peer->codec_config, num_protect, bta_av_co_cp_scmst); 1566 *p_restart_output = true; 1567 } 1568 1569 done: 1570 // We send the upcall if there is no change or the user config failed for 1571 // current active peer, so the caller would know it failed. If there is no 1572 // error, the new selected codec configuration would be sent after we are 1573 // ready to start a new session with the audio HAL. 1574 // For none active peer, we unconditionally send the upcall, so the caller 1575 // would always know the result. 1576 // NOTE: Currently, the input is restarted by sending an upcall 1577 // and informing the Media Framework about the change. 1578 if (p_peer != nullptr && 1579 (!restart_output || !success || p_peer != active_peer_)) { 1580 return ReportSourceCodecState(p_peer); 1581 } 1582 1583 return success; 1584 } 1585 1586 bool BtaAvCo::SetCodecAudioConfig( 1587 const btav_a2dp_codec_config_t& codec_audio_config) { 1588 uint8_t result_codec_config[AVDT_CODEC_SIZE]; 1589 bool restart_output = false; 1590 bool config_updated = false; 1591 1592 VLOG(1) << __func__ 1593 << ": codec_audio_config: " << codec_audio_config.ToString(); 1594 1595 // Find the peer that is currently open 1596 BtaAvCoPeer* p_peer = active_peer_; 1597 if (p_peer == nullptr) { 1598 LOG(ERROR) << __func__ << ": no active peer to configure"; 1599 return false; 1600 } 1601 1602 // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities 1603 if ((p_peer->num_rx_sinks != p_peer->num_sinks) && 1604 (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) { 1605 LOG(WARNING) << __func__ << ": peer " << p_peer->addr 1606 << " : not all peer's capabilities have been retrieved"; 1607 return false; 1608 } 1609 1610 // Use the current sink codec 1611 const BtaAvCoSep* p_sink = p_peer->p_sink; 1612 if (p_sink == nullptr) { 1613 LOG(ERROR) << __func__ << ": peer " << p_peer->addr 1614 << " : cannot find peer SEP to configure"; 1615 return false; 1616 } 1617 1618 tA2DP_ENCODER_INIT_PEER_PARAMS peer_params; 1619 GetPeerEncoderParameters(p_peer->addr, &peer_params); 1620 if (!p_peer->GetCodecs()->setCodecAudioConfig( 1621 codec_audio_config, &peer_params, p_sink->codec_caps, 1622 result_codec_config, &restart_output, &config_updated)) { 1623 return false; 1624 } 1625 1626 if (restart_output) { 1627 uint8_t num_protect = 0; 1628 if (ContentProtectEnabled() && p_peer->ContentProtectActive()) { 1629 num_protect = AVDT_CP_INFO_LEN; 1630 } 1631 1632 SaveNewCodecConfig(p_peer, result_codec_config, p_sink->num_protect, 1633 p_sink->protect_info); 1634 1635 p_peer->acceptor = false; 1636 VLOG(1) << __func__ << ": call BTA_AvReconfig(" 1637 << loghex(p_peer->BtaAvHandle()) << ")"; 1638 BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx, 1639 p_peer->codec_config, num_protect, bta_av_co_cp_scmst); 1640 } 1641 1642 if (config_updated) { 1643 // NOTE: Currently, the input is restarted by sending an upcall 1644 // and informing the Media Framework about the change of selected codec. 1645 return ReportSourceCodecState(p_peer); 1646 } 1647 1648 return true; 1649 } 1650 1651 bool BtaAvCo::ReportSourceCodecState(BtaAvCoPeer* p_peer) { 1652 btav_a2dp_codec_config_t codec_config; 1653 std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities; 1654 std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities; 1655 1656 VLOG(1) << __func__ << ": peer_address=" << p_peer->addr; 1657 A2dpCodecs* codecs = p_peer->GetCodecs(); 1658 CHECK(codecs != nullptr); 1659 if (!codecs->getCodecConfigAndCapabilities(&codec_config, 1660 &codecs_local_capabilities, 1661 &codecs_selectable_capabilities)) { 1662 LOG(WARNING) << __func__ << ": Peer " << p_peer->addr 1663 << " : error reporting audio source codec state: cannot get " 1664 "codec config and capabilities"; 1665 return false; 1666 } 1667 LOG(INFO) << __func__ << ": peer " << p_peer->addr << " codec_config={" 1668 << codec_config.ToString() << "}"; 1669 btif_av_report_source_codec_state(p_peer->addr, codec_config, 1670 codecs_local_capabilities, 1671 codecs_selectable_capabilities); 1672 return true; 1673 } 1674 1675 bool BtaAvCo::ReportSinkCodecState(BtaAvCoPeer* p_peer) { 1676 APPL_TRACE_DEBUG("%s: peer_address=%s", __func__, 1677 p_peer->addr.ToString().c_str()); 1678 // Nothing to do (for now) 1679 return true; 1680 } 1681 1682 void BtaAvCo::DebugDump(int fd) { 1683 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 1684 1685 // 1686 // Active peer codec-specific stats 1687 // 1688 if (active_peer_ != nullptr) { 1689 A2dpCodecs* a2dp_codecs = active_peer_->GetCodecs(); 1690 if (a2dp_codecs != nullptr) { 1691 a2dp_codecs->debug_codec_dump(fd); 1692 } 1693 } 1694 1695 if (appl_trace_level < BT_TRACE_LEVEL_DEBUG) return; 1696 1697 dprintf(fd, "\nA2DP Peers State:\n"); 1698 dprintf(fd, " Active peer: %s\n", 1699 (active_peer_ != nullptr) ? active_peer_->addr.ToString().c_str() 1700 : "null"); 1701 1702 for (size_t i = 0; i < BTA_AV_CO_NUM_ELEMENTS(peers_); i++) { 1703 const BtaAvCoPeer& peer = peers_[i]; 1704 if (peer.addr.IsEmpty()) { 1705 continue; 1706 } 1707 dprintf(fd, " Peer: %s\n", peer.addr.ToString().c_str()); 1708 dprintf(fd, " Number of sinks: %u\n", peer.num_sinks); 1709 dprintf(fd, " Number of sources: %u\n", peer.num_sources); 1710 dprintf(fd, " Number of SEPs: %u\n", peer.num_seps); 1711 dprintf(fd, " Number of received sinks: %u\n", peer.num_rx_sinks); 1712 dprintf(fd, " Number of received sources: %u\n", peer.num_rx_sources); 1713 dprintf(fd, " Number of supported sinks: %u\n", peer.num_sup_sinks); 1714 dprintf(fd, " Number of supported sources: %u\n", peer.num_sup_sources); 1715 dprintf(fd, " Acceptor: %s\n", (peer.acceptor) ? "true" : "false"); 1716 dprintf(fd, " Reconfig needed: %s\n", 1717 (peer.reconfig_needed) ? "true" : "false"); 1718 dprintf(fd, " Opened: %s\n", (peer.opened) ? "true" : "false"); 1719 dprintf(fd, " MTU: %u\n", peer.mtu); 1720 dprintf(fd, " UUID to connect: 0x%x\n", peer.uuid_to_connect); 1721 dprintf(fd, " BTA AV handle: %u\n", peer.BtaAvHandle()); 1722 } 1723 } 1724 1725 bool BtaAvCo::ContentProtectIsScmst(const uint8_t* p_protect_info) { 1726 APPL_TRACE_DEBUG("%s", __func__); 1727 1728 if (*p_protect_info >= AVDT_CP_LOSC) { 1729 uint16_t cp_id; 1730 p_protect_info++; 1731 STREAM_TO_UINT16(cp_id, p_protect_info); 1732 if (cp_id == AVDT_CP_SCMS_T_ID) { 1733 APPL_TRACE_DEBUG("%s: SCMS-T found", __func__); 1734 return true; 1735 } 1736 } 1737 return false; 1738 } 1739 1740 bool BtaAvCo::AudioProtectHasScmst(uint8_t num_protect, 1741 const uint8_t* p_protect_info) { 1742 APPL_TRACE_DEBUG("%s", __func__); 1743 while (num_protect--) { 1744 if (BtaAvCo::ContentProtectIsScmst(p_protect_info)) return true; 1745 // Move to the next Content Protect schema 1746 p_protect_info += *p_protect_info + 1; 1747 } 1748 APPL_TRACE_DEBUG("%s: SCMS-T not found", __func__); 1749 return false; 1750 } 1751 1752 bool BtaAvCo::AudioSepHasContentProtection(const BtaAvCoSep* p_sep) { 1753 APPL_TRACE_DEBUG("%s", __func__); 1754 1755 // Check if content protection is enabled for this stream 1756 if (ContentProtectFlag() != AVDT_CP_SCMS_COPY_FREE) { 1757 return BtaAvCo::AudioProtectHasScmst(p_sep->num_protect, 1758 p_sep->protect_info); 1759 } 1760 1761 APPL_TRACE_DEBUG("%s: not required", __func__); 1762 return true; 1763 } 1764 1765 const BtaAvCoSep* BtaAvCo::SelectSourceCodec(BtaAvCoPeer* p_peer) { 1766 const BtaAvCoSep* p_sink = nullptr; 1767 1768 // Update all selectable codecs. 1769 // This is needed to update the selectable parameters for each codec. 1770 // NOTE: The selectable codec info is used only for informational purpose. 1771 UpdateAllSelectableSourceCodecs(p_peer); 1772 1773 // Select the codec 1774 for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) { 1775 VLOG(1) << __func__ << ": trying codec " << iter->name(); 1776 p_sink = AttemptSourceCodecSelection(*iter, p_peer); 1777 if (p_sink != nullptr) { 1778 VLOG(1) << __func__ << ": selected codec " << iter->name(); 1779 break; 1780 } 1781 VLOG(1) << __func__ << ": cannot use codec " << iter->name(); 1782 } 1783 return p_sink; 1784 } 1785 1786 const BtaAvCoSep* BtaAvCo::SelectSinkCodec(BtaAvCoPeer* p_peer) { 1787 const BtaAvCoSep* p_source = nullptr; 1788 1789 // Update all selectable codecs. 1790 // This is needed to update the selectable parameters for each codec. 1791 // NOTE: The selectable codec info is used only for informational purpose. 1792 UpdateAllSelectableSinkCodecs(p_peer); 1793 1794 // Select the codec 1795 for (const auto& iter : p_peer->GetCodecs()->orderedSinkCodecs()) { 1796 APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str()); 1797 p_source = AttemptSinkCodecSelection(*iter, p_peer); 1798 if (p_source != nullptr) { 1799 APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str()); 1800 break; 1801 } 1802 APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str()); 1803 } 1804 1805 // NOTE: Unconditionally dispatch the event to make sure a callback with 1806 // the most recent codec info is generated. 1807 ReportSinkCodecState(p_peer); 1808 1809 return p_source; 1810 } 1811 1812 BtaAvCoSep* BtaAvCo::FindPeerSink(BtaAvCoPeer* p_peer, 1813 btav_a2dp_codec_index_t codec_index) { 1814 if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) { 1815 APPL_TRACE_WARNING("%s: invalid codec index for peer %s", __func__, 1816 p_peer->addr.ToString().c_str()); 1817 return nullptr; 1818 } 1819 1820 // Find the peer Sink for the codec 1821 for (size_t index = 0; index < p_peer->num_sup_sinks; index++) { 1822 BtaAvCoSep* p_sink = &p_peer->sinks[index]; 1823 btav_a2dp_codec_index_t peer_codec_index = 1824 A2DP_SourceCodecIndex(p_sink->codec_caps); 1825 if (peer_codec_index != codec_index) { 1826 continue; 1827 } 1828 if (!AudioSepHasContentProtection(p_sink)) { 1829 APPL_TRACE_DEBUG( 1830 "%s: peer Sink for codec %s does not support " 1831 "Content Protection", 1832 __func__, A2DP_CodecIndexStr(codec_index)); 1833 continue; 1834 } 1835 return p_sink; 1836 } 1837 return nullptr; 1838 } 1839 1840 BtaAvCoSep* BtaAvCo::FindPeerSource(BtaAvCoPeer* p_peer, 1841 btav_a2dp_codec_index_t codec_index) { 1842 if (codec_index == BTAV_A2DP_CODEC_INDEX_MAX) { 1843 APPL_TRACE_WARNING("%s: invalid codec index for peer %s", __func__, 1844 p_peer->addr.ToString().c_str()); 1845 return nullptr; 1846 } 1847 1848 // Find the peer Source for the codec 1849 for (size_t index = 0; index < p_peer->num_sup_sources; index++) { 1850 BtaAvCoSep* p_source = &p_peer->sources[index]; 1851 btav_a2dp_codec_index_t peer_codec_index = 1852 A2DP_SinkCodecIndex(p_source->codec_caps); 1853 if (peer_codec_index != codec_index) { 1854 continue; 1855 } 1856 if (!AudioSepHasContentProtection(p_source)) { 1857 APPL_TRACE_DEBUG( 1858 "%s: peer Source for codec %s does not support " 1859 "Content Protection", 1860 __func__, A2DP_CodecIndexStr(codec_index)); 1861 continue; 1862 } 1863 return p_source; 1864 } 1865 return nullptr; 1866 } 1867 1868 const BtaAvCoSep* BtaAvCo::AttemptSourceCodecSelection( 1869 const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) { 1870 uint8_t new_codec_config[AVDT_CODEC_SIZE]; 1871 1872 APPL_TRACE_DEBUG("%s", __func__); 1873 1874 // Find the peer Sink for the codec 1875 BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex()); 1876 if (p_sink == nullptr) { 1877 APPL_TRACE_DEBUG("%s: peer Sink for codec %s not found", __func__, 1878 codec_config.name().c_str()); 1879 return nullptr; 1880 } 1881 if (!p_peer->GetCodecs()->setCodecConfig( 1882 p_sink->codec_caps, true /* is_capability */, new_codec_config, 1883 true /* select_current_codec */)) { 1884 APPL_TRACE_DEBUG("%s: cannot set source codec %s", __func__, 1885 codec_config.name().c_str()); 1886 return nullptr; 1887 } 1888 p_peer->p_sink = p_sink; 1889 1890 SaveNewCodecConfig(p_peer, new_codec_config, p_sink->num_protect, 1891 p_sink->protect_info); 1892 1893 return p_sink; 1894 } 1895 1896 const BtaAvCoSep* BtaAvCo::AttemptSinkCodecSelection( 1897 const A2dpCodecConfig& codec_config, BtaAvCoPeer* p_peer) { 1898 uint8_t new_codec_config[AVDT_CODEC_SIZE]; 1899 1900 APPL_TRACE_DEBUG("%s", __func__); 1901 1902 // Find the peer Source for the codec 1903 BtaAvCoSep* p_source = FindPeerSource(p_peer, codec_config.codecIndex()); 1904 if (p_source == nullptr) { 1905 APPL_TRACE_DEBUG("%s: peer Source for codec %s not found", __func__, 1906 codec_config.name().c_str()); 1907 return nullptr; 1908 } 1909 if (!p_peer->GetCodecs()->setSinkCodecConfig( 1910 p_source->codec_caps, true /* is_capability */, new_codec_config, 1911 true /* select_current_codec */)) { 1912 APPL_TRACE_DEBUG("%s: cannot set sink codec %s", __func__, 1913 codec_config.name().c_str()); 1914 return nullptr; 1915 } 1916 p_peer->p_source = p_source; 1917 1918 SaveNewCodecConfig(p_peer, new_codec_config, p_source->num_protect, 1919 p_source->protect_info); 1920 1921 return p_source; 1922 } 1923 1924 size_t BtaAvCo::UpdateAllSelectableSourceCodecs(BtaAvCoPeer* p_peer) { 1925 APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str()); 1926 1927 size_t updated_codecs = 0; 1928 for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) { 1929 APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__, 1930 iter->name().c_str()); 1931 if (UpdateSelectableSourceCodec(*iter, p_peer)) { 1932 updated_codecs++; 1933 } 1934 } 1935 return updated_codecs; 1936 } 1937 1938 bool BtaAvCo::UpdateSelectableSourceCodec(const A2dpCodecConfig& codec_config, 1939 BtaAvCoPeer* p_peer) { 1940 APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str()); 1941 1942 // Find the peer Sink for the codec 1943 const BtaAvCoSep* p_sink = FindPeerSink(p_peer, codec_config.codecIndex()); 1944 if (p_sink == nullptr) { 1945 // The peer Sink device does not support this codec 1946 return false; 1947 } 1948 if (!p_peer->GetCodecs()->setPeerSinkCodecCapabilities(p_sink->codec_caps)) { 1949 APPL_TRACE_WARNING("%s: cannot update peer %s codec capabilities for %s", 1950 __func__, p_peer->addr.ToString().c_str(), 1951 A2DP_CodecName(p_sink->codec_caps)); 1952 return false; 1953 } 1954 return true; 1955 } 1956 1957 size_t BtaAvCo::UpdateAllSelectableSinkCodecs(BtaAvCoPeer* p_peer) { 1958 APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str()); 1959 1960 size_t updated_codecs = 0; 1961 for (const auto& iter : p_peer->GetCodecs()->orderedSinkCodecs()) { 1962 APPL_TRACE_DEBUG("%s: updating selectable codec %s", __func__, 1963 iter->name().c_str()); 1964 if (UpdateSelectableSinkCodec(*iter, p_peer)) { 1965 updated_codecs++; 1966 } 1967 } 1968 return updated_codecs; 1969 } 1970 1971 bool BtaAvCo::UpdateSelectableSinkCodec(const A2dpCodecConfig& codec_config, 1972 BtaAvCoPeer* p_peer) { 1973 APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str()); 1974 1975 // Find the peer Source for the codec 1976 const BtaAvCoSep* p_source = 1977 FindPeerSource(p_peer, codec_config.codecIndex()); 1978 if (p_source == nullptr) { 1979 // The peer Source device does not support this codec 1980 return false; 1981 } 1982 if (!p_peer->GetCodecs()->setPeerSourceCodecCapabilities( 1983 p_source->codec_caps)) { 1984 APPL_TRACE_WARNING("%s: cannot update peer %s codec capabilities for %s", 1985 __func__, p_peer->addr.ToString().c_str(), 1986 A2DP_CodecName(p_source->codec_caps)); 1987 return false; 1988 } 1989 return true; 1990 } 1991 1992 void BtaAvCo::SaveNewCodecConfig(BtaAvCoPeer* p_peer, 1993 const uint8_t* new_codec_config, 1994 uint8_t num_protect, 1995 const uint8_t* p_protect_info) { 1996 APPL_TRACE_DEBUG("%s: peer %s", __func__, p_peer->addr.ToString().c_str()); 1997 APPL_TRACE_DEBUG("%s: codec: %s", __func__, 1998 A2DP_CodecInfoString(new_codec_config).c_str()); 1999 2000 std::lock_guard<std::recursive_mutex> lock(codec_lock_); 2001 2002 memcpy(codec_config_, new_codec_config, sizeof(codec_config_)); 2003 memcpy(p_peer->codec_config, new_codec_config, AVDT_CODEC_SIZE); 2004 2005 if (ContentProtectEnabled()) { 2006 // Check if this Sink supports SCMS 2007 bool cp_active = BtaAvCo::AudioProtectHasScmst(num_protect, p_protect_info); 2008 p_peer->SetContentProtectActive(cp_active); 2009 } 2010 } 2011 2012 bool BtaAvCo::SetCodecOtaConfig(BtaAvCoPeer* p_peer, 2013 const uint8_t* p_ota_codec_config, 2014 uint8_t num_protect, 2015 const uint8_t* p_protect_info, 2016 bool* p_restart_output) { 2017 uint8_t result_codec_config[AVDT_CODEC_SIZE]; 2018 bool restart_input = false; 2019 bool restart_output = false; 2020 bool config_updated = false; 2021 2022 LOG(INFO) << __func__ << ": peer_address=" << p_peer->addr 2023 << ", codec: " << A2DP_CodecInfoString(p_ota_codec_config); 2024 2025 *p_restart_output = false; 2026 2027 // Find the peer SEP codec to use 2028 const BtaAvCoSep* p_sink = 2029 FindPeerSink(p_peer, A2DP_SourceCodecIndex(p_ota_codec_config)); 2030 if ((p_peer->num_sup_sinks > 0) && (p_sink == nullptr)) { 2031 // There are no peer SEPs if we didn't do the discovery procedure yet. 2032 // We have all the information we need from the peer, so we can 2033 // proceed with the OTA codec configuration. 2034 LOG(ERROR) << __func__ << ": peer " << p_peer->addr 2035 << " : cannot find peer SEP to configure"; 2036 return false; 2037 } 2038 2039 tA2DP_ENCODER_INIT_PEER_PARAMS peer_params; 2040 GetPeerEncoderParameters(p_peer->addr, &peer_params); 2041 if (!p_peer->GetCodecs()->setCodecOtaConfig( 2042 p_ota_codec_config, &peer_params, result_codec_config, &restart_input, 2043 &restart_output, &config_updated)) { 2044 LOG(ERROR) << __func__ << ": peer " << p_peer->addr 2045 << " : cannot set OTA config"; 2046 return false; 2047 } 2048 2049 if (restart_output) { 2050 VLOG(1) << __func__ << ": restart output for codec: " 2051 << A2DP_CodecInfoString(result_codec_config); 2052 2053 *p_restart_output = true; 2054 p_peer->p_sink = p_sink; 2055 SaveNewCodecConfig(p_peer, result_codec_config, num_protect, 2056 p_protect_info); 2057 } 2058 2059 if (restart_input || config_updated) { 2060 // NOTE: Currently, the input is restarted by sending an upcall 2061 // and informing the Media Framework about the change of selected codec. 2062 ReportSourceCodecState(p_peer); 2063 } 2064 2065 return true; 2066 } 2067 2068 void bta_av_co_init( 2069 const std::vector<btav_a2dp_codec_config_t>& codec_priorities) { 2070 bta_av_co_cb.Init(codec_priorities); 2071 } 2072 2073 bool bta_av_co_is_supported_codec(btav_a2dp_codec_index_t codec_index) { 2074 return bta_av_co_cb.IsSupportedCodec(codec_index); 2075 } 2076 2077 A2dpCodecConfig* bta_av_get_a2dp_current_codec(void) { 2078 return bta_av_co_cb.GetActivePeerCurrentCodec(); 2079 } 2080 2081 A2dpCodecConfig* bta_av_get_a2dp_peer_current_codec( 2082 const RawAddress& peer_address) { 2083 return bta_av_co_cb.GetPeerCurrentCodec(peer_address); 2084 } 2085 2086 bool bta_av_co_audio_init(btav_a2dp_codec_index_t codec_index, 2087 AvdtpSepConfig* p_cfg) { 2088 return A2DP_InitCodecConfig(codec_index, p_cfg); 2089 } 2090 2091 void bta_av_co_audio_disc_res(tBTA_AV_HNDL bta_av_handle, 2092 const RawAddress& peer_address, uint8_t num_seps, 2093 uint8_t num_sinks, uint8_t num_sources, 2094 uint16_t uuid_local) { 2095 bta_av_co_cb.ProcessDiscoveryResult(bta_av_handle, peer_address, num_seps, 2096 num_sinks, num_sources, uuid_local); 2097 } 2098 2099 tA2DP_STATUS bta_av_co_audio_getconfig(tBTA_AV_HNDL bta_av_handle, 2100 const RawAddress& peer_address, 2101 uint8_t* p_codec_info, 2102 uint8_t* p_sep_info_idx, uint8_t seid, 2103 uint8_t* p_num_protect, 2104 uint8_t* p_protect_info) { 2105 uint16_t peer_uuid = bta_av_co_cb.FindPeerUuid(bta_av_handle); 2106 2107 APPL_TRACE_DEBUG("%s: peer %s bta_av_handle=0x%x peer_uuid=0x%x", __func__, 2108 peer_address.ToString().c_str(), bta_av_handle, peer_uuid); 2109 2110 switch (peer_uuid) { 2111 case UUID_SERVCLASS_AUDIO_SOURCE: 2112 return bta_av_co_cb.ProcessSinkGetConfig( 2113 bta_av_handle, peer_address, p_codec_info, p_sep_info_idx, seid, 2114 p_num_protect, p_protect_info); 2115 case UUID_SERVCLASS_AUDIO_SINK: 2116 return bta_av_co_cb.ProcessSourceGetConfig( 2117 bta_av_handle, peer_address, p_codec_info, p_sep_info_idx, seid, 2118 p_num_protect, p_protect_info); 2119 default: 2120 break; 2121 } 2122 APPL_TRACE_ERROR( 2123 "%s: peer %s : Invalid peer UUID: 0x%x for bta_av_handle 0x%x", 2124 peer_address.ToString().c_str(), peer_uuid, bta_av_handle); 2125 return A2DP_FAIL; 2126 } 2127 2128 void bta_av_co_audio_setconfig(tBTA_AV_HNDL bta_av_handle, 2129 const RawAddress& peer_address, 2130 const uint8_t* p_codec_info, uint8_t seid, 2131 uint8_t num_protect, 2132 const uint8_t* p_protect_info, 2133 uint8_t t_local_sep, uint8_t avdt_handle) { 2134 bta_av_co_cb.ProcessSetConfig(bta_av_handle, peer_address, p_codec_info, seid, 2135 num_protect, p_protect_info, t_local_sep, 2136 avdt_handle); 2137 } 2138 2139 void bta_av_co_audio_open(tBTA_AV_HNDL bta_av_handle, 2140 const RawAddress& peer_address, uint16_t mtu) { 2141 bta_av_co_cb.ProcessOpen(bta_av_handle, peer_address, mtu); 2142 } 2143 2144 void bta_av_co_audio_close(tBTA_AV_HNDL bta_av_handle, 2145 const RawAddress& peer_address) { 2146 bta_av_co_cb.ProcessClose(bta_av_handle, peer_address); 2147 } 2148 2149 void bta_av_co_audio_start(tBTA_AV_HNDL bta_av_handle, 2150 const RawAddress& peer_address, 2151 const uint8_t* p_codec_info, bool* p_no_rtp_header) { 2152 bta_av_co_cb.ProcessStart(bta_av_handle, peer_address, p_codec_info, 2153 p_no_rtp_header); 2154 } 2155 2156 void bta_av_co_audio_stop(tBTA_AV_HNDL bta_av_handle, 2157 const RawAddress& peer_address) { 2158 bta_av_co_cb.ProcessStop(bta_av_handle, peer_address); 2159 } 2160 2161 BT_HDR* bta_av_co_audio_source_data_path(const uint8_t* p_codec_info, 2162 uint32_t* p_timestamp) { 2163 return bta_av_co_cb.GetNextSourceDataPacket(p_codec_info, p_timestamp); 2164 } 2165 2166 void bta_av_co_audio_drop(tBTA_AV_HNDL bta_av_handle, 2167 const RawAddress& peer_address) { 2168 bta_av_co_cb.DataPacketWasDropped(bta_av_handle, peer_address); 2169 } 2170 2171 void bta_av_co_audio_delay(tBTA_AV_HNDL bta_av_handle, 2172 const RawAddress& peer_address, uint16_t delay) { 2173 bta_av_co_cb.ProcessAudioDelay(bta_av_handle, peer_address, delay); 2174 } 2175 2176 void bta_av_co_audio_update_mtu(tBTA_AV_HNDL bta_av_handle, 2177 const RawAddress& peer_address, uint16_t mtu) { 2178 bta_av_co_cb.UpdateMtu(bta_av_handle, peer_address, mtu); 2179 } 2180 2181 bool bta_av_co_set_active_peer(const RawAddress& peer_address) { 2182 return bta_av_co_cb.SetActivePeer(peer_address); 2183 } 2184 2185 void bta_av_co_get_peer_params(const RawAddress& peer_address, 2186 tA2DP_ENCODER_INIT_PEER_PARAMS* p_peer_params) { 2187 bta_av_co_cb.GetPeerEncoderParameters(peer_address, p_peer_params); 2188 } 2189 2190 const tA2DP_ENCODER_INTERFACE* bta_av_co_get_encoder_interface(void) { 2191 return bta_av_co_cb.GetSourceEncoderInterface(); 2192 } 2193 2194 const tA2DP_DECODER_INTERFACE* bta_av_co_get_decoder_interface(void) { 2195 return bta_av_co_cb.GetSinkDecoderInterface(); 2196 } 2197 2198 bool bta_av_co_set_codec_user_config( 2199 const RawAddress& peer_address, 2200 const btav_a2dp_codec_config_t& codec_user_config, bool* p_restart_output) { 2201 return bta_av_co_cb.SetCodecUserConfig(peer_address, codec_user_config, 2202 p_restart_output); 2203 } 2204 2205 bool bta_av_co_set_codec_audio_config( 2206 const btav_a2dp_codec_config_t& codec_audio_config) { 2207 return bta_av_co_cb.SetCodecAudioConfig(codec_audio_config); 2208 } 2209 2210 bool bta_av_co_content_protect_is_active(const RawAddress& peer_address) { 2211 BtaAvCoPeer* p_peer = bta_av_co_cb.FindPeer(peer_address); 2212 CHECK(p_peer != nullptr); 2213 return p_peer->ContentProtectActive(); 2214 } 2215 2216 void btif_a2dp_codec_debug_dump(int fd) { bta_av_co_cb.DebugDump(fd); } 2217