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