xref: /btstack/example/avrcp_browsing_client.c (revision 5666fff44089744800be537861a711f7a8fb725e)
1462aa085SMilanka Ringwald /*
2462aa085SMilanka Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3462aa085SMilanka Ringwald  *
4462aa085SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5462aa085SMilanka Ringwald  * modification, are permitted provided that the following conditions
6462aa085SMilanka Ringwald  * are met:
7462aa085SMilanka Ringwald  *
8462aa085SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9462aa085SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10462aa085SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11462aa085SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12462aa085SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13462aa085SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14462aa085SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15462aa085SMilanka Ringwald  *    from this software without specific prior written permission.
16462aa085SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17462aa085SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18462aa085SMilanka Ringwald  *    monetary gain.
19462aa085SMilanka Ringwald  *
20462aa085SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21462aa085SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22462aa085SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23462aa085SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24462aa085SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25462aa085SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26462aa085SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27462aa085SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28462aa085SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29462aa085SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30462aa085SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31462aa085SMilanka Ringwald  * SUCH DAMAGE.
32462aa085SMilanka Ringwald  *
33462aa085SMilanka Ringwald  * Please inquire about commercial licensing options at
34462aa085SMilanka Ringwald  * [email protected]
35462aa085SMilanka Ringwald  *
36462aa085SMilanka Ringwald  */
37462aa085SMilanka Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avrcp_browsing_client.c"
39462aa085SMilanka Ringwald 
40462aa085SMilanka Ringwald /*
41462aa085SMilanka Ringwald  * avrcp_browsing_client.c
42462aa085SMilanka Ringwald  */
43462aa085SMilanka Ringwald 
44462aa085SMilanka Ringwald // *****************************************************************************
45462aa085SMilanka Ringwald /* EXAMPLE_START(avrcp_browsing_client): Browse media players and media information on a remote device.
46462aa085SMilanka Ringwald  *
47462aa085SMilanka Ringwald  * @text This example demonstrates how to use the AVRCP Controller Browsing service to
48462aa085SMilanka Ringwald  * browse madia players and media information on a remote AVRCP Source device.
49462aa085SMilanka Ringwald  *
5069f3ffd7SMilanka Ringwald  * @text To test with a remote device, e.g. a mobile phone,
5169f3ffd7SMilanka Ringwald  * pair from the remote device with the demo, then use the UI for browsing. If HAVE_BTSTACK_STDIN is set,
5269f3ffd7SMilanka Ringwald  * press SPACE on the console to show the available AVDTP and AVRCP commands.
53462aa085SMilanka Ringwald  *
54462aa085SMilanka Ringwald  */
55462aa085SMilanka Ringwald // *****************************************************************************
56462aa085SMilanka Ringwald 
57462aa085SMilanka Ringwald #include <stdint.h>
58954cc391SMilanka Ringwald #include <inttypes.h>
59462aa085SMilanka Ringwald #include <stdio.h>
60462aa085SMilanka Ringwald #include <stdlib.h>
61462aa085SMilanka Ringwald #include <string.h>
62462aa085SMilanka Ringwald 
63462aa085SMilanka Ringwald #include "btstack.h"
64462aa085SMilanka Ringwald 
65462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
66462aa085SMilanka Ringwald #include "btstack_stdin.h"
67462aa085SMilanka Ringwald #endif
68462aa085SMilanka Ringwald 
694f0111ebSMilanka Ringwald #define AVRCP_BROWSING_ENABLED
704f0111ebSMilanka Ringwald 
71db79553aSMilanka Ringwald #define AVRCP_BROWSING_MAX_PLAYERS                  10
72db79553aSMilanka Ringwald #define AVRCP_BROWSING_MAX_FOLDERS                  10
73*5666fff4SMilanka Ringwald #define AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN  30
74*5666fff4SMilanka Ringwald #define AVRCP_BROWSING_MAX_MEDIA_ITEMS              10
75db79553aSMilanka Ringwald 
76462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
77462aa085SMilanka Ringwald // mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
78462aa085SMilanka Ringwald // pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
79462aa085SMilanka Ringwald // mac 2013:
80462aa085SMilanka Ringwald // static const char * device_addr_string = "84:38:35:65:d1:15";
81462aa085SMilanka Ringwald // iPhone 5S: static const char * device_addr_string = "54:E4:3A:26:A2:39";
82462aa085SMilanka Ringwald // phone 2013:
83143efbe8SMilanka Ringwald // static const char * device_addr_string = "B0:34:95:CB:97:C4";
8402d2f9caSMilanka Ringwald // iPod
850eebc132SMilanka Ringwald // static const char * device_addr_string = "B0:34:95:CB:97:C4";
860eebc132SMilanka Ringwald // iPhone
870eebc132SMilanka Ringwald static const char * device_addr_string = "6C:72:E7:10:22:EE";
88143efbe8SMilanka Ringwald 
89462aa085SMilanka Ringwald static bd_addr_t device_addr;
90462aa085SMilanka Ringwald #endif
91462aa085SMilanka Ringwald 
92*5666fff4SMilanka Ringwald typedef enum {
93*5666fff4SMilanka Ringwald     AVRCP_BROWSING_STATE_IDLE,
94*5666fff4SMilanka Ringwald     AVRCP_BROWSING_STATE_W4_GET_PLAYERS,
95*5666fff4SMilanka Ringwald     AVRCP_BROWSING_STATE_W4_SET_PLAYER,
96*5666fff4SMilanka Ringwald     AVRCP_BROWSING_STATE_READY
97*5666fff4SMilanka Ringwald } avrcp_browsing_state_t;
98954cc391SMilanka Ringwald 
99db79553aSMilanka Ringwald typedef struct {
100db79553aSMilanka Ringwald     uint16_t  charset;
101db79553aSMilanka Ringwald     uint8_t   depth;
102db79553aSMilanka Ringwald     uint16_t  name_len;
103*5666fff4SMilanka Ringwald     char      name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
104db79553aSMilanka Ringwald } avrcp_browsing_root_folder_t;
105db79553aSMilanka Ringwald 
106db79553aSMilanka Ringwald typedef struct {
107db79553aSMilanka Ringwald     uint8_t  uid[8];
108db79553aSMilanka Ringwald     uint16_t name_len;
109*5666fff4SMilanka Ringwald     char     name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
110*5666fff4SMilanka Ringwald } avrcp_browsable_item_t;
111*5666fff4SMilanka Ringwald 
112*5666fff4SMilanka Ringwald typedef struct {
113*5666fff4SMilanka Ringwald     uint16_t player_id;
114*5666fff4SMilanka Ringwald     uint8_t  major_player_type;
115*5666fff4SMilanka Ringwald     uint32_t player_sub_type;
116*5666fff4SMilanka Ringwald     uint8_t  play_status;
117*5666fff4SMilanka Ringwald     uint8_t  feature_bitmask[16];
118*5666fff4SMilanka Ringwald     uint16_t charset;
119*5666fff4SMilanka Ringwald     uint16_t name_len;
120*5666fff4SMilanka Ringwald     char     name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
121*5666fff4SMilanka Ringwald } avrcp_browsable_media_player_item_t;
122*5666fff4SMilanka Ringwald 
123*5666fff4SMilanka Ringwald typedef struct {
124*5666fff4SMilanka Ringwald     uint32_t id;
125*5666fff4SMilanka Ringwald     uint16_t charset;
126*5666fff4SMilanka Ringwald     uint16_t value_len;
127*5666fff4SMilanka Ringwald     char     value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
128*5666fff4SMilanka Ringwald } avrcp_browsable_media_element_item_attribute_t;
129*5666fff4SMilanka Ringwald 
130*5666fff4SMilanka Ringwald typedef struct {
131*5666fff4SMilanka Ringwald     uint8_t  uid[8];
132*5666fff4SMilanka Ringwald     uint8_t  media_type;
133*5666fff4SMilanka Ringwald     uint16_t charset;
134*5666fff4SMilanka Ringwald     uint16_t name_len;
135*5666fff4SMilanka Ringwald     char     name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
136*5666fff4SMilanka Ringwald     uint8_t  num_attributes;
137*5666fff4SMilanka Ringwald } avrcp_browsable_media_element_item_t;
138*5666fff4SMilanka Ringwald 
139*5666fff4SMilanka Ringwald static avrcp_browsing_state_t browsing_state = AVRCP_BROWSING_STATE_IDLE;
140*5666fff4SMilanka Ringwald static uint16_t avrcp_cid = 0;
141*5666fff4SMilanka Ringwald static bool     avrcp_connected = false;
142*5666fff4SMilanka Ringwald 
143*5666fff4SMilanka Ringwald static uint16_t browsing_cid = 0;
144*5666fff4SMilanka Ringwald static bool     browsing_connected = false;
145*5666fff4SMilanka Ringwald 
146*5666fff4SMilanka Ringwald static uint8_t  sdp_avrcp_browsing_controller_service_buffer[200];
147*5666fff4SMilanka Ringwald static uint8_t  sdp_avdtp_sink_service_buffer[150];
148*5666fff4SMilanka Ringwald 
149*5666fff4SMilanka Ringwald static uint16_t a2dp_cid = 0;
150*5666fff4SMilanka Ringwald static uint8_t  a2dp_local_seid = 0;
151*5666fff4SMilanka Ringwald 
152*5666fff4SMilanka Ringwald static uint8_t media_sbc_codec_capabilities[] = {
153*5666fff4SMilanka Ringwald     0xFF,//(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
154*5666fff4SMilanka Ringwald     0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
155*5666fff4SMilanka Ringwald     2, 53
156*5666fff4SMilanka Ringwald };
157*5666fff4SMilanka Ringwald 
158*5666fff4SMilanka Ringwald static uint8_t media_sbc_codec_configuration[] = {
159*5666fff4SMilanka Ringwald     (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
160*5666fff4SMilanka Ringwald     (AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
161*5666fff4SMilanka Ringwald     2, 53
162*5666fff4SMilanka Ringwald };
163*5666fff4SMilanka Ringwald 
164*5666fff4SMilanka Ringwald static bool     browsing_query_active = false;
165*5666fff4SMilanka Ringwald // static avrcp_media_item_context_t media_item_context;
166*5666fff4SMilanka Ringwald 
167*5666fff4SMilanka Ringwald static int playable_folder_index = 0;
168*5666fff4SMilanka Ringwald 
169*5666fff4SMilanka Ringwald 
170*5666fff4SMilanka Ringwald static uint16_t browsing_uid_counter = 0;
171db79553aSMilanka Ringwald 
172db79553aSMilanka Ringwald static uint8_t  parent_folder_set = 0;
173db79553aSMilanka Ringwald static uint8_t  parent_folder_uid[8];
174*5666fff4SMilanka Ringwald static char     parent_folder_name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
175*5666fff4SMilanka Ringwald 
176*5666fff4SMilanka Ringwald static avrcp_browsable_item_t folders[AVRCP_BROWSING_MAX_FOLDERS];
177db79553aSMilanka Ringwald static int folder_index = -1;
178*5666fff4SMilanka Ringwald 
179*5666fff4SMilanka Ringwald static avrcp_browsable_media_element_item_t media_element_items[AVRCP_BROWSING_MAX_MEDIA_ITEMS];
180*5666fff4SMilanka Ringwald static int media_element_item_index = -1;
181*5666fff4SMilanka Ringwald 
182*5666fff4SMilanka Ringwald static avrcp_browsable_media_player_item_t media_player_items[AVRCP_BROWSING_MAX_MEDIA_ITEMS];
183*5666fff4SMilanka Ringwald static int media_player_item_index = -1;
184db79553aSMilanka Ringwald 
185462aa085SMilanka Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
186462aa085SMilanka Ringwald 
187462aa085SMilanka Ringwald static uint8_t ertm_buffer[10000];
188462aa085SMilanka Ringwald static l2cap_ertm_config_t ertm_config = {
189462aa085SMilanka Ringwald     1,  // ertm mandatory
190462aa085SMilanka Ringwald     2,  // max transmit, some tests require > 1
191462aa085SMilanka Ringwald     2000,
192462aa085SMilanka Ringwald     12000,
193462aa085SMilanka Ringwald     144,    // l2cap ertm mtu
194462aa085SMilanka Ringwald     4,
195462aa085SMilanka Ringwald     4,
196c425ea4aSMatthias Ringwald     0,      // No FCS
197462aa085SMilanka Ringwald };
198462aa085SMilanka Ringwald 
199*5666fff4SMilanka Ringwald 
200db79553aSMilanka Ringwald static inline int next_index(int * index, int max_value){
201db79553aSMilanka Ringwald     if ((*index) < max_value){
202db79553aSMilanka Ringwald         (*index)++;
203db79553aSMilanka Ringwald     } else {
204db79553aSMilanka Ringwald         (*index) = 0;
205db79553aSMilanka Ringwald     }
206db79553aSMilanka Ringwald     return (*index);
207db79553aSMilanka Ringwald }
208db79553aSMilanka Ringwald 
209*5666fff4SMilanka Ringwald static int next_folder_index(){
210db79553aSMilanka Ringwald     return next_index(&folder_index, AVRCP_BROWSING_MAX_FOLDERS);
211db79553aSMilanka Ringwald }
212db79553aSMilanka Ringwald 
213*5666fff4SMilanka Ringwald static int next_media_element_item_index(){
214*5666fff4SMilanka Ringwald     return next_index(&media_element_item_index, AVRCP_BROWSING_MAX_MEDIA_ITEMS);
215db79553aSMilanka Ringwald }
216*5666fff4SMilanka Ringwald static int next_media_player_item_index(){
217*5666fff4SMilanka Ringwald     return next_index(&media_player_item_index, AVRCP_BROWSING_MAX_MEDIA_ITEMS);
218*5666fff4SMilanka Ringwald }
219db79553aSMilanka Ringwald 
220462aa085SMilanka Ringwald /* @section Main Application Setup
221462aa085SMilanka Ringwald  *
222462aa085SMilanka Ringwald  * @text The Listing MainConfiguration shows how to setup AVRCP Controller Browsing service.
223462aa085SMilanka Ringwald  * To announce AVRCP Controller Browsing service, you need to create corresponding
224462aa085SMilanka Ringwald  * SDP record and register it with the SDP service.
225462aa085SMilanka Ringwald  * You'll also need to register several packet handlers:
226462aa085SMilanka Ringwald  * - stdin_process callback - used to trigger AVRCP commands, such are get media players, playlists, albums, etc. Requires HAVE_BTSTACK_STDIN.
227*5666fff4SMilanka Ringwald  * - avrcp_browsing_controller_packet_handler - used to receive answers for AVRCP commands.
228462aa085SMilanka Ringwald  *
229462aa085SMilanka Ringwald  */
230462aa085SMilanka Ringwald 
231462aa085SMilanka Ringwald /* LISTING_START(MainConfiguration): Setup Audio Sink and AVRCP Controller services */
232*5666fff4SMilanka Ringwald static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
23302d2f9caSMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
234*5666fff4SMilanka Ringwald static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
23502d2f9caSMilanka Ringwald 
236462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
237462aa085SMilanka Ringwald static void stdin_process(char cmd);
238462aa085SMilanka Ringwald #endif
239462aa085SMilanka Ringwald 
240462aa085SMilanka Ringwald 
241462aa085SMilanka Ringwald int btstack_main(int argc, const char * argv[]);
242462aa085SMilanka Ringwald int btstack_main(int argc, const char * argv[]){
243462aa085SMilanka Ringwald     (void)argc;
244462aa085SMilanka Ringwald     (void)argv;
245462aa085SMilanka Ringwald 
246462aa085SMilanka Ringwald     // Initialize L2CAP.
247462aa085SMilanka Ringwald     l2cap_init();
248462aa085SMilanka Ringwald 
249*5666fff4SMilanka Ringwald     a2dp_sink_init();
250*5666fff4SMilanka Ringwald     a2dp_sink_register_packet_handler(&a2dp_sink_packet_handler);
251*5666fff4SMilanka Ringwald 
252*5666fff4SMilanka Ringwald     avdtp_stream_endpoint_t * local_stream_endpoint = a2dp_sink_create_stream_endpoint(AVDTP_AUDIO,
253*5666fff4SMilanka Ringwald         AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities),
254*5666fff4SMilanka Ringwald         media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration));
255*5666fff4SMilanka Ringwald     if (!local_stream_endpoint){
256*5666fff4SMilanka Ringwald         printf("A2DP Sink: not enough memory to create local stream endpoint\n");
257*5666fff4SMilanka Ringwald         return 1;
258*5666fff4SMilanka Ringwald     }
259*5666fff4SMilanka Ringwald     a2dp_local_seid = avdtp_local_seid(local_stream_endpoint);
260*5666fff4SMilanka Ringwald 
26119691e0aSMilanka Ringwald     // Initialize AVRCP service.
26219691e0aSMilanka Ringwald     avrcp_init();
26302d2f9caSMilanka Ringwald     // Initialize AVRCP Controller & Target Service.
264462aa085SMilanka Ringwald     avrcp_controller_init();
26502d2f9caSMilanka Ringwald     avrcp_target_init();
26602d2f9caSMilanka Ringwald 
26702d2f9caSMilanka Ringwald     avrcp_register_packet_handler(&avrcp_packet_handler);
26802d2f9caSMilanka Ringwald     avrcp_controller_register_packet_handler(&avrcp_packet_handler);
26902d2f9caSMilanka Ringwald     avrcp_target_register_packet_handler(&avrcp_packet_handler);
270462aa085SMilanka Ringwald 
2710eebc132SMilanka Ringwald     // Initialize AVRCP Browsing Service.
2720eebc132SMilanka Ringwald     avrcp_browsing_init();
273462aa085SMilanka Ringwald     avrcp_browsing_controller_init();
2740eebc132SMilanka Ringwald     avrcp_browsing_target_init();
2750eebc132SMilanka Ringwald 
2760eebc132SMilanka Ringwald     // Register for HCI events.
277*5666fff4SMilanka Ringwald     avrcp_browsing_controller_register_packet_handler(&avrcp_browsing_controller_packet_handler);
278*5666fff4SMilanka Ringwald     avrcp_browsing_target_register_packet_handler(&avrcp_browsing_controller_packet_handler);
279*5666fff4SMilanka Ringwald     avrcp_browsing_register_packet_handler(&avrcp_browsing_controller_packet_handler);
280462aa085SMilanka Ringwald 
281462aa085SMilanka Ringwald     // Initialize SDP.
282462aa085SMilanka Ringwald     sdp_init();
283*5666fff4SMilanka Ringwald     // setup AVDTP sink
284*5666fff4SMilanka Ringwald     memset(sdp_avdtp_sink_service_buffer, 0, sizeof(sdp_avdtp_sink_service_buffer));
285*5666fff4SMilanka Ringwald     a2dp_sink_create_sdp_record(sdp_avdtp_sink_service_buffer, 0x10001, AVDTP_SINK_FEATURE_MASK_HEADPHONE, NULL, NULL);
286*5666fff4SMilanka Ringwald     sdp_register_service(sdp_avdtp_sink_service_buffer);
287462aa085SMilanka Ringwald 
288462aa085SMilanka Ringwald     // Create AVRCP service record and register it with SDP.
289462aa085SMilanka Ringwald     memset(sdp_avrcp_browsing_controller_service_buffer, 0, sizeof(sdp_avrcp_browsing_controller_service_buffer));
29011014891SMilanka Ringwald 
291e2f25417SMilanka Ringwald     uint16_t supported_features = AVRCP_FEATURE_MASK_CATEGORY_PLAYER_OR_RECORDER;
2924f0111ebSMilanka Ringwald #ifdef AVRCP_BROWSING_ENABLED
293e2f25417SMilanka Ringwald     supported_features |= AVRCP_FEATURE_MASK_BROWSING;
2944f0111ebSMilanka Ringwald #endif
295*5666fff4SMilanka Ringwald     avrcp_controller_create_sdp_record(sdp_avrcp_browsing_controller_service_buffer, 0x10002, supported_features, NULL, NULL);
296462aa085SMilanka Ringwald     sdp_register_service(sdp_avrcp_browsing_controller_service_buffer);
297462aa085SMilanka Ringwald 
298462aa085SMilanka Ringwald     // Set local name with a template Bluetooth address, that will be automatically
299462aa085SMilanka Ringwald     // replaced with a actual address once it is available, i.e. when BTstack boots
300462aa085SMilanka Ringwald     // up and starts talking to a Bluetooth module.
301462aa085SMilanka Ringwald     gap_set_local_name("AVRCP Browsing Client 00:00:00:00:00:00");
302462aa085SMilanka Ringwald     gap_discoverable_control(1);
303462aa085SMilanka Ringwald     gap_set_class_of_device(0x200408);
304462aa085SMilanka Ringwald 
305a4fe6467SMatthias Ringwald     // Register for HCI events.
306*5666fff4SMilanka Ringwald     hci_event_callback_registration.callback = &avrcp_browsing_controller_packet_handler;
307a4fe6467SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
308a4fe6467SMatthias Ringwald 
309a4fe6467SMatthias Ringwald 
310462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
311462aa085SMilanka Ringwald     // Parse human readable Bluetooth address.
312462aa085SMilanka Ringwald     sscanf_bd_addr(device_addr_string, device_addr);
313462aa085SMilanka Ringwald     btstack_stdin_setup(stdin_process);
314462aa085SMilanka Ringwald #endif
315462aa085SMilanka Ringwald     printf("Starting BTstack ...\n");
316462aa085SMilanka Ringwald     hci_power_control(HCI_POWER_ON);
317462aa085SMilanka Ringwald     return 0;
318462aa085SMilanka Ringwald }
319462aa085SMilanka Ringwald /* LISTING_END */
320462aa085SMilanka Ringwald 
32102d2f9caSMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
32202d2f9caSMilanka Ringwald     UNUSED(channel);
32302d2f9caSMilanka Ringwald     UNUSED(size);
32402d2f9caSMilanka Ringwald     uint16_t local_cid;
32502d2f9caSMilanka Ringwald     uint8_t  status = 0xFF;
32602d2f9caSMilanka Ringwald     bd_addr_t adress;
32702d2f9caSMilanka Ringwald 
32802d2f9caSMilanka Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
32902d2f9caSMilanka Ringwald     if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
33002d2f9caSMilanka Ringwald     switch (packet[2]){
33102d2f9caSMilanka Ringwald         case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
33202d2f9caSMilanka Ringwald             local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
33302d2f9caSMilanka Ringwald             status = avrcp_subevent_connection_established_get_status(packet);
33402d2f9caSMilanka Ringwald             if (status != ERROR_CODE_SUCCESS){
33502d2f9caSMilanka Ringwald                 printf("AVRCP: Connection failed: status 0x%02x\n", status);
33602d2f9caSMilanka Ringwald                 avrcp_cid = 0;
33702d2f9caSMilanka Ringwald                 return;
33802d2f9caSMilanka Ringwald             }
33902d2f9caSMilanka Ringwald 
34002d2f9caSMilanka Ringwald             avrcp_cid = local_cid;
341ace5ab2aSMilanka Ringwald             avrcp_connected = true;
34202d2f9caSMilanka Ringwald             avrcp_subevent_connection_established_get_bd_addr(packet, adress);
34302d2f9caSMilanka Ringwald             printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(adress), avrcp_cid);
34402d2f9caSMilanka Ringwald             return;
34502d2f9caSMilanka Ringwald         }
34602d2f9caSMilanka Ringwald 
34702d2f9caSMilanka Ringwald         case AVRCP_SUBEVENT_CONNECTION_RELEASED:
34802d2f9caSMilanka Ringwald             printf("AVRCP: Channel released: cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
34902d2f9caSMilanka Ringwald             avrcp_cid = 0;
350ace5ab2aSMilanka Ringwald             avrcp_connected = false;
35102d2f9caSMilanka Ringwald             return;
35202d2f9caSMilanka Ringwald         default:
35302d2f9caSMilanka Ringwald             break;
35402d2f9caSMilanka Ringwald     }
35502d2f9caSMilanka Ringwald }
356462aa085SMilanka Ringwald 
357*5666fff4SMilanka Ringwald static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
358*5666fff4SMilanka Ringwald     UNUSED(channel);
359*5666fff4SMilanka Ringwald     UNUSED(size);
360*5666fff4SMilanka Ringwald     bd_addr_t address;
361*5666fff4SMilanka Ringwald     uint8_t status;
362*5666fff4SMilanka Ringwald 
363*5666fff4SMilanka Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
364*5666fff4SMilanka Ringwald     if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return;
365*5666fff4SMilanka Ringwald 
366*5666fff4SMilanka Ringwald     switch (packet[2]){
367*5666fff4SMilanka Ringwald         case A2DP_SUBEVENT_STREAM_ESTABLISHED:
368*5666fff4SMilanka Ringwald             a2dp_subevent_stream_established_get_bd_addr(packet, address);
369*5666fff4SMilanka Ringwald             status = a2dp_subevent_stream_established_get_status(packet);
370*5666fff4SMilanka Ringwald 
371*5666fff4SMilanka Ringwald             if (status){
372*5666fff4SMilanka Ringwald                 printf("A2DP  Sink      : Streaming connection failed, status 0x%02x\n", status);
373*5666fff4SMilanka Ringwald                 break;
374*5666fff4SMilanka Ringwald             }
375*5666fff4SMilanka Ringwald 
376*5666fff4SMilanka Ringwald             a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet);
377*5666fff4SMilanka Ringwald             memcpy(device_addr, address, 6);
378*5666fff4SMilanka Ringwald             printf("A2DP  Sink: Connection established, address %s, a2dp_cid 0x%02x\n", bd_addr_to_str(address), a2dp_cid);
379*5666fff4SMilanka Ringwald             break;
380*5666fff4SMilanka Ringwald 
381*5666fff4SMilanka Ringwald         case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
382*5666fff4SMilanka Ringwald             printf("A2DP  Sink: Connection released\n");
383*5666fff4SMilanka Ringwald             break;
384*5666fff4SMilanka Ringwald 
385*5666fff4SMilanka Ringwald         default:
386*5666fff4SMilanka Ringwald             break;
387*5666fff4SMilanka Ringwald     }
388*5666fff4SMilanka Ringwald }
389*5666fff4SMilanka Ringwald 
390*5666fff4SMilanka Ringwald 
391*5666fff4SMilanka Ringwald static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
392*5666fff4SMilanka Ringwald     UNUSED(channel);
393*5666fff4SMilanka Ringwald     UNUSED(size);
394*5666fff4SMilanka Ringwald     bd_addr_t address;
395*5666fff4SMilanka Ringwald     uint8_t  status;
396*5666fff4SMilanka Ringwald     uint16_t pos = 0;
397*5666fff4SMilanka Ringwald     uint16_t local_cid;
398*5666fff4SMilanka Ringwald 
399*5666fff4SMilanka Ringwald     // printf("avrcp_browsing_controller_packet_handler packet type 0x%02X, subevent 0x%02X\n", packet_type, packet[2]);
400954cc391SMilanka Ringwald     switch (packet_type) {
401*5666fff4SMilanka Ringwald         case HCI_EVENT_PACKET:
402*5666fff4SMilanka Ringwald             switch (packet[0]){
403*5666fff4SMilanka Ringwald                 case HCI_EVENT_AVRCP_META:
404*5666fff4SMilanka Ringwald                      switch (packet[2]){
405*5666fff4SMilanka Ringwald                         case AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED: {
406*5666fff4SMilanka Ringwald                             local_cid = avrcp_subevent_browsing_connection_established_get_browsing_cid(packet);
407*5666fff4SMilanka Ringwald                             status = avrcp_subevent_browsing_connection_established_get_status(packet);
408*5666fff4SMilanka Ringwald                             if (status != ERROR_CODE_SUCCESS){
409*5666fff4SMilanka Ringwald                                 printf("AVRCP: Connection failed: status 0x%02x\n", status);
410*5666fff4SMilanka Ringwald                                 browsing_cid = 0;
411*5666fff4SMilanka Ringwald                                 return;
412*5666fff4SMilanka Ringwald                             }
413*5666fff4SMilanka Ringwald                             avrcp_subevent_browsing_connection_established_get_bd_addr(packet, address);
414*5666fff4SMilanka Ringwald                             browsing_cid = local_cid;
415*5666fff4SMilanka Ringwald                             browsing_connected = true;
416*5666fff4SMilanka Ringwald                             printf("AVRCP Browsing: Connection established, address %s, browsing_cid 0x%02x\n", bd_addr_to_str(address), browsing_cid);
417*5666fff4SMilanka Ringwald                             return;
418*5666fff4SMilanka Ringwald                         }
419*5666fff4SMilanka Ringwald 
420*5666fff4SMilanka Ringwald                         case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED:
421*5666fff4SMilanka Ringwald                             printf("AVRCP: Connection released, cid 0x%02x\n", avrcp_subevent_browsing_connection_released_get_browsing_cid(packet));
422*5666fff4SMilanka Ringwald                             browsing_cid = 0;
423*5666fff4SMilanka Ringwald                             browsing_connected = false;
424*5666fff4SMilanka Ringwald                             return;
425*5666fff4SMilanka Ringwald                         case AVRCP_SUBEVENT_BROWSING_DONE:
426*5666fff4SMilanka Ringwald 
427*5666fff4SMilanka Ringwald                             browsing_query_active = 0;
428*5666fff4SMilanka Ringwald                             browsing_uid_counter = 0;
429*5666fff4SMilanka Ringwald                             if (avrcp_subevent_browsing_done_get_browsing_status(packet) != AVRCP_BROWSING_ERROR_CODE_SUCCESS){
430*5666fff4SMilanka Ringwald                                 printf("AVRCP Browsing query done with browsing status 0x%02x, bluetooth status 0x%02x.\n",
431*5666fff4SMilanka Ringwald                                     avrcp_subevent_browsing_done_get_browsing_status(packet),
432*5666fff4SMilanka Ringwald                                     avrcp_subevent_browsing_done_get_bluetooth_status(packet));
433*5666fff4SMilanka Ringwald                                 return;
434*5666fff4SMilanka Ringwald                             }
435*5666fff4SMilanka Ringwald                             browsing_uid_counter = avrcp_subevent_browsing_done_get_uid_counter(packet);
436*5666fff4SMilanka Ringwald                             printf("DONE, browsing_uid_counter %d.\n", browsing_uid_counter);
437*5666fff4SMilanka Ringwald 
438*5666fff4SMilanka Ringwald                             switch (browsing_state){
439*5666fff4SMilanka Ringwald                                 case AVRCP_BROWSING_STATE_W4_GET_PLAYERS:
440*5666fff4SMilanka Ringwald                                     if (media_player_item_index < 0) {
441*5666fff4SMilanka Ringwald                                         printf("Get media players first\n");
442*5666fff4SMilanka Ringwald                                         break;
443*5666fff4SMilanka Ringwald                                     }
444*5666fff4SMilanka Ringwald                                     printf("Set browsed player\n");
445*5666fff4SMilanka Ringwald                                     browsing_state = AVRCP_BROWSING_STATE_W4_SET_PLAYER;
446*5666fff4SMilanka Ringwald                                     status = avrcp_browsing_controller_set_browsed_player(browsing_cid, media_player_items[0].player_id);
447*5666fff4SMilanka Ringwald                                     if (status != ERROR_CODE_SUCCESS){
448*5666fff4SMilanka Ringwald                                         printf("Could not set player, status 0x%02X\n", status);
449*5666fff4SMilanka Ringwald                                         status = AVRCP_BROWSING_STATE_W4_GET_PLAYERS;
450*5666fff4SMilanka Ringwald                                         break;
451*5666fff4SMilanka Ringwald                                     }
452*5666fff4SMilanka Ringwald                                     break;
453*5666fff4SMilanka Ringwald                                 case AVRCP_BROWSING_STATE_W4_SET_PLAYER:
454*5666fff4SMilanka Ringwald                                     browsing_state = AVRCP_BROWSING_STATE_READY;
455*5666fff4SMilanka Ringwald                                     break;
456*5666fff4SMilanka Ringwald                                 default:
457*5666fff4SMilanka Ringwald                                     break;
458*5666fff4SMilanka Ringwald                             }
459*5666fff4SMilanka Ringwald                             break;
460*5666fff4SMilanka Ringwald                         default:
461*5666fff4SMilanka Ringwald                             break;
462*5666fff4SMilanka Ringwald                     }
463*5666fff4SMilanka Ringwald 
464*5666fff4SMilanka Ringwald                 default:
465*5666fff4SMilanka Ringwald                     break;
466*5666fff4SMilanka Ringwald             }
467*5666fff4SMilanka Ringwald             break;
468*5666fff4SMilanka Ringwald 
469954cc391SMilanka Ringwald         case AVRCP_BROWSING_DATA_PACKET:
470*5666fff4SMilanka Ringwald             browsing_query_active = 1;
471954cc391SMilanka Ringwald             avrcp_browsing_item_type_t data_type = (avrcp_browsing_item_type_t)packet[pos++];
472954cc391SMilanka Ringwald 
473954cc391SMilanka Ringwald             switch (data_type){
474db79553aSMilanka Ringwald                 case AVRCP_BROWSING_MEDIA_ROOT_FOLDER:{
475*5666fff4SMilanka Ringwald                     uint16_t folder_name_length = size - pos;
476*5666fff4SMilanka Ringwald                     char folder_name[AVRCP_MAX_FOLDER_NAME_SIZE];
477*5666fff4SMilanka Ringwald                     memcpy(folder_name, &packet[pos], folder_name_length);
478*5666fff4SMilanka Ringwald                     folder_name[folder_name_length] = 0;
479*5666fff4SMilanka Ringwald                     printf("Found root folder: name %s \n", folder_name);
480*5666fff4SMilanka Ringwald                     break;
481*5666fff4SMilanka Ringwald                 }
4822f511ffbSMilanka Ringwald 
483954cc391SMilanka Ringwald                 case AVRCP_BROWSING_FOLDER_ITEM:{
484db79553aSMilanka Ringwald                     int index = next_folder_index();
485db79553aSMilanka Ringwald                     memcpy(folders[index].uid, packet+pos, 8);
486*5666fff4SMilanka Ringwald 
487954cc391SMilanka Ringwald                     uint32_t folder_uid_high = big_endian_read_32(packet, pos);
488954cc391SMilanka Ringwald                     pos += 4;
489db79553aSMilanka Ringwald                     uint32_t folder_uid_low  = big_endian_read_32(packet, pos);
490954cc391SMilanka Ringwald                     pos += 4;
491954cc391SMilanka Ringwald                     avrcp_browsing_folder_type_t folder_type = packet[pos++];
492954cc391SMilanka Ringwald                     uint8_t  is_playable = packet[pos++];
493954cc391SMilanka Ringwald                     uint16_t charset = big_endian_read_16(packet, pos);
494954cc391SMilanka Ringwald                     pos += 2;
495954cc391SMilanka Ringwald                     uint16_t displayable_name_length = big_endian_read_16(packet, pos);
496954cc391SMilanka Ringwald                     pos += 2;
4972f511ffbSMilanka Ringwald 
498*5666fff4SMilanka Ringwald                     char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
499*5666fff4SMilanka Ringwald                     memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN);
500*5666fff4SMilanka Ringwald                     uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1);
501954cc391SMilanka Ringwald                     memcpy(value, packet+pos, value_len);
502db79553aSMilanka Ringwald 
503*5666fff4SMilanka Ringwald                     printf("Folder UID 0x%08" PRIx32 "%08" PRIx32 ", type 0x%02x, is_playable %d, charset 0x%02x, name %s\n",
5042f511ffbSMilanka Ringwald                         folder_uid_high, folder_uid_low, folder_type, is_playable, charset, value);
505*5666fff4SMilanka Ringwald                     if (is_playable){
506*5666fff4SMilanka Ringwald                         playable_folder_index = index;
507*5666fff4SMilanka Ringwald                     }
508db79553aSMilanka Ringwald                     memcpy(folders[index].name, value, value_len);
509db79553aSMilanka Ringwald                     folders[index].name_len = value_len;
510954cc391SMilanka Ringwald                     break;
511954cc391SMilanka Ringwald                 }
512954cc391SMilanka Ringwald 
513*5666fff4SMilanka Ringwald                 case AVRCP_BROWSING_MEDIA_PLAYER_ITEM:{
514*5666fff4SMilanka Ringwald                     printf("Received media player item:  ");
515*5666fff4SMilanka Ringwald                     uint16_t player_id = big_endian_read_16(packet, pos);
516*5666fff4SMilanka Ringwald                     pos += 2;
517*5666fff4SMilanka Ringwald                     avrcp_browsing_media_player_major_type_t major_type = packet[pos++];
518*5666fff4SMilanka Ringwald                     avrcp_browsing_media_player_subtype_t subtype = big_endian_read_32(packet, pos);
519954cc391SMilanka Ringwald                     pos += 4;
520*5666fff4SMilanka Ringwald                     status = packet[pos++];
521*5666fff4SMilanka Ringwald                     uint8_t feature_bitmask[16];
522*5666fff4SMilanka Ringwald                     memcpy(feature_bitmask, packet, 16);
523*5666fff4SMilanka Ringwald                     pos += 16;
524*5666fff4SMilanka Ringwald                     printf("player ID 0x%04x, major_type %d, subtype %d, status %d\n", player_id, major_type, subtype, status);
525*5666fff4SMilanka Ringwald                     media_player_items[next_media_player_item_index()].player_id = player_id;
526*5666fff4SMilanka Ringwald                     break;
527*5666fff4SMilanka Ringwald                 }
528*5666fff4SMilanka Ringwald 
529*5666fff4SMilanka Ringwald                 case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM:{
530*5666fff4SMilanka Ringwald                     int index = next_media_element_item_index();
531*5666fff4SMilanka Ringwald                     memcpy(media_element_items[index].uid, packet+pos, 8);
532*5666fff4SMilanka Ringwald                     printf("Received media element item UID (index %d): ", index);
533*5666fff4SMilanka Ringwald 
534*5666fff4SMilanka Ringwald                     // uint32_t media_uid_high = big_endian_read_32(packet, pos);
535954cc391SMilanka Ringwald                     pos += 4;
536*5666fff4SMilanka Ringwald                     // uint32_t media_uid_low  = big_endian_read_32(packet, pos+4);
537*5666fff4SMilanka Ringwald                     pos += 4;
538*5666fff4SMilanka Ringwald 
539954cc391SMilanka Ringwald                     avrcp_browsing_media_type_t media_type = packet[pos++];
540954cc391SMilanka Ringwald                     uint16_t charset = big_endian_read_16(packet, pos);
541954cc391SMilanka Ringwald                     pos += 2;
542954cc391SMilanka Ringwald                     uint16_t displayable_name_length = big_endian_read_16(packet, pos);
543954cc391SMilanka Ringwald                     pos += 2;
544*5666fff4SMilanka Ringwald 
545*5666fff4SMilanka Ringwald                     char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
546*5666fff4SMilanka Ringwald                     memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN);
547*5666fff4SMilanka Ringwald                     uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1);
548*5666fff4SMilanka Ringwald                     memcpy(value, packet+pos, value_len);
549*5666fff4SMilanka Ringwald                     memcpy(media_element_items[index].name, value, value_len);
550*5666fff4SMilanka Ringwald 
551954cc391SMilanka Ringwald                     pos += displayable_name_length;
552*5666fff4SMilanka Ringwald                     // 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);
553954cc391SMilanka Ringwald 
554*5666fff4SMilanka Ringwald                     printf_hexdump(media_element_items[index].uid, 8);
555954cc391SMilanka Ringwald                     uint8_t num_attributes = packet[pos++];
556*5666fff4SMilanka Ringwald                     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);
557954cc391SMilanka Ringwald 
558*5666fff4SMilanka Ringwald                     avrcp_media_item_context_t media_item_context;
559954cc391SMilanka Ringwald                     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)){
560954cc391SMilanka Ringwald                         uint32_t attr_id            = avrcp_media_item_iterator_get_attr_id(&media_item_context);
561954cc391SMilanka Ringwald                         uint16_t attr_charset       = avrcp_media_item_iterator_get_attr_charset(&media_item_context);
562954cc391SMilanka Ringwald                         uint16_t attr_value_length  = avrcp_media_item_iterator_get_attr_value_len(&media_item_context);
563954cc391SMilanka Ringwald                         const uint8_t * attr_value  = avrcp_media_item_iterator_get_attr_value(&media_item_context);
564954cc391SMilanka Ringwald 
565*5666fff4SMilanka Ringwald                         memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN);
566*5666fff4SMilanka Ringwald                         value_len = btstack_min(attr_value_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1);
567*5666fff4SMilanka Ringwald                         memcpy(value, attr_value, value_len);
568*5666fff4SMilanka Ringwald 
569*5666fff4SMilanka Ringwald                         printf("    - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, value_len, value);
570954cc391SMilanka Ringwald                     }
571954cc391SMilanka Ringwald                     break;
572954cc391SMilanka Ringwald                 }
573954cc391SMilanka Ringwald 
574*5666fff4SMilanka Ringwald                 case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE:{
575*5666fff4SMilanka Ringwald                     uint8_t num_attributes = packet[pos++];
576*5666fff4SMilanka Ringwald                     printf("Num media attributes %d:\n", num_attributes);
577*5666fff4SMilanka Ringwald                     avrcp_media_item_context_t media_item_context;
578*5666fff4SMilanka Ringwald                     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)){
579*5666fff4SMilanka Ringwald                         uint32_t attr_id            = avrcp_media_item_iterator_get_attr_id(&media_item_context);
580*5666fff4SMilanka Ringwald                         uint16_t attr_charset       = avrcp_media_item_iterator_get_attr_charset(&media_item_context);
581*5666fff4SMilanka Ringwald                         uint16_t attr_value_length  = avrcp_media_item_iterator_get_attr_value_len(&media_item_context);
582*5666fff4SMilanka Ringwald                         const uint8_t * attr_value  = avrcp_media_item_iterator_get_attr_value(&media_item_context);
583*5666fff4SMilanka Ringwald                         printf("    - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, attr_value_length, attr_value);
584*5666fff4SMilanka Ringwald                     }
585*5666fff4SMilanka Ringwald                 }
586954cc391SMilanka Ringwald                 default:
587*5666fff4SMilanka Ringwald                     printf("AVRCP browsing: unknown browsable item type 0%02x\n", data_type);
588954cc391SMilanka Ringwald                     break;
589954cc391SMilanka Ringwald             }
590954cc391SMilanka Ringwald             break;
591462aa085SMilanka Ringwald         default:
592462aa085SMilanka Ringwald             break;
593462aa085SMilanka Ringwald     }
594462aa085SMilanka Ringwald }
595462aa085SMilanka Ringwald 
596462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
597462aa085SMilanka Ringwald static void show_usage(void){
598462aa085SMilanka Ringwald     bd_addr_t      iut_address;
599462aa085SMilanka Ringwald     gap_local_bd_addr(iut_address);
6008ee7c9daSMilanka Ringwald     printf("\n--- Bluetooth AVRCP Browsing Service Test Console %s ---\n", bd_addr_to_str(iut_address));
6018ee7c9daSMilanka Ringwald     printf("c      - AVRCP Service create connection to addr %s\n", bd_addr_to_str(device_addr));
6028ee7c9daSMilanka Ringwald     printf("C      - AVRCP Service disconnect\n");
6038ee7c9daSMilanka Ringwald     printf("e      - AVRCP Browsing Service create connection to addr %s\n", bd_addr_to_str(device_addr));
6048ee7c9daSMilanka Ringwald     printf("E      - AVRCP Browsing Service disconnect\n");
605db79553aSMilanka Ringwald 
606c0a054f6SMilanka Ringwald     printf("I      - Set first found player as addressed player\n");
607c0a054f6SMilanka Ringwald     printf("O      - Set first found player as browsed player\n");
608db79553aSMilanka Ringwald 
609c0a054f6SMilanka Ringwald     printf("p      - Get media players\n");
610c0a054f6SMilanka Ringwald     printf("Q      - Browse folders\n");
611c0a054f6SMilanka Ringwald     printf("P      - Go up one level\n");
612c0a054f6SMilanka Ringwald     printf("W      - Go down one level\n");
613c0a054f6SMilanka Ringwald     printf("T      - Browse media items\n");
614462aa085SMilanka Ringwald     printf("---\n");
615462aa085SMilanka Ringwald }
616462aa085SMilanka Ringwald #endif
617462aa085SMilanka Ringwald 
618ed0df7b2SMilanka Ringwald 
619462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
620462aa085SMilanka Ringwald static void stdin_process(char cmd){
621462aa085SMilanka Ringwald     uint8_t status = ERROR_CODE_SUCCESS;
622462aa085SMilanka Ringwald 
623954cc391SMilanka Ringwald     if (cmd != 'a' && cmd != 'A' && cmd != 'c' && cmd != 'C'){
624954cc391SMilanka Ringwald         if (browsing_query_active){
625954cc391SMilanka Ringwald             printf("Query active, try later!\n");
626954cc391SMilanka Ringwald             return;
627954cc391SMilanka Ringwald         }
628954cc391SMilanka Ringwald     }
629954cc391SMilanka Ringwald 
630462aa085SMilanka Ringwald     switch (cmd){
631*5666fff4SMilanka Ringwald         case 'b':
632*5666fff4SMilanka Ringwald             status = a2dp_sink_establish_stream(device_addr, a2dp_local_seid, &a2dp_cid);
633*5666fff4SMilanka Ringwald             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);
634*5666fff4SMilanka Ringwald             break;
635*5666fff4SMilanka Ringwald         case 'B':
636*5666fff4SMilanka Ringwald             printf(" - AVDTP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
637*5666fff4SMilanka Ringwald             a2dp_sink_disconnect(a2dp_cid);
638*5666fff4SMilanka Ringwald             break;
639*5666fff4SMilanka Ringwald 
640c0a054f6SMilanka Ringwald         case 'c':
6418ee7c9daSMilanka Ringwald             printf(" - Connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr));
642fe10780bSMilanka Ringwald             status = avrcp_connect(device_addr, &avrcp_cid);
643462aa085SMilanka Ringwald             break;
644c0a054f6SMilanka Ringwald         case 'C':
645247956eaSMilanka Ringwald             if (avrcp_connected){
6468ee7c9daSMilanka Ringwald                 printf(" - AVRCP Service disconnect from addr %s.\n", bd_addr_to_str(device_addr));
647fe10780bSMilanka Ringwald                 status = avrcp_disconnect(avrcp_cid);
648247956eaSMilanka Ringwald                 break;
649247956eaSMilanka Ringwald             }
6508ee7c9daSMilanka Ringwald             printf("AVRCP Service already disconnected\n");
651247956eaSMilanka Ringwald             break;
652247956eaSMilanka Ringwald 
653c0a054f6SMilanka Ringwald         case 'e':
654462aa085SMilanka Ringwald             if (!avrcp_connected) {
6558ee7c9daSMilanka Ringwald                 printf(" You must first connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr));
656462aa085SMilanka Ringwald                 break;
657462aa085SMilanka Ringwald             }
6588ee7c9daSMilanka Ringwald             printf(" - Connect to AVRCP Browsing Service at addr %s.\n", bd_addr_to_str(device_addr));
6593121b998SMilanka Ringwald             status = avrcp_browsing_connect(device_addr, ertm_buffer, sizeof(ertm_buffer), &ertm_config, &browsing_cid);
660462aa085SMilanka Ringwald             break;
661c0a054f6SMilanka Ringwald         case 'E':
662*5666fff4SMilanka Ringwald             if (browsing_connected){
6638ee7c9daSMilanka Ringwald                 printf(" - AVRCP Browsing Service disconnect from addr %s.\n", bd_addr_to_str(device_addr));
6648ee7c9daSMilanka Ringwald                 status = avrcp_browsing_disconnect(browsing_cid);
665462aa085SMilanka Ringwald                 break;
666247956eaSMilanka Ringwald             }
6678ee7c9daSMilanka Ringwald             printf("AVRCP Browsing Service already disconnected\n");
668247956eaSMilanka Ringwald             break;
669462aa085SMilanka Ringwald         case '\n':
670462aa085SMilanka Ringwald         case '\r':
671462aa085SMilanka Ringwald             break;
672db79553aSMilanka Ringwald 
673db79553aSMilanka Ringwald         default:
674*5666fff4SMilanka Ringwald             if (!browsing_connected){
675db79553aSMilanka Ringwald                 show_usage();
676db79553aSMilanka Ringwald                 break;
677db79553aSMilanka Ringwald             }
678db79553aSMilanka Ringwald 
679db79553aSMilanka Ringwald             switch (cmd) {
680c0a054f6SMilanka Ringwald                 case 'I':
681*5666fff4SMilanka Ringwald                     if (media_player_item_index < 0) {
6828ee7c9daSMilanka Ringwald                         printf("AVRCP Browsing:Get media players first\n");
683db79553aSMilanka Ringwald                         break;
684db79553aSMilanka Ringwald                     }
6858ee7c9daSMilanka Ringwald                     printf("AVRCP Browsing:Set addressed player\n");
686*5666fff4SMilanka Ringwald                     status = avrcp_controller_set_addressed_player(avrcp_cid, media_player_items[0].player_id);
687db79553aSMilanka Ringwald                     break;
688c0a054f6SMilanka Ringwald                 case 'O':
689*5666fff4SMilanka Ringwald                     if (media_player_item_index < 0) {
6908ee7c9daSMilanka Ringwald                         printf("AVRCP Browsing:Get media players first\n");
691db79553aSMilanka Ringwald                         break;
692db79553aSMilanka Ringwald                     }
693db79553aSMilanka Ringwald                     printf("Set browsed player\n");
694*5666fff4SMilanka Ringwald                     status = avrcp_browsing_controller_set_browsed_player(browsing_cid, media_player_items[0].player_id);
695db79553aSMilanka Ringwald                     break;
696c0a054f6SMilanka Ringwald                 case 'p':
697db79553aSMilanka Ringwald                     printf("AVRCP Browsing: get media players\n");
698*5666fff4SMilanka Ringwald                     media_player_item_index = -1;
6992f511ffbSMilanka Ringwald                     status = avrcp_browsing_controller_get_media_players(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
700db79553aSMilanka Ringwald                     break;
701c0a054f6SMilanka Ringwald                 case 'Q':
702db79553aSMilanka Ringwald                     printf("AVRCP Browsing: browse folders\n");
703db79553aSMilanka Ringwald                     folder_index = -1;
7042f511ffbSMilanka Ringwald                     status = avrcp_browsing_controller_browse_file_system(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
705db79553aSMilanka Ringwald                     break;
706c0a054f6SMilanka Ringwald                 case 'P':
707db79553aSMilanka Ringwald                     printf("AVRCP Browsing: browse media items\n");
7082f511ffbSMilanka Ringwald                     avrcp_browsing_controller_browse_media(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
709db79553aSMilanka Ringwald                     break;
710c0a054f6SMilanka Ringwald                 case 'W':
711e5b24613SMilanka Ringwald                     printf("AVRCP Browsing: go up one level\n");
712e5b24613SMilanka Ringwald                     status = avrcp_browsing_controller_go_up_one_level(browsing_cid);
713db79553aSMilanka Ringwald                     folder_index = -1;
714db79553aSMilanka Ringwald                     break;
715c0a054f6SMilanka Ringwald                 case 'T':
716db79553aSMilanka Ringwald                     if (folder_index < 0 && !parent_folder_set){
717db79553aSMilanka Ringwald                         printf("AVRCP Browsing: no folders available\n");
718db79553aSMilanka Ringwald                         break;
719db79553aSMilanka Ringwald                     }
720db79553aSMilanka Ringwald                     if (!parent_folder_set){
721db79553aSMilanka Ringwald                         parent_folder_set = 1;
722db79553aSMilanka Ringwald                         memcpy(parent_folder_name, folders[0].name, folders[0].name_len);
723db79553aSMilanka Ringwald                         memcpy(parent_folder_uid, folders[0].uid, 8);
724db79553aSMilanka Ringwald                     }
725db79553aSMilanka Ringwald                     printf("AVRCP Browsing: go down one level of %s\n", (char *)parent_folder_name);
726db79553aSMilanka Ringwald                     status = avrcp_browsing_controller_go_down_one_level(browsing_cid, parent_folder_uid);
727db79553aSMilanka Ringwald                     folder_index = -1;
728db79553aSMilanka Ringwald                     break;
729462aa085SMilanka Ringwald                 default:
730462aa085SMilanka Ringwald                     show_usage();
731db79553aSMilanka Ringwald                     break;
732db79553aSMilanka Ringwald             }
733db79553aSMilanka Ringwald             break;
734462aa085SMilanka Ringwald     }
735ed0df7b2SMilanka Ringwald 
736462aa085SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
7378ee7c9daSMilanka Ringwald         printf("AVRCP Browsing: Could not perform command, status 0x%2x\n", status);
738462aa085SMilanka Ringwald     }
739462aa085SMilanka Ringwald }
740462aa085SMilanka Ringwald #endif
741462aa085SMilanka Ringwald /* EXAMPLE_END */
742