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; 67*b1935866SMilanka 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 209*b1935866SMilanka Ringwald uint16_t avdtp_get_next_transaction_label(void){ 210*b1935866SMilanka Ringwald transaction_id_counter++; 211*b1935866SMilanka Ringwald if (transaction_id_counter == 16){ 212*b1935866SMilanka Ringwald transaction_id_counter = 1; 2135ace758fSMilanka Ringwald } 214*b1935866SMilanka 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; 224*b1935866SMilanka 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; 2675797104aSMilanka Ringwald default: 2685797104aSMilanka Ringwald continue; 2695797104aSMilanka Ringwald } 2705797104aSMilanka Ringwald sdp_query_context_avdtp_cid = connection->avdtp_cid; 2715797104aSMilanka Ringwald sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP); 2725797104aSMilanka Ringwald return; 2735797104aSMilanka Ringwald } 27484521ac1SMilanka Ringwald } 27584521ac1SMilanka Ringwald 276a1fb0563SMilanka Ringwald uint8_t avdtp_connect(bd_addr_t remote, avdtp_role_t role, uint16_t * avdtp_cid){ 2775ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_bd_addr(remote); 27884521ac1SMilanka Ringwald if (connection){ 27984521ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2804567cc17SMilanka Ringwald } 28184521ac1SMilanka Ringwald 28236da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 2832ad6b656SMilanka Ringwald if (avdtp_cid != NULL) { 28484521ac1SMilanka Ringwald *avdtp_cid = cid; 2852ad6b656SMilanka Ringwald } 2862ad6b656SMilanka Ringwald 2875ace758fSMilanka Ringwald connection = avdtp_create_connection(remote, cid); 28836da8747SMilanka Ringwald if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED; 28936da8747SMilanka Ringwald 29084521ac1SMilanka Ringwald connection->avdtp_cid = cid; 291b1549ed3SMilanka Ringwald 2925797104aSMilanka Ringwald connection->avdtp_l2cap_psm = 0; 2935797104aSMilanka Ringwald connection->avdtp_version = 0; 2945797104aSMilanka Ringwald connection->sink_supported = false; 2955797104aSMilanka Ringwald connection->source_supported = false; 2965797104aSMilanka Ringwald 297b1549ed3SMilanka Ringwald switch (role){ 298149deddbSMilanka Ringwald case AVDTP_ROLE_SOURCE: 2995797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK; 300149deddbSMilanka Ringwald break; 301149deddbSMilanka Ringwald case AVDTP_ROLE_SINK: 3025797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE; 303149deddbSMilanka Ringwald break; 304149deddbSMilanka Ringwald default: 3055797104aSMilanka Ringwald btstack_assert(false); 306149deddbSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 307149deddbSMilanka Ringwald } 3085797104aSMilanka Ringwald 3095797104aSMilanka Ringwald avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query; 3105797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 3115797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 3125797104aSMilanka Ringwald return ERROR_CODE_SUCCESS; 313692c0605SMilanka Ringwald } 314747ec646SMilanka Ringwald 315a1fb0563SMilanka Ringwald 316a1fb0563SMilanka Ringwald void avdtp_register_sink_packet_handler(btstack_packet_handler_t callback){ 317a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 318a1fb0563SMilanka Ringwald avdtp_sink_callback = callback; 319a1fb0563SMilanka Ringwald } 320a1fb0563SMilanka Ringwald 321a1fb0563SMilanka Ringwald void avdtp_register_source_packet_handler(btstack_packet_handler_t callback){ 322a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 323a1fb0563SMilanka Ringwald avdtp_source_callback = callback; 324a1fb0563SMilanka Ringwald } 325a1fb0563SMilanka Ringwald 326747ec646SMilanka Ringwald void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){ 327747ec646SMilanka Ringwald if (!stream_endpoint){ 3289900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 329747ec646SMilanka Ringwald return; 330747ec646SMilanka Ringwald } 331747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1); 332747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 333747ec646SMilanka Ringwald } 334747ec646SMilanka Ringwald 335747ec646SMilanka Ringwald void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 336747ec646SMilanka Ringwald if (!stream_endpoint){ 3379900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 338747ec646SMilanka Ringwald return; 339747ec646SMilanka Ringwald } 340747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_REPORTING, 1); 341747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 342747ec646SMilanka Ringwald } 343747ec646SMilanka Ringwald 344747ec646SMilanka Ringwald void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 345747ec646SMilanka Ringwald if (!stream_endpoint){ 3469900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 347747ec646SMilanka Ringwald return; 348747ec646SMilanka Ringwald } 349747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_DELAY_REPORTING, 1); 350747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 351747ec646SMilanka Ringwald } 352747ec646SMilanka Ringwald 353747ec646SMilanka Ringwald void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){ 354747ec646SMilanka Ringwald if (!stream_endpoint){ 3559900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 356747ec646SMilanka Ringwald return; 357747ec646SMilanka Ringwald } 358747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_RECOVERY, 1); 359747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 360747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.recovery_type = 0x01; // 0x01 = RFC2733 361747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_recovery_window_size = maximum_recovery_window_size; 362747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_number_media_packets = maximum_number_media_packets; 363747ec646SMilanka Ringwald } 364747ec646SMilanka Ringwald 365747ec646SMilanka 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){ 366747ec646SMilanka Ringwald if (!stream_endpoint){ 3679900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 368747ec646SMilanka Ringwald return; 369747ec646SMilanka Ringwald } 370747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_CONTENT_PROTECTION, 1); 371747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 372747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type = cp_type; 3736535961aSMatthias Ringwald (void)memcpy(stream_endpoint->sep.capabilities.content_protection.cp_type_value, 3746535961aSMatthias Ringwald cp_type_value, 3756535961aSMatthias Ringwald btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN)); 37667ae582dSMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type_value_len = btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN); 377747ec646SMilanka Ringwald } 378747ec646SMilanka Ringwald 379747ec646SMilanka Ringwald void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery){ 380747ec646SMilanka Ringwald if (!stream_endpoint){ 3819900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 382747ec646SMilanka Ringwald return; 383747ec646SMilanka Ringwald } 384747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_HEADER_COMPRESSION, 1); 385747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 386747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.back_ch = back_ch; 387747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.media = media; 388747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.recovery = recovery; 389747ec646SMilanka Ringwald } 390747ec646SMilanka Ringwald 39178d08d09SMilanka 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){ 392747ec646SMilanka Ringwald if (!stream_endpoint){ 3939900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 394747ec646SMilanka Ringwald return; 395747ec646SMilanka Ringwald } 396747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1); 397747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 398747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_type = media_type; 399747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type; 400747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information = media_codec_info; 401747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information_len = media_codec_info_len; 402747ec646SMilanka Ringwald } 403747ec646SMilanka Ringwald 404747ec646SMilanka Ringwald void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation){ 405747ec646SMilanka Ringwald if (!stream_endpoint){ 4069900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 407747ec646SMilanka Ringwald return; 408747ec646SMilanka Ringwald } 409747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MULTIPLEXING, 1); 410747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 411747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.multiplexing_mode.fragmentation = fragmentation; 412747ec646SMilanka Ringwald } 413747ec646SMilanka Ringwald 414951d2774SMatthias Ringwald void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size)){ 415951d2774SMatthias Ringwald avdtp_sink_handle_media_data = callback; 416951d2774SMatthias Ringwald } 417747ec646SMilanka Ringwald 418747ec646SMilanka Ringwald /* START: tracking can send now requests pro l2cap cid */ 41977092f3eSMatthias Ringwald void avdtp_handle_can_send_now(avdtp_connection_t *connection, uint16_t l2cap_cid) { 420747ec646SMilanka Ringwald if (connection->wait_to_send_acceptor){ 421c6bc5965SMilanka Ringwald log_debug("call avdtp_acceptor_stream_config_subsm_run"); 422747ec646SMilanka Ringwald connection->wait_to_send_acceptor = 0; 42377092f3eSMatthias Ringwald avdtp_acceptor_stream_config_subsm_run(connection); 424747ec646SMilanka Ringwald } else if (connection->wait_to_send_initiator){ 425c6bc5965SMilanka Ringwald log_debug("call avdtp_initiator_stream_config_subsm_run"); 426747ec646SMilanka Ringwald connection->wait_to_send_initiator = 0; 42777092f3eSMatthias Ringwald avdtp_initiator_stream_config_subsm_run(connection); 428747ec646SMilanka Ringwald } 429747ec646SMilanka Ringwald 430747ec646SMilanka Ringwald // re-register 431f01aeca4SMilanka Ringwald bool more_to_send = connection->wait_to_send_acceptor || connection->wait_to_send_initiator; 432f01aeca4SMilanka 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); 433c6bc5965SMilanka Ringwald 434747ec646SMilanka Ringwald if (more_to_send){ 435747ec646SMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 436747ec646SMilanka Ringwald } 437747ec646SMilanka Ringwald } 438747ec646SMilanka Ringwald /* END: tracking can send now requests pro l2cap cid */ 439747ec646SMilanka Ringwald 440747ec646SMilanka Ringwald 441297feb5fSMilanka Ringwald avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){ 442747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = btstack_memory_avdtp_stream_endpoint_get(); 4434567cc17SMilanka Ringwald if (!stream_endpoint){ 4449900b7faSMilanka Ringwald log_error("Not enough memory to create stream endpoint"); 4454567cc17SMilanka Ringwald return NULL; 4464567cc17SMilanka Ringwald } 447560b3f31SMilanka Ringwald stream_endpoint->sep.seid = avdtp_get_next_local_seid(); 448747ec646SMilanka Ringwald stream_endpoint->sep.media_type = media_type; 449747ec646SMilanka Ringwald stream_endpoint->sep.type = sep_type; 450d8e15394SMilanka Ringwald btstack_linked_list_add(avdtp_get_stream_endpoints(), (btstack_linked_item_t *) stream_endpoint); 451747ec646SMilanka Ringwald return stream_endpoint; 452747ec646SMilanka Ringwald } 453747ec646SMilanka Ringwald 45417ddf501SMatthias Ringwald void avdtp_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ 45517ddf501SMatthias Ringwald btstack_linked_list_remove(avdtp_get_stream_endpoints(), (btstack_linked_item_t* ) stream_endpoint); 45617ddf501SMatthias Ringwald btstack_memory_avdtp_stream_endpoint_free(stream_endpoint); 45717ddf501SMatthias Ringwald } 45817ddf501SMatthias Ringwald 45977092f3eSMatthias Ringwald static void 46077092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t *connection, uint8_t *packet, uint16_t size) { 461c1c40ea1SMatthias Ringwald if (size < 2) return; 462c1c40ea1SMatthias Ringwald 463c1c40ea1SMatthias Ringwald uint16_t offset; 464c1c40ea1SMatthias Ringwald avdtp_message_type_t message_type = avdtp_get_signaling_packet_type(packet); 465c1c40ea1SMatthias Ringwald switch (message_type){ 466747ec646SMilanka Ringwald case AVDTP_CMD_MSG: 46750453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->acceptor_signaling_packet, packet, size); 46877092f3eSMatthias Ringwald avdtp_acceptor_stream_config_subsm(connection, packet, size, offset); 469747ec646SMilanka Ringwald break; 470747ec646SMilanka Ringwald default: 47150453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->initiator_signaling_packet, packet, size); 47277092f3eSMatthias Ringwald avdtp_initiator_stream_config_subsm(connection, packet, size, offset); 473747ec646SMilanka Ringwald break; 474747ec646SMilanka Ringwald } 475747ec646SMilanka Ringwald } 476747ec646SMilanka Ringwald 477b1549ed3SMilanka Ringwald static void avdtp_handle_sdp_client_query_attribute_value(avdtp_connection_t * connection, uint8_t *packet){ 478692c0605SMilanka Ringwald des_iterator_t des_list_it; 479692c0605SMilanka Ringwald des_iterator_t prot_it; 480692c0605SMilanka Ringwald 481692c0605SMilanka Ringwald // Handle new SDP record 482692c0605SMilanka Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id) { 483692c0605SMilanka Ringwald record_id = sdp_event_query_attribute_byte_get_record_id(packet); 4848587e32cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 485692c0605SMilanka Ringwald } 486692c0605SMilanka Ringwald 487692c0605SMilanka Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 488692c0605SMilanka Ringwald attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 489692c0605SMilanka Ringwald 490692c0605SMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 491692c0605SMilanka Ringwald 492692c0605SMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 493149deddbSMilanka Ringwald 494692c0605SMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 495692c0605SMilanka Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 496692c0605SMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 497692c0605SMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 498692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 499692c0605SMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 500692c0605SMilanka Ringwald switch (uuid){ 501692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE: 502b1549ed3SMilanka Ringwald connection->source_supported = true; 503149deddbSMilanka Ringwald log_info("source_supported"); 504692c0605SMilanka Ringwald break; 505692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK: 506b1549ed3SMilanka Ringwald connection->sink_supported = true; 507149deddbSMilanka Ringwald log_info("sink_supported"); 508692c0605SMilanka Ringwald break; 509692c0605SMilanka Ringwald default: 510692c0605SMilanka Ringwald break; 511692c0605SMilanka Ringwald } 512692c0605SMilanka Ringwald } 513692c0605SMilanka Ringwald break; 514692c0605SMilanka Ringwald 515149deddbSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 5168587e32cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 517692c0605SMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 518692c0605SMilanka Ringwald uint8_t *des_element; 519692c0605SMilanka Ringwald uint8_t *element; 520692c0605SMilanka Ringwald uint32_t uuid; 521692c0605SMilanka Ringwald 522692c0605SMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 523692c0605SMilanka Ringwald 524692c0605SMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 525692c0605SMilanka Ringwald des_iterator_init(&prot_it, des_element); 526692c0605SMilanka Ringwald element = des_iterator_get_element(&prot_it); 527692c0605SMilanka Ringwald 528692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 529692c0605SMilanka Ringwald 530692c0605SMilanka Ringwald uuid = de_get_uuid32(element); 53114fd128cSMatthias Ringwald des_iterator_next(&prot_it); 532149deddbSMilanka Ringwald // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both 533692c0605SMilanka Ringwald switch (uuid){ 534692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 535692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 536b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_l2cap_psm); 537692c0605SMilanka Ringwald break; 538692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_AVDTP: 539692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 540b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_version); 541692c0605SMilanka Ringwald break; 542692c0605SMilanka Ringwald default: 543692c0605SMilanka Ringwald break; 544692c0605SMilanka Ringwald } 545692c0605SMilanka Ringwald } 546692c0605SMilanka Ringwald break; 547149deddbSMilanka Ringwald 548692c0605SMilanka Ringwald default: 549692c0605SMilanka Ringwald break; 550692c0605SMilanka Ringwald } 551692c0605SMilanka Ringwald } 552692c0605SMilanka Ringwald } else { 5538587e32cSMilanka Ringwald log_error("SDP attribute value buffer size exceeded: available %d, required %d", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); 554692c0605SMilanka Ringwald } 5556ed344c3SMatthias Ringwald 5566ed344c3SMatthias Ringwald } 5576ed344c3SMatthias Ringwald 5585ace758fSMilanka Ringwald static void avdtp_finalize_connection(avdtp_connection_t * connection){ 559ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 5605ace758fSMilanka Ringwald btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection); 561f0c39502SMilanka Ringwald btstack_memory_avdtp_connection_free(connection); 562f0c39502SMilanka Ringwald } 563f0c39502SMilanka Ringwald 564f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_failed(avdtp_connection_t * connection, uint8_t status){ 565a1fb0563SMilanka Ringwald switch (connection->state){ 566a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 567c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, connection->remote_addr, status); 568a1fb0563SMilanka Ringwald break; 569a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 570c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, connection->remote_addr, status); 571a1fb0563SMilanka Ringwald break; 572a1fb0563SMilanka Ringwald default: 573a1fb0563SMilanka Ringwald return; 574a1fb0563SMilanka Ringwald } 5755ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 576ca2c9990SMilanka Ringwald sdp_query_context_avdtp_cid = 0; 577f0c39502SMilanka Ringwald log_info("SDP query failed with status 0x%02x.", status); 578f0c39502SMilanka Ringwald } 579f0c39502SMilanka Ringwald 580f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){ 581f0c39502SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 582f0c39502SMilanka Ringwald } 583f0c39502SMilanka Ringwald 5846ed344c3SMatthias Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 585149deddbSMilanka Ringwald UNUSED(packet_type); 586149deddbSMilanka Ringwald UNUSED(channel); 587149deddbSMilanka Ringwald UNUSED(size); 588149deddbSMilanka Ringwald 589ca2c9990SMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(sdp_query_context_avdtp_cid); 5906ed344c3SMatthias Ringwald if (!connection) { 591ca2c9990SMilanka Ringwald log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context_avdtp_cid); 5926ed344c3SMatthias Ringwald return; 5936ed344c3SMatthias Ringwald } 5946ed344c3SMatthias Ringwald 595722c03bdSMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 596149deddbSMilanka Ringwald switch (connection->state){ 597149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 5986ed344c3SMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 5996ed344c3SMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 600b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 601149deddbSMilanka Ringwald return; 602692c0605SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 6031e1ae2bcSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 604149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 605722c03bdSMatthias Ringwald if (!connection->sink_supported) { 606722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 607722c03bdSMatthias Ringwald break; 608722c03bdSMatthias Ringwald } 609722c03bdSMatthias Ringwald if (connection->avdtp_l2cap_psm == 0) { 610722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 611722c03bdSMatthias Ringwald break; 612722c03bdSMatthias Ringwald } 613149deddbSMilanka Ringwald break; 614149deddbSMilanka Ringwald default: 615149deddbSMilanka Ringwald btstack_assert(false); 616722c03bdSMatthias Ringwald return; 6171e1ae2bcSMilanka Ringwald } 618149deddbSMilanka Ringwald break; 619149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 620149deddbSMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 621149deddbSMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 622b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 623149deddbSMilanka Ringwald return; 624149deddbSMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 625149deddbSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 626149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 627722c03bdSMatthias Ringwald if (!connection->source_supported) { 628722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 629722c03bdSMatthias Ringwald break; 630722c03bdSMatthias Ringwald } 631722c03bdSMatthias Ringwald if (connection->avdtp_l2cap_psm == 0) { 632722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 633722c03bdSMatthias Ringwald break; 634722c03bdSMatthias Ringwald } 635149deddbSMilanka Ringwald break; 636149deddbSMilanka Ringwald default: 637149deddbSMilanka Ringwald btstack_assert(false); 638722c03bdSMatthias Ringwald return; 639974d4d6eSMilanka Ringwald } 6402f6083d0SMilanka Ringwald break; 641149deddbSMilanka Ringwald default: 64208cb850dSMilanka Ringwald // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete 64308cb850dSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 64408cb850dSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 64508cb850dSMilanka Ringwald } 646149deddbSMilanka Ringwald return; 6472f6083d0SMilanka Ringwald } 648f0c39502SMilanka Ringwald 649722c03bdSMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 650149deddbSMilanka Ringwald avdtp_handle_sdp_query_succeeded(connection); 651ed161adbSMilanka Ringwald l2cap_create_channel(avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 652149deddbSMilanka Ringwald } else { 653149deddbSMilanka Ringwald avdtp_handle_sdp_query_failed(connection, status); 654692c0605SMilanka Ringwald } 6555797104aSMilanka Ringwald 6565797104aSMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 6575797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 6585797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 659692c0605SMilanka Ringwald } 660692c0605SMilanka Ringwald 6615ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_handle_incoming_connection(avdtp_connection_t * connection, bd_addr_t event_addr, uint16_t local_cid){ 66236da8747SMilanka Ringwald if (connection == NULL){ 66336da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 6645ace758fSMilanka Ringwald connection = avdtp_create_connection(event_addr, cid); 66536da8747SMilanka Ringwald } 666692c0605SMilanka Ringwald 66736da8747SMilanka Ringwald if (connection) { 66836da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 66936da8747SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 670ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 67136da8747SMilanka Ringwald } 67236da8747SMilanka Ringwald return connection; 67336da8747SMilanka Ringwald } 674f0c39502SMilanka Ringwald 675ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 676326e3662SMilanka Ringwald uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 677326e3662SMilanka Ringwald 6785ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 679326e3662SMilanka Ringwald if (connection == NULL) return; 680326e3662SMilanka Ringwald 681ff53b162SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){ 682326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 683326e3662SMilanka Ringwald l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 684326e3662SMilanka Ringwald } 685326e3662SMilanka Ringwald } 686326e3662SMilanka Ringwald 687ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){ 688ff53b162SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler); 689ff53b162SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid); 690326e3662SMilanka Ringwald 691326e3662SMilanka Ringwald // add some jitter/randomness to reconnect delay 692326e3662SMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 693ff53b162SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 694ff53b162SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 695326e3662SMilanka Ringwald } 696326e3662SMilanka Ringwald 697326e3662SMilanka Ringwald 698326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 699747ec646SMilanka Ringwald bd_addr_t event_addr; 700747ec646SMilanka Ringwald uint16_t psm; 701747ec646SMilanka Ringwald uint16_t local_cid; 7021e1ae2bcSMilanka Ringwald uint8_t status; 703326e3662SMilanka Ringwald uint16_t l2cap_mtu; 70436da8747SMilanka Ringwald 70536da8747SMilanka Ringwald bool accept_streaming_connection; 70636da8747SMilanka Ringwald bool outoing_signaling_active; 70736da8747SMilanka Ringwald bool decline_connection; 70884521ac1SMilanka Ringwald 709747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = NULL; 710747ec646SMilanka Ringwald avdtp_connection_t * connection = NULL; 71136da8747SMilanka Ringwald 712747ec646SMilanka Ringwald switch (packet_type) { 713747ec646SMilanka Ringwald case L2CAP_DATA_PACKET: 7145ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 715747ec646SMilanka Ringwald if (connection){ 71677092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 717747ec646SMilanka Ringwald break; 718747ec646SMilanka Ringwald } 719747ec646SMilanka Ringwald 7206f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 721747ec646SMilanka Ringwald if (!stream_endpoint){ 722747ec646SMilanka Ringwald if (!connection) break; 72377092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 724747ec646SMilanka Ringwald break; 725747ec646SMilanka Ringwald } 726747ec646SMilanka Ringwald 7278c0f3635SMilanka Ringwald if (stream_endpoint->connection){ 7289413b167SMilanka Ringwald if (channel == stream_endpoint->connection->l2cap_signaling_cid){ 72977092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size); 730747ec646SMilanka Ringwald break; 731747ec646SMilanka Ringwald } 7328c0f3635SMilanka Ringwald } 733747ec646SMilanka Ringwald 734747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_media_cid){ 735951d2774SMatthias Ringwald btstack_assert(avdtp_sink_handle_media_data); 736951d2774SMatthias Ringwald (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size); 737747ec646SMilanka Ringwald break; 738747ec646SMilanka Ringwald } 739747ec646SMilanka Ringwald 740747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_reporting_cid){ 7418587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED"); 742747ec646SMilanka Ringwald } else if (channel == stream_endpoint->l2cap_recovery_cid){ 7438587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED"); 744747ec646SMilanka Ringwald } else { 745747ec646SMilanka Ringwald log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel); 746747ec646SMilanka Ringwald } 747747ec646SMilanka Ringwald break; 748747ec646SMilanka Ringwald 749747ec646SMilanka Ringwald case HCI_EVENT_PACKET: 750747ec646SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 75136da8747SMilanka Ringwald 752747ec646SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 753747ec646SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 754747ec646SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 75584521ac1SMilanka Ringwald 75636da8747SMilanka Ringwald outoing_signaling_active = false; 75736da8747SMilanka Ringwald accept_streaming_connection = false; 75836da8747SMilanka Ringwald 7595ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 76036da8747SMilanka Ringwald if (connection != NULL){ 7610d4a198eSMatthias Ringwald switch (connection->state){ 7620d4a198eSMatthias Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED: 76336da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 76436da8747SMilanka Ringwald outoing_signaling_active = true; 76536da8747SMilanka Ringwald connection->incoming_declined = true; 76636da8747SMilanka Ringwald break; 76736da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 76836da8747SMilanka Ringwald outoing_signaling_active = true; 76936da8747SMilanka Ringwald accept_streaming_connection = true; 77036da8747SMilanka Ringwald break; 771f0c39502SMilanka Ringwald default: 772f0c39502SMilanka Ringwald break; 7730d4a198eSMatthias Ringwald } 774747ec646SMilanka Ringwald } 77536da8747SMilanka Ringwald log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d", 77636da8747SMilanka Ringwald bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection); 777747ec646SMilanka Ringwald 77836da8747SMilanka Ringwald decline_connection = outoing_signaling_active && !accept_streaming_connection; 77936da8747SMilanka Ringwald if (outoing_signaling_active == false){ 7805ace758fSMilanka Ringwald connection = avdtp_handle_incoming_connection(connection, event_addr, local_cid); 78136da8747SMilanka Ringwald if (connection == NULL){ 78236da8747SMilanka Ringwald decline_connection = true; 78336da8747SMilanka Ringwald } 78436da8747SMilanka Ringwald } else if (accept_streaming_connection){ 78536da8747SMilanka Ringwald if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) { 78636da8747SMilanka Ringwald decline_connection = true; 78736da8747SMilanka Ringwald } else { 788939e12adSMatthias Ringwald // now, we're only dealing with media connections that are created by remote side - we're acceptor here 7896f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_with_seid(connection->acceptor_local_seid); 79036da8747SMilanka Ringwald if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) { 79136da8747SMilanka Ringwald decline_connection = true; 79236da8747SMilanka Ringwald } 79336da8747SMilanka Ringwald } 794747ec646SMilanka Ringwald } 795747ec646SMilanka Ringwald 79636da8747SMilanka Ringwald if (decline_connection){ 797a3ce0109SMatthias Ringwald l2cap_decline_connection(local_cid); 79836da8747SMilanka Ringwald } else { 799747ec646SMilanka Ringwald l2cap_accept_connection(local_cid); 80036da8747SMilanka Ringwald } 801747ec646SMilanka Ringwald break; 802747ec646SMilanka Ringwald 803747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 804a5114819SMilanka Ringwald 805a0b8a58cSMilanka Ringwald psm = l2cap_event_channel_opened_get_psm(packet); 80684e3541eSMilanka Ringwald if (psm != BLUETOOTH_PSM_AVDTP){ 807355ac553SMilanka Ringwald log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED "); 808a0b8a58cSMilanka Ringwald return; 809a0b8a58cSMilanka Ringwald } 810a0b8a58cSMilanka Ringwald 8111e1ae2bcSMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 812747ec646SMilanka Ringwald // inform about new l2cap connection 813747ec646SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 8147050d2caSMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 815326e3662SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 8165ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 81736da8747SMilanka Ringwald if (connection == NULL){ 81836da8747SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr)); 819a0b8a58cSMilanka Ringwald break; 820a0b8a58cSMilanka Ringwald } 821a0b8a58cSMilanka Ringwald 822a5114819SMilanka Ringwald switch (connection->state){ 823a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 824326e3662SMilanka Ringwald switch (status){ 825326e3662SMilanka Ringwald case ERROR_CODE_SUCCESS: 826326e3662SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 827326e3662SMilanka Ringwald connection->incoming_declined = false; 828326e3662SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 829326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_OPENED; 830326e3662SMilanka Ringwald log_info("Connection opened l2cap_signaling_cid 0x%02x, avdtp_cid 0x%02x", connection->l2cap_signaling_cid, connection->avdtp_cid); 831c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, 832c69f4ba5SMatthias Ringwald status); 833326e3662SMilanka Ringwald return; 834326e3662SMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 835326e3662SMilanka Ringwald if (connection->incoming_declined == true) { 836326e3662SMilanka Ringwald log_info("Connection was declined, and the outgoing failed"); 837ff53b162SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY; 838326e3662SMilanka Ringwald connection->incoming_declined = false; 839ff53b162SMilanka Ringwald avdtp_retry_timer_start(connection); 840326e3662SMilanka Ringwald return; 841326e3662SMilanka Ringwald } 842326e3662SMilanka Ringwald break; 843326e3662SMilanka Ringwald default: 844326e3662SMilanka Ringwald log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 845326e3662SMilanka Ringwald break; 846326e3662SMilanka Ringwald } 847c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, status); 848f82b60efSMilanka Ringwald avdtp_finalize_connection(connection); 849a0b8a58cSMilanka Ringwald break; 850747ec646SMilanka Ringwald 851a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 85219a000d1SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid); 853747ec646SMilanka Ringwald if (!stream_endpoint){ 8545bd73fa2SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid); 855747ec646SMilanka Ringwald return; 856747ec646SMilanka Ringwald } 857326e3662SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 858355ac553SMilanka 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)); 859a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 860f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, status); 861a466d508SMilanka Ringwald break; 862a466d508SMilanka Ringwald } 863a5114819SMilanka Ringwald switch (stream_endpoint->state){ 864a5114819SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED: 865a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED; 866a466d508SMilanka Ringwald stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet); 867a466d508SMilanka Ringwald stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet); 868d1207cd8SMilanka Ringwald 869355ac553SMilanka 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)); 870f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS); 871a5114819SMilanka Ringwald break; 872a5114819SMilanka Ringwald default: 873a5114819SMilanka 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)); 87423edb87eSMilanka Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_COMMAND_DISALLOWED); 875a5114819SMilanka Ringwald break; 876a5114819SMilanka Ringwald } 877a5114819SMilanka Ringwald break; 878a5114819SMilanka Ringwald 879a5114819SMilanka Ringwald default: 880326e3662SMilanka Ringwald log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state); 881a5114819SMilanka Ringwald break; 882a5114819SMilanka Ringwald } 883747ec646SMilanka Ringwald break; 884747ec646SMilanka Ringwald 885747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 886747ec646SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 8876f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid); 8885ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid); 88936da8747SMilanka Ringwald 890f01aeca4SMilanka Ringwald log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint); 891f01aeca4SMilanka Ringwald 892a466d508SMilanka Ringwald if (stream_endpoint){ 893a466d508SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == local_cid){ 894a466d508SMilanka Ringwald connection = stream_endpoint->connection; 895596b7fdcSMilanka Ringwald if (connection) { 896f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_released(stream_endpoint, 897f751daa3SMatthias Ringwald connection->avdtp_cid, 898f751daa3SMatthias Ringwald avdtp_local_seid(stream_endpoint)); 899596b7fdcSMilanka Ringwald } 900485c0a4cSMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 901a466d508SMilanka Ringwald break; 902a466d508SMilanka Ringwald } 903a466d508SMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == local_cid){ 904355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid); 905a466d508SMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0; 906a466d508SMilanka Ringwald break; 907a466d508SMilanka Ringwald } 908a466d508SMilanka Ringwald 909a466d508SMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == local_cid){ 910355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid); 911a466d508SMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0; 912a466d508SMilanka Ringwald break; 913a466d508SMilanka Ringwald } 914a466d508SMilanka Ringwald } 915596b7fdcSMilanka Ringwald 916596b7fdcSMilanka Ringwald if (connection){ 917596b7fdcSMilanka Ringwald btstack_linked_list_iterator_t it; 918d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 919596b7fdcSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 920f01aeca4SMilanka Ringwald stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 921f01aeca4SMilanka Ringwald if (stream_endpoint->connection == connection){ 922f01aeca4SMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 923596b7fdcSMilanka Ringwald } 924596b7fdcSMilanka Ringwald } 925c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_released(connection->avdtp_cid); 9265ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 927596b7fdcSMilanka Ringwald break; 928596b7fdcSMilanka Ringwald } 929747ec646SMilanka Ringwald break; 930747ec646SMilanka Ringwald 931747ec646SMilanka Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 932747ec646SMilanka Ringwald break; 933747ec646SMilanka Ringwald 934747ec646SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 935c6bc5965SMilanka Ringwald log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel); 9365ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 937747ec646SMilanka Ringwald if (!connection) { 9386f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 939747ec646SMilanka Ringwald if (!stream_endpoint->connection) break; 940747ec646SMilanka Ringwald connection = stream_endpoint->connection; 941747ec646SMilanka Ringwald } 94277092f3eSMatthias Ringwald avdtp_handle_can_send_now(connection, channel); 943747ec646SMilanka Ringwald break; 944747ec646SMilanka Ringwald default: 945355ac553SMilanka Ringwald log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet)); 946747ec646SMilanka Ringwald break; 947747ec646SMilanka Ringwald } 948747ec646SMilanka Ringwald break; 949747ec646SMilanka Ringwald 950747ec646SMilanka Ringwald default: 951747ec646SMilanka Ringwald // other packet type 952747ec646SMilanka Ringwald break; 953747ec646SMilanka Ringwald } 954747ec646SMilanka Ringwald } 955747ec646SMilanka Ringwald 956b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){ 9575ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 95823edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 959b401ff59SMilanka Ringwald 960a466d508SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS; 961747ec646SMilanka Ringwald 962f01aeca4SMilanka Ringwald btstack_linked_list_iterator_t it; 963f01aeca4SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 964f01aeca4SMilanka Ringwald 965f01aeca4SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 966f01aeca4SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 967f01aeca4SMilanka Ringwald if (stream_endpoint->connection != connection) continue; 968f01aeca4SMilanka Ringwald 969f01aeca4SMilanka Ringwald switch (stream_endpoint->state){ 970f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_OPENED: 971f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_STREAMING: 972f01aeca4SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED; 973f01aeca4SMilanka Ringwald l2cap_disconnect(stream_endpoint->l2cap_media_cid, 0); 974f01aeca4SMilanka Ringwald break; 975f01aeca4SMilanka Ringwald default: 976f01aeca4SMilanka Ringwald break; 977f01aeca4SMilanka Ringwald } 978f01aeca4SMilanka Ringwald } 979f01aeca4SMilanka Ringwald 980f01aeca4SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED; 981f01aeca4SMilanka Ringwald l2cap_disconnect(connection->l2cap_signaling_cid, 0); 9824ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 983747ec646SMilanka Ringwald } 984747ec646SMilanka Ringwald 985297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){ 9865ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 987747ec646SMilanka Ringwald if (!connection){ 9888587e32cSMilanka Ringwald log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid); 98923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 990747ec646SMilanka Ringwald } 991747ec646SMilanka Ringwald 992747ec646SMilanka Ringwald if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) { 9938587e32cSMilanka Ringwald log_error("avdtp_media_connect: wrong connection state %d", connection->state); 99423edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 995747ec646SMilanka Ringwald } 996747ec646SMilanka Ringwald 9976f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 998747ec646SMilanka Ringwald if (!stream_endpoint) { 9996b0ee1d0SMilanka Ringwald log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid); 100023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1001747ec646SMilanka Ringwald } 1002747ec646SMilanka Ringwald 1003485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid != remote_seid){ 1004485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid); 100523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1006485c0a4cSMilanka Ringwald } 1007485c0a4cSMilanka Ringwald 100823edb87eSMilanka Ringwald if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return ERROR_CODE_COMMAND_DISALLOWED; 1009747ec646SMilanka Ringwald 1010*b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 101196dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 10125bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1013747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM; 1014747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM; 10159413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 10164ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1017747ec646SMilanka Ringwald } 1018747ec646SMilanka Ringwald 1019297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10205ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 102146e6b063SMilanka Ringwald if (!connection){ 10224ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 102323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 102446e6b063SMilanka Ringwald } 10255cfe7f4cSMilanka Ringwald 10266f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 10274ccacc40SMilanka Ringwald if (!stream_endpoint) { 10284ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid); 102923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10304ccacc40SMilanka Ringwald } 10314ccacc40SMilanka Ringwald 10324ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 10334ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid); 103423edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10354ccacc40SMilanka Ringwald } 10364ccacc40SMilanka Ringwald 1037485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 1038485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep registered with the stream endpoint"); 103923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10404ccacc40SMilanka Ringwald } 10414ccacc40SMilanka Ringwald 1042440d8d82SMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){ 1043440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1044440d8d82SMilanka Ringwald } 1045440d8d82SMilanka Ringwald 104660ec20d0SMilanka Ringwald stream_endpoint->start_stream = 1; 10475bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 104896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 10499413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 10504ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1051747ec646SMilanka Ringwald } 1052747ec646SMilanka Ringwald 1053297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10545ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1055747ec646SMilanka Ringwald if (!connection){ 10564ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 105723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1058747ec646SMilanka Ringwald } 10594ccacc40SMilanka Ringwald 10606f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 10614ccacc40SMilanka Ringwald if (!stream_endpoint) { 10624ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid); 106323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10644ccacc40SMilanka Ringwald } 10654ccacc40SMilanka Ringwald 10664ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 10674ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid); 106823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10694ccacc40SMilanka Ringwald } 1070485c0a4cSMilanka Ringwald 1071485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->stop_stream){ 1072440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1073485c0a4cSMilanka Ringwald } 10744ccacc40SMilanka Ringwald 107560ec20d0SMilanka Ringwald stream_endpoint->stop_stream = 1; 10765bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 107796dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 10789413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 10794ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1080747ec646SMilanka Ringwald } 1081747ec646SMilanka Ringwald 1082297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10835ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 108460ec20d0SMilanka Ringwald if (!connection){ 10854ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 108623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1087747ec646SMilanka Ringwald } 10884ccacc40SMilanka Ringwald 10896f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 10904ccacc40SMilanka Ringwald if (!stream_endpoint) { 10914ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid); 109223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10934ccacc40SMilanka Ringwald } 10944ccacc40SMilanka Ringwald 10954ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 10964ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid); 109723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10984ccacc40SMilanka Ringwald } 1099485c0a4cSMilanka Ringwald 1100485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){ 1101440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1102485c0a4cSMilanka Ringwald } 11034ccacc40SMilanka Ringwald 110460ec20d0SMilanka Ringwald stream_endpoint->abort_stream = 1; 11055bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 110696dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 11079413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 11084ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1109747ec646SMilanka Ringwald } 1110747ec646SMilanka Ringwald 1111297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11125ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1113747ec646SMilanka Ringwald if (!connection){ 11144ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 111523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 111660ec20d0SMilanka Ringwald } 11176f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 11184ccacc40SMilanka Ringwald if (!stream_endpoint) { 11194ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid); 112023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11214ccacc40SMilanka Ringwald } 11224ccacc40SMilanka Ringwald 11234ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11244ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid); 112523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11264ccacc40SMilanka Ringwald } 1127485c0a4cSMilanka Ringwald 1128485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){ 1129440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1130485c0a4cSMilanka Ringwald } 11314ccacc40SMilanka Ringwald 113260ec20d0SMilanka Ringwald stream_endpoint->suspend_stream = 1; 11335bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 113496dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 11359413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 11364ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1137747ec646SMilanka Ringwald } 1138747ec646SMilanka Ringwald 11395ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){ 11405ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1141747ec646SMilanka Ringwald if (!connection){ 11428587e32cSMilanka Ringwald log_error("avdtp_discover_stream_endpoints: no connection for signaling cid 0x%02x found", avdtp_cid); 114323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11449974aee0SMilanka Ringwald } 11450e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1146c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 114723edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1148747ec646SMilanka Ringwald } 1149ec3d71e3SMilanka Ringwald 1150*b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1151747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS; 11529974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1153747ec646SMilanka Ringwald } 1154747ec646SMilanka Ringwald 1155747ec646SMilanka Ringwald 11565ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 11575ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1158747ec646SMilanka Ringwald if (!connection){ 11599900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 116023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1161747ec646SMilanka Ringwald } 11620e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1163c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 116423edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 11659974aee0SMilanka Ringwald } 11669974aee0SMilanka Ringwald 1167*b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1168747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 116996dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 11709974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1171747ec646SMilanka Ringwald } 1172747ec646SMilanka Ringwald 1173747ec646SMilanka Ringwald 11745ace758fSMilanka Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 11755ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1176747ec646SMilanka Ringwald if (!connection){ 11779900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 117823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1179747ec646SMilanka Ringwald } 11800e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1181c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 118223edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 11839974aee0SMilanka Ringwald } 11849974aee0SMilanka Ringwald 1185*b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1186747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 118796dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 11889974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1189747ec646SMilanka Ringwald } 1190747ec646SMilanka Ringwald 11915ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){ 11925ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1193747ec646SMilanka Ringwald if (!connection){ 11949900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 119523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1196747ec646SMilanka Ringwald } 11970e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1198c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 119923edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12009974aee0SMilanka Ringwald } 12019974aee0SMilanka Ringwald 1202*b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1203747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION; 120496dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 12059974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1206747ec646SMilanka Ringwald } 1207747ec646SMilanka Ringwald 1208cec76c5bSMilanka 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){ 12095ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1210747ec646SMilanka Ringwald if (!connection){ 12119900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 121223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1213747ec646SMilanka Ringwald } 12140e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1215c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 1216485c0a4cSMilanka Ringwald log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state); 121723edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12189974aee0SMilanka Ringwald } 1219a3ce0109SMatthias Ringwald if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){ 1220a3ce0109SMatthias Ringwald log_info("configuration already started, config state %u", connection->configuration_state); 122123edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1222a3ce0109SMatthias Ringwald } 1223747ec646SMilanka Ringwald 1224d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1225747ec646SMilanka Ringwald if (!stream_endpoint) { 12269900b7faSMilanka Ringwald log_error("No initiator stream endpoint for seid %d", local_seid); 122723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1228747ec646SMilanka Ringwald } 1229417b4996SMilanka Ringwald if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){ 1230485c0a4cSMilanka Ringwald log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state); 123123edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1232417b4996SMilanka Ringwald } 1233a3ce0109SMatthias Ringwald 1234bdbc3ef6SMilanka Ringwald connection->active_stream_endpoint = (void*) stream_endpoint; 1235a3ce0109SMatthias Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED; 1236747ec646SMilanka Ringwald 1237*b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 123896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 12395bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1240f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1241f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1242747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION; 1243ffa6c160SMilanka Ringwald 1244ffa6c160SMilanka Ringwald // cache media codec information for SBC 1245ffa6c160SMilanka Ringwald stream_endpoint->media_codec_type = configuration.media_codec.media_codec_type; 1246ffa6c160SMilanka Ringwald if (configuration.media_codec.media_codec_type == AVDTP_CODEC_SBC){ 1247ffa6c160SMilanka Ringwald stream_endpoint->media_type = configuration.media_codec.media_type; 12486535961aSMatthias Ringwald (void)memcpy(stream_endpoint->media_codec_sbc_info, 12496535961aSMatthias Ringwald configuration.media_codec.media_codec_information, 4); 1250ffa6c160SMilanka Ringwald } 12519974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1252747ec646SMilanka Ringwald } 1253747ec646SMilanka Ringwald 1254cec76c5bSMilanka 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){ 12555ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1256747ec646SMilanka Ringwald if (!connection){ 12579900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 125823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1259747ec646SMilanka Ringwald } 1260747ec646SMilanka Ringwald //TODO: if opened only app capabilities, enable reconfigure for not opened 12610e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1262c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 126323edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12649974aee0SMilanka Ringwald } 12659e42cfccSMilanka Ringwald 1266d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 126778d08d09SMilanka Ringwald if (!stream_endpoint) { 12684ccacc40SMilanka Ringwald log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid); 126923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 127078d08d09SMilanka Ringwald } 127178d08d09SMilanka Ringwald 1272485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 12738587e32cSMilanka Ringwald log_error("avdtp_reconfigure: no associated remote sep"); 127423edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 127578d08d09SMilanka Ringwald } 1276485c0a4cSMilanka Ringwald 1277*b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 127896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 12795bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1280f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1281f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1282747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID; 12839974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1284747ec646SMilanka Ringwald } 1285747ec646SMilanka Ringwald 12868e7044f9SMatthias Ringwald void avdtp_set_preferred_sampling_frequeny(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){ 12878e7044f9SMatthias Ringwald stream_endpoint->preferred_sampling_frequency = sampling_frequency; 12888e7044f9SMatthias Ringwald } 12898e7044f9SMatthias Ringwald 129078d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){ 129178d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 129278d08d09SMilanka Ringwald uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap; 129378d08d09SMilanka Ringwald 129478d08d09SMilanka Ringwald uint8_t channel_mode = AVDTP_SBC_STEREO; 129578d08d09SMilanka Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 129678d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_JOINT_STEREO; 129778d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 129878d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_STEREO; 129978d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 130078d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_DUAL_CHANNEL; 130178d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_MONO){ 130278d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_MONO; 130378d08d09SMilanka Ringwald } 130478d08d09SMilanka Ringwald return channel_mode; 130578d08d09SMilanka Ringwald } 130678d08d09SMilanka Ringwald 130778d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){ 130878d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 130978d08d09SMilanka Ringwald uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap; 131078d08d09SMilanka Ringwald 131178d08d09SMilanka Ringwald uint8_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 131278d08d09SMilanka Ringwald if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){ 131378d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 131478d08d09SMilanka Ringwald } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){ 131578d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR; 131678d08d09SMilanka Ringwald } 131778d08d09SMilanka Ringwald return allocation_method; 131878d08d09SMilanka Ringwald } 131978d08d09SMilanka Ringwald 1320bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){ 1321bd1ecb8aSMilanka Ringwald if (!stream_endpoint) return 0; 1322bd1ecb8aSMilanka Ringwald return stream_endpoint->sep.seid; 1323bd1ecb8aSMilanka Ringwald } 132478d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){ 132567ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 132678d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 132778d08d09SMilanka Ringwald uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap; 132878d08d09SMilanka Ringwald 132978d08d09SMilanka Ringwald uint8_t subbands = AVDTP_SBC_SUBBANDS_8; 133078d08d09SMilanka Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 133178d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_8; 133278d08d09SMilanka Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 133378d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_4; 133478d08d09SMilanka Ringwald } 133578d08d09SMilanka Ringwald return subbands; 133678d08d09SMilanka Ringwald } 133778d08d09SMilanka Ringwald 133878d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){ 133967ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 134078d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 134178d08d09SMilanka Ringwald uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap; 134278d08d09SMilanka Ringwald 134378d08d09SMilanka Ringwald uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16; 134478d08d09SMilanka Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 134578d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_16; 134678d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 134778d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_12; 134878d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 134978d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_8; 135078d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 135178d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_4; 135278d08d09SMilanka Ringwald } 135378d08d09SMilanka Ringwald return block_length; 135478d08d09SMilanka Ringwald } 135578d08d09SMilanka Ringwald 135678d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){ 135767ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 135878d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 13598e7044f9SMatthias Ringwald uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap; 136078d08d09SMilanka Ringwald 13618e7044f9SMatthias Ringwald // use preferred sampling frequency if possible 13628e7044f9SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){ 13636ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 13648e7044f9SMatthias Ringwald } 13656ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){ 13666ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 13676ed344c3SMatthias Ringwald } 13686ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){ 13696ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 13706ed344c3SMatthias Ringwald } 13716ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){ 13726ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 13736ed344c3SMatthias Ringwald } 13746ed344c3SMatthias Ringwald 13758e7044f9SMatthias Ringwald // otherwise, use highest available 13766ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_48000){ 13776ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 137878d08d09SMilanka Ringwald } 13796ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_44100){ 13806ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 13816ed344c3SMatthias Ringwald } 13826ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_32000){ 13836ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 13846ed344c3SMatthias Ringwald } 13856ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_16000){ 13866ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 13876ed344c3SMatthias Ringwald } 13886ed344c3SMatthias Ringwald return AVDTP_SBC_44100; // some default 138978d08d09SMilanka Ringwald } 139078d08d09SMilanka Ringwald 139178d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){ 139267ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 139378d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 139478d08d09SMilanka Ringwald return btstack_min(media_codec[3], remote_max_bitpool_value); 139578d08d09SMilanka Ringwald } 139678d08d09SMilanka Ringwald 139778d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){ 139867ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 139978d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 140078d08d09SMilanka Ringwald return btstack_max(media_codec[2], remote_min_bitpool_value); 1401747ec646SMilanka Ringwald } 1402485c0a4cSMilanka Ringwald 1403485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){ 1404485c0a4cSMilanka Ringwald if (!stream_endpoint) return 0; 1405485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid == 0) return 0; 1406485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid > 0x3E) return 0; 1407485c0a4cSMilanka Ringwald return 1; 1408485c0a4cSMilanka Ringwald } 14098322fb3aSMatthias Ringwald 14108322fb3aSMatthias Ringwald void avdtp_init(void){ 14118322fb3aSMatthias Ringwald static bool l2cap_registered = false; 14128322fb3aSMatthias Ringwald if (!l2cap_registered){ 14138322fb3aSMatthias Ringwald l2cap_registered = true; 14148322fb3aSMatthias Ringwald l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, 0xffff, gap_get_security_level()); 14158322fb3aSMatthias Ringwald } 14168322fb3aSMatthias Ringwald } 1417