xref: /btstack/src/classic/avdtp.c (revision c70720c67056dadfbbef227c89dcb22a37fba036)
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"
50*c70720c6SMatthias Ringwald #include "classic/avdtp_util.h"
514cb889a5SMilanka Ringwald #include "classic/avdtp_acceptor.h"
524cb889a5SMilanka Ringwald #include "classic/avdtp_initiator.h"
5384e3541eSMilanka Ringwald #include "classic/avdtp_util.h"
5484e3541eSMilanka Ringwald #include "classic/sdp_client.h"
5584e3541eSMilanka Ringwald #include "classic/sdp_util.h"
56747ec646SMilanka Ringwald 
57d8e15394SMilanka Ringwald btstack_linked_list_t stream_endpoints;
58d8e15394SMilanka Ringwald 
5957fb24ffSMatthias Ringwald static bool l2cap_registered;
6057fb24ffSMatthias Ringwald 
61a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_source_callback;
62a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_sink_callback;
635797104aSMilanka Ringwald static btstack_context_callback_registration_t avdtp_handle_sdp_client_query_request;
64*c70720c6SMatthias Ringwald static uint8_t (*avdtp_media_config_validator)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size);
65a1fb0563SMilanka Ringwald 
66ca2c9990SMilanka Ringwald static uint16_t sdp_query_context_avdtp_cid = 0;
67f0c39502SMilanka Ringwald 
68560b3f31SMilanka Ringwald static uint16_t stream_endpoints_id_counter = 0;
69560b3f31SMilanka Ringwald 
705ace758fSMilanka Ringwald static btstack_linked_list_t connections;
71b1935866SMilanka Ringwald static uint16_t transaction_id_counter = 0;
725ace758fSMilanka Ringwald 
7357fb24ffSMatthias Ringwald static int record_id;
74fa1ee4d3SMilanka Ringwald static uint8_t attribute_value[45];
75692c0605SMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value);
76747ec646SMilanka Ringwald 
77951d2774SMatthias Ringwald static void (*avdtp_sink_handle_media_data)(uint8_t local_seid, uint8_t *packet, uint16_t size);
78951d2774SMatthias Ringwald 
79af121d54SMilanka Ringwald static uint16_t avdtp_cid_counter = 0;
80747ec646SMilanka Ringwald 
81692c0605SMilanka Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
82692c0605SMilanka Ringwald 
83f751daa3SMatthias Ringwald btstack_packet_handler_t
84f751daa3SMatthias Ringwald avdtp_packet_handler_for_stream_endpoint(const avdtp_stream_endpoint_t *stream_endpoint) {
85f751daa3SMatthias Ringwald     return (stream_endpoint->sep.type == AVDTP_SOURCE) ? avdtp_source_callback : avdtp_sink_callback;
86f751daa3SMatthias Ringwald }
87f751daa3SMatthias Ringwald 
88c69f4ba5SMatthias Ringwald void avdtp_emit_sink_and_source(uint8_t * packet, uint16_t size){
89c69f4ba5SMatthias Ringwald     if (avdtp_source_callback != NULL){
90c69f4ba5SMatthias Ringwald         (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size);
91c69f4ba5SMatthias Ringwald     }
92c69f4ba5SMatthias Ringwald     if (avdtp_sink_callback != NULL){
93c69f4ba5SMatthias Ringwald         (*avdtp_sink_callback)(HCI_EVENT_PACKET, 0, packet, size);
94c69f4ba5SMatthias Ringwald     }
95c69f4ba5SMatthias Ringwald }
96c69f4ba5SMatthias Ringwald 
974b7d40bbSMatthias Ringwald void avdtp_emit_source(uint8_t * packet, uint16_t size){
984b7d40bbSMatthias Ringwald     if (avdtp_source_callback != NULL){
994b7d40bbSMatthias Ringwald         (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size);
100f751daa3SMatthias Ringwald     }
101f08f4934SMatthias Ringwald }
102f08f4934SMatthias Ringwald 
103f751daa3SMatthias Ringwald btstack_linked_list_t * avdtp_get_stream_endpoints(void){
104f751daa3SMatthias Ringwald     return &stream_endpoints;
105f751daa3SMatthias Ringwald }
10636da8747SMilanka Ringwald 
10762c4ec82SMilanka Ringwald btstack_linked_list_t * avdtp_get_connections(void){
10862c4ec82SMilanka Ringwald     return &connections;
10962c4ec82SMilanka Ringwald }
11062c4ec82SMilanka Ringwald 
1113ec98973SMatthias Ringwald avdtp_connection_t * avdtp_get_connection_for_bd_addr(bd_addr_t addr){
1125ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
1135ace758fSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
1145ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1155ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1165ace758fSMilanka Ringwald         if (memcmp(addr, connection->remote_addr, 6) != 0) continue;
1175ace758fSMilanka Ringwald         return connection;
118b0d75c91SMilanka Ringwald     }
1195ace758fSMilanka Ringwald     return NULL;
120b0d75c91SMilanka Ringwald }
121b0d75c91SMilanka Ringwald 
1225ace758fSMilanka Ringwald  avdtp_connection_t * avdtp_get_connection_for_avdtp_cid(uint16_t avdtp_cid){
1235ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
1245ace758fSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
1255ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1265ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1275ace758fSMilanka Ringwald         if (connection->avdtp_cid != avdtp_cid) continue;
1285ace758fSMilanka Ringwald         return connection;
1295ace758fSMilanka Ringwald     }
1305ace758fSMilanka Ringwald     return NULL;
1315ace758fSMilanka Ringwald }
1325ace758fSMilanka Ringwald 
1335ace758fSMilanka Ringwald 
1343338afc0SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_seid(uint16_t seid){
1355ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
136d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1375ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1385ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1395ace758fSMilanka Ringwald         if (stream_endpoint->sep.seid == seid){
1405ace758fSMilanka Ringwald             return stream_endpoint;
1415ace758fSMilanka Ringwald         }
1425ace758fSMilanka Ringwald     }
1435ace758fSMilanka Ringwald     return NULL;
1445ace758fSMilanka Ringwald }
1455ace758fSMilanka Ringwald 
146f24f7543SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_source_stream_endpoint_for_media_codec(avdtp_media_codec_type_t codec_type){
147f24f7543SMatthias Ringwald     btstack_linked_list_iterator_t it;
148f24f7543SMatthias Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
149f24f7543SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
150f24f7543SMatthias Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
151f24f7543SMatthias Ringwald         if (stream_endpoint->sep.type != AVDTP_SOURCE) continue;
15284cef9b8SMatthias Ringwald         if (stream_endpoint->sep.media_type != AVDTP_AUDIO) continue;
153f24f7543SMatthias Ringwald         if (stream_endpoint->sep.capabilities.media_codec.media_codec_type != codec_type) continue;
1547982528cSMatthias Ringwald         if (stream_endpoint->sep.in_use) continue;
155f24f7543SMatthias Ringwald         return stream_endpoint;
156f24f7543SMatthias Ringwald     }
157f24f7543SMatthias Ringwald     return NULL;
158f24f7543SMatthias Ringwald }
159f24f7543SMatthias Ringwald 
16084cef9b8SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_source_stream_endpoint_for_media_codec_other(uint32_t vendor_id, uint16_t codec_id){
16184cef9b8SMatthias Ringwald     btstack_linked_list_iterator_t it;
16284cef9b8SMatthias Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
16384cef9b8SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
16484cef9b8SMatthias Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
16584cef9b8SMatthias Ringwald         if (stream_endpoint->sep.type != AVDTP_SOURCE) continue;
16684cef9b8SMatthias Ringwald         if (stream_endpoint->sep.media_type != AVDTP_AUDIO) continue;
1677982528cSMatthias Ringwald         if (stream_endpoint->sep.in_use) continue;
16884cef9b8SMatthias Ringwald         if (stream_endpoint->sep.capabilities.media_codec.media_codec_type != AVDTP_CODEC_NON_A2DP) continue;
16984cef9b8SMatthias Ringwald         if (stream_endpoint->sep.capabilities.media_codec.media_codec_information_len < 6) continue;
17084cef9b8SMatthias Ringwald         if (little_endian_read_32(stream_endpoint->sep.capabilities.media_codec.media_codec_information, 0) != vendor_id) continue;
171a9207bf9SBjoern Hartmann         if (little_endian_read_16(stream_endpoint->sep.capabilities.media_codec.media_codec_information, 4) != codec_id) continue;
17284cef9b8SMatthias Ringwald         return stream_endpoint;
17384cef9b8SMatthias Ringwald     }
17484cef9b8SMatthias Ringwald     return NULL;
17584cef9b8SMatthias Ringwald }
17684cef9b8SMatthias Ringwald 
177f24f7543SMatthias Ringwald 
1785ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid){
1795ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
1805ace758fSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
1815ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1825ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1835ace758fSMilanka Ringwald         if (connection->l2cap_signaling_cid != l2cap_cid) continue;
1845ace758fSMilanka Ringwald         return connection;
1855ace758fSMilanka Ringwald     }
1865ace758fSMilanka Ringwald     return NULL;
1875ace758fSMilanka Ringwald }
1885ace758fSMilanka Ringwald 
1896f98b084SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid){
1905ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
191d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1925ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1935ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1945ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_media_cid == l2cap_cid){
1955ace758fSMilanka Ringwald             return stream_endpoint;
1965ace758fSMilanka Ringwald         }
1975ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_reporting_cid == l2cap_cid){
1985ace758fSMilanka Ringwald             return stream_endpoint;
1995ace758fSMilanka Ringwald         }
2005ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_recovery_cid == l2cap_cid){
2015ace758fSMilanka Ringwald             return stream_endpoint;
2025ace758fSMilanka Ringwald         }
2035ace758fSMilanka Ringwald     }
2045ace758fSMilanka Ringwald     return NULL;
2055ace758fSMilanka Ringwald }
2065ace758fSMilanka Ringwald 
20719a000d1SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_signaling_cid(uint16_t l2cap_cid){
2085ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
209d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
2105ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2115ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
2125ace758fSMilanka Ringwald         if (stream_endpoint->connection){
2135ace758fSMilanka Ringwald             if (stream_endpoint->connection->l2cap_signaling_cid == l2cap_cid){
2145ace758fSMilanka Ringwald                 return stream_endpoint;
2155ace758fSMilanka Ringwald             }
2165ace758fSMilanka Ringwald         }
2175ace758fSMilanka Ringwald     }
2185ace758fSMilanka Ringwald     return NULL;
2195ace758fSMilanka Ringwald }
2205ace758fSMilanka Ringwald 
221b1935866SMilanka Ringwald uint16_t avdtp_get_next_transaction_label(void){
222b1935866SMilanka Ringwald     transaction_id_counter++;
223b1935866SMilanka Ringwald     if (transaction_id_counter == 16){
224b1935866SMilanka Ringwald         transaction_id_counter = 1;
2255ace758fSMilanka Ringwald     }
226b1935866SMilanka Ringwald     return transaction_id_counter;
2275ace758fSMilanka Ringwald }
2285ace758fSMilanka Ringwald 
2295ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_create_connection(bd_addr_t remote_addr, uint16_t cid){
23036da8747SMilanka Ringwald     avdtp_connection_t * connection = btstack_memory_avdtp_connection_get();
23136da8747SMilanka Ringwald     if (!connection){
23236da8747SMilanka Ringwald         log_error("Not enough memory to create connection");
23336da8747SMilanka Ringwald         return NULL;
23436da8747SMilanka Ringwald     }
23536da8747SMilanka Ringwald     connection->state = AVDTP_SIGNALING_CONNECTION_IDLE;
236b1935866SMilanka Ringwald     connection->initiator_transaction_label = avdtp_get_next_transaction_label();
23736da8747SMilanka Ringwald     connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE;
23862c4ec82SMilanka Ringwald     connection->a2dp_source_discover_seps = false;
23936da8747SMilanka Ringwald     connection->avdtp_cid = cid;
24036da8747SMilanka Ringwald     (void)memcpy(connection->remote_addr, remote_addr, 6);
24136da8747SMilanka Ringwald 
2425ace758fSMilanka Ringwald     btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection);
24336da8747SMilanka Ringwald     return connection;
24436da8747SMilanka Ringwald }
24536da8747SMilanka Ringwald 
24636da8747SMilanka Ringwald static uint16_t avdtp_get_next_cid(void){
247af121d54SMilanka Ringwald     if (avdtp_cid_counter == 0xffff) {
2484ccacc40SMilanka Ringwald         avdtp_cid_counter = 1;
249af121d54SMilanka Ringwald     } else {
250af121d54SMilanka Ringwald         avdtp_cid_counter++;
2514ccacc40SMilanka Ringwald     }
2524ccacc40SMilanka Ringwald     return avdtp_cid_counter;
2534ccacc40SMilanka Ringwald }
2544ccacc40SMilanka Ringwald 
255560b3f31SMilanka Ringwald static uint16_t avdtp_get_next_local_seid(void){
256560b3f31SMilanka Ringwald     if (stream_endpoints_id_counter == 0xffff) {
257560b3f31SMilanka Ringwald         stream_endpoints_id_counter = 1;
258af121d54SMilanka Ringwald     } else {
259560b3f31SMilanka Ringwald         stream_endpoints_id_counter++;
2604ccacc40SMilanka Ringwald     }
261560b3f31SMilanka Ringwald     return stream_endpoints_id_counter;
2624ccacc40SMilanka Ringwald }
2634ccacc40SMilanka Ringwald 
2645797104aSMilanka Ringwald static void avdtp_handle_start_sdp_client_query(void * context){
2655797104aSMilanka Ringwald     UNUSED(context);
266b1549ed3SMilanka Ringwald 
2675797104aSMilanka Ringwald     btstack_linked_list_iterator_t it;
2685797104aSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &connections);
2695797104aSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2705797104aSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
2715797104aSMilanka Ringwald 
2725797104aSMilanka Ringwald         switch (connection->state){
2735797104aSMilanka Ringwald             case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE:
2745797104aSMilanka Ringwald                 connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE;
2755797104aSMilanka Ringwald                 break;
2765797104aSMilanka Ringwald             case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK:
2775797104aSMilanka Ringwald                 connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE;
2785797104aSMilanka Ringwald                 break;
279cc61e7e9SMilanka Ringwald             case AVDTP_SIGNALING_CONNECTION_OPENED:
280cc61e7e9SMilanka Ringwald                 if (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES) continue;
281cc61e7e9SMilanka Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SDP_QUERY_COMPLETE_THEN_GET_ALL_CAPABILITIES;
282cc61e7e9SMilanka Ringwald                 break;
2835797104aSMilanka Ringwald             default:
2845797104aSMilanka Ringwald                 continue;
2855797104aSMilanka Ringwald         }
2865797104aSMilanka Ringwald         sdp_query_context_avdtp_cid = connection->avdtp_cid;
28757fb24ffSMatthias Ringwald         record_id = -1;
2885797104aSMilanka Ringwald         sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP);
2895797104aSMilanka Ringwald         return;
2905797104aSMilanka Ringwald     }
29184521ac1SMilanka Ringwald }
29284521ac1SMilanka Ringwald 
293a1fb0563SMilanka Ringwald uint8_t avdtp_connect(bd_addr_t remote, avdtp_role_t role, uint16_t * avdtp_cid){
2945ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_bd_addr(remote);
29584521ac1SMilanka Ringwald     if (connection){
29684521ac1SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
2974567cc17SMilanka Ringwald     }
29884521ac1SMilanka Ringwald 
29936da8747SMilanka Ringwald     uint16_t cid = avdtp_get_next_cid();
3002ad6b656SMilanka Ringwald     if (avdtp_cid != NULL) {
30184521ac1SMilanka Ringwald         *avdtp_cid = cid;
3022ad6b656SMilanka Ringwald     }
3032ad6b656SMilanka Ringwald 
3045ace758fSMilanka Ringwald     connection = avdtp_create_connection(remote, cid);
30536da8747SMilanka Ringwald     if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED;
30636da8747SMilanka Ringwald 
30784521ac1SMilanka Ringwald     connection->avdtp_cid = cid;
308b1549ed3SMilanka Ringwald 
3095797104aSMilanka Ringwald     connection->avdtp_l2cap_psm = 0;
3105797104aSMilanka Ringwald     connection->avdtp_version  = 0;
3115797104aSMilanka Ringwald     connection->sink_supported = false;
3125797104aSMilanka Ringwald     connection->source_supported = false;
3135797104aSMilanka Ringwald 
314b1549ed3SMilanka Ringwald     switch (role){
315149deddbSMilanka Ringwald         case AVDTP_ROLE_SOURCE:
3165797104aSMilanka Ringwald             connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK;
317149deddbSMilanka Ringwald             break;
318149deddbSMilanka Ringwald         case AVDTP_ROLE_SINK:
3195797104aSMilanka Ringwald             connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE;
320149deddbSMilanka Ringwald             break;
321149deddbSMilanka Ringwald         default:
3225797104aSMilanka Ringwald             btstack_assert(false);
323149deddbSMilanka Ringwald             return ERROR_CODE_COMMAND_DISALLOWED;
324149deddbSMilanka Ringwald     }
3255797104aSMilanka Ringwald 
3265797104aSMilanka Ringwald     avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query;
3275797104aSMilanka Ringwald     // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
3285797104aSMilanka Ringwald     (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
3295797104aSMilanka Ringwald     return ERROR_CODE_SUCCESS;
330692c0605SMilanka Ringwald }
331747ec646SMilanka Ringwald 
332a1fb0563SMilanka Ringwald 
333a1fb0563SMilanka Ringwald void avdtp_register_sink_packet_handler(btstack_packet_handler_t callback){
334a1fb0563SMilanka Ringwald     btstack_assert(callback != NULL);
335a1fb0563SMilanka Ringwald     avdtp_sink_callback = callback;
336a1fb0563SMilanka Ringwald }
337a1fb0563SMilanka Ringwald 
338a1fb0563SMilanka Ringwald void avdtp_register_source_packet_handler(btstack_packet_handler_t callback){
339a1fb0563SMilanka Ringwald     btstack_assert(callback != NULL);
340a1fb0563SMilanka Ringwald     avdtp_source_callback = callback;
341a1fb0563SMilanka Ringwald }
342a1fb0563SMilanka Ringwald 
343747ec646SMilanka Ringwald void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){
344747ec646SMilanka Ringwald     if (!stream_endpoint){
3459900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
346747ec646SMilanka Ringwald         return;
347747ec646SMilanka Ringwald     }
348747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1);
349747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
350747ec646SMilanka Ringwald }
351747ec646SMilanka Ringwald 
352747ec646SMilanka Ringwald void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){
353747ec646SMilanka Ringwald     if (!stream_endpoint){
3549900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
355747ec646SMilanka Ringwald         return;
356747ec646SMilanka Ringwald     }
357747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_REPORTING, 1);
358747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
359747ec646SMilanka Ringwald }
360747ec646SMilanka Ringwald 
361747ec646SMilanka Ringwald void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){
362747ec646SMilanka Ringwald     if (!stream_endpoint){
3639900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
364747ec646SMilanka Ringwald         return;
365747ec646SMilanka Ringwald     }
366747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_DELAY_REPORTING, 1);
367747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
368747ec646SMilanka Ringwald }
369747ec646SMilanka Ringwald 
370747ec646SMilanka Ringwald void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){
371747ec646SMilanka Ringwald     if (!stream_endpoint){
3729900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
373747ec646SMilanka Ringwald         return;
374747ec646SMilanka Ringwald     }
375747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_RECOVERY, 1);
376747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
377747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.recovery_type = 0x01; // 0x01 = RFC2733
378747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.maximum_recovery_window_size = maximum_recovery_window_size;
379747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.maximum_number_media_packets = maximum_number_media_packets;
380747ec646SMilanka Ringwald }
381747ec646SMilanka Ringwald 
382747ec646SMilanka 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){
383747ec646SMilanka Ringwald     if (!stream_endpoint){
3849900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
385747ec646SMilanka Ringwald         return;
386747ec646SMilanka Ringwald     }
387747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_CONTENT_PROTECTION, 1);
388747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
389747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.content_protection.cp_type = cp_type;
3906535961aSMatthias Ringwald     (void)memcpy(stream_endpoint->sep.capabilities.content_protection.cp_type_value,
3916535961aSMatthias Ringwald                  cp_type_value,
3926535961aSMatthias Ringwald                  btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN));
39367ae582dSMilanka Ringwald     stream_endpoint->sep.capabilities.content_protection.cp_type_value_len = btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN);
394747ec646SMilanka Ringwald }
395747ec646SMilanka Ringwald 
396747ec646SMilanka Ringwald void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery){
397747ec646SMilanka Ringwald     if (!stream_endpoint){
3989900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
399747ec646SMilanka Ringwald         return;
400747ec646SMilanka Ringwald     }
401747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_HEADER_COMPRESSION, 1);
402747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
403747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.back_ch = back_ch;
404747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.media = media;
405747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.recovery = recovery;
406747ec646SMilanka Ringwald }
407747ec646SMilanka Ringwald 
4083e6cf581SMatthias 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, const uint8_t *media_codec_info, uint16_t media_codec_info_len){
409747ec646SMilanka Ringwald     if (!stream_endpoint){
4109900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
411747ec646SMilanka Ringwald         return;
412747ec646SMilanka Ringwald     }
413747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1);
414747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
415747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_type = media_type;
416747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type;
4173e6cf581SMatthias Ringwald     // @todo should be stored in struct as const
4183e6cf581SMatthias Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_information = (uint8_t*) media_codec_info;
419747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_information_len = media_codec_info_len;
420747ec646SMilanka Ringwald }
421747ec646SMilanka Ringwald 
422747ec646SMilanka Ringwald void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation){
423747ec646SMilanka Ringwald     if (!stream_endpoint){
4249900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
425747ec646SMilanka Ringwald         return;
426747ec646SMilanka Ringwald     }
427747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MULTIPLEXING, 1);
428747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
429747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.multiplexing_mode.fragmentation = fragmentation;
430747ec646SMilanka Ringwald }
431747ec646SMilanka Ringwald 
432951d2774SMatthias Ringwald void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size)){
433951d2774SMatthias Ringwald     avdtp_sink_handle_media_data = callback;
434951d2774SMatthias Ringwald }
435747ec646SMilanka Ringwald 
436*c70720c6SMatthias Ringwald void avdtp_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size)){
4371ef2d533SMatthias Ringwald     avdtp_media_config_validator = callback;
4381ef2d533SMatthias Ringwald }
4391ef2d533SMatthias Ringwald 
440*c70720c6SMatthias Ringwald uint8_t avdtp_validate_media_configuration(const avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid,
441*c70720c6SMatthias Ringwald                                            uint8_t reconfigure, const adtvp_media_codec_capabilities_t *media_codec) {
4421ef2d533SMatthias Ringwald     if (avdtp_media_config_validator == NULL) {
4431ef2d533SMatthias Ringwald         return 0;
4441ef2d533SMatthias Ringwald     }
445*c70720c6SMatthias Ringwald     uint8_t event[AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN];
446*c70720c6SMatthias Ringwald     uint16_t size = avdtp_setup_media_codec_config_event(event, sizeof(event), stream_endpoint, avdtp_cid, reconfigure, media_codec);
447*c70720c6SMatthias Ringwald     return (*avdtp_media_config_validator)(stream_endpoint, event, size);
4481ef2d533SMatthias Ringwald }
4491ef2d533SMatthias Ringwald 
450d80ccd43SMatthias Ringwald /* START: tracking can send now requests per l2cap cid */
451d80ccd43SMatthias Ringwald static void avdtp_handle_can_send_now(uint16_t l2cap_cid) {
452d80ccd43SMatthias Ringwald 
453d80ccd43SMatthias Ringwald 	log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", l2cap_cid);
454d80ccd43SMatthias Ringwald 
455d80ccd43SMatthias Ringwald 	// get signaling connection for l2cap cid
456d80ccd43SMatthias Ringwald 	avdtp_connection_t * connection = avdtp_get_connection_for_l2cap_signaling_cid(l2cap_cid);
457d80ccd43SMatthias Ringwald 
458d80ccd43SMatthias Ringwald 	if (connection != NULL) {
459747ec646SMilanka Ringwald 		if (connection->wait_to_send_acceptor) {
460d80ccd43SMatthias Ringwald 			log_debug("call avdtp_acceptor_stream_config_subsm_run %p", connection);
461d80ccd43SMatthias Ringwald 			connection->wait_to_send_acceptor = false;
46277092f3eSMatthias Ringwald 			avdtp_acceptor_stream_config_subsm_run(connection);
463747ec646SMilanka Ringwald 		} else if (connection->wait_to_send_initiator) {
464d80ccd43SMatthias Ringwald 			log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling %p", connection);
465d80ccd43SMatthias Ringwald 			connection->wait_to_send_initiator = false;
466d80ccd43SMatthias Ringwald 			avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling(connection);
467d80ccd43SMatthias Ringwald 		}
468d80ccd43SMatthias Ringwald 		bool more_to_send = connection->wait_to_send_acceptor || connection->wait_to_send_initiator;
469d80ccd43SMatthias Ringwald 		if (more_to_send){
470d80ccd43SMatthias Ringwald 			l2cap_request_can_send_now_event(l2cap_cid);
471d80ccd43SMatthias Ringwald 		}
472d80ccd43SMatthias Ringwald 		return;
473747ec646SMilanka Ringwald 	}
474747ec646SMilanka Ringwald 
475d80ccd43SMatthias Ringwald 	// get stream endpoint connection for l2cap cid
476d80ccd43SMatthias Ringwald 	avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(l2cap_cid);
477d80ccd43SMatthias Ringwald 	if (stream_endpoint != NULL) {
478d80ccd43SMatthias Ringwald 		log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint %p", stream_endpoint);
479d80ccd43SMatthias Ringwald 		if (stream_endpoint->request_can_send_now) {
480d0676819SMatthias Ringwald 			stream_endpoint->request_can_send_now = false;
481d80ccd43SMatthias Ringwald 			avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint(stream_endpoint);
482d80ccd43SMatthias Ringwald 		}
483d0676819SMatthias Ringwald 		if (stream_endpoint->request_can_send_now){
484747ec646SMilanka Ringwald 			l2cap_request_can_send_now_event(l2cap_cid);
485747ec646SMilanka Ringwald 		}
486747ec646SMilanka Ringwald 	}
487d80ccd43SMatthias Ringwald }
488d80ccd43SMatthias Ringwald /* END: tracking can send now requests per l2cap cid */
489747ec646SMilanka Ringwald 
490747ec646SMilanka Ringwald 
491297feb5fSMilanka Ringwald avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){
492747ec646SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = btstack_memory_avdtp_stream_endpoint_get();
4934567cc17SMilanka Ringwald     if (!stream_endpoint){
4949900b7faSMilanka Ringwald         log_error("Not enough memory to create stream endpoint");
4954567cc17SMilanka Ringwald         return NULL;
4964567cc17SMilanka Ringwald     }
497560b3f31SMilanka Ringwald     stream_endpoint->sep.seid = avdtp_get_next_local_seid();
498747ec646SMilanka Ringwald     stream_endpoint->sep.media_type = media_type;
499747ec646SMilanka Ringwald     stream_endpoint->sep.type = sep_type;
500d8e15394SMilanka Ringwald     btstack_linked_list_add(avdtp_get_stream_endpoints(), (btstack_linked_item_t *) stream_endpoint);
501747ec646SMilanka Ringwald     return stream_endpoint;
502747ec646SMilanka Ringwald }
503747ec646SMilanka Ringwald 
50417ddf501SMatthias Ringwald void avdtp_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){
50517ddf501SMatthias Ringwald     btstack_linked_list_remove(avdtp_get_stream_endpoints(), (btstack_linked_item_t* ) stream_endpoint);
50617ddf501SMatthias Ringwald     btstack_memory_avdtp_stream_endpoint_free(stream_endpoint);
50717ddf501SMatthias Ringwald }
50817ddf501SMatthias Ringwald 
50977092f3eSMatthias Ringwald static void
51077092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t *connection, uint8_t *packet, uint16_t size) {
511c1c40ea1SMatthias Ringwald     if (size < 2) return;
512c1c40ea1SMatthias Ringwald 
513c1c40ea1SMatthias Ringwald     uint16_t offset;
514c1c40ea1SMatthias Ringwald     avdtp_message_type_t message_type = avdtp_get_signaling_packet_type(packet);
515c1c40ea1SMatthias Ringwald     switch (message_type){
516747ec646SMilanka Ringwald         case AVDTP_CMD_MSG:
51750453b92SMatthias Ringwald             offset = avdtp_read_signaling_header(&connection->acceptor_signaling_packet, packet, size);
51877092f3eSMatthias Ringwald             avdtp_acceptor_stream_config_subsm(connection, packet, size, offset);
519747ec646SMilanka Ringwald             break;
520747ec646SMilanka Ringwald         default:
52150453b92SMatthias Ringwald             offset = avdtp_read_signaling_header(&connection->initiator_signaling_packet, packet, size);
52277092f3eSMatthias Ringwald             avdtp_initiator_stream_config_subsm(connection, packet, size, offset);
523747ec646SMilanka Ringwald             break;
524747ec646SMilanka Ringwald     }
525747ec646SMilanka Ringwald }
526747ec646SMilanka Ringwald 
527b1549ed3SMilanka Ringwald static void avdtp_handle_sdp_client_query_attribute_value(avdtp_connection_t * connection, uint8_t *packet){
528692c0605SMilanka Ringwald     des_iterator_t des_list_it;
529692c0605SMilanka Ringwald     des_iterator_t prot_it;
530692c0605SMilanka Ringwald 
531692c0605SMilanka Ringwald     // Handle new SDP record
532692c0605SMilanka Ringwald     if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id) {
533692c0605SMilanka Ringwald         record_id = sdp_event_query_attribute_byte_get_record_id(packet);
5348587e32cSMilanka Ringwald         // log_info("SDP Record: Nr: %d", record_id);
535692c0605SMilanka Ringwald     }
536692c0605SMilanka Ringwald 
537692c0605SMilanka Ringwald     if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) {
538692c0605SMilanka Ringwald         attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
539692c0605SMilanka Ringwald 
540692c0605SMilanka Ringwald         if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) {
541692c0605SMilanka Ringwald 
542692c0605SMilanka Ringwald             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
543149deddbSMilanka Ringwald 
544692c0605SMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST:
545692c0605SMilanka Ringwald                     if (de_get_element_type(attribute_value) != DE_DES) break;
546692c0605SMilanka Ringwald                     for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
547692c0605SMilanka Ringwald                         uint8_t * element = des_iterator_get_element(&des_list_it);
548692c0605SMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
549692c0605SMilanka Ringwald                         uint32_t uuid = de_get_uuid32(element);
550692c0605SMilanka Ringwald                         switch (uuid){
551692c0605SMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE:
552b1549ed3SMilanka Ringwald                                 connection->source_supported = true;
553149deddbSMilanka Ringwald                                 log_info("source_supported");
554692c0605SMilanka Ringwald                                 break;
555692c0605SMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK:
556b1549ed3SMilanka Ringwald                                 connection->sink_supported = true;
557149deddbSMilanka Ringwald                                 log_info("sink_supported");
558692c0605SMilanka Ringwald                                 break;
559692c0605SMilanka Ringwald                             default:
560692c0605SMilanka Ringwald                                 break;
561692c0605SMilanka Ringwald                         }
562692c0605SMilanka Ringwald                     }
563692c0605SMilanka Ringwald                     break;
564692c0605SMilanka Ringwald 
565149deddbSMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
5668587e32cSMilanka Ringwald                     // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
567692c0605SMilanka Ringwald                     for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
568692c0605SMilanka Ringwald                         uint8_t       *des_element;
569692c0605SMilanka Ringwald                         uint8_t       *element;
570692c0605SMilanka Ringwald                         uint32_t       uuid;
571692c0605SMilanka Ringwald 
572692c0605SMilanka Ringwald                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
573692c0605SMilanka Ringwald 
574692c0605SMilanka Ringwald                         des_element = des_iterator_get_element(&des_list_it);
575692c0605SMilanka Ringwald                         des_iterator_init(&prot_it, des_element);
576692c0605SMilanka Ringwald                         element = des_iterator_get_element(&prot_it);
577692c0605SMilanka Ringwald 
578692c0605SMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
579692c0605SMilanka Ringwald 
580692c0605SMilanka Ringwald                         uuid = de_get_uuid32(element);
58114fd128cSMatthias Ringwald                         des_iterator_next(&prot_it);
582149deddbSMilanka Ringwald                         // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both
583692c0605SMilanka Ringwald                         switch (uuid){
584692c0605SMilanka Ringwald                             case BLUETOOTH_PROTOCOL_L2CAP:
585692c0605SMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
586b1549ed3SMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_l2cap_psm);
587692c0605SMilanka Ringwald                                 break;
588692c0605SMilanka Ringwald                             case BLUETOOTH_PROTOCOL_AVDTP:
589692c0605SMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
590b1549ed3SMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_version);
591cc61e7e9SMilanka Ringwald                                 log_info("avdtp version 0x%02x", connection->avdtp_version);
592692c0605SMilanka Ringwald                                 break;
593692c0605SMilanka Ringwald                             default:
594692c0605SMilanka Ringwald                                 break;
595692c0605SMilanka Ringwald                         }
596692c0605SMilanka Ringwald                     }
597692c0605SMilanka Ringwald                     break;
598149deddbSMilanka Ringwald 
599692c0605SMilanka Ringwald                 default:
600692c0605SMilanka Ringwald                     break;
601692c0605SMilanka Ringwald             }
602692c0605SMilanka Ringwald         }
603692c0605SMilanka Ringwald     } else {
6048587e32cSMilanka 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));
605692c0605SMilanka Ringwald     }
6066ed344c3SMatthias Ringwald 
6076ed344c3SMatthias Ringwald }
6086ed344c3SMatthias Ringwald 
6095ace758fSMilanka Ringwald static void avdtp_finalize_connection(avdtp_connection_t * connection){
610ff53b162SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->retry_timer);
6115ace758fSMilanka Ringwald     btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection);
612f0c39502SMilanka Ringwald     btstack_memory_avdtp_connection_free(connection);
613f0c39502SMilanka Ringwald }
614f0c39502SMilanka Ringwald 
615f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_failed(avdtp_connection_t * connection, uint8_t status){
616a1fb0563SMilanka Ringwald     switch (connection->state){
617a1fb0563SMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE:
618a1fb0563SMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE:
619146fc0fbSMilanka Ringwald             avdtp_signaling_emit_connection_established(connection->avdtp_cid, connection->remote_addr, connection->con_handle, status);
620a1fb0563SMilanka Ringwald             break;
621cc61e7e9SMilanka Ringwald 
622cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
623cc61e7e9SMilanka Ringwald             // SDP query failed: try query that must be supported
624cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
625d80ccd43SMatthias Ringwald 			avdtp_request_can_send_now_initiator(connection);
626a1fb0563SMilanka Ringwald             return;
627cc61e7e9SMilanka Ringwald 
628cc61e7e9SMilanka Ringwald         default:
629cc61e7e9SMilanka Ringwald             btstack_assert(false);
630cc61e7e9SMilanka Ringwald             break;
631a1fb0563SMilanka Ringwald     }
6325ace758fSMilanka Ringwald     avdtp_finalize_connection(connection);
633ca2c9990SMilanka Ringwald     sdp_query_context_avdtp_cid = 0;
634f0c39502SMilanka Ringwald     log_info("SDP query failed with status 0x%02x.", status);
635f0c39502SMilanka Ringwald }
636f0c39502SMilanka Ringwald 
637f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){
638cc61e7e9SMilanka Ringwald     log_info("avdtp_handle_sdp_query_succeeded: state %d", connection->state);
639cc61e7e9SMilanka Ringwald 
640cc61e7e9SMilanka Ringwald     switch (connection->state){
641cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
642cc61e7e9SMilanka Ringwald             if (connection->avdtp_version < 0x0103){
643cc61e7e9SMilanka Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
644cc61e7e9SMilanka Ringwald             } else {
645cc61e7e9SMilanka Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES;
646cc61e7e9SMilanka Ringwald             }
647d80ccd43SMatthias Ringwald 			avdtp_request_can_send_now_initiator(connection);
648cc61e7e9SMilanka Ringwald             break;
649cc61e7e9SMilanka Ringwald         default:
650f0c39502SMilanka Ringwald             connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
651cc61e7e9SMilanka Ringwald             l2cap_create_channel(avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL);
652cc61e7e9SMilanka Ringwald             break;
653cc61e7e9SMilanka Ringwald     }
654f0c39502SMilanka Ringwald }
655f0c39502SMilanka Ringwald 
6566ed344c3SMatthias Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
657149deddbSMilanka Ringwald     UNUSED(packet_type);
658149deddbSMilanka Ringwald     UNUSED(channel);
659149deddbSMilanka Ringwald     UNUSED(size);
660149deddbSMilanka Ringwald 
661ca2c9990SMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(sdp_query_context_avdtp_cid);
6626ed344c3SMatthias Ringwald     if (!connection) {
663ca2c9990SMilanka Ringwald         log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context_avdtp_cid);
6646ed344c3SMatthias Ringwald         return;
6656ed344c3SMatthias Ringwald     }
6666ed344c3SMatthias Ringwald 
667722c03bdSMatthias Ringwald     uint8_t status = ERROR_CODE_SUCCESS;
668149deddbSMilanka Ringwald     switch (connection->state){
669149deddbSMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE:
6706ed344c3SMatthias Ringwald             switch (hci_event_packet_get_type(packet)){
6716ed344c3SMatthias Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
672b1549ed3SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
673149deddbSMilanka Ringwald                     return;
674692c0605SMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
6751e1ae2bcSMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
676149deddbSMilanka Ringwald                     if (status != ERROR_CODE_SUCCESS) break;
677cc92f22bSMatthias Ringwald                     if (!connection->sink_supported || (connection->avdtp_l2cap_psm == 0)) {
678cc92f22bSMatthias Ringwald                         status = SDP_SERVICE_NOT_FOUND;
679722c03bdSMatthias Ringwald                         break;
680722c03bdSMatthias Ringwald                     }
681149deddbSMilanka Ringwald                     break;
682149deddbSMilanka Ringwald                 default:
683149deddbSMilanka Ringwald                     btstack_assert(false);
684722c03bdSMatthias Ringwald                     return;
6851e1ae2bcSMilanka Ringwald             }
686149deddbSMilanka Ringwald             break;
687149deddbSMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE:
688149deddbSMilanka Ringwald             switch (hci_event_packet_get_type(packet)){
689149deddbSMilanka Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
690b1549ed3SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
691149deddbSMilanka Ringwald                     return;
692149deddbSMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
693149deddbSMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
694149deddbSMilanka Ringwald                     if (status != ERROR_CODE_SUCCESS) break;
695cc92f22bSMatthias Ringwald                     if (!connection->source_supported || (connection->avdtp_l2cap_psm == 0)) {
696cc92f22bSMatthias Ringwald                         status = SDP_SERVICE_NOT_FOUND;
697722c03bdSMatthias Ringwald                         break;
698722c03bdSMatthias Ringwald                     }
699149deddbSMilanka Ringwald                     break;
700149deddbSMilanka Ringwald                 default:
701149deddbSMilanka Ringwald                     btstack_assert(false);
702722c03bdSMatthias Ringwald                     return;
703974d4d6eSMilanka Ringwald             }
7042f6083d0SMilanka Ringwald             break;
705cc61e7e9SMilanka Ringwald 
706cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
707cc61e7e9SMilanka Ringwald             switch (hci_event_packet_get_type(packet)){
708cc61e7e9SMilanka Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
709cc61e7e9SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
710cc61e7e9SMilanka Ringwald                     return;
711cc61e7e9SMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
712cc92f22bSMatthias Ringwald                     // without suitable SDP Record, avdtp version v0.0 is assumed
713cc61e7e9SMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
714cc61e7e9SMilanka Ringwald                     break;
715cc61e7e9SMilanka Ringwald                 default:
716cc61e7e9SMilanka Ringwald                     btstack_assert(false);
717cc61e7e9SMilanka Ringwald                     return;
718cc61e7e9SMilanka Ringwald             }
719cc61e7e9SMilanka Ringwald             break;
720cc61e7e9SMilanka Ringwald 
721149deddbSMilanka Ringwald         default:
72208cb850dSMilanka Ringwald             // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete
72308cb850dSMilanka Ringwald             if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){
72408cb850dSMilanka Ringwald                 (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
72508cb850dSMilanka Ringwald             }
726149deddbSMilanka Ringwald             return;
7272f6083d0SMilanka Ringwald     }
728f0c39502SMilanka Ringwald 
729722c03bdSMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
730149deddbSMilanka Ringwald         avdtp_handle_sdp_query_succeeded(connection);
731149deddbSMilanka Ringwald     } else {
732149deddbSMilanka Ringwald         avdtp_handle_sdp_query_failed(connection, status);
733692c0605SMilanka Ringwald     }
7345797104aSMilanka Ringwald 
7355797104aSMilanka Ringwald     // register the SDP Query request to check if there is another connection waiting for the query
7365797104aSMilanka Ringwald     // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
7375797104aSMilanka Ringwald     (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
738692c0605SMilanka Ringwald }
739692c0605SMilanka Ringwald 
740146fc0fbSMilanka 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){
74136da8747SMilanka Ringwald     if (connection == NULL){
74236da8747SMilanka Ringwald         uint16_t cid = avdtp_get_next_cid();
7435ace758fSMilanka Ringwald         connection = avdtp_create_connection(event_addr, cid);
74436da8747SMilanka Ringwald     }
745692c0605SMilanka Ringwald 
74636da8747SMilanka Ringwald     if (connection) {
74736da8747SMilanka Ringwald         connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
74836da8747SMilanka Ringwald         connection->l2cap_signaling_cid = local_cid;
749146fc0fbSMilanka Ringwald         connection->con_handle = con_handle;
750ff53b162SMilanka Ringwald         btstack_run_loop_remove_timer(&connection->retry_timer);
75136da8747SMilanka Ringwald     }
75236da8747SMilanka Ringwald     return connection;
75336da8747SMilanka Ringwald }
754f0c39502SMilanka Ringwald 
755ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){
756326e3662SMilanka Ringwald     uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer);
757326e3662SMilanka Ringwald 
7585ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
759326e3662SMilanka Ringwald     if (connection == NULL) return;
760326e3662SMilanka Ringwald 
761ff53b162SMilanka Ringwald     if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){
762326e3662SMilanka Ringwald         connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
763326e3662SMilanka Ringwald         l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL);
764326e3662SMilanka Ringwald     }
765326e3662SMilanka Ringwald }
766326e3662SMilanka Ringwald 
767ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){
768ff53b162SMilanka Ringwald     btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler);
769ff53b162SMilanka Ringwald     btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid);
770326e3662SMilanka Ringwald 
771326e3662SMilanka Ringwald     // add some jitter/randomness to reconnect delay
772326e3662SMilanka Ringwald     uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F);
773ff53b162SMilanka Ringwald     btstack_run_loop_set_timer(&connection->retry_timer, timeout);
774ff53b162SMilanka Ringwald     btstack_run_loop_add_timer(&connection->retry_timer);
775326e3662SMilanka Ringwald }
776326e3662SMilanka Ringwald 
77739a45651SMatthias Ringwald static void avdtp_handle_close_media_channel(avdtp_stream_endpoint_t * stream_endpoint){
77839a45651SMatthias Ringwald     avdtp_connection_t * connection = stream_endpoint->connection;
77939a45651SMatthias Ringwald     btstack_assert(connection != NULL);
78039a45651SMatthias Ringwald     avdtp_streaming_emit_connection_released(stream_endpoint, connection->avdtp_cid, avdtp_local_seid(stream_endpoint));
78139a45651SMatthias Ringwald     avdtp_reset_stream_endpoint(stream_endpoint);
78239a45651SMatthias Ringwald     connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE;
78339a45651SMatthias Ringwald }
78439a45651SMatthias Ringwald 
78539a45651SMatthias Ringwald static void avdtp_handle_close_recovery_channel(avdtp_stream_endpoint_t * stream_endpoint){
78639a45651SMatthias Ringwald     log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", stream_endpoint->l2cap_recovery_cid);
78739a45651SMatthias Ringwald     stream_endpoint->l2cap_recovery_cid = 0;
78839a45651SMatthias Ringwald }
78939a45651SMatthias Ringwald 
79039a45651SMatthias Ringwald static void avdtp_handle_close_reporting_channel(avdtp_stream_endpoint_t * stream_endpoint){
79139a45651SMatthias Ringwald     log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", stream_endpoint->l2cap_reporting_cid);
79239a45651SMatthias Ringwald     stream_endpoint->l2cap_reporting_cid = 0;
79339a45651SMatthias Ringwald }
79439a45651SMatthias Ringwald 
795326e3662SMilanka Ringwald 
796326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
797747ec646SMilanka Ringwald     bd_addr_t event_addr;
798747ec646SMilanka Ringwald     uint16_t psm;
799747ec646SMilanka Ringwald     uint16_t local_cid;
8001e1ae2bcSMilanka Ringwald     uint8_t  status;
801326e3662SMilanka Ringwald     uint16_t l2cap_mtu;
802146fc0fbSMilanka Ringwald     hci_con_handle_t con_handle;
80336da8747SMilanka Ringwald 
80436da8747SMilanka Ringwald     bool accept_streaming_connection;
80536da8747SMilanka Ringwald     bool outoing_signaling_active;
80636da8747SMilanka Ringwald     bool decline_connection;
80784521ac1SMilanka Ringwald 
808747ec646SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = NULL;
809747ec646SMilanka Ringwald     avdtp_connection_t * connection = NULL;
81036da8747SMilanka Ringwald 
811747ec646SMilanka Ringwald     switch (packet_type) {
812747ec646SMilanka Ringwald         case L2CAP_DATA_PACKET:
8135ace758fSMilanka Ringwald             connection = avdtp_get_connection_for_l2cap_signaling_cid(channel);
814747ec646SMilanka Ringwald             if (connection){
81577092f3eSMatthias Ringwald                 handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);
816747ec646SMilanka Ringwald                 break;
817747ec646SMilanka Ringwald             }
818747ec646SMilanka Ringwald 
8196f98b084SMilanka Ringwald             stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel);
820747ec646SMilanka Ringwald             if (!stream_endpoint){
821747ec646SMilanka Ringwald                 if (!connection) break;
82277092f3eSMatthias Ringwald                 handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);
823747ec646SMilanka Ringwald                 break;
824747ec646SMilanka Ringwald             }
825747ec646SMilanka Ringwald 
8268c0f3635SMilanka Ringwald             if (stream_endpoint->connection){
8279413b167SMilanka Ringwald                 if (channel == stream_endpoint->connection->l2cap_signaling_cid){
82877092f3eSMatthias Ringwald                     handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size);
829747ec646SMilanka Ringwald                     break;
830747ec646SMilanka Ringwald                 }
8318c0f3635SMilanka Ringwald             }
832747ec646SMilanka Ringwald 
833747ec646SMilanka Ringwald             if (channel == stream_endpoint->l2cap_media_cid){
834951d2774SMatthias Ringwald                 btstack_assert(avdtp_sink_handle_media_data);
835951d2774SMatthias Ringwald                 (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size);
836747ec646SMilanka Ringwald                 break;
837747ec646SMilanka Ringwald             }
838747ec646SMilanka Ringwald 
839747ec646SMilanka Ringwald             if (channel == stream_endpoint->l2cap_reporting_cid){
8408587e32cSMilanka Ringwald                 log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED");
841747ec646SMilanka Ringwald             } else if (channel == stream_endpoint->l2cap_recovery_cid){
8428587e32cSMilanka Ringwald                 log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED");
843747ec646SMilanka Ringwald             } else {
844747ec646SMilanka Ringwald                 log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel);
845747ec646SMilanka Ringwald             }
846747ec646SMilanka Ringwald             break;
847747ec646SMilanka Ringwald 
848747ec646SMilanka Ringwald         case HCI_EVENT_PACKET:
849747ec646SMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
85036da8747SMilanka Ringwald 
851747ec646SMilanka Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
852747ec646SMilanka Ringwald                     l2cap_event_incoming_connection_get_address(packet, event_addr);
853747ec646SMilanka Ringwald                     local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
854146fc0fbSMilanka Ringwald                     con_handle = l2cap_event_incoming_connection_get_handle(packet);
85536da8747SMilanka Ringwald                     outoing_signaling_active = false;
85636da8747SMilanka Ringwald                     accept_streaming_connection = false;
85736da8747SMilanka Ringwald 
8585ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_bd_addr(event_addr);
85936da8747SMilanka Ringwald                     if (connection != NULL){
8600d4a198eSMatthias Ringwald                         switch (connection->state){
8610d4a198eSMatthias Ringwald                             case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED:
86236da8747SMilanka Ringwald                             case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED:
86336da8747SMilanka Ringwald                                 outoing_signaling_active = true;
86436da8747SMilanka Ringwald                                 connection->incoming_declined = true;
86536da8747SMilanka Ringwald                                 break;
86636da8747SMilanka Ringwald                             case AVDTP_SIGNALING_CONNECTION_OPENED:
86736da8747SMilanka Ringwald                                 outoing_signaling_active = true;
86836da8747SMilanka Ringwald                                 accept_streaming_connection = true;
86936da8747SMilanka Ringwald                                 break;
870f0c39502SMilanka Ringwald                             default:
871f0c39502SMilanka Ringwald                                 break;
8720d4a198eSMatthias Ringwald                         }
873747ec646SMilanka Ringwald                     }
87436da8747SMilanka Ringwald                     log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d",
87536da8747SMilanka Ringwald                         bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection);
876747ec646SMilanka Ringwald 
87736da8747SMilanka Ringwald                     decline_connection = outoing_signaling_active && !accept_streaming_connection;
87836da8747SMilanka Ringwald                     if (outoing_signaling_active == false){
879146fc0fbSMilanka Ringwald                         connection = avdtp_handle_incoming_connection(connection, event_addr, con_handle, local_cid);
88036da8747SMilanka Ringwald                         if (connection == NULL){
88136da8747SMilanka Ringwald                             decline_connection = true;
88236da8747SMilanka Ringwald                         }
88336da8747SMilanka Ringwald                     } else if (accept_streaming_connection){
88436da8747SMilanka Ringwald                         if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) {
88536da8747SMilanka Ringwald                             decline_connection = true;
88636da8747SMilanka Ringwald                         } else {
887939e12adSMatthias Ringwald                             // now, we're only dealing with media connections that are created by remote side - we're acceptor here
8883338afc0SMatthias Ringwald                             stream_endpoint = avdtp_get_stream_endpoint_for_seid(connection->acceptor_local_seid);
88936da8747SMilanka Ringwald                             if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) {
89036da8747SMilanka Ringwald                                 decline_connection = true;
89136da8747SMilanka Ringwald                             }
89236da8747SMilanka Ringwald                         }
893747ec646SMilanka Ringwald                     }
894747ec646SMilanka Ringwald 
89536da8747SMilanka Ringwald                     if (decline_connection){
896a3ce0109SMatthias Ringwald                         l2cap_decline_connection(local_cid);
89736da8747SMilanka Ringwald                     } else {
898747ec646SMilanka Ringwald                         l2cap_accept_connection(local_cid);
89936da8747SMilanka Ringwald                     }
900747ec646SMilanka Ringwald                     break;
901747ec646SMilanka Ringwald 
902747ec646SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
903a5114819SMilanka Ringwald 
904a0b8a58cSMilanka Ringwald                     psm = l2cap_event_channel_opened_get_psm(packet);
90584e3541eSMilanka Ringwald                     if (psm != BLUETOOTH_PSM_AVDTP){
906355ac553SMilanka Ringwald                         log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED ");
907a0b8a58cSMilanka Ringwald                         return;
908a0b8a58cSMilanka Ringwald                     }
909a0b8a58cSMilanka Ringwald 
9101e1ae2bcSMilanka Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
911747ec646SMilanka Ringwald                     // inform about new l2cap connection
912747ec646SMilanka Ringwald                     l2cap_event_channel_opened_get_address(packet, event_addr);
9137050d2caSMilanka Ringwald                     local_cid = l2cap_event_channel_opened_get_local_cid(packet);
914326e3662SMilanka Ringwald                     l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet);
9155ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_bd_addr(event_addr);
91636da8747SMilanka Ringwald                     if (connection == NULL){
91736da8747SMilanka Ringwald                         log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr));
918a0b8a58cSMilanka Ringwald                         break;
919a0b8a58cSMilanka Ringwald                     }
920a0b8a58cSMilanka Ringwald 
921146fc0fbSMilanka Ringwald                     con_handle = l2cap_event_channel_opened_get_handle(packet);
922146fc0fbSMilanka Ringwald 
923a5114819SMilanka Ringwald                     switch (connection->state){
924a5114819SMilanka Ringwald                         case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED:
925326e3662SMilanka Ringwald                             switch (status){
926326e3662SMilanka Ringwald                                 case ERROR_CODE_SUCCESS:
927326e3662SMilanka Ringwald                                     connection->l2cap_signaling_cid = local_cid;
928326e3662SMilanka Ringwald                                     connection->incoming_declined = false;
929326e3662SMilanka Ringwald                                     connection->l2cap_mtu = l2cap_mtu;
930146fc0fbSMilanka Ringwald                                     connection->con_handle = con_handle;
931326e3662SMilanka Ringwald                                     connection->state = AVDTP_SIGNALING_CONNECTION_OPENED;
932146fc0fbSMilanka 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);
933146fc0fbSMilanka Ringwald                                     avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status);
934326e3662SMilanka Ringwald                                     return;
935326e3662SMilanka Ringwald                                 case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES:
936326e3662SMilanka Ringwald                                     if (connection->incoming_declined == true) {
937326e3662SMilanka Ringwald                                         log_info("Connection was declined, and the outgoing failed");
938ff53b162SMilanka Ringwald                                         connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY;
939326e3662SMilanka Ringwald                                         connection->incoming_declined = false;
940ff53b162SMilanka Ringwald                                         avdtp_retry_timer_start(connection);
941326e3662SMilanka Ringwald                                         return;
942326e3662SMilanka Ringwald                                     }
943326e3662SMilanka Ringwald                                     break;
944326e3662SMilanka Ringwald                                 default:
945326e3662SMilanka Ringwald                                     log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status);
946326e3662SMilanka Ringwald                                     break;
947326e3662SMilanka Ringwald                             }
948146fc0fbSMilanka Ringwald                             avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status);
949f82b60efSMilanka Ringwald                             avdtp_finalize_connection(connection);
950a0b8a58cSMilanka Ringwald                             break;
951747ec646SMilanka Ringwald 
952a5114819SMilanka Ringwald                         case AVDTP_SIGNALING_CONNECTION_OPENED:
95319a000d1SMilanka Ringwald                             stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid);
954747ec646SMilanka Ringwald                             if (!stream_endpoint){
9555bd73fa2SMatthias Ringwald                                 log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid);
956747ec646SMilanka Ringwald                                 return;
957747ec646SMilanka Ringwald                             }
958326e3662SMilanka Ringwald                             if (status != ERROR_CODE_SUCCESS){
959355ac553SMilanka 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));
960a466d508SMilanka Ringwald                                 stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
961f751daa3SMatthias Ringwald                                 avdtp_streaming_emit_connection_established(stream_endpoint, status);
962a466d508SMilanka Ringwald                                 break;
963a466d508SMilanka Ringwald                             }
964a5114819SMilanka Ringwald                             switch (stream_endpoint->state){
965a5114819SMilanka Ringwald                                 case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED:
966a466d508SMilanka Ringwald                                     stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
967a466d508SMilanka Ringwald                                     stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet);
968a466d508SMilanka Ringwald                                     stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet);
969d1207cd8SMilanka Ringwald 
970355ac553SMilanka 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));
971f751daa3SMatthias Ringwald                                     avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS);
972a5114819SMilanka Ringwald                                     break;
973a5114819SMilanka Ringwald                                 default:
974a5114819SMilanka 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));
97523edb87eSMilanka Ringwald                                     avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_COMMAND_DISALLOWED);
976a5114819SMilanka Ringwald                                     break;
977a5114819SMilanka Ringwald                             }
978a5114819SMilanka Ringwald                             break;
979a5114819SMilanka Ringwald 
980a5114819SMilanka Ringwald                         default:
981326e3662SMilanka Ringwald                             log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state);
982a5114819SMilanka Ringwald                             break;
983a5114819SMilanka Ringwald                     }
984747ec646SMilanka Ringwald                     break;
985747ec646SMilanka Ringwald 
986747ec646SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
987747ec646SMilanka Ringwald                     local_cid = l2cap_event_channel_closed_get_local_cid(packet);
9886f98b084SMilanka Ringwald                     stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid);
9895ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid);
99036da8747SMilanka Ringwald 
991f01aeca4SMilanka Ringwald                     log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint);
992f01aeca4SMilanka Ringwald 
993a466d508SMilanka Ringwald                     if (stream_endpoint){
994a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_media_cid == local_cid){
99539a45651SMatthias Ringwald                             avdtp_handle_close_media_channel(stream_endpoint);
996a466d508SMilanka Ringwald                             break;
997a466d508SMilanka Ringwald                         }
998a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_recovery_cid == local_cid){
99939a45651SMatthias Ringwald                             avdtp_handle_close_recovery_channel(stream_endpoint);
1000a466d508SMilanka Ringwald                             break;
1001a466d508SMilanka Ringwald                         }
1002a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_reporting_cid == local_cid){
100339a45651SMatthias Ringwald                             avdtp_handle_close_reporting_channel(stream_endpoint);
1004a466d508SMilanka Ringwald                             break;
1005a466d508SMilanka Ringwald                         }
1006a466d508SMilanka Ringwald                     }
1007596b7fdcSMilanka Ringwald 
1008596b7fdcSMilanka Ringwald                     if (connection){
1009535ff088SMatthias Ringwald                         // closing signaling channel invalidates all other channels as well
1010596b7fdcSMilanka Ringwald                         btstack_linked_list_iterator_t it;
1011d8e15394SMilanka Ringwald                         btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1012596b7fdcSMilanka Ringwald                         while (btstack_linked_list_iterator_has_next(&it)){
1013f01aeca4SMilanka Ringwald                             stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1014f01aeca4SMilanka Ringwald                             if (stream_endpoint->connection == connection){
1015535ff088SMatthias Ringwald                                 avdtp_handle_close_recovery_channel(stream_endpoint);
1016535ff088SMatthias Ringwald                                 avdtp_handle_close_reporting_channel(stream_endpoint);
1017535ff088SMatthias Ringwald                                 avdtp_handle_close_media_channel(stream_endpoint);
1018f01aeca4SMilanka Ringwald                                 avdtp_reset_stream_endpoint(stream_endpoint);
1019596b7fdcSMilanka Ringwald                             }
1020596b7fdcSMilanka Ringwald                         }
1021c69f4ba5SMatthias Ringwald                         avdtp_signaling_emit_connection_released(connection->avdtp_cid);
10225ace758fSMilanka Ringwald                         avdtp_finalize_connection(connection);
1023596b7fdcSMilanka Ringwald                         break;
1024596b7fdcSMilanka Ringwald                     }
1025747ec646SMilanka Ringwald                     break;
1026747ec646SMilanka Ringwald 
1027747ec646SMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
1028c6bc5965SMilanka Ringwald                     log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel);
1029d80ccd43SMatthias Ringwald 					avdtp_handle_can_send_now(channel);
1030747ec646SMilanka Ringwald                     break;
1031747ec646SMilanka Ringwald                 default:
1032355ac553SMilanka Ringwald                     log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet));
1033747ec646SMilanka Ringwald                     break;
1034747ec646SMilanka Ringwald             }
1035747ec646SMilanka Ringwald             break;
1036747ec646SMilanka Ringwald 
1037747ec646SMilanka Ringwald         default:
1038747ec646SMilanka Ringwald             // other packet type
1039747ec646SMilanka Ringwald             break;
1040747ec646SMilanka Ringwald     }
1041747ec646SMilanka Ringwald }
1042747ec646SMilanka Ringwald 
1043b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){
10445ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
104523edb87eSMilanka Ringwald     if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1046b401ff59SMilanka Ringwald 
1047a466d508SMilanka Ringwald     if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS;
1048747ec646SMilanka Ringwald 
1049f01aeca4SMilanka Ringwald     btstack_linked_list_iterator_t it;
1050f01aeca4SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1051f01aeca4SMilanka Ringwald 
1052f01aeca4SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1053f01aeca4SMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1054f01aeca4SMilanka Ringwald         if (stream_endpoint->connection != connection) continue;
1055f01aeca4SMilanka Ringwald 
1056f01aeca4SMilanka Ringwald         switch (stream_endpoint->state){
1057f01aeca4SMilanka Ringwald             case AVDTP_STREAM_ENDPOINT_OPENED:
1058f01aeca4SMilanka Ringwald             case AVDTP_STREAM_ENDPOINT_STREAMING:
1059f01aeca4SMilanka Ringwald                 stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED;
1060f01aeca4SMilanka Ringwald                 l2cap_disconnect(stream_endpoint->l2cap_media_cid, 0);
1061f01aeca4SMilanka Ringwald                 break;
1062f01aeca4SMilanka Ringwald             default:
1063f01aeca4SMilanka Ringwald                 break;
1064f01aeca4SMilanka Ringwald         }
1065f01aeca4SMilanka Ringwald     }
1066f01aeca4SMilanka Ringwald 
1067f01aeca4SMilanka Ringwald     connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED;
1068f01aeca4SMilanka Ringwald     l2cap_disconnect(connection->l2cap_signaling_cid, 0);
10694ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1070747ec646SMilanka Ringwald }
1071747ec646SMilanka Ringwald 
1072297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){
10735ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1074747ec646SMilanka Ringwald     if (!connection){
10758587e32cSMilanka Ringwald         log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid);
107623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1077747ec646SMilanka Ringwald     }
1078747ec646SMilanka Ringwald 
1079747ec646SMilanka Ringwald     if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
10808587e32cSMilanka Ringwald         log_error("avdtp_media_connect: wrong connection state %d", connection->state);
108123edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1082747ec646SMilanka Ringwald     }
1083747ec646SMilanka Ringwald 
10843338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
1085747ec646SMilanka Ringwald     if (!stream_endpoint) {
10866b0ee1d0SMilanka Ringwald         log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid);
108723edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1088747ec646SMilanka Ringwald     }
1089747ec646SMilanka Ringwald 
1090485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid != remote_seid){
1091485c0a4cSMilanka Ringwald         log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid);
109223edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1093485c0a4cSMilanka Ringwald     }
1094485c0a4cSMilanka Ringwald 
109523edb87eSMilanka Ringwald     if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return ERROR_CODE_COMMAND_DISALLOWED;
1096747ec646SMilanka Ringwald 
1097b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
109896dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
10995bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1100747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM;
1101747ec646SMilanka Ringwald     stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM;
1102d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
11034ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1104747ec646SMilanka Ringwald }
1105747ec646SMilanka Ringwald 
1106297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){
11075ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
110846e6b063SMilanka Ringwald     if (!connection){
11094ccacc40SMilanka Ringwald         log_error("avdtp_start_stream: no connection for signaling cid 0x%02x found", avdtp_cid);
111023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
111146e6b063SMilanka Ringwald     }
11125cfe7f4cSMilanka Ringwald 
11133338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
11144ccacc40SMilanka Ringwald     if (!stream_endpoint) {
11154ccacc40SMilanka Ringwald         log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid);
111623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11174ccacc40SMilanka Ringwald     }
11184ccacc40SMilanka Ringwald 
11194ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
11204ccacc40SMilanka Ringwald         log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid);
112123edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11224ccacc40SMilanka Ringwald     }
11234ccacc40SMilanka Ringwald 
1124485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint)){
1125485c0a4cSMilanka Ringwald         log_error("avdtp_media_connect: no remote sep registered with the stream endpoint");
112623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11274ccacc40SMilanka Ringwald     }
11284ccacc40SMilanka Ringwald 
1129440d8d82SMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){
1130440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1131440d8d82SMilanka Ringwald     }
1132440d8d82SMilanka Ringwald 
11334e7bc04fSMilanka Ringwald     if (stream_endpoint->start_stream == 1) {
11344e7bc04fSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
11354e7bc04fSMilanka Ringwald     }
11364e7bc04fSMilanka Ringwald 
113760ec20d0SMilanka Ringwald     stream_endpoint->start_stream = 1;
11385bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
113996dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1140d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
11414ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1142747ec646SMilanka Ringwald }
1143747ec646SMilanka Ringwald 
1144297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){
11455ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1146747ec646SMilanka Ringwald     if (!connection){
11474ccacc40SMilanka Ringwald         log_error("avdtp_stop_stream: no connection for signaling cid 0x%02x found", avdtp_cid);
114823edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1149747ec646SMilanka Ringwald     }
11504ccacc40SMilanka Ringwald 
11513338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
11524ccacc40SMilanka Ringwald     if (!stream_endpoint) {
11534ccacc40SMilanka Ringwald         log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid);
115423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11554ccacc40SMilanka Ringwald     }
11564ccacc40SMilanka Ringwald 
11574ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
11584ccacc40SMilanka Ringwald         log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid);
115923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11604ccacc40SMilanka Ringwald     }
1161485c0a4cSMilanka Ringwald 
1162fa4419dbSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->close_stream){
1163440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1164485c0a4cSMilanka Ringwald     }
11654ccacc40SMilanka Ringwald 
11664e7bc04fSMilanka Ringwald     if (stream_endpoint->close_stream == 1) {
11674e7bc04fSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
11684e7bc04fSMilanka Ringwald     }
11694e7bc04fSMilanka Ringwald 
1170fa4419dbSMilanka Ringwald     stream_endpoint->close_stream = 1;
11715bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
117296dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1173d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
11744ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1175747ec646SMilanka Ringwald }
1176747ec646SMilanka Ringwald 
1177297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){
11785ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
117960ec20d0SMilanka Ringwald     if (!connection){
11804ccacc40SMilanka Ringwald         log_error("avdtp_abort_stream: no connection for signaling cid 0x%02x found", avdtp_cid);
118123edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1182747ec646SMilanka Ringwald     }
11834ccacc40SMilanka Ringwald 
11843338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
11854ccacc40SMilanka Ringwald     if (!stream_endpoint) {
11864ccacc40SMilanka Ringwald         log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid);
118723edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11884ccacc40SMilanka Ringwald     }
11894ccacc40SMilanka Ringwald 
11904ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
11914ccacc40SMilanka Ringwald         log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid);
119223edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11934ccacc40SMilanka Ringwald     }
1194485c0a4cSMilanka Ringwald 
1195485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){
1196440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1197485c0a4cSMilanka Ringwald     }
11984ccacc40SMilanka Ringwald 
11994e7bc04fSMilanka Ringwald     if (stream_endpoint->abort_stream == 1) {
12004e7bc04fSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12014e7bc04fSMilanka Ringwald     }
12024e7bc04fSMilanka Ringwald 
120360ec20d0SMilanka Ringwald     stream_endpoint->abort_stream = 1;
12045bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
120596dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1206d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
12074ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1208747ec646SMilanka Ringwald }
1209747ec646SMilanka Ringwald 
1210297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){
12115ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1212747ec646SMilanka Ringwald     if (!connection){
12134ccacc40SMilanka Ringwald         log_error("avdtp_suspend_stream: no connection for signaling cid 0x%02x found", avdtp_cid);
121423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
121560ec20d0SMilanka Ringwald     }
12163338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
12174ccacc40SMilanka Ringwald     if (!stream_endpoint) {
12184ccacc40SMilanka Ringwald         log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid);
121923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12204ccacc40SMilanka Ringwald     }
12214ccacc40SMilanka Ringwald 
12224ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
12234ccacc40SMilanka Ringwald         log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid);
122423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12254ccacc40SMilanka Ringwald     }
1226485c0a4cSMilanka Ringwald 
1227485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){
1228440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1229485c0a4cSMilanka Ringwald     }
12304ccacc40SMilanka Ringwald 
12314e7bc04fSMilanka Ringwald     if (stream_endpoint->suspend_stream == 1) {
12324e7bc04fSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12334e7bc04fSMilanka Ringwald     }
12344e7bc04fSMilanka Ringwald 
123560ec20d0SMilanka Ringwald     stream_endpoint->suspend_stream = 1;
12365bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
123796dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1238d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
12394ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1240747ec646SMilanka Ringwald }
1241747ec646SMilanka Ringwald 
12425ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){
12435ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1244747ec646SMilanka Ringwald     if (!connection){
12458587e32cSMilanka Ringwald         log_error("avdtp_discover_stream_endpoints: no connection for signaling cid 0x%02x found", avdtp_cid);
124623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12479974aee0SMilanka Ringwald     }
12480e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1249c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
125023edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1251747ec646SMilanka Ringwald     }
1252ec3d71e3SMilanka Ringwald 
1253b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1254747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS;
1255d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1256747ec646SMilanka Ringwald }
1257747ec646SMilanka Ringwald 
1258747ec646SMilanka Ringwald 
12595ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){
12605ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1261747ec646SMilanka Ringwald     if (!connection){
12629900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
126323edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1264747ec646SMilanka Ringwald     }
12650e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1266c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
126723edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12689974aee0SMilanka Ringwald     }
12699974aee0SMilanka Ringwald 
1270b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1271747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
127296dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1273d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1274747ec646SMilanka Ringwald }
1275747ec646SMilanka Ringwald 
1276747ec646SMilanka Ringwald 
12775ace758fSMilanka Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){
12785ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1279747ec646SMilanka Ringwald     if (!connection){
12809900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
128123edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1282747ec646SMilanka Ringwald     }
12830e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1284c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
128523edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12869974aee0SMilanka Ringwald     }
12879974aee0SMilanka Ringwald 
1288b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
128996dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1290cc61e7e9SMilanka Ringwald 
1291cc61e7e9SMilanka Ringwald     if (connection->avdtp_version == 0){
1292cc61e7e9SMilanka Ringwald         connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES;
1293cc61e7e9SMilanka Ringwald         avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query;
1294cc61e7e9SMilanka Ringwald         // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
1295cc61e7e9SMilanka Ringwald         (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
1296cc61e7e9SMilanka Ringwald         return ERROR_CODE_SUCCESS;
1297cc61e7e9SMilanka Ringwald     } else {
1298cc61e7e9SMilanka Ringwald         // AVDTP version lower then 1.3 supports only get capabilities command
1299cc61e7e9SMilanka Ringwald         if (connection->avdtp_version < 0x103){
1300cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
1301cc61e7e9SMilanka Ringwald         } else {
1302cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES;
1303cc61e7e9SMilanka Ringwald         }
1304d80ccd43SMatthias Ringwald         return avdtp_request_can_send_now_initiator(connection);
1305747ec646SMilanka Ringwald     }
1306cc61e7e9SMilanka Ringwald }
1307747ec646SMilanka Ringwald 
13085ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){
13095ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1310747ec646SMilanka Ringwald     if (!connection){
13119900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
131223edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1313747ec646SMilanka Ringwald     }
13140e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1315c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
131623edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
13179974aee0SMilanka Ringwald     }
13189974aee0SMilanka Ringwald 
1319b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1320747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION;
132196dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1322d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1323747ec646SMilanka Ringwald }
1324747ec646SMilanka Ringwald 
1325cec76c5bSMilanka 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){
13265ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1327747ec646SMilanka Ringwald     if (!connection){
13289900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
132923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1330747ec646SMilanka Ringwald     }
13310e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1332c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
1333485c0a4cSMilanka Ringwald         log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state);
133423edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
13359974aee0SMilanka Ringwald     }
1336a3ce0109SMatthias Ringwald     if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){
1337a3ce0109SMatthias Ringwald         log_info("configuration already started, config state %u", connection->configuration_state);
133823edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1339a3ce0109SMatthias Ringwald     }
1340747ec646SMilanka Ringwald 
1341d8e15394SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
1342747ec646SMilanka Ringwald     if (!stream_endpoint) {
13439900b7faSMilanka Ringwald         log_error("No initiator stream endpoint for seid %d", local_seid);
134423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1345747ec646SMilanka Ringwald     }
1346417b4996SMilanka Ringwald     if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){
1347485c0a4cSMilanka Ringwald         log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state);
134823edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1349417b4996SMilanka Ringwald     }
1350a3ce0109SMatthias Ringwald 
1351bdbc3ef6SMilanka Ringwald     connection->active_stream_endpoint = (void*) stream_endpoint;
1352a3ce0109SMatthias Ringwald     connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED;
1353747ec646SMilanka Ringwald 
1354b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
135596dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
13565bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1357f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration_bitmap = configured_services_bitmap;
1358f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration = configuration;
1359747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION;
1360ffa6c160SMilanka Ringwald 
136144e638f3SMatthias Ringwald 	log_debug("SE %p, initiator_config_state: 0x%02x", stream_endpoint, stream_endpoint->initiator_config_state);
13623a69f723SMatthias Ringwald 
1363d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1364747ec646SMilanka Ringwald }
1365747ec646SMilanka Ringwald 
1366cec76c5bSMilanka 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){
13675ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1368747ec646SMilanka Ringwald     if (!connection){
13699900b7faSMilanka Ringwald         log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid);
137023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1371747ec646SMilanka Ringwald     }
1372747ec646SMilanka Ringwald     //TODO: if opened only app capabilities, enable reconfigure for not opened
13730e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1374c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
137523edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
13769974aee0SMilanka Ringwald     }
13779e42cfccSMilanka Ringwald 
1378d8e15394SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
137978d08d09SMilanka Ringwald     if (!stream_endpoint) {
13804ccacc40SMilanka Ringwald         log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid);
138123edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
138278d08d09SMilanka Ringwald     }
138378d08d09SMilanka Ringwald 
1384485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint)){
13858587e32cSMilanka Ringwald         log_error("avdtp_reconfigure: no associated remote sep");
138623edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
138778d08d09SMilanka Ringwald     }
1388485c0a4cSMilanka Ringwald 
1389b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
139096dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
13915bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1392f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration_bitmap = configured_services_bitmap;
1393f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration = configuration;
1394747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID;
1395d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1396747ec646SMilanka Ringwald }
1397747ec646SMilanka Ringwald 
1398093c3dfdSMatthias Ringwald void    avdtp_set_preferred_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){
13998e7044f9SMatthias Ringwald     stream_endpoint->preferred_sampling_frequency = sampling_frequency;
14008e7044f9SMatthias Ringwald }
14018e7044f9SMatthias Ringwald 
140279654d96SMilanka Ringwald void    avdtp_set_preferred_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t channel_mode){
140379654d96SMilanka Ringwald     stream_endpoint->preferred_channel_mode = channel_mode;
140479654d96SMilanka Ringwald }
140579654d96SMilanka Ringwald 
140679654d96SMilanka Ringwald 
140780dc0088SMatthias Ringwald avdtp_channel_mode_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){
140878d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
140978d08d09SMilanka Ringwald     uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap;
141078d08d09SMilanka Ringwald 
141179654d96SMilanka Ringwald     // use preferred channel mode if possible
141279654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_JOINT_STEREO){
141380dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_JOINT_STEREO;
141479654d96SMilanka Ringwald     }
141579654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_STEREO){
141680dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_STEREO;
141779654d96SMilanka Ringwald     }
141879654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_DUAL_CHANNEL){
141980dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
142079654d96SMilanka Ringwald     }
142179654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_MONO){
142280dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_MONO;
142379654d96SMilanka Ringwald     }
142479654d96SMilanka Ringwald 
142579654d96SMilanka Ringwald 
142678d08d09SMilanka Ringwald     if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){
142780dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_JOINT_STEREO;
142878d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){
142980dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_STEREO;
143078d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){
143180dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
143278d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_MONO){
143380dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_MONO;
143478d08d09SMilanka Ringwald     }
143580dc0088SMatthias Ringwald     return AVDTP_CHANNEL_MODE_JOINT_STEREO;
143678d08d09SMilanka Ringwald }
143778d08d09SMilanka Ringwald 
143880dc0088SMatthias Ringwald avdtp_sbc_allocation_method_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){
143978d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
1440b5bbcbf4SMatthias Ringwald     uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap;
144178d08d09SMilanka Ringwald 
1442b5bbcbf4SMatthias Ringwald     avdtp_sbc_allocation_method_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS;
144378d08d09SMilanka Ringwald     if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){
144478d08d09SMilanka Ringwald         allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS;
144578d08d09SMilanka Ringwald     } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){
144678d08d09SMilanka Ringwald         allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR;
144778d08d09SMilanka Ringwald     }
144878d08d09SMilanka Ringwald     return allocation_method;
144978d08d09SMilanka Ringwald }
145078d08d09SMilanka Ringwald 
1451bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){
1452bd1ecb8aSMilanka Ringwald     if (!stream_endpoint) return 0;
1453bd1ecb8aSMilanka Ringwald     return stream_endpoint->sep.seid;
1454bd1ecb8aSMilanka Ringwald }
145578d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){
145667ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
145778d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
145878d08d09SMilanka Ringwald     uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap;
145978d08d09SMilanka Ringwald 
146078d08d09SMilanka Ringwald     uint8_t subbands = AVDTP_SBC_SUBBANDS_8;
146178d08d09SMilanka Ringwald     if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){
146278d08d09SMilanka Ringwald         subbands = AVDTP_SBC_SUBBANDS_8;
146378d08d09SMilanka Ringwald     } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){
146478d08d09SMilanka Ringwald         subbands = AVDTP_SBC_SUBBANDS_4;
146578d08d09SMilanka Ringwald     }
146678d08d09SMilanka Ringwald     return subbands;
146778d08d09SMilanka Ringwald }
146878d08d09SMilanka Ringwald 
146978d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){
147067ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
147178d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
147278d08d09SMilanka Ringwald     uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap;
147378d08d09SMilanka Ringwald 
147478d08d09SMilanka Ringwald     uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16;
147578d08d09SMilanka Ringwald     if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){
147678d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_16;
147778d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){
147878d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_12;
147978d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){
148078d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_8;
148178d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){
148278d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_4;
148378d08d09SMilanka Ringwald     }
148478d08d09SMilanka Ringwald     return block_length;
148578d08d09SMilanka Ringwald }
148678d08d09SMilanka Ringwald 
148780dc0088SMatthias Ringwald uint16_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){
148867ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
148978d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
14908e7044f9SMatthias Ringwald     uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap;
149178d08d09SMilanka Ringwald 
14928e7044f9SMatthias Ringwald     // use preferred sampling frequency if possible
14938e7044f9SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){
149480dc0088SMatthias Ringwald         return stream_endpoint->preferred_sampling_frequency;
14958e7044f9SMatthias Ringwald     }
14966ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){
149780dc0088SMatthias Ringwald         return stream_endpoint->preferred_sampling_frequency;
14986ed344c3SMatthias Ringwald     }
14996ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){
150080dc0088SMatthias Ringwald         return stream_endpoint->preferred_sampling_frequency;
15016ed344c3SMatthias Ringwald     }
15026ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){
150380dc0088SMatthias Ringwald         return stream_endpoint->preferred_sampling_frequency;
15046ed344c3SMatthias Ringwald     }
15056ed344c3SMatthias Ringwald 
15068e7044f9SMatthias Ringwald     // otherwise, use highest available
15076ed344c3SMatthias Ringwald     if (supported_sampling_frequency_bitmap & AVDTP_SBC_48000){
150880dc0088SMatthias Ringwald         return 48000;
150978d08d09SMilanka Ringwald     }
15106ed344c3SMatthias Ringwald     if (supported_sampling_frequency_bitmap & AVDTP_SBC_44100){
151180dc0088SMatthias Ringwald         return 44100;
15126ed344c3SMatthias Ringwald     }
15136ed344c3SMatthias Ringwald     if (supported_sampling_frequency_bitmap & AVDTP_SBC_32000){
151480dc0088SMatthias Ringwald         return 32000;
15156ed344c3SMatthias Ringwald     }
15166ed344c3SMatthias Ringwald     if (supported_sampling_frequency_bitmap & AVDTP_SBC_16000){
151780dc0088SMatthias Ringwald         return 16000;
15186ed344c3SMatthias Ringwald     }
151980dc0088SMatthias Ringwald     return 44100; // some default
152078d08d09SMilanka Ringwald }
152178d08d09SMilanka Ringwald 
152278d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){
152367ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
152478d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
152578d08d09SMilanka Ringwald     return btstack_min(media_codec[3], remote_max_bitpool_value);
152678d08d09SMilanka Ringwald }
152778d08d09SMilanka Ringwald 
152878d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){
152967ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
153078d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
153178d08d09SMilanka Ringwald     return btstack_max(media_codec[2], remote_min_bitpool_value);
1532747ec646SMilanka Ringwald }
1533485c0a4cSMilanka Ringwald 
1534485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){
1535485c0a4cSMilanka Ringwald     if (!stream_endpoint) return 0;
1536485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid == 0) return 0;
1537485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid > 0x3E) return 0;
1538485c0a4cSMilanka Ringwald     return 1;
1539485c0a4cSMilanka Ringwald }
15408322fb3aSMatthias Ringwald 
15418322fb3aSMatthias Ringwald void avdtp_init(void){
15428322fb3aSMatthias Ringwald     if (!l2cap_registered){
15438322fb3aSMatthias Ringwald         l2cap_registered = true;
15448322fb3aSMatthias Ringwald         l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, 0xffff, gap_get_security_level());
15458322fb3aSMatthias Ringwald     }
15468322fb3aSMatthias Ringwald }
154757fb24ffSMatthias Ringwald 
154857fb24ffSMatthias Ringwald void avdtp_deinit(void){
154957fb24ffSMatthias Ringwald     l2cap_registered = false;
155057fb24ffSMatthias Ringwald     stream_endpoints = NULL;
155157fb24ffSMatthias Ringwald     connections = NULL;
155257fb24ffSMatthias Ringwald     avdtp_sink_handle_media_data = NULL;
15531ef2d533SMatthias Ringwald     avdtp_media_config_validator = NULL;
155457fb24ffSMatthias Ringwald 
155557fb24ffSMatthias Ringwald     sdp_query_context_avdtp_cid = 0;
155657fb24ffSMatthias Ringwald     stream_endpoints_id_counter = 0;
155757fb24ffSMatthias Ringwald     transaction_id_counter = 0;
155857fb24ffSMatthias Ringwald     avdtp_cid_counter = 0;
155957fb24ffSMatthias Ringwald }
1560