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 335aeb99916SMilanka Ringwald uint16_t avctp_get_num_bytes_for_header(avctp_packet_type_t avctp_packet_type) { 33666b242bbSMilanka Ringwald switch (avctp_packet_type){ 33766b242bbSMilanka Ringwald case AVCTP_SINGLE_PACKET: 338aeb99916SMilanka Ringwald // AVCTP message: transport header (1), pid (2) 339aeb99916SMilanka Ringwald return 3; 34066b242bbSMilanka Ringwald case AVCTP_START_PACKET: 341aeb99916SMilanka Ringwald // AVCTP message: transport header (1), num_packets (1), pid (2) 342aeb99916SMilanka Ringwald return 4; 34366b242bbSMilanka Ringwald default: 344aeb99916SMilanka Ringwald // AVCTP message: transport header (1) 345aeb99916SMilanka Ringwald return 1; 34666b242bbSMilanka Ringwald } 34766b242bbSMilanka Ringwald } 34866b242bbSMilanka Ringwald 349aeb99916SMilanka Ringwald uint16_t avrcp_get_num_bytes_for_header(avrcp_command_opcode_t command_opcode, avctp_packet_type_t avctp_packet_type) { 3504d7cf390SMilanka Ringwald switch (avctp_packet_type){ 3514d7cf390SMilanka Ringwald case AVCTP_SINGLE_PACKET: 3524d7cf390SMilanka Ringwald case AVCTP_START_PACKET: 3534d7cf390SMilanka Ringwald break; 3544d7cf390SMilanka Ringwald default: 3554d7cf390SMilanka Ringwald return 0; 3564d7cf390SMilanka Ringwald } 3574d7cf390SMilanka Ringwald 3584d7cf390SMilanka Ringwald uint16_t offset = 3; // AVRCP message: cmd type (1), subunit (1), opcode (1) 3594d7cf390SMilanka Ringwald switch (command_opcode){ 3604d7cf390SMilanka Ringwald case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: 3614d7cf390SMilanka Ringwald offset += 7; // AVRCP message: company (3), pdu id(1), AVRCP packet type (1), param_len (2) 3624d7cf390SMilanka Ringwald break; 3634d7cf390SMilanka Ringwald case AVRCP_CMD_OPCODE_PASS_THROUGH: 3644d7cf390SMilanka Ringwald offset += 3; // AVRCP message: operation id (1), param_len (2) 3654d7cf390SMilanka Ringwald break; 3664d7cf390SMilanka Ringwald default: 3674d7cf390SMilanka Ringwald break; 3684d7cf390SMilanka Ringwald } 3694d7cf390SMilanka Ringwald return offset; 3704d7cf390SMilanka Ringwald } 3714d7cf390SMilanka Ringwald 372aeb99916SMilanka Ringwald static uint16_t avrcp_get_num_free_bytes_for_payload(uint16_t l2cap_cid, avrcp_command_opcode_t command_opcode, avctp_packet_type_t avctp_packet_type){ 3734d7cf390SMilanka Ringwald uint16_t max_frame_size = btstack_min(l2cap_get_remote_mtu_for_local_cid(l2cap_cid), AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE); 374aeb99916SMilanka Ringwald uint16_t payload_offset = avctp_get_num_bytes_for_header(avctp_packet_type) + 375aeb99916SMilanka Ringwald avrcp_get_num_bytes_for_header(command_opcode, avctp_packet_type); 3764d7cf390SMilanka Ringwald 377aeb99916SMilanka Ringwald btstack_assert(max_frame_size >= payload_offset); 378aeb99916SMilanka Ringwald return (max_frame_size - payload_offset); 3794d7cf390SMilanka Ringwald } 3804d7cf390SMilanka Ringwald 3814d7cf390SMilanka Ringwald 3824d7cf390SMilanka Ringwald avctp_packet_type_t avctp_get_packet_type(avrcp_connection_t * connection, uint16_t * max_payload_size){ 38366b242bbSMilanka Ringwald if (connection->data_offset == 0){ 384*96e5f69aSMilanka Ringwald uint16_t max_payload_size_for_single_packet = avrcp_get_num_free_bytes_for_payload(connection->l2cap_signaling_cid, 385aeb99916SMilanka Ringwald connection->command_opcode, 386aeb99916SMilanka Ringwald AVCTP_SINGLE_PACKET); 387*96e5f69aSMilanka Ringwald if (max_payload_size_for_single_packet >= connection->data_len){ 388*96e5f69aSMilanka Ringwald *max_payload_size = max_payload_size_for_single_packet; 38966b242bbSMilanka Ringwald return AVCTP_SINGLE_PACKET; 39066b242bbSMilanka Ringwald } else { 391*96e5f69aSMilanka Ringwald uint16_t max_payload_size_for_start_packet = max_payload_size_for_single_packet - 1; 392*96e5f69aSMilanka Ringwald *max_payload_size = max_payload_size_for_start_packet; 39366b242bbSMilanka Ringwald return AVCTP_START_PACKET; 39466b242bbSMilanka Ringwald } 39566b242bbSMilanka Ringwald } else { 396*96e5f69aSMilanka Ringwald // both packet types have the same single byte AVCTP header 397aeb99916SMilanka Ringwald *max_payload_size = avrcp_get_num_free_bytes_for_payload(connection->l2cap_signaling_cid, 398aeb99916SMilanka Ringwald connection->command_opcode, 399aeb99916SMilanka Ringwald AVCTP_CONTINUE_PACKET); 4004d7cf390SMilanka Ringwald if ((connection->data_len - connection->data_offset) > *max_payload_size){ 40166b242bbSMilanka Ringwald return AVCTP_CONTINUE_PACKET; 40266b242bbSMilanka Ringwald } else { 40366b242bbSMilanka Ringwald return AVCTP_END_PACKET; 40466b242bbSMilanka Ringwald } 40566b242bbSMilanka Ringwald } 40666b242bbSMilanka Ringwald } 40766b242bbSMilanka Ringwald 408aeb99916SMilanka Ringwald avrcp_packet_type_t avrcp_get_packet_type(avrcp_connection_t * connection){ 409aeb99916SMilanka Ringwald switch (connection->avctp_packet_type) { 410aeb99916SMilanka Ringwald case AVCTP_SINGLE_PACKET: 411aeb99916SMilanka Ringwald case AVCTP_START_PACKET: 412aeb99916SMilanka Ringwald break; 413aeb99916SMilanka Ringwald default: 414aeb99916SMilanka Ringwald return connection->packet_type; 415aeb99916SMilanka Ringwald } 416aeb99916SMilanka Ringwald 417aeb99916SMilanka Ringwald if (connection->data_offset == 0){ 418aeb99916SMilanka Ringwald if (AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE >= connection->data_len){ 419aeb99916SMilanka Ringwald return AVRCP_SINGLE_PACKET; 420aeb99916SMilanka Ringwald } else { 421aeb99916SMilanka Ringwald return AVRCP_START_PACKET; 422aeb99916SMilanka Ringwald } 423aeb99916SMilanka Ringwald } else { 424aeb99916SMilanka Ringwald if ((connection->data_len - connection->data_offset) > AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE){ 425aeb99916SMilanka Ringwald return AVRCP_CONTINUE_PACKET; 426aeb99916SMilanka Ringwald } else { 427aeb99916SMilanka Ringwald return AVRCP_END_PACKET; 428aeb99916SMilanka Ringwald } 429aeb99916SMilanka Ringwald } 430aeb99916SMilanka Ringwald } 431aeb99916SMilanka Ringwald 4321945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_bd_addr_for_role(avrcp_role_t role, bd_addr_t addr){ 4336983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 43465bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 4356983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 4366983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 43794d9400dSMilanka Ringwald if (connection->role != role) continue; 4386983e65eSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 4396983e65eSMilanka Ringwald return connection; 4406983e65eSMilanka Ringwald } 4416983e65eSMilanka Ringwald return NULL; 442be32e7f1SMilanka Ringwald } 443be32e7f1SMilanka Ringwald 4441945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_l2cap_signaling_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 4456983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 44665bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 4476983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 4486983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 44994d9400dSMilanka Ringwald if (connection->role != role) continue; 4506983e65eSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 4516983e65eSMilanka Ringwald return connection; 4526983e65eSMilanka Ringwald } 4536983e65eSMilanka Ringwald return NULL; 454be32e7f1SMilanka Ringwald } 455be32e7f1SMilanka Ringwald 4561945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_avrcp_cid_for_role(avrcp_role_t role, uint16_t avrcp_cid){ 4576983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 45865bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 4596983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 4606983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 46194d9400dSMilanka Ringwald if (connection->role != role) continue; 46201dc6e35SMilanka Ringwald if (connection->avrcp_cid != avrcp_cid) continue; 4636983e65eSMilanka Ringwald return connection; 4646983e65eSMilanka Ringwald } 4656983e65eSMilanka Ringwald return NULL; 4666983e65eSMilanka Ringwald } 4676983e65eSMilanka Ringwald 4681945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid){ 46903a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 47065bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 47103a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 47203a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 47303a72c8eSMatthias Ringwald if (connection->role != role) continue; 47403a72c8eSMatthias Ringwald if (connection->avrcp_browsing_cid != browsing_cid) continue; 47503a72c8eSMatthias Ringwald return connection; 47603a72c8eSMatthias Ringwald } 47703a72c8eSMatthias Ringwald return NULL; 47803a72c8eSMatthias Ringwald } 47903a72c8eSMatthias Ringwald 4801945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_l2cap_cid_for_role(avrcp_role_t role, uint16_t browsing_l2cap_cid){ 48103a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 48265bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 48303a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 48403a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 48503a72c8eSMatthias Ringwald if (connection->role != role) continue; 48603a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != browsing_l2cap_cid)) continue; 48703a72c8eSMatthias Ringwald return connection; 48803a72c8eSMatthias Ringwald } 48903a72c8eSMatthias Ringwald return NULL; 49003a72c8eSMatthias Ringwald } 49103a72c8eSMatthias Ringwald 4921945fe3eSMilanka Ringwald avrcp_browsing_connection_t * avrcp_get_browsing_connection_for_l2cap_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 49303a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 49465bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 49503a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 49603a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 49703a72c8eSMatthias Ringwald if (connection->role != role) continue; 49803a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != l2cap_cid)) continue; 49903a72c8eSMatthias Ringwald return connection->browsing_connection; 50003a72c8eSMatthias Ringwald } 50103a72c8eSMatthias Ringwald return NULL; 50203a72c8eSMatthias Ringwald } 50303a72c8eSMatthias Ringwald 5046983e65eSMilanka Ringwald void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){ 505cf36dea0SMilanka Ringwald connection->wait_to_send = true; 5066983e65eSMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 5076983e65eSMilanka Ringwald } 5086983e65eSMilanka Ringwald 509298aeecdSMilanka Ringwald uint16_t avrcp_get_next_cid(avrcp_role_t role){ 510298aeecdSMilanka Ringwald do { 511298aeecdSMilanka Ringwald if (avrcp_cid_counter == 0xffff) { 5126983e65eSMilanka Ringwald avrcp_cid_counter = 1; 513298aeecdSMilanka Ringwald } else { 514298aeecdSMilanka Ringwald avrcp_cid_counter++; 5156983e65eSMilanka Ringwald } 5161945fe3eSMilanka Ringwald } while (avrcp_get_connection_for_avrcp_cid_for_role(role, avrcp_cid_counter) != NULL) ; 5176983e65eSMilanka Ringwald return avrcp_cid_counter; 5186983e65eSMilanka Ringwald } 5196983e65eSMilanka Ringwald 520638481deSMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){ 5216983e65eSMilanka Ringwald avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); 5224567cc17SMilanka Ringwald if (!connection){ 5230ec79bd0SMilanka Ringwald log_error("Not enough memory to create connection for role %d", role); 5244567cc17SMilanka Ringwald return NULL; 5254567cc17SMilanka Ringwald } 5260036e267SMilanka Ringwald 5276983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_IDLE; 5280036e267SMilanka Ringwald connection->role = role; 529022b77fcSMilanka Ringwald 530022b77fcSMilanka Ringwald connection->transaction_id = 0xFF; 53123773c45SMilanka Ringwald connection->transaction_id_counter = 0; 532022b77fcSMilanka Ringwald 5338b2b4034SMilanka Ringwald connection->max_num_fragments = 0xFF; 534f0af2234SMatthias Ringwald 535f0af2234SMatthias Ringwald // setup default unit / subunit info 536f0af2234SMatthias Ringwald connection->company_id = 0xffffff; 537f0af2234SMatthias Ringwald connection->unit_type = AVRCP_SUBUNIT_TYPE_PANEL; 538f0af2234SMatthias Ringwald connection->subunit_info_data_size = sizeof(avrcp_default_subunit_info); 539f0af2234SMatthias Ringwald connection->subunit_info_data = avrcp_default_subunit_info; 540f0af2234SMatthias Ringwald 541c91f9817SMilanka Ringwald log_info("avrcp_create_connection, role %d", role); 5426535961aSMatthias Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 54365bd7af5SMatthias Ringwald btstack_linked_list_add(&avrcp_connections, (btstack_linked_item_t *) connection); 5446983e65eSMilanka Ringwald return connection; 5456983e65eSMilanka Ringwald } 5466983e65eSMilanka Ringwald 547638481deSMilanka Ringwald static void avrcp_finalize_connection(avrcp_connection_t * connection){ 54837fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 54965bd7af5SMatthias Ringwald btstack_linked_list_remove(&avrcp_connections, (btstack_linked_item_t*) connection); 55055e8029cSMatthias Ringwald btstack_memory_avrcp_connection_free(connection); 55155e8029cSMatthias Ringwald } 5526983e65eSMilanka Ringwald 5537dbc6cb8SMilanka Ringwald static void avrcp_emit_connection_established(uint16_t avrcp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status){ 554cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 555cee0e5b6SMilanka Ringwald 5567dbc6cb8SMilanka Ringwald uint8_t event[14]; 557b193c45eSMilanka Ringwald int pos = 0; 558b193c45eSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 559b193c45eSMilanka Ringwald event[pos++] = sizeof(event) - 2; 560b193c45eSMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED; 5616f43fcd7SMatthias Ringwald event[pos++] = status; 5627dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 5637dbc6cb8SMilanka Ringwald pos += 2; 564b193c45eSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 565b193c45eSMilanka Ringwald pos += 6; 5667dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, con_handle); 567b193c45eSMilanka Ringwald pos += 2; 568cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 569b193c45eSMilanka Ringwald } 570b193c45eSMilanka Ringwald 571cee0e5b6SMilanka Ringwald static void avrcp_emit_connection_closed(uint16_t avrcp_cid){ 572cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 573cee0e5b6SMilanka Ringwald 574be32e7f1SMilanka Ringwald uint8_t event[5]; 575be32e7f1SMilanka Ringwald int pos = 0; 576be32e7f1SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 577be32e7f1SMilanka Ringwald event[pos++] = sizeof(event) - 2; 578be32e7f1SMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED; 579b193c45eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 580be32e7f1SMilanka Ringwald pos += 2; 581cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 582be32e7f1SMilanka Ringwald } 583be32e7f1SMilanka Ringwald 5846d8f569dSMilanka Ringwald uint16_t avrcp_sdp_query_browsing_l2cap_psm(void){ 58565bd7af5SMatthias Ringwald return avrcp_sdp_query_context.browsing_l2cap_psm; 5864dc95c12SMatthias Ringwald } 5874dc95c12SMatthias Ringwald 5884dc95c12SMatthias Ringwald void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ 5896086246cSMilanka Ringwald des_iterator_t des_list_it; 5906086246cSMilanka Ringwald des_iterator_t prot_it; 5916086246cSMilanka Ringwald 5926086246cSMilanka Ringwald // Handle new SDP record 59365bd7af5SMatthias Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != avrcp_sdp_query_context.record_id) { 59465bd7af5SMatthias Ringwald avrcp_sdp_query_context.record_id = sdp_event_query_attribute_byte_get_record_id(packet); 59565bd7af5SMatthias Ringwald avrcp_sdp_query_context.parse_sdp_record = 0; 5966086246cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 5976086246cSMilanka Ringwald } 5986086246cSMilanka Ringwald 59965bd7af5SMatthias Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= avrcp_sdp_query_attribute_value_buffer_size) { 60065bd7af5SMatthias Ringwald avrcp_sdp_query_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 6016086246cSMilanka Ringwald 6026086246cSMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 6036086246cSMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 6046086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 60565bd7af5SMatthias Ringwald if (de_get_element_type(avrcp_sdp_query_attribute_value) != DE_DES) break; 60665bd7af5SMatthias 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)) { 6076086246cSMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 6086086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 6096086246cSMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 6106086246cSMilanka Ringwald switch (uuid){ 6116086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET: 6126086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL: 613df642728SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: 61465bd7af5SMatthias Ringwald avrcp_sdp_query_context.parse_sdp_record = 1; 6156086246cSMilanka Ringwald break; 6166086246cSMilanka Ringwald default: 6176086246cSMilanka Ringwald break; 6186086246cSMilanka Ringwald } 6196086246cSMilanka Ringwald } 6206086246cSMilanka Ringwald break; 6216086246cSMilanka Ringwald 6226086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: { 62365bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.parse_sdp_record) break; 6246086246cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 62565bd7af5SMatthias 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)) { 6266086246cSMilanka Ringwald uint8_t *des_element; 6276086246cSMilanka Ringwald uint8_t *element; 6286086246cSMilanka Ringwald uint32_t uuid; 6296086246cSMilanka Ringwald 6306086246cSMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 6316086246cSMilanka Ringwald 6326086246cSMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 6336086246cSMilanka Ringwald des_iterator_init(&prot_it, des_element); 6346086246cSMilanka Ringwald element = des_iterator_get_element(&prot_it); 6356086246cSMilanka Ringwald 6366086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 6376086246cSMilanka Ringwald 6386086246cSMilanka Ringwald uuid = de_get_uuid32(element); 63914fd128cSMatthias Ringwald des_iterator_next(&prot_it); 6406086246cSMilanka Ringwald switch (uuid){ 6416086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 6426086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 64365bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.avrcp_l2cap_psm); 6446086246cSMilanka Ringwald break; 6456086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 6466086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 64765bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.avrcp_version); 6486086246cSMilanka Ringwald break; 6496086246cSMilanka Ringwald default: 6506086246cSMilanka Ringwald break; 6516086246cSMilanka Ringwald } 6526086246cSMilanka Ringwald } 6536086246cSMilanka Ringwald } 6546086246cSMilanka Ringwald break; 655227d16a5SMatthias Ringwald case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: { 656227d16a5SMatthias Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 65765bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.parse_sdp_record) break; 65865bd7af5SMatthias Ringwald if (de_get_element_type(avrcp_sdp_query_attribute_value) != DE_DES) break; 659227d16a5SMatthias Ringwald 660227d16a5SMatthias Ringwald des_iterator_t des_list_0_it; 661227d16a5SMatthias Ringwald uint8_t *element_0; 662227d16a5SMatthias Ringwald 66365bd7af5SMatthias Ringwald des_iterator_init(&des_list_0_it, avrcp_sdp_query_attribute_value); 664227d16a5SMatthias Ringwald element_0 = des_iterator_get_element(&des_list_0_it); 665227d16a5SMatthias Ringwald 666227d16a5SMatthias Ringwald for (des_iterator_init(&des_list_it, element_0); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 667227d16a5SMatthias Ringwald uint8_t *des_element; 668227d16a5SMatthias Ringwald uint8_t *element; 669227d16a5SMatthias Ringwald uint32_t uuid; 670227d16a5SMatthias Ringwald 671227d16a5SMatthias Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 672227d16a5SMatthias Ringwald 673227d16a5SMatthias Ringwald des_element = des_iterator_get_element(&des_list_it); 674227d16a5SMatthias Ringwald des_iterator_init(&prot_it, des_element); 675227d16a5SMatthias Ringwald element = des_iterator_get_element(&prot_it); 676227d16a5SMatthias Ringwald 677227d16a5SMatthias Ringwald if (de_get_element_type(element) != DE_UUID) continue; 678227d16a5SMatthias Ringwald 679227d16a5SMatthias Ringwald uuid = de_get_uuid32(element); 68014fd128cSMatthias Ringwald des_iterator_next(&prot_it); 681227d16a5SMatthias Ringwald switch (uuid){ 682227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 683227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 68465bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.browsing_l2cap_psm); 685227d16a5SMatthias Ringwald break; 686227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 687227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 68865bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.browsing_version); 689227d16a5SMatthias Ringwald break; 690227d16a5SMatthias Ringwald default: 691227d16a5SMatthias Ringwald break; 692227d16a5SMatthias Ringwald } 693227d16a5SMatthias Ringwald } 694227d16a5SMatthias Ringwald } 695227d16a5SMatthias Ringwald break; 6966086246cSMilanka Ringwald default: 6976086246cSMilanka Ringwald break; 6986086246cSMilanka Ringwald } 6996086246cSMilanka Ringwald } 7006086246cSMilanka Ringwald } else { 70165bd7af5SMatthias 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)); 7026086246cSMilanka Ringwald } 7037b81669aSMatthias Ringwald } 7047b81669aSMatthias Ringwald 705463f41baSMilanka Ringwald static void avrcp_handle_sdp_query_failed(avrcp_connection_t * connection, uint8_t status){ 706b68672eaSMilanka Ringwald if (connection == NULL) return; 707463f41baSMilanka Ringwald log_info("AVRCP: SDP query failed with status 0x%02x.", status); 7087dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection->avrcp_cid, connection->remote_addr, connection->con_handle, status); 709463f41baSMilanka Ringwald avrcp_finalize_connection(connection); 710463f41baSMilanka Ringwald } 711463f41baSMilanka Ringwald 712a062fcddSMilanka Ringwald static void avrcp_handle_sdp_query_succeeded(avrcp_connection_t * connection){ 713b68672eaSMilanka Ringwald if (connection == NULL) return; 714463f41baSMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 71565bd7af5SMatthias Ringwald connection->avrcp_l2cap_psm = avrcp_sdp_query_context.avrcp_l2cap_psm; 71665bd7af5SMatthias Ringwald connection->browsing_version = avrcp_sdp_query_context.browsing_version; 71765bd7af5SMatthias Ringwald connection->browsing_l2cap_psm = avrcp_sdp_query_context.browsing_l2cap_psm; 718463f41baSMilanka Ringwald } 719463f41baSMilanka Ringwald 720a062fcddSMilanka Ringwald static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 72150fc39c5SMilanka Ringwald UNUSED(packet_type); 72250fc39c5SMilanka Ringwald UNUSED(channel); 72350fc39c5SMilanka Ringwald UNUSED(size); 72450fc39c5SMilanka Ringwald 7252423506bSMilanka Ringwald bool state_ok = true; 72665bd7af5SMatthias Ringwald avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_sdp_query_context.avrcp_cid); 7272423506bSMilanka Ringwald if (!avrcp_target_connection || avrcp_target_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 7282423506bSMilanka Ringwald state_ok = false; 72964a27ec5SMilanka Ringwald } 73065bd7af5SMatthias Ringwald avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_sdp_query_context.avrcp_cid); 7312423506bSMilanka Ringwald if (!avrcp_controller_connection || avrcp_controller_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 7322423506bSMilanka Ringwald state_ok = false; 7332423506bSMilanka Ringwald } 7342423506bSMilanka Ringwald if (!state_ok){ 7352423506bSMilanka Ringwald // something wrong, nevertheless, start next sdp query if this one is complete 7362423506bSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 73765bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 7382423506bSMilanka Ringwald } 73964a27ec5SMilanka Ringwald return; 74064a27ec5SMilanka Ringwald } 7417b81669aSMatthias Ringwald 7427b81669aSMatthias Ringwald uint8_t status; 7437b81669aSMatthias Ringwald 7447b81669aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 7457b81669aSMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 74650fc39c5SMilanka Ringwald avrcp_handle_sdp_client_query_attribute_value(packet); 7472423506bSMilanka Ringwald return; 7486086246cSMilanka Ringwald 74950fc39c5SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 7505448c259SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 751247956eaSMilanka Ringwald 7525448c259SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 753b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, status); 754b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, status); 7555448c259SMilanka Ringwald break; 7565448c259SMilanka Ringwald } 7575448c259SMilanka Ringwald 75865bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.avrcp_l2cap_psm){ 759b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, SDP_SERVICE_NOT_FOUND); 760b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, SDP_SERVICE_NOT_FOUND); 7616983e65eSMilanka Ringwald break; 7626983e65eSMilanka Ringwald } 763be32e7f1SMilanka Ringwald 764a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_controller_connection); 765a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_target_connection); 766bd66227aSMilanka Ringwald 76765bd7af5SMatthias Ringwald l2cap_create_channel(&avrcp_packet_handler, avrcp_target_connection->remote_addr, avrcp_sdp_query_context.avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 768463f41baSMilanka Ringwald break; 76950fc39c5SMilanka Ringwald 77050fc39c5SMilanka Ringwald default: 7712423506bSMilanka Ringwald return; 7720036e267SMilanka Ringwald } 77364a27ec5SMilanka Ringwald 77464a27ec5SMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 77564a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 77665bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 777463f41baSMilanka Ringwald } 77850fc39c5SMilanka Ringwald 779be32e7f1SMilanka Ringwald 7807dbc6cb8SMilanka 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){ 781a062fcddSMilanka Ringwald if (connection == NULL){ 782a062fcddSMilanka Ringwald connection = avrcp_create_connection(role, event_addr); 783be32e7f1SMilanka Ringwald } 784a062fcddSMilanka Ringwald if (connection) { 7850f76c2d7SMatthias Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 7860f76c2d7SMatthias Ringwald connection->l2cap_signaling_cid = local_cid; 7877403cbbaSMilanka Ringwald connection->avrcp_cid = avrcp_cid; 7887dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 78937fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 790a062fcddSMilanka Ringwald } 791a062fcddSMilanka Ringwald return connection; 792654724deSMilanka Ringwald } 793be32e7f1SMilanka Ringwald 7947dbc6cb8SMilanka 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){ 795be32e7f1SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 7960036e267SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 7977dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 798558ceb4aSMilanka Ringwald connection->incoming_declined = false; 799d1207cd8SMilanka Ringwald connection->song_length_ms = 0xFFFFFFFF; 800d1207cd8SMilanka Ringwald connection->song_position_ms = 0xFFFFFFFF; 801283fdeb7SMilanka Ringwald connection->playback_status = AVRCP_PLAYBACK_STATUS_STOPPED; 802cee0e5b6SMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 803d1207cd8SMilanka Ringwald 80464a27ec5SMilanka 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); 8050036e267SMilanka Ringwald } 8060036e267SMilanka Ringwald 80737fae987SMilanka Ringwald static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 808a062fcddSMilanka Ringwald uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 8091945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 81014c8559dSMilanka Ringwald if (connection_controller == NULL) return; 8111945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 81214c8559dSMilanka Ringwald if (connection_target == NULL) return; 813a062fcddSMilanka Ringwald 81437fae987SMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W2_L2CAP_RETRY){ 81514c8559dSMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 81614c8559dSMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 81714c8559dSMilanka Ringwald l2cap_create_channel(&avrcp_packet_handler, connection_controller->remote_addr, connection_controller->avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 81814c8559dSMilanka Ringwald } 819a062fcddSMilanka Ringwald } 820a062fcddSMilanka Ringwald 82137fae987SMilanka Ringwald static void avrcp_retry_timer_start(avrcp_connection_t * connection){ 82237fae987SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avrcp_retry_timer_timeout_handler); 82337fae987SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avrcp_cid); 824a062fcddSMilanka Ringwald 825a062fcddSMilanka Ringwald // add some jitter/randomness to reconnect delay 826a062fcddSMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 82737fae987SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 828a062fcddSMilanka Ringwald 82937fae987SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 830a062fcddSMilanka Ringwald } 831a062fcddSMilanka Ringwald 832b8081399SMilanka Ringwald static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){ 833b8081399SMilanka Ringwald return (avrcp_frame_type_t)((header & 0x02) >> 1); 834b8081399SMilanka Ringwald } 835b8081399SMilanka Ringwald 8360036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 8370036e267SMilanka Ringwald UNUSED(channel); 8380036e267SMilanka Ringwald UNUSED(size); 8390036e267SMilanka Ringwald bd_addr_t event_addr; 8400036e267SMilanka Ringwald uint16_t local_cid; 8410036e267SMilanka Ringwald uint16_t l2cap_mtu; 8420036e267SMilanka Ringwald uint8_t status; 8439b1b0ebdSMatthias Ringwald bool decline_connection; 8449b1b0ebdSMatthias Ringwald bool outoing_active; 8457dbc6cb8SMilanka Ringwald hci_con_handle_t con_handle; 8460036e267SMilanka Ringwald 847cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_controller; 848cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_target; 849bf67b2dbSMatthias Ringwald bool can_send; 850cee0e5b6SMilanka Ringwald 8510036e267SMilanka Ringwald switch (packet_type) { 8520036e267SMilanka Ringwald case HCI_EVENT_PACKET: 8530036e267SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 8540036e267SMilanka Ringwald 8550036e267SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 856e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 857e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 858e3d57ee2SMilanka Ringwald 8590036e267SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 8600036e267SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 8617dbc6cb8SMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 862cee0e5b6SMilanka Ringwald 8637dbc6cb8SMilanka Ringwald outoing_active = false; 8641945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 865cee0e5b6SMilanka Ringwald if (connection_target != NULL){ 866a062fcddSMilanka Ringwald if (connection_target->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){ 8679b1b0ebdSMatthias Ringwald outoing_active = true; 868cee0e5b6SMilanka Ringwald connection_target->incoming_declined = true; 8699b1b0ebdSMatthias Ringwald } 870a062fcddSMilanka Ringwald } 871558ceb4aSMilanka Ringwald 8721945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 873cee0e5b6SMilanka Ringwald if (connection_controller != NULL){ 874a062fcddSMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) { 8759b1b0ebdSMatthias Ringwald outoing_active = true; 876cee0e5b6SMilanka Ringwald connection_controller->incoming_declined = true; 8779b1b0ebdSMatthias Ringwald } 878a062fcddSMilanka Ringwald } 879558ceb4aSMilanka Ringwald 8809b1b0ebdSMatthias Ringwald decline_connection = outoing_active; 881a062fcddSMilanka Ringwald if (decline_connection == false){ 882a062fcddSMilanka Ringwald uint16_t avrcp_cid; 883a062fcddSMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)){ 884a062fcddSMilanka Ringwald avrcp_cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 885a062fcddSMilanka Ringwald } else { 886a062fcddSMilanka Ringwald avrcp_cid = connection_controller->avrcp_cid; 887a062fcddSMilanka Ringwald } 8880036e267SMilanka Ringwald // create two connection objects (both) 8897dbc6cb8SMilanka Ringwald connection_target = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, connection_target, event_addr, con_handle, local_cid, avrcp_cid); 8907dbc6cb8SMilanka Ringwald connection_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, connection_controller, event_addr, con_handle, local_cid, avrcp_cid); 891a062fcddSMilanka Ringwald if ((connection_target == NULL) || (connection_controller == NULL)){ 8929b1b0ebdSMatthias Ringwald decline_connection = true; 893a062fcddSMilanka Ringwald if (connection_target) { 894a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_target); 895a062fcddSMilanka Ringwald } 896a062fcddSMilanka Ringwald if (connection_controller) { 897a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_controller); 898a062fcddSMilanka Ringwald } 8990036e267SMilanka Ringwald } 9009b1b0ebdSMatthias Ringwald } 9019b1b0ebdSMatthias Ringwald if (decline_connection){ 9029b1b0ebdSMatthias Ringwald l2cap_decline_connection(local_cid); 9039b1b0ebdSMatthias Ringwald } else { 90464a27ec5SMilanka Ringwald log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION local cid 0x%02x, state %d", local_cid, connection_controller->state); 9050036e267SMilanka Ringwald l2cap_accept_connection(local_cid); 9069b1b0ebdSMatthias Ringwald } 9070036e267SMilanka Ringwald break; 9080036e267SMilanka Ringwald 9090036e267SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 9100036e267SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 9110036e267SMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 9120036e267SMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 9130036e267SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 9147dbc6cb8SMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 9150036e267SMilanka Ringwald 9161945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 9171945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 918a062fcddSMilanka Ringwald 919a062fcddSMilanka Ringwald // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION 920a062fcddSMilanka Ringwald // outgoing: structs are cteated in avrcp_connect() 921cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 922cee0e5b6SMilanka Ringwald break; 923cee0e5b6SMilanka Ringwald } 924cee0e5b6SMilanka Ringwald 925a062fcddSMilanka Ringwald switch (status){ 926a062fcddSMilanka Ringwald case ERROR_CODE_SUCCESS: 9277dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_target, con_handle, local_cid, l2cap_mtu); 9287dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_controller, con_handle, local_cid, l2cap_mtu); 9297dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 930a062fcddSMilanka Ringwald return; 931a062fcddSMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 932a062fcddSMilanka Ringwald if (connection_controller->incoming_declined == true){ 933a062fcddSMilanka Ringwald log_info("Incoming connection was declined, and the outgoing failed"); 93437fae987SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 935a062fcddSMilanka Ringwald connection_controller->incoming_declined = false; 93637fae987SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 937a062fcddSMilanka Ringwald connection_target->incoming_declined = false; 93837fae987SMilanka Ringwald avrcp_retry_timer_start(connection_controller); 939a062fcddSMilanka Ringwald return; 940a062fcddSMilanka Ringwald } 941a062fcddSMilanka Ringwald break; 942a062fcddSMilanka Ringwald default: 943a062fcddSMilanka Ringwald break; 944a062fcddSMilanka Ringwald } 945cee0e5b6SMilanka Ringwald log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 9467dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 947cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 948cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 949cee0e5b6SMilanka Ringwald 950be32e7f1SMilanka Ringwald break; 951be32e7f1SMilanka Ringwald 952be32e7f1SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 953be32e7f1SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 954cee0e5b6SMilanka Ringwald 9551945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 9561945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 957cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 958cee0e5b6SMilanka Ringwald break; 959cee0e5b6SMilanka Ringwald } 960cee0e5b6SMilanka Ringwald avrcp_emit_connection_closed(connection_controller->avrcp_cid); 961cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 962cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 9630036e267SMilanka Ringwald break; 9640036e267SMilanka Ringwald 9650036e267SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 9660036e267SMilanka Ringwald local_cid = l2cap_event_can_send_now_get_local_cid(packet); 967bf67b2dbSMatthias Ringwald can_send = true; 968e3d57ee2SMilanka Ringwald 9691945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 970cf36dea0SMilanka Ringwald if ((connection_target != NULL) && connection_target->wait_to_send){ 971cf36dea0SMilanka Ringwald connection_target->wait_to_send = false; 9720036e267SMilanka Ringwald (*avrcp_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 973bf67b2dbSMatthias Ringwald can_send = false; 9740036e267SMilanka Ringwald } 9750036e267SMilanka Ringwald 9761945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 977cf36dea0SMilanka Ringwald if ((connection_controller != NULL) && connection_controller->wait_to_send){ 978bf67b2dbSMatthias Ringwald if (can_send){ 979cf36dea0SMilanka Ringwald connection_controller->wait_to_send = false; 9800036e267SMilanka Ringwald (*avrcp_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 981bf67b2dbSMatthias Ringwald } else { 982bf67b2dbSMatthias Ringwald l2cap_request_can_send_now_event(local_cid); 983bf67b2dbSMatthias Ringwald } 984be32e7f1SMilanka Ringwald } 985be32e7f1SMilanka Ringwald break; 9860036e267SMilanka Ringwald 987be32e7f1SMilanka Ringwald default: 988be32e7f1SMilanka Ringwald break; 989be32e7f1SMilanka Ringwald } 990b106f728SMilanka Ringwald break; 991e3d57ee2SMilanka Ringwald 992e3d57ee2SMilanka Ringwald case L2CAP_DATA_PACKET: 993b8081399SMilanka Ringwald switch (avrcp_get_frame_type(packet[0])){ 994e3d57ee2SMilanka Ringwald case AVRCP_RESPONSE_FRAME: 995e3d57ee2SMilanka Ringwald (*avrcp_controller_packet_handler)(packet_type, channel, packet, size); 996e3d57ee2SMilanka Ringwald break; 997e3d57ee2SMilanka Ringwald case AVRCP_COMMAND_FRAME: 998e3d57ee2SMilanka Ringwald default: // make compiler happy 999e3d57ee2SMilanka Ringwald (*avrcp_target_packet_handler)(packet_type, channel, packet, size); 1000e3d57ee2SMilanka Ringwald break; 1001e3d57ee2SMilanka Ringwald } 1002e3d57ee2SMilanka Ringwald break; 1003e3d57ee2SMilanka Ringwald 1004b106f728SMilanka Ringwald default: 1005b106f728SMilanka Ringwald break; 1006b106f728SMilanka Ringwald } 1007be32e7f1SMilanka Ringwald } 1008be32e7f1SMilanka Ringwald 1009fe10780bSMilanka Ringwald uint8_t avrcp_disconnect(uint16_t avrcp_cid){ 10101945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 1011fe10780bSMilanka Ringwald if (!connection_controller){ 1012fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1013fe10780bSMilanka Ringwald } 10141945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 1015fe10780bSMilanka Ringwald if (!connection_target){ 1016fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1017fe10780bSMilanka Ringwald } 1018fe10780bSMilanka Ringwald if (connection_controller->browsing_connection){ 1019b93f8966SMatthias Ringwald l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid); 1020fe10780bSMilanka Ringwald } 1021b93f8966SMatthias Ringwald l2cap_disconnect(connection_controller->l2cap_signaling_cid); 1022fe10780bSMilanka Ringwald return ERROR_CODE_SUCCESS; 1023fe10780bSMilanka Ringwald } 1024fe10780bSMilanka Ringwald 102564a27ec5SMilanka Ringwald static void avrcp_handle_start_sdp_client_query(void * context){ 102664a27ec5SMilanka Ringwald UNUSED(context); 10274dc95c12SMatthias Ringwald 102864a27ec5SMilanka Ringwald btstack_linked_list_iterator_t it; 102965bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, &avrcp_connections); 103064a27ec5SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 103164a27ec5SMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 103264a27ec5SMilanka Ringwald 103364a27ec5SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_W2_SEND_SDP_QUERY) continue; 103464a27ec5SMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 103564a27ec5SMilanka Ringwald 103664a27ec5SMilanka Ringwald // prevent triggering SDP query twice (for each role once) 103764a27ec5SMilanka Ringwald avrcp_connection_t * connection_with_opposite_role; 103864a27ec5SMilanka Ringwald switch (connection->role){ 103964a27ec5SMilanka Ringwald case AVRCP_CONTROLLER: 104064a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid); 104164a27ec5SMilanka Ringwald break; 104264a27ec5SMilanka Ringwald case AVRCP_TARGET: 104364a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid); 104464a27ec5SMilanka Ringwald break; 104564a27ec5SMilanka Ringwald default: 104664a27ec5SMilanka Ringwald btstack_assert(false); 104764a27ec5SMilanka Ringwald return; 104864a27ec5SMilanka Ringwald } 104964a27ec5SMilanka Ringwald connection_with_opposite_role->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 105064a27ec5SMilanka Ringwald 105165bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_l2cap_psm = 0; 105265bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_version = 0; 105365bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_cid = connection->avrcp_cid; 105464a27ec5SMilanka Ringwald sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP); 105564a27ec5SMilanka Ringwald return; 105664a27ec5SMilanka Ringwald } 10574dc95c12SMatthias Ringwald } 10584dc95c12SMatthias Ringwald 1059fe10780bSMilanka Ringwald uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){ 1060e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 1061e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 1062f9ef80eaSMilanka Ringwald 10631945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); 1064bd66227aSMilanka Ringwald if (connection_controller){ 1065bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1066bd66227aSMilanka Ringwald } 10671945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr); 1068bd66227aSMilanka Ringwald if (connection_target){ 1069bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1070bd66227aSMilanka Ringwald } 1071bd66227aSMilanka Ringwald 10727403cbbaSMilanka Ringwald uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 10737403cbbaSMilanka Ringwald 1074bd66227aSMilanka Ringwald connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 1075bd66227aSMilanka Ringwald if (!connection_controller) return BTSTACK_MEMORY_ALLOC_FAILED; 1076bd66227aSMilanka Ringwald 1077bd66227aSMilanka Ringwald connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 1078bd66227aSMilanka Ringwald if (!connection_target){ 1079bd66227aSMilanka Ringwald avrcp_finalize_connection(connection_controller); 1080bd66227aSMilanka Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 1081bd66227aSMilanka Ringwald } 1082bd66227aSMilanka Ringwald 1083bd66227aSMilanka Ringwald if (avrcp_cid != NULL){ 1084bd66227aSMilanka Ringwald *avrcp_cid = cid; 1085bd66227aSMilanka Ringwald } 1086bd66227aSMilanka Ringwald 108764a27ec5SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 10887403cbbaSMilanka Ringwald connection_controller->avrcp_cid = cid; 10897403cbbaSMilanka Ringwald 109064a27ec5SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 10917403cbbaSMilanka Ringwald connection_target->avrcp_cid = cid; 10925dd5e7e3SMilanka Ringwald 109365bd7af5SMatthias Ringwald avrcp_sdp_query_registration.callback = &avrcp_handle_start_sdp_client_query; 109464a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 109565bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 109664a27ec5SMilanka Ringwald return ERROR_CODE_SUCCESS; 1097be32e7f1SMilanka Ringwald } 1098638481deSMilanka Ringwald 1099638481deSMilanka Ringwald void avrcp_init(void){ 110065bd7af5SMatthias Ringwald avrcp_connections = NULL; 110165bd7af5SMatthias Ringwald if (avrcp_l2cap_service_registered) return; 11020036e267SMilanka Ringwald 110378315a58SMatthias Ringwald int status = l2cap_register_service(&avrcp_packet_handler, BLUETOOTH_PSM_AVCTP, 0xffff, gap_get_security_level()); 1104b106f728SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return; 110565bd7af5SMatthias Ringwald avrcp_l2cap_service_registered = true; 1106638481deSMilanka Ringwald } 1107b106f728SMilanka Ringwald 1108680af5dcSMatthias Ringwald void avrcp_deinit(void){ 110965bd7af5SMatthias Ringwald avrcp_l2cap_service_registered = false; 1110680af5dcSMatthias Ringwald 111165bd7af5SMatthias Ringwald avrcp_cid_counter = 0; 111265bd7af5SMatthias Ringwald avrcp_connections = NULL; 1113680af5dcSMatthias Ringwald 1114680af5dcSMatthias Ringwald avrcp_callback = NULL; 1115680af5dcSMatthias Ringwald avrcp_controller_packet_handler = NULL; 1116680af5dcSMatthias Ringwald avrcp_target_packet_handler = NULL; 111765bd7af5SMatthias Ringwald 111865bd7af5SMatthias Ringwald (void) memset(&avrcp_sdp_query_registration, 0, sizeof(avrcp_sdp_query_registration)); 111965bd7af5SMatthias Ringwald (void) memset(&avrcp_sdp_query_context, 0, sizeof(avrcp_sdp_query_context_t)); 112065bd7af5SMatthias Ringwald (void) memset(avrcp_sdp_query_attribute_value, 0, sizeof(avrcp_sdp_query_attribute_value)); 1121680af5dcSMatthias Ringwald } 1122680af5dcSMatthias Ringwald 1123b106f728SMilanka Ringwald void avrcp_register_controller_packet_handler(btstack_packet_handler_t callback){ 1124b106f728SMilanka Ringwald avrcp_controller_packet_handler = callback; 1125b106f728SMilanka Ringwald } 1126b106f728SMilanka Ringwald 1127b106f728SMilanka Ringwald void avrcp_register_target_packet_handler(btstack_packet_handler_t callback){ 1128b106f728SMilanka Ringwald avrcp_target_packet_handler = callback; 1129b106f728SMilanka Ringwald } 1130b106f728SMilanka Ringwald 1131cee0e5b6SMilanka Ringwald void avrcp_register_packet_handler(btstack_packet_handler_t callback){ 1132cee0e5b6SMilanka Ringwald btstack_assert(callback != NULL); 1133cee0e5b6SMilanka Ringwald avrcp_callback = callback; 1134cee0e5b6SMilanka Ringwald } 1135697b823eSMatthias Ringwald 1136697b823eSMatthias Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 1137697b823eSMatthias Ringwald #define FUZZ_CID 0x44 11383cd982f4SMatthias Ringwald #define FUZZ_CON_HANDLE 0x0001 1139697b823eSMatthias Ringwald static bd_addr_t remote_addr = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 }; 1140697b823eSMatthias Ringwald void avrcp_init_fuzz(void){ 1141697b823eSMatthias Ringwald // setup avrcp connections for cid 1142697b823eSMatthias Ringwald avrcp_connection_t * connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 1143697b823eSMatthias Ringwald avrcp_connection_t * connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 11443cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_controller, FUZZ_CON_HANDLE, FUZZ_CID, 999); 11453cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_target, FUZZ_CON_HANDLE, FUZZ_CID, 999); 1146697b823eSMatthias Ringwald } 1147697b823eSMatthias Ringwald void avrcp_packet_handler_fuzz(uint8_t *packet, uint16_t size){ 1148697b823eSMatthias Ringwald avrcp_packet_handler(L2CAP_DATA_PACKET, FUZZ_CID, packet, size); 1149697b823eSMatthias Ringwald } 1150697b823eSMatthias Ringwald #endif