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> 42be32e7f1SMilanka Ringwald 4384e3541eSMilanka Ringwald #include "bluetooth_psm.h" 4484e3541eSMilanka Ringwald #include "bluetooth_sdp.h" 4584e3541eSMilanka Ringwald #include "btstack_debug.h" 4684e3541eSMilanka Ringwald #include "btstack_event.h" 4784e3541eSMilanka Ringwald #include "btstack_memory.h" 4884e3541eSMilanka Ringwald #include "classic/sdp_client.h" 4984e3541eSMilanka Ringwald #include "classic/sdp_util.h" 50be32e7f1SMilanka Ringwald #include "classic/avrcp.h" 510eebc132SMilanka Ringwald 5264a27ec5SMilanka Ringwald 5364a27ec5SMilanka Ringwald typedef struct { 5464a27ec5SMilanka Ringwald uint8_t parse_sdp_record; 5564a27ec5SMilanka Ringwald uint32_t record_id; 5664a27ec5SMilanka Ringwald uint16_t avrcp_cid; 5764a27ec5SMilanka Ringwald uint16_t avrcp_l2cap_psm; 5864a27ec5SMilanka Ringwald uint16_t avrcp_version; 5964a27ec5SMilanka Ringwald 6064a27ec5SMilanka Ringwald uint16_t browsing_l2cap_psm; 6164a27ec5SMilanka Ringwald uint16_t browsing_version; 6264a27ec5SMilanka Ringwald } avrcp_sdp_query_context_t; 6364a27ec5SMilanka Ringwald 6464a27ec5SMilanka Ringwald 650036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 660036e267SMilanka Ringwald 67be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service"; 68be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_provider_name = "BTstack AVRCP Controller Service Provider"; 69be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_name = "BTstack AVRCP Target Service"; 70be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_provider_name = "BTstack AVRCP Target Service Provider"; 71be32e7f1SMilanka Ringwald 72680af5dcSMatthias Ringwald static uint16_t avrcp_cid_counter; 73be32e7f1SMilanka Ringwald 7464a27ec5SMilanka Ringwald static btstack_context_callback_registration_t avrcp_handle_sdp_client_query_request; 7564a27ec5SMilanka Ringwald 7664a27ec5SMilanka Ringwald static avrcp_sdp_query_context_t sdp_query_context; 775dd5e7e3SMilanka Ringwald 78cee0e5b6SMilanka Ringwald static btstack_packet_handler_t avrcp_callback; 79cee0e5b6SMilanka Ringwald 80fa1ee4d3SMilanka Ringwald static uint8_t attribute_value[45]; 816983e65eSMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); 826983e65eSMilanka Ringwald 83638481deSMilanka Ringwald static btstack_linked_list_t connections; 84b106f728SMilanka Ringwald static btstack_packet_handler_t avrcp_controller_packet_handler; 85b106f728SMilanka Ringwald static btstack_packet_handler_t avrcp_target_packet_handler; 860eebc132SMilanka Ringwald static bool l2cap_service_registered = false; 870eebc132SMilanka Ringwald 88be32e7f1SMilanka Ringwald static const char * avrcp_subunit_type_name[] = { 89be32e7f1SMilanka Ringwald "MONITOR", "AUDIO", "PRINTER", "DISC", "TAPE_RECORDER_PLAYER", "TUNER", 90be32e7f1SMilanka Ringwald "CA", "CAMERA", "RESERVED", "PANEL", "BULLETIN_BOARD", "CAMERA_STORAGE", 91be32e7f1SMilanka Ringwald "VENDOR_UNIQUE", "RESERVED_FOR_ALL_SUBUNIT_TYPES", 92be32e7f1SMilanka Ringwald "EXTENDED_TO_NEXT_BYTE", "UNIT", "ERROR" 93be32e7f1SMilanka Ringwald }; 946983e65eSMilanka Ringwald 95be32e7f1SMilanka Ringwald const char * avrcp_subunit2str(uint16_t index){ 96be32e7f1SMilanka Ringwald if (index <= 11) return avrcp_subunit_type_name[index]; 970e588213SMatthias Ringwald if ((index >= 0x1C) && (index <= 0x1F)) return avrcp_subunit_type_name[index - 0x10]; 98be32e7f1SMilanka Ringwald return avrcp_subunit_type_name[16]; 99be32e7f1SMilanka Ringwald } 100be32e7f1SMilanka Ringwald 101be32e7f1SMilanka Ringwald static const char * avrcp_event_name[] = { 102be32e7f1SMilanka Ringwald "ERROR", "PLAYBACK_STATUS_CHANGED", 103be32e7f1SMilanka Ringwald "TRACK_CHANGED", "TRACK_REACHED_END", "TRACK_REACHED_START", 104be32e7f1SMilanka Ringwald "PLAYBACK_POS_CHANGED", "BATT_STATUS_CHANGED", "SYSTEM_STATUS_CHANGED", 105be32e7f1SMilanka Ringwald "PLAYER_APPLICATION_SETTING_CHANGED", "NOW_PLAYING_CONTENT_CHANGED", 106be32e7f1SMilanka Ringwald "AVAILABLE_PLAYERS_CHANGED", "ADDRESSED_PLAYER_CHANGED", "UIDS_CHANGED", "VOLUME_CHANGED" 107be32e7f1SMilanka Ringwald }; 108be32e7f1SMilanka Ringwald const char * avrcp_event2str(uint16_t index){ 109be32e7f1SMilanka Ringwald if (index <= 0x0d) return avrcp_event_name[index]; 110be32e7f1SMilanka Ringwald return avrcp_event_name[0]; 111be32e7f1SMilanka Ringwald } 112be32e7f1SMilanka Ringwald 113be32e7f1SMilanka Ringwald static const char * avrcp_operation_name[] = { 114*ce66cc7aSMilanka Ringwald NULL, // 0x3B 115*ce66cc7aSMilanka Ringwald "SKIP", NULL, NULL, NULL, NULL, 116*ce66cc7aSMilanka Ringwald "VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", NULL, 117*ce66cc7aSMilanka Ringwald "REWIND", "FAST_FORWARD", NULL, "FORWARD", "BACKWARD" // 0x4C 118be32e7f1SMilanka Ringwald }; 119be32e7f1SMilanka Ringwald const char * avrcp_operation2str(uint8_t index){ 120*ce66cc7aSMilanka Ringwald char * name = NULL; 121*ce66cc7aSMilanka Ringwald if ((index >= 0x3B) && (index <= 0x4C)){ 122*ce66cc7aSMilanka Ringwald name = (char *)avrcp_operation_name[index - 0x3B]; 123*ce66cc7aSMilanka Ringwald } 124*ce66cc7aSMilanka Ringwald if (name == NULL){ 125*ce66cc7aSMilanka Ringwald static char buffer[13]; 126*ce66cc7aSMilanka Ringwald snprintf(buffer, sizeof(buffer), "Unknown 0x%02x", index); 127*ce66cc7aSMilanka Ringwald buffer[sizeof(buffer)-1] = 0; 128*ce66cc7aSMilanka Ringwald return buffer; 129*ce66cc7aSMilanka Ringwald } else { 130*ce66cc7aSMilanka Ringwald return name; 131*ce66cc7aSMilanka Ringwald } 132be32e7f1SMilanka Ringwald } 133be32e7f1SMilanka Ringwald 134be32e7f1SMilanka Ringwald static const char * avrcp_media_attribute_id_name[] = { 135be32e7f1SMilanka Ringwald "NONE", "TITLE", "ARTIST", "ALBUM", "TRACK", "TOTAL TRACKS", "GENRE", "SONG LENGTH" 136be32e7f1SMilanka Ringwald }; 137be32e7f1SMilanka Ringwald const char * avrcp_attribute2str(uint8_t index){ 138c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 7)) return avrcp_media_attribute_id_name[index]; 139be32e7f1SMilanka Ringwald return avrcp_media_attribute_id_name[0]; 140be32e7f1SMilanka Ringwald } 141be32e7f1SMilanka Ringwald 142be32e7f1SMilanka Ringwald static const char * avrcp_play_status_name[] = { 143be32e7f1SMilanka Ringwald "STOPPED", "PLAYING", "PAUSED", "FORWARD SEEK", "REVERSE SEEK", 144be32e7f1SMilanka Ringwald "ERROR" // 0xFF 145be32e7f1SMilanka Ringwald }; 146be32e7f1SMilanka Ringwald const char * avrcp_play_status2str(uint8_t index){ 147c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 4)) return avrcp_play_status_name[index]; 148be32e7f1SMilanka Ringwald return avrcp_play_status_name[5]; 149be32e7f1SMilanka Ringwald } 150be32e7f1SMilanka Ringwald 151be32e7f1SMilanka Ringwald static const char * avrcp_ctype_name[] = { 152be32e7f1SMilanka Ringwald "CONTROL", 153be32e7f1SMilanka Ringwald "STATUS", 154be32e7f1SMilanka Ringwald "SPECIFIC_INQUIRY", 155be32e7f1SMilanka Ringwald "NOTIFY", 156be32e7f1SMilanka Ringwald "GENERAL_INQUIRY", 157be32e7f1SMilanka Ringwald "RESERVED5", 158be32e7f1SMilanka Ringwald "RESERVED6", 159be32e7f1SMilanka Ringwald "RESERVED7", 1609cc1f3ceSMilanka Ringwald "NOT IMPLEMENTED IN REMOTE", 1619cc1f3ceSMilanka Ringwald "ACCEPTED BY REMOTE", 1629cc1f3ceSMilanka Ringwald "REJECTED BY REMOTE", 163be32e7f1SMilanka Ringwald "IN_TRANSITION", 164be32e7f1SMilanka Ringwald "IMPLEMENTED_STABLE", 165be32e7f1SMilanka Ringwald "CHANGED_STABLE", 166be32e7f1SMilanka Ringwald "RESERVED", 167be32e7f1SMilanka Ringwald "INTERIM" 168be32e7f1SMilanka Ringwald }; 169be32e7f1SMilanka Ringwald const char * avrcp_ctype2str(uint8_t index){ 1703982eab9SMatthias Ringwald if (index < sizeof(avrcp_ctype_name)){ 171be32e7f1SMilanka Ringwald return avrcp_ctype_name[index]; 172be32e7f1SMilanka Ringwald } 173be32e7f1SMilanka Ringwald return "NONE"; 174be32e7f1SMilanka Ringwald } 175be32e7f1SMilanka Ringwald 176be32e7f1SMilanka Ringwald static const char * avrcp_shuffle_mode_name[] = { 177be32e7f1SMilanka Ringwald "SHUFFLE OFF", 178be32e7f1SMilanka Ringwald "SHUFFLE ALL TRACKS", 179be32e7f1SMilanka Ringwald "SHUFFLE GROUP" 180be32e7f1SMilanka Ringwald }; 181be32e7f1SMilanka Ringwald 182be32e7f1SMilanka Ringwald const char * avrcp_shuffle2str(uint8_t index){ 183c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 3)) return avrcp_shuffle_mode_name[index-1]; 184be32e7f1SMilanka Ringwald return "NONE"; 185be32e7f1SMilanka Ringwald } 186be32e7f1SMilanka Ringwald 187be32e7f1SMilanka Ringwald static const char * avrcp_repeat_mode_name[] = { 188be32e7f1SMilanka Ringwald "REPEAT OFF", 189be32e7f1SMilanka Ringwald "REPEAT SINGLE TRACK", 190be32e7f1SMilanka Ringwald "REPEAT ALL TRACKS", 191be32e7f1SMilanka Ringwald "REPEAT GROUP" 192be32e7f1SMilanka Ringwald }; 193be32e7f1SMilanka Ringwald 194be32e7f1SMilanka Ringwald const char * avrcp_repeat2str(uint8_t index){ 195c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 4)) return avrcp_repeat_mode_name[index-1]; 196be32e7f1SMilanka Ringwald return "NONE"; 197be32e7f1SMilanka Ringwald } 1986086246cSMilanka Ringwald 19964a27ec5SMilanka Ringwald btstack_linked_list_t avrcp_get_connections(void){ 20064a27ec5SMilanka Ringwald return connections; 20164a27ec5SMilanka Ringwald } 20264a27ec5SMilanka Ringwald 2034b338011SMilanka Ringwald uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ 2044b338011SMilanka Ringwald uint8_t cmd_opcode_index = 5; 2054b338011SMilanka Ringwald if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; 2064b338011SMilanka Ringwald return packet[cmd_opcode_index]; 2074b338011SMilanka Ringwald } 2084b338011SMilanka Ringwald 209654724deSMilanka Ringwald void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, 210654724deSMilanka Ringwald const char * service_name, const char * service_provider_name){ 211be32e7f1SMilanka Ringwald uint8_t* attribute; 212be32e7f1SMilanka Ringwald de_create_sequence(service); 213be32e7f1SMilanka Ringwald 214be32e7f1SMilanka Ringwald // 0x0000 "Service Record Handle" 215235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE); 216be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle); 217be32e7f1SMilanka Ringwald 218be32e7f1SMilanka Ringwald // 0x0001 "Service Class ID List" 219235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST); 220be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 221be32e7f1SMilanka Ringwald { 222be32e7f1SMilanka Ringwald if (controller){ 2236086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 2246086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER); 225be32e7f1SMilanka Ringwald } else { 2266086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET); 227be32e7f1SMilanka Ringwald } 228be32e7f1SMilanka Ringwald } 229be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 230be32e7f1SMilanka Ringwald 231be32e7f1SMilanka Ringwald // 0x0004 "Protocol Descriptor List" 232235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST); 233be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 234be32e7f1SMilanka Ringwald { 235be32e7f1SMilanka Ringwald uint8_t* l2cpProtocol = de_push_sequence(attribute); 236be32e7f1SMilanka Ringwald { 237235946f1SMatthias Ringwald de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 23884e3541eSMilanka Ringwald de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP); 239be32e7f1SMilanka Ringwald } 240be32e7f1SMilanka Ringwald de_pop_sequence(attribute, l2cpProtocol); 241be32e7f1SMilanka Ringwald 242be32e7f1SMilanka Ringwald uint8_t* avctpProtocol = de_push_sequence(attribute); 243be32e7f1SMilanka Ringwald { 244235946f1SMatthias Ringwald de_add_number(avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // avctpProtocol_service 2450b322400SMilanka Ringwald de_add_number(avctpProtocol, DE_UINT, DE_SIZE_16, 0x0104); // version 246be32e7f1SMilanka Ringwald } 247be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avctpProtocol); 248be32e7f1SMilanka Ringwald } 249be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 250be32e7f1SMilanka Ringwald 251be32e7f1SMilanka Ringwald // 0x0005 "Public Browse Group" 252235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group 253be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 254be32e7f1SMilanka Ringwald { 255235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT); 256be32e7f1SMilanka Ringwald } 257be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 258be32e7f1SMilanka Ringwald 259be32e7f1SMilanka Ringwald // 0x0009 "Bluetooth Profile Descriptor List" 260235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST); 261be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 262be32e7f1SMilanka Ringwald { 263be32e7f1SMilanka Ringwald uint8_t *avrcProfile = de_push_sequence(attribute); 264be32e7f1SMilanka Ringwald { 2656086246cSMilanka Ringwald de_add_number(avrcProfile, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 2660b322400SMilanka Ringwald de_add_number(avrcProfile, DE_UINT, DE_SIZE_16, 0x0106); 267be32e7f1SMilanka Ringwald } 268be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avrcProfile); 269be32e7f1SMilanka Ringwald } 270be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 271be32e7f1SMilanka Ringwald 272a0f524f0SMatthias Ringwald // 0x000d "Additional Bluetooth Profile Descriptor List" 2735c806868SMatthias Ringwald if (browsing){ 274a0f524f0SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS); 275a0f524f0SMatthias Ringwald attribute = de_push_sequence(service); 2765c806868SMatthias Ringwald { 2775c806868SMatthias Ringwald uint8_t * des = de_push_sequence(attribute); 2785c806868SMatthias Ringwald { 2795c806868SMatthias Ringwald uint8_t* browsing_l2cpProtocol = de_push_sequence(des); 280a0f524f0SMatthias Ringwald { 281a0f524f0SMatthias Ringwald de_add_number(browsing_l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 28284e3541eSMilanka Ringwald de_add_number(browsing_l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP_BROWSING); 283a0f524f0SMatthias Ringwald } 2845c806868SMatthias Ringwald de_pop_sequence(des, browsing_l2cpProtocol); 285a0f524f0SMatthias Ringwald 2865c806868SMatthias Ringwald uint8_t* browsing_avctpProtocol = de_push_sequence(des); 287a0f524f0SMatthias Ringwald { 288a0f524f0SMatthias Ringwald de_add_number(browsing_avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // browsing_avctpProtocol_service 2890b322400SMilanka Ringwald de_add_number(browsing_avctpProtocol, DE_UINT, DE_SIZE_16, 0x0104); // version 290a0f524f0SMatthias Ringwald } 2915c806868SMatthias Ringwald de_pop_sequence(des, browsing_avctpProtocol); 2925c806868SMatthias Ringwald } 2935c806868SMatthias Ringwald de_pop_sequence(attribute, des); 294a0f524f0SMatthias Ringwald } 295a0f524f0SMatthias Ringwald de_pop_sequence(service, attribute); 2965c806868SMatthias Ringwald } 297a0f524f0SMatthias Ringwald 298be32e7f1SMilanka Ringwald 299be32e7f1SMilanka Ringwald // 0x0100 "Service Name" 300be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); 301be32e7f1SMilanka Ringwald if (service_name){ 302be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name); 303be32e7f1SMilanka Ringwald } else { 304be32e7f1SMilanka Ringwald if (controller){ 305be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_controller_service_name), (uint8_t *) default_avrcp_controller_service_name); 306be32e7f1SMilanka Ringwald } else { 307be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_target_service_name), (uint8_t *) default_avrcp_target_service_name); 308be32e7f1SMilanka Ringwald } 309be32e7f1SMilanka Ringwald } 310be32e7f1SMilanka Ringwald 311be32e7f1SMilanka Ringwald // 0x0100 "Provider Name" 312be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102); 313be32e7f1SMilanka Ringwald if (service_provider_name){ 314be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name); 315be32e7f1SMilanka Ringwald } else { 316be32e7f1SMilanka Ringwald if (controller){ 317be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_controller_service_provider_name), (uint8_t *) default_avrcp_controller_service_provider_name); 318be32e7f1SMilanka Ringwald } else { 319be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(default_avrcp_target_service_provider_name), (uint8_t *) default_avrcp_target_service_provider_name); 320be32e7f1SMilanka Ringwald } 321be32e7f1SMilanka Ringwald } 322be32e7f1SMilanka Ringwald 323be32e7f1SMilanka Ringwald // 0x0311 "Supported Features" 324be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); 325be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 326be32e7f1SMilanka Ringwald } 327be32e7f1SMilanka Ringwald 3281945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_bd_addr_for_role(avrcp_role_t role, bd_addr_t addr){ 3296983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 330638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 3316983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3326983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 33394d9400dSMilanka Ringwald if (connection->role != role) continue; 3346983e65eSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 3356983e65eSMilanka Ringwald return connection; 3366983e65eSMilanka Ringwald } 3376983e65eSMilanka Ringwald return NULL; 338be32e7f1SMilanka Ringwald } 339be32e7f1SMilanka Ringwald 3401945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_l2cap_signaling_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 3416983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 342638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 3436983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3446983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 34594d9400dSMilanka Ringwald if (connection->role != role) continue; 3466983e65eSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 3476983e65eSMilanka Ringwald return connection; 3486983e65eSMilanka Ringwald } 3496983e65eSMilanka Ringwald return NULL; 350be32e7f1SMilanka Ringwald } 351be32e7f1SMilanka Ringwald 3521945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_avrcp_cid_for_role(avrcp_role_t role, uint16_t avrcp_cid){ 3536983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 354638481deSMilanka Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 3556983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3566983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 35794d9400dSMilanka Ringwald if (connection->role != role) continue; 35801dc6e35SMilanka Ringwald if (connection->avrcp_cid != avrcp_cid) continue; 3596983e65eSMilanka Ringwald return connection; 3606983e65eSMilanka Ringwald } 3616983e65eSMilanka Ringwald return NULL; 3626983e65eSMilanka Ringwald } 3636983e65eSMilanka Ringwald 3641945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid){ 36503a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 36603a72c8eSMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 36703a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 36803a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 36903a72c8eSMatthias Ringwald if (connection->role != role) continue; 37003a72c8eSMatthias Ringwald if (connection->avrcp_browsing_cid != browsing_cid) continue; 37103a72c8eSMatthias Ringwald return connection; 37203a72c8eSMatthias Ringwald } 37303a72c8eSMatthias Ringwald return NULL; 37403a72c8eSMatthias Ringwald } 37503a72c8eSMatthias Ringwald 3761945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_l2cap_cid_for_role(avrcp_role_t role, uint16_t browsing_l2cap_cid){ 37703a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 37803a72c8eSMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 37903a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 38003a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 38103a72c8eSMatthias Ringwald if (connection->role != role) continue; 38203a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != browsing_l2cap_cid)) continue; 38303a72c8eSMatthias Ringwald return connection; 38403a72c8eSMatthias Ringwald } 38503a72c8eSMatthias Ringwald return NULL; 38603a72c8eSMatthias Ringwald } 38703a72c8eSMatthias Ringwald 3881945fe3eSMilanka Ringwald avrcp_browsing_connection_t * avrcp_get_browsing_connection_for_l2cap_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 38903a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 39003a72c8eSMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections); 39103a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 39203a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 39303a72c8eSMatthias Ringwald if (connection->role != role) continue; 39403a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != l2cap_cid)) continue; 39503a72c8eSMatthias Ringwald return connection->browsing_connection; 39603a72c8eSMatthias Ringwald } 39703a72c8eSMatthias Ringwald return NULL; 39803a72c8eSMatthias Ringwald } 39903a72c8eSMatthias Ringwald 4006983e65eSMilanka Ringwald void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){ 401cf36dea0SMilanka Ringwald connection->wait_to_send = true; 4026983e65eSMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 4036983e65eSMilanka Ringwald } 4046983e65eSMilanka Ringwald 405298aeecdSMilanka Ringwald uint16_t avrcp_get_next_cid(avrcp_role_t role){ 406298aeecdSMilanka Ringwald do { 407298aeecdSMilanka Ringwald if (avrcp_cid_counter == 0xffff) { 4086983e65eSMilanka Ringwald avrcp_cid_counter = 1; 409298aeecdSMilanka Ringwald } else { 410298aeecdSMilanka Ringwald avrcp_cid_counter++; 4116983e65eSMilanka Ringwald } 4121945fe3eSMilanka Ringwald } while (avrcp_get_connection_for_avrcp_cid_for_role(role, avrcp_cid_counter) != NULL) ; 4136983e65eSMilanka Ringwald return avrcp_cid_counter; 4146983e65eSMilanka Ringwald } 4156983e65eSMilanka Ringwald 416298aeecdSMilanka Ringwald 417638481deSMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){ 4186983e65eSMilanka Ringwald avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); 4194567cc17SMilanka Ringwald if (!connection){ 4200ec79bd0SMilanka Ringwald log_error("Not enough memory to create connection for role %d", role); 4214567cc17SMilanka Ringwald return NULL; 4224567cc17SMilanka Ringwald } 4230036e267SMilanka Ringwald 4246983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_IDLE; 4250036e267SMilanka Ringwald connection->role = role; 426022b77fcSMilanka Ringwald 427022b77fcSMilanka Ringwald connection->transaction_id = 0xFF; 42823773c45SMilanka Ringwald connection->transaction_id_counter = 0; 429022b77fcSMilanka Ringwald 4308b2b4034SMilanka Ringwald connection->max_num_fragments = 0xFF; 431c91f9817SMilanka Ringwald log_info("avrcp_create_connection, role %d", role); 4326535961aSMatthias Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 433638481deSMilanka Ringwald btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection); 4346983e65eSMilanka Ringwald return connection; 4356983e65eSMilanka Ringwald } 4366983e65eSMilanka Ringwald 437638481deSMilanka Ringwald static void avrcp_finalize_connection(avrcp_connection_t * connection){ 43837fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 439638481deSMilanka Ringwald btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection); 44055e8029cSMatthias Ringwald btstack_memory_avrcp_connection_free(connection); 44155e8029cSMatthias Ringwald } 4426983e65eSMilanka Ringwald 4437dbc6cb8SMilanka Ringwald static void avrcp_emit_connection_established(uint16_t avrcp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status){ 444cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 445cee0e5b6SMilanka Ringwald 4467dbc6cb8SMilanka Ringwald uint8_t event[14]; 447b193c45eSMilanka Ringwald int pos = 0; 448b193c45eSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 449b193c45eSMilanka Ringwald event[pos++] = sizeof(event) - 2; 450b193c45eSMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED; 4516f43fcd7SMatthias Ringwald event[pos++] = status; 4527dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 4537dbc6cb8SMilanka Ringwald pos += 2; 454b193c45eSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 455b193c45eSMilanka Ringwald pos += 6; 4567dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, con_handle); 457b193c45eSMilanka Ringwald pos += 2; 458cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 459b193c45eSMilanka Ringwald } 460b193c45eSMilanka Ringwald 461cee0e5b6SMilanka Ringwald static void avrcp_emit_connection_closed(uint16_t avrcp_cid){ 462cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 463cee0e5b6SMilanka Ringwald 464be32e7f1SMilanka Ringwald uint8_t event[5]; 465be32e7f1SMilanka Ringwald int pos = 0; 466be32e7f1SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 467be32e7f1SMilanka Ringwald event[pos++] = sizeof(event) - 2; 468be32e7f1SMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED; 469b193c45eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 470be32e7f1SMilanka Ringwald pos += 2; 471cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 472be32e7f1SMilanka Ringwald } 473be32e7f1SMilanka Ringwald 4746d8f569dSMilanka Ringwald uint16_t avrcp_sdp_query_browsing_l2cap_psm(void){ 47564a27ec5SMilanka Ringwald return sdp_query_context.browsing_l2cap_psm; 4764dc95c12SMatthias Ringwald } 4774dc95c12SMatthias Ringwald 4784dc95c12SMatthias Ringwald void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ 4796086246cSMilanka Ringwald des_iterator_t des_list_it; 4806086246cSMilanka Ringwald des_iterator_t prot_it; 4816086246cSMilanka Ringwald 4826086246cSMilanka Ringwald // Handle new SDP record 48364a27ec5SMilanka Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != sdp_query_context.record_id) { 48464a27ec5SMilanka Ringwald sdp_query_context.record_id = sdp_event_query_attribute_byte_get_record_id(packet); 48564a27ec5SMilanka Ringwald sdp_query_context.parse_sdp_record = 0; 4866086246cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 4876086246cSMilanka Ringwald } 4886086246cSMilanka Ringwald 4896086246cSMilanka Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 4906086246cSMilanka Ringwald attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 4916086246cSMilanka Ringwald 4926086246cSMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 4936086246cSMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 4946086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 4956086246cSMilanka Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 4966086246cSMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 4976086246cSMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 4986086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 4996086246cSMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 5006086246cSMilanka Ringwald switch (uuid){ 5016086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET: 5026086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL: 503df642728SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: 50464a27ec5SMilanka Ringwald sdp_query_context.parse_sdp_record = 1; 5056086246cSMilanka Ringwald break; 5066086246cSMilanka Ringwald default: 5076086246cSMilanka Ringwald break; 5086086246cSMilanka Ringwald } 5096086246cSMilanka Ringwald } 5106086246cSMilanka Ringwald break; 5116086246cSMilanka Ringwald 5126086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: { 51364a27ec5SMilanka Ringwald if (!sdp_query_context.parse_sdp_record) break; 5146086246cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 5156086246cSMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 5166086246cSMilanka Ringwald uint8_t *des_element; 5176086246cSMilanka Ringwald uint8_t *element; 5186086246cSMilanka Ringwald uint32_t uuid; 5196086246cSMilanka Ringwald 5206086246cSMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 5216086246cSMilanka Ringwald 5226086246cSMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 5236086246cSMilanka Ringwald des_iterator_init(&prot_it, des_element); 5246086246cSMilanka Ringwald element = des_iterator_get_element(&prot_it); 5256086246cSMilanka Ringwald 5266086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 5276086246cSMilanka Ringwald 5286086246cSMilanka Ringwald uuid = de_get_uuid32(element); 52914fd128cSMatthias Ringwald des_iterator_next(&prot_it); 5306086246cSMilanka Ringwald switch (uuid){ 5316086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 5326086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 53364a27ec5SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_l2cap_psm); 5346086246cSMilanka Ringwald break; 5356086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 5366086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 53764a27ec5SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.avrcp_version); 5386086246cSMilanka Ringwald break; 5396086246cSMilanka Ringwald default: 5406086246cSMilanka Ringwald break; 5416086246cSMilanka Ringwald } 5426086246cSMilanka Ringwald } 5436086246cSMilanka Ringwald } 5446086246cSMilanka Ringwald break; 545227d16a5SMatthias Ringwald case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: { 546227d16a5SMatthias Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 54764a27ec5SMilanka Ringwald if (!sdp_query_context.parse_sdp_record) break; 548227d16a5SMatthias Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 549227d16a5SMatthias Ringwald 550227d16a5SMatthias Ringwald des_iterator_t des_list_0_it; 551227d16a5SMatthias Ringwald uint8_t *element_0; 552227d16a5SMatthias Ringwald 553227d16a5SMatthias Ringwald des_iterator_init(&des_list_0_it, attribute_value); 554227d16a5SMatthias Ringwald element_0 = des_iterator_get_element(&des_list_0_it); 555227d16a5SMatthias Ringwald 556227d16a5SMatthias Ringwald for (des_iterator_init(&des_list_it, element_0); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 557227d16a5SMatthias Ringwald uint8_t *des_element; 558227d16a5SMatthias Ringwald uint8_t *element; 559227d16a5SMatthias Ringwald uint32_t uuid; 560227d16a5SMatthias Ringwald 561227d16a5SMatthias Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 562227d16a5SMatthias Ringwald 563227d16a5SMatthias Ringwald des_element = des_iterator_get_element(&des_list_it); 564227d16a5SMatthias Ringwald des_iterator_init(&prot_it, des_element); 565227d16a5SMatthias Ringwald element = des_iterator_get_element(&prot_it); 566227d16a5SMatthias Ringwald 567227d16a5SMatthias Ringwald if (de_get_element_type(element) != DE_UUID) continue; 568227d16a5SMatthias Ringwald 569227d16a5SMatthias Ringwald uuid = de_get_uuid32(element); 57014fd128cSMatthias Ringwald des_iterator_next(&prot_it); 571227d16a5SMatthias Ringwald switch (uuid){ 572227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 573227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 57464a27ec5SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.browsing_l2cap_psm); 575227d16a5SMatthias Ringwald break; 576227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 577227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 57864a27ec5SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context.browsing_version); 579227d16a5SMatthias Ringwald break; 580227d16a5SMatthias Ringwald default: 581227d16a5SMatthias Ringwald break; 582227d16a5SMatthias Ringwald } 583227d16a5SMatthias Ringwald } 584227d16a5SMatthias Ringwald } 585227d16a5SMatthias Ringwald break; 5866086246cSMilanka Ringwald default: 5876086246cSMilanka Ringwald break; 5886086246cSMilanka Ringwald } 5896086246cSMilanka Ringwald } 5906086246cSMilanka Ringwald } else { 5916086246cSMilanka 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)); 5926086246cSMilanka Ringwald } 5937b81669aSMatthias Ringwald } 5947b81669aSMatthias Ringwald 595463f41baSMilanka Ringwald static void avrcp_handle_sdp_query_failed(avrcp_connection_t * connection, uint8_t status){ 596b68672eaSMilanka Ringwald if (connection == NULL) return; 597463f41baSMilanka Ringwald log_info("AVRCP: SDP query failed with status 0x%02x.", status); 5987dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection->avrcp_cid, connection->remote_addr, connection->con_handle, status); 599463f41baSMilanka Ringwald avrcp_finalize_connection(connection); 600463f41baSMilanka Ringwald } 601463f41baSMilanka Ringwald 602a062fcddSMilanka Ringwald static void avrcp_handle_sdp_query_succeeded(avrcp_connection_t * connection){ 603b68672eaSMilanka Ringwald if (connection == NULL) return; 604463f41baSMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 60564a27ec5SMilanka Ringwald connection->avrcp_l2cap_psm = sdp_query_context.avrcp_l2cap_psm; 60664a27ec5SMilanka Ringwald connection->browsing_version = sdp_query_context.browsing_version; 60764a27ec5SMilanka Ringwald connection->browsing_l2cap_psm = sdp_query_context.browsing_l2cap_psm; 608463f41baSMilanka Ringwald } 609463f41baSMilanka Ringwald 610a062fcddSMilanka Ringwald static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 61150fc39c5SMilanka Ringwald UNUSED(packet_type); 61250fc39c5SMilanka Ringwald UNUSED(channel); 61350fc39c5SMilanka Ringwald UNUSED(size); 61450fc39c5SMilanka Ringwald 6152423506bSMilanka Ringwald bool state_ok = true; 61664a27ec5SMilanka Ringwald avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, sdp_query_context.avrcp_cid); 6172423506bSMilanka Ringwald if (!avrcp_target_connection || avrcp_target_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 6182423506bSMilanka Ringwald state_ok = false; 61964a27ec5SMilanka Ringwald } 62064a27ec5SMilanka Ringwald avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, sdp_query_context.avrcp_cid); 6212423506bSMilanka Ringwald if (!avrcp_controller_connection || avrcp_controller_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 6222423506bSMilanka Ringwald state_ok = false; 6232423506bSMilanka Ringwald } 6242423506bSMilanka Ringwald if (!state_ok){ 6252423506bSMilanka Ringwald // something wrong, nevertheless, start next sdp query if this one is complete 6262423506bSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 6272423506bSMilanka Ringwald (void) sdp_client_register_query_callback(&avrcp_handle_sdp_client_query_request); 6282423506bSMilanka Ringwald } 62964a27ec5SMilanka Ringwald return; 63064a27ec5SMilanka Ringwald } 6317b81669aSMatthias Ringwald 6327b81669aSMatthias Ringwald uint8_t status; 6337b81669aSMatthias Ringwald 6347b81669aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 6357b81669aSMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 63650fc39c5SMilanka Ringwald avrcp_handle_sdp_client_query_attribute_value(packet); 6372423506bSMilanka Ringwald return; 6386086246cSMilanka Ringwald 63950fc39c5SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 6405448c259SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 641247956eaSMilanka Ringwald 6425448c259SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 643b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, status); 644b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, status); 6455448c259SMilanka Ringwald break; 6465448c259SMilanka Ringwald } 6475448c259SMilanka Ringwald 64864a27ec5SMilanka Ringwald if (!sdp_query_context.avrcp_l2cap_psm){ 649b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, SDP_SERVICE_NOT_FOUND); 650b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, SDP_SERVICE_NOT_FOUND); 6516983e65eSMilanka Ringwald break; 6526983e65eSMilanka Ringwald } 653be32e7f1SMilanka Ringwald 654a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_controller_connection); 655a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_target_connection); 656bd66227aSMilanka Ringwald 65764a27ec5SMilanka Ringwald l2cap_create_channel(&avrcp_packet_handler, avrcp_target_connection->remote_addr, sdp_query_context.avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 658463f41baSMilanka Ringwald break; 65950fc39c5SMilanka Ringwald 66050fc39c5SMilanka Ringwald default: 6612423506bSMilanka Ringwald return; 6620036e267SMilanka Ringwald } 66364a27ec5SMilanka Ringwald 66464a27ec5SMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 66564a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 66664a27ec5SMilanka Ringwald (void) sdp_client_register_query_callback(&avrcp_handle_sdp_client_query_request); 667463f41baSMilanka Ringwald } 66850fc39c5SMilanka Ringwald 669be32e7f1SMilanka Ringwald 6707dbc6cb8SMilanka 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){ 671a062fcddSMilanka Ringwald if (connection == NULL){ 672a062fcddSMilanka Ringwald connection = avrcp_create_connection(role, event_addr); 673be32e7f1SMilanka Ringwald } 674a062fcddSMilanka Ringwald if (connection) { 6750f76c2d7SMatthias Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 6760f76c2d7SMatthias Ringwald connection->l2cap_signaling_cid = local_cid; 6777403cbbaSMilanka Ringwald connection->avrcp_cid = avrcp_cid; 6787dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 67937fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 680a062fcddSMilanka Ringwald } 681a062fcddSMilanka Ringwald return connection; 682654724deSMilanka Ringwald } 683be32e7f1SMilanka Ringwald 6847dbc6cb8SMilanka 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){ 685be32e7f1SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 6860036e267SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 6877dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 688558ceb4aSMilanka Ringwald connection->incoming_declined = false; 689d1207cd8SMilanka Ringwald connection->song_length_ms = 0xFFFFFFFF; 690d1207cd8SMilanka Ringwald connection->song_position_ms = 0xFFFFFFFF; 691d1207cd8SMilanka Ringwald connection->playback_status = AVRCP_PLAYBACK_STATUS_ERROR; 692cee0e5b6SMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 693d1207cd8SMilanka Ringwald 69464a27ec5SMilanka 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); 6950036e267SMilanka Ringwald } 6960036e267SMilanka Ringwald 69737fae987SMilanka Ringwald static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 698a062fcddSMilanka Ringwald uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 6991945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 70014c8559dSMilanka Ringwald if (connection_controller == NULL) return; 7011945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 70214c8559dSMilanka Ringwald if (connection_target == NULL) return; 703a062fcddSMilanka Ringwald 70437fae987SMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W2_L2CAP_RETRY){ 70514c8559dSMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 70614c8559dSMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 70714c8559dSMilanka Ringwald l2cap_create_channel(&avrcp_packet_handler, connection_controller->remote_addr, connection_controller->avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 70814c8559dSMilanka Ringwald } 709a062fcddSMilanka Ringwald } 710a062fcddSMilanka Ringwald 71137fae987SMilanka Ringwald static void avrcp_retry_timer_start(avrcp_connection_t * connection){ 71237fae987SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avrcp_retry_timer_timeout_handler); 71337fae987SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avrcp_cid); 714a062fcddSMilanka Ringwald 715a062fcddSMilanka Ringwald // add some jitter/randomness to reconnect delay 716a062fcddSMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 71737fae987SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 718a062fcddSMilanka Ringwald 71937fae987SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 720a062fcddSMilanka Ringwald } 721a062fcddSMilanka Ringwald 722b8081399SMilanka Ringwald static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){ 723b8081399SMilanka Ringwald return (avrcp_frame_type_t)((header & 0x02) >> 1); 724b8081399SMilanka Ringwald } 725b8081399SMilanka Ringwald 7260036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 7270036e267SMilanka Ringwald UNUSED(channel); 7280036e267SMilanka Ringwald UNUSED(size); 7290036e267SMilanka Ringwald bd_addr_t event_addr; 7300036e267SMilanka Ringwald uint16_t local_cid; 7310036e267SMilanka Ringwald uint16_t l2cap_mtu; 7320036e267SMilanka Ringwald uint8_t status; 7339b1b0ebdSMatthias Ringwald bool decline_connection; 7349b1b0ebdSMatthias Ringwald bool outoing_active; 7357dbc6cb8SMilanka Ringwald hci_con_handle_t con_handle; 7360036e267SMilanka Ringwald 737cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_controller; 738cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_target; 739bf67b2dbSMatthias Ringwald bool can_send; 740cee0e5b6SMilanka Ringwald 7410036e267SMilanka Ringwald switch (packet_type) { 7420036e267SMilanka Ringwald case HCI_EVENT_PACKET: 7430036e267SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 7440036e267SMilanka Ringwald 7450036e267SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 746e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 747e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 748e3d57ee2SMilanka Ringwald 7490036e267SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 7500036e267SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 7517dbc6cb8SMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 752cee0e5b6SMilanka Ringwald 7537dbc6cb8SMilanka Ringwald outoing_active = false; 7541945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 755cee0e5b6SMilanka Ringwald if (connection_target != NULL){ 756a062fcddSMilanka Ringwald if (connection_target->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){ 7579b1b0ebdSMatthias Ringwald outoing_active = true; 758cee0e5b6SMilanka Ringwald connection_target->incoming_declined = true; 7599b1b0ebdSMatthias Ringwald } 760a062fcddSMilanka Ringwald } 761558ceb4aSMilanka Ringwald 7621945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 763cee0e5b6SMilanka Ringwald if (connection_controller != NULL){ 764a062fcddSMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) { 7659b1b0ebdSMatthias Ringwald outoing_active = true; 766cee0e5b6SMilanka Ringwald connection_controller->incoming_declined = true; 7679b1b0ebdSMatthias Ringwald } 768a062fcddSMilanka Ringwald } 769558ceb4aSMilanka Ringwald 7709b1b0ebdSMatthias Ringwald decline_connection = outoing_active; 771a062fcddSMilanka Ringwald if (decline_connection == false){ 772a062fcddSMilanka Ringwald uint16_t avrcp_cid; 773a062fcddSMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)){ 774a062fcddSMilanka Ringwald avrcp_cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 775a062fcddSMilanka Ringwald } else { 776a062fcddSMilanka Ringwald avrcp_cid = connection_controller->avrcp_cid; 777a062fcddSMilanka Ringwald } 7780036e267SMilanka Ringwald // create two connection objects (both) 7797dbc6cb8SMilanka Ringwald connection_target = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, connection_target, event_addr, con_handle, local_cid, avrcp_cid); 7807dbc6cb8SMilanka Ringwald connection_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, connection_controller, event_addr, con_handle, local_cid, avrcp_cid); 781a062fcddSMilanka Ringwald if ((connection_target == NULL) || (connection_controller == NULL)){ 7829b1b0ebdSMatthias Ringwald decline_connection = true; 783a062fcddSMilanka Ringwald if (connection_target) { 784a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_target); 785a062fcddSMilanka Ringwald } 786a062fcddSMilanka Ringwald if (connection_controller) { 787a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_controller); 788a062fcddSMilanka Ringwald } 7890036e267SMilanka Ringwald } 7909b1b0ebdSMatthias Ringwald } 7919b1b0ebdSMatthias Ringwald if (decline_connection){ 7929b1b0ebdSMatthias Ringwald l2cap_decline_connection(local_cid); 7939b1b0ebdSMatthias Ringwald } else { 79464a27ec5SMilanka Ringwald log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION local cid 0x%02x, state %d", local_cid, connection_controller->state); 7950036e267SMilanka Ringwald l2cap_accept_connection(local_cid); 7969b1b0ebdSMatthias Ringwald } 7970036e267SMilanka Ringwald break; 7980036e267SMilanka Ringwald 7990036e267SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 8000036e267SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 8010036e267SMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 8020036e267SMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 8030036e267SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 8047dbc6cb8SMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 8050036e267SMilanka Ringwald 8061945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 8071945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 808a062fcddSMilanka Ringwald 809a062fcddSMilanka Ringwald // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION 810a062fcddSMilanka Ringwald // outgoing: structs are cteated in avrcp_connect() 811cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 812cee0e5b6SMilanka Ringwald break; 813cee0e5b6SMilanka Ringwald } 814cee0e5b6SMilanka Ringwald 815a062fcddSMilanka Ringwald switch (status){ 816a062fcddSMilanka Ringwald case ERROR_CODE_SUCCESS: 8177dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_target, con_handle, local_cid, l2cap_mtu); 8187dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_controller, con_handle, local_cid, l2cap_mtu); 8197dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 820a062fcddSMilanka Ringwald return; 821a062fcddSMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 822a062fcddSMilanka Ringwald if (connection_controller->incoming_declined == true){ 823a062fcddSMilanka Ringwald log_info("Incoming connection was declined, and the outgoing failed"); 82437fae987SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 825a062fcddSMilanka Ringwald connection_controller->incoming_declined = false; 82637fae987SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 827a062fcddSMilanka Ringwald connection_target->incoming_declined = false; 82837fae987SMilanka Ringwald avrcp_retry_timer_start(connection_controller); 829a062fcddSMilanka Ringwald return; 830a062fcddSMilanka Ringwald } 831a062fcddSMilanka Ringwald break; 832a062fcddSMilanka Ringwald default: 833a062fcddSMilanka Ringwald break; 834a062fcddSMilanka Ringwald } 835cee0e5b6SMilanka Ringwald log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 8367dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 837cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 838cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 839cee0e5b6SMilanka Ringwald 840be32e7f1SMilanka Ringwald break; 841be32e7f1SMilanka Ringwald 842be32e7f1SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 843be32e7f1SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 844cee0e5b6SMilanka Ringwald 8451945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 8461945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 847cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 848cee0e5b6SMilanka Ringwald break; 849cee0e5b6SMilanka Ringwald } 850cee0e5b6SMilanka Ringwald avrcp_emit_connection_closed(connection_controller->avrcp_cid); 851cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 852cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 8530036e267SMilanka Ringwald break; 8540036e267SMilanka Ringwald 8550036e267SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 8560036e267SMilanka Ringwald local_cid = l2cap_event_can_send_now_get_local_cid(packet); 857bf67b2dbSMatthias Ringwald can_send = true; 858e3d57ee2SMilanka Ringwald 8591945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 860cf36dea0SMilanka Ringwald if ((connection_target != NULL) && connection_target->wait_to_send){ 861cf36dea0SMilanka Ringwald connection_target->wait_to_send = false; 8620036e267SMilanka Ringwald (*avrcp_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 863bf67b2dbSMatthias Ringwald can_send = false; 8640036e267SMilanka Ringwald } 8650036e267SMilanka Ringwald 8661945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 867cf36dea0SMilanka Ringwald if ((connection_controller != NULL) && connection_controller->wait_to_send){ 868bf67b2dbSMatthias Ringwald if (can_send){ 869cf36dea0SMilanka Ringwald connection_controller->wait_to_send = false; 8700036e267SMilanka Ringwald (*avrcp_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 871bf67b2dbSMatthias Ringwald } else { 872bf67b2dbSMatthias Ringwald l2cap_request_can_send_now_event(local_cid); 873bf67b2dbSMatthias Ringwald } 874be32e7f1SMilanka Ringwald } 875be32e7f1SMilanka Ringwald break; 8760036e267SMilanka Ringwald 877be32e7f1SMilanka Ringwald default: 878be32e7f1SMilanka Ringwald break; 879be32e7f1SMilanka Ringwald } 880b106f728SMilanka Ringwald break; 881e3d57ee2SMilanka Ringwald 882e3d57ee2SMilanka Ringwald case L2CAP_DATA_PACKET: 883b8081399SMilanka Ringwald switch (avrcp_get_frame_type(packet[0])){ 884e3d57ee2SMilanka Ringwald case AVRCP_RESPONSE_FRAME: 885e3d57ee2SMilanka Ringwald (*avrcp_controller_packet_handler)(packet_type, channel, packet, size); 886e3d57ee2SMilanka Ringwald break; 887e3d57ee2SMilanka Ringwald case AVRCP_COMMAND_FRAME: 888e3d57ee2SMilanka Ringwald default: // make compiler happy 889e3d57ee2SMilanka Ringwald (*avrcp_target_packet_handler)(packet_type, channel, packet, size); 890e3d57ee2SMilanka Ringwald break; 891e3d57ee2SMilanka Ringwald } 892e3d57ee2SMilanka Ringwald break; 893e3d57ee2SMilanka Ringwald 894b106f728SMilanka Ringwald default: 895b106f728SMilanka Ringwald break; 896b106f728SMilanka Ringwald } 897be32e7f1SMilanka Ringwald } 898be32e7f1SMilanka Ringwald 899fe10780bSMilanka Ringwald uint8_t avrcp_disconnect(uint16_t avrcp_cid){ 9001945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 901fe10780bSMilanka Ringwald if (!connection_controller){ 902fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 903fe10780bSMilanka Ringwald } 9041945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 905fe10780bSMilanka Ringwald if (!connection_target){ 906fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 907fe10780bSMilanka Ringwald } 908fe10780bSMilanka Ringwald if (connection_controller->browsing_connection){ 909fe10780bSMilanka Ringwald l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid, 0); 910fe10780bSMilanka Ringwald } 911fe10780bSMilanka Ringwald l2cap_disconnect(connection_controller->l2cap_signaling_cid, 0); 912fe10780bSMilanka Ringwald return ERROR_CODE_SUCCESS; 913fe10780bSMilanka Ringwald } 914fe10780bSMilanka Ringwald 91564a27ec5SMilanka Ringwald static void avrcp_handle_start_sdp_client_query(void * context){ 91664a27ec5SMilanka Ringwald UNUSED(context); 9174dc95c12SMatthias Ringwald 91864a27ec5SMilanka Ringwald btstack_linked_list_iterator_t it; 91964a27ec5SMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 92064a27ec5SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 92164a27ec5SMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 92264a27ec5SMilanka Ringwald 92364a27ec5SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_W2_SEND_SDP_QUERY) continue; 92464a27ec5SMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 92564a27ec5SMilanka Ringwald 92664a27ec5SMilanka Ringwald // prevent triggering SDP query twice (for each role once) 92764a27ec5SMilanka Ringwald avrcp_connection_t * connection_with_opposite_role; 92864a27ec5SMilanka Ringwald switch (connection->role){ 92964a27ec5SMilanka Ringwald case AVRCP_CONTROLLER: 93064a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid); 93164a27ec5SMilanka Ringwald break; 93264a27ec5SMilanka Ringwald case AVRCP_TARGET: 93364a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid); 93464a27ec5SMilanka Ringwald break; 93564a27ec5SMilanka Ringwald default: 93664a27ec5SMilanka Ringwald btstack_assert(false); 93764a27ec5SMilanka Ringwald return; 93864a27ec5SMilanka Ringwald } 93964a27ec5SMilanka Ringwald connection_with_opposite_role->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 94064a27ec5SMilanka Ringwald 94164a27ec5SMilanka Ringwald sdp_query_context.avrcp_l2cap_psm = 0; 94264a27ec5SMilanka Ringwald sdp_query_context.avrcp_version = 0; 94364a27ec5SMilanka Ringwald sdp_query_context.avrcp_cid = connection->avrcp_cid; 94464a27ec5SMilanka Ringwald sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP); 94564a27ec5SMilanka Ringwald return; 94664a27ec5SMilanka Ringwald } 9474dc95c12SMatthias Ringwald } 9484dc95c12SMatthias Ringwald 949fe10780bSMilanka Ringwald uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){ 950e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 951e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 952f9ef80eaSMilanka Ringwald 9531945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); 954bd66227aSMilanka Ringwald if (connection_controller){ 955bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 956bd66227aSMilanka Ringwald } 9571945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr); 958bd66227aSMilanka Ringwald if (connection_target){ 959bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 960bd66227aSMilanka Ringwald } 961bd66227aSMilanka Ringwald 9627403cbbaSMilanka Ringwald uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 9637403cbbaSMilanka Ringwald 964bd66227aSMilanka Ringwald connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 965bd66227aSMilanka Ringwald if (!connection_controller) return BTSTACK_MEMORY_ALLOC_FAILED; 966bd66227aSMilanka Ringwald 967bd66227aSMilanka Ringwald connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 968bd66227aSMilanka Ringwald if (!connection_target){ 969bd66227aSMilanka Ringwald avrcp_finalize_connection(connection_controller); 970bd66227aSMilanka Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 971bd66227aSMilanka Ringwald } 972bd66227aSMilanka Ringwald 973bd66227aSMilanka Ringwald if (avrcp_cid != NULL){ 974bd66227aSMilanka Ringwald *avrcp_cid = cid; 975bd66227aSMilanka Ringwald } 976bd66227aSMilanka Ringwald 97764a27ec5SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 9787403cbbaSMilanka Ringwald connection_controller->avrcp_cid = cid; 9797403cbbaSMilanka Ringwald 98064a27ec5SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 9817403cbbaSMilanka Ringwald connection_target->avrcp_cid = cid; 9825dd5e7e3SMilanka Ringwald 98364a27ec5SMilanka Ringwald avrcp_handle_sdp_client_query_request.callback = &avrcp_handle_start_sdp_client_query; 98464a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 98564a27ec5SMilanka Ringwald (void) sdp_client_register_query_callback(&avrcp_handle_sdp_client_query_request); 98664a27ec5SMilanka Ringwald return ERROR_CODE_SUCCESS; 987be32e7f1SMilanka Ringwald } 988638481deSMilanka Ringwald 989638481deSMilanka Ringwald void avrcp_init(void){ 990638481deSMilanka Ringwald connections = NULL; 991b106f728SMilanka Ringwald if (l2cap_service_registered) return; 9920036e267SMilanka Ringwald 99378315a58SMatthias Ringwald int status = l2cap_register_service(&avrcp_packet_handler, BLUETOOTH_PSM_AVCTP, 0xffff, gap_get_security_level()); 994b106f728SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return; 9950eebc132SMilanka Ringwald l2cap_service_registered = true; 996638481deSMilanka Ringwald } 997b106f728SMilanka Ringwald 998680af5dcSMatthias Ringwald void avrcp_deinit(void){ 999680af5dcSMatthias Ringwald avrcp_cid_counter = 0; 1000680af5dcSMatthias Ringwald l2cap_service_registered = false; 1001680af5dcSMatthias Ringwald 1002680af5dcSMatthias Ringwald (void) memset(&sdp_query_context, 0, sizeof(avrcp_sdp_query_context_t)); 1003680af5dcSMatthias Ringwald (void) memset(attribute_value,0, sizeof(attribute_value)); 1004680af5dcSMatthias Ringwald 1005680af5dcSMatthias Ringwald avrcp_callback = NULL; 1006680af5dcSMatthias Ringwald connections = NULL; 1007680af5dcSMatthias Ringwald avrcp_controller_packet_handler = NULL; 1008680af5dcSMatthias Ringwald avrcp_target_packet_handler = NULL; 1009680af5dcSMatthias Ringwald } 1010680af5dcSMatthias Ringwald 1011b106f728SMilanka Ringwald void avrcp_register_controller_packet_handler(btstack_packet_handler_t callback){ 1012b106f728SMilanka Ringwald avrcp_controller_packet_handler = callback; 1013b106f728SMilanka Ringwald } 1014b106f728SMilanka Ringwald 1015b106f728SMilanka Ringwald void avrcp_register_target_packet_handler(btstack_packet_handler_t callback){ 1016b106f728SMilanka Ringwald avrcp_target_packet_handler = callback; 1017b106f728SMilanka Ringwald } 1018b106f728SMilanka Ringwald 1019cee0e5b6SMilanka Ringwald void avrcp_register_packet_handler(btstack_packet_handler_t callback){ 1020cee0e5b6SMilanka Ringwald btstack_assert(callback != NULL); 1021cee0e5b6SMilanka Ringwald avrcp_callback = callback; 1022cee0e5b6SMilanka Ringwald } 1023697b823eSMatthias Ringwald 1024697b823eSMatthias Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 1025697b823eSMatthias Ringwald #define FUZZ_CID 0x44 10263cd982f4SMatthias Ringwald #define FUZZ_CON_HANDLE 0x0001 1027697b823eSMatthias Ringwald static bd_addr_t remote_addr = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 }; 1028697b823eSMatthias Ringwald void avrcp_init_fuzz(void){ 1029697b823eSMatthias Ringwald // setup avrcp connections for cid 1030697b823eSMatthias Ringwald avrcp_connection_t * connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 1031697b823eSMatthias Ringwald avrcp_connection_t * connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 10323cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_controller, FUZZ_CON_HANDLE, FUZZ_CID, 999); 10333cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_target, FUZZ_CON_HANDLE, FUZZ_CID, 999); 1034697b823eSMatthias Ringwald } 1035697b823eSMatthias Ringwald void avrcp_packet_handler_fuzz(uint8_t *packet, uint16_t size){ 1036697b823eSMatthias Ringwald avrcp_packet_handler(L2CAP_DATA_PACKET, FUZZ_CID, packet, size); 1037697b823eSMatthias Ringwald } 1038697b823eSMatthias Ringwald #endif