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 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH 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 660036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 670036e267SMilanka Ringwald 6865bd7af5SMatthias Ringwald static const char * avrcp_default_controller_service_name = "BTstack AVRCP Controller Service"; 6965bd7af5SMatthias Ringwald static const char * avrcp_default_controller_service_provider_name = "BTstack AVRCP Controller Service Provider"; 7065bd7af5SMatthias Ringwald static const char * avrcp_defaul_target_service_name = "BTstack AVRCP Target Service"; 7165bd7af5SMatthias Ringwald static const char * avrcp_default_target_service_provider_name = "BTstack AVRCP Target Service Provider"; 720eebc132SMilanka Ringwald 73be32e7f1SMilanka Ringwald static const char * avrcp_subunit_type_name[] = { 74be32e7f1SMilanka Ringwald "MONITOR", "AUDIO", "PRINTER", "DISC", "TAPE_RECORDER_PLAYER", "TUNER", 75be32e7f1SMilanka Ringwald "CA", "CAMERA", "RESERVED", "PANEL", "BULLETIN_BOARD", "CAMERA_STORAGE", 76be32e7f1SMilanka Ringwald "VENDOR_UNIQUE", "RESERVED_FOR_ALL_SUBUNIT_TYPES", 77be32e7f1SMilanka Ringwald "EXTENDED_TO_NEXT_BYTE", "UNIT", "ERROR" 78be32e7f1SMilanka Ringwald }; 796983e65eSMilanka Ringwald 8065bd7af5SMatthias Ringwald // default subunit info: single PANEL subunit 8165bd7af5SMatthias Ringwald static const uint8_t avrcp_default_subunit_info[] = { AVRCP_SUBUNIT_TYPE_PANEL << 3}; 8265bd7af5SMatthias Ringwald 8365bd7af5SMatthias Ringwald // globals 8465bd7af5SMatthias Ringwald static bool avrcp_l2cap_service_registered = false; 8565bd7af5SMatthias Ringwald 8665bd7af5SMatthias Ringwald // connections 8765bd7af5SMatthias Ringwald static uint16_t avrcp_cid_counter; 8865bd7af5SMatthias Ringwald static btstack_linked_list_t avrcp_connections; 8965bd7af5SMatthias Ringwald 9065bd7af5SMatthias Ringwald // higher layer callbacks 9165bd7af5SMatthias Ringwald static btstack_packet_handler_t avrcp_callback; 9265bd7af5SMatthias Ringwald static btstack_packet_handler_t avrcp_controller_packet_handler; 9365bd7af5SMatthias Ringwald static btstack_packet_handler_t avrcp_target_packet_handler; 9465bd7af5SMatthias Ringwald 9565bd7af5SMatthias Ringwald // sdp query 9665bd7af5SMatthias Ringwald static btstack_context_callback_registration_t avrcp_sdp_query_registration; 9765bd7af5SMatthias Ringwald static avrcp_sdp_query_context_t avrcp_sdp_query_context; 9865bd7af5SMatthias Ringwald static uint8_t avrcp_sdp_query_attribute_value[45]; 9965bd7af5SMatthias Ringwald static const unsigned int avrcp_sdp_query_attribute_value_buffer_size = sizeof(avrcp_sdp_query_attribute_value); 10065bd7af5SMatthias Ringwald 10165bd7af5SMatthias Ringwald 102be32e7f1SMilanka Ringwald const char * avrcp_subunit2str(uint16_t index){ 103be32e7f1SMilanka Ringwald if (index <= 11) return avrcp_subunit_type_name[index]; 1040e588213SMatthias Ringwald if ((index >= 0x1C) && (index <= 0x1F)) return avrcp_subunit_type_name[index - 0x10]; 105be32e7f1SMilanka Ringwald return avrcp_subunit_type_name[16]; 106be32e7f1SMilanka Ringwald } 107be32e7f1SMilanka Ringwald 108be32e7f1SMilanka Ringwald static const char * avrcp_event_name[] = { 109be32e7f1SMilanka Ringwald "ERROR", "PLAYBACK_STATUS_CHANGED", 110be32e7f1SMilanka Ringwald "TRACK_CHANGED", "TRACK_REACHED_END", "TRACK_REACHED_START", 111be32e7f1SMilanka Ringwald "PLAYBACK_POS_CHANGED", "BATT_STATUS_CHANGED", "SYSTEM_STATUS_CHANGED", 112be32e7f1SMilanka Ringwald "PLAYER_APPLICATION_SETTING_CHANGED", "NOW_PLAYING_CONTENT_CHANGED", 113be32e7f1SMilanka Ringwald "AVAILABLE_PLAYERS_CHANGED", "ADDRESSED_PLAYER_CHANGED", "UIDS_CHANGED", "VOLUME_CHANGED" 114be32e7f1SMilanka Ringwald }; 115be32e7f1SMilanka Ringwald const char * avrcp_event2str(uint16_t index){ 116be32e7f1SMilanka Ringwald if (index <= 0x0d) return avrcp_event_name[index]; 117be32e7f1SMilanka Ringwald return avrcp_event_name[0]; 118be32e7f1SMilanka Ringwald } 119be32e7f1SMilanka Ringwald 120be32e7f1SMilanka Ringwald static const char * avrcp_operation_name[] = { 121ce66cc7aSMilanka Ringwald "SKIP", NULL, NULL, NULL, NULL, 122ce66cc7aSMilanka Ringwald "VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", NULL, 123ce66cc7aSMilanka Ringwald "REWIND", "FAST_FORWARD", NULL, "FORWARD", "BACKWARD" // 0x4C 124be32e7f1SMilanka Ringwald }; 1250b578d06SMilanka Ringwald 1260b578d06SMilanka Ringwald const char * avrcp_operation2str(uint8_t operation_id){ 127ce66cc7aSMilanka Ringwald char * name = NULL; 1280b578d06SMilanka Ringwald if ((operation_id >= AVRCP_OPERATION_ID_SKIP) && (operation_id <= AVRCP_OPERATION_ID_BACKWARD)){ 1290b578d06SMilanka Ringwald name = (char *)avrcp_operation_name[operation_id - AVRCP_OPERATION_ID_SKIP]; 130ce66cc7aSMilanka Ringwald } 131ce66cc7aSMilanka Ringwald if (name == NULL){ 132ce66cc7aSMilanka Ringwald static char buffer[13]; 1330b578d06SMilanka Ringwald snprintf(buffer, sizeof(buffer), "Unknown 0x%02x", operation_id); 134ce66cc7aSMilanka Ringwald buffer[sizeof(buffer)-1] = 0; 135ce66cc7aSMilanka Ringwald return buffer; 136ce66cc7aSMilanka Ringwald } else { 137ce66cc7aSMilanka Ringwald return name; 138ce66cc7aSMilanka Ringwald } 139be32e7f1SMilanka Ringwald } 140be32e7f1SMilanka Ringwald 141be32e7f1SMilanka Ringwald static const char * avrcp_media_attribute_id_name[] = { 142be32e7f1SMilanka Ringwald "NONE", "TITLE", "ARTIST", "ALBUM", "TRACK", "TOTAL TRACKS", "GENRE", "SONG LENGTH" 143be32e7f1SMilanka Ringwald }; 144be32e7f1SMilanka Ringwald const char * avrcp_attribute2str(uint8_t index){ 145c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 7)) return avrcp_media_attribute_id_name[index]; 146be32e7f1SMilanka Ringwald return avrcp_media_attribute_id_name[0]; 147be32e7f1SMilanka Ringwald } 148be32e7f1SMilanka Ringwald 149be32e7f1SMilanka Ringwald static const char * avrcp_play_status_name[] = { 150be32e7f1SMilanka Ringwald "STOPPED", "PLAYING", "PAUSED", "FORWARD SEEK", "REVERSE SEEK", 151be32e7f1SMilanka Ringwald "ERROR" // 0xFF 152be32e7f1SMilanka Ringwald }; 153be32e7f1SMilanka Ringwald const char * avrcp_play_status2str(uint8_t index){ 154c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 4)) return avrcp_play_status_name[index]; 155be32e7f1SMilanka Ringwald return avrcp_play_status_name[5]; 156be32e7f1SMilanka Ringwald } 157be32e7f1SMilanka Ringwald 158be32e7f1SMilanka Ringwald static const char * avrcp_ctype_name[] = { 159be32e7f1SMilanka Ringwald "CONTROL", 160be32e7f1SMilanka Ringwald "STATUS", 161be32e7f1SMilanka Ringwald "SPECIFIC_INQUIRY", 162be32e7f1SMilanka Ringwald "NOTIFY", 163be32e7f1SMilanka Ringwald "GENERAL_INQUIRY", 164be32e7f1SMilanka Ringwald "RESERVED5", 165be32e7f1SMilanka Ringwald "RESERVED6", 166be32e7f1SMilanka Ringwald "RESERVED7", 1679cc1f3ceSMilanka Ringwald "NOT IMPLEMENTED IN REMOTE", 1689cc1f3ceSMilanka Ringwald "ACCEPTED BY REMOTE", 1699cc1f3ceSMilanka Ringwald "REJECTED BY REMOTE", 170be32e7f1SMilanka Ringwald "IN_TRANSITION", 171be32e7f1SMilanka Ringwald "IMPLEMENTED_STABLE", 172be32e7f1SMilanka Ringwald "CHANGED_STABLE", 173be32e7f1SMilanka Ringwald "RESERVED", 174be32e7f1SMilanka Ringwald "INTERIM" 175be32e7f1SMilanka Ringwald }; 176be32e7f1SMilanka Ringwald const char * avrcp_ctype2str(uint8_t index){ 1773982eab9SMatthias Ringwald if (index < sizeof(avrcp_ctype_name)){ 178be32e7f1SMilanka Ringwald return avrcp_ctype_name[index]; 179be32e7f1SMilanka Ringwald } 180be32e7f1SMilanka Ringwald return "NONE"; 181be32e7f1SMilanka Ringwald } 182be32e7f1SMilanka Ringwald 183be32e7f1SMilanka Ringwald static const char * avrcp_shuffle_mode_name[] = { 184be32e7f1SMilanka Ringwald "SHUFFLE OFF", 185be32e7f1SMilanka Ringwald "SHUFFLE ALL TRACKS", 186be32e7f1SMilanka Ringwald "SHUFFLE GROUP" 187be32e7f1SMilanka Ringwald }; 188be32e7f1SMilanka Ringwald 189be32e7f1SMilanka Ringwald const char * avrcp_shuffle2str(uint8_t index){ 190c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 3)) return avrcp_shuffle_mode_name[index-1]; 191be32e7f1SMilanka Ringwald return "NONE"; 192be32e7f1SMilanka Ringwald } 193be32e7f1SMilanka Ringwald 194be32e7f1SMilanka Ringwald static const char * avrcp_repeat_mode_name[] = { 195be32e7f1SMilanka Ringwald "REPEAT OFF", 196be32e7f1SMilanka Ringwald "REPEAT SINGLE TRACK", 197be32e7f1SMilanka Ringwald "REPEAT ALL TRACKS", 198be32e7f1SMilanka Ringwald "REPEAT GROUP" 199be32e7f1SMilanka Ringwald }; 200be32e7f1SMilanka Ringwald 201be32e7f1SMilanka Ringwald const char * avrcp_repeat2str(uint8_t index){ 202c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 4)) return avrcp_repeat_mode_name[index-1]; 203be32e7f1SMilanka Ringwald return "NONE"; 204be32e7f1SMilanka Ringwald } 2056086246cSMilanka Ringwald 20664a27ec5SMilanka Ringwald btstack_linked_list_t avrcp_get_connections(void){ 20765bd7af5SMatthias Ringwald return avrcp_connections; 20864a27ec5SMilanka Ringwald } 20964a27ec5SMilanka Ringwald 2104b338011SMilanka Ringwald uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ 2114b338011SMilanka Ringwald uint8_t cmd_opcode_index = 5; 2124b338011SMilanka Ringwald if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; 2134b338011SMilanka Ringwald return packet[cmd_opcode_index]; 2144b338011SMilanka Ringwald } 2154b338011SMilanka Ringwald 216654724deSMilanka Ringwald void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, 217654724deSMilanka Ringwald const char * service_name, const char * service_provider_name){ 218be32e7f1SMilanka Ringwald uint8_t* attribute; 219be32e7f1SMilanka Ringwald de_create_sequence(service); 220be32e7f1SMilanka Ringwald 221be32e7f1SMilanka Ringwald // 0x0000 "Service Record Handle" 222235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE); 223be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle); 224be32e7f1SMilanka Ringwald 225be32e7f1SMilanka Ringwald // 0x0001 "Service Class ID List" 226235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST); 227be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 228be32e7f1SMilanka Ringwald { 229be32e7f1SMilanka Ringwald if (controller){ 2306086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 2316086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER); 232be32e7f1SMilanka Ringwald } else { 2336086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET); 234be32e7f1SMilanka Ringwald } 235be32e7f1SMilanka Ringwald } 236be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 237be32e7f1SMilanka Ringwald 238be32e7f1SMilanka Ringwald // 0x0004 "Protocol Descriptor List" 239235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST); 240be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 241be32e7f1SMilanka Ringwald { 242be32e7f1SMilanka Ringwald uint8_t* l2cpProtocol = de_push_sequence(attribute); 243be32e7f1SMilanka Ringwald { 244235946f1SMatthias Ringwald de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 24584e3541eSMilanka Ringwald de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP); 246be32e7f1SMilanka Ringwald } 247be32e7f1SMilanka Ringwald de_pop_sequence(attribute, l2cpProtocol); 248be32e7f1SMilanka Ringwald 249be32e7f1SMilanka Ringwald uint8_t* avctpProtocol = de_push_sequence(attribute); 250be32e7f1SMilanka Ringwald { 251235946f1SMatthias Ringwald de_add_number(avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // avctpProtocol_service 2520b322400SMilanka Ringwald de_add_number(avctpProtocol, DE_UINT, DE_SIZE_16, 0x0104); // version 253be32e7f1SMilanka Ringwald } 254be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avctpProtocol); 255be32e7f1SMilanka Ringwald } 256be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 257be32e7f1SMilanka Ringwald 258be32e7f1SMilanka Ringwald // 0x0005 "Public Browse Group" 259235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group 260be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 261be32e7f1SMilanka Ringwald { 262235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT); 263be32e7f1SMilanka Ringwald } 264be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 265be32e7f1SMilanka Ringwald 266be32e7f1SMilanka Ringwald // 0x0009 "Bluetooth Profile Descriptor List" 267235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST); 268be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 269be32e7f1SMilanka Ringwald { 270be32e7f1SMilanka Ringwald uint8_t *avrcProfile = de_push_sequence(attribute); 271be32e7f1SMilanka Ringwald { 2726086246cSMilanka Ringwald de_add_number(avrcProfile, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 2730b322400SMilanka Ringwald de_add_number(avrcProfile, DE_UINT, DE_SIZE_16, 0x0106); 274be32e7f1SMilanka Ringwald } 275be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avrcProfile); 276be32e7f1SMilanka Ringwald } 277be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 278be32e7f1SMilanka Ringwald 279a0f524f0SMatthias Ringwald // 0x000d "Additional Bluetooth Profile Descriptor List" 2805c806868SMatthias Ringwald if (browsing){ 281a0f524f0SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS); 282a0f524f0SMatthias Ringwald attribute = de_push_sequence(service); 2835c806868SMatthias Ringwald { 2845c806868SMatthias Ringwald uint8_t * des = de_push_sequence(attribute); 2855c806868SMatthias Ringwald { 2865c806868SMatthias Ringwald uint8_t* browsing_l2cpProtocol = de_push_sequence(des); 287a0f524f0SMatthias Ringwald { 288a0f524f0SMatthias Ringwald de_add_number(browsing_l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 28984e3541eSMilanka Ringwald de_add_number(browsing_l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP_BROWSING); 290a0f524f0SMatthias Ringwald } 2915c806868SMatthias Ringwald de_pop_sequence(des, browsing_l2cpProtocol); 292a0f524f0SMatthias Ringwald 2935c806868SMatthias Ringwald uint8_t* browsing_avctpProtocol = de_push_sequence(des); 294a0f524f0SMatthias Ringwald { 295a0f524f0SMatthias Ringwald de_add_number(browsing_avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // browsing_avctpProtocol_service 2960b322400SMilanka Ringwald de_add_number(browsing_avctpProtocol, DE_UINT, DE_SIZE_16, 0x0104); // version 297a0f524f0SMatthias Ringwald } 2985c806868SMatthias Ringwald de_pop_sequence(des, browsing_avctpProtocol); 2995c806868SMatthias Ringwald } 3005c806868SMatthias Ringwald de_pop_sequence(attribute, des); 301a0f524f0SMatthias Ringwald } 302a0f524f0SMatthias Ringwald de_pop_sequence(service, attribute); 3035c806868SMatthias Ringwald } 304a0f524f0SMatthias Ringwald 305be32e7f1SMilanka Ringwald 306be32e7f1SMilanka Ringwald // 0x0100 "Service Name" 307be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); 308be32e7f1SMilanka Ringwald if (service_name){ 309be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name); 310be32e7f1SMilanka Ringwald } else { 311be32e7f1SMilanka Ringwald if (controller){ 31265bd7af5SMatthias Ringwald de_add_data(service, DE_STRING, strlen(avrcp_default_controller_service_name), (uint8_t *) avrcp_default_controller_service_name); 313be32e7f1SMilanka Ringwald } else { 31465bd7af5SMatthias Ringwald de_add_data(service, DE_STRING, strlen(avrcp_defaul_target_service_name), (uint8_t *) avrcp_defaul_target_service_name); 315be32e7f1SMilanka Ringwald } 316be32e7f1SMilanka Ringwald } 317be32e7f1SMilanka Ringwald 318be32e7f1SMilanka Ringwald // 0x0100 "Provider Name" 319be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102); 320be32e7f1SMilanka Ringwald if (service_provider_name){ 321be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name); 322be32e7f1SMilanka Ringwald } else { 323be32e7f1SMilanka Ringwald if (controller){ 32465bd7af5SMatthias Ringwald de_add_data(service, DE_STRING, strlen(avrcp_default_controller_service_provider_name), (uint8_t *) avrcp_default_controller_service_provider_name); 325be32e7f1SMilanka Ringwald } else { 32665bd7af5SMatthias Ringwald de_add_data(service, DE_STRING, strlen(avrcp_default_target_service_provider_name), (uint8_t *) avrcp_default_target_service_provider_name); 327be32e7f1SMilanka Ringwald } 328be32e7f1SMilanka Ringwald } 329be32e7f1SMilanka Ringwald 330be32e7f1SMilanka Ringwald // 0x0311 "Supported Features" 331be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); 332be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 333be32e7f1SMilanka Ringwald } 334be32e7f1SMilanka Ringwald 335*66b242bbSMilanka Ringwald static uint16_t avrcp_get_max_payload_size_for_avctp_packet_type(avrcp_connection_t * connection, avctp_packet_type_t avctp_packet_type){ 336*66b242bbSMilanka Ringwald uint16_t max_frame_size = btstack_min(l2cap_get_remote_mtu_for_local_cid(connection->l2cap_signaling_cid), AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE); 337*66b242bbSMilanka Ringwald 338*66b242bbSMilanka Ringwald switch (avctp_packet_type){ 339*66b242bbSMilanka Ringwald case AVCTP_SINGLE_PACKET: 340*66b242bbSMilanka Ringwald return max_frame_size - 3; 341*66b242bbSMilanka Ringwald case AVCTP_START_PACKET: 342*66b242bbSMilanka Ringwald return max_frame_size - 4; 343*66b242bbSMilanka Ringwald case AVCTP_CONTINUE_PACKET: 344*66b242bbSMilanka Ringwald case AVCTP_END_PACKET: 345*66b242bbSMilanka Ringwald return max_frame_size - 1; 346*66b242bbSMilanka Ringwald default: 347*66b242bbSMilanka Ringwald btstack_assert(false); 348*66b242bbSMilanka Ringwald return 0; 349*66b242bbSMilanka Ringwald } 350*66b242bbSMilanka Ringwald } 351*66b242bbSMilanka Ringwald 352*66b242bbSMilanka Ringwald avctp_packet_type_t avrcp_get_avctp_packet_type(avrcp_connection_t * connection){ 353*66b242bbSMilanka Ringwald if (connection->data_offset == 0){ 354*66b242bbSMilanka Ringwald if (avrcp_get_max_payload_size_for_avctp_packet_type(connection, AVCTP_SINGLE_PACKET) >= connection->data_len){ 355*66b242bbSMilanka Ringwald return AVCTP_SINGLE_PACKET; 356*66b242bbSMilanka Ringwald } else { 357*66b242bbSMilanka Ringwald return AVCTP_START_PACKET; 358*66b242bbSMilanka Ringwald } 359*66b242bbSMilanka Ringwald 360*66b242bbSMilanka Ringwald } else { 361*66b242bbSMilanka Ringwald if ((connection->data_len - connection->data_offset) > avrcp_get_max_payload_size_for_avctp_packet_type(connection, AVCTP_CONTINUE_PACKET)){ 362*66b242bbSMilanka Ringwald return AVCTP_CONTINUE_PACKET; 363*66b242bbSMilanka Ringwald } else { 364*66b242bbSMilanka Ringwald return AVCTP_END_PACKET; 365*66b242bbSMilanka Ringwald } 366*66b242bbSMilanka Ringwald } 367*66b242bbSMilanka Ringwald } 368*66b242bbSMilanka Ringwald 3691945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_bd_addr_for_role(avrcp_role_t role, bd_addr_t addr){ 3706983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 37165bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 3726983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3736983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 37494d9400dSMilanka Ringwald if (connection->role != role) continue; 3756983e65eSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 3766983e65eSMilanka Ringwald return connection; 3776983e65eSMilanka Ringwald } 3786983e65eSMilanka Ringwald return NULL; 379be32e7f1SMilanka Ringwald } 380be32e7f1SMilanka Ringwald 3811945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_l2cap_signaling_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 3826983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 38365bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 3846983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3856983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 38694d9400dSMilanka Ringwald if (connection->role != role) continue; 3876983e65eSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 3886983e65eSMilanka Ringwald return connection; 3896983e65eSMilanka Ringwald } 3906983e65eSMilanka Ringwald return NULL; 391be32e7f1SMilanka Ringwald } 392be32e7f1SMilanka Ringwald 3931945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_avrcp_cid_for_role(avrcp_role_t role, uint16_t avrcp_cid){ 3946983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 39565bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 3966983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3976983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 39894d9400dSMilanka Ringwald if (connection->role != role) continue; 39901dc6e35SMilanka Ringwald if (connection->avrcp_cid != avrcp_cid) continue; 4006983e65eSMilanka Ringwald return connection; 4016983e65eSMilanka Ringwald } 4026983e65eSMilanka Ringwald return NULL; 4036983e65eSMilanka Ringwald } 4046983e65eSMilanka Ringwald 4051945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid){ 40603a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 40765bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 40803a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 40903a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 41003a72c8eSMatthias Ringwald if (connection->role != role) continue; 41103a72c8eSMatthias Ringwald if (connection->avrcp_browsing_cid != browsing_cid) continue; 41203a72c8eSMatthias Ringwald return connection; 41303a72c8eSMatthias Ringwald } 41403a72c8eSMatthias Ringwald return NULL; 41503a72c8eSMatthias Ringwald } 41603a72c8eSMatthias Ringwald 4171945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_l2cap_cid_for_role(avrcp_role_t role, uint16_t browsing_l2cap_cid){ 41803a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 41965bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 42003a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 42103a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 42203a72c8eSMatthias Ringwald if (connection->role != role) continue; 42303a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != browsing_l2cap_cid)) continue; 42403a72c8eSMatthias Ringwald return connection; 42503a72c8eSMatthias Ringwald } 42603a72c8eSMatthias Ringwald return NULL; 42703a72c8eSMatthias Ringwald } 42803a72c8eSMatthias Ringwald 4291945fe3eSMilanka Ringwald avrcp_browsing_connection_t * avrcp_get_browsing_connection_for_l2cap_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 43003a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 43165bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 43203a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 43303a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 43403a72c8eSMatthias Ringwald if (connection->role != role) continue; 43503a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != l2cap_cid)) continue; 43603a72c8eSMatthias Ringwald return connection->browsing_connection; 43703a72c8eSMatthias Ringwald } 43803a72c8eSMatthias Ringwald return NULL; 43903a72c8eSMatthias Ringwald } 44003a72c8eSMatthias Ringwald 4416983e65eSMilanka Ringwald void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){ 442cf36dea0SMilanka Ringwald connection->wait_to_send = true; 4436983e65eSMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 4446983e65eSMilanka Ringwald } 4456983e65eSMilanka Ringwald 446298aeecdSMilanka Ringwald uint16_t avrcp_get_next_cid(avrcp_role_t role){ 447298aeecdSMilanka Ringwald do { 448298aeecdSMilanka Ringwald if (avrcp_cid_counter == 0xffff) { 4496983e65eSMilanka Ringwald avrcp_cid_counter = 1; 450298aeecdSMilanka Ringwald } else { 451298aeecdSMilanka Ringwald avrcp_cid_counter++; 4526983e65eSMilanka Ringwald } 4531945fe3eSMilanka Ringwald } while (avrcp_get_connection_for_avrcp_cid_for_role(role, avrcp_cid_counter) != NULL) ; 4546983e65eSMilanka Ringwald return avrcp_cid_counter; 4556983e65eSMilanka Ringwald } 4566983e65eSMilanka Ringwald 457638481deSMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){ 4586983e65eSMilanka Ringwald avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); 4594567cc17SMilanka Ringwald if (!connection){ 4600ec79bd0SMilanka Ringwald log_error("Not enough memory to create connection for role %d", role); 4614567cc17SMilanka Ringwald return NULL; 4624567cc17SMilanka Ringwald } 4630036e267SMilanka Ringwald 4646983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_IDLE; 4650036e267SMilanka Ringwald connection->role = role; 466022b77fcSMilanka Ringwald 467022b77fcSMilanka Ringwald connection->transaction_id = 0xFF; 46823773c45SMilanka Ringwald connection->transaction_id_counter = 0; 469022b77fcSMilanka Ringwald 4708b2b4034SMilanka Ringwald connection->max_num_fragments = 0xFF; 471f0af2234SMatthias Ringwald 472f0af2234SMatthias Ringwald // setup default unit / subunit info 473f0af2234SMatthias Ringwald connection->company_id = 0xffffff; 474f0af2234SMatthias Ringwald connection->unit_type = AVRCP_SUBUNIT_TYPE_PANEL; 475f0af2234SMatthias Ringwald connection->subunit_info_data_size = sizeof(avrcp_default_subunit_info); 476f0af2234SMatthias Ringwald connection->subunit_info_data = avrcp_default_subunit_info; 477f0af2234SMatthias Ringwald 478c91f9817SMilanka Ringwald log_info("avrcp_create_connection, role %d", role); 4796535961aSMatthias Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 48065bd7af5SMatthias Ringwald btstack_linked_list_add(&avrcp_connections, (btstack_linked_item_t *) connection); 4816983e65eSMilanka Ringwald return connection; 4826983e65eSMilanka Ringwald } 4836983e65eSMilanka Ringwald 484638481deSMilanka Ringwald static void avrcp_finalize_connection(avrcp_connection_t * connection){ 48537fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 48665bd7af5SMatthias Ringwald btstack_linked_list_remove(&avrcp_connections, (btstack_linked_item_t*) connection); 48755e8029cSMatthias Ringwald btstack_memory_avrcp_connection_free(connection); 48855e8029cSMatthias Ringwald } 4896983e65eSMilanka Ringwald 4907dbc6cb8SMilanka Ringwald static void avrcp_emit_connection_established(uint16_t avrcp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status){ 491cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 492cee0e5b6SMilanka Ringwald 4937dbc6cb8SMilanka Ringwald uint8_t event[14]; 494b193c45eSMilanka Ringwald int pos = 0; 495b193c45eSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 496b193c45eSMilanka Ringwald event[pos++] = sizeof(event) - 2; 497b193c45eSMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED; 4986f43fcd7SMatthias Ringwald event[pos++] = status; 4997dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 5007dbc6cb8SMilanka Ringwald pos += 2; 501b193c45eSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 502b193c45eSMilanka Ringwald pos += 6; 5037dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, con_handle); 504b193c45eSMilanka Ringwald pos += 2; 505cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 506b193c45eSMilanka Ringwald } 507b193c45eSMilanka Ringwald 508cee0e5b6SMilanka Ringwald static void avrcp_emit_connection_closed(uint16_t avrcp_cid){ 509cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 510cee0e5b6SMilanka Ringwald 511be32e7f1SMilanka Ringwald uint8_t event[5]; 512be32e7f1SMilanka Ringwald int pos = 0; 513be32e7f1SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 514be32e7f1SMilanka Ringwald event[pos++] = sizeof(event) - 2; 515be32e7f1SMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED; 516b193c45eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 517be32e7f1SMilanka Ringwald pos += 2; 518cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 519be32e7f1SMilanka Ringwald } 520be32e7f1SMilanka Ringwald 5216d8f569dSMilanka Ringwald uint16_t avrcp_sdp_query_browsing_l2cap_psm(void){ 52265bd7af5SMatthias Ringwald return avrcp_sdp_query_context.browsing_l2cap_psm; 5234dc95c12SMatthias Ringwald } 5244dc95c12SMatthias Ringwald 5254dc95c12SMatthias Ringwald void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ 5266086246cSMilanka Ringwald des_iterator_t des_list_it; 5276086246cSMilanka Ringwald des_iterator_t prot_it; 5286086246cSMilanka Ringwald 5296086246cSMilanka Ringwald // Handle new SDP record 53065bd7af5SMatthias Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != avrcp_sdp_query_context.record_id) { 53165bd7af5SMatthias Ringwald avrcp_sdp_query_context.record_id = sdp_event_query_attribute_byte_get_record_id(packet); 53265bd7af5SMatthias Ringwald avrcp_sdp_query_context.parse_sdp_record = 0; 5336086246cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 5346086246cSMilanka Ringwald } 5356086246cSMilanka Ringwald 53665bd7af5SMatthias Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= avrcp_sdp_query_attribute_value_buffer_size) { 53765bd7af5SMatthias Ringwald avrcp_sdp_query_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 5386086246cSMilanka Ringwald 5396086246cSMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 5406086246cSMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 5416086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 54265bd7af5SMatthias Ringwald if (de_get_element_type(avrcp_sdp_query_attribute_value) != DE_DES) break; 54365bd7af5SMatthias Ringwald for (des_iterator_init(&des_list_it, avrcp_sdp_query_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 5446086246cSMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 5456086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 5466086246cSMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 5476086246cSMilanka Ringwald switch (uuid){ 5486086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET: 5496086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL: 550df642728SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: 55165bd7af5SMatthias Ringwald avrcp_sdp_query_context.parse_sdp_record = 1; 5526086246cSMilanka Ringwald break; 5536086246cSMilanka Ringwald default: 5546086246cSMilanka Ringwald break; 5556086246cSMilanka Ringwald } 5566086246cSMilanka Ringwald } 5576086246cSMilanka Ringwald break; 5586086246cSMilanka Ringwald 5596086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: { 56065bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.parse_sdp_record) break; 5616086246cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 56265bd7af5SMatthias Ringwald for (des_iterator_init(&des_list_it, avrcp_sdp_query_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 5636086246cSMilanka Ringwald uint8_t *des_element; 5646086246cSMilanka Ringwald uint8_t *element; 5656086246cSMilanka Ringwald uint32_t uuid; 5666086246cSMilanka Ringwald 5676086246cSMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 5686086246cSMilanka Ringwald 5696086246cSMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 5706086246cSMilanka Ringwald des_iterator_init(&prot_it, des_element); 5716086246cSMilanka Ringwald element = des_iterator_get_element(&prot_it); 5726086246cSMilanka Ringwald 5736086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 5746086246cSMilanka Ringwald 5756086246cSMilanka Ringwald uuid = de_get_uuid32(element); 57614fd128cSMatthias Ringwald des_iterator_next(&prot_it); 5776086246cSMilanka Ringwald switch (uuid){ 5786086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 5796086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 58065bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.avrcp_l2cap_psm); 5816086246cSMilanka Ringwald break; 5826086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 5836086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 58465bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.avrcp_version); 5856086246cSMilanka Ringwald break; 5866086246cSMilanka Ringwald default: 5876086246cSMilanka Ringwald break; 5886086246cSMilanka Ringwald } 5896086246cSMilanka Ringwald } 5906086246cSMilanka Ringwald } 5916086246cSMilanka Ringwald break; 592227d16a5SMatthias Ringwald case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: { 593227d16a5SMatthias Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 59465bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.parse_sdp_record) break; 59565bd7af5SMatthias Ringwald if (de_get_element_type(avrcp_sdp_query_attribute_value) != DE_DES) break; 596227d16a5SMatthias Ringwald 597227d16a5SMatthias Ringwald des_iterator_t des_list_0_it; 598227d16a5SMatthias Ringwald uint8_t *element_0; 599227d16a5SMatthias Ringwald 60065bd7af5SMatthias Ringwald des_iterator_init(&des_list_0_it, avrcp_sdp_query_attribute_value); 601227d16a5SMatthias Ringwald element_0 = des_iterator_get_element(&des_list_0_it); 602227d16a5SMatthias Ringwald 603227d16a5SMatthias Ringwald for (des_iterator_init(&des_list_it, element_0); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 604227d16a5SMatthias Ringwald uint8_t *des_element; 605227d16a5SMatthias Ringwald uint8_t *element; 606227d16a5SMatthias Ringwald uint32_t uuid; 607227d16a5SMatthias Ringwald 608227d16a5SMatthias Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 609227d16a5SMatthias Ringwald 610227d16a5SMatthias Ringwald des_element = des_iterator_get_element(&des_list_it); 611227d16a5SMatthias Ringwald des_iterator_init(&prot_it, des_element); 612227d16a5SMatthias Ringwald element = des_iterator_get_element(&prot_it); 613227d16a5SMatthias Ringwald 614227d16a5SMatthias Ringwald if (de_get_element_type(element) != DE_UUID) continue; 615227d16a5SMatthias Ringwald 616227d16a5SMatthias Ringwald uuid = de_get_uuid32(element); 61714fd128cSMatthias Ringwald des_iterator_next(&prot_it); 618227d16a5SMatthias Ringwald switch (uuid){ 619227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 620227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 62165bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.browsing_l2cap_psm); 622227d16a5SMatthias Ringwald break; 623227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 624227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 62565bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.browsing_version); 626227d16a5SMatthias Ringwald break; 627227d16a5SMatthias Ringwald default: 628227d16a5SMatthias Ringwald break; 629227d16a5SMatthias Ringwald } 630227d16a5SMatthias Ringwald } 631227d16a5SMatthias Ringwald } 632227d16a5SMatthias Ringwald break; 6336086246cSMilanka Ringwald default: 6346086246cSMilanka Ringwald break; 6356086246cSMilanka Ringwald } 6366086246cSMilanka Ringwald } 6376086246cSMilanka Ringwald } else { 63865bd7af5SMatthias Ringwald log_error("SDP attribute value buffer size exceeded: available %d, required %d", avrcp_sdp_query_attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); 6396086246cSMilanka Ringwald } 6407b81669aSMatthias Ringwald } 6417b81669aSMatthias Ringwald 642463f41baSMilanka Ringwald static void avrcp_handle_sdp_query_failed(avrcp_connection_t * connection, uint8_t status){ 643b68672eaSMilanka Ringwald if (connection == NULL) return; 644463f41baSMilanka Ringwald log_info("AVRCP: SDP query failed with status 0x%02x.", status); 6457dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection->avrcp_cid, connection->remote_addr, connection->con_handle, status); 646463f41baSMilanka Ringwald avrcp_finalize_connection(connection); 647463f41baSMilanka Ringwald } 648463f41baSMilanka Ringwald 649a062fcddSMilanka Ringwald static void avrcp_handle_sdp_query_succeeded(avrcp_connection_t * connection){ 650b68672eaSMilanka Ringwald if (connection == NULL) return; 651463f41baSMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 65265bd7af5SMatthias Ringwald connection->avrcp_l2cap_psm = avrcp_sdp_query_context.avrcp_l2cap_psm; 65365bd7af5SMatthias Ringwald connection->browsing_version = avrcp_sdp_query_context.browsing_version; 65465bd7af5SMatthias Ringwald connection->browsing_l2cap_psm = avrcp_sdp_query_context.browsing_l2cap_psm; 655463f41baSMilanka Ringwald } 656463f41baSMilanka Ringwald 657a062fcddSMilanka Ringwald static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 65850fc39c5SMilanka Ringwald UNUSED(packet_type); 65950fc39c5SMilanka Ringwald UNUSED(channel); 66050fc39c5SMilanka Ringwald UNUSED(size); 66150fc39c5SMilanka Ringwald 6622423506bSMilanka Ringwald bool state_ok = true; 66365bd7af5SMatthias Ringwald avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_sdp_query_context.avrcp_cid); 6642423506bSMilanka Ringwald if (!avrcp_target_connection || avrcp_target_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 6652423506bSMilanka Ringwald state_ok = false; 66664a27ec5SMilanka Ringwald } 66765bd7af5SMatthias Ringwald avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_sdp_query_context.avrcp_cid); 6682423506bSMilanka Ringwald if (!avrcp_controller_connection || avrcp_controller_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 6692423506bSMilanka Ringwald state_ok = false; 6702423506bSMilanka Ringwald } 6712423506bSMilanka Ringwald if (!state_ok){ 6722423506bSMilanka Ringwald // something wrong, nevertheless, start next sdp query if this one is complete 6732423506bSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 67465bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 6752423506bSMilanka Ringwald } 67664a27ec5SMilanka Ringwald return; 67764a27ec5SMilanka Ringwald } 6787b81669aSMatthias Ringwald 6797b81669aSMatthias Ringwald uint8_t status; 6807b81669aSMatthias Ringwald 6817b81669aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 6827b81669aSMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 68350fc39c5SMilanka Ringwald avrcp_handle_sdp_client_query_attribute_value(packet); 6842423506bSMilanka Ringwald return; 6856086246cSMilanka Ringwald 68650fc39c5SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 6875448c259SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 688247956eaSMilanka Ringwald 6895448c259SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 690b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, status); 691b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, status); 6925448c259SMilanka Ringwald break; 6935448c259SMilanka Ringwald } 6945448c259SMilanka Ringwald 69565bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.avrcp_l2cap_psm){ 696b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, SDP_SERVICE_NOT_FOUND); 697b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, SDP_SERVICE_NOT_FOUND); 6986983e65eSMilanka Ringwald break; 6996983e65eSMilanka Ringwald } 700be32e7f1SMilanka Ringwald 701a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_controller_connection); 702a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_target_connection); 703bd66227aSMilanka Ringwald 70465bd7af5SMatthias Ringwald l2cap_create_channel(&avrcp_packet_handler, avrcp_target_connection->remote_addr, avrcp_sdp_query_context.avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 705463f41baSMilanka Ringwald break; 70650fc39c5SMilanka Ringwald 70750fc39c5SMilanka Ringwald default: 7082423506bSMilanka Ringwald return; 7090036e267SMilanka Ringwald } 71064a27ec5SMilanka Ringwald 71164a27ec5SMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 71264a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 71365bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 714463f41baSMilanka Ringwald } 71550fc39c5SMilanka Ringwald 716be32e7f1SMilanka Ringwald 7177dbc6cb8SMilanka 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){ 718a062fcddSMilanka Ringwald if (connection == NULL){ 719a062fcddSMilanka Ringwald connection = avrcp_create_connection(role, event_addr); 720be32e7f1SMilanka Ringwald } 721a062fcddSMilanka Ringwald if (connection) { 7220f76c2d7SMatthias Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 7230f76c2d7SMatthias Ringwald connection->l2cap_signaling_cid = local_cid; 7247403cbbaSMilanka Ringwald connection->avrcp_cid = avrcp_cid; 7257dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 72637fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 727a062fcddSMilanka Ringwald } 728a062fcddSMilanka Ringwald return connection; 729654724deSMilanka Ringwald } 730be32e7f1SMilanka Ringwald 7317dbc6cb8SMilanka 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){ 732be32e7f1SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 7330036e267SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 7347dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 735558ceb4aSMilanka Ringwald connection->incoming_declined = false; 736d1207cd8SMilanka Ringwald connection->song_length_ms = 0xFFFFFFFF; 737d1207cd8SMilanka Ringwald connection->song_position_ms = 0xFFFFFFFF; 738283fdeb7SMilanka Ringwald connection->playback_status = AVRCP_PLAYBACK_STATUS_STOPPED; 739cee0e5b6SMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 740d1207cd8SMilanka Ringwald 74164a27ec5SMilanka 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); 7420036e267SMilanka Ringwald } 7430036e267SMilanka Ringwald 74437fae987SMilanka Ringwald static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 745a062fcddSMilanka Ringwald uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 7461945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 74714c8559dSMilanka Ringwald if (connection_controller == NULL) return; 7481945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 74914c8559dSMilanka Ringwald if (connection_target == NULL) return; 750a062fcddSMilanka Ringwald 75137fae987SMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W2_L2CAP_RETRY){ 75214c8559dSMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 75314c8559dSMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 75414c8559dSMilanka Ringwald l2cap_create_channel(&avrcp_packet_handler, connection_controller->remote_addr, connection_controller->avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 75514c8559dSMilanka Ringwald } 756a062fcddSMilanka Ringwald } 757a062fcddSMilanka Ringwald 75837fae987SMilanka Ringwald static void avrcp_retry_timer_start(avrcp_connection_t * connection){ 75937fae987SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avrcp_retry_timer_timeout_handler); 76037fae987SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avrcp_cid); 761a062fcddSMilanka Ringwald 762a062fcddSMilanka Ringwald // add some jitter/randomness to reconnect delay 763a062fcddSMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 76437fae987SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 765a062fcddSMilanka Ringwald 76637fae987SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 767a062fcddSMilanka Ringwald } 768a062fcddSMilanka Ringwald 769b8081399SMilanka Ringwald static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){ 770b8081399SMilanka Ringwald return (avrcp_frame_type_t)((header & 0x02) >> 1); 771b8081399SMilanka Ringwald } 772b8081399SMilanka Ringwald 7730036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 7740036e267SMilanka Ringwald UNUSED(channel); 7750036e267SMilanka Ringwald UNUSED(size); 7760036e267SMilanka Ringwald bd_addr_t event_addr; 7770036e267SMilanka Ringwald uint16_t local_cid; 7780036e267SMilanka Ringwald uint16_t l2cap_mtu; 7790036e267SMilanka Ringwald uint8_t status; 7809b1b0ebdSMatthias Ringwald bool decline_connection; 7819b1b0ebdSMatthias Ringwald bool outoing_active; 7827dbc6cb8SMilanka Ringwald hci_con_handle_t con_handle; 7830036e267SMilanka Ringwald 784cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_controller; 785cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_target; 786bf67b2dbSMatthias Ringwald bool can_send; 787cee0e5b6SMilanka Ringwald 7880036e267SMilanka Ringwald switch (packet_type) { 7890036e267SMilanka Ringwald case HCI_EVENT_PACKET: 7900036e267SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 7910036e267SMilanka Ringwald 7920036e267SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 793e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 794e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 795e3d57ee2SMilanka Ringwald 7960036e267SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 7970036e267SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 7987dbc6cb8SMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 799cee0e5b6SMilanka Ringwald 8007dbc6cb8SMilanka Ringwald outoing_active = false; 8011945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 802cee0e5b6SMilanka Ringwald if (connection_target != NULL){ 803a062fcddSMilanka Ringwald if (connection_target->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){ 8049b1b0ebdSMatthias Ringwald outoing_active = true; 805cee0e5b6SMilanka Ringwald connection_target->incoming_declined = true; 8069b1b0ebdSMatthias Ringwald } 807a062fcddSMilanka Ringwald } 808558ceb4aSMilanka Ringwald 8091945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 810cee0e5b6SMilanka Ringwald if (connection_controller != NULL){ 811a062fcddSMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) { 8129b1b0ebdSMatthias Ringwald outoing_active = true; 813cee0e5b6SMilanka Ringwald connection_controller->incoming_declined = true; 8149b1b0ebdSMatthias Ringwald } 815a062fcddSMilanka Ringwald } 816558ceb4aSMilanka Ringwald 8179b1b0ebdSMatthias Ringwald decline_connection = outoing_active; 818a062fcddSMilanka Ringwald if (decline_connection == false){ 819a062fcddSMilanka Ringwald uint16_t avrcp_cid; 820a062fcddSMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)){ 821a062fcddSMilanka Ringwald avrcp_cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 822a062fcddSMilanka Ringwald } else { 823a062fcddSMilanka Ringwald avrcp_cid = connection_controller->avrcp_cid; 824a062fcddSMilanka Ringwald } 8250036e267SMilanka Ringwald // create two connection objects (both) 8267dbc6cb8SMilanka Ringwald connection_target = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, connection_target, event_addr, con_handle, local_cid, avrcp_cid); 8277dbc6cb8SMilanka Ringwald connection_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, connection_controller, event_addr, con_handle, local_cid, avrcp_cid); 828a062fcddSMilanka Ringwald if ((connection_target == NULL) || (connection_controller == NULL)){ 8299b1b0ebdSMatthias Ringwald decline_connection = true; 830a062fcddSMilanka Ringwald if (connection_target) { 831a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_target); 832a062fcddSMilanka Ringwald } 833a062fcddSMilanka Ringwald if (connection_controller) { 834a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_controller); 835a062fcddSMilanka Ringwald } 8360036e267SMilanka Ringwald } 8379b1b0ebdSMatthias Ringwald } 8389b1b0ebdSMatthias Ringwald if (decline_connection){ 8399b1b0ebdSMatthias Ringwald l2cap_decline_connection(local_cid); 8409b1b0ebdSMatthias Ringwald } else { 84164a27ec5SMilanka Ringwald log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION local cid 0x%02x, state %d", local_cid, connection_controller->state); 8420036e267SMilanka Ringwald l2cap_accept_connection(local_cid); 8439b1b0ebdSMatthias Ringwald } 8440036e267SMilanka Ringwald break; 8450036e267SMilanka Ringwald 8460036e267SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 8470036e267SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 8480036e267SMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 8490036e267SMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 8500036e267SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 8517dbc6cb8SMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 8520036e267SMilanka Ringwald 8531945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 8541945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 855a062fcddSMilanka Ringwald 856a062fcddSMilanka Ringwald // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION 857a062fcddSMilanka Ringwald // outgoing: structs are cteated in avrcp_connect() 858cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 859cee0e5b6SMilanka Ringwald break; 860cee0e5b6SMilanka Ringwald } 861cee0e5b6SMilanka Ringwald 862a062fcddSMilanka Ringwald switch (status){ 863a062fcddSMilanka Ringwald case ERROR_CODE_SUCCESS: 8647dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_target, con_handle, local_cid, l2cap_mtu); 8657dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_controller, con_handle, local_cid, l2cap_mtu); 8667dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 867a062fcddSMilanka Ringwald return; 868a062fcddSMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 869a062fcddSMilanka Ringwald if (connection_controller->incoming_declined == true){ 870a062fcddSMilanka Ringwald log_info("Incoming connection was declined, and the outgoing failed"); 87137fae987SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 872a062fcddSMilanka Ringwald connection_controller->incoming_declined = false; 87337fae987SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 874a062fcddSMilanka Ringwald connection_target->incoming_declined = false; 87537fae987SMilanka Ringwald avrcp_retry_timer_start(connection_controller); 876a062fcddSMilanka Ringwald return; 877a062fcddSMilanka Ringwald } 878a062fcddSMilanka Ringwald break; 879a062fcddSMilanka Ringwald default: 880a062fcddSMilanka Ringwald break; 881a062fcddSMilanka Ringwald } 882cee0e5b6SMilanka Ringwald log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 8837dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 884cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 885cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 886cee0e5b6SMilanka Ringwald 887be32e7f1SMilanka Ringwald break; 888be32e7f1SMilanka Ringwald 889be32e7f1SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 890be32e7f1SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 891cee0e5b6SMilanka Ringwald 8921945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 8931945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 894cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 895cee0e5b6SMilanka Ringwald break; 896cee0e5b6SMilanka Ringwald } 897cee0e5b6SMilanka Ringwald avrcp_emit_connection_closed(connection_controller->avrcp_cid); 898cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 899cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 9000036e267SMilanka Ringwald break; 9010036e267SMilanka Ringwald 9020036e267SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 9030036e267SMilanka Ringwald local_cid = l2cap_event_can_send_now_get_local_cid(packet); 904bf67b2dbSMatthias Ringwald can_send = true; 905e3d57ee2SMilanka Ringwald 9061945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 907cf36dea0SMilanka Ringwald if ((connection_target != NULL) && connection_target->wait_to_send){ 908cf36dea0SMilanka Ringwald connection_target->wait_to_send = false; 9090036e267SMilanka Ringwald (*avrcp_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 910bf67b2dbSMatthias Ringwald can_send = false; 9110036e267SMilanka Ringwald } 9120036e267SMilanka Ringwald 9131945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 914cf36dea0SMilanka Ringwald if ((connection_controller != NULL) && connection_controller->wait_to_send){ 915bf67b2dbSMatthias Ringwald if (can_send){ 916cf36dea0SMilanka Ringwald connection_controller->wait_to_send = false; 9170036e267SMilanka Ringwald (*avrcp_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 918bf67b2dbSMatthias Ringwald } else { 919bf67b2dbSMatthias Ringwald l2cap_request_can_send_now_event(local_cid); 920bf67b2dbSMatthias Ringwald } 921be32e7f1SMilanka Ringwald } 922be32e7f1SMilanka Ringwald break; 9230036e267SMilanka Ringwald 924be32e7f1SMilanka Ringwald default: 925be32e7f1SMilanka Ringwald break; 926be32e7f1SMilanka Ringwald } 927b106f728SMilanka Ringwald break; 928e3d57ee2SMilanka Ringwald 929e3d57ee2SMilanka Ringwald case L2CAP_DATA_PACKET: 930b8081399SMilanka Ringwald switch (avrcp_get_frame_type(packet[0])){ 931e3d57ee2SMilanka Ringwald case AVRCP_RESPONSE_FRAME: 932e3d57ee2SMilanka Ringwald (*avrcp_controller_packet_handler)(packet_type, channel, packet, size); 933e3d57ee2SMilanka Ringwald break; 934e3d57ee2SMilanka Ringwald case AVRCP_COMMAND_FRAME: 935e3d57ee2SMilanka Ringwald default: // make compiler happy 936e3d57ee2SMilanka Ringwald (*avrcp_target_packet_handler)(packet_type, channel, packet, size); 937e3d57ee2SMilanka Ringwald break; 938e3d57ee2SMilanka Ringwald } 939e3d57ee2SMilanka Ringwald break; 940e3d57ee2SMilanka Ringwald 941b106f728SMilanka Ringwald default: 942b106f728SMilanka Ringwald break; 943b106f728SMilanka Ringwald } 944be32e7f1SMilanka Ringwald } 945be32e7f1SMilanka Ringwald 946fe10780bSMilanka Ringwald uint8_t avrcp_disconnect(uint16_t avrcp_cid){ 9471945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 948fe10780bSMilanka Ringwald if (!connection_controller){ 949fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 950fe10780bSMilanka Ringwald } 9511945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 952fe10780bSMilanka Ringwald if (!connection_target){ 953fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 954fe10780bSMilanka Ringwald } 955fe10780bSMilanka Ringwald if (connection_controller->browsing_connection){ 956b93f8966SMatthias Ringwald l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid); 957fe10780bSMilanka Ringwald } 958b93f8966SMatthias Ringwald l2cap_disconnect(connection_controller->l2cap_signaling_cid); 959fe10780bSMilanka Ringwald return ERROR_CODE_SUCCESS; 960fe10780bSMilanka Ringwald } 961fe10780bSMilanka Ringwald 96264a27ec5SMilanka Ringwald static void avrcp_handle_start_sdp_client_query(void * context){ 96364a27ec5SMilanka Ringwald UNUSED(context); 9644dc95c12SMatthias Ringwald 96564a27ec5SMilanka Ringwald btstack_linked_list_iterator_t it; 96665bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, &avrcp_connections); 96764a27ec5SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 96864a27ec5SMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 96964a27ec5SMilanka Ringwald 97064a27ec5SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_W2_SEND_SDP_QUERY) continue; 97164a27ec5SMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 97264a27ec5SMilanka Ringwald 97364a27ec5SMilanka Ringwald // prevent triggering SDP query twice (for each role once) 97464a27ec5SMilanka Ringwald avrcp_connection_t * connection_with_opposite_role; 97564a27ec5SMilanka Ringwald switch (connection->role){ 97664a27ec5SMilanka Ringwald case AVRCP_CONTROLLER: 97764a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid); 97864a27ec5SMilanka Ringwald break; 97964a27ec5SMilanka Ringwald case AVRCP_TARGET: 98064a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid); 98164a27ec5SMilanka Ringwald break; 98264a27ec5SMilanka Ringwald default: 98364a27ec5SMilanka Ringwald btstack_assert(false); 98464a27ec5SMilanka Ringwald return; 98564a27ec5SMilanka Ringwald } 98664a27ec5SMilanka Ringwald connection_with_opposite_role->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 98764a27ec5SMilanka Ringwald 98865bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_l2cap_psm = 0; 98965bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_version = 0; 99065bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_cid = connection->avrcp_cid; 99164a27ec5SMilanka Ringwald sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP); 99264a27ec5SMilanka Ringwald return; 99364a27ec5SMilanka Ringwald } 9944dc95c12SMatthias Ringwald } 9954dc95c12SMatthias Ringwald 996fe10780bSMilanka Ringwald uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){ 997e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 998e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 999f9ef80eaSMilanka Ringwald 10001945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); 1001bd66227aSMilanka Ringwald if (connection_controller){ 1002bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1003bd66227aSMilanka Ringwald } 10041945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr); 1005bd66227aSMilanka Ringwald if (connection_target){ 1006bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1007bd66227aSMilanka Ringwald } 1008bd66227aSMilanka Ringwald 10097403cbbaSMilanka Ringwald uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 10107403cbbaSMilanka Ringwald 1011bd66227aSMilanka Ringwald connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 1012bd66227aSMilanka Ringwald if (!connection_controller) return BTSTACK_MEMORY_ALLOC_FAILED; 1013bd66227aSMilanka Ringwald 1014bd66227aSMilanka Ringwald connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 1015bd66227aSMilanka Ringwald if (!connection_target){ 1016bd66227aSMilanka Ringwald avrcp_finalize_connection(connection_controller); 1017bd66227aSMilanka Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 1018bd66227aSMilanka Ringwald } 1019bd66227aSMilanka Ringwald 1020bd66227aSMilanka Ringwald if (avrcp_cid != NULL){ 1021bd66227aSMilanka Ringwald *avrcp_cid = cid; 1022bd66227aSMilanka Ringwald } 1023bd66227aSMilanka Ringwald 102464a27ec5SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 10257403cbbaSMilanka Ringwald connection_controller->avrcp_cid = cid; 10267403cbbaSMilanka Ringwald 102764a27ec5SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 10287403cbbaSMilanka Ringwald connection_target->avrcp_cid = cid; 10295dd5e7e3SMilanka Ringwald 103065bd7af5SMatthias Ringwald avrcp_sdp_query_registration.callback = &avrcp_handle_start_sdp_client_query; 103164a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 103265bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 103364a27ec5SMilanka Ringwald return ERROR_CODE_SUCCESS; 1034be32e7f1SMilanka Ringwald } 1035638481deSMilanka Ringwald 1036638481deSMilanka Ringwald void avrcp_init(void){ 103765bd7af5SMatthias Ringwald avrcp_connections = NULL; 103865bd7af5SMatthias Ringwald if (avrcp_l2cap_service_registered) return; 10390036e267SMilanka Ringwald 104078315a58SMatthias Ringwald int status = l2cap_register_service(&avrcp_packet_handler, BLUETOOTH_PSM_AVCTP, 0xffff, gap_get_security_level()); 1041b106f728SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return; 104265bd7af5SMatthias Ringwald avrcp_l2cap_service_registered = true; 1043638481deSMilanka Ringwald } 1044b106f728SMilanka Ringwald 1045680af5dcSMatthias Ringwald void avrcp_deinit(void){ 104665bd7af5SMatthias Ringwald avrcp_l2cap_service_registered = false; 1047680af5dcSMatthias Ringwald 104865bd7af5SMatthias Ringwald avrcp_cid_counter = 0; 104965bd7af5SMatthias Ringwald avrcp_connections = NULL; 1050680af5dcSMatthias Ringwald 1051680af5dcSMatthias Ringwald avrcp_callback = NULL; 1052680af5dcSMatthias Ringwald avrcp_controller_packet_handler = NULL; 1053680af5dcSMatthias Ringwald avrcp_target_packet_handler = NULL; 105465bd7af5SMatthias Ringwald 105565bd7af5SMatthias Ringwald (void) memset(&avrcp_sdp_query_registration, 0, sizeof(avrcp_sdp_query_registration)); 105665bd7af5SMatthias Ringwald (void) memset(&avrcp_sdp_query_context, 0, sizeof(avrcp_sdp_query_context_t)); 105765bd7af5SMatthias Ringwald (void) memset(avrcp_sdp_query_attribute_value, 0, sizeof(avrcp_sdp_query_attribute_value)); 1058680af5dcSMatthias Ringwald } 1059680af5dcSMatthias Ringwald 1060b106f728SMilanka Ringwald void avrcp_register_controller_packet_handler(btstack_packet_handler_t callback){ 1061b106f728SMilanka Ringwald avrcp_controller_packet_handler = callback; 1062b106f728SMilanka Ringwald } 1063b106f728SMilanka Ringwald 1064b106f728SMilanka Ringwald void avrcp_register_target_packet_handler(btstack_packet_handler_t callback){ 1065b106f728SMilanka Ringwald avrcp_target_packet_handler = callback; 1066b106f728SMilanka Ringwald } 1067b106f728SMilanka Ringwald 1068cee0e5b6SMilanka Ringwald void avrcp_register_packet_handler(btstack_packet_handler_t callback){ 1069cee0e5b6SMilanka Ringwald btstack_assert(callback != NULL); 1070cee0e5b6SMilanka Ringwald avrcp_callback = callback; 1071cee0e5b6SMilanka Ringwald } 1072697b823eSMatthias Ringwald 1073697b823eSMatthias Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 1074697b823eSMatthias Ringwald #define FUZZ_CID 0x44 10753cd982f4SMatthias Ringwald #define FUZZ_CON_HANDLE 0x0001 1076697b823eSMatthias Ringwald static bd_addr_t remote_addr = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 }; 1077697b823eSMatthias Ringwald void avrcp_init_fuzz(void){ 1078697b823eSMatthias Ringwald // setup avrcp connections for cid 1079697b823eSMatthias Ringwald avrcp_connection_t * connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 1080697b823eSMatthias Ringwald avrcp_connection_t * connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 10813cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_controller, FUZZ_CON_HANDLE, FUZZ_CID, 999); 10823cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_target, FUZZ_CON_HANDLE, FUZZ_CID, 999); 1083697b823eSMatthias Ringwald } 1084697b823eSMatthias Ringwald void avrcp_packet_handler_fuzz(uint8_t *packet, uint16_t size){ 1085697b823eSMatthias Ringwald avrcp_packet_handler(L2CAP_DATA_PACKET, FUZZ_CID, packet, size); 1086697b823eSMatthias Ringwald } 1087697b823eSMatthias Ringwald #endif