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