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