xref: /btstack/src/classic/avrcp.c (revision cf36dea0749042424676f65e1324feb1cf6fdfbf)
1be32e7f1SMilanka Ringwald /*
2be32e7f1SMilanka Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3be32e7f1SMilanka Ringwald  *
4be32e7f1SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5be32e7f1SMilanka Ringwald  * modification, are permitted provided that the following conditions
6be32e7f1SMilanka Ringwald  * are met:
7be32e7f1SMilanka Ringwald  *
8be32e7f1SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9be32e7f1SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10be32e7f1SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11be32e7f1SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12be32e7f1SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13be32e7f1SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14be32e7f1SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15be32e7f1SMilanka Ringwald  *    from this software without specific prior written permission.
16be32e7f1SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17be32e7f1SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18be32e7f1SMilanka Ringwald  *    monetary gain.
19be32e7f1SMilanka Ringwald  *
20be32e7f1SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21be32e7f1SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22be32e7f1SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23be32e7f1SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24be32e7f1SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25be32e7f1SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26be32e7f1SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27be32e7f1SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28be32e7f1SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29be32e7f1SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30be32e7f1SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31be32e7f1SMilanka Ringwald  * SUCH DAMAGE.
32be32e7f1SMilanka Ringwald  *
33be32e7f1SMilanka Ringwald  * Please inquire about commercial licensing options at
34be32e7f1SMilanka Ringwald  * [email protected]
35be32e7f1SMilanka Ringwald  *
36be32e7f1SMilanka Ringwald  */
37be32e7f1SMilanka Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avrcp.c"
39ab2c6ae4SMatthias Ringwald 
40be32e7f1SMilanka Ringwald #include <stdint.h>
41be32e7f1SMilanka Ringwald #include <string.h>
42be32e7f1SMilanka Ringwald 
4384e3541eSMilanka Ringwald #include "bluetooth_psm.h"
4484e3541eSMilanka Ringwald #include "bluetooth_sdp.h"
4584e3541eSMilanka Ringwald #include "btstack_debug.h"
4684e3541eSMilanka Ringwald #include "btstack_event.h"
4784e3541eSMilanka Ringwald #include "btstack_memory.h"
4884e3541eSMilanka Ringwald #include "classic/sdp_client.h"
4984e3541eSMilanka Ringwald #include "classic/sdp_util.h"
50be32e7f1SMilanka Ringwald #include "classic/avrcp.h"
516983e65eSMilanka Ringwald #include "classic/avrcp_controller.h"
52be32e7f1SMilanka Ringwald 
530eebc132SMilanka Ringwald #define PSM_AVCTP_BROWSING              0x001b
540eebc132SMilanka Ringwald 
550036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
560eebc132SMilanka Ringwald static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
570036e267SMilanka Ringwald 
58be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service";
59be32e7f1SMilanka Ringwald static const char * default_avrcp_controller_service_provider_name = "BTstack AVRCP Controller Service Provider";
60be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_name = "BTstack AVRCP Target Service";
61be32e7f1SMilanka Ringwald static const char * default_avrcp_target_service_provider_name = "BTstack AVRCP Target Service Provider";
62be32e7f1SMilanka Ringwald 
636983e65eSMilanka Ringwald static uint16_t  avrcp_cid_counter = 0;
64be32e7f1SMilanka Ringwald 
656983e65eSMilanka Ringwald static avrcp_context_t * sdp_query_context;
66e3d57ee2SMilanka Ringwald static avrcp_context_t avrcp_context;
675dd5e7e3SMilanka Ringwald 
68cee0e5b6SMilanka Ringwald static btstack_packet_handler_t avrcp_callback;
690eebc132SMilanka Ringwald static btstack_packet_handler_t avrcp_browsing_callback;
70cee0e5b6SMilanka Ringwald 
71fa1ee4d3SMilanka Ringwald static uint8_t   attribute_value[45];
726983e65eSMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value);
736983e65eSMilanka Ringwald 
74638481deSMilanka Ringwald static btstack_linked_list_t connections;
75b106f728SMilanka Ringwald static btstack_packet_handler_t avrcp_controller_packet_handler;
76b106f728SMilanka Ringwald static btstack_packet_handler_t avrcp_target_packet_handler;
770eebc132SMilanka Ringwald static bool l2cap_service_registered = false;
780eebc132SMilanka Ringwald 
790eebc132SMilanka Ringwald static bool l2cap_browsing_service_registered = false;
800eebc132SMilanka Ringwald static btstack_packet_handler_t avrcp_browsing_controller_packet_handler;
810eebc132SMilanka Ringwald static btstack_packet_handler_t avrcp_browsing_target_packet_handler;
826086246cSMilanka Ringwald 
83be32e7f1SMilanka Ringwald static const char * avrcp_subunit_type_name[] = {
84be32e7f1SMilanka Ringwald     "MONITOR", "AUDIO", "PRINTER", "DISC", "TAPE_RECORDER_PLAYER", "TUNER",
85be32e7f1SMilanka Ringwald     "CA", "CAMERA", "RESERVED", "PANEL", "BULLETIN_BOARD", "CAMERA_STORAGE",
86be32e7f1SMilanka Ringwald     "VENDOR_UNIQUE", "RESERVED_FOR_ALL_SUBUNIT_TYPES",
87be32e7f1SMilanka Ringwald     "EXTENDED_TO_NEXT_BYTE", "UNIT", "ERROR"
88be32e7f1SMilanka Ringwald };
896983e65eSMilanka Ringwald 
90be32e7f1SMilanka Ringwald const char * avrcp_subunit2str(uint16_t index){
91be32e7f1SMilanka Ringwald     if (index <= 11) return avrcp_subunit_type_name[index];
920e588213SMatthias Ringwald     if ((index >= 0x1C) && (index <= 0x1F)) return avrcp_subunit_type_name[index - 0x10];
93be32e7f1SMilanka Ringwald     return avrcp_subunit_type_name[16];
94be32e7f1SMilanka Ringwald }
95be32e7f1SMilanka Ringwald 
96be32e7f1SMilanka Ringwald static const char * avrcp_event_name[] = {
97be32e7f1SMilanka Ringwald     "ERROR", "PLAYBACK_STATUS_CHANGED",
98be32e7f1SMilanka Ringwald     "TRACK_CHANGED", "TRACK_REACHED_END", "TRACK_REACHED_START",
99be32e7f1SMilanka Ringwald     "PLAYBACK_POS_CHANGED", "BATT_STATUS_CHANGED", "SYSTEM_STATUS_CHANGED",
100be32e7f1SMilanka Ringwald     "PLAYER_APPLICATION_SETTING_CHANGED", "NOW_PLAYING_CONTENT_CHANGED",
101be32e7f1SMilanka Ringwald     "AVAILABLE_PLAYERS_CHANGED", "ADDRESSED_PLAYER_CHANGED", "UIDS_CHANGED", "VOLUME_CHANGED"
102be32e7f1SMilanka Ringwald };
103be32e7f1SMilanka Ringwald const char * avrcp_event2str(uint16_t index){
104be32e7f1SMilanka Ringwald     if (index <= 0x0d) return avrcp_event_name[index];
105be32e7f1SMilanka Ringwald     return avrcp_event_name[0];
106be32e7f1SMilanka Ringwald }
107be32e7f1SMilanka Ringwald 
108be32e7f1SMilanka Ringwald static const char * avrcp_operation_name[] = {
109be32e7f1SMilanka Ringwald     "NOT SUPPORTED", // 0x3B
110be32e7f1SMilanka Ringwald     "SKIP", "NOT SUPPORTED", "NOT SUPPORTED", "NOT SUPPORTED", "NOT SUPPORTED",
111be32e7f1SMilanka Ringwald     "VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", "NOT SUPPORTED",
112be32e7f1SMilanka Ringwald     "REWIND", "FAST_FORWARD", "NOT SUPPORTED", "FORWARD", "BACKWARD" // 0x4C
113be32e7f1SMilanka Ringwald };
114be32e7f1SMilanka Ringwald const char * avrcp_operation2str(uint8_t index){
1150e588213SMatthias Ringwald     if ((index >= 0x3B) && (index <= 0x4C)) return avrcp_operation_name[index - 0x3B];
116be32e7f1SMilanka Ringwald     return avrcp_operation_name[0];
117be32e7f1SMilanka Ringwald }
118be32e7f1SMilanka Ringwald 
119be32e7f1SMilanka Ringwald static const char * avrcp_media_attribute_id_name[] = {
120be32e7f1SMilanka Ringwald     "NONE", "TITLE", "ARTIST", "ALBUM", "TRACK", "TOTAL TRACKS", "GENRE", "SONG LENGTH"
121be32e7f1SMilanka Ringwald };
122be32e7f1SMilanka Ringwald const char * avrcp_attribute2str(uint8_t index){
123c1ab6cc1SMatthias Ringwald     if ((index >= 1) && (index <= 7)) return avrcp_media_attribute_id_name[index];
124be32e7f1SMilanka Ringwald     return avrcp_media_attribute_id_name[0];
125be32e7f1SMilanka Ringwald }
126be32e7f1SMilanka Ringwald 
127be32e7f1SMilanka Ringwald static const char * avrcp_play_status_name[] = {
128be32e7f1SMilanka Ringwald     "STOPPED", "PLAYING", "PAUSED", "FORWARD SEEK", "REVERSE SEEK",
129be32e7f1SMilanka Ringwald     "ERROR" // 0xFF
130be32e7f1SMilanka Ringwald };
131be32e7f1SMilanka Ringwald const char * avrcp_play_status2str(uint8_t index){
132c1ab6cc1SMatthias Ringwald     if ((index >= 1) && (index <= 4)) return avrcp_play_status_name[index];
133be32e7f1SMilanka Ringwald     return avrcp_play_status_name[5];
134be32e7f1SMilanka Ringwald }
135be32e7f1SMilanka Ringwald 
136be32e7f1SMilanka Ringwald static const char * avrcp_ctype_name[] = {
137be32e7f1SMilanka Ringwald     "CONTROL",
138be32e7f1SMilanka Ringwald     "STATUS",
139be32e7f1SMilanka Ringwald     "SPECIFIC_INQUIRY",
140be32e7f1SMilanka Ringwald     "NOTIFY",
141be32e7f1SMilanka Ringwald     "GENERAL_INQUIRY",
142be32e7f1SMilanka Ringwald     "RESERVED5",
143be32e7f1SMilanka Ringwald     "RESERVED6",
144be32e7f1SMilanka Ringwald     "RESERVED7",
1459cc1f3ceSMilanka Ringwald     "NOT IMPLEMENTED IN REMOTE",
1469cc1f3ceSMilanka Ringwald     "ACCEPTED BY REMOTE",
1479cc1f3ceSMilanka Ringwald     "REJECTED BY REMOTE",
148be32e7f1SMilanka Ringwald     "IN_TRANSITION",
149be32e7f1SMilanka Ringwald     "IMPLEMENTED_STABLE",
150be32e7f1SMilanka Ringwald     "CHANGED_STABLE",
151be32e7f1SMilanka Ringwald     "RESERVED",
152be32e7f1SMilanka Ringwald     "INTERIM"
153be32e7f1SMilanka Ringwald };
154be32e7f1SMilanka Ringwald const char * avrcp_ctype2str(uint8_t index){
1553982eab9SMatthias Ringwald     if (index < sizeof(avrcp_ctype_name)){
156be32e7f1SMilanka Ringwald         return avrcp_ctype_name[index];
157be32e7f1SMilanka Ringwald     }
158be32e7f1SMilanka Ringwald     return "NONE";
159be32e7f1SMilanka Ringwald }
160be32e7f1SMilanka Ringwald 
161be32e7f1SMilanka Ringwald static const char * avrcp_shuffle_mode_name[] = {
162be32e7f1SMilanka Ringwald     "SHUFFLE OFF",
163be32e7f1SMilanka Ringwald     "SHUFFLE ALL TRACKS",
164be32e7f1SMilanka Ringwald     "SHUFFLE GROUP"
165be32e7f1SMilanka Ringwald };
166be32e7f1SMilanka Ringwald 
167be32e7f1SMilanka Ringwald const char * avrcp_shuffle2str(uint8_t index){
168c1ab6cc1SMatthias Ringwald     if ((index >= 1) && (index <= 3)) return avrcp_shuffle_mode_name[index-1];
169be32e7f1SMilanka Ringwald     return "NONE";
170be32e7f1SMilanka Ringwald }
171be32e7f1SMilanka Ringwald 
172be32e7f1SMilanka Ringwald static const char * avrcp_repeat_mode_name[] = {
173be32e7f1SMilanka Ringwald     "REPEAT OFF",
174be32e7f1SMilanka Ringwald     "REPEAT SINGLE TRACK",
175be32e7f1SMilanka Ringwald     "REPEAT ALL TRACKS",
176be32e7f1SMilanka Ringwald     "REPEAT GROUP"
177be32e7f1SMilanka Ringwald };
178be32e7f1SMilanka Ringwald 
179be32e7f1SMilanka Ringwald const char * avrcp_repeat2str(uint8_t index){
180c1ab6cc1SMatthias Ringwald     if ((index >= 1) && (index <= 4)) return avrcp_repeat_mode_name[index-1];
181be32e7f1SMilanka Ringwald     return "NONE";
182be32e7f1SMilanka Ringwald }
1836086246cSMilanka Ringwald 
1844b338011SMilanka Ringwald uint8_t avrcp_cmd_opcode(uint8_t *packet, uint16_t size){
1854b338011SMilanka Ringwald     uint8_t cmd_opcode_index = 5;
1864b338011SMilanka Ringwald     if (cmd_opcode_index > size) return AVRCP_CMD_OPCODE_UNDEFINED;
1874b338011SMilanka Ringwald     return packet[cmd_opcode_index];
1884b338011SMilanka Ringwald }
1894b338011SMilanka Ringwald 
190654724deSMilanka Ringwald void avrcp_create_sdp_record(uint8_t controller, uint8_t * service, uint32_t service_record_handle, uint8_t browsing, uint16_t supported_features,
191654724deSMilanka Ringwald     const char * service_name, const char * service_provider_name){
192be32e7f1SMilanka Ringwald     uint8_t* attribute;
193be32e7f1SMilanka Ringwald     de_create_sequence(service);
194be32e7f1SMilanka Ringwald 
195be32e7f1SMilanka Ringwald     // 0x0000 "Service Record Handle"
196235946f1SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
197be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
198be32e7f1SMilanka Ringwald 
199be32e7f1SMilanka Ringwald     // 0x0001 "Service Class ID List"
200235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
201be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
202be32e7f1SMilanka Ringwald     {
203be32e7f1SMilanka Ringwald         if (controller){
2046086246cSMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL);
2056086246cSMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER);
206be32e7f1SMilanka Ringwald         } else {
2076086246cSMilanka Ringwald             de_add_number(attribute, DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET);
208be32e7f1SMilanka Ringwald         }
209be32e7f1SMilanka Ringwald     }
210be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
211be32e7f1SMilanka Ringwald 
212be32e7f1SMilanka Ringwald     // 0x0004 "Protocol Descriptor List"
213235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
214be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
215be32e7f1SMilanka Ringwald     {
216be32e7f1SMilanka Ringwald         uint8_t* l2cpProtocol = de_push_sequence(attribute);
217be32e7f1SMilanka Ringwald         {
218235946f1SMatthias Ringwald             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
21984e3541eSMilanka Ringwald             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP);
220be32e7f1SMilanka Ringwald         }
221be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, l2cpProtocol);
222be32e7f1SMilanka Ringwald 
223be32e7f1SMilanka Ringwald         uint8_t* avctpProtocol = de_push_sequence(attribute);
224be32e7f1SMilanka Ringwald         {
225235946f1SMatthias Ringwald             de_add_number(avctpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP);  // avctpProtocol_service
226be32e7f1SMilanka Ringwald             de_add_number(avctpProtocol,  DE_UINT, DE_SIZE_16,  0x0103);    // version
227be32e7f1SMilanka Ringwald         }
228be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, avctpProtocol);
229be32e7f1SMilanka Ringwald     }
230be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
231be32e7f1SMilanka Ringwald 
232be32e7f1SMilanka Ringwald     // 0x0005 "Public Browse Group"
233235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
234be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
235be32e7f1SMilanka Ringwald     {
236235946f1SMatthias Ringwald         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
237be32e7f1SMilanka Ringwald     }
238be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
239be32e7f1SMilanka Ringwald 
240be32e7f1SMilanka Ringwald     // 0x0009 "Bluetooth Profile Descriptor List"
241235946f1SMatthias Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
242be32e7f1SMilanka Ringwald     attribute = de_push_sequence(service);
243be32e7f1SMilanka Ringwald     {
244be32e7f1SMilanka Ringwald         uint8_t *avrcProfile = de_push_sequence(attribute);
245be32e7f1SMilanka Ringwald         {
2466086246cSMilanka Ringwald             de_add_number(avrcProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL);
247be32e7f1SMilanka Ringwald             de_add_number(avrcProfile,  DE_UINT, DE_SIZE_16, 0x0105);
248be32e7f1SMilanka Ringwald         }
249be32e7f1SMilanka Ringwald         de_pop_sequence(attribute, avrcProfile);
250be32e7f1SMilanka Ringwald     }
251be32e7f1SMilanka Ringwald     de_pop_sequence(service, attribute);
252be32e7f1SMilanka Ringwald 
253a0f524f0SMatthias Ringwald     // 0x000d "Additional Bluetooth Profile Descriptor List"
2545c806868SMatthias Ringwald     if (browsing){
255a0f524f0SMatthias Ringwald         de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS);
256a0f524f0SMatthias Ringwald         attribute = de_push_sequence(service);
2575c806868SMatthias Ringwald         {
2585c806868SMatthias Ringwald             uint8_t * des = de_push_sequence(attribute);
2595c806868SMatthias Ringwald             {
2605c806868SMatthias Ringwald                 uint8_t* browsing_l2cpProtocol = de_push_sequence(des);
261a0f524f0SMatthias Ringwald                 {
262a0f524f0SMatthias Ringwald                     de_add_number(browsing_l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
26384e3541eSMilanka Ringwald                     de_add_number(browsing_l2cpProtocol,  DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVCTP_BROWSING);
264a0f524f0SMatthias Ringwald                 }
2655c806868SMatthias Ringwald                 de_pop_sequence(des, browsing_l2cpProtocol);
266a0f524f0SMatthias Ringwald 
2675c806868SMatthias Ringwald                 uint8_t* browsing_avctpProtocol = de_push_sequence(des);
268a0f524f0SMatthias Ringwald                 {
269a0f524f0SMatthias Ringwald                     de_add_number(browsing_avctpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVCTP);  // browsing_avctpProtocol_service
270a0f524f0SMatthias Ringwald                     de_add_number(browsing_avctpProtocol,  DE_UINT, DE_SIZE_16,  0x0103);    // version
271a0f524f0SMatthias Ringwald                 }
2725c806868SMatthias Ringwald                 de_pop_sequence(des, browsing_avctpProtocol);
2735c806868SMatthias Ringwald             }
2745c806868SMatthias Ringwald             de_pop_sequence(attribute, des);
275a0f524f0SMatthias Ringwald         }
276a0f524f0SMatthias Ringwald         de_pop_sequence(service, attribute);
2775c806868SMatthias Ringwald     }
278a0f524f0SMatthias Ringwald 
279be32e7f1SMilanka Ringwald 
280be32e7f1SMilanka Ringwald     // 0x0100 "Service Name"
281be32e7f1SMilanka Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
282be32e7f1SMilanka Ringwald     if (service_name){
283be32e7f1SMilanka Ringwald         de_add_data(service,  DE_STRING, strlen(service_name), (uint8_t *) service_name);
284be32e7f1SMilanka Ringwald     } else {
285be32e7f1SMilanka Ringwald         if (controller){
286be32e7f1SMilanka Ringwald             de_add_data(service,  DE_STRING, strlen(default_avrcp_controller_service_name), (uint8_t *) default_avrcp_controller_service_name);
287be32e7f1SMilanka Ringwald         } else {
288be32e7f1SMilanka Ringwald             de_add_data(service,  DE_STRING, strlen(default_avrcp_target_service_name), (uint8_t *) default_avrcp_target_service_name);
289be32e7f1SMilanka Ringwald         }
290be32e7f1SMilanka Ringwald     }
291be32e7f1SMilanka Ringwald 
292be32e7f1SMilanka Ringwald     // 0x0100 "Provider Name"
293be32e7f1SMilanka Ringwald     de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0102);
294be32e7f1SMilanka Ringwald     if (service_provider_name){
295be32e7f1SMilanka Ringwald         de_add_data(service,  DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name);
296be32e7f1SMilanka Ringwald     } else {
297be32e7f1SMilanka Ringwald         if (controller){
298be32e7f1SMilanka Ringwald             de_add_data(service,  DE_STRING, strlen(default_avrcp_controller_service_provider_name), (uint8_t *) default_avrcp_controller_service_provider_name);
299be32e7f1SMilanka Ringwald         } else {
300be32e7f1SMilanka Ringwald             de_add_data(service,  DE_STRING, strlen(default_avrcp_target_service_provider_name), (uint8_t *) default_avrcp_target_service_provider_name);
301be32e7f1SMilanka Ringwald         }
302be32e7f1SMilanka Ringwald     }
303be32e7f1SMilanka Ringwald 
304be32e7f1SMilanka Ringwald     // 0x0311 "Supported Features"
305be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);
306be32e7f1SMilanka Ringwald     de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
307be32e7f1SMilanka Ringwald }
308be32e7f1SMilanka Ringwald 
30916d860d2SMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_bd_addr_for_role(avrcp_role_t role, bd_addr_t addr){
3106983e65eSMilanka Ringwald     btstack_linked_list_iterator_t it;
311638481deSMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections);
3126983e65eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
3136983e65eSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
31494d9400dSMilanka Ringwald         if (connection->role != role) continue;
3156983e65eSMilanka Ringwald         if (memcmp(addr, connection->remote_addr, 6) != 0) continue;
3166983e65eSMilanka Ringwald         return connection;
3176983e65eSMilanka Ringwald     }
3186983e65eSMilanka Ringwald     return NULL;
319be32e7f1SMilanka Ringwald }
320be32e7f1SMilanka Ringwald 
32116d860d2SMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_l2cap_signaling_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){
3226983e65eSMilanka Ringwald     btstack_linked_list_iterator_t it;
323638481deSMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections);
3246983e65eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
3256983e65eSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
32694d9400dSMilanka Ringwald         if (connection->role != role) continue;
3276983e65eSMilanka Ringwald         if (connection->l2cap_signaling_cid != l2cap_cid) continue;
3286983e65eSMilanka Ringwald         return connection;
3296983e65eSMilanka Ringwald     }
3306983e65eSMilanka Ringwald     return NULL;
331be32e7f1SMilanka Ringwald }
332be32e7f1SMilanka Ringwald 
33316d860d2SMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_avrcp_cid_for_role(avrcp_role_t role, uint16_t avrcp_cid){
3346983e65eSMilanka Ringwald     btstack_linked_list_iterator_t it;
335638481deSMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections);
3366983e65eSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
3376983e65eSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
33894d9400dSMilanka Ringwald         if (connection->role != role) continue;
33901dc6e35SMilanka Ringwald         if (connection->avrcp_cid != avrcp_cid) continue;
3406983e65eSMilanka Ringwald         return connection;
3416983e65eSMilanka Ringwald     }
3426983e65eSMilanka Ringwald     return NULL;
3436983e65eSMilanka Ringwald }
3446983e65eSMilanka Ringwald 
34516d860d2SMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_browsing_cid_for_role(avrcp_role_t role, uint16_t browsing_cid){
346638481deSMilanka Ringwald     btstack_linked_list_iterator_t it;
347638481deSMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections);
348638481deSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
349638481deSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
35094d9400dSMilanka Ringwald         if (connection->role != role) continue;
351638481deSMilanka Ringwald         if (connection->avrcp_browsing_cid != browsing_cid) continue;
352638481deSMilanka Ringwald         return connection;
353638481deSMilanka Ringwald     }
354638481deSMilanka Ringwald     return NULL;
355638481deSMilanka Ringwald }
356638481deSMilanka Ringwald 
35716d860d2SMilanka Ringwald avrcp_connection_t * get_avrcp_connection_for_browsing_l2cap_cid_for_role(avrcp_role_t role, uint16_t browsing_l2cap_cid){
358638481deSMilanka Ringwald     btstack_linked_list_iterator_t it;
359638481deSMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections);
360638481deSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
361638481deSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
36294d9400dSMilanka Ringwald         if (connection->role != role) continue;
363c1ab6cc1SMatthias Ringwald         if (connection->browsing_connection &&  (connection->browsing_connection->l2cap_browsing_cid != browsing_l2cap_cid)) continue;
364638481deSMilanka Ringwald         return connection;
365638481deSMilanka Ringwald     }
366638481deSMilanka Ringwald     return NULL;
367638481deSMilanka Ringwald }
368638481deSMilanka Ringwald 
36916d860d2SMilanka Ringwald avrcp_browsing_connection_t * get_avrcp_browsing_connection_for_l2cap_cid_for_role(avrcp_role_t role, uint16_t l2cap_cid){
370638481deSMilanka Ringwald     btstack_linked_list_iterator_t it;
371638481deSMilanka Ringwald     btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &connections);
372638481deSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
373638481deSMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
37494d9400dSMilanka Ringwald         if (connection->role != role) continue;
375c1ab6cc1SMatthias Ringwald         if (connection->browsing_connection && (connection->browsing_connection->l2cap_browsing_cid != l2cap_cid)) continue;
376638481deSMilanka Ringwald         return connection->browsing_connection;
377638481deSMilanka Ringwald     }
378638481deSMilanka Ringwald     return NULL;
379638481deSMilanka Ringwald }
38094d9400dSMilanka Ringwald 
3816983e65eSMilanka Ringwald void avrcp_request_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){
382*cf36dea0SMilanka Ringwald     connection->wait_to_send = true;
3836983e65eSMilanka Ringwald     l2cap_request_can_send_now_event(l2cap_cid);
3846983e65eSMilanka Ringwald }
3856983e65eSMilanka Ringwald 
3860eebc132SMilanka Ringwald void avrcp_browsing_request_can_send_now(avrcp_browsing_connection_t * connection, uint16_t l2cap_cid){
387eab0c1eeSMilanka Ringwald     connection->wait_to_send = true;
3880eebc132SMilanka Ringwald     l2cap_request_can_send_now_event(l2cap_cid);
3890eebc132SMilanka Ringwald }
3906983e65eSMilanka Ringwald 
391298aeecdSMilanka Ringwald uint16_t avrcp_get_next_cid(avrcp_role_t role){
392298aeecdSMilanka Ringwald     do {
393298aeecdSMilanka Ringwald         if (avrcp_cid_counter == 0xffff) {
3946983e65eSMilanka Ringwald             avrcp_cid_counter = 1;
395298aeecdSMilanka Ringwald         } else {
396298aeecdSMilanka Ringwald             avrcp_cid_counter++;
3976983e65eSMilanka Ringwald         }
39816d860d2SMilanka Ringwald     } while (get_avrcp_connection_for_avrcp_cid_for_role(role, avrcp_cid_counter) !=  NULL) ;
3996983e65eSMilanka Ringwald     return avrcp_cid_counter;
4006983e65eSMilanka Ringwald }
4016983e65eSMilanka Ringwald 
402298aeecdSMilanka Ringwald 
403638481deSMilanka Ringwald static avrcp_connection_t * avrcp_create_connection(avrcp_role_t role, bd_addr_t remote_addr){
4046983e65eSMilanka Ringwald     avrcp_connection_t * connection = btstack_memory_avrcp_connection_get();
4054567cc17SMilanka Ringwald     if (!connection){
4060ec79bd0SMilanka Ringwald         log_error("Not enough memory to create connection for role %d", role);
4074567cc17SMilanka Ringwald         return NULL;
4084567cc17SMilanka Ringwald     }
4090036e267SMilanka Ringwald 
4106983e65eSMilanka Ringwald     connection->state = AVCTP_CONNECTION_IDLE;
4110036e267SMilanka Ringwald     connection->role = role;
4126983e65eSMilanka Ringwald     connection->transaction_label = 0xFF;
4138b2b4034SMilanka Ringwald     connection->max_num_fragments = 0xFF;
4140ec79bd0SMilanka Ringwald     log_info("avrcp_create_connection, role %d, avrcp cid 0x%02x", role, connection->avrcp_cid);
4156535961aSMatthias Ringwald     (void)memcpy(connection->remote_addr, remote_addr, 6);
416638481deSMilanka Ringwald     btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection);
4176983e65eSMilanka Ringwald     return connection;
4186983e65eSMilanka Ringwald }
4196983e65eSMilanka Ringwald 
420638481deSMilanka Ringwald static void avrcp_finalize_connection(avrcp_connection_t * connection){
421a062fcddSMilanka Ringwald     btstack_run_loop_remove_timer(&connection->reconnect_timer);
422638481deSMilanka Ringwald     btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection);
42355e8029cSMatthias Ringwald     btstack_memory_avrcp_connection_free(connection);
42455e8029cSMatthias Ringwald }
4256983e65eSMilanka Ringwald 
426cee0e5b6SMilanka Ringwald static void avrcp_emit_connection_established(uint16_t avrcp_cid, bd_addr_t addr, uint8_t status){
427cee0e5b6SMilanka Ringwald     btstack_assert(avrcp_callback != NULL);
428cee0e5b6SMilanka Ringwald 
4296086246cSMilanka Ringwald     uint8_t event[12];
430b193c45eSMilanka Ringwald     int pos = 0;
431b193c45eSMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
432b193c45eSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
433b193c45eSMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_CONNECTION_ESTABLISHED;
4346f43fcd7SMatthias Ringwald     event[pos++] = status;
435b193c45eSMilanka Ringwald     reverse_bd_addr(addr,&event[pos]);
436b193c45eSMilanka Ringwald     pos += 6;
437b193c45eSMilanka Ringwald     little_endian_store_16(event, pos, avrcp_cid);
438b193c45eSMilanka Ringwald     pos += 2;
439cee0e5b6SMilanka Ringwald     (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
440b193c45eSMilanka Ringwald }
441b193c45eSMilanka Ringwald 
442cee0e5b6SMilanka Ringwald static void avrcp_emit_connection_closed(uint16_t avrcp_cid){
443cee0e5b6SMilanka Ringwald     btstack_assert(avrcp_callback != NULL);
444cee0e5b6SMilanka Ringwald 
445be32e7f1SMilanka Ringwald     uint8_t event[5];
446be32e7f1SMilanka Ringwald     int pos = 0;
447be32e7f1SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
448be32e7f1SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
449be32e7f1SMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_CONNECTION_RELEASED;
450b193c45eSMilanka Ringwald     little_endian_store_16(event, pos, avrcp_cid);
451be32e7f1SMilanka Ringwald     pos += 2;
452cee0e5b6SMilanka Ringwald     (*avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
453be32e7f1SMilanka Ringwald }
454be32e7f1SMilanka Ringwald 
45550fc39c5SMilanka Ringwald static void avrcp_handle_sdp_client_query_attribute_value(uint8_t *packet){
4566086246cSMilanka Ringwald     des_iterator_t des_list_it;
4576086246cSMilanka Ringwald     des_iterator_t prot_it;
4586086246cSMilanka Ringwald 
4596086246cSMilanka Ringwald     // Handle new SDP record
460f12a3722SMilanka Ringwald     if (sdp_event_query_attribute_byte_get_record_id(packet) != sdp_query_context->record_id) {
461f12a3722SMilanka Ringwald         sdp_query_context->record_id = sdp_event_query_attribute_byte_get_record_id(packet);
462f12a3722SMilanka Ringwald         sdp_query_context->parse_sdp_record = 0;
4636086246cSMilanka Ringwald         // log_info("SDP Record: Nr: %d", record_id);
4646086246cSMilanka Ringwald     }
4656086246cSMilanka Ringwald 
4666086246cSMilanka Ringwald     if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) {
4676086246cSMilanka Ringwald         attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
4686086246cSMilanka Ringwald 
4696086246cSMilanka Ringwald         if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) {
4706086246cSMilanka Ringwald             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
4716086246cSMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST:
4726086246cSMilanka Ringwald                     if (de_get_element_type(attribute_value) != DE_DES) break;
4736086246cSMilanka Ringwald                     for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
4746086246cSMilanka Ringwald                         uint8_t * element = des_iterator_get_element(&des_list_it);
4756086246cSMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
4766086246cSMilanka Ringwald                         uint32_t uuid = de_get_uuid32(element);
4776086246cSMilanka Ringwald                         switch (uuid){
4786086246cSMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_TARGET:
4796983e65eSMilanka Ringwald                                 if (sdp_query_context->role == AVRCP_CONTROLLER) {
480f12a3722SMilanka Ringwald                                     sdp_query_context->parse_sdp_record = 1;
4816086246cSMilanka Ringwald                                     break;
4826086246cSMilanka Ringwald                                 }
4836086246cSMilanka Ringwald                                 break;
4846086246cSMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL:
485df642728SMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL_CONTROLLER:
4866983e65eSMilanka Ringwald                                 if (sdp_query_context->role == AVRCP_TARGET) {
487f12a3722SMilanka Ringwald                                     sdp_query_context->parse_sdp_record = 1;
4886086246cSMilanka Ringwald                                     break;
4896086246cSMilanka Ringwald                                 }
4906086246cSMilanka Ringwald                                 break;
4916086246cSMilanka Ringwald                             default:
4926086246cSMilanka Ringwald                                 break;
4936086246cSMilanka Ringwald                         }
4946086246cSMilanka Ringwald                     }
4956086246cSMilanka Ringwald                     break;
4966086246cSMilanka Ringwald 
4976086246cSMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: {
498f12a3722SMilanka Ringwald                     if (!sdp_query_context->parse_sdp_record) break;
4996086246cSMilanka Ringwald                     // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
5006086246cSMilanka Ringwald                     for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
5016086246cSMilanka Ringwald                         uint8_t       *des_element;
5026086246cSMilanka Ringwald                         uint8_t       *element;
5036086246cSMilanka Ringwald                         uint32_t       uuid;
5046086246cSMilanka Ringwald 
5056086246cSMilanka Ringwald                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
5066086246cSMilanka Ringwald 
5076086246cSMilanka Ringwald                         des_element = des_iterator_get_element(&des_list_it);
5086086246cSMilanka Ringwald                         des_iterator_init(&prot_it, des_element);
5096086246cSMilanka Ringwald                         element = des_iterator_get_element(&prot_it);
5106086246cSMilanka Ringwald 
5116086246cSMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
5126086246cSMilanka Ringwald 
5136086246cSMilanka Ringwald                         uuid = de_get_uuid32(element);
51414fd128cSMatthias Ringwald                         des_iterator_next(&prot_it);
5156086246cSMilanka Ringwald                         switch (uuid){
5166086246cSMilanka Ringwald                             case BLUETOOTH_PROTOCOL_L2CAP:
5176086246cSMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
5186983e65eSMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_l2cap_psm);
5196086246cSMilanka Ringwald                                 break;
5206086246cSMilanka Ringwald                             case BLUETOOTH_PROTOCOL_AVCTP:
5216086246cSMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
5226983e65eSMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->avrcp_version);
5236086246cSMilanka Ringwald                                 break;
5246086246cSMilanka Ringwald                             default:
5256086246cSMilanka Ringwald                                 break;
5266086246cSMilanka Ringwald                         }
5276086246cSMilanka Ringwald                     }
5286086246cSMilanka Ringwald                 }
5296086246cSMilanka Ringwald                     break;
530227d16a5SMatthias Ringwald                 case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS: {
531227d16a5SMatthias Ringwald                     // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
532f12a3722SMilanka Ringwald                     if (!sdp_query_context->parse_sdp_record) break;
533227d16a5SMatthias Ringwald                     if (de_get_element_type(attribute_value) != DE_DES) break;
534227d16a5SMatthias Ringwald 
535227d16a5SMatthias Ringwald                     des_iterator_t des_list_0_it;
536227d16a5SMatthias Ringwald                     uint8_t       *element_0;
537227d16a5SMatthias Ringwald 
538227d16a5SMatthias Ringwald                     des_iterator_init(&des_list_0_it, attribute_value);
539227d16a5SMatthias Ringwald                     element_0 = des_iterator_get_element(&des_list_0_it);
540227d16a5SMatthias Ringwald 
541227d16a5SMatthias Ringwald                     for (des_iterator_init(&des_list_it, element_0); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
542227d16a5SMatthias Ringwald                         uint8_t       *des_element;
543227d16a5SMatthias Ringwald                         uint8_t       *element;
544227d16a5SMatthias Ringwald                         uint32_t       uuid;
545227d16a5SMatthias Ringwald 
546227d16a5SMatthias Ringwald                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
547227d16a5SMatthias Ringwald 
548227d16a5SMatthias Ringwald                         des_element = des_iterator_get_element(&des_list_it);
549227d16a5SMatthias Ringwald                         des_iterator_init(&prot_it, des_element);
550227d16a5SMatthias Ringwald                         element = des_iterator_get_element(&prot_it);
551227d16a5SMatthias Ringwald 
552227d16a5SMatthias Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
553227d16a5SMatthias Ringwald 
554227d16a5SMatthias Ringwald                         uuid = de_get_uuid32(element);
55514fd128cSMatthias Ringwald                         des_iterator_next(&prot_it);
556227d16a5SMatthias Ringwald                         switch (uuid){
557227d16a5SMatthias Ringwald                             case BLUETOOTH_PROTOCOL_L2CAP:
558227d16a5SMatthias Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
55950fc39c5SMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->browsing_l2cap_psm);
560227d16a5SMatthias Ringwald                                 break;
561227d16a5SMatthias Ringwald                             case BLUETOOTH_PROTOCOL_AVCTP:
562227d16a5SMatthias Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
56350fc39c5SMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &sdp_query_context->browsing_version);
564227d16a5SMatthias Ringwald                                 break;
565227d16a5SMatthias Ringwald                             default:
566227d16a5SMatthias Ringwald                                 break;
567227d16a5SMatthias Ringwald                         }
568227d16a5SMatthias Ringwald                     }
569227d16a5SMatthias Ringwald                 }
570227d16a5SMatthias Ringwald                     break;
5716086246cSMilanka Ringwald                 default:
5726086246cSMilanka Ringwald                     break;
5736086246cSMilanka Ringwald             }
5746086246cSMilanka Ringwald         }
5756086246cSMilanka Ringwald     } else {
5766086246cSMilanka Ringwald         log_error("SDP attribute value buffer size exceeded: available %d, required %d", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet));
5776086246cSMilanka Ringwald     }
5787b81669aSMatthias Ringwald }
5797b81669aSMatthias Ringwald 
580463f41baSMilanka Ringwald static void avrcp_handle_sdp_query_failed(avrcp_connection_t * connection, uint8_t status){
581b68672eaSMilanka Ringwald     if (connection == NULL) return;
582463f41baSMilanka Ringwald     log_info("AVRCP: SDP query failed with status 0x%02x.", status);
583cee0e5b6SMilanka Ringwald     avrcp_emit_connection_established(connection->avrcp_cid, connection->remote_addr, status);
584463f41baSMilanka Ringwald     avrcp_finalize_connection(connection);
585463f41baSMilanka Ringwald }
586463f41baSMilanka Ringwald 
587a062fcddSMilanka Ringwald static void avrcp_handle_sdp_query_succeeded(avrcp_connection_t * connection){
588b68672eaSMilanka Ringwald     if (connection == NULL) return;
589463f41baSMilanka Ringwald     connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
590a062fcddSMilanka Ringwald     connection->avrcp_l2cap_psm = sdp_query_context->avrcp_l2cap_psm;
591a062fcddSMilanka Ringwald     connection->browsing_version = sdp_query_context->browsing_version;
592a062fcddSMilanka Ringwald     connection->browsing_l2cap_psm = sdp_query_context->browsing_l2cap_psm;
593463f41baSMilanka Ringwald }
594463f41baSMilanka Ringwald 
595a062fcddSMilanka Ringwald static void avrcp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
59650fc39c5SMilanka Ringwald     UNUSED(packet_type);
59750fc39c5SMilanka Ringwald     UNUSED(channel);
59850fc39c5SMilanka Ringwald     UNUSED(size);
59950fc39c5SMilanka Ringwald 
600b68672eaSMilanka Ringwald     avrcp_connection_t * avrcp_target_connection = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, sdp_query_context->remote_addr);
601b68672eaSMilanka Ringwald     avrcp_connection_t * avrcp_controller_connection = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, sdp_query_context->remote_addr);
6027b81669aSMatthias Ringwald 
6037b81669aSMatthias Ringwald     uint8_t status;
6047b81669aSMatthias Ringwald 
6057b81669aSMatthias Ringwald     switch (hci_event_packet_get_type(packet)){
6067b81669aSMatthias Ringwald         case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
60750fc39c5SMilanka Ringwald             avrcp_handle_sdp_client_query_attribute_value(packet);
6086086246cSMilanka Ringwald             break;
6096086246cSMilanka Ringwald 
61050fc39c5SMilanka Ringwald         case SDP_EVENT_QUERY_COMPLETE:
6115448c259SMilanka Ringwald             status = sdp_event_query_complete_get_status(packet);
612247956eaSMilanka Ringwald 
6135448c259SMilanka Ringwald             if (status != ERROR_CODE_SUCCESS){
614b68672eaSMilanka Ringwald                 avrcp_handle_sdp_query_failed(avrcp_controller_connection, status);
615b68672eaSMilanka Ringwald                 avrcp_handle_sdp_query_failed(avrcp_target_connection, status);
6165448c259SMilanka Ringwald                 break;
6175448c259SMilanka Ringwald             }
6185448c259SMilanka Ringwald 
619e1ad7f0dSMatthias Ringwald             if (!sdp_query_context->avrcp_l2cap_psm){
620b68672eaSMilanka Ringwald                 avrcp_handle_sdp_query_failed(avrcp_controller_connection, SDP_SERVICE_NOT_FOUND);
621b68672eaSMilanka Ringwald                 avrcp_handle_sdp_query_failed(avrcp_target_connection, SDP_SERVICE_NOT_FOUND);
6226983e65eSMilanka Ringwald                 break;
6236983e65eSMilanka Ringwald             }
624be32e7f1SMilanka Ringwald 
625a062fcddSMilanka Ringwald             avrcp_handle_sdp_query_succeeded(avrcp_controller_connection);
626a062fcddSMilanka Ringwald             avrcp_handle_sdp_query_succeeded(avrcp_target_connection);
627bd66227aSMilanka Ringwald 
628bd66227aSMilanka Ringwald             l2cap_create_channel(&avrcp_packet_handler, sdp_query_context->remote_addr, sdp_query_context->avrcp_l2cap_psm, l2cap_max_mtu(), NULL);
629463f41baSMilanka Ringwald             break;
63050fc39c5SMilanka Ringwald 
63150fc39c5SMilanka Ringwald         default:
63250fc39c5SMilanka Ringwald             break;
63350fc39c5SMilanka Ringwald 
6340036e267SMilanka Ringwald     }
635463f41baSMilanka Ringwald }
63650fc39c5SMilanka Ringwald 
637be32e7f1SMilanka Ringwald 
638a062fcddSMilanka Ringwald static avrcp_connection_t * avrcp_handle_incoming_connection_for_role(avrcp_role_t role, avrcp_connection_t * connection, bd_addr_t event_addr, uint16_t local_cid, uint16_t avrcp_cid){
639a062fcddSMilanka Ringwald     if (connection == NULL){
640a062fcddSMilanka Ringwald         connection = avrcp_create_connection(role, event_addr);
641be32e7f1SMilanka Ringwald     }
642a062fcddSMilanka Ringwald     if (connection) {
6430f76c2d7SMatthias Ringwald         connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
6440f76c2d7SMatthias Ringwald         connection->l2cap_signaling_cid = local_cid;
6457403cbbaSMilanka Ringwald         connection->avrcp_cid = avrcp_cid;
646a062fcddSMilanka Ringwald         btstack_run_loop_remove_timer(&connection->reconnect_timer);
647a062fcddSMilanka Ringwald     }
648a062fcddSMilanka Ringwald     return connection;
649654724deSMilanka Ringwald }
650be32e7f1SMilanka Ringwald 
651cee0e5b6SMilanka Ringwald static void avrcp_handle_open_connection_for_role( avrcp_connection_t * connection, uint16_t local_cid, uint16_t l2cap_mtu){
652be32e7f1SMilanka Ringwald     connection->l2cap_signaling_cid = local_cid;
6530036e267SMilanka Ringwald     connection->l2cap_mtu = l2cap_mtu;
654558ceb4aSMilanka Ringwald     connection->incoming_declined = false;
655d1207cd8SMilanka Ringwald     connection->song_length_ms = 0xFFFFFFFF;
656d1207cd8SMilanka Ringwald     connection->song_position_ms = 0xFFFFFFFF;
657d1207cd8SMilanka Ringwald     connection->playback_status = AVRCP_PLAYBACK_STATUS_ERROR;
658cee0e5b6SMilanka Ringwald     connection->state = AVCTP_CONNECTION_OPENED;
659d1207cd8SMilanka Ringwald 
6600036e267SMilanka Ringwald     log_info("L2CAP_EVENT_CHANNEL_OPENED avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d", connection->avrcp_cid, connection->l2cap_signaling_cid, connection->role);
6610036e267SMilanka Ringwald }
6620036e267SMilanka Ringwald 
663a062fcddSMilanka Ringwald static void avrcp_reconnect_timer_timeout_handler(btstack_timer_source_t * timer){
664a062fcddSMilanka Ringwald     uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer);
665a062fcddSMilanka Ringwald     avrcp_connection_t * controller_connection = get_avrcp_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid);
666a062fcddSMilanka Ringwald     if (controller_connection == NULL) return;
667a062fcddSMilanka Ringwald     avrcp_connection_t * target_connection = get_avrcp_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid);
668a062fcddSMilanka Ringwald     if (target_connection == NULL) return;
669a062fcddSMilanka Ringwald 
670a062fcddSMilanka Ringwald     controller_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
671a062fcddSMilanka Ringwald     target_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
672a062fcddSMilanka Ringwald 
673a062fcddSMilanka Ringwald     l2cap_create_channel(&avrcp_packet_handler, controller_connection->remote_addr, controller_connection->avrcp_l2cap_psm, l2cap_max_mtu(), NULL);
674a062fcddSMilanka Ringwald }
675a062fcddSMilanka Ringwald 
676a062fcddSMilanka Ringwald static void avrcp_reconnect_timer_start(avrcp_connection_t * connection){
677a062fcddSMilanka Ringwald     btstack_run_loop_set_timer_handler(&connection->reconnect_timer, avrcp_reconnect_timer_timeout_handler);
678a062fcddSMilanka Ringwald     btstack_run_loop_set_timer_context(&connection->reconnect_timer, (void *)(uintptr_t)connection->avrcp_cid);
679a062fcddSMilanka Ringwald 
680a062fcddSMilanka Ringwald     // add some jitter/randomness to reconnect delay
681a062fcddSMilanka Ringwald     uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F);
682a062fcddSMilanka Ringwald     btstack_run_loop_set_timer(&connection->reconnect_timer, timeout);
683a062fcddSMilanka Ringwald 
684a062fcddSMilanka Ringwald     btstack_run_loop_add_timer(&connection->reconnect_timer);
685a062fcddSMilanka Ringwald }
686a062fcddSMilanka Ringwald 
687b8081399SMilanka Ringwald static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){
688b8081399SMilanka Ringwald     return (avrcp_frame_type_t)((header & 0x02) >> 1);
689b8081399SMilanka Ringwald }
690b8081399SMilanka Ringwald 
6910036e267SMilanka Ringwald static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
6920036e267SMilanka Ringwald     UNUSED(channel);
6930036e267SMilanka Ringwald     UNUSED(size);
6940036e267SMilanka Ringwald     bd_addr_t event_addr;
6950036e267SMilanka Ringwald     uint16_t local_cid;
6960036e267SMilanka Ringwald     uint16_t l2cap_mtu;
6970036e267SMilanka Ringwald     uint8_t  status;
6989b1b0ebdSMatthias Ringwald     bool decline_connection;
6999b1b0ebdSMatthias Ringwald     bool outoing_active;
7000036e267SMilanka Ringwald 
701cee0e5b6SMilanka Ringwald     avrcp_connection_t * connection_controller;
702cee0e5b6SMilanka Ringwald     avrcp_connection_t * connection_target;
703cee0e5b6SMilanka Ringwald 
7040036e267SMilanka Ringwald     switch (packet_type) {
7050036e267SMilanka Ringwald         case HCI_EVENT_PACKET:
7060036e267SMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
7070036e267SMilanka Ringwald 
7080036e267SMilanka Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
709e3d57ee2SMilanka Ringwald                     btstack_assert(avrcp_controller_packet_handler != NULL);
710e3d57ee2SMilanka Ringwald                     btstack_assert(avrcp_target_packet_handler != NULL);
711e3d57ee2SMilanka Ringwald 
7120036e267SMilanka Ringwald                     l2cap_event_incoming_connection_get_address(packet, event_addr);
7130036e267SMilanka Ringwald                     local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
7149b1b0ebdSMatthias Ringwald                     outoing_active = false;
715cee0e5b6SMilanka Ringwald 
716cee0e5b6SMilanka Ringwald                     connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr);
717cee0e5b6SMilanka Ringwald                     if (connection_target != NULL){
718a062fcddSMilanka Ringwald                         if (connection_target->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){
7199b1b0ebdSMatthias Ringwald                             outoing_active = true;
720cee0e5b6SMilanka Ringwald                             connection_target->incoming_declined = true;
7219b1b0ebdSMatthias Ringwald                         }
722a062fcddSMilanka Ringwald                     }
723558ceb4aSMilanka Ringwald 
724cee0e5b6SMilanka Ringwald                     connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr);
725cee0e5b6SMilanka Ringwald                     if (connection_controller != NULL){
726a062fcddSMilanka Ringwald                         if (connection_controller->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) {
7279b1b0ebdSMatthias Ringwald                             outoing_active = true;
728cee0e5b6SMilanka Ringwald                             connection_controller->incoming_declined = true;
7299b1b0ebdSMatthias Ringwald                         }
730a062fcddSMilanka Ringwald                     }
731558ceb4aSMilanka Ringwald 
7329b1b0ebdSMatthias Ringwald                     decline_connection = outoing_active;
733a062fcddSMilanka Ringwald                     if (decline_connection == false){
734a062fcddSMilanka Ringwald                         uint16_t avrcp_cid;
735a062fcddSMilanka Ringwald                         if ((connection_controller == NULL) || (connection_target == NULL)){
736a062fcddSMilanka Ringwald                             avrcp_cid = avrcp_get_next_cid(AVRCP_CONTROLLER);
737a062fcddSMilanka Ringwald                         } else {
738a062fcddSMilanka Ringwald                             avrcp_cid = connection_controller->avrcp_cid;
739a062fcddSMilanka Ringwald                         }
7400036e267SMilanka Ringwald                         // create two connection objects (both)
741a062fcddSMilanka Ringwald                         connection_target     = avrcp_handle_incoming_connection_for_role(AVRCP_TARGET, connection_target, event_addr, local_cid, avrcp_cid);
742a062fcddSMilanka Ringwald                         connection_controller = avrcp_handle_incoming_connection_for_role(AVRCP_CONTROLLER, connection_controller, event_addr, local_cid, avrcp_cid);
743a062fcddSMilanka Ringwald                         if ((connection_target == NULL) || (connection_controller == NULL)){
7449b1b0ebdSMatthias Ringwald                             decline_connection = true;
745a062fcddSMilanka Ringwald                             if (connection_target) {
746a062fcddSMilanka Ringwald                                 avrcp_finalize_connection(connection_target);
747a062fcddSMilanka Ringwald                             }
748a062fcddSMilanka Ringwald                             if (connection_controller) {
749a062fcddSMilanka Ringwald                                 avrcp_finalize_connection(connection_controller);
750a062fcddSMilanka Ringwald                             }
7510036e267SMilanka Ringwald                         }
7529b1b0ebdSMatthias Ringwald                     }
7539b1b0ebdSMatthias Ringwald                     if (decline_connection){
7549b1b0ebdSMatthias Ringwald                         l2cap_decline_connection(local_cid);
7559b1b0ebdSMatthias Ringwald                     } else {
7560036e267SMilanka Ringwald                         log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION avrcp_cid 0x%02x", local_cid);
7570036e267SMilanka Ringwald                         l2cap_accept_connection(local_cid);
7589b1b0ebdSMatthias Ringwald                     }
7590036e267SMilanka Ringwald                     break;
7600036e267SMilanka Ringwald 
7610036e267SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
7620036e267SMilanka Ringwald                     l2cap_event_channel_opened_get_address(packet, event_addr);
7630036e267SMilanka Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
7640036e267SMilanka Ringwald                     local_cid = l2cap_event_channel_opened_get_local_cid(packet);
7650036e267SMilanka Ringwald                     l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet);
7660036e267SMilanka Ringwald 
767cee0e5b6SMilanka Ringwald                     connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr);
768cee0e5b6SMilanka Ringwald                     connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr);
769a062fcddSMilanka Ringwald 
770a062fcddSMilanka Ringwald                     // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION
771a062fcddSMilanka Ringwald                     // outgoing: structs are cteated in avrcp_connect()
772cee0e5b6SMilanka Ringwald                     if ((connection_controller == NULL) || (connection_target == NULL)) {
773cee0e5b6SMilanka Ringwald                         break;
774cee0e5b6SMilanka Ringwald                     }
775cee0e5b6SMilanka Ringwald 
776a062fcddSMilanka Ringwald                     switch (status){
777a062fcddSMilanka Ringwald                         case ERROR_CODE_SUCCESS:
778a062fcddSMilanka Ringwald                             avrcp_handle_open_connection_for_role(connection_target, local_cid, l2cap_mtu);
779a062fcddSMilanka Ringwald                             avrcp_handle_open_connection_for_role(connection_controller, local_cid, l2cap_mtu);
780a062fcddSMilanka Ringwald                             avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, status);
781a062fcddSMilanka Ringwald                             return;
782a062fcddSMilanka Ringwald                         case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES:
783a062fcddSMilanka Ringwald                             if (connection_controller->incoming_declined == true){
784a062fcddSMilanka Ringwald                                 log_info("Incoming connection was declined, and the outgoing failed");
785a062fcddSMilanka Ringwald                                 connection_controller->state = AVCTP_CONNECTION_W2_L2CAP_RECONNECT;
786a062fcddSMilanka Ringwald                                 connection_controller->incoming_declined = false;
787a062fcddSMilanka Ringwald                                 connection_target->state = AVCTP_CONNECTION_W2_L2CAP_RECONNECT;
788a062fcddSMilanka Ringwald                                 connection_target->incoming_declined = false;
789a062fcddSMilanka Ringwald                                 avrcp_reconnect_timer_start(connection_controller);
790a062fcddSMilanka Ringwald                                 return;
791a062fcddSMilanka Ringwald                             }
792a062fcddSMilanka Ringwald                             break;
793a062fcddSMilanka Ringwald                         default:
794a062fcddSMilanka Ringwald                             break;
795a062fcddSMilanka Ringwald                     }
796cee0e5b6SMilanka Ringwald                     log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status);
797cee0e5b6SMilanka Ringwald                     avrcp_emit_connection_established(connection_controller->avrcp_cid, event_addr, status);
798cee0e5b6SMilanka Ringwald                     avrcp_finalize_connection(connection_controller);
799cee0e5b6SMilanka Ringwald                     avrcp_finalize_connection(connection_target);
800cee0e5b6SMilanka Ringwald 
801be32e7f1SMilanka Ringwald                     break;
802be32e7f1SMilanka Ringwald 
803be32e7f1SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
804be32e7f1SMilanka Ringwald                     local_cid = l2cap_event_channel_closed_get_local_cid(packet);
805cee0e5b6SMilanka Ringwald 
806cee0e5b6SMilanka Ringwald                     connection_controller = get_avrcp_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid);
807cee0e5b6SMilanka Ringwald                     connection_target = get_avrcp_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid);
808cee0e5b6SMilanka Ringwald                     if ((connection_controller == NULL) || (connection_target == NULL)) {
809cee0e5b6SMilanka Ringwald                         break;
810cee0e5b6SMilanka Ringwald                     }
811cee0e5b6SMilanka Ringwald                     avrcp_emit_connection_closed(connection_controller->avrcp_cid);
812cee0e5b6SMilanka Ringwald                     avrcp_finalize_connection(connection_controller);
813cee0e5b6SMilanka Ringwald 
814cee0e5b6SMilanka Ringwald                     avrcp_emit_connection_closed(connection_target->avrcp_cid);
815cee0e5b6SMilanka Ringwald                     avrcp_finalize_connection(connection_target);
8160036e267SMilanka Ringwald                     break;
8170036e267SMilanka Ringwald 
8180036e267SMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
8190036e267SMilanka Ringwald                     local_cid = l2cap_event_can_send_now_get_local_cid(packet);
820e3d57ee2SMilanka Ringwald 
821cee0e5b6SMilanka Ringwald                     connection_target = get_avrcp_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid);
822*cf36dea0SMilanka Ringwald                     if ((connection_target != NULL) && connection_target->wait_to_send){
823*cf36dea0SMilanka Ringwald                         connection_target->wait_to_send = false;
8240036e267SMilanka Ringwald                         (*avrcp_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size);
8250036e267SMilanka Ringwald                         break;
8260036e267SMilanka Ringwald                     }
8270036e267SMilanka Ringwald 
828cee0e5b6SMilanka Ringwald                     connection_controller = get_avrcp_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid);
829*cf36dea0SMilanka Ringwald                     if ((connection_controller != NULL) && connection_controller->wait_to_send){
830*cf36dea0SMilanka Ringwald                         connection_controller->wait_to_send = false;
8310036e267SMilanka Ringwald                         (*avrcp_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size);
832be32e7f1SMilanka Ringwald                         break;
833be32e7f1SMilanka Ringwald                     }
834be32e7f1SMilanka Ringwald                     break;
8350036e267SMilanka Ringwald 
836be32e7f1SMilanka Ringwald                 default:
837be32e7f1SMilanka Ringwald                     break;
838be32e7f1SMilanka Ringwald             }
839b106f728SMilanka Ringwald             break;
840e3d57ee2SMilanka Ringwald 
841e3d57ee2SMilanka Ringwald         case L2CAP_DATA_PACKET:
842b8081399SMilanka Ringwald             switch (avrcp_get_frame_type(packet[0])){
843e3d57ee2SMilanka Ringwald                 case AVRCP_RESPONSE_FRAME:
844e3d57ee2SMilanka Ringwald                     (*avrcp_controller_packet_handler)(packet_type, channel, packet, size);
845e3d57ee2SMilanka Ringwald                     break;
846e3d57ee2SMilanka Ringwald                 case AVRCP_COMMAND_FRAME:
847e3d57ee2SMilanka Ringwald                 default:    // make compiler happy
848e3d57ee2SMilanka Ringwald                     (*avrcp_target_packet_handler)(packet_type, channel, packet, size);
849e3d57ee2SMilanka Ringwald                     break;
850e3d57ee2SMilanka Ringwald             }
851e3d57ee2SMilanka Ringwald             break;
852e3d57ee2SMilanka Ringwald 
853b106f728SMilanka Ringwald         default:
854b106f728SMilanka Ringwald             break;
855b106f728SMilanka Ringwald     }
856be32e7f1SMilanka Ringwald }
857be32e7f1SMilanka Ringwald 
858fe10780bSMilanka Ringwald uint8_t avrcp_disconnect(uint16_t avrcp_cid){
859fe10780bSMilanka Ringwald     avrcp_connection_t * connection_controller = get_avrcp_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid);
860fe10780bSMilanka Ringwald     if (!connection_controller){
861fe10780bSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
862fe10780bSMilanka Ringwald     }
863fe10780bSMilanka Ringwald     avrcp_connection_t * connection_target = get_avrcp_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid);
864fe10780bSMilanka Ringwald     if (!connection_target){
865fe10780bSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
866fe10780bSMilanka Ringwald     }
867fe10780bSMilanka Ringwald     if (connection_controller->browsing_connection){
868fe10780bSMilanka Ringwald         l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid, 0);
869fe10780bSMilanka Ringwald     }
870fe10780bSMilanka Ringwald     l2cap_disconnect(connection_controller->l2cap_signaling_cid, 0);
871fe10780bSMilanka Ringwald     return ERROR_CODE_SUCCESS;
872fe10780bSMilanka Ringwald }
873fe10780bSMilanka Ringwald 
874fe10780bSMilanka Ringwald uint8_t avrcp_connect(bd_addr_t remote_addr, uint16_t * avrcp_cid){
875e3d57ee2SMilanka Ringwald     btstack_assert(avrcp_controller_packet_handler != NULL);
876e3d57ee2SMilanka Ringwald     btstack_assert(avrcp_target_packet_handler != NULL);
877f9ef80eaSMilanka Ringwald 
878bd66227aSMilanka Ringwald     // TODO: implement delayed SDP query
879bd66227aSMilanka Ringwald     if (sdp_client_ready() == 0){
880bd66227aSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
881dd5e5981SMatthias Ringwald     }
8825dd5e7e3SMilanka Ringwald 
883bd66227aSMilanka Ringwald     avrcp_connection_t * connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr);
884bd66227aSMilanka Ringwald     if (connection_controller){
885bd66227aSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
886bd66227aSMilanka Ringwald     }
887bd66227aSMilanka Ringwald     avrcp_connection_t * connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr);
888bd66227aSMilanka Ringwald     if (connection_target){
889bd66227aSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
890bd66227aSMilanka Ringwald     }
891bd66227aSMilanka Ringwald 
8927403cbbaSMilanka Ringwald     uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER);
8937403cbbaSMilanka Ringwald 
894bd66227aSMilanka Ringwald     connection_controller = avrcp_create_connection(AVRCP_CONTROLLER, remote_addr);
895bd66227aSMilanka Ringwald     if (!connection_controller) return BTSTACK_MEMORY_ALLOC_FAILED;
896bd66227aSMilanka Ringwald 
897bd66227aSMilanka Ringwald     connection_target = avrcp_create_connection(AVRCP_TARGET, remote_addr);
898bd66227aSMilanka Ringwald     if (!connection_target){
899bd66227aSMilanka Ringwald         avrcp_finalize_connection(connection_controller);
900bd66227aSMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
901bd66227aSMilanka Ringwald     }
902bd66227aSMilanka Ringwald 
903bd66227aSMilanka Ringwald     if (avrcp_cid != NULL){
904bd66227aSMilanka Ringwald         *avrcp_cid = cid;
905bd66227aSMilanka Ringwald     }
906bd66227aSMilanka Ringwald 
907bd66227aSMilanka Ringwald     connection_controller->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
9087403cbbaSMilanka Ringwald     connection_controller->avrcp_cid = cid;
9097403cbbaSMilanka Ringwald 
910bd66227aSMilanka Ringwald     connection_target->state     = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
9117403cbbaSMilanka Ringwald     connection_target->avrcp_cid = cid;
9125dd5e7e3SMilanka Ringwald 
913e3d57ee2SMilanka Ringwald     sdp_query_context = &avrcp_context;
9145dd5e7e3SMilanka Ringwald     sdp_query_context->avrcp_l2cap_psm = 0;
9155dd5e7e3SMilanka Ringwald     sdp_query_context->avrcp_version  = 0;
916bd66227aSMilanka Ringwald     sdp_query_context->avrcp_cid = cid;
917bd66227aSMilanka Ringwald     memcpy(sdp_query_context->remote_addr, remote_addr, 6);
9185dd5e7e3SMilanka Ringwald 
919bd66227aSMilanka Ringwald     sdp_client_query_uuid16(&avrcp_handle_sdp_client_query_result, remote_addr, BLUETOOTH_PROTOCOL_AVCTP);
920f9ef80eaSMilanka Ringwald     return ERROR_CODE_SUCCESS;
921be32e7f1SMilanka Ringwald }
922638481deSMilanka Ringwald 
923638481deSMilanka Ringwald void avrcp_init(void){
924638481deSMilanka Ringwald     connections = NULL;
925b106f728SMilanka Ringwald     if (l2cap_service_registered) return;
9260036e267SMilanka Ringwald 
92778315a58SMatthias Ringwald     int status = l2cap_register_service(&avrcp_packet_handler, BLUETOOTH_PSM_AVCTP, 0xffff, gap_get_security_level());
928b106f728SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return;
9290eebc132SMilanka Ringwald     l2cap_service_registered = true;
930638481deSMilanka Ringwald }
931b106f728SMilanka Ringwald 
932b106f728SMilanka Ringwald void avrcp_register_controller_packet_handler(btstack_packet_handler_t callback){
933b106f728SMilanka Ringwald     avrcp_controller_packet_handler = callback;
934b106f728SMilanka Ringwald }
935b106f728SMilanka Ringwald 
936b106f728SMilanka Ringwald void avrcp_register_target_packet_handler(btstack_packet_handler_t callback){
937b106f728SMilanka Ringwald     avrcp_target_packet_handler = callback;
938b106f728SMilanka Ringwald }
939b106f728SMilanka Ringwald 
940cee0e5b6SMilanka Ringwald void avrcp_register_packet_handler(btstack_packet_handler_t callback){
941cee0e5b6SMilanka Ringwald     btstack_assert(callback != NULL);
942cee0e5b6SMilanka Ringwald     avrcp_callback = callback;
943cee0e5b6SMilanka Ringwald }
944b99ca858SMilanka Ringwald 
945b99ca858SMilanka Ringwald // AVRCP Browsing Service functions
9463121b998SMilanka Ringwald static void avrcp_browsing_finalize_connection(avrcp_connection_t * connection){
9473121b998SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->browsing_connection->reconnect_timer);
9483121b998SMilanka Ringwald     btstack_memory_avrcp_browsing_connection_free(connection->browsing_connection);
9493121b998SMilanka Ringwald     connection->browsing_connection = NULL;
950b99ca858SMilanka Ringwald }
951b99ca858SMilanka Ringwald 
952f4ffe59aSMilanka Ringwald static void avrcp_browsing_emit_connection_established(uint16_t browsing_cid, bd_addr_t addr, uint8_t status){
9530eebc132SMilanka Ringwald     btstack_assert(avrcp_browsing_callback != NULL);
954119bdcb2SMilanka Ringwald 
955119bdcb2SMilanka Ringwald     uint8_t event[12];
956119bdcb2SMilanka Ringwald     int pos = 0;
957119bdcb2SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
958119bdcb2SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
959119bdcb2SMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED;
960119bdcb2SMilanka Ringwald     event[pos++] = status;
961119bdcb2SMilanka Ringwald     reverse_bd_addr(addr,&event[pos]);
962119bdcb2SMilanka Ringwald     pos += 6;
963119bdcb2SMilanka Ringwald     little_endian_store_16(event, pos, browsing_cid);
964119bdcb2SMilanka Ringwald     pos += 2;
9650eebc132SMilanka Ringwald     (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
966119bdcb2SMilanka Ringwald }
967119bdcb2SMilanka Ringwald 
968f4ffe59aSMilanka Ringwald static void avrcp_browsing_emit_incoming_connection(uint16_t browsing_cid, bd_addr_t addr){
9690eebc132SMilanka Ringwald     btstack_assert(avrcp_browsing_callback != NULL);
970119bdcb2SMilanka Ringwald 
971119bdcb2SMilanka Ringwald     uint8_t event[11];
972119bdcb2SMilanka Ringwald     int pos = 0;
973119bdcb2SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
974119bdcb2SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
975119bdcb2SMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_INCOMING_BROWSING_CONNECTION;
976119bdcb2SMilanka Ringwald     reverse_bd_addr(addr,&event[pos]);
977119bdcb2SMilanka Ringwald     pos += 6;
978119bdcb2SMilanka Ringwald     little_endian_store_16(event, pos, browsing_cid);
979119bdcb2SMilanka Ringwald     pos += 2;
9800eebc132SMilanka Ringwald     (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
981119bdcb2SMilanka Ringwald }
982119bdcb2SMilanka Ringwald 
983f4ffe59aSMilanka Ringwald static void avrcp_browsing_emit_connection_closed(uint16_t browsing_cid){
9840eebc132SMilanka Ringwald     btstack_assert(avrcp_browsing_callback != NULL);
985119bdcb2SMilanka Ringwald 
986119bdcb2SMilanka Ringwald     uint8_t event[5];
987119bdcb2SMilanka Ringwald     int pos = 0;
988119bdcb2SMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
989119bdcb2SMilanka Ringwald     event[pos++] = sizeof(event) - 2;
990119bdcb2SMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED;
991119bdcb2SMilanka Ringwald     little_endian_store_16(event, pos, browsing_cid);
992119bdcb2SMilanka Ringwald     pos += 2;
9930eebc132SMilanka Ringwald     (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
994119bdcb2SMilanka Ringwald }
995119bdcb2SMilanka Ringwald 
9960eebc132SMilanka Ringwald 
997a6344352SMilanka Ringwald static avrcp_browsing_connection_t * avrcp_browsing_create_connection(avrcp_connection_t * avrcp_connection, uint16_t avrcp_browsing_cid){
9983121b998SMilanka Ringwald     avrcp_browsing_connection_t * browsing_connection = btstack_memory_avrcp_browsing_connection_get();
9993121b998SMilanka Ringwald     if (!browsing_connection){
10003121b998SMilanka Ringwald         log_error("Not enough memory to create browsing connection");
10013121b998SMilanka Ringwald         return NULL;
10023121b998SMilanka Ringwald     }
10033121b998SMilanka Ringwald     browsing_connection->state = AVCTP_CONNECTION_IDLE;
10043121b998SMilanka Ringwald     browsing_connection->transaction_label = 0xFF;
10053121b998SMilanka Ringwald 
10063121b998SMilanka Ringwald     avrcp_connection->avrcp_browsing_cid = avrcp_browsing_cid;
10073121b998SMilanka Ringwald     avrcp_connection->browsing_connection = browsing_connection;
10083121b998SMilanka Ringwald 
10093121b998SMilanka Ringwald     log_info("avrcp_browsing_create_connection, avrcp cid 0x%02x", avrcp_connection->avrcp_browsing_cid);
10103121b998SMilanka Ringwald     return browsing_connection;
10113121b998SMilanka Ringwald }
10123121b998SMilanka Ringwald 
1013a6344352SMilanka Ringwald static void avrcp_browsing_configure_ertm(avrcp_browsing_connection_t * browsing_connection, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config){
1014a6344352SMilanka Ringwald     browsing_connection->ertm_buffer = ertm_buffer;
1015a6344352SMilanka Ringwald     browsing_connection->ertm_buffer_size = ertm_buffer_size;
1016a6344352SMilanka Ringwald 
1017a6344352SMilanka Ringwald     if (ertm_buffer_size > 0) {
1018a6344352SMilanka Ringwald         (void)memcpy(&browsing_connection->ertm_config, ertm_config,
1019a6344352SMilanka Ringwald                  sizeof(l2cap_ertm_config_t));
1020a6344352SMilanka Ringwald         log_info("avrcp_browsing_configure_ertm");
1021a6344352SMilanka Ringwald     }
1022a6344352SMilanka Ringwald }
10233121b998SMilanka Ringwald 
10243121b998SMilanka Ringwald static avrcp_browsing_connection_t * avrcp_browsing_handle_incoming_connection(avrcp_connection_t * connection, uint16_t local_cid, uint16_t avrcp_browsing_cid){
10253121b998SMilanka Ringwald     if (connection->browsing_connection == NULL){
1026a6344352SMilanka Ringwald         avrcp_browsing_create_connection(connection, avrcp_browsing_cid);
10273121b998SMilanka Ringwald     }
10283121b998SMilanka Ringwald     if (connection->browsing_connection) {
10293121b998SMilanka Ringwald         connection->browsing_connection->l2cap_browsing_cid = local_cid;
10303121b998SMilanka Ringwald         connection->browsing_connection->state = AVCTP_CONNECTION_W4_ERTM_CONFIGURATION;
10313121b998SMilanka Ringwald         btstack_run_loop_remove_timer(&connection->browsing_connection->reconnect_timer);
10323121b998SMilanka Ringwald     }
10333121b998SMilanka Ringwald     return connection->browsing_connection;
10343121b998SMilanka Ringwald }
10353121b998SMilanka Ringwald 
10363121b998SMilanka Ringwald static void avrcp_browsing_handle_open_connection_for_role(avrcp_connection_t * connection, uint16_t local_cid){
10373121b998SMilanka Ringwald     connection->browsing_connection->l2cap_browsing_cid = local_cid;
10383121b998SMilanka Ringwald     connection->browsing_connection->incoming_declined = false;
10393121b998SMilanka Ringwald     connection->browsing_connection->state = AVCTP_CONNECTION_OPENED;
10403121b998SMilanka Ringwald     log_info("L2CAP_EVENT_CHANNEL_OPENED browsing_avrcp_cid 0x%02x, l2cap_signaling_cid 0x%02x, role %d", connection->avrcp_cid, connection->l2cap_signaling_cid, connection->role);
10413121b998SMilanka Ringwald }
10423121b998SMilanka Ringwald 
10430eebc132SMilanka Ringwald static void avrcp_browsing_packet_handler_with_role(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size, avrcp_role_t avrcp_role){
104412c4a6eeSMilanka Ringwald     UNUSED(channel);
104512c4a6eeSMilanka Ringwald     UNUSED(size);
104612c4a6eeSMilanka Ringwald     bd_addr_t event_addr;
104712c4a6eeSMilanka Ringwald     uint16_t local_cid;
104812c4a6eeSMilanka Ringwald     uint8_t  status;
10493121b998SMilanka Ringwald     bool decline_connection;
10503121b998SMilanka Ringwald     bool outoing_active;
10510eebc132SMilanka Ringwald 
10523121b998SMilanka Ringwald     btstack_packet_handler_t browsing_callback;
10533121b998SMilanka Ringwald     avrcp_connection_t * connection_controller;
10543121b998SMilanka Ringwald     avrcp_connection_t * connection_target;
1055b8081399SMilanka Ringwald 
1056b8081399SMilanka Ringwald     switch (packet_type){
1057b8081399SMilanka Ringwald         case L2CAP_DATA_PACKET:
1058b8081399SMilanka Ringwald             switch (avrcp_get_frame_type(packet[0])){
1059b8081399SMilanka Ringwald                 case AVRCP_RESPONSE_FRAME:
1060b8081399SMilanka Ringwald                     (*avrcp_browsing_controller_packet_handler)(packet_type, channel, packet, size);
1061b8081399SMilanka Ringwald                     break;
1062b8081399SMilanka Ringwald                 case AVRCP_COMMAND_FRAME:
1063b8081399SMilanka Ringwald                 default:    // make compiler happy
1064b8081399SMilanka Ringwald                     (*avrcp_browsing_target_packet_handler)(packet_type, channel, packet, size);
1065b8081399SMilanka Ringwald                     break;
1066b8081399SMilanka Ringwald             }
1067b8081399SMilanka Ringwald             break;
1068b8081399SMilanka Ringwald         case HCI_EVENT_PACKET:
10690eebc132SMilanka Ringwald              switch (avrcp_role){
10700eebc132SMilanka Ringwald                 case AVRCP_CONTROLLER:
10710eebc132SMilanka Ringwald                     browsing_callback = avrcp_browsing_controller_packet_handler;
10720eebc132SMilanka Ringwald                     break;
10730eebc132SMilanka Ringwald                 case AVRCP_TARGET:
10740eebc132SMilanka Ringwald                 default:
1075b8081399SMilanka Ringwald                     browsing_callback = avrcp_browsing_target_packet_handler;
10760eebc132SMilanka Ringwald                     break;
10770eebc132SMilanka Ringwald             }
10780eebc132SMilanka Ringwald             btstack_assert(browsing_callback != NULL);
10790eebc132SMilanka Ringwald 
108012c4a6eeSMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
10810eebc132SMilanka Ringwald 
108212c4a6eeSMilanka Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
10833121b998SMilanka Ringwald                     btstack_assert(avrcp_browsing_controller_packet_handler != NULL);
10843121b998SMilanka Ringwald                     btstack_assert(avrcp_browsing_target_packet_handler != NULL);
10853121b998SMilanka Ringwald 
108612c4a6eeSMilanka Ringwald                     l2cap_event_incoming_connection_get_address(packet, event_addr);
108712c4a6eeSMilanka Ringwald                     local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
10883121b998SMilanka Ringwald                     outoing_active = false;
10893121b998SMilanka Ringwald 
10903121b998SMilanka Ringwald                     connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr);
10913121b998SMilanka Ringwald                     connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr);
10923121b998SMilanka Ringwald 
10933121b998SMilanka Ringwald                     if (connection_target == NULL || connection_controller == NULL) {
109412c4a6eeSMilanka Ringwald                         l2cap_decline_connection(local_cid);
10953121b998SMilanka Ringwald                         return;
109612c4a6eeSMilanka Ringwald                     }
10973121b998SMilanka Ringwald 
10983121b998SMilanka Ringwald                     if (connection_target->browsing_connection != NULL){
10993121b998SMilanka Ringwald                         if (connection_target->browsing_connection->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){
11003121b998SMilanka Ringwald                             outoing_active = true;
11013121b998SMilanka Ringwald                             connection_target->browsing_connection->incoming_declined = true;
11023121b998SMilanka Ringwald                         }
11033121b998SMilanka Ringwald                     }
11043121b998SMilanka Ringwald 
11053121b998SMilanka Ringwald                     if (connection_controller->browsing_connection != NULL){
11063121b998SMilanka Ringwald                         if (connection_controller->browsing_connection->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) {
11073121b998SMilanka Ringwald                             outoing_active = true;
11083121b998SMilanka Ringwald                             connection_controller->browsing_connection->incoming_declined = true;
11093121b998SMilanka Ringwald                         }
11103121b998SMilanka Ringwald                     }
11113121b998SMilanka Ringwald 
11123121b998SMilanka Ringwald                     decline_connection = outoing_active;
11133121b998SMilanka Ringwald                     if (decline_connection == false){
11143121b998SMilanka Ringwald                         uint16_t avrcp_browsing_cid;
11153121b998SMilanka Ringwald                         if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)){
11163121b998SMilanka Ringwald                             avrcp_browsing_cid = avrcp_get_next_cid(AVRCP_CONTROLLER);
11173121b998SMilanka Ringwald                         } else {
11183121b998SMilanka Ringwald                             avrcp_browsing_cid = connection_controller->avrcp_browsing_cid;
11193121b998SMilanka Ringwald                         }
11203121b998SMilanka Ringwald 
11213121b998SMilanka Ringwald                         // create two connection objects (both)
11223121b998SMilanka Ringwald                         connection_target->browsing_connection     = avrcp_browsing_handle_incoming_connection(connection_target, local_cid, avrcp_browsing_cid);
11233121b998SMilanka Ringwald                         connection_controller->browsing_connection = avrcp_browsing_handle_incoming_connection(connection_controller, local_cid, avrcp_browsing_cid);
11243121b998SMilanka Ringwald 
11253121b998SMilanka Ringwald                         if ((connection_target->browsing_connection  == NULL) || (connection_controller->browsing_connection == NULL)){
11263121b998SMilanka Ringwald                             decline_connection = true;
11273121b998SMilanka Ringwald                             if (connection_target->browsing_connection) {
11283121b998SMilanka Ringwald                                 avrcp_browsing_finalize_connection(connection_target);
11293121b998SMilanka Ringwald                             }
11303121b998SMilanka Ringwald                             if (connection_controller->browsing_connection) {
11313121b998SMilanka Ringwald                                 avrcp_browsing_finalize_connection(connection_controller);
11323121b998SMilanka Ringwald                             }
11333121b998SMilanka Ringwald                         }
11343121b998SMilanka Ringwald                     }
11353121b998SMilanka Ringwald                     if (decline_connection){
11363121b998SMilanka Ringwald                         l2cap_decline_connection(local_cid);
11373121b998SMilanka Ringwald                     } else {
11383121b998SMilanka Ringwald                         log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION browsing_avrcp_cid 0x%02x", connection_controller->avrcp_browsing_cid);
1139f4ffe59aSMilanka Ringwald                         avrcp_browsing_emit_incoming_connection(connection_controller->avrcp_browsing_cid, event_addr);
11403121b998SMilanka Ringwald                     }
114112c4a6eeSMilanka Ringwald                     break;
114212c4a6eeSMilanka Ringwald 
114312c4a6eeSMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
114412c4a6eeSMilanka Ringwald                     l2cap_event_channel_opened_get_address(packet, event_addr);
114512c4a6eeSMilanka Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
114612c4a6eeSMilanka Ringwald                     local_cid = l2cap_event_channel_opened_get_local_cid(packet);
114712c4a6eeSMilanka Ringwald 
11483121b998SMilanka Ringwald                     connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr);
1149f4ffe59aSMilanka Ringwald                     connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr);
1150f4ffe59aSMilanka Ringwald 
1151f4ffe59aSMilanka Ringwald                     // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION
1152f4ffe59aSMilanka Ringwald                     // outgoing: structs are cteated in avrcp_connect() and avrcp_browsing_connect()
1153f4ffe59aSMilanka Ringwald                     if ((connection_controller == NULL) || (connection_target == NULL)) {
1154f4ffe59aSMilanka Ringwald                         break;
1155f4ffe59aSMilanka Ringwald                     }
1156f4ffe59aSMilanka Ringwald                     if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)) {
115712c4a6eeSMilanka Ringwald                         break;
115812c4a6eeSMilanka Ringwald                     }
115912c4a6eeSMilanka Ringwald 
1160f4ffe59aSMilanka Ringwald                     switch (status){
1161f4ffe59aSMilanka Ringwald                         case ERROR_CODE_SUCCESS:
1162f4ffe59aSMilanka Ringwald                             avrcp_browsing_handle_open_connection_for_role(connection_target, local_cid);
1163f4ffe59aSMilanka Ringwald                             avrcp_browsing_handle_open_connection_for_role(connection_controller, local_cid);
1164f4ffe59aSMilanka Ringwald                             avrcp_browsing_emit_connection_established(connection_controller->avrcp_browsing_cid, event_addr, status);
1165f4ffe59aSMilanka Ringwald                             return;
1166f4ffe59aSMilanka Ringwald                         case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES:
1167f4ffe59aSMilanka Ringwald                             if (connection_controller->browsing_connection->incoming_declined == true){
1168f4ffe59aSMilanka Ringwald                                 log_info("Incoming browsing connection was declined, and the outgoing failed");
1169f4ffe59aSMilanka Ringwald                                 connection_controller->browsing_connection->state = AVCTP_CONNECTION_W2_L2CAP_RECONNECT;
1170f4ffe59aSMilanka Ringwald                                 connection_controller->browsing_connection->incoming_declined = false;
1171f4ffe59aSMilanka Ringwald                                 connection_target->browsing_connection->state = AVCTP_CONNECTION_W2_L2CAP_RECONNECT;
1172f4ffe59aSMilanka Ringwald                                 connection_target->browsing_connection->incoming_declined = false;
1173f4ffe59aSMilanka Ringwald                                 avrcp_reconnect_timer_start(connection_controller);
1174f4ffe59aSMilanka Ringwald                                 return;
1175f4ffe59aSMilanka Ringwald                             }
1176f4ffe59aSMilanka Ringwald                             break;
1177f4ffe59aSMilanka Ringwald                         default:
1178f4ffe59aSMilanka Ringwald                             break;
1179f4ffe59aSMilanka Ringwald                     }
118012c4a6eeSMilanka Ringwald                     log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status);
1181f4ffe59aSMilanka Ringwald                     avrcp_browsing_emit_connection_established(connection_controller->avrcp_browsing_cid, event_addr, status);
118261bf14d6SMilanka Ringwald                     avrcp_browsing_finalize_connection(connection_controller);
118361bf14d6SMilanka Ringwald                     avrcp_browsing_finalize_connection(connection_target);
118412c4a6eeSMilanka Ringwald                     break;
118512c4a6eeSMilanka Ringwald 
118612c4a6eeSMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
118712c4a6eeSMilanka Ringwald                     local_cid = l2cap_event_channel_closed_get_local_cid(packet);
118812c4a6eeSMilanka Ringwald 
118961bf14d6SMilanka Ringwald                     connection_controller = get_avrcp_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid);
119061bf14d6SMilanka Ringwald                     connection_target = get_avrcp_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid);
119161bf14d6SMilanka Ringwald                     if ((connection_controller == NULL) || (connection_target == NULL)) {
119212c4a6eeSMilanka Ringwald                         break;
119312c4a6eeSMilanka Ringwald                     }
119461bf14d6SMilanka Ringwald                     if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)) {
119512c4a6eeSMilanka Ringwald                         break;
119661bf14d6SMilanka Ringwald                     }
119761bf14d6SMilanka Ringwald                     avrcp_browsing_emit_connection_closed(connection_controller->avrcp_browsing_cid);
119861bf14d6SMilanka Ringwald                     avrcp_browsing_finalize_connection(connection_controller);
119961bf14d6SMilanka Ringwald 
120061bf14d6SMilanka Ringwald                     avrcp_browsing_emit_connection_closed(connection_target->avrcp_browsing_cid);
120161bf14d6SMilanka Ringwald                     avrcp_browsing_finalize_connection(connection_target);
12023121b998SMilanka Ringwald                     break;
120361bf14d6SMilanka Ringwald 
12043121b998SMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
1205eab0c1eeSMilanka Ringwald                     local_cid = l2cap_event_can_send_now_get_local_cid(packet);
1206eab0c1eeSMilanka Ringwald 
1207eab0c1eeSMilanka Ringwald                     connection_target = get_avrcp_connection_for_l2cap_signaling_cid_for_role(AVRCP_TARGET, local_cid);
1208eab0c1eeSMilanka Ringwald                     if ((connection_target != NULL) && (connection_target->browsing_connection != NULL) && connection_target->browsing_connection->wait_to_send) {
1209eab0c1eeSMilanka Ringwald                         connection_target->browsing_connection->wait_to_send = false;
1210eab0c1eeSMilanka Ringwald                         (*avrcp_browsing_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size);
1211eab0c1eeSMilanka Ringwald                         break;
1212eab0c1eeSMilanka Ringwald                     }
1213eab0c1eeSMilanka Ringwald 
1214eab0c1eeSMilanka Ringwald                     connection_controller = get_avrcp_connection_for_l2cap_signaling_cid_for_role(AVRCP_CONTROLLER, local_cid);
1215eab0c1eeSMilanka Ringwald                     if ((connection_controller != NULL) && (connection_controller->browsing_connection != NULL) && connection_controller->browsing_connection->wait_to_send) {
1216eab0c1eeSMilanka Ringwald                         connection_controller->browsing_connection->wait_to_send = false;
1217eab0c1eeSMilanka Ringwald                         (*avrcp_browsing_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size);
1218eab0c1eeSMilanka Ringwald                         break;
1219eab0c1eeSMilanka Ringwald                     }
12203121b998SMilanka Ringwald                     break;
12213121b998SMilanka Ringwald 
122212c4a6eeSMilanka Ringwald                 default:
122312c4a6eeSMilanka Ringwald                     break;
122412c4a6eeSMilanka Ringwald             }
12250eebc132SMilanka Ringwald             break;
12260eebc132SMilanka Ringwald         default:
12270eebc132SMilanka Ringwald             break;
122812c4a6eeSMilanka Ringwald     }
122912c4a6eeSMilanka Ringwald 
12300eebc132SMilanka Ringwald }
12310eebc132SMilanka Ringwald 
12320eebc132SMilanka Ringwald static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
12330eebc132SMilanka Ringwald     avrcp_browsing_packet_handler_with_role(packet_type, channel, packet, size, AVRCP_CONTROLLER);
12340eebc132SMilanka Ringwald     // avrcp_browsing_packet_handler_with_role(packet_type, channel, packet, size, AVRCP_TARGET);
12350eebc132SMilanka Ringwald }
12360eebc132SMilanka Ringwald 
12370eebc132SMilanka Ringwald void avrcp_browsing_init(void){
12380eebc132SMilanka Ringwald     if (l2cap_browsing_service_registered) return;
12390eebc132SMilanka Ringwald     int status = l2cap_register_service(&avrcp_browsing_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_2);
12400eebc132SMilanka Ringwald 
12410eebc132SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return;
12420eebc132SMilanka Ringwald     l2cap_browsing_service_registered = true;
12430eebc132SMilanka Ringwald }
12440eebc132SMilanka Ringwald 
1245b99ca858SMilanka Ringwald 
12463121b998SMilanka Ringwald uint8_t avrcp_browsing_connect(bd_addr_t remote_addr, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid){
12473121b998SMilanka Ringwald     btstack_assert(avrcp_browsing_controller_packet_handler != NULL);
12483121b998SMilanka Ringwald     btstack_assert(avrcp_browsing_target_packet_handler != NULL);
12493121b998SMilanka Ringwald 
12503121b998SMilanka Ringwald     avrcp_connection_t * connection_controller = get_avrcp_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr);
12513121b998SMilanka Ringwald     if (!connection_controller){
12523121b998SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12533121b998SMilanka Ringwald     }
12543121b998SMilanka Ringwald     avrcp_connection_t * connection_target = get_avrcp_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr);
12553121b998SMilanka Ringwald     if (!connection_target){
1256b99ca858SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1257b99ca858SMilanka Ringwald     }
1258b99ca858SMilanka Ringwald 
1259a6344352SMilanka Ringwald     if (connection_controller->browsing_connection){
12603121b998SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12613121b998SMilanka Ringwald     }
1262a6344352SMilanka Ringwald     if (connection_target->browsing_connection){
12633121b998SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1264b99ca858SMilanka Ringwald     }
1265b99ca858SMilanka Ringwald 
12663121b998SMilanka Ringwald     uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER);
12673121b998SMilanka Ringwald 
1268a6344352SMilanka Ringwald     connection_controller->browsing_connection = avrcp_browsing_create_connection(connection_controller, cid);
1269a6344352SMilanka Ringwald     if (!connection_controller->browsing_connection) return BTSTACK_MEMORY_ALLOC_FAILED;
12703121b998SMilanka Ringwald 
1271a6344352SMilanka Ringwald     connection_target->browsing_connection = avrcp_browsing_create_connection(connection_target, cid);
1272a6344352SMilanka Ringwald     if (!connection_target->browsing_connection){
12733121b998SMilanka Ringwald         avrcp_browsing_finalize_connection(connection_controller);
1274b99ca858SMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
1275b99ca858SMilanka Ringwald     }
1276a6344352SMilanka Ringwald     avrcp_browsing_configure_ertm(connection_controller->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config);
1277a6344352SMilanka Ringwald     avrcp_browsing_configure_ertm(connection_target->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config);
1278b99ca858SMilanka Ringwald 
12793121b998SMilanka Ringwald     if (avrcp_browsing_cid != NULL){
12803121b998SMilanka Ringwald         *avrcp_browsing_cid = cid;
1281b99ca858SMilanka Ringwald     }
1282b99ca858SMilanka Ringwald 
12833121b998SMilanka Ringwald     connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
12843121b998SMilanka Ringwald     connection_target->browsing_connection->state     = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
12853121b998SMilanka Ringwald 
12863121b998SMilanka Ringwald     return l2cap_create_ertm_channel(avrcp_browsing_packet_handler, remote_addr, connection_controller->browsing_l2cap_psm,
12873121b998SMilanka Ringwald                     &connection_controller->browsing_connection->ertm_config,
12883121b998SMilanka Ringwald                     connection_controller->browsing_connection->ertm_buffer,
12893121b998SMilanka Ringwald                     connection_controller->browsing_connection->ertm_buffer_size, NULL);
1290b99ca858SMilanka Ringwald 
1291b99ca858SMilanka Ringwald }
1292ace5ab2aSMilanka Ringwald 
1293a6344352SMilanka Ringwald uint8_t avrcp_browsing_configure_incoming_connection(uint16_t avrcp_browsing_cid, uint8_t * ertm_buffer, uint32_t ertm_buffer_size, l2cap_ertm_config_t * ertm_config){
1294a6344352SMilanka Ringwald     avrcp_connection_t * connection_controller = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
1295a6344352SMilanka Ringwald     if (!connection_controller){
1296a6344352SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1297a6344352SMilanka Ringwald     }
1298a6344352SMilanka Ringwald     avrcp_connection_t * connection_target = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid);
1299a6344352SMilanka Ringwald     if (!connection_target){
1300a6344352SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1301a6344352SMilanka Ringwald     }
1302a6344352SMilanka Ringwald 
1303a6344352SMilanka Ringwald     if (!connection_controller->browsing_connection){
1304a6344352SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1305a6344352SMilanka Ringwald     }
13068ee7c9daSMilanka Ringwald     if (!connection_target->browsing_connection){
1307a6344352SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1308a6344352SMilanka Ringwald     }
1309a6344352SMilanka Ringwald 
1310a6344352SMilanka Ringwald     if (connection_controller->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){
1311a6344352SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1312a6344352SMilanka Ringwald     }
1313a6344352SMilanka Ringwald 
1314a6344352SMilanka Ringwald     avrcp_browsing_configure_ertm(connection_controller->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config);
1315a6344352SMilanka Ringwald     avrcp_browsing_configure_ertm(connection_target->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config);
1316a6344352SMilanka Ringwald 
1317a6344352SMilanka Ringwald     connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
1318a6344352SMilanka Ringwald     connection_target->browsing_connection->state     = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
1319a6344352SMilanka Ringwald 
1320a6344352SMilanka Ringwald     l2cap_accept_ertm_connection(connection_controller->browsing_connection->l2cap_browsing_cid,
1321a6344352SMilanka Ringwald         &connection_controller->browsing_connection->ertm_config,
1322a6344352SMilanka Ringwald         connection_controller->browsing_connection->ertm_buffer,
1323a6344352SMilanka Ringwald         connection_controller->browsing_connection->ertm_buffer_size);
1324a6344352SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1325a6344352SMilanka Ringwald }
1326a6344352SMilanka Ringwald 
1327f9294da5SMilanka Ringwald 
1328f9294da5SMilanka Ringwald uint8_t avrcp_browsing_decline_incoming_connection(uint16_t avrcp_browsing_cid){
1329f9294da5SMilanka Ringwald     avrcp_connection_t * connection_controller = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
1330f9294da5SMilanka Ringwald     if (!connection_controller){
1331f9294da5SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1332f9294da5SMilanka Ringwald     }
1333f9294da5SMilanka Ringwald     avrcp_connection_t * connection_target = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid);
1334f9294da5SMilanka Ringwald     if (!connection_target){
1335f9294da5SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1336f9294da5SMilanka Ringwald     }
1337f9294da5SMilanka Ringwald 
1338f9294da5SMilanka Ringwald     if (!connection_controller->browsing_connection){
1339f9294da5SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1340f9294da5SMilanka Ringwald     }
13418ee7c9daSMilanka Ringwald     if (!connection_target->browsing_connection){
1342f9294da5SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1343f9294da5SMilanka Ringwald     }
1344f9294da5SMilanka Ringwald 
1345f9294da5SMilanka Ringwald     if (connection_controller->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){
1346f9294da5SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1347f9294da5SMilanka Ringwald     }
1348f9294da5SMilanka Ringwald 
1349f9294da5SMilanka Ringwald     l2cap_decline_connection(connection_controller->browsing_connection->l2cap_browsing_cid);
1350f9294da5SMilanka Ringwald 
1351f9294da5SMilanka Ringwald     avrcp_browsing_finalize_connection(connection_controller);
1352f9294da5SMilanka Ringwald     avrcp_browsing_finalize_connection(connection_target);
1353f9294da5SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1354f9294da5SMilanka Ringwald }
1355f9294da5SMilanka Ringwald 
13568ee7c9daSMilanka Ringwald uint8_t avrcp_browsing_disconnect(uint16_t avrcp_browsing_cid){
13578ee7c9daSMilanka Ringwald     avrcp_connection_t * connection_controller = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
13588ee7c9daSMilanka Ringwald     if (!connection_controller){
1359ace5ab2aSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1360ace5ab2aSMilanka Ringwald     }
13618ee7c9daSMilanka Ringwald     avrcp_connection_t * connection_target = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid);
13628ee7c9daSMilanka Ringwald     if (!connection_target){
13638ee7c9daSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
13648ee7c9daSMilanka Ringwald     }
1365ace5ab2aSMilanka Ringwald 
13668ee7c9daSMilanka Ringwald     if (!connection_controller->browsing_connection){
13678ee7c9daSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
13688ee7c9daSMilanka Ringwald     }
13698ee7c9daSMilanka Ringwald     if (!connection_target->browsing_connection){
13708ee7c9daSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
13718ee7c9daSMilanka Ringwald     }
13728ee7c9daSMilanka Ringwald 
13738ee7c9daSMilanka Ringwald     l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid, 0);
1374ace5ab2aSMilanka Ringwald     return ERROR_CODE_SUCCESS;
1375ace5ab2aSMilanka Ringwald }
13760eebc132SMilanka Ringwald 
13770eebc132SMilanka Ringwald void avrcp_browsing_register_controller_packet_handler(btstack_packet_handler_t callback){
13780eebc132SMilanka Ringwald     avrcp_browsing_controller_packet_handler = callback;
13790eebc132SMilanka Ringwald }
13800eebc132SMilanka Ringwald 
13810eebc132SMilanka Ringwald void avrcp_browsing_register_target_packet_handler(btstack_packet_handler_t callback){
13820eebc132SMilanka Ringwald     avrcp_browsing_target_packet_handler = callback;
13830eebc132SMilanka Ringwald }
13840eebc132SMilanka Ringwald 
13850eebc132SMilanka Ringwald void avrcp_browsing_register_packet_handler(btstack_packet_handler_t callback){
13860eebc132SMilanka Ringwald     btstack_assert(callback != NULL);
13870eebc132SMilanka Ringwald     avrcp_browsing_callback = callback;
13880eebc132SMilanka Ringwald }