xref: /btstack/src/classic/avdtp.c (revision 335dba6a8f1618f200debbc47e346d04b1c4b468)
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
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH 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"
50c70720c6SMatthias 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 
57137e2954SMatthias Ringwald // higher layer callbacks
58a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_source_callback;
59a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_sink_callback;
60137e2954SMatthias Ringwald 
61137e2954SMatthias Ringwald static void (*avdtp_sink_handle_media_data)(uint8_t local_seid, uint8_t *packet, uint16_t size);
62137e2954SMatthias Ringwald 
636a737fb6SMatthias Ringwald static uint8_t (*avdtp_sink_media_config_validator)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size);
646a737fb6SMatthias Ringwald static uint8_t (*avdtp_source_media_config_validator)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size);
65a1fb0563SMilanka Ringwald 
66137e2954SMatthias Ringwald // sdp query
676a737fb6SMatthias Ringwald static btstack_context_callback_registration_t avdtp_handle_sdp_client_query_request;
68137e2954SMatthias Ringwald static uint16_t avdtp_sdp_query_context_avdtp_cid = 0;
69f0c39502SMilanka Ringwald 
70137e2954SMatthias Ringwald // registered stream endpoints
71137e2954SMatthias Ringwald static btstack_linked_list_t avdtp_stream_endpoints;
72ab2445a0SMatthias Ringwald static uint8_t avdtp_stream_endpoints_id_counter = 0;
73560b3f31SMilanka Ringwald 
74137e2954SMatthias Ringwald static bool avdtp_l2cap_registered;
755ace758fSMilanka Ringwald 
76137e2954SMatthias Ringwald static btstack_linked_list_t avdtp_connections;
77ab2445a0SMatthias Ringwald static uint8_t avdtp_transaction_id_counter = 0;
78747ec646SMilanka Ringwald 
79137e2954SMatthias Ringwald static int avdtp_record_id;
80137e2954SMatthias Ringwald static uint8_t avdtp_attribute_value[45];
81137e2954SMatthias Ringwald static const unsigned int avdtp_attribute_value_buffer_size = sizeof(avdtp_attribute_value);
82951d2774SMatthias Ringwald 
83af121d54SMilanka Ringwald static uint16_t avdtp_cid_counter = 0;
84747ec646SMilanka Ringwald 
85692c0605SMilanka Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
86692c0605SMilanka Ringwald 
87f751daa3SMatthias Ringwald btstack_packet_handler_t
88f751daa3SMatthias Ringwald avdtp_packet_handler_for_stream_endpoint(const avdtp_stream_endpoint_t *stream_endpoint) {
89f751daa3SMatthias Ringwald     return (stream_endpoint->sep.type == AVDTP_SOURCE) ? avdtp_source_callback : avdtp_sink_callback;
90f751daa3SMatthias Ringwald }
91f751daa3SMatthias Ringwald 
92c69f4ba5SMatthias Ringwald void avdtp_emit_sink_and_source(uint8_t * packet, uint16_t size){
93c69f4ba5SMatthias Ringwald     if (avdtp_source_callback != NULL){
94c69f4ba5SMatthias Ringwald         (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size);
95c69f4ba5SMatthias Ringwald     }
96c69f4ba5SMatthias Ringwald     if (avdtp_sink_callback != NULL){
97c69f4ba5SMatthias Ringwald         (*avdtp_sink_callback)(HCI_EVENT_PACKET, 0, packet, size);
98c69f4ba5SMatthias Ringwald     }
99c69f4ba5SMatthias Ringwald }
100c69f4ba5SMatthias Ringwald 
1014b7d40bbSMatthias Ringwald void avdtp_emit_source(uint8_t * packet, uint16_t size){
1024b7d40bbSMatthias Ringwald     if (avdtp_source_callback != NULL){
1034b7d40bbSMatthias Ringwald         (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size);
104f751daa3SMatthias Ringwald     }
105f08f4934SMatthias Ringwald }
106f08f4934SMatthias Ringwald 
107f751daa3SMatthias Ringwald btstack_linked_list_t * avdtp_get_stream_endpoints(void){
108137e2954SMatthias Ringwald     return &avdtp_stream_endpoints;
109f751daa3SMatthias Ringwald }
11036da8747SMilanka Ringwald 
11162c4ec82SMilanka Ringwald btstack_linked_list_t * avdtp_get_connections(void){
112137e2954SMatthias Ringwald     return &avdtp_connections;
11362c4ec82SMilanka Ringwald }
11462c4ec82SMilanka Ringwald 
1153ec98973SMatthias Ringwald avdtp_connection_t * avdtp_get_connection_for_bd_addr(bd_addr_t addr){
1165ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
117137e2954SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &avdtp_connections);
1185ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1195ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1205ace758fSMilanka Ringwald         if (memcmp(addr, connection->remote_addr, 6) != 0) continue;
1215ace758fSMilanka Ringwald         return connection;
122b0d75c91SMilanka Ringwald     }
1235ace758fSMilanka Ringwald     return NULL;
124b0d75c91SMilanka Ringwald }
125b0d75c91SMilanka Ringwald 
1265ace758fSMilanka Ringwald  avdtp_connection_t * avdtp_get_connection_for_avdtp_cid(uint16_t avdtp_cid){
1275ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
128137e2954SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &avdtp_connections);
1295ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1305ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1315ace758fSMilanka Ringwald         if (connection->avdtp_cid != avdtp_cid) continue;
1325ace758fSMilanka Ringwald         return connection;
1335ace758fSMilanka Ringwald     }
1345ace758fSMilanka Ringwald     return NULL;
1355ace758fSMilanka Ringwald }
1365ace758fSMilanka Ringwald 
1375ace758fSMilanka Ringwald 
1383338afc0SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_seid(uint16_t seid){
1395ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
140d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1415ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1425ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1435ace758fSMilanka Ringwald         if (stream_endpoint->sep.seid == seid){
1445ace758fSMilanka Ringwald             return stream_endpoint;
1455ace758fSMilanka Ringwald         }
1465ace758fSMilanka Ringwald     }
1475ace758fSMilanka Ringwald     return NULL;
1485ace758fSMilanka Ringwald }
1495ace758fSMilanka Ringwald 
150e121d2c5SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_source_stream_endpoint_for_media_codec_and_type(avdtp_media_codec_type_t codec_type, avdtp_sep_type_t sep_type){
151f24f7543SMatthias Ringwald     btstack_linked_list_iterator_t it;
152f24f7543SMatthias Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
153f24f7543SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
154f24f7543SMatthias Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
155e121d2c5SMatthias Ringwald         if (stream_endpoint->sep.type != sep_type) continue;
15684cef9b8SMatthias Ringwald         if (stream_endpoint->sep.media_type != AVDTP_AUDIO) continue;
157f24f7543SMatthias Ringwald         if (stream_endpoint->sep.capabilities.media_codec.media_codec_type != codec_type) continue;
1587982528cSMatthias Ringwald         if (stream_endpoint->sep.in_use) continue;
159f24f7543SMatthias Ringwald         return stream_endpoint;
160f24f7543SMatthias Ringwald     }
161f24f7543SMatthias Ringwald     return NULL;
162f24f7543SMatthias Ringwald }
163f24f7543SMatthias Ringwald 
164e121d2c5SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_source_stream_endpoint_for_media_codec(avdtp_media_codec_type_t codec_type){
165e121d2c5SMatthias Ringwald     return avdtp_get_source_stream_endpoint_for_media_codec_and_type(codec_type, AVDTP_SOURCE);
166e121d2c5SMatthias Ringwald }
167e121d2c5SMatthias Ringwald 
168e121d2c5SMatthias Ringwald 
16984cef9b8SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_source_stream_endpoint_for_media_codec_other(uint32_t vendor_id, uint16_t codec_id){
17084cef9b8SMatthias Ringwald     btstack_linked_list_iterator_t it;
17184cef9b8SMatthias Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
17284cef9b8SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
17384cef9b8SMatthias Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
17484cef9b8SMatthias Ringwald         if (stream_endpoint->sep.type != AVDTP_SOURCE) continue;
17584cef9b8SMatthias Ringwald         if (stream_endpoint->sep.media_type != AVDTP_AUDIO) continue;
1767982528cSMatthias Ringwald         if (stream_endpoint->sep.in_use) continue;
17784cef9b8SMatthias Ringwald         if (stream_endpoint->sep.capabilities.media_codec.media_codec_type != AVDTP_CODEC_NON_A2DP) continue;
17884cef9b8SMatthias Ringwald         if (stream_endpoint->sep.capabilities.media_codec.media_codec_information_len < 6) continue;
17984cef9b8SMatthias Ringwald         if (little_endian_read_32(stream_endpoint->sep.capabilities.media_codec.media_codec_information, 0) != vendor_id) continue;
180a9207bf9SBjoern Hartmann         if (little_endian_read_16(stream_endpoint->sep.capabilities.media_codec.media_codec_information, 4) != codec_id) continue;
18184cef9b8SMatthias Ringwald         return stream_endpoint;
18284cef9b8SMatthias Ringwald     }
18384cef9b8SMatthias Ringwald     return NULL;
18484cef9b8SMatthias Ringwald }
18584cef9b8SMatthias Ringwald 
186f24f7543SMatthias Ringwald 
1875ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid){
1885ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
189137e2954SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &avdtp_connections);
1905ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1915ace758fSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
1925ace758fSMilanka Ringwald         if (connection->l2cap_signaling_cid != l2cap_cid) continue;
1935ace758fSMilanka Ringwald         return connection;
1945ace758fSMilanka Ringwald     }
1955ace758fSMilanka Ringwald     return NULL;
1965ace758fSMilanka Ringwald }
1975ace758fSMilanka Ringwald 
1986f98b084SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid){
1995ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
200d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
2015ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2025ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
2035ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_media_cid == l2cap_cid){
2045ace758fSMilanka Ringwald             return stream_endpoint;
2055ace758fSMilanka Ringwald         }
2065ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_reporting_cid == l2cap_cid){
2075ace758fSMilanka Ringwald             return stream_endpoint;
2085ace758fSMilanka Ringwald         }
2095ace758fSMilanka Ringwald         if (stream_endpoint->l2cap_recovery_cid == l2cap_cid){
2105ace758fSMilanka Ringwald             return stream_endpoint;
2115ace758fSMilanka Ringwald         }
2125ace758fSMilanka Ringwald     }
2135ace758fSMilanka Ringwald     return NULL;
2145ace758fSMilanka Ringwald }
2155ace758fSMilanka Ringwald 
21619a000d1SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_signaling_cid(uint16_t l2cap_cid){
2175ace758fSMilanka Ringwald     btstack_linked_list_iterator_t it;
218d8e15394SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
2195ace758fSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2205ace758fSMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
2215ace758fSMilanka Ringwald         if (stream_endpoint->connection){
2225ace758fSMilanka Ringwald             if (stream_endpoint->connection->l2cap_signaling_cid == l2cap_cid){
2235ace758fSMilanka Ringwald                 return stream_endpoint;
2245ace758fSMilanka Ringwald             }
2255ace758fSMilanka Ringwald         }
2265ace758fSMilanka Ringwald     }
2275ace758fSMilanka Ringwald     return NULL;
2285ace758fSMilanka Ringwald }
2295ace758fSMilanka Ringwald 
230ab2445a0SMatthias Ringwald uint8_t avdtp_get_next_transaction_label(void){
231137e2954SMatthias Ringwald     avdtp_transaction_id_counter++;
232137e2954SMatthias Ringwald     if (avdtp_transaction_id_counter == 16){
233137e2954SMatthias Ringwald         avdtp_transaction_id_counter = 1;
2345ace758fSMilanka Ringwald     }
235137e2954SMatthias Ringwald     return avdtp_transaction_id_counter;
2365ace758fSMilanka Ringwald }
2375ace758fSMilanka Ringwald 
2385ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_create_connection(bd_addr_t remote_addr, uint16_t cid){
23936da8747SMilanka Ringwald     avdtp_connection_t * connection = btstack_memory_avdtp_connection_get();
24036da8747SMilanka Ringwald     if (!connection){
24136da8747SMilanka Ringwald         log_error("Not enough memory to create connection");
24236da8747SMilanka Ringwald         return NULL;
24336da8747SMilanka Ringwald     }
24436da8747SMilanka Ringwald     connection->state = AVDTP_SIGNALING_CONNECTION_IDLE;
245b1935866SMilanka Ringwald     connection->initiator_transaction_label = avdtp_get_next_transaction_label();
24636da8747SMilanka Ringwald     connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE;
247ffc20ab4SMatthias Ringwald     connection->a2dp_source_config_process.discover_seps = false;
24836da8747SMilanka Ringwald     connection->avdtp_cid = cid;
24936da8747SMilanka Ringwald     (void)memcpy(connection->remote_addr, remote_addr, 6);
25036da8747SMilanka Ringwald 
251137e2954SMatthias Ringwald     btstack_linked_list_add(&avdtp_connections, (btstack_linked_item_t *) connection);
25236da8747SMilanka Ringwald     return connection;
25336da8747SMilanka Ringwald }
25436da8747SMilanka Ringwald 
25536da8747SMilanka Ringwald static uint16_t avdtp_get_next_cid(void){
256af121d54SMilanka Ringwald     if (avdtp_cid_counter == 0xffff) {
2574ccacc40SMilanka Ringwald         avdtp_cid_counter = 1;
258af121d54SMilanka Ringwald     } else {
259af121d54SMilanka Ringwald         avdtp_cid_counter++;
2604ccacc40SMilanka Ringwald     }
2614ccacc40SMilanka Ringwald     return avdtp_cid_counter;
2624ccacc40SMilanka Ringwald }
2634ccacc40SMilanka Ringwald 
264ab2445a0SMatthias Ringwald // Stream Endpoint Identifier are 6-bit
265ab2445a0SMatthias Ringwald static uint8_t avdtp_get_next_local_seid(void){
266ab2445a0SMatthias Ringwald     if (avdtp_stream_endpoints_id_counter >= 0x3f) {
267137e2954SMatthias Ringwald         avdtp_stream_endpoints_id_counter = 1;
268af121d54SMilanka Ringwald     } else {
269137e2954SMatthias Ringwald         avdtp_stream_endpoints_id_counter++;
2704ccacc40SMilanka Ringwald     }
271137e2954SMatthias Ringwald     return avdtp_stream_endpoints_id_counter;
2724ccacc40SMilanka Ringwald }
2734ccacc40SMilanka Ringwald 
2745797104aSMilanka Ringwald static void avdtp_handle_start_sdp_client_query(void * context){
2755797104aSMilanka Ringwald     UNUSED(context);
276b1549ed3SMilanka Ringwald 
27737139939SMatthias Ringwald     uint16_t uuid;
2785797104aSMilanka Ringwald     btstack_linked_list_iterator_t it;
279137e2954SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &avdtp_connections);
2805797104aSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
2815797104aSMilanka Ringwald         avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
2825797104aSMilanka Ringwald 
2835797104aSMilanka Ringwald         switch (connection->state){
2845797104aSMilanka Ringwald             case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE:
28537139939SMatthias Ringwald                 uuid = BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE;
2865797104aSMilanka Ringwald                 connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE;
2875797104aSMilanka Ringwald                 break;
2885797104aSMilanka Ringwald             case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK:
28937139939SMatthias Ringwald                 uuid = BLUETOOTH_SERVICE_CLASS_AUDIO_SINK;
2905797104aSMilanka Ringwald                 connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE;
2915797104aSMilanka Ringwald                 break;
292cc61e7e9SMilanka Ringwald             case AVDTP_SIGNALING_CONNECTION_OPENED:
293e71e31feSMatthias Ringwald                 switch (connection->initiator_connection_state ){
294e71e31feSMatthias Ringwald                     case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES_FROM_REMOTE_SOURCE:
29537139939SMatthias Ringwald                         uuid = BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE;
29637139939SMatthias Ringwald                         connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SDP_QUERY_COMPLETE_THEN_GET_ALL_CAPABILITIES;
29737139939SMatthias Ringwald                         break;
29837139939SMatthias Ringwald                     case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES_FROM_REMOTE_SINK:
29937139939SMatthias Ringwald                         uuid = BLUETOOTH_SERVICE_CLASS_AUDIO_SINK;
300cc61e7e9SMilanka Ringwald                         connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SDP_QUERY_COMPLETE_THEN_GET_ALL_CAPABILITIES;
301cc61e7e9SMilanka Ringwald                         break;
3025797104aSMilanka Ringwald                     default:
3035797104aSMilanka Ringwald                         continue;
3045797104aSMilanka Ringwald                 }
305e71e31feSMatthias Ringwald                 break;
306e71e31feSMatthias Ringwald             default:
307e71e31feSMatthias Ringwald                 continue;
308e71e31feSMatthias Ringwald         }
309137e2954SMatthias Ringwald         avdtp_sdp_query_context_avdtp_cid = connection->avdtp_cid;
310137e2954SMatthias Ringwald         avdtp_record_id = -1;
31137139939SMatthias Ringwald         sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, uuid);
3125797104aSMilanka Ringwald         return;
3135797104aSMilanka Ringwald     }
31484521ac1SMilanka Ringwald }
31584521ac1SMilanka Ringwald 
316a1fb0563SMilanka Ringwald uint8_t avdtp_connect(bd_addr_t remote, avdtp_role_t role, uint16_t * avdtp_cid){
3175ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_bd_addr(remote);
31884521ac1SMilanka Ringwald     if (connection){
3199e974b90SMatthias Ringwald         // allow to call avdtp_connect after signaling connection was triggered remotely
3209e974b90SMatthias Ringwald         // @note this also allows to call avdtp_connect again before SLC is complete
3219e974b90SMatthias Ringwald         if (connection->state < AVDTP_SIGNALING_CONNECTION_OPENED){
3229e974b90SMatthias Ringwald             return ERROR_CODE_SUCCESS;
3239e974b90SMatthias Ringwald         } else {
32484521ac1SMilanka Ringwald             return ERROR_CODE_COMMAND_DISALLOWED;
3254567cc17SMilanka Ringwald         }
3269e974b90SMatthias Ringwald     }
32784521ac1SMilanka Ringwald 
32836da8747SMilanka Ringwald     uint16_t cid = avdtp_get_next_cid();
3292ad6b656SMilanka Ringwald     if (avdtp_cid != NULL) {
33084521ac1SMilanka Ringwald         *avdtp_cid = cid;
3312ad6b656SMilanka Ringwald     }
3322ad6b656SMilanka Ringwald 
3335ace758fSMilanka Ringwald     connection = avdtp_create_connection(remote, cid);
33436da8747SMilanka Ringwald     if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED;
33536da8747SMilanka Ringwald 
33684521ac1SMilanka Ringwald     connection->avdtp_cid = cid;
337b1549ed3SMilanka Ringwald 
3385797104aSMilanka Ringwald     connection->avdtp_l2cap_psm = 0;
3395797104aSMilanka Ringwald     connection->avdtp_version  = 0;
3405797104aSMilanka Ringwald     connection->sink_supported = false;
3415797104aSMilanka Ringwald     connection->source_supported = false;
3425797104aSMilanka Ringwald 
343b1549ed3SMilanka Ringwald     switch (role){
344149deddbSMilanka Ringwald         case AVDTP_ROLE_SOURCE:
3455797104aSMilanka Ringwald             connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK;
346149deddbSMilanka Ringwald             break;
347149deddbSMilanka Ringwald         case AVDTP_ROLE_SINK:
3485797104aSMilanka Ringwald             connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE;
349149deddbSMilanka Ringwald             break;
350149deddbSMilanka Ringwald         default:
3515797104aSMilanka Ringwald             btstack_assert(false);
352149deddbSMilanka Ringwald             return ERROR_CODE_COMMAND_DISALLOWED;
353149deddbSMilanka Ringwald     }
3545797104aSMilanka Ringwald 
3555797104aSMilanka Ringwald     avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query;
3565797104aSMilanka Ringwald     // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
3575797104aSMilanka Ringwald     (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
3585797104aSMilanka Ringwald     return ERROR_CODE_SUCCESS;
359692c0605SMilanka Ringwald }
360747ec646SMilanka Ringwald 
361a1fb0563SMilanka Ringwald 
362a1fb0563SMilanka Ringwald void avdtp_register_sink_packet_handler(btstack_packet_handler_t callback){
363a1fb0563SMilanka Ringwald     btstack_assert(callback != NULL);
364a1fb0563SMilanka Ringwald     avdtp_sink_callback = callback;
365a1fb0563SMilanka Ringwald }
366a1fb0563SMilanka Ringwald 
367a1fb0563SMilanka Ringwald void avdtp_register_source_packet_handler(btstack_packet_handler_t callback){
368a1fb0563SMilanka Ringwald     btstack_assert(callback != NULL);
369a1fb0563SMilanka Ringwald     avdtp_source_callback = callback;
370a1fb0563SMilanka Ringwald }
371a1fb0563SMilanka Ringwald 
372747ec646SMilanka Ringwald void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){
373747ec646SMilanka Ringwald     if (!stream_endpoint){
3749900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
375747ec646SMilanka Ringwald         return;
376747ec646SMilanka Ringwald     }
377747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1);
378747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
379747ec646SMilanka Ringwald }
380747ec646SMilanka Ringwald 
381747ec646SMilanka Ringwald void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){
382747ec646SMilanka Ringwald     if (!stream_endpoint){
3839900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
384747ec646SMilanka Ringwald         return;
385747ec646SMilanka Ringwald     }
386747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_REPORTING, 1);
387747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
388747ec646SMilanka Ringwald }
389747ec646SMilanka Ringwald 
390747ec646SMilanka Ringwald void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){
391747ec646SMilanka Ringwald     if (!stream_endpoint){
3929900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
393747ec646SMilanka Ringwald         return;
394747ec646SMilanka Ringwald     }
395747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_DELAY_REPORTING, 1);
396747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
397747ec646SMilanka Ringwald }
398747ec646SMilanka Ringwald 
399747ec646SMilanka Ringwald void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){
400747ec646SMilanka Ringwald     if (!stream_endpoint){
4019900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
402747ec646SMilanka Ringwald         return;
403747ec646SMilanka Ringwald     }
404747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_RECOVERY, 1);
405747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
406747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.recovery_type = 0x01; // 0x01 = RFC2733
407747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.maximum_recovery_window_size = maximum_recovery_window_size;
408747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.recovery.maximum_number_media_packets = maximum_number_media_packets;
409747ec646SMilanka Ringwald }
410747ec646SMilanka Ringwald 
411747ec646SMilanka 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){
412747ec646SMilanka Ringwald     if (!stream_endpoint){
4139900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
414747ec646SMilanka Ringwald         return;
415747ec646SMilanka Ringwald     }
416747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_CONTENT_PROTECTION, 1);
417747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
418747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.content_protection.cp_type = cp_type;
4196535961aSMatthias Ringwald     (void)memcpy(stream_endpoint->sep.capabilities.content_protection.cp_type_value,
4206535961aSMatthias Ringwald                  cp_type_value,
4216535961aSMatthias Ringwald                  btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN));
42267ae582dSMilanka Ringwald     stream_endpoint->sep.capabilities.content_protection.cp_type_value_len = btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN);
423747ec646SMilanka Ringwald }
424747ec646SMilanka Ringwald 
425747ec646SMilanka Ringwald void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery){
426747ec646SMilanka Ringwald     if (!stream_endpoint){
4279900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
428747ec646SMilanka Ringwald         return;
429747ec646SMilanka Ringwald     }
430747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_HEADER_COMPRESSION, 1);
431747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
432747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.back_ch = back_ch;
433747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.media = media;
434747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.header_compression.recovery = recovery;
435747ec646SMilanka Ringwald }
436747ec646SMilanka Ringwald 
4373e6cf581SMatthias 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){
438747ec646SMilanka Ringwald     if (!stream_endpoint){
4399900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
440747ec646SMilanka Ringwald         return;
441747ec646SMilanka Ringwald     }
442747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1);
443747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
444747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_type = media_type;
445747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type;
4463e6cf581SMatthias Ringwald     // @todo should be stored in struct as const
4473e6cf581SMatthias Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_information = (uint8_t*) media_codec_info;
448747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.media_codec.media_codec_information_len = media_codec_info_len;
449747ec646SMilanka Ringwald }
450747ec646SMilanka Ringwald 
451747ec646SMilanka Ringwald void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation){
452747ec646SMilanka Ringwald     if (!stream_endpoint){
4539900b7faSMilanka Ringwald         log_error("Stream endpoint with given seid is not registered.");
454747ec646SMilanka Ringwald         return;
455747ec646SMilanka Ringwald     }
456747ec646SMilanka Ringwald     uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MULTIPLEXING, 1);
457747ec646SMilanka Ringwald     stream_endpoint->sep.registered_service_categories = bitmap;
458747ec646SMilanka Ringwald     stream_endpoint->sep.capabilities.multiplexing_mode.fragmentation = fragmentation;
459747ec646SMilanka Ringwald }
460747ec646SMilanka Ringwald 
461951d2774SMatthias Ringwald void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size)){
462951d2774SMatthias Ringwald     avdtp_sink_handle_media_data = callback;
463951d2774SMatthias Ringwald }
464747ec646SMilanka Ringwald 
4656a737fb6SMatthias Ringwald void avdtp_sink_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size)){
4666a737fb6SMatthias Ringwald     avdtp_sink_media_config_validator = callback;
4676a737fb6SMatthias Ringwald }
4686a737fb6SMatthias Ringwald 
4696a737fb6SMatthias Ringwald void avdtp_source_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size)){
4706a737fb6SMatthias Ringwald     avdtp_source_media_config_validator = callback;
4711ef2d533SMatthias Ringwald }
4721ef2d533SMatthias Ringwald 
473c70720c6SMatthias Ringwald uint8_t avdtp_validate_media_configuration(const avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid,
474c70720c6SMatthias Ringwald                                            uint8_t reconfigure, const adtvp_media_codec_capabilities_t *media_codec) {
4756a737fb6SMatthias Ringwald     uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size);
4766a737fb6SMatthias Ringwald     if (stream_endpoint->sep.type == AVDTP_SOURCE){
4776a737fb6SMatthias Ringwald         callback = avdtp_source_media_config_validator;
4786a737fb6SMatthias Ringwald     } else {
4796a737fb6SMatthias Ringwald         callback = avdtp_sink_media_config_validator;
4806a737fb6SMatthias Ringwald     }
4816a737fb6SMatthias Ringwald     if (callback == NULL) {
4826a737fb6SMatthias Ringwald         // config valid
4831ef2d533SMatthias Ringwald         return 0;
4841ef2d533SMatthias Ringwald     }
485c70720c6SMatthias Ringwald     uint8_t event[AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN];
486c70720c6SMatthias Ringwald     uint16_t size = avdtp_setup_media_codec_config_event(event, sizeof(event), stream_endpoint, avdtp_cid, reconfigure, media_codec);
4876a737fb6SMatthias Ringwald     return (*callback)(stream_endpoint, event, size);
4881ef2d533SMatthias Ringwald }
4891ef2d533SMatthias Ringwald 
490d80ccd43SMatthias Ringwald /* START: tracking can send now requests per l2cap cid */
491d80ccd43SMatthias Ringwald static void avdtp_handle_can_send_now(uint16_t l2cap_cid) {
492d80ccd43SMatthias Ringwald 
493d80ccd43SMatthias Ringwald 	log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", l2cap_cid);
494d80ccd43SMatthias Ringwald 
495d80ccd43SMatthias Ringwald 	// get signaling connection for l2cap cid
496d80ccd43SMatthias Ringwald 	avdtp_connection_t * connection = avdtp_get_connection_for_l2cap_signaling_cid(l2cap_cid);
497d80ccd43SMatthias Ringwald 
498d80ccd43SMatthias Ringwald 	if (connection != NULL) {
499747ec646SMilanka Ringwald 		if (connection->wait_to_send_acceptor) {
500d80ccd43SMatthias Ringwald 			log_debug("call avdtp_acceptor_stream_config_subsm_run %p", connection);
501d80ccd43SMatthias Ringwald 			connection->wait_to_send_acceptor = false;
50277092f3eSMatthias Ringwald 			avdtp_acceptor_stream_config_subsm_run(connection);
503747ec646SMilanka Ringwald 		} else if (connection->wait_to_send_initiator) {
504d80ccd43SMatthias Ringwald 			log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling %p", connection);
505d80ccd43SMatthias Ringwald 			connection->wait_to_send_initiator = false;
506d80ccd43SMatthias Ringwald 			avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling(connection);
507d80ccd43SMatthias Ringwald 		}
508d80ccd43SMatthias Ringwald 		bool more_to_send = connection->wait_to_send_acceptor || connection->wait_to_send_initiator;
509d80ccd43SMatthias Ringwald 		if (more_to_send){
510d80ccd43SMatthias Ringwald 			l2cap_request_can_send_now_event(l2cap_cid);
511d80ccd43SMatthias Ringwald 		}
512d80ccd43SMatthias Ringwald 		return;
513747ec646SMilanka Ringwald 	}
514747ec646SMilanka Ringwald 
515d80ccd43SMatthias Ringwald 	// get stream endpoint connection for l2cap cid
516d80ccd43SMatthias Ringwald 	avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(l2cap_cid);
517d80ccd43SMatthias Ringwald 	if (stream_endpoint != NULL) {
518d80ccd43SMatthias Ringwald 		log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint %p", stream_endpoint);
519d80ccd43SMatthias Ringwald 		if (stream_endpoint->request_can_send_now) {
520d0676819SMatthias Ringwald 			stream_endpoint->request_can_send_now = false;
521d80ccd43SMatthias Ringwald 			avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint(stream_endpoint);
522d80ccd43SMatthias Ringwald 		}
523d0676819SMatthias Ringwald 		if (stream_endpoint->request_can_send_now){
524747ec646SMilanka Ringwald 			l2cap_request_can_send_now_event(l2cap_cid);
525747ec646SMilanka Ringwald 		}
526747ec646SMilanka Ringwald 	}
527d80ccd43SMatthias Ringwald }
528d80ccd43SMatthias Ringwald /* END: tracking can send now requests per l2cap cid */
529747ec646SMilanka Ringwald 
530747ec646SMilanka Ringwald 
531297feb5fSMilanka Ringwald avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){
532747ec646SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = btstack_memory_avdtp_stream_endpoint_get();
5334567cc17SMilanka Ringwald     if (!stream_endpoint){
5349900b7faSMilanka Ringwald         log_error("Not enough memory to create stream endpoint");
5354567cc17SMilanka Ringwald         return NULL;
5364567cc17SMilanka Ringwald     }
537560b3f31SMilanka Ringwald     stream_endpoint->sep.seid = avdtp_get_next_local_seid();
538747ec646SMilanka Ringwald     stream_endpoint->sep.media_type = media_type;
539747ec646SMilanka Ringwald     stream_endpoint->sep.type = sep_type;
540d8e15394SMilanka Ringwald     btstack_linked_list_add(avdtp_get_stream_endpoints(), (btstack_linked_item_t *) stream_endpoint);
541747ec646SMilanka Ringwald     return stream_endpoint;
542747ec646SMilanka Ringwald }
543747ec646SMilanka Ringwald 
54417ddf501SMatthias Ringwald void avdtp_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){
54517ddf501SMatthias Ringwald     btstack_linked_list_remove(avdtp_get_stream_endpoints(), (btstack_linked_item_t* ) stream_endpoint);
54617ddf501SMatthias Ringwald     btstack_memory_avdtp_stream_endpoint_free(stream_endpoint);
54717ddf501SMatthias Ringwald }
54817ddf501SMatthias Ringwald 
54977092f3eSMatthias Ringwald static void
55077092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t *connection, uint8_t *packet, uint16_t size) {
551c1c40ea1SMatthias Ringwald     if (size < 2) return;
552c1c40ea1SMatthias Ringwald 
553c1c40ea1SMatthias Ringwald     uint16_t offset;
554*335dba6aSMatthias Ringwald     avdtp_message_type_t message_type = avdtp_get_signaling_message_type(packet);
555c1c40ea1SMatthias Ringwald     switch (message_type){
556747ec646SMilanka Ringwald         case AVDTP_CMD_MSG:
55750453b92SMatthias Ringwald             offset = avdtp_read_signaling_header(&connection->acceptor_signaling_packet, packet, size);
55877092f3eSMatthias Ringwald             avdtp_acceptor_stream_config_subsm(connection, packet, size, offset);
559747ec646SMilanka Ringwald             break;
560747ec646SMilanka Ringwald         default:
56150453b92SMatthias Ringwald             offset = avdtp_read_signaling_header(&connection->initiator_signaling_packet, packet, size);
56277092f3eSMatthias Ringwald             avdtp_initiator_stream_config_subsm(connection, packet, size, offset);
563747ec646SMilanka Ringwald             break;
564747ec646SMilanka Ringwald     }
565747ec646SMilanka Ringwald }
566747ec646SMilanka Ringwald 
567b1549ed3SMilanka Ringwald static void avdtp_handle_sdp_client_query_attribute_value(avdtp_connection_t * connection, uint8_t *packet){
568692c0605SMilanka Ringwald     des_iterator_t des_list_it;
569692c0605SMilanka Ringwald     des_iterator_t prot_it;
570692c0605SMilanka Ringwald 
571692c0605SMilanka Ringwald     // Handle new SDP record
572137e2954SMatthias Ringwald     if (sdp_event_query_attribute_byte_get_record_id(packet) != avdtp_record_id) {
573137e2954SMatthias Ringwald         avdtp_record_id = sdp_event_query_attribute_byte_get_record_id(packet);
5748587e32cSMilanka Ringwald         // log_info("SDP Record: Nr: %d", record_id);
575692c0605SMilanka Ringwald     }
576692c0605SMilanka Ringwald 
577137e2954SMatthias Ringwald     if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= avdtp_attribute_value_buffer_size) {
578137e2954SMatthias Ringwald         avdtp_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
579692c0605SMilanka Ringwald 
580692c0605SMilanka Ringwald         if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) {
581692c0605SMilanka Ringwald 
582692c0605SMilanka Ringwald             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
583149deddbSMilanka Ringwald 
584692c0605SMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST:
585137e2954SMatthias Ringwald                     if (de_get_element_type(avdtp_attribute_value) != DE_DES) break;
586137e2954SMatthias Ringwald                     for (des_iterator_init(&des_list_it, avdtp_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
587692c0605SMilanka Ringwald                         uint8_t * element = des_iterator_get_element(&des_list_it);
588692c0605SMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
589692c0605SMilanka Ringwald                         uint32_t uuid = de_get_uuid32(element);
590692c0605SMilanka Ringwald                         switch (uuid){
591692c0605SMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE:
592b1549ed3SMilanka Ringwald                                 connection->source_supported = true;
593149deddbSMilanka Ringwald                                 log_info("source_supported");
594692c0605SMilanka Ringwald                                 break;
595692c0605SMilanka Ringwald                             case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK:
596b1549ed3SMilanka Ringwald                                 connection->sink_supported = true;
597149deddbSMilanka Ringwald                                 log_info("sink_supported");
598692c0605SMilanka Ringwald                                 break;
599692c0605SMilanka Ringwald                             default:
600692c0605SMilanka Ringwald                                 break;
601692c0605SMilanka Ringwald                         }
602692c0605SMilanka Ringwald                     }
603692c0605SMilanka Ringwald                     break;
604692c0605SMilanka Ringwald 
605149deddbSMilanka Ringwald                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
6068587e32cSMilanka Ringwald                     // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet));
607137e2954SMatthias Ringwald                     for (des_iterator_init(&des_list_it, avdtp_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
608692c0605SMilanka Ringwald                         uint8_t       *des_element;
609692c0605SMilanka Ringwald                         uint8_t       *element;
610692c0605SMilanka Ringwald                         uint32_t       uuid;
611692c0605SMilanka Ringwald 
612692c0605SMilanka Ringwald                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
613692c0605SMilanka Ringwald 
614692c0605SMilanka Ringwald                         des_element = des_iterator_get_element(&des_list_it);
615692c0605SMilanka Ringwald                         des_iterator_init(&prot_it, des_element);
616692c0605SMilanka Ringwald                         element = des_iterator_get_element(&prot_it);
617692c0605SMilanka Ringwald 
618692c0605SMilanka Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
619692c0605SMilanka Ringwald 
620692c0605SMilanka Ringwald                         uuid = de_get_uuid32(element);
62114fd128cSMatthias Ringwald                         des_iterator_next(&prot_it);
622149deddbSMilanka Ringwald                         // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both
623692c0605SMilanka Ringwald                         switch (uuid){
624692c0605SMilanka Ringwald                             case BLUETOOTH_PROTOCOL_L2CAP:
625692c0605SMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
626b1549ed3SMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_l2cap_psm);
627692c0605SMilanka Ringwald                                 break;
628692c0605SMilanka Ringwald                             case BLUETOOTH_PROTOCOL_AVDTP:
629692c0605SMilanka Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
630b1549ed3SMilanka Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_version);
631cc61e7e9SMilanka Ringwald                                 log_info("avdtp version 0x%02x", connection->avdtp_version);
632692c0605SMilanka Ringwald                                 break;
633692c0605SMilanka Ringwald                             default:
634692c0605SMilanka Ringwald                                 break;
635692c0605SMilanka Ringwald                         }
636692c0605SMilanka Ringwald                     }
637692c0605SMilanka Ringwald                     break;
638149deddbSMilanka Ringwald 
639692c0605SMilanka Ringwald                 default:
640692c0605SMilanka Ringwald                     break;
641692c0605SMilanka Ringwald             }
642692c0605SMilanka Ringwald         }
643692c0605SMilanka Ringwald     } else {
644137e2954SMatthias Ringwald         log_error("SDP attribute value buffer size exceeded: available %d, required %d", avdtp_attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet));
645692c0605SMilanka Ringwald     }
6466ed344c3SMatthias Ringwald 
6476ed344c3SMatthias Ringwald }
6486ed344c3SMatthias Ringwald 
6495ace758fSMilanka Ringwald static void avdtp_finalize_connection(avdtp_connection_t * connection){
650ff53b162SMilanka Ringwald     btstack_run_loop_remove_timer(&connection->retry_timer);
651137e2954SMatthias Ringwald     btstack_linked_list_remove(&avdtp_connections, (btstack_linked_item_t*) connection);
652f0c39502SMilanka Ringwald     btstack_memory_avdtp_connection_free(connection);
653f0c39502SMilanka Ringwald }
654f0c39502SMilanka Ringwald 
655f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_failed(avdtp_connection_t * connection, uint8_t status){
656a1fb0563SMilanka Ringwald     switch (connection->state){
657a1fb0563SMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE:
658a1fb0563SMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE:
659146fc0fbSMilanka Ringwald             avdtp_signaling_emit_connection_established(connection->avdtp_cid, connection->remote_addr, connection->con_handle, status);
660a1fb0563SMilanka Ringwald             break;
661cc61e7e9SMilanka Ringwald 
662cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
663cc61e7e9SMilanka Ringwald             // SDP query failed: try query that must be supported
664cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
665d80ccd43SMatthias Ringwald 			avdtp_request_can_send_now_initiator(connection);
666a1fb0563SMilanka Ringwald             return;
667cc61e7e9SMilanka Ringwald 
668cc61e7e9SMilanka Ringwald         default:
669cc61e7e9SMilanka Ringwald             btstack_assert(false);
670cc61e7e9SMilanka Ringwald             break;
671a1fb0563SMilanka Ringwald     }
6725ace758fSMilanka Ringwald     avdtp_finalize_connection(connection);
673137e2954SMatthias Ringwald     avdtp_sdp_query_context_avdtp_cid = 0;
674f0c39502SMilanka Ringwald     log_info("SDP query failed with status 0x%02x.", status);
675f0c39502SMilanka Ringwald }
676f0c39502SMilanka Ringwald 
677f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){
678cc61e7e9SMilanka Ringwald     log_info("avdtp_handle_sdp_query_succeeded: state %d", connection->state);
679cc61e7e9SMilanka Ringwald 
680cc61e7e9SMilanka Ringwald     switch (connection->state){
681cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
682cc61e7e9SMilanka Ringwald             if (connection->avdtp_version < 0x0103){
683cc61e7e9SMilanka Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
684cc61e7e9SMilanka Ringwald             } else {
685cc61e7e9SMilanka Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES;
686cc61e7e9SMilanka Ringwald             }
687d80ccd43SMatthias Ringwald 			avdtp_request_can_send_now_initiator(connection);
688cc61e7e9SMilanka Ringwald             break;
689cc61e7e9SMilanka Ringwald         default:
690f0c39502SMilanka Ringwald             connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
6918366bc41SMatthias Ringwald             l2cap_create_channel(avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, AVDTP_L2CAP_MTU, NULL);
692cc61e7e9SMilanka Ringwald             break;
693cc61e7e9SMilanka Ringwald     }
694f0c39502SMilanka Ringwald }
695f0c39502SMilanka Ringwald 
6966ed344c3SMatthias Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
697149deddbSMilanka Ringwald     UNUSED(packet_type);
698149deddbSMilanka Ringwald     UNUSED(channel);
699149deddbSMilanka Ringwald     UNUSED(size);
700149deddbSMilanka Ringwald 
701137e2954SMatthias Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_sdp_query_context_avdtp_cid);
7026ed344c3SMatthias Ringwald     if (!connection) {
703137e2954SMatthias Ringwald         log_error("SDP query, connection with 0x%02x cid not found", avdtp_sdp_query_context_avdtp_cid);
7046ed344c3SMatthias Ringwald         return;
7056ed344c3SMatthias Ringwald     }
7066ed344c3SMatthias Ringwald 
707722c03bdSMatthias Ringwald     uint8_t status = ERROR_CODE_SUCCESS;
708149deddbSMilanka Ringwald     switch (connection->state){
709149deddbSMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE:
7106ed344c3SMatthias Ringwald             switch (hci_event_packet_get_type(packet)){
7116ed344c3SMatthias Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
712b1549ed3SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
713149deddbSMilanka Ringwald                     return;
714692c0605SMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
7151e1ae2bcSMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
716149deddbSMilanka Ringwald                     if (status != ERROR_CODE_SUCCESS) break;
717cc92f22bSMatthias Ringwald                     if (!connection->sink_supported || (connection->avdtp_l2cap_psm == 0)) {
718cc92f22bSMatthias Ringwald                         status = SDP_SERVICE_NOT_FOUND;
719722c03bdSMatthias Ringwald                         break;
720722c03bdSMatthias Ringwald                     }
721149deddbSMilanka Ringwald                     break;
722149deddbSMilanka Ringwald                 default:
723149deddbSMilanka Ringwald                     btstack_assert(false);
724722c03bdSMatthias Ringwald                     return;
7251e1ae2bcSMilanka Ringwald             }
726149deddbSMilanka Ringwald             break;
727149deddbSMilanka Ringwald         case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE:
728149deddbSMilanka Ringwald             switch (hci_event_packet_get_type(packet)){
729149deddbSMilanka Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
730b1549ed3SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
731149deddbSMilanka Ringwald                     return;
732149deddbSMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
733149deddbSMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
734149deddbSMilanka Ringwald                     if (status != ERROR_CODE_SUCCESS) break;
735cc92f22bSMatthias Ringwald                     if (!connection->source_supported || (connection->avdtp_l2cap_psm == 0)) {
736cc92f22bSMatthias Ringwald                         status = SDP_SERVICE_NOT_FOUND;
737722c03bdSMatthias Ringwald                         break;
738722c03bdSMatthias Ringwald                     }
739149deddbSMilanka Ringwald                     break;
740149deddbSMilanka Ringwald                 default:
741149deddbSMilanka Ringwald                     btstack_assert(false);
742722c03bdSMatthias Ringwald                     return;
743974d4d6eSMilanka Ringwald             }
7442f6083d0SMilanka Ringwald             break;
745cc61e7e9SMilanka Ringwald 
746cc61e7e9SMilanka Ringwald         case AVDTP_SIGNALING_CONNECTION_OPENED:
747cc61e7e9SMilanka Ringwald             switch (hci_event_packet_get_type(packet)){
748cc61e7e9SMilanka Ringwald                 case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
749cc61e7e9SMilanka Ringwald                     avdtp_handle_sdp_client_query_attribute_value(connection, packet);
750cc61e7e9SMilanka Ringwald                     return;
751cc61e7e9SMilanka Ringwald                 case SDP_EVENT_QUERY_COMPLETE:
752cc92f22bSMatthias Ringwald                     // without suitable SDP Record, avdtp version v0.0 is assumed
753cc61e7e9SMilanka Ringwald                     status = sdp_event_query_complete_get_status(packet);
754cc61e7e9SMilanka Ringwald                     break;
755cc61e7e9SMilanka Ringwald                 default:
756cc61e7e9SMilanka Ringwald                     btstack_assert(false);
757cc61e7e9SMilanka Ringwald                     return;
758cc61e7e9SMilanka Ringwald             }
759cc61e7e9SMilanka Ringwald             break;
760cc61e7e9SMilanka Ringwald 
761149deddbSMilanka Ringwald         default:
76208cb850dSMilanka Ringwald             // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete
76308cb850dSMilanka Ringwald             if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){
76408cb850dSMilanka Ringwald                 (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
76508cb850dSMilanka Ringwald             }
766149deddbSMilanka Ringwald             return;
7672f6083d0SMilanka Ringwald     }
768f0c39502SMilanka Ringwald 
769722c03bdSMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
770149deddbSMilanka Ringwald         avdtp_handle_sdp_query_succeeded(connection);
771149deddbSMilanka Ringwald     } else {
772149deddbSMilanka Ringwald         avdtp_handle_sdp_query_failed(connection, status);
773692c0605SMilanka Ringwald     }
7745797104aSMilanka Ringwald 
7755797104aSMilanka Ringwald     // register the SDP Query request to check if there is another connection waiting for the query
7765797104aSMilanka Ringwald     // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
7775797104aSMilanka Ringwald     (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
778692c0605SMilanka Ringwald }
779692c0605SMilanka Ringwald 
780146fc0fbSMilanka 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){
78136da8747SMilanka Ringwald     if (connection == NULL){
78236da8747SMilanka Ringwald         uint16_t cid = avdtp_get_next_cid();
7835ace758fSMilanka Ringwald         connection = avdtp_create_connection(event_addr, cid);
78436da8747SMilanka Ringwald     }
785692c0605SMilanka Ringwald 
78636da8747SMilanka Ringwald     if (connection) {
78736da8747SMilanka Ringwald         connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
78836da8747SMilanka Ringwald         connection->l2cap_signaling_cid = local_cid;
789146fc0fbSMilanka Ringwald         connection->con_handle = con_handle;
790ff53b162SMilanka Ringwald         btstack_run_loop_remove_timer(&connection->retry_timer);
79136da8747SMilanka Ringwald     }
79236da8747SMilanka Ringwald     return connection;
79336da8747SMilanka Ringwald }
794f0c39502SMilanka Ringwald 
795ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){
796326e3662SMilanka Ringwald     uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer);
797326e3662SMilanka Ringwald 
7985ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
799326e3662SMilanka Ringwald     if (connection == NULL) return;
800326e3662SMilanka Ringwald 
801ff53b162SMilanka Ringwald     if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){
802326e3662SMilanka Ringwald         connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED;
803b9fe4fc7SMatthias Ringwald         l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, AVDTP_L2CAP_MTU, NULL);
804326e3662SMilanka Ringwald     }
805326e3662SMilanka Ringwald }
806326e3662SMilanka Ringwald 
807ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){
808ff53b162SMilanka Ringwald     btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler);
809ff53b162SMilanka Ringwald     btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid);
810326e3662SMilanka Ringwald 
811326e3662SMilanka Ringwald     // add some jitter/randomness to reconnect delay
812326e3662SMilanka Ringwald     uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F);
813ff53b162SMilanka Ringwald     btstack_run_loop_set_timer(&connection->retry_timer, timeout);
814ff53b162SMilanka Ringwald     btstack_run_loop_add_timer(&connection->retry_timer);
815326e3662SMilanka Ringwald }
816326e3662SMilanka Ringwald 
81739a45651SMatthias Ringwald static void avdtp_handle_close_media_channel(avdtp_stream_endpoint_t * stream_endpoint){
81839a45651SMatthias Ringwald     avdtp_connection_t * connection = stream_endpoint->connection;
81939a45651SMatthias Ringwald     btstack_assert(connection != NULL);
82039a45651SMatthias Ringwald     avdtp_streaming_emit_connection_released(stream_endpoint, connection->avdtp_cid, avdtp_local_seid(stream_endpoint));
82139a45651SMatthias Ringwald     avdtp_reset_stream_endpoint(stream_endpoint);
82239a45651SMatthias Ringwald     connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE;
82339a45651SMatthias Ringwald }
82439a45651SMatthias Ringwald 
82539a45651SMatthias Ringwald static void avdtp_handle_close_recovery_channel(avdtp_stream_endpoint_t * stream_endpoint){
82639a45651SMatthias Ringwald     log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", stream_endpoint->l2cap_recovery_cid);
82739a45651SMatthias Ringwald     stream_endpoint->l2cap_recovery_cid = 0;
82839a45651SMatthias Ringwald }
82939a45651SMatthias Ringwald 
83039a45651SMatthias Ringwald static void avdtp_handle_close_reporting_channel(avdtp_stream_endpoint_t * stream_endpoint){
83139a45651SMatthias Ringwald     log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", stream_endpoint->l2cap_reporting_cid);
83239a45651SMatthias Ringwald     stream_endpoint->l2cap_reporting_cid = 0;
83339a45651SMatthias Ringwald }
83439a45651SMatthias Ringwald 
835326e3662SMilanka Ringwald 
836326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
837747ec646SMilanka Ringwald     bd_addr_t event_addr;
838747ec646SMilanka Ringwald     uint16_t psm;
839747ec646SMilanka Ringwald     uint16_t local_cid;
8401e1ae2bcSMilanka Ringwald     uint8_t  status;
841326e3662SMilanka Ringwald     uint16_t l2cap_mtu;
842146fc0fbSMilanka Ringwald     hci_con_handle_t con_handle;
84336da8747SMilanka Ringwald 
84436da8747SMilanka Ringwald     bool accept_streaming_connection;
84536da8747SMilanka Ringwald     bool outoing_signaling_active;
84636da8747SMilanka Ringwald     bool decline_connection;
84784521ac1SMilanka Ringwald 
848747ec646SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = NULL;
849747ec646SMilanka Ringwald     avdtp_connection_t * connection = NULL;
85036da8747SMilanka Ringwald 
851747ec646SMilanka Ringwald     switch (packet_type) {
852747ec646SMilanka Ringwald         case L2CAP_DATA_PACKET:
8535ace758fSMilanka Ringwald             connection = avdtp_get_connection_for_l2cap_signaling_cid(channel);
854747ec646SMilanka Ringwald             if (connection){
85577092f3eSMatthias Ringwald                 handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);
856747ec646SMilanka Ringwald                 break;
857747ec646SMilanka Ringwald             }
858747ec646SMilanka Ringwald 
8596f98b084SMilanka Ringwald             stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel);
860747ec646SMilanka Ringwald             if (!stream_endpoint){
861747ec646SMilanka Ringwald                 if (!connection) break;
86277092f3eSMatthias Ringwald                 handle_l2cap_data_packet_for_signaling_connection(connection, packet, size);
863747ec646SMilanka Ringwald                 break;
864747ec646SMilanka Ringwald             }
865747ec646SMilanka Ringwald 
8668c0f3635SMilanka Ringwald             if (stream_endpoint->connection){
8679413b167SMilanka Ringwald                 if (channel == stream_endpoint->connection->l2cap_signaling_cid){
86877092f3eSMatthias Ringwald                     handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size);
869747ec646SMilanka Ringwald                     break;
870747ec646SMilanka Ringwald                 }
8718c0f3635SMilanka Ringwald             }
872747ec646SMilanka Ringwald 
873747ec646SMilanka Ringwald             if (channel == stream_endpoint->l2cap_media_cid){
874951d2774SMatthias Ringwald                 btstack_assert(avdtp_sink_handle_media_data);
875951d2774SMatthias Ringwald                 (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size);
876747ec646SMilanka Ringwald                 break;
877747ec646SMilanka Ringwald             }
878747ec646SMilanka Ringwald 
879747ec646SMilanka Ringwald             if (channel == stream_endpoint->l2cap_reporting_cid){
8808587e32cSMilanka Ringwald                 log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED");
881747ec646SMilanka Ringwald             } else if (channel == stream_endpoint->l2cap_recovery_cid){
8828587e32cSMilanka Ringwald                 log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED");
883747ec646SMilanka Ringwald             } else {
884747ec646SMilanka Ringwald                 log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel);
885747ec646SMilanka Ringwald             }
886747ec646SMilanka Ringwald             break;
887747ec646SMilanka Ringwald 
888747ec646SMilanka Ringwald         case HCI_EVENT_PACKET:
889747ec646SMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
89036da8747SMilanka Ringwald 
891747ec646SMilanka Ringwald                 case L2CAP_EVENT_INCOMING_CONNECTION:
892747ec646SMilanka Ringwald                     l2cap_event_incoming_connection_get_address(packet, event_addr);
893747ec646SMilanka Ringwald                     local_cid = l2cap_event_incoming_connection_get_local_cid(packet);
894146fc0fbSMilanka Ringwald                     con_handle = l2cap_event_incoming_connection_get_handle(packet);
89536da8747SMilanka Ringwald                     outoing_signaling_active = false;
89636da8747SMilanka Ringwald                     accept_streaming_connection = false;
89736da8747SMilanka Ringwald 
8985ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_bd_addr(event_addr);
89936da8747SMilanka Ringwald                     if (connection != NULL){
9000d4a198eSMatthias Ringwald                         switch (connection->state){
9010d4a198eSMatthias Ringwald                             case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED:
90236da8747SMilanka Ringwald                             case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED:
90336da8747SMilanka Ringwald                                 outoing_signaling_active = true;
90436da8747SMilanka Ringwald                                 connection->incoming_declined = true;
90536da8747SMilanka Ringwald                                 break;
90636da8747SMilanka Ringwald                             case AVDTP_SIGNALING_CONNECTION_OPENED:
90736da8747SMilanka Ringwald                                 outoing_signaling_active = true;
90836da8747SMilanka Ringwald                                 accept_streaming_connection = true;
90936da8747SMilanka Ringwald                                 break;
910f0c39502SMilanka Ringwald                             default:
911f0c39502SMilanka Ringwald                                 break;
9120d4a198eSMatthias Ringwald                         }
913747ec646SMilanka Ringwald                     }
91436da8747SMilanka Ringwald                     log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d",
91536da8747SMilanka Ringwald                         bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection);
916747ec646SMilanka Ringwald 
91736da8747SMilanka Ringwald                     decline_connection = outoing_signaling_active && !accept_streaming_connection;
91836da8747SMilanka Ringwald                     if (outoing_signaling_active == false){
919146fc0fbSMilanka Ringwald                         connection = avdtp_handle_incoming_connection(connection, event_addr, con_handle, local_cid);
92036da8747SMilanka Ringwald                         if (connection == NULL){
92136da8747SMilanka Ringwald                             decline_connection = true;
92236da8747SMilanka Ringwald                         }
92336da8747SMilanka Ringwald                     } else if (accept_streaming_connection){
92436da8747SMilanka Ringwald                         if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) {
92536da8747SMilanka Ringwald                             decline_connection = true;
92636da8747SMilanka Ringwald                         } else {
927939e12adSMatthias Ringwald                             // now, we're only dealing with media connections that are created by remote side - we're acceptor here
9283338afc0SMatthias Ringwald                             stream_endpoint = avdtp_get_stream_endpoint_for_seid(connection->acceptor_local_seid);
92936da8747SMilanka Ringwald                             if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) {
93036da8747SMilanka Ringwald                                 decline_connection = true;
93136da8747SMilanka Ringwald                             }
93236da8747SMilanka Ringwald                         }
933747ec646SMilanka Ringwald                     }
934747ec646SMilanka Ringwald 
93536da8747SMilanka Ringwald                     if (decline_connection){
936a3ce0109SMatthias Ringwald                         l2cap_decline_connection(local_cid);
93736da8747SMilanka Ringwald                     } else {
938747ec646SMilanka Ringwald                         l2cap_accept_connection(local_cid);
93936da8747SMilanka Ringwald                     }
940747ec646SMilanka Ringwald                     break;
941747ec646SMilanka Ringwald 
942747ec646SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
943a5114819SMilanka Ringwald 
944a0b8a58cSMilanka Ringwald                     psm = l2cap_event_channel_opened_get_psm(packet);
94584e3541eSMilanka Ringwald                     if (psm != BLUETOOTH_PSM_AVDTP){
946355ac553SMilanka Ringwald                         log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED ");
947a0b8a58cSMilanka Ringwald                         return;
948a0b8a58cSMilanka Ringwald                     }
949a0b8a58cSMilanka Ringwald 
9501e1ae2bcSMilanka Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
951747ec646SMilanka Ringwald                     // inform about new l2cap connection
952747ec646SMilanka Ringwald                     l2cap_event_channel_opened_get_address(packet, event_addr);
9537050d2caSMilanka Ringwald                     local_cid = l2cap_event_channel_opened_get_local_cid(packet);
954326e3662SMilanka Ringwald                     l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet);
9555ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_bd_addr(event_addr);
95636da8747SMilanka Ringwald                     if (connection == NULL){
95736da8747SMilanka Ringwald                         log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr));
958a0b8a58cSMilanka Ringwald                         break;
959a0b8a58cSMilanka Ringwald                     }
960a0b8a58cSMilanka Ringwald 
961146fc0fbSMilanka Ringwald                     con_handle = l2cap_event_channel_opened_get_handle(packet);
962146fc0fbSMilanka Ringwald 
963a5114819SMilanka Ringwald                     switch (connection->state){
964a5114819SMilanka Ringwald                         case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED:
965326e3662SMilanka Ringwald                             switch (status){
966326e3662SMilanka Ringwald                                 case ERROR_CODE_SUCCESS:
967326e3662SMilanka Ringwald                                     connection->l2cap_signaling_cid = local_cid;
968326e3662SMilanka Ringwald                                     connection->incoming_declined = false;
969326e3662SMilanka Ringwald                                     connection->l2cap_mtu = l2cap_mtu;
970146fc0fbSMilanka Ringwald                                     connection->con_handle = con_handle;
971326e3662SMilanka Ringwald                                     connection->state = AVDTP_SIGNALING_CONNECTION_OPENED;
972146fc0fbSMilanka 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);
973146fc0fbSMilanka Ringwald                                     avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status);
974326e3662SMilanka Ringwald                                     return;
975326e3662SMilanka Ringwald                                 case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES:
976326e3662SMilanka Ringwald                                     if (connection->incoming_declined == true) {
977326e3662SMilanka Ringwald                                         log_info("Connection was declined, and the outgoing failed");
978ff53b162SMilanka Ringwald                                         connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY;
979326e3662SMilanka Ringwald                                         connection->incoming_declined = false;
980ff53b162SMilanka Ringwald                                         avdtp_retry_timer_start(connection);
981326e3662SMilanka Ringwald                                         return;
982326e3662SMilanka Ringwald                                     }
983326e3662SMilanka Ringwald                                     break;
984326e3662SMilanka Ringwald                                 default:
985326e3662SMilanka Ringwald                                     log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status);
986326e3662SMilanka Ringwald                                     break;
987326e3662SMilanka Ringwald                             }
988146fc0fbSMilanka Ringwald                             avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status);
989f82b60efSMilanka Ringwald                             avdtp_finalize_connection(connection);
990a0b8a58cSMilanka Ringwald                             break;
991747ec646SMilanka Ringwald 
992a5114819SMilanka Ringwald                         case AVDTP_SIGNALING_CONNECTION_OPENED:
99319a000d1SMilanka Ringwald                             stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid);
994747ec646SMilanka Ringwald                             if (!stream_endpoint){
9955bd73fa2SMatthias Ringwald                                 log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid);
996747ec646SMilanka Ringwald                                 return;
997747ec646SMilanka Ringwald                             }
998326e3662SMilanka Ringwald                             if (status != ERROR_CODE_SUCCESS){
999355ac553SMilanka 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));
1000a466d508SMilanka Ringwald                                 stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
1001f751daa3SMatthias Ringwald                                 avdtp_streaming_emit_connection_established(stream_endpoint, status);
1002a466d508SMilanka Ringwald                                 break;
1003a466d508SMilanka Ringwald                             }
1004a5114819SMilanka Ringwald                             switch (stream_endpoint->state){
1005a5114819SMilanka Ringwald                                 case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED:
1006a466d508SMilanka Ringwald                                     stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
1007a466d508SMilanka Ringwald                                     stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet);
1008a466d508SMilanka Ringwald                                     stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet);
1009d1207cd8SMilanka Ringwald 
1010355ac553SMilanka 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));
1011f751daa3SMatthias Ringwald                                     avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS);
1012a5114819SMilanka Ringwald                                     break;
1013a5114819SMilanka Ringwald                                 default:
1014a5114819SMilanka 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));
101523edb87eSMilanka Ringwald                                     avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_COMMAND_DISALLOWED);
1016a5114819SMilanka Ringwald                                     break;
1017a5114819SMilanka Ringwald                             }
1018a5114819SMilanka Ringwald                             break;
1019a5114819SMilanka Ringwald 
1020a5114819SMilanka Ringwald                         default:
1021326e3662SMilanka Ringwald                             log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state);
1022a5114819SMilanka Ringwald                             break;
1023a5114819SMilanka Ringwald                     }
1024747ec646SMilanka Ringwald                     break;
1025747ec646SMilanka Ringwald 
1026747ec646SMilanka Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
1027747ec646SMilanka Ringwald                     local_cid = l2cap_event_channel_closed_get_local_cid(packet);
10286f98b084SMilanka Ringwald                     stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid);
10295ace758fSMilanka Ringwald                     connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid);
103036da8747SMilanka Ringwald 
1031f01aeca4SMilanka Ringwald                     log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint);
1032f01aeca4SMilanka Ringwald 
1033a466d508SMilanka Ringwald                     if (stream_endpoint){
1034a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_media_cid == local_cid){
103539a45651SMatthias Ringwald                             avdtp_handle_close_media_channel(stream_endpoint);
1036a466d508SMilanka Ringwald                             break;
1037a466d508SMilanka Ringwald                         }
1038a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_recovery_cid == local_cid){
103939a45651SMatthias Ringwald                             avdtp_handle_close_recovery_channel(stream_endpoint);
1040a466d508SMilanka Ringwald                             break;
1041a466d508SMilanka Ringwald                         }
1042a466d508SMilanka Ringwald                         if (stream_endpoint->l2cap_reporting_cid == local_cid){
104339a45651SMatthias Ringwald                             avdtp_handle_close_reporting_channel(stream_endpoint);
1044a466d508SMilanka Ringwald                             break;
1045a466d508SMilanka Ringwald                         }
1046a466d508SMilanka Ringwald                     }
1047596b7fdcSMilanka Ringwald 
1048596b7fdcSMilanka Ringwald                     if (connection){
1049535ff088SMatthias Ringwald                         // closing signaling channel invalidates all other channels as well
1050596b7fdcSMilanka Ringwald                         btstack_linked_list_iterator_t it;
1051d8e15394SMilanka Ringwald                         btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1052596b7fdcSMilanka Ringwald                         while (btstack_linked_list_iterator_has_next(&it)){
1053f01aeca4SMilanka Ringwald                             stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1054f01aeca4SMilanka Ringwald                             if (stream_endpoint->connection == connection){
1055535ff088SMatthias Ringwald                                 avdtp_handle_close_recovery_channel(stream_endpoint);
1056535ff088SMatthias Ringwald                                 avdtp_handle_close_reporting_channel(stream_endpoint);
1057535ff088SMatthias Ringwald                                 avdtp_handle_close_media_channel(stream_endpoint);
1058f01aeca4SMilanka Ringwald                                 avdtp_reset_stream_endpoint(stream_endpoint);
1059596b7fdcSMilanka Ringwald                             }
1060596b7fdcSMilanka Ringwald                         }
1061c69f4ba5SMatthias Ringwald                         avdtp_signaling_emit_connection_released(connection->avdtp_cid);
10625ace758fSMilanka Ringwald                         avdtp_finalize_connection(connection);
1063596b7fdcSMilanka Ringwald                         break;
1064596b7fdcSMilanka Ringwald                     }
1065747ec646SMilanka Ringwald                     break;
1066747ec646SMilanka Ringwald 
1067747ec646SMilanka Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
1068c6bc5965SMilanka Ringwald                     log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel);
1069d80ccd43SMatthias Ringwald 					avdtp_handle_can_send_now(channel);
1070747ec646SMilanka Ringwald                     break;
1071747ec646SMilanka Ringwald                 default:
1072355ac553SMilanka Ringwald                     log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet));
1073747ec646SMilanka Ringwald                     break;
1074747ec646SMilanka Ringwald             }
1075747ec646SMilanka Ringwald             break;
1076747ec646SMilanka Ringwald 
1077747ec646SMilanka Ringwald         default:
1078747ec646SMilanka Ringwald             // other packet type
1079747ec646SMilanka Ringwald             break;
1080747ec646SMilanka Ringwald     }
1081747ec646SMilanka Ringwald }
1082747ec646SMilanka Ringwald 
1083b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){
10845ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
108523edb87eSMilanka Ringwald     if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1086b401ff59SMilanka Ringwald 
1087a466d508SMilanka Ringwald     if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS;
1088747ec646SMilanka Ringwald 
1089f01aeca4SMilanka Ringwald     btstack_linked_list_iterator_t it;
1090f01aeca4SMilanka Ringwald     btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints());
1091f01aeca4SMilanka Ringwald 
1092f01aeca4SMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1093f01aeca4SMilanka Ringwald         avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it);
1094f01aeca4SMilanka Ringwald         if (stream_endpoint->connection != connection) continue;
1095f01aeca4SMilanka Ringwald 
1096f01aeca4SMilanka Ringwald         switch (stream_endpoint->state){
1097f01aeca4SMilanka Ringwald             case AVDTP_STREAM_ENDPOINT_OPENED:
1098f01aeca4SMilanka Ringwald             case AVDTP_STREAM_ENDPOINT_STREAMING:
1099f01aeca4SMilanka Ringwald                 stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED;
1100b93f8966SMatthias Ringwald                 l2cap_disconnect(stream_endpoint->l2cap_media_cid);
1101f01aeca4SMilanka Ringwald                 break;
1102f01aeca4SMilanka Ringwald             default:
1103f01aeca4SMilanka Ringwald                 break;
1104f01aeca4SMilanka Ringwald         }
1105f01aeca4SMilanka Ringwald     }
1106f01aeca4SMilanka Ringwald 
1107f01aeca4SMilanka Ringwald     connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED;
1108b93f8966SMatthias Ringwald     l2cap_disconnect(connection->l2cap_signaling_cid);
11094ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1110747ec646SMilanka Ringwald }
1111747ec646SMilanka Ringwald 
111248ce193cSMilanka Ringwald 
111348ce193cSMilanka Ringwald #ifdef ENABLE_AVDTP_ACCEPTOR_EXPLICIT_START_STREAM_CONFIRMATION
111448ce193cSMilanka Ringwald static uint8_t avdtp_handle_explicit_start_stream_confirmation(uint16_t avdtp_cid, uint8_t local_seid, bool accept_stream_requested){
111548ce193cSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
111648ce193cSMilanka Ringwald     if (!connection){
111748ce193cSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
111848ce193cSMilanka Ringwald     }
111948ce193cSMilanka Ringwald 
112048ce193cSMilanka Ringwald     if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
112148ce193cSMilanka Ringwald         log_error("avdtp_media_connect: wrong connection state %d", connection->state);
112248ce193cSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
112348ce193cSMilanka Ringwald     }
112448ce193cSMilanka Ringwald 
112548ce193cSMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
112648ce193cSMilanka Ringwald     if (!stream_endpoint) {
112748ce193cSMilanka Ringwald         log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid);
112848ce193cSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
112948ce193cSMilanka Ringwald     }
113048ce193cSMilanka Ringwald 
113148ce193cSMilanka Ringwald     if (stream_endpoint->acceptor_config_state != AVDTP_ACCEPTOR_W4_USER_CONFIRM_START_STREAM){
113248ce193cSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
113348ce193cSMilanka Ringwald     }
113448ce193cSMilanka Ringwald 
113548ce193cSMilanka Ringwald     if (accept_stream_requested){
113648ce193cSMilanka Ringwald         stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ACCEPT_START_STREAM;
113748ce193cSMilanka Ringwald     } else {
113848ce193cSMilanka Ringwald         stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_START_STREAM;
113948ce193cSMilanka Ringwald     }
114048ce193cSMilanka Ringwald     avdtp_request_can_send_now_acceptor(connection);
114148ce193cSMilanka Ringwald     return ERROR_CODE_SUCCESS;
114248ce193cSMilanka Ringwald }
114348ce193cSMilanka Ringwald 
114448ce193cSMilanka Ringwald uint8_t avdtp_start_stream_accept(uint16_t avdtp_cid, uint8_t local_seid){
114548ce193cSMilanka Ringwald     return avdtp_handle_explicit_start_stream_confirmation(avdtp_cid, local_seid, true);
114648ce193cSMilanka Ringwald }
114748ce193cSMilanka Ringwald 
114848ce193cSMilanka Ringwald uint8_t avdtp_start_stream_reject(uint16_t avdtp_cid, uint8_t local_seid){
114948ce193cSMilanka Ringwald     return avdtp_handle_explicit_start_stream_confirmation(avdtp_cid, local_seid, false);
115048ce193cSMilanka Ringwald }
115148ce193cSMilanka Ringwald #endif
115248ce193cSMilanka Ringwald 
1153297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){
11545ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1155747ec646SMilanka Ringwald     if (!connection){
115623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1157747ec646SMilanka Ringwald     }
1158747ec646SMilanka Ringwald 
1159747ec646SMilanka Ringwald     if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) {
11608587e32cSMilanka Ringwald         log_error("avdtp_media_connect: wrong connection state %d", connection->state);
116123edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1162747ec646SMilanka Ringwald     }
1163747ec646SMilanka Ringwald 
11643338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
1165747ec646SMilanka Ringwald     if (!stream_endpoint) {
11666b0ee1d0SMilanka Ringwald         log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid);
116723edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1168747ec646SMilanka Ringwald     }
1169747ec646SMilanka Ringwald 
1170485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid != remote_seid){
1171485c0a4cSMilanka Ringwald         log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid);
117223edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1173485c0a4cSMilanka Ringwald     }
1174485c0a4cSMilanka Ringwald 
117523edb87eSMilanka Ringwald     if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return ERROR_CODE_COMMAND_DISALLOWED;
1176747ec646SMilanka Ringwald 
1177b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
117896dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
11795bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1180747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM;
1181747ec646SMilanka Ringwald     stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM;
1182d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
11834ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1184747ec646SMilanka Ringwald }
1185747ec646SMilanka Ringwald 
1186297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){
11875ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
118846e6b063SMilanka Ringwald     if (!connection){
118923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
119046e6b063SMilanka Ringwald     }
11915cfe7f4cSMilanka Ringwald 
11923338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
11934ccacc40SMilanka Ringwald     if (!stream_endpoint) {
11944ccacc40SMilanka Ringwald         log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid);
119523edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
11964ccacc40SMilanka Ringwald     }
11974ccacc40SMilanka Ringwald 
11984ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
11994ccacc40SMilanka Ringwald         log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid);
120023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12014ccacc40SMilanka Ringwald     }
12024ccacc40SMilanka Ringwald 
1203485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint)){
1204485c0a4cSMilanka Ringwald         log_error("avdtp_media_connect: no remote sep registered with the stream endpoint");
120523edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12064ccacc40SMilanka Ringwald     }
12074ccacc40SMilanka Ringwald 
1208440d8d82SMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){
1209440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1210440d8d82SMilanka Ringwald     }
1211440d8d82SMilanka Ringwald 
12124e7bc04fSMilanka Ringwald     if (stream_endpoint->start_stream == 1) {
12134e7bc04fSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12144e7bc04fSMilanka Ringwald     }
12154e7bc04fSMilanka Ringwald 
121660ec20d0SMilanka Ringwald     stream_endpoint->start_stream = 1;
12175bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
121896dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1219d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
12204ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1221747ec646SMilanka Ringwald }
1222747ec646SMilanka Ringwald 
1223297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){
12245ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1225747ec646SMilanka Ringwald     if (!connection){
122623edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1227747ec646SMilanka Ringwald     }
12284ccacc40SMilanka Ringwald 
12293338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
12304ccacc40SMilanka Ringwald     if (!stream_endpoint) {
12314ccacc40SMilanka Ringwald         log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid);
123223edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12334ccacc40SMilanka Ringwald     }
12344ccacc40SMilanka Ringwald 
12354ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
12364ccacc40SMilanka Ringwald         log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid);
123723edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12384ccacc40SMilanka Ringwald     }
1239485c0a4cSMilanka Ringwald 
1240fa4419dbSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->close_stream){
1241440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1242485c0a4cSMilanka Ringwald     }
12434ccacc40SMilanka Ringwald 
12444e7bc04fSMilanka Ringwald     if (stream_endpoint->close_stream == 1) {
12454e7bc04fSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12464e7bc04fSMilanka Ringwald     }
12474e7bc04fSMilanka Ringwald 
1248fa4419dbSMilanka Ringwald     stream_endpoint->close_stream = 1;
12495bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
125096dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1251d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
12524ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1253747ec646SMilanka Ringwald }
1254747ec646SMilanka Ringwald 
1255297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){
12565ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
125760ec20d0SMilanka Ringwald     if (!connection){
125823edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1259747ec646SMilanka Ringwald     }
12604ccacc40SMilanka Ringwald 
12613338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
12624ccacc40SMilanka Ringwald     if (!stream_endpoint) {
12634ccacc40SMilanka Ringwald         log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid);
126423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12654ccacc40SMilanka Ringwald     }
12664ccacc40SMilanka Ringwald 
12674ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
12684ccacc40SMilanka Ringwald         log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid);
126923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12704ccacc40SMilanka Ringwald     }
1271485c0a4cSMilanka Ringwald 
1272485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){
1273440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1274485c0a4cSMilanka Ringwald     }
12754ccacc40SMilanka Ringwald 
12764e7bc04fSMilanka Ringwald     if (stream_endpoint->abort_stream == 1) {
12774e7bc04fSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
12784e7bc04fSMilanka Ringwald     }
12794e7bc04fSMilanka Ringwald 
128060ec20d0SMilanka Ringwald     stream_endpoint->abort_stream = 1;
12815bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
128296dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1283d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
12844ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1285747ec646SMilanka Ringwald }
1286747ec646SMilanka Ringwald 
1287297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){
12885ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1289747ec646SMilanka Ringwald     if (!connection){
129023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
129160ec20d0SMilanka Ringwald     }
12923338afc0SMatthias Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
12934ccacc40SMilanka Ringwald     if (!stream_endpoint) {
12944ccacc40SMilanka Ringwald         log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid);
129523edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
12964ccacc40SMilanka Ringwald     }
12974ccacc40SMilanka Ringwald 
12984ccacc40SMilanka Ringwald     if (stream_endpoint->l2cap_media_cid == 0){
12994ccacc40SMilanka Ringwald         log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid);
130023edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
13014ccacc40SMilanka Ringwald     }
1302485c0a4cSMilanka Ringwald 
13039cb061cbSMatthias Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint)){
13049cb061cbSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
13059cb061cbSMatthias Ringwald     }
13069cb061cbSMatthias Ringwald 
13079cb061cbSMatthias Ringwald     if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_STREAMING){
1308440d8d82SMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1309485c0a4cSMilanka Ringwald     }
13104ccacc40SMilanka Ringwald 
13114e7bc04fSMilanka Ringwald     if (stream_endpoint->suspend_stream == 1) {
13124e7bc04fSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
13134e7bc04fSMilanka Ringwald     }
13144e7bc04fSMilanka Ringwald 
131560ec20d0SMilanka Ringwald     stream_endpoint->suspend_stream = 1;
13165bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
131796dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = stream_endpoint->remote_sep.seid;
1318d80ccd43SMatthias Ringwald 	avdtp_request_can_send_now_initiator(connection);
13194ccacc40SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1320747ec646SMilanka Ringwald }
1321747ec646SMilanka Ringwald 
13225ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){
13235ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1324747ec646SMilanka Ringwald     if (!connection){
132523edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
13269974aee0SMilanka Ringwald     }
13270e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1328c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
132923edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1330747ec646SMilanka Ringwald     }
1331ec3d71e3SMilanka Ringwald 
1332b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1333747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS;
1334d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1335747ec646SMilanka Ringwald }
1336747ec646SMilanka Ringwald 
1337747ec646SMilanka Ringwald 
13385ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){
13395ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1340747ec646SMilanka Ringwald     if (!connection){
134123edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1342747ec646SMilanka Ringwald     }
13430e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1344c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
134523edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
13469974aee0SMilanka Ringwald     }
13479974aee0SMilanka Ringwald 
1348b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1349747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
135096dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1351d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1352747ec646SMilanka Ringwald }
1353747ec646SMilanka Ringwald 
1354747ec646SMilanka Ringwald 
1355a145558fSMatthias Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_role_t role) {
13565ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1357747ec646SMilanka Ringwald     if (!connection){
135823edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1359747ec646SMilanka Ringwald     }
13600e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1361c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
136223edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
13639974aee0SMilanka Ringwald     }
13649974aee0SMilanka Ringwald 
1365b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
136696dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1367cc61e7e9SMilanka Ringwald 
1368cc61e7e9SMilanka Ringwald     if (connection->avdtp_version == 0){
1369e71e31feSMatthias Ringwald         switch(role){
1370e71e31feSMatthias Ringwald             case AVDTP_ROLE_SINK:
1371e71e31feSMatthias Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES_FROM_REMOTE_SOURCE;
1372e71e31feSMatthias Ringwald                 break;
1373e71e31feSMatthias Ringwald             case AVDTP_ROLE_SOURCE:
1374e71e31feSMatthias Ringwald                 connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES_FROM_REMOTE_SINK;
1375e71e31feSMatthias Ringwald                 break;
1376e71e31feSMatthias Ringwald             default:
1377e71e31feSMatthias Ringwald                 btstack_unreachable();
1378e71e31feSMatthias Ringwald                 break;
1379e71e31feSMatthias Ringwald         }
1380cc61e7e9SMilanka Ringwald         avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query;
1381cc61e7e9SMilanka Ringwald         // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback
1382cc61e7e9SMilanka Ringwald         (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request);
1383cc61e7e9SMilanka Ringwald         return ERROR_CODE_SUCCESS;
1384cc61e7e9SMilanka Ringwald     } else {
1385cc61e7e9SMilanka Ringwald         // AVDTP version lower then 1.3 supports only get capabilities command
1386cc61e7e9SMilanka Ringwald         if (connection->avdtp_version < 0x103){
1387cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES;
1388cc61e7e9SMilanka Ringwald         } else {
1389cc61e7e9SMilanka Ringwald             connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES;
1390cc61e7e9SMilanka Ringwald         }
1391d80ccd43SMatthias Ringwald         return avdtp_request_can_send_now_initiator(connection);
1392747ec646SMilanka Ringwald     }
1393cc61e7e9SMilanka Ringwald }
1394747ec646SMilanka Ringwald 
13955ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){
13965ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1397747ec646SMilanka Ringwald     if (!connection){
139823edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1399747ec646SMilanka Ringwald     }
14000e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1401c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
140223edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
14039974aee0SMilanka Ringwald     }
14049974aee0SMilanka Ringwald 
1405b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
1406747ec646SMilanka Ringwald     connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION;
140796dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
1408d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1409747ec646SMilanka Ringwald }
1410747ec646SMilanka Ringwald 
1411cec76c5bSMilanka 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){
14125ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1413747ec646SMilanka Ringwald     if (!connection){
141423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1415747ec646SMilanka Ringwald     }
14160e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1417c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
1418485c0a4cSMilanka Ringwald         log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state);
141923edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
14209974aee0SMilanka Ringwald     }
1421a3ce0109SMatthias Ringwald     if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){
1422a3ce0109SMatthias Ringwald         log_info("configuration already started, config state %u", connection->configuration_state);
142323edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1424a3ce0109SMatthias Ringwald     }
1425747ec646SMilanka Ringwald 
1426d8e15394SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
1427747ec646SMilanka Ringwald     if (!stream_endpoint) {
14289900b7faSMilanka Ringwald         log_error("No initiator stream endpoint for seid %d", local_seid);
142923edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1430747ec646SMilanka Ringwald     }
1431417b4996SMilanka Ringwald     if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){
1432485c0a4cSMilanka Ringwald         log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state);
143323edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
1434417b4996SMilanka Ringwald     }
1435a3ce0109SMatthias Ringwald 
1436bdbc3ef6SMilanka Ringwald     connection->active_stream_endpoint = (void*) stream_endpoint;
1437a3ce0109SMatthias Ringwald     connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED;
1438747ec646SMilanka Ringwald 
1439b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
144096dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
14415bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1442f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration_bitmap = configured_services_bitmap;
1443f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration = configuration;
1444747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION;
1445ffa6c160SMilanka Ringwald 
144644e638f3SMatthias Ringwald 	log_debug("SE %p, initiator_config_state: 0x%02x", stream_endpoint, stream_endpoint->initiator_config_state);
14473a69f723SMatthias Ringwald 
1448d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1449747ec646SMilanka Ringwald }
1450747ec646SMilanka Ringwald 
1451cec76c5bSMilanka 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){
14525ace758fSMilanka Ringwald     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
1453747ec646SMilanka Ringwald     if (!connection){
145423edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1455747ec646SMilanka Ringwald     }
1456747ec646SMilanka Ringwald     //TODO: if opened only app capabilities, enable reconfigure for not opened
14570e588213SMatthias Ringwald     if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) ||
1458c1ab6cc1SMatthias Ringwald         (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) {
145923edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
14609974aee0SMilanka Ringwald     }
14619e42cfccSMilanka Ringwald 
1462d8e15394SMilanka Ringwald     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
146378d08d09SMilanka Ringwald     if (!stream_endpoint) {
14644ccacc40SMilanka Ringwald         log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid);
146523edb87eSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
146678d08d09SMilanka Ringwald     }
146778d08d09SMilanka Ringwald 
1468485c0a4cSMilanka Ringwald     if (!is_avdtp_remote_seid_registered(stream_endpoint)){
14698587e32cSMilanka Ringwald         log_error("avdtp_reconfigure: no associated remote sep");
147023edb87eSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
147178d08d09SMilanka Ringwald     }
1472485c0a4cSMilanka Ringwald 
1473b1935866SMilanka Ringwald     connection->initiator_transaction_label= avdtp_get_next_transaction_label();
147496dcd0f4SMatthias Ringwald     connection->initiator_remote_seid = remote_seid;
14755bd73fa2SMatthias Ringwald     connection->initiator_local_seid = local_seid;
1476f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration_bitmap = configured_services_bitmap;
1477f53d6fa7SMilanka Ringwald     stream_endpoint->remote_configuration = configuration;
1478747ec646SMilanka Ringwald     stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID;
1479d80ccd43SMatthias Ringwald     return avdtp_request_can_send_now_initiator(connection);
1480747ec646SMilanka Ringwald }
1481747ec646SMilanka Ringwald 
1482093c3dfdSMatthias Ringwald void    avdtp_set_preferred_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){
14838e7044f9SMatthias Ringwald     stream_endpoint->preferred_sampling_frequency = sampling_frequency;
14848e7044f9SMatthias Ringwald }
14858e7044f9SMatthias Ringwald 
148679654d96SMilanka Ringwald void    avdtp_set_preferred_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t channel_mode){
148779654d96SMilanka Ringwald     stream_endpoint->preferred_channel_mode = channel_mode;
148879654d96SMilanka Ringwald }
148979654d96SMilanka Ringwald 
149079654d96SMilanka Ringwald 
149180dc0088SMatthias Ringwald avdtp_channel_mode_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){
149278d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
149378d08d09SMilanka Ringwald     uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap;
149478d08d09SMilanka Ringwald 
149579654d96SMilanka Ringwald     // use preferred channel mode if possible
149679654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_JOINT_STEREO){
149780dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_JOINT_STEREO;
149879654d96SMilanka Ringwald     }
149979654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_STEREO){
150080dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_STEREO;
150179654d96SMilanka Ringwald     }
150279654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_DUAL_CHANNEL){
150380dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
150479654d96SMilanka Ringwald     }
150579654d96SMilanka Ringwald     if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_MONO){
150680dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_MONO;
150779654d96SMilanka Ringwald     }
150879654d96SMilanka Ringwald 
150979654d96SMilanka Ringwald 
151078d08d09SMilanka Ringwald     if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){
151180dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_JOINT_STEREO;
151278d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){
151380dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_STEREO;
151478d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){
151580dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
151678d08d09SMilanka Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_MONO){
151780dc0088SMatthias Ringwald         return AVDTP_CHANNEL_MODE_MONO;
151878d08d09SMilanka Ringwald     }
151980dc0088SMatthias Ringwald     return AVDTP_CHANNEL_MODE_JOINT_STEREO;
152078d08d09SMilanka Ringwald }
152178d08d09SMilanka Ringwald 
152280dc0088SMatthias Ringwald avdtp_sbc_allocation_method_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){
152378d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
1524b5bbcbf4SMatthias Ringwald     uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap;
152578d08d09SMilanka Ringwald 
1526b5bbcbf4SMatthias Ringwald     avdtp_sbc_allocation_method_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS;
152778d08d09SMilanka Ringwald     if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){
152878d08d09SMilanka Ringwald         allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS;
152978d08d09SMilanka Ringwald     } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){
153078d08d09SMilanka Ringwald         allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR;
153178d08d09SMilanka Ringwald     }
153278d08d09SMilanka Ringwald     return allocation_method;
153378d08d09SMilanka Ringwald }
153478d08d09SMilanka Ringwald 
1535bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){
1536bd1ecb8aSMilanka Ringwald     if (!stream_endpoint) return 0;
1537bd1ecb8aSMilanka Ringwald     return stream_endpoint->sep.seid;
1538bd1ecb8aSMilanka Ringwald }
153978d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){
154067ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
154178d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
154278d08d09SMilanka Ringwald     uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap;
154378d08d09SMilanka Ringwald 
154478d08d09SMilanka Ringwald     uint8_t subbands = AVDTP_SBC_SUBBANDS_8;
154578d08d09SMilanka Ringwald     if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){
154678d08d09SMilanka Ringwald         subbands = AVDTP_SBC_SUBBANDS_8;
154778d08d09SMilanka Ringwald     } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){
154878d08d09SMilanka Ringwald         subbands = AVDTP_SBC_SUBBANDS_4;
154978d08d09SMilanka Ringwald     }
155078d08d09SMilanka Ringwald     return subbands;
155178d08d09SMilanka Ringwald }
155278d08d09SMilanka Ringwald 
155378d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){
155467ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
155578d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
155678d08d09SMilanka Ringwald     uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap;
155778d08d09SMilanka Ringwald 
155878d08d09SMilanka Ringwald     uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16;
155978d08d09SMilanka Ringwald     if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){
156078d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_16;
156178d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){
156278d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_12;
156378d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){
156478d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_8;
156578d08d09SMilanka Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){
156678d08d09SMilanka Ringwald         block_length = AVDTP_SBC_BLOCK_LENGTH_4;
156778d08d09SMilanka Ringwald     }
156878d08d09SMilanka Ringwald     return block_length;
156978d08d09SMilanka Ringwald }
157078d08d09SMilanka Ringwald 
1571d44ccd27SMatthias Ringwald uint16_t avdtp_get_highest_sampling_frequency(uint8_t sampling_frequency_bitmap){
1572d44ccd27SMatthias Ringwald     if (sampling_frequency_bitmap & AVDTP_SBC_48000){
1573d44ccd27SMatthias Ringwald         return 48000;
1574d44ccd27SMatthias Ringwald     }
1575d44ccd27SMatthias Ringwald     if (sampling_frequency_bitmap & AVDTP_SBC_44100){
1576d44ccd27SMatthias Ringwald         return 44100;
1577d44ccd27SMatthias Ringwald     }
1578d44ccd27SMatthias Ringwald     if (sampling_frequency_bitmap & AVDTP_SBC_32000){
1579d44ccd27SMatthias Ringwald         return 32000;
1580d44ccd27SMatthias Ringwald     }
1581d44ccd27SMatthias Ringwald     if (sampling_frequency_bitmap & AVDTP_SBC_16000){
1582d44ccd27SMatthias Ringwald         return 16000;
1583d44ccd27SMatthias Ringwald     }
1584d44ccd27SMatthias Ringwald     return 0;
1585d44ccd27SMatthias Ringwald }
1586d44ccd27SMatthias Ringwald 
158780dc0088SMatthias Ringwald uint16_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){
158867ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
158978d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
15908e7044f9SMatthias Ringwald     uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap;
159178d08d09SMilanka Ringwald 
15928e7044f9SMatthias Ringwald     // use preferred sampling frequency if possible
15938e7044f9SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){
159480dc0088SMatthias Ringwald         return stream_endpoint->preferred_sampling_frequency;
15958e7044f9SMatthias Ringwald     }
15966ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){
159780dc0088SMatthias Ringwald         return stream_endpoint->preferred_sampling_frequency;
15986ed344c3SMatthias Ringwald     }
15996ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){
160080dc0088SMatthias Ringwald         return stream_endpoint->preferred_sampling_frequency;
16016ed344c3SMatthias Ringwald     }
16026ed344c3SMatthias Ringwald     if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){
160380dc0088SMatthias Ringwald         return stream_endpoint->preferred_sampling_frequency;
16046ed344c3SMatthias Ringwald     }
16056ed344c3SMatthias Ringwald 
16068e7044f9SMatthias Ringwald     // otherwise, use highest available
1607d44ccd27SMatthias Ringwald     uint16_t sampling_frequency = avdtp_get_highest_sampling_frequency(supported_sampling_frequency_bitmap);
1608d44ccd27SMatthias Ringwald     if (sampling_frequency != 0){
1609d44ccd27SMatthias Ringwald         return sampling_frequency;
1610d44ccd27SMatthias Ringwald     } else {
161180dc0088SMatthias Ringwald         return 44100; // some default
161278d08d09SMilanka Ringwald     }
1613d44ccd27SMatthias Ringwald }
161478d08d09SMilanka Ringwald 
161578d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){
161667ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
161778d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
161878d08d09SMilanka Ringwald     return btstack_min(media_codec[3], remote_max_bitpool_value);
161978d08d09SMilanka Ringwald }
162078d08d09SMilanka Ringwald 
162178d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){
162267ae582dSMilanka Ringwald     if (!stream_endpoint) return 0;
162378d08d09SMilanka Ringwald     uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information;
162478d08d09SMilanka Ringwald     return btstack_max(media_codec[2], remote_min_bitpool_value);
1625747ec646SMilanka Ringwald }
1626485c0a4cSMilanka Ringwald 
1627485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){
1628485c0a4cSMilanka Ringwald     if (!stream_endpoint) return 0;
1629485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid == 0) return 0;
1630485c0a4cSMilanka Ringwald     if (stream_endpoint->remote_sep.seid > 0x3E) return 0;
1631485c0a4cSMilanka Ringwald     return 1;
1632485c0a4cSMilanka Ringwald }
16338322fb3aSMatthias Ringwald 
16348322fb3aSMatthias Ringwald void avdtp_init(void){
1635137e2954SMatthias Ringwald     if (!avdtp_l2cap_registered){
1636137e2954SMatthias Ringwald         avdtp_l2cap_registered = true;
16378366bc41SMatthias Ringwald         l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, AVDTP_L2CAP_MTU, gap_get_security_level());
16388322fb3aSMatthias Ringwald     }
16398322fb3aSMatthias Ringwald }
164057fb24ffSMatthias Ringwald 
164157fb24ffSMatthias Ringwald void avdtp_deinit(void){
164257fb24ffSMatthias Ringwald     avdtp_sink_handle_media_data = NULL;
16436a737fb6SMatthias Ringwald     avdtp_sink_media_config_validator = NULL;
16446a737fb6SMatthias Ringwald     avdtp_source_media_config_validator = NULL;
1645137e2954SMatthias Ringwald     avdtp_source_callback = NULL;
1646137e2954SMatthias Ringwald     avdtp_sink_callback = NULL;
164757fb24ffSMatthias Ringwald 
1648137e2954SMatthias Ringwald     avdtp_sdp_query_context_avdtp_cid = 0;
1649137e2954SMatthias Ringwald 
1650137e2954SMatthias Ringwald     avdtp_stream_endpoints = NULL;
1651137e2954SMatthias Ringwald     avdtp_stream_endpoints_id_counter = 0;
1652137e2954SMatthias Ringwald 
1653137e2954SMatthias Ringwald     avdtp_l2cap_registered = false;
1654137e2954SMatthias Ringwald 
1655137e2954SMatthias Ringwald     avdtp_connections = NULL;
1656137e2954SMatthias Ringwald     avdtp_transaction_id_counter = 0;
1657137e2954SMatthias Ringwald 
1658137e2954SMatthias Ringwald     avdtp_record_id = 0;
165957fb24ffSMatthias Ringwald     avdtp_cid_counter = 0;
166057fb24ffSMatthias Ringwald }
1661