1462aa085SMilanka Ringwald /* 2462aa085SMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3462aa085SMilanka Ringwald * 4462aa085SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5462aa085SMilanka Ringwald * modification, are permitted provided that the following conditions 6462aa085SMilanka Ringwald * are met: 7462aa085SMilanka Ringwald * 8462aa085SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9462aa085SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10462aa085SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11462aa085SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12462aa085SMilanka Ringwald * documentation and/or other materials provided with the distribution. 13462aa085SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14462aa085SMilanka Ringwald * contributors may be used to endorse or promote products derived 15462aa085SMilanka Ringwald * from this software without specific prior written permission. 16462aa085SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17462aa085SMilanka Ringwald * personal benefit and not for any commercial purpose or for 18462aa085SMilanka Ringwald * monetary gain. 19462aa085SMilanka Ringwald * 20462aa085SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21462aa085SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22462aa085SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23462aa085SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24462aa085SMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25462aa085SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26462aa085SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27462aa085SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28462aa085SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29462aa085SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30462aa085SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31462aa085SMilanka Ringwald * SUCH DAMAGE. 32462aa085SMilanka Ringwald * 33462aa085SMilanka Ringwald * Please inquire about commercial licensing options at 34462aa085SMilanka Ringwald * [email protected] 35462aa085SMilanka Ringwald * 36462aa085SMilanka Ringwald */ 37462aa085SMilanka Ringwald 38462aa085SMilanka Ringwald #define __BTSTACK_FILE__ "avrcp_browsing_client.c" 39462aa085SMilanka Ringwald 40462aa085SMilanka Ringwald /* 41462aa085SMilanka Ringwald * avrcp_browsing_client.c 42462aa085SMilanka Ringwald */ 43462aa085SMilanka Ringwald 44462aa085SMilanka Ringwald // ***************************************************************************** 45462aa085SMilanka Ringwald /* EXAMPLE_START(avrcp_browsing_client): Browse media players and media information on a remote device. 46462aa085SMilanka Ringwald * 47462aa085SMilanka Ringwald * @text This example demonstrates how to use the AVRCP Controller Browsing service to 48462aa085SMilanka Ringwald * browse madia players and media information on a remote AVRCP Source device. 49462aa085SMilanka Ringwald * 50462aa085SMilanka Ringwald * @test To test with a remote device, e.g. a mobile phone, 51462aa085SMilanka Ringwald * pair from the remote device with the demo, then use the UI for browsing (tap 52462aa085SMilanka Ringwald * SPACE on the console to show the available AVRCP commands). 53462aa085SMilanka Ringwald * 54462aa085SMilanka Ringwald */ 55462aa085SMilanka Ringwald // ***************************************************************************** 56462aa085SMilanka Ringwald 57462aa085SMilanka Ringwald #include <stdint.h> 58462aa085SMilanka Ringwald #include <stdio.h> 59462aa085SMilanka Ringwald #include <stdlib.h> 60462aa085SMilanka Ringwald #include <string.h> 61462aa085SMilanka Ringwald 62462aa085SMilanka Ringwald #include "btstack.h" 63462aa085SMilanka Ringwald #include "avrcp_browsing_controller.h" 64462aa085SMilanka Ringwald 65462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 66462aa085SMilanka Ringwald #include "btstack_stdin.h" 67462aa085SMilanka Ringwald #endif 68462aa085SMilanka Ringwald 69462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 70462aa085SMilanka Ringwald // mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3}; 71462aa085SMilanka Ringwald // pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5}; 72462aa085SMilanka Ringwald // mac 2013: 73462aa085SMilanka Ringwald // static const char * device_addr_string = "84:38:35:65:d1:15"; 74462aa085SMilanka Ringwald // iPhone 5S: static const char * device_addr_string = "54:E4:3A:26:A2:39"; 75462aa085SMilanka Ringwald // phone 2013: 76462aa085SMilanka Ringwald static const char * device_addr_string = "D8:BB:2C:DF:F1:08"; 77462aa085SMilanka Ringwald static bd_addr_t device_addr; 78462aa085SMilanka Ringwald #endif 79462aa085SMilanka Ringwald 80462aa085SMilanka Ringwald static uint16_t avrcp_cid = 0; 81462aa085SMilanka Ringwald static uint8_t avrcp_connected = 0; 82462aa085SMilanka Ringwald 83462aa085SMilanka Ringwald static uint16_t browsing_cid = 0; 84462aa085SMilanka Ringwald static uint8_t avrcp_browsing_connected = 0; 85462aa085SMilanka Ringwald static uint8_t sdp_avrcp_browsing_controller_service_buffer[200]; 86462aa085SMilanka Ringwald 87462aa085SMilanka Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 88462aa085SMilanka Ringwald 89462aa085SMilanka Ringwald static uint8_t ertm_buffer[10000]; 90462aa085SMilanka Ringwald static l2cap_ertm_config_t ertm_config = { 91462aa085SMilanka Ringwald 1, // ertm mandatory 92462aa085SMilanka Ringwald 2, // max transmit, some tests require > 1 93462aa085SMilanka Ringwald 2000, 94462aa085SMilanka Ringwald 12000, 95462aa085SMilanka Ringwald 144, // l2cap ertm mtu 96462aa085SMilanka Ringwald 4, 97462aa085SMilanka Ringwald 4, 98462aa085SMilanka Ringwald }; 99462aa085SMilanka Ringwald 100462aa085SMilanka Ringwald 101462aa085SMilanka Ringwald /* @section Main Application Setup 102462aa085SMilanka Ringwald * 103462aa085SMilanka Ringwald * @text The Listing MainConfiguration shows how to setup AVRCP Controller Browsing service. 104462aa085SMilanka Ringwald * To announce AVRCP Controller Browsing service, you need to create corresponding 105462aa085SMilanka Ringwald * SDP record and register it with the SDP service. 106462aa085SMilanka Ringwald * You'll also need to register several packet handlers: 107462aa085SMilanka Ringwald * - stdin_process callback - used to trigger AVRCP commands, such are get media players, playlists, albums, etc. Requires HAVE_BTSTACK_STDIN. 108462aa085SMilanka Ringwald * - avrcp_browsing_controller_packet_handler - used to receive answers for AVRCP commands. 109462aa085SMilanka Ringwald * 110462aa085SMilanka Ringwald */ 111462aa085SMilanka Ringwald 112462aa085SMilanka Ringwald /* LISTING_START(MainConfiguration): Setup Audio Sink and AVRCP Controller services */ 113462aa085SMilanka Ringwald static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 114462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 115462aa085SMilanka Ringwald static void stdin_process(char cmd); 116462aa085SMilanka Ringwald #endif 117462aa085SMilanka Ringwald 118462aa085SMilanka Ringwald #define BROWSING_ENABLED 1 119462aa085SMilanka Ringwald 120462aa085SMilanka Ringwald int btstack_main(int argc, const char * argv[]); 121462aa085SMilanka Ringwald int btstack_main(int argc, const char * argv[]){ 122462aa085SMilanka Ringwald (void)argc; 123462aa085SMilanka Ringwald (void)argv; 124462aa085SMilanka Ringwald 125462aa085SMilanka Ringwald // Register for HCI events. 126462aa085SMilanka Ringwald hci_event_callback_registration.callback = &avrcp_browsing_controller_packet_handler; 127462aa085SMilanka Ringwald hci_add_event_handler(&hci_event_callback_registration); 128462aa085SMilanka Ringwald 129462aa085SMilanka Ringwald // Initialize L2CAP. 130462aa085SMilanka Ringwald l2cap_init(); 131462aa085SMilanka Ringwald 132462aa085SMilanka Ringwald // Initialize AVRCP Controller. 133462aa085SMilanka Ringwald avrcp_controller_init(); 134462aa085SMilanka Ringwald // Register AVRCP for HCI events. 135462aa085SMilanka Ringwald avrcp_controller_register_packet_handler(&avrcp_browsing_controller_packet_handler); 136462aa085SMilanka Ringwald 137247956eaSMilanka Ringwald // Initialize AVRCP Browsing Controller, HCI events will be sent to the AVRCP Controller callback. 138462aa085SMilanka Ringwald avrcp_browsing_controller_init(); 139*e30788a3SMilanka Ringwald // // Register AVRCP for HCI events. 140*e30788a3SMilanka Ringwald // avrcp_browsing_controller_register_packet_handler(&avrcp_browsing_controller_packet_handler); 141462aa085SMilanka Ringwald 142462aa085SMilanka Ringwald // Initialize SDP. 143462aa085SMilanka Ringwald sdp_init(); 144462aa085SMilanka Ringwald 145462aa085SMilanka Ringwald // Create AVRCP service record and register it with SDP. 146462aa085SMilanka Ringwald memset(sdp_avrcp_browsing_controller_service_buffer, 0, sizeof(sdp_avrcp_browsing_controller_service_buffer)); 147462aa085SMilanka Ringwald avrcp_controller_create_sdp_record(sdp_avrcp_browsing_controller_service_buffer, 0x10001, BROWSING_ENABLED, 1, NULL, NULL); 148462aa085SMilanka Ringwald sdp_register_service(sdp_avrcp_browsing_controller_service_buffer); 149462aa085SMilanka Ringwald 150462aa085SMilanka Ringwald // Set local name with a template Bluetooth address, that will be automatically 151462aa085SMilanka Ringwald // replaced with a actual address once it is available, i.e. when BTstack boots 152462aa085SMilanka Ringwald // up and starts talking to a Bluetooth module. 153462aa085SMilanka Ringwald gap_set_local_name("AVRCP Browsing Client 00:00:00:00:00:00"); 154462aa085SMilanka Ringwald gap_discoverable_control(1); 155462aa085SMilanka Ringwald gap_set_class_of_device(0x200408); 156462aa085SMilanka Ringwald 157462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 158462aa085SMilanka Ringwald // Parse human readable Bluetooth address. 159462aa085SMilanka Ringwald sscanf_bd_addr(device_addr_string, device_addr); 160462aa085SMilanka Ringwald btstack_stdin_setup(stdin_process); 161462aa085SMilanka Ringwald #endif 162462aa085SMilanka Ringwald printf("Starting BTstack ...\n"); 163462aa085SMilanka Ringwald hci_power_control(HCI_POWER_ON); 164462aa085SMilanka Ringwald return 0; 165462aa085SMilanka Ringwald } 166462aa085SMilanka Ringwald /* LISTING_END */ 167462aa085SMilanka Ringwald 168462aa085SMilanka Ringwald 169462aa085SMilanka Ringwald static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 170462aa085SMilanka Ringwald UNUSED(channel); 171462aa085SMilanka Ringwald UNUSED(size); 172462aa085SMilanka Ringwald if (packet_type != HCI_EVENT_PACKET) return; 173462aa085SMilanka Ringwald if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return; 174462aa085SMilanka Ringwald 175462aa085SMilanka Ringwald uint16_t local_cid; 176462aa085SMilanka Ringwald uint8_t status = 0xFF; 177462aa085SMilanka Ringwald bd_addr_t adress; 178462aa085SMilanka Ringwald 179462aa085SMilanka Ringwald switch (packet[2]){ 180462aa085SMilanka Ringwald case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: { 181462aa085SMilanka Ringwald local_cid = avrcp_subevent_connection_established_get_avrcp_cid(packet); 182462aa085SMilanka Ringwald if (browsing_cid != 0 && browsing_cid != local_cid) { 183247956eaSMilanka Ringwald printf("AVRCP Browsing Client: AVRCP Controller connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", browsing_cid, local_cid); 184462aa085SMilanka Ringwald return; 185462aa085SMilanka Ringwald } 186462aa085SMilanka Ringwald 187462aa085SMilanka Ringwald status = avrcp_subevent_connection_established_get_status(packet); 188462aa085SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 189247956eaSMilanka Ringwald printf("AVRCP Browsing Client: AVRCP Controller connection failed: status 0x%02x\n", status); 190462aa085SMilanka Ringwald browsing_cid = 0; 191462aa085SMilanka Ringwald return; 192462aa085SMilanka Ringwald } 193462aa085SMilanka Ringwald 194462aa085SMilanka Ringwald avrcp_cid = local_cid; 195462aa085SMilanka Ringwald avrcp_connected = 1; 196462aa085SMilanka Ringwald avrcp_subevent_connection_established_get_bd_addr(packet, adress); 197247956eaSMilanka Ringwald printf("AVRCP Browsing Client: AVRCP Controller Channel successfully opened: %s, avrcp_cid 0x%02x\n", bd_addr_to_str(adress), avrcp_cid); 198462aa085SMilanka Ringwald return; 199462aa085SMilanka Ringwald } 200462aa085SMilanka Ringwald case AVRCP_SUBEVENT_CONNECTION_RELEASED: 201247956eaSMilanka Ringwald printf("AVRCP Browsing Client: AVRCP Controller Channel released: avrcp_cid 0x%02x\n", avrcp_subevent_connection_released_get_avrcp_cid(packet)); 202462aa085SMilanka Ringwald browsing_cid = 0; 203462aa085SMilanka Ringwald avrcp_browsing_connected = 0; 204462aa085SMilanka Ringwald return; 205462aa085SMilanka Ringwald 206462aa085SMilanka Ringwald case AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED: { 207462aa085SMilanka Ringwald local_cid = avrcp_subevent_browsing_connection_established_get_browsing_cid(packet); 208462aa085SMilanka Ringwald if (browsing_cid != 0 && browsing_cid != local_cid) { 209247956eaSMilanka Ringwald printf("AVRCP Browsing Client: AVRCP Browsing Controller Connection failed, expected 0x%02X l2cap cid, received 0x%02X\n", browsing_cid, local_cid); 210462aa085SMilanka Ringwald return; 211462aa085SMilanka Ringwald } 212462aa085SMilanka Ringwald 213462aa085SMilanka Ringwald status = avrcp_subevent_browsing_connection_established_get_status(packet); 214462aa085SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 215247956eaSMilanka Ringwald printf("AVRCP Browsing Client: AVRCP Browsing Controller Connection failed: status 0x%02x\n", status); 216462aa085SMilanka Ringwald browsing_cid = 0; 217462aa085SMilanka Ringwald return; 218462aa085SMilanka Ringwald } 219462aa085SMilanka Ringwald 220462aa085SMilanka Ringwald browsing_cid = local_cid; 221462aa085SMilanka Ringwald avrcp_browsing_connected = 1; 222462aa085SMilanka Ringwald avrcp_subevent_browsing_connection_established_get_bd_addr(packet, adress); 223247956eaSMilanka Ringwald printf("AVRCP Browsing Client: AVRCP Browsing Controller Channel successfully opened: %s, browsing_cid 0x%02x\n", bd_addr_to_str(adress), browsing_cid); 224462aa085SMilanka Ringwald return; 225462aa085SMilanka Ringwald } 226462aa085SMilanka Ringwald case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED: 227247956eaSMilanka Ringwald printf("AVRCP Browsing Client: AVRCP Browsing Controller Channel released: browsing_cid 0x%02x\n", avrcp_subevent_browsing_connection_released_get_browsing_cid(packet)); 228462aa085SMilanka Ringwald browsing_cid = 0; 229462aa085SMilanka Ringwald avrcp_browsing_connected = 0; 230462aa085SMilanka Ringwald return; 231462aa085SMilanka Ringwald default: 232462aa085SMilanka Ringwald printf("AVRCP Browsing Client: event is not parsed\n"); 233462aa085SMilanka Ringwald break; 234462aa085SMilanka Ringwald } 235462aa085SMilanka Ringwald } 236462aa085SMilanka Ringwald 237462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 238462aa085SMilanka Ringwald static void show_usage(void){ 239462aa085SMilanka Ringwald bd_addr_t iut_address; 240462aa085SMilanka Ringwald gap_local_bd_addr(iut_address); 241462aa085SMilanka Ringwald printf("\n--- Bluetooth AVRCP Controller Connection Test Console %s ---\n", bd_addr_to_str(iut_address)); 242247956eaSMilanka Ringwald printf("a - AVRCP Controller create connection to addr %s\n", bd_addr_to_str(device_addr)); 243247956eaSMilanka Ringwald printf("c - AVRCP Browsing Controller create connection to addr %s\n", bd_addr_to_str(device_addr)); 244247956eaSMilanka Ringwald printf("C - AVRCP Browsing Controller disconnect\n"); 245247956eaSMilanka Ringwald printf("A - AVRCP Controller disconnect\n"); 246ed0df7b2SMilanka Ringwald printf("p - Get player list\n"); 247462aa085SMilanka Ringwald printf("---\n"); 248462aa085SMilanka Ringwald } 249462aa085SMilanka Ringwald #endif 250462aa085SMilanka Ringwald 251ed0df7b2SMilanka Ringwald 252462aa085SMilanka Ringwald #ifdef HAVE_BTSTACK_STDIN 253462aa085SMilanka Ringwald static void stdin_process(char cmd){ 254462aa085SMilanka Ringwald uint8_t status = ERROR_CODE_SUCCESS; 255462aa085SMilanka Ringwald 256462aa085SMilanka Ringwald switch (cmd){ 257462aa085SMilanka Ringwald case 'a': 258247956eaSMilanka Ringwald printf(" - Create AVRCP connection for control to addr %s.\n", bd_addr_to_str(device_addr)); 259462aa085SMilanka Ringwald status = avrcp_controller_connect(device_addr, &avrcp_cid); 260462aa085SMilanka Ringwald break; 261247956eaSMilanka Ringwald case 'A': 262247956eaSMilanka Ringwald if (avrcp_connected){ 263247956eaSMilanka Ringwald printf(" - AVRCP Controller disconnect from addr %s.\n", bd_addr_to_str(device_addr)); 264247956eaSMilanka Ringwald status = avrcp_controller_disconnect(avrcp_cid); 265247956eaSMilanka Ringwald break; 266247956eaSMilanka Ringwald } 267247956eaSMilanka Ringwald printf("AVRCP Controller already disconnected\n"); 268247956eaSMilanka Ringwald break; 269247956eaSMilanka Ringwald 270462aa085SMilanka Ringwald case 'c': 271462aa085SMilanka Ringwald if (!avrcp_connected) { 272247956eaSMilanka Ringwald printf(" You must first create AVRCP connection for control to addr %s.\n", bd_addr_to_str(device_addr)); 273462aa085SMilanka Ringwald break; 274462aa085SMilanka Ringwald } 275462aa085SMilanka Ringwald printf(" - Create AVRCP connection for browsing to addr %s.\n", bd_addr_to_str(device_addr)); 276462aa085SMilanka Ringwald status = avrcp_browsing_controller_connect(device_addr, ertm_buffer, sizeof(ertm_buffer), &ertm_config, &browsing_cid); 277462aa085SMilanka Ringwald break; 278462aa085SMilanka Ringwald case 'C': 279247956eaSMilanka Ringwald if (avrcp_browsing_connected){ 280247956eaSMilanka Ringwald printf(" - AVRCP Browsing Controller disconnect from addr %s.\n", bd_addr_to_str(device_addr)); 281462aa085SMilanka Ringwald status = avrcp_browsing_controller_disconnect(browsing_cid); 282462aa085SMilanka Ringwald break; 283247956eaSMilanka Ringwald } 284247956eaSMilanka Ringwald printf("AVRCP Browsing Controller already disconnected\n"); 285247956eaSMilanka Ringwald break; 286ed0df7b2SMilanka Ringwald 287ed0df7b2SMilanka Ringwald case 'p': 288ed0df7b2SMilanka Ringwald printf("AVRCP Browsing: get player list\n"); 289ed0df7b2SMilanka Ringwald avrcp_browsing_controller_get_player_list(browsing_cid); 290ed0df7b2SMilanka Ringwald break; 291ed0df7b2SMilanka Ringwald 292462aa085SMilanka Ringwald case '\n': 293462aa085SMilanka Ringwald case '\r': 294462aa085SMilanka Ringwald break; 295462aa085SMilanka Ringwald default: 296462aa085SMilanka Ringwald show_usage(); 297462aa085SMilanka Ringwald return; 298462aa085SMilanka Ringwald } 299ed0df7b2SMilanka Ringwald 300462aa085SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 301462aa085SMilanka Ringwald printf("Could not perform command, status 0x%2x\n", status); 302462aa085SMilanka Ringwald } 303462aa085SMilanka Ringwald } 304462aa085SMilanka Ringwald #endif 305462aa085SMilanka Ringwald /* EXAMPLE_END */ 306