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