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 BLUEKITCHEN 24 * GMBH 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_client.c" 39 40 /* 41 * avrcp_browsing_client.c 42 */ 43 44 // ***************************************************************************** 45 /* EXAMPLE_START(avrcp_browsing_client): AVRCP Browsing - Browse Media Players and Media Information 46 * 47 * @text This example demonstrates how to use the AVRCP Controller Browsing service to 48 * browse madia players and media information on a remote AVRCP Source device. 49 * 50 * @text To test with a remote device, e.g. a mobile phone, 51 * pair from the remote device with the demo, then use the UI for browsing. If HAVE_BTSTACK_STDIN is set, 52 * press SPACE on the console to show the available AVDTP and AVRCP commands. 53 * 54 */ 55 // ***************************************************************************** 56 57 #include <stdint.h> 58 #include <inttypes.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 63 #include "btstack.h" 64 65 #ifdef HAVE_BTSTACK_STDIN 66 #include "btstack_stdin.h" 67 #endif 68 69 #ifndef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE 70 #error "AVRCP Browsing requires L2CAP ERTM, please add ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE to your btstack_config.h" 71 #endif 72 73 #define AVRCP_BROWSING_ENABLED 74 75 #define AVRCP_BROWSING_MAX_PLAYERS 10 76 #define AVRCP_BROWSING_MAX_FOLDERS 10 77 #define AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN 30 78 #define AVRCP_BROWSING_MAX_MEDIA_ITEMS 10 79 80 #ifdef HAVE_BTSTACK_STDIN 81 // mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3}; 82 // pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5}; 83 // mac 2013: 84 // static const char * device_addr_string = "84:38:35:65:d1:15"; 85 // iPhone 5S: static const char * device_addr_string = "54:E4:3A:26:A2:39"; 86 // phone 2013: 87 // static const char * device_addr_string = "B0:34:95:CB:97:C4"; 88 // iPod 89 // static const char * device_addr_string = "B0:34:95:CB:97:C4"; 90 // iPhone 91 static const char * device_addr_string = "6C:72:E7:10:22:EE"; 92 93 static bd_addr_t device_addr; 94 #endif 95 96 typedef enum { 97 AVRCP_BROWSING_STATE_IDLE, 98 AVRCP_BROWSING_STATE_W4_GET_PLAYERS, 99 AVRCP_BROWSING_STATE_W4_SET_PLAYER, 100 AVRCP_BROWSING_STATE_READY 101 } avrcp_browsing_state_t; 102 103 typedef struct { 104 uint16_t charset; 105 uint8_t depth; 106 uint16_t name_len; 107 char name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 108 } avrcp_browsing_root_folder_t; 109 110 typedef struct { 111 uint8_t uid[8]; 112 uint16_t name_len; 113 char name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 114 } avrcp_browsable_item_t; 115 116 typedef struct { 117 uint16_t player_id; 118 uint8_t major_player_type; 119 uint32_t player_sub_type; 120 uint8_t play_status; 121 uint8_t feature_bitmask[16]; 122 uint16_t charset; 123 uint16_t name_len; 124 char name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 125 } avrcp_browsable_media_player_item_t; 126 127 typedef struct { 128 uint32_t id; 129 uint16_t charset; 130 uint16_t value_len; 131 char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 132 } avrcp_browsable_media_element_item_attribute_t; 133 134 typedef struct { 135 uint8_t uid[8]; 136 uint8_t media_type; 137 uint16_t charset; 138 uint16_t name_len; 139 char name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 140 uint8_t num_attributes; 141 } avrcp_browsable_media_element_item_t; 142 143 static avrcp_browsing_state_t browsing_state = AVRCP_BROWSING_STATE_IDLE; 144 static uint16_t avrcp_cid = 0; 145 static bool avrcp_connected = false; 146 147 static uint16_t browsing_cid = 0; 148 static bool browsing_connected = false; 149 150 static uint8_t sdp_avrcp_browsing_controller_service_buffer[200]; 151 static uint8_t sdp_avdtp_sink_service_buffer[150]; 152 153 static uint16_t a2dp_cid = 0; 154 static uint8_t a2dp_local_seid = 0; 155 156 static uint8_t media_sbc_codec_capabilities[] = { 157 0xFF,//(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO, 158 0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS, 159 2, 53 160 }; 161 162 static uint8_t media_sbc_codec_configuration[] = { 163 (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO, 164 (AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS, 165 2, 53 166 }; 167 168 static bool browsing_query_active = false; 169 // static avrcp_media_item_context_t media_item_context; 170 171 static int playable_folder_index = 0; 172 173 174 static uint16_t browsing_uid_counter = 0; 175 176 static uint8_t parent_folder_set = 0; 177 static uint8_t parent_folder_uid[8]; 178 static char parent_folder_name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 179 180 static avrcp_browsable_item_t folders[AVRCP_BROWSING_MAX_FOLDERS]; 181 static int folder_index = -1; 182 183 static avrcp_browsable_media_element_item_t media_element_items[AVRCP_BROWSING_MAX_MEDIA_ITEMS]; 184 static int media_element_item_index = -1; 185 186 static avrcp_browsable_media_player_item_t media_player_items[AVRCP_BROWSING_MAX_MEDIA_ITEMS]; 187 static int media_player_item_index = -1; 188 189 static btstack_packet_callback_registration_t hci_event_callback_registration; 190 191 static uint8_t ertm_buffer[10000]; 192 static l2cap_ertm_config_t ertm_config = { 193 1, // ertm mandatory 194 2, // max transmit, some tests require > 1 195 2000, 196 12000, 197 144, // l2cap ertm mtu 198 4, 199 4, 200 1, // 16-bit FCS 201 }; 202 203 204 static inline int next_index(int * index, int max_value){ 205 if ((*index) < max_value){ 206 (*index)++; 207 } else { 208 (*index) = 0; 209 } 210 return (*index); 211 } 212 213 static int next_folder_index(void){ 214 return next_index(&folder_index, AVRCP_BROWSING_MAX_FOLDERS); 215 } 216 217 static int next_media_element_item_index(void){ 218 return next_index(&media_element_item_index, AVRCP_BROWSING_MAX_MEDIA_ITEMS); 219 } 220 static int next_media_player_item_index(void){ 221 return next_index(&media_player_item_index, AVRCP_BROWSING_MAX_MEDIA_ITEMS); 222 } 223 224 /* @section Main Application Setup 225 * 226 * @text The Listing MainConfiguration shows how to setup AVRCP Controller Browsing service. 227 * To announce AVRCP Controller Browsing service, you need to create corresponding 228 * SDP record and register it with the SDP service. 229 * You'll also need to register several packet handlers: 230 * - stdin_process callback - used to trigger AVRCP commands, such are get media players, playlists, albums, etc. Requires HAVE_BTSTACK_STDIN. 231 * - avrcp_browsing_controller_packet_handler - used to receive answers for AVRCP commands. 232 * 233 */ 234 235 /* LISTING_START(MainConfiguration): Setup Audio Sink and AVRCP Controller services */ 236 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 237 static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 238 static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 239 240 #ifdef HAVE_BTSTACK_STDIN 241 static void stdin_process(char cmd); 242 #endif 243 244 245 int btstack_main(int argc, const char * argv[]); 246 int btstack_main(int argc, const char * argv[]){ 247 (void)argc; 248 (void)argv; 249 250 // Initialize L2CAP. 251 l2cap_init(); 252 253 #ifdef ENABLE_BLE 254 // Initialize LE Security Manager. Needed for cross-transport key derivation 255 sm_init(); 256 #endif 257 258 a2dp_sink_init(); 259 a2dp_sink_register_packet_handler(&a2dp_sink_packet_handler); 260 261 avdtp_stream_endpoint_t * local_stream_endpoint = a2dp_sink_create_stream_endpoint(AVDTP_AUDIO, 262 AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities), 263 media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration)); 264 if (!local_stream_endpoint){ 265 printf("A2DP Sink: not enough memory to create local stream endpoint\n"); 266 return 1; 267 } 268 a2dp_local_seid = avdtp_local_seid(local_stream_endpoint); 269 270 // Initialize AVRCP service. 271 avrcp_init(); 272 // Initialize AVRCP Controller & Target Service. 273 avrcp_controller_init(); 274 avrcp_target_init(); 275 276 avrcp_register_packet_handler(&avrcp_packet_handler); 277 avrcp_controller_register_packet_handler(&avrcp_packet_handler); 278 avrcp_target_register_packet_handler(&avrcp_packet_handler); 279 280 // Initialize AVRCP Browsing Service. 281 avrcp_browsing_init(); 282 avrcp_browsing_controller_init(); 283 avrcp_browsing_target_init(); 284 285 // Register for HCI events. 286 avrcp_browsing_controller_register_packet_handler(&avrcp_browsing_controller_packet_handler); 287 avrcp_browsing_target_register_packet_handler(&avrcp_browsing_controller_packet_handler); 288 avrcp_browsing_register_packet_handler(&avrcp_browsing_controller_packet_handler); 289 290 // Initialize SDP. 291 sdp_init(); 292 // setup AVDTP sink 293 memset(sdp_avdtp_sink_service_buffer, 0, sizeof(sdp_avdtp_sink_service_buffer)); 294 a2dp_sink_create_sdp_record(sdp_avdtp_sink_service_buffer, 0x10001, AVDTP_SINK_FEATURE_MASK_HEADPHONE, NULL, NULL); 295 sdp_register_service(sdp_avdtp_sink_service_buffer); 296 297 // Create AVRCP service record and register it with SDP. 298 memset(sdp_avrcp_browsing_controller_service_buffer, 0, sizeof(sdp_avrcp_browsing_controller_service_buffer)); 299 300 uint16_t supported_features = AVRCP_FEATURE_MASK_CATEGORY_PLAYER_OR_RECORDER; 301 #ifdef AVRCP_BROWSING_ENABLED 302 supported_features |= AVRCP_FEATURE_MASK_BROWSING; 303 #endif 304 avrcp_controller_create_sdp_record(sdp_avrcp_browsing_controller_service_buffer, 0x10002, supported_features, NULL, NULL); 305 sdp_register_service(sdp_avrcp_browsing_controller_service_buffer); 306 307 // Set local name with a template Bluetooth address, that will be automatically 308 // replaced with a actual address once it is available, i.e. when BTstack boots 309 // up and starts talking to a Bluetooth module. 310 gap_set_local_name("AVRCP Browsing Client 00:00:00:00:00:00"); 311 gap_discoverable_control(1); 312 gap_set_class_of_device(0x200408); 313 314 // Register for HCI events. 315 hci_event_callback_registration.callback = &avrcp_browsing_controller_packet_handler; 316 hci_add_event_handler(&hci_event_callback_registration); 317 318 319 #ifdef HAVE_BTSTACK_STDIN 320 // Parse human readable Bluetooth address. 321 sscanf_bd_addr(device_addr_string, device_addr); 322 btstack_stdin_setup(stdin_process); 323 #endif 324 printf("Starting BTstack ...\n"); 325 hci_power_control(HCI_POWER_ON); 326 return 0; 327 } 328 /* LISTING_END */ 329 330 static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 331 UNUSED(channel); 332 UNUSED(size); 333 uint16_t local_cid; 334 uint8_t status = 0xFF; 335 bd_addr_t adress; 336 337 if (packet_type != HCI_EVENT_PACKET) return; 338 if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return; 339 switch (packet[2]){ 340 case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: { 341 local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet); 342 status = avrcp_subevent_connection_established_get_status(packet); 343 if (status != ERROR_CODE_SUCCESS){ 344 printf("AVRCP: Connection failed, status 0x%02x\n", status); 345 avrcp_cid = 0; 346 return; 347 } 348 349 avrcp_cid = local_cid; 350 avrcp_connected = true; 351 avrcp_subevent_connection_established_get_bd_addr(packet, adress); 352 printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(adress), avrcp_cid); 353 return; 354 } 355 356 case AVRCP_SUBEVENT_CONNECTION_RELEASED: 357 printf("AVRCP: Channel released: cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet)); 358 avrcp_cid = 0; 359 avrcp_connected = false; 360 return; 361 default: 362 break; 363 } 364 } 365 366 static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 367 UNUSED(channel); 368 UNUSED(size); 369 bd_addr_t address; 370 uint8_t status; 371 372 if (packet_type != HCI_EVENT_PACKET) return; 373 if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return; 374 375 switch (packet[2]){ 376 case A2DP_SUBEVENT_STREAM_ESTABLISHED: 377 a2dp_subevent_stream_established_get_bd_addr(packet, address); 378 status = a2dp_subevent_stream_established_get_status(packet); 379 380 if (status != ERROR_CODE_SUCCESS){ 381 printf("A2DP Sink : Streaming connection failed, status 0x%02x\n", status); 382 break; 383 } 384 385 a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet); 386 memcpy(device_addr, address, 6); 387 printf("A2DP Sink: Connection established, address %s, a2dp_cid 0x%02x\n", bd_addr_to_str(address), a2dp_cid); 388 break; 389 390 case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED: 391 printf("A2DP Sink: Connection released\n"); 392 break; 393 394 default: 395 break; 396 } 397 } 398 399 400 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 401 UNUSED(channel); 402 UNUSED(size); 403 bd_addr_t address; 404 uint8_t status; 405 uint16_t pos = 0; 406 uint16_t local_cid; 407 408 // printf("avrcp_browsing_controller_packet_handler packet type 0x%02X, subevent 0x%02X\n", packet_type, packet[2]); 409 switch (packet_type) { 410 case HCI_EVENT_PACKET: 411 switch (packet[0]){ 412 case HCI_EVENT_AVRCP_META: 413 switch (packet[2]){ 414 case AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED: { 415 local_cid = avrcp_subevent_browsing_connection_established_get_browsing_cid(packet); 416 status = avrcp_subevent_browsing_connection_established_get_status(packet); 417 if (status != ERROR_CODE_SUCCESS){ 418 printf("AVRCP: Connection failed, status 0x%02x\n", status); 419 browsing_cid = 0; 420 return; 421 } 422 avrcp_subevent_browsing_connection_established_get_bd_addr(packet, address); 423 browsing_cid = local_cid; 424 browsing_connected = true; 425 printf("AVRCP Browsing: Connection established, address %s, browsing_cid 0x%02x\n", bd_addr_to_str(address), browsing_cid); 426 return; 427 } 428 429 case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED: 430 printf("AVRCP: Connection released, cid 0x%02x\n", avrcp_subevent_browsing_connection_released_get_browsing_cid(packet)); 431 browsing_cid = 0; 432 browsing_connected = false; 433 return; 434 case AVRCP_SUBEVENT_BROWSING_DONE: 435 436 browsing_query_active = 0; 437 browsing_uid_counter = 0; 438 if (avrcp_subevent_browsing_done_get_browsing_status(packet) != AVRCP_BROWSING_ERROR_CODE_SUCCESS){ 439 printf("AVRCP Browsing query done with browsing status 0x%02x, bluetooth status 0x%02x.\n", 440 avrcp_subevent_browsing_done_get_browsing_status(packet), 441 avrcp_subevent_browsing_done_get_bluetooth_status(packet)); 442 return; 443 } 444 browsing_uid_counter = avrcp_subevent_browsing_done_get_uid_counter(packet); 445 printf("DONE, browsing_uid_counter %d.\n", browsing_uid_counter); 446 447 switch (browsing_state){ 448 case AVRCP_BROWSING_STATE_W4_GET_PLAYERS: 449 if (media_player_item_index < 0) { 450 printf("Get media players first\n"); 451 break; 452 } 453 printf("Set browsed player\n"); 454 browsing_state = AVRCP_BROWSING_STATE_W4_SET_PLAYER; 455 status = avrcp_browsing_controller_set_browsed_player(browsing_cid, media_player_items[0].player_id); 456 if (status != ERROR_CODE_SUCCESS){ 457 printf("Could not set player, status 0x%02x\n", status); 458 status = AVRCP_BROWSING_STATE_W4_GET_PLAYERS; 459 break; 460 } 461 break; 462 case AVRCP_BROWSING_STATE_W4_SET_PLAYER: 463 browsing_state = AVRCP_BROWSING_STATE_READY; 464 break; 465 default: 466 break; 467 } 468 break; 469 default: 470 break; 471 } 472 473 default: 474 break; 475 } 476 break; 477 478 case AVRCP_BROWSING_DATA_PACKET: 479 browsing_query_active = 1; 480 avrcp_browsing_item_type_t data_type = (avrcp_browsing_item_type_t)packet[pos++]; 481 482 switch (data_type){ 483 case AVRCP_BROWSING_MEDIA_ROOT_FOLDER:{ 484 uint16_t folder_name_length = size - pos; 485 char folder_name[AVRCP_MAX_FOLDER_NAME_SIZE]; 486 memcpy(folder_name, &packet[pos], folder_name_length); 487 folder_name[folder_name_length] = 0; 488 printf("Found root folder: name %s \n", folder_name); 489 break; 490 } 491 492 case AVRCP_BROWSING_FOLDER_ITEM:{ 493 int index = next_folder_index(); 494 memcpy(folders[index].uid, packet+pos, 8); 495 496 uint32_t folder_uid_high = big_endian_read_32(packet, pos); 497 pos += 4; 498 uint32_t folder_uid_low = big_endian_read_32(packet, pos); 499 pos += 4; 500 avrcp_browsing_folder_type_t folder_type = packet[pos++]; 501 uint8_t is_playable = packet[pos++]; 502 uint16_t charset = big_endian_read_16(packet, pos); 503 pos += 2; 504 uint16_t displayable_name_length = big_endian_read_16(packet, pos); 505 pos += 2; 506 507 char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 508 memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN); 509 uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1); 510 memcpy(value, packet+pos, value_len); 511 512 printf("Folder UID 0x%08" PRIx32 "%08" PRIx32 ", type 0x%02x, is_playable %d, charset 0x%02x, name %s\n", 513 folder_uid_high, folder_uid_low, folder_type, is_playable, charset, value); 514 if (is_playable){ 515 playable_folder_index = index; 516 } 517 memcpy(folders[index].name, value, value_len); 518 folders[index].name_len = value_len; 519 break; 520 } 521 522 case AVRCP_BROWSING_MEDIA_PLAYER_ITEM:{ 523 printf("Received media player item: "); 524 uint16_t player_id = big_endian_read_16(packet, pos); 525 pos += 2; 526 avrcp_browsing_media_player_major_type_t major_type = packet[pos++]; 527 avrcp_browsing_media_player_subtype_t subtype = big_endian_read_32(packet, pos); 528 pos += 4; 529 status = packet[pos++]; 530 uint8_t feature_bitmask[16]; 531 memcpy(feature_bitmask, packet, 16); 532 pos += 16; 533 printf("player ID 0x%04x, major_type %d, subtype %d, status 0x%02x\n", player_id, major_type, subtype, status); 534 media_player_items[next_media_player_item_index()].player_id = player_id; 535 break; 536 } 537 538 case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM:{ 539 int index = next_media_element_item_index(); 540 memcpy(media_element_items[index].uid, packet+pos, 8); 541 printf("Received media element item UID (index %d): ", index); 542 543 // uint32_t media_uid_high = big_endian_read_32(packet, pos); 544 pos += 4; 545 // uint32_t media_uid_low = big_endian_read_32(packet, pos+4); 546 pos += 4; 547 548 avrcp_browsing_media_type_t media_type = packet[pos++]; 549 uint16_t charset = big_endian_read_16(packet, pos); 550 pos += 2; 551 uint16_t displayable_name_length = big_endian_read_16(packet, pos); 552 pos += 2; 553 554 char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 555 memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN); 556 uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1); 557 memcpy(value, packet+pos, value_len); 558 memcpy(media_element_items[index].name, value, value_len); 559 560 pos += displayable_name_length; 561 // printf("Media UID: 0x%08" PRIx32 "%08" PRIx32 ", media_type 0x%02x, charset 0x%02x, actual len %d, name %s\n", media_uid_high, media_uid_low, media_type, charset, value_len, value); 562 563 printf_hexdump(media_element_items[index].uid, 8); 564 uint8_t num_attributes = packet[pos++]; 565 printf(" Media type 0x%02x, charset 0x%02x, actual len %d, name %s, num attributes %d:\n", media_type, charset, value_len, value, num_attributes); 566 567 avrcp_media_item_context_t media_item_context; 568 for (avrcp_media_item_iterator_init(&media_item_context, size-pos, packet+pos); avrcp_media_item_iterator_has_more(&media_item_context); avrcp_media_item_iterator_next(&media_item_context)){ 569 uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context); 570 uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context); 571 uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context); 572 const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context); 573 574 memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN); 575 value_len = btstack_min(attr_value_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1); 576 memcpy(value, attr_value, value_len); 577 578 printf(" - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, value_len, value); 579 } 580 break; 581 } 582 583 case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE:{ 584 uint8_t num_attributes = packet[pos++]; 585 printf("Num media attributes %d:\n", num_attributes); 586 avrcp_media_item_context_t media_item_context; 587 for (avrcp_media_item_iterator_init(&media_item_context, size-pos, packet+pos); avrcp_media_item_iterator_has_more(&media_item_context); avrcp_media_item_iterator_next(&media_item_context)){ 588 uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context); 589 uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context); 590 uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context); 591 const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context); 592 printf(" - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, attr_value_length, attr_value); 593 } 594 } 595 default: 596 printf("AVRCP browsing: unknown browsable item type 0%02x\n", data_type); 597 break; 598 } 599 break; 600 default: 601 break; 602 } 603 } 604 605 #ifdef HAVE_BTSTACK_STDIN 606 static void show_usage(void){ 607 bd_addr_t iut_address; 608 gap_local_bd_addr(iut_address); 609 printf("\n--- Bluetooth AVRCP Browsing Service Test Console %s ---\n", bd_addr_to_str(iut_address)); 610 printf("c - AVRCP Service create connection to addr %s\n", bd_addr_to_str(device_addr)); 611 printf("C - AVRCP Service disconnect\n"); 612 printf("e - AVRCP Browsing Service create connection to addr %s\n", bd_addr_to_str(device_addr)); 613 printf("E - AVRCP Browsing Service disconnect\n"); 614 615 printf("I - Set first found player as addressed player\n"); 616 printf("O - Set first found player as browsed player\n"); 617 618 printf("p - Get media players\n"); 619 printf("Q - Browse folders\n"); 620 printf("P - Go up one level\n"); 621 printf("W - Go down one level\n"); 622 printf("T - Browse media items\n"); 623 printf("---\n"); 624 } 625 #endif 626 627 628 #ifdef HAVE_BTSTACK_STDIN 629 static void stdin_process(char cmd){ 630 uint8_t status = ERROR_CODE_SUCCESS; 631 632 if (cmd != 'a' && cmd != 'A' && cmd != 'c' && cmd != 'C'){ 633 if (browsing_query_active){ 634 printf("Query active, try later!\n"); 635 return; 636 } 637 } 638 639 switch (cmd){ 640 case 'b': 641 status = a2dp_sink_establish_stream(device_addr, a2dp_local_seid, &a2dp_cid); 642 printf(" - Create AVDTP connection to addr %s, and local seid %d, expected cid 0x%02x.\n", bd_addr_to_str(device_addr), a2dp_local_seid, a2dp_cid); 643 break; 644 case 'B': 645 printf(" - AVDTP disconnect from addr %s.\n", bd_addr_to_str(device_addr)); 646 a2dp_sink_disconnect(a2dp_cid); 647 break; 648 649 case 'c': 650 printf(" - Connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr)); 651 status = avrcp_connect(device_addr, &avrcp_cid); 652 break; 653 case 'C': 654 if (avrcp_connected){ 655 printf(" - AVRCP Service disconnect from addr %s.\n", bd_addr_to_str(device_addr)); 656 status = avrcp_disconnect(avrcp_cid); 657 break; 658 } 659 printf("AVRCP Service already disconnected\n"); 660 break; 661 662 case 'e': 663 if (!avrcp_connected) { 664 printf(" You must first connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr)); 665 break; 666 } 667 printf(" - Connect to AVRCP Browsing Service at addr %s.\n", bd_addr_to_str(device_addr)); 668 status = avrcp_browsing_connect(device_addr, ertm_buffer, sizeof(ertm_buffer), &ertm_config, &browsing_cid); 669 break; 670 case 'E': 671 if (browsing_connected){ 672 printf(" - AVRCP Browsing Service disconnect from addr %s.\n", bd_addr_to_str(device_addr)); 673 status = avrcp_browsing_disconnect(browsing_cid); 674 break; 675 } 676 printf("AVRCP Browsing Service already disconnected\n"); 677 break; 678 case '\n': 679 case '\r': 680 break; 681 682 default: 683 if (!browsing_connected){ 684 show_usage(); 685 break; 686 } 687 688 switch (cmd) { 689 case 'I': 690 if (media_player_item_index < 0) { 691 printf("AVRCP Browsing:Get media players first\n"); 692 break; 693 } 694 printf("AVRCP Browsing:Set addressed player\n"); 695 status = avrcp_controller_set_addressed_player(avrcp_cid, media_player_items[0].player_id); 696 break; 697 case 'O': 698 if (media_player_item_index < 0) { 699 printf("AVRCP Browsing:Get media players first\n"); 700 break; 701 } 702 printf("Set browsed player\n"); 703 status = avrcp_browsing_controller_set_browsed_player(browsing_cid, media_player_items[0].player_id); 704 break; 705 case 'p': 706 printf("AVRCP Browsing: get media players\n"); 707 media_player_item_index = -1; 708 status = avrcp_browsing_controller_get_media_players(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL); 709 break; 710 case 'Q': 711 printf("AVRCP Browsing: browse folders\n"); 712 folder_index = -1; 713 status = avrcp_browsing_controller_browse_file_system(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL); 714 break; 715 case 'P': 716 printf("AVRCP Browsing: browse media items\n"); 717 avrcp_browsing_controller_browse_media(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL); 718 break; 719 case 'W': 720 printf("AVRCP Browsing: go up one level\n"); 721 status = avrcp_browsing_controller_go_up_one_level(browsing_cid); 722 folder_index = -1; 723 break; 724 case 'T': 725 if (folder_index < 0 && !parent_folder_set){ 726 printf("AVRCP Browsing: no folders available\n"); 727 break; 728 } 729 if (!parent_folder_set){ 730 parent_folder_set = 1; 731 memcpy(parent_folder_name, folders[0].name, folders[0].name_len); 732 memcpy(parent_folder_uid, folders[0].uid, 8); 733 } 734 printf("AVRCP Browsing: go down one level of %s\n", (char *)parent_folder_name); 735 status = avrcp_browsing_controller_go_down_one_level(browsing_cid, parent_folder_uid); 736 folder_index = -1; 737 break; 738 default: 739 show_usage(); 740 break; 741 } 742 break; 743 } 744 745 if (status != ERROR_CODE_SUCCESS){ 746 printf("AVRCP Browsing: Could not perform command, status 0x%2x\n", status); 747 } 748 } 749 #endif 750 /* EXAMPLE_END */ 751