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_controller.c" 39 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <inttypes.h> 45 #include "btstack.h" 46 #include "classic/avrcp.h" 47 #include "classic/avrcp_browsing_controller.h" 48 49 #define PSM_AVCTP_BROWSING 0x001b 50 51 static void avrcp_browser_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_context_t * context); 52 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 53 54 static void avrcp_emit_browsing_connection_established(btstack_packet_handler_t callback, uint16_t browsing_cid, bd_addr_t addr, uint8_t status){ 55 btstack_assert(callback != NULL); 56 57 uint8_t event[12]; 58 int pos = 0; 59 event[pos++] = HCI_EVENT_AVRCP_META; 60 event[pos++] = sizeof(event) - 2; 61 event[pos++] = AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED; 62 event[pos++] = status; 63 reverse_bd_addr(addr,&event[pos]); 64 pos += 6; 65 little_endian_store_16(event, pos, browsing_cid); 66 pos += 2; 67 (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 68 } 69 70 static void avrcp_emit_incoming_browsing_connection(btstack_packet_handler_t callback, uint16_t browsing_cid, bd_addr_t addr){ 71 btstack_assert(callback != NULL); 72 73 uint8_t event[11]; 74 int pos = 0; 75 event[pos++] = HCI_EVENT_AVRCP_META; 76 event[pos++] = sizeof(event) - 2; 77 event[pos++] = AVRCP_SUBEVENT_INCOMING_BROWSING_CONNECTION; 78 reverse_bd_addr(addr,&event[pos]); 79 pos += 6; 80 little_endian_store_16(event, pos, browsing_cid); 81 pos += 2; 82 (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 83 } 84 85 static void avrcp_emit_browsing_connection_closed(btstack_packet_handler_t callback, uint16_t browsing_cid){ 86 btstack_assert(callback != NULL); 87 88 uint8_t event[5]; 89 int pos = 0; 90 event[pos++] = HCI_EVENT_AVRCP_META; 91 event[pos++] = sizeof(event) - 2; 92 event[pos++] = AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED; 93 little_endian_store_16(event, pos, browsing_cid); 94 pos += 2; 95 (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 96 } 97 98 static avrcp_browsing_connection_t * avrcp_browsing_create_connection(avrcp_connection_t * avrcp_connection){ 99 avrcp_browsing_connection_t * connection = btstack_memory_avrcp_browsing_connection_get(); 100 connection->state = AVCTP_CONNECTION_IDLE; 101 connection->transaction_label = 0xFF; 102 avrcp_connection->avrcp_browsing_cid = avrcp_get_next_cid(avrcp_connection->role); 103 avrcp_connection->browsing_connection = connection; 104 return connection; 105 } 106 107 static uint8_t avrcp_browsing_connect(bd_addr_t remote_addr, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config, uint16_t * browsing_cid){ 108 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); 109 110 if (!avrcp_connection){ 111 log_error("avrcp: there is no previously established AVRCP controller connection."); 112 return ERROR_CODE_COMMAND_DISALLOWED; 113 } 114 115 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 116 if (connection){ 117 log_error(" avrcp_browsing_connect connection exists."); 118 return ERROR_CODE_SUCCESS; 119 } 120 121 connection = avrcp_browsing_create_connection(avrcp_connection); 122 if (!connection){ 123 log_error("avrcp: could not allocate connection struct."); 124 return BTSTACK_MEMORY_ALLOC_FAILED; 125 } 126 127 if (browsing_cid){ 128 *browsing_cid = avrcp_connection->avrcp_browsing_cid; 129 } 130 131 connection->ertm_buffer = ertm_buffer; 132 connection->ertm_buffer_size = size; 133 avrcp_connection->browsing_connection = connection; 134 avrcp_connection->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 135 (void)memcpy(&connection->ertm_config, ertm_config, 136 sizeof(l2cap_ertm_config_t)); 137 138 return l2cap_create_ertm_channel(avrcp_browsing_controller_packet_handler, remote_addr, avrcp_connection->browsing_l2cap_psm, 139 &connection->ertm_config, connection->ertm_buffer, connection->ertm_buffer_size, NULL); 140 141 } 142 143 static void avrcp_browser_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_context_t * context){ 144 UNUSED(channel); 145 UNUSED(size); 146 bd_addr_t event_addr; 147 uint16_t local_cid; 148 uint8_t status; 149 avrcp_browsing_connection_t * browsing_connection = NULL; 150 avrcp_connection_t * avrcp_connection = NULL; 151 152 if (packet_type != HCI_EVENT_PACKET) return; 153 154 switch (hci_event_packet_get_type(packet)) { 155 case HCI_EVENT_DISCONNECTION_COMPLETE: 156 avrcp_emit_browsing_connection_closed(context->browsing_avrcp_callback, 0); 157 break; 158 case L2CAP_EVENT_INCOMING_CONNECTION: 159 l2cap_event_incoming_connection_get_address(packet, event_addr); 160 local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 161 avrcp_connection = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 162 if (!avrcp_connection) { 163 log_error("No previously created AVRCP controller connections"); 164 l2cap_decline_connection(local_cid); 165 break; 166 } 167 browsing_connection = avrcp_browsing_create_connection(avrcp_connection); 168 browsing_connection->l2cap_browsing_cid = local_cid; 169 browsing_connection->state = AVCTP_CONNECTION_W4_ERTM_CONFIGURATION; 170 log_info("Emit AVRCP_SUBEVENT_INCOMING_BROWSING_CONNECTION browsing_cid 0x%02x, l2cap_signaling_cid 0x%02x\n", avrcp_connection->avrcp_browsing_cid, browsing_connection->l2cap_browsing_cid); 171 avrcp_emit_incoming_browsing_connection(context->browsing_avrcp_callback, avrcp_connection->avrcp_browsing_cid, event_addr); 172 break; 173 174 case L2CAP_EVENT_CHANNEL_OPENED: 175 l2cap_event_channel_opened_get_address(packet, event_addr); 176 status = l2cap_event_channel_opened_get_status(packet); 177 local_cid = l2cap_event_channel_opened_get_local_cid(packet); 178 179 avrcp_connection = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 180 if (!avrcp_connection){ 181 log_error("Failed to find AVRCP connection for bd_addr %s", bd_addr_to_str(event_addr)); 182 avrcp_emit_browsing_connection_established(context->browsing_avrcp_callback, local_cid, event_addr, L2CAP_LOCAL_CID_DOES_NOT_EXIST); 183 l2cap_disconnect(local_cid, 0); // reason isn't used 184 break; 185 } 186 187 browsing_connection = avrcp_connection->browsing_connection; 188 if (status != ERROR_CODE_SUCCESS){ 189 log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 190 avrcp_emit_browsing_connection_established(context->browsing_avrcp_callback, avrcp_connection->avrcp_browsing_cid, event_addr, status); 191 btstack_memory_avrcp_browsing_connection_free(browsing_connection); 192 avrcp_connection->browsing_connection = NULL; 193 break; 194 } 195 browsing_connection->l2cap_browsing_cid = local_cid; 196 197 log_info("L2CAP_EVENT_CHANNEL_OPENED browsing cid 0x%02x, l2cap cid 0x%02x", avrcp_connection->avrcp_browsing_cid, browsing_connection->l2cap_browsing_cid); 198 browsing_connection->state = AVCTP_CONNECTION_OPENED; 199 avrcp_emit_browsing_connection_established(context->browsing_avrcp_callback, avrcp_connection->avrcp_browsing_cid, event_addr, ERROR_CODE_SUCCESS); 200 break; 201 202 case L2CAP_EVENT_CHANNEL_CLOSED: 203 local_cid = l2cap_event_channel_closed_get_local_cid(packet); 204 avrcp_connection = get_avrcp_connection_for_browsing_l2cap_cid_for_role(context->role, local_cid); 205 206 if (avrcp_connection && avrcp_connection->browsing_connection){ 207 avrcp_emit_browsing_connection_closed(context->browsing_avrcp_callback, avrcp_connection->avrcp_browsing_cid); 208 // free connection 209 btstack_memory_avrcp_browsing_connection_free(avrcp_connection->browsing_connection); 210 avrcp_connection->browsing_connection = NULL; 211 break; 212 } 213 break; 214 default: 215 break; 216 } 217 } 218 219 static int avrcp_browsing_controller_send_get_folder_items_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 220 uint8_t command[100]; 221 int pos = 0; 222 // transport header 223 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 224 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 225 // Profile IDentifier (PID) 226 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 227 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 228 command[pos++] = AVRCP_PDU_ID_GET_FOLDER_ITEMS; 229 230 uint32_t attribute_count = 0; 231 uint32_t attributes_to_copy = 0; 232 233 switch (connection->attr_bitmap){ 234 case AVRCP_MEDIA_ATTR_NONE: 235 attribute_count = AVRCP_MEDIA_ATTR_NONE; // 0xFFFFFFFF 236 break; 237 case AVRCP_MEDIA_ATTR_ALL: 238 attribute_count = AVRCP_MEDIA_ATTR_ALL; // 0 239 break; 240 default: 241 attribute_count = count_set_bits_uint32(connection->attr_bitmap & 0xff); 242 attributes_to_copy = attribute_count; 243 break; 244 } 245 big_endian_store_16(command, pos, 9 + 1 + (attribute_count*4)); 246 pos += 2; 247 248 command[pos++] = connection->scope; 249 big_endian_store_32(command, pos, connection->start_item); 250 pos += 4; 251 big_endian_store_32(command, pos, connection->end_item); 252 pos += 4; 253 command[pos++] = attribute_count; 254 255 int bit_position = 1; 256 while (attributes_to_copy){ 257 if (connection->attr_bitmap & (1 << bit_position)){ 258 big_endian_store_32(command, pos, bit_position); 259 pos += 4; 260 attributes_to_copy--; 261 } 262 bit_position++; 263 } 264 return l2cap_send(cid, command, pos); 265 } 266 267 268 static int avrcp_browsing_controller_send_get_item_attributes_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 269 uint8_t command[100]; 270 int pos = 0; 271 // transport header 272 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 273 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 274 // Profile IDentifier (PID) 275 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 276 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 277 command[pos++] = AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES; 278 279 uint32_t attribute_count; 280 uint32_t attributes_to_copy = 0; 281 282 switch (connection->attr_bitmap){ 283 case AVRCP_MEDIA_ATTR_NONE: 284 case AVRCP_MEDIA_ATTR_ALL: 285 attribute_count = 0; 286 break; 287 default: 288 attribute_count = count_set_bits_uint32(connection->attr_bitmap & 0xff); 289 attributes_to_copy = attribute_count; 290 break; 291 } 292 293 big_endian_store_16(command, pos, 12 + (attribute_count*4)); 294 pos += 2; 295 296 command[pos++] = connection->scope; 297 (void)memcpy(command + pos, connection->folder_uid, 8); 298 pos += 8; 299 big_endian_store_16(command, pos, connection->uid_counter); 300 pos += 2; 301 command[pos++] = attribute_count; 302 303 int bit_position = 1; 304 while (attributes_to_copy){ 305 if (connection->attr_bitmap & (1 << bit_position)){ 306 big_endian_store_32(command, pos, bit_position); 307 pos += 4; 308 attributes_to_copy--; 309 } 310 bit_position++; 311 } 312 313 return l2cap_send(cid, command, pos); 314 } 315 316 317 static int avrcp_browsing_controller_send_change_path_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 318 uint8_t command[100]; 319 int pos = 0; 320 // transport header 321 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 322 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 323 // Profile IDentifier (PID) 324 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 325 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 326 command[pos++] = AVRCP_PDU_ID_CHANGE_PATH; 327 328 big_endian_store_16(command, pos, 11); 329 pos += 2; 330 pos += 2; 331 command[pos++] = connection->direction; 332 (void)memcpy(command + pos, connection->folder_uid, 8); 333 pos += 8; 334 return l2cap_send(cid, command, pos); 335 } 336 337 static int avrcp_browsing_controller_send_search_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 338 uint8_t command[100]; 339 int pos = 0; 340 // transport header 341 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 342 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 343 // Profile IDentifier (PID) 344 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 345 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 346 command[pos++] = AVRCP_PDU_ID_SEARCH; 347 348 big_endian_store_16(command, pos, 4 + connection->search_str_len); 349 pos += 2; 350 351 big_endian_store_16(command, pos, 0x006A); 352 pos += 2; 353 big_endian_store_16(command, pos, connection->search_str_len); 354 pos += 2; 355 356 (void)memcpy(command + pos, connection->search_str, 357 connection->search_str_len); 358 pos += connection->search_str_len; 359 return l2cap_send(cid, command, pos); 360 } 361 362 static int avrcp_browsing_controller_send_set_browsed_player_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 363 uint8_t command[100]; 364 int pos = 0; 365 // transport header 366 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 367 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 368 // Profile IDentifier (PID) 369 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 370 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 371 command[pos++] = AVRCP_PDU_ID_SET_BROWSED_PLAYER; 372 373 big_endian_store_16(command, pos, 2); 374 pos += 2; 375 big_endian_store_16(command, pos, connection->browsed_player_id); 376 pos += 2; 377 return l2cap_send(cid, command, pos); 378 } 379 380 static int avrcp_browsing_controller_send_get_total_nr_items_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 381 uint8_t command[7]; 382 int pos = 0; 383 // transport header 384 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 385 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 386 // Profile IDentifier (PID) 387 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 388 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 389 command[pos++] = AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS; 390 391 big_endian_store_16(command, pos, 1); 392 pos += 2; 393 command[pos++] = connection->get_total_nr_items_scope; 394 return l2cap_send(cid, command, pos); 395 } 396 397 static void avrcp_browsing_controller_handle_can_send_now(avrcp_browsing_connection_t * connection){ 398 switch (connection->state){ 399 case AVCTP_CONNECTION_OPENED: 400 if (connection->set_browsed_player_id){ 401 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 402 connection->set_browsed_player_id = 0; 403 avrcp_browsing_controller_send_set_browsed_player_cmd(connection->l2cap_browsing_cid, connection); 404 break; 405 } 406 407 if (connection->get_total_nr_items){ 408 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 409 connection->get_total_nr_items = 0; 410 avrcp_browsing_controller_send_get_total_nr_items_cmd(connection->l2cap_browsing_cid, connection); 411 break; 412 } 413 414 if (connection->get_folder_items){ 415 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 416 connection->get_folder_items = 0; 417 avrcp_browsing_controller_send_get_folder_items_cmd(connection->l2cap_browsing_cid, connection); 418 break; 419 } 420 421 if (connection->get_item_attributes){ 422 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 423 connection->get_item_attributes = 0; 424 avrcp_browsing_controller_send_get_item_attributes_cmd(connection->l2cap_browsing_cid, connection); 425 break; 426 } 427 428 if (connection->change_path){ 429 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 430 connection->change_path = 0; 431 avrcp_browsing_controller_send_change_path_cmd(connection->l2cap_browsing_cid, connection); 432 break; 433 } 434 435 if (connection->search){ 436 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 437 connection->search = 0; 438 avrcp_browsing_controller_send_search_cmd(connection->l2cap_browsing_cid, connection); 439 break; 440 } 441 break; 442 default: 443 return; 444 } 445 } 446 447 448 static void avrcp_browsing_controller_emit_done_with_uid_counter(btstack_packet_handler_t callback, uint16_t browsing_cid, uint16_t uid_counter, uint8_t browsing_status, uint8_t bluetooth_status){ 449 btstack_assert(callback != NULL); 450 451 uint8_t event[9]; 452 int pos = 0; 453 event[pos++] = HCI_EVENT_AVRCP_META; 454 event[pos++] = sizeof(event) - 2; 455 event[pos++] = AVRCP_SUBEVENT_BROWSING_DONE; 456 little_endian_store_16(event, pos, browsing_cid); 457 pos += 2; 458 little_endian_store_16(event, pos, uid_counter); 459 pos += 2; 460 event[pos++] = browsing_status; 461 event[pos++] = bluetooth_status; 462 (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 463 } 464 465 static void avrcp_parser_reset(avrcp_browsing_connection_t * connection){ 466 connection->parser_attribute_header_pos = 0; 467 connection->parsed_attribute_value_offset = 0; 468 connection->parsed_num_attributes = 0; 469 connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; 470 } 471 472 473 static void avrcp_browsing_parser_process_byte(uint8_t byte, avrcp_browsing_connection_t * connection){ 474 uint8_t prepended_header_size = 1; 475 uint16_t attribute_total_value_len; 476 477 switch(connection->parser_state){ 478 case AVRCP_PARSER_GET_ATTRIBUTE_HEADER: 479 connection->parser_attribute_header[connection->parser_attribute_header_pos++] = byte; 480 if (connection->parser_attribute_header_pos < AVRCP_BROWSING_ITEM_HEADER_LEN) break; 481 482 attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 1); 483 connection->parsed_attribute_value[connection->parsed_attribute_value_offset++] = connection->parser_attribute_header[0]; // prepend with item type 484 connection->parsed_attribute_value_len = btstack_min(attribute_total_value_len, AVRCP_MAX_ATTRIBUTTE_SIZE - prepended_header_size); // reduce AVRCP_MAX_ATTRIBUTTE_SIZE for the size ot item type 485 connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_VALUE; 486 break; 487 488 case AVRCP_PARSER_GET_ATTRIBUTE_VALUE: 489 connection->parsed_attribute_value[connection->parsed_attribute_value_offset++] = byte; 490 if (connection->parsed_attribute_value_offset < (connection->parsed_attribute_value_len + prepended_header_size)){ 491 break; 492 } 493 if (connection->parsed_attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 1)){ 494 connection->parser_state = AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE; 495 break; 496 } 497 connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; 498 (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, connection->l2cap_browsing_cid, &connection->parsed_attribute_value[0], connection->parsed_attribute_value_offset); 499 connection->parsed_num_attributes++; 500 connection->parsed_attribute_value_offset = 0; 501 connection->parser_attribute_header_pos = 0; 502 503 if (connection->parsed_num_attributes == connection->num_items){ 504 avrcp_parser_reset(connection); 505 break; 506 } 507 break; 508 509 case AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE: 510 connection->parsed_attribute_value_offset++; 511 if (connection->parsed_attribute_value_offset < (big_endian_read_16(connection->parser_attribute_header, 1) + prepended_header_size)){ 512 break; 513 } 514 connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; 515 (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, connection->l2cap_browsing_cid, &connection->parsed_attribute_value[0], connection->parsed_attribute_value_offset); 516 connection->parsed_num_attributes++; 517 connection->parsed_attribute_value_offset = 0; 518 connection->parser_attribute_header_pos = 0; 519 520 if (connection->parsed_num_attributes == connection->num_items){ 521 avrcp_parser_reset(connection); 522 break; 523 } 524 break; 525 default: 526 break; 527 } 528 } 529 530 static void avrcp_browsing_parse_and_emit_element_attrs(uint8_t * packet, uint16_t num_bytes_to_read, avrcp_browsing_connection_t * connection){ 531 int i; 532 for (i=0;i<num_bytes_to_read;i++){ 533 avrcp_browsing_parser_process_byte(packet[i], connection); 534 } 535 } 536 537 static void avrcp_browsing_controller_emit_failed(btstack_packet_handler_t callback, uint16_t browsing_cid, uint8_t browsing_status, uint8_t bluetooth_status){ 538 avrcp_browsing_controller_emit_done_with_uid_counter(callback, browsing_cid, 0, browsing_status, bluetooth_status); 539 } 540 541 542 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 543 avrcp_browsing_connection_t * browsing_connection; 544 uint8_t transport_header; 545 int pos; 546 547 switch (packet_type) { 548 case L2CAP_DATA_PACKET: 549 browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid_for_role(AVRCP_CONTROLLER, channel); 550 if (!browsing_connection) break; 551 pos = 0; 552 transport_header = packet[pos++]; 553 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 554 browsing_connection->transaction_label = transport_header >> 4; 555 avrcp_packet_type_t avctp_packet_type = (transport_header & 0x0F) >> 2; 556 switch (avctp_packet_type){ 557 case AVRCP_SINGLE_PACKET: 558 case AVRCP_START_PACKET: 559 pos += 2; 560 browsing_connection->num_packets = 1; 561 if (avctp_packet_type == AVRCP_START_PACKET){ 562 browsing_connection->num_packets = packet[pos++]; 563 } 564 if ((pos + 4) > size){ 565 browsing_connection->state = AVCTP_CONNECTION_OPENED; 566 avrcp_browsing_controller_emit_failed(avrcp_controller_context.browsing_avrcp_callback, channel, AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND, ERROR_CODE_SUCCESS); 567 return; 568 } 569 browsing_connection->pdu_id = packet[pos++]; 570 pos += 2; 571 browsing_connection->browsing_status = packet[pos++]; 572 if (browsing_connection->browsing_status != AVRCP_BROWSING_ERROR_CODE_SUCCESS){ 573 browsing_connection->state = AVCTP_CONNECTION_OPENED; 574 avrcp_browsing_controller_emit_failed(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_connection->browsing_status, ERROR_CODE_SUCCESS); 575 return; 576 } 577 break; 578 default: 579 break; 580 } 581 582 uint32_t i; 583 uint8_t folder_depth; 584 585 switch(browsing_connection->pdu_id){ 586 case AVRCP_PDU_ID_CHANGE_PATH: 587 break; 588 case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER: 589 break; 590 case AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS: 591 break; 592 case AVRCP_PDU_ID_SET_BROWSED_PLAYER: 593 browsing_connection->uid_counter = big_endian_read_16(packet, pos); 594 pos += 2; 595 // num_items 596 pos += 4; 597 // charset 598 pos += 2; 599 folder_depth = packet[pos++]; 600 601 for (i = 0; i < folder_depth; i++){ 602 uint16_t folder_name_length = big_endian_read_16(packet, pos); 603 pos += 2; 604 // reuse packet and add data type as a header 605 packet[pos-1] = AVRCP_BROWSING_MEDIA_ROOT_FOLDER; 606 (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos-1, folder_name_length+1); 607 pos += folder_name_length; 608 } 609 break; 610 611 case AVRCP_PDU_ID_GET_FOLDER_ITEMS:{ 612 switch (avctp_packet_type){ 613 case AVRCP_SINGLE_PACKET: 614 case AVRCP_START_PACKET: 615 avrcp_parser_reset(browsing_connection); 616 browsing_connection->uid_counter = big_endian_read_16(packet, pos); 617 pos += 2; 618 browsing_connection->num_items = big_endian_read_16(packet, pos); //num_items 619 pos += 2; 620 avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection); 621 break; 622 623 case AVRCP_CONTINUE_PACKET: 624 avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection); 625 break; 626 627 case AVRCP_END_PACKET: 628 avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection); 629 avrcp_parser_reset(browsing_connection); 630 break; 631 default: 632 break; 633 } 634 break; 635 } 636 case AVRCP_PDU_ID_SEARCH: 637 browsing_connection->uid_counter = big_endian_read_16(packet, pos); 638 pos += 2; 639 break; 640 case AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES: 641 packet[pos-1] = AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE; 642 (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos-1, size - pos + 1); 643 break; 644 default: 645 log_info(" not parsed pdu ID 0x%02x", browsing_connection->pdu_id); 646 break; 647 } 648 649 switch (avctp_packet_type){ 650 case AVRCP_SINGLE_PACKET: 651 case AVRCP_END_PACKET: 652 browsing_connection->state = AVCTP_CONNECTION_OPENED; 653 avrcp_browsing_controller_emit_done_with_uid_counter(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_connection->uid_counter, browsing_connection->browsing_status, ERROR_CODE_SUCCESS); 654 break; 655 default: 656 break; 657 } 658 break; 659 660 case HCI_EVENT_PACKET: 661 switch (hci_event_packet_get_type(packet)){ 662 case L2CAP_EVENT_CAN_SEND_NOW: 663 browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid_for_role(AVRCP_CONTROLLER,channel); 664 if (!browsing_connection) break; 665 avrcp_browsing_controller_handle_can_send_now(browsing_connection); 666 break; 667 default: 668 avrcp_browser_packet_handler(packet_type, channel, packet, size, &avrcp_controller_context); 669 break; 670 } 671 break; 672 673 default: 674 break; 675 } 676 } 677 678 void avrcp_browsing_controller_init(void){ 679 avrcp_controller_context.browsing_packet_handler = avrcp_browsing_controller_packet_handler; 680 l2cap_register_service(&avrcp_browsing_controller_packet_handler, PSM_AVCTP_BROWSING, 0xffff, gap_get_security_level()); 681 } 682 683 void avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback){ 684 btstack_assert(callback != NULL); 685 avrcp_controller_context.browsing_avrcp_callback = callback; 686 } 687 688 uint8_t avrcp_browsing_controller_connect(bd_addr_t bd_addr, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid){ 689 return avrcp_browsing_connect(bd_addr, ertm_buffer, size, ertm_config, avrcp_browsing_cid); 690 } 691 692 uint8_t avrcp_browsing_controller_disconnect(uint16_t avrcp_browsing_cid){ 693 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 694 if (!avrcp_connection){ 695 log_error("avrcp_browsing_controller_disconnect: could not find a connection."); 696 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 697 } 698 if (avrcp_connection->browsing_connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; 699 700 l2cap_disconnect(avrcp_connection->browsing_connection->l2cap_browsing_cid, 0); 701 return ERROR_CODE_SUCCESS; 702 } 703 704 uint8_t avrcp_browsing_controller_configure_incoming_connection(uint16_t avrcp_browsing_cid, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config){ 705 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 706 if (!avrcp_connection){ 707 log_error("avrcp_browsing_controller_decline_incoming_connection: could not find a connection."); 708 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 709 } 710 if (!avrcp_connection->browsing_connection){ 711 log_error("avrcp_browsing_controller_decline_incoming_connection: no browsing connection."); 712 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 713 } 714 715 if (avrcp_connection->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){ 716 log_error("avrcp_browsing_controller_decline_incoming_connection: browsing connection in a wrong state."); 717 return ERROR_CODE_COMMAND_DISALLOWED; 718 } 719 720 avrcp_connection->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 721 avrcp_connection->browsing_connection->ertm_buffer = ertm_buffer; 722 avrcp_connection->browsing_connection->ertm_buffer_size = size; 723 (void)memcpy(&avrcp_connection->browsing_connection->ertm_config, 724 ertm_config, sizeof(l2cap_ertm_config_t)); 725 l2cap_accept_ertm_connection(avrcp_connection->browsing_connection->l2cap_browsing_cid, &avrcp_connection->browsing_connection->ertm_config, avrcp_connection->browsing_connection->ertm_buffer, avrcp_connection->browsing_connection->ertm_buffer_size); 726 return ERROR_CODE_SUCCESS; 727 } 728 729 uint8_t avrcp_browsing_controller_decline_incoming_connection(uint16_t avrcp_browsing_cid){ 730 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 731 if (!avrcp_connection){ 732 log_error("avrcp_browsing_controller_decline_incoming_connection: could not find a connection."); 733 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 734 } 735 if (!avrcp_connection->browsing_connection) return ERROR_CODE_SUCCESS; 736 if (avrcp_connection->browsing_connection->state > AVCTP_CONNECTION_W4_ERTM_CONFIGURATION) return ERROR_CODE_COMMAND_DISALLOWED; 737 738 l2cap_decline_connection(avrcp_connection->browsing_connection->l2cap_browsing_cid); 739 // free connection 740 btstack_memory_avrcp_browsing_connection_free(avrcp_connection->browsing_connection); 741 avrcp_connection->browsing_connection = NULL; 742 return ERROR_CODE_SUCCESS; 743 } 744 745 uint8_t avrcp_browsing_controller_get_item_attributes_for_scope(uint16_t avrcp_browsing_cid, uint8_t * uid, uint16_t uid_counter, uint32_t attr_bitmap, avrcp_browsing_scope_t scope){ 746 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 747 if (!avrcp_connection){ 748 log_error("avrcp_browsing_controller_get_item_attributes: could not find a connection."); 749 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 750 } 751 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 752 if (connection->state != AVCTP_CONNECTION_OPENED){ 753 log_error("avrcp_browsing_controller_get_item_attributes: connection in wrong state %d, expected %d.", connection->state, AVCTP_CONNECTION_OPENED); 754 return ERROR_CODE_COMMAND_DISALLOWED; 755 } 756 757 connection->get_item_attributes = 1; 758 connection->scope = scope; 759 (void)memcpy(connection->folder_uid, uid, 8); 760 connection->uid_counter = uid_counter; 761 connection->attr_bitmap = attr_bitmap; 762 763 avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); 764 return ERROR_CODE_SUCCESS; 765 } 766 767 /** 768 * @brief Retrieve a listing of the contents of a folder. 769 * @param scope 0-player list, 1-virtual file system, 2-search, 3-now playing 770 * @param start_item 771 * @param end_item 772 * @param attribute_count 773 * @param attribute_list 774 **/ 775 static uint8_t avrcp_browsing_controller_get_folder_items(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ 776 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 777 if (!avrcp_connection){ 778 log_error("avrcp_browsing_controller_disconnect: could not find a connection."); 779 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 780 } 781 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 782 if (connection->state != AVCTP_CONNECTION_OPENED) { 783 log_error("avrcp_browsing_controller_get_folder_items: connection in wrong state %d, expected %d.", connection->state, AVCTP_CONNECTION_OPENED); 784 return ERROR_CODE_COMMAND_DISALLOWED; 785 } 786 787 connection->get_folder_items = 1; 788 connection->scope = scope; 789 connection->start_item = start_item; 790 connection->end_item = end_item; 791 connection->attr_bitmap = attr_bitmap; 792 793 avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); 794 return ERROR_CODE_SUCCESS; 795 } 796 797 uint8_t avrcp_browsing_controller_get_media_players(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ 798 return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_LIST, start_item, end_item, attr_bitmap); 799 } 800 801 uint8_t avrcp_browsing_controller_browse_file_system(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ 802 // return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 1, 0, 0xFFFFFFFF, attr_bitmap); 803 return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM, start_item, end_item, attr_bitmap); 804 } 805 806 uint8_t avrcp_browsing_controller_browse_media(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ 807 // return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 2, 0, 0xFFFFFFFF, 0, NULL); 808 return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_SEARCH, start_item, end_item, attr_bitmap); 809 } 810 811 uint8_t avrcp_browsing_controller_browse_now_playing_list(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ 812 return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_NOW_PLAYING, start_item, end_item, attr_bitmap); 813 } 814 815 816 uint8_t avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid, uint16_t browsed_player_id){ 817 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 818 if (!avrcp_connection){ 819 log_error("avrcp_browsing_controller_change_path: could not find a connection."); 820 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 821 } 822 823 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 824 if (connection->state != AVCTP_CONNECTION_OPENED){ 825 log_error("avrcp_browsing_controller_change_path: connection in wrong state."); 826 return ERROR_CODE_COMMAND_DISALLOWED; 827 } 828 829 connection->set_browsed_player_id = 1; 830 connection->browsed_player_id = browsed_player_id; 831 avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); 832 return ERROR_CODE_SUCCESS; 833 } 834 835 /** 836 * @brief Retrieve a listing of the contents of a folder. 837 * @param direction 0-folder up, 1-folder down 838 * @param folder_uid 8 bytes long 839 **/ 840 uint8_t avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid, uint8_t direction, uint8_t * folder_uid){ 841 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 842 if (!avrcp_connection){ 843 log_error("avrcp_browsing_controller_change_path: could not find a connection."); 844 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 845 } 846 847 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 848 849 if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){ 850 log_error("avrcp_browsing_controller_change_path: connection in wrong state."); 851 return ERROR_CODE_COMMAND_DISALLOWED; 852 } 853 854 if (!connection->browsed_player_id){ 855 log_error("avrcp_browsing_controller_change_path: no browsed player set."); 856 return ERROR_CODE_COMMAND_DISALLOWED; 857 } 858 connection->change_path = 1; 859 connection->direction = direction; 860 memset(connection->folder_uid, 0, 8); 861 if (folder_uid){ 862 (void)memcpy(connection->folder_uid, folder_uid, 8); 863 } 864 865 avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); 866 return ERROR_CODE_SUCCESS; 867 } 868 869 uint8_t avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid){ 870 return avrcp_browsing_controller_change_path(avrcp_browsing_cid, 0, NULL); 871 } 872 873 uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid){ 874 return avrcp_browsing_controller_change_path(avrcp_browsing_cid, 1, folder_uid); 875 } 876 877 uint8_t avrcp_browsing_controller_search(uint16_t avrcp_browsing_cid, uint16_t search_str_len, char * search_str){ 878 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 879 if (!avrcp_connection){ 880 log_error("avrcp_browsing_controller_change_path: could not find a connection."); 881 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 882 } 883 884 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 885 886 if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){ 887 log_error("avrcp_browsing_controller_change_path: connection in wrong state."); 888 return ERROR_CODE_COMMAND_DISALLOWED; 889 } 890 891 if (!connection->browsed_player_id){ 892 log_error("avrcp_browsing_controller_change_path: no browsed player set."); 893 return ERROR_CODE_COMMAND_DISALLOWED; 894 } 895 if (!search_str || (search_str_len == 0)){ 896 return AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND; 897 } 898 899 connection->search = 1; 900 901 connection->search_str_len = btstack_min(search_str_len, sizeof(connection->search_str)-1); 902 memset(connection->search_str, 0, sizeof(connection->search_str)); 903 (void)memcpy(connection->search_str, search_str, 904 connection->search_str_len); 905 avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); 906 return ERROR_CODE_SUCCESS; 907 } 908 909 uint8_t avrcp_browsing_controller_get_total_nr_items_for_scope(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope){ 910 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 911 if (!avrcp_connection){ 912 log_error("avrcp_browsing_controller_change_path: could not find a connection."); 913 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 914 } 915 916 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 917 918 if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){ 919 log_error("avrcp_browsing_controller_change_path: connection in wrong state."); 920 return ERROR_CODE_COMMAND_DISALLOWED; 921 } 922 923 if (!connection->browsed_player_id){ 924 log_error("avrcp_browsing_controller_change_path: no browsed player set."); 925 return ERROR_CODE_COMMAND_DISALLOWED; 926 } 927 connection->get_total_nr_items = 1; 928 connection->get_total_nr_items_scope = scope; 929 avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid); 930 return ERROR_CODE_SUCCESS; 931 } 932