xref: /btstack/example/avrcp_browsing_client.c (revision 98f1394d9d4c33f501ec5dcff54d145a92013c5e)
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