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 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avrcp.c" 39ab2c6ae4SMatthias Ringwald 40be32e7f1SMilanka Ringwald #include <stdint.h> 41be32e7f1SMilanka Ringwald #include <string.h> 423cfa4086SMatthias Ringwald // snprintf 433cfa4086SMatthias Ringwald #include <stdio.h> 44be32e7f1SMilanka Ringwald 4584e3541eSMilanka Ringwald #include "bluetooth_psm.h" 4684e3541eSMilanka Ringwald #include "bluetooth_sdp.h" 4784e3541eSMilanka Ringwald #include "btstack_debug.h" 4884e3541eSMilanka Ringwald #include "btstack_event.h" 4984e3541eSMilanka Ringwald #include "btstack_memory.h" 5084e3541eSMilanka Ringwald #include "classic/sdp_client.h" 5184e3541eSMilanka Ringwald #include "classic/sdp_util.h" 52be32e7f1SMilanka Ringwald #include "classic/avrcp.h" 530eebc132SMilanka Ringwald 5464a27ec5SMilanka Ringwald 5564a27ec5SMilanka Ringwald typedef struct { 5664a27ec5SMilanka Ringwald uint8_t parse_sdp_record; 5764a27ec5SMilanka Ringwald uint32_t record_id; 5864a27ec5SMilanka Ringwald uint16_t avrcp_cid; 5964a27ec5SMilanka Ringwald uint16_t avrcp_l2cap_psm; 6064a27ec5SMilanka Ringwald uint16_t avrcp_version; 6164a27ec5SMilanka Ringwald 6264a27ec5SMilanka Ringwald uint16_t browsing_l2cap_psm; 6364a27ec5SMilanka Ringwald uint16_t browsing_version; 6464a27ec5SMilanka Ringwald } avrcp_sdp_query_context_t; 6564a27ec5SMilanka Ringwald 6664a27ec5SMilanka Ringwald 670036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 680036e267SMilanka Ringwald 69be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service"; 70be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_provider_name = "BTstack AVRCP Controller Service Provider"; 71be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_name = "BTstack AVRCP Target Service"; 72be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_provider_name = "BTstack AVRCP Target Service Provider"; 73be32e7f1SMilanka Ringwald 74*f0af2234SMatthias Ringwald // default subunit info: single PANEL subunit 75*f0af2234SMatthias Ringwald static const uint8_t avrcp_default_subunit_info[] = { AVRCP_SUBUNIT_TYPE_PANEL << 3}; 76*f0af2234SMatthias Ringwald 77680af5dcSMatthias Ringwald static uint16_t avrcp_cid_counter; 78be32e7f1SMilanka Ringwald 7964a27ec5SMilanka Ringwald static btstack_context_callback_registration_t avrcp_handle_sdp_client_query_request; 8064a27ec5SMilanka Ringwald 8164a27ec5SMilanka Ringwald static avrcp_sdp_query_context_t sdp_query_context; 825dd5e7e3SMilanka Ringwald 83cee0e5b6SMilanka Ringwald static btstack_packet_handler_t avrcp_callback; 84cee0e5b6SMilanka Ringwald 85fa1ee4d3SMilanka Ringwald static uint8_t attribute_value[45]; 866983e65eSMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); 876983e65eSMilanka Ringwald 88638481deSMilanka Ringwald static btstack_linked_list_t connections; 89b106f728SMilanka Ringwald static btstack_packet_handler_t avrcp_controller_packet_handler; 90b106f728SMilanka Ringwald static btstack_packet_handler_t avrcp_target_packet_handler; 910eebc132SMilanka Ringwald static bool l2cap_service_registered = false; 920eebc132SMilanka Ringwald 93be32e7f1SMilanka Ringwald static const char * avrcp_subunit_type_name[] = { 94be32e7f1SMilanka Ringwald "MONITOR", "AUDIO", "PRINTER", "DISC", "TAPE_RECORDER_PLAYER", "TUNER", 95be32e7f1SMilanka Ringwald "CA", "CAMERA", "RESERVED", "PANEL", "BULLETIN_BOARD", "CAMERA_STORAGE", 96be32e7f1SMilanka Ringwald "VENDOR_UNIQUE", "RESERVED_FOR_ALL_SUBUNIT_TYPES", 97be32e7f1SMilanka Ringwald "EXTENDED_TO_NEXT_BYTE", "UNIT", "ERROR" 98be32e7f1SMilanka Ringwald }; 996983e65eSMilanka Ringwald 100be32e7f1SMilanka Ringwald const char * avrcp_subunit2str(uint16_t index){ 101be32e7f1SMilanka Ringwald if (index <= 11) return avrcp_subunit_type_name[index]; 1020e588213SMatthias Ringwald if ((index >= 0x1C) && (index <= 0x1F)) return avrcp_subunit_type_name[index - 0x10]; 103be32e7f1SMilanka Ringwald return avrcp_subunit_type_name[16]; 104be32e7f1SMilanka Ringwald } 105be32e7f1SMilanka Ringwald 106be32e7f1SMilanka Ringwald static const char * avrcp_event_name[] = { 107be32e7f1SMilanka Ringwald "ERROR", "PLAYBACK_STATUS_CHANGED", 108be32e7f1SMilanka Ringwald "TRACK_CHANGED", "TRACK_REACHED_END", "TRACK_REACHED_START", 109be32e7f1SMilanka Ringwald "PLAYBACK_POS_CHANGED", "BATT_STATUS_CHANGED", "SYSTEM_STATUS_CHANGED", 110be32e7f1SMilanka Ringwald "PLAYER_APPLICATION_SETTING_CHANGED", "NOW_PLAYING_CONTENT_CHANGED", 111be32e7f1SMilanka Ringwald "AVAILABLE_PLAYERS_CHANGED", "ADDRESSED_PLAYER_CHANGED", "UIDS_CHANGED", "VOLUME_CHANGED" 112be32e7f1SMilanka Ringwald }; 113be32e7f1SMilanka Ringwald const char * avrcp_event2str(uint16_t index){ 114be32e7f1SMilanka Ringwald if (index <= 0x0d) return avrcp_event_name[index]; 115be32e7f1SMilanka Ringwald return avrcp_event_name[0]; 116be32e7f1SMilanka Ringwald } 117be32e7f1SMilanka Ringwald 118be32e7f1SMilanka Ringwald static const char * avrcp_operation_name[] = { 119ce66cc7aSMilanka Ringwald "SKIP", NULL, NULL, NULL, NULL, 120ce66cc7aSMilanka Ringwald "VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", NULL, 121ce66cc7aSMilanka Ringwald "REWIND", "FAST_FORWARD", NULL, "FORWARD", "BACKWARD" // 0x4C 122be32e7f1SMilanka Ringwald }; 1230b578d06SMilanka Ringwald 1240b578d06SMilanka Ringwald const char * avrcp_operation2str(uint8_t operation_id){ 125ce66cc7aSMilanka Ringwald char * name = NULL; 1260b578d06SMilanka Ringwald if ((operation_id >= AVRCP_OPERATION_ID_SKIP) && (operation_id <= AVRCP_OPERATION_ID_BACKWARD)){ 1270b578d06SMilanka Ringwald name = (char *)avrcp_operation_name[operation_id - AVRCP_OPERATION_ID_SKIP]; 128ce66cc7aSMilanka Ringwald } 129ce66cc7aSMilanka Ringwald if (name == NULL){ 130ce66cc7aSMilanka Ringwald static char buffer[13]; 1310b578d06SMilanka Ringwald snprintf(buffer, sizeof(buffer), "Unknown 0x%02x", operation_id); 132ce66cc7aSMilanka Ringwald buffer[sizeof(buffer)-1] = 0; 133ce66cc7aSMilanka Ringwald return buffer; 134ce66cc7aSMilanka Ringwald } else { 135ce66cc7aSMilanka Ringwald return name; 136ce66cc7aSMilanka Ringwald } 137be32e7f1SMilanka Ringwald } 138be32e7f1SMilanka Ringwald 139be32e7f1SMilanka Ringwald static const char * avrcp_media_attribute_id_name[] = { 140be32e7f1SMilanka Ringwald "NONE", "TITLE", "ARTIST", "ALBUM", "TRACK", "TOTAL TRACKS", "GENRE", "SONG LENGTH" 141be32e7f1SMilanka Ringwald }; 142be32e7f1SMilanka Ringwald const char * avrcp_attribute2str(uint8_t index){ 143c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 7)) return avrcp_media_attribute_id_name[index]; 144be32e7f1SMilanka Ringwald return avrcp_media_attribute_id_name[0]; 145be32e7f1SMilanka Ringwald } 146be32e7f1SMilanka Ringwald 147be32e7f1SMilanka Ringwald static const char * avrcp_play_status_name[] = { 148be32e7f1SMilanka Ringwald "STOPPED", "PLAYING", "PAUSED", "FORWARD SEEK", "REVERSE SEEK", 149be32e7f1SMilanka Ringwald "ERROR" // 0xFF 150be32e7f1SMilanka Ringwald }; 151be32e7f1SMilanka Ringwald const char * avrcp_play_status2str(uint8_t index){ 152c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 4)) return avrcp_play_status_name[index]; 153be32e7f1SMilanka Ringwald return avrcp_play_status_name[5]; 154be32e7f1SMilanka Ringwald } 155be32e7f1SMilanka Ringwald 156be32e7f1SMilanka Ringwald static const char * avrcp_ctype_name[] = { 157be32e7f1SMilanka Ringwald "CONTROL", 158be32e7f1SMilanka Ringwald "STATUS", 159be32e7f1SMilanka Ringwald "SPECIFIC_INQUIRY", 160be32e7f1SMilanka Ringwald "NOTIFY", 161be32e7f1SMilanka Ringwald "GENERAL_INQUIRY", 162be32e7f1SMilanka Ringwald "RESERVED5", 163be32e7f1SMilanka Ringwald "RESERVED6", 164be32e7f1SMilanka Ringwald "RESERVED7", 1659cc1f3ceSMilanka Ringwald "NOT IMPLEMENTED IN REMOTE", 1669cc1f3ceSMilanka Ringwald "ACCEPTED BY REMOTE", 1679cc1f3ceSMilanka Ringwald "REJECTED BY REMOTE", 168be32e7f1SMilanka Ringwald "IN_TRANSITION", 169be32e7f1SMilanka Ringwald "IMPLEMENTED_STABLE", 170be32e7f1SMilanka Ringwald "CHANGED_STABLE", 171be32e7f1SMilanka Ringwald "RESERVED", 172be32e7f1SMilanka Ringwald "INTERIM" 173be32e7f1SMilanka Ringwald }; 174be32e7f1SMilanka Ringwald const char * avrcp_ctype2str(uint8_t index){ 1753982eab9SMatthias Ringwald if (index < sizeof(avrcp_ctype_name)){ 176be32e7f1SMilanka Ringwald return avrcp_ctype_name[index]; 177be32e7f1SMilanka Ringwald } 178be32e7f1SMilanka Ringwald return "NONE"; 179be32e7f1SMilanka Ringwald } 180be32e7f1SMilanka Ringwald 181be32e7f1SMilanka Ringwald static const char * avrcp_shuffle_mode_name[] = { 182be32e7f1SMilanka Ringwald "SHUFFLE OFF", 183be32e7f1SMilanka Ringwald "SHUFFLE ALL TRACKS", 184be32e7f1SMilanka Ringwald "SHUFFLE GROUP" 185be32e7f1SMilanka Ringwald }; 186be32e7f1SMilanka Ringwald 187be32e7f1SMilanka Ringwald const char * avrcp_shuffle2str(uint8_t index){ 188c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 3)) return avrcp_shuffle_mode_name[index-1]; 189be32e7f1SMilanka Ringwald return "NONE"; 190be32e7f1SMilanka Ringwald } 191be32e7f1SMilanka Ringwald 192be32e7f1SMilanka Ringwald static const char * avrcp_repeat_mode_name[] = { 193be32e7f1SMilanka Ringwald "REPEAT OFF", 194be32e7f1SMilanka Ringwald "REPEAT SINGLE TRACK", 195be32e7f1SMilanka Ringwald "REPEAT ALL TRACKS", 196be32e7f1SMilanka Ringwald "REPEAT GROUP" 197be32e7f1SMilanka Ringwald }; 198be32e7f1SMilanka Ringwald 199be32e7f1SMilanka Ringwald const char * avrcp_repeat2str(uint8_t index){ 200c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 4)) return avrcp_repeat_mode_name[index-1]; 201be32e7f1SMilanka Ringwald return "NONE"; 202be32e7f1SMilanka Ringwald } 2036086246cSMilanka Ringwald 20464a27ec5SMilanka Ringwald btstack_linked_list_t avrcp_get_connections(void){ 20564a27ec5SMilanka Ringwald return connections; 20664a27ec5SMilanka Ringwald } 20764a27ec5SMilanka Ringwald 2084b338011SMilanka Ringwald uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ 2094b338011SMilanka Ringwald uint8_t cmd_opcode_index = 5; 2104b338011SMilanka Ringwald if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; 2114b338011SMilanka Ringwald return packet[cmd_opcode_index]; 2124b338011SMilanka Ringwald } 2134b338011SMilanka Ringwald 214654724deSMilanka Ringwald void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, 215654724deSMilanka Ringwald const char * service_name, const char * service_provider_name){ 216be32e7f1SMilanka Ringwald uint8_t* attribute; 217be32e7f1SMilanka Ringwald de_create_sequence(service); 218be32e7f1SMilanka Ringwald 219be32e7f1SMilanka Ringwald // 0x0000 "Service Record Handle" 220235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE); 221be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle); 222be32e7f1SMilanka Ringwald 223be32e7f1SMilanka Ringwald // 0x0001 "Service Class ID List" 224235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST); 225be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 226be32e7f1SMilanka Ringwald { 227be32e7f1SMilanka Ringwald if (controller){ 2286086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 2296086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER); 230be32e7f1SMilanka Ringwald } else { 2316086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET); 232be32e7f1SMilanka Ringwald } 233be32e7f1SMilanka Ringwald } 234be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 235be32e7f1SMilanka Ringwald 236be32e7f1SMilanka Ringwald // 0x0004 "Protocol Descriptor List" 237235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST); 238be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 239be32e7f1SMilanka Ringwald { 240be32e7f1SMilanka Ringwald uint8_t* l2cpProtocol = de_push_sequence(attribute); 241be32e7f1SMilanka Ringwald { 242235946f1SMatthias Ringwald de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 24384e3541eSMilanka Ringwald de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP); 244be32e7f1SMilanka Ringwald } 245be32e7f1SMilanka Ringwald de_pop_sequence(attribute, l2cpProtocol); 246be32e7f1SMilanka Ringwald 247be32e7f1SMilanka Ringwald uint8_t* avctpProtocol = de_push_sequence(attribute); 248be32e7f1SMilanka Ringwald { 249235946f1SMatthias Ringwald de_add_number(avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // avctpProtocol_service 2500b322400SMilanka Ringwald de_add_number(avctpProtocol, DE_UINT, DE_SIZE_16, 0x0104); // version 251be32e7f1SMilanka Ringwald } 252be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avctpProtocol); 253be32e7f1SMilanka Ringwald } 254be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 255be32e7f1SMilanka Ringwald 256be32e7f1SMilanka Ringwald // 0x0005 "Public Browse Group" 257235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group 258be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 259be32e7f1SMilanka Ringwald { 260235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT); 261be32e7f1SMilanka Ringwald } 262be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 263be32e7f1SMilanka Ringwald 264be32e7f1SMilanka Ringwald // 0x0009 "Bluetooth Profile Descriptor List" 265235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST); 266be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 267be32e7f1SMilanka Ringwald { 268be32e7f1SMilanka Ringwald uint8_t *avrcProfile = de_push_sequence(attribute); 269be32e7f1SMilanka Ringwald { 2706086246cSMilanka Ringwald de_add_number(avrcProfile, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 2710b322400SMilanka Ringwald de_add_number(avrcProfile, DE_UINT, DE_SIZE_16, 0x0106); 272be32e7f1SMilanka Ringwald } 273be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avrcProfile); 274be32e7f1SMilanka Ringwald } 275be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 276be32e7f1SMilanka Ringwald 277a0f524f0SMatthias Ringwald // 0x000d "Additional Bluetooth Profile Descriptor List" 2785c806868SMatthias Ringwald if (browsing){ 279a0f524f0SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS); 280a0f524f0SMatthias Ringwald attribute = de_push_sequence(service); 2815c806868SMatthias Ringwald { 2825c806868SMatthias Ringwald uint8_t * des = de_push_sequence(attribute); 2835c806868SMatthias Ringwald { 2845c806868SMatthias Ringwald uint8_t* browsing_l2cpProtocol = de_push_sequence(des); 285a0f524f0SMatthias Ringwald { 286a0f524f0SMatthias Ringwald de_add_number(browsing_l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 28784e3541eSMilanka Ringwald de_add_number(browsing_l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP_BROWSING); 288a0f524f0SMatthias Ringwald } 2895c806868SMatthias Ringwald de_pop_sequence(des, browsing_l2cpProtocol); 290a0f524f0SMatthias Ringwald 2915c806868SMatthias Ringwald uint8_t* browsing_avctpProtocol = de_push_sequence(des); 292a0f524f0SMatthias Ringwald { 293a0f524f0SMatthias Ringwald de_add_number(browsing_avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // browsing_avctpProtocol_service 2940b322400SMilanka Ringwald de_add_number(browsing_avctpProtocol, DE_UINT, DE_SIZE_16, 0x0104); // version 295a0f524f0SMatthias Ringwald } 2965c806868SMatthias Ringwald de_pop_sequence(des, browsing_avctpProtocol); 2975c806868SMatthias Ringwald } 2985c806868SMatthias Ringwald de_pop_sequence(attribute, des); 299a0f524f0SMatthias Ringwald } 300a0f524f0SMatthias Ringwald de_pop_sequence(service, attribute); 3015c806868SMatthias Ringwald } 302a0f524f0SMatthias Ringwald 303be32e7f1SMilanka Ringwald 304be32e7f1SMilanka Ringwald // 0x0100 "Service Name" 305be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); 306be32e7f1SMilanka Ringwald if (service_name){ 307be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name); 308be32e7f1SMilanka Ringwald } else { 309be32e7f1SMilanka Ringwald if (controller){ 310be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_controller_service_name), (uint8_t *) default_avrcp_controller_service_name); 311be32e7f1SMilanka Ringwald } else { 312be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_target_service_name), (uint8_t *) default_avrcp_target_service_name); 313be32e7f1SMilanka Ringwald } 314be32e7f1SMilanka Ringwald } 315be32e7f1SMilanka Ringwald 316be32e7f1SMilanka Ringwald // 0x0100 "Provider Name" 317be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102); 318be32e7f1SMilanka Ringwald if (service_provider_name){ 319be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name); 320be32e7f1SMilanka Ringwald } else { 321be32e7f1SMilanka Ringwald if (controller){ 322be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_controller_service_provider_name), (uint8_t *) default_avrcp_controller_service_provider_name); 323be32e7f1SMilanka Ringwald } else { 324be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_target_service_provider_name), (uint8_t *) default_avrcp_target_service_provider_name); 325be32e7f1SMilanka Ringwald } 326be32e7f1SMilanka Ringwald } 327be32e7f1SMilanka Ringwald 328be32e7f1SMilanka Ringwald // 0x0311 "Supported Features" 329be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); 330be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 331be32e7f1SMilanka Ringwald } 332be32e7f1SMilanka Ringwald 3331945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_bd_addr_for_role(avrcp_role_t role, bd_addr_t addr){ 3346983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 335638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 3366983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3376983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 33894d9400dSMilanka Ringwald if (connection->role != role) continue; 3396983e65eSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 3406983e65eSMilanka Ringwald return connection; 3416983e65eSMilanka Ringwald } 3426983e65eSMilanka Ringwald return NULL; 343be32e7f1SMilanka Ringwald } 344be32e7f1SMilanka Ringwald 3451945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_l2cap_signaling_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 3466983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 347638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 3486983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3496983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 35094d9400dSMilanka Ringwald if (connection->role != role) continue; 3516983e65eSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 3526983e65eSMilanka Ringwald return connection; 3536983e65eSMilanka Ringwald } 3546983e65eSMilanka Ringwald return NULL; 355be32e7f1SMilanka Ringwald } 356be32e7f1SMilanka Ringwald 3571945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_avrcp_cid_for_role(avrcp_role_t role, uint16_t avrcp_cid){ 3586983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 359638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 3606983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3616983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 36294d9400dSMilanka Ringwald if (connection->role != role) continue; 36301dc6e35SMilanka Ringwald if (connection->avrcp_cid != avrcp_cid) continue; 3646983e65eSMilanka Ringwald return connection; 3656983e65eSMilanka Ringwald } 3666983e65eSMilanka Ringwald return NULL; 3676983e65eSMilanka Ringwald } 3686983e65eSMilanka Ringwald 3691945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid){ 37003a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 37103a72c8eSMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 37203a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 37303a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 37403a72c8eSMatthias Ringwald if (connection->role != role) continue; 37503a72c8eSMatthias Ringwald if (connection->avrcp_browsing_cid != browsing_cid) continue; 37603a72c8eSMatthias Ringwald return connection; 37703a72c8eSMatthias Ringwald } 37803a72c8eSMatthias Ringwald return NULL; 37903a72c8eSMatthias Ringwald } 38003a72c8eSMatthias Ringwald 3811945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_l2cap_cid_for_role(avrcp_role_t role, uint16_t browsing_l2cap_cid){ 38203a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 38303a72c8eSMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 38403a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 38503a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 38603a72c8eSMatthias Ringwald if (connection->role != role) continue; 38703a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != browsing_l2cap_cid)) continue; 38803a72c8eSMatthias Ringwald return connection; 38903a72c8eSMatthias Ringwald } 39003a72c8eSMatthias Ringwald return NULL; 39103a72c8eSMatthias Ringwald } 39203a72c8eSMatthias Ringwald 3931945fe3eSMilanka Ringwald avrcp_browsing_connection_t * avrcp_get_browsing_connection_for_l2cap_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 39403a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 39503a72c8eSMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 39603a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 39703a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 39803a72c8eSMatthias Ringwald if (connection->role != role) continue; 39903a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != l2cap_cid)) continue; 40003a72c8eSMatthias Ringwald return connection->browsing_connection; 40103a72c8eSMatthias Ringwald } 40203a72c8eSMatthias Ringwald return NULL; 40303a72c8eSMatthias Ringwald } 40403a72c8eSMatthias Ringwald 4056983e65eSMilanka Ringwald void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){ 406cf36dea0SMilanka Ringwald connection->wait_to_send = true; 4076983e65eSMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 4086983e65eSMilanka Ringwald } 4096983e65eSMilanka Ringwald 410298aeecdSMilanka Ringwald uint16_t avrcp_get_next_cid(avrcp_role_t role){ 411298aeecdSMilanka Ringwald do { 412298aeecdSMilanka Ringwald if (avrcp_cid_counter == 0xffff) { 4136983e65eSMilanka Ringwald avrcp_cid_counter = 1; 414298aeecdSMilanka Ringwald } else { 415298aeecdSMilanka Ringwald avrcp_cid_counter++; 4166983e65eSMilanka Ringwald } 4171945fe3eSMilanka Ringwald } while (avrcp_get_connection_for_avrcp_cid_for_role(role, avrcp_cid_counter) != NULL) ; 4186983e65eSMilanka Ringwald return avrcp_cid_counter; 4196983e65eSMilanka Ringwald } 4206983e65eSMilanka Ringwald 421638481deSMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){ 4226983e65eSMilanka Ringwald avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); 4234567cc17SMilanka Ringwald if (!connection){ 4240ec79bd0SMilanka Ringwald log_error("Not enough memory to create connection for role %d", role); 4254567cc17SMilanka Ringwald return NULL; 4264567cc17SMilanka Ringwald } 4270036e267SMilanka Ringwald 4286983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_IDLE; 4290036e267SMilanka Ringwald connection->role = role; 430022b77fcSMilanka Ringwald 431022b77fcSMilanka Ringwald connection->transaction_id = 0xFF; 43223773c45SMilanka Ringwald connection->transaction_id_counter = 0; 433022b77fcSMilanka Ringwald 4348b2b4034SMilanka Ringwald connection->max_num_fragments = 0xFF; 435*f0af2234SMatthias Ringwald 436*f0af2234SMatthias Ringwald // setup default unit / subunit info 437*f0af2234SMatthias Ringwald connection->company_id = 0xffffff; 438*f0af2234SMatthias Ringwald connection->unit_type = AVRCP_SUBUNIT_TYPE_PANEL; 439*f0af2234SMatthias Ringwald connection->subunit_info_data_size = sizeof(avrcp_default_subunit_info); 440*f0af2234SMatthias Ringwald connection->subunit_info_data = avrcp_default_subunit_info; 441*f0af2234SMatthias Ringwald 442c91f9817SMilanka Ringwald log_info("avrcp_create_connection, role %d", role); 4436535961aSMatthias Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 444638481deSMilanka Ringwald btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection); 4456983e65eSMilanka Ringwald return connection; 4466983e65eSMilanka Ringwald } 4476983e65eSMilanka Ringwald 448638481deSMilanka Ringwald static void avrcp_finalize_connection(avrcp_connection_t * connection){ 44937fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 450638481deSMilanka Ringwald btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection); 45155e8029cSMatthias Ringwald btstack_memory_avrcp_connection_free(connection); 45255e8029cSMatthias Ringwald } 4536983e65eSMilanka Ringwald 4547dbc6cb8SMilanka Ringwald static void avrcp_emit_connection_established(uint16_t avrcp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status){ 455cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 456cee0e5b6SMilanka Ringwald 4577dbc6cb8SMilanka Ringwald uint8_t event[14]; 458b193c45eSMilanka Ringwald int pos = 0; 459b193c45eSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 460b193c45eSMilanka Ringwald event[pos++] = sizeof(event) - 2; 461b193c45eSMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED; 4626f43fcd7SMatthias Ringwald event[pos++] = status; 4637dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 4647dbc6cb8SMilanka Ringwald pos += 2; 465b193c45eSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 466b193c45eSMilanka Ringwald pos += 6; 4677dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, con_handle); 468b193c45eSMilanka Ringwald pos += 2; 469cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 470b193c45eSMilanka Ringwald } 471b193c45eSMilanka Ringwald 472cee0e5b6SMilanka Ringwald static void avrcp_emit_connection_closed(uint16_t avrcp_cid){ 473cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 474cee0e5b6SMilanka Ringwald 475be32e7f1SMilanka Ringwald uint8_t event[5]; 476be32e7f1SMilanka Ringwald int pos = 0; 477be32e7f1SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 478be32e7f1SMilanka Ringwald event[pos++] = sizeof(event) - 2; 479be32e7f1SMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED; 480b193c45eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 481be32e7f1SMilanka Ringwald pos += 2; 482cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 483be32e7f1SMilanka Ringwald } 484be32e7f1SMilanka Ringwald 4856d8f569dSMilanka Ringwald uint16_t avrcp_sdp_query_browsing_l2cap_psm(void){ 48664a27ec5SMilanka Ringwald return sdp_query_context.browsing_l2cap_psm; 4874dc95c12SMatthias Ringwald } 4884dc95c12SMatthias Ringwald 4894dc95c12SMatthias Ringwald void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ 4906086246cSMilanka Ringwald des_iterator_t des_list_it; 4916086246cSMilanka Ringwald des_iterator_t prot_it; 4926086246cSMilanka Ringwald 4936086246cSMilanka Ringwald // Handle new SDP record 49464a27ec5SMilanka Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != sdp_query_context.record_id) { 49564a27ec5SMilanka Ringwald sdp_query_context.record_id = sdp_event_query_attribute_byte_get_record_id(packet); 49664a27ec5SMilanka Ringwald sdp_query_context.parse_sdp_record = 0; 4976086246cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 4986086246cSMilanka Ringwald } 4996086246cSMilanka Ringwald 5006086246cSMilanka Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 5016086246cSMilanka Ringwald attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 5026086246cSMilanka Ringwald 5036086246cSMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 5046086246cSMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 5056086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 5066086246cSMilanka Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 5076086246cSMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 5086086246cSMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 5096086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 5106086246cSMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 5116086246cSMilanka Ringwald switch (uuid){ 5126086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET: 5136086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL: 514df642728SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: 51564a27ec5SMilanka Ringwald sdp_query_context.parse_sdp_record = 1; 5166086246cSMilanka Ringwald break; 5176086246cSMilanka Ringwald default: 5186086246cSMilanka Ringwald break; 5196086246cSMilanka Ringwald } 5206086246cSMilanka Ringwald } 5216086246cSMilanka Ringwald break; 5226086246cSMilanka Ringwald 5236086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: { 52464a27ec5SMilanka Ringwald if (!sdp_query_context.parse_sdp_record) break; 5256086246cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 5266086246cSMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 5276086246cSMilanka Ringwald uint8_t *des_element; 5286086246cSMilanka Ringwald uint8_t *element; 5296086246cSMilanka Ringwald uint32_t uuid; 5306086246cSMilanka Ringwald 5316086246cSMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 5326086246cSMilanka Ringwald 5336086246cSMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 5346086246cSMilanka Ringwald des_iterator_init(&prot_it, des_element); 5356086246cSMilanka Ringwald element = des_iterator_get_element(&prot_it); 5366086246cSMilanka Ringwald 5376086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 5386086246cSMilanka Ringwald 5396086246cSMilanka Ringwald uuid = de_get_uuid32(element); 54014fd128cSMatthias Ringwald des_iterator_next(&prot_it); 5416086246cSMilanka Ringwald switch (uuid){ 5426086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 5436086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 54464a27ec5SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_l2cap_psm); 5456086246cSMilanka Ringwald break; 5466086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 5476086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 54864a27ec5SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_version); 5496086246cSMilanka Ringwald break; 5506086246cSMilanka Ringwald default: 5516086246cSMilanka Ringwald break; 5526086246cSMilanka Ringwald } 5536086246cSMilanka Ringwald } 5546086246cSMilanka Ringwald } 5556086246cSMilanka Ringwald break; 556227d16a5SMatthias Ringwald case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: { 557227d16a5SMatthias Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 55864a27ec5SMilanka Ringwald if (!sdp_query_context.parse_sdp_record) break; 559227d16a5SMatthias Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 560227d16a5SMatthias Ringwald 561227d16a5SMatthias Ringwald des_iterator_t des_list_0_it; 562227d16a5SMatthias Ringwald uint8_t *element_0; 563227d16a5SMatthias Ringwald 564227d16a5SMatthias Ringwald des_iterator_init(&des_list_0_it, attribute_value); 565227d16a5SMatthias Ringwald element_0 = des_iterator_get_element(&des_list_0_it); 566227d16a5SMatthias Ringwald 567227d16a5SMatthias Ringwald for (des_iterator_init(&des_list_it, element_0); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 568227d16a5SMatthias Ringwald uint8_t *des_element; 569227d16a5SMatthias Ringwald uint8_t *element; 570227d16a5SMatthias Ringwald uint32_t uuid; 571227d16a5SMatthias Ringwald 572227d16a5SMatthias Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 573227d16a5SMatthias Ringwald 574227d16a5SMatthias Ringwald des_element = des_iterator_get_element(&des_list_it); 575227d16a5SMatthias Ringwald des_iterator_init(&prot_it, des_element); 576227d16a5SMatthias Ringwald element = des_iterator_get_element(&prot_it); 577227d16a5SMatthias Ringwald 578227d16a5SMatthias Ringwald if (de_get_element_type(element) != DE_UUID) continue; 579227d16a5SMatthias Ringwald 580227d16a5SMatthias Ringwald uuid = de_get_uuid32(element); 58114fd128cSMatthias Ringwald des_iterator_next(&prot_it); 582227d16a5SMatthias Ringwald switch (uuid){ 583227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 584227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 58564a27ec5SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.browsing_l2cap_psm); 586227d16a5SMatthias Ringwald break; 587227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 588227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 58964a27ec5SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.browsing_version); 590227d16a5SMatthias Ringwald break; 591227d16a5SMatthias Ringwald default: 592227d16a5SMatthias Ringwald break; 593227d16a5SMatthias Ringwald } 594227d16a5SMatthias Ringwald } 595227d16a5SMatthias Ringwald } 596227d16a5SMatthias Ringwald break; 5976086246cSMilanka Ringwald default: 5986086246cSMilanka Ringwald break; 5996086246cSMilanka Ringwald } 6006086246cSMilanka Ringwald } 6016086246cSMilanka Ringwald } else { 6026086246cSMilanka 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)); 6036086246cSMilanka Ringwald } 6047b81669aSMatthias Ringwald } 6057b81669aSMatthias Ringwald 606463f41baSMilanka Ringwald static void avrcp_handle_sdp_query_failed(avrcp_connection_t * connection, uint8_t status){ 607b68672eaSMilanka Ringwald if (connection == NULL) return; 608463f41baSMilanka Ringwald log_info("AVRCP: SDP query failed with status 0x%02x.", status); 6097dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection->avrcp_cid, connection->remote_addr, connection->con_handle, status); 610463f41baSMilanka Ringwald avrcp_finalize_connection(connection); 611463f41baSMilanka Ringwald } 612463f41baSMilanka Ringwald 613a062fcddSMilanka Ringwald static void avrcp_handle_sdp_query_succeeded(avrcp_connection_t * connection){ 614b68672eaSMilanka Ringwald if (connection == NULL) return; 615463f41baSMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 61664a27ec5SMilanka Ringwald connection->avrcp_l2cap_psm = sdp_query_context.avrcp_l2cap_psm; 61764a27ec5SMilanka Ringwald connection->browsing_version = sdp_query_context.browsing_version; 61864a27ec5SMilanka Ringwald connection->browsing_l2cap_psm = sdp_query_context.browsing_l2cap_psm; 619463f41baSMilanka Ringwald } 620463f41baSMilanka Ringwald 621a062fcddSMilanka Ringwald static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 62250fc39c5SMilanka Ringwald UNUSED(packet_type); 62350fc39c5SMilanka Ringwald UNUSED(channel); 62450fc39c5SMilanka Ringwald UNUSED(size); 62550fc39c5SMilanka Ringwald 6262423506bSMilanka Ringwald bool state_ok = true; 62764a27ec5SMilanka Ringwald avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, sdp_query_context.avrcp_cid); 6282423506bSMilanka Ringwald if (!avrcp_target_connection || avrcp_target_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 6292423506bSMilanka Ringwald state_ok = false; 63064a27ec5SMilanka Ringwald } 63164a27ec5SMilanka Ringwald avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, sdp_query_context.avrcp_cid); 6322423506bSMilanka Ringwald if (!avrcp_controller_connection || avrcp_controller_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 6332423506bSMilanka Ringwald state_ok = false; 6342423506bSMilanka Ringwald } 6352423506bSMilanka Ringwald if (!state_ok){ 6362423506bSMilanka Ringwald // something wrong, nevertheless, start next sdp query if this one is complete 6372423506bSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 6382423506bSMilanka Ringwald (void) sdp_client_register_query_callback(&avrcp_handle_sdp_client_query_request); 6392423506bSMilanka Ringwald } 64064a27ec5SMilanka Ringwald return; 64164a27ec5SMilanka Ringwald } 6427b81669aSMatthias Ringwald 6437b81669aSMatthias Ringwald uint8_t status; 6447b81669aSMatthias Ringwald 6457b81669aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 6467b81669aSMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 64750fc39c5SMilanka Ringwald avrcp_handle_sdp_client_query_attribute_value(packet); 6482423506bSMilanka Ringwald return; 6496086246cSMilanka Ringwald 65050fc39c5SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 6515448c259SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 652247956eaSMilanka Ringwald 6535448c259SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 654b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, status); 655b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, status); 6565448c259SMilanka Ringwald break; 6575448c259SMilanka Ringwald } 6585448c259SMilanka Ringwald 65964a27ec5SMilanka Ringwald if (!sdp_query_context.avrcp_l2cap_psm){ 660b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, SDP_SERVICE_NOT_FOUND); 661b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, SDP_SERVICE_NOT_FOUND); 6626983e65eSMilanka Ringwald break; 6636983e65eSMilanka Ringwald } 664be32e7f1SMilanka Ringwald 665a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_controller_connection); 666a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_target_connection); 667bd66227aSMilanka Ringwald 66864a27ec5SMilanka Ringwald l2cap_create_channel(&avrcp_packet_handler, avrcp_target_connection->remote_addr, sdp_query_context.avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 669463f41baSMilanka Ringwald break; 67050fc39c5SMilanka Ringwald 67150fc39c5SMilanka Ringwald default: 6722423506bSMilanka Ringwald return; 6730036e267SMilanka Ringwald } 67464a27ec5SMilanka Ringwald 67564a27ec5SMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 67664a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 67764a27ec5SMilanka Ringwald (void) sdp_client_register_query_callback(&avrcp_handle_sdp_client_query_request); 678463f41baSMilanka Ringwald } 67950fc39c5SMilanka Ringwald 680be32e7f1SMilanka Ringwald 6817dbc6cb8SMilanka Ringwald static avrcp_connection_t * avrcp_handle_incoming_connection_for_role(avrcp_role_t role, avrcp_connection_t * connection, bd_addr_t event_addr, hci_con_handle_t con_handle, uint16_t local_cid, uint16_t avrcp_cid){ 682a062fcddSMilanka Ringwald if (connection == NULL){ 683a062fcddSMilanka Ringwald connection = avrcp_create_connection(role, event_addr); 684be32e7f1SMilanka Ringwald } 685a062fcddSMilanka Ringwald if (connection) { 6860f76c2d7SMatthias Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 6870f76c2d7SMatthias Ringwald connection->l2cap_signaling_cid = local_cid; 6887403cbbaSMilanka Ringwald connection->avrcp_cid = avrcp_cid; 6897dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 69037fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 691a062fcddSMilanka Ringwald } 692a062fcddSMilanka Ringwald return connection; 693654724deSMilanka Ringwald } 694be32e7f1SMilanka Ringwald 6957dbc6cb8SMilanka Ringwald static void avrcp_handle_open_connection(avrcp_connection_t * connection, hci_con_handle_t con_handle, uint16_t local_cid, uint16_t l2cap_mtu){ 696be32e7f1SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 6970036e267SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 6987dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 699558ceb4aSMilanka Ringwald connection->incoming_declined = false; 700d1207cd8SMilanka Ringwald connection->song_length_ms = 0xFFFFFFFF; 701d1207cd8SMilanka Ringwald connection->song_position_ms = 0xFFFFFFFF; 702d1207cd8SMilanka Ringwald connection->playback_status = AVRCP_PLAYBACK_STATUS_ERROR; 703cee0e5b6SMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 704d1207cd8SMilanka Ringwald 70564a27ec5SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d, state %d", connection->avrcp_cid, connection->l2cap_signaling_cid, connection->role, connection->state); 7060036e267SMilanka Ringwald } 7070036e267SMilanka Ringwald 70837fae987SMilanka Ringwald static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 709a062fcddSMilanka Ringwald uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 7101945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 71114c8559dSMilanka Ringwald if (connection_controller == NULL) return; 7121945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 71314c8559dSMilanka Ringwald if (connection_target == NULL) return; 714a062fcddSMilanka Ringwald 71537fae987SMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W2_L2CAP_RETRY){ 71614c8559dSMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 71714c8559dSMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 71814c8559dSMilanka Ringwald l2cap_create_channel(&avrcp_packet_handler, connection_controller->remote_addr, connection_controller->avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 71914c8559dSMilanka Ringwald } 720a062fcddSMilanka Ringwald } 721a062fcddSMilanka Ringwald 72237fae987SMilanka Ringwald static void avrcp_retry_timer_start(avrcp_connection_t * connection){ 72337fae987SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avrcp_retry_timer_timeout_handler); 72437fae987SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avrcp_cid); 725a062fcddSMilanka Ringwald 726a062fcddSMilanka Ringwald // add some jitter/randomness to reconnect delay 727a062fcddSMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 72837fae987SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 729a062fcddSMilanka Ringwald 73037fae987SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 731a062fcddSMilanka Ringwald } 732a062fcddSMilanka Ringwald 733b8081399SMilanka Ringwald static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){ 734b8081399SMilanka Ringwald return (avrcp_frame_type_t)((header & 0x02) >> 1); 735b8081399SMilanka Ringwald } 736b8081399SMilanka Ringwald 7370036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 7380036e267SMilanka Ringwald UNUSED(channel); 7390036e267SMilanka Ringwald UNUSED(size); 7400036e267SMilanka Ringwald bd_addr_t event_addr; 7410036e267SMilanka Ringwald uint16_t local_cid; 7420036e267SMilanka Ringwald uint16_t l2cap_mtu; 7430036e267SMilanka Ringwald uint8_t status; 7449b1b0ebdSMatthias Ringwald bool decline_connection; 7459b1b0ebdSMatthias Ringwald bool outoing_active; 7467dbc6cb8SMilanka Ringwald hci_con_handle_t con_handle; 7470036e267SMilanka Ringwald 748cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_controller; 749cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_target; 750bf67b2dbSMatthias Ringwald bool can_send; 751cee0e5b6SMilanka Ringwald 7520036e267SMilanka Ringwald switch (packet_type) { 7530036e267SMilanka Ringwald case HCI_EVENT_PACKET: 7540036e267SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 7550036e267SMilanka Ringwald 7560036e267SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 757e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 758e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 759e3d57ee2SMilanka Ringwald 7600036e267SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 7610036e267SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 7627dbc6cb8SMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 763cee0e5b6SMilanka Ringwald 7647dbc6cb8SMilanka Ringwald outoing_active = false; 7651945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 766cee0e5b6SMilanka Ringwald if (connection_target != NULL){ 767a062fcddSMilanka Ringwald if (connection_target->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){ 7689b1b0ebdSMatthias Ringwald outoing_active = true; 769cee0e5b6SMilanka Ringwald connection_target->incoming_declined = true; 7709b1b0ebdSMatthias Ringwald } 771a062fcddSMilanka Ringwald } 772558ceb4aSMilanka Ringwald 7731945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 774cee0e5b6SMilanka Ringwald if (connection_controller != NULL){ 775a062fcddSMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) { 7769b1b0ebdSMatthias Ringwald outoing_active = true; 777cee0e5b6SMilanka Ringwald connection_controller->incoming_declined = true; 7789b1b0ebdSMatthias Ringwald } 779a062fcddSMilanka Ringwald } 780558ceb4aSMilanka Ringwald 7819b1b0ebdSMatthias Ringwald decline_connection = outoing_active; 782a062fcddSMilanka Ringwald if (decline_connection == false){ 783a062fcddSMilanka Ringwald uint16_t avrcp_cid; 784a062fcddSMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)){ 785a062fcddSMilanka Ringwald avrcp_cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 786a062fcddSMilanka Ringwald } else { 787a062fcddSMilanka Ringwald avrcp_cid = connection_controller->avrcp_cid; 788a062fcddSMilanka Ringwald } 7890036e267SMilanka Ringwald // create two connection objects (both) 7907dbc6cb8SMilanka Ringwald connection_target = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, connection_target, event_addr, con_handle, local_cid, avrcp_cid); 7917dbc6cb8SMilanka Ringwald connection_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, connection_controller, event_addr, con_handle, local_cid, avrcp_cid); 792a062fcddSMilanka Ringwald if ((connection_target == NULL) || (connection_controller == NULL)){ 7939b1b0ebdSMatthias Ringwald decline_connection = true; 794a062fcddSMilanka Ringwald if (connection_target) { 795a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_target); 796a062fcddSMilanka Ringwald } 797a062fcddSMilanka Ringwald if (connection_controller) { 798a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_controller); 799a062fcddSMilanka Ringwald } 8000036e267SMilanka Ringwald } 8019b1b0ebdSMatthias Ringwald } 8029b1b0ebdSMatthias Ringwald if (decline_connection){ 8039b1b0ebdSMatthias Ringwald l2cap_decline_connection(local_cid); 8049b1b0ebdSMatthias Ringwald } else { 80564a27ec5SMilanka Ringwald log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION local cid 0x%02x, state %d", local_cid, connection_controller->state); 8060036e267SMilanka Ringwald l2cap_accept_connection(local_cid); 8079b1b0ebdSMatthias Ringwald } 8080036e267SMilanka Ringwald break; 8090036e267SMilanka Ringwald 8100036e267SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 8110036e267SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 8120036e267SMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 8130036e267SMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 8140036e267SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 8157dbc6cb8SMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 8160036e267SMilanka Ringwald 8171945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 8181945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 819a062fcddSMilanka Ringwald 820a062fcddSMilanka Ringwald // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION 821a062fcddSMilanka Ringwald // outgoing: structs are cteated in avrcp_connect() 822cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 823cee0e5b6SMilanka Ringwald break; 824cee0e5b6SMilanka Ringwald } 825cee0e5b6SMilanka Ringwald 826a062fcddSMilanka Ringwald switch (status){ 827a062fcddSMilanka Ringwald case ERROR_CODE_SUCCESS: 8287dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_target, con_handle, local_cid, l2cap_mtu); 8297dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_controller, con_handle, local_cid, l2cap_mtu); 8307dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 831a062fcddSMilanka Ringwald return; 832a062fcddSMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 833a062fcddSMilanka Ringwald if (connection_controller->incoming_declined == true){ 834a062fcddSMilanka Ringwald log_info("Incoming connection was declined, and the outgoing failed"); 83537fae987SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 836a062fcddSMilanka Ringwald connection_controller->incoming_declined = false; 83737fae987SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 838a062fcddSMilanka Ringwald connection_target->incoming_declined = false; 83937fae987SMilanka Ringwald avrcp_retry_timer_start(connection_controller); 840a062fcddSMilanka Ringwald return; 841a062fcddSMilanka Ringwald } 842a062fcddSMilanka Ringwald break; 843a062fcddSMilanka Ringwald default: 844a062fcddSMilanka Ringwald break; 845a062fcddSMilanka Ringwald } 846cee0e5b6SMilanka Ringwald log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 8477dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 848cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 849cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 850cee0e5b6SMilanka Ringwald 851be32e7f1SMilanka Ringwald break; 852be32e7f1SMilanka Ringwald 853be32e7f1SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 854be32e7f1SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 855cee0e5b6SMilanka Ringwald 8561945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 8571945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 858cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 859cee0e5b6SMilanka Ringwald break; 860cee0e5b6SMilanka Ringwald } 861cee0e5b6SMilanka Ringwald avrcp_emit_connection_closed(connection_controller->avrcp_cid); 862cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 863cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 8640036e267SMilanka Ringwald break; 8650036e267SMilanka Ringwald 8660036e267SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 8670036e267SMilanka Ringwald local_cid = l2cap_event_can_send_now_get_local_cid(packet); 868bf67b2dbSMatthias Ringwald can_send = true; 869e3d57ee2SMilanka Ringwald 8701945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 871cf36dea0SMilanka Ringwald if ((connection_target != NULL) && connection_target->wait_to_send){ 872cf36dea0SMilanka Ringwald connection_target->wait_to_send = false; 8730036e267SMilanka Ringwald (*avrcp_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 874bf67b2dbSMatthias Ringwald can_send = false; 8750036e267SMilanka Ringwald } 8760036e267SMilanka Ringwald 8771945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 878cf36dea0SMilanka Ringwald if ((connection_controller != NULL) && connection_controller->wait_to_send){ 879bf67b2dbSMatthias Ringwald if (can_send){ 880cf36dea0SMilanka Ringwald connection_controller->wait_to_send = false; 8810036e267SMilanka Ringwald (*avrcp_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 882bf67b2dbSMatthias Ringwald } else { 883bf67b2dbSMatthias Ringwald l2cap_request_can_send_now_event(local_cid); 884bf67b2dbSMatthias Ringwald } 885be32e7f1SMilanka Ringwald } 886be32e7f1SMilanka Ringwald break; 8870036e267SMilanka Ringwald 888be32e7f1SMilanka Ringwald default: 889be32e7f1SMilanka Ringwald break; 890be32e7f1SMilanka Ringwald } 891b106f728SMilanka Ringwald break; 892e3d57ee2SMilanka Ringwald 893e3d57ee2SMilanka Ringwald case L2CAP_DATA_PACKET: 894b8081399SMilanka Ringwald switch (avrcp_get_frame_type(packet[0])){ 895e3d57ee2SMilanka Ringwald case AVRCP_RESPONSE_FRAME: 896e3d57ee2SMilanka Ringwald (*avrcp_controller_packet_handler)(packet_type, channel, packet, size); 897e3d57ee2SMilanka Ringwald break; 898e3d57ee2SMilanka Ringwald case AVRCP_COMMAND_FRAME: 899e3d57ee2SMilanka Ringwald default: // make compiler happy 900e3d57ee2SMilanka Ringwald (*avrcp_target_packet_handler)(packet_type, channel, packet, size); 901e3d57ee2SMilanka Ringwald break; 902e3d57ee2SMilanka Ringwald } 903e3d57ee2SMilanka Ringwald break; 904e3d57ee2SMilanka Ringwald 905b106f728SMilanka Ringwald default: 906b106f728SMilanka Ringwald break; 907b106f728SMilanka Ringwald } 908be32e7f1SMilanka Ringwald } 909be32e7f1SMilanka Ringwald 910fe10780bSMilanka Ringwald uint8_t avrcp_disconnect(uint16_t avrcp_cid){ 9111945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 912fe10780bSMilanka Ringwald if (!connection_controller){ 913fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 914fe10780bSMilanka Ringwald } 9151945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 916fe10780bSMilanka Ringwald if (!connection_target){ 917fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 918fe10780bSMilanka Ringwald } 919fe10780bSMilanka Ringwald if (connection_controller->browsing_connection){ 920fe10780bSMilanka Ringwald l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid, 0); 921fe10780bSMilanka Ringwald } 922fe10780bSMilanka Ringwald l2cap_disconnect(connection_controller->l2cap_signaling_cid, 0); 923fe10780bSMilanka Ringwald return ERROR_CODE_SUCCESS; 924fe10780bSMilanka Ringwald } 925fe10780bSMilanka Ringwald 92664a27ec5SMilanka Ringwald static void avrcp_handle_start_sdp_client_query(void * context){ 92764a27ec5SMilanka Ringwald UNUSED(context); 9284dc95c12SMatthias Ringwald 92964a27ec5SMilanka Ringwald btstack_linked_list_iterator_t it; 93064a27ec5SMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 93164a27ec5SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 93264a27ec5SMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 93364a27ec5SMilanka Ringwald 93464a27ec5SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_W2_SEND_SDP_QUERY) continue; 93564a27ec5SMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 93664a27ec5SMilanka Ringwald 93764a27ec5SMilanka Ringwald // prevent triggering SDP query twice (for each role once) 93864a27ec5SMilanka Ringwald avrcp_connection_t * connection_with_opposite_role; 93964a27ec5SMilanka Ringwald switch (connection->role){ 94064a27ec5SMilanka Ringwald case AVRCP_CONTROLLER: 94164a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid); 94264a27ec5SMilanka Ringwald break; 94364a27ec5SMilanka Ringwald case AVRCP_TARGET: 94464a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid); 94564a27ec5SMilanka Ringwald break; 94664a27ec5SMilanka Ringwald default: 94764a27ec5SMilanka Ringwald btstack_assert(false); 94864a27ec5SMilanka Ringwald return; 94964a27ec5SMilanka Ringwald } 95064a27ec5SMilanka Ringwald connection_with_opposite_role->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 95164a27ec5SMilanka Ringwald 95264a27ec5SMilanka Ringwald sdp_query_context.avrcp_l2cap_psm = 0; 95364a27ec5SMilanka Ringwald sdp_query_context.avrcp_version = 0; 95464a27ec5SMilanka Ringwald sdp_query_context.avrcp_cid = connection->avrcp_cid; 95564a27ec5SMilanka Ringwald sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP); 95664a27ec5SMilanka Ringwald return; 95764a27ec5SMilanka Ringwald } 9584dc95c12SMatthias Ringwald } 9594dc95c12SMatthias Ringwald 960fe10780bSMilanka Ringwald uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){ 961e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 962e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 963f9ef80eaSMilanka Ringwald 9641945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); 965bd66227aSMilanka Ringwald if (connection_controller){ 966bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 967bd66227aSMilanka Ringwald } 9681945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr); 969bd66227aSMilanka Ringwald if (connection_target){ 970bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 971bd66227aSMilanka Ringwald } 972bd66227aSMilanka Ringwald 9737403cbbaSMilanka Ringwald uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 9747403cbbaSMilanka Ringwald 975bd66227aSMilanka Ringwald connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 976bd66227aSMilanka Ringwald if (!connection_controller) return BTSTACK_MEMORY_ALLOC_FAILED; 977bd66227aSMilanka Ringwald 978bd66227aSMilanka Ringwald connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 979bd66227aSMilanka Ringwald if (!connection_target){ 980bd66227aSMilanka Ringwald avrcp_finalize_connection(connection_controller); 981bd66227aSMilanka Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 982bd66227aSMilanka Ringwald } 983bd66227aSMilanka Ringwald 984bd66227aSMilanka Ringwald if (avrcp_cid != NULL){ 985bd66227aSMilanka Ringwald *avrcp_cid = cid; 986bd66227aSMilanka Ringwald } 987bd66227aSMilanka Ringwald 98864a27ec5SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 9897403cbbaSMilanka Ringwald connection_controller->avrcp_cid = cid; 9907403cbbaSMilanka Ringwald 99164a27ec5SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 9927403cbbaSMilanka Ringwald connection_target->avrcp_cid = cid; 9935dd5e7e3SMilanka Ringwald 99464a27ec5SMilanka Ringwald avrcp_handle_sdp_client_query_request.callback = &avrcp_handle_start_sdp_client_query; 99564a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 99664a27ec5SMilanka Ringwald (void) sdp_client_register_query_callback(&avrcp_handle_sdp_client_query_request); 99764a27ec5SMilanka Ringwald return ERROR_CODE_SUCCESS; 998be32e7f1SMilanka Ringwald } 999638481deSMilanka Ringwald 1000638481deSMilanka Ringwald void avrcp_init(void){ 1001638481deSMilanka Ringwald connections = NULL; 1002b106f728SMilanka Ringwald if (l2cap_service_registered) return; 10030036e267SMilanka Ringwald 100478315a58SMatthias Ringwald int status = l2cap_register_service(&avrcp_packet_handler, BLUETOOTH_PSM_AVCTP, 0xffff, gap_get_security_level()); 1005b106f728SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return; 10060eebc132SMilanka Ringwald l2cap_service_registered = true; 1007638481deSMilanka Ringwald } 1008b106f728SMilanka Ringwald 1009680af5dcSMatthias Ringwald void avrcp_deinit(void){ 1010680af5dcSMatthias Ringwald avrcp_cid_counter = 0; 1011680af5dcSMatthias Ringwald l2cap_service_registered = false; 1012680af5dcSMatthias Ringwald 1013680af5dcSMatthias Ringwald (void) memset(&sdp_query_context, 0, sizeof(avrcp_sdp_query_context_t)); 1014680af5dcSMatthias Ringwald (void) memset(attribute_value,0, sizeof(attribute_value)); 1015680af5dcSMatthias Ringwald 1016680af5dcSMatthias Ringwald avrcp_callback = NULL; 1017680af5dcSMatthias Ringwald connections = NULL; 1018680af5dcSMatthias Ringwald avrcp_controller_packet_handler = NULL; 1019680af5dcSMatthias Ringwald avrcp_target_packet_handler = NULL; 1020680af5dcSMatthias Ringwald } 1021680af5dcSMatthias Ringwald 1022b106f728SMilanka Ringwald void avrcp_register_controller_packet_handler(btstack_packet_handler_t callback){ 1023b106f728SMilanka Ringwald avrcp_controller_packet_handler = callback; 1024b106f728SMilanka Ringwald } 1025b106f728SMilanka Ringwald 1026b106f728SMilanka Ringwald void avrcp_register_target_packet_handler(btstack_packet_handler_t callback){ 1027b106f728SMilanka Ringwald avrcp_target_packet_handler = callback; 1028b106f728SMilanka Ringwald } 1029b106f728SMilanka Ringwald 1030cee0e5b6SMilanka Ringwald void avrcp_register_packet_handler(btstack_packet_handler_t callback){ 1031cee0e5b6SMilanka Ringwald btstack_assert(callback != NULL); 1032cee0e5b6SMilanka Ringwald avrcp_callback = callback; 1033cee0e5b6SMilanka Ringwald } 1034697b823eSMatthias Ringwald 1035697b823eSMatthias Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 1036697b823eSMatthias Ringwald #define FUZZ_CID 0x44 10373cd982f4SMatthias Ringwald #define FUZZ_CON_HANDLE 0x0001 1038697b823eSMatthias Ringwald static bd_addr_t remote_addr = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 }; 1039697b823eSMatthias Ringwald void avrcp_init_fuzz(void){ 1040697b823eSMatthias Ringwald // setup avrcp connections for cid 1041697b823eSMatthias Ringwald avrcp_connection_t * connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 1042697b823eSMatthias Ringwald avrcp_connection_t * connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 10433cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_controller, FUZZ_CON_HANDLE, FUZZ_CID, 999); 10443cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_target, FUZZ_CON_HANDLE, FUZZ_CID, 999); 1045697b823eSMatthias Ringwald } 1046697b823eSMatthias Ringwald void avrcp_packet_handler_fuzz(uint8_t *packet, uint16_t size){ 1047697b823eSMatthias Ringwald avrcp_packet_handler(L2CAP_DATA_PACKET, FUZZ_CID, packet, size); 1048697b823eSMatthias Ringwald } 1049697b823eSMatthias Ringwald #endif