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