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