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