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