1747ec646SMilanka Ringwald /* 2747ec646SMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3747ec646SMilanka Ringwald * 4747ec646SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5747ec646SMilanka Ringwald * modification, are permitted provided that the following conditions 6747ec646SMilanka Ringwald * are met: 7747ec646SMilanka Ringwald * 8747ec646SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9747ec646SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10747ec646SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11747ec646SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12747ec646SMilanka Ringwald * documentation and/or other materials provided with the distribution. 13747ec646SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14747ec646SMilanka Ringwald * contributors may be used to endorse or promote products derived 15747ec646SMilanka Ringwald * from this software without specific prior written permission. 16747ec646SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17747ec646SMilanka Ringwald * personal benefit and not for any commercial purpose or for 18747ec646SMilanka Ringwald * monetary gain. 19747ec646SMilanka Ringwald * 20747ec646SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21747ec646SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22747ec646SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23747ec646SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24747ec646SMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25747ec646SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26747ec646SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27747ec646SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28747ec646SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29747ec646SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30747ec646SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31747ec646SMilanka Ringwald * SUCH DAMAGE. 32747ec646SMilanka Ringwald * 33747ec646SMilanka Ringwald * Please inquire about commercial licensing options at 34747ec646SMilanka Ringwald * [email protected] 35747ec646SMilanka Ringwald * 36747ec646SMilanka Ringwald */ 37747ec646SMilanka Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avdtp.c" 39ab2c6ae4SMatthias Ringwald 40747ec646SMilanka Ringwald 41747ec646SMilanka Ringwald #include <stdint.h> 42747ec646SMilanka Ringwald #include <string.h> 43747ec646SMilanka Ringwald 4484e3541eSMilanka Ringwald #include "bluetooth_psm.h" 4584e3541eSMilanka Ringwald #include "bluetooth_sdp.h" 4684e3541eSMilanka Ringwald #include "btstack_debug.h" 4784e3541eSMilanka Ringwald #include "btstack_event.h" 4884e3541eSMilanka Ringwald #include "btstack_memory.h" 494cb889a5SMilanka Ringwald #include "classic/avdtp.h" 504cb889a5SMilanka Ringwald #include "classic/avdtp_acceptor.h" 514cb889a5SMilanka Ringwald #include "classic/avdtp_initiator.h" 5284e3541eSMilanka Ringwald #include "classic/avdtp_util.h" 5384e3541eSMilanka Ringwald #include "classic/sdp_client.h" 5484e3541eSMilanka Ringwald #include "classic/sdp_util.h" 55747ec646SMilanka Ringwald 56d8e15394SMilanka Ringwald btstack_linked_list_t stream_endpoints; 57d8e15394SMilanka Ringwald 58a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_source_callback; 59a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_sink_callback; 605797104aSMilanka Ringwald static btstack_context_callback_registration_t avdtp_handle_sdp_client_query_request; 61a1fb0563SMilanka Ringwald 62ca2c9990SMilanka Ringwald static uint16_t sdp_query_context_avdtp_cid = 0; 63f0c39502SMilanka Ringwald 64560b3f31SMilanka Ringwald static uint16_t stream_endpoints_id_counter = 0; 65560b3f31SMilanka Ringwald 665ace758fSMilanka Ringwald static btstack_linked_list_t connections; 67b1935866SMilanka Ringwald static uint16_t transaction_id_counter = 0; 685ace758fSMilanka Ringwald 69692c0605SMilanka Ringwald static int record_id = -1; 70fa1ee4d3SMilanka Ringwald static uint8_t attribute_value[45]; 71692c0605SMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); 72747ec646SMilanka Ringwald 73951d2774SMatthias Ringwald static void (*avdtp_sink_handle_media_data)(uint8_t local_seid, uint8_t *packet, uint16_t size); 74951d2774SMatthias Ringwald 75af121d54SMilanka Ringwald static uint16_t avdtp_cid_counter = 0; 76747ec646SMilanka Ringwald 77692c0605SMilanka Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 78692c0605SMilanka Ringwald 79f751daa3SMatthias Ringwald btstack_packet_handler_t 80f751daa3SMatthias Ringwald avdtp_packet_handler_for_stream_endpoint(const avdtp_stream_endpoint_t *stream_endpoint) { 81f751daa3SMatthias Ringwald return (stream_endpoint->sep.type == AVDTP_SOURCE) ? avdtp_source_callback : avdtp_sink_callback; 82f751daa3SMatthias Ringwald } 83f751daa3SMatthias Ringwald 84c69f4ba5SMatthias Ringwald void avdtp_emit_sink_and_source(uint8_t * packet, uint16_t size){ 85c69f4ba5SMatthias Ringwald if (avdtp_source_callback != NULL){ 86c69f4ba5SMatthias Ringwald (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size); 87c69f4ba5SMatthias Ringwald } 88c69f4ba5SMatthias Ringwald if (avdtp_sink_callback != NULL){ 89c69f4ba5SMatthias Ringwald (*avdtp_sink_callback)(HCI_EVENT_PACKET, 0, packet, size); 90c69f4ba5SMatthias Ringwald } 91c69f4ba5SMatthias Ringwald } 92c69f4ba5SMatthias Ringwald 934b7d40bbSMatthias Ringwald void avdtp_emit_source(uint8_t * packet, uint16_t size){ 944b7d40bbSMatthias Ringwald if (avdtp_source_callback != NULL){ 954b7d40bbSMatthias Ringwald (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size); 96f751daa3SMatthias Ringwald } 97f08f4934SMatthias Ringwald } 98f08f4934SMatthias Ringwald 99f751daa3SMatthias Ringwald btstack_linked_list_t * avdtp_get_stream_endpoints(void){ 100f751daa3SMatthias Ringwald return &stream_endpoints; 101f751daa3SMatthias Ringwald } 10236da8747SMilanka Ringwald 10362c4ec82SMilanka Ringwald btstack_linked_list_t * avdtp_get_connections(void){ 10462c4ec82SMilanka Ringwald return &connections; 10562c4ec82SMilanka Ringwald } 10662c4ec82SMilanka Ringwald 1075ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_get_connection_for_bd_addr(bd_addr_t addr){ 1085ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 1095ace758fSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 1105ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1115ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 1125ace758fSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 1135ace758fSMilanka Ringwald return connection; 114b0d75c91SMilanka Ringwald } 1155ace758fSMilanka Ringwald return NULL; 116b0d75c91SMilanka Ringwald } 117b0d75c91SMilanka Ringwald 1185ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_avdtp_cid(uint16_t avdtp_cid){ 1195ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 1205ace758fSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 1215ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1225ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 1235ace758fSMilanka Ringwald if (connection->avdtp_cid != avdtp_cid) continue; 1245ace758fSMilanka Ringwald return connection; 1255ace758fSMilanka Ringwald } 1265ace758fSMilanka Ringwald return NULL; 1275ace758fSMilanka Ringwald } 1285ace758fSMilanka Ringwald 1295ace758fSMilanka Ringwald 130d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_seid(uint16_t seid){ 1315ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 132d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1335ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1345ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1355ace758fSMilanka Ringwald if (stream_endpoint->sep.seid == seid){ 1365ace758fSMilanka Ringwald return stream_endpoint; 1375ace758fSMilanka Ringwald } 1385ace758fSMilanka Ringwald } 1395ace758fSMilanka Ringwald return NULL; 1405ace758fSMilanka Ringwald } 1415ace758fSMilanka Ringwald 1425ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid){ 1435ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 1445ace758fSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 1455ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1465ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 1475ace758fSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 1485ace758fSMilanka Ringwald return connection; 1495ace758fSMilanka Ringwald } 1505ace758fSMilanka Ringwald return NULL; 1515ace758fSMilanka Ringwald } 1525ace758fSMilanka Ringwald 1536f98b084SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid){ 1545ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 155d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1565ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1575ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1585ace758fSMilanka Ringwald if (stream_endpoint->l2cap_media_cid == l2cap_cid){ 1595ace758fSMilanka Ringwald return stream_endpoint; 1605ace758fSMilanka Ringwald } 1615ace758fSMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == l2cap_cid){ 1625ace758fSMilanka Ringwald return stream_endpoint; 1635ace758fSMilanka Ringwald } 1645ace758fSMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == l2cap_cid){ 1655ace758fSMilanka Ringwald return stream_endpoint; 1665ace758fSMilanka Ringwald } 1675ace758fSMilanka Ringwald } 1685ace758fSMilanka Ringwald return NULL; 1695ace758fSMilanka Ringwald } 1705ace758fSMilanka Ringwald 17119a000d1SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_signaling_cid(uint16_t l2cap_cid){ 1725ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 173d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1745ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1755ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1765ace758fSMilanka Ringwald if (stream_endpoint->connection){ 1775ace758fSMilanka Ringwald if (stream_endpoint->connection->l2cap_signaling_cid == l2cap_cid){ 1785ace758fSMilanka Ringwald return stream_endpoint; 1795ace758fSMilanka Ringwald } 1805ace758fSMilanka Ringwald } 1815ace758fSMilanka Ringwald } 1825ace758fSMilanka Ringwald return NULL; 1835ace758fSMilanka Ringwald } 1845ace758fSMilanka Ringwald 1856f98b084SMilanka Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_with_seid(uint8_t seid){ 1865ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 187d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1885ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1895ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1905ace758fSMilanka Ringwald if (stream_endpoint->sep.seid == seid){ 1915ace758fSMilanka Ringwald return stream_endpoint; 1925ace758fSMilanka Ringwald } 1935ace758fSMilanka Ringwald } 1945ace758fSMilanka Ringwald return NULL; 1955ace758fSMilanka Ringwald } 1965ace758fSMilanka Ringwald 197054be048SMilanka Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_associated_with_acp_seid(uint16_t acp_seid){ 1985ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 199d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 2005ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2015ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 2025ace758fSMilanka Ringwald if (stream_endpoint->remote_sep.seid == acp_seid){ 2035ace758fSMilanka Ringwald return stream_endpoint; 2045ace758fSMilanka Ringwald } 2055ace758fSMilanka Ringwald } 2065ace758fSMilanka Ringwald return NULL; 2075ace758fSMilanka Ringwald } 2085ace758fSMilanka Ringwald 209b1935866SMilanka Ringwald uint16_t avdtp_get_next_transaction_label(void){ 210b1935866SMilanka Ringwald transaction_id_counter++; 211b1935866SMilanka Ringwald if (transaction_id_counter == 16){ 212b1935866SMilanka Ringwald transaction_id_counter = 1; 2135ace758fSMilanka Ringwald } 214b1935866SMilanka Ringwald return transaction_id_counter; 2155ace758fSMilanka Ringwald } 2165ace758fSMilanka Ringwald 2175ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_create_connection(bd_addr_t remote_addr, uint16_t cid){ 21836da8747SMilanka Ringwald avdtp_connection_t * connection = btstack_memory_avdtp_connection_get(); 21936da8747SMilanka Ringwald if (!connection){ 22036da8747SMilanka Ringwald log_error("Not enough memory to create connection"); 22136da8747SMilanka Ringwald return NULL; 22236da8747SMilanka Ringwald } 22336da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_IDLE; 224b1935866SMilanka Ringwald connection->initiator_transaction_label = avdtp_get_next_transaction_label(); 22536da8747SMilanka Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE; 22662c4ec82SMilanka Ringwald connection->a2dp_source_discover_seps = false; 22736da8747SMilanka Ringwald connection->avdtp_cid = cid; 22836da8747SMilanka Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 22936da8747SMilanka Ringwald 2305ace758fSMilanka Ringwald btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection); 23136da8747SMilanka Ringwald return connection; 23236da8747SMilanka Ringwald } 23336da8747SMilanka Ringwald 23436da8747SMilanka Ringwald static uint16_t avdtp_get_next_cid(void){ 235af121d54SMilanka Ringwald if (avdtp_cid_counter == 0xffff) { 2364ccacc40SMilanka Ringwald avdtp_cid_counter = 1; 237af121d54SMilanka Ringwald } else { 238af121d54SMilanka Ringwald avdtp_cid_counter++; 2394ccacc40SMilanka Ringwald } 2404ccacc40SMilanka Ringwald return avdtp_cid_counter; 2414ccacc40SMilanka Ringwald } 2424ccacc40SMilanka Ringwald 243560b3f31SMilanka Ringwald static uint16_t avdtp_get_next_local_seid(void){ 244560b3f31SMilanka Ringwald if (stream_endpoints_id_counter == 0xffff) { 245560b3f31SMilanka Ringwald stream_endpoints_id_counter = 1; 246af121d54SMilanka Ringwald } else { 247560b3f31SMilanka Ringwald stream_endpoints_id_counter++; 2484ccacc40SMilanka Ringwald } 249560b3f31SMilanka Ringwald return stream_endpoints_id_counter; 2504ccacc40SMilanka Ringwald } 2514ccacc40SMilanka Ringwald 2525797104aSMilanka Ringwald static void avdtp_handle_start_sdp_client_query(void * context){ 2535797104aSMilanka Ringwald UNUSED(context); 254b1549ed3SMilanka Ringwald 2555797104aSMilanka Ringwald btstack_linked_list_iterator_t it; 2565797104aSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 2575797104aSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2585797104aSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 2595797104aSMilanka Ringwald 2605797104aSMilanka Ringwald switch (connection->state){ 2615797104aSMilanka Ringwald case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE: 2625797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE; 2635797104aSMilanka Ringwald break; 2645797104aSMilanka Ringwald case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK: 2655797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE; 2665797104aSMilanka Ringwald break; 267cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 268cc61e7e9SMilanka Ringwald if (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES) continue; 269cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SDP_QUERY_COMPLETE_THEN_GET_ALL_CAPABILITIES; 270cc61e7e9SMilanka Ringwald break; 2715797104aSMilanka Ringwald default: 2725797104aSMilanka Ringwald continue; 2735797104aSMilanka Ringwald } 2745797104aSMilanka Ringwald sdp_query_context_avdtp_cid = connection->avdtp_cid; 2755797104aSMilanka Ringwald sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP); 2765797104aSMilanka Ringwald return; 2775797104aSMilanka Ringwald } 27884521ac1SMilanka Ringwald } 27984521ac1SMilanka Ringwald 280a1fb0563SMilanka Ringwald uint8_t avdtp_connect(bd_addr_t remote, avdtp_role_t role, uint16_t * avdtp_cid){ 2815ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_bd_addr(remote); 28284521ac1SMilanka Ringwald if (connection){ 28384521ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2844567cc17SMilanka Ringwald } 28584521ac1SMilanka Ringwald 28636da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 2872ad6b656SMilanka Ringwald if (avdtp_cid != NULL) { 28884521ac1SMilanka Ringwald *avdtp_cid = cid; 2892ad6b656SMilanka Ringwald } 2902ad6b656SMilanka Ringwald 2915ace758fSMilanka Ringwald connection = avdtp_create_connection(remote, cid); 29236da8747SMilanka Ringwald if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED; 29336da8747SMilanka Ringwald 29484521ac1SMilanka Ringwald connection->avdtp_cid = cid; 295b1549ed3SMilanka Ringwald 2965797104aSMilanka Ringwald connection->avdtp_l2cap_psm = 0; 2975797104aSMilanka Ringwald connection->avdtp_version = 0; 2985797104aSMilanka Ringwald connection->sink_supported = false; 2995797104aSMilanka Ringwald connection->source_supported = false; 3005797104aSMilanka Ringwald 301b1549ed3SMilanka Ringwald switch (role){ 302149deddbSMilanka Ringwald case AVDTP_ROLE_SOURCE: 3035797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK; 304149deddbSMilanka Ringwald break; 305149deddbSMilanka Ringwald case AVDTP_ROLE_SINK: 3065797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE; 307149deddbSMilanka Ringwald break; 308149deddbSMilanka Ringwald default: 3095797104aSMilanka Ringwald btstack_assert(false); 310149deddbSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 311149deddbSMilanka Ringwald } 3125797104aSMilanka Ringwald 3135797104aSMilanka Ringwald avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query; 3145797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 3155797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 3165797104aSMilanka Ringwald return ERROR_CODE_SUCCESS; 317692c0605SMilanka Ringwald } 318747ec646SMilanka Ringwald 319a1fb0563SMilanka Ringwald 320a1fb0563SMilanka Ringwald void avdtp_register_sink_packet_handler(btstack_packet_handler_t callback){ 321a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 322a1fb0563SMilanka Ringwald avdtp_sink_callback = callback; 323a1fb0563SMilanka Ringwald } 324a1fb0563SMilanka Ringwald 325a1fb0563SMilanka Ringwald void avdtp_register_source_packet_handler(btstack_packet_handler_t callback){ 326a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 327a1fb0563SMilanka Ringwald avdtp_source_callback = callback; 328a1fb0563SMilanka Ringwald } 329a1fb0563SMilanka Ringwald 330747ec646SMilanka Ringwald void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){ 331747ec646SMilanka Ringwald if (!stream_endpoint){ 3329900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 333747ec646SMilanka Ringwald return; 334747ec646SMilanka Ringwald } 335747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1); 336747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 337747ec646SMilanka Ringwald } 338747ec646SMilanka Ringwald 339747ec646SMilanka Ringwald void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 340747ec646SMilanka Ringwald if (!stream_endpoint){ 3419900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 342747ec646SMilanka Ringwald return; 343747ec646SMilanka Ringwald } 344747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_REPORTING, 1); 345747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 346747ec646SMilanka Ringwald } 347747ec646SMilanka Ringwald 348747ec646SMilanka Ringwald void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 349747ec646SMilanka Ringwald if (!stream_endpoint){ 3509900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 351747ec646SMilanka Ringwald return; 352747ec646SMilanka Ringwald } 353747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_DELAY_REPORTING, 1); 354747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 355747ec646SMilanka Ringwald } 356747ec646SMilanka Ringwald 357747ec646SMilanka Ringwald void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){ 358747ec646SMilanka Ringwald if (!stream_endpoint){ 3599900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 360747ec646SMilanka Ringwald return; 361747ec646SMilanka Ringwald } 362747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_RECOVERY, 1); 363747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 364747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.recovery_type = 0x01; // 0x01 = RFC2733 365747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_recovery_window_size = maximum_recovery_window_size; 366747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_number_media_packets = maximum_number_media_packets; 367747ec646SMilanka Ringwald } 368747ec646SMilanka Ringwald 369747ec646SMilanka 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){ 370747ec646SMilanka Ringwald if (!stream_endpoint){ 3719900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 372747ec646SMilanka Ringwald return; 373747ec646SMilanka Ringwald } 374747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_CONTENT_PROTECTION, 1); 375747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 376747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type = cp_type; 3776535961aSMatthias Ringwald (void)memcpy(stream_endpoint->sep.capabilities.content_protection.cp_type_value, 3786535961aSMatthias Ringwald cp_type_value, 3796535961aSMatthias Ringwald btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN)); 38067ae582dSMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type_value_len = btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN); 381747ec646SMilanka Ringwald } 382747ec646SMilanka Ringwald 383747ec646SMilanka Ringwald void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery){ 384747ec646SMilanka Ringwald if (!stream_endpoint){ 3859900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 386747ec646SMilanka Ringwald return; 387747ec646SMilanka Ringwald } 388747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_HEADER_COMPRESSION, 1); 389747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 390747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.back_ch = back_ch; 391747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.media = media; 392747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.recovery = recovery; 393747ec646SMilanka Ringwald } 394747ec646SMilanka Ringwald 39578d08d09SMilanka Ringwald void avdtp_register_media_codec_category(avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len){ 396747ec646SMilanka Ringwald if (!stream_endpoint){ 3979900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 398747ec646SMilanka Ringwald return; 399747ec646SMilanka Ringwald } 400747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1); 401747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 402747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_type = media_type; 403747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type; 404747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information = media_codec_info; 405747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information_len = media_codec_info_len; 406747ec646SMilanka Ringwald } 407747ec646SMilanka Ringwald 408747ec646SMilanka Ringwald void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation){ 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_MULTIPLEXING, 1); 414747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 415747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.multiplexing_mode.fragmentation = fragmentation; 416747ec646SMilanka Ringwald } 417747ec646SMilanka Ringwald 418951d2774SMatthias Ringwald void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size)){ 419951d2774SMatthias Ringwald avdtp_sink_handle_media_data = callback; 420951d2774SMatthias Ringwald } 421747ec646SMilanka Ringwald 422747ec646SMilanka Ringwald /* START: tracking can send now requests pro l2cap cid */ 42377092f3eSMatthias Ringwald void avdtp_handle_can_send_now(avdtp_connection_t *connection, uint16_t l2cap_cid) { 424747ec646SMilanka Ringwald if (connection->wait_to_send_acceptor){ 425c6bc5965SMilanka Ringwald log_debug("call avdtp_acceptor_stream_config_subsm_run"); 426747ec646SMilanka Ringwald connection->wait_to_send_acceptor = 0; 42777092f3eSMatthias Ringwald avdtp_acceptor_stream_config_subsm_run(connection); 428747ec646SMilanka Ringwald } else if (connection->wait_to_send_initiator){ 429c6bc5965SMilanka Ringwald log_debug("call avdtp_initiator_stream_config_subsm_run"); 430747ec646SMilanka Ringwald connection->wait_to_send_initiator = 0; 43177092f3eSMatthias Ringwald avdtp_initiator_stream_config_subsm_run(connection); 432747ec646SMilanka Ringwald } 433747ec646SMilanka Ringwald 434747ec646SMilanka Ringwald // re-register 435f01aeca4SMilanka Ringwald bool more_to_send = connection->wait_to_send_acceptor || connection->wait_to_send_initiator; 436f01aeca4SMilanka Ringwald log_debug("ask for more to send %d: acc-%d, ini-%d", more_to_send, connection->wait_to_send_acceptor, connection->wait_to_send_initiator); 437c6bc5965SMilanka Ringwald 438747ec646SMilanka Ringwald if (more_to_send){ 439747ec646SMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 440747ec646SMilanka Ringwald } 441747ec646SMilanka Ringwald } 442747ec646SMilanka Ringwald /* END: tracking can send now requests pro l2cap cid */ 443747ec646SMilanka Ringwald 444747ec646SMilanka Ringwald 445297feb5fSMilanka Ringwald avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){ 446747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = btstack_memory_avdtp_stream_endpoint_get(); 4474567cc17SMilanka Ringwald if (!stream_endpoint){ 4489900b7faSMilanka Ringwald log_error("Not enough memory to create stream endpoint"); 4494567cc17SMilanka Ringwald return NULL; 4504567cc17SMilanka Ringwald } 451560b3f31SMilanka Ringwald stream_endpoint->sep.seid = avdtp_get_next_local_seid(); 452747ec646SMilanka Ringwald stream_endpoint->sep.media_type = media_type; 453747ec646SMilanka Ringwald stream_endpoint->sep.type = sep_type; 454d8e15394SMilanka Ringwald btstack_linked_list_add(avdtp_get_stream_endpoints(), (btstack_linked_item_t *) stream_endpoint); 455747ec646SMilanka Ringwald return stream_endpoint; 456747ec646SMilanka Ringwald } 457747ec646SMilanka Ringwald 45817ddf501SMatthias Ringwald void avdtp_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ 45917ddf501SMatthias Ringwald btstack_linked_list_remove(avdtp_get_stream_endpoints(), (btstack_linked_item_t* ) stream_endpoint); 46017ddf501SMatthias Ringwald btstack_memory_avdtp_stream_endpoint_free(stream_endpoint); 46117ddf501SMatthias Ringwald } 46217ddf501SMatthias Ringwald 46377092f3eSMatthias Ringwald static void 46477092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t *connection, uint8_t *packet, uint16_t size) { 465c1c40ea1SMatthias Ringwald if (size < 2) return; 466c1c40ea1SMatthias Ringwald 467c1c40ea1SMatthias Ringwald uint16_t offset; 468c1c40ea1SMatthias Ringwald avdtp_message_type_t message_type = avdtp_get_signaling_packet_type(packet); 469c1c40ea1SMatthias Ringwald switch (message_type){ 470747ec646SMilanka Ringwald case AVDTP_CMD_MSG: 47150453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->acceptor_signaling_packet, packet, size); 47277092f3eSMatthias Ringwald avdtp_acceptor_stream_config_subsm(connection, packet, size, offset); 473747ec646SMilanka Ringwald break; 474747ec646SMilanka Ringwald default: 47550453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->initiator_signaling_packet, packet, size); 47677092f3eSMatthias Ringwald avdtp_initiator_stream_config_subsm(connection, packet, size, offset); 477747ec646SMilanka Ringwald break; 478747ec646SMilanka Ringwald } 479747ec646SMilanka Ringwald } 480747ec646SMilanka Ringwald 481b1549ed3SMilanka Ringwald static void avdtp_handle_sdp_client_query_attribute_value(avdtp_connection_t * connection, uint8_t *packet){ 482692c0605SMilanka Ringwald des_iterator_t des_list_it; 483692c0605SMilanka Ringwald des_iterator_t prot_it; 484692c0605SMilanka Ringwald 485692c0605SMilanka Ringwald // Handle new SDP record 486692c0605SMilanka Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id) { 487692c0605SMilanka Ringwald record_id = sdp_event_query_attribute_byte_get_record_id(packet); 4888587e32cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 489692c0605SMilanka Ringwald } 490692c0605SMilanka Ringwald 491692c0605SMilanka Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 492692c0605SMilanka Ringwald attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 493692c0605SMilanka Ringwald 494692c0605SMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 495692c0605SMilanka Ringwald 496692c0605SMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 497149deddbSMilanka Ringwald 498692c0605SMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 499692c0605SMilanka Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 500692c0605SMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 501692c0605SMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 502692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 503692c0605SMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 504692c0605SMilanka Ringwald switch (uuid){ 505692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE: 506b1549ed3SMilanka Ringwald connection->source_supported = true; 507149deddbSMilanka Ringwald log_info("source_supported"); 508692c0605SMilanka Ringwald break; 509692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK: 510b1549ed3SMilanka Ringwald connection->sink_supported = true; 511149deddbSMilanka Ringwald log_info("sink_supported"); 512692c0605SMilanka Ringwald break; 513692c0605SMilanka Ringwald default: 514692c0605SMilanka Ringwald break; 515692c0605SMilanka Ringwald } 516692c0605SMilanka Ringwald } 517692c0605SMilanka Ringwald break; 518692c0605SMilanka Ringwald 519149deddbSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 5208587e32cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 521692c0605SMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 522692c0605SMilanka Ringwald uint8_t *des_element; 523692c0605SMilanka Ringwald uint8_t *element; 524692c0605SMilanka Ringwald uint32_t uuid; 525692c0605SMilanka Ringwald 526692c0605SMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 527692c0605SMilanka Ringwald 528692c0605SMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 529692c0605SMilanka Ringwald des_iterator_init(&prot_it, des_element); 530692c0605SMilanka Ringwald element = des_iterator_get_element(&prot_it); 531692c0605SMilanka Ringwald 532692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 533692c0605SMilanka Ringwald 534692c0605SMilanka Ringwald uuid = de_get_uuid32(element); 53514fd128cSMatthias Ringwald des_iterator_next(&prot_it); 536149deddbSMilanka Ringwald // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both 537692c0605SMilanka Ringwald switch (uuid){ 538692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 539692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 540b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_l2cap_psm); 541692c0605SMilanka Ringwald break; 542692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_AVDTP: 543692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 544b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_version); 545cc61e7e9SMilanka Ringwald log_info("avdtp version 0x%02x", connection->avdtp_version); 546692c0605SMilanka Ringwald break; 547692c0605SMilanka Ringwald default: 548692c0605SMilanka Ringwald break; 549692c0605SMilanka Ringwald } 550692c0605SMilanka Ringwald } 551692c0605SMilanka Ringwald break; 552149deddbSMilanka Ringwald 553692c0605SMilanka Ringwald default: 554692c0605SMilanka Ringwald break; 555692c0605SMilanka Ringwald } 556692c0605SMilanka Ringwald } 557692c0605SMilanka Ringwald } else { 5588587e32cSMilanka 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)); 559692c0605SMilanka Ringwald } 5606ed344c3SMatthias Ringwald 5616ed344c3SMatthias Ringwald } 5626ed344c3SMatthias Ringwald 5635ace758fSMilanka Ringwald static void avdtp_finalize_connection(avdtp_connection_t * connection){ 564ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 5655ace758fSMilanka Ringwald btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection); 566f0c39502SMilanka Ringwald btstack_memory_avdtp_connection_free(connection); 567f0c39502SMilanka Ringwald } 568f0c39502SMilanka Ringwald 569f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_failed(avdtp_connection_t * connection, uint8_t status){ 570a1fb0563SMilanka Ringwald switch (connection->state){ 571a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 572a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 573146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, connection->remote_addr, connection->con_handle, status); 574a1fb0563SMilanka Ringwald break; 575cc61e7e9SMilanka Ringwald 576cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 577cc61e7e9SMilanka Ringwald // SDP query failed: try query that must be supported 578cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 579cc61e7e9SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 580a1fb0563SMilanka Ringwald return; 581cc61e7e9SMilanka Ringwald 582cc61e7e9SMilanka Ringwald default: 583cc61e7e9SMilanka Ringwald btstack_assert(false); 584cc61e7e9SMilanka Ringwald break; 585a1fb0563SMilanka Ringwald } 5865ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 587ca2c9990SMilanka Ringwald sdp_query_context_avdtp_cid = 0; 588f0c39502SMilanka Ringwald log_info("SDP query failed with status 0x%02x.", status); 589f0c39502SMilanka Ringwald } 590f0c39502SMilanka Ringwald 591f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){ 592cc61e7e9SMilanka Ringwald log_info("avdtp_handle_sdp_query_succeeded: state %d", connection->state); 593cc61e7e9SMilanka Ringwald 594cc61e7e9SMilanka Ringwald switch (connection->state){ 595cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 596cc61e7e9SMilanka Ringwald if (connection->avdtp_version < 0x0103){ 597cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 598cc61e7e9SMilanka Ringwald } else { 599cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 600cc61e7e9SMilanka Ringwald } 601cc61e7e9SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 602cc61e7e9SMilanka Ringwald break; 603cc61e7e9SMilanka Ringwald default: 604f0c39502SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 605cc61e7e9SMilanka Ringwald l2cap_create_channel(avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 606cc61e7e9SMilanka Ringwald break; 607cc61e7e9SMilanka Ringwald } 608f0c39502SMilanka Ringwald } 609f0c39502SMilanka Ringwald 6106ed344c3SMatthias Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 611149deddbSMilanka Ringwald UNUSED(packet_type); 612149deddbSMilanka Ringwald UNUSED(channel); 613149deddbSMilanka Ringwald UNUSED(size); 614149deddbSMilanka Ringwald 615ca2c9990SMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(sdp_query_context_avdtp_cid); 6166ed344c3SMatthias Ringwald if (!connection) { 617ca2c9990SMilanka Ringwald log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context_avdtp_cid); 6186ed344c3SMatthias Ringwald return; 6196ed344c3SMatthias Ringwald } 6206ed344c3SMatthias Ringwald 621722c03bdSMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 622149deddbSMilanka Ringwald switch (connection->state){ 623149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 6246ed344c3SMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 6256ed344c3SMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 626b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 627149deddbSMilanka Ringwald return; 628692c0605SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 6291e1ae2bcSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 630149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 631722c03bdSMatthias Ringwald if (!connection->sink_supported) { 632722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 633722c03bdSMatthias Ringwald break; 634722c03bdSMatthias Ringwald } 635722c03bdSMatthias Ringwald if (connection->avdtp_l2cap_psm == 0) { 636722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 637722c03bdSMatthias Ringwald break; 638722c03bdSMatthias Ringwald } 639149deddbSMilanka Ringwald break; 640149deddbSMilanka Ringwald default: 641149deddbSMilanka Ringwald btstack_assert(false); 642722c03bdSMatthias Ringwald return; 6431e1ae2bcSMilanka Ringwald } 644149deddbSMilanka Ringwald break; 645149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 646149deddbSMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 647149deddbSMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 648b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 649149deddbSMilanka Ringwald return; 650149deddbSMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 651149deddbSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 652149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 653722c03bdSMatthias Ringwald if (!connection->source_supported) { 654722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 655722c03bdSMatthias Ringwald break; 656722c03bdSMatthias Ringwald } 657722c03bdSMatthias Ringwald if (connection->avdtp_l2cap_psm == 0) { 658722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 659722c03bdSMatthias Ringwald break; 660722c03bdSMatthias Ringwald } 661149deddbSMilanka Ringwald break; 662149deddbSMilanka Ringwald default: 663149deddbSMilanka Ringwald btstack_assert(false); 664722c03bdSMatthias Ringwald return; 665974d4d6eSMilanka Ringwald } 6662f6083d0SMilanka Ringwald break; 667cc61e7e9SMilanka Ringwald 668cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 669cc61e7e9SMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 670cc61e7e9SMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 671cc61e7e9SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 672cc61e7e9SMilanka Ringwald return; 673cc61e7e9SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 674cc61e7e9SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 675cc61e7e9SMilanka Ringwald break; 676cc61e7e9SMilanka Ringwald default: 677cc61e7e9SMilanka Ringwald btstack_assert(false); 678cc61e7e9SMilanka Ringwald return; 679cc61e7e9SMilanka Ringwald } 680cc61e7e9SMilanka Ringwald break; 681cc61e7e9SMilanka Ringwald 682149deddbSMilanka Ringwald default: 68308cb850dSMilanka Ringwald // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete 68408cb850dSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 68508cb850dSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 68608cb850dSMilanka Ringwald } 687149deddbSMilanka Ringwald return; 6882f6083d0SMilanka Ringwald } 689f0c39502SMilanka Ringwald 690722c03bdSMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 691149deddbSMilanka Ringwald avdtp_handle_sdp_query_succeeded(connection); 692149deddbSMilanka Ringwald } else { 693149deddbSMilanka Ringwald avdtp_handle_sdp_query_failed(connection, status); 694692c0605SMilanka Ringwald } 6955797104aSMilanka Ringwald 6965797104aSMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 6975797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 6985797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 699692c0605SMilanka Ringwald } 700692c0605SMilanka Ringwald 701146fc0fbSMilanka 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){ 70236da8747SMilanka Ringwald if (connection == NULL){ 70336da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 7045ace758fSMilanka Ringwald connection = avdtp_create_connection(event_addr, cid); 70536da8747SMilanka Ringwald } 706692c0605SMilanka Ringwald 70736da8747SMilanka Ringwald if (connection) { 70836da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 70936da8747SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 710146fc0fbSMilanka Ringwald connection->con_handle = con_handle; 711ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 71236da8747SMilanka Ringwald } 71336da8747SMilanka Ringwald return connection; 71436da8747SMilanka Ringwald } 715f0c39502SMilanka Ringwald 716ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 717326e3662SMilanka Ringwald uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 718326e3662SMilanka Ringwald 7195ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 720326e3662SMilanka Ringwald if (connection == NULL) return; 721326e3662SMilanka Ringwald 722ff53b162SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){ 723326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 724326e3662SMilanka Ringwald l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 725326e3662SMilanka Ringwald } 726326e3662SMilanka Ringwald } 727326e3662SMilanka Ringwald 728ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){ 729ff53b162SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler); 730ff53b162SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid); 731326e3662SMilanka Ringwald 732326e3662SMilanka Ringwald // add some jitter/randomness to reconnect delay 733326e3662SMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 734ff53b162SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 735ff53b162SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 736326e3662SMilanka Ringwald } 737326e3662SMilanka Ringwald 738326e3662SMilanka Ringwald 739326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 740747ec646SMilanka Ringwald bd_addr_t event_addr; 741747ec646SMilanka Ringwald uint16_t psm; 742747ec646SMilanka Ringwald uint16_t local_cid; 7431e1ae2bcSMilanka Ringwald uint8_t status; 744326e3662SMilanka Ringwald uint16_t l2cap_mtu; 745146fc0fbSMilanka Ringwald hci_con_handle_t con_handle; 74636da8747SMilanka Ringwald 74736da8747SMilanka Ringwald bool accept_streaming_connection; 74836da8747SMilanka Ringwald bool outoing_signaling_active; 74936da8747SMilanka Ringwald bool decline_connection; 75084521ac1SMilanka Ringwald 751747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = NULL; 752747ec646SMilanka Ringwald avdtp_connection_t * connection = NULL; 75336da8747SMilanka Ringwald 754747ec646SMilanka Ringwald switch (packet_type) { 755747ec646SMilanka Ringwald case L2CAP_DATA_PACKET: 7565ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 757747ec646SMilanka Ringwald if (connection){ 75877092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 759747ec646SMilanka Ringwald break; 760747ec646SMilanka Ringwald } 761747ec646SMilanka Ringwald 7626f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 763747ec646SMilanka Ringwald if (!stream_endpoint){ 764747ec646SMilanka Ringwald if (!connection) break; 76577092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 766747ec646SMilanka Ringwald break; 767747ec646SMilanka Ringwald } 768747ec646SMilanka Ringwald 7698c0f3635SMilanka Ringwald if (stream_endpoint->connection){ 7709413b167SMilanka Ringwald if (channel == stream_endpoint->connection->l2cap_signaling_cid){ 77177092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size); 772747ec646SMilanka Ringwald break; 773747ec646SMilanka Ringwald } 7748c0f3635SMilanka Ringwald } 775747ec646SMilanka Ringwald 776747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_media_cid){ 777951d2774SMatthias Ringwald btstack_assert(avdtp_sink_handle_media_data); 778951d2774SMatthias Ringwald (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size); 779747ec646SMilanka Ringwald break; 780747ec646SMilanka Ringwald } 781747ec646SMilanka Ringwald 782747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_reporting_cid){ 7838587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED"); 784747ec646SMilanka Ringwald } else if (channel == stream_endpoint->l2cap_recovery_cid){ 7858587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED"); 786747ec646SMilanka Ringwald } else { 787747ec646SMilanka Ringwald log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel); 788747ec646SMilanka Ringwald } 789747ec646SMilanka Ringwald break; 790747ec646SMilanka Ringwald 791747ec646SMilanka Ringwald case HCI_EVENT_PACKET: 792747ec646SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 79336da8747SMilanka Ringwald 794747ec646SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 795747ec646SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 796747ec646SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 797146fc0fbSMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 79836da8747SMilanka Ringwald outoing_signaling_active = false; 79936da8747SMilanka Ringwald accept_streaming_connection = false; 80036da8747SMilanka Ringwald 8015ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 80236da8747SMilanka Ringwald if (connection != NULL){ 8030d4a198eSMatthias Ringwald switch (connection->state){ 8040d4a198eSMatthias Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED: 80536da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 80636da8747SMilanka Ringwald outoing_signaling_active = true; 80736da8747SMilanka Ringwald connection->incoming_declined = true; 80836da8747SMilanka Ringwald break; 80936da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 81036da8747SMilanka Ringwald outoing_signaling_active = true; 81136da8747SMilanka Ringwald accept_streaming_connection = true; 81236da8747SMilanka Ringwald break; 813f0c39502SMilanka Ringwald default: 814f0c39502SMilanka Ringwald break; 8150d4a198eSMatthias Ringwald } 816747ec646SMilanka Ringwald } 81736da8747SMilanka Ringwald log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d", 81836da8747SMilanka Ringwald bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection); 819747ec646SMilanka Ringwald 82036da8747SMilanka Ringwald decline_connection = outoing_signaling_active && !accept_streaming_connection; 82136da8747SMilanka Ringwald if (outoing_signaling_active == false){ 822146fc0fbSMilanka Ringwald connection = avdtp_handle_incoming_connection(connection, event_addr, con_handle, local_cid); 82336da8747SMilanka Ringwald if (connection == NULL){ 82436da8747SMilanka Ringwald decline_connection = true; 82536da8747SMilanka Ringwald } 82636da8747SMilanka Ringwald } else if (accept_streaming_connection){ 82736da8747SMilanka Ringwald if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) { 82836da8747SMilanka Ringwald decline_connection = true; 82936da8747SMilanka Ringwald } else { 830939e12adSMatthias Ringwald // now, we're only dealing with media connections that are created by remote side - we're acceptor here 8316f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_with_seid(connection->acceptor_local_seid); 83236da8747SMilanka Ringwald if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) { 83336da8747SMilanka Ringwald decline_connection = true; 83436da8747SMilanka Ringwald } 83536da8747SMilanka Ringwald } 836747ec646SMilanka Ringwald } 837747ec646SMilanka Ringwald 83836da8747SMilanka Ringwald if (decline_connection){ 839a3ce0109SMatthias Ringwald l2cap_decline_connection(local_cid); 84036da8747SMilanka Ringwald } else { 841747ec646SMilanka Ringwald l2cap_accept_connection(local_cid); 84236da8747SMilanka Ringwald } 843747ec646SMilanka Ringwald break; 844747ec646SMilanka Ringwald 845747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 846a5114819SMilanka Ringwald 847a0b8a58cSMilanka Ringwald psm = l2cap_event_channel_opened_get_psm(packet); 84884e3541eSMilanka Ringwald if (psm != BLUETOOTH_PSM_AVDTP){ 849355ac553SMilanka Ringwald log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED "); 850a0b8a58cSMilanka Ringwald return; 851a0b8a58cSMilanka Ringwald } 852a0b8a58cSMilanka Ringwald 8531e1ae2bcSMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 854747ec646SMilanka Ringwald // inform about new l2cap connection 855747ec646SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 8567050d2caSMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 857326e3662SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 8585ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 85936da8747SMilanka Ringwald if (connection == NULL){ 86036da8747SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr)); 861a0b8a58cSMilanka Ringwald break; 862a0b8a58cSMilanka Ringwald } 863a0b8a58cSMilanka Ringwald 864146fc0fbSMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 865146fc0fbSMilanka Ringwald 866a5114819SMilanka Ringwald switch (connection->state){ 867a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 868326e3662SMilanka Ringwald switch (status){ 869326e3662SMilanka Ringwald case ERROR_CODE_SUCCESS: 870326e3662SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 871326e3662SMilanka Ringwald connection->incoming_declined = false; 872326e3662SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 873146fc0fbSMilanka Ringwald connection->con_handle = con_handle; 874326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_OPENED; 875146fc0fbSMilanka 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); 876146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status); 877326e3662SMilanka Ringwald return; 878326e3662SMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 879326e3662SMilanka Ringwald if (connection->incoming_declined == true) { 880326e3662SMilanka Ringwald log_info("Connection was declined, and the outgoing failed"); 881ff53b162SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY; 882326e3662SMilanka Ringwald connection->incoming_declined = false; 883ff53b162SMilanka Ringwald avdtp_retry_timer_start(connection); 884326e3662SMilanka Ringwald return; 885326e3662SMilanka Ringwald } 886326e3662SMilanka Ringwald break; 887326e3662SMilanka Ringwald default: 888326e3662SMilanka Ringwald log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 889326e3662SMilanka Ringwald break; 890326e3662SMilanka Ringwald } 891146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status); 892f82b60efSMilanka Ringwald avdtp_finalize_connection(connection); 893a0b8a58cSMilanka Ringwald break; 894747ec646SMilanka Ringwald 895a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 89619a000d1SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid); 897747ec646SMilanka Ringwald if (!stream_endpoint){ 8985bd73fa2SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid); 899747ec646SMilanka Ringwald return; 900747ec646SMilanka Ringwald } 901326e3662SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 902355ac553SMilanka 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)); 903a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 904f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, status); 905a466d508SMilanka Ringwald break; 906a466d508SMilanka Ringwald } 907a5114819SMilanka Ringwald switch (stream_endpoint->state){ 908a5114819SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED: 909a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED; 910a466d508SMilanka Ringwald stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet); 911a466d508SMilanka Ringwald stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet); 912d1207cd8SMilanka Ringwald 913355ac553SMilanka 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)); 914f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS); 915a5114819SMilanka Ringwald break; 916a5114819SMilanka Ringwald default: 917a5114819SMilanka 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)); 91823edb87eSMilanka Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_COMMAND_DISALLOWED); 919a5114819SMilanka Ringwald break; 920a5114819SMilanka Ringwald } 921a5114819SMilanka Ringwald break; 922a5114819SMilanka Ringwald 923a5114819SMilanka Ringwald default: 924326e3662SMilanka Ringwald log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state); 925a5114819SMilanka Ringwald break; 926a5114819SMilanka Ringwald } 927747ec646SMilanka Ringwald break; 928747ec646SMilanka Ringwald 929747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 930747ec646SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 9316f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid); 9325ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid); 93336da8747SMilanka Ringwald 934f01aeca4SMilanka Ringwald log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint); 935f01aeca4SMilanka Ringwald 936a466d508SMilanka Ringwald if (stream_endpoint){ 937a466d508SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == local_cid){ 938a466d508SMilanka Ringwald connection = stream_endpoint->connection; 939596b7fdcSMilanka Ringwald if (connection) { 940f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_released(stream_endpoint, 941f751daa3SMatthias Ringwald connection->avdtp_cid, 942f751daa3SMatthias Ringwald avdtp_local_seid(stream_endpoint)); 943596b7fdcSMilanka Ringwald } 944485c0a4cSMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 9457f162947SMilanka Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE; 946a466d508SMilanka Ringwald break; 947a466d508SMilanka Ringwald } 948a466d508SMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == local_cid){ 949355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid); 950a466d508SMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0; 951a466d508SMilanka Ringwald break; 952a466d508SMilanka Ringwald } 953a466d508SMilanka Ringwald 954a466d508SMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == local_cid){ 955355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid); 956a466d508SMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0; 957a466d508SMilanka Ringwald break; 958a466d508SMilanka Ringwald } 959a466d508SMilanka Ringwald } 960596b7fdcSMilanka Ringwald 961596b7fdcSMilanka Ringwald if (connection){ 962596b7fdcSMilanka Ringwald btstack_linked_list_iterator_t it; 963d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 964596b7fdcSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 965f01aeca4SMilanka Ringwald stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 966f01aeca4SMilanka Ringwald if (stream_endpoint->connection == connection){ 967f01aeca4SMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 968596b7fdcSMilanka Ringwald } 969596b7fdcSMilanka Ringwald } 970c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_released(connection->avdtp_cid); 9715ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 972596b7fdcSMilanka Ringwald break; 973596b7fdcSMilanka Ringwald } 974747ec646SMilanka Ringwald break; 975747ec646SMilanka Ringwald 976747ec646SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 977c6bc5965SMilanka Ringwald log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel); 9785ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 979747ec646SMilanka Ringwald if (!connection) { 9806f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 981747ec646SMilanka Ringwald if (!stream_endpoint->connection) break; 982747ec646SMilanka Ringwald connection = stream_endpoint->connection; 983747ec646SMilanka Ringwald } 98477092f3eSMatthias Ringwald avdtp_handle_can_send_now(connection, channel); 985747ec646SMilanka Ringwald break; 986747ec646SMilanka Ringwald default: 987355ac553SMilanka Ringwald log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet)); 988747ec646SMilanka Ringwald break; 989747ec646SMilanka Ringwald } 990747ec646SMilanka Ringwald break; 991747ec646SMilanka Ringwald 992747ec646SMilanka Ringwald default: 993747ec646SMilanka Ringwald // other packet type 994747ec646SMilanka Ringwald break; 995747ec646SMilanka Ringwald } 996747ec646SMilanka Ringwald } 997747ec646SMilanka Ringwald 998b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){ 9995ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 100023edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1001b401ff59SMilanka Ringwald 1002a466d508SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS; 1003747ec646SMilanka Ringwald 1004f01aeca4SMilanka Ringwald btstack_linked_list_iterator_t it; 1005f01aeca4SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1006f01aeca4SMilanka Ringwald 1007f01aeca4SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1008f01aeca4SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1009f01aeca4SMilanka Ringwald if (stream_endpoint->connection != connection) continue; 1010f01aeca4SMilanka Ringwald 1011f01aeca4SMilanka Ringwald switch (stream_endpoint->state){ 1012f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_OPENED: 1013f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_STREAMING: 1014f01aeca4SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED; 1015f01aeca4SMilanka Ringwald l2cap_disconnect(stream_endpoint->l2cap_media_cid, 0); 1016f01aeca4SMilanka Ringwald break; 1017f01aeca4SMilanka Ringwald default: 1018f01aeca4SMilanka Ringwald break; 1019f01aeca4SMilanka Ringwald } 1020f01aeca4SMilanka Ringwald } 1021f01aeca4SMilanka Ringwald 1022f01aeca4SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED; 1023f01aeca4SMilanka Ringwald l2cap_disconnect(connection->l2cap_signaling_cid, 0); 10244ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1025747ec646SMilanka Ringwald } 1026747ec646SMilanka Ringwald 1027297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){ 10285ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1029747ec646SMilanka Ringwald if (!connection){ 10308587e32cSMilanka Ringwald log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid); 103123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1032747ec646SMilanka Ringwald } 1033747ec646SMilanka Ringwald 1034747ec646SMilanka Ringwald if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) { 10358587e32cSMilanka Ringwald log_error("avdtp_media_connect: wrong connection state %d", connection->state); 103623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1037747ec646SMilanka Ringwald } 1038747ec646SMilanka Ringwald 10396f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 1040747ec646SMilanka Ringwald if (!stream_endpoint) { 10416b0ee1d0SMilanka Ringwald log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid); 104223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1043747ec646SMilanka Ringwald } 1044747ec646SMilanka Ringwald 1045485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid != remote_seid){ 1046485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid); 104723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1048485c0a4cSMilanka Ringwald } 1049485c0a4cSMilanka Ringwald 105023edb87eSMilanka Ringwald if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return ERROR_CODE_COMMAND_DISALLOWED; 1051747ec646SMilanka Ringwald 1052b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 105396dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 10545bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1055747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM; 1056747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM; 10579413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 10584ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1059747ec646SMilanka Ringwald } 1060747ec646SMilanka Ringwald 1061297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10625ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 106346e6b063SMilanka Ringwald if (!connection){ 10644ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 106523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 106646e6b063SMilanka Ringwald } 10675cfe7f4cSMilanka Ringwald 10686f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 10694ccacc40SMilanka Ringwald if (!stream_endpoint) { 10704ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid); 107123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10724ccacc40SMilanka Ringwald } 10734ccacc40SMilanka Ringwald 10744ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 10754ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid); 107623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10774ccacc40SMilanka Ringwald } 10784ccacc40SMilanka Ringwald 1079485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 1080485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep registered with the stream endpoint"); 108123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10824ccacc40SMilanka Ringwald } 10834ccacc40SMilanka Ringwald 1084440d8d82SMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){ 1085440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1086440d8d82SMilanka Ringwald } 1087440d8d82SMilanka Ringwald 108860ec20d0SMilanka Ringwald stream_endpoint->start_stream = 1; 10895bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 109096dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 10919413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 10924ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1093747ec646SMilanka Ringwald } 1094747ec646SMilanka Ringwald 1095297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10965ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1097747ec646SMilanka Ringwald if (!connection){ 10984ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 109923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1100747ec646SMilanka Ringwald } 11014ccacc40SMilanka Ringwald 11026f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 11034ccacc40SMilanka Ringwald if (!stream_endpoint) { 11044ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid); 110523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11064ccacc40SMilanka Ringwald } 11074ccacc40SMilanka Ringwald 11084ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11094ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid); 111023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11114ccacc40SMilanka Ringwald } 1112485c0a4cSMilanka Ringwald 1113fa4419dbSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->close_stream){ 1114440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1115485c0a4cSMilanka Ringwald } 11164ccacc40SMilanka Ringwald 1117fa4419dbSMilanka Ringwald stream_endpoint->close_stream = 1; 11185bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 111996dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 11209413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 11214ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1122747ec646SMilanka Ringwald } 1123747ec646SMilanka Ringwald 1124297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11255ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 112660ec20d0SMilanka Ringwald if (!connection){ 11274ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 112823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1129747ec646SMilanka Ringwald } 11304ccacc40SMilanka Ringwald 11316f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 11324ccacc40SMilanka Ringwald if (!stream_endpoint) { 11334ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid); 113423edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11354ccacc40SMilanka Ringwald } 11364ccacc40SMilanka Ringwald 11374ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11384ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid); 113923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11404ccacc40SMilanka Ringwald } 1141485c0a4cSMilanka Ringwald 1142485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){ 1143440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1144485c0a4cSMilanka Ringwald } 11454ccacc40SMilanka Ringwald 114660ec20d0SMilanka Ringwald stream_endpoint->abort_stream = 1; 11475bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 114896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 11499413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 11504ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1151747ec646SMilanka Ringwald } 1152747ec646SMilanka Ringwald 1153297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11545ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1155747ec646SMilanka Ringwald if (!connection){ 11564ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 115723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 115860ec20d0SMilanka Ringwald } 11596f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 11604ccacc40SMilanka Ringwald if (!stream_endpoint) { 11614ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid); 116223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11634ccacc40SMilanka Ringwald } 11644ccacc40SMilanka Ringwald 11654ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11664ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid); 116723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11684ccacc40SMilanka Ringwald } 1169485c0a4cSMilanka Ringwald 1170485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){ 1171440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1172485c0a4cSMilanka Ringwald } 11734ccacc40SMilanka Ringwald 117460ec20d0SMilanka Ringwald stream_endpoint->suspend_stream = 1; 11755bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 117696dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 11779413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 11784ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1179747ec646SMilanka Ringwald } 1180747ec646SMilanka Ringwald 11815ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){ 11825ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1183747ec646SMilanka Ringwald if (!connection){ 11848587e32cSMilanka Ringwald log_error("avdtp_discover_stream_endpoints: no connection for signaling cid 0x%02x found", avdtp_cid); 118523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11869974aee0SMilanka Ringwald } 11870e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1188c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 118923edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1190747ec646SMilanka Ringwald } 1191ec3d71e3SMilanka Ringwald 1192b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1193747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS; 11949974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1195747ec646SMilanka Ringwald } 1196747ec646SMilanka Ringwald 1197747ec646SMilanka Ringwald 11985ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 11995ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1200747ec646SMilanka Ringwald if (!connection){ 12019900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 120223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1203747ec646SMilanka Ringwald } 12040e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1205c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 120623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12079974aee0SMilanka Ringwald } 12089974aee0SMilanka Ringwald 1209b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1210747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 121196dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 12129974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1213747ec646SMilanka Ringwald } 1214747ec646SMilanka Ringwald 1215747ec646SMilanka Ringwald 12165ace758fSMilanka Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 12175ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1218747ec646SMilanka Ringwald if (!connection){ 12199900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 122023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1221747ec646SMilanka Ringwald } 12220e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1223c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 122423edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12259974aee0SMilanka Ringwald } 12269974aee0SMilanka Ringwald 1227b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 122896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1229cc61e7e9SMilanka Ringwald 1230cc61e7e9SMilanka Ringwald if (connection->avdtp_version == 0){ 1231cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES; 1232cc61e7e9SMilanka Ringwald avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query; 1233cc61e7e9SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 1234cc61e7e9SMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 1235cc61e7e9SMilanka Ringwald return ERROR_CODE_SUCCESS; 1236cc61e7e9SMilanka Ringwald } else { 1237cc61e7e9SMilanka Ringwald // AVDTP version lower then 1.3 supports only get capabilities command 1238cc61e7e9SMilanka Ringwald if (connection->avdtp_version < 0x103){ 1239cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 1240cc61e7e9SMilanka Ringwald } else { 1241cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 1242cc61e7e9SMilanka Ringwald } 12439974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1244747ec646SMilanka Ringwald } 1245cc61e7e9SMilanka Ringwald } 1246747ec646SMilanka Ringwald 12475ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){ 12485ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1249747ec646SMilanka Ringwald if (!connection){ 12509900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 125123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1252747ec646SMilanka Ringwald } 12530e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1254c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 125523edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12569974aee0SMilanka Ringwald } 12579974aee0SMilanka Ringwald 1258b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1259747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION; 126096dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 12619974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1262747ec646SMilanka Ringwald } 1263747ec646SMilanka Ringwald 1264cec76c5bSMilanka 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){ 12655ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1266747ec646SMilanka Ringwald if (!connection){ 12679900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 126823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1269747ec646SMilanka Ringwald } 12700e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1271c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 1272485c0a4cSMilanka Ringwald log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state); 127323edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12749974aee0SMilanka Ringwald } 1275a3ce0109SMatthias Ringwald if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){ 1276a3ce0109SMatthias Ringwald log_info("configuration already started, config state %u", connection->configuration_state); 127723edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1278a3ce0109SMatthias Ringwald } 1279747ec646SMilanka Ringwald 1280d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1281747ec646SMilanka Ringwald if (!stream_endpoint) { 12829900b7faSMilanka Ringwald log_error("No initiator stream endpoint for seid %d", local_seid); 128323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1284747ec646SMilanka Ringwald } 1285417b4996SMilanka Ringwald if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){ 1286485c0a4cSMilanka Ringwald log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state); 128723edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1288417b4996SMilanka Ringwald } 1289a3ce0109SMatthias Ringwald 1290bdbc3ef6SMilanka Ringwald connection->active_stream_endpoint = (void*) stream_endpoint; 1291a3ce0109SMatthias Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED; 1292747ec646SMilanka Ringwald 1293b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 129496dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 12955bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1296f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1297f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1298747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION; 1299ffa6c160SMilanka Ringwald 1300*3a69f723SMatthias Ringwald log_debug("SE %p, initiator_config_state: 0x%02x", stream_endpoint->initiator_config_state); 1301*3a69f723SMatthias Ringwald 1302ffa6c160SMilanka Ringwald // cache media codec information for SBC 1303ffa6c160SMilanka Ringwald stream_endpoint->media_codec_type = configuration.media_codec.media_codec_type; 1304ffa6c160SMilanka Ringwald if (configuration.media_codec.media_codec_type == AVDTP_CODEC_SBC){ 1305ffa6c160SMilanka Ringwald stream_endpoint->media_type = configuration.media_codec.media_type; 13066535961aSMatthias Ringwald (void)memcpy(stream_endpoint->media_codec_sbc_info, 13076535961aSMatthias Ringwald configuration.media_codec.media_codec_information, 4); 1308ffa6c160SMilanka Ringwald } 13099974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1310747ec646SMilanka Ringwald } 1311747ec646SMilanka Ringwald 1312cec76c5bSMilanka 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){ 13135ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1314747ec646SMilanka Ringwald if (!connection){ 13159900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 131623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1317747ec646SMilanka Ringwald } 1318747ec646SMilanka Ringwald //TODO: if opened only app capabilities, enable reconfigure for not opened 13190e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1320c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 132123edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 13229974aee0SMilanka Ringwald } 13239e42cfccSMilanka Ringwald 1324d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 132578d08d09SMilanka Ringwald if (!stream_endpoint) { 13264ccacc40SMilanka Ringwald log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid); 132723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 132878d08d09SMilanka Ringwald } 132978d08d09SMilanka Ringwald 1330485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 13318587e32cSMilanka Ringwald log_error("avdtp_reconfigure: no associated remote sep"); 133223edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 133378d08d09SMilanka Ringwald } 1334485c0a4cSMilanka Ringwald 1335b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 133696dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 13375bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1338f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1339f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1340747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID; 13419974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1342747ec646SMilanka Ringwald } 1343747ec646SMilanka Ringwald 13448e7044f9SMatthias Ringwald void avdtp_set_preferred_sampling_frequeny(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){ 13458e7044f9SMatthias Ringwald stream_endpoint->preferred_sampling_frequency = sampling_frequency; 13468e7044f9SMatthias Ringwald } 13478e7044f9SMatthias Ringwald 134878d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){ 134978d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 135078d08d09SMilanka Ringwald uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap; 135178d08d09SMilanka Ringwald 135278d08d09SMilanka Ringwald uint8_t channel_mode = AVDTP_SBC_STEREO; 135378d08d09SMilanka Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 135478d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_JOINT_STEREO; 135578d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 135678d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_STEREO; 135778d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 135878d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_DUAL_CHANNEL; 135978d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_MONO){ 136078d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_MONO; 136178d08d09SMilanka Ringwald } 136278d08d09SMilanka Ringwald return channel_mode; 136378d08d09SMilanka Ringwald } 136478d08d09SMilanka Ringwald 136578d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){ 136678d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 136778d08d09SMilanka Ringwald uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap; 136878d08d09SMilanka Ringwald 136978d08d09SMilanka Ringwald uint8_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 137078d08d09SMilanka Ringwald if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){ 137178d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 137278d08d09SMilanka Ringwald } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){ 137378d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR; 137478d08d09SMilanka Ringwald } 137578d08d09SMilanka Ringwald return allocation_method; 137678d08d09SMilanka Ringwald } 137778d08d09SMilanka Ringwald 1378bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){ 1379bd1ecb8aSMilanka Ringwald if (!stream_endpoint) return 0; 1380bd1ecb8aSMilanka Ringwald return stream_endpoint->sep.seid; 1381bd1ecb8aSMilanka Ringwald } 138278d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){ 138367ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 138478d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 138578d08d09SMilanka Ringwald uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap; 138678d08d09SMilanka Ringwald 138778d08d09SMilanka Ringwald uint8_t subbands = AVDTP_SBC_SUBBANDS_8; 138878d08d09SMilanka Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 138978d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_8; 139078d08d09SMilanka Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 139178d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_4; 139278d08d09SMilanka Ringwald } 139378d08d09SMilanka Ringwald return subbands; 139478d08d09SMilanka Ringwald } 139578d08d09SMilanka Ringwald 139678d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){ 139767ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 139878d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 139978d08d09SMilanka Ringwald uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap; 140078d08d09SMilanka Ringwald 140178d08d09SMilanka Ringwald uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16; 140278d08d09SMilanka Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 140378d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_16; 140478d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 140578d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_12; 140678d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 140778d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_8; 140878d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 140978d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_4; 141078d08d09SMilanka Ringwald } 141178d08d09SMilanka Ringwald return block_length; 141278d08d09SMilanka Ringwald } 141378d08d09SMilanka Ringwald 141478d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){ 141567ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 141678d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 14178e7044f9SMatthias Ringwald uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap; 141878d08d09SMilanka Ringwald 14198e7044f9SMatthias Ringwald // use preferred sampling frequency if possible 14208e7044f9SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){ 14216ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 14228e7044f9SMatthias Ringwald } 14236ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){ 14246ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 14256ed344c3SMatthias Ringwald } 14266ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){ 14276ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 14286ed344c3SMatthias Ringwald } 14296ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){ 14306ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 14316ed344c3SMatthias Ringwald } 14326ed344c3SMatthias Ringwald 14338e7044f9SMatthias Ringwald // otherwise, use highest available 14346ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_48000){ 14356ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 143678d08d09SMilanka Ringwald } 14376ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_44100){ 14386ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 14396ed344c3SMatthias Ringwald } 14406ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_32000){ 14416ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 14426ed344c3SMatthias Ringwald } 14436ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_16000){ 14446ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 14456ed344c3SMatthias Ringwald } 14466ed344c3SMatthias Ringwald return AVDTP_SBC_44100; // some default 144778d08d09SMilanka Ringwald } 144878d08d09SMilanka Ringwald 144978d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){ 145067ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 145178d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 145278d08d09SMilanka Ringwald return btstack_min(media_codec[3], remote_max_bitpool_value); 145378d08d09SMilanka Ringwald } 145478d08d09SMilanka Ringwald 145578d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){ 145667ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 145778d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 145878d08d09SMilanka Ringwald return btstack_max(media_codec[2], remote_min_bitpool_value); 1459747ec646SMilanka Ringwald } 1460485c0a4cSMilanka Ringwald 1461485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){ 1462485c0a4cSMilanka Ringwald if (!stream_endpoint) return 0; 1463485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid == 0) return 0; 1464485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid > 0x3E) return 0; 1465485c0a4cSMilanka Ringwald return 1; 1466485c0a4cSMilanka Ringwald } 14678322fb3aSMatthias Ringwald 14688322fb3aSMatthias Ringwald void avdtp_init(void){ 14698322fb3aSMatthias Ringwald static bool l2cap_registered = false; 14708322fb3aSMatthias Ringwald if (!l2cap_registered){ 14718322fb3aSMatthias Ringwald l2cap_registered = true; 14728322fb3aSMatthias Ringwald l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, 0xffff, gap_get_security_level()); 14738322fb3aSMatthias Ringwald } 14748322fb3aSMatthias Ringwald } 1475