xref: /btstack/example/avrcp_browsing_client.c (revision 462aa08556a49e21346cab6e370aae63597ea15b)
1*462aa085SMilanka Ringwald /*
2*462aa085SMilanka Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3*462aa085SMilanka Ringwald  *
4*462aa085SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5*462aa085SMilanka Ringwald  * modification, are permitted provided that the following conditions
6*462aa085SMilanka Ringwald  * are met:
7*462aa085SMilanka Ringwald  *
8*462aa085SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9*462aa085SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10*462aa085SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*462aa085SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*462aa085SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13*462aa085SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*462aa085SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15*462aa085SMilanka Ringwald  *    from this software without specific prior written permission.
16*462aa085SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*462aa085SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18*462aa085SMilanka Ringwald  *    monetary gain.
19*462aa085SMilanka Ringwald  *
20*462aa085SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*462aa085SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*462aa085SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*462aa085SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*462aa085SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*462aa085SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*462aa085SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*462aa085SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*462aa085SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*462aa085SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*462aa085SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*462aa085SMilanka Ringwald  * SUCH DAMAGE.
32*462aa085SMilanka Ringwald  *
33*462aa085SMilanka Ringwald  * Please inquire about commercial licensing options at
34*462aa085SMilanka Ringwald  * [email protected]
35*462aa085SMilanka Ringwald  *
36*462aa085SMilanka Ringwald  */
37*462aa085SMilanka Ringwald 
38*462aa085SMilanka Ringwald #define __BTSTACK_FILE__ "avrcp_browsing_client.c"
39*462aa085SMilanka Ringwald 
40*462aa085SMilanka Ringwald /*
41*462aa085SMilanka Ringwald  * avrcp_browsing_client.c
42*462aa085SMilanka Ringwald  */
43*462aa085SMilanka Ringwald 
44*462aa085SMilanka Ringwald // *****************************************************************************
45*462aa085SMilanka Ringwald /* EXAMPLE_START(avrcp_browsing_client): Browse media players and media information on a remote device.
46*462aa085SMilanka Ringwald  *
47*462aa085SMilanka Ringwald  * @text This example demonstrates how to use the AVRCP Controller Browsing service to
48*462aa085SMilanka Ringwald  * browse madia players and media information on a remote AVRCP Source device.
49*462aa085SMilanka Ringwald  *
50*462aa085SMilanka Ringwald  * @test To test with a remote device, e.g. a mobile phone,
51*462aa085SMilanka Ringwald  * pair from the remote device with the demo, then use the UI for browsing (tap
52*462aa085SMilanka Ringwald  * SPACE on the console to show the available AVRCP commands).
53*462aa085SMilanka Ringwald  *
54*462aa085SMilanka Ringwald  */
55*462aa085SMilanka Ringwald // *****************************************************************************
56*462aa085SMilanka Ringwald 
57*462aa085SMilanka Ringwald #include <stdint.h>
58*462aa085SMilanka Ringwald #include <stdio.h>
59*462aa085SMilanka Ringwald #include <stdlib.h>
60*462aa085SMilanka Ringwald #include <string.h>
61*462aa085SMilanka Ringwald 
62*462aa085SMilanka Ringwald #include "btstack.h"
63*462aa085SMilanka Ringwald #include "avrcp_browsing_controller.h"
64*462aa085SMilanka Ringwald 
65*462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
66*462aa085SMilanka Ringwald #include "btstack_stdin.h"
67*462aa085SMilanka Ringwald #endif
68*462aa085SMilanka Ringwald 
69*462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
70*462aa085SMilanka Ringwald // mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3};
71*462aa085SMilanka Ringwald // pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5};
72*462aa085SMilanka Ringwald // mac 2013:
73*462aa085SMilanka Ringwald // static const char * device_addr_string = "84:38:35:65:d1:15";
74*462aa085SMilanka Ringwald // iPhone 5S: static const char * device_addr_string = "54:E4:3A:26:A2:39";
75*462aa085SMilanka Ringwald // phone 2013:
76*462aa085SMilanka Ringwald static const char * device_addr_string = "D8:BB:2C:DF:F1:08";
77*462aa085SMilanka Ringwald static bd_addr_t device_addr;
78*462aa085SMilanka Ringwald #endif
79*462aa085SMilanka Ringwald 
80*462aa085SMilanka Ringwald static uint16_t avrcp_cid = 0;
81*462aa085SMilanka Ringwald static uint8_t  avrcp_connected = 0;
82*462aa085SMilanka Ringwald 
83*462aa085SMilanka Ringwald static uint16_t browsing_cid = 0;
84*462aa085SMilanka Ringwald static uint8_t  avrcp_browsing_connected = 0;
85*462aa085SMilanka Ringwald static uint8_t  sdp_avrcp_browsing_controller_service_buffer[200];
86*462aa085SMilanka Ringwald 
87*462aa085SMilanka Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
88*462aa085SMilanka Ringwald 
89*462aa085SMilanka Ringwald static uint8_t ertm_buffer[10000];
90*462aa085SMilanka Ringwald static l2cap_ertm_config_t ertm_config = {
91*462aa085SMilanka Ringwald     1,  // ertm mandatory
92*462aa085SMilanka Ringwald     2,  // max transmit, some tests require > 1
93*462aa085SMilanka Ringwald     2000,
94*462aa085SMilanka Ringwald     12000,
95*462aa085SMilanka Ringwald     144,    // l2cap ertm mtu
96*462aa085SMilanka Ringwald     4,
97*462aa085SMilanka Ringwald     4,
98*462aa085SMilanka Ringwald };
99*462aa085SMilanka Ringwald 
100*462aa085SMilanka Ringwald 
101*462aa085SMilanka Ringwald /* @section Main Application Setup
102*462aa085SMilanka Ringwald  *
103*462aa085SMilanka Ringwald  * @text The Listing MainConfiguration shows how to setup AVRCP Controller Browsing service.
104*462aa085SMilanka Ringwald  * To announce AVRCP Controller Browsing service, you need to create corresponding
105*462aa085SMilanka Ringwald  * SDP record and register it with the SDP service.
106*462aa085SMilanka Ringwald  * You'll also need to register several packet handlers:
107*462aa085SMilanka Ringwald  * - stdin_process callback - used to trigger AVRCP commands, such are get media players, playlists, albums, etc. Requires HAVE_BTSTACK_STDIN.
108*462aa085SMilanka Ringwald  * - avrcp_browsing_controller_packet_handler - used to receive answers for AVRCP commands.
109*462aa085SMilanka Ringwald  *
110*462aa085SMilanka Ringwald  */
111*462aa085SMilanka Ringwald 
112*462aa085SMilanka Ringwald /* LISTING_START(MainConfiguration): Setup Audio Sink and AVRCP Controller services */
113*462aa085SMilanka Ringwald static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
114*462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
115*462aa085SMilanka Ringwald static void stdin_process(char cmd);
116*462aa085SMilanka Ringwald #endif
117*462aa085SMilanka Ringwald 
118*462aa085SMilanka Ringwald #define BROWSING_ENABLED 1
119*462aa085SMilanka Ringwald 
120*462aa085SMilanka Ringwald int btstack_main(int argc, const char * argv[]);
121*462aa085SMilanka Ringwald int btstack_main(int argc, const char * argv[]){
122*462aa085SMilanka Ringwald     (void)argc;
123*462aa085SMilanka Ringwald     (void)argv;
124*462aa085SMilanka Ringwald 
125*462aa085SMilanka Ringwald     // Register for HCI events.
126*462aa085SMilanka Ringwald     hci_event_callback_registration.callback = &avrcp_browsing_controller_packet_handler;
127*462aa085SMilanka Ringwald     hci_add_event_handler(&hci_event_callback_registration);
128*462aa085SMilanka Ringwald 
129*462aa085SMilanka Ringwald     // Initialize L2CAP.
130*462aa085SMilanka Ringwald     l2cap_init();
131*462aa085SMilanka Ringwald 
132*462aa085SMilanka Ringwald     // Initialize AVRCP Controller.
133*462aa085SMilanka Ringwald     avrcp_controller_init();
134*462aa085SMilanka Ringwald     // Register AVRCP for HCI events.
135*462aa085SMilanka Ringwald     avrcp_controller_register_packet_handler(&avrcp_browsing_controller_packet_handler);
136*462aa085SMilanka Ringwald 
137*462aa085SMilanka Ringwald     // Initialize AVRCP Controller.
138*462aa085SMilanka Ringwald     avrcp_browsing_controller_init();
139*462aa085SMilanka Ringwald     // Register AVRCP for HCI events.
140*462aa085SMilanka Ringwald     avrcp_browsing_controller_register_packet_handler(&avrcp_browsing_controller_packet_handler);
141*462aa085SMilanka Ringwald 
142*462aa085SMilanka Ringwald     // Initialize SDP.
143*462aa085SMilanka Ringwald     sdp_init();
144*462aa085SMilanka Ringwald 
145*462aa085SMilanka Ringwald     // Create AVRCP service record and register it with SDP.
146*462aa085SMilanka Ringwald     memset(sdp_avrcp_browsing_controller_service_buffer, 0, sizeof(sdp_avrcp_browsing_controller_service_buffer));
147*462aa085SMilanka Ringwald     avrcp_controller_create_sdp_record(sdp_avrcp_browsing_controller_service_buffer, 0x10001, BROWSING_ENABLED, 1, NULL, NULL);
148*462aa085SMilanka Ringwald     sdp_register_service(sdp_avrcp_browsing_controller_service_buffer);
149*462aa085SMilanka Ringwald 
150*462aa085SMilanka Ringwald     // Set local name with a template Bluetooth address, that will be automatically
151*462aa085SMilanka Ringwald     // replaced with a actual address once it is available, i.e. when BTstack boots
152*462aa085SMilanka Ringwald     // up and starts talking to a Bluetooth module.
153*462aa085SMilanka Ringwald     gap_set_local_name("AVRCP Browsing Client 00:00:00:00:00:00");
154*462aa085SMilanka Ringwald     gap_discoverable_control(1);
155*462aa085SMilanka Ringwald     gap_set_class_of_device(0x200408);
156*462aa085SMilanka Ringwald 
157*462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
158*462aa085SMilanka Ringwald     // Parse human readable Bluetooth address.
159*462aa085SMilanka Ringwald     sscanf_bd_addr(device_addr_string, device_addr);
160*462aa085SMilanka Ringwald     btstack_stdin_setup(stdin_process);
161*462aa085SMilanka Ringwald #endif
162*462aa085SMilanka Ringwald     printf("Starting BTstack ...\n");
163*462aa085SMilanka Ringwald     hci_power_control(HCI_POWER_ON);
164*462aa085SMilanka Ringwald     return 0;
165*462aa085SMilanka Ringwald }
166*462aa085SMilanka Ringwald /* LISTING_END */
167*462aa085SMilanka Ringwald 
168*462aa085SMilanka Ringwald 
169*462aa085SMilanka Ringwald static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
170*462aa085SMilanka Ringwald     UNUSED(channel);
171*462aa085SMilanka Ringwald     UNUSED(size);
172*462aa085SMilanka Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
173*462aa085SMilanka Ringwald     if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
174*462aa085SMilanka Ringwald 
175*462aa085SMilanka Ringwald     uint16_t local_cid;
176*462aa085SMilanka Ringwald     uint8_t  status = 0xFF;
177*462aa085SMilanka Ringwald     bd_addr_t adress;
178*462aa085SMilanka Ringwald 
179*462aa085SMilanka Ringwald     switch (packet[2]){
180*462aa085SMilanka Ringwald         case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
181*462aa085SMilanka Ringwald             local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet);
182*462aa085SMilanka Ringwald             if (browsing_cid != 0 && browsing_cid != local_cid) {
183*462aa085SMilanka Ringwald                 printf("AVRCP Browsing Client: Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", browsing_cid, local_cid);
184*462aa085SMilanka Ringwald                 return;
185*462aa085SMilanka Ringwald             }
186*462aa085SMilanka Ringwald 
187*462aa085SMilanka Ringwald             status = avrcp_subevent_connection_established_get_status(packet);
188*462aa085SMilanka Ringwald             if (status != ERROR_CODE_SUCCESS){
189*462aa085SMilanka Ringwald                 printf("AVRCP Browsing Client: Connection failed: status 0x%02x\n", status);
190*462aa085SMilanka Ringwald                 browsing_cid = 0;
191*462aa085SMilanka Ringwald                 return;
192*462aa085SMilanka Ringwald             }
193*462aa085SMilanka Ringwald 
194*462aa085SMilanka Ringwald             avrcp_cid = local_cid;
195*462aa085SMilanka Ringwald             avrcp_connected = 1;
196*462aa085SMilanka Ringwald             avrcp_subevent_connection_established_get_bd_addr(packet, adress);
197*462aa085SMilanka Ringwald             printf("AVRCP Browsing Client: Channel successfully opened: %s, browsing_cid 0x%02x\n", bd_addr_to_str(adress), avrcp_cid);
198*462aa085SMilanka Ringwald             return;
199*462aa085SMilanka Ringwald         }
200*462aa085SMilanka Ringwald         case AVRCP_SUBEVENT_CONNECTION_RELEASED:
201*462aa085SMilanka Ringwald             printf("AVRCP Browsing Client: Channel released: browsing_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet));
202*462aa085SMilanka Ringwald             browsing_cid = 0;
203*462aa085SMilanka Ringwald             avrcp_browsing_connected = 0;
204*462aa085SMilanka Ringwald             return;
205*462aa085SMilanka Ringwald 
206*462aa085SMilanka Ringwald         case AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED: {
207*462aa085SMilanka Ringwald             local_cid = avrcp_subevent_browsing_connection_established_get_browsing_cid(packet);
208*462aa085SMilanka Ringwald             if (browsing_cid != 0 && browsing_cid != local_cid) {
209*462aa085SMilanka Ringwald                 printf("AVRCP Browsing Client: Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", browsing_cid, local_cid);
210*462aa085SMilanka Ringwald                 return;
211*462aa085SMilanka Ringwald             }
212*462aa085SMilanka Ringwald 
213*462aa085SMilanka Ringwald             status = avrcp_subevent_browsing_connection_established_get_status(packet);
214*462aa085SMilanka Ringwald             if (status != ERROR_CODE_SUCCESS){
215*462aa085SMilanka Ringwald                 printf("AVRCP Browsing Client: Connection failed: status 0x%02x\n", status);
216*462aa085SMilanka Ringwald                 browsing_cid = 0;
217*462aa085SMilanka Ringwald                 return;
218*462aa085SMilanka Ringwald             }
219*462aa085SMilanka Ringwald 
220*462aa085SMilanka Ringwald             browsing_cid = local_cid;
221*462aa085SMilanka Ringwald             avrcp_browsing_connected = 1;
222*462aa085SMilanka Ringwald             avrcp_subevent_browsing_connection_established_get_bd_addr(packet, adress);
223*462aa085SMilanka Ringwald             printf("AVRCP Browsing Client: Channel successfully opened: %s, browsing_cid 0x%02x\n", bd_addr_to_str(adress), browsing_cid);
224*462aa085SMilanka Ringwald             return;
225*462aa085SMilanka Ringwald         }
226*462aa085SMilanka Ringwald         case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED:
227*462aa085SMilanka Ringwald             printf("AVRCP Browsing Client: Channel released: browsing_cid 0x%02x\n", avrcp_subevent_browsing_connection_released_get_browsing_cid(packet));
228*462aa085SMilanka Ringwald             browsing_cid = 0;
229*462aa085SMilanka Ringwald             avrcp_browsing_connected = 0;
230*462aa085SMilanka Ringwald             return;
231*462aa085SMilanka Ringwald         default:
232*462aa085SMilanka Ringwald             printf("AVRCP Browsing Client: event is not parsed\n");
233*462aa085SMilanka Ringwald             break;
234*462aa085SMilanka Ringwald     }
235*462aa085SMilanka Ringwald }
236*462aa085SMilanka Ringwald 
237*462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
238*462aa085SMilanka Ringwald static void show_usage(void){
239*462aa085SMilanka Ringwald     bd_addr_t      iut_address;
240*462aa085SMilanka Ringwald     gap_local_bd_addr(iut_address);
241*462aa085SMilanka Ringwald     printf("\n--- Bluetooth AVRCP Controller Connection Test Console %s ---\n", bd_addr_to_str(iut_address));
242*462aa085SMilanka Ringwald     printf("c      - AVRCP create connection for browsing to addr %s\n", bd_addr_to_str(device_addr));
243*462aa085SMilanka Ringwald     printf("C      - AVRCP disconnect\n");
244*462aa085SMilanka Ringwald     printf("---\n");
245*462aa085SMilanka Ringwald }
246*462aa085SMilanka Ringwald #endif
247*462aa085SMilanka Ringwald 
248*462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN
249*462aa085SMilanka Ringwald static void stdin_process(char cmd){
250*462aa085SMilanka Ringwald     uint8_t status = ERROR_CODE_SUCCESS;
251*462aa085SMilanka Ringwald 
252*462aa085SMilanka Ringwald     switch (cmd){
253*462aa085SMilanka Ringwald         case 'a':
254*462aa085SMilanka Ringwald             printf(" - Create AVRCP connection for controll to addr %s.\n", bd_addr_to_str(device_addr));
255*462aa085SMilanka Ringwald             status = avrcp_controller_connect(device_addr, &avrcp_cid);
256*462aa085SMilanka Ringwald             break;
257*462aa085SMilanka Ringwald         case 'c':
258*462aa085SMilanka Ringwald             if (!avrcp_connected) {
259*462aa085SMilanka Ringwald                 printf(" You must first create AVRCP connection for controll to addr %s.\n", bd_addr_to_str(device_addr));
260*462aa085SMilanka Ringwald                 break;
261*462aa085SMilanka Ringwald             }
262*462aa085SMilanka Ringwald             printf(" - Create AVRCP connection for browsing to addr %s.\n", bd_addr_to_str(device_addr));
263*462aa085SMilanka Ringwald             status = avrcp_browsing_controller_connect(device_addr, ertm_buffer, sizeof(ertm_buffer), &ertm_config, &browsing_cid);
264*462aa085SMilanka Ringwald             break;
265*462aa085SMilanka Ringwald         case 'C':
266*462aa085SMilanka Ringwald             printf(" - AVRCP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
267*462aa085SMilanka Ringwald             status = avrcp_browsing_controller_disconnect(browsing_cid);
268*462aa085SMilanka Ringwald             break;
269*462aa085SMilanka Ringwald         case '\n':
270*462aa085SMilanka Ringwald         case '\r':
271*462aa085SMilanka Ringwald             break;
272*462aa085SMilanka Ringwald         default:
273*462aa085SMilanka Ringwald             show_usage();
274*462aa085SMilanka Ringwald             return;
275*462aa085SMilanka Ringwald     }
276*462aa085SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
277*462aa085SMilanka Ringwald         printf("Could not perform command, status 0x%2x\n", status);
278*462aa085SMilanka Ringwald     }
279*462aa085SMilanka Ringwald }
280*462aa085SMilanka Ringwald #endif
281*462aa085SMilanka Ringwald /* EXAMPLE_END */
282