xref: /btstack/src/classic/avrcp_browsing.c (revision 65bd7af57bf8fb88dfaee25da2730914822c02ef)
1665a00cbSMilanka Ringwald /*
2665a00cbSMilanka Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3665a00cbSMilanka Ringwald  *
4665a00cbSMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5665a00cbSMilanka Ringwald  * modification, are permitted provided that the following conditions
6665a00cbSMilanka Ringwald  * are met:
7665a00cbSMilanka Ringwald  *
8665a00cbSMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9665a00cbSMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10665a00cbSMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11665a00cbSMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12665a00cbSMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13665a00cbSMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14665a00cbSMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15665a00cbSMilanka Ringwald  *    from this software without specific prior written permission.
16665a00cbSMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17665a00cbSMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18665a00cbSMilanka Ringwald  *    monetary gain.
19665a00cbSMilanka Ringwald  *
20665a00cbSMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21665a00cbSMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22665a00cbSMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23665a00cbSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24665a00cbSMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25665a00cbSMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26665a00cbSMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27665a00cbSMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28665a00cbSMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29665a00cbSMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30665a00cbSMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31665a00cbSMilanka Ringwald  * SUCH DAMAGE.
32665a00cbSMilanka Ringwald  *
33665a00cbSMilanka Ringwald  * Please inquire about commercial licensing options at
34665a00cbSMilanka Ringwald  * [email protected]
35665a00cbSMilanka Ringwald  *
36665a00cbSMilanka Ringwald  */
37665a00cbSMilanka Ringwald 
38665a00cbSMilanka Ringwald #define BTSTACK_FILE__ "avrcp_browsing.c"
39665a00cbSMilanka Ringwald 
40665a00cbSMilanka Ringwald #include <stdint.h>
41665a00cbSMilanka Ringwald #include <string.h>
42665a00cbSMilanka Ringwald 
43665a00cbSMilanka Ringwald #include "bluetooth_psm.h"
44665a00cbSMilanka Ringwald #include "bluetooth_sdp.h"
45665a00cbSMilanka Ringwald #include "btstack_debug.h"
46665a00cbSMilanka Ringwald #include "btstack_event.h"
47665a00cbSMilanka Ringwald #include "btstack_memory.h"
48665a00cbSMilanka Ringwald #include "classic/sdp_client.h"
49665a00cbSMilanka Ringwald #include "classic/sdp_util.h"
50665a00cbSMilanka Ringwald #include "classic/avrcp_browsing.h"
51665a00cbSMilanka Ringwald 
5264a27ec5SMilanka Ringwald typedef struct {
5364a27ec5SMilanka Ringwald     uint16_t browsing_cid;
5464a27ec5SMilanka Ringwald     uint16_t browsing_l2cap_psm;
5564a27ec5SMilanka Ringwald     uint16_t browsing_version;
5664a27ec5SMilanka Ringwald } avrcp_browsing_sdp_query_context_t;
57665a00cbSMilanka Ringwald 
58665a00cbSMilanka Ringwald static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
59665a00cbSMilanka Ringwald 
60*65bd7af5SMatthias Ringwald // higher layer callbacks
61665a00cbSMilanka Ringwald static btstack_packet_handler_t           avrcp_browsing_callback;
62665a00cbSMilanka Ringwald static btstack_packet_handler_t avrcp_browsing_controller_packet_handler;
63665a00cbSMilanka Ringwald static btstack_packet_handler_t avrcp_browsing_target_packet_handler;
64665a00cbSMilanka Ringwald 
65*65bd7af5SMatthias Ringwald // sdp query
66e71114b0SMatthias Ringwald static bd_addr_t avrcp_browsing_sdp_addr;
67*65bd7af5SMatthias Ringwald static btstack_context_callback_registration_t avrcp_browsing_handle_sdp_client_query_request;
68*65bd7af5SMatthias Ringwald static avrcp_browsing_sdp_query_context_t avrcp_browsing_sdp_query_context;
69*65bd7af5SMatthias Ringwald 
70*65bd7af5SMatthias Ringwald static bool avrcp_browsing_l2cap_service_registered;
71*65bd7af5SMatthias Ringwald 
72665a00cbSMilanka Ringwald 
73665a00cbSMilanka Ringwald void avrcp_browsing_request_can_send_now(avrcp_browsing_connection_t * connection, uint16_t l2cap_cid){
74665a00cbSMilanka Ringwald     connection->wait_to_send = true;
75665a00cbSMilanka Ringwald     l2cap_request_can_send_now_event(l2cap_cid);
76665a00cbSMilanka Ringwald }
77665a00cbSMilanka Ringwald 
7837fae987SMilanka Ringwald static void avrcp_retry_timer_timeout_handler(btstack_timer_source_t * timer){
79665a00cbSMilanka Ringwald     uint16_t avrcp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer);
801945fe3eSMilanka Ringwald     avrcp_connection_t * connection_controller = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, avrcp_cid);
81665a00cbSMilanka Ringwald     if (connection_controller == NULL) return;
821945fe3eSMilanka Ringwald     avrcp_connection_t * connection_target = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, avrcp_cid);
83665a00cbSMilanka Ringwald     if (connection_target == NULL) return;
84665a00cbSMilanka Ringwald 
85665a00cbSMilanka Ringwald     if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)) return;
86665a00cbSMilanka Ringwald 
8737fae987SMilanka Ringwald     if (connection_controller->browsing_connection->state == AVCTP_CONNECTION_W2_L2CAP_RETRY){
88665a00cbSMilanka Ringwald         connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
89665a00cbSMilanka Ringwald         connection_target->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
90665a00cbSMilanka Ringwald 
91665a00cbSMilanka Ringwald         l2cap_create_ertm_channel(avrcp_browsing_packet_handler, connection_controller->remote_addr, connection_controller->browsing_l2cap_psm,
92665a00cbSMilanka Ringwald                 &connection_controller->browsing_connection->ertm_config,
93665a00cbSMilanka Ringwald                 connection_controller->browsing_connection->ertm_buffer,
94665a00cbSMilanka Ringwald                 connection_controller->browsing_connection->ertm_buffer_size, NULL);
95665a00cbSMilanka Ringwald     }
96665a00cbSMilanka Ringwald }
97665a00cbSMilanka Ringwald 
9837fae987SMilanka Ringwald static void avrcp_retry_timer_start(avrcp_connection_t * connection){
9937fae987SMilanka Ringwald     btstack_run_loop_set_timer_handler(&connection->retry_timer, avrcp_retry_timer_timeout_handler);
10037fae987SMilanka Ringwald     btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avrcp_cid);
101665a00cbSMilanka Ringwald 
102665a00cbSMilanka Ringwald     // add some jitter/randomness to reconnect delay
103665a00cbSMilanka Ringwald     uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F);
10437fae987SMilanka Ringwald     btstack_run_loop_set_timer(&connection->retry_timer, timeout);
105665a00cbSMilanka Ringwald 
10637fae987SMilanka Ringwald     btstack_run_loop_add_timer(&connection->retry_timer);
107665a00cbSMilanka Ringwald }
108665a00cbSMilanka Ringwald 
109665a00cbSMilanka Ringwald // AVRCP Browsing Service functions
110665a00cbSMilanka Ringwald static void avrcp_browsing_finalize_connection(avrcp_connection_t * connection){
11137fae987SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->retry_timer);
112665a00cbSMilanka Ringwald     btstack_memory_avrcp_browsing_connection_free(connection->browsing_connection);
113665a00cbSMilanka Ringwald     connection->browsing_connection = NULL;
114665a00cbSMilanka Ringwald }
115665a00cbSMilanka Ringwald 
116665a00cbSMilanka Ringwald static void avrcp_browsing_emit_connection_established(uint16_t browsing_cid, bd_addr_t addr, uint8_t status){
117665a00cbSMilanka Ringwald     btstack_assert(avrcp_browsing_callback != NULL);
118665a00cbSMilanka Ringwald 
119665a00cbSMilanka Ringwald     uint8_t event[12];
120665a00cbSMilanka Ringwald     int pos = 0;
121665a00cbSMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
122665a00cbSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
123665a00cbSMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_BROWSING_CONNECTION_ESTABLISHED;
124665a00cbSMilanka Ringwald     event[pos++] = status;
125665a00cbSMilanka Ringwald     reverse_bd_addr(addr,&event[pos]);
126665a00cbSMilanka Ringwald     pos += 6;
127665a00cbSMilanka Ringwald     little_endian_store_16(event, pos, browsing_cid);
128665a00cbSMilanka Ringwald     pos += 2;
129665a00cbSMilanka Ringwald     (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
130665a00cbSMilanka Ringwald }
131665a00cbSMilanka Ringwald 
132665a00cbSMilanka Ringwald static void avrcp_browsing_emit_incoming_connection(uint16_t browsing_cid, bd_addr_t addr){
133665a00cbSMilanka Ringwald     btstack_assert(avrcp_browsing_callback != NULL);
134665a00cbSMilanka Ringwald 
135665a00cbSMilanka Ringwald     uint8_t event[11];
136665a00cbSMilanka Ringwald     int pos = 0;
137665a00cbSMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
138665a00cbSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
139665a00cbSMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_INCOMING_BROWSING_CONNECTION;
140665a00cbSMilanka Ringwald     reverse_bd_addr(addr,&event[pos]);
141665a00cbSMilanka Ringwald     pos += 6;
142665a00cbSMilanka Ringwald     little_endian_store_16(event, pos, browsing_cid);
143665a00cbSMilanka Ringwald     pos += 2;
144665a00cbSMilanka Ringwald     (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
145665a00cbSMilanka Ringwald }
146665a00cbSMilanka Ringwald 
147665a00cbSMilanka Ringwald static void avrcp_browsing_emit_connection_closed(uint16_t browsing_cid){
148665a00cbSMilanka Ringwald     btstack_assert(avrcp_browsing_callback != NULL);
149665a00cbSMilanka Ringwald 
150665a00cbSMilanka Ringwald     uint8_t event[5];
151665a00cbSMilanka Ringwald     int pos = 0;
152665a00cbSMilanka Ringwald     event[pos++] = HCI_EVENT_AVRCP_META;
153665a00cbSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
154665a00cbSMilanka Ringwald     event[pos++] = AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED;
155665a00cbSMilanka Ringwald     little_endian_store_16(event, pos, browsing_cid);
156665a00cbSMilanka Ringwald     pos += 2;
157665a00cbSMilanka Ringwald     (*avrcp_browsing_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
158665a00cbSMilanka Ringwald }
159665a00cbSMilanka Ringwald 
160665a00cbSMilanka Ringwald 
161665a00cbSMilanka Ringwald static avrcp_browsing_connection_t * avrcp_browsing_create_connection(avrcp_connection_t * avrcp_connection, uint16_t avrcp_browsing_cid){
162665a00cbSMilanka Ringwald     avrcp_browsing_connection_t * browsing_connection = btstack_memory_avrcp_browsing_connection_get();
163665a00cbSMilanka Ringwald     if (!browsing_connection){
164665a00cbSMilanka Ringwald         log_error("Not enough memory to create browsing connection");
165665a00cbSMilanka Ringwald         return NULL;
166665a00cbSMilanka Ringwald     }
167665a00cbSMilanka Ringwald     browsing_connection->state = AVCTP_CONNECTION_IDLE;
168665a00cbSMilanka Ringwald     browsing_connection->transaction_label = 0xFF;
169665a00cbSMilanka Ringwald 
170665a00cbSMilanka Ringwald     avrcp_connection->avrcp_browsing_cid = avrcp_browsing_cid;
171665a00cbSMilanka Ringwald     avrcp_connection->browsing_connection = browsing_connection;
172665a00cbSMilanka Ringwald 
173665a00cbSMilanka Ringwald     log_info("avrcp_browsing_create_connection, avrcp cid 0x%02x", avrcp_connection->avrcp_browsing_cid);
174665a00cbSMilanka Ringwald     return browsing_connection;
175665a00cbSMilanka Ringwald }
176665a00cbSMilanka Ringwald 
177665a00cbSMilanka 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){
178665a00cbSMilanka Ringwald     browsing_connection->ertm_buffer = ertm_buffer;
179665a00cbSMilanka Ringwald     browsing_connection->ertm_buffer_size = ertm_buffer_size;
180665a00cbSMilanka Ringwald 
181665a00cbSMilanka Ringwald     if (ertm_buffer_size > 0) {
182665a00cbSMilanka Ringwald         (void)memcpy(&browsing_connection->ertm_config, ertm_config,
183665a00cbSMilanka Ringwald                  sizeof(l2cap_ertm_config_t));
184665a00cbSMilanka Ringwald         log_info("avrcp_browsing_configure_ertm");
185665a00cbSMilanka Ringwald     }
186665a00cbSMilanka Ringwald }
187665a00cbSMilanka Ringwald 
188665a00cbSMilanka Ringwald static avrcp_browsing_connection_t * avrcp_browsing_handle_incoming_connection(avrcp_connection_t * connection, uint16_t local_cid, uint16_t avrcp_browsing_cid){
189665a00cbSMilanka Ringwald     if (connection->browsing_connection == NULL){
190665a00cbSMilanka Ringwald         avrcp_browsing_create_connection(connection, avrcp_browsing_cid);
191665a00cbSMilanka Ringwald     }
192665a00cbSMilanka Ringwald     if (connection->browsing_connection) {
193665a00cbSMilanka Ringwald         connection->browsing_connection->l2cap_browsing_cid = local_cid;
194665a00cbSMilanka Ringwald         connection->browsing_connection->state = AVCTP_CONNECTION_W4_ERTM_CONFIGURATION;
19537fae987SMilanka Ringwald         btstack_run_loop_remove_timer(&connection->retry_timer);
196665a00cbSMilanka Ringwald     }
197665a00cbSMilanka Ringwald     return connection->browsing_connection;
198665a00cbSMilanka Ringwald }
199665a00cbSMilanka Ringwald 
200665a00cbSMilanka Ringwald static void avrcp_browsing_handle_open_connection_for_role(avrcp_connection_t * connection, uint16_t local_cid){
201665a00cbSMilanka Ringwald     connection->browsing_connection->l2cap_browsing_cid = local_cid;
202665a00cbSMilanka Ringwald     connection->browsing_connection->incoming_declined = false;
203665a00cbSMilanka Ringwald     connection->browsing_connection->state = AVCTP_CONNECTION_OPENED;
204665a00cbSMilanka 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);
205665a00cbSMilanka Ringwald }
206665a00cbSMilanka Ringwald 
207665a00cbSMilanka Ringwald static avrcp_frame_type_t avrcp_get_frame_type(uint8_t header){
208665a00cbSMilanka Ringwald     return (avrcp_frame_type_t)((header & 0x02) >> 1);
209665a00cbSMilanka Ringwald }
210665a00cbSMilanka Ringwald 
211665a00cbSMilanka Ringwald static void avrcp_browsing_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
212665a00cbSMilanka Ringwald     UNUSED(channel);
213665a00cbSMilanka Ringwald     UNUSED(size);
214665a00cbSMilanka Ringwald     bd_addr_t event_addr;
215665a00cbSMilanka Ringwald     uint16_t local_cid;
216665a00cbSMilanka Ringwald     uint8_t  status;
217665a00cbSMilanka Ringwald     bool decline_connection;
218665a00cbSMilanka Ringwald     bool outoing_active;
219665a00cbSMilanka Ringwald 
220665a00cbSMilanka Ringwald     avrcp_connection_t * connection_controller;
221665a00cbSMilanka Ringwald     avrcp_connection_t * connection_target;
222665a00cbSMilanka Ringwald 
223665a00cbSMilanka Ringwald     switch (packet_type){
224665a00cbSMilanka Ringwald         case L2CAP_DATA_PACKET:
225665a00cbSMilanka Ringwald             switch (avrcp_get_frame_type(packet[0])){
226665a00cbSMilanka Ringwald                 case AVRCP_RESPONSE_FRAME:
227665a00cbSMilanka Ringwald                     (*avrcp_browsing_controller_packet_handler)(packet_type, channel, packet, size);
228665a00cbSMilanka Ringwald                     break;
229665a00cbSMilanka Ringwald                 case AVRCP_COMMAND_FRAME:
230665a00cbSMilanka Ringwald                 default:    // make compiler happy
231665a00cbSMilanka Ringwald                     (*avrcp_browsing_target_packet_handler)(packet_type, channel, packet, size);
232665a00cbSMilanka Ringwald                     break;
233665a00cbSMilanka Ringwald             }
234665a00cbSMilanka Ringwald             break;
235665a00cbSMilanka Ringwald         case HCI_EVENT_PACKET:
236665a00cbSMilanka Ringwald             btstack_assert(avrcp_browsing_controller_packet_handler != NULL);
237665a00cbSMilanka Ringwald             btstack_assert(avrcp_browsing_target_packet_handler != NULL);
238665a00cbSMilanka Ringwald 
239665a00cbSMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
240665a00cbSMilanka Ringwald 
241665a00cbSMilanka Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
242665a00cbSMilanka Ringwald                     btstack_assert(avrcp_browsing_controller_packet_handler != NULL);
243665a00cbSMilanka Ringwald                     btstack_assert(avrcp_browsing_target_packet_handler != NULL);
244665a00cbSMilanka Ringwald 
245665a00cbSMilanka Ringwald                     l2cap_event_incoming_connection_get_address(packet, event_addr);
246665a00cbSMilanka Ringwald                     local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
247665a00cbSMilanka Ringwald                     outoing_active = false;
248665a00cbSMilanka Ringwald 
2491945fe3eSMilanka Ringwald                     connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr);
2501945fe3eSMilanka Ringwald                     connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr);
251665a00cbSMilanka Ringwald 
252665a00cbSMilanka Ringwald                     if (connection_target == NULL || connection_controller == NULL) {
253665a00cbSMilanka Ringwald                         l2cap_decline_connection(local_cid);
254665a00cbSMilanka Ringwald                         return;
255665a00cbSMilanka Ringwald                     }
256665a00cbSMilanka Ringwald 
257665a00cbSMilanka Ringwald                     if (connection_target->browsing_connection != NULL){
258665a00cbSMilanka Ringwald                         if (connection_target->browsing_connection->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED){
259665a00cbSMilanka Ringwald                             outoing_active = true;
260665a00cbSMilanka Ringwald                             connection_target->browsing_connection->incoming_declined = true;
261665a00cbSMilanka Ringwald                         }
262665a00cbSMilanka Ringwald                     }
263665a00cbSMilanka Ringwald 
264665a00cbSMilanka Ringwald                     if (connection_controller->browsing_connection != NULL){
265665a00cbSMilanka Ringwald                         if (connection_controller->browsing_connection->state == AVCTP_CONNECTION_W4_L2CAP_CONNECTED) {
266665a00cbSMilanka Ringwald                             outoing_active = true;
267665a00cbSMilanka Ringwald                             connection_controller->browsing_connection->incoming_declined = true;
268665a00cbSMilanka Ringwald                         }
269665a00cbSMilanka Ringwald                     }
270665a00cbSMilanka Ringwald 
271665a00cbSMilanka Ringwald                     decline_connection = outoing_active;
272665a00cbSMilanka Ringwald                     if (decline_connection == false){
273665a00cbSMilanka Ringwald                         uint16_t avrcp_browsing_cid;
274665a00cbSMilanka Ringwald                         if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)){
275665a00cbSMilanka Ringwald                             avrcp_browsing_cid = avrcp_get_next_cid(AVRCP_CONTROLLER);
276665a00cbSMilanka Ringwald                         } else {
277665a00cbSMilanka Ringwald                             avrcp_browsing_cid = connection_controller->avrcp_browsing_cid;
278665a00cbSMilanka Ringwald                         }
279665a00cbSMilanka Ringwald 
280665a00cbSMilanka Ringwald                         // create two connection objects (both)
281665a00cbSMilanka Ringwald                         connection_target->browsing_connection     = avrcp_browsing_handle_incoming_connection(connection_target, local_cid, avrcp_browsing_cid);
282665a00cbSMilanka Ringwald                         connection_controller->browsing_connection = avrcp_browsing_handle_incoming_connection(connection_controller, local_cid, avrcp_browsing_cid);
283665a00cbSMilanka Ringwald 
284665a00cbSMilanka Ringwald                         if ((connection_target->browsing_connection  == NULL) || (connection_controller->browsing_connection == NULL)){
285665a00cbSMilanka Ringwald                             decline_connection = true;
286665a00cbSMilanka Ringwald                             if (connection_target->browsing_connection) {
287665a00cbSMilanka Ringwald                                 avrcp_browsing_finalize_connection(connection_target);
288665a00cbSMilanka Ringwald                             }
289665a00cbSMilanka Ringwald                             if (connection_controller->browsing_connection) {
290665a00cbSMilanka Ringwald                                 avrcp_browsing_finalize_connection(connection_controller);
291665a00cbSMilanka Ringwald                             }
292665a00cbSMilanka Ringwald                         }
293665a00cbSMilanka Ringwald                     }
294665a00cbSMilanka Ringwald                     if (decline_connection){
295665a00cbSMilanka Ringwald                         l2cap_decline_connection(local_cid);
296665a00cbSMilanka Ringwald                     } else {
297665a00cbSMilanka Ringwald                         log_info("AVRCP: L2CAP_EVENT_INCOMING_CONNECTION browsing_avrcp_cid 0x%02x", connection_controller->avrcp_browsing_cid);
298665a00cbSMilanka Ringwald                         avrcp_browsing_emit_incoming_connection(connection_controller->avrcp_browsing_cid, event_addr);
299665a00cbSMilanka Ringwald                     }
300665a00cbSMilanka Ringwald                     break;
301665a00cbSMilanka Ringwald 
302665a00cbSMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
303665a00cbSMilanka Ringwald                     l2cap_event_channel_opened_get_address(packet, event_addr);
304665a00cbSMilanka Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
305665a00cbSMilanka Ringwald                     local_cid = l2cap_event_channel_opened_get_local_cid(packet);
306665a00cbSMilanka Ringwald 
3071945fe3eSMilanka Ringwald                     connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, event_addr);
3081945fe3eSMilanka Ringwald                     connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, event_addr);
309665a00cbSMilanka Ringwald 
310665a00cbSMilanka Ringwald                     // incoming: structs are already created in L2CAP_EVENT_INCOMING_CONNECTION
311665a00cbSMilanka Ringwald                     // outgoing: structs are cteated in avrcp_connect() and avrcp_browsing_connect()
312665a00cbSMilanka Ringwald                     if ((connection_controller == NULL) || (connection_target == NULL)) {
313665a00cbSMilanka Ringwald                         break;
314665a00cbSMilanka Ringwald                     }
315665a00cbSMilanka Ringwald                     if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)) {
316665a00cbSMilanka Ringwald                         break;
317665a00cbSMilanka Ringwald                     }
318665a00cbSMilanka Ringwald 
319665a00cbSMilanka Ringwald                     switch (status){
320665a00cbSMilanka Ringwald                         case ERROR_CODE_SUCCESS:
321665a00cbSMilanka Ringwald                             avrcp_browsing_handle_open_connection_for_role(connection_target, local_cid);
322665a00cbSMilanka Ringwald                             avrcp_browsing_handle_open_connection_for_role(connection_controller, local_cid);
323665a00cbSMilanka Ringwald                             avrcp_browsing_emit_connection_established(connection_controller->avrcp_browsing_cid, event_addr, status);
324665a00cbSMilanka Ringwald                             return;
325665a00cbSMilanka Ringwald                         case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES:
326665a00cbSMilanka Ringwald                             if (connection_controller->browsing_connection->incoming_declined == true){
327665a00cbSMilanka Ringwald                                 log_info("Incoming browsing connection was declined, and the outgoing failed");
32837fae987SMilanka Ringwald                                 connection_controller->browsing_connection->state = AVCTP_CONNECTION_W2_L2CAP_RETRY;
329665a00cbSMilanka Ringwald                                 connection_controller->browsing_connection->incoming_declined = false;
33037fae987SMilanka Ringwald                                 connection_target->browsing_connection->state = AVCTP_CONNECTION_W2_L2CAP_RETRY;
331665a00cbSMilanka Ringwald                                 connection_target->browsing_connection->incoming_declined = false;
33237fae987SMilanka Ringwald                                 avrcp_retry_timer_start(connection_controller);
333665a00cbSMilanka Ringwald                                 return;
334665a00cbSMilanka Ringwald                             }
335665a00cbSMilanka Ringwald                             break;
336665a00cbSMilanka Ringwald                         default:
337665a00cbSMilanka Ringwald                             break;
338665a00cbSMilanka Ringwald                     }
339665a00cbSMilanka Ringwald                     log_info("L2CAP connection to connection %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status);
340665a00cbSMilanka Ringwald                     avrcp_browsing_emit_connection_established(connection_controller->avrcp_browsing_cid, event_addr, status);
341665a00cbSMilanka Ringwald                     avrcp_browsing_finalize_connection(connection_controller);
342665a00cbSMilanka Ringwald                     avrcp_browsing_finalize_connection(connection_target);
343665a00cbSMilanka Ringwald                     break;
344665a00cbSMilanka Ringwald 
345665a00cbSMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
346665a00cbSMilanka Ringwald                     local_cid = l2cap_event_channel_closed_get_local_cid(packet);
347665a00cbSMilanka Ringwald 
3481945fe3eSMilanka Ringwald                     connection_controller = avrcp_get_connection_for_browsing_l2cap_cid_for_role(AVRCP_CONTROLLER, local_cid);
3491945fe3eSMilanka Ringwald                     connection_target = avrcp_get_connection_for_browsing_l2cap_cid_for_role(AVRCP_TARGET, local_cid);
350665a00cbSMilanka Ringwald                     if ((connection_controller == NULL) || (connection_target == NULL)) {
351665a00cbSMilanka Ringwald                         break;
352665a00cbSMilanka Ringwald                     }
353665a00cbSMilanka Ringwald                     if ((connection_controller->browsing_connection == NULL) || (connection_target->browsing_connection == NULL)) {
354665a00cbSMilanka Ringwald                         break;
355665a00cbSMilanka Ringwald                     }
356665a00cbSMilanka Ringwald                     avrcp_browsing_emit_connection_closed(connection_controller->avrcp_browsing_cid);
357665a00cbSMilanka Ringwald                     avrcp_browsing_finalize_connection(connection_controller);
358665a00cbSMilanka Ringwald                     avrcp_browsing_finalize_connection(connection_target);
359665a00cbSMilanka Ringwald                     break;
360665a00cbSMilanka Ringwald 
361665a00cbSMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
362665a00cbSMilanka Ringwald                     local_cid = l2cap_event_can_send_now_get_local_cid(packet);
3631945fe3eSMilanka Ringwald                     connection_target = avrcp_get_connection_for_browsing_l2cap_cid_for_role(AVRCP_TARGET, local_cid);
364665a00cbSMilanka Ringwald                     if ((connection_target != NULL) && (connection_target->browsing_connection != NULL) && connection_target->browsing_connection->wait_to_send) {
365665a00cbSMilanka Ringwald                         connection_target->browsing_connection->wait_to_send = false;
366665a00cbSMilanka Ringwald                         (*avrcp_browsing_target_packet_handler)(HCI_EVENT_PACKET, channel, packet, size);
367665a00cbSMilanka Ringwald                         break;
368665a00cbSMilanka Ringwald                     }
3691945fe3eSMilanka Ringwald                     connection_controller = avrcp_get_connection_for_browsing_l2cap_cid_for_role(AVRCP_CONTROLLER, local_cid);
370665a00cbSMilanka Ringwald                     if ((connection_controller != NULL) && (connection_controller->browsing_connection != NULL) && connection_controller->browsing_connection->wait_to_send) {
371665a00cbSMilanka Ringwald                         connection_controller->browsing_connection->wait_to_send = false;
372665a00cbSMilanka Ringwald                         (*avrcp_browsing_controller_packet_handler)(HCI_EVENT_PACKET, channel, packet, size);
373665a00cbSMilanka Ringwald                         break;
374665a00cbSMilanka Ringwald                     }
375665a00cbSMilanka Ringwald                     break;
376665a00cbSMilanka Ringwald 
377665a00cbSMilanka Ringwald                 default:
378665a00cbSMilanka Ringwald                     break;
379665a00cbSMilanka Ringwald             }
380665a00cbSMilanka Ringwald             break;
381665a00cbSMilanka Ringwald         default:
382665a00cbSMilanka Ringwald             break;
383665a00cbSMilanka Ringwald     }
384665a00cbSMilanka Ringwald 
385665a00cbSMilanka Ringwald }
386665a00cbSMilanka Ringwald 
387665a00cbSMilanka Ringwald void avrcp_browsing_init(void){
388*65bd7af5SMatthias Ringwald     if (avrcp_browsing_l2cap_service_registered) return;
389665a00cbSMilanka Ringwald     int status = l2cap_register_service(&avrcp_browsing_packet_handler, PSM_AVCTP_BROWSING, 0xffff, LEVEL_2);
390665a00cbSMilanka Ringwald 
391665a00cbSMilanka Ringwald     if (status != ERROR_CODE_SUCCESS) return;
392*65bd7af5SMatthias Ringwald     avrcp_browsing_l2cap_service_registered = true;
393665a00cbSMilanka Ringwald }
394665a00cbSMilanka Ringwald 
395680af5dcSMatthias Ringwald void avrcp_browsing_deinit(void){
396680af5dcSMatthias Ringwald     avrcp_browsing_callback = NULL;
397680af5dcSMatthias Ringwald     avrcp_browsing_controller_packet_handler = NULL;
398680af5dcSMatthias Ringwald     avrcp_browsing_target_packet_handler = NULL;
399*65bd7af5SMatthias Ringwald 
400680af5dcSMatthias Ringwald     (void) memset(avrcp_browsing_sdp_addr, 0, 6);
401*65bd7af5SMatthias Ringwald     (void) memset(&avrcp_browsing_handle_sdp_client_query_request, 0, sizeof(avrcp_browsing_handle_sdp_client_query_request));
402*65bd7af5SMatthias Ringwald     (void) memset(&avrcp_browsing_sdp_query_context, 0, sizeof(avrcp_browsing_sdp_query_context_t));
403*65bd7af5SMatthias Ringwald 
404*65bd7af5SMatthias Ringwald     avrcp_browsing_l2cap_service_registered = false;
405680af5dcSMatthias Ringwald }
406680af5dcSMatthias Ringwald 
407e71114b0SMatthias Ringwald static void avrcp_browsing_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
408e71114b0SMatthias Ringwald     UNUSED(packet_type);
409e71114b0SMatthias Ringwald     UNUSED(channel);
410e71114b0SMatthias Ringwald     UNUSED(size);
411e71114b0SMatthias Ringwald 
412*65bd7af5SMatthias Ringwald     avrcp_connection_t * avrcp_target_connection = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_sdp_query_context.browsing_cid);
413*65bd7af5SMatthias Ringwald     avrcp_connection_t * avrcp_controller_connection = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_sdp_query_context.browsing_cid);
41464a27ec5SMilanka Ringwald 
41564a27ec5SMilanka Ringwald     if ((avrcp_target_connection == NULL) || (avrcp_target_connection->browsing_connection == NULL)) return;
41664a27ec5SMilanka Ringwald     if (avrcp_target_connection->browsing_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) return;
41764a27ec5SMilanka Ringwald 
41864a27ec5SMilanka Ringwald     if ((avrcp_controller_connection == NULL) || (avrcp_controller_connection->browsing_connection == NULL)) return;
41964a27ec5SMilanka Ringwald     if (avrcp_controller_connection->browsing_connection->state != AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE) return;
42064a27ec5SMilanka Ringwald 
421e71114b0SMatthias Ringwald 
422e71114b0SMatthias Ringwald     uint8_t status;
423e71114b0SMatthias Ringwald     uint16_t browsing_l2cap_psm;
424e71114b0SMatthias Ringwald 
425e71114b0SMatthias Ringwald     switch (hci_event_packet_get_type(packet)){
426e71114b0SMatthias Ringwald         case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
427e71114b0SMatthias Ringwald             avrcp_handle_sdp_client_query_attribute_value(packet);
428e71114b0SMatthias Ringwald             break;
429e71114b0SMatthias Ringwald 
430e71114b0SMatthias Ringwald         case SDP_EVENT_QUERY_COMPLETE:
431e71114b0SMatthias Ringwald             status = sdp_event_query_complete_get_status(packet);
432e71114b0SMatthias Ringwald 
433e71114b0SMatthias Ringwald             if (status != ERROR_CODE_SUCCESS){
43494518574SMatthias Ringwald                 avrcp_browsing_emit_connection_established(avrcp_target_connection->avrcp_browsing_cid, avrcp_browsing_sdp_addr, status);
43594518574SMatthias Ringwald                 avrcp_browsing_finalize_connection(avrcp_target_connection);
43694518574SMatthias Ringwald                 avrcp_browsing_finalize_connection(avrcp_controller_connection);
437e71114b0SMatthias Ringwald                 break;
438e71114b0SMatthias Ringwald             }
439e71114b0SMatthias Ringwald 
4406d8f569dSMilanka Ringwald             browsing_l2cap_psm = avrcp_sdp_query_browsing_l2cap_psm();
441e71114b0SMatthias Ringwald             if (!browsing_l2cap_psm){
44294518574SMatthias Ringwald                 avrcp_browsing_emit_connection_established(avrcp_target_connection->avrcp_browsing_cid, avrcp_browsing_sdp_addr, SDP_SERVICE_NOT_FOUND);
44394518574SMatthias Ringwald                 avrcp_browsing_finalize_connection(avrcp_target_connection);
44494518574SMatthias Ringwald                 avrcp_browsing_finalize_connection(avrcp_controller_connection);
445e71114b0SMatthias Ringwald                 break;
446e71114b0SMatthias Ringwald             }
447e71114b0SMatthias Ringwald 
448e71114b0SMatthias Ringwald             l2cap_create_ertm_channel(avrcp_browsing_packet_handler, avrcp_browsing_sdp_addr, browsing_l2cap_psm,
449e71114b0SMatthias Ringwald                                             &avrcp_controller_connection->browsing_connection->ertm_config,
450e71114b0SMatthias Ringwald                                             avrcp_controller_connection->browsing_connection->ertm_buffer,
451e71114b0SMatthias Ringwald                                             avrcp_controller_connection->browsing_connection->ertm_buffer_size, NULL);
452e71114b0SMatthias Ringwald             break;
453e71114b0SMatthias Ringwald 
454e71114b0SMatthias Ringwald         default:
455e71114b0SMatthias Ringwald             break;
45664a27ec5SMilanka Ringwald     }
45764a27ec5SMilanka Ringwald     // register the SDP Query request to check if there is another connection waiting for the query
45864a27ec5SMilanka Ringwald     // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
45964a27ec5SMilanka Ringwald     (void) sdp_client_register_query_callback(&avrcp_browsing_handle_sdp_client_query_request);
46064a27ec5SMilanka Ringwald }
461e71114b0SMatthias Ringwald 
46264a27ec5SMilanka Ringwald static void avrcp_browsing_handle_start_sdp_client_query(void * context){
46364a27ec5SMilanka Ringwald     UNUSED(context);
46464a27ec5SMilanka Ringwald     // TODO
46564a27ec5SMilanka Ringwald 
46664a27ec5SMilanka Ringwald     btstack_linked_list_t connections = avrcp_get_connections();
46764a27ec5SMilanka Ringwald     btstack_linked_list_iterator_t it;
46864a27ec5SMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
46964a27ec5SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
47064a27ec5SMilanka Ringwald         avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it);
47164a27ec5SMilanka Ringwald         if (connection->browsing_connection == NULL) continue;
47264a27ec5SMilanka Ringwald         if (connection->browsing_connection->state != AVCTP_CONNECTION_W2_SEND_SDP_QUERY) continue;
47364a27ec5SMilanka Ringwald         connection->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
47464a27ec5SMilanka Ringwald 
47564a27ec5SMilanka Ringwald         // prevent triggering SDP query twice (for each role once)
47664a27ec5SMilanka Ringwald         avrcp_connection_t * connection_with_opposite_role;
47764a27ec5SMilanka Ringwald         switch (connection->role){
47864a27ec5SMilanka Ringwald             case AVRCP_CONTROLLER:
47964a27ec5SMilanka Ringwald                 connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_TARGET, connection->avrcp_cid);
48064a27ec5SMilanka Ringwald                 break;
48164a27ec5SMilanka Ringwald             case AVRCP_TARGET:
48264a27ec5SMilanka Ringwald                 connection_with_opposite_role = avrcp_get_connection_for_avrcp_cid_for_role(AVRCP_CONTROLLER, connection->avrcp_cid);
48364a27ec5SMilanka Ringwald                 break;
48464a27ec5SMilanka Ringwald             default:
48564a27ec5SMilanka Ringwald                 btstack_assert(false);
48664a27ec5SMilanka Ringwald                 return;
48764a27ec5SMilanka Ringwald         }
48864a27ec5SMilanka Ringwald         if (connection->browsing_connection != NULL){
48964a27ec5SMilanka Ringwald             connection_with_opposite_role->browsing_connection->state = AVCTP_CONNECTION_W4_SDP_QUERY_COMPLETE;
49064a27ec5SMilanka Ringwald         }
49164a27ec5SMilanka Ringwald 
492*65bd7af5SMatthias Ringwald         avrcp_browsing_sdp_query_context.browsing_l2cap_psm = 0;
493*65bd7af5SMatthias Ringwald         avrcp_browsing_sdp_query_context.browsing_version = 0;
494*65bd7af5SMatthias Ringwald         avrcp_browsing_sdp_query_context.browsing_cid = connection->avrcp_browsing_cid;
49564a27ec5SMilanka Ringwald 
49664a27ec5SMilanka Ringwald         sdp_client_query_uuid16(&avrcp_browsing_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVCTP);
49764a27ec5SMilanka Ringwald         return;
498e71114b0SMatthias Ringwald     }
499e71114b0SMatthias Ringwald }
500665a00cbSMilanka Ringwald 
50164a27ec5SMilanka Ringwald 
502665a00cbSMilanka 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){
503665a00cbSMilanka Ringwald     btstack_assert(avrcp_browsing_controller_packet_handler != NULL);
504665a00cbSMilanka Ringwald     btstack_assert(avrcp_browsing_target_packet_handler != NULL);
505665a00cbSMilanka Ringwald 
5061945fe3eSMilanka Ringwald     avrcp_connection_t * connection_controller = avrcp_get_connection_for_bd_addr_for_role(AVRCP_CONTROLLER, remote_addr);
507665a00cbSMilanka Ringwald     if (!connection_controller){
508665a00cbSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
509665a00cbSMilanka Ringwald     }
5101945fe3eSMilanka Ringwald     avrcp_connection_t * connection_target = avrcp_get_connection_for_bd_addr_for_role(AVRCP_TARGET, remote_addr);
511665a00cbSMilanka Ringwald     if (!connection_target){
512665a00cbSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
513665a00cbSMilanka Ringwald     }
514665a00cbSMilanka Ringwald 
515665a00cbSMilanka Ringwald     if (connection_controller->browsing_connection){
516665a00cbSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
517665a00cbSMilanka Ringwald     }
518665a00cbSMilanka Ringwald     if (connection_target->browsing_connection){
519665a00cbSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
520665a00cbSMilanka Ringwald     }
521665a00cbSMilanka Ringwald 
522665a00cbSMilanka Ringwald     uint16_t cid = avrcp_get_next_cid(AVRCP_CONTROLLER);
523665a00cbSMilanka Ringwald 
524665a00cbSMilanka Ringwald     connection_controller->browsing_connection = avrcp_browsing_create_connection(connection_controller, cid);
525665a00cbSMilanka Ringwald     if (!connection_controller->browsing_connection) return BTSTACK_MEMORY_ALLOC_FAILED;
526665a00cbSMilanka Ringwald 
527665a00cbSMilanka Ringwald     connection_target->browsing_connection = avrcp_browsing_create_connection(connection_target, cid);
528665a00cbSMilanka Ringwald     if (!connection_target->browsing_connection){
529665a00cbSMilanka Ringwald         avrcp_browsing_finalize_connection(connection_controller);
530665a00cbSMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
531665a00cbSMilanka Ringwald     }
532665a00cbSMilanka Ringwald     avrcp_browsing_configure_ertm(connection_controller->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config);
533665a00cbSMilanka Ringwald     avrcp_browsing_configure_ertm(connection_target->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config);
534665a00cbSMilanka Ringwald 
535665a00cbSMilanka Ringwald     if (avrcp_browsing_cid != NULL){
536665a00cbSMilanka Ringwald         *avrcp_browsing_cid = cid;
537665a00cbSMilanka Ringwald     }
538665a00cbSMilanka Ringwald 
539e71114b0SMatthias Ringwald     if (connection_controller->browsing_l2cap_psm == 0){
540e71114b0SMatthias Ringwald         memcpy(avrcp_browsing_sdp_addr, remote_addr, 6);
54164a27ec5SMilanka Ringwald         connection_controller->browsing_connection->state = AVCTP_CONNECTION_W2_SEND_SDP_QUERY;
54264a27ec5SMilanka Ringwald         connection_target->browsing_connection->state     = AVCTP_CONNECTION_W2_SEND_SDP_QUERY;
54364a27ec5SMilanka Ringwald         avrcp_browsing_handle_sdp_client_query_request.callback = &avrcp_browsing_handle_start_sdp_client_query;
54464a27ec5SMilanka Ringwald 
54564a27ec5SMilanka Ringwald         // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
54664a27ec5SMilanka Ringwald         (void) sdp_client_register_query_callback(&avrcp_browsing_handle_sdp_client_query_request);
54764a27ec5SMilanka Ringwald         return ERROR_CODE_SUCCESS;
548e71114b0SMatthias Ringwald     } else {
549665a00cbSMilanka Ringwald         connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
550665a00cbSMilanka Ringwald         connection_target->browsing_connection->state     = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
551665a00cbSMilanka Ringwald 
552665a00cbSMilanka Ringwald         return l2cap_create_ertm_channel(avrcp_browsing_packet_handler, remote_addr, connection_controller->browsing_l2cap_psm,
553665a00cbSMilanka Ringwald                                          &connection_controller->browsing_connection->ertm_config,
554665a00cbSMilanka Ringwald                                          connection_controller->browsing_connection->ertm_buffer,
555665a00cbSMilanka Ringwald                                          connection_controller->browsing_connection->ertm_buffer_size, NULL);
556e71114b0SMatthias Ringwald     }
557665a00cbSMilanka Ringwald }
558665a00cbSMilanka Ringwald 
559665a00cbSMilanka 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){
5601945fe3eSMilanka Ringwald     avrcp_connection_t * connection_controller = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
561665a00cbSMilanka Ringwald     if (!connection_controller){
562665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
563665a00cbSMilanka Ringwald     }
5641945fe3eSMilanka Ringwald     avrcp_connection_t * connection_target = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid);
565665a00cbSMilanka Ringwald     if (!connection_target){
566665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
567665a00cbSMilanka Ringwald     }
568665a00cbSMilanka Ringwald 
569665a00cbSMilanka Ringwald     if (!connection_controller->browsing_connection){
570665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
571665a00cbSMilanka Ringwald     }
572665a00cbSMilanka Ringwald     if (!connection_target->browsing_connection){
573665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
574665a00cbSMilanka Ringwald     }
575665a00cbSMilanka Ringwald 
576665a00cbSMilanka Ringwald     if (connection_controller->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){
577665a00cbSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
578665a00cbSMilanka Ringwald     }
579665a00cbSMilanka Ringwald 
580665a00cbSMilanka Ringwald     avrcp_browsing_configure_ertm(connection_controller->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config);
581665a00cbSMilanka Ringwald     avrcp_browsing_configure_ertm(connection_target->browsing_connection, ertm_buffer, ertm_buffer_size, ertm_config);
582665a00cbSMilanka Ringwald 
583665a00cbSMilanka Ringwald     connection_controller->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
584665a00cbSMilanka Ringwald     connection_target->browsing_connection->state     = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
585665a00cbSMilanka Ringwald 
586665a00cbSMilanka Ringwald     l2cap_accept_ertm_connection(connection_controller->browsing_connection->l2cap_browsing_cid,
587665a00cbSMilanka Ringwald         &connection_controller->browsing_connection->ertm_config,
588665a00cbSMilanka Ringwald         connection_controller->browsing_connection->ertm_buffer,
589665a00cbSMilanka Ringwald         connection_controller->browsing_connection->ertm_buffer_size);
590665a00cbSMilanka Ringwald     return ERROR_CODE_SUCCESS;
591665a00cbSMilanka Ringwald }
592665a00cbSMilanka Ringwald 
593665a00cbSMilanka Ringwald 
594665a00cbSMilanka Ringwald uint8_t avrcp_browsing_decline_incoming_connection(uint16_t avrcp_browsing_cid){
5951945fe3eSMilanka Ringwald     avrcp_connection_t * connection_controller = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
596665a00cbSMilanka Ringwald     if (!connection_controller){
597665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
598665a00cbSMilanka Ringwald     }
5991945fe3eSMilanka Ringwald     avrcp_connection_t * connection_target = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid);
600665a00cbSMilanka Ringwald     if (!connection_target){
601665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
602665a00cbSMilanka Ringwald     }
603665a00cbSMilanka Ringwald 
604665a00cbSMilanka Ringwald     if (!connection_controller->browsing_connection){
605665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
606665a00cbSMilanka Ringwald     }
607665a00cbSMilanka Ringwald     if (!connection_target->browsing_connection){
608665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
609665a00cbSMilanka Ringwald     }
610665a00cbSMilanka Ringwald 
611665a00cbSMilanka Ringwald     if (connection_controller->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){
612665a00cbSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
613665a00cbSMilanka Ringwald     }
614665a00cbSMilanka Ringwald 
615665a00cbSMilanka Ringwald     l2cap_decline_connection(connection_controller->browsing_connection->l2cap_browsing_cid);
616665a00cbSMilanka Ringwald 
617665a00cbSMilanka Ringwald     avrcp_browsing_finalize_connection(connection_controller);
618665a00cbSMilanka Ringwald     avrcp_browsing_finalize_connection(connection_target);
619665a00cbSMilanka Ringwald     return ERROR_CODE_SUCCESS;
620665a00cbSMilanka Ringwald }
621665a00cbSMilanka Ringwald 
622665a00cbSMilanka Ringwald uint8_t avrcp_browsing_disconnect(uint16_t avrcp_browsing_cid){
6231945fe3eSMilanka Ringwald     avrcp_connection_t * connection_controller = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
624665a00cbSMilanka Ringwald     if (!connection_controller){
625665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
626665a00cbSMilanka Ringwald     }
6271945fe3eSMilanka Ringwald     avrcp_connection_t * connection_target = avrcp_get_connection_for_browsing_cid_for_role(AVRCP_TARGET, avrcp_browsing_cid);
628665a00cbSMilanka Ringwald     if (!connection_target){
629665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
630665a00cbSMilanka Ringwald     }
631665a00cbSMilanka Ringwald 
632665a00cbSMilanka Ringwald     if (!connection_controller->browsing_connection){
633665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
634665a00cbSMilanka Ringwald     }
635665a00cbSMilanka Ringwald     if (!connection_target->browsing_connection){
636665a00cbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
637665a00cbSMilanka Ringwald     }
638665a00cbSMilanka Ringwald 
639665a00cbSMilanka Ringwald     l2cap_disconnect(connection_controller->browsing_connection->l2cap_browsing_cid, 0);
640665a00cbSMilanka Ringwald     return ERROR_CODE_SUCCESS;
641665a00cbSMilanka Ringwald }
642665a00cbSMilanka Ringwald 
643665a00cbSMilanka Ringwald void avrcp_browsing_register_controller_packet_handler(btstack_packet_handler_t callback){
644665a00cbSMilanka Ringwald     avrcp_browsing_controller_packet_handler = callback;
645665a00cbSMilanka Ringwald }
646665a00cbSMilanka Ringwald 
647665a00cbSMilanka Ringwald void avrcp_browsing_register_target_packet_handler(btstack_packet_handler_t callback){
648665a00cbSMilanka Ringwald     avrcp_browsing_target_packet_handler = callback;
649665a00cbSMilanka Ringwald }
650665a00cbSMilanka Ringwald 
651665a00cbSMilanka Ringwald void avrcp_browsing_register_packet_handler(btstack_packet_handler_t callback){
652665a00cbSMilanka Ringwald     btstack_assert(callback != NULL);
653665a00cbSMilanka Ringwald     avrcp_browsing_callback = callback;
654665a00cbSMilanka Ringwald }
655