xref: /btstack/src/classic/avrcp.c (revision 6eafac075caab72daf837e35c110a04d5197c203)
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);
677a3e6573SMatthias Ringwald static void avrcp_start_next_sdp_query(void);
680036e267SMilanka Ringwald 
6965bd7af5SMatthias Ringwald static const char * avrcp_default_controller_service_name = "BTstack AVRCP Controller Service";
7065bd7af5SMatthias Ringwald static const char * avrcp_default_controller_service_provider_name = "BTstack AVRCP Controller Service Provider";
7165bd7af5SMatthias Ringwald static const char * avrcp_defaul_target_service_name = "BTstack AVRCP Target Service";
7265bd7af5SMatthias Ringwald static const char * avrcp_default_target_service_provider_name = "BTstack AVRCP Target Service Provider";
730eebc132SMilanka Ringwald 
74be32e7f1SMilanka Ringwald static const char * avrcp_subunit_type_name[] = {
75be32e7f1SMilanka Ringwald         "MONITOR", "AUDIO", "PRINTER", "DISC", "TAPE_RECORDER_PLAYER", "TUNER",
76be32e7f1SMilanka Ringwald         "CA", "CAMERA", "RESERVED", "PANEL", "BULLETIN_BOARD", "CAMERA_STORAGE",
77be32e7f1SMilanka Ringwald         "VENDOR_UNIQUE", "RESERVED_FOR_ALL_SUBUNIT_TYPES",
78be32e7f1SMilanka Ringwald         "EXTENDED_TO_NEXT_BYTE", "UNIT", "ERROR"
79be32e7f1SMilanka Ringwald };
806983e65eSMilanka Ringwald 
8165bd7af5SMatthias Ringwald // default subunit info: single PANEL subunit
8265bd7af5SMatthias Ringwald static const uint8_t avrcp_default_subunit_info[] = { AVRCP_SUBUNIT_TYPE_PANEL << 3};
8365bd7af5SMatthias Ringwald 
8465bd7af5SMatthias Ringwald // globals
8565bd7af5SMatthias Ringwald static bool avrcp_l2cap_service_registered = false;
8665bd7af5SMatthias Ringwald 
8765bd7af5SMatthias Ringwald // connections
8865bd7af5SMatthias Ringwald static uint16_t                 avrcp_cid_counter;
8965bd7af5SMatthias Ringwald static btstack_linked_list_t    avrcp_connections;
9065bd7af5SMatthias Ringwald 
9165bd7af5SMatthias Ringwald // higher layer callbacks
9265bd7af5SMatthias Ringwald static btstack_packet_handler_t avrcp_callback;
9365bd7af5SMatthias Ringwald static btstack_packet_handler_t avrcp_controller_packet_handler;
9465bd7af5SMatthias Ringwald static btstack_packet_handler_t avrcp_target_packet_handler;
9565bd7af5SMatthias Ringwald 
9665bd7af5SMatthias Ringwald // sdp query
9765bd7af5SMatthias Ringwald static btstack_context_callback_registration_t avrcp_sdp_query_registration;
9865bd7af5SMatthias Ringwald static avrcp_sdp_query_context_t               avrcp_sdp_query_context;
9965bd7af5SMatthias Ringwald static uint8_t                                 avrcp_sdp_query_attribute_value[45];
10065bd7af5SMatthias Ringwald static const unsigned int                      avrcp_sdp_query_attribute_value_buffer_size = sizeof(avrcp_sdp_query_attribute_value);
10165bd7af5SMatthias Ringwald 
10211256635SMatthias Ringwald static void (*avrcp_browsing_sdp_query_complete_handler)(avrcp_connection_t * connection, uint8_t status);
10311256635SMatthias Ringwald 
10465bd7af5SMatthias Ringwald 
105be32e7f1SMilanka Ringwald const char * avrcp_subunit2str(uint16_t index){
106be32e7f1SMilanka Ringwald     if (index <= 11) return avrcp_subunit_type_name[index];
1070e588213SMatthias Ringwald     if ((index >= 0x1C) && (index <= 0x1F)) return avrcp_subunit_type_name[index - 0x10];
108be32e7f1SMilanka Ringwald     return avrcp_subunit_type_name[16];
109be32e7f1SMilanka Ringwald }
110be32e7f1SMilanka Ringwald 
111be32e7f1SMilanka Ringwald static const char * avrcp_event_name[] = {
112be32e7f1SMilanka Ringwald     "ERROR", "PLAYBACK_STATUS_CHANGED",
113be32e7f1SMilanka Ringwald     "TRACK_CHANGED", "TRACK_REACHED_END", "TRACK_REACHED_START",
114be32e7f1SMilanka Ringwald     "PLAYBACK_POS_CHANGED", "BATT_STATUS_CHANGED", "SYSTEM_STATUS_CHANGED",
115be32e7f1SMilanka Ringwald     "PLAYER_APPLICATION_SETTING_CHANGED", "NOW_PLAYING_CONTENT_CHANGED",
116be32e7f1SMilanka Ringwald     "AVAILABLE_PLAYERS_CHANGED", "ADDRESSED_PLAYER_CHANGED", "UIDS_CHANGED", "VOLUME_CHANGED"
117be32e7f1SMilanka Ringwald };
118be32e7f1SMilanka Ringwald const char * avrcp_event2str(uint16_t index){
119be32e7f1SMilanka Ringwald     if (index <= 0x0d) return avrcp_event_name[index];
120be32e7f1SMilanka Ringwald     return avrcp_event_name[0];
121be32e7f1SMilanka Ringwald }
122be32e7f1SMilanka Ringwald 
123be32e7f1SMilanka Ringwald static const char * avrcp_operation_name[] = {
124ce66cc7aSMilanka Ringwald     "SKIP", NULL, NULL, NULL, NULL,
125ce66cc7aSMilanka Ringwald     "VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", NULL,
126ce66cc7aSMilanka Ringwald     "REWIND", "FAST_FORWARD", NULL, "FORWARD", "BACKWARD" // 0x4C
127be32e7f1SMilanka Ringwald };
1280b578d06SMilanka Ringwald 
1290b578d06SMilanka Ringwald const char * avrcp_operation2str(uint8_t operation_id){
130ce66cc7aSMilanka Ringwald     char * name = NULL;
1310b578d06SMilanka Ringwald     if ((operation_id >= AVRCP_OPERATION_ID_SKIP) && (operation_id <= AVRCP_OPERATION_ID_BACKWARD)){
1320b578d06SMilanka Ringwald         name = (char *)avrcp_operation_name[operation_id - AVRCP_OPERATION_ID_SKIP];
133ce66cc7aSMilanka Ringwald     }
134ce66cc7aSMilanka Ringwald     if (name == NULL){
135ce66cc7aSMilanka Ringwald         static char buffer[13];
1360b578d06SMilanka Ringwald         snprintf(buffer, sizeof(buffer), "Unknown 0x%02x", operation_id);
137ce66cc7aSMilanka Ringwald         buffer[sizeof(buffer)-1] = 0;
138ce66cc7aSMilanka Ringwald         return buffer;
139ce66cc7aSMilanka Ringwald     } else {
140ce66cc7aSMilanka Ringwald         return name;
141ce66cc7aSMilanka Ringwald     }
142be32e7f1SMilanka Ringwald }
143be32e7f1SMilanka Ringwald 
144be32e7f1SMilanka Ringwald static const char * avrcp_media_attribute_id_name[] = {
145be32e7f1SMilanka Ringwald     "NONE", "TITLE", "ARTIST", "ALBUM", "TRACK", "TOTAL TRACKS", "GENRE", "SONG LENGTH"
146be32e7f1SMilanka Ringwald };
147be32e7f1SMilanka Ringwald const char * avrcp_attribute2str(uint8_t index){
1484c7a1d3aSMatthias Ringwald     if (index > 7){
1494c7a1d3aSMatthias Ringwald         index = 0;
1504c7a1d3aSMatthias Ringwald     }
151be32e7f1SMilanka Ringwald     return avrcp_media_attribute_id_name[0];
152be32e7f1SMilanka Ringwald }
153be32e7f1SMilanka Ringwald 
154be32e7f1SMilanka Ringwald static const char * avrcp_play_status_name[] = {
155be32e7f1SMilanka Ringwald     "STOPPED", "PLAYING", "PAUSED", "FORWARD SEEK", "REVERSE SEEK",
156be32e7f1SMilanka Ringwald     "ERROR" // 0xFF
157be32e7f1SMilanka Ringwald };
158be32e7f1SMilanka Ringwald const char * avrcp_play_status2str(uint8_t index){
15912448779SMatthias Ringwald     if (index > 4){
1604c7a1d3aSMatthias Ringwald         index = 5;
161be32e7f1SMilanka Ringwald     }
16212448779SMatthias Ringwald     return avrcp_play_status_name[index];
16312448779SMatthias Ringwald }
164be32e7f1SMilanka Ringwald 
165be32e7f1SMilanka Ringwald static const char * avrcp_ctype_name[] = {
166be32e7f1SMilanka Ringwald     "CONTROL",
167be32e7f1SMilanka Ringwald     "STATUS",
168be32e7f1SMilanka Ringwald     "SPECIFIC_INQUIRY",
169be32e7f1SMilanka Ringwald     "NOTIFY",
170be32e7f1SMilanka Ringwald     "GENERAL_INQUIRY",
171be32e7f1SMilanka Ringwald     "RESERVED5",
172be32e7f1SMilanka Ringwald     "RESERVED6",
173be32e7f1SMilanka Ringwald     "RESERVED7",
1749cc1f3ceSMilanka Ringwald     "NOT IMPLEMENTED IN REMOTE",
1759cc1f3ceSMilanka Ringwald     "ACCEPTED BY REMOTE",
1769cc1f3ceSMilanka Ringwald     "REJECTED BY REMOTE",
177be32e7f1SMilanka Ringwald     "IN_TRANSITION",
178be32e7f1SMilanka Ringwald     "IMPLEMENTED_STABLE",
179be32e7f1SMilanka Ringwald     "CHANGED_STABLE",
180be32e7f1SMilanka Ringwald     "RESERVED",
181be32e7f1SMilanka Ringwald     "INTERIM"
182be32e7f1SMilanka Ringwald };
1837d1b72e5SMilanka Ringwald static const uint16_t avrcp_ctype_name_num = 16;
184447150e4SMilanka Ringwald 
185be32e7f1SMilanka Ringwald const char * avrcp_ctype2str(uint8_t index){
186447150e4SMilanka Ringwald     if (index < avrcp_ctype_name_num){
187be32e7f1SMilanka Ringwald         return avrcp_ctype_name[index];
188be32e7f1SMilanka Ringwald     }
189be32e7f1SMilanka Ringwald     return "NONE";
190be32e7f1SMilanka Ringwald }
191be32e7f1SMilanka Ringwald 
192be32e7f1SMilanka Ringwald static const char * avrcp_shuffle_mode_name[] = {
193be32e7f1SMilanka Ringwald     "SHUFFLE OFF",
194be32e7f1SMilanka Ringwald     "SHUFFLE ALL TRACKS",
195be32e7f1SMilanka Ringwald     "SHUFFLE GROUP"
196be32e7f1SMilanka Ringwald };
197be32e7f1SMilanka Ringwald 
198be32e7f1SMilanka Ringwald const char * avrcp_shuffle2str(uint8_t index){
199c1ab6cc1SMatthias Ringwald     if ((index >= 1) && (index <= 3)) return avrcp_shuffle_mode_name[index-1];
200be32e7f1SMilanka Ringwald     return "NONE";
201be32e7f1SMilanka Ringwald }
202be32e7f1SMilanka Ringwald 
203be32e7f1SMilanka Ringwald static const char * avrcp_repeat_mode_name[] = {
204be32e7f1SMilanka Ringwald     "REPEAT OFF",
205be32e7f1SMilanka Ringwald     "REPEAT SINGLE TRACK",
206be32e7f1SMilanka Ringwald     "REPEAT ALL TRACKS",
207be32e7f1SMilanka Ringwald     "REPEAT GROUP"
208be32e7f1SMilanka Ringwald };
209be32e7f1SMilanka Ringwald 
210be32e7f1SMilanka Ringwald const char * avrcp_repeat2str(uint8_t index){
211c1ab6cc1SMatthias Ringwald     if ((index >= 1) && (index <= 4)) return avrcp_repeat_mode_name[index-1];
212be32e7f1SMilanka Ringwald     return "NONE";
213be32e7f1SMilanka Ringwald }
2146086246cSMilanka Ringwald 
2156fb6f866SMilanka Ringwald static const char * notification_name[] = {
2166fb6f866SMilanka Ringwald     "INVALID_INDEX",
2176fb6f866SMilanka Ringwald     "PLAYBACK_STATUS_CHANGED",
2186fb6f866SMilanka Ringwald     "TRACK_CHANGED",
2196fb6f866SMilanka Ringwald     "TRACK_REACHED_END",
2206fb6f866SMilanka Ringwald     "TRACK_REACHED_START",
2216fb6f866SMilanka Ringwald     "PLAYBACK_POS_CHANGED",
2226fb6f866SMilanka Ringwald     "BATT_STATUS_CHANGED",
2236fb6f866SMilanka Ringwald     "SYSTEM_STATUS_CHANGED",
2246fb6f866SMilanka Ringwald     "PLAYER_APPLICATION_SETTING_CHANGED",
2256fb6f866SMilanka Ringwald     "NOW_PLAYING_CONTENT_CHANGED",
2266fb6f866SMilanka Ringwald     "AVAILABLE_PLAYERS_CHANGED",
2276fb6f866SMilanka Ringwald     "ADDRESSED_PLAYER_CHANGED",
2286fb6f866SMilanka Ringwald     "UIDS_CHANGED",
2296fb6f866SMilanka Ringwald     "VOLUME_CHANGED",
2306fb6f866SMilanka Ringwald     "MAX_VALUE"
2316fb6f866SMilanka Ringwald };
2326fb6f866SMilanka Ringwald 
2336fb6f866SMilanka Ringwald const char * avrcp_notification2str(avrcp_notification_event_id_t index){
2346fb6f866SMilanka Ringwald     if ((index >= AVRCP_NOTIFICATION_EVENT_FIRST_INDEX) && (index <= AVRCP_NOTIFICATION_EVENT_LAST_INDEX)){
2356fb6f866SMilanka Ringwald         return notification_name[index];
2366fb6f866SMilanka Ringwald     }
2376fb6f866SMilanka Ringwald     return notification_name[0];
2386fb6f866SMilanka Ringwald }
2396fb6f866SMilanka Ringwald 
24064a27ec5SMilanka Ringwald btstack_linked_list_t avrcp_get_connections(void){
24165bd7af5SMatthias Ringwald     return avrcp_connections;
24264a27ec5SMilanka Ringwald }
24364a27ec5SMilanka Ringwald 
2444b338011SMilanka Ringwald uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){
2454b338011SMilanka Ringwald     uint8_t cmd_opcode_index = 5;
2464b338011SMilanka Ringwald     if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED;
2474b338011SMilanka Ringwald     return packet[cmd_opcode_index];
2484b338011SMilanka Ringwald }
2494b338011SMilanka Ringwald 
250654724deSMilanka Ringwald void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features,
251654724deSMilanka Ringwald     const char * service_name, const char * service_provider_name){
252be32e7f1SMilanka Ringwald     uint8_t* attribute;
253be32e7f1SMilanka Ringwald     de_create_sequence(service);
254be32e7f1SMilanka Ringwald 
255be32e7f1SMilanka Ringwald     // 0x0000 "Service Record Handle"
256235946f1SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
257be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
258be32e7f1SMilanka Ringwald 
259be32e7f1SMilanka Ringwald     // 0x0001 "Service Class ID List"
260235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
261be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
262be32e7f1SMilanka Ringwald     {
263be32e7f1SMilanka Ringwald         if (controller){
2646086246cSMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL);
2656086246cSMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER);
266be32e7f1SMilanka Ringwald         } else {
2676086246cSMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET);
268be32e7f1SMilanka Ringwald         }
269be32e7f1SMilanka Ringwald     }
270be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
271be32e7f1SMilanka Ringwald 
272be32e7f1SMilanka Ringwald     // 0x0004 "Protocol Descriptor List"
273235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
274be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
275be32e7f1SMilanka Ringwald     {
276be32e7f1SMilanka Ringwald         uint8_t* l2cpProtocol = de_push_sequence(attribute);
277be32e7f1SMilanka Ringwald         {
278235946f1SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
27984e3541eSMilanka Ringwald             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP);
280be32e7f1SMilanka Ringwald         }
281be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, l2cpProtocol);
282be32e7f1SMilanka Ringwald 
283be32e7f1SMilanka Ringwald         uint8_t* avctpProtocol = de_push_sequence(attribute);
284be32e7f1SMilanka Ringwald         {
285235946f1SMatthias Ringwald             de_add_number(avctpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP);  // avctpProtocol_service
2860b322400SMilanka Ringwald             de_add_number(avctpProtocol,  DE_UINT, DE_SIZE_16,  0x0104);    // version
287be32e7f1SMilanka Ringwald         }
288be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, avctpProtocol);
289be32e7f1SMilanka Ringwald     }
290be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
291be32e7f1SMilanka Ringwald 
292be32e7f1SMilanka Ringwald     // 0x0005 "Public Browse Group"
293235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
294be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
295be32e7f1SMilanka Ringwald     {
296235946f1SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
297be32e7f1SMilanka Ringwald     }
298be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
299be32e7f1SMilanka Ringwald 
300be32e7f1SMilanka Ringwald     // 0x0009 "Bluetooth Profile Descriptor List"
301235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
302be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
303be32e7f1SMilanka Ringwald     {
304be32e7f1SMilanka Ringwald         uint8_t *avrcProfile = de_push_sequence(attribute);
305be32e7f1SMilanka Ringwald         {
3066086246cSMilanka Ringwald             de_add_number(avrcProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL);
3070b322400SMilanka Ringwald             de_add_number(avrcProfile,  DE_UINT, DE_SIZE_16, 0x0106);
308be32e7f1SMilanka Ringwald         }
309be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, avrcProfile);
310be32e7f1SMilanka Ringwald     }
311be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
312be32e7f1SMilanka Ringwald 
313a0f524f0SMatthias Ringwald     // 0x000d "Additional Bluetooth Profile Descriptor List"
3145c806868SMatthias Ringwald     if (browsing){
315a0f524f0SMatthias Ringwald         de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS);
316a0f524f0SMatthias Ringwald         attribute = de_push_sequence(service);
3175c806868SMatthias Ringwald         {
3185c806868SMatthias Ringwald             uint8_t * des = de_push_sequence(attribute);
3195c806868SMatthias Ringwald             {
3205c806868SMatthias Ringwald                 uint8_t* browsing_l2cpProtocol = de_push_sequence(des);
321a0f524f0SMatthias Ringwald                 {
322a0f524f0SMatthias Ringwald                     de_add_number(browsing_l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
32384e3541eSMilanka Ringwald                     de_add_number(browsing_l2cpProtocol,  DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP_BROWSING);
324a0f524f0SMatthias Ringwald                 }
3255c806868SMatthias Ringwald                 de_pop_sequence(des, browsing_l2cpProtocol);
326a0f524f0SMatthias Ringwald 
3275c806868SMatthias Ringwald                 uint8_t* browsing_avctpProtocol = de_push_sequence(des);
328a0f524f0SMatthias Ringwald                 {
329a0f524f0SMatthias Ringwald                     de_add_number(browsing_avctpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP);  // browsing_avctpProtocol_service
3300b322400SMilanka Ringwald                     de_add_number(browsing_avctpProtocol,  DE_UINT, DE_SIZE_16, 0x0104);                   // version
331a0f524f0SMatthias Ringwald                 }
3325c806868SMatthias Ringwald                 de_pop_sequence(des, browsing_avctpProtocol);
3335c806868SMatthias Ringwald             }
3345c806868SMatthias Ringwald             de_pop_sequence(attribute, des);
335a0f524f0SMatthias Ringwald         }
336a0f524f0SMatthias Ringwald         de_pop_sequence(service, attribute);
3375c806868SMatthias Ringwald     }
338a0f524f0SMatthias Ringwald 
339be32e7f1SMilanka Ringwald 
340be32e7f1SMilanka Ringwald     // 0x0100 "Service Name"
341be32e7f1SMilanka Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
342be32e7f1SMilanka Ringwald     if (service_name){
343ab2445a0SMatthias Ringwald         de_add_data(service,  DE_STRING, (uint16_t) strlen(service_name), (uint8_t *) service_name);
344be32e7f1SMilanka Ringwald     } else {
345be32e7f1SMilanka Ringwald         if (controller){
346ab2445a0SMatthias Ringwald             de_add_data(service, DE_STRING, (uint16_t) strlen(avrcp_default_controller_service_name), (uint8_t *) avrcp_default_controller_service_name);
347be32e7f1SMilanka Ringwald         } else {
348ab2445a0SMatthias Ringwald             de_add_data(service, DE_STRING, (uint16_t) strlen(avrcp_defaul_target_service_name), (uint8_t *) avrcp_defaul_target_service_name);
349be32e7f1SMilanka Ringwald         }
350be32e7f1SMilanka Ringwald     }
351be32e7f1SMilanka Ringwald 
352be32e7f1SMilanka Ringwald     // 0x0100 "Provider Name"
353be32e7f1SMilanka Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0102);
354be32e7f1SMilanka Ringwald     if (service_provider_name){
355ab2445a0SMatthias Ringwald         de_add_data(service,  DE_STRING, (uint16_t) strlen(service_provider_name), (uint8_t *) service_provider_name);
356be32e7f1SMilanka Ringwald     } else {
357be32e7f1SMilanka Ringwald         if (controller){
358ab2445a0SMatthias Ringwald             de_add_data(service, DE_STRING, (uint16_t) strlen(avrcp_default_controller_service_provider_name), (uint8_t *) avrcp_default_controller_service_provider_name);
359be32e7f1SMilanka Ringwald         } else {
360ab2445a0SMatthias Ringwald             de_add_data(service, DE_STRING, (uint16_t) strlen(avrcp_default_target_service_provider_name), (uint8_t *) avrcp_default_target_service_provider_name);
361be32e7f1SMilanka Ringwald         }
362be32e7f1SMilanka Ringwald     }
363be32e7f1SMilanka Ringwald 
364be32e7f1SMilanka Ringwald     // 0x0311 "Supported Features"
365be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);
366be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
367be32e7f1SMilanka Ringwald }
368be32e7f1SMilanka Ringwald 
369aeb99916SMilanka Ringwald uint16_t avctp_get_num_bytes_for_header(avctp_packet_type_t avctp_packet_type) {
37066b242bbSMilanka Ringwald     switch (avctp_packet_type){
37166b242bbSMilanka Ringwald         case AVCTP_SINGLE_PACKET:
372aeb99916SMilanka Ringwald             // AVCTP message: transport header (1), pid (2)
373aeb99916SMilanka Ringwald             return 3;
37466b242bbSMilanka Ringwald         case AVCTP_START_PACKET:
375aeb99916SMilanka Ringwald             // AVCTP message: transport header (1), num_packets (1), pid (2)
376aeb99916SMilanka Ringwald             return 4;
37766b242bbSMilanka Ringwald         default:
378aeb99916SMilanka Ringwald             // AVCTP message: transport header (1)
379aeb99916SMilanka Ringwald             return 1;
38066b242bbSMilanka Ringwald     }
38166b242bbSMilanka Ringwald }
38266b242bbSMilanka Ringwald 
383aeb99916SMilanka Ringwald uint16_t avrcp_get_num_bytes_for_header(avrcp_command_opcode_t command_opcode, avctp_packet_type_t avctp_packet_type) {
3844d7cf390SMilanka Ringwald     switch (avctp_packet_type){
3854d7cf390SMilanka Ringwald         case AVCTP_SINGLE_PACKET:
3864d7cf390SMilanka Ringwald         case AVCTP_START_PACKET:
3874d7cf390SMilanka Ringwald             break;
3884d7cf390SMilanka Ringwald         default:
3894d7cf390SMilanka Ringwald             return 0;
3904d7cf390SMilanka Ringwald     }
3914d7cf390SMilanka Ringwald 
3924d7cf390SMilanka Ringwald     uint16_t offset = 3; // AVRCP message: cmd type (1), subunit (1), opcode (1)
3934d7cf390SMilanka Ringwald     switch (command_opcode){
3944d7cf390SMilanka Ringwald         case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT:
3954d7cf390SMilanka Ringwald             offset += 7; // AVRCP message:  company (3), pdu id(1), AVRCP packet type (1), param_len (2)
3964d7cf390SMilanka Ringwald             break;
3974d7cf390SMilanka Ringwald         case AVRCP_CMD_OPCODE_PASS_THROUGH:
3984d7cf390SMilanka Ringwald             offset += 3;  // AVRCP message: operation id (1), param_len (2)
3994d7cf390SMilanka Ringwald             break;
4004d7cf390SMilanka Ringwald         default:
4014d7cf390SMilanka Ringwald             break;
4024d7cf390SMilanka Ringwald     }
4034d7cf390SMilanka Ringwald     return offset;
4044d7cf390SMilanka Ringwald }
4054d7cf390SMilanka Ringwald 
406c3d92d4cSMilanka 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){
407c3d92d4cSMilanka Ringwald     uint16_t max_frame_size = btstack_min(l2cap_mtu, AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE);
408aeb99916SMilanka Ringwald     uint16_t payload_offset = avctp_get_num_bytes_for_header(avctp_packet_type) +
409aeb99916SMilanka Ringwald                               avrcp_get_num_bytes_for_header(command_opcode, avctp_packet_type);
4104d7cf390SMilanka Ringwald 
411aeb99916SMilanka Ringwald     btstack_assert(max_frame_size >= payload_offset);
412aeb99916SMilanka Ringwald     return (max_frame_size - payload_offset);
4134d7cf390SMilanka Ringwald }
4144d7cf390SMilanka Ringwald 
4154d7cf390SMilanka Ringwald 
4164d7cf390SMilanka Ringwald avctp_packet_type_t avctp_get_packet_type(avrcp_connection_t * connection, uint16_t * max_payload_size){
4177ff388bdSMilanka Ringwald     if (connection->l2cap_mtu >= AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE){
4187ff388bdSMilanka Ringwald         return AVCTP_SINGLE_PACKET;
4197ff388bdSMilanka Ringwald     }
4207ff388bdSMilanka Ringwald 
42166b242bbSMilanka Ringwald     if (connection->data_offset == 0){
422c3d92d4cSMilanka Ringwald         uint16_t max_payload_size_for_single_packet = avrcp_get_num_free_bytes_for_payload(connection->l2cap_mtu,
423aeb99916SMilanka Ringwald                                                                  connection->command_opcode,
424aeb99916SMilanka Ringwald                                                                  AVCTP_SINGLE_PACKET);
42596e5f69aSMilanka Ringwald         if (max_payload_size_for_single_packet >= connection->data_len){
42696e5f69aSMilanka Ringwald             *max_payload_size = max_payload_size_for_single_packet;
42766b242bbSMilanka Ringwald             return AVCTP_SINGLE_PACKET;
42866b242bbSMilanka Ringwald         } else {
42996e5f69aSMilanka Ringwald             uint16_t max_payload_size_for_start_packet = max_payload_size_for_single_packet - 1;
43096e5f69aSMilanka Ringwald             *max_payload_size = max_payload_size_for_start_packet;
43166b242bbSMilanka Ringwald             return AVCTP_START_PACKET;
43266b242bbSMilanka Ringwald         }
43366b242bbSMilanka Ringwald     } else {
43496e5f69aSMilanka Ringwald         // both packet types have the same single byte AVCTP header
435c3d92d4cSMilanka Ringwald         *max_payload_size = avrcp_get_num_free_bytes_for_payload(connection->l2cap_mtu,
436aeb99916SMilanka Ringwald                                                                  connection->command_opcode,
437aeb99916SMilanka Ringwald                                                                  AVCTP_CONTINUE_PACKET);
4384d7cf390SMilanka Ringwald         if ((connection->data_len - connection->data_offset) > *max_payload_size){
43966b242bbSMilanka Ringwald             return AVCTP_CONTINUE_PACKET;
44066b242bbSMilanka Ringwald         } else {
44166b242bbSMilanka Ringwald             return AVCTP_END_PACKET;
44266b242bbSMilanka Ringwald         }
44366b242bbSMilanka Ringwald     }
44466b242bbSMilanka Ringwald }
44566b242bbSMilanka Ringwald 
446aeb99916SMilanka Ringwald avrcp_packet_type_t avrcp_get_packet_type(avrcp_connection_t * connection){
447aeb99916SMilanka Ringwald     switch (connection->avctp_packet_type) {
448aeb99916SMilanka Ringwald         case AVCTP_SINGLE_PACKET:
449aeb99916SMilanka Ringwald         case AVCTP_START_PACKET:
450aeb99916SMilanka Ringwald             break;
451aeb99916SMilanka Ringwald         default:
452393f5724SMilanka Ringwald             return connection->avrcp_packet_type;
453aeb99916SMilanka Ringwald     }
454aeb99916SMilanka Ringwald 
455d6c2d4bcSMilanka Ringwald     uint16_t payload_offset = avctp_get_num_bytes_for_header(connection->avctp_packet_type) +
456d6c2d4bcSMilanka Ringwald                               avrcp_get_num_bytes_for_header(connection->command_opcode, connection->avctp_packet_type);
457d6c2d4bcSMilanka Ringwald     uint16_t bytes_to_send = (connection->data_len - connection->data_offset) + payload_offset;
458d6c2d4bcSMilanka Ringwald 
459aeb99916SMilanka Ringwald     if (connection->data_offset == 0){
460d6c2d4bcSMilanka Ringwald         if (bytes_to_send <= AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE){
461aeb99916SMilanka Ringwald             return AVRCP_SINGLE_PACKET;
462aeb99916SMilanka Ringwald         } else {
463aeb99916SMilanka Ringwald             return AVRCP_START_PACKET;
464aeb99916SMilanka Ringwald         }
465aeb99916SMilanka Ringwald     } else {
466d6c2d4bcSMilanka Ringwald         if (bytes_to_send > AVRCP_MAX_AV_C_MESSAGE_FRAME_SIZE){
467aeb99916SMilanka Ringwald             return AVRCP_CONTINUE_PACKET;
468aeb99916SMilanka Ringwald         } else {
469aeb99916SMilanka Ringwald             return AVRCP_END_PACKET;
470aeb99916SMilanka Ringwald         }
471aeb99916SMilanka Ringwald     }
472aeb99916SMilanka Ringwald }
473aeb99916SMilanka Ringwald 
4741945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_bd_addr_for_role(avrcp_role_t role, bd_addr_t addr){
4756983e65eSMilanka Ringwald     btstack_linked_list_iterator_t it;
47665bd7af5SMatthias Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
4776983e65eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
4786983e65eSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
47994d9400dSMilanka Ringwald         if (connection->role != role) continue;
4806983e65eSMilanka Ringwald         if (memcmp(addr, connection->remote_addr, 6) != 0) continue;
4816983e65eSMilanka Ringwald         return connection;
4826983e65eSMilanka Ringwald     }
4836983e65eSMilanka Ringwald     return NULL;
484be32e7f1SMilanka Ringwald }
485be32e7f1SMilanka Ringwald 
4861945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_l2cap_signaling_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){
4876983e65eSMilanka Ringwald     btstack_linked_list_iterator_t it;
48865bd7af5SMatthias Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
4896983e65eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
4906983e65eSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
49194d9400dSMilanka Ringwald         if (connection->role != role) continue;
4926983e65eSMilanka Ringwald         if (connection->l2cap_signaling_cid != l2cap_cid) continue;
4936983e65eSMilanka Ringwald         return connection;
4946983e65eSMilanka Ringwald     }
4956983e65eSMilanka Ringwald     return NULL;
496be32e7f1SMilanka Ringwald }
497be32e7f1SMilanka Ringwald 
4981945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_avrcp_cid_for_role(avrcp_role_t role, uint16_t avrcp_cid){
4996983e65eSMilanka Ringwald     btstack_linked_list_iterator_t it;
50065bd7af5SMatthias Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
5016983e65eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
5026983e65eSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
50394d9400dSMilanka Ringwald         if (connection->role != role) continue;
50401dc6e35SMilanka Ringwald         if (connection->avrcp_cid != avrcp_cid) continue;
5056983e65eSMilanka Ringwald         return connection;
5066983e65eSMilanka Ringwald     }
5076983e65eSMilanka Ringwald     return NULL;
5086983e65eSMilanka Ringwald }
5096983e65eSMilanka Ringwald 
5101945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid){
51103a72c8eSMatthias Ringwald     btstack_linked_list_iterator_t it;
51265bd7af5SMatthias Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
51303a72c8eSMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
51403a72c8eSMatthias Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
51503a72c8eSMatthias Ringwald         if (connection->role != role) continue;
51603a72c8eSMatthias Ringwald         if (connection->avrcp_browsing_cid != browsing_cid) continue;
51703a72c8eSMatthias Ringwald         return connection;
51803a72c8eSMatthias Ringwald     }
51903a72c8eSMatthias Ringwald     return NULL;
52003a72c8eSMatthias Ringwald }
52103a72c8eSMatthias Ringwald 
5221945fe3eSMilanka Ringwald avrcp_connection_t * avrcp_get_connection_for_browsing_l2cap_cid_for_role(avrcp_role_t role, uint16_t browsing_l2cap_cid){
52303a72c8eSMatthias Ringwald     btstack_linked_list_iterator_t it;
52465bd7af5SMatthias Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
52503a72c8eSMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
52603a72c8eSMatthias Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
52703a72c8eSMatthias Ringwald         if (connection->role != role) continue;
52803a72c8eSMatthias Ringwald         if (connection->browsing_connection &&  (connection->browsing_connection->l2cap_browsing_cid != browsing_l2cap_cid)) continue;
52903a72c8eSMatthias Ringwald         return connection;
53003a72c8eSMatthias Ringwald     }
53103a72c8eSMatthias Ringwald     return NULL;
53203a72c8eSMatthias Ringwald }
53303a72c8eSMatthias Ringwald 
5341945fe3eSMilanka Ringwald avrcp_browsing_connection_t * avrcp_get_browsing_connection_for_l2cap_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){
53503a72c8eSMatthias Ringwald     btstack_linked_list_iterator_t it;
53665bd7af5SMatthias Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections);
53703a72c8eSMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
53803a72c8eSMatthias Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
53903a72c8eSMatthias Ringwald         if (connection->role != role) continue;
54003a72c8eSMatthias Ringwald         if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != l2cap_cid)) continue;
54103a72c8eSMatthias Ringwald         return connection->browsing_connection;
54203a72c8eSMatthias Ringwald     }
54303a72c8eSMatthias Ringwald     return NULL;
54403a72c8eSMatthias Ringwald }
54503a72c8eSMatthias Ringwald 
5466983e65eSMilanka Ringwald void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){
547cf36dea0SMilanka Ringwald     connection->wait_to_send = true;
5486983e65eSMilanka Ringwald     l2cap_request_can_send_now_event(l2cap_cid);
5496983e65eSMilanka Ringwald }
5506983e65eSMilanka Ringwald 
551298aeecdSMilanka Ringwald uint16_t avrcp_get_next_cid(avrcp_role_t role){
552298aeecdSMilanka Ringwald     do {
553298aeecdSMilanka Ringwald         if (avrcp_cid_counter == 0xffff) {
5546983e65eSMilanka Ringwald             avrcp_cid_counter = 1;
555298aeecdSMilanka Ringwald         } else {
556298aeecdSMilanka Ringwald             avrcp_cid_counter++;
5576983e65eSMilanka Ringwald         }
5581945fe3eSMilanka Ringwald     } while (avrcp_get_connection_for_avrcp_cid_for_role(role, avrcp_cid_counter) !=  NULL) ;
5596983e65eSMilanka Ringwald     return avrcp_cid_counter;
5606983e65eSMilanka Ringwald }
5616983e65eSMilanka Ringwald 
562638481deSMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){
5636983e65eSMilanka Ringwald     avrcp_connection_t * connection = btstack_memory_avrcp_connection_get();
5644567cc17SMilanka Ringwald     if (!connection){
5650ec79bd0SMilanka Ringwald         log_error("Not enough memory to create connection for role %d", role);
5664567cc17SMilanka Ringwald         return NULL;
5674567cc17SMilanka Ringwald     }
5680036e267SMilanka Ringwald 
5696983e65eSMilanka Ringwald     connection->state = AVCTP_CONNECTION_IDLE;
5700036e267SMilanka Ringwald     connection->role = role;
571022b77fcSMilanka Ringwald 
572022b77fcSMilanka Ringwald     connection->transaction_id = 0xFF;
57323773c45SMilanka Ringwald     connection->transaction_id_counter = 0;
574022b77fcSMilanka Ringwald 
5753d73cc81SMilanka Ringwald     connection->controller_max_num_fragments = 0xFF;
576f0af2234SMatthias Ringwald 
577f0af2234SMatthias Ringwald     // setup default unit / subunit info
578f0af2234SMatthias Ringwald     connection->company_id = 0xffffff;
579393f5724SMilanka Ringwald     connection->target_unit_type = AVRCP_SUBUNIT_TYPE_PANEL;
580393f5724SMilanka Ringwald     connection->target_subunit_info_data_size = sizeof(avrcp_default_subunit_info);
581393f5724SMilanka Ringwald     connection->target_subunit_info_data = avrcp_default_subunit_info;
582f0af2234SMatthias Ringwald 
583c91f9817SMilanka Ringwald     log_info("avrcp_create_connection, role %d", role);
5846535961aSMatthias Ringwald     (void)memcpy(connection->remote_addr, remote_addr, 6);
58565bd7af5SMatthias Ringwald     btstack_linked_list_add(&avrcp_connections, (btstack_linked_item_t *) connection);
5866983e65eSMilanka Ringwald     return connection;
5876983e65eSMilanka Ringwald }
5886983e65eSMilanka Ringwald 
589638481deSMilanka Ringwald static void avrcp_finalize_connection(avrcp_connection_t * connection){
59037fae987SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->retry_timer);
591cf78f005SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->controller_press_and_hold_cmd_timer);
59265bd7af5SMatthias Ringwald     btstack_linked_list_remove(&avrcp_connections, (btstack_linked_item_t*) connection);
59355e8029cSMatthias Ringwald     btstack_memory_avrcp_connection_free(connection);
59455e8029cSMatthias Ringwald }
5956983e65eSMilanka Ringwald 
5967dbc6cb8SMilanka Ringwald static void avrcp_emit_connection_established(uint16_t avrcp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status){
597cee0e5b6SMilanka Ringwald     btstack_assert(avrcp_callback != NULL);
598cee0e5b6SMilanka Ringwald 
5997dbc6cb8SMilanka Ringwald     uint8_t event[14];
600b193c45eSMilanka Ringwald     int pos = 0;
601b193c45eSMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
602b193c45eSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
603b193c45eSMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED;
6046f43fcd7SMatthias Ringwald     event[pos++] = status;
6057dbc6cb8SMilanka Ringwald     little_endian_store_16(event, pos, avrcp_cid);
6067dbc6cb8SMilanka Ringwald     pos += 2;
607b193c45eSMilanka Ringwald     reverse_bd_addr(addr,&event[pos]);
608b193c45eSMilanka Ringwald     pos += 6;
6097dbc6cb8SMilanka Ringwald     little_endian_store_16(event, pos, con_handle);
610b193c45eSMilanka Ringwald     pos += 2;
611cee0e5b6SMilanka Ringwald     (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
612b193c45eSMilanka Ringwald }
613b193c45eSMilanka Ringwald 
614cee0e5b6SMilanka Ringwald static void avrcp_emit_connection_closed(uint16_t avrcp_cid){
615cee0e5b6SMilanka Ringwald     btstack_assert(avrcp_callback != NULL);
616cee0e5b6SMilanka Ringwald 
617be32e7f1SMilanka Ringwald     uint8_t event[5];
618be32e7f1SMilanka Ringwald     int pos = 0;
619be32e7f1SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
620be32e7f1SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
621be32e7f1SMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED;
622b193c45eSMilanka Ringwald     little_endian_store_16(event, pos, avrcp_cid);
623be32e7f1SMilanka Ringwald     pos += 2;
624cee0e5b6SMilanka Ringwald     (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
625be32e7f1SMilanka Ringwald }
626be32e7f1SMilanka Ringwald 
6276d8f569dSMilanka Ringwald uint16_t avrcp_sdp_query_browsing_l2cap_psm(void){
62865bd7af5SMatthias Ringwald     return avrcp_sdp_query_context.browsing_l2cap_psm;
6294dc95c12SMatthias Ringwald }
6304dc95c12SMatthias Ringwald 
6314dc95c12SMatthias Ringwald void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
6326086246cSMilanka Ringwald     des_iterator_t des_list_it;
6336086246cSMilanka Ringwald     des_iterator_t prot_it;
6346086246cSMilanka Ringwald 
6356086246cSMilanka Ringwald     // Handle new SDP record
63665bd7af5SMatthias Ringwald     if (sdp_event_query_attribute_byte_get_record_id(packet) != avrcp_sdp_query_context.record_id) {
63765bd7af5SMatthias Ringwald         avrcp_sdp_query_context.record_id = sdp_event_query_attribute_byte_get_record_id(packet);
63865bd7af5SMatthias Ringwald         avrcp_sdp_query_context.parse_sdp_record = 0;
6396086246cSMilanka Ringwald         // log_info("SDP Record: Nr: %d", record_id);
6406086246cSMilanka Ringwald     }
6416086246cSMilanka Ringwald 
64265bd7af5SMatthias Ringwald     if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= avrcp_sdp_query_attribute_value_buffer_size) {
64365bd7af5SMatthias Ringwald         avrcp_sdp_query_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
6446086246cSMilanka Ringwald 
6456086246cSMilanka Ringwald         if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) {
6466086246cSMilanka Ringwald             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
6476086246cSMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST:
64865bd7af5SMatthias Ringwald                     if (de_get_element_type(avrcp_sdp_query_attribute_value) != DE_DES) break;
64965bd7af5SMatthias 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)) {
6506086246cSMilanka Ringwald                         uint8_t * element = des_iterator_get_element(&des_list_it);
6516086246cSMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
6526086246cSMilanka Ringwald                         uint32_t uuid = de_get_uuid32(element);
6536086246cSMilanka Ringwald                         switch (uuid){
6546086246cSMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET:
6556086246cSMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL:
656df642728SMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER:
65765bd7af5SMatthias Ringwald                                 avrcp_sdp_query_context.parse_sdp_record = 1;
6586086246cSMilanka Ringwald                                 break;
6596086246cSMilanka Ringwald                             default:
6606086246cSMilanka Ringwald                                 break;
6616086246cSMilanka Ringwald                         }
6626086246cSMilanka Ringwald                     }
6636086246cSMilanka Ringwald                     break;
6646086246cSMilanka Ringwald 
6656086246cSMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: {
66665bd7af5SMatthias Ringwald                     if (!avrcp_sdp_query_context.parse_sdp_record) break;
6676086246cSMilanka Ringwald                     // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
66865bd7af5SMatthias 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)) {
6696086246cSMilanka Ringwald                         uint8_t       *des_element;
6706086246cSMilanka Ringwald                         uint8_t       *element;
6716086246cSMilanka Ringwald                         uint32_t       uuid;
6726086246cSMilanka Ringwald 
6736086246cSMilanka Ringwald                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
6746086246cSMilanka Ringwald 
6756086246cSMilanka Ringwald                         des_element = des_iterator_get_element(&des_list_it);
6766086246cSMilanka Ringwald                         des_iterator_init(&prot_it, des_element);
6776086246cSMilanka Ringwald                         element = des_iterator_get_element(&prot_it);
6786086246cSMilanka Ringwald 
6796086246cSMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
6806086246cSMilanka Ringwald 
6816086246cSMilanka Ringwald                         uuid = de_get_uuid32(element);
68214fd128cSMatthias Ringwald                         des_iterator_next(&prot_it);
6836086246cSMilanka Ringwald                         switch (uuid){
6846086246cSMilanka Ringwald                             case BLUETOOTH_PROTOCOL_L2CAP:
6856086246cSMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
68665bd7af5SMatthias Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.avrcp_l2cap_psm);
6876086246cSMilanka Ringwald                                 break;
6886086246cSMilanka Ringwald                             case BLUETOOTH_PROTOCOL_AVCTP:
6896086246cSMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
69065bd7af5SMatthias Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.avrcp_version);
6916086246cSMilanka Ringwald                                 break;
6926086246cSMilanka Ringwald                             default:
6936086246cSMilanka Ringwald                                 break;
6946086246cSMilanka Ringwald                         }
6956086246cSMilanka Ringwald                     }
6966086246cSMilanka Ringwald                 }
6976086246cSMilanka Ringwald                     break;
698227d16a5SMatthias Ringwald                 case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: {
699227d16a5SMatthias Ringwald                     // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
70065bd7af5SMatthias Ringwald                     if (!avrcp_sdp_query_context.parse_sdp_record) break;
70165bd7af5SMatthias Ringwald                     if (de_get_element_type(avrcp_sdp_query_attribute_value) != DE_DES) break;
702227d16a5SMatthias Ringwald 
703227d16a5SMatthias Ringwald                     des_iterator_t des_list_0_it;
704227d16a5SMatthias Ringwald                     uint8_t       *element_0;
705227d16a5SMatthias Ringwald 
70665bd7af5SMatthias Ringwald                     des_iterator_init(&des_list_0_it, avrcp_sdp_query_attribute_value);
707227d16a5SMatthias Ringwald                     element_0 = des_iterator_get_element(&des_list_0_it);
708227d16a5SMatthias Ringwald 
709227d16a5SMatthias Ringwald                     for (des_iterator_init(&des_list_it, element_0); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
710227d16a5SMatthias Ringwald                         uint8_t       *des_element;
711227d16a5SMatthias Ringwald                         uint8_t       *element;
712227d16a5SMatthias Ringwald                         uint32_t       uuid;
713227d16a5SMatthias Ringwald 
714227d16a5SMatthias Ringwald                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
715227d16a5SMatthias Ringwald 
716227d16a5SMatthias Ringwald                         des_element = des_iterator_get_element(&des_list_it);
717227d16a5SMatthias Ringwald                         des_iterator_init(&prot_it, des_element);
718227d16a5SMatthias Ringwald                         element = des_iterator_get_element(&prot_it);
719227d16a5SMatthias Ringwald 
720227d16a5SMatthias Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
721227d16a5SMatthias Ringwald 
722227d16a5SMatthias Ringwald                         uuid = de_get_uuid32(element);
72314fd128cSMatthias Ringwald                         des_iterator_next(&prot_it);
724227d16a5SMatthias Ringwald                         switch (uuid){
725227d16a5SMatthias Ringwald                             case BLUETOOTH_PROTOCOL_L2CAP:
726227d16a5SMatthias Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
72765bd7af5SMatthias Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.browsing_l2cap_psm);
728227d16a5SMatthias Ringwald                                 break;
729227d16a5SMatthias Ringwald                             case BLUETOOTH_PROTOCOL_AVCTP:
730227d16a5SMatthias Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
73165bd7af5SMatthias Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &avrcp_sdp_query_context.browsing_version);
732227d16a5SMatthias Ringwald                                 break;
733227d16a5SMatthias Ringwald                             default:
734227d16a5SMatthias Ringwald                                 break;
735227d16a5SMatthias Ringwald                         }
736227d16a5SMatthias Ringwald                     }
737227d16a5SMatthias Ringwald                 }
738227d16a5SMatthias Ringwald                     break;
7396086246cSMilanka Ringwald                 default:
7406086246cSMilanka Ringwald                     break;
7416086246cSMilanka Ringwald             }
7426086246cSMilanka Ringwald         }
7436086246cSMilanka Ringwald     } else {
74465bd7af5SMatthias 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));
7456086246cSMilanka Ringwald     }
7467b81669aSMatthias Ringwald }
7477b81669aSMatthias Ringwald 
74811256635SMatthias Ringwald static void avrcp_signaling_handle_sdp_query_complete(avrcp_connection_t * connection, uint8_t status){
74934d5ddfaSMatthias Ringwald 
75034d5ddfaSMatthias Ringwald     // l2cap available?
75147749e04SMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
75234d5ddfaSMatthias Ringwald         if (avrcp_sdp_query_context.avrcp_l2cap_psm == 0){
75334d5ddfaSMatthias Ringwald             status = SDP_SERVICE_NOT_FOUND;
75434d5ddfaSMatthias Ringwald         }
75534d5ddfaSMatthias Ringwald     }
75634d5ddfaSMatthias Ringwald 
75734d5ddfaSMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
75834d5ddfaSMatthias Ringwald         // cache SDP result
75965bd7af5SMatthias Ringwald         connection->avrcp_l2cap_psm = avrcp_sdp_query_context.avrcp_l2cap_psm;
76065bd7af5SMatthias Ringwald         connection->browsing_version = avrcp_sdp_query_context.browsing_version;
76165bd7af5SMatthias Ringwald         connection->browsing_l2cap_psm = avrcp_sdp_query_context.browsing_l2cap_psm;
76234d5ddfaSMatthias Ringwald 
76334d5ddfaSMatthias Ringwald         // ready to connect
76434d5ddfaSMatthias Ringwald         connection->state = AVCTP_CONNECTION_W2_L2CAP_CONNECT;
76534d5ddfaSMatthias Ringwald 
76634d5ddfaSMatthias Ringwald         // check if both events have been handled
76734d5ddfaSMatthias Ringwald         avrcp_connection_t * connection_with_opposite_role;
76834d5ddfaSMatthias Ringwald         switch (connection->role){
76934d5ddfaSMatthias Ringwald             case AVRCP_CONTROLLER:
77034d5ddfaSMatthias Ringwald                 connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid);
77134d5ddfaSMatthias Ringwald                 break;
77234d5ddfaSMatthias Ringwald             case AVRCP_TARGET:
77334d5ddfaSMatthias Ringwald                 connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid);
77434d5ddfaSMatthias Ringwald                 break;
77534d5ddfaSMatthias Ringwald             default:
77634d5ddfaSMatthias Ringwald                 btstack_assert(false);
77734d5ddfaSMatthias Ringwald                 return;
77834d5ddfaSMatthias Ringwald         }
77934d5ddfaSMatthias Ringwald         if (connection_with_opposite_role->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){
78034d5ddfaSMatthias Ringwald             connection->state                    = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
78134d5ddfaSMatthias Ringwald             connection_with_opposite_role->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
78234d5ddfaSMatthias Ringwald             l2cap_create_channel(&avrcp_packet_handler, connection->remote_addr, connection->avrcp_l2cap_psm, l2cap_max_mtu(), NULL);
78334d5ddfaSMatthias Ringwald         }
78447749e04SMatthias Ringwald     } else {
78547749e04SMatthias Ringwald         log_info("AVRCP: SDP query failed with status 0x%02x.", status);
78647749e04SMatthias Ringwald         avrcp_emit_connection_established(connection->avrcp_cid, connection->remote_addr, connection->con_handle, status);
78747749e04SMatthias Ringwald         avrcp_finalize_connection(connection);
78847749e04SMatthias Ringwald     }
789463f41baSMilanka Ringwald }
790463f41baSMilanka Ringwald 
79111256635SMatthias Ringwald static void avrcp_handle_sdp_query_completed(avrcp_connection_t * connection, uint8_t status){
79211256635SMatthias Ringwald     btstack_assert(connection != NULL);
79311256635SMatthias Ringwald     // SDP Signaling Query?
79411256635SMatthias Ringwald     if (connection->state == AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE){
79511256635SMatthias Ringwald         avrcp_signaling_handle_sdp_query_complete(connection, status);
79611256635SMatthias Ringwald         return;
79711256635SMatthias Ringwald     }
79811256635SMatthias Ringwald     // Browsing SDP <- Browsing Connection <- Existing SDP Connection => it wasn't an SDP query for signaling
79911256635SMatthias Ringwald     if (avrcp_browsing_sdp_query_complete_handler != NULL){
80011256635SMatthias Ringwald         (*avrcp_browsing_sdp_query_complete_handler)(connection, status);
80111256635SMatthias Ringwald     }
80211256635SMatthias Ringwald }
80311256635SMatthias Ringwald 
804a062fcddSMilanka Ringwald static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
80550fc39c5SMilanka Ringwald     UNUSED(packet_type);
80650fc39c5SMilanka Ringwald     UNUSED(channel);
80750fc39c5SMilanka Ringwald     UNUSED(size);
80850fc39c5SMilanka Ringwald 
80965bd7af5SMatthias Ringwald     avrcp_connection_t * avrcp_target_connection     = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET,     avrcp_sdp_query_context.avrcp_cid);
81065bd7af5SMatthias Ringwald     avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_sdp_query_context.avrcp_cid);
81111256635SMatthias Ringwald     bool state_ok = (avrcp_target_connection != NULL) && (avrcp_controller_connection != NULL);
81211256635SMatthias Ringwald 
8132423506bSMilanka Ringwald     if (!state_ok){
8142423506bSMilanka Ringwald         // something wrong, nevertheless, start next sdp query if this one is complete
8152423506bSMilanka Ringwald         if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){
81634d5ddfaSMatthias Ringwald             avrcp_sdp_query_context.avrcp_cid = 0;
8177a3e6573SMatthias Ringwald             avrcp_start_next_sdp_query();
8182423506bSMilanka Ringwald         }
81964a27ec5SMilanka Ringwald         return;
82064a27ec5SMilanka Ringwald     }
8217b81669aSMatthias Ringwald 
8227b81669aSMatthias Ringwald     uint8_t status;
8237b81669aSMatthias Ringwald 
8247b81669aSMatthias Ringwald     switch (hci_event_packet_get_type(packet)){
8257b81669aSMatthias Ringwald         case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
82650fc39c5SMilanka Ringwald             avrcp_handle_sdp_client_query_attribute_value(packet);
8272423506bSMilanka Ringwald             return;
8286086246cSMilanka Ringwald 
82950fc39c5SMilanka Ringwald         case SDP_EVENT_QUERY_COMPLETE:
83034d5ddfaSMatthias Ringwald             // handle result
8315448c259SMilanka Ringwald             status = sdp_event_query_complete_get_status(packet);
83247749e04SMatthias Ringwald             avrcp_handle_sdp_query_completed(avrcp_controller_connection, status);
83347749e04SMatthias Ringwald             avrcp_handle_sdp_query_completed(avrcp_target_connection, status);
8345448c259SMilanka Ringwald 
83534d5ddfaSMatthias Ringwald             // query done, start next one
83634d5ddfaSMatthias Ringwald             avrcp_sdp_query_context.avrcp_cid = 0;
83734d5ddfaSMatthias Ringwald             avrcp_start_next_sdp_query();
838463f41baSMilanka Ringwald             break;
83950fc39c5SMilanka Ringwald 
84050fc39c5SMilanka Ringwald         default:
8412423506bSMilanka Ringwald             return;
8420036e267SMilanka Ringwald     }
84364a27ec5SMilanka Ringwald 
8447a3e6573SMatthias Ringwald }
8457a3e6573SMatthias Ringwald 
8467a3e6573SMatthias Ringwald static void avrcp_handle_start_sdp_client_query(void * context){
8477a3e6573SMatthias Ringwald     UNUSED(context);
8487a3e6573SMatthias Ringwald 
84934d5ddfaSMatthias Ringwald     avrcp_connection_t * avrcp_target_connection     = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET,     avrcp_sdp_query_context.avrcp_cid);
85034d5ddfaSMatthias Ringwald     avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_sdp_query_context.avrcp_cid);
85134d5ddfaSMatthias Ringwald     bool state_ok = (avrcp_target_connection != NULL) && (avrcp_controller_connection != NULL);
85234d5ddfaSMatthias Ringwald     if (state_ok == false){
85334d5ddfaSMatthias Ringwald         // connection seems to got finalized in the meantime, just trigger next query
85434d5ddfaSMatthias Ringwald         avrcp_start_next_sdp_query();
85534d5ddfaSMatthias Ringwald         return;
85634d5ddfaSMatthias Ringwald     }
85734d5ddfaSMatthias Ringwald 
85834d5ddfaSMatthias Ringwald     // prevent triggering SDP query twice (for each role once)
85934d5ddfaSMatthias Ringwald     avrcp_target_connection->trigger_sdp_query = false;
86034d5ddfaSMatthias Ringwald     avrcp_controller_connection->trigger_sdp_query = false;
86134d5ddfaSMatthias Ringwald 
86234d5ddfaSMatthias Ringwald     sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, avrcp_target_connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP);
86334d5ddfaSMatthias Ringwald }
86434d5ddfaSMatthias Ringwald 
86534d5ddfaSMatthias Ringwald static void avrcp_start_next_sdp_query(void) {
86634d5ddfaSMatthias Ringwald     if (avrcp_sdp_query_context.avrcp_cid != 0) {
86734d5ddfaSMatthias Ringwald         return;
86834d5ddfaSMatthias Ringwald     }
8697a3e6573SMatthias Ringwald     btstack_linked_list_iterator_t it;
8707a3e6573SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &avrcp_connections);
8717a3e6573SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
8727a3e6573SMatthias Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
873a8fcc0f5SMatthias Ringwald         if (connection->trigger_sdp_query == false) continue;
8747a3e6573SMatthias Ringwald 
87534d5ddfaSMatthias Ringwald         // we're ready => setup avrcp_sdp_query_context and request sdp query
87634d5ddfaSMatthias Ringwald         avrcp_sdp_query_context.avrcp_cid = connection->avrcp_cid;
8777a3e6573SMatthias Ringwald         avrcp_sdp_query_context.avrcp_l2cap_psm = 0;
8787a3e6573SMatthias Ringwald         avrcp_sdp_query_context.avrcp_version  = 0;
8797a3e6573SMatthias Ringwald         avrcp_sdp_query_registration.callback = &avrcp_handle_start_sdp_client_query;
88034d5ddfaSMatthias Ringwald         uint8_t status = sdp_client_register_query_callback(&avrcp_sdp_query_registration);
88134d5ddfaSMatthias Ringwald         btstack_assert(status == ERROR_CODE_SUCCESS);
88234d5ddfaSMatthias Ringwald         break;
88334d5ddfaSMatthias Ringwald     }
884463f41baSMilanka Ringwald }
88550fc39c5SMilanka Ringwald 
8867dbc6cb8SMilanka 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){
887a062fcddSMilanka Ringwald     if (connection == NULL){
888a062fcddSMilanka Ringwald         connection = avrcp_create_connection(role, event_addr);
889be32e7f1SMilanka Ringwald     }
890a062fcddSMilanka Ringwald     if (connection) {
8910f76c2d7SMatthias Ringwald         connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
8920f76c2d7SMatthias Ringwald         connection->l2cap_signaling_cid = local_cid;
8937403cbbaSMilanka Ringwald         connection->avrcp_cid = avrcp_cid;
8947dbc6cb8SMilanka Ringwald         connection->con_handle = con_handle;
89537fae987SMilanka Ringwald         btstack_run_loop_remove_timer(&connection->retry_timer);
896a062fcddSMilanka Ringwald     }
897a062fcddSMilanka Ringwald     return connection;
898654724deSMilanka Ringwald }
899be32e7f1SMilanka Ringwald 
9007dbc6cb8SMilanka 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){
901be32e7f1SMilanka Ringwald     connection->l2cap_signaling_cid = local_cid;
9020036e267SMilanka Ringwald     connection->l2cap_mtu = l2cap_mtu;
9037dbc6cb8SMilanka Ringwald     connection->con_handle = con_handle;
904558ceb4aSMilanka Ringwald     connection->incoming_declined = false;
905393f5724SMilanka Ringwald     connection->target_song_length_ms = 0xFFFFFFFF;
906393f5724SMilanka Ringwald     connection->target_song_position_ms = 0xFFFFFFFF;
907f28ce84eSMilanka Ringwald     memset(connection->target_track_id, 0xFF, 8);
908f28ce84eSMilanka Ringwald     connection->target_track_selected = false;
9097d1b72e5SMilanka Ringwald     connection->target_track_changed = false;
910393f5724SMilanka Ringwald     connection->target_playback_status = AVRCP_PLAYBACK_STATUS_STOPPED;
911cee0e5b6SMilanka Ringwald     connection->state = AVCTP_CONNECTION_OPENED;
912d1207cd8SMilanka Ringwald 
91364a27ec5SMilanka 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);
9140036e267SMilanka Ringwald }
9150036e267SMilanka Ringwald 
91637fae987SMilanka Ringwald static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){
917a062fcddSMilanka Ringwald     uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer);
9181945fe3eSMilanka Ringwald     avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid);
91914c8559dSMilanka Ringwald     if (connection_controller == NULL) return;
9201945fe3eSMilanka Ringwald     avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid);
92114c8559dSMilanka Ringwald     if (connection_target == NULL) return;
922a062fcddSMilanka Ringwald 
92337fae987SMilanka Ringwald     if (connection_controller->state == AVCTP_CONNECTION_W2_L2CAP_RETRY){
92414c8559dSMilanka Ringwald         connection_controller->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
92514c8559dSMilanka Ringwald         connection_target->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
92614c8559dSMilanka Ringwald         l2cap_create_channel(&avrcp_packet_handler, connection_controller->remote_addr, connection_controller->avrcp_l2cap_psm, l2cap_max_mtu(), NULL);
92714c8559dSMilanka Ringwald     }
928a062fcddSMilanka Ringwald }
929a062fcddSMilanka Ringwald 
93037fae987SMilanka Ringwald static void avrcp_retry_timer_start(avrcp_connection_t * connection){
93137fae987SMilanka Ringwald     btstack_run_loop_set_timer_handler(&connection->retry_timer, avrcp_retry_timer_timeout_handler);
93237fae987SMilanka Ringwald     btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avrcp_cid);
933a062fcddSMilanka Ringwald 
934a062fcddSMilanka Ringwald     // add some jitter/randomness to reconnect delay
935a062fcddSMilanka Ringwald     uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F);
93637fae987SMilanka Ringwald     btstack_run_loop_set_timer(&connection->retry_timer, timeout);
937a062fcddSMilanka Ringwald 
93837fae987SMilanka Ringwald     btstack_run_loop_add_timer(&connection->retry_timer);
939a062fcddSMilanka Ringwald }
940a062fcddSMilanka Ringwald 
941b8081399SMilanka Ringwald static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){
942b8081399SMilanka Ringwald     return (avrcp_frame_type_t)((header & 0x02) >> 1);
943b8081399SMilanka Ringwald }
944b8081399SMilanka Ringwald 
9450036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
9460036e267SMilanka Ringwald     UNUSED(channel);
9470036e267SMilanka Ringwald     UNUSED(size);
9480036e267SMilanka Ringwald     bd_addr_t event_addr;
9490036e267SMilanka Ringwald     uint16_t local_cid;
9500036e267SMilanka Ringwald     uint16_t l2cap_mtu;
9510036e267SMilanka Ringwald     uint8_t  status;
9529b1b0ebdSMatthias Ringwald     bool decline_connection;
9539b1b0ebdSMatthias Ringwald     bool outoing_active;
9547dbc6cb8SMilanka Ringwald     hci_con_handle_t con_handle;
9550036e267SMilanka Ringwald 
956cee0e5b6SMilanka Ringwald     avrcp_connection_t * connection_controller;
957cee0e5b6SMilanka Ringwald     avrcp_connection_t * connection_target;
958bf67b2dbSMatthias Ringwald     bool can_send;
959cee0e5b6SMilanka Ringwald 
9600036e267SMilanka Ringwald     switch (packet_type) {
9610036e267SMilanka Ringwald         case HCI_EVENT_PACKET:
9620036e267SMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
9630036e267SMilanka Ringwald 
9640036e267SMilanka Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
965e3d57ee2SMilanka Ringwald                     btstack_assert(avrcp_controller_packet_handler != NULL);
966e3d57ee2SMilanka Ringwald                     btstack_assert(avrcp_target_packet_handler != NULL);
967e3d57ee2SMilanka Ringwald 
9680036e267SMilanka Ringwald                     l2cap_event_incoming_connection_get_address(packet, event_addr);
9690036e267SMilanka Ringwald                     local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
9707dbc6cb8SMilanka Ringwald                     con_handle = l2cap_event_incoming_connection_get_handle(packet);
971cee0e5b6SMilanka Ringwald 
9727dbc6cb8SMilanka Ringwald                     outoing_active = false;
9731945fe3eSMilanka Ringwald                     connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr);
974cee0e5b6SMilanka Ringwald                     if (connection_target != NULL){
975a062fcddSMilanka Ringwald                         if (connection_target->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){
9769b1b0ebdSMatthias Ringwald                             outoing_active = true;
977cee0e5b6SMilanka Ringwald                             connection_target->incoming_declined = true;
9789b1b0ebdSMatthias Ringwald                         }
979a062fcddSMilanka Ringwald                     }
980558ceb4aSMilanka Ringwald 
9811945fe3eSMilanka Ringwald                     connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr);
982cee0e5b6SMilanka Ringwald                     if (connection_controller != NULL){
983a062fcddSMilanka Ringwald                         if (connection_controller->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) {
9849b1b0ebdSMatthias Ringwald                             outoing_active = true;
985cee0e5b6SMilanka Ringwald                             connection_controller->incoming_declined = true;
9869b1b0ebdSMatthias Ringwald                         }
987a062fcddSMilanka Ringwald                     }
988558ceb4aSMilanka Ringwald 
9899b1b0ebdSMatthias Ringwald                     decline_connection = outoing_active;
990a062fcddSMilanka Ringwald                     if (decline_connection == false){
991a062fcddSMilanka Ringwald                         uint16_t avrcp_cid;
992a062fcddSMilanka Ringwald                         if ((connection_controller == NULL) || (connection_target == NULL)){
993a062fcddSMilanka Ringwald                             avrcp_cid = avrcp_get_next_cid(AVRCP_CONTROLLER);
994a062fcddSMilanka Ringwald                         } else {
995a062fcddSMilanka Ringwald                             avrcp_cid = connection_controller->avrcp_cid;
996a062fcddSMilanka Ringwald                         }
9970036e267SMilanka Ringwald                         // create two connection objects (both)
9987dbc6cb8SMilanka Ringwald                         connection_target     = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, connection_target, event_addr, con_handle, local_cid, avrcp_cid);
9997dbc6cb8SMilanka Ringwald                         connection_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, connection_controller, event_addr, con_handle, local_cid, avrcp_cid);
1000a062fcddSMilanka Ringwald                         if ((connection_target == NULL) || (connection_controller == NULL)){
10019b1b0ebdSMatthias Ringwald                             decline_connection = true;
1002a062fcddSMilanka Ringwald                             if (connection_target) {
1003a062fcddSMilanka Ringwald                                 avrcp_finalize_connection(connection_target);
1004a062fcddSMilanka Ringwald                             }
1005a062fcddSMilanka Ringwald                             if (connection_controller) {
1006a062fcddSMilanka Ringwald                                 avrcp_finalize_connection(connection_controller);
1007a062fcddSMilanka Ringwald                             }
10080036e267SMilanka Ringwald                         }
10099b1b0ebdSMatthias Ringwald                     }
10109b1b0ebdSMatthias Ringwald                     if (decline_connection){
10119b1b0ebdSMatthias Ringwald                         l2cap_decline_connection(local_cid);
10129b1b0ebdSMatthias Ringwald                     } else {
101364a27ec5SMilanka Ringwald                         log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION local cid 0x%02x, state %d", local_cid, connection_controller->state);
10140036e267SMilanka Ringwald                         l2cap_accept_connection(local_cid);
10159b1b0ebdSMatthias Ringwald                     }
10160036e267SMilanka Ringwald                     break;
10170036e267SMilanka Ringwald 
10180036e267SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
10190036e267SMilanka Ringwald                     l2cap_event_channel_opened_get_address(packet, event_addr);
10200036e267SMilanka Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
10210036e267SMilanka Ringwald                     local_cid = l2cap_event_channel_opened_get_local_cid(packet);
10220036e267SMilanka Ringwald                     l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet);
10237dbc6cb8SMilanka Ringwald                     con_handle = l2cap_event_channel_opened_get_handle(packet);
10240036e267SMilanka Ringwald 
10251945fe3eSMilanka Ringwald                     connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr);
10261945fe3eSMilanka Ringwald                     connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr);
1027a062fcddSMilanka Ringwald 
1028a062fcddSMilanka Ringwald                     // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION
1029a062fcddSMilanka Ringwald                     // outgoing: structs are cteated in avrcp_connect()
1030cee0e5b6SMilanka Ringwald                     if ((connection_controller == NULL) || (connection_target == NULL)) {
1031cee0e5b6SMilanka Ringwald                         break;
1032cee0e5b6SMilanka Ringwald                     }
1033cee0e5b6SMilanka Ringwald 
1034a062fcddSMilanka Ringwald                     switch (status){
1035a062fcddSMilanka Ringwald                         case ERROR_CODE_SUCCESS:
10367dbc6cb8SMilanka Ringwald                             avrcp_handle_open_connection(connection_target, con_handle, local_cid, l2cap_mtu);
10377dbc6cb8SMilanka Ringwald                             avrcp_handle_open_connection(connection_controller, con_handle, local_cid, l2cap_mtu);
10387dbc6cb8SMilanka Ringwald                             avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status);
1039a062fcddSMilanka Ringwald                             return;
1040a062fcddSMilanka Ringwald                         case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES:
1041a062fcddSMilanka Ringwald                             if (connection_controller->incoming_declined == true){
1042a062fcddSMilanka Ringwald                                 log_info("Incoming connection was declined, and the outgoing failed");
104337fae987SMilanka Ringwald                                 connection_controller->state = AVCTP_CONNECTION_W2_L2CAP_RETRY;
1044a062fcddSMilanka Ringwald                                 connection_controller->incoming_declined = false;
104537fae987SMilanka Ringwald                                 connection_target->state = AVCTP_CONNECTION_W2_L2CAP_RETRY;
1046a062fcddSMilanka Ringwald                                 connection_target->incoming_declined = false;
104737fae987SMilanka Ringwald                                 avrcp_retry_timer_start(connection_controller);
1048a062fcddSMilanka Ringwald                                 return;
1049a062fcddSMilanka Ringwald                             }
1050a062fcddSMilanka Ringwald                             break;
1051a062fcddSMilanka Ringwald                         default:
1052a062fcddSMilanka Ringwald                             break;
1053a062fcddSMilanka Ringwald                     }
1054cee0e5b6SMilanka Ringwald                     log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status);
10557dbc6cb8SMilanka Ringwald                     avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, con_handle, status);
1056cee0e5b6SMilanka Ringwald                     avrcp_finalize_connection(connection_controller);
1057cee0e5b6SMilanka Ringwald                     avrcp_finalize_connection(connection_target);
1058cee0e5b6SMilanka Ringwald 
1059be32e7f1SMilanka Ringwald                     break;
1060be32e7f1SMilanka Ringwald 
1061be32e7f1SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
1062be32e7f1SMilanka Ringwald                     local_cid = l2cap_event_channel_closed_get_local_cid(packet);
1063cee0e5b6SMilanka Ringwald 
10641945fe3eSMilanka Ringwald                     connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid);
10651945fe3eSMilanka Ringwald                     connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid);
1066cee0e5b6SMilanka Ringwald                     if ((connection_controller == NULL) || (connection_target == NULL)) {
1067cee0e5b6SMilanka Ringwald                         break;
1068cee0e5b6SMilanka Ringwald                     }
1069cee0e5b6SMilanka Ringwald                     avrcp_emit_connection_closed(connection_controller->avrcp_cid);
1070cee0e5b6SMilanka Ringwald                     avrcp_finalize_connection(connection_controller);
1071cee0e5b6SMilanka Ringwald                     avrcp_finalize_connection(connection_target);
10720036e267SMilanka Ringwald                     break;
10730036e267SMilanka Ringwald 
10740036e267SMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
10750036e267SMilanka Ringwald                     local_cid = l2cap_event_can_send_now_get_local_cid(packet);
1076bf67b2dbSMatthias Ringwald                     can_send = true;
1077e3d57ee2SMilanka Ringwald 
10781945fe3eSMilanka Ringwald                     connection_target = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid);
1079cf36dea0SMilanka Ringwald                     if ((connection_target != NULL) && connection_target->wait_to_send){
1080cf36dea0SMilanka Ringwald                         connection_target->wait_to_send = false;
10810036e267SMilanka Ringwald                         (*avrcp_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size);
1082bf67b2dbSMatthias Ringwald                         can_send = false;
10830036e267SMilanka Ringwald                     }
10840036e267SMilanka Ringwald 
10851945fe3eSMilanka Ringwald                     connection_controller = avrcp_get_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid);
1086cf36dea0SMilanka Ringwald                     if ((connection_controller != NULL) && connection_controller->wait_to_send){
1087bf67b2dbSMatthias Ringwald                         if (can_send){
1088cf36dea0SMilanka Ringwald                             connection_controller->wait_to_send = false;
10890036e267SMilanka Ringwald                             (*avrcp_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size);
1090bf67b2dbSMatthias Ringwald                         } else {
1091bf67b2dbSMatthias Ringwald                             l2cap_request_can_send_now_event(local_cid);
1092bf67b2dbSMatthias Ringwald                         }
1093be32e7f1SMilanka Ringwald                     }
1094be32e7f1SMilanka Ringwald                     break;
10950036e267SMilanka Ringwald 
1096be32e7f1SMilanka Ringwald                 default:
1097be32e7f1SMilanka Ringwald                     break;
1098be32e7f1SMilanka Ringwald             }
1099b106f728SMilanka Ringwald             break;
1100e3d57ee2SMilanka Ringwald 
1101e3d57ee2SMilanka Ringwald         case L2CAP_DATA_PACKET:
1102b8081399SMilanka Ringwald             switch (avrcp_get_frame_type(packet[0])){
1103e3d57ee2SMilanka Ringwald                 case AVRCP_RESPONSE_FRAME:
1104e3d57ee2SMilanka Ringwald                     (*avrcp_controller_packet_handler)(packet_type, channel, packet, size);
1105e3d57ee2SMilanka Ringwald                     break;
1106e3d57ee2SMilanka Ringwald                 case AVRCP_COMMAND_FRAME:
1107e3d57ee2SMilanka Ringwald                 default:    // make compiler happy
1108e3d57ee2SMilanka Ringwald                     (*avrcp_target_packet_handler)(packet_type, channel, packet, size);
1109e3d57ee2SMilanka Ringwald                     break;
1110e3d57ee2SMilanka Ringwald             }
1111e3d57ee2SMilanka Ringwald             break;
1112e3d57ee2SMilanka Ringwald 
1113b106f728SMilanka Ringwald         default:
1114b106f728SMilanka Ringwald             break;
1115b106f728SMilanka Ringwald     }
1116be32e7f1SMilanka Ringwald }
1117be32e7f1SMilanka Ringwald 
1118bd9a32e4SMatthias Ringwald void avrcp_init(void){
1119bd9a32e4SMatthias Ringwald     avrcp_connections = NULL;
1120bd9a32e4SMatthias Ringwald     if (avrcp_l2cap_service_registered) return;
1121bd9a32e4SMatthias Ringwald 
1122bd9a32e4SMatthias Ringwald     int status = l2cap_register_service(&avrcp_packet_handler, BLUETOOTH_PSM_AVCTP, 0xffff, gap_get_security_level());
1123bd9a32e4SMatthias Ringwald     if (status != ERROR_CODE_SUCCESS) return;
1124bd9a32e4SMatthias Ringwald     avrcp_l2cap_service_registered = true;
1125bd9a32e4SMatthias Ringwald }
1126bd9a32e4SMatthias Ringwald 
1127bd9a32e4SMatthias Ringwald void avrcp_register_controller_packet_handler(btstack_packet_handler_t callback){
1128bd9a32e4SMatthias Ringwald     // note: called by avrcp_controller_init
1129bd9a32e4SMatthias Ringwald     avrcp_controller_packet_handler = callback;
1130bd9a32e4SMatthias Ringwald }
1131bd9a32e4SMatthias Ringwald 
1132bd9a32e4SMatthias Ringwald void avrcp_register_target_packet_handler(btstack_packet_handler_t callback){
1133bd9a32e4SMatthias Ringwald     // note: called by avrcp_target_init
1134bd9a32e4SMatthias Ringwald     avrcp_target_packet_handler = callback;
1135bd9a32e4SMatthias Ringwald }
1136bd9a32e4SMatthias Ringwald 
1137bd9a32e4SMatthias Ringwald void avrcp_register_packet_handler(btstack_packet_handler_t callback){
1138bd9a32e4SMatthias Ringwald     btstack_assert(callback != NULL);
1139bd9a32e4SMatthias Ringwald     avrcp_callback = callback;
1140bd9a32e4SMatthias Ringwald }
1141bd9a32e4SMatthias Ringwald 
1142bd9a32e4SMatthias Ringwald void avrcp_register_browsing_sdp_query_complete_handler(void (*callback)(avrcp_connection_t * connection, uint8_t status)){
1143bd9a32e4SMatthias Ringwald     btstack_assert(callback != NULL);
1144bd9a32e4SMatthias Ringwald     avrcp_browsing_sdp_query_complete_handler = callback;
1145bd9a32e4SMatthias Ringwald }
1146bd9a32e4SMatthias Ringwald 
1147bd9a32e4SMatthias Ringwald 
1148*6eafac07SMatthias Ringwald void avrcp_trigger_sdp_query(avrcp_connection_t *connection_controller, avrcp_connection_t *connection_target) {
1149*6eafac07SMatthias Ringwald     connection_controller->trigger_sdp_query = true;
1150*6eafac07SMatthias Ringwald     connection_target->trigger_sdp_query     = true;
1151*6eafac07SMatthias Ringwald 
1152*6eafac07SMatthias Ringwald     avrcp_start_next_sdp_query();
1153*6eafac07SMatthias Ringwald }
1154*6eafac07SMatthias Ringwald 
1155fe10780bSMilanka Ringwald uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){
1156e3d57ee2SMilanka Ringwald     btstack_assert(avrcp_controller_packet_handler != NULL);
1157e3d57ee2SMilanka Ringwald     btstack_assert(avrcp_target_packet_handler != NULL);
1158f9ef80eaSMilanka Ringwald 
11591945fe3eSMilanka Ringwald     avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr);
1160bd66227aSMilanka Ringwald     if (connection_controller){
1161bd66227aSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1162bd66227aSMilanka Ringwald     }
11631945fe3eSMilanka Ringwald     avrcp_connection_t * connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr);
1164bd66227aSMilanka Ringwald     if (connection_target){
1165bd66227aSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1166bd66227aSMilanka Ringwald     }
1167bd66227aSMilanka Ringwald 
11687403cbbaSMilanka Ringwald     uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER);
11697403cbbaSMilanka Ringwald 
1170bd66227aSMilanka Ringwald     connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr);
1171bd66227aSMilanka Ringwald     if (!connection_controller) return BTSTACK_MEMORY_ALLOC_FAILED;
1172bd66227aSMilanka Ringwald 
1173bd66227aSMilanka Ringwald     connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr);
1174bd66227aSMilanka Ringwald     if (!connection_target){
1175bd66227aSMilanka Ringwald         avrcp_finalize_connection(connection_controller);
1176bd66227aSMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
1177bd66227aSMilanka Ringwald     }
1178bd66227aSMilanka Ringwald 
1179bd66227aSMilanka Ringwald     if (avrcp_cid != NULL){
1180bd66227aSMilanka Ringwald         *avrcp_cid = cid;
1181bd66227aSMilanka Ringwald     }
1182bd66227aSMilanka Ringwald 
11837403cbbaSMilanka Ringwald     connection_controller->avrcp_cid = cid;
11847403cbbaSMilanka Ringwald     connection_target->avrcp_cid     = cid;
11855dd5e7e3SMilanka Ringwald 
1186a8fcc0f5SMatthias Ringwald     connection_controller->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
1187a8fcc0f5SMatthias Ringwald     connection_target->state     = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
1188a8fcc0f5SMatthias Ringwald 
1189*6eafac07SMatthias Ringwald     avrcp_trigger_sdp_query(connection_controller, connection_target);
1190a8fcc0f5SMatthias Ringwald 
119164a27ec5SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1192be32e7f1SMilanka Ringwald }
1193638481deSMilanka Ringwald 
1194bd9a32e4SMatthias Ringwald uint8_t avrcp_disconnect(uint16_t avrcp_cid){
1195bd9a32e4SMatthias Ringwald     avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid);
1196bd9a32e4SMatthias Ringwald     if (!connection_controller){
1197bd9a32e4SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1198bd9a32e4SMatthias Ringwald     }
1199bd9a32e4SMatthias Ringwald     avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid);
1200bd9a32e4SMatthias Ringwald     if (!connection_target){
1201bd9a32e4SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1202bd9a32e4SMatthias Ringwald     }
1203bd9a32e4SMatthias Ringwald     if (connection_controller->browsing_connection){
1204bd9a32e4SMatthias Ringwald         l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid);
1205bd9a32e4SMatthias Ringwald     }
1206bd9a32e4SMatthias Ringwald     l2cap_disconnect(connection_controller->l2cap_signaling_cid);
1207bd9a32e4SMatthias Ringwald     return ERROR_CODE_SUCCESS;
1208638481deSMilanka Ringwald }
1209b106f728SMilanka Ringwald 
1210680af5dcSMatthias Ringwald void avrcp_deinit(void){
121165bd7af5SMatthias Ringwald     avrcp_l2cap_service_registered = false;
1212680af5dcSMatthias Ringwald 
121365bd7af5SMatthias Ringwald     avrcp_cid_counter = 0;
121465bd7af5SMatthias Ringwald     avrcp_connections = NULL;
1215680af5dcSMatthias Ringwald 
1216680af5dcSMatthias Ringwald     avrcp_callback = NULL;
1217680af5dcSMatthias Ringwald     avrcp_controller_packet_handler = NULL;
1218680af5dcSMatthias Ringwald     avrcp_target_packet_handler = NULL;
121965bd7af5SMatthias Ringwald 
122065bd7af5SMatthias Ringwald     (void) memset(&avrcp_sdp_query_registration, 0, sizeof(avrcp_sdp_query_registration));
122165bd7af5SMatthias Ringwald     (void) memset(&avrcp_sdp_query_context, 0, sizeof(avrcp_sdp_query_context_t));
122265bd7af5SMatthias Ringwald     (void) memset(avrcp_sdp_query_attribute_value, 0, sizeof(avrcp_sdp_query_attribute_value));
1223680af5dcSMatthias Ringwald }
1224697b823eSMatthias Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1225697b823eSMatthias Ringwald #define FUZZ_CID 0x44
12263cd982f4SMatthias Ringwald #define FUZZ_CON_HANDLE 0x0001
1227697b823eSMatthias Ringwald static bd_addr_t remote_addr = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33 };
1228697b823eSMatthias Ringwald void avrcp_init_fuzz(void){
1229697b823eSMatthias Ringwald     // setup avrcp connections for cid
1230697b823eSMatthias Ringwald     avrcp_connection_t * connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr);
1231697b823eSMatthias Ringwald     avrcp_connection_t * connection_target     = avrcp_create_connection(AVRCP_TARGET, remote_addr);
12323cd982f4SMatthias Ringwald     avrcp_handle_open_connection(connection_controller, FUZZ_CON_HANDLE, FUZZ_CID, 999);
12333cd982f4SMatthias Ringwald     avrcp_handle_open_connection(connection_target, FUZZ_CON_HANDLE, FUZZ_CID, 999);
1234697b823eSMatthias Ringwald }
1235697b823eSMatthias Ringwald void avrcp_packet_handler_fuzz(uint8_t *packet, uint16_t size){
1236697b823eSMatthias Ringwald     avrcp_packet_handler(L2CAP_DATA_PACKET, FUZZ_CID, packet, size);
1237697b823eSMatthias Ringwald }
1238697b823eSMatthias Ringwald #endif
1239