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
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH 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 // *****************************************************************************
45ec8ae085SMilanka Ringwald /* EXAMPLE_START(avrcp_browsing_client): AVRCP Browsing - Browse Media Players and Media Information
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
6916fc96d5SMatthias Ringwald #ifndef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
7016fc96d5SMatthias Ringwald #error "AVRCP Browsing requires L2CAP ERTM, please add ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE to your btstack_config.h"
7116fc96d5SMatthias Ringwald #endif
7216fc96d5SMatthias Ringwald
734f0111ebSMilanka Ringwald #define AVRCP_BROWSING_ENABLED
744f0111ebSMilanka Ringwald
75db79553aSMilanka Ringwald #define AVRCP_BROWSING_MAX_PLAYERS 10
76db79553aSMilanka Ringwald #define AVRCP_BROWSING_MAX_FOLDERS 10
775666fff4SMilanka Ringwald #define AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN 30
785666fff4SMilanka Ringwald #define AVRCP_BROWSING_MAX_MEDIA_ITEMS 10
79db79553aSMilanka Ringwald
80462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
81462aa085SMilanka Ringwald // mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
82462aa085SMilanka Ringwald // pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
83462aa085SMilanka Ringwald // mac 2013:
84462aa085SMilanka Ringwald // static const char * device_addr_string = "84:38:35:65:d1:15";
85462aa085SMilanka Ringwald // iPhone 5S: static const char * device_addr_string = "54:E4:3A:26:A2:39";
86462aa085SMilanka Ringwald // phone 2013:
87143efbe8SMilanka Ringwald // static const char * device_addr_string = "B0:34:95:CB:97:C4";
8802d2f9caSMilanka Ringwald // iPod
890eebc132SMilanka Ringwald // static const char * device_addr_string = "B0:34:95:CB:97:C4";
900eebc132SMilanka Ringwald // iPhone
910eebc132SMilanka Ringwald static const char * device_addr_string = "6C:72:E7:10:22:EE";
92143efbe8SMilanka Ringwald
93462aa085SMilanka Ringwald static bd_addr_t device_addr;
94462aa085SMilanka Ringwald #endif
95462aa085SMilanka Ringwald
965666fff4SMilanka Ringwald typedef enum {
975666fff4SMilanka Ringwald AVRCP_BROWSING_STATE_IDLE,
985666fff4SMilanka Ringwald AVRCP_BROWSING_STATE_W4_GET_PLAYERS,
995666fff4SMilanka Ringwald AVRCP_BROWSING_STATE_W4_SET_PLAYER,
1005666fff4SMilanka Ringwald AVRCP_BROWSING_STATE_READY
1015666fff4SMilanka Ringwald } avrcp_browsing_state_t;
102954cc391SMilanka Ringwald
103db79553aSMilanka Ringwald typedef struct {
104db79553aSMilanka Ringwald uint16_t charset;
105db79553aSMilanka Ringwald uint8_t depth;
106db79553aSMilanka Ringwald uint16_t name_len;
1075666fff4SMilanka Ringwald char name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
108db79553aSMilanka Ringwald } avrcp_browsing_root_folder_t;
109db79553aSMilanka Ringwald
110db79553aSMilanka Ringwald typedef struct {
111db79553aSMilanka Ringwald uint8_t uid[8];
112db79553aSMilanka Ringwald uint16_t name_len;
1135666fff4SMilanka Ringwald char name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
1145666fff4SMilanka Ringwald } avrcp_browsable_item_t;
1155666fff4SMilanka Ringwald
1165666fff4SMilanka Ringwald typedef struct {
1175666fff4SMilanka Ringwald uint16_t player_id;
1185666fff4SMilanka Ringwald uint8_t major_player_type;
1195666fff4SMilanka Ringwald uint32_t player_sub_type;
1205666fff4SMilanka Ringwald uint8_t play_status;
1215666fff4SMilanka Ringwald uint8_t feature_bitmask[16];
1225666fff4SMilanka Ringwald uint16_t charset;
1235666fff4SMilanka Ringwald uint16_t name_len;
1245666fff4SMilanka Ringwald char name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
1255666fff4SMilanka Ringwald } avrcp_browsable_media_player_item_t;
1265666fff4SMilanka Ringwald
1275666fff4SMilanka Ringwald typedef struct {
1285666fff4SMilanka Ringwald uint32_t id;
1295666fff4SMilanka Ringwald uint16_t charset;
1305666fff4SMilanka Ringwald uint16_t value_len;
1315666fff4SMilanka Ringwald char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
1325666fff4SMilanka Ringwald } avrcp_browsable_media_element_item_attribute_t;
1335666fff4SMilanka Ringwald
1345666fff4SMilanka Ringwald typedef struct {
1355666fff4SMilanka Ringwald uint8_t uid[8];
1365666fff4SMilanka Ringwald uint8_t media_type;
1375666fff4SMilanka Ringwald uint16_t charset;
1385666fff4SMilanka Ringwald uint16_t name_len;
1395666fff4SMilanka Ringwald char name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
1405666fff4SMilanka Ringwald uint8_t num_attributes;
1415666fff4SMilanka Ringwald } avrcp_browsable_media_element_item_t;
1425666fff4SMilanka Ringwald
1435666fff4SMilanka Ringwald static avrcp_browsing_state_t browsing_state = AVRCP_BROWSING_STATE_IDLE;
1445666fff4SMilanka Ringwald static uint16_t avrcp_cid = 0;
1455666fff4SMilanka Ringwald static bool avrcp_connected = false;
1465666fff4SMilanka Ringwald
1475666fff4SMilanka Ringwald static uint16_t browsing_cid = 0;
1485666fff4SMilanka Ringwald static bool browsing_connected = false;
1495666fff4SMilanka Ringwald
1505666fff4SMilanka Ringwald static uint8_t sdp_avrcp_browsing_controller_service_buffer[200];
1515666fff4SMilanka Ringwald static uint8_t sdp_avdtp_sink_service_buffer[150];
1525666fff4SMilanka Ringwald
1535666fff4SMilanka Ringwald static uint16_t a2dp_cid = 0;
1545666fff4SMilanka Ringwald static uint8_t a2dp_local_seid = 0;
1555666fff4SMilanka Ringwald
1565666fff4SMilanka Ringwald static uint8_t media_sbc_codec_capabilities[] = {
1575666fff4SMilanka Ringwald 0xFF,//(AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
1585666fff4SMilanka Ringwald 0xFF,//(AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
1595666fff4SMilanka Ringwald 2, 53
1605666fff4SMilanka Ringwald };
1615666fff4SMilanka Ringwald
1625666fff4SMilanka Ringwald static uint8_t media_sbc_codec_configuration[] = {
1635666fff4SMilanka Ringwald (AVDTP_SBC_44100 << 4) | AVDTP_SBC_STEREO,
1645666fff4SMilanka Ringwald (AVDTP_SBC_BLOCK_LENGTH_16 << 4) | (AVDTP_SBC_SUBBANDS_8 << 2) | AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS,
1655666fff4SMilanka Ringwald 2, 53
1665666fff4SMilanka Ringwald };
1675666fff4SMilanka Ringwald
1685666fff4SMilanka Ringwald static bool browsing_query_active = false;
1695666fff4SMilanka Ringwald // static avrcp_media_item_context_t media_item_context;
1705666fff4SMilanka Ringwald
1715666fff4SMilanka Ringwald static int playable_folder_index = 0;
1725666fff4SMilanka Ringwald
1735666fff4SMilanka Ringwald
1745666fff4SMilanka Ringwald static uint16_t browsing_uid_counter = 0;
175db79553aSMilanka Ringwald
176db79553aSMilanka Ringwald static uint8_t parent_folder_set = 0;
177db79553aSMilanka Ringwald static uint8_t parent_folder_uid[8];
1785666fff4SMilanka Ringwald static char parent_folder_name[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
1795666fff4SMilanka Ringwald
1805666fff4SMilanka Ringwald static avrcp_browsable_item_t folders[AVRCP_BROWSING_MAX_FOLDERS];
181db79553aSMilanka Ringwald static int folder_index = -1;
1825666fff4SMilanka Ringwald
1835666fff4SMilanka Ringwald static avrcp_browsable_media_element_item_t media_element_items[AVRCP_BROWSING_MAX_MEDIA_ITEMS];
1845666fff4SMilanka Ringwald static int media_element_item_index = -1;
1855666fff4SMilanka Ringwald
1865666fff4SMilanka Ringwald static avrcp_browsable_media_player_item_t media_player_items[AVRCP_BROWSING_MAX_MEDIA_ITEMS];
1875666fff4SMilanka Ringwald static int media_player_item_index = -1;
188db79553aSMilanka Ringwald
189462aa085SMilanka Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
190462aa085SMilanka Ringwald
191462aa085SMilanka Ringwald static uint8_t ertm_buffer[10000];
192462aa085SMilanka Ringwald static l2cap_ertm_config_t ertm_config = {
193462aa085SMilanka Ringwald 1, // ertm mandatory
194462aa085SMilanka Ringwald 2, // max transmit, some tests require > 1
195462aa085SMilanka Ringwald 2000,
196462aa085SMilanka Ringwald 12000,
197462aa085SMilanka Ringwald 144, // l2cap ertm mtu
198462aa085SMilanka Ringwald 4,
199462aa085SMilanka Ringwald 4,
2007c7befacSMatthias Ringwald 1, // 16-bit FCS
201462aa085SMilanka Ringwald };
202462aa085SMilanka Ringwald
2035666fff4SMilanka Ringwald
next_index(int * index,int max_value)204db79553aSMilanka Ringwald static inline int next_index(int * index, int max_value){
205db79553aSMilanka Ringwald if ((*index) < max_value){
206db79553aSMilanka Ringwald (*index)++;
207db79553aSMilanka Ringwald } else {
208db79553aSMilanka Ringwald (*index) = 0;
209db79553aSMilanka Ringwald }
210db79553aSMilanka Ringwald return (*index);
211db79553aSMilanka Ringwald }
212db79553aSMilanka Ringwald
next_folder_index(void)2130bd372cfSMatthias Ringwald static int next_folder_index(void){
214db79553aSMilanka Ringwald return next_index(&folder_index, AVRCP_BROWSING_MAX_FOLDERS);
215db79553aSMilanka Ringwald }
216db79553aSMilanka Ringwald
next_media_element_item_index(void)2170bd372cfSMatthias Ringwald static int next_media_element_item_index(void){
2185666fff4SMilanka Ringwald return next_index(&media_element_item_index, AVRCP_BROWSING_MAX_MEDIA_ITEMS);
219db79553aSMilanka Ringwald }
next_media_player_item_index(void)2200bd372cfSMatthias Ringwald static int next_media_player_item_index(void){
2215666fff4SMilanka Ringwald return next_index(&media_player_item_index, AVRCP_BROWSING_MAX_MEDIA_ITEMS);
2225666fff4SMilanka Ringwald }
223db79553aSMilanka Ringwald
224462aa085SMilanka Ringwald /* @section Main Application Setup
225462aa085SMilanka Ringwald *
226462aa085SMilanka Ringwald * @text The Listing MainConfiguration shows how to setup AVRCP Controller Browsing service.
227462aa085SMilanka Ringwald * To announce AVRCP Controller Browsing service, you need to create corresponding
228462aa085SMilanka Ringwald * SDP record and register it with the SDP service.
229462aa085SMilanka Ringwald * You'll also need to register several packet handlers:
230462aa085SMilanka Ringwald * - stdin_process callback - used to trigger AVRCP commands, such are get media players, playlists, albums, etc. Requires HAVE_BTSTACK_STDIN.
2315666fff4SMilanka Ringwald * - avrcp_browsing_controller_packet_handler - used to receive answers for AVRCP commands.
232462aa085SMilanka Ringwald *
233462aa085SMilanka Ringwald */
234462aa085SMilanka Ringwald
235462aa085SMilanka Ringwald /* LISTING_START(MainConfiguration): Setup Audio Sink and AVRCP Controller services */
2365666fff4SMilanka Ringwald static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
23702d2f9caSMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
2385666fff4SMilanka Ringwald static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
23902d2f9caSMilanka Ringwald
240462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
241462aa085SMilanka Ringwald static void stdin_process(char cmd);
242462aa085SMilanka Ringwald #endif
243462aa085SMilanka Ringwald
244462aa085SMilanka Ringwald
245462aa085SMilanka Ringwald int btstack_main(int argc, const char * argv[]);
btstack_main(int argc,const char * argv[])246462aa085SMilanka Ringwald int btstack_main(int argc, const char * argv[]){
247462aa085SMilanka Ringwald (void)argc;
248462aa085SMilanka Ringwald (void)argv;
249462aa085SMilanka Ringwald
250462aa085SMilanka Ringwald // Initialize L2CAP.
251462aa085SMilanka Ringwald l2cap_init();
252462aa085SMilanka Ringwald
2538c9bb29eSMatthias Ringwald #ifdef ENABLE_BLE
2548c9bb29eSMatthias Ringwald // Initialize LE Security Manager. Needed for cross-transport key derivation
2558c9bb29eSMatthias Ringwald sm_init();
2568c9bb29eSMatthias Ringwald #endif
2578c9bb29eSMatthias Ringwald
2585666fff4SMilanka Ringwald a2dp_sink_init();
2595666fff4SMilanka Ringwald a2dp_sink_register_packet_handler(&a2dp_sink_packet_handler);
2605666fff4SMilanka Ringwald
2615666fff4SMilanka Ringwald avdtp_stream_endpoint_t * local_stream_endpoint = a2dp_sink_create_stream_endpoint(AVDTP_AUDIO,
2625666fff4SMilanka Ringwald AVDTP_CODEC_SBC, media_sbc_codec_capabilities, sizeof(media_sbc_codec_capabilities),
2635666fff4SMilanka Ringwald media_sbc_codec_configuration, sizeof(media_sbc_codec_configuration));
2645666fff4SMilanka Ringwald if (!local_stream_endpoint){
2655666fff4SMilanka Ringwald printf("A2DP Sink: not enough memory to create local stream endpoint\n");
2665666fff4SMilanka Ringwald return 1;
2675666fff4SMilanka Ringwald }
2685666fff4SMilanka Ringwald a2dp_local_seid = avdtp_local_seid(local_stream_endpoint);
2695666fff4SMilanka Ringwald
27019691e0aSMilanka Ringwald // Initialize AVRCP service.
27119691e0aSMilanka Ringwald avrcp_init();
27202d2f9caSMilanka Ringwald // Initialize AVRCP Controller & Target Service.
273462aa085SMilanka Ringwald avrcp_controller_init();
27402d2f9caSMilanka Ringwald avrcp_target_init();
27502d2f9caSMilanka Ringwald
27602d2f9caSMilanka Ringwald avrcp_register_packet_handler(&avrcp_packet_handler);
27702d2f9caSMilanka Ringwald avrcp_controller_register_packet_handler(&avrcp_packet_handler);
27802d2f9caSMilanka Ringwald avrcp_target_register_packet_handler(&avrcp_packet_handler);
279462aa085SMilanka Ringwald
2800eebc132SMilanka Ringwald // Initialize AVRCP Browsing Service.
2810eebc132SMilanka Ringwald avrcp_browsing_init();
282462aa085SMilanka Ringwald avrcp_browsing_controller_init();
2830eebc132SMilanka Ringwald avrcp_browsing_target_init();
2840eebc132SMilanka Ringwald
2850eebc132SMilanka Ringwald // Register for HCI events.
2865666fff4SMilanka Ringwald avrcp_browsing_controller_register_packet_handler(&avrcp_browsing_controller_packet_handler);
2875666fff4SMilanka Ringwald avrcp_browsing_target_register_packet_handler(&avrcp_browsing_controller_packet_handler);
2885666fff4SMilanka Ringwald avrcp_browsing_register_packet_handler(&avrcp_browsing_controller_packet_handler);
289462aa085SMilanka Ringwald
290462aa085SMilanka Ringwald // Initialize SDP.
291462aa085SMilanka Ringwald sdp_init();
2925666fff4SMilanka Ringwald // setup AVDTP sink
2935666fff4SMilanka Ringwald memset(sdp_avdtp_sink_service_buffer, 0, sizeof(sdp_avdtp_sink_service_buffer));
294762141afSMatthias Ringwald a2dp_sink_create_sdp_record(sdp_avdtp_sink_service_buffer, sdp_create_service_record_handle(), AVDTP_SINK_FEATURE_MASK_HEADPHONE, NULL, NULL);
295762141afSMatthias Ringwald btstack_assert(de_get_len( sdp_avdtp_sink_service_buffer) <= sizeof(sdp_avdtp_sink_service_buffer));
2965666fff4SMilanka Ringwald sdp_register_service(sdp_avdtp_sink_service_buffer);
297462aa085SMilanka Ringwald
298462aa085SMilanka Ringwald // Create AVRCP service record and register it with SDP.
299462aa085SMilanka Ringwald memset(sdp_avrcp_browsing_controller_service_buffer, 0, sizeof(sdp_avrcp_browsing_controller_service_buffer));
30011014891SMilanka Ringwald
301e2f25417SMilanka Ringwald uint16_t supported_features = AVRCP_FEATURE_MASK_CATEGORY_PLAYER_OR_RECORDER;
3024f0111ebSMilanka Ringwald #ifdef AVRCP_BROWSING_ENABLED
303e2f25417SMilanka Ringwald supported_features |= AVRCP_FEATURE_MASK_BROWSING;
3044f0111ebSMilanka Ringwald #endif
305762141afSMatthias Ringwald avrcp_controller_create_sdp_record(sdp_avrcp_browsing_controller_service_buffer, sdp_create_service_record_handle(), supported_features, NULL, NULL);
306762141afSMatthias Ringwald btstack_assert(de_get_len( sdp_avrcp_browsing_controller_service_buffer) <= sizeof(sdp_avrcp_browsing_controller_service_buffer));
307462aa085SMilanka Ringwald sdp_register_service(sdp_avrcp_browsing_controller_service_buffer);
308462aa085SMilanka Ringwald
309462aa085SMilanka Ringwald // Set local name with a template Bluetooth address, that will be automatically
310462aa085SMilanka Ringwald // replaced with a actual address once it is available, i.e. when BTstack boots
311462aa085SMilanka Ringwald // up and starts talking to a Bluetooth module.
312462aa085SMilanka Ringwald gap_set_local_name("AVRCP Browsing Client 00:00:00:00:00:00");
313462aa085SMilanka Ringwald gap_discoverable_control(1);
314462aa085SMilanka Ringwald gap_set_class_of_device(0x200408);
315462aa085SMilanka Ringwald
316a4fe6467SMatthias Ringwald // Register for HCI events.
3175666fff4SMilanka Ringwald hci_event_callback_registration.callback = &avrcp_browsing_controller_packet_handler;
318a4fe6467SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration);
319a4fe6467SMatthias Ringwald
320a4fe6467SMatthias Ringwald
321462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
322462aa085SMilanka Ringwald // Parse human readable Bluetooth address.
323462aa085SMilanka Ringwald sscanf_bd_addr(device_addr_string, device_addr);
324462aa085SMilanka Ringwald btstack_stdin_setup(stdin_process);
325462aa085SMilanka Ringwald #endif
326462aa085SMilanka Ringwald printf("Starting BTstack ...\n");
327462aa085SMilanka Ringwald hci_power_control(HCI_POWER_ON);
328462aa085SMilanka Ringwald return 0;
329462aa085SMilanka Ringwald }
330462aa085SMilanka Ringwald /* LISTING_END */
331462aa085SMilanka Ringwald
avrcp_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)33202d2f9caSMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
33302d2f9caSMilanka Ringwald UNUSED(channel);
33402d2f9caSMilanka Ringwald UNUSED(size);
33502d2f9caSMilanka Ringwald uint16_t local_cid;
33602d2f9caSMilanka Ringwald uint8_t status = 0xFF;
33702d2f9caSMilanka Ringwald bd_addr_t adress;
33802d2f9caSMilanka Ringwald
33902d2f9caSMilanka Ringwald if (packet_type != HCI_EVENT_PACKET) return;
34002d2f9caSMilanka Ringwald if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
34102d2f9caSMilanka Ringwald switch (packet[2]){
34202d2f9caSMilanka Ringwald case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
34302d2f9caSMilanka Ringwald local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
34402d2f9caSMilanka Ringwald status = avrcp_subevent_connection_established_get_status(packet);
34502d2f9caSMilanka Ringwald if (status != ERROR_CODE_SUCCESS){
346fcd55a0bSMilanka Ringwald printf("AVRCP: Connection failed, status 0x%02x\n", status);
34702d2f9caSMilanka Ringwald avrcp_cid = 0;
34802d2f9caSMilanka Ringwald return;
34902d2f9caSMilanka Ringwald }
35002d2f9caSMilanka Ringwald
35102d2f9caSMilanka Ringwald avrcp_cid = local_cid;
352ace5ab2aSMilanka Ringwald avrcp_connected = true;
35302d2f9caSMilanka Ringwald avrcp_subevent_connection_established_get_bd_addr(packet, adress);
35402d2f9caSMilanka Ringwald printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(adress), avrcp_cid);
35502d2f9caSMilanka Ringwald return;
35602d2f9caSMilanka Ringwald }
35702d2f9caSMilanka Ringwald
35802d2f9caSMilanka Ringwald case AVRCP_SUBEVENT_CONNECTION_RELEASED:
35902d2f9caSMilanka Ringwald printf("AVRCP: Channel released: cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
36002d2f9caSMilanka Ringwald avrcp_cid = 0;
361ace5ab2aSMilanka Ringwald avrcp_connected = false;
36202d2f9caSMilanka Ringwald return;
36302d2f9caSMilanka Ringwald default:
36402d2f9caSMilanka Ringwald break;
36502d2f9caSMilanka Ringwald }
36602d2f9caSMilanka Ringwald }
367462aa085SMilanka Ringwald
a2dp_sink_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)3685666fff4SMilanka Ringwald static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
3695666fff4SMilanka Ringwald UNUSED(channel);
3705666fff4SMilanka Ringwald UNUSED(size);
3715666fff4SMilanka Ringwald bd_addr_t address;
3725666fff4SMilanka Ringwald uint8_t status;
3735666fff4SMilanka Ringwald
3745666fff4SMilanka Ringwald if (packet_type != HCI_EVENT_PACKET) return;
3755666fff4SMilanka Ringwald if (hci_event_packet_get_type(packet) != HCI_EVENT_A2DP_META) return;
3765666fff4SMilanka Ringwald
3775666fff4SMilanka Ringwald switch (packet[2]){
3785666fff4SMilanka Ringwald case A2DP_SUBEVENT_STREAM_ESTABLISHED:
3795666fff4SMilanka Ringwald a2dp_subevent_stream_established_get_bd_addr(packet, address);
3805666fff4SMilanka Ringwald status = a2dp_subevent_stream_established_get_status(packet);
3815666fff4SMilanka Ringwald
3826058cb0dSMatthias Ringwald if (status != ERROR_CODE_SUCCESS){
3835666fff4SMilanka Ringwald printf("A2DP Sink : Streaming connection failed, status 0x%02x\n", status);
3845666fff4SMilanka Ringwald break;
3855666fff4SMilanka Ringwald }
3865666fff4SMilanka Ringwald
3875666fff4SMilanka Ringwald a2dp_cid = a2dp_subevent_stream_established_get_a2dp_cid(packet);
3885666fff4SMilanka Ringwald memcpy(device_addr, address, 6);
3895666fff4SMilanka Ringwald printf("A2DP Sink: Connection established, address %s, a2dp_cid 0x%02x\n", bd_addr_to_str(address), a2dp_cid);
3905666fff4SMilanka Ringwald break;
3915666fff4SMilanka Ringwald
3925666fff4SMilanka Ringwald case A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
3935666fff4SMilanka Ringwald printf("A2DP Sink: Connection released\n");
3945666fff4SMilanka Ringwald break;
3955666fff4SMilanka Ringwald
3965666fff4SMilanka Ringwald default:
3975666fff4SMilanka Ringwald break;
3985666fff4SMilanka Ringwald }
3995666fff4SMilanka Ringwald }
4005666fff4SMilanka Ringwald
4015666fff4SMilanka Ringwald
avrcp_browsing_controller_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)4025666fff4SMilanka Ringwald static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
4035666fff4SMilanka Ringwald UNUSED(channel);
4045666fff4SMilanka Ringwald UNUSED(size);
4055666fff4SMilanka Ringwald bd_addr_t address;
4065666fff4SMilanka Ringwald uint8_t status;
4075666fff4SMilanka Ringwald uint16_t pos = 0;
4085666fff4SMilanka Ringwald uint16_t local_cid;
4095666fff4SMilanka Ringwald
4105666fff4SMilanka Ringwald // printf("avrcp_browsing_controller_packet_handler packet type 0x%02X, subevent 0x%02X\n", packet_type, packet[2]);
411954cc391SMilanka Ringwald switch (packet_type) {
4125666fff4SMilanka Ringwald case HCI_EVENT_PACKET:
4135666fff4SMilanka Ringwald switch (packet[0]){
4145666fff4SMilanka Ringwald case HCI_EVENT_AVRCP_META:
4155666fff4SMilanka Ringwald switch (packet[2]){
4165666fff4SMilanka Ringwald case AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED: {
4175666fff4SMilanka Ringwald local_cid = avrcp_subevent_browsing_connection_established_get_browsing_cid(packet);
4185666fff4SMilanka Ringwald status = avrcp_subevent_browsing_connection_established_get_status(packet);
4195666fff4SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){
420fcd55a0bSMilanka Ringwald printf("AVRCP: Connection failed, status 0x%02x\n", status);
4215666fff4SMilanka Ringwald browsing_cid = 0;
4225666fff4SMilanka Ringwald return;
4235666fff4SMilanka Ringwald }
4245666fff4SMilanka Ringwald avrcp_subevent_browsing_connection_established_get_bd_addr(packet, address);
4255666fff4SMilanka Ringwald browsing_cid = local_cid;
4265666fff4SMilanka Ringwald browsing_connected = true;
4275666fff4SMilanka Ringwald printf("AVRCP Browsing: Connection established, address %s, browsing_cid 0x%02x\n", bd_addr_to_str(address), browsing_cid);
4285666fff4SMilanka Ringwald return;
4295666fff4SMilanka Ringwald }
4305666fff4SMilanka Ringwald
4315666fff4SMilanka Ringwald case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED:
4325666fff4SMilanka Ringwald printf("AVRCP: Connection released, cid 0x%02x\n", avrcp_subevent_browsing_connection_released_get_browsing_cid(packet));
4335666fff4SMilanka Ringwald browsing_cid = 0;
4345666fff4SMilanka Ringwald browsing_connected = false;
4355666fff4SMilanka Ringwald return;
4365666fff4SMilanka Ringwald case AVRCP_SUBEVENT_BROWSING_DONE:
4375666fff4SMilanka Ringwald
4385666fff4SMilanka Ringwald browsing_query_active = 0;
4395666fff4SMilanka Ringwald browsing_uid_counter = 0;
4405666fff4SMilanka Ringwald if (avrcp_subevent_browsing_done_get_browsing_status(packet) != AVRCP_BROWSING_ERROR_CODE_SUCCESS){
4415666fff4SMilanka Ringwald printf("AVRCP Browsing query done with browsing status 0x%02x, bluetooth status 0x%02x.\n",
4425666fff4SMilanka Ringwald avrcp_subevent_browsing_done_get_browsing_status(packet),
4435666fff4SMilanka Ringwald avrcp_subevent_browsing_done_get_bluetooth_status(packet));
4445666fff4SMilanka Ringwald return;
4455666fff4SMilanka Ringwald }
4465666fff4SMilanka Ringwald browsing_uid_counter = avrcp_subevent_browsing_done_get_uid_counter(packet);
4475666fff4SMilanka Ringwald printf("DONE, browsing_uid_counter %d.\n", browsing_uid_counter);
4485666fff4SMilanka Ringwald
4495666fff4SMilanka Ringwald switch (browsing_state){
4505666fff4SMilanka Ringwald case AVRCP_BROWSING_STATE_W4_GET_PLAYERS:
4515666fff4SMilanka Ringwald if (media_player_item_index < 0) {
4525666fff4SMilanka Ringwald printf("Get media players first\n");
4535666fff4SMilanka Ringwald break;
4545666fff4SMilanka Ringwald }
4555666fff4SMilanka Ringwald printf("Set browsed player\n");
4565666fff4SMilanka Ringwald browsing_state = AVRCP_BROWSING_STATE_W4_SET_PLAYER;
4575666fff4SMilanka Ringwald status = avrcp_browsing_controller_set_browsed_player(browsing_cid, media_player_items[0].player_id);
4585666fff4SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){
459fcd55a0bSMilanka Ringwald printf("Could not set player, status 0x%02x\n", status);
4605666fff4SMilanka Ringwald status = AVRCP_BROWSING_STATE_W4_GET_PLAYERS;
4615666fff4SMilanka Ringwald break;
4625666fff4SMilanka Ringwald }
4635666fff4SMilanka Ringwald break;
4645666fff4SMilanka Ringwald case AVRCP_BROWSING_STATE_W4_SET_PLAYER:
4655666fff4SMilanka Ringwald browsing_state = AVRCP_BROWSING_STATE_READY;
4665666fff4SMilanka Ringwald break;
4675666fff4SMilanka Ringwald default:
4685666fff4SMilanka Ringwald break;
4695666fff4SMilanka Ringwald }
4705666fff4SMilanka Ringwald break;
4715666fff4SMilanka Ringwald default:
4725666fff4SMilanka Ringwald break;
4735666fff4SMilanka Ringwald }
4745666fff4SMilanka Ringwald
4755666fff4SMilanka Ringwald default:
4765666fff4SMilanka Ringwald break;
4775666fff4SMilanka Ringwald }
4785666fff4SMilanka Ringwald break;
4795666fff4SMilanka Ringwald
480954cc391SMilanka Ringwald case AVRCP_BROWSING_DATA_PACKET:
4815666fff4SMilanka Ringwald browsing_query_active = 1;
482954cc391SMilanka Ringwald avrcp_browsing_item_type_t data_type = (avrcp_browsing_item_type_t)packet[pos++];
483954cc391SMilanka Ringwald
484954cc391SMilanka Ringwald switch (data_type){
485db79553aSMilanka Ringwald case AVRCP_BROWSING_MEDIA_ROOT_FOLDER:{
4865666fff4SMilanka Ringwald uint16_t folder_name_length = size - pos;
4875666fff4SMilanka Ringwald char folder_name[AVRCP_MAX_FOLDER_NAME_SIZE];
4885666fff4SMilanka Ringwald memcpy(folder_name, &packet[pos], folder_name_length);
4895666fff4SMilanka Ringwald folder_name[folder_name_length] = 0;
4905666fff4SMilanka Ringwald printf("Found root folder: name %s \n", folder_name);
4915666fff4SMilanka Ringwald break;
4925666fff4SMilanka Ringwald }
4932f511ffbSMilanka Ringwald
494954cc391SMilanka Ringwald case AVRCP_BROWSING_FOLDER_ITEM:{
495db79553aSMilanka Ringwald int index = next_folder_index();
496db79553aSMilanka Ringwald memcpy(folders[index].uid, packet+pos, 8);
4975666fff4SMilanka Ringwald
498954cc391SMilanka Ringwald uint32_t folder_uid_high = big_endian_read_32(packet, pos);
499954cc391SMilanka Ringwald pos += 4;
500db79553aSMilanka Ringwald uint32_t folder_uid_low = big_endian_read_32(packet, pos);
501954cc391SMilanka Ringwald pos += 4;
502954cc391SMilanka Ringwald avrcp_browsing_folder_type_t folder_type = packet[pos++];
503954cc391SMilanka Ringwald uint8_t is_playable = packet[pos++];
504954cc391SMilanka Ringwald uint16_t charset = big_endian_read_16(packet, pos);
505954cc391SMilanka Ringwald pos += 2;
506954cc391SMilanka Ringwald uint16_t displayable_name_length = big_endian_read_16(packet, pos);
507954cc391SMilanka Ringwald pos += 2;
5082f511ffbSMilanka Ringwald
5095666fff4SMilanka Ringwald char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
5105666fff4SMilanka Ringwald memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN);
5115666fff4SMilanka Ringwald uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1);
512954cc391SMilanka Ringwald memcpy(value, packet+pos, value_len);
513db79553aSMilanka Ringwald
5145666fff4SMilanka Ringwald printf("Folder UID 0x%08" PRIx32 "%08" PRIx32 ", type 0x%02x, is_playable %d, charset 0x%02x, name %s\n",
5152f511ffbSMilanka Ringwald folder_uid_high, folder_uid_low, folder_type, is_playable, charset, value);
5165666fff4SMilanka Ringwald if (is_playable){
5175666fff4SMilanka Ringwald playable_folder_index = index;
5185666fff4SMilanka Ringwald }
519db79553aSMilanka Ringwald memcpy(folders[index].name, value, value_len);
520db79553aSMilanka Ringwald folders[index].name_len = value_len;
521954cc391SMilanka Ringwald break;
522954cc391SMilanka Ringwald }
523954cc391SMilanka Ringwald
5245666fff4SMilanka Ringwald case AVRCP_BROWSING_MEDIA_PLAYER_ITEM:{
5255666fff4SMilanka Ringwald printf("Received media player item: ");
5265666fff4SMilanka Ringwald uint16_t player_id = big_endian_read_16(packet, pos);
5275666fff4SMilanka Ringwald pos += 2;
5285666fff4SMilanka Ringwald avrcp_browsing_media_player_major_type_t major_type = packet[pos++];
5295666fff4SMilanka Ringwald avrcp_browsing_media_player_subtype_t subtype = big_endian_read_32(packet, pos);
530954cc391SMilanka Ringwald pos += 4;
5315666fff4SMilanka Ringwald status = packet[pos++];
5325666fff4SMilanka Ringwald uint8_t feature_bitmask[16];
5335666fff4SMilanka Ringwald memcpy(feature_bitmask, packet, 16);
5345666fff4SMilanka Ringwald pos += 16;
535fcd55a0bSMilanka Ringwald printf("player ID 0x%04x, major_type %d, subtype %d, status 0x%02x\n", player_id, major_type, subtype, status);
5365666fff4SMilanka Ringwald media_player_items[next_media_player_item_index()].player_id = player_id;
5375666fff4SMilanka Ringwald break;
5385666fff4SMilanka Ringwald }
5395666fff4SMilanka Ringwald
5405666fff4SMilanka Ringwald case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM:{
5415666fff4SMilanka Ringwald int index = next_media_element_item_index();
5425666fff4SMilanka Ringwald memcpy(media_element_items[index].uid, packet+pos, 8);
5435666fff4SMilanka Ringwald printf("Received media element item UID (index %d): ", index);
5445666fff4SMilanka Ringwald
5455666fff4SMilanka Ringwald // uint32_t media_uid_high = big_endian_read_32(packet, pos);
546954cc391SMilanka Ringwald pos += 4;
5475666fff4SMilanka Ringwald // uint32_t media_uid_low = big_endian_read_32(packet, pos+4);
5485666fff4SMilanka Ringwald pos += 4;
5495666fff4SMilanka Ringwald
550954cc391SMilanka Ringwald avrcp_browsing_media_type_t media_type = packet[pos++];
551954cc391SMilanka Ringwald uint16_t charset = big_endian_read_16(packet, pos);
552954cc391SMilanka Ringwald pos += 2;
553954cc391SMilanka Ringwald uint16_t displayable_name_length = big_endian_read_16(packet, pos);
554954cc391SMilanka Ringwald pos += 2;
5555666fff4SMilanka Ringwald
5565666fff4SMilanka Ringwald char value[AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN];
5575666fff4SMilanka Ringwald memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN);
5585666fff4SMilanka Ringwald uint16_t value_len = btstack_min(displayable_name_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1);
5595666fff4SMilanka Ringwald memcpy(value, packet+pos, value_len);
5605666fff4SMilanka Ringwald memcpy(media_element_items[index].name, value, value_len);
5615666fff4SMilanka Ringwald
562954cc391SMilanka Ringwald pos += displayable_name_length;
5635666fff4SMilanka 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);
564954cc391SMilanka Ringwald
5655666fff4SMilanka Ringwald printf_hexdump(media_element_items[index].uid, 8);
566954cc391SMilanka Ringwald uint8_t num_attributes = packet[pos++];
5675666fff4SMilanka 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);
568954cc391SMilanka Ringwald
5695666fff4SMilanka Ringwald avrcp_media_item_context_t media_item_context;
570954cc391SMilanka 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)){
571954cc391SMilanka Ringwald uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context);
572954cc391SMilanka Ringwald uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context);
573954cc391SMilanka Ringwald uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context);
574954cc391SMilanka Ringwald const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context);
575954cc391SMilanka Ringwald
5765666fff4SMilanka Ringwald memset(value, 0, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN);
5775666fff4SMilanka Ringwald value_len = btstack_min(attr_value_length, AVRCP_BROWSING_MAX_BROWSABLE_ITEM_NAME_LEN - 1);
5785666fff4SMilanka Ringwald memcpy(value, attr_value, value_len);
5795666fff4SMilanka Ringwald
5805666fff4SMilanka Ringwald printf(" - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, value_len, value);
581954cc391SMilanka Ringwald }
582954cc391SMilanka Ringwald break;
583954cc391SMilanka Ringwald }
584954cc391SMilanka Ringwald
5855666fff4SMilanka Ringwald case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE:{
5865666fff4SMilanka Ringwald uint8_t num_attributes = packet[pos++];
5875666fff4SMilanka Ringwald printf("Num media attributes %d:\n", num_attributes);
5885666fff4SMilanka Ringwald avrcp_media_item_context_t media_item_context;
5895666fff4SMilanka 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)){
5905666fff4SMilanka Ringwald uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context);
5915666fff4SMilanka Ringwald uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context);
5925666fff4SMilanka Ringwald uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context);
5935666fff4SMilanka Ringwald const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context);
5945666fff4SMilanka 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);
5955666fff4SMilanka Ringwald }
596*0ba57472SMatthias Ringwald break;
5975666fff4SMilanka Ringwald }
598954cc391SMilanka Ringwald default:
5995666fff4SMilanka Ringwald printf("AVRCP browsing: unknown browsable item type 0%02x\n", data_type);
600954cc391SMilanka Ringwald break;
601954cc391SMilanka Ringwald }
602954cc391SMilanka Ringwald break;
603462aa085SMilanka Ringwald default:
604462aa085SMilanka Ringwald break;
605462aa085SMilanka Ringwald }
606462aa085SMilanka Ringwald }
607462aa085SMilanka Ringwald
608462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
show_usage(void)609462aa085SMilanka Ringwald static void show_usage(void){
610462aa085SMilanka Ringwald bd_addr_t iut_address;
611462aa085SMilanka Ringwald gap_local_bd_addr(iut_address);
6128ee7c9daSMilanka Ringwald printf("\n--- Bluetooth AVRCP Browsing Service Test Console %s ---\n", bd_addr_to_str(iut_address));
6138ee7c9daSMilanka Ringwald printf("c - AVRCP Service create connection to addr %s\n", bd_addr_to_str(device_addr));
6148ee7c9daSMilanka Ringwald printf("C - AVRCP Service disconnect\n");
6158ee7c9daSMilanka Ringwald printf("e - AVRCP Browsing Service create connection to addr %s\n", bd_addr_to_str(device_addr));
6168ee7c9daSMilanka Ringwald printf("E - AVRCP Browsing Service disconnect\n");
617db79553aSMilanka Ringwald
618c0a054f6SMilanka Ringwald printf("I - Set first found player as addressed player\n");
619c0a054f6SMilanka Ringwald printf("O - Set first found player as browsed player\n");
620db79553aSMilanka Ringwald
621c0a054f6SMilanka Ringwald printf("p - Get media players\n");
622c0a054f6SMilanka Ringwald printf("Q - Browse folders\n");
623c0a054f6SMilanka Ringwald printf("P - Go up one level\n");
624c0a054f6SMilanka Ringwald printf("W - Go down one level\n");
625c0a054f6SMilanka Ringwald printf("T - Browse media items\n");
626462aa085SMilanka Ringwald printf("---\n");
627462aa085SMilanka Ringwald }
628462aa085SMilanka Ringwald #endif
629462aa085SMilanka Ringwald
630ed0df7b2SMilanka Ringwald
631462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
stdin_process(char cmd)632462aa085SMilanka Ringwald static void stdin_process(char cmd){
633462aa085SMilanka Ringwald uint8_t status = ERROR_CODE_SUCCESS;
634462aa085SMilanka Ringwald
635954cc391SMilanka Ringwald if (cmd != 'a' && cmd != 'A' && cmd != 'c' && cmd != 'C'){
636954cc391SMilanka Ringwald if (browsing_query_active){
637954cc391SMilanka Ringwald printf("Query active, try later!\n");
638954cc391SMilanka Ringwald return;
639954cc391SMilanka Ringwald }
640954cc391SMilanka Ringwald }
641954cc391SMilanka Ringwald
642462aa085SMilanka Ringwald switch (cmd){
6435666fff4SMilanka Ringwald case 'b':
644bab2ac96SMatthias Ringwald status = a2dp_sink_establish_stream(device_addr, &a2dp_cid);
6455666fff4SMilanka 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);
6465666fff4SMilanka Ringwald break;
6475666fff4SMilanka Ringwald case 'B':
6485666fff4SMilanka Ringwald printf(" - AVDTP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
6495666fff4SMilanka Ringwald a2dp_sink_disconnect(a2dp_cid);
6505666fff4SMilanka Ringwald break;
6515666fff4SMilanka Ringwald
652c0a054f6SMilanka Ringwald case 'c':
6538ee7c9daSMilanka Ringwald printf(" - Connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr));
654fe10780bSMilanka Ringwald status = avrcp_connect(device_addr, &avrcp_cid);
655462aa085SMilanka Ringwald break;
656c0a054f6SMilanka Ringwald case 'C':
657247956eaSMilanka Ringwald if (avrcp_connected){
6588ee7c9daSMilanka Ringwald printf(" - AVRCP Service disconnect from addr %s.\n", bd_addr_to_str(device_addr));
659fe10780bSMilanka Ringwald status = avrcp_disconnect(avrcp_cid);
660247956eaSMilanka Ringwald break;
661247956eaSMilanka Ringwald }
6628ee7c9daSMilanka Ringwald printf("AVRCP Service already disconnected\n");
663247956eaSMilanka Ringwald break;
664247956eaSMilanka Ringwald
665c0a054f6SMilanka Ringwald case 'e':
666462aa085SMilanka Ringwald if (!avrcp_connected) {
6678ee7c9daSMilanka Ringwald printf(" You must first connect to AVRCP Service on addr %s.\n", bd_addr_to_str(device_addr));
668462aa085SMilanka Ringwald break;
669462aa085SMilanka Ringwald }
6708ee7c9daSMilanka Ringwald printf(" - Connect to AVRCP Browsing Service at addr %s.\n", bd_addr_to_str(device_addr));
6713121b998SMilanka Ringwald status = avrcp_browsing_connect(device_addr, ertm_buffer, sizeof(ertm_buffer), &ertm_config, &browsing_cid);
672462aa085SMilanka Ringwald break;
673c0a054f6SMilanka Ringwald case 'E':
6745666fff4SMilanka Ringwald if (browsing_connected){
6758ee7c9daSMilanka Ringwald printf(" - AVRCP Browsing Service disconnect from addr %s.\n", bd_addr_to_str(device_addr));
6768ee7c9daSMilanka Ringwald status = avrcp_browsing_disconnect(browsing_cid);
677462aa085SMilanka Ringwald break;
678247956eaSMilanka Ringwald }
6798ee7c9daSMilanka Ringwald printf("AVRCP Browsing Service already disconnected\n");
680247956eaSMilanka Ringwald break;
681462aa085SMilanka Ringwald case '\n':
682462aa085SMilanka Ringwald case '\r':
683462aa085SMilanka Ringwald break;
684db79553aSMilanka Ringwald
685db79553aSMilanka Ringwald default:
6865666fff4SMilanka Ringwald if (!browsing_connected){
687db79553aSMilanka Ringwald show_usage();
688db79553aSMilanka Ringwald break;
689db79553aSMilanka Ringwald }
690db79553aSMilanka Ringwald
691db79553aSMilanka Ringwald switch (cmd) {
692c0a054f6SMilanka Ringwald case 'I':
6935666fff4SMilanka Ringwald if (media_player_item_index < 0) {
6948ee7c9daSMilanka Ringwald printf("AVRCP Browsing:Get media players first\n");
695db79553aSMilanka Ringwald break;
696db79553aSMilanka Ringwald }
6978ee7c9daSMilanka Ringwald printf("AVRCP Browsing:Set addressed player\n");
6985666fff4SMilanka Ringwald status = avrcp_controller_set_addressed_player(avrcp_cid, media_player_items[0].player_id);
699db79553aSMilanka Ringwald break;
700c0a054f6SMilanka Ringwald case 'O':
7015666fff4SMilanka Ringwald if (media_player_item_index < 0) {
7028ee7c9daSMilanka Ringwald printf("AVRCP Browsing:Get media players first\n");
703db79553aSMilanka Ringwald break;
704db79553aSMilanka Ringwald }
705db79553aSMilanka Ringwald printf("Set browsed player\n");
7065666fff4SMilanka Ringwald status = avrcp_browsing_controller_set_browsed_player(browsing_cid, media_player_items[0].player_id);
707db79553aSMilanka Ringwald break;
708c0a054f6SMilanka Ringwald case 'p':
709db79553aSMilanka Ringwald printf("AVRCP Browsing: get media players\n");
7105666fff4SMilanka Ringwald media_player_item_index = -1;
7112f511ffbSMilanka Ringwald status = avrcp_browsing_controller_get_media_players(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
712db79553aSMilanka Ringwald break;
713c0a054f6SMilanka Ringwald case 'Q':
714db79553aSMilanka Ringwald printf("AVRCP Browsing: browse folders\n");
715db79553aSMilanka Ringwald folder_index = -1;
7162f511ffbSMilanka Ringwald status = avrcp_browsing_controller_browse_file_system(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
717db79553aSMilanka Ringwald break;
718c0a054f6SMilanka Ringwald case 'P':
719db79553aSMilanka Ringwald printf("AVRCP Browsing: browse media items\n");
7202f511ffbSMilanka Ringwald avrcp_browsing_controller_browse_media(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
721db79553aSMilanka Ringwald break;
722c0a054f6SMilanka Ringwald case 'W':
723e5b24613SMilanka Ringwald printf("AVRCP Browsing: go up one level\n");
724e5b24613SMilanka Ringwald status = avrcp_browsing_controller_go_up_one_level(browsing_cid);
725db79553aSMilanka Ringwald folder_index = -1;
726db79553aSMilanka Ringwald break;
727c0a054f6SMilanka Ringwald case 'T':
728db79553aSMilanka Ringwald if (folder_index < 0 && !parent_folder_set){
729db79553aSMilanka Ringwald printf("AVRCP Browsing: no folders available\n");
730db79553aSMilanka Ringwald break;
731db79553aSMilanka Ringwald }
732db79553aSMilanka Ringwald if (!parent_folder_set){
733db79553aSMilanka Ringwald parent_folder_set = 1;
734db79553aSMilanka Ringwald memcpy(parent_folder_name, folders[0].name, folders[0].name_len);
735db79553aSMilanka Ringwald memcpy(parent_folder_uid, folders[0].uid, 8);
736db79553aSMilanka Ringwald }
737db79553aSMilanka Ringwald printf("AVRCP Browsing: go down one level of %s\n", (char *)parent_folder_name);
738db79553aSMilanka Ringwald status = avrcp_browsing_controller_go_down_one_level(browsing_cid, parent_folder_uid);
739db79553aSMilanka Ringwald folder_index = -1;
740db79553aSMilanka Ringwald break;
741462aa085SMilanka Ringwald default:
742462aa085SMilanka Ringwald show_usage();
743db79553aSMilanka Ringwald break;
744db79553aSMilanka Ringwald }
745db79553aSMilanka Ringwald break;
746462aa085SMilanka Ringwald }
747ed0df7b2SMilanka Ringwald
748462aa085SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){
7498ee7c9daSMilanka Ringwald printf("AVRCP Browsing: Could not perform command, status 0x%2x\n", status);
750462aa085SMilanka Ringwald }
751462aa085SMilanka Ringwald }
752462aa085SMilanka Ringwald #endif
753462aa085SMilanka Ringwald /* EXAMPLE_END */
754