1 /* 2 * Copyright (C) 2016 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "avrcp_browsing.c" 39 40 #include <stdint.h> 41 #include <string.h> 42 43 #include "bluetooth_psm.h" 44 #include "bluetooth_sdp.h" 45 #include "btstack_debug.h" 46 #include "btstack_event.h" 47 #include "btstack_memory.h" 48 #include "classic/sdp_client.h" 49 #include "classic/sdp_util.h" 50 #include "classic/avrcp_browsing.h" 51 52 53 static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 54 55 static btstack_packet_handler_t avrcp_browsing_callback; 56 57 static bool l2cap_browsing_service_registered = false; 58 static btstack_packet_handler_t avrcp_browsing_controller_packet_handler; 59 static btstack_packet_handler_t avrcp_browsing_target_packet_handler; 60 61 62 63 void avrcp_browsing_request_can_send_now(avrcp_browsing_connection_t * connection, uint16_t l2cap_cid){ 64 connection->wait_to_send = true; 65 l2cap_request_can_send_now_event(l2cap_cid); 66 } 67 68 static void avrcp_reconnect_timer_timeout_handler(btstack_timer_source_t * timer){ 69 uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 70 avrcp_connection_t * connection_controller = get_avrcp_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 71 if (connection_controller == NULL) return; 72 avrcp_connection_t * connection_target = get_avrcp_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 73 if (connection_target == NULL) return; 74 75 if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)) return; 76 77 if (connection_controller->browsing_connection->state == AVCTP_CONNECTION_W2_L2CAP_RECONNECT){ 78 connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 79 connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 80 81 l2cap_create_ertm_channel(avrcp_browsing_packet_handler, connection_controller->remote_addr, connection_controller->browsing_l2cap_psm, 82 &connection_controller->browsing_connection->ertm_config, 83 connection_controller->browsing_connection->ertm_buffer, 84 connection_controller->browsing_connection->ertm_buffer_size, NULL); 85 } 86 } 87 88 static void avrcp_reconnect_timer_start(avrcp_connection_t * connection){ 89 btstack_run_loop_set_timer_handler(&connection->reconnect_timer, avrcp_reconnect_timer_timeout_handler); 90 btstack_run_loop_set_timer_context(&connection->reconnect_timer, (void *)(uintptr_t)connection->avrcp_cid); 91 92 // add some jitter/randomness to reconnect delay 93 uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 94 btstack_run_loop_set_timer(&connection->reconnect_timer, timeout); 95 96 btstack_run_loop_add_timer(&connection->reconnect_timer); 97 } 98 99 // AVRCP Browsing Service functions 100 static void avrcp_browsing_finalize_connection(avrcp_connection_t * connection){ 101 btstack_run_loop_remove_timer(&connection->reconnect_timer); 102 btstack_memory_avrcp_browsing_connection_free(connection->browsing_connection); 103 connection->browsing_connection = NULL; 104 } 105 106 static void avrcp_browsing_emit_connection_established(uint16_t browsing_cid, bd_addr_t addr, uint8_t status){ 107 btstack_assert(avrcp_browsing_callback != NULL); 108 109 uint8_t event[12]; 110 int pos = 0; 111 event[pos++] = HCI_EVENT_AVRCP_META; 112 event[pos++] = sizeof(event) - 2; 113 event[pos++] = AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED; 114 event[pos++] = status; 115 reverse_bd_addr(addr,&event[pos]); 116 pos += 6; 117 little_endian_store_16(event, pos, browsing_cid); 118 pos += 2; 119 (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 120 } 121 122 static void avrcp_browsing_emit_incoming_connection(uint16_t browsing_cid, bd_addr_t addr){ 123 btstack_assert(avrcp_browsing_callback != NULL); 124 125 uint8_t event[11]; 126 int pos = 0; 127 event[pos++] = HCI_EVENT_AVRCP_META; 128 event[pos++] = sizeof(event) - 2; 129 event[pos++] = AVRCP_SUBEVENT_INCOMING_BROWSING_CONNECTION; 130 reverse_bd_addr(addr,&event[pos]); 131 pos += 6; 132 little_endian_store_16(event, pos, browsing_cid); 133 pos += 2; 134 (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 135 } 136 137 static void avrcp_browsing_emit_connection_closed(uint16_t browsing_cid){ 138 btstack_assert(avrcp_browsing_callback != NULL); 139 140 uint8_t event[5]; 141 int pos = 0; 142 event[pos++] = HCI_EVENT_AVRCP_META; 143 event[pos++] = sizeof(event) - 2; 144 event[pos++] = AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED; 145 little_endian_store_16(event, pos, browsing_cid); 146 pos += 2; 147 (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 148 } 149 150 151 static avrcp_browsing_connection_t * avrcp_browsing_create_connection(avrcp_connection_t * avrcp_connection, uint16_t avrcp_browsing_cid){ 152 avrcp_browsing_connection_t * browsing_connection = btstack_memory_avrcp_browsing_connection_get(); 153 if (!browsing_connection){ 154 log_error("Not enough memory to create browsing connection"); 155 return NULL; 156 } 157 browsing_connection->state = AVCTP_CONNECTION_IDLE; 158 browsing_connection->transaction_label = 0xFF; 159 160 avrcp_connection->avrcp_browsing_cid = avrcp_browsing_cid; 161 avrcp_connection->browsing_connection = browsing_connection; 162 163 log_info("avrcp_browsing_create_connection, avrcp cid 0x%02x", avrcp_connection->avrcp_browsing_cid); 164 return browsing_connection; 165 } 166 167 static void avrcp_browsing_configure_ertm(avrcp_browsing_connection_t * browsing_connection, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config){ 168 browsing_connection->ertm_buffer = ertm_buffer; 169 browsing_connection->ertm_buffer_size = ertm_buffer_size; 170 171 if (ertm_buffer_size > 0) { 172 (void)memcpy(&browsing_connection->ertm_config, ertm_config, 173 sizeof(l2cap_ertm_config_t)); 174 log_info("avrcp_browsing_configure_ertm"); 175 } 176 } 177 178 static avrcp_browsing_connection_t * avrcp_browsing_handle_incoming_connection(avrcp_connection_t * connection, uint16_t local_cid, uint16_t avrcp_browsing_cid){ 179 if (connection->browsing_connection == NULL){ 180 avrcp_browsing_create_connection(connection, avrcp_browsing_cid); 181 } 182 if (connection->browsing_connection) { 183 connection->browsing_connection->l2cap_browsing_cid = local_cid; 184 connection->browsing_connection->state = AVCTP_CONNECTION_W4_ERTM_CONFIGURATION; 185 btstack_run_loop_remove_timer(&connection->reconnect_timer); 186 } 187 return connection->browsing_connection; 188 } 189 190 static void avrcp_browsing_handle_open_connection_for_role(avrcp_connection_t * connection, uint16_t local_cid){ 191 connection->browsing_connection->l2cap_browsing_cid = local_cid; 192 connection->browsing_connection->incoming_declined = false; 193 connection->browsing_connection->state = AVCTP_CONNECTION_OPENED; 194 log_info("L2CAP_EVENT_CHANNEL_OPENED browsing_avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d", connection->avrcp_cid, connection->l2cap_signaling_cid, connection->role); 195 } 196 197 static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){ 198 return (avrcp_frame_type_t)((header & 0x02) >> 1); 199 } 200 201 static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 202 UNUSED(channel); 203 UNUSED(size); 204 bd_addr_t event_addr; 205 uint16_t local_cid; 206 uint8_t status; 207 bool decline_connection; 208 bool outoing_active; 209 210 avrcp_connection_t * connection_controller; 211 avrcp_connection_t * connection_target; 212 213 switch (packet_type){ 214 case L2CAP_DATA_PACKET: 215 switch (avrcp_get_frame_type(packet[0])){ 216 case AVRCP_RESPONSE_FRAME: 217 (*avrcp_browsing_controller_packet_handler)(packet_type, channel, packet, size); 218 break; 219 case AVRCP_COMMAND_FRAME: 220 default: // make compiler happy 221 (*avrcp_browsing_target_packet_handler)(packet_type, channel, packet, size); 222 break; 223 } 224 break; 225 case HCI_EVENT_PACKET: 226 btstack_assert(avrcp_browsing_controller_packet_handler != NULL); 227 btstack_assert(avrcp_browsing_target_packet_handler != NULL); 228 229 switch (hci_event_packet_get_type(packet)) { 230 231 case L2CAP_EVENT_INCOMING_CONNECTION: 232 btstack_assert(avrcp_browsing_controller_packet_handler != NULL); 233 btstack_assert(avrcp_browsing_target_packet_handler != NULL); 234 235 l2cap_event_incoming_connection_get_address(packet, event_addr); 236 local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 237 outoing_active = false; 238 239 connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 240 connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 241 242 if (connection_target == NULL || connection_controller == NULL) { 243 l2cap_decline_connection(local_cid); 244 return; 245 } 246 247 if (connection_target->browsing_connection != NULL){ 248 if (connection_target->browsing_connection->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){ 249 outoing_active = true; 250 connection_target->browsing_connection->incoming_declined = true; 251 } 252 } 253 254 if (connection_controller->browsing_connection != NULL){ 255 if (connection_controller->browsing_connection->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) { 256 outoing_active = true; 257 connection_controller->browsing_connection->incoming_declined = true; 258 } 259 } 260 261 decline_connection = outoing_active; 262 if (decline_connection == false){ 263 uint16_t avrcp_browsing_cid; 264 if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)){ 265 avrcp_browsing_cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 266 } else { 267 avrcp_browsing_cid = connection_controller->avrcp_browsing_cid; 268 } 269 270 // create two connection objects (both) 271 connection_target->browsing_connection = avrcp_browsing_handle_incoming_connection(connection_target, local_cid, avrcp_browsing_cid); 272 connection_controller->browsing_connection = avrcp_browsing_handle_incoming_connection(connection_controller, local_cid, avrcp_browsing_cid); 273 274 if ((connection_target->browsing_connection == NULL) || (connection_controller->browsing_connection == NULL)){ 275 decline_connection = true; 276 if (connection_target->browsing_connection) { 277 avrcp_browsing_finalize_connection(connection_target); 278 } 279 if (connection_controller->browsing_connection) { 280 avrcp_browsing_finalize_connection(connection_controller); 281 } 282 } 283 } 284 if (decline_connection){ 285 l2cap_decline_connection(local_cid); 286 } else { 287 log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION browsing_avrcp_cid 0x%02x", connection_controller->avrcp_browsing_cid); 288 avrcp_browsing_emit_incoming_connection(connection_controller->avrcp_browsing_cid, event_addr); 289 } 290 break; 291 292 case L2CAP_EVENT_CHANNEL_OPENED: 293 l2cap_event_channel_opened_get_address(packet, event_addr); 294 status = l2cap_event_channel_opened_get_status(packet); 295 local_cid = l2cap_event_channel_opened_get_local_cid(packet); 296 297 connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 298 connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 299 300 // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION 301 // outgoing: structs are cteated in avrcp_connect() and avrcp_browsing_connect() 302 if ((connection_controller == NULL) || (connection_target == NULL)) { 303 break; 304 } 305 if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)) { 306 break; 307 } 308 309 switch (status){ 310 case ERROR_CODE_SUCCESS: 311 avrcp_browsing_handle_open_connection_for_role(connection_target, local_cid); 312 avrcp_browsing_handle_open_connection_for_role(connection_controller, local_cid); 313 avrcp_browsing_emit_connection_established(connection_controller->avrcp_browsing_cid, event_addr, status); 314 return; 315 case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 316 if (connection_controller->browsing_connection->incoming_declined == true){ 317 log_info("Incoming browsing connection was declined, and the outgoing failed"); 318 connection_controller->browsing_connection->state = AVCTP_CONNECTION_W2_L2CAP_RECONNECT; 319 connection_controller->browsing_connection->incoming_declined = false; 320 connection_target->browsing_connection->state = AVCTP_CONNECTION_W2_L2CAP_RECONNECT; 321 connection_target->browsing_connection->incoming_declined = false; 322 avrcp_reconnect_timer_start(connection_controller); 323 return; 324 } 325 break; 326 default: 327 break; 328 } 329 log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 330 avrcp_browsing_emit_connection_established(connection_controller->avrcp_browsing_cid, event_addr, status); 331 avrcp_browsing_finalize_connection(connection_controller); 332 avrcp_browsing_finalize_connection(connection_target); 333 break; 334 335 case L2CAP_EVENT_CHANNEL_CLOSED: 336 local_cid = l2cap_event_channel_closed_get_local_cid(packet); 337 338 connection_controller = get_avrcp_connection_for_browsing_l2cap_cid_for_role(AVRCP_CONTROLLER, local_cid); 339 connection_target = get_avrcp_connection_for_browsing_l2cap_cid_for_role(AVRCP_TARGET, local_cid); 340 if ((connection_controller == NULL) || (connection_target == NULL)) { 341 break; 342 } 343 if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)) { 344 break; 345 } 346 avrcp_browsing_emit_connection_closed(connection_controller->avrcp_browsing_cid); 347 avrcp_browsing_finalize_connection(connection_controller); 348 avrcp_browsing_finalize_connection(connection_target); 349 break; 350 351 case L2CAP_EVENT_CAN_SEND_NOW: 352 local_cid = l2cap_event_can_send_now_get_local_cid(packet); 353 connection_target = get_avrcp_connection_for_browsing_l2cap_cid_for_role(AVRCP_TARGET, local_cid); 354 if ((connection_target != NULL) && (connection_target->browsing_connection != NULL) && connection_target->browsing_connection->wait_to_send) { 355 connection_target->browsing_connection->wait_to_send = false; 356 (*avrcp_browsing_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 357 break; 358 } 359 connection_controller = get_avrcp_connection_for_browsing_l2cap_cid_for_role(AVRCP_CONTROLLER, local_cid); 360 if ((connection_controller != NULL) && (connection_controller->browsing_connection != NULL) && connection_controller->browsing_connection->wait_to_send) { 361 connection_controller->browsing_connection->wait_to_send = false; 362 (*avrcp_browsing_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 363 break; 364 } 365 break; 366 367 default: 368 break; 369 } 370 break; 371 default: 372 break; 373 } 374 375 } 376 377 void avrcp_browsing_init(void){ 378 if (l2cap_browsing_service_registered) return; 379 int status = l2cap_register_service(&avrcp_browsing_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_2); 380 381 if (status != ERROR_CODE_SUCCESS) return; 382 l2cap_browsing_service_registered = true; 383 } 384 385 386 uint8_t avrcp_browsing_connect(bd_addr_t remote_addr, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid){ 387 btstack_assert(avrcp_browsing_controller_packet_handler != NULL); 388 btstack_assert(avrcp_browsing_target_packet_handler != NULL); 389 390 avrcp_connection_t * connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); 391 if (!connection_controller){ 392 return ERROR_CODE_COMMAND_DISALLOWED; 393 } 394 avrcp_connection_t * connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr); 395 if (!connection_target){ 396 return ERROR_CODE_COMMAND_DISALLOWED; 397 } 398 399 if (connection_controller->browsing_connection){ 400 return ERROR_CODE_COMMAND_DISALLOWED; 401 } 402 if (connection_target->browsing_connection){ 403 return ERROR_CODE_COMMAND_DISALLOWED; 404 } 405 406 uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 407 408 connection_controller->browsing_connection = avrcp_browsing_create_connection(connection_controller, cid); 409 if (!connection_controller->browsing_connection) return BTSTACK_MEMORY_ALLOC_FAILED; 410 411 connection_target->browsing_connection = avrcp_browsing_create_connection(connection_target, cid); 412 if (!connection_target->browsing_connection){ 413 avrcp_browsing_finalize_connection(connection_controller); 414 return BTSTACK_MEMORY_ALLOC_FAILED; 415 } 416 avrcp_browsing_configure_ertm(connection_controller->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config); 417 avrcp_browsing_configure_ertm(connection_target->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config); 418 419 if (avrcp_browsing_cid != NULL){ 420 *avrcp_browsing_cid = cid; 421 } 422 423 connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 424 connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 425 426 return l2cap_create_ertm_channel(avrcp_browsing_packet_handler, remote_addr, connection_controller->browsing_l2cap_psm, 427 &connection_controller->browsing_connection->ertm_config, 428 connection_controller->browsing_connection->ertm_buffer, 429 connection_controller->browsing_connection->ertm_buffer_size, NULL); 430 431 } 432 433 uint8_t avrcp_browsing_configure_incoming_connection(uint16_t avrcp_browsing_cid, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config){ 434 avrcp_connection_t * connection_controller = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 435 if (!connection_controller){ 436 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 437 } 438 avrcp_connection_t * connection_target = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid); 439 if (!connection_target){ 440 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 441 } 442 443 if (!connection_controller->browsing_connection){ 444 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 445 } 446 if (!connection_target->browsing_connection){ 447 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 448 } 449 450 if (connection_controller->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){ 451 return ERROR_CODE_COMMAND_DISALLOWED; 452 } 453 454 avrcp_browsing_configure_ertm(connection_controller->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config); 455 avrcp_browsing_configure_ertm(connection_target->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config); 456 457 connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 458 connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 459 460 l2cap_accept_ertm_connection(connection_controller->browsing_connection->l2cap_browsing_cid, 461 &connection_controller->browsing_connection->ertm_config, 462 connection_controller->browsing_connection->ertm_buffer, 463 connection_controller->browsing_connection->ertm_buffer_size); 464 return ERROR_CODE_SUCCESS; 465 } 466 467 468 uint8_t avrcp_browsing_decline_incoming_connection(uint16_t avrcp_browsing_cid){ 469 avrcp_connection_t * connection_controller = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 470 if (!connection_controller){ 471 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 472 } 473 avrcp_connection_t * connection_target = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid); 474 if (!connection_target){ 475 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 476 } 477 478 if (!connection_controller->browsing_connection){ 479 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 480 } 481 if (!connection_target->browsing_connection){ 482 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 483 } 484 485 if (connection_controller->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){ 486 return ERROR_CODE_COMMAND_DISALLOWED; 487 } 488 489 l2cap_decline_connection(connection_controller->browsing_connection->l2cap_browsing_cid); 490 491 avrcp_browsing_finalize_connection(connection_controller); 492 avrcp_browsing_finalize_connection(connection_target); 493 return ERROR_CODE_SUCCESS; 494 } 495 496 uint8_t avrcp_browsing_disconnect(uint16_t avrcp_browsing_cid){ 497 avrcp_connection_t * connection_controller = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 498 if (!connection_controller){ 499 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 500 } 501 avrcp_connection_t * connection_target = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid); 502 if (!connection_target){ 503 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 504 } 505 506 if (!connection_controller->browsing_connection){ 507 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 508 } 509 if (!connection_target->browsing_connection){ 510 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 511 } 512 513 l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid, 0); 514 return ERROR_CODE_SUCCESS; 515 } 516 517 void avrcp_browsing_register_controller_packet_handler(btstack_packet_handler_t callback){ 518 avrcp_browsing_controller_packet_handler = callback; 519 } 520 521 void avrcp_browsing_register_target_packet_handler(btstack_packet_handler_t callback){ 522 avrcp_browsing_target_packet_handler = callback; 523 } 524 525 void avrcp_browsing_register_packet_handler(btstack_packet_handler_t callback){ 526 btstack_assert(callback != NULL); 527 avrcp_browsing_callback = callback; 528 }