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, sdp_create_service_record_handle(), AVDTP_SINK_FEATURE_MASK_HEADPHONE, NULL, NULL); 295 btstack_assert(de_get_len( sdp_avdtp_sink_service_buffer) <= sizeof(sdp_avdtp_sink_service_buffer)); 296 sdp_register_service(sdp_avdtp_sink_service_buffer); 297 298 // Create AVRCP service record and register it with SDP. 299 memset(sdp_avrcp_browsing_controller_service_buffer, 0, sizeof(sdp_avrcp_browsing_controller_service_buffer)); 300 301 uint16_t supported_features = AVRCP_FEATURE_MASK_CATEGORY_PLAYER_OR_RECORDER; 302 #ifdef AVRCP_BROWSING_ENABLED 303 supported_features |= AVRCP_FEATURE_MASK_BROWSING; 304 #endif 305 avrcp_controller_create_sdp_record(sdp_avrcp_browsing_controller_service_buffer, sdp_create_service_record_handle(), supported_features, NULL, NULL); 306 btstack_assert(de_get_len( sdp_avrcp_browsing_controller_service_buffer) <= sizeof(sdp_avrcp_browsing_controller_service_buffer)); 307 sdp_register_service(sdp_avrcp_browsing_controller_service_buffer); 308 309 // Set local name with a template Bluetooth address, that will be automatically 310 // replaced with a actual address once it is available, i.e. when BTstack boots 311 // up and starts talking to a Bluetooth module. 312 gap_set_local_name("AVRCP Browsing Client 00:00:00:00:00:00"); 313 gap_discoverable_control(1); 314 gap_set_class_of_device(0x200408); 315 316 // Register for HCI events. 317 hci_event_callback_registration.callback = &avrcp_browsing_controller_packet_handler; 318 hci_add_event_handler(&hci_event_callback_registration); 319 320 321 #ifdef HAVE_BTSTACK_STDIN 322 // Parse human readable Bluetooth address. 323 sscanf_bd_addr(device_addr_string, device_addr); 324 btstack_stdin_setup(stdin_process); 325 #endif 326 printf("Starting BTstack ...\n"); 327 hci_power_control(HCI_POWER_ON); 328 return 0; 329 } 330 /* LISTING_END */ 331 332 static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 333 UNUSED(channel); 334 UNUSED(size); 335 uint16_t local_cid; 336 uint8_t status = 0xFF; 337 bd_addr_t adress; 338 339 if (packet_type != HCI_EVENT_PACKET) return; 340 if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return; 341 switch (packet[2]){ 342 case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: { 343 local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet); 344 status = avrcp_subevent_connection_established_get_status(packet); 345 if (status != ERROR_CODE_SUCCESS){ 346 printf("AVRCP: Connection failed, status 0x%02x\n", status); 347 avrcp_cid = 0; 348 return; 349 } 350 351 avrcp_cid = local_cid; 352 avrcp_connected = true; 353 avrcp_subevent_connection_established_get_bd_addr(packet, adress); 354 printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(adress), avrcp_cid); 355 return; 356 } 357 358 case AVRCP_SUBEVENT_CONNECTION_RELEASED: 359 printf("AVRCP: Channel released: cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet)); 360 avrcp_cid = 0; 361 avrcp_connected = false; 362 return; 363 default: 364 break; 365 } 366 } 367 368 static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 369 UNUSED(channel); 370 UNUSED(size); 371 bd_addr_t address; 372 uint8_t status; 373 374 if (packet_type != HCI_EVENT_PACKET) return; 375 if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return; 376 377 switch (packet[2]){ 378 case A2DP_SUBEVENT_STREAM_ESTABLISHED: 379 a2dp_subevent_stream_established_get_bd_addr(packet, address); 380 status = a2dp_subevent_stream_established_get_status(packet); 381 382 if (status != ERROR_CODE_SUCCESS){ 383 printf("A2DP Sink : Streaming connection failed, status 0x%02x\n", status); 384 break; 385 } 386 387 a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet); 388 memcpy(device_addr, address, 6); 389 printf("A2DP Sink: Connection established, address %s, a2dp_cid 0x%02x\n", bd_addr_to_str(address), a2dp_cid); 390 break; 391 392 case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED: 393 printf("A2DP Sink: Connection released\n"); 394 break; 395 396 default: 397 break; 398 } 399 } 400 401 402 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 403 UNUSED(channel); 404 UNUSED(size); 405 bd_addr_t address; 406 uint8_t status; 407 uint16_t pos = 0; 408 uint16_t local_cid; 409 410 // printf("avrcp_browsing_controller_packet_handler packet type 0x%02X, subevent 0x%02X\n", packet_type, packet[2]); 411 switch (packet_type) { 412 case HCI_EVENT_PACKET: 413 switch (packet[0]){ 414 case HCI_EVENT_AVRCP_META: 415 switch (packet[2]){ 416 case AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED: { 417 local_cid = avrcp_subevent_browsing_connection_established_get_browsing_cid(packet); 418 status = avrcp_subevent_browsing_connection_established_get_status(packet); 419 if (status != ERROR_CODE_SUCCESS){ 420 printf("AVRCP: Connection failed, status 0x%02x\n", status); 421 browsing_cid = 0; 422 return; 423 } 424 avrcp_subevent_browsing_connection_established_get_bd_addr(packet, address); 425 browsing_cid = local_cid; 426 browsing_connected = true; 427 printf("AVRCP Browsing: Connection established, address %s, browsing_cid 0x%02x\n", bd_addr_to_str(address), browsing_cid); 428 return; 429 } 430 431 case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED: 432 printf("AVRCP: Connection released, cid 0x%02x\n", avrcp_subevent_browsing_connection_released_get_browsing_cid(packet)); 433 browsing_cid = 0; 434 browsing_connected = false; 435 return; 436 case AVRCP_SUBEVENT_BROWSING_DONE: 437 438 browsing_query_active = 0; 439 browsing_uid_counter = 0; 440 if (avrcp_subevent_browsing_done_get_browsing_status(packet) != AVRCP_BROWSING_ERROR_CODE_SUCCESS){ 441 printf("AVRCP Browsing query done with browsing status 0x%02x, bluetooth status 0x%02x.\n", 442 avrcp_subevent_browsing_done_get_browsing_status(packet), 443 avrcp_subevent_browsing_done_get_bluetooth_status(packet)); 444 return; 445 } 446 browsing_uid_counter = avrcp_subevent_browsing_done_get_uid_counter(packet); 447 printf("DONE, browsing_uid_counter %d.\n", browsing_uid_counter); 448 449 switch (browsing_state){ 450 case AVRCP_BROWSING_STATE_W4_GET_PLAYERS: 451 if (media_player_item_index < 0) { 452 printf("Get media players first\n"); 453 break; 454 } 455 printf("Set browsed player\n"); 456 browsing_state = AVRCP_BROWSING_STATE_W4_SET_PLAYER; 457 status = avrcp_browsing_controller_set_browsed_player(browsing_cid, media_player_items[0].player_id); 458 if (status != ERROR_CODE_SUCCESS){ 459 printf("Could not set player, status 0x%02x\n", status); 460 status = AVRCP_BROWSING_STATE_W4_GET_PLAYERS; 461 break; 462 } 463 break; 464 case AVRCP_BROWSING_STATE_W4_SET_PLAYER: 465 browsing_state = AVRCP_BROWSING_STATE_READY; 466 break; 467 default: 468 break; 469 } 470 break; 471 default: 472 break; 473 } 474 475 default: 476 break; 477 } 478 break; 479 480 case AVRCP_BROWSING_DATA_PACKET: 481 browsing_query_active = 1; 482 avrcp_browsing_item_type_t data_type = (avrcp_browsing_item_type_t)packet[pos++]; 483 484 switch (data_type){ 485 case AVRCP_BROWSING_MEDIA_ROOT_FOLDER:{ 486 uint16_t folder_name_length = size - pos; 487 char folder_name[AVRCP_MAX_FOLDER_NAME_SIZE]; 488 memcpy(folder_name, &packet[pos], folder_name_length); 489 folder_name[folder_name_length] = 0; 490 printf("Found root folder: name %s \n", folder_name); 491 break; 492 } 493 494 case AVRCP_BROWSING_FOLDER_ITEM:{ 495 int index = next_folder_index(); 496 memcpy(folders[index].uid, packet+pos, 8); 497 498 uint32_t folder_uid_high = big_endian_read_32(packet, pos); 499 pos += 4; 500 uint32_t folder_uid_low = big_endian_read_32(packet, pos); 501 pos += 4; 502 avrcp_browsing_folder_type_t folder_type = packet[pos++]; 503 uint8_t is_playable = packet[pos++]; 504 uint16_t charset = big_endian_read_16(packet, pos); 505 pos += 2; 506 uint16_t displayable_name_length = big_endian_read_16(packet, pos); 507 pos += 2; 508 509 char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 510 memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN); 511 uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1); 512 memcpy(value, packet+pos, value_len); 513 514 printf("Folder UID 0x%08" PRIx32 "%08" PRIx32 ", type 0x%02x, is_playable %d, charset 0x%02x, name %s\n", 515 folder_uid_high, folder_uid_low, folder_type, is_playable, charset, value); 516 if (is_playable){ 517 playable_folder_index = index; 518 } 519 memcpy(folders[index].name, value, value_len); 520 folders[index].name_len = value_len; 521 break; 522 } 523 524 case AVRCP_BROWSING_MEDIA_PLAYER_ITEM:{ 525 printf("Received media player item: "); 526 uint16_t player_id = big_endian_read_16(packet, pos); 527 pos += 2; 528 avrcp_browsing_media_player_major_type_t major_type = packet[pos++]; 529 avrcp_browsing_media_player_subtype_t subtype = big_endian_read_32(packet, pos); 530 pos += 4; 531 status = packet[pos++]; 532 uint8_t feature_bitmask[16]; 533 memcpy(feature_bitmask, packet, 16); 534 pos += 16; 535 printf("player ID 0x%04x, major_type %d, subtype %d, status 0x%02x\n", player_id, major_type, subtype, status); 536 media_player_items[next_media_player_item_index()].player_id = player_id; 537 break; 538 } 539 540 case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM:{ 541 int index = next_media_element_item_index(); 542 memcpy(media_element_items[index].uid, packet+pos, 8); 543 printf("Received media element item UID (index %d): ", index); 544 545 // uint32_t media_uid_high = big_endian_read_32(packet, pos); 546 pos += 4; 547 // uint32_t media_uid_low = big_endian_read_32(packet, pos+4); 548 pos += 4; 549 550 avrcp_browsing_media_type_t media_type = packet[pos++]; 551 uint16_t charset = big_endian_read_16(packet, pos); 552 pos += 2; 553 uint16_t displayable_name_length = big_endian_read_16(packet, pos); 554 pos += 2; 555 556 char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN]; 557 memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN); 558 uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1); 559 memcpy(value, packet+pos, value_len); 560 memcpy(media_element_items[index].name, value, value_len); 561 562 pos += displayable_name_length; 563 // 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); 564 565 printf_hexdump(media_element_items[index].uid, 8); 566 uint8_t num_attributes = packet[pos++]; 567 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); 568 569 avrcp_media_item_context_t media_item_context; 570 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)){ 571 uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context); 572 uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context); 573 uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context); 574 const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context); 575 576 memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN); 577 value_len = btstack_min(attr_value_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1); 578 memcpy(value, attr_value, value_len); 579 580 printf(" - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, value_len, value); 581 } 582 break; 583 } 584 585 case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE:{ 586 uint8_t num_attributes = packet[pos++]; 587 printf("Num media attributes %d:\n", num_attributes); 588 avrcp_media_item_context_t media_item_context; 589 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)){ 590 uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context); 591 uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context); 592 uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context); 593 const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context); 594 printf(" - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, attr_value_length, attr_value); 595 } 596 break; 597 } 598 default: 599 printf("AVRCP browsing: unknown browsable item type 0%02x\n", data_type); 600 break; 601 } 602 break; 603 default: 604 break; 605 } 606 } 607 608 #ifdef HAVE_BTSTACK_STDIN 609 static void show_usage(void){ 610 bd_addr_t iut_address; 611 gap_local_bd_addr(iut_address); 612 printf("\n--- Bluetooth AVRCP Browsing Service Test Console %s ---\n", bd_addr_to_str(iut_address)); 613 printf("c - AVRCP Service create connection to addr %s\n", bd_addr_to_str(device_addr)); 614 printf("C - AVRCP Service disconnect\n"); 615 printf("e - AVRCP Browsing Service create connection to addr %s\n", bd_addr_to_str(device_addr)); 616 printf("E - AVRCP Browsing Service disconnect\n"); 617 618 printf("I - Set first found player as addressed player\n"); 619 printf("O - Set first found player as browsed player\n"); 620 621 printf("p - Get media players\n"); 622 printf("Q - Browse folders\n"); 623 printf("P - Go up one level\n"); 624 printf("W - Go down one level\n"); 625 printf("T - Browse media items\n"); 626 printf("---\n"); 627 } 628 #endif 629 630 631 #ifdef HAVE_BTSTACK_STDIN 632 static void stdin_process(char cmd){ 633 uint8_t status = ERROR_CODE_SUCCESS; 634 635 if (cmd != 'a' && cmd != 'A' && cmd != 'c' && cmd != 'C'){ 636 if (browsing_query_active){ 637 printf("Query active, try later!\n"); 638 return; 639 } 640 } 641 642 switch (cmd){ 643 case 'b': 644 status = a2dp_sink_establish_stream(device_addr, &a2dp_cid); 645 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); 646 break; 647 case 'B': 648 printf(" - AVDTP disconnect from addr %s.\n", bd_addr_to_str(device_addr)); 649 a2dp_sink_disconnect(a2dp_cid); 650 break; 651 652 case 'c': 653 printf(" - Connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr)); 654 status = avrcp_connect(device_addr, &avrcp_cid); 655 break; 656 case 'C': 657 if (avrcp_connected){ 658 printf(" - AVRCP Service disconnect from addr %s.\n", bd_addr_to_str(device_addr)); 659 status = avrcp_disconnect(avrcp_cid); 660 break; 661 } 662 printf("AVRCP Service already disconnected\n"); 663 break; 664 665 case 'e': 666 if (!avrcp_connected) { 667 printf(" You must first connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr)); 668 break; 669 } 670 printf(" - Connect to AVRCP Browsing Service at addr %s.\n", bd_addr_to_str(device_addr)); 671 status = avrcp_browsing_connect(device_addr, ertm_buffer, sizeof(ertm_buffer), &ertm_config, &browsing_cid); 672 break; 673 case 'E': 674 if (browsing_connected){ 675 printf(" - AVRCP Browsing Service disconnect from addr %s.\n", bd_addr_to_str(device_addr)); 676 status = avrcp_browsing_disconnect(browsing_cid); 677 break; 678 } 679 printf("AVRCP Browsing Service already disconnected\n"); 680 break; 681 case '\n': 682 case '\r': 683 break; 684 685 default: 686 if (!browsing_connected){ 687 show_usage(); 688 break; 689 } 690 691 switch (cmd) { 692 case 'I': 693 if (media_player_item_index < 0) { 694 printf("AVRCP Browsing:Get media players first\n"); 695 break; 696 } 697 printf("AVRCP Browsing:Set addressed player\n"); 698 status = avrcp_controller_set_addressed_player(avrcp_cid, media_player_items[0].player_id); 699 break; 700 case 'O': 701 if (media_player_item_index < 0) { 702 printf("AVRCP Browsing:Get media players first\n"); 703 break; 704 } 705 printf("Set browsed player\n"); 706 status = avrcp_browsing_controller_set_browsed_player(browsing_cid, media_player_items[0].player_id); 707 break; 708 case 'p': 709 printf("AVRCP Browsing: get media players\n"); 710 media_player_item_index = -1; 711 status = avrcp_browsing_controller_get_media_players(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL); 712 break; 713 case 'Q': 714 printf("AVRCP Browsing: browse folders\n"); 715 folder_index = -1; 716 status = avrcp_browsing_controller_browse_file_system(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL); 717 break; 718 case 'P': 719 printf("AVRCP Browsing: browse media items\n"); 720 avrcp_browsing_controller_browse_media(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL); 721 break; 722 case 'W': 723 printf("AVRCP Browsing: go up one level\n"); 724 status = avrcp_browsing_controller_go_up_one_level(browsing_cid); 725 folder_index = -1; 726 break; 727 case 'T': 728 if (folder_index < 0 && !parent_folder_set){ 729 printf("AVRCP Browsing: no folders available\n"); 730 break; 731 } 732 if (!parent_folder_set){ 733 parent_folder_set = 1; 734 memcpy(parent_folder_name, folders[0].name, folders[0].name_len); 735 memcpy(parent_folder_uid, folders[0].uid, 8); 736 } 737 printf("AVRCP Browsing: go down one level of %s\n", (char *)parent_folder_name); 738 status = avrcp_browsing_controller_go_down_one_level(browsing_cid, parent_folder_uid); 739 folder_index = -1; 740 break; 741 default: 742 show_usage(); 743 break; 744 } 745 break; 746 } 747 748 if (status != ERROR_CODE_SUCCESS){ 749 printf("AVRCP Browsing: Could not perform command, status 0x%2x\n", status); 750 } 751 } 752 #endif 753 /* EXAMPLE_END */ 754