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