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