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 }; 1767d1b72e5SMilanka Ringwald static const uint16_t avrcp_ctype_name_num = 16; 177447150e4SMilanka Ringwald 178be32e7f1SMilanka Ringwald const char * avrcp_ctype2str(uint8_t index){ 179447150e4SMilanka Ringwald if (index < avrcp_ctype_name_num){ 180be32e7f1SMilanka Ringwald return avrcp_ctype_name[index]; 181be32e7f1SMilanka Ringwald } 182be32e7f1SMilanka Ringwald return "NONE"; 183be32e7f1SMilanka Ringwald } 184be32e7f1SMilanka Ringwald 185be32e7f1SMilanka Ringwald static const char * avrcp_shuffle_mode_name[] = { 186be32e7f1SMilanka Ringwald "SHUFFLE OFF", 187be32e7f1SMilanka Ringwald "SHUFFLE ALL TRACKS", 188be32e7f1SMilanka Ringwald "SHUFFLE GROUP" 189be32e7f1SMilanka Ringwald }; 190be32e7f1SMilanka Ringwald 191be32e7f1SMilanka Ringwald const char * avrcp_shuffle2str(uint8_t index){ 192c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 3)) return avrcp_shuffle_mode_name[index-1]; 193be32e7f1SMilanka Ringwald return "NONE"; 194be32e7f1SMilanka Ringwald } 195be32e7f1SMilanka Ringwald 196be32e7f1SMilanka Ringwald static const char * avrcp_repeat_mode_name[] = { 197be32e7f1SMilanka Ringwald "REPEAT OFF", 198be32e7f1SMilanka Ringwald "REPEAT SINGLE TRACK", 199be32e7f1SMilanka Ringwald "REPEAT ALL TRACKS", 200be32e7f1SMilanka Ringwald "REPEAT GROUP" 201be32e7f1SMilanka Ringwald }; 202be32e7f1SMilanka Ringwald 203be32e7f1SMilanka Ringwald const char * avrcp_repeat2str(uint8_t index){ 204c1ab6cc1SMatthias Ringwald if ((index >= 1) && (index <= 4)) return avrcp_repeat_mode_name[index-1]; 205be32e7f1SMilanka Ringwald return "NONE"; 206be32e7f1SMilanka Ringwald } 2076086246cSMilanka Ringwald 20864a27ec5SMilanka Ringwald btstack_linked_list_t avrcp_get_connections(void){ 20965bd7af5SMatthias Ringwald return avrcp_connections; 21064a27ec5SMilanka Ringwald } 21164a27ec5SMilanka Ringwald 2124b338011SMilanka Ringwald uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){ 2134b338011SMilanka Ringwald uint8_t cmd_opcode_index = 5; 2144b338011SMilanka Ringwald if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED; 2154b338011SMilanka Ringwald return packet[cmd_opcode_index]; 2164b338011SMilanka Ringwald } 2174b338011SMilanka Ringwald 218654724deSMilanka Ringwald void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features, 219654724deSMilanka Ringwald const char * service_name, const char * service_provider_name){ 220be32e7f1SMilanka Ringwald uint8_t* attribute; 221be32e7f1SMilanka Ringwald de_create_sequence(service); 222be32e7f1SMilanka Ringwald 223be32e7f1SMilanka Ringwald // 0x0000 "Service Record Handle" 224235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE); 225be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle); 226be32e7f1SMilanka Ringwald 227be32e7f1SMilanka Ringwald // 0x0001 "Service Class ID List" 228235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST); 229be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 230be32e7f1SMilanka Ringwald { 231be32e7f1SMilanka Ringwald if (controller){ 2326086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 2336086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER); 234be32e7f1SMilanka Ringwald } else { 2356086246cSMilanka Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET); 236be32e7f1SMilanka Ringwald } 237be32e7f1SMilanka Ringwald } 238be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 239be32e7f1SMilanka Ringwald 240be32e7f1SMilanka Ringwald // 0x0004 "Protocol Descriptor List" 241235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST); 242be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 243be32e7f1SMilanka Ringwald { 244be32e7f1SMilanka Ringwald uint8_t* l2cpProtocol = de_push_sequence(attribute); 245be32e7f1SMilanka Ringwald { 246235946f1SMatthias Ringwald de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 24784e3541eSMilanka Ringwald de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP); 248be32e7f1SMilanka Ringwald } 249be32e7f1SMilanka Ringwald de_pop_sequence(attribute, l2cpProtocol); 250be32e7f1SMilanka Ringwald 251be32e7f1SMilanka Ringwald uint8_t* avctpProtocol = de_push_sequence(attribute); 252be32e7f1SMilanka Ringwald { 253235946f1SMatthias Ringwald de_add_number(avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // avctpProtocol_service 2540b322400SMilanka Ringwald de_add_number(avctpProtocol, DE_UINT, DE_SIZE_16, 0x0104); // version 255be32e7f1SMilanka Ringwald } 256be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avctpProtocol); 257be32e7f1SMilanka Ringwald } 258be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 259be32e7f1SMilanka Ringwald 260be32e7f1SMilanka Ringwald // 0x0005 "Public Browse Group" 261235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group 262be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 263be32e7f1SMilanka Ringwald { 264235946f1SMatthias Ringwald de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT); 265be32e7f1SMilanka Ringwald } 266be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 267be32e7f1SMilanka Ringwald 268be32e7f1SMilanka Ringwald // 0x0009 "Bluetooth Profile Descriptor List" 269235946f1SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST); 270be32e7f1SMilanka Ringwald attribute = de_push_sequence(service); 271be32e7f1SMilanka Ringwald { 272be32e7f1SMilanka Ringwald uint8_t *avrcProfile = de_push_sequence(attribute); 273be32e7f1SMilanka Ringwald { 2746086246cSMilanka Ringwald de_add_number(avrcProfile, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL); 2750b322400SMilanka Ringwald de_add_number(avrcProfile, DE_UINT, DE_SIZE_16, 0x0106); 276be32e7f1SMilanka Ringwald } 277be32e7f1SMilanka Ringwald de_pop_sequence(attribute, avrcProfile); 278be32e7f1SMilanka Ringwald } 279be32e7f1SMilanka Ringwald de_pop_sequence(service, attribute); 280be32e7f1SMilanka Ringwald 281a0f524f0SMatthias Ringwald // 0x000d "Additional Bluetooth Profile Descriptor List" 2825c806868SMatthias Ringwald if (browsing){ 283a0f524f0SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS); 284a0f524f0SMatthias Ringwald attribute = de_push_sequence(service); 2855c806868SMatthias Ringwald { 2865c806868SMatthias Ringwald uint8_t * des = de_push_sequence(attribute); 2875c806868SMatthias Ringwald { 2885c806868SMatthias Ringwald uint8_t* browsing_l2cpProtocol = de_push_sequence(des); 289a0f524f0SMatthias Ringwald { 290a0f524f0SMatthias Ringwald de_add_number(browsing_l2cpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP); 29184e3541eSMilanka Ringwald de_add_number(browsing_l2cpProtocol, DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP_BROWSING); 292a0f524f0SMatthias Ringwald } 2935c806868SMatthias Ringwald de_pop_sequence(des, browsing_l2cpProtocol); 294a0f524f0SMatthias Ringwald 2955c806868SMatthias Ringwald uint8_t* browsing_avctpProtocol = de_push_sequence(des); 296a0f524f0SMatthias Ringwald { 297a0f524f0SMatthias Ringwald de_add_number(browsing_avctpProtocol, DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP); // browsing_avctpProtocol_service 2980b322400SMilanka Ringwald de_add_number(browsing_avctpProtocol, DE_UINT, DE_SIZE_16, 0x0104); // version 299a0f524f0SMatthias Ringwald } 3005c806868SMatthias Ringwald de_pop_sequence(des, browsing_avctpProtocol); 3015c806868SMatthias Ringwald } 3025c806868SMatthias Ringwald de_pop_sequence(attribute, des); 303a0f524f0SMatthias Ringwald } 304a0f524f0SMatthias Ringwald de_pop_sequence(service, attribute); 3055c806868SMatthias Ringwald } 306a0f524f0SMatthias Ringwald 307be32e7f1SMilanka Ringwald 308be32e7f1SMilanka Ringwald // 0x0100 "Service Name" 309be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); 310be32e7f1SMilanka Ringwald if (service_name){ 311be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name); 312be32e7f1SMilanka Ringwald } else { 313be32e7f1SMilanka Ringwald if (controller){ 31465bd7af5SMatthias Ringwald de_add_data(service, DE_STRING, strlen(avrcp_default_controller_service_name), (uint8_t *) avrcp_default_controller_service_name); 315be32e7f1SMilanka Ringwald } else { 31665bd7af5SMatthias Ringwald de_add_data(service, DE_STRING, strlen(avrcp_defaul_target_service_name), (uint8_t *) avrcp_defaul_target_service_name); 317be32e7f1SMilanka Ringwald } 318be32e7f1SMilanka Ringwald } 319be32e7f1SMilanka Ringwald 320be32e7f1SMilanka Ringwald // 0x0100 "Provider Name" 321be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102); 322be32e7f1SMilanka Ringwald if (service_provider_name){ 323be32e7f1SMilanka Ringwald de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name); 324be32e7f1SMilanka Ringwald } else { 325be32e7f1SMilanka Ringwald if (controller){ 32665bd7af5SMatthias Ringwald de_add_data(service, DE_STRING, strlen(avrcp_default_controller_service_provider_name), (uint8_t *) avrcp_default_controller_service_provider_name); 327be32e7f1SMilanka Ringwald } else { 32865bd7af5SMatthias Ringwald de_add_data(service, DE_STRING, strlen(avrcp_default_target_service_provider_name), (uint8_t *) avrcp_default_target_service_provider_name); 329be32e7f1SMilanka Ringwald } 330be32e7f1SMilanka Ringwald } 331be32e7f1SMilanka Ringwald 332be32e7f1SMilanka Ringwald // 0x0311 "Supported Features" 333be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); 334be32e7f1SMilanka Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 335be32e7f1SMilanka Ringwald } 336be32e7f1SMilanka Ringwald 337aeb99916SMilanka Ringwald uint16_t avctp_get_num_bytes_for_header(avctp_packet_type_t avctp_packet_type) { 33866b242bbSMilanka Ringwald switch (avctp_packet_type){ 33966b242bbSMilanka Ringwald case AVCTP_SINGLE_PACKET: 340aeb99916SMilanka Ringwald // AVCTP message: transport header (1), pid (2) 341aeb99916SMilanka Ringwald return 3; 34266b242bbSMilanka Ringwald case AVCTP_START_PACKET: 343aeb99916SMilanka Ringwald // AVCTP message: transport header (1), num_packets (1), pid (2) 344aeb99916SMilanka Ringwald return 4; 34566b242bbSMilanka Ringwald default: 346aeb99916SMilanka Ringwald // AVCTP message: transport header (1) 347aeb99916SMilanka Ringwald return 1; 34866b242bbSMilanka Ringwald } 34966b242bbSMilanka Ringwald } 35066b242bbSMilanka Ringwald 351aeb99916SMilanka Ringwald uint16_t avrcp_get_num_bytes_for_header(avrcp_command_opcode_t command_opcode, avctp_packet_type_t avctp_packet_type) { 3524d7cf390SMilanka Ringwald switch (avctp_packet_type){ 3534d7cf390SMilanka Ringwald case AVCTP_SINGLE_PACKET: 3544d7cf390SMilanka Ringwald case AVCTP_START_PACKET: 3554d7cf390SMilanka Ringwald break; 3564d7cf390SMilanka Ringwald default: 3574d7cf390SMilanka Ringwald return 0; 3584d7cf390SMilanka Ringwald } 3594d7cf390SMilanka Ringwald 3604d7cf390SMilanka Ringwald uint16_t offset = 3; // AVRCP message: cmd type (1), subunit (1), opcode (1) 3614d7cf390SMilanka Ringwald switch (command_opcode){ 3624d7cf390SMilanka Ringwald case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: 3634d7cf390SMilanka Ringwald offset += 7; // AVRCP message: company (3), pdu id(1), AVRCP packet type (1), param_len (2) 3644d7cf390SMilanka Ringwald break; 3654d7cf390SMilanka Ringwald case AVRCP_CMD_OPCODE_PASS_THROUGH: 3664d7cf390SMilanka Ringwald offset += 3; // AVRCP message: operation id (1), param_len (2) 3674d7cf390SMilanka Ringwald break; 3684d7cf390SMilanka Ringwald default: 3694d7cf390SMilanka Ringwald break; 3704d7cf390SMilanka Ringwald } 3714d7cf390SMilanka Ringwald return offset; 3724d7cf390SMilanka Ringwald } 3734d7cf390SMilanka Ringwald 374c3d92d4cSMilanka Ringwald static uint16_t avrcp_get_num_free_bytes_for_payload(uint16_t l2cap_mtu, avrcp_command_opcode_t command_opcode, avctp_packet_type_t avctp_packet_type){ 375c3d92d4cSMilanka Ringwald uint16_t max_frame_size = btstack_min(l2cap_mtu, AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE); 376aeb99916SMilanka Ringwald uint16_t payload_offset = avctp_get_num_bytes_for_header(avctp_packet_type) + 377aeb99916SMilanka Ringwald avrcp_get_num_bytes_for_header(command_opcode, avctp_packet_type); 3784d7cf390SMilanka Ringwald 379aeb99916SMilanka Ringwald btstack_assert(max_frame_size >= payload_offset); 380aeb99916SMilanka Ringwald return (max_frame_size - payload_offset); 3814d7cf390SMilanka Ringwald } 3824d7cf390SMilanka Ringwald 3834d7cf390SMilanka Ringwald 3844d7cf390SMilanka Ringwald avctp_packet_type_t avctp_get_packet_type(avrcp_connection_t * connection, uint16_t * max_payload_size){ 3857ff388bdSMilanka Ringwald if (connection->l2cap_mtu >= AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE){ 3867ff388bdSMilanka Ringwald return AVCTP_SINGLE_PACKET; 3877ff388bdSMilanka Ringwald } 3887ff388bdSMilanka Ringwald 38966b242bbSMilanka Ringwald if (connection->data_offset == 0){ 390c3d92d4cSMilanka Ringwald uint16_t max_payload_size_for_single_packet = avrcp_get_num_free_bytes_for_payload(connection->l2cap_mtu, 391aeb99916SMilanka Ringwald connection->command_opcode, 392aeb99916SMilanka Ringwald AVCTP_SINGLE_PACKET); 39396e5f69aSMilanka Ringwald if (max_payload_size_for_single_packet >= connection->data_len){ 39496e5f69aSMilanka Ringwald *max_payload_size = max_payload_size_for_single_packet; 39566b242bbSMilanka Ringwald return AVCTP_SINGLE_PACKET; 39666b242bbSMilanka Ringwald } else { 39796e5f69aSMilanka Ringwald uint16_t max_payload_size_for_start_packet = max_payload_size_for_single_packet - 1; 39896e5f69aSMilanka Ringwald *max_payload_size = max_payload_size_for_start_packet; 39966b242bbSMilanka Ringwald return AVCTP_START_PACKET; 40066b242bbSMilanka Ringwald } 40166b242bbSMilanka Ringwald } else { 40296e5f69aSMilanka Ringwald // both packet types have the same single byte AVCTP header 403c3d92d4cSMilanka Ringwald *max_payload_size = avrcp_get_num_free_bytes_for_payload(connection->l2cap_mtu, 404aeb99916SMilanka Ringwald connection->command_opcode, 405aeb99916SMilanka Ringwald AVCTP_CONTINUE_PACKET); 4064d7cf390SMilanka Ringwald if ((connection->data_len - connection->data_offset) > *max_payload_size){ 40766b242bbSMilanka Ringwald return AVCTP_CONTINUE_PACKET; 40866b242bbSMilanka Ringwald } else { 40966b242bbSMilanka Ringwald return AVCTP_END_PACKET; 41066b242bbSMilanka Ringwald } 41166b242bbSMilanka Ringwald } 41266b242bbSMilanka Ringwald } 41366b242bbSMilanka Ringwald 414aeb99916SMilanka Ringwald avrcp_packet_type_t avrcp_get_packet_type(avrcp_connection_t * connection){ 415aeb99916SMilanka Ringwald switch (connection->avctp_packet_type) { 416aeb99916SMilanka Ringwald case AVCTP_SINGLE_PACKET: 417aeb99916SMilanka Ringwald case AVCTP_START_PACKET: 418aeb99916SMilanka Ringwald break; 419aeb99916SMilanka Ringwald default: 420393f5724SMilanka Ringwald return connection->avrcp_packet_type; 421aeb99916SMilanka Ringwald } 422aeb99916SMilanka Ringwald 423d6c2d4bcSMilanka Ringwald uint16_t payload_offset = avctp_get_num_bytes_for_header(connection->avctp_packet_type) + 424d6c2d4bcSMilanka Ringwald avrcp_get_num_bytes_for_header(connection->command_opcode, connection->avctp_packet_type); 425d6c2d4bcSMilanka Ringwald uint16_t bytes_to_send = (connection->data_len - connection->data_offset) + payload_offset; 426d6c2d4bcSMilanka Ringwald 427aeb99916SMilanka Ringwald if (connection->data_offset == 0){ 428d6c2d4bcSMilanka Ringwald if (bytes_to_send <= AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE){ 429aeb99916SMilanka Ringwald return AVRCP_SINGLE_PACKET; 430aeb99916SMilanka Ringwald } else { 431aeb99916SMilanka Ringwald return AVRCP_START_PACKET; 432aeb99916SMilanka Ringwald } 433aeb99916SMilanka Ringwald } else { 434d6c2d4bcSMilanka Ringwald if (bytes_to_send > AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE){ 435aeb99916SMilanka Ringwald return AVRCP_CONTINUE_PACKET; 436aeb99916SMilanka Ringwald } else { 437aeb99916SMilanka Ringwald return AVRCP_END_PACKET; 438aeb99916SMilanka Ringwald } 439aeb99916SMilanka Ringwald } 440aeb99916SMilanka Ringwald } 441aeb99916SMilanka Ringwald 4421945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_bd_addr_for_role(avrcp_role_t role, bd_addr_t addr){ 4436983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 44465bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 4456983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 4466983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 44794d9400dSMilanka Ringwald if (connection->role != role) continue; 4486983e65eSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 4496983e65eSMilanka Ringwald return connection; 4506983e65eSMilanka Ringwald } 4516983e65eSMilanka Ringwald return NULL; 452be32e7f1SMilanka Ringwald } 453be32e7f1SMilanka Ringwald 4541945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_l2cap_signaling_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 4556983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 45665bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 4576983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 4586983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 45994d9400dSMilanka Ringwald if (connection->role != role) continue; 4606983e65eSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 4616983e65eSMilanka Ringwald return connection; 4626983e65eSMilanka Ringwald } 4636983e65eSMilanka Ringwald return NULL; 464be32e7f1SMilanka Ringwald } 465be32e7f1SMilanka Ringwald 4661945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_avrcp_cid_for_role(avrcp_role_t role, uint16_t avrcp_cid){ 4676983e65eSMilanka Ringwald btstack_linked_list_iterator_t it; 46865bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 4696983e65eSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 4706983e65eSMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 47194d9400dSMilanka Ringwald if (connection->role != role) continue; 47201dc6e35SMilanka Ringwald if (connection->avrcp_cid != avrcp_cid) continue; 4736983e65eSMilanka Ringwald return connection; 4746983e65eSMilanka Ringwald } 4756983e65eSMilanka Ringwald return NULL; 4766983e65eSMilanka Ringwald } 4776983e65eSMilanka Ringwald 4781945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid){ 47903a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 48065bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 48103a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 48203a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 48303a72c8eSMatthias Ringwald if (connection->role != role) continue; 48403a72c8eSMatthias Ringwald if (connection->avrcp_browsing_cid != browsing_cid) continue; 48503a72c8eSMatthias Ringwald return connection; 48603a72c8eSMatthias Ringwald } 48703a72c8eSMatthias Ringwald return NULL; 48803a72c8eSMatthias Ringwald } 48903a72c8eSMatthias Ringwald 4901945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_l2cap_cid_for_role(avrcp_role_t role, uint16_t browsing_l2cap_cid){ 49103a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 49265bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 49303a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 49403a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 49503a72c8eSMatthias Ringwald if (connection->role != role) continue; 49603a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != browsing_l2cap_cid)) continue; 49703a72c8eSMatthias Ringwald return connection; 49803a72c8eSMatthias Ringwald } 49903a72c8eSMatthias Ringwald return NULL; 50003a72c8eSMatthias Ringwald } 50103a72c8eSMatthias Ringwald 5021945fe3eSMilanka Ringwald avrcp_browsing_connection_t * avrcp_get_browsing_connection_for_l2cap_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){ 50303a72c8eSMatthias Ringwald btstack_linked_list_iterator_t it; 50465bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); 50503a72c8eSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 50603a72c8eSMatthias Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 50703a72c8eSMatthias Ringwald if (connection->role != role) continue; 50803a72c8eSMatthias Ringwald if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != l2cap_cid)) continue; 50903a72c8eSMatthias Ringwald return connection->browsing_connection; 51003a72c8eSMatthias Ringwald } 51103a72c8eSMatthias Ringwald return NULL; 51203a72c8eSMatthias Ringwald } 51303a72c8eSMatthias Ringwald 5146983e65eSMilanka Ringwald void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){ 515cf36dea0SMilanka Ringwald connection->wait_to_send = true; 5166983e65eSMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 5176983e65eSMilanka Ringwald } 5186983e65eSMilanka Ringwald 519298aeecdSMilanka Ringwald uint16_t avrcp_get_next_cid(avrcp_role_t role){ 520298aeecdSMilanka Ringwald do { 521298aeecdSMilanka Ringwald if (avrcp_cid_counter == 0xffff) { 5226983e65eSMilanka Ringwald avrcp_cid_counter = 1; 523298aeecdSMilanka Ringwald } else { 524298aeecdSMilanka Ringwald avrcp_cid_counter++; 5256983e65eSMilanka Ringwald } 5261945fe3eSMilanka Ringwald } while (avrcp_get_connection_for_avrcp_cid_for_role(role, avrcp_cid_counter) != NULL) ; 5276983e65eSMilanka Ringwald return avrcp_cid_counter; 5286983e65eSMilanka Ringwald } 5296983e65eSMilanka Ringwald 530638481deSMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){ 5316983e65eSMilanka Ringwald avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); 5324567cc17SMilanka Ringwald if (!connection){ 5330ec79bd0SMilanka Ringwald log_error("Not enough memory to create connection for role %d", role); 5344567cc17SMilanka Ringwald return NULL; 5354567cc17SMilanka Ringwald } 5360036e267SMilanka Ringwald 5376983e65eSMilanka Ringwald connection->state = AVCTP_CONNECTION_IDLE; 5380036e267SMilanka Ringwald connection->role = role; 539022b77fcSMilanka Ringwald 540022b77fcSMilanka Ringwald connection->transaction_id = 0xFF; 54123773c45SMilanka Ringwald connection->transaction_id_counter = 0; 542022b77fcSMilanka Ringwald 5433d73cc81SMilanka Ringwald connection->controller_max_num_fragments = 0xFF; 544f0af2234SMatthias Ringwald 545f0af2234SMatthias Ringwald // setup default unit / subunit info 546f0af2234SMatthias Ringwald connection->company_id = 0xffffff; 547393f5724SMilanka Ringwald connection->target_unit_type = AVRCP_SUBUNIT_TYPE_PANEL; 548393f5724SMilanka Ringwald connection->target_subunit_info_data_size = sizeof(avrcp_default_subunit_info); 549393f5724SMilanka Ringwald connection->target_subunit_info_data = avrcp_default_subunit_info; 550f0af2234SMatthias Ringwald 551c91f9817SMilanka Ringwald log_info("avrcp_create_connection, role %d", role); 5526535961aSMatthias Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 55365bd7af5SMatthias Ringwald btstack_linked_list_add(&avrcp_connections, (btstack_linked_item_t *) connection); 5546983e65eSMilanka Ringwald return connection; 5556983e65eSMilanka Ringwald } 5566983e65eSMilanka Ringwald 557638481deSMilanka Ringwald static void avrcp_finalize_connection(avrcp_connection_t * connection){ 55837fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 559*cf78f005SMilanka Ringwald btstack_run_loop_remove_timer(&connection->controller_press_and_hold_cmd_timer); 56065bd7af5SMatthias Ringwald btstack_linked_list_remove(&avrcp_connections, (btstack_linked_item_t*) connection); 56155e8029cSMatthias Ringwald btstack_memory_avrcp_connection_free(connection); 56255e8029cSMatthias Ringwald } 5636983e65eSMilanka Ringwald 5647dbc6cb8SMilanka Ringwald static void avrcp_emit_connection_established(uint16_t avrcp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status){ 565cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 566cee0e5b6SMilanka Ringwald 5677dbc6cb8SMilanka Ringwald uint8_t event[14]; 568b193c45eSMilanka Ringwald int pos = 0; 569b193c45eSMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 570b193c45eSMilanka Ringwald event[pos++] = sizeof(event) - 2; 571b193c45eSMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED; 5726f43fcd7SMatthias Ringwald event[pos++] = status; 5737dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 5747dbc6cb8SMilanka Ringwald pos += 2; 575b193c45eSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 576b193c45eSMilanka Ringwald pos += 6; 5777dbc6cb8SMilanka Ringwald little_endian_store_16(event, pos, con_handle); 578b193c45eSMilanka Ringwald pos += 2; 579cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 580b193c45eSMilanka Ringwald } 581b193c45eSMilanka Ringwald 582cee0e5b6SMilanka Ringwald static void avrcp_emit_connection_closed(uint16_t avrcp_cid){ 583cee0e5b6SMilanka Ringwald btstack_assert(avrcp_callback != NULL); 584cee0e5b6SMilanka Ringwald 585be32e7f1SMilanka Ringwald uint8_t event[5]; 586be32e7f1SMilanka Ringwald int pos = 0; 587be32e7f1SMilanka Ringwald event[pos++] = HCI_EVENT_AVRCP_META; 588be32e7f1SMilanka Ringwald event[pos++] = sizeof(event) - 2; 589be32e7f1SMilanka Ringwald event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED; 590b193c45eSMilanka Ringwald little_endian_store_16(event, pos, avrcp_cid); 591be32e7f1SMilanka Ringwald pos += 2; 592cee0e5b6SMilanka Ringwald (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 593be32e7f1SMilanka Ringwald } 594be32e7f1SMilanka Ringwald 5956d8f569dSMilanka Ringwald uint16_t avrcp_sdp_query_browsing_l2cap_psm(void){ 59665bd7af5SMatthias Ringwald return avrcp_sdp_query_context.browsing_l2cap_psm; 5974dc95c12SMatthias Ringwald } 5984dc95c12SMatthias Ringwald 5994dc95c12SMatthias Ringwald void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){ 6006086246cSMilanka Ringwald des_iterator_t des_list_it; 6016086246cSMilanka Ringwald des_iterator_t prot_it; 6026086246cSMilanka Ringwald 6036086246cSMilanka Ringwald // Handle new SDP record 60465bd7af5SMatthias Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != avrcp_sdp_query_context.record_id) { 60565bd7af5SMatthias Ringwald avrcp_sdp_query_context.record_id = sdp_event_query_attribute_byte_get_record_id(packet); 60665bd7af5SMatthias Ringwald avrcp_sdp_query_context.parse_sdp_record = 0; 6076086246cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 6086086246cSMilanka Ringwald } 6096086246cSMilanka Ringwald 61065bd7af5SMatthias Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= avrcp_sdp_query_attribute_value_buffer_size) { 61165bd7af5SMatthias Ringwald avrcp_sdp_query_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 6126086246cSMilanka Ringwald 6136086246cSMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 6146086246cSMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 6156086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 61665bd7af5SMatthias Ringwald if (de_get_element_type(avrcp_sdp_query_attribute_value) != DE_DES) break; 61765bd7af5SMatthias 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)) { 6186086246cSMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 6196086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 6206086246cSMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 6216086246cSMilanka Ringwald switch (uuid){ 6226086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET: 6236086246cSMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL: 624df642728SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER: 62565bd7af5SMatthias Ringwald avrcp_sdp_query_context.parse_sdp_record = 1; 6266086246cSMilanka Ringwald break; 6276086246cSMilanka Ringwald default: 6286086246cSMilanka Ringwald break; 6296086246cSMilanka Ringwald } 6306086246cSMilanka Ringwald } 6316086246cSMilanka Ringwald break; 6326086246cSMilanka Ringwald 6336086246cSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: { 63465bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.parse_sdp_record) break; 6356086246cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 63665bd7af5SMatthias 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)) { 6376086246cSMilanka Ringwald uint8_t *des_element; 6386086246cSMilanka Ringwald uint8_t *element; 6396086246cSMilanka Ringwald uint32_t uuid; 6406086246cSMilanka Ringwald 6416086246cSMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 6426086246cSMilanka Ringwald 6436086246cSMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 6446086246cSMilanka Ringwald des_iterator_init(&prot_it, des_element); 6456086246cSMilanka Ringwald element = des_iterator_get_element(&prot_it); 6466086246cSMilanka Ringwald 6476086246cSMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 6486086246cSMilanka Ringwald 6496086246cSMilanka Ringwald uuid = de_get_uuid32(element); 65014fd128cSMatthias Ringwald des_iterator_next(&prot_it); 6516086246cSMilanka Ringwald switch (uuid){ 6526086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 6536086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 65465bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.avrcp_l2cap_psm); 6556086246cSMilanka Ringwald break; 6566086246cSMilanka Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 6576086246cSMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 65865bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.avrcp_version); 6596086246cSMilanka Ringwald break; 6606086246cSMilanka Ringwald default: 6616086246cSMilanka Ringwald break; 6626086246cSMilanka Ringwald } 6636086246cSMilanka Ringwald } 6646086246cSMilanka Ringwald } 6656086246cSMilanka Ringwald break; 666227d16a5SMatthias Ringwald case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: { 667227d16a5SMatthias Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 66865bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.parse_sdp_record) break; 66965bd7af5SMatthias Ringwald if (de_get_element_type(avrcp_sdp_query_attribute_value) != DE_DES) break; 670227d16a5SMatthias Ringwald 671227d16a5SMatthias Ringwald des_iterator_t des_list_0_it; 672227d16a5SMatthias Ringwald uint8_t *element_0; 673227d16a5SMatthias Ringwald 67465bd7af5SMatthias Ringwald des_iterator_init(&des_list_0_it, avrcp_sdp_query_attribute_value); 675227d16a5SMatthias Ringwald element_0 = des_iterator_get_element(&des_list_0_it); 676227d16a5SMatthias Ringwald 677227d16a5SMatthias Ringwald for (des_iterator_init(&des_list_it, element_0); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 678227d16a5SMatthias Ringwald uint8_t *des_element; 679227d16a5SMatthias Ringwald uint8_t *element; 680227d16a5SMatthias Ringwald uint32_t uuid; 681227d16a5SMatthias Ringwald 682227d16a5SMatthias Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 683227d16a5SMatthias Ringwald 684227d16a5SMatthias Ringwald des_element = des_iterator_get_element(&des_list_it); 685227d16a5SMatthias Ringwald des_iterator_init(&prot_it, des_element); 686227d16a5SMatthias Ringwald element = des_iterator_get_element(&prot_it); 687227d16a5SMatthias Ringwald 688227d16a5SMatthias Ringwald if (de_get_element_type(element) != DE_UUID) continue; 689227d16a5SMatthias Ringwald 690227d16a5SMatthias Ringwald uuid = de_get_uuid32(element); 69114fd128cSMatthias Ringwald des_iterator_next(&prot_it); 692227d16a5SMatthias Ringwald switch (uuid){ 693227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 694227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 69565bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.browsing_l2cap_psm); 696227d16a5SMatthias Ringwald break; 697227d16a5SMatthias Ringwald case BLUETOOTH_PROTOCOL_AVCTP: 698227d16a5SMatthias Ringwald if (!des_iterator_has_more(&prot_it)) continue; 69965bd7af5SMatthias Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.browsing_version); 700227d16a5SMatthias Ringwald break; 701227d16a5SMatthias Ringwald default: 702227d16a5SMatthias Ringwald break; 703227d16a5SMatthias Ringwald } 704227d16a5SMatthias Ringwald } 705227d16a5SMatthias Ringwald } 706227d16a5SMatthias Ringwald break; 7076086246cSMilanka Ringwald default: 7086086246cSMilanka Ringwald break; 7096086246cSMilanka Ringwald } 7106086246cSMilanka Ringwald } 7116086246cSMilanka Ringwald } else { 71265bd7af5SMatthias 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)); 7136086246cSMilanka Ringwald } 7147b81669aSMatthias Ringwald } 7157b81669aSMatthias Ringwald 716463f41baSMilanka Ringwald static void avrcp_handle_sdp_query_failed(avrcp_connection_t * connection, uint8_t status){ 717b68672eaSMilanka Ringwald if (connection == NULL) return; 718463f41baSMilanka Ringwald log_info("AVRCP: SDP query failed with status 0x%02x.", status); 7197dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection->avrcp_cid, connection->remote_addr, connection->con_handle, status); 720463f41baSMilanka Ringwald avrcp_finalize_connection(connection); 721463f41baSMilanka Ringwald } 722463f41baSMilanka Ringwald 723a062fcddSMilanka Ringwald static void avrcp_handle_sdp_query_succeeded(avrcp_connection_t * connection){ 724b68672eaSMilanka Ringwald if (connection == NULL) return; 725463f41baSMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 72665bd7af5SMatthias Ringwald connection->avrcp_l2cap_psm = avrcp_sdp_query_context.avrcp_l2cap_psm; 72765bd7af5SMatthias Ringwald connection->browsing_version = avrcp_sdp_query_context.browsing_version; 72865bd7af5SMatthias Ringwald connection->browsing_l2cap_psm = avrcp_sdp_query_context.browsing_l2cap_psm; 729463f41baSMilanka Ringwald } 730463f41baSMilanka Ringwald 731a062fcddSMilanka Ringwald static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 73250fc39c5SMilanka Ringwald UNUSED(packet_type); 73350fc39c5SMilanka Ringwald UNUSED(channel); 73450fc39c5SMilanka Ringwald UNUSED(size); 73550fc39c5SMilanka Ringwald 7362423506bSMilanka Ringwald bool state_ok = true; 73765bd7af5SMatthias Ringwald avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_sdp_query_context.avrcp_cid); 7382423506bSMilanka Ringwald if (!avrcp_target_connection || avrcp_target_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 7392423506bSMilanka Ringwald state_ok = false; 74064a27ec5SMilanka Ringwald } 74165bd7af5SMatthias Ringwald avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_sdp_query_context.avrcp_cid); 7422423506bSMilanka Ringwald if (!avrcp_controller_connection || avrcp_controller_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) { 7432423506bSMilanka Ringwald state_ok = false; 7442423506bSMilanka Ringwald } 7452423506bSMilanka Ringwald if (!state_ok){ 7462423506bSMilanka Ringwald // something wrong, nevertheless, start next sdp query if this one is complete 7472423506bSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 74865bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 7492423506bSMilanka Ringwald } 75064a27ec5SMilanka Ringwald return; 75164a27ec5SMilanka Ringwald } 7527b81669aSMatthias Ringwald 7537b81669aSMatthias Ringwald uint8_t status; 7547b81669aSMatthias Ringwald 7557b81669aSMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 7567b81669aSMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 75750fc39c5SMilanka Ringwald avrcp_handle_sdp_client_query_attribute_value(packet); 7582423506bSMilanka Ringwald return; 7596086246cSMilanka Ringwald 76050fc39c5SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 7615448c259SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 762247956eaSMilanka Ringwald 7635448c259SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 764b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, status); 765b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, status); 7665448c259SMilanka Ringwald break; 7675448c259SMilanka Ringwald } 7685448c259SMilanka Ringwald 76965bd7af5SMatthias Ringwald if (!avrcp_sdp_query_context.avrcp_l2cap_psm){ 770b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_controller_connection, SDP_SERVICE_NOT_FOUND); 771b68672eaSMilanka Ringwald avrcp_handle_sdp_query_failed(avrcp_target_connection, SDP_SERVICE_NOT_FOUND); 7726983e65eSMilanka Ringwald break; 7736983e65eSMilanka Ringwald } 774be32e7f1SMilanka Ringwald 775a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_controller_connection); 776a062fcddSMilanka Ringwald avrcp_handle_sdp_query_succeeded(avrcp_target_connection); 777bd66227aSMilanka Ringwald 77865bd7af5SMatthias Ringwald l2cap_create_channel(&avrcp_packet_handler, avrcp_target_connection->remote_addr, avrcp_sdp_query_context.avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 779463f41baSMilanka Ringwald break; 78050fc39c5SMilanka Ringwald 78150fc39c5SMilanka Ringwald default: 7822423506bSMilanka Ringwald return; 7830036e267SMilanka Ringwald } 78464a27ec5SMilanka Ringwald 78564a27ec5SMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 78664a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 78765bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 788463f41baSMilanka Ringwald } 78950fc39c5SMilanka Ringwald 790be32e7f1SMilanka Ringwald 7917dbc6cb8SMilanka 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){ 792a062fcddSMilanka Ringwald if (connection == NULL){ 793a062fcddSMilanka Ringwald connection = avrcp_create_connection(role, event_addr); 794be32e7f1SMilanka Ringwald } 795a062fcddSMilanka Ringwald if (connection) { 7960f76c2d7SMatthias Ringwald connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 7970f76c2d7SMatthias Ringwald connection->l2cap_signaling_cid = local_cid; 7987403cbbaSMilanka Ringwald connection->avrcp_cid = avrcp_cid; 7997dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 80037fae987SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 801a062fcddSMilanka Ringwald } 802a062fcddSMilanka Ringwald return connection; 803654724deSMilanka Ringwald } 804be32e7f1SMilanka Ringwald 8057dbc6cb8SMilanka 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){ 806be32e7f1SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 8070036e267SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 8087dbc6cb8SMilanka Ringwald connection->con_handle = con_handle; 809558ceb4aSMilanka Ringwald connection->incoming_declined = false; 810393f5724SMilanka Ringwald connection->target_song_length_ms = 0xFFFFFFFF; 811393f5724SMilanka Ringwald connection->target_song_position_ms = 0xFFFFFFFF; 812f28ce84eSMilanka Ringwald memset(connection->target_track_id, 0xFF, 8); 813f28ce84eSMilanka Ringwald connection->target_track_selected = false; 8147d1b72e5SMilanka Ringwald connection->target_track_changed = false; 815393f5724SMilanka Ringwald connection->target_playback_status = AVRCP_PLAYBACK_STATUS_STOPPED; 816cee0e5b6SMilanka Ringwald connection->state = AVCTP_CONNECTION_OPENED; 817d1207cd8SMilanka Ringwald 81864a27ec5SMilanka 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); 8190036e267SMilanka Ringwald } 8200036e267SMilanka Ringwald 82137fae987SMilanka Ringwald static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 822a062fcddSMilanka Ringwald uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 8231945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 82414c8559dSMilanka Ringwald if (connection_controller == NULL) return; 8251945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 82614c8559dSMilanka Ringwald if (connection_target == NULL) return; 827a062fcddSMilanka Ringwald 82837fae987SMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W2_L2CAP_RETRY){ 82914c8559dSMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 83014c8559dSMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; 83114c8559dSMilanka Ringwald l2cap_create_channel(&avrcp_packet_handler, connection_controller->remote_addr, connection_controller->avrcp_l2cap_psm, l2cap_max_mtu(), NULL); 83214c8559dSMilanka Ringwald } 833a062fcddSMilanka Ringwald } 834a062fcddSMilanka Ringwald 83537fae987SMilanka Ringwald static void avrcp_retry_timer_start(avrcp_connection_t * connection){ 83637fae987SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avrcp_retry_timer_timeout_handler); 83737fae987SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avrcp_cid); 838a062fcddSMilanka Ringwald 839a062fcddSMilanka Ringwald // add some jitter/randomness to reconnect delay 840a062fcddSMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 84137fae987SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 842a062fcddSMilanka Ringwald 84337fae987SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 844a062fcddSMilanka Ringwald } 845a062fcddSMilanka Ringwald 846b8081399SMilanka Ringwald static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){ 847b8081399SMilanka Ringwald return (avrcp_frame_type_t)((header & 0x02) >> 1); 848b8081399SMilanka Ringwald } 849b8081399SMilanka Ringwald 8500036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 8510036e267SMilanka Ringwald UNUSED(channel); 8520036e267SMilanka Ringwald UNUSED(size); 8530036e267SMilanka Ringwald bd_addr_t event_addr; 8540036e267SMilanka Ringwald uint16_t local_cid; 8550036e267SMilanka Ringwald uint16_t l2cap_mtu; 8560036e267SMilanka Ringwald uint8_t status; 8579b1b0ebdSMatthias Ringwald bool decline_connection; 8589b1b0ebdSMatthias Ringwald bool outoing_active; 8597dbc6cb8SMilanka Ringwald hci_con_handle_t con_handle; 8600036e267SMilanka Ringwald 861cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_controller; 862cee0e5b6SMilanka Ringwald avrcp_connection_t * connection_target; 863bf67b2dbSMatthias Ringwald bool can_send; 864cee0e5b6SMilanka Ringwald 8650036e267SMilanka Ringwald switch (packet_type) { 8660036e267SMilanka Ringwald case HCI_EVENT_PACKET: 8670036e267SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 8680036e267SMilanka Ringwald 8690036e267SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 870e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 871e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 872e3d57ee2SMilanka Ringwald 8730036e267SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 8740036e267SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 8757dbc6cb8SMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 876cee0e5b6SMilanka Ringwald 8777dbc6cb8SMilanka Ringwald outoing_active = false; 8781945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 879cee0e5b6SMilanka Ringwald if (connection_target != NULL){ 880a062fcddSMilanka Ringwald if (connection_target->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){ 8819b1b0ebdSMatthias Ringwald outoing_active = true; 882cee0e5b6SMilanka Ringwald connection_target->incoming_declined = true; 8839b1b0ebdSMatthias Ringwald } 884a062fcddSMilanka Ringwald } 885558ceb4aSMilanka Ringwald 8861945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 887cee0e5b6SMilanka Ringwald if (connection_controller != NULL){ 888a062fcddSMilanka Ringwald if (connection_controller->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) { 8899b1b0ebdSMatthias Ringwald outoing_active = true; 890cee0e5b6SMilanka Ringwald connection_controller->incoming_declined = true; 8919b1b0ebdSMatthias Ringwald } 892a062fcddSMilanka Ringwald } 893558ceb4aSMilanka Ringwald 8949b1b0ebdSMatthias Ringwald decline_connection = outoing_active; 895a062fcddSMilanka Ringwald if (decline_connection == false){ 896a062fcddSMilanka Ringwald uint16_t avrcp_cid; 897a062fcddSMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)){ 898a062fcddSMilanka Ringwald avrcp_cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 899a062fcddSMilanka Ringwald } else { 900a062fcddSMilanka Ringwald avrcp_cid = connection_controller->avrcp_cid; 901a062fcddSMilanka Ringwald } 9020036e267SMilanka Ringwald // create two connection objects (both) 9037dbc6cb8SMilanka Ringwald connection_target = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, connection_target, event_addr, con_handle, local_cid, avrcp_cid); 9047dbc6cb8SMilanka Ringwald connection_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, connection_controller, event_addr, con_handle, local_cid, avrcp_cid); 905a062fcddSMilanka Ringwald if ((connection_target == NULL) || (connection_controller == NULL)){ 9069b1b0ebdSMatthias Ringwald decline_connection = true; 907a062fcddSMilanka Ringwald if (connection_target) { 908a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_target); 909a062fcddSMilanka Ringwald } 910a062fcddSMilanka Ringwald if (connection_controller) { 911a062fcddSMilanka Ringwald avrcp_finalize_connection(connection_controller); 912a062fcddSMilanka Ringwald } 9130036e267SMilanka Ringwald } 9149b1b0ebdSMatthias Ringwald } 9159b1b0ebdSMatthias Ringwald if (decline_connection){ 9169b1b0ebdSMatthias Ringwald l2cap_decline_connection(local_cid); 9179b1b0ebdSMatthias Ringwald } else { 91864a27ec5SMilanka Ringwald log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION local cid 0x%02x, state %d", local_cid, connection_controller->state); 9190036e267SMilanka Ringwald l2cap_accept_connection(local_cid); 9209b1b0ebdSMatthias Ringwald } 9210036e267SMilanka Ringwald break; 9220036e267SMilanka Ringwald 9230036e267SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 9240036e267SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 9250036e267SMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 9260036e267SMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 9270036e267SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 9287dbc6cb8SMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 9290036e267SMilanka Ringwald 9301945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr); 9311945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr); 932a062fcddSMilanka Ringwald 933a062fcddSMilanka Ringwald // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION 934a062fcddSMilanka Ringwald // outgoing: structs are cteated in avrcp_connect() 935cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 936cee0e5b6SMilanka Ringwald break; 937cee0e5b6SMilanka Ringwald } 938cee0e5b6SMilanka Ringwald 939a062fcddSMilanka Ringwald switch (status){ 940a062fcddSMilanka Ringwald case ERROR_CODE_SUCCESS: 9417dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_target, con_handle, local_cid, l2cap_mtu); 9427dbc6cb8SMilanka Ringwald avrcp_handle_open_connection(connection_controller, con_handle, local_cid, l2cap_mtu); 9437dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 944a062fcddSMilanka Ringwald return; 945a062fcddSMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 946a062fcddSMilanka Ringwald if (connection_controller->incoming_declined == true){ 947a062fcddSMilanka Ringwald log_info("Incoming connection was declined, and the outgoing failed"); 94837fae987SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 949a062fcddSMilanka Ringwald connection_controller->incoming_declined = false; 95037fae987SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_L2CAP_RETRY; 951a062fcddSMilanka Ringwald connection_target->incoming_declined = false; 95237fae987SMilanka Ringwald avrcp_retry_timer_start(connection_controller); 953a062fcddSMilanka Ringwald return; 954a062fcddSMilanka Ringwald } 955a062fcddSMilanka Ringwald break; 956a062fcddSMilanka Ringwald default: 957a062fcddSMilanka Ringwald break; 958a062fcddSMilanka Ringwald } 959cee0e5b6SMilanka Ringwald log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 9607dbc6cb8SMilanka Ringwald avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status); 961cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 962cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 963cee0e5b6SMilanka Ringwald 964be32e7f1SMilanka Ringwald break; 965be32e7f1SMilanka Ringwald 966be32e7f1SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 967be32e7f1SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 968cee0e5b6SMilanka Ringwald 9691945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 9701945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 971cee0e5b6SMilanka Ringwald if ((connection_controller == NULL) || (connection_target == NULL)) { 972cee0e5b6SMilanka Ringwald break; 973cee0e5b6SMilanka Ringwald } 974cee0e5b6SMilanka Ringwald avrcp_emit_connection_closed(connection_controller->avrcp_cid); 975cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_controller); 976cee0e5b6SMilanka Ringwald avrcp_finalize_connection(connection_target); 9770036e267SMilanka Ringwald break; 9780036e267SMilanka Ringwald 9790036e267SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 9800036e267SMilanka Ringwald local_cid = l2cap_event_can_send_now_get_local_cid(packet); 981bf67b2dbSMatthias Ringwald can_send = true; 982e3d57ee2SMilanka Ringwald 9831945fe3eSMilanka Ringwald connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid); 984cf36dea0SMilanka Ringwald if ((connection_target != NULL) && connection_target->wait_to_send){ 985cf36dea0SMilanka Ringwald connection_target->wait_to_send = false; 9860036e267SMilanka Ringwald (*avrcp_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 987bf67b2dbSMatthias Ringwald can_send = false; 9880036e267SMilanka Ringwald } 9890036e267SMilanka Ringwald 9901945fe3eSMilanka Ringwald connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid); 991cf36dea0SMilanka Ringwald if ((connection_controller != NULL) && connection_controller->wait_to_send){ 992bf67b2dbSMatthias Ringwald if (can_send){ 993cf36dea0SMilanka Ringwald connection_controller->wait_to_send = false; 9940036e267SMilanka Ringwald (*avrcp_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size); 995bf67b2dbSMatthias Ringwald } else { 996bf67b2dbSMatthias Ringwald l2cap_request_can_send_now_event(local_cid); 997bf67b2dbSMatthias Ringwald } 998be32e7f1SMilanka Ringwald } 999be32e7f1SMilanka Ringwald break; 10000036e267SMilanka Ringwald 1001be32e7f1SMilanka Ringwald default: 1002be32e7f1SMilanka Ringwald break; 1003be32e7f1SMilanka Ringwald } 1004b106f728SMilanka Ringwald break; 1005e3d57ee2SMilanka Ringwald 1006e3d57ee2SMilanka Ringwald case L2CAP_DATA_PACKET: 1007b8081399SMilanka Ringwald switch (avrcp_get_frame_type(packet[0])){ 1008e3d57ee2SMilanka Ringwald case AVRCP_RESPONSE_FRAME: 1009e3d57ee2SMilanka Ringwald (*avrcp_controller_packet_handler)(packet_type, channel, packet, size); 1010e3d57ee2SMilanka Ringwald break; 1011e3d57ee2SMilanka Ringwald case AVRCP_COMMAND_FRAME: 1012e3d57ee2SMilanka Ringwald default: // make compiler happy 1013e3d57ee2SMilanka Ringwald (*avrcp_target_packet_handler)(packet_type, channel, packet, size); 1014e3d57ee2SMilanka Ringwald break; 1015e3d57ee2SMilanka Ringwald } 1016e3d57ee2SMilanka Ringwald break; 1017e3d57ee2SMilanka Ringwald 1018b106f728SMilanka Ringwald default: 1019b106f728SMilanka Ringwald break; 1020b106f728SMilanka Ringwald } 1021be32e7f1SMilanka Ringwald } 1022be32e7f1SMilanka Ringwald 1023fe10780bSMilanka Ringwald uint8_t avrcp_disconnect(uint16_t avrcp_cid){ 10241945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid); 1025fe10780bSMilanka Ringwald if (!connection_controller){ 1026fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1027fe10780bSMilanka Ringwald } 10281945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid); 1029fe10780bSMilanka Ringwald if (!connection_target){ 1030fe10780bSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1031fe10780bSMilanka Ringwald } 1032fe10780bSMilanka Ringwald if (connection_controller->browsing_connection){ 1033b93f8966SMatthias Ringwald l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid); 1034fe10780bSMilanka Ringwald } 1035b93f8966SMatthias Ringwald l2cap_disconnect(connection_controller->l2cap_signaling_cid); 1036fe10780bSMilanka Ringwald return ERROR_CODE_SUCCESS; 1037fe10780bSMilanka Ringwald } 1038fe10780bSMilanka Ringwald 103964a27ec5SMilanka Ringwald static void avrcp_handle_start_sdp_client_query(void * context){ 104064a27ec5SMilanka Ringwald UNUSED(context); 10414dc95c12SMatthias Ringwald 104264a27ec5SMilanka Ringwald btstack_linked_list_iterator_t it; 104365bd7af5SMatthias Ringwald btstack_linked_list_iterator_init(&it, &avrcp_connections); 104464a27ec5SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 104564a27ec5SMilanka Ringwald avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); 104664a27ec5SMilanka Ringwald 104764a27ec5SMilanka Ringwald if (connection->state != AVCTP_CONNECTION_W2_SEND_SDP_QUERY) continue; 104864a27ec5SMilanka Ringwald connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 104964a27ec5SMilanka Ringwald 105064a27ec5SMilanka Ringwald // prevent triggering SDP query twice (for each role once) 105164a27ec5SMilanka Ringwald avrcp_connection_t * connection_with_opposite_role; 105264a27ec5SMilanka Ringwald switch (connection->role){ 105364a27ec5SMilanka Ringwald case AVRCP_CONTROLLER: 105464a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid); 105564a27ec5SMilanka Ringwald break; 105664a27ec5SMilanka Ringwald case AVRCP_TARGET: 105764a27ec5SMilanka Ringwald connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid); 105864a27ec5SMilanka Ringwald break; 105964a27ec5SMilanka Ringwald default: 106064a27ec5SMilanka Ringwald btstack_assert(false); 106164a27ec5SMilanka Ringwald return; 106264a27ec5SMilanka Ringwald } 106364a27ec5SMilanka Ringwald connection_with_opposite_role->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE; 106464a27ec5SMilanka Ringwald 106565bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_l2cap_psm = 0; 106665bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_version = 0; 106765bd7af5SMatthias Ringwald avrcp_sdp_query_context.avrcp_cid = connection->avrcp_cid; 106864a27ec5SMilanka Ringwald sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP); 106964a27ec5SMilanka Ringwald return; 107064a27ec5SMilanka Ringwald } 10714dc95c12SMatthias Ringwald } 10724dc95c12SMatthias Ringwald 1073fe10780bSMilanka Ringwald uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){ 1074e3d57ee2SMilanka Ringwald btstack_assert(avrcp_controller_packet_handler != NULL); 1075e3d57ee2SMilanka Ringwald btstack_assert(avrcp_target_packet_handler != NULL); 1076f9ef80eaSMilanka Ringwald 10771945fe3eSMilanka Ringwald avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr); 1078bd66227aSMilanka Ringwald if (connection_controller){ 1079bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1080bd66227aSMilanka Ringwald } 10811945fe3eSMilanka Ringwald avrcp_connection_t * connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr); 1082bd66227aSMilanka Ringwald if (connection_target){ 1083bd66227aSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1084bd66227aSMilanka Ringwald } 1085bd66227aSMilanka Ringwald 10867403cbbaSMilanka Ringwald uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER); 10877403cbbaSMilanka Ringwald 1088bd66227aSMilanka Ringwald connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 1089bd66227aSMilanka Ringwald if (!connection_controller) return BTSTACK_MEMORY_ALLOC_FAILED; 1090bd66227aSMilanka Ringwald 1091bd66227aSMilanka Ringwald connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 1092bd66227aSMilanka Ringwald if (!connection_target){ 1093bd66227aSMilanka Ringwald avrcp_finalize_connection(connection_controller); 1094bd66227aSMilanka Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 1095bd66227aSMilanka Ringwald } 1096bd66227aSMilanka Ringwald 1097bd66227aSMilanka Ringwald if (avrcp_cid != NULL){ 1098bd66227aSMilanka Ringwald *avrcp_cid = cid; 1099bd66227aSMilanka Ringwald } 1100bd66227aSMilanka Ringwald 110164a27ec5SMilanka Ringwald connection_controller->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 11027403cbbaSMilanka Ringwald connection_controller->avrcp_cid = cid; 11037403cbbaSMilanka Ringwald 110464a27ec5SMilanka Ringwald connection_target->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY; 11057403cbbaSMilanka Ringwald connection_target->avrcp_cid = cid; 11065dd5e7e3SMilanka Ringwald 110765bd7af5SMatthias Ringwald avrcp_sdp_query_registration.callback = &avrcp_handle_start_sdp_client_query; 110864a27ec5SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 110965bd7af5SMatthias Ringwald (void) sdp_client_register_query_callback(&avrcp_sdp_query_registration); 111064a27ec5SMilanka Ringwald return ERROR_CODE_SUCCESS; 1111be32e7f1SMilanka Ringwald } 1112638481deSMilanka Ringwald 1113638481deSMilanka Ringwald void avrcp_init(void){ 111465bd7af5SMatthias Ringwald avrcp_connections = NULL; 111565bd7af5SMatthias Ringwald if (avrcp_l2cap_service_registered) return; 11160036e267SMilanka Ringwald 111778315a58SMatthias Ringwald int status = l2cap_register_service(&avrcp_packet_handler, BLUETOOTH_PSM_AVCTP, 0xffff, gap_get_security_level()); 1118b106f728SMilanka Ringwald if (status != ERROR_CODE_SUCCESS) return; 111965bd7af5SMatthias Ringwald avrcp_l2cap_service_registered = true; 1120638481deSMilanka Ringwald } 1121b106f728SMilanka Ringwald 1122680af5dcSMatthias Ringwald void avrcp_deinit(void){ 112365bd7af5SMatthias Ringwald avrcp_l2cap_service_registered = false; 1124680af5dcSMatthias Ringwald 112565bd7af5SMatthias Ringwald avrcp_cid_counter = 0; 112665bd7af5SMatthias Ringwald avrcp_connections = NULL; 1127680af5dcSMatthias Ringwald 1128680af5dcSMatthias Ringwald avrcp_callback = NULL; 1129680af5dcSMatthias Ringwald avrcp_controller_packet_handler = NULL; 1130680af5dcSMatthias Ringwald avrcp_target_packet_handler = NULL; 113165bd7af5SMatthias Ringwald 113265bd7af5SMatthias Ringwald (void) memset(&avrcp_sdp_query_registration, 0, sizeof(avrcp_sdp_query_registration)); 113365bd7af5SMatthias Ringwald (void) memset(&avrcp_sdp_query_context, 0, sizeof(avrcp_sdp_query_context_t)); 113465bd7af5SMatthias Ringwald (void) memset(avrcp_sdp_query_attribute_value, 0, sizeof(avrcp_sdp_query_attribute_value)); 1135680af5dcSMatthias Ringwald } 1136680af5dcSMatthias Ringwald 1137b106f728SMilanka Ringwald void avrcp_register_controller_packet_handler(btstack_packet_handler_t callback){ 1138b106f728SMilanka Ringwald avrcp_controller_packet_handler = callback; 1139b106f728SMilanka Ringwald } 1140b106f728SMilanka Ringwald 1141b106f728SMilanka Ringwald void avrcp_register_target_packet_handler(btstack_packet_handler_t callback){ 1142b106f728SMilanka Ringwald avrcp_target_packet_handler = callback; 1143b106f728SMilanka Ringwald } 1144b106f728SMilanka Ringwald 1145cee0e5b6SMilanka Ringwald void avrcp_register_packet_handler(btstack_packet_handler_t callback){ 1146cee0e5b6SMilanka Ringwald btstack_assert(callback != NULL); 1147cee0e5b6SMilanka Ringwald avrcp_callback = callback; 1148cee0e5b6SMilanka Ringwald } 1149697b823eSMatthias Ringwald 1150697b823eSMatthias Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 1151697b823eSMatthias Ringwald #define FUZZ_CID 0x44 11523cd982f4SMatthias Ringwald #define FUZZ_CON_HANDLE 0x0001 1153697b823eSMatthias Ringwald static bd_addr_t remote_addr = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 }; 1154697b823eSMatthias Ringwald void avrcp_init_fuzz(void){ 1155697b823eSMatthias Ringwald // setup avrcp connections for cid 1156697b823eSMatthias Ringwald avrcp_connection_t * connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr); 1157697b823eSMatthias Ringwald avrcp_connection_t * connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr); 11583cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_controller, FUZZ_CON_HANDLE, FUZZ_CID, 999); 11593cd982f4SMatthias Ringwald avrcp_handle_open_connection(connection_target, FUZZ_CON_HANDLE, FUZZ_CID, 999); 1160697b823eSMatthias Ringwald } 1161697b823eSMatthias Ringwald void avrcp_packet_handler_fuzz(uint8_t *packet, uint16_t size){ 1162697b823eSMatthias Ringwald avrcp_packet_handler(L2CAP_DATA_PACKET, FUZZ_CID, packet, size); 1163697b823eSMatthias Ringwald } 1164697b823eSMatthias Ringwald #endif