xref: /btstack/src/classic/avdtp.c (revision 79654d96bbff5eddd46f42f4b0bce34dc9bae5d3)
1747ec646SMilanka Ringwald /*
2747ec646SMilanka Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3747ec646SMilanka Ringwald  *
4747ec646SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5747ec646SMilanka Ringwald  * modification, are permitted provided that the following conditions
6747ec646SMilanka Ringwald  * are met:
7747ec646SMilanka Ringwald  *
8747ec646SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9747ec646SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10747ec646SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11747ec646SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12747ec646SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13747ec646SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14747ec646SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15747ec646SMilanka Ringwald  *    from this software without specific prior written permission.
16747ec646SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17747ec646SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18747ec646SMilanka Ringwald  *    monetary gain.
19747ec646SMilanka Ringwald  *
20747ec646SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21747ec646SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22747ec646SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23747ec646SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24747ec646SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25747ec646SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26747ec646SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27747ec646SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28747ec646SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29747ec646SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30747ec646SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31747ec646SMilanka Ringwald  * SUCH DAMAGE.
32747ec646SMilanka Ringwald  *
33747ec646SMilanka Ringwald  * Please inquire about commercial licensing options at
34747ec646SMilanka Ringwald  * [email protected]
35747ec646SMilanka Ringwald  *
36747ec646SMilanka Ringwald  */
37747ec646SMilanka Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avdtp.c"
39ab2c6ae4SMatthias Ringwald 
40747ec646SMilanka Ringwald 
41747ec646SMilanka Ringwald #include <stdint.h>
42747ec646SMilanka Ringwald #include <string.h>
43747ec646SMilanka Ringwald 
4484e3541eSMilanka Ringwald #include "bluetooth_psm.h"
4584e3541eSMilanka Ringwald #include "bluetooth_sdp.h"
4684e3541eSMilanka Ringwald #include "btstack_debug.h"
4784e3541eSMilanka Ringwald #include "btstack_event.h"
4884e3541eSMilanka Ringwald #include "btstack_memory.h"
494cb889a5SMilanka Ringwald #include "classic/avdtp.h"
504cb889a5SMilanka Ringwald #include "classic/avdtp_acceptor.h"
514cb889a5SMilanka Ringwald #include "classic/avdtp_initiator.h"
5284e3541eSMilanka Ringwald #include "classic/avdtp_util.h"
5384e3541eSMilanka Ringwald #include "classic/sdp_client.h"
5484e3541eSMilanka Ringwald #include "classic/sdp_util.h"
55747ec646SMilanka Ringwald 
56d8e15394SMilanka Ringwald btstack_linked_list_t stream_endpoints;
57d8e15394SMilanka Ringwald 
58a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_source_callback;
59a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_sink_callback;
605797104aSMilanka Ringwald static btstack_context_callback_registration_t avdtp_handle_sdp_client_query_request;
61a1fb0563SMilanka Ringwald 
62ca2c9990SMilanka Ringwald static uint16_t sdp_query_context_avdtp_cid = 0;
63f0c39502SMilanka Ringwald 
64560b3f31SMilanka Ringwald static uint16_t stream_endpoints_id_counter = 0;
65560b3f31SMilanka Ringwald 
665ace758fSMilanka Ringwald static btstack_linked_list_t connections;
67b1935866SMilanka Ringwald static uint16_t transaction_id_counter = 0;
685ace758fSMilanka Ringwald 
69692c0605SMilanka Ringwald static int record_id = -1;
70fa1ee4d3SMilanka Ringwald static uint8_t   attribute_value[45];
71692c0605SMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value);
72747ec646SMilanka Ringwald 
73951d2774SMatthias Ringwald static void (*avdtp_sink_handle_media_data)(uint8_t local_seid, uint8_t *packet, uint16_t size);
74951d2774SMatthias Ringwald 
75af121d54SMilanka Ringwald static uint16_t avdtp_cid_counter = 0;
76747ec646SMilanka Ringwald 
77692c0605SMilanka Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
78692c0605SMilanka Ringwald 
79f751daa3SMatthias Ringwald btstack_packet_handler_t
80f751daa3SMatthias Ringwald avdtp_packet_handler_for_stream_endpoint(const avdtp_stream_endpoint_t *stream_endpoint) {
81f751daa3SMatthias Ringwald     return (stream_endpoint->sep.type == AVDTP_SOURCE) ? avdtp_source_callback : avdtp_sink_callback;
82f751daa3SMatthias Ringwald }
83f751daa3SMatthias Ringwald 
84c69f4ba5SMatthias Ringwald void avdtp_emit_sink_and_source(uint8_t * packet, uint16_t size){
85c69f4ba5SMatthias Ringwald     if (avdtp_source_callback != NULL){
86c69f4ba5SMatthias Ringwald         (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size);
87c69f4ba5SMatthias Ringwald     }
88c69f4ba5SMatthias Ringwald     if (avdtp_sink_callback != NULL){
89c69f4ba5SMatthias Ringwald         (*avdtp_sink_callback)(HCI_EVENT_PACKET, 0, packet, size);
90c69f4ba5SMatthias Ringwald     }
91c69f4ba5SMatthias Ringwald }
92c69f4ba5SMatthias Ringwald 
934b7d40bbSMatthias Ringwald void avdtp_emit_source(uint8_t * packet, uint16_t size){
944b7d40bbSMatthias Ringwald     if (avdtp_source_callback != NULL){
954b7d40bbSMatthias Ringwald         (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size);
96f751daa3SMatthias Ringwald     }
97f08f4934SMatthias Ringwald }
98f08f4934SMatthias Ringwald 
99f751daa3SMatthias Ringwald btstack_linked_list_t * avdtp_get_stream_endpoints(void){
100f751daa3SMatthias Ringwald     return &stream_endpoints;
101f751daa3SMatthias Ringwald }
10236da8747SMilanka Ringwald 
10362c4ec82SMilanka Ringwald btstack_linked_list_t * avdtp_get_connections(void){
10462c4ec82SMilanka Ringwald     return &connections;
10562c4ec82SMilanka Ringwald }
10662c4ec82SMilanka Ringwald 
1075ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_get_connection_for_bd_addr(bd_addr_t addr){
1085ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
1095ace758fSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
1105ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1115ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1125ace758fSMilanka Ringwald         if (memcmp(addr, connection->remote_addr, 6) != 0) continue;
1135ace758fSMilanka Ringwald         return connection;
114b0d75c91SMilanka Ringwald     }
1155ace758fSMilanka Ringwald     return NULL;
116b0d75c91SMilanka Ringwald }
117b0d75c91SMilanka Ringwald 
1185ace758fSMilanka Ringwald  avdtp_connection_t * avdtp_get_connection_for_avdtp_cid(uint16_t avdtp_cid){
1195ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
1205ace758fSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
1215ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1225ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1235ace758fSMilanka Ringwald         if (connection->avdtp_cid != avdtp_cid) continue;
1245ace758fSMilanka Ringwald         return connection;
1255ace758fSMilanka Ringwald     }
1265ace758fSMilanka Ringwald     return NULL;
1275ace758fSMilanka Ringwald }
1285ace758fSMilanka Ringwald 
1295ace758fSMilanka Ringwald 
1303338afc0SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_seid(uint16_t seid){
1315ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
132d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1335ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1345ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1355ace758fSMilanka Ringwald         if (stream_endpoint->sep.seid == seid){
1365ace758fSMilanka Ringwald             return stream_endpoint;
1375ace758fSMilanka Ringwald         }
1385ace758fSMilanka Ringwald     }
1395ace758fSMilanka Ringwald     return NULL;
1405ace758fSMilanka Ringwald }
1415ace758fSMilanka Ringwald 
1425ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid){
1435ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
1445ace758fSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
1455ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1465ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1475ace758fSMilanka Ringwald         if (connection->l2cap_signaling_cid != l2cap_cid) continue;
1485ace758fSMilanka Ringwald         return connection;
1495ace758fSMilanka Ringwald     }
1505ace758fSMilanka Ringwald     return NULL;
1515ace758fSMilanka Ringwald }
1525ace758fSMilanka Ringwald 
1536f98b084SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid){
1545ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
155d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1565ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1575ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1585ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_media_cid == l2cap_cid){
1595ace758fSMilanka Ringwald             return stream_endpoint;
1605ace758fSMilanka Ringwald         }
1615ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_reporting_cid == l2cap_cid){
1625ace758fSMilanka Ringwald             return stream_endpoint;
1635ace758fSMilanka Ringwald         }
1645ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_recovery_cid == l2cap_cid){
1655ace758fSMilanka Ringwald             return stream_endpoint;
1665ace758fSMilanka Ringwald         }
1675ace758fSMilanka Ringwald     }
1685ace758fSMilanka Ringwald     return NULL;
1695ace758fSMilanka Ringwald }
1705ace758fSMilanka Ringwald 
17119a000d1SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_signaling_cid(uint16_t l2cap_cid){
1725ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
173d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1745ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1755ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1765ace758fSMilanka Ringwald         if (stream_endpoint->connection){
1775ace758fSMilanka Ringwald             if (stream_endpoint->connection->l2cap_signaling_cid == l2cap_cid){
1785ace758fSMilanka Ringwald                 return stream_endpoint;
1795ace758fSMilanka Ringwald             }
1805ace758fSMilanka Ringwald         }
1815ace758fSMilanka Ringwald     }
1825ace758fSMilanka Ringwald     return NULL;
1835ace758fSMilanka Ringwald }
1845ace758fSMilanka Ringwald 
185b1935866SMilanka Ringwald uint16_t avdtp_get_next_transaction_label(void){
186b1935866SMilanka Ringwald     transaction_id_counter++;
187b1935866SMilanka Ringwald     if (transaction_id_counter == 16){
188b1935866SMilanka Ringwald         transaction_id_counter = 1;
1895ace758fSMilanka Ringwald     }
190b1935866SMilanka Ringwald     return transaction_id_counter;
1915ace758fSMilanka Ringwald }
1925ace758fSMilanka Ringwald 
1935ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_create_connection(bd_addr_t remote_addr, uint16_t cid){
19436da8747SMilanka Ringwald     avdtp_connection_t * connection = btstack_memory_avdtp_connection_get();
19536da8747SMilanka Ringwald     if (!connection){
19636da8747SMilanka Ringwald         log_error("Not enough memory to create connection");
19736da8747SMilanka Ringwald         return NULL;
19836da8747SMilanka Ringwald     }
19936da8747SMilanka Ringwald     connection->state = AVDTP_SIGNALING_CONNECTION_IDLE;
200b1935866SMilanka Ringwald     connection->initiator_transaction_label = avdtp_get_next_transaction_label();
20136da8747SMilanka Ringwald     connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE;
20262c4ec82SMilanka Ringwald     connection->a2dp_source_discover_seps = false;
20336da8747SMilanka Ringwald     connection->avdtp_cid = cid;
20436da8747SMilanka Ringwald     (void)memcpy(connection->remote_addr, remote_addr, 6);
20536da8747SMilanka Ringwald 
2065ace758fSMilanka Ringwald     btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection);
20736da8747SMilanka Ringwald     return connection;
20836da8747SMilanka Ringwald }
20936da8747SMilanka Ringwald 
21036da8747SMilanka Ringwald static uint16_t avdtp_get_next_cid(void){
211af121d54SMilanka Ringwald     if (avdtp_cid_counter == 0xffff) {
2124ccacc40SMilanka Ringwald         avdtp_cid_counter = 1;
213af121d54SMilanka Ringwald     } else {
214af121d54SMilanka Ringwald         avdtp_cid_counter++;
2154ccacc40SMilanka Ringwald     }
2164ccacc40SMilanka Ringwald     return avdtp_cid_counter;
2174ccacc40SMilanka Ringwald }
2184ccacc40SMilanka Ringwald 
219560b3f31SMilanka Ringwald static uint16_t avdtp_get_next_local_seid(void){
220560b3f31SMilanka Ringwald     if (stream_endpoints_id_counter == 0xffff) {
221560b3f31SMilanka Ringwald         stream_endpoints_id_counter = 1;
222af121d54SMilanka Ringwald     } else {
223560b3f31SMilanka Ringwald         stream_endpoints_id_counter++;
2244ccacc40SMilanka Ringwald     }
225560b3f31SMilanka Ringwald     return stream_endpoints_id_counter;
2264ccacc40SMilanka Ringwald }
2274ccacc40SMilanka Ringwald 
2285797104aSMilanka Ringwald static void avdtp_handle_start_sdp_client_query(void * context){
2295797104aSMilanka Ringwald     UNUSED(context);
230b1549ed3SMilanka Ringwald 
2315797104aSMilanka Ringwald     btstack_linked_list_iterator_t it;
2325797104aSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
2335797104aSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2345797104aSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
2355797104aSMilanka Ringwald 
2365797104aSMilanka Ringwald         switch (connection->state){
2375797104aSMilanka Ringwald             case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE:
2385797104aSMilanka Ringwald                 connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE;
2395797104aSMilanka Ringwald                 break;
2405797104aSMilanka Ringwald             case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK:
2415797104aSMilanka Ringwald                 connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE;
2425797104aSMilanka Ringwald                 break;
243cc61e7e9SMilanka Ringwald             case AVDTP_SIGNALING_CONNECTION_OPENED:
244cc61e7e9SMilanka Ringwald                 if (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES) continue;
245cc61e7e9SMilanka Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SDP_QUERY_COMPLETE_THEN_GET_ALL_CAPABILITIES;
246cc61e7e9SMilanka Ringwald                 break;
2475797104aSMilanka Ringwald             default:
2485797104aSMilanka Ringwald                 continue;
2495797104aSMilanka Ringwald         }
2505797104aSMilanka Ringwald         sdp_query_context_avdtp_cid = connection->avdtp_cid;
2515797104aSMilanka Ringwald         sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP);
2525797104aSMilanka Ringwald         return;
2535797104aSMilanka Ringwald     }
25484521ac1SMilanka Ringwald }
25584521ac1SMilanka Ringwald 
256a1fb0563SMilanka Ringwald uint8_t avdtp_connect(bd_addr_t remote, avdtp_role_t role, uint16_t * avdtp_cid){
2575ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_bd_addr(remote);
25884521ac1SMilanka Ringwald     if (connection){
25984521ac1SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
2604567cc17SMilanka Ringwald     }
26184521ac1SMilanka Ringwald 
26236da8747SMilanka Ringwald     uint16_t cid = avdtp_get_next_cid();
2632ad6b656SMilanka Ringwald     if (avdtp_cid != NULL) {
26484521ac1SMilanka Ringwald         *avdtp_cid = cid;
2652ad6b656SMilanka Ringwald     }
2662ad6b656SMilanka Ringwald 
2675ace758fSMilanka Ringwald     connection = avdtp_create_connection(remote, cid);
26836da8747SMilanka Ringwald     if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED;
26936da8747SMilanka Ringwald 
27084521ac1SMilanka Ringwald     connection->avdtp_cid = cid;
271b1549ed3SMilanka Ringwald 
2725797104aSMilanka Ringwald     connection->avdtp_l2cap_psm = 0;
2735797104aSMilanka Ringwald     connection->avdtp_version  = 0;
2745797104aSMilanka Ringwald     connection->sink_supported = false;
2755797104aSMilanka Ringwald     connection->source_supported = false;
2765797104aSMilanka Ringwald 
277b1549ed3SMilanka Ringwald     switch (role){
278149deddbSMilanka Ringwald         case AVDTP_ROLE_SOURCE:
2795797104aSMilanka Ringwald             connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK;
280149deddbSMilanka Ringwald             break;
281149deddbSMilanka Ringwald         case AVDTP_ROLE_SINK:
2825797104aSMilanka Ringwald             connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE;
283149deddbSMilanka Ringwald             break;
284149deddbSMilanka Ringwald         default:
2855797104aSMilanka Ringwald             btstack_assert(false);
286149deddbSMilanka Ringwald             return ERROR_CODE_COMMAND_DISALLOWED;
287149deddbSMilanka Ringwald     }
2885797104aSMilanka Ringwald 
2895797104aSMilanka Ringwald     avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query;
2905797104aSMilanka Ringwald     // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
2915797104aSMilanka Ringwald     (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
2925797104aSMilanka Ringwald     return ERROR_CODE_SUCCESS;
293692c0605SMilanka Ringwald }
294747ec646SMilanka Ringwald 
295a1fb0563SMilanka Ringwald 
296a1fb0563SMilanka Ringwald void avdtp_register_sink_packet_handler(btstack_packet_handler_t callback){
297a1fb0563SMilanka Ringwald     btstack_assert(callback != NULL);
298a1fb0563SMilanka Ringwald     avdtp_sink_callback = callback;
299a1fb0563SMilanka Ringwald }
300a1fb0563SMilanka Ringwald 
301a1fb0563SMilanka Ringwald void avdtp_register_source_packet_handler(btstack_packet_handler_t callback){
302a1fb0563SMilanka Ringwald     btstack_assert(callback != NULL);
303a1fb0563SMilanka Ringwald     avdtp_source_callback = callback;
304a1fb0563SMilanka Ringwald }
305a1fb0563SMilanka Ringwald 
306747ec646SMilanka Ringwald void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){
307747ec646SMilanka Ringwald     if (!stream_endpoint){
3089900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
309747ec646SMilanka Ringwald         return;
310747ec646SMilanka Ringwald     }
311747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1);
312747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
313747ec646SMilanka Ringwald }
314747ec646SMilanka Ringwald 
315747ec646SMilanka Ringwald void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){
316747ec646SMilanka Ringwald     if (!stream_endpoint){
3179900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
318747ec646SMilanka Ringwald         return;
319747ec646SMilanka Ringwald     }
320747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_REPORTING, 1);
321747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
322747ec646SMilanka Ringwald }
323747ec646SMilanka Ringwald 
324747ec646SMilanka Ringwald void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){
325747ec646SMilanka Ringwald     if (!stream_endpoint){
3269900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
327747ec646SMilanka Ringwald         return;
328747ec646SMilanka Ringwald     }
329747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_DELAY_REPORTING, 1);
330747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
331747ec646SMilanka Ringwald }
332747ec646SMilanka Ringwald 
333747ec646SMilanka Ringwald void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){
334747ec646SMilanka Ringwald     if (!stream_endpoint){
3359900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
336747ec646SMilanka Ringwald         return;
337747ec646SMilanka Ringwald     }
338747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_RECOVERY, 1);
339747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
340747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.recovery_type = 0x01; // 0x01 = RFC2733
341747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.maximum_recovery_window_size = maximum_recovery_window_size;
342747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.maximum_number_media_packets = maximum_number_media_packets;
343747ec646SMilanka Ringwald }
344747ec646SMilanka Ringwald 
345747ec646SMilanka Ringwald void avdtp_register_content_protection_category(avdtp_stream_endpoint_t * stream_endpoint, uint16_t cp_type, const uint8_t * cp_type_value, uint8_t cp_type_value_len){
346747ec646SMilanka Ringwald     if (!stream_endpoint){
3479900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
348747ec646SMilanka Ringwald         return;
349747ec646SMilanka Ringwald     }
350747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_CONTENT_PROTECTION, 1);
351747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
352747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.content_protection.cp_type = cp_type;
3536535961aSMatthias Ringwald     (void)memcpy(stream_endpoint->sep.capabilities.content_protection.cp_type_value,
3546535961aSMatthias Ringwald                  cp_type_value,
3556535961aSMatthias Ringwald                  btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN));
35667ae582dSMilanka Ringwald     stream_endpoint->sep.capabilities.content_protection.cp_type_value_len = btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN);
357747ec646SMilanka Ringwald }
358747ec646SMilanka Ringwald 
359747ec646SMilanka Ringwald void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery){
360747ec646SMilanka Ringwald     if (!stream_endpoint){
3619900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
362747ec646SMilanka Ringwald         return;
363747ec646SMilanka Ringwald     }
364747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_HEADER_COMPRESSION, 1);
365747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
366747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.back_ch = back_ch;
367747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.media = media;
368747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.recovery = recovery;
369747ec646SMilanka Ringwald }
370747ec646SMilanka Ringwald 
37178d08d09SMilanka Ringwald void avdtp_register_media_codec_category(avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len){
372747ec646SMilanka Ringwald     if (!stream_endpoint){
3739900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
374747ec646SMilanka Ringwald         return;
375747ec646SMilanka Ringwald     }
376747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1);
377747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
378747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_type = media_type;
379747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type;
380747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_information = media_codec_info;
381747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_information_len = media_codec_info_len;
382747ec646SMilanka Ringwald }
383747ec646SMilanka Ringwald 
384747ec646SMilanka Ringwald void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation){
385747ec646SMilanka Ringwald     if (!stream_endpoint){
3869900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
387747ec646SMilanka Ringwald         return;
388747ec646SMilanka Ringwald     }
389747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MULTIPLEXING, 1);
390747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
391747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.multiplexing_mode.fragmentation = fragmentation;
392747ec646SMilanka Ringwald }
393747ec646SMilanka Ringwald 
394951d2774SMatthias Ringwald void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size)){
395951d2774SMatthias Ringwald     avdtp_sink_handle_media_data = callback;
396951d2774SMatthias Ringwald }
397747ec646SMilanka Ringwald 
398d80ccd43SMatthias Ringwald /* START: tracking can send now requests per l2cap cid */
399d80ccd43SMatthias Ringwald static void avdtp_handle_can_send_now(uint16_t l2cap_cid) {
400d80ccd43SMatthias Ringwald 
401d80ccd43SMatthias Ringwald 	log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", l2cap_cid);
402d80ccd43SMatthias Ringwald 
403d80ccd43SMatthias Ringwald 	// get signaling connection for l2cap cid
404d80ccd43SMatthias Ringwald 	avdtp_connection_t * connection = avdtp_get_connection_for_l2cap_signaling_cid(l2cap_cid);
405d80ccd43SMatthias Ringwald 
406d80ccd43SMatthias Ringwald 	if (connection != NULL) {
407747ec646SMilanka Ringwald 		if (connection->wait_to_send_acceptor) {
408d80ccd43SMatthias Ringwald 			log_debug("call avdtp_acceptor_stream_config_subsm_run %p", connection);
409d80ccd43SMatthias Ringwald 			connection->wait_to_send_acceptor = false;
41077092f3eSMatthias Ringwald 			avdtp_acceptor_stream_config_subsm_run(connection);
411747ec646SMilanka Ringwald 		} else if (connection->wait_to_send_initiator) {
412d80ccd43SMatthias Ringwald 			log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling %p", connection);
413d80ccd43SMatthias Ringwald 			connection->wait_to_send_initiator = false;
414d80ccd43SMatthias Ringwald 			avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling(connection);
415d80ccd43SMatthias Ringwald 		}
416d80ccd43SMatthias Ringwald 		bool more_to_send = connection->wait_to_send_acceptor || connection->wait_to_send_initiator;
417d80ccd43SMatthias Ringwald 		if (more_to_send){
418d80ccd43SMatthias Ringwald 			l2cap_request_can_send_now_event(l2cap_cid);
419d80ccd43SMatthias Ringwald 		}
420d80ccd43SMatthias Ringwald 		return;
421747ec646SMilanka Ringwald 	}
422747ec646SMilanka Ringwald 
423d80ccd43SMatthias Ringwald 	// get stream endpoint connection for l2cap cid
424d80ccd43SMatthias Ringwald 	avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(l2cap_cid);
425d80ccd43SMatthias Ringwald 	if (stream_endpoint != NULL) {
426d80ccd43SMatthias Ringwald 		log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint %p", stream_endpoint);
427d80ccd43SMatthias Ringwald 		if (stream_endpoint->request_can_send_now) {
428d80ccd43SMatthias Ringwald 			stream_endpoint->request_can_send_now = 0;
429d80ccd43SMatthias Ringwald 			avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint(stream_endpoint);
430d80ccd43SMatthias Ringwald 		}
431d80ccd43SMatthias Ringwald 		bool more_to_send = stream_endpoint->request_can_send_now != 0;
432747ec646SMilanka Ringwald 		if (more_to_send){
433747ec646SMilanka Ringwald 			l2cap_request_can_send_now_event(l2cap_cid);
434747ec646SMilanka Ringwald 		}
435747ec646SMilanka Ringwald 	}
436d80ccd43SMatthias Ringwald }
437d80ccd43SMatthias Ringwald /* END: tracking can send now requests per l2cap cid */
438747ec646SMilanka Ringwald 
439747ec646SMilanka Ringwald 
440297feb5fSMilanka Ringwald avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){
441747ec646SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = btstack_memory_avdtp_stream_endpoint_get();
4424567cc17SMilanka Ringwald     if (!stream_endpoint){
4439900b7faSMilanka Ringwald         log_error("Not enough memory to create stream endpoint");
4444567cc17SMilanka Ringwald         return NULL;
4454567cc17SMilanka Ringwald     }
446560b3f31SMilanka Ringwald     stream_endpoint->sep.seid = avdtp_get_next_local_seid();
447747ec646SMilanka Ringwald     stream_endpoint->sep.media_type = media_type;
448747ec646SMilanka Ringwald     stream_endpoint->sep.type = sep_type;
449d8e15394SMilanka Ringwald     btstack_linked_list_add(avdtp_get_stream_endpoints(), (btstack_linked_item_t *) stream_endpoint);
450747ec646SMilanka Ringwald     return stream_endpoint;
451747ec646SMilanka Ringwald }
452747ec646SMilanka Ringwald 
45317ddf501SMatthias Ringwald void avdtp_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){
45417ddf501SMatthias Ringwald     btstack_linked_list_remove(avdtp_get_stream_endpoints(), (btstack_linked_item_t* ) stream_endpoint);
45517ddf501SMatthias Ringwald     btstack_memory_avdtp_stream_endpoint_free(stream_endpoint);
45617ddf501SMatthias Ringwald }
45717ddf501SMatthias Ringwald 
45877092f3eSMatthias Ringwald static void
45977092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t *connection, uint8_t *packet, uint16_t size) {
460c1c40ea1SMatthias Ringwald     if (size < 2) return;
461c1c40ea1SMatthias Ringwald 
462c1c40ea1SMatthias Ringwald     uint16_t offset;
463c1c40ea1SMatthias Ringwald     avdtp_message_type_t message_type = avdtp_get_signaling_packet_type(packet);
464c1c40ea1SMatthias Ringwald     switch (message_type){
465747ec646SMilanka Ringwald         case AVDTP_CMD_MSG:
46650453b92SMatthias Ringwald             offset = avdtp_read_signaling_header(&connection->acceptor_signaling_packet, packet, size);
46777092f3eSMatthias Ringwald             avdtp_acceptor_stream_config_subsm(connection, packet, size, offset);
468747ec646SMilanka Ringwald             break;
469747ec646SMilanka Ringwald         default:
47050453b92SMatthias Ringwald             offset = avdtp_read_signaling_header(&connection->initiator_signaling_packet, packet, size);
47177092f3eSMatthias Ringwald             avdtp_initiator_stream_config_subsm(connection, packet, size, offset);
472747ec646SMilanka Ringwald             break;
473747ec646SMilanka Ringwald     }
474747ec646SMilanka Ringwald }
475747ec646SMilanka Ringwald 
476b1549ed3SMilanka Ringwald static void avdtp_handle_sdp_client_query_attribute_value(avdtp_connection_t * connection, uint8_t *packet){
477692c0605SMilanka Ringwald     des_iterator_t des_list_it;
478692c0605SMilanka Ringwald     des_iterator_t prot_it;
479692c0605SMilanka Ringwald 
480692c0605SMilanka Ringwald     // Handle new SDP record
481692c0605SMilanka Ringwald     if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id) {
482692c0605SMilanka Ringwald         record_id = sdp_event_query_attribute_byte_get_record_id(packet);
4838587e32cSMilanka Ringwald         // log_info("SDP Record: Nr: %d", record_id);
484692c0605SMilanka Ringwald     }
485692c0605SMilanka Ringwald 
486692c0605SMilanka Ringwald     if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) {
487692c0605SMilanka Ringwald         attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
488692c0605SMilanka Ringwald 
489692c0605SMilanka Ringwald         if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) {
490692c0605SMilanka Ringwald 
491692c0605SMilanka Ringwald             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
492149deddbSMilanka Ringwald 
493692c0605SMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST:
494692c0605SMilanka Ringwald                     if (de_get_element_type(attribute_value) != DE_DES) break;
495692c0605SMilanka Ringwald                     for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
496692c0605SMilanka Ringwald                         uint8_t * element = des_iterator_get_element(&des_list_it);
497692c0605SMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
498692c0605SMilanka Ringwald                         uint32_t uuid = de_get_uuid32(element);
499692c0605SMilanka Ringwald                         switch (uuid){
500692c0605SMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE:
501b1549ed3SMilanka Ringwald                                 connection->source_supported = true;
502149deddbSMilanka Ringwald                                 log_info("source_supported");
503692c0605SMilanka Ringwald                                 break;
504692c0605SMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK:
505b1549ed3SMilanka Ringwald                                 connection->sink_supported = true;
506149deddbSMilanka Ringwald                                 log_info("sink_supported");
507692c0605SMilanka Ringwald                                 break;
508692c0605SMilanka Ringwald                             default:
509692c0605SMilanka Ringwald                                 break;
510692c0605SMilanka Ringwald                         }
511692c0605SMilanka Ringwald                     }
512692c0605SMilanka Ringwald                     break;
513692c0605SMilanka Ringwald 
514149deddbSMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
5158587e32cSMilanka Ringwald                     // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
516692c0605SMilanka Ringwald                     for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
517692c0605SMilanka Ringwald                         uint8_t       *des_element;
518692c0605SMilanka Ringwald                         uint8_t       *element;
519692c0605SMilanka Ringwald                         uint32_t       uuid;
520692c0605SMilanka Ringwald 
521692c0605SMilanka Ringwald                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
522692c0605SMilanka Ringwald 
523692c0605SMilanka Ringwald                         des_element = des_iterator_get_element(&des_list_it);
524692c0605SMilanka Ringwald                         des_iterator_init(&prot_it, des_element);
525692c0605SMilanka Ringwald                         element = des_iterator_get_element(&prot_it);
526692c0605SMilanka Ringwald 
527692c0605SMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
528692c0605SMilanka Ringwald 
529692c0605SMilanka Ringwald                         uuid = de_get_uuid32(element);
53014fd128cSMatthias Ringwald                         des_iterator_next(&prot_it);
531149deddbSMilanka Ringwald                         // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both
532692c0605SMilanka Ringwald                         switch (uuid){
533692c0605SMilanka Ringwald                             case BLUETOOTH_PROTOCOL_L2CAP:
534692c0605SMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
535b1549ed3SMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_l2cap_psm);
536692c0605SMilanka Ringwald                                 break;
537692c0605SMilanka Ringwald                             case BLUETOOTH_PROTOCOL_AVDTP:
538692c0605SMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
539b1549ed3SMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_version);
540cc61e7e9SMilanka Ringwald                                 log_info("avdtp version 0x%02x", connection->avdtp_version);
541692c0605SMilanka Ringwald                                 break;
542692c0605SMilanka Ringwald                             default:
543692c0605SMilanka Ringwald                                 break;
544692c0605SMilanka Ringwald                         }
545692c0605SMilanka Ringwald                     }
546692c0605SMilanka Ringwald                     break;
547149deddbSMilanka Ringwald 
548692c0605SMilanka Ringwald                 default:
549692c0605SMilanka Ringwald                     break;
550692c0605SMilanka Ringwald             }
551692c0605SMilanka Ringwald         }
552692c0605SMilanka Ringwald     } else {
5538587e32cSMilanka 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));
554692c0605SMilanka Ringwald     }
5556ed344c3SMatthias Ringwald 
5566ed344c3SMatthias Ringwald }
5576ed344c3SMatthias Ringwald 
5585ace758fSMilanka Ringwald static void avdtp_finalize_connection(avdtp_connection_t * connection){
559ff53b162SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->retry_timer);
5605ace758fSMilanka Ringwald     btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection);
561f0c39502SMilanka Ringwald     btstack_memory_avdtp_connection_free(connection);
562f0c39502SMilanka Ringwald }
563f0c39502SMilanka Ringwald 
564f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_failed(avdtp_connection_t * connection, uint8_t status){
565a1fb0563SMilanka Ringwald     switch (connection->state){
566a1fb0563SMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE:
567a1fb0563SMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE:
568146fc0fbSMilanka Ringwald             avdtp_signaling_emit_connection_established(connection->avdtp_cid, connection->remote_addr, connection->con_handle, status);
569a1fb0563SMilanka Ringwald             break;
570cc61e7e9SMilanka Ringwald 
571cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
572cc61e7e9SMilanka Ringwald             // SDP query failed: try query that must be supported
573cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
574d80ccd43SMatthias Ringwald 			avdtp_request_can_send_now_initiator(connection);
575a1fb0563SMilanka Ringwald             return;
576cc61e7e9SMilanka Ringwald 
577cc61e7e9SMilanka Ringwald         default:
578cc61e7e9SMilanka Ringwald             btstack_assert(false);
579cc61e7e9SMilanka Ringwald             break;
580a1fb0563SMilanka Ringwald     }
5815ace758fSMilanka Ringwald     avdtp_finalize_connection(connection);
582ca2c9990SMilanka Ringwald     sdp_query_context_avdtp_cid = 0;
583f0c39502SMilanka Ringwald     log_info("SDP query failed with status 0x%02x.", status);
584f0c39502SMilanka Ringwald }
585f0c39502SMilanka Ringwald 
586f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){
587cc61e7e9SMilanka Ringwald     log_info("avdtp_handle_sdp_query_succeeded: state %d", connection->state);
588cc61e7e9SMilanka Ringwald 
589cc61e7e9SMilanka Ringwald     switch (connection->state){
590cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
591cc61e7e9SMilanka Ringwald             if (connection->avdtp_version < 0x0103){
592cc61e7e9SMilanka Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
593cc61e7e9SMilanka Ringwald             } else {
594cc61e7e9SMilanka Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES;
595cc61e7e9SMilanka Ringwald             }
596d80ccd43SMatthias Ringwald 			avdtp_request_can_send_now_initiator(connection);
597cc61e7e9SMilanka Ringwald             break;
598cc61e7e9SMilanka Ringwald         default:
599f0c39502SMilanka Ringwald             connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
600cc61e7e9SMilanka Ringwald             l2cap_create_channel(avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL);
601cc61e7e9SMilanka Ringwald             break;
602cc61e7e9SMilanka Ringwald     }
603f0c39502SMilanka Ringwald }
604f0c39502SMilanka Ringwald 
6056ed344c3SMatthias Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
606149deddbSMilanka Ringwald     UNUSED(packet_type);
607149deddbSMilanka Ringwald     UNUSED(channel);
608149deddbSMilanka Ringwald     UNUSED(size);
609149deddbSMilanka Ringwald 
610ca2c9990SMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(sdp_query_context_avdtp_cid);
6116ed344c3SMatthias Ringwald     if (!connection) {
612ca2c9990SMilanka Ringwald         log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context_avdtp_cid);
6136ed344c3SMatthias Ringwald         return;
6146ed344c3SMatthias Ringwald     }
6156ed344c3SMatthias Ringwald 
616722c03bdSMatthias Ringwald     uint8_t status = ERROR_CODE_SUCCESS;
617149deddbSMilanka Ringwald     switch (connection->state){
618149deddbSMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE:
6196ed344c3SMatthias Ringwald             switch (hci_event_packet_get_type(packet)){
6206ed344c3SMatthias Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
621b1549ed3SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
622149deddbSMilanka Ringwald                     return;
623692c0605SMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
6241e1ae2bcSMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
625149deddbSMilanka Ringwald                     if (status != ERROR_CODE_SUCCESS) break;
626722c03bdSMatthias Ringwald                     if (!connection->sink_supported) {
627722c03bdSMatthias Ringwald                         status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
628722c03bdSMatthias Ringwald                         break;
629722c03bdSMatthias Ringwald                     }
630722c03bdSMatthias Ringwald                     if (connection->avdtp_l2cap_psm == 0) {
631722c03bdSMatthias Ringwald                         status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
632722c03bdSMatthias Ringwald                         break;
633722c03bdSMatthias Ringwald                     }
634149deddbSMilanka Ringwald                     break;
635149deddbSMilanka Ringwald                 default:
636149deddbSMilanka Ringwald                     btstack_assert(false);
637722c03bdSMatthias Ringwald                     return;
6381e1ae2bcSMilanka Ringwald             }
639149deddbSMilanka Ringwald             break;
640149deddbSMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE:
641149deddbSMilanka Ringwald             switch (hci_event_packet_get_type(packet)){
642149deddbSMilanka Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
643b1549ed3SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
644149deddbSMilanka Ringwald                     return;
645149deddbSMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
646149deddbSMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
647149deddbSMilanka Ringwald                     if (status != ERROR_CODE_SUCCESS) break;
648722c03bdSMatthias Ringwald                     if (!connection->source_supported) {
649722c03bdSMatthias Ringwald                         status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
650722c03bdSMatthias Ringwald                         break;
651722c03bdSMatthias Ringwald                     }
652722c03bdSMatthias Ringwald                     if (connection->avdtp_l2cap_psm == 0) {
653722c03bdSMatthias Ringwald                         status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE;
654722c03bdSMatthias Ringwald                         break;
655722c03bdSMatthias Ringwald                     }
656149deddbSMilanka Ringwald                     break;
657149deddbSMilanka Ringwald                 default:
658149deddbSMilanka Ringwald                     btstack_assert(false);
659722c03bdSMatthias Ringwald                     return;
660974d4d6eSMilanka Ringwald             }
6612f6083d0SMilanka Ringwald             break;
662cc61e7e9SMilanka Ringwald 
663cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
664cc61e7e9SMilanka Ringwald             switch (hci_event_packet_get_type(packet)){
665cc61e7e9SMilanka Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
666cc61e7e9SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
667cc61e7e9SMilanka Ringwald                     return;
668cc61e7e9SMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
669cc61e7e9SMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
670cc61e7e9SMilanka Ringwald                     break;
671cc61e7e9SMilanka Ringwald                 default:
672cc61e7e9SMilanka Ringwald                     btstack_assert(false);
673cc61e7e9SMilanka Ringwald                     return;
674cc61e7e9SMilanka Ringwald             }
675cc61e7e9SMilanka Ringwald             break;
676cc61e7e9SMilanka Ringwald 
677149deddbSMilanka Ringwald         default:
67808cb850dSMilanka Ringwald             // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete
67908cb850dSMilanka Ringwald             if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){
68008cb850dSMilanka Ringwald                 (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
68108cb850dSMilanka Ringwald             }
682149deddbSMilanka Ringwald             return;
6832f6083d0SMilanka Ringwald     }
684f0c39502SMilanka Ringwald 
685722c03bdSMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
686149deddbSMilanka Ringwald         avdtp_handle_sdp_query_succeeded(connection);
687149deddbSMilanka Ringwald     } else {
688149deddbSMilanka Ringwald         avdtp_handle_sdp_query_failed(connection, status);
689692c0605SMilanka Ringwald     }
6905797104aSMilanka Ringwald 
6915797104aSMilanka Ringwald     // register the SDP Query request to check if there is another connection waiting for the query
6925797104aSMilanka Ringwald     // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
6935797104aSMilanka Ringwald     (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
694692c0605SMilanka Ringwald }
695692c0605SMilanka Ringwald 
696146fc0fbSMilanka Ringwald static avdtp_connection_t * avdtp_handle_incoming_connection(avdtp_connection_t * connection, bd_addr_t event_addr, hci_con_handle_t con_handle, uint16_t local_cid){
69736da8747SMilanka Ringwald     if (connection == NULL){
69836da8747SMilanka Ringwald         uint16_t cid = avdtp_get_next_cid();
6995ace758fSMilanka Ringwald         connection = avdtp_create_connection(event_addr, cid);
70036da8747SMilanka Ringwald     }
701692c0605SMilanka Ringwald 
70236da8747SMilanka Ringwald     if (connection) {
70336da8747SMilanka Ringwald         connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
70436da8747SMilanka Ringwald         connection->l2cap_signaling_cid = local_cid;
705146fc0fbSMilanka Ringwald         connection->con_handle = con_handle;
706ff53b162SMilanka Ringwald         btstack_run_loop_remove_timer(&connection->retry_timer);
70736da8747SMilanka Ringwald     }
70836da8747SMilanka Ringwald     return connection;
70936da8747SMilanka Ringwald }
710f0c39502SMilanka Ringwald 
711ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){
712326e3662SMilanka Ringwald     uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer);
713326e3662SMilanka Ringwald 
7145ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
715326e3662SMilanka Ringwald     if (connection == NULL) return;
716326e3662SMilanka Ringwald 
717ff53b162SMilanka Ringwald     if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){
718326e3662SMilanka Ringwald         connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
719326e3662SMilanka Ringwald         l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL);
720326e3662SMilanka Ringwald     }
721326e3662SMilanka Ringwald }
722326e3662SMilanka Ringwald 
723ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){
724ff53b162SMilanka Ringwald     btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler);
725ff53b162SMilanka Ringwald     btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid);
726326e3662SMilanka Ringwald 
727326e3662SMilanka Ringwald     // add some jitter/randomness to reconnect delay
728326e3662SMilanka Ringwald     uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F);
729ff53b162SMilanka Ringwald     btstack_run_loop_set_timer(&connection->retry_timer, timeout);
730ff53b162SMilanka Ringwald     btstack_run_loop_add_timer(&connection->retry_timer);
731326e3662SMilanka Ringwald }
732326e3662SMilanka Ringwald 
733326e3662SMilanka Ringwald 
734326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
735747ec646SMilanka Ringwald     bd_addr_t event_addr;
736747ec646SMilanka Ringwald     uint16_t psm;
737747ec646SMilanka Ringwald     uint16_t local_cid;
7381e1ae2bcSMilanka Ringwald     uint8_t  status;
739326e3662SMilanka Ringwald     uint16_t l2cap_mtu;
740146fc0fbSMilanka Ringwald     hci_con_handle_t con_handle;
74136da8747SMilanka Ringwald 
74236da8747SMilanka Ringwald     bool accept_streaming_connection;
74336da8747SMilanka Ringwald     bool outoing_signaling_active;
74436da8747SMilanka Ringwald     bool decline_connection;
74584521ac1SMilanka Ringwald 
746747ec646SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = NULL;
747747ec646SMilanka Ringwald     avdtp_connection_t * connection = NULL;
74836da8747SMilanka Ringwald 
749747ec646SMilanka Ringwald     switch (packet_type) {
750747ec646SMilanka Ringwald         case L2CAP_DATA_PACKET:
7515ace758fSMilanka Ringwald             connection = avdtp_get_connection_for_l2cap_signaling_cid(channel);
752747ec646SMilanka Ringwald             if (connection){
75377092f3eSMatthias Ringwald                 handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);
754747ec646SMilanka Ringwald                 break;
755747ec646SMilanka Ringwald             }
756747ec646SMilanka Ringwald 
7576f98b084SMilanka Ringwald             stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel);
758747ec646SMilanka Ringwald             if (!stream_endpoint){
759747ec646SMilanka Ringwald                 if (!connection) break;
76077092f3eSMatthias Ringwald                 handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);
761747ec646SMilanka Ringwald                 break;
762747ec646SMilanka Ringwald             }
763747ec646SMilanka Ringwald 
7648c0f3635SMilanka Ringwald             if (stream_endpoint->connection){
7659413b167SMilanka Ringwald                 if (channel == stream_endpoint->connection->l2cap_signaling_cid){
76677092f3eSMatthias Ringwald                     handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size);
767747ec646SMilanka Ringwald                     break;
768747ec646SMilanka Ringwald                 }
7698c0f3635SMilanka Ringwald             }
770747ec646SMilanka Ringwald 
771747ec646SMilanka Ringwald             if (channel == stream_endpoint->l2cap_media_cid){
772951d2774SMatthias Ringwald                 btstack_assert(avdtp_sink_handle_media_data);
773951d2774SMatthias Ringwald                 (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size);
774747ec646SMilanka Ringwald                 break;
775747ec646SMilanka Ringwald             }
776747ec646SMilanka Ringwald 
777747ec646SMilanka Ringwald             if (channel == stream_endpoint->l2cap_reporting_cid){
7788587e32cSMilanka Ringwald                 log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED");
779747ec646SMilanka Ringwald             } else if (channel == stream_endpoint->l2cap_recovery_cid){
7808587e32cSMilanka Ringwald                 log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED");
781747ec646SMilanka Ringwald             } else {
782747ec646SMilanka Ringwald                 log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel);
783747ec646SMilanka Ringwald             }
784747ec646SMilanka Ringwald             break;
785747ec646SMilanka Ringwald 
786747ec646SMilanka Ringwald         case HCI_EVENT_PACKET:
787747ec646SMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
78836da8747SMilanka Ringwald 
789747ec646SMilanka Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
790747ec646SMilanka Ringwald                     l2cap_event_incoming_connection_get_address(packet, event_addr);
791747ec646SMilanka Ringwald                     local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
792146fc0fbSMilanka Ringwald                     con_handle = l2cap_event_incoming_connection_get_handle(packet);
79336da8747SMilanka Ringwald                     outoing_signaling_active = false;
79436da8747SMilanka Ringwald                     accept_streaming_connection = false;
79536da8747SMilanka Ringwald 
7965ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_bd_addr(event_addr);
79736da8747SMilanka Ringwald                     if (connection != NULL){
7980d4a198eSMatthias Ringwald                         switch (connection->state){
7990d4a198eSMatthias Ringwald                             case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED:
80036da8747SMilanka Ringwald                             case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED:
80136da8747SMilanka Ringwald                                 outoing_signaling_active = true;
80236da8747SMilanka Ringwald                                 connection->incoming_declined = true;
80336da8747SMilanka Ringwald                                 break;
80436da8747SMilanka Ringwald                             case AVDTP_SIGNALING_CONNECTION_OPENED:
80536da8747SMilanka Ringwald                                 outoing_signaling_active = true;
80636da8747SMilanka Ringwald                                 accept_streaming_connection = true;
80736da8747SMilanka Ringwald                                 break;
808f0c39502SMilanka Ringwald                             default:
809f0c39502SMilanka Ringwald                                 break;
8100d4a198eSMatthias Ringwald                         }
811747ec646SMilanka Ringwald                     }
81236da8747SMilanka Ringwald                     log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d",
81336da8747SMilanka Ringwald                         bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection);
814747ec646SMilanka Ringwald 
81536da8747SMilanka Ringwald                     decline_connection = outoing_signaling_active && !accept_streaming_connection;
81636da8747SMilanka Ringwald                     if (outoing_signaling_active == false){
817146fc0fbSMilanka Ringwald                         connection = avdtp_handle_incoming_connection(connection, event_addr, con_handle, local_cid);
81836da8747SMilanka Ringwald                         if (connection == NULL){
81936da8747SMilanka Ringwald                             decline_connection = true;
82036da8747SMilanka Ringwald                         }
82136da8747SMilanka Ringwald                     } else if (accept_streaming_connection){
82236da8747SMilanka Ringwald                         if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) {
82336da8747SMilanka Ringwald                             decline_connection = true;
82436da8747SMilanka Ringwald                         } else {
825939e12adSMatthias Ringwald                             // now, we're only dealing with media connections that are created by remote side - we're acceptor here
8263338afc0SMatthias Ringwald                             stream_endpoint = avdtp_get_stream_endpoint_for_seid(connection->acceptor_local_seid);
82736da8747SMilanka Ringwald                             if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) {
82836da8747SMilanka Ringwald                                 decline_connection = true;
82936da8747SMilanka Ringwald                             }
83036da8747SMilanka Ringwald                         }
831747ec646SMilanka Ringwald                     }
832747ec646SMilanka Ringwald 
83336da8747SMilanka Ringwald                     if (decline_connection){
834a3ce0109SMatthias Ringwald                         l2cap_decline_connection(local_cid);
83536da8747SMilanka Ringwald                     } else {
836747ec646SMilanka Ringwald                         l2cap_accept_connection(local_cid);
83736da8747SMilanka Ringwald                     }
838747ec646SMilanka Ringwald                     break;
839747ec646SMilanka Ringwald 
840747ec646SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
841a5114819SMilanka Ringwald 
842a0b8a58cSMilanka Ringwald                     psm = l2cap_event_channel_opened_get_psm(packet);
84384e3541eSMilanka Ringwald                     if (psm != BLUETOOTH_PSM_AVDTP){
844355ac553SMilanka Ringwald                         log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED ");
845a0b8a58cSMilanka Ringwald                         return;
846a0b8a58cSMilanka Ringwald                     }
847a0b8a58cSMilanka Ringwald 
8481e1ae2bcSMilanka Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
849747ec646SMilanka Ringwald                     // inform about new l2cap connection
850747ec646SMilanka Ringwald                     l2cap_event_channel_opened_get_address(packet, event_addr);
8517050d2caSMilanka Ringwald                     local_cid = l2cap_event_channel_opened_get_local_cid(packet);
852326e3662SMilanka Ringwald                     l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet);
8535ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_bd_addr(event_addr);
85436da8747SMilanka Ringwald                     if (connection == NULL){
85536da8747SMilanka Ringwald                         log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr));
856a0b8a58cSMilanka Ringwald                         break;
857a0b8a58cSMilanka Ringwald                     }
858a0b8a58cSMilanka Ringwald 
859146fc0fbSMilanka Ringwald                     con_handle = l2cap_event_channel_opened_get_handle(packet);
860146fc0fbSMilanka Ringwald 
861a5114819SMilanka Ringwald                     switch (connection->state){
862a5114819SMilanka Ringwald                         case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED:
863326e3662SMilanka Ringwald                             switch (status){
864326e3662SMilanka Ringwald                                 case ERROR_CODE_SUCCESS:
865326e3662SMilanka Ringwald                                     connection->l2cap_signaling_cid = local_cid;
866326e3662SMilanka Ringwald                                     connection->incoming_declined = false;
867326e3662SMilanka Ringwald                                     connection->l2cap_mtu = l2cap_mtu;
868146fc0fbSMilanka Ringwald                                     connection->con_handle = con_handle;
869326e3662SMilanka Ringwald                                     connection->state = AVDTP_SIGNALING_CONNECTION_OPENED;
870146fc0fbSMilanka Ringwald                                     log_info("Connection opened l2cap_signaling_cid 0x%02x, avdtp_cid 0x%02x, con_handle 0x%02x", connection->l2cap_signaling_cid, connection->avdtp_cid, con_handle);
871146fc0fbSMilanka Ringwald                                     avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status);
872326e3662SMilanka Ringwald                                     return;
873326e3662SMilanka Ringwald                                 case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES:
874326e3662SMilanka Ringwald                                     if (connection->incoming_declined == true) {
875326e3662SMilanka Ringwald                                         log_info("Connection was declined, and the outgoing failed");
876ff53b162SMilanka Ringwald                                         connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY;
877326e3662SMilanka Ringwald                                         connection->incoming_declined = false;
878ff53b162SMilanka Ringwald                                         avdtp_retry_timer_start(connection);
879326e3662SMilanka Ringwald                                         return;
880326e3662SMilanka Ringwald                                     }
881326e3662SMilanka Ringwald                                     break;
882326e3662SMilanka Ringwald                                 default:
883326e3662SMilanka Ringwald                                     log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status);
884326e3662SMilanka Ringwald                                     break;
885326e3662SMilanka Ringwald                             }
886146fc0fbSMilanka Ringwald                             avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status);
887f82b60efSMilanka Ringwald                             avdtp_finalize_connection(connection);
888a0b8a58cSMilanka Ringwald                             break;
889747ec646SMilanka Ringwald 
890a5114819SMilanka Ringwald                         case AVDTP_SIGNALING_CONNECTION_OPENED:
89119a000d1SMilanka Ringwald                             stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid);
892747ec646SMilanka Ringwald                             if (!stream_endpoint){
8935bd73fa2SMatthias Ringwald                                 log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid);
894747ec646SMilanka Ringwald                                 return;
895747ec646SMilanka Ringwald                             }
896326e3662SMilanka Ringwald                             if (status != ERROR_CODE_SUCCESS){
897355ac553SMilanka Ringwald                                 log_info("AVDTP_STREAM_ENDPOINT_OPENED failed with status %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", status, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
898a466d508SMilanka Ringwald                                 stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
899f751daa3SMatthias Ringwald                                 avdtp_streaming_emit_connection_established(stream_endpoint, status);
900a466d508SMilanka Ringwald                                 break;
901a466d508SMilanka Ringwald                             }
902a5114819SMilanka Ringwald                             switch (stream_endpoint->state){
903a5114819SMilanka Ringwald                                 case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED:
904a466d508SMilanka Ringwald                                     stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
905a466d508SMilanka Ringwald                                     stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet);
906a466d508SMilanka Ringwald                                     stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet);
907d1207cd8SMilanka Ringwald 
908355ac553SMilanka Ringwald                                     log_info("AVDTP_STREAM_ENDPOINT_OPENED, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
909f751daa3SMatthias Ringwald                                     avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS);
910a5114819SMilanka Ringwald                                     break;
911a5114819SMilanka Ringwald                                 default:
912a5114819SMilanka Ringwald                                     log_info("AVDTP_STREAM_ENDPOINT_OPENED failed - stream endpoint in wrong state %d, avdtp cid 0x%02x, l2cap_media_cid 0x%02x, local seid %d, remote seid %d", stream_endpoint->state, connection->avdtp_cid, stream_endpoint->l2cap_media_cid, avdtp_local_seid(stream_endpoint), avdtp_remote_seid(stream_endpoint));
91323edb87eSMilanka Ringwald                                     avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_COMMAND_DISALLOWED);
914a5114819SMilanka Ringwald                                     break;
915a5114819SMilanka Ringwald                             }
916a5114819SMilanka Ringwald                             break;
917a5114819SMilanka Ringwald 
918a5114819SMilanka Ringwald                         default:
919326e3662SMilanka Ringwald                             log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state);
920a5114819SMilanka Ringwald                             break;
921a5114819SMilanka Ringwald                     }
922747ec646SMilanka Ringwald                     break;
923747ec646SMilanka Ringwald 
924747ec646SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
925747ec646SMilanka Ringwald                     local_cid = l2cap_event_channel_closed_get_local_cid(packet);
9266f98b084SMilanka Ringwald                     stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid);
9275ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid);
92836da8747SMilanka Ringwald 
929f01aeca4SMilanka Ringwald                     log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint);
930f01aeca4SMilanka Ringwald 
931a466d508SMilanka Ringwald                     if (stream_endpoint){
932a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_media_cid == local_cid){
933a466d508SMilanka Ringwald                             connection = stream_endpoint->connection;
934596b7fdcSMilanka Ringwald                             if (connection) {
935f751daa3SMatthias Ringwald                                 avdtp_streaming_emit_connection_released(stream_endpoint,
936f751daa3SMatthias Ringwald                                                                          connection->avdtp_cid,
937f751daa3SMatthias Ringwald                                                                          avdtp_local_seid(stream_endpoint));
938596b7fdcSMilanka Ringwald                             }
939485c0a4cSMilanka Ringwald                             avdtp_reset_stream_endpoint(stream_endpoint);
9407f162947SMilanka Ringwald                             connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE;
941a466d508SMilanka Ringwald                             break;
942a466d508SMilanka Ringwald                         }
943a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_recovery_cid == local_cid){
944355ac553SMilanka Ringwald                             log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid);
945a466d508SMilanka Ringwald                             stream_endpoint->l2cap_recovery_cid = 0;
946a466d508SMilanka Ringwald                             break;
947a466d508SMilanka Ringwald                         }
948a466d508SMilanka Ringwald 
949a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_reporting_cid == local_cid){
950355ac553SMilanka Ringwald                             log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid);
951a466d508SMilanka Ringwald                             stream_endpoint->l2cap_reporting_cid = 0;
952a466d508SMilanka Ringwald                             break;
953a466d508SMilanka Ringwald                         }
954a466d508SMilanka Ringwald                     }
955596b7fdcSMilanka Ringwald 
956596b7fdcSMilanka Ringwald                     if (connection){
957596b7fdcSMilanka Ringwald                         btstack_linked_list_iterator_t it;
958d8e15394SMilanka Ringwald                         btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
959596b7fdcSMilanka Ringwald                         while (btstack_linked_list_iterator_has_next(&it)){
960f01aeca4SMilanka Ringwald                             stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
961f01aeca4SMilanka Ringwald                             if (stream_endpoint->connection == connection){
962f01aeca4SMilanka Ringwald                                 avdtp_reset_stream_endpoint(stream_endpoint);
963596b7fdcSMilanka Ringwald                             }
964596b7fdcSMilanka Ringwald                         }
965c69f4ba5SMatthias Ringwald                         avdtp_signaling_emit_connection_released(connection->avdtp_cid);
9665ace758fSMilanka Ringwald                         avdtp_finalize_connection(connection);
967596b7fdcSMilanka Ringwald                         break;
968596b7fdcSMilanka Ringwald                     }
969747ec646SMilanka Ringwald                     break;
970747ec646SMilanka Ringwald 
971747ec646SMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
972c6bc5965SMilanka Ringwald                     log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel);
973d80ccd43SMatthias Ringwald 					avdtp_handle_can_send_now(channel);
974747ec646SMilanka Ringwald                     break;
975747ec646SMilanka Ringwald                 default:
976355ac553SMilanka Ringwald                     log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet));
977747ec646SMilanka Ringwald                     break;
978747ec646SMilanka Ringwald             }
979747ec646SMilanka Ringwald             break;
980747ec646SMilanka Ringwald 
981747ec646SMilanka Ringwald         default:
982747ec646SMilanka Ringwald             // other packet type
983747ec646SMilanka Ringwald             break;
984747ec646SMilanka Ringwald     }
985747ec646SMilanka Ringwald }
986747ec646SMilanka Ringwald 
987b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){
9885ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
98923edb87eSMilanka Ringwald     if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
990b401ff59SMilanka Ringwald 
991a466d508SMilanka Ringwald     if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS;
992747ec646SMilanka Ringwald 
993f01aeca4SMilanka Ringwald     btstack_linked_list_iterator_t it;
994f01aeca4SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
995f01aeca4SMilanka Ringwald 
996f01aeca4SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
997f01aeca4SMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
998f01aeca4SMilanka Ringwald         if (stream_endpoint->connection != connection) continue;
999f01aeca4SMilanka Ringwald 
1000f01aeca4SMilanka Ringwald         switch (stream_endpoint->state){
1001f01aeca4SMilanka Ringwald             case AVDTP_STREAM_ENDPOINT_OPENED:
1002f01aeca4SMilanka Ringwald             case AVDTP_STREAM_ENDPOINT_STREAMING:
1003f01aeca4SMilanka Ringwald                 stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED;
1004f01aeca4SMilanka Ringwald                 l2cap_disconnect(stream_endpoint->l2cap_media_cid, 0);
1005f01aeca4SMilanka Ringwald                 break;
1006f01aeca4SMilanka Ringwald             default:
1007f01aeca4SMilanka Ringwald                 break;
1008f01aeca4SMilanka Ringwald         }
1009f01aeca4SMilanka Ringwald     }
1010f01aeca4SMilanka Ringwald 
1011f01aeca4SMilanka Ringwald     connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED;
1012f01aeca4SMilanka Ringwald     l2cap_disconnect(connection->l2cap_signaling_cid, 0);
10134ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1014747ec646SMilanka Ringwald }
1015747ec646SMilanka Ringwald 
1016297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){
10175ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1018747ec646SMilanka Ringwald     if (!connection){
10198587e32cSMilanka Ringwald         log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid);
102023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1021747ec646SMilanka Ringwald     }
1022747ec646SMilanka Ringwald 
1023747ec646SMilanka Ringwald     if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
10248587e32cSMilanka Ringwald         log_error("avdtp_media_connect: wrong connection state %d", connection->state);
102523edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1026747ec646SMilanka Ringwald     }
1027747ec646SMilanka Ringwald 
10283338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
1029747ec646SMilanka Ringwald     if (!stream_endpoint) {
10306b0ee1d0SMilanka Ringwald         log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid);
103123edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1032747ec646SMilanka Ringwald     }
1033747ec646SMilanka Ringwald 
1034485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid != remote_seid){
1035485c0a4cSMilanka Ringwald         log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid);
103623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1037485c0a4cSMilanka Ringwald     }
1038485c0a4cSMilanka Ringwald 
103923edb87eSMilanka Ringwald     if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return ERROR_CODE_COMMAND_DISALLOWED;
1040747ec646SMilanka Ringwald 
1041b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
104296dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
10435bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1044747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM;
1045747ec646SMilanka Ringwald     stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM;
1046d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
10474ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1048747ec646SMilanka Ringwald }
1049747ec646SMilanka Ringwald 
1050297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){
10515ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
105246e6b063SMilanka Ringwald     if (!connection){
10534ccacc40SMilanka Ringwald         log_error("avdtp_start_stream: no connection for signaling cid 0x%02x found", avdtp_cid);
105423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
105546e6b063SMilanka Ringwald     }
10565cfe7f4cSMilanka Ringwald 
10573338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
10584ccacc40SMilanka Ringwald     if (!stream_endpoint) {
10594ccacc40SMilanka Ringwald         log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid);
106023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
10614ccacc40SMilanka Ringwald     }
10624ccacc40SMilanka Ringwald 
10634ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
10644ccacc40SMilanka Ringwald         log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid);
106523edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
10664ccacc40SMilanka Ringwald     }
10674ccacc40SMilanka Ringwald 
1068485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint)){
1069485c0a4cSMilanka Ringwald         log_error("avdtp_media_connect: no remote sep registered with the stream endpoint");
107023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
10714ccacc40SMilanka Ringwald     }
10724ccacc40SMilanka Ringwald 
1073440d8d82SMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){
1074440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1075440d8d82SMilanka Ringwald     }
1076440d8d82SMilanka Ringwald 
107760ec20d0SMilanka Ringwald     stream_endpoint->start_stream = 1;
10785bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
107996dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1080d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
10814ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1082747ec646SMilanka Ringwald }
1083747ec646SMilanka Ringwald 
1084297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){
10855ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1086747ec646SMilanka Ringwald     if (!connection){
10874ccacc40SMilanka Ringwald         log_error("avdtp_stop_stream: no connection for signaling cid 0x%02x found", avdtp_cid);
108823edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1089747ec646SMilanka Ringwald     }
10904ccacc40SMilanka Ringwald 
10913338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
10924ccacc40SMilanka Ringwald     if (!stream_endpoint) {
10934ccacc40SMilanka Ringwald         log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid);
109423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
10954ccacc40SMilanka Ringwald     }
10964ccacc40SMilanka Ringwald 
10974ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
10984ccacc40SMilanka Ringwald         log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid);
109923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11004ccacc40SMilanka Ringwald     }
1101485c0a4cSMilanka Ringwald 
1102fa4419dbSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->close_stream){
1103440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1104485c0a4cSMilanka Ringwald     }
11054ccacc40SMilanka Ringwald 
1106fa4419dbSMilanka Ringwald     stream_endpoint->close_stream = 1;
11075bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
110896dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1109d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
11104ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1111747ec646SMilanka Ringwald }
1112747ec646SMilanka Ringwald 
1113297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){
11145ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
111560ec20d0SMilanka Ringwald     if (!connection){
11164ccacc40SMilanka Ringwald         log_error("avdtp_abort_stream: no connection for signaling cid 0x%02x found", avdtp_cid);
111723edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1118747ec646SMilanka Ringwald     }
11194ccacc40SMilanka Ringwald 
11203338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
11214ccacc40SMilanka Ringwald     if (!stream_endpoint) {
11224ccacc40SMilanka Ringwald         log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid);
112323edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11244ccacc40SMilanka Ringwald     }
11254ccacc40SMilanka Ringwald 
11264ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
11274ccacc40SMilanka Ringwald         log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid);
112823edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11294ccacc40SMilanka Ringwald     }
1130485c0a4cSMilanka Ringwald 
1131485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){
1132440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1133485c0a4cSMilanka Ringwald     }
11344ccacc40SMilanka Ringwald 
113560ec20d0SMilanka Ringwald     stream_endpoint->abort_stream = 1;
11365bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
113796dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1138d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
11394ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1140747ec646SMilanka Ringwald }
1141747ec646SMilanka Ringwald 
1142297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){
11435ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1144747ec646SMilanka Ringwald     if (!connection){
11454ccacc40SMilanka Ringwald         log_error("avdtp_suspend_stream: no connection for signaling cid 0x%02x found", avdtp_cid);
114623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
114760ec20d0SMilanka Ringwald     }
11483338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
11494ccacc40SMilanka Ringwald     if (!stream_endpoint) {
11504ccacc40SMilanka Ringwald         log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid);
115123edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11524ccacc40SMilanka Ringwald     }
11534ccacc40SMilanka Ringwald 
11544ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
11554ccacc40SMilanka Ringwald         log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid);
115623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11574ccacc40SMilanka Ringwald     }
1158485c0a4cSMilanka Ringwald 
1159485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){
1160440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1161485c0a4cSMilanka Ringwald     }
11624ccacc40SMilanka Ringwald 
116360ec20d0SMilanka Ringwald     stream_endpoint->suspend_stream = 1;
11645bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
116596dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1166d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
11674ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1168747ec646SMilanka Ringwald }
1169747ec646SMilanka Ringwald 
11705ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){
11715ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1172747ec646SMilanka Ringwald     if (!connection){
11738587e32cSMilanka Ringwald         log_error("avdtp_discover_stream_endpoints: no connection for signaling cid 0x%02x found", avdtp_cid);
117423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11759974aee0SMilanka Ringwald     }
11760e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1177c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
117823edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1179747ec646SMilanka Ringwald     }
1180ec3d71e3SMilanka Ringwald 
1181b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1182747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS;
1183d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1184747ec646SMilanka Ringwald }
1185747ec646SMilanka Ringwald 
1186747ec646SMilanka Ringwald 
11875ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){
11885ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1189747ec646SMilanka Ringwald     if (!connection){
11909900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
119123edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1192747ec646SMilanka Ringwald     }
11930e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1194c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
119523edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
11969974aee0SMilanka Ringwald     }
11979974aee0SMilanka Ringwald 
1198b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1199747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
120096dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1201d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1202747ec646SMilanka Ringwald }
1203747ec646SMilanka Ringwald 
1204747ec646SMilanka Ringwald 
12055ace758fSMilanka Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){
12065ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1207747ec646SMilanka Ringwald     if (!connection){
12089900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
120923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1210747ec646SMilanka Ringwald     }
12110e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1212c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
121323edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12149974aee0SMilanka Ringwald     }
12159974aee0SMilanka Ringwald 
1216b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
121796dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1218cc61e7e9SMilanka Ringwald 
1219cc61e7e9SMilanka Ringwald     if (connection->avdtp_version == 0){
1220cc61e7e9SMilanka Ringwald         connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES;
1221cc61e7e9SMilanka Ringwald         avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query;
1222cc61e7e9SMilanka Ringwald         // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
1223cc61e7e9SMilanka Ringwald         (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
1224cc61e7e9SMilanka Ringwald         return ERROR_CODE_SUCCESS;
1225cc61e7e9SMilanka Ringwald     } else {
1226cc61e7e9SMilanka Ringwald         // AVDTP version lower then 1.3 supports only get capabilities command
1227cc61e7e9SMilanka Ringwald         if (connection->avdtp_version < 0x103){
1228cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
1229cc61e7e9SMilanka Ringwald         } else {
1230cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES;
1231cc61e7e9SMilanka Ringwald         }
1232d80ccd43SMatthias Ringwald         return avdtp_request_can_send_now_initiator(connection);
1233747ec646SMilanka Ringwald     }
1234cc61e7e9SMilanka Ringwald }
1235747ec646SMilanka Ringwald 
12365ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){
12375ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1238747ec646SMilanka Ringwald     if (!connection){
12399900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
124023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1241747ec646SMilanka Ringwald     }
12420e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1243c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
124423edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12459974aee0SMilanka Ringwald     }
12469974aee0SMilanka Ringwald 
1247b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1248747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION;
124996dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1250d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1251747ec646SMilanka Ringwald }
1252747ec646SMilanka Ringwald 
1253cec76c5bSMilanka Ringwald uint8_t avdtp_set_configuration(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
12545ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1255747ec646SMilanka Ringwald     if (!connection){
12569900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
125723edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1258747ec646SMilanka Ringwald     }
12590e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1260c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
1261485c0a4cSMilanka Ringwald         log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state);
126223edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12639974aee0SMilanka Ringwald     }
1264a3ce0109SMatthias Ringwald     if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){
1265a3ce0109SMatthias Ringwald         log_info("configuration already started, config state %u", connection->configuration_state);
126623edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1267a3ce0109SMatthias Ringwald     }
1268747ec646SMilanka Ringwald 
1269d8e15394SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
1270747ec646SMilanka Ringwald     if (!stream_endpoint) {
12719900b7faSMilanka Ringwald         log_error("No initiator stream endpoint for seid %d", local_seid);
127223edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1273747ec646SMilanka Ringwald     }
1274417b4996SMilanka Ringwald     if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){
1275485c0a4cSMilanka Ringwald         log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state);
127623edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1277417b4996SMilanka Ringwald     }
1278a3ce0109SMatthias Ringwald 
1279bdbc3ef6SMilanka Ringwald     connection->active_stream_endpoint = (void*) stream_endpoint;
1280a3ce0109SMatthias Ringwald     connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED;
1281747ec646SMilanka Ringwald 
1282b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
128396dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
12845bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1285f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration_bitmap = configured_services_bitmap;
1286f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration = configuration;
1287747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION;
1288ffa6c160SMilanka Ringwald 
128944e638f3SMatthias Ringwald 	log_debug("SE %p, initiator_config_state: 0x%02x", stream_endpoint, stream_endpoint->initiator_config_state);
12903a69f723SMatthias Ringwald 
1291d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1292747ec646SMilanka Ringwald }
1293747ec646SMilanka Ringwald 
1294cec76c5bSMilanka Ringwald uint8_t avdtp_reconfigure(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid, uint16_t configured_services_bitmap, avdtp_capabilities_t configuration){
12955ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1296747ec646SMilanka Ringwald     if (!connection){
12979900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
129823edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1299747ec646SMilanka Ringwald     }
1300747ec646SMilanka Ringwald     //TODO: if opened only app capabilities, enable reconfigure for not opened
13010e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1302c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
130323edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
13049974aee0SMilanka Ringwald     }
13059e42cfccSMilanka Ringwald 
1306d8e15394SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
130778d08d09SMilanka Ringwald     if (!stream_endpoint) {
13084ccacc40SMilanka Ringwald         log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid);
130923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
131078d08d09SMilanka Ringwald     }
131178d08d09SMilanka Ringwald 
1312485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint)){
13138587e32cSMilanka Ringwald         log_error("avdtp_reconfigure: no associated remote sep");
131423edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
131578d08d09SMilanka Ringwald     }
1316485c0a4cSMilanka Ringwald 
1317b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
131896dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
13195bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1320f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration_bitmap = configured_services_bitmap;
1321f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration = configuration;
1322747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID;
1323d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1324747ec646SMilanka Ringwald }
1325747ec646SMilanka Ringwald 
13268e7044f9SMatthias Ringwald void    avdtp_set_preferred_sampling_frequeny(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){
13278e7044f9SMatthias Ringwald     stream_endpoint->preferred_sampling_frequency = sampling_frequency;
13288e7044f9SMatthias Ringwald }
13298e7044f9SMatthias Ringwald 
1330*79654d96SMilanka Ringwald void    avdtp_set_preferred_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t channel_mode){
1331*79654d96SMilanka Ringwald     stream_endpoint->preferred_channel_mode = channel_mode;
1332*79654d96SMilanka Ringwald }
1333*79654d96SMilanka Ringwald 
1334*79654d96SMilanka Ringwald 
133578d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){
133678d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
133778d08d09SMilanka Ringwald     uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap;
133878d08d09SMilanka Ringwald 
133978d08d09SMilanka Ringwald     uint8_t channel_mode = AVDTP_SBC_STEREO;
1340*79654d96SMilanka Ringwald     // use preferred channel mode if possible
1341*79654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_JOINT_STEREO){
1342*79654d96SMilanka Ringwald         return AVDTP_SBC_JOINT_STEREO;
1343*79654d96SMilanka Ringwald     }
1344*79654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_STEREO){
1345*79654d96SMilanka Ringwald         return AVDTP_SBC_STEREO;
1346*79654d96SMilanka Ringwald     }
1347*79654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_DUAL_CHANNEL){
1348*79654d96SMilanka Ringwald         return AVDTP_SBC_DUAL_CHANNEL;
1349*79654d96SMilanka Ringwald     }
1350*79654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_MONO){
1351*79654d96SMilanka Ringwald         return AVDTP_SBC_MONO;
1352*79654d96SMilanka Ringwald     }
1353*79654d96SMilanka Ringwald 
1354*79654d96SMilanka Ringwald 
135578d08d09SMilanka Ringwald     if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){
135678d08d09SMilanka Ringwald         channel_mode = AVDTP_SBC_JOINT_STEREO;
135778d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){
135878d08d09SMilanka Ringwald         channel_mode = AVDTP_SBC_STEREO;
135978d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){
136078d08d09SMilanka Ringwald         channel_mode = AVDTP_SBC_DUAL_CHANNEL;
136178d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_MONO){
136278d08d09SMilanka Ringwald         channel_mode = AVDTP_SBC_MONO;
136378d08d09SMilanka Ringwald     }
136478d08d09SMilanka Ringwald     return channel_mode;
136578d08d09SMilanka Ringwald }
136678d08d09SMilanka Ringwald 
136778d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){
136878d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
136978d08d09SMilanka Ringwald     uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap;
137078d08d09SMilanka Ringwald 
137178d08d09SMilanka Ringwald     uint8_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS;
137278d08d09SMilanka Ringwald     if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){
137378d08d09SMilanka Ringwald         allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS;
137478d08d09SMilanka Ringwald     } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){
137578d08d09SMilanka Ringwald         allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR;
137678d08d09SMilanka Ringwald     }
137778d08d09SMilanka Ringwald     return allocation_method;
137878d08d09SMilanka Ringwald }
137978d08d09SMilanka Ringwald 
1380bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){
1381bd1ecb8aSMilanka Ringwald     if (!stream_endpoint) return 0;
1382bd1ecb8aSMilanka Ringwald     return stream_endpoint->sep.seid;
1383bd1ecb8aSMilanka Ringwald }
138478d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){
138567ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
138678d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
138778d08d09SMilanka Ringwald     uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap;
138878d08d09SMilanka Ringwald 
138978d08d09SMilanka Ringwald     uint8_t subbands = AVDTP_SBC_SUBBANDS_8;
139078d08d09SMilanka Ringwald     if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){
139178d08d09SMilanka Ringwald         subbands = AVDTP_SBC_SUBBANDS_8;
139278d08d09SMilanka Ringwald     } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){
139378d08d09SMilanka Ringwald         subbands = AVDTP_SBC_SUBBANDS_4;
139478d08d09SMilanka Ringwald     }
139578d08d09SMilanka Ringwald     return subbands;
139678d08d09SMilanka Ringwald }
139778d08d09SMilanka Ringwald 
139878d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){
139967ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
140078d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
140178d08d09SMilanka Ringwald     uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap;
140278d08d09SMilanka Ringwald 
140378d08d09SMilanka Ringwald     uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16;
140478d08d09SMilanka Ringwald     if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){
140578d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_16;
140678d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){
140778d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_12;
140878d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){
140978d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_8;
141078d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){
141178d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_4;
141278d08d09SMilanka Ringwald     }
141378d08d09SMilanka Ringwald     return block_length;
141478d08d09SMilanka Ringwald }
141578d08d09SMilanka Ringwald 
141678d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){
141767ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
141878d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
14198e7044f9SMatthias Ringwald     uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap;
142078d08d09SMilanka Ringwald 
14218e7044f9SMatthias Ringwald     // use preferred sampling frequency if possible
14228e7044f9SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){
14236ed344c3SMatthias Ringwald         return AVDTP_SBC_48000;
14248e7044f9SMatthias Ringwald     }
14256ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){
14266ed344c3SMatthias Ringwald         return AVDTP_SBC_44100;
14276ed344c3SMatthias Ringwald     }
14286ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){
14296ed344c3SMatthias Ringwald         return AVDTP_SBC_32000;
14306ed344c3SMatthias Ringwald     }
14316ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){
14326ed344c3SMatthias Ringwald         return AVDTP_SBC_16000;
14336ed344c3SMatthias Ringwald     }
14346ed344c3SMatthias Ringwald 
14358e7044f9SMatthias Ringwald     // otherwise, use highest available
14366ed344c3SMatthias Ringwald     if (supported_sampling_frequency_bitmap & AVDTP_SBC_48000){
14376ed344c3SMatthias Ringwald         return AVDTP_SBC_48000;
143878d08d09SMilanka Ringwald     }
14396ed344c3SMatthias Ringwald     if (supported_sampling_frequency_bitmap & AVDTP_SBC_44100){
14406ed344c3SMatthias Ringwald         return AVDTP_SBC_44100;
14416ed344c3SMatthias Ringwald     }
14426ed344c3SMatthias Ringwald     if (supported_sampling_frequency_bitmap & AVDTP_SBC_32000){
14436ed344c3SMatthias Ringwald         return AVDTP_SBC_32000;
14446ed344c3SMatthias Ringwald     }
14456ed344c3SMatthias Ringwald     if (supported_sampling_frequency_bitmap & AVDTP_SBC_16000){
14466ed344c3SMatthias Ringwald         return AVDTP_SBC_16000;
14476ed344c3SMatthias Ringwald     }
14486ed344c3SMatthias Ringwald     return AVDTP_SBC_44100; // some default
144978d08d09SMilanka Ringwald }
145078d08d09SMilanka Ringwald 
145178d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){
145267ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
145378d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
145478d08d09SMilanka Ringwald     return btstack_min(media_codec[3], remote_max_bitpool_value);
145578d08d09SMilanka Ringwald }
145678d08d09SMilanka Ringwald 
145778d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){
145867ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
145978d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
146078d08d09SMilanka Ringwald     return btstack_max(media_codec[2], remote_min_bitpool_value);
1461747ec646SMilanka Ringwald }
1462485c0a4cSMilanka Ringwald 
1463485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){
1464485c0a4cSMilanka Ringwald     if (!stream_endpoint) return 0;
1465485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid == 0) return 0;
1466485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid > 0x3E) return 0;
1467485c0a4cSMilanka Ringwald     return 1;
1468485c0a4cSMilanka Ringwald }
14698322fb3aSMatthias Ringwald 
14708322fb3aSMatthias Ringwald void avdtp_init(void){
14718322fb3aSMatthias Ringwald     static bool l2cap_registered = false;
14728322fb3aSMatthias Ringwald     if (!l2cap_registered){
14738322fb3aSMatthias Ringwald         l2cap_registered = true;
14748322fb3aSMatthias Ringwald         l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, 0xffff, gap_get_security_level());
14758322fb3aSMatthias Ringwald     }
14768322fb3aSMatthias Ringwald }
1477