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 50 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 51 52 static int avrcp_browsing_controller_send_get_folder_items_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 53 uint8_t command[100]; 54 int pos = 0; 55 // transport header 56 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 57 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 58 // Profile IDentifier (PID) 59 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 60 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 61 command[pos++] = AVRCP_PDU_ID_GET_FOLDER_ITEMS; 62 63 uint32_t attribute_count = 0; 64 uint32_t attributes_to_copy = 0; 65 66 switch (connection->attr_bitmap){ 67 case AVRCP_MEDIA_ATTR_NONE: 68 attribute_count = AVRCP_MEDIA_ATTR_NONE; // 0xFFFFFFFF 69 break; 70 case AVRCP_MEDIA_ATTR_ALL: 71 attribute_count = AVRCP_MEDIA_ATTR_ALL; // 0 72 break; 73 default: 74 attribute_count = count_set_bits_uint32(connection->attr_bitmap & 0xff); 75 attributes_to_copy = attribute_count; 76 break; 77 } 78 big_endian_store_16(command, pos, 9 + 1 + (attribute_count*4)); 79 pos += 2; 80 81 command[pos++] = connection->scope; 82 big_endian_store_32(command, pos, connection->start_item); 83 pos += 4; 84 big_endian_store_32(command, pos, connection->end_item); 85 pos += 4; 86 command[pos++] = attribute_count; 87 88 int bit_position = 1; 89 while (attributes_to_copy){ 90 if (connection->attr_bitmap & (1 << bit_position)){ 91 big_endian_store_32(command, pos, bit_position); 92 pos += 4; 93 attributes_to_copy--; 94 } 95 bit_position++; 96 } 97 return l2cap_send(cid, command, pos); 98 } 99 100 101 static int avrcp_browsing_controller_send_get_item_attributes_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 102 uint8_t command[100]; 103 int pos = 0; 104 // transport header 105 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 106 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 107 // Profile IDentifier (PID) 108 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 109 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 110 command[pos++] = AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES; 111 112 uint32_t attribute_count; 113 uint32_t attributes_to_copy = 0; 114 115 switch (connection->attr_bitmap){ 116 case AVRCP_MEDIA_ATTR_NONE: 117 case AVRCP_MEDIA_ATTR_ALL: 118 attribute_count = 0; 119 break; 120 default: 121 attribute_count = count_set_bits_uint32(connection->attr_bitmap & 0xff); 122 attributes_to_copy = attribute_count; 123 break; 124 } 125 126 big_endian_store_16(command, pos, 12 + (attribute_count*4)); 127 pos += 2; 128 129 command[pos++] = connection->scope; 130 (void)memcpy(command + pos, connection->folder_uid, 8); 131 pos += 8; 132 big_endian_store_16(command, pos, connection->uid_counter); 133 pos += 2; 134 command[pos++] = attribute_count; 135 136 int bit_position = 1; 137 while (attributes_to_copy){ 138 if (connection->attr_bitmap & (1 << bit_position)){ 139 big_endian_store_32(command, pos, bit_position); 140 pos += 4; 141 attributes_to_copy--; 142 } 143 bit_position++; 144 } 145 146 return l2cap_send(cid, command, pos); 147 } 148 149 150 static int avrcp_browsing_controller_send_change_path_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 151 uint8_t command[100]; 152 int pos = 0; 153 // transport header 154 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 155 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 156 // Profile IDentifier (PID) 157 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 158 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 159 command[pos++] = AVRCP_PDU_ID_CHANGE_PATH; 160 161 big_endian_store_16(command, pos, 11); 162 pos += 2; 163 pos += 2; 164 command[pos++] = connection->direction; 165 (void)memcpy(command + pos, connection->folder_uid, 8); 166 pos += 8; 167 return l2cap_send(cid, command, pos); 168 } 169 170 static int avrcp_browsing_controller_send_search_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 171 uint8_t command[100]; 172 int pos = 0; 173 // transport header 174 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 175 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 176 // Profile IDentifier (PID) 177 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 178 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 179 command[pos++] = AVRCP_PDU_ID_SEARCH; 180 181 big_endian_store_16(command, pos, 4 + connection->search_str_len); 182 pos += 2; 183 184 big_endian_store_16(command, pos, 0x006A); 185 pos += 2; 186 big_endian_store_16(command, pos, connection->search_str_len); 187 pos += 2; 188 189 (void)memcpy(command + pos, connection->search_str, 190 connection->search_str_len); 191 pos += connection->search_str_len; 192 return l2cap_send(cid, command, pos); 193 } 194 195 static int avrcp_browsing_controller_send_set_browsed_player_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 196 uint8_t command[100]; 197 int pos = 0; 198 // transport header 199 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 200 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 201 // Profile IDentifier (PID) 202 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 203 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 204 command[pos++] = AVRCP_PDU_ID_SET_BROWSED_PLAYER; 205 206 big_endian_store_16(command, pos, 2); 207 pos += 2; 208 big_endian_store_16(command, pos, connection->browsed_player_id); 209 pos += 2; 210 return l2cap_send(cid, command, pos); 211 } 212 213 static int avrcp_browsing_controller_send_get_total_nr_items_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){ 214 uint8_t command[7]; 215 int pos = 0; 216 // transport header 217 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 218 command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0; 219 // Profile IDentifier (PID) 220 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8; 221 command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF; 222 command[pos++] = AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS; 223 224 big_endian_store_16(command, pos, 1); 225 pos += 2; 226 command[pos++] = connection->get_total_nr_items_scope; 227 return l2cap_send(cid, command, pos); 228 } 229 230 static void avrcp_browsing_controller_handle_can_send_now(avrcp_browsing_connection_t * connection){ 231 switch (connection->state){ 232 case AVCTP_CONNECTION_OPENED: 233 if (connection->set_browsed_player_id){ 234 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 235 connection->set_browsed_player_id = 0; 236 avrcp_browsing_controller_send_set_browsed_player_cmd(connection->l2cap_browsing_cid, connection); 237 break; 238 } 239 240 if (connection->get_total_nr_items){ 241 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 242 connection->get_total_nr_items = 0; 243 avrcp_browsing_controller_send_get_total_nr_items_cmd(connection->l2cap_browsing_cid, connection); 244 break; 245 } 246 247 if (connection->get_folder_items){ 248 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 249 connection->get_folder_items = 0; 250 avrcp_browsing_controller_send_get_folder_items_cmd(connection->l2cap_browsing_cid, connection); 251 break; 252 } 253 254 if (connection->get_item_attributes){ 255 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 256 connection->get_item_attributes = 0; 257 avrcp_browsing_controller_send_get_item_attributes_cmd(connection->l2cap_browsing_cid, connection); 258 break; 259 } 260 261 if (connection->change_path){ 262 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 263 connection->change_path = 0; 264 avrcp_browsing_controller_send_change_path_cmd(connection->l2cap_browsing_cid, connection); 265 break; 266 } 267 268 if (connection->search){ 269 connection->state = AVCTP_W2_RECEIVE_RESPONSE; 270 connection->search = 0; 271 avrcp_browsing_controller_send_search_cmd(connection->l2cap_browsing_cid, connection); 272 break; 273 } 274 break; 275 default: 276 return; 277 } 278 } 279 280 281 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){ 282 btstack_assert(callback != NULL); 283 284 uint8_t event[9]; 285 int pos = 0; 286 event[pos++] = HCI_EVENT_AVRCP_META; 287 event[pos++] = sizeof(event) - 2; 288 event[pos++] = AVRCP_SUBEVENT_BROWSING_DONE; 289 little_endian_store_16(event, pos, browsing_cid); 290 pos += 2; 291 little_endian_store_16(event, pos, uid_counter); 292 pos += 2; 293 event[pos++] = browsing_status; 294 event[pos++] = bluetooth_status; 295 (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 296 } 297 298 static void avrcp_parser_reset(avrcp_browsing_connection_t * connection){ 299 connection->parser_attribute_header_pos = 0; 300 connection->parsed_attribute_value_offset = 0; 301 connection->parsed_num_attributes = 0; 302 connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; 303 } 304 305 306 static void avrcp_browsing_parser_process_byte(uint8_t byte, avrcp_browsing_connection_t * connection){ 307 uint8_t prepended_header_size = 1; 308 uint16_t attribute_total_value_len; 309 310 switch(connection->parser_state){ 311 case AVRCP_PARSER_GET_ATTRIBUTE_HEADER: 312 connection->parser_attribute_header[connection->parser_attribute_header_pos++] = byte; 313 if (connection->parser_attribute_header_pos < AVRCP_BROWSING_ITEM_HEADER_LEN) break; 314 315 attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 1); 316 connection->parsed_attribute_value[connection->parsed_attribute_value_offset++] = connection->parser_attribute_header[0]; // prepend with item type 317 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 318 connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_VALUE; 319 break; 320 321 case AVRCP_PARSER_GET_ATTRIBUTE_VALUE: 322 connection->parsed_attribute_value[connection->parsed_attribute_value_offset++] = byte; 323 if (connection->parsed_attribute_value_offset < (connection->parsed_attribute_value_len + prepended_header_size)){ 324 break; 325 } 326 if (connection->parsed_attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 1)){ 327 connection->parser_state = AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE; 328 break; 329 } 330 connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; 331 (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, connection->l2cap_browsing_cid, &connection->parsed_attribute_value[0], connection->parsed_attribute_value_offset); 332 connection->parsed_num_attributes++; 333 connection->parsed_attribute_value_offset = 0; 334 connection->parser_attribute_header_pos = 0; 335 336 if (connection->parsed_num_attributes == connection->num_items){ 337 avrcp_parser_reset(connection); 338 break; 339 } 340 break; 341 342 case AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE: 343 connection->parsed_attribute_value_offset++; 344 if (connection->parsed_attribute_value_offset < (big_endian_read_16(connection->parser_attribute_header, 1) + prepended_header_size)){ 345 break; 346 } 347 connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER; 348 (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, connection->l2cap_browsing_cid, &connection->parsed_attribute_value[0], connection->parsed_attribute_value_offset); 349 connection->parsed_num_attributes++; 350 connection->parsed_attribute_value_offset = 0; 351 connection->parser_attribute_header_pos = 0; 352 353 if (connection->parsed_num_attributes == connection->num_items){ 354 avrcp_parser_reset(connection); 355 break; 356 } 357 break; 358 default: 359 break; 360 } 361 } 362 363 static void avrcp_browsing_parse_and_emit_element_attrs(uint8_t * packet, uint16_t num_bytes_to_read, avrcp_browsing_connection_t * connection){ 364 int i; 365 for (i=0;i<num_bytes_to_read;i++){ 366 avrcp_browsing_parser_process_byte(packet[i], connection); 367 } 368 } 369 370 static void avrcp_browsing_controller_emit_failed(btstack_packet_handler_t callback, uint16_t browsing_cid, uint8_t browsing_status, uint8_t bluetooth_status){ 371 avrcp_browsing_controller_emit_done_with_uid_counter(callback, browsing_cid, 0, browsing_status, bluetooth_status); 372 } 373 374 375 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 376 avrcp_browsing_connection_t * browsing_connection; 377 uint8_t transport_header; 378 int pos; 379 switch (packet_type) { 380 case L2CAP_DATA_PACKET: 381 browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid_for_role(AVRCP_CONTROLLER, channel); 382 if (!browsing_connection) break; 383 pos = 0; 384 transport_header = packet[pos++]; 385 // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier) 386 browsing_connection->transaction_label = transport_header >> 4; 387 avrcp_packet_type_t avctp_packet_type = (transport_header & 0x0F) >> 2; 388 switch (avctp_packet_type){ 389 case AVRCP_SINGLE_PACKET: 390 case AVRCP_START_PACKET: 391 pos += 2; 392 browsing_connection->num_packets = 1; 393 if (avctp_packet_type == AVRCP_START_PACKET){ 394 browsing_connection->num_packets = packet[pos++]; 395 } 396 if ((pos + 4) > size){ 397 browsing_connection->state = AVCTP_CONNECTION_OPENED; 398 avrcp_browsing_controller_emit_failed(avrcp_controller_context.browsing_avrcp_callback, channel, AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND, ERROR_CODE_SUCCESS); 399 return; 400 } 401 browsing_connection->pdu_id = packet[pos++]; 402 pos += 2; 403 browsing_connection->browsing_status = packet[pos++]; 404 if (browsing_connection->browsing_status != AVRCP_BROWSING_ERROR_CODE_SUCCESS){ 405 browsing_connection->state = AVCTP_CONNECTION_OPENED; 406 avrcp_browsing_controller_emit_failed(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_connection->browsing_status, ERROR_CODE_SUCCESS); 407 return; 408 } 409 break; 410 default: 411 break; 412 } 413 414 uint32_t i; 415 uint8_t folder_depth; 416 417 switch(browsing_connection->pdu_id){ 418 case AVRCP_PDU_ID_CHANGE_PATH: 419 break; 420 case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER: 421 break; 422 case AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS: 423 break; 424 case AVRCP_PDU_ID_SET_BROWSED_PLAYER: 425 browsing_connection->uid_counter = big_endian_read_16(packet, pos); 426 pos += 2; 427 // num_items 428 pos += 4; 429 // charset 430 pos += 2; 431 folder_depth = packet[pos++]; 432 433 for (i = 0; i < folder_depth; i++){ 434 uint16_t folder_name_length = big_endian_read_16(packet, pos); 435 pos += 2; 436 // reuse packet and add data type as a header 437 packet[pos-1] = AVRCP_BROWSING_MEDIA_ROOT_FOLDER; 438 (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos-1, folder_name_length+1); 439 pos += folder_name_length; 440 } 441 break; 442 443 case AVRCP_PDU_ID_GET_FOLDER_ITEMS:{ 444 switch (avctp_packet_type){ 445 case AVRCP_SINGLE_PACKET: 446 case AVRCP_START_PACKET: 447 avrcp_parser_reset(browsing_connection); 448 browsing_connection->uid_counter = big_endian_read_16(packet, pos); 449 pos += 2; 450 browsing_connection->num_items = big_endian_read_16(packet, pos); //num_items 451 pos += 2; 452 avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection); 453 break; 454 455 case AVRCP_CONTINUE_PACKET: 456 avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection); 457 break; 458 459 case AVRCP_END_PACKET: 460 avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection); 461 avrcp_parser_reset(browsing_connection); 462 break; 463 default: 464 break; 465 } 466 break; 467 } 468 case AVRCP_PDU_ID_SEARCH: 469 browsing_connection->uid_counter = big_endian_read_16(packet, pos); 470 pos += 2; 471 break; 472 case AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES: 473 packet[pos-1] = AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE; 474 (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos-1, size - pos + 1); 475 break; 476 default: 477 log_info(" not parsed pdu ID 0x%02x", browsing_connection->pdu_id); 478 break; 479 } 480 481 switch (avctp_packet_type){ 482 case AVRCP_SINGLE_PACKET: 483 case AVRCP_END_PACKET: 484 browsing_connection->state = AVCTP_CONNECTION_OPENED; 485 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); 486 break; 487 default: 488 break; 489 } 490 break; 491 492 case HCI_EVENT_PACKET: 493 switch (hci_event_packet_get_type(packet)){ 494 case L2CAP_EVENT_CAN_SEND_NOW: 495 browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid_for_role(AVRCP_CONTROLLER,channel); 496 avrcp_browsing_controller_handle_can_send_now(browsing_connection); 497 break; 498 default: 499 break; 500 } 501 break; 502 503 default: 504 break; 505 } 506 } 507 508 void avrcp_browsing_controller_init(void){ 509 avrcp_controller_context.browsing_packet_handler = avrcp_browsing_controller_packet_handler; 510 avrcp_browsing_register_controller_packet_handler(avrcp_browsing_controller_packet_handler); 511 } 512 513 void avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback){ 514 btstack_assert(callback != NULL); 515 avrcp_controller_context.browsing_avrcp_callback = callback; 516 } 517 518 uint8_t avrcp_browsing_controller_disconnect(uint16_t avrcp_browsing_cid){ 519 return avrcp_browsing_disconnect(avrcp_browsing_cid, AVRCP_CONTROLLER); 520 } 521 522 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){ 523 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 524 if (!avrcp_connection){ 525 log_error("avrcp_browsing_controller_configure_incoming_connection: could not find a connection."); 526 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 527 } 528 if (!avrcp_connection->browsing_connection){ 529 log_error("avrcp_browsing_controller_configure_incoming_connection: no browsing connection."); 530 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 531 } 532 533 if (avrcp_connection->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){ 534 log_error("avrcp_browsing_controller_configure_incoming_connection: browsing connection in a wrong state."); 535 return ERROR_CODE_COMMAND_DISALLOWED; 536 } 537 log_error("avrcp_browsing_controller_configure_incoming_connection: l2cap_accept_ertm_connection."); 538 avrcp_connection->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 539 avrcp_connection->browsing_connection->ertm_buffer = ertm_buffer; 540 avrcp_connection->browsing_connection->ertm_buffer_size = size; 541 (void)memcpy(&avrcp_connection->browsing_connection->ertm_config, 542 ertm_config, sizeof(l2cap_ertm_config_t)); 543 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); 544 return ERROR_CODE_SUCCESS; 545 } 546 547 uint8_t avrcp_browsing_controller_decline_incoming_connection(uint16_t avrcp_browsing_cid){ 548 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 549 if (!avrcp_connection){ 550 log_error("avrcp_browsing_controller_decline_incoming_connection: could not find a connection."); 551 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 552 } 553 if (!avrcp_connection->browsing_connection) return ERROR_CODE_SUCCESS; 554 if (avrcp_connection->browsing_connection->state > AVCTP_CONNECTION_W4_ERTM_CONFIGURATION) return ERROR_CODE_COMMAND_DISALLOWED; 555 556 l2cap_decline_connection(avrcp_connection->browsing_connection->l2cap_browsing_cid); 557 // free connection 558 btstack_memory_avrcp_browsing_connection_free(avrcp_connection->browsing_connection); 559 avrcp_connection->browsing_connection = NULL; 560 return ERROR_CODE_SUCCESS; 561 } 562 563 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){ 564 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 565 if (!avrcp_connection){ 566 log_error("avrcp_browsing_controller_get_item_attributes: could not find a connection."); 567 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 568 } 569 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 570 if (connection->state != AVCTP_CONNECTION_OPENED){ 571 log_error("avrcp_browsing_controller_get_item_attributes: connection in wrong state %d, expected %d.", connection->state, AVCTP_CONNECTION_OPENED); 572 return ERROR_CODE_COMMAND_DISALLOWED; 573 } 574 575 connection->get_item_attributes = 1; 576 connection->scope = scope; 577 (void)memcpy(connection->folder_uid, uid, 8); 578 connection->uid_counter = uid_counter; 579 connection->attr_bitmap = attr_bitmap; 580 581 avrcp_browsing_request_can_send_now(connection, connection->l2cap_browsing_cid); 582 return ERROR_CODE_SUCCESS; 583 } 584 585 /** 586 * @brief Retrieve a listing of the contents of a folder. 587 * @param scope 0-player list, 1-virtual file system, 2-search, 3-now playing 588 * @param start_item 589 * @param end_item 590 * @param attribute_count 591 * @param attribute_list 592 **/ 593 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){ 594 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 595 if (!avrcp_connection){ 596 log_error("avrcp_browsing_controller_disconnect: could not find a connection."); 597 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 598 } 599 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 600 if (connection->state != AVCTP_CONNECTION_OPENED) { 601 log_error("avrcp_browsing_controller_get_folder_items: connection in wrong state %d, expected %d.", connection->state, AVCTP_CONNECTION_OPENED); 602 return ERROR_CODE_COMMAND_DISALLOWED; 603 } 604 605 connection->get_folder_items = 1; 606 connection->scope = scope; 607 connection->start_item = start_item; 608 connection->end_item = end_item; 609 connection->attr_bitmap = attr_bitmap; 610 611 avrcp_browsing_request_can_send_now(connection, connection->l2cap_browsing_cid); 612 return ERROR_CODE_SUCCESS; 613 } 614 615 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){ 616 return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_LIST, start_item, end_item, attr_bitmap); 617 } 618 619 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){ 620 // return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 1, 0, 0xFFFFFFFF, attr_bitmap); 621 return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM, start_item, end_item, attr_bitmap); 622 } 623 624 uint8_t avrcp_browsing_controller_browse_media(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){ 625 // return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 2, 0, 0xFFFFFFFF, 0, NULL); 626 return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_SEARCH, start_item, end_item, attr_bitmap); 627 } 628 629 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){ 630 return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_NOW_PLAYING, start_item, end_item, attr_bitmap); 631 } 632 633 634 uint8_t avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid, uint16_t browsed_player_id){ 635 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 636 if (!avrcp_connection){ 637 log_error("avrcp_browsing_controller_change_path: could not find a connection."); 638 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 639 } 640 641 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 642 if (connection->state != AVCTP_CONNECTION_OPENED){ 643 log_error("avrcp_browsing_controller_change_path: connection in wrong state."); 644 return ERROR_CODE_COMMAND_DISALLOWED; 645 } 646 647 connection->set_browsed_player_id = 1; 648 connection->browsed_player_id = browsed_player_id; 649 avrcp_browsing_request_can_send_now(connection, connection->l2cap_browsing_cid); 650 return ERROR_CODE_SUCCESS; 651 } 652 653 /** 654 * @brief Retrieve a listing of the contents of a folder. 655 * @param direction 0-folder up, 1-folder down 656 * @param folder_uid 8 bytes long 657 **/ 658 uint8_t avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid, uint8_t direction, uint8_t * folder_uid){ 659 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 660 if (!avrcp_connection){ 661 log_error("avrcp_browsing_controller_change_path: could not find a connection."); 662 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 663 } 664 665 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 666 667 if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){ 668 log_error("avrcp_browsing_controller_change_path: connection in wrong state."); 669 return ERROR_CODE_COMMAND_DISALLOWED; 670 } 671 672 if (!connection->browsed_player_id){ 673 log_error("avrcp_browsing_controller_change_path: no browsed player set."); 674 return ERROR_CODE_COMMAND_DISALLOWED; 675 } 676 connection->change_path = 1; 677 connection->direction = direction; 678 memset(connection->folder_uid, 0, 8); 679 if (folder_uid){ 680 (void)memcpy(connection->folder_uid, folder_uid, 8); 681 } 682 683 avrcp_browsing_request_can_send_now(connection, connection->l2cap_browsing_cid); 684 return ERROR_CODE_SUCCESS; 685 } 686 687 uint8_t avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid){ 688 return avrcp_browsing_controller_change_path(avrcp_browsing_cid, 0, NULL); 689 } 690 691 uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid){ 692 return avrcp_browsing_controller_change_path(avrcp_browsing_cid, 1, folder_uid); 693 } 694 695 uint8_t avrcp_browsing_controller_search(uint16_t avrcp_browsing_cid, uint16_t search_str_len, char * search_str){ 696 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 697 if (!avrcp_connection){ 698 log_error("avrcp_browsing_controller_change_path: could not find a connection."); 699 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 700 } 701 702 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 703 704 if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){ 705 log_error("avrcp_browsing_controller_change_path: connection in wrong state."); 706 return ERROR_CODE_COMMAND_DISALLOWED; 707 } 708 709 if (!connection->browsed_player_id){ 710 log_error("avrcp_browsing_controller_change_path: no browsed player set."); 711 return ERROR_CODE_COMMAND_DISALLOWED; 712 } 713 if (!search_str || (search_str_len == 0)){ 714 return AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND; 715 } 716 717 connection->search = 1; 718 719 connection->search_str_len = btstack_min(search_str_len, sizeof(connection->search_str)-1); 720 memset(connection->search_str, 0, sizeof(connection->search_str)); 721 (void)memcpy(connection->search_str, search_str, 722 connection->search_str_len); 723 avrcp_browsing_request_can_send_now(connection, connection->l2cap_browsing_cid); 724 return ERROR_CODE_SUCCESS; 725 } 726 727 uint8_t avrcp_browsing_controller_get_total_nr_items_for_scope(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope){ 728 avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid); 729 if (!avrcp_connection){ 730 log_error("avrcp_browsing_controller_change_path: could not find a connection."); 731 return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 732 } 733 734 avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection; 735 736 if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){ 737 log_error("avrcp_browsing_controller_change_path: connection in wrong state."); 738 return ERROR_CODE_COMMAND_DISALLOWED; 739 } 740 741 if (!connection->browsed_player_id){ 742 log_error("avrcp_browsing_controller_change_path: no browsed player set."); 743 return ERROR_CODE_COMMAND_DISALLOWED; 744 } 745 connection->get_total_nr_items = 1; 746 connection->get_total_nr_items_scope = scope; 747 avrcp_browsing_request_can_send_now(connection, connection->l2cap_browsing_cid); 748 return ERROR_CODE_SUCCESS; 749 } 750