1be32e7f1SMilanka Ringwald /* 2be32e7f1SMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3be32e7f1SMilanka Ringwald * 4be32e7f1SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5be32e7f1SMilanka Ringwald * modification, are permitted provided that the following conditions 6be32e7f1SMilanka Ringwald * are met: 7be32e7f1SMilanka Ringwald * 8be32e7f1SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9be32e7f1SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10be32e7f1SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11be32e7f1SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12be32e7f1SMilanka Ringwald * documentation and/or other materials provided with the distribution. 13be32e7f1SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14be32e7f1SMilanka Ringwald * contributors may be used to endorse or promote products derived 15be32e7f1SMilanka Ringwald * from this software without specific prior written permission. 16be32e7f1SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17be32e7f1SMilanka Ringwald * personal benefit and not for any commercial purpose or for 18be32e7f1SMilanka Ringwald * monetary gain. 19be32e7f1SMilanka Ringwald * 20be32e7f1SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21be32e7f1SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22be32e7f1SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23be32e7f1SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24be32e7f1SMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25be32e7f1SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26be32e7f1SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27be32e7f1SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28be32e7f1SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29be32e7f1SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30be32e7f1SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31be32e7f1SMilanka Ringwald * SUCH DAMAGE. 32be32e7f1SMilanka Ringwald * 33be32e7f1SMilanka Ringwald * Please inquire about commercial licensing options at 34be32e7f1SMilanka Ringwald * [email protected] 35be32e7f1SMilanka Ringwald * 36be32e7f1SMilanka Ringwald */ 37be32e7f1SMilanka Ringwald 38ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "avrcp.c" 39ab2c6ae4SMatthias Ringwald 40be32e7f1SMilanka Ringwald #include <stdint.h> 41be32e7f1SMilanka Ringwald #include <stdio.h> 42be32e7f1SMilanka Ringwald #include <stdlib.h> 43be32e7f1SMilanka Ringwald #include <string.h> 44be32e7f1SMilanka Ringwald 45be32e7f1SMilanka Ringwald #include "btstack.h" 46be32e7f1SMilanka Ringwald #include "classic/avrcp.h" 476983e65eSMilanka Ringwald #include "classic/avrcp_controller.h" 48be32e7f1SMilanka Ringwald 49235946f1SMatthias Ringwald #define PSM_AVCTP BLUETOOTH_PROTOCOL_AVCTP 50a0f524f0SMatthias Ringwald #define PSM_AVCTP_BROWSING 0x001b 51be32e7f1SMilanka Ringwald 520036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 530036e267SMilanka Ringwald 54be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service"; 55be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_provider_name = "BTstack AVRCP Controller Service Provider"; 56be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_name = "BTstack AVRCP Target Service"; 57be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_provider_name = "BTstack AVRCP Target Service Provider"; 58be32e7f1SMilanka Ringwald 596983e65eSMilanka Ringwald static uint16_t avrcp_cid_counter = 0; 60be32e7f1SMilanka Ringwald 616983e65eSMilanka Ringwald static avrcp_context_t * sdp_query_context; 626983e65eSMilanka Ringwald static uint8_t attribute_value[1000]; 636983e65eSMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); 646983e65eSMilanka Ringwald 65638481deSMilanka Ringwald static btstack_linked_list_t connections; 66b106f728SMilanka Ringwald static btstack_packet_handler_t avrcp_controller_packet_handler; 67b106f728SMilanka Ringwald static btstack_packet_handler_t avrcp_target_packet_handler; 680036e267SMilanka Ringwald static int l2cap_service_registered = 0; 696086246cSMilanka Ringwald 70be32e7f1SMilanka Ringwald static const char * avrcp_subunit_type_name[] = { 71be32e7f1SMilanka Ringwald "MONITOR", "AUDIO", "PRINTER", "DISC", "TAPE_RECORDER_PLAYER", "TUNER", 72be32e7f1SMilanka Ringwald "CA", "CAMERA", "RESERVED", "PANEL", "BULLETIN_BOARD", "CAMERA_STORAGE", 73be32e7f1SMilanka Ringwald "VENDOR_UNIQUE", "RESERVED_FOR_ALL_SUBUNIT_TYPES", 74be32e7f1SMilanka Ringwald "EXTENDED_TO_NEXT_BYTE", "UNIT", "ERROR" 75be32e7f1SMilanka Ringwald }; 766983e65eSMilanka Ringwald 77be32e7f1SMilanka Ringwald const char * avrcp_subunit2str(uint16_t index){ 78be32e7f1SMilanka Ringwald if (index <= 11) return avrcp_subunit_type_name[index]; 79be32e7f1SMilanka Ringwald if (index >= 0x1C && index <= 0x1F) return avrcp_subunit_type_name[index - 0x10]; 80be32e7f1SMilanka Ringwald return avrcp_subunit_type_name[16]; 81be32e7f1SMilanka Ringwald } 82be32e7f1SMilanka Ringwald 83be32e7f1SMilanka Ringwald static const char * avrcp_event_name[] = { 84be32e7f1SMilanka Ringwald "ERROR", "PLAYBACK_STATUS_CHANGED", 85be32e7f1SMilanka Ringwald "TRACK_CHANGED", "TRACK_REACHED_END", "TRACK_REACHED_START", 86be32e7f1SMilanka Ringwald "PLAYBACK_POS_CHANGED", "BATT_STATUS_CHANGED", "SYSTEM_STATUS_CHANGED", 87be32e7f1SMilanka Ringwald "PLAYER_APPLICATION_SETTING_CHANGED", "NOW_PLAYING_CONTENT_CHANGED", 88be32e7f1SMilanka Ringwald "AVAILABLE_PLAYERS_CHANGED", "ADDRESSED_PLAYER_CHANGED", "UIDS_CHANGED", "VOLUME_CHANGED" 89be32e7f1SMilanka Ringwald }; 90be32e7f1SMilanka Ringwald const char * avrcp_event2str(uint16_t index){ 91be32e7f1SMilanka Ringwald if (index <= 0x0d) return avrcp_event_name[index]; 92be32e7f1SMilanka Ringwald return avrcp_event_name[0]; 93be32e7f1SMilanka Ringwald } 94be32e7f1SMilanka Ringwald 95be32e7f1SMilanka Ringwald static const char * avrcp_operation_name[] = { 96be32e7f1SMilanka Ringwald "NOT SUPPORTED", // 0x3B 97be32e7f1SMilanka Ringwald "SKIP", "NOT SUPPORTED", "NOT SUPPORTED", "NOT SUPPORTED", "NOT SUPPORTED", 98be32e7f1SMilanka Ringwald "VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", "NOT SUPPORTED", 99be32e7f1SMilanka Ringwald "REWIND", "FAST_FORWARD", "NOT SUPPORTED", "FORWARD", "BACKWARD" // 0x4C 100be32e7f1SMilanka Ringwald }; 101be32e7f1SMilanka Ringwald const char * avrcp_operation2str(uint8_t index){ 102be32e7f1SMilanka Ringwald if (index >= 0x3B && index <= 0x4C) return avrcp_operation_name[index - 0x3B]; 103be32e7f1SMilanka Ringwald return avrcp_operation_name[0]; 104be32e7f1SMilanka Ringwald } 105be32e7f1SMilanka Ringwald 106be32e7f1SMilanka Ringwald static const char * avrcp_media_attribute_id_name[] = { 107be32e7f1SMilanka Ringwald "NONE", "TITLE", "ARTIST", "ALBUM", "TRACK", "TOTAL TRACKS", "GENRE", "SONG LENGTH" 108be32e7f1SMilanka Ringwald }; 109be32e7f1SMilanka Ringwald const char * avrcp_attribute2str(uint8_t index){ 110be32e7f1SMilanka Ringwald if (index >= 1 && index <= 7) return avrcp_media_attribute_id_name[index]; 111be32e7f1SMilanka Ringwald return avrcp_media_attribute_id_name[0]; 112be32e7f1SMilanka Ringwald } 113be32e7f1SMilanka Ringwald 114be32e7f1SMilanka Ringwald static const char * avrcp_play_status_name[] = { 115be32e7f1SMilanka Ringwald "STOPPED", "PLAYING", "PAUSED", "FORWARD SEEK", "REVERSE SEEK", 116be32e7f1SMilanka Ringwald "ERROR" // 0xFF 117be32e7f1SMilanka Ringwald }; 118be32e7f1SMilanka Ringwald const char * avrcp_play_status2str(uint8_t index){ 119be32e7f1SMilanka Ringwald if (index >= 1 && index <= 4) return avrcp_play_status_name[index]; 120be32e7f1SMilanka Ringwald return avrcp_play_status_name[5]; 121be32e7f1SMilanka Ringwald } 122be32e7f1SMilanka Ringwald 123be32e7f1SMilanka Ringwald static const char * avrcp_ctype_name[] = { 124be32e7f1SMilanka Ringwald "CONTROL", 125be32e7f1SMilanka Ringwald "STATUS", 126be32e7f1SMilanka Ringwald "SPECIFIC_INQUIRY", 127be32e7f1SMilanka Ringwald "NOTIFY", 128be32e7f1SMilanka Ringwald "GENERAL_INQUIRY", 129be32e7f1SMilanka Ringwald "RESERVED5", 130be32e7f1SMilanka Ringwald "RESERVED6", 131be32e7f1SMilanka Ringwald "RESERVED7", 1329cc1f3ceSMilanka Ringwald "NOT IMPLEMENTED IN REMOTE", 1339cc1f3ceSMilanka Ringwald "ACCEPTED BY REMOTE", 1349cc1f3ceSMilanka Ringwald "REJECTED BY REMOTE", 135be32e7f1SMilanka Ringwald "IN_TRANSITION", 136be32e7f1SMilanka Ringwald "IMPLEMENTED_STABLE", 137be32e7f1SMilanka Ringwald "CHANGED_STABLE", 138be32e7f1SMilanka Ringwald "RESERVED", 139be32e7f1SMilanka Ringwald "INTERIM" 140be32e7f1SMilanka Ringwald }; 141be32e7f1SMilanka Ringwald const char * avrcp_ctype2str(uint8_t index){ 1423982eab9SMatthias Ringwald if (index < sizeof(avrcp_ctype_name)){ 143be32e7f1SMilanka Ringwald return avrcp_ctype_name[index]; 144be32e7f1SMilanka Ringwald } 145be32e7f1SMilanka Ringwald return "NONE"; 146be32e7f1SMilanka Ringwald } 147be32e7f1SMilanka Ringwald 148be32e7f1SMilanka Ringwald static const char * avrcp_shuffle_mode_name[] = { 149be32e7f1SMilanka Ringwald "SHUFFLE OFF", 150be32e7f1SMilanka Ringwald "SHUFFLE ALL TRACKS", 151be32e7f1SMilanka Ringwald "SHUFFLE GROUP" 152be32e7f1SMilanka Ringwald }; 153be32e7f1SMilanka Ringwald 154be32e7f1SMilanka Ringwald const char * avrcp_shuffle2str(uint8_t index){ 155be32e7f1SMilanka Ringwald if (index >= 1 && index <= 3) return avrcp_shuffle_mode_name[index-1]; 156be32e7f1SMilanka Ringwald return "NONE"; 157be32e7f1SMilanka Ringwald } 158be32e7f1SMilanka Ringwald 159be32e7f1SMilanka Ringwald static const char * avrcp_repeat_mode_name[] = { 160be32e7f1SMilanka Ringwald "REPEAT OFF", 161be32e7f1SMilanka Ringwald "REPEAT SINGLE TRACK", 162be32e7f1SMilanka Ringwald "REPEAT ALL TRACKS", 163be32e7f1SMilanka Ringwald "REPEAT GROUP" 164be32e7f1SMilanka Ringwald }; 165be32e7f1SMilanka Ringwald 166be32e7f1SMilanka Ringwald const char * avrcp_repeat2str(uint8_t index){ 167be32e7f1SMilanka Ringwald if (index >= 1 && index <= 4) return avrcp_repeat_mode_name[index-1]; 168be32e7f1SMilanka Ringwald return "NONE"; 169be32e7f1SMilanka Ringwald } 1706086246cSMilanka Ringwald 1714b338011SMilanka Ringwald uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ 1724b338011SMilanka Ringwald uint8_t cmd_opcode_index = 5; 1734b338011SMilanka Ringwald if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; 1744b338011SMilanka Ringwald return packet[cmd_opcode_index]; 1754b338011SMilanka Ringwald } 1764b338011SMilanka Ringwald 177654724deSMilanka Ringwald void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, 178654724deSMilanka Ringwald const char * service_name, const char * service_provider_name){ 179be32e7f1SMilanka Ringwald uint8_t* attribute; 180be32e7f1SMilanka Ringwald de_create_sequence(service); 181be32e7f1SMilanka Ringwald 182be32e7f1SMilanka Ringwald // 0x0000 "Service Record Handle" 183235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE); 184be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle); 185be32e7f1SMilanka Ringwald 186be32e7f1SMilanka Ringwald // 0x0001 "Service Class ID List" 187235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST); 188be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 189be32e7f1SMilanka Ringwald { 190be32e7f1SMilanka Ringwald if (controller){ 1916086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 1926086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER); 193be32e7f1SMilanka Ringwald } else { 1946086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET); 195be32e7f1SMilanka Ringwald } 196be32e7f1SMilanka Ringwald } 197be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 198be32e7f1SMilanka Ringwald 199be32e7f1SMilanka Ringwald // 0x0004 "Protocol Descriptor List" 200235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST); 201be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 202be32e7f1SMilanka Ringwald { 203be32e7f1SMilanka Ringwald uint8_t* l2cpProtocol = de_push_sequence(attribute); 204be32e7f1SMilanka Ringwald { 205235946f1SMatthias Ringwald de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 206235946f1SMatthias Ringwald de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); 207be32e7f1SMilanka Ringwald } 208be32e7f1SMilanka Ringwald de_pop_sequence(attribute, l2cpProtocol); 209be32e7f1SMilanka Ringwald 210be32e7f1SMilanka Ringwald uint8_t* avctpProtocol = de_push_sequence(attribute); 211be32e7f1SMilanka Ringwald { 212235946f1SMatthias Ringwald de_add_number(avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // avctpProtocol_service 213be32e7f1SMilanka Ringwald de_add_number(avctpProtocol, DE_UINT, DE_SIZE_16, 0x0103); // version 214be32e7f1SMilanka Ringwald } 215be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avctpProtocol); 216be32e7f1SMilanka Ringwald } 217be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 218be32e7f1SMilanka Ringwald 219be32e7f1SMilanka Ringwald // 0x0005 "Public Browse Group" 220235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group 221be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 222be32e7f1SMilanka Ringwald { 223235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT); 224be32e7f1SMilanka Ringwald } 225be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 226be32e7f1SMilanka Ringwald 227be32e7f1SMilanka Ringwald // 0x0009 "Bluetooth Profile Descriptor List" 228235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST); 229be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 230be32e7f1SMilanka Ringwald { 231be32e7f1SMilanka Ringwald uint8_t *avrcProfile = de_push_sequence(attribute); 232be32e7f1SMilanka Ringwald { 2336086246cSMilanka Ringwald de_add_number(avrcProfile, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 234be32e7f1SMilanka Ringwald de_add_number(avrcProfile, DE_UINT, DE_SIZE_16, 0x0105); 235be32e7f1SMilanka Ringwald } 236be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avrcProfile); 237be32e7f1SMilanka Ringwald } 238be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 239be32e7f1SMilanka Ringwald 240a0f524f0SMatthias Ringwald // 0x000d "Additional Bluetooth Profile Descriptor List" 2415c806868SMatthias Ringwald if (browsing){ 242a0f524f0SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS); 243a0f524f0SMatthias Ringwald attribute = de_push_sequence(service); 2445c806868SMatthias Ringwald { 2455c806868SMatthias Ringwald uint8_t * des = de_push_sequence(attribute); 2465c806868SMatthias Ringwald { 2475c806868SMatthias Ringwald uint8_t* browsing_l2cpProtocol = de_push_sequence(des); 248a0f524f0SMatthias Ringwald { 249a0f524f0SMatthias Ringwald de_add_number(browsing_l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 250a0f524f0SMatthias Ringwald de_add_number(browsing_l2cpProtocol, DE_UINT, DE_SIZE_16, PSM_AVCTP_BROWSING); 251a0f524f0SMatthias Ringwald } 2525c806868SMatthias Ringwald de_pop_sequence(des, browsing_l2cpProtocol); 253a0f524f0SMatthias Ringwald 2545c806868SMatthias Ringwald uint8_t* browsing_avctpProtocol = de_push_sequence(des); 255a0f524f0SMatthias Ringwald { 256a0f524f0SMatthias Ringwald de_add_number(browsing_avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // browsing_avctpProtocol_service 257a0f524f0SMatthias Ringwald de_add_number(browsing_avctpProtocol, DE_UINT, DE_SIZE_16, 0x0103); // version 258a0f524f0SMatthias Ringwald } 2595c806868SMatthias Ringwald de_pop_sequence(des, browsing_avctpProtocol); 2605c806868SMatthias Ringwald } 2615c806868SMatthias Ringwald de_pop_sequence(attribute, des); 262a0f524f0SMatthias Ringwald } 263a0f524f0SMatthias Ringwald de_pop_sequence(service, attribute); 2645c806868SMatthias Ringwald } 265a0f524f0SMatthias Ringwald 266be32e7f1SMilanka Ringwald 267be32e7f1SMilanka Ringwald // 0x0100 "Service Name" 268be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); 269be32e7f1SMilanka Ringwald if (service_name){ 270be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name); 271be32e7f1SMilanka Ringwald } else { 272be32e7f1SMilanka Ringwald if (controller){ 273be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_controller_service_name), (uint8_t *) default_avrcp_controller_service_name); 274be32e7f1SMilanka Ringwald } else { 275be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_target_service_name), (uint8_t *) default_avrcp_target_service_name); 276be32e7f1SMilanka Ringwald } 277be32e7f1SMilanka Ringwald } 278be32e7f1SMilanka Ringwald 279be32e7f1SMilanka Ringwald // 0x0100 "Provider Name" 280be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102); 281be32e7f1SMilanka Ringwald if (service_provider_name){ 282be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name); 283be32e7f1SMilanka Ringwald } else { 284be32e7f1SMilanka Ringwald if (controller){ 285be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_controller_service_provider_name), (uint8_t *) default_avrcp_controller_service_provider_name); 286be32e7f1SMilanka Ringwald } else { 287be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_target_service_provider_name), (uint8_t *) default_avrcp_target_service_provider_name); 288be32e7f1SMilanka Ringwald } 289be32e7f1SMilanka Ringwald } 290be32e7f1SMilanka Ringwald 291be32e7f1SMilanka Ringwald // 0x0311 "Supported Features" 292be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); 293be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 294be32e7f1SMilanka Ringwald } 295be32e7f1SMilanka Ringwald 29694d9400dSMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_bd_addr(avrcp_role_t role, bd_addr_t addr){ 2976983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 298638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 2996983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3006983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 30194d9400dSMilanka Ringwald if (connection->role != role) continue; 3026983e65eSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 3036983e65eSMilanka Ringwald return connection; 3046983e65eSMilanka Ringwald } 3056983e65eSMilanka Ringwald return NULL; 306be32e7f1SMilanka Ringwald } 307be32e7f1SMilanka Ringwald 30894d9400dSMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_l2cap_signaling_cid(avrcp_role_t role, uint16_t l2cap_cid){ 3096983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 310638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 3116983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3126983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 31394d9400dSMilanka Ringwald if (connection->role != role) continue; 3146983e65eSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 3156983e65eSMilanka Ringwald return connection; 3166983e65eSMilanka Ringwald } 3176983e65eSMilanka Ringwald return NULL; 318be32e7f1SMilanka Ringwald } 319be32e7f1SMilanka Ringwald 32094d9400dSMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_avrcp_cid(avrcp_role_t role, uint16_t avrcp_cid){ 3216983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 322638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 3236983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3246983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 32594d9400dSMilanka Ringwald if (connection->role != role) continue; 32601dc6e35SMilanka Ringwald if (connection->avrcp_cid != avrcp_cid) continue; 3276983e65eSMilanka Ringwald return connection; 3286983e65eSMilanka Ringwald } 3296983e65eSMilanka Ringwald return NULL; 3306983e65eSMilanka Ringwald } 3316983e65eSMilanka Ringwald 33294d9400dSMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_browsing_cid(avrcp_role_t role, uint16_t browsing_cid){ 333638481deSMilanka Ringwald btstack_linked_list_iterator_t it; 334638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 335638481deSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 336638481deSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 33794d9400dSMilanka Ringwald if (connection->role != role) continue; 338638481deSMilanka Ringwald if (connection->avrcp_browsing_cid != browsing_cid) continue; 339638481deSMilanka Ringwald return connection; 340638481deSMilanka Ringwald } 341638481deSMilanka Ringwald return NULL; 342638481deSMilanka Ringwald } 343638481deSMilanka Ringwald 34494d9400dSMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_browsing_l2cap_cid(avrcp_role_t role, uint16_t browsing_l2cap_cid){ 345638481deSMilanka Ringwald btstack_linked_list_iterator_t it; 346638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 347638481deSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 348638481deSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 34994d9400dSMilanka Ringwald if (connection->role != role) continue; 350638481deSMilanka Ringwald if (connection->browsing_connection && connection->browsing_connection->l2cap_browsing_cid != browsing_l2cap_cid) continue; 351638481deSMilanka Ringwald return connection; 352638481deSMilanka Ringwald } 353638481deSMilanka Ringwald return NULL; 354638481deSMilanka Ringwald } 355638481deSMilanka Ringwald 35694d9400dSMilanka Ringwald avrcp_browsing_connection_t * get_avrcp_browsing_connection_for_l2cap_cid(avrcp_role_t role, uint16_t l2cap_cid){ 357638481deSMilanka Ringwald btstack_linked_list_iterator_t it; 358638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 359638481deSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 360638481deSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 36194d9400dSMilanka Ringwald if (connection->role != role) continue; 362638481deSMilanka Ringwald if (connection->browsing_connection && connection->browsing_connection->l2cap_browsing_cid != l2cap_cid) continue; 363638481deSMilanka Ringwald return connection->browsing_connection; 364638481deSMilanka Ringwald } 365638481deSMilanka Ringwald return NULL; 366638481deSMilanka Ringwald } 36794d9400dSMilanka Ringwald 3686983e65eSMilanka Ringwald void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){ 3690036e267SMilanka Ringwald // printf("AVRCP: avrcp_request_can_send_now, role %d\n", connection->role); 3706983e65eSMilanka Ringwald connection->wait_to_send = 1; 3716983e65eSMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 3726983e65eSMilanka Ringwald } 3736983e65eSMilanka Ringwald 3746983e65eSMilanka Ringwald 375247956eaSMilanka Ringwald uint16_t avrcp_get_next_cid(void){ 3766983e65eSMilanka Ringwald avrcp_cid_counter++; 3776983e65eSMilanka Ringwald if (avrcp_cid_counter == 0){ 3786983e65eSMilanka Ringwald avrcp_cid_counter = 1; 3796983e65eSMilanka Ringwald } 3806983e65eSMilanka Ringwald return avrcp_cid_counter; 3816983e65eSMilanka Ringwald } 3826983e65eSMilanka Ringwald 383638481deSMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){ 3846983e65eSMilanka Ringwald avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); 3854567cc17SMilanka Ringwald if (!connection){ 386*0ec79bd0SMilanka Ringwald log_error("Not enough memory to create connection for role %d", role); 3874567cc17SMilanka Ringwald return NULL; 3884567cc17SMilanka Ringwald } 3890036e267SMilanka Ringwald 3906983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_IDLE; 3910036e267SMilanka Ringwald connection->role = role; 3926983e65eSMilanka Ringwald connection->transaction_label = 0xFF; 3938b2b4034SMilanka Ringwald connection->max_num_fragments = 0xFF; 394f12a3722SMilanka Ringwald connection->avrcp_cid = avrcp_get_next_cid(); 395*0ec79bd0SMilanka Ringwald log_info("avrcp_create_connection, role %d, avrcp cid 0x%02x", role, connection->avrcp_cid); 3966983e65eSMilanka Ringwald memcpy(connection->remote_addr, remote_addr, 6); 397638481deSMilanka Ringwald btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection); 3986983e65eSMilanka Ringwald return connection; 3996983e65eSMilanka Ringwald } 4006983e65eSMilanka Ringwald 401638481deSMilanka Ringwald static void avrcp_finalize_connection(avrcp_connection_t * connection){ 402638481deSMilanka Ringwald btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection); 40355e8029cSMatthias Ringwald btstack_memory_avrcp_connection_free(connection); 40455e8029cSMatthias Ringwald } 4056983e65eSMilanka Ringwald 4066983e65eSMilanka Ringwald void avrcp_emit_connection_established(btstack_packet_handler_t callback, uint16_t avrcp_cid, bd_addr_t addr, uint8_t status){ 407b193c45eSMilanka Ringwald if (!callback) return; 4086086246cSMilanka Ringwald uint8_t event[12]; 409b193c45eSMilanka Ringwald int pos = 0; 410b193c45eSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 411b193c45eSMilanka Ringwald event[pos++] = sizeof(event) - 2; 412b193c45eSMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED; 4136f43fcd7SMatthias Ringwald event[pos++] = status; 414b193c45eSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 415b193c45eSMilanka Ringwald pos += 6; 416b193c45eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 417b193c45eSMilanka Ringwald pos += 2; 418b193c45eSMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 419b193c45eSMilanka Ringwald } 420b193c45eSMilanka Ringwald 4216983e65eSMilanka Ringwald void avrcp_emit_connection_closed(btstack_packet_handler_t callback, uint16_t avrcp_cid){ 422be32e7f1SMilanka Ringwald if (!callback) return; 423be32e7f1SMilanka Ringwald uint8_t event[5]; 424be32e7f1SMilanka Ringwald int pos = 0; 425be32e7f1SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 426be32e7f1SMilanka Ringwald event[pos++] = sizeof(event) - 2; 427be32e7f1SMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED; 428b193c45eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 429be32e7f1SMilanka Ringwald pos += 2; 430be32e7f1SMilanka Ringwald (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 431be32e7f1SMilanka Ringwald } 432be32e7f1SMilanka Ringwald 433247956eaSMilanka Ringwald void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 43494d9400dSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(sdp_query_context->role, sdp_query_context->avrcp_cid); 4356983e65eSMilanka Ringwald if (!connection) return; 436f12a3722SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) return; 437247956eaSMilanka Ringwald 4386086246cSMilanka Ringwald UNUSED(packet_type); 4396086246cSMilanka Ringwald UNUSED(channel); 4406086246cSMilanka Ringwald UNUSED(size); 4415448c259SMilanka Ringwald uint8_t status; 4426086246cSMilanka Ringwald des_iterator_t des_list_it; 4436086246cSMilanka Ringwald des_iterator_t prot_it; 4446086246cSMilanka Ringwald // uint32_t avdtp_remote_uuid = 0; 4456086246cSMilanka Ringwald 4466086246cSMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 4476086246cSMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 4486086246cSMilanka Ringwald // Handle new SDP record 449f12a3722SMilanka Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != sdp_query_context->record_id) { 450f12a3722SMilanka Ringwald sdp_query_context->record_id = sdp_event_query_attribute_byte_get_record_id(packet); 451f12a3722SMilanka Ringwald sdp_query_context->parse_sdp_record = 0; 4526086246cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 4536086246cSMilanka Ringwald } 4546086246cSMilanka Ringwald 4556086246cSMilanka Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 4566086246cSMilanka Ringwald attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 4576086246cSMilanka Ringwald 4586086246cSMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 4596086246cSMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 4606086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 4616086246cSMilanka Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 4626086246cSMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 4636086246cSMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 4646086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 4656086246cSMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 4666086246cSMilanka Ringwald switch (uuid){ 4676086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET: 4686983e65eSMilanka Ringwald if (sdp_query_context->role == AVRCP_CONTROLLER) { 469f12a3722SMilanka Ringwald sdp_query_context->parse_sdp_record = 1; 4706086246cSMilanka Ringwald break; 4716086246cSMilanka Ringwald } 4726086246cSMilanka Ringwald break; 4736086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL: 474df642728SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: 4756983e65eSMilanka Ringwald if (sdp_query_context->role == AVRCP_TARGET) { 476f12a3722SMilanka Ringwald sdp_query_context->parse_sdp_record = 1; 4776086246cSMilanka Ringwald break; 4786086246cSMilanka Ringwald } 4796086246cSMilanka Ringwald break; 4806086246cSMilanka Ringwald default: 4816086246cSMilanka Ringwald break; 4826086246cSMilanka Ringwald } 4836086246cSMilanka Ringwald } 4846086246cSMilanka Ringwald break; 4856086246cSMilanka Ringwald 4866086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: { 487f12a3722SMilanka Ringwald if (!sdp_query_context->parse_sdp_record) break; 4886086246cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 4896086246cSMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 4906086246cSMilanka Ringwald uint8_t *des_element; 4916086246cSMilanka Ringwald uint8_t *element; 4926086246cSMilanka Ringwald uint32_t uuid; 4936086246cSMilanka Ringwald 4946086246cSMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 4956086246cSMilanka Ringwald 4966086246cSMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 4976086246cSMilanka Ringwald des_iterator_init(&prot_it, des_element); 4986086246cSMilanka Ringwald element = des_iterator_get_element(&prot_it); 4996086246cSMilanka Ringwald 5006086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 5016086246cSMilanka Ringwald 5026086246cSMilanka Ringwald uuid = de_get_uuid32(element); 50314fd128cSMatthias Ringwald des_iterator_next(&prot_it); 5046086246cSMilanka Ringwald switch (uuid){ 5056086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 5066086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 5076983e65eSMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_l2cap_psm); 5086086246cSMilanka Ringwald break; 5096086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 5106086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 5116983e65eSMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_version); 5126086246cSMilanka Ringwald break; 5136086246cSMilanka Ringwald default: 5146086246cSMilanka Ringwald break; 5156086246cSMilanka Ringwald } 5166086246cSMilanka Ringwald } 5176086246cSMilanka Ringwald } 5186086246cSMilanka Ringwald break; 519227d16a5SMatthias Ringwald case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: { 520227d16a5SMatthias Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 521f12a3722SMilanka Ringwald if (!sdp_query_context->parse_sdp_record) break; 522227d16a5SMatthias Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 523227d16a5SMatthias Ringwald 524227d16a5SMatthias Ringwald des_iterator_t des_list_0_it; 525227d16a5SMatthias Ringwald uint8_t *element_0; 526227d16a5SMatthias Ringwald 527227d16a5SMatthias Ringwald des_iterator_init(&des_list_0_it, attribute_value); 528227d16a5SMatthias Ringwald element_0 = des_iterator_get_element(&des_list_0_it); 529227d16a5SMatthias Ringwald 530227d16a5SMatthias Ringwald for (des_iterator_init(&des_list_it, element_0); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 531227d16a5SMatthias Ringwald uint8_t *des_element; 532227d16a5SMatthias Ringwald uint8_t *element; 533227d16a5SMatthias Ringwald uint32_t uuid; 534227d16a5SMatthias Ringwald 535227d16a5SMatthias Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 536227d16a5SMatthias Ringwald 537227d16a5SMatthias Ringwald des_element = des_iterator_get_element(&des_list_it); 538227d16a5SMatthias Ringwald des_iterator_init(&prot_it, des_element); 539227d16a5SMatthias Ringwald element = des_iterator_get_element(&prot_it); 540227d16a5SMatthias Ringwald 541227d16a5SMatthias Ringwald if (de_get_element_type(element) != DE_UUID) continue; 542227d16a5SMatthias Ringwald 543227d16a5SMatthias Ringwald uuid = de_get_uuid32(element); 54414fd128cSMatthias Ringwald des_iterator_next(&prot_it); 545227d16a5SMatthias Ringwald switch (uuid){ 546227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 547227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 548247956eaSMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->browsing_l2cap_psm); 549227d16a5SMatthias Ringwald break; 550227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 551227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 552247956eaSMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->browsing_version); 553227d16a5SMatthias Ringwald break; 554227d16a5SMatthias Ringwald default: 555227d16a5SMatthias Ringwald break; 556227d16a5SMatthias Ringwald } 557227d16a5SMatthias Ringwald } 558227d16a5SMatthias Ringwald } 559227d16a5SMatthias Ringwald break; 5606086246cSMilanka Ringwald default: 5616086246cSMilanka Ringwald break; 5626086246cSMilanka Ringwald } 5636086246cSMilanka Ringwald } 5646086246cSMilanka Ringwald } else { 5656086246cSMilanka Ringwald log_error("SDP attribute value buffer size exceeded: available %d, required %d", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); 5666086246cSMilanka Ringwald } 5676086246cSMilanka Ringwald break; 5686086246cSMilanka Ringwald 569247956eaSMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE:{ 5705448c259SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 571247956eaSMilanka Ringwald 5725448c259SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 5735448c259SMilanka Ringwald log_info("AVRCP: SDP query failed with status 0x%02x.", status); 57455e8029cSMatthias Ringwald avrcp_emit_connection_established(sdp_query_context->avrcp_callback, connection->avrcp_cid, connection->remote_addr, status); 575638481deSMilanka Ringwald avrcp_finalize_connection(connection); 5765448c259SMilanka Ringwald break; 5775448c259SMilanka Ringwald } 5785448c259SMilanka Ringwald 579e1ad7f0dSMatthias Ringwald if (!sdp_query_context->avrcp_l2cap_psm){ 580be32e7f1SMilanka Ringwald connection->state = AVCTP_CONNECTION_IDLE; 581e1ad7f0dSMatthias Ringwald log_info("AVRCP: no suitable service found"); 5826983e65eSMilanka Ringwald avrcp_emit_connection_established(sdp_query_context->avrcp_callback, connection->avrcp_cid, connection->remote_addr, SDP_SERVICE_NOT_FOUND); 583638481deSMilanka Ringwald avrcp_finalize_connection(connection); 5846983e65eSMilanka Ringwald break; 5856983e65eSMilanka Ringwald } 5866983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 5870036e267SMilanka Ringwald l2cap_create_channel(&avrcp_packet_handler, connection->remote_addr, sdp_query_context->avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 5886983e65eSMilanka Ringwald break; 5896983e65eSMilanka Ringwald } 590be32e7f1SMilanka Ringwald } 591247956eaSMilanka Ringwald } 592be32e7f1SMilanka Ringwald 5930036e267SMilanka Ringwald static btstack_packet_handler_t avrcp_packet_handler_for_role(avrcp_role_t role){ 5940036e267SMilanka Ringwald switch (role){ 5950036e267SMilanka Ringwald case AVRCP_CONTROLLER: 5960036e267SMilanka Ringwald return avrcp_controller_packet_handler; 5970036e267SMilanka Ringwald case AVRCP_TARGET: 5980036e267SMilanka Ringwald return avrcp_target_packet_handler; 5990036e267SMilanka Ringwald } 6000036e267SMilanka Ringwald return NULL; 6010036e267SMilanka Ringwald } 602be32e7f1SMilanka Ringwald 6030036e267SMilanka Ringwald static int avrcp_handle_incoming_connection_for_role(avrcp_role_t role, bd_addr_t event_addr, uint16_t local_cid){ 604*0ec79bd0SMilanka Ringwald if (!avrcp_packet_handler_for_role(role)) { 605*0ec79bd0SMilanka Ringwald // printf("AVRCP: avrcp_handle_incoming_connection_for_role %d, PH not defined\n", role); 606*0ec79bd0SMilanka Ringwald return 0; 607*0ec79bd0SMilanka Ringwald } 608be32e7f1SMilanka Ringwald 6090036e267SMilanka Ringwald avrcp_connection_t * connection = avrcp_create_connection(role, event_addr); 6100f76c2d7SMatthias Ringwald if (!connection) { 611*0ec79bd0SMilanka Ringwald // printf("AVRCP: avrcp_handle_incoming_connection_for_role %d, no connection created\n", role); 6120036e267SMilanka Ringwald return 0 ; 613be32e7f1SMilanka Ringwald } 614*0ec79bd0SMilanka Ringwald 6150036e267SMilanka Ringwald // printf("AVRCP: AVCTP_CONNECTION_W4_L2CAP_CONNECTED, role %d\n", role); 6160f76c2d7SMatthias Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 6170f76c2d7SMatthias Ringwald connection->l2cap_signaling_cid = local_cid; 6180036e267SMilanka Ringwald return 1; 619654724deSMilanka Ringwald } 620be32e7f1SMilanka Ringwald 6210036e267SMilanka Ringwald static void avrcp_handle_open_connection_for_role(avrcp_role_t role, bd_addr_t event_addr, uint16_t local_cid, uint16_t l2cap_mtu, uint8_t status){ 6220036e267SMilanka Ringwald // printf("AVRCP: avrcp_handle_open_connection_for_role %d\n", role); 6230f76c2d7SMatthias Ringwald 624*0ec79bd0SMilanka Ringwald btstack_packet_handler_t packet_handler = avrcp_packet_handler_for_role(role); 625*0ec79bd0SMilanka Ringwald if (!packet_handler) { 626*0ec79bd0SMilanka Ringwald // printf("AVRCP: avrcp_handle_open_connection_for_role %d, PH not defined\n", role); 627*0ec79bd0SMilanka Ringwald return; 628*0ec79bd0SMilanka Ringwald } 6290036e267SMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_bd_addr(role, event_addr); 630*0ec79bd0SMilanka Ringwald if (!connection) { 631*0ec79bd0SMilanka Ringwald // printf("AVRCP: avrcp_handle_open_connection_for_role %d, no connection found\n", role); 632*0ec79bd0SMilanka Ringwald return; 633*0ec79bd0SMilanka Ringwald } 634*0ec79bd0SMilanka Ringwald 635*0ec79bd0SMilanka Ringwald if (connection->state == AVCTP_CONNECTION_OPENED) return; 6360036e267SMilanka Ringwald 637b0d75c91SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 638b0d75c91SMilanka Ringwald log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 6390036e267SMilanka Ringwald avrcp_emit_connection_established(packet_handler, connection->avrcp_cid, event_addr, status); 640638481deSMilanka Ringwald avrcp_finalize_connection(connection); 6410036e267SMilanka Ringwald return; 6426086246cSMilanka Ringwald } 643654724deSMilanka Ringwald 644be32e7f1SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 6450036e267SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 646d1207cd8SMilanka Ringwald connection->song_length_ms = 0xFFFFFFFF; 647d1207cd8SMilanka Ringwald connection->song_position_ms = 0xFFFFFFFF; 648d1207cd8SMilanka Ringwald connection->playback_status = AVRCP_PLAYBACK_STATUS_ERROR; 649d1207cd8SMilanka Ringwald 6500036e267SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d", connection->avrcp_cid, connection->l2cap_signaling_cid, connection->role); 651be32e7f1SMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 652b106f728SMilanka Ringwald // emit twice for each role 6530036e267SMilanka Ringwald avrcp_emit_connection_established(packet_handler, connection->avrcp_cid, event_addr, ERROR_CODE_SUCCESS); 654654724deSMilanka Ringwald } 6550036e267SMilanka Ringwald 6560036e267SMilanka Ringwald static void avrcp_handle_close_connection_for_role(avrcp_role_t role,uint16_t local_cid){ 6570036e267SMilanka Ringwald // printf("AVRCP: avrcp_handle_close_connection_for_role %d\n", role); 6580036e267SMilanka Ringwald btstack_packet_handler_t packet_handler = avrcp_packet_handler_for_role(role); 6590036e267SMilanka Ringwald if (!packet_handler) return; 6600036e267SMilanka Ringwald 6610036e267SMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_l2cap_signaling_cid(role, local_cid); 6620036e267SMilanka Ringwald if (!connection) return; 6630036e267SMilanka Ringwald 664*0ec79bd0SMilanka Ringwald // printf("avrcp_handle_close_connection_for_role avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d\n", connection->avrcp_cid, connection->l2cap_signaling_cid, role); 6650036e267SMilanka Ringwald 6660036e267SMilanka Ringwald avrcp_emit_connection_closed(packet_handler, connection->avrcp_cid); 6670036e267SMilanka Ringwald avrcp_finalize_connection(connection); 6680036e267SMilanka Ringwald } 6690036e267SMilanka Ringwald 670*0ec79bd0SMilanka Ringwald static avrcp_role_t avrcp_role_from_transport_header(uint8_t transport_header){ 671*0ec79bd0SMilanka Ringwald avrcp_frame_type_t frame_type = (avrcp_frame_type_t)((transport_header & 0x02) >> 1); 672*0ec79bd0SMilanka Ringwald switch (frame_type){ 673*0ec79bd0SMilanka Ringwald case AVRCP_COMMAND_FRAME: 674*0ec79bd0SMilanka Ringwald return AVRCP_TARGET; 675*0ec79bd0SMilanka Ringwald case AVRCP_RESPONSE_FRAME: 676*0ec79bd0SMilanka Ringwald return AVRCP_CONTROLLER; 677*0ec79bd0SMilanka Ringwald } 678*0ec79bd0SMilanka Ringwald } 679*0ec79bd0SMilanka Ringwald 6800036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 6810036e267SMilanka Ringwald UNUSED(channel); 6820036e267SMilanka Ringwald UNUSED(size); 6830036e267SMilanka Ringwald bd_addr_t event_addr; 6840036e267SMilanka Ringwald uint16_t local_cid; 6850036e267SMilanka Ringwald uint16_t l2cap_mtu; 6860036e267SMilanka Ringwald uint8_t status; 6870036e267SMilanka Ringwald avrcp_connection_t * connection = NULL; 688*0ec79bd0SMilanka Ringwald avrcp_role_t role; 689*0ec79bd0SMilanka Ringwald btstack_packet_handler_t packet_handler; 690*0ec79bd0SMilanka Ringwald uint8_t status_target; 691*0ec79bd0SMilanka Ringwald uint8_t status_controller; 6920036e267SMilanka Ringwald 6930036e267SMilanka Ringwald switch (packet_type) { 6940036e267SMilanka Ringwald case L2CAP_DATA_PACKET: 695*0ec79bd0SMilanka Ringwald role = avrcp_role_from_transport_header(packet[0]); 696*0ec79bd0SMilanka Ringwald packet_handler = avrcp_packet_handler_for_role(role); 697*0ec79bd0SMilanka Ringwald if (!packet_handler) return; 6980036e267SMilanka Ringwald 699*0ec79bd0SMilanka Ringwald (*packet_handler)(packet_type, channel, packet, size); 7000036e267SMilanka Ringwald break; 7010036e267SMilanka Ringwald 7020036e267SMilanka Ringwald case HCI_EVENT_PACKET: 7030036e267SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 7040036e267SMilanka Ringwald 7050036e267SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 7060036e267SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 7070036e267SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 7080036e267SMilanka Ringwald // create two connection objects (both) 709*0ec79bd0SMilanka Ringwald status_target = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, event_addr, local_cid); 710*0ec79bd0SMilanka Ringwald status_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, event_addr, local_cid); 711*0ec79bd0SMilanka Ringwald 712*0ec79bd0SMilanka Ringwald if (!status_target && !status_controller){ 7130036e267SMilanka Ringwald l2cap_decline_connection(local_cid); 7140036e267SMilanka Ringwald break; 7150036e267SMilanka Ringwald } 716*0ec79bd0SMilanka Ringwald 7170036e267SMilanka Ringwald log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION avrcp_cid 0x%02x", local_cid); 7180036e267SMilanka Ringwald l2cap_accept_connection(local_cid); 7190036e267SMilanka Ringwald break; 7200036e267SMilanka Ringwald 7210036e267SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 7220036e267SMilanka Ringwald // printf("AVRCP: L2CAP_EVENT_CHANNEL_OPENED \n"); 7230036e267SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 7240036e267SMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 7250036e267SMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 7260036e267SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 7270036e267SMilanka Ringwald 7280036e267SMilanka Ringwald avrcp_handle_open_connection_for_role(AVRCP_TARGET, event_addr, local_cid, l2cap_mtu, status); 7290036e267SMilanka Ringwald avrcp_handle_open_connection_for_role(AVRCP_CONTROLLER, event_addr, local_cid, l2cap_mtu, status); 730be32e7f1SMilanka Ringwald break; 731be32e7f1SMilanka Ringwald 732be32e7f1SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 733be32e7f1SMilanka Ringwald // data: event (8), len(8), channel (16) 734be32e7f1SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 7350036e267SMilanka Ringwald avrcp_handle_close_connection_for_role(AVRCP_TARGET, local_cid); 7360036e267SMilanka Ringwald avrcp_handle_close_connection_for_role(AVRCP_CONTROLLER, local_cid); 7370036e267SMilanka Ringwald break; 7380036e267SMilanka Ringwald 7390036e267SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 7400036e267SMilanka Ringwald local_cid = l2cap_event_can_send_now_get_local_cid(packet); 7410036e267SMilanka Ringwald 7420036e267SMilanka Ringwald connection = get_avrcp_connection_for_l2cap_signaling_cid(AVRCP_TARGET, local_cid); 7430036e267SMilanka Ringwald if (connection && connection->wait_to_send){ 7440036e267SMilanka Ringwald // printf("AVRCP: L2CAP_EVENT_CAN_SEND_NOW target\n"); 7450036e267SMilanka Ringwald (*avrcp_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 7460036e267SMilanka Ringwald break; 7470036e267SMilanka Ringwald } 7480036e267SMilanka Ringwald 7490036e267SMilanka Ringwald connection = get_avrcp_connection_for_l2cap_signaling_cid(AVRCP_CONTROLLER, local_cid); 7500036e267SMilanka Ringwald if (connection && connection->wait_to_send){ 7510036e267SMilanka Ringwald // printf("AVRCP: L2CAP_EVENT_CAN_SEND_NOW controller\n"); 7520036e267SMilanka Ringwald (*avrcp_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 753be32e7f1SMilanka Ringwald break; 754be32e7f1SMilanka Ringwald } 755be32e7f1SMilanka Ringwald break; 7560036e267SMilanka Ringwald 757be32e7f1SMilanka Ringwald default: 758be32e7f1SMilanka Ringwald break; 759be32e7f1SMilanka Ringwald } 760b106f728SMilanka Ringwald break; 761b106f728SMilanka Ringwald default: 762b106f728SMilanka Ringwald break; 763b106f728SMilanka Ringwald } 764be32e7f1SMilanka Ringwald } 765be32e7f1SMilanka Ringwald 7664590ebd9SMilanka Ringwald uint8_t avrcp_connect(avrcp_role_t role, bd_addr_t bd_addr, avrcp_context_t * context, uint16_t * avrcp_cid){ 76794d9400dSMilanka Ringwald avrcp_connection_t * connection = get_avrcp_connection_for_bd_addr(context->role, bd_addr); 768f9ef80eaSMilanka Ringwald if (connection) return ERROR_CODE_COMMAND_DISALLOWED; 769f9ef80eaSMilanka Ringwald 770f9ef80eaSMilanka Ringwald if (!sdp_client_ready()) return ERROR_CODE_COMMAND_DISALLOWED; 771f9ef80eaSMilanka Ringwald 7720036e267SMilanka Ringwald btstack_packet_handler_t packet_handler = avrcp_packet_handler_for_role(role); 7730036e267SMilanka Ringwald if (!packet_handler) return 0; 7740036e267SMilanka Ringwald 775638481deSMilanka Ringwald connection = avrcp_create_connection(role, bd_addr); 776*0ec79bd0SMilanka Ringwald if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED; 7778a2c6c7cSMilanka Ringwald 778dd5e5981SMatthias Ringwald if (avrcp_cid){ 779b0d75c91SMilanka Ringwald *avrcp_cid = connection->avrcp_cid; 780dd5e5981SMatthias Ringwald } 7816983e65eSMilanka Ringwald context->avrcp_l2cap_psm = 0; 7826983e65eSMilanka Ringwald context->avrcp_version = 0; 7836983e65eSMilanka Ringwald context->avrcp_cid = connection->avrcp_cid; 784247956eaSMilanka Ringwald connection->browsing_l2cap_psm = 0; 785f9ef80eaSMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 7866983e65eSMilanka Ringwald sdp_query_context = context; 787f9ef80eaSMilanka Ringwald sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP); 788f9ef80eaSMilanka Ringwald return ERROR_CODE_SUCCESS; 789be32e7f1SMilanka Ringwald } 790638481deSMilanka Ringwald 791638481deSMilanka Ringwald void avrcp_init(void){ 792638481deSMilanka Ringwald connections = NULL; 793b106f728SMilanka Ringwald if (l2cap_service_registered) return; 7940036e267SMilanka Ringwald 795b106f728SMilanka Ringwald int status = l2cap_register_service(&avrcp_packet_handler, BLUETOOTH_PROTOCOL_AVCTP, 0xffff, LEVEL_2); 796b106f728SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return; 797b106f728SMilanka Ringwald l2cap_service_registered = 1; 798638481deSMilanka Ringwald } 799b106f728SMilanka Ringwald 800b106f728SMilanka Ringwald void avrcp_register_controller_packet_handler(btstack_packet_handler_t callback){ 801b106f728SMilanka Ringwald avrcp_controller_packet_handler = callback; 802b106f728SMilanka Ringwald } 803b106f728SMilanka Ringwald 804b106f728SMilanka Ringwald void avrcp_register_target_packet_handler(btstack_packet_handler_t callback){ 805b106f728SMilanka Ringwald avrcp_target_packet_handler = callback; 806b106f728SMilanka Ringwald } 807b106f728SMilanka Ringwald 808