1747ec646SMilanka Ringwald /* 2747ec646SMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3747ec646SMilanka Ringwald * 4747ec646SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5747ec646SMilanka Ringwald * modification, are permitted provided that the following conditions 6747ec646SMilanka Ringwald * are met: 7747ec646SMilanka Ringwald * 8747ec646SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9747ec646SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10747ec646SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11747ec646SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12747ec646SMilanka Ringwald * documentation and/or other materials provided with the distribution. 13747ec646SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14747ec646SMilanka Ringwald * contributors may be used to endorse or promote products derived 15747ec646SMilanka Ringwald * from this software without specific prior written permission. 16747ec646SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17747ec646SMilanka Ringwald * personal benefit and not for any commercial purpose or for 18747ec646SMilanka Ringwald * monetary gain. 19747ec646SMilanka Ringwald * 20747ec646SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21747ec646SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22747ec646SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23747ec646SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24747ec646SMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25747ec646SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26747ec646SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27747ec646SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28747ec646SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29747ec646SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30747ec646SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31747ec646SMilanka Ringwald * SUCH DAMAGE. 32747ec646SMilanka Ringwald * 33747ec646SMilanka Ringwald * Please inquire about commercial licensing options at 34747ec646SMilanka Ringwald * [email protected] 35747ec646SMilanka Ringwald * 36747ec646SMilanka Ringwald */ 37747ec646SMilanka Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avdtp.c" 39ab2c6ae4SMatthias Ringwald 40747ec646SMilanka Ringwald 41747ec646SMilanka Ringwald #include <stdint.h> 42747ec646SMilanka Ringwald #include <string.h> 43747ec646SMilanka Ringwald 4484e3541eSMilanka Ringwald #include "bluetooth_psm.h" 4584e3541eSMilanka Ringwald #include "bluetooth_sdp.h" 4684e3541eSMilanka Ringwald #include "btstack_debug.h" 4784e3541eSMilanka Ringwald #include "btstack_event.h" 4884e3541eSMilanka Ringwald #include "btstack_memory.h" 494cb889a5SMilanka Ringwald #include "classic/avdtp.h" 504cb889a5SMilanka Ringwald #include "classic/avdtp_acceptor.h" 514cb889a5SMilanka Ringwald #include "classic/avdtp_initiator.h" 5284e3541eSMilanka Ringwald #include "classic/avdtp_util.h" 5384e3541eSMilanka Ringwald #include "classic/sdp_client.h" 5484e3541eSMilanka Ringwald #include "classic/sdp_util.h" 55747ec646SMilanka Ringwald 56d8e15394SMilanka Ringwald btstack_linked_list_t stream_endpoints; 57d8e15394SMilanka Ringwald 58a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_source_callback; 59a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_sink_callback; 605797104aSMilanka Ringwald static btstack_context_callback_registration_t avdtp_handle_sdp_client_query_request; 61a1fb0563SMilanka Ringwald 62ca2c9990SMilanka Ringwald static uint16_t sdp_query_context_avdtp_cid = 0; 63f0c39502SMilanka Ringwald 64560b3f31SMilanka Ringwald static uint16_t stream_endpoints_id_counter = 0; 65560b3f31SMilanka Ringwald 665ace758fSMilanka Ringwald static btstack_linked_list_t connections; 67b1935866SMilanka Ringwald static uint16_t transaction_id_counter = 0; 685ace758fSMilanka Ringwald 69692c0605SMilanka Ringwald static int record_id = -1; 70fa1ee4d3SMilanka Ringwald static uint8_t attribute_value[45]; 71692c0605SMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); 72747ec646SMilanka Ringwald 73951d2774SMatthias Ringwald static void (*avdtp_sink_handle_media_data)(uint8_t local_seid, uint8_t *packet, uint16_t size); 74951d2774SMatthias Ringwald 75af121d54SMilanka Ringwald static uint16_t avdtp_cid_counter = 0; 76747ec646SMilanka Ringwald 77692c0605SMilanka Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 78692c0605SMilanka Ringwald 79f751daa3SMatthias Ringwald btstack_packet_handler_t 80f751daa3SMatthias Ringwald avdtp_packet_handler_for_stream_endpoint(const avdtp_stream_endpoint_t *stream_endpoint) { 81f751daa3SMatthias Ringwald return (stream_endpoint->sep.type == AVDTP_SOURCE) ? avdtp_source_callback : avdtp_sink_callback; 82f751daa3SMatthias Ringwald } 83f751daa3SMatthias Ringwald 84c69f4ba5SMatthias Ringwald void avdtp_emit_sink_and_source(uint8_t * packet, uint16_t size){ 85c69f4ba5SMatthias Ringwald if (avdtp_source_callback != NULL){ 86c69f4ba5SMatthias Ringwald (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size); 87c69f4ba5SMatthias Ringwald } 88c69f4ba5SMatthias Ringwald if (avdtp_sink_callback != NULL){ 89c69f4ba5SMatthias Ringwald (*avdtp_sink_callback)(HCI_EVENT_PACKET, 0, packet, size); 90c69f4ba5SMatthias Ringwald } 91c69f4ba5SMatthias Ringwald } 92c69f4ba5SMatthias Ringwald 934b7d40bbSMatthias Ringwald void avdtp_emit_source(uint8_t * packet, uint16_t size){ 944b7d40bbSMatthias Ringwald if (avdtp_source_callback != NULL){ 954b7d40bbSMatthias Ringwald (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size); 96f751daa3SMatthias Ringwald } 97f08f4934SMatthias Ringwald } 98f08f4934SMatthias Ringwald 99f751daa3SMatthias Ringwald btstack_linked_list_t * avdtp_get_stream_endpoints(void){ 100f751daa3SMatthias Ringwald return &stream_endpoints; 101f751daa3SMatthias Ringwald } 10236da8747SMilanka Ringwald 10362c4ec82SMilanka Ringwald btstack_linked_list_t * avdtp_get_connections(void){ 10462c4ec82SMilanka Ringwald return &connections; 10562c4ec82SMilanka Ringwald } 10662c4ec82SMilanka Ringwald 1075ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_get_connection_for_bd_addr(bd_addr_t addr){ 1085ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 1095ace758fSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 1105ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1115ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 1125ace758fSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 1135ace758fSMilanka Ringwald return connection; 114b0d75c91SMilanka Ringwald } 1155ace758fSMilanka Ringwald return NULL; 116b0d75c91SMilanka Ringwald } 117b0d75c91SMilanka Ringwald 1185ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_avdtp_cid(uint16_t avdtp_cid){ 1195ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 1205ace758fSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 1215ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1225ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 1235ace758fSMilanka Ringwald if (connection->avdtp_cid != avdtp_cid) continue; 1245ace758fSMilanka Ringwald return connection; 1255ace758fSMilanka Ringwald } 1265ace758fSMilanka Ringwald return NULL; 1275ace758fSMilanka Ringwald } 1285ace758fSMilanka Ringwald 1295ace758fSMilanka Ringwald 1303338afc0SMatthias 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 185b1935866SMilanka Ringwald uint16_t avdtp_get_next_transaction_label(void){ 186b1935866SMilanka Ringwald transaction_id_counter++; 187b1935866SMilanka Ringwald if (transaction_id_counter == 16){ 188b1935866SMilanka Ringwald transaction_id_counter = 1; 1895ace758fSMilanka Ringwald } 190b1935866SMilanka Ringwald return transaction_id_counter; 1915ace758fSMilanka Ringwald } 1925ace758fSMilanka Ringwald 1935ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_create_connection(bd_addr_t remote_addr, uint16_t cid){ 19436da8747SMilanka Ringwald avdtp_connection_t * connection = btstack_memory_avdtp_connection_get(); 19536da8747SMilanka Ringwald if (!connection){ 19636da8747SMilanka Ringwald log_error("Not enough memory to create connection"); 19736da8747SMilanka Ringwald return NULL; 19836da8747SMilanka Ringwald } 19936da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_IDLE; 200b1935866SMilanka Ringwald connection->initiator_transaction_label = avdtp_get_next_transaction_label(); 20136da8747SMilanka Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE; 20262c4ec82SMilanka Ringwald connection->a2dp_source_discover_seps = false; 20336da8747SMilanka Ringwald connection->avdtp_cid = cid; 20436da8747SMilanka Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 20536da8747SMilanka Ringwald 2065ace758fSMilanka Ringwald btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection); 20736da8747SMilanka Ringwald return connection; 20836da8747SMilanka Ringwald } 20936da8747SMilanka Ringwald 21036da8747SMilanka Ringwald static uint16_t avdtp_get_next_cid(void){ 211af121d54SMilanka Ringwald if (avdtp_cid_counter == 0xffff) { 2124ccacc40SMilanka Ringwald avdtp_cid_counter = 1; 213af121d54SMilanka Ringwald } else { 214af121d54SMilanka Ringwald avdtp_cid_counter++; 2154ccacc40SMilanka Ringwald } 2164ccacc40SMilanka Ringwald return avdtp_cid_counter; 2174ccacc40SMilanka Ringwald } 2184ccacc40SMilanka Ringwald 219560b3f31SMilanka Ringwald static uint16_t avdtp_get_next_local_seid(void){ 220560b3f31SMilanka Ringwald if (stream_endpoints_id_counter == 0xffff) { 221560b3f31SMilanka Ringwald stream_endpoints_id_counter = 1; 222af121d54SMilanka Ringwald } else { 223560b3f31SMilanka Ringwald stream_endpoints_id_counter++; 2244ccacc40SMilanka Ringwald } 225560b3f31SMilanka Ringwald return stream_endpoints_id_counter; 2264ccacc40SMilanka Ringwald } 2274ccacc40SMilanka Ringwald 2285797104aSMilanka Ringwald static void avdtp_handle_start_sdp_client_query(void * context){ 2295797104aSMilanka Ringwald UNUSED(context); 230b1549ed3SMilanka Ringwald 2315797104aSMilanka Ringwald btstack_linked_list_iterator_t it; 2325797104aSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 2335797104aSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2345797104aSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 2355797104aSMilanka Ringwald 2365797104aSMilanka Ringwald switch (connection->state){ 2375797104aSMilanka Ringwald case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE: 2385797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE; 2395797104aSMilanka Ringwald break; 2405797104aSMilanka Ringwald case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK: 2415797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE; 2425797104aSMilanka Ringwald break; 243cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 244cc61e7e9SMilanka Ringwald if (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES) continue; 245cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SDP_QUERY_COMPLETE_THEN_GET_ALL_CAPABILITIES; 246cc61e7e9SMilanka Ringwald break; 2475797104aSMilanka Ringwald default: 2485797104aSMilanka Ringwald continue; 2495797104aSMilanka Ringwald } 2505797104aSMilanka Ringwald sdp_query_context_avdtp_cid = connection->avdtp_cid; 2515797104aSMilanka Ringwald sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP); 2525797104aSMilanka Ringwald return; 2535797104aSMilanka Ringwald } 25484521ac1SMilanka Ringwald } 25584521ac1SMilanka Ringwald 256a1fb0563SMilanka Ringwald uint8_t avdtp_connect(bd_addr_t remote, avdtp_role_t role, uint16_t * avdtp_cid){ 2575ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_bd_addr(remote); 25884521ac1SMilanka Ringwald if (connection){ 25984521ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 2604567cc17SMilanka Ringwald } 26184521ac1SMilanka Ringwald 26236da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 2632ad6b656SMilanka Ringwald if (avdtp_cid != NULL) { 26484521ac1SMilanka Ringwald *avdtp_cid = cid; 2652ad6b656SMilanka Ringwald } 2662ad6b656SMilanka Ringwald 2675ace758fSMilanka Ringwald connection = avdtp_create_connection(remote, cid); 26836da8747SMilanka Ringwald if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED; 26936da8747SMilanka Ringwald 27084521ac1SMilanka Ringwald connection->avdtp_cid = cid; 271b1549ed3SMilanka Ringwald 2725797104aSMilanka Ringwald connection->avdtp_l2cap_psm = 0; 2735797104aSMilanka Ringwald connection->avdtp_version = 0; 2745797104aSMilanka Ringwald connection->sink_supported = false; 2755797104aSMilanka Ringwald connection->source_supported = false; 2765797104aSMilanka Ringwald 277b1549ed3SMilanka Ringwald switch (role){ 278149deddbSMilanka Ringwald case AVDTP_ROLE_SOURCE: 2795797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK; 280149deddbSMilanka Ringwald break; 281149deddbSMilanka Ringwald case AVDTP_ROLE_SINK: 2825797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE; 283149deddbSMilanka Ringwald break; 284149deddbSMilanka Ringwald default: 2855797104aSMilanka Ringwald btstack_assert(false); 286149deddbSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 287149deddbSMilanka Ringwald } 2885797104aSMilanka Ringwald 2895797104aSMilanka Ringwald avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query; 2905797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 2915797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 2925797104aSMilanka Ringwald return ERROR_CODE_SUCCESS; 293692c0605SMilanka Ringwald } 294747ec646SMilanka Ringwald 295a1fb0563SMilanka Ringwald 296a1fb0563SMilanka Ringwald void avdtp_register_sink_packet_handler(btstack_packet_handler_t callback){ 297a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 298a1fb0563SMilanka Ringwald avdtp_sink_callback = callback; 299a1fb0563SMilanka Ringwald } 300a1fb0563SMilanka Ringwald 301a1fb0563SMilanka Ringwald void avdtp_register_source_packet_handler(btstack_packet_handler_t callback){ 302a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 303a1fb0563SMilanka Ringwald avdtp_source_callback = callback; 304a1fb0563SMilanka Ringwald } 305a1fb0563SMilanka Ringwald 306747ec646SMilanka Ringwald void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){ 307747ec646SMilanka Ringwald if (!stream_endpoint){ 3089900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 309747ec646SMilanka Ringwald return; 310747ec646SMilanka Ringwald } 311747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1); 312747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 313747ec646SMilanka Ringwald } 314747ec646SMilanka Ringwald 315747ec646SMilanka Ringwald void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 316747ec646SMilanka Ringwald if (!stream_endpoint){ 3179900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 318747ec646SMilanka Ringwald return; 319747ec646SMilanka Ringwald } 320747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_REPORTING, 1); 321747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 322747ec646SMilanka Ringwald } 323747ec646SMilanka Ringwald 324747ec646SMilanka Ringwald void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 325747ec646SMilanka Ringwald if (!stream_endpoint){ 3269900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 327747ec646SMilanka Ringwald return; 328747ec646SMilanka Ringwald } 329747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_DELAY_REPORTING, 1); 330747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 331747ec646SMilanka Ringwald } 332747ec646SMilanka Ringwald 333747ec646SMilanka Ringwald void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){ 334747ec646SMilanka Ringwald if (!stream_endpoint){ 3359900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 336747ec646SMilanka Ringwald return; 337747ec646SMilanka Ringwald } 338747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_RECOVERY, 1); 339747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 340747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.recovery_type = 0x01; // 0x01 = RFC2733 341747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_recovery_window_size = maximum_recovery_window_size; 342747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_number_media_packets = maximum_number_media_packets; 343747ec646SMilanka Ringwald } 344747ec646SMilanka Ringwald 345747ec646SMilanka 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){ 346747ec646SMilanka Ringwald if (!stream_endpoint){ 3479900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 348747ec646SMilanka Ringwald return; 349747ec646SMilanka Ringwald } 350747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_CONTENT_PROTECTION, 1); 351747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 352747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type = cp_type; 3536535961aSMatthias Ringwald (void)memcpy(stream_endpoint->sep.capabilities.content_protection.cp_type_value, 3546535961aSMatthias Ringwald cp_type_value, 3556535961aSMatthias Ringwald btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN)); 35667ae582dSMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type_value_len = btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN); 357747ec646SMilanka Ringwald } 358747ec646SMilanka Ringwald 359747ec646SMilanka Ringwald void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery){ 360747ec646SMilanka Ringwald if (!stream_endpoint){ 3619900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 362747ec646SMilanka Ringwald return; 363747ec646SMilanka Ringwald } 364747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_HEADER_COMPRESSION, 1); 365747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 366747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.back_ch = back_ch; 367747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.media = media; 368747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.recovery = recovery; 369747ec646SMilanka Ringwald } 370747ec646SMilanka Ringwald 37178d08d09SMilanka 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){ 372747ec646SMilanka Ringwald if (!stream_endpoint){ 3739900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 374747ec646SMilanka Ringwald return; 375747ec646SMilanka Ringwald } 376747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1); 377747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 378747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_type = media_type; 379747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type; 380747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information = media_codec_info; 381747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information_len = media_codec_info_len; 382747ec646SMilanka Ringwald } 383747ec646SMilanka Ringwald 384747ec646SMilanka Ringwald void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation){ 385747ec646SMilanka Ringwald if (!stream_endpoint){ 3869900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 387747ec646SMilanka Ringwald return; 388747ec646SMilanka Ringwald } 389747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MULTIPLEXING, 1); 390747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 391747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.multiplexing_mode.fragmentation = fragmentation; 392747ec646SMilanka Ringwald } 393747ec646SMilanka Ringwald 394951d2774SMatthias Ringwald void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size)){ 395951d2774SMatthias Ringwald avdtp_sink_handle_media_data = callback; 396951d2774SMatthias Ringwald } 397747ec646SMilanka Ringwald 398d80ccd43SMatthias Ringwald /* START: tracking can send now requests per l2cap cid */ 399d80ccd43SMatthias Ringwald static void avdtp_handle_can_send_now(uint16_t l2cap_cid) { 400d80ccd43SMatthias Ringwald 401d80ccd43SMatthias Ringwald log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", l2cap_cid); 402d80ccd43SMatthias Ringwald 403d80ccd43SMatthias Ringwald // get signaling connection for l2cap cid 404d80ccd43SMatthias Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_l2cap_signaling_cid(l2cap_cid); 405d80ccd43SMatthias Ringwald 406d80ccd43SMatthias Ringwald if (connection != NULL) { 407747ec646SMilanka Ringwald if (connection->wait_to_send_acceptor) { 408d80ccd43SMatthias Ringwald log_debug("call avdtp_acceptor_stream_config_subsm_run %p", connection); 409d80ccd43SMatthias Ringwald connection->wait_to_send_acceptor = false; 41077092f3eSMatthias Ringwald avdtp_acceptor_stream_config_subsm_run(connection); 411747ec646SMilanka Ringwald } else if (connection->wait_to_send_initiator) { 412d80ccd43SMatthias Ringwald log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling %p", connection); 413d80ccd43SMatthias Ringwald connection->wait_to_send_initiator = false; 414d80ccd43SMatthias Ringwald avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling(connection); 415d80ccd43SMatthias Ringwald } 416d80ccd43SMatthias Ringwald bool more_to_send = connection->wait_to_send_acceptor || connection->wait_to_send_initiator; 417d80ccd43SMatthias Ringwald if (more_to_send){ 418d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(l2cap_cid); 419d80ccd43SMatthias Ringwald } 420d80ccd43SMatthias Ringwald return; 421747ec646SMilanka Ringwald } 422747ec646SMilanka Ringwald 423d80ccd43SMatthias Ringwald // get stream endpoint connection for l2cap cid 424d80ccd43SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(l2cap_cid); 425d80ccd43SMatthias Ringwald if (stream_endpoint != NULL) { 426d80ccd43SMatthias Ringwald log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint %p", stream_endpoint); 427d80ccd43SMatthias Ringwald if (stream_endpoint->request_can_send_now) { 428d80ccd43SMatthias Ringwald stream_endpoint->request_can_send_now = 0; 429d80ccd43SMatthias Ringwald avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint(stream_endpoint); 430d80ccd43SMatthias Ringwald } 431d80ccd43SMatthias Ringwald bool more_to_send = stream_endpoint->request_can_send_now != 0; 432747ec646SMilanka Ringwald if (more_to_send){ 433747ec646SMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 434747ec646SMilanka Ringwald } 435747ec646SMilanka Ringwald } 436d80ccd43SMatthias Ringwald } 437d80ccd43SMatthias Ringwald /* END: tracking can send now requests per l2cap cid */ 438747ec646SMilanka Ringwald 439747ec646SMilanka Ringwald 440297feb5fSMilanka Ringwald avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){ 441747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = btstack_memory_avdtp_stream_endpoint_get(); 4424567cc17SMilanka Ringwald if (!stream_endpoint){ 4439900b7faSMilanka Ringwald log_error("Not enough memory to create stream endpoint"); 4444567cc17SMilanka Ringwald return NULL; 4454567cc17SMilanka Ringwald } 446560b3f31SMilanka Ringwald stream_endpoint->sep.seid = avdtp_get_next_local_seid(); 447747ec646SMilanka Ringwald stream_endpoint->sep.media_type = media_type; 448747ec646SMilanka Ringwald stream_endpoint->sep.type = sep_type; 449d8e15394SMilanka Ringwald btstack_linked_list_add(avdtp_get_stream_endpoints(), (btstack_linked_item_t *) stream_endpoint); 450747ec646SMilanka Ringwald return stream_endpoint; 451747ec646SMilanka Ringwald } 452747ec646SMilanka Ringwald 45317ddf501SMatthias Ringwald void avdtp_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ 45417ddf501SMatthias Ringwald btstack_linked_list_remove(avdtp_get_stream_endpoints(), (btstack_linked_item_t* ) stream_endpoint); 45517ddf501SMatthias Ringwald btstack_memory_avdtp_stream_endpoint_free(stream_endpoint); 45617ddf501SMatthias Ringwald } 45717ddf501SMatthias Ringwald 45877092f3eSMatthias Ringwald static void 45977092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t *connection, uint8_t *packet, uint16_t size) { 460c1c40ea1SMatthias Ringwald if (size < 2) return; 461c1c40ea1SMatthias Ringwald 462c1c40ea1SMatthias Ringwald uint16_t offset; 463c1c40ea1SMatthias Ringwald avdtp_message_type_t message_type = avdtp_get_signaling_packet_type(packet); 464c1c40ea1SMatthias Ringwald switch (message_type){ 465747ec646SMilanka Ringwald case AVDTP_CMD_MSG: 46650453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->acceptor_signaling_packet, packet, size); 46777092f3eSMatthias Ringwald avdtp_acceptor_stream_config_subsm(connection, packet, size, offset); 468747ec646SMilanka Ringwald break; 469747ec646SMilanka Ringwald default: 47050453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->initiator_signaling_packet, packet, size); 47177092f3eSMatthias Ringwald avdtp_initiator_stream_config_subsm(connection, packet, size, offset); 472747ec646SMilanka Ringwald break; 473747ec646SMilanka Ringwald } 474747ec646SMilanka Ringwald } 475747ec646SMilanka Ringwald 476b1549ed3SMilanka Ringwald static void avdtp_handle_sdp_client_query_attribute_value(avdtp_connection_t * connection, uint8_t *packet){ 477692c0605SMilanka Ringwald des_iterator_t des_list_it; 478692c0605SMilanka Ringwald des_iterator_t prot_it; 479692c0605SMilanka Ringwald 480692c0605SMilanka Ringwald // Handle new SDP record 481692c0605SMilanka Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id) { 482692c0605SMilanka Ringwald record_id = sdp_event_query_attribute_byte_get_record_id(packet); 4838587e32cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 484692c0605SMilanka Ringwald } 485692c0605SMilanka Ringwald 486692c0605SMilanka Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 487692c0605SMilanka Ringwald attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 488692c0605SMilanka Ringwald 489692c0605SMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 490692c0605SMilanka Ringwald 491692c0605SMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 492149deddbSMilanka Ringwald 493692c0605SMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 494692c0605SMilanka Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 495692c0605SMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 496692c0605SMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 497692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 498692c0605SMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 499692c0605SMilanka Ringwald switch (uuid){ 500692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE: 501b1549ed3SMilanka Ringwald connection->source_supported = true; 502149deddbSMilanka Ringwald log_info("source_supported"); 503692c0605SMilanka Ringwald break; 504692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK: 505b1549ed3SMilanka Ringwald connection->sink_supported = true; 506149deddbSMilanka Ringwald log_info("sink_supported"); 507692c0605SMilanka Ringwald break; 508692c0605SMilanka Ringwald default: 509692c0605SMilanka Ringwald break; 510692c0605SMilanka Ringwald } 511692c0605SMilanka Ringwald } 512692c0605SMilanka Ringwald break; 513692c0605SMilanka Ringwald 514149deddbSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 5158587e32cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 516692c0605SMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 517692c0605SMilanka Ringwald uint8_t *des_element; 518692c0605SMilanka Ringwald uint8_t *element; 519692c0605SMilanka Ringwald uint32_t uuid; 520692c0605SMilanka Ringwald 521692c0605SMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 522692c0605SMilanka Ringwald 523692c0605SMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 524692c0605SMilanka Ringwald des_iterator_init(&prot_it, des_element); 525692c0605SMilanka Ringwald element = des_iterator_get_element(&prot_it); 526692c0605SMilanka Ringwald 527692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 528692c0605SMilanka Ringwald 529692c0605SMilanka Ringwald uuid = de_get_uuid32(element); 53014fd128cSMatthias Ringwald des_iterator_next(&prot_it); 531149deddbSMilanka Ringwald // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both 532692c0605SMilanka Ringwald switch (uuid){ 533692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 534692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 535b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_l2cap_psm); 536692c0605SMilanka Ringwald break; 537692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_AVDTP: 538692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 539b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_version); 540cc61e7e9SMilanka Ringwald log_info("avdtp version 0x%02x", 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: 567a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 568146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, connection->remote_addr, connection->con_handle, status); 569a1fb0563SMilanka Ringwald break; 570cc61e7e9SMilanka Ringwald 571cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 572cc61e7e9SMilanka Ringwald // SDP query failed: try query that must be supported 573cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 574d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 575a1fb0563SMilanka Ringwald return; 576cc61e7e9SMilanka Ringwald 577cc61e7e9SMilanka Ringwald default: 578cc61e7e9SMilanka Ringwald btstack_assert(false); 579cc61e7e9SMilanka Ringwald break; 580a1fb0563SMilanka Ringwald } 5815ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 582ca2c9990SMilanka Ringwald sdp_query_context_avdtp_cid = 0; 583f0c39502SMilanka Ringwald log_info("SDP query failed with status 0x%02x.", status); 584f0c39502SMilanka Ringwald } 585f0c39502SMilanka Ringwald 586f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){ 587cc61e7e9SMilanka Ringwald log_info("avdtp_handle_sdp_query_succeeded: state %d", connection->state); 588cc61e7e9SMilanka Ringwald 589cc61e7e9SMilanka Ringwald switch (connection->state){ 590cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 591cc61e7e9SMilanka Ringwald if (connection->avdtp_version < 0x0103){ 592cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 593cc61e7e9SMilanka Ringwald } else { 594cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 595cc61e7e9SMilanka Ringwald } 596d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 597cc61e7e9SMilanka Ringwald break; 598cc61e7e9SMilanka Ringwald default: 599f0c39502SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 600cc61e7e9SMilanka Ringwald l2cap_create_channel(avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 601cc61e7e9SMilanka Ringwald break; 602cc61e7e9SMilanka Ringwald } 603f0c39502SMilanka Ringwald } 604f0c39502SMilanka Ringwald 6056ed344c3SMatthias Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 606149deddbSMilanka Ringwald UNUSED(packet_type); 607149deddbSMilanka Ringwald UNUSED(channel); 608149deddbSMilanka Ringwald UNUSED(size); 609149deddbSMilanka Ringwald 610ca2c9990SMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(sdp_query_context_avdtp_cid); 6116ed344c3SMatthias Ringwald if (!connection) { 612ca2c9990SMilanka Ringwald log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context_avdtp_cid); 6136ed344c3SMatthias Ringwald return; 6146ed344c3SMatthias Ringwald } 6156ed344c3SMatthias Ringwald 616722c03bdSMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 617149deddbSMilanka Ringwald switch (connection->state){ 618149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 6196ed344c3SMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 6206ed344c3SMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 621b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 622149deddbSMilanka Ringwald return; 623692c0605SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 6241e1ae2bcSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 625149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 626722c03bdSMatthias Ringwald if (!connection->sink_supported) { 627722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 628722c03bdSMatthias Ringwald break; 629722c03bdSMatthias Ringwald } 630722c03bdSMatthias Ringwald if (connection->avdtp_l2cap_psm == 0) { 631722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 632722c03bdSMatthias Ringwald break; 633722c03bdSMatthias Ringwald } 634149deddbSMilanka Ringwald break; 635149deddbSMilanka Ringwald default: 636149deddbSMilanka Ringwald btstack_assert(false); 637722c03bdSMatthias Ringwald return; 6381e1ae2bcSMilanka Ringwald } 639149deddbSMilanka Ringwald break; 640149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 641149deddbSMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 642149deddbSMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 643b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 644149deddbSMilanka Ringwald return; 645149deddbSMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 646149deddbSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 647149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 648722c03bdSMatthias Ringwald if (!connection->source_supported) { 649722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 650722c03bdSMatthias Ringwald break; 651722c03bdSMatthias Ringwald } 652722c03bdSMatthias Ringwald if (connection->avdtp_l2cap_psm == 0) { 653722c03bdSMatthias Ringwald status = ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE; 654722c03bdSMatthias Ringwald break; 655722c03bdSMatthias Ringwald } 656149deddbSMilanka Ringwald break; 657149deddbSMilanka Ringwald default: 658149deddbSMilanka Ringwald btstack_assert(false); 659722c03bdSMatthias Ringwald return; 660974d4d6eSMilanka Ringwald } 6612f6083d0SMilanka Ringwald break; 662cc61e7e9SMilanka Ringwald 663cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 664cc61e7e9SMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 665cc61e7e9SMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 666cc61e7e9SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 667cc61e7e9SMilanka Ringwald return; 668cc61e7e9SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 669cc61e7e9SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 670cc61e7e9SMilanka Ringwald break; 671cc61e7e9SMilanka Ringwald default: 672cc61e7e9SMilanka Ringwald btstack_assert(false); 673cc61e7e9SMilanka Ringwald return; 674cc61e7e9SMilanka Ringwald } 675cc61e7e9SMilanka Ringwald break; 676cc61e7e9SMilanka Ringwald 677149deddbSMilanka Ringwald default: 67808cb850dSMilanka Ringwald // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete 67908cb850dSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 68008cb850dSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 68108cb850dSMilanka Ringwald } 682149deddbSMilanka Ringwald return; 6832f6083d0SMilanka Ringwald } 684f0c39502SMilanka Ringwald 685722c03bdSMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 686149deddbSMilanka Ringwald avdtp_handle_sdp_query_succeeded(connection); 687149deddbSMilanka Ringwald } else { 688149deddbSMilanka Ringwald avdtp_handle_sdp_query_failed(connection, status); 689692c0605SMilanka Ringwald } 6905797104aSMilanka Ringwald 6915797104aSMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 6925797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 6935797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 694692c0605SMilanka Ringwald } 695692c0605SMilanka Ringwald 696146fc0fbSMilanka Ringwald static avdtp_connection_t * avdtp_handle_incoming_connection(avdtp_connection_t * connection, bd_addr_t event_addr, hci_con_handle_t con_handle, uint16_t local_cid){ 69736da8747SMilanka Ringwald if (connection == NULL){ 69836da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 6995ace758fSMilanka Ringwald connection = avdtp_create_connection(event_addr, cid); 70036da8747SMilanka Ringwald } 701692c0605SMilanka Ringwald 70236da8747SMilanka Ringwald if (connection) { 70336da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 70436da8747SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 705146fc0fbSMilanka Ringwald connection->con_handle = con_handle; 706ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 70736da8747SMilanka Ringwald } 70836da8747SMilanka Ringwald return connection; 70936da8747SMilanka Ringwald } 710f0c39502SMilanka Ringwald 711ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 712326e3662SMilanka Ringwald uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 713326e3662SMilanka Ringwald 7145ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 715326e3662SMilanka Ringwald if (connection == NULL) return; 716326e3662SMilanka Ringwald 717ff53b162SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){ 718326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 719326e3662SMilanka Ringwald l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 720326e3662SMilanka Ringwald } 721326e3662SMilanka Ringwald } 722326e3662SMilanka Ringwald 723ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){ 724ff53b162SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler); 725ff53b162SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid); 726326e3662SMilanka Ringwald 727326e3662SMilanka Ringwald // add some jitter/randomness to reconnect delay 728326e3662SMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 729ff53b162SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 730ff53b162SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 731326e3662SMilanka Ringwald } 732326e3662SMilanka Ringwald 733326e3662SMilanka Ringwald 734326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 735747ec646SMilanka Ringwald bd_addr_t event_addr; 736747ec646SMilanka Ringwald uint16_t psm; 737747ec646SMilanka Ringwald uint16_t local_cid; 7381e1ae2bcSMilanka Ringwald uint8_t status; 739326e3662SMilanka Ringwald uint16_t l2cap_mtu; 740146fc0fbSMilanka Ringwald hci_con_handle_t con_handle; 74136da8747SMilanka Ringwald 74236da8747SMilanka Ringwald bool accept_streaming_connection; 74336da8747SMilanka Ringwald bool outoing_signaling_active; 74436da8747SMilanka Ringwald bool decline_connection; 74584521ac1SMilanka Ringwald 746747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = NULL; 747747ec646SMilanka Ringwald avdtp_connection_t * connection = NULL; 74836da8747SMilanka Ringwald 749747ec646SMilanka Ringwald switch (packet_type) { 750747ec646SMilanka Ringwald case L2CAP_DATA_PACKET: 7515ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 752747ec646SMilanka Ringwald if (connection){ 75377092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 754747ec646SMilanka Ringwald break; 755747ec646SMilanka Ringwald } 756747ec646SMilanka Ringwald 7576f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 758747ec646SMilanka Ringwald if (!stream_endpoint){ 759747ec646SMilanka Ringwald if (!connection) break; 76077092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 761747ec646SMilanka Ringwald break; 762747ec646SMilanka Ringwald } 763747ec646SMilanka Ringwald 7648c0f3635SMilanka Ringwald if (stream_endpoint->connection){ 7659413b167SMilanka Ringwald if (channel == stream_endpoint->connection->l2cap_signaling_cid){ 76677092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size); 767747ec646SMilanka Ringwald break; 768747ec646SMilanka Ringwald } 7698c0f3635SMilanka Ringwald } 770747ec646SMilanka Ringwald 771747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_media_cid){ 772951d2774SMatthias Ringwald btstack_assert(avdtp_sink_handle_media_data); 773951d2774SMatthias Ringwald (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size); 774747ec646SMilanka Ringwald break; 775747ec646SMilanka Ringwald } 776747ec646SMilanka Ringwald 777747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_reporting_cid){ 7788587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED"); 779747ec646SMilanka Ringwald } else if (channel == stream_endpoint->l2cap_recovery_cid){ 7808587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED"); 781747ec646SMilanka Ringwald } else { 782747ec646SMilanka Ringwald log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel); 783747ec646SMilanka Ringwald } 784747ec646SMilanka Ringwald break; 785747ec646SMilanka Ringwald 786747ec646SMilanka Ringwald case HCI_EVENT_PACKET: 787747ec646SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 78836da8747SMilanka Ringwald 789747ec646SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 790747ec646SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 791747ec646SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 792146fc0fbSMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 79336da8747SMilanka Ringwald outoing_signaling_active = false; 79436da8747SMilanka Ringwald accept_streaming_connection = false; 79536da8747SMilanka Ringwald 7965ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 79736da8747SMilanka Ringwald if (connection != NULL){ 7980d4a198eSMatthias Ringwald switch (connection->state){ 7990d4a198eSMatthias Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED: 80036da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 80136da8747SMilanka Ringwald outoing_signaling_active = true; 80236da8747SMilanka Ringwald connection->incoming_declined = true; 80336da8747SMilanka Ringwald break; 80436da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 80536da8747SMilanka Ringwald outoing_signaling_active = true; 80636da8747SMilanka Ringwald accept_streaming_connection = true; 80736da8747SMilanka Ringwald break; 808f0c39502SMilanka Ringwald default: 809f0c39502SMilanka Ringwald break; 8100d4a198eSMatthias Ringwald } 811747ec646SMilanka Ringwald } 81236da8747SMilanka Ringwald log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d", 81336da8747SMilanka Ringwald bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection); 814747ec646SMilanka Ringwald 81536da8747SMilanka Ringwald decline_connection = outoing_signaling_active && !accept_streaming_connection; 81636da8747SMilanka Ringwald if (outoing_signaling_active == false){ 817146fc0fbSMilanka Ringwald connection = avdtp_handle_incoming_connection(connection, event_addr, con_handle, local_cid); 81836da8747SMilanka Ringwald if (connection == NULL){ 81936da8747SMilanka Ringwald decline_connection = true; 82036da8747SMilanka Ringwald } 82136da8747SMilanka Ringwald } else if (accept_streaming_connection){ 82236da8747SMilanka Ringwald if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) { 82336da8747SMilanka Ringwald decline_connection = true; 82436da8747SMilanka Ringwald } else { 825939e12adSMatthias Ringwald // now, we're only dealing with media connections that are created by remote side - we're acceptor here 8263338afc0SMatthias Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_seid(connection->acceptor_local_seid); 82736da8747SMilanka Ringwald if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) { 82836da8747SMilanka Ringwald decline_connection = true; 82936da8747SMilanka Ringwald } 83036da8747SMilanka Ringwald } 831747ec646SMilanka Ringwald } 832747ec646SMilanka Ringwald 83336da8747SMilanka Ringwald if (decline_connection){ 834a3ce0109SMatthias Ringwald l2cap_decline_connection(local_cid); 83536da8747SMilanka Ringwald } else { 836747ec646SMilanka Ringwald l2cap_accept_connection(local_cid); 83736da8747SMilanka Ringwald } 838747ec646SMilanka Ringwald break; 839747ec646SMilanka Ringwald 840747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 841a5114819SMilanka Ringwald 842a0b8a58cSMilanka Ringwald psm = l2cap_event_channel_opened_get_psm(packet); 84384e3541eSMilanka Ringwald if (psm != BLUETOOTH_PSM_AVDTP){ 844355ac553SMilanka Ringwald log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED "); 845a0b8a58cSMilanka Ringwald return; 846a0b8a58cSMilanka Ringwald } 847a0b8a58cSMilanka Ringwald 8481e1ae2bcSMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 849747ec646SMilanka Ringwald // inform about new l2cap connection 850747ec646SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 8517050d2caSMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 852326e3662SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 8535ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 85436da8747SMilanka Ringwald if (connection == NULL){ 85536da8747SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr)); 856a0b8a58cSMilanka Ringwald break; 857a0b8a58cSMilanka Ringwald } 858a0b8a58cSMilanka Ringwald 859146fc0fbSMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 860146fc0fbSMilanka Ringwald 861a5114819SMilanka Ringwald switch (connection->state){ 862a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 863326e3662SMilanka Ringwald switch (status){ 864326e3662SMilanka Ringwald case ERROR_CODE_SUCCESS: 865326e3662SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 866326e3662SMilanka Ringwald connection->incoming_declined = false; 867326e3662SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 868146fc0fbSMilanka Ringwald connection->con_handle = con_handle; 869326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_OPENED; 870146fc0fbSMilanka Ringwald log_info("Connection opened l2cap_signaling_cid 0x%02x, avdtp_cid 0x%02x, con_handle 0x%02x", connection->l2cap_signaling_cid, connection->avdtp_cid, con_handle); 871146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status); 872326e3662SMilanka Ringwald return; 873326e3662SMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 874326e3662SMilanka Ringwald if (connection->incoming_declined == true) { 875326e3662SMilanka Ringwald log_info("Connection was declined, and the outgoing failed"); 876ff53b162SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY; 877326e3662SMilanka Ringwald connection->incoming_declined = false; 878ff53b162SMilanka Ringwald avdtp_retry_timer_start(connection); 879326e3662SMilanka Ringwald return; 880326e3662SMilanka Ringwald } 881326e3662SMilanka Ringwald break; 882326e3662SMilanka Ringwald default: 883326e3662SMilanka Ringwald log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 884326e3662SMilanka Ringwald break; 885326e3662SMilanka Ringwald } 886146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status); 887f82b60efSMilanka Ringwald avdtp_finalize_connection(connection); 888a0b8a58cSMilanka Ringwald break; 889747ec646SMilanka Ringwald 890a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 89119a000d1SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid); 892747ec646SMilanka Ringwald if (!stream_endpoint){ 8935bd73fa2SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid); 894747ec646SMilanka Ringwald return; 895747ec646SMilanka Ringwald } 896326e3662SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 897355ac553SMilanka 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)); 898a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 899f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, status); 900a466d508SMilanka Ringwald break; 901a466d508SMilanka Ringwald } 902a5114819SMilanka Ringwald switch (stream_endpoint->state){ 903a5114819SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED: 904a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED; 905a466d508SMilanka Ringwald stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet); 906a466d508SMilanka Ringwald stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet); 907d1207cd8SMilanka Ringwald 908355ac553SMilanka 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)); 909f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS); 910a5114819SMilanka Ringwald break; 911a5114819SMilanka Ringwald default: 912a5114819SMilanka 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)); 91323edb87eSMilanka Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_COMMAND_DISALLOWED); 914a5114819SMilanka Ringwald break; 915a5114819SMilanka Ringwald } 916a5114819SMilanka Ringwald break; 917a5114819SMilanka Ringwald 918a5114819SMilanka Ringwald default: 919326e3662SMilanka Ringwald log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state); 920a5114819SMilanka Ringwald break; 921a5114819SMilanka Ringwald } 922747ec646SMilanka Ringwald break; 923747ec646SMilanka Ringwald 924747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 925747ec646SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 9266f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid); 9275ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid); 92836da8747SMilanka Ringwald 929f01aeca4SMilanka Ringwald log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint); 930f01aeca4SMilanka Ringwald 931a466d508SMilanka Ringwald if (stream_endpoint){ 932a466d508SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == local_cid){ 933a466d508SMilanka Ringwald connection = stream_endpoint->connection; 934596b7fdcSMilanka Ringwald if (connection) { 935f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_released(stream_endpoint, 936f751daa3SMatthias Ringwald connection->avdtp_cid, 937f751daa3SMatthias Ringwald avdtp_local_seid(stream_endpoint)); 938596b7fdcSMilanka Ringwald } 939485c0a4cSMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 9407f162947SMilanka Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE; 941a466d508SMilanka Ringwald break; 942a466d508SMilanka Ringwald } 943a466d508SMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == local_cid){ 944355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid); 945a466d508SMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0; 946a466d508SMilanka Ringwald break; 947a466d508SMilanka Ringwald } 948a466d508SMilanka Ringwald 949a466d508SMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == local_cid){ 950355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid); 951a466d508SMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0; 952a466d508SMilanka Ringwald break; 953a466d508SMilanka Ringwald } 954a466d508SMilanka Ringwald } 955596b7fdcSMilanka Ringwald 956596b7fdcSMilanka Ringwald if (connection){ 957596b7fdcSMilanka Ringwald btstack_linked_list_iterator_t it; 958d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 959596b7fdcSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 960f01aeca4SMilanka Ringwald stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 961f01aeca4SMilanka Ringwald if (stream_endpoint->connection == connection){ 962f01aeca4SMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 963596b7fdcSMilanka Ringwald } 964596b7fdcSMilanka Ringwald } 965c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_released(connection->avdtp_cid); 9665ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 967596b7fdcSMilanka Ringwald break; 968596b7fdcSMilanka Ringwald } 969747ec646SMilanka Ringwald break; 970747ec646SMilanka Ringwald 971747ec646SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 972c6bc5965SMilanka Ringwald log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel); 973d80ccd43SMatthias Ringwald avdtp_handle_can_send_now(channel); 974747ec646SMilanka Ringwald break; 975747ec646SMilanka Ringwald default: 976355ac553SMilanka Ringwald log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet)); 977747ec646SMilanka Ringwald break; 978747ec646SMilanka Ringwald } 979747ec646SMilanka Ringwald break; 980747ec646SMilanka Ringwald 981747ec646SMilanka Ringwald default: 982747ec646SMilanka Ringwald // other packet type 983747ec646SMilanka Ringwald break; 984747ec646SMilanka Ringwald } 985747ec646SMilanka Ringwald } 986747ec646SMilanka Ringwald 987b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){ 9885ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 98923edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 990b401ff59SMilanka Ringwald 991a466d508SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS; 992747ec646SMilanka Ringwald 993f01aeca4SMilanka Ringwald btstack_linked_list_iterator_t it; 994f01aeca4SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 995f01aeca4SMilanka Ringwald 996f01aeca4SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 997f01aeca4SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 998f01aeca4SMilanka Ringwald if (stream_endpoint->connection != connection) continue; 999f01aeca4SMilanka Ringwald 1000f01aeca4SMilanka Ringwald switch (stream_endpoint->state){ 1001f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_OPENED: 1002f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_STREAMING: 1003f01aeca4SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED; 1004f01aeca4SMilanka Ringwald l2cap_disconnect(stream_endpoint->l2cap_media_cid, 0); 1005f01aeca4SMilanka Ringwald break; 1006f01aeca4SMilanka Ringwald default: 1007f01aeca4SMilanka Ringwald break; 1008f01aeca4SMilanka Ringwald } 1009f01aeca4SMilanka Ringwald } 1010f01aeca4SMilanka Ringwald 1011f01aeca4SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED; 1012f01aeca4SMilanka Ringwald l2cap_disconnect(connection->l2cap_signaling_cid, 0); 10134ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1014747ec646SMilanka Ringwald } 1015747ec646SMilanka Ringwald 1016297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){ 10175ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1018747ec646SMilanka Ringwald if (!connection){ 10198587e32cSMilanka Ringwald log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid); 102023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1021747ec646SMilanka Ringwald } 1022747ec646SMilanka Ringwald 1023747ec646SMilanka Ringwald if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) { 10248587e32cSMilanka Ringwald log_error("avdtp_media_connect: wrong connection state %d", connection->state); 102523edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1026747ec646SMilanka Ringwald } 1027747ec646SMilanka Ringwald 10283338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1029747ec646SMilanka Ringwald if (!stream_endpoint) { 10306b0ee1d0SMilanka Ringwald log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid); 103123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1032747ec646SMilanka Ringwald } 1033747ec646SMilanka Ringwald 1034485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid != remote_seid){ 1035485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid); 103623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1037485c0a4cSMilanka Ringwald } 1038485c0a4cSMilanka Ringwald 103923edb87eSMilanka Ringwald if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return ERROR_CODE_COMMAND_DISALLOWED; 1040747ec646SMilanka Ringwald 1041b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 104296dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 10435bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1044747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM; 1045747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM; 1046d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 10474ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1048747ec646SMilanka Ringwald } 1049747ec646SMilanka Ringwald 1050297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10515ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 105246e6b063SMilanka Ringwald if (!connection){ 10534ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 105423edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 105546e6b063SMilanka Ringwald } 10565cfe7f4cSMilanka Ringwald 10573338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 10584ccacc40SMilanka Ringwald if (!stream_endpoint) { 10594ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid); 106023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10614ccacc40SMilanka Ringwald } 10624ccacc40SMilanka Ringwald 10634ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 10644ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid); 106523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10664ccacc40SMilanka Ringwald } 10674ccacc40SMilanka Ringwald 1068485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 1069485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep registered with the stream endpoint"); 107023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10714ccacc40SMilanka Ringwald } 10724ccacc40SMilanka Ringwald 1073440d8d82SMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){ 1074440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1075440d8d82SMilanka Ringwald } 1076440d8d82SMilanka Ringwald 107760ec20d0SMilanka Ringwald stream_endpoint->start_stream = 1; 10785bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 107996dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1080d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 10814ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1082747ec646SMilanka Ringwald } 1083747ec646SMilanka Ringwald 1084297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10855ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1086747ec646SMilanka Ringwald if (!connection){ 10874ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 108823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1089747ec646SMilanka Ringwald } 10904ccacc40SMilanka Ringwald 10913338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 10924ccacc40SMilanka Ringwald if (!stream_endpoint) { 10934ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid); 109423edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10954ccacc40SMilanka Ringwald } 10964ccacc40SMilanka Ringwald 10974ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 10984ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid); 109923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11004ccacc40SMilanka Ringwald } 1101485c0a4cSMilanka Ringwald 1102fa4419dbSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->close_stream){ 1103440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1104485c0a4cSMilanka Ringwald } 11054ccacc40SMilanka Ringwald 1106fa4419dbSMilanka Ringwald stream_endpoint->close_stream = 1; 11075bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 110896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1109d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 11104ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1111747ec646SMilanka Ringwald } 1112747ec646SMilanka Ringwald 1113297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11145ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 111560ec20d0SMilanka Ringwald if (!connection){ 11164ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 111723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1118747ec646SMilanka Ringwald } 11194ccacc40SMilanka Ringwald 11203338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 11214ccacc40SMilanka Ringwald if (!stream_endpoint) { 11224ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid); 112323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11244ccacc40SMilanka Ringwald } 11254ccacc40SMilanka Ringwald 11264ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11274ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid); 112823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11294ccacc40SMilanka Ringwald } 1130485c0a4cSMilanka Ringwald 1131485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){ 1132440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1133485c0a4cSMilanka Ringwald } 11344ccacc40SMilanka Ringwald 113560ec20d0SMilanka Ringwald stream_endpoint->abort_stream = 1; 11365bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 113796dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1138d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 11394ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1140747ec646SMilanka Ringwald } 1141747ec646SMilanka Ringwald 1142297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11435ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1144747ec646SMilanka Ringwald if (!connection){ 11454ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 114623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 114760ec20d0SMilanka Ringwald } 11483338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 11494ccacc40SMilanka Ringwald if (!stream_endpoint) { 11504ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid); 115123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11524ccacc40SMilanka Ringwald } 11534ccacc40SMilanka Ringwald 11544ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11554ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid); 115623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11574ccacc40SMilanka Ringwald } 1158485c0a4cSMilanka Ringwald 1159485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){ 1160440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1161485c0a4cSMilanka Ringwald } 11624ccacc40SMilanka Ringwald 116360ec20d0SMilanka Ringwald stream_endpoint->suspend_stream = 1; 11645bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 116596dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1166d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 11674ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1168747ec646SMilanka Ringwald } 1169747ec646SMilanka Ringwald 11705ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){ 11715ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1172747ec646SMilanka Ringwald if (!connection){ 11738587e32cSMilanka Ringwald log_error("avdtp_discover_stream_endpoints: no connection for signaling cid 0x%02x found", avdtp_cid); 117423edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11759974aee0SMilanka Ringwald } 11760e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1177c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 117823edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1179747ec646SMilanka Ringwald } 1180ec3d71e3SMilanka Ringwald 1181b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1182747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS; 1183d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1184747ec646SMilanka Ringwald } 1185747ec646SMilanka Ringwald 1186747ec646SMilanka Ringwald 11875ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 11885ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1189747ec646SMilanka Ringwald if (!connection){ 11909900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 119123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1192747ec646SMilanka Ringwald } 11930e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1194c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 119523edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 11969974aee0SMilanka Ringwald } 11979974aee0SMilanka Ringwald 1198b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1199747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 120096dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1201d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1202747ec646SMilanka Ringwald } 1203747ec646SMilanka Ringwald 1204747ec646SMilanka Ringwald 12055ace758fSMilanka Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 12065ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1207747ec646SMilanka Ringwald if (!connection){ 12089900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 120923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1210747ec646SMilanka Ringwald } 12110e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1212c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 121323edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12149974aee0SMilanka Ringwald } 12159974aee0SMilanka Ringwald 1216b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 121796dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1218cc61e7e9SMilanka Ringwald 1219cc61e7e9SMilanka Ringwald if (connection->avdtp_version == 0){ 1220cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES; 1221cc61e7e9SMilanka Ringwald avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query; 1222cc61e7e9SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 1223cc61e7e9SMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 1224cc61e7e9SMilanka Ringwald return ERROR_CODE_SUCCESS; 1225cc61e7e9SMilanka Ringwald } else { 1226cc61e7e9SMilanka Ringwald // AVDTP version lower then 1.3 supports only get capabilities command 1227cc61e7e9SMilanka Ringwald if (connection->avdtp_version < 0x103){ 1228cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 1229cc61e7e9SMilanka Ringwald } else { 1230cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 1231cc61e7e9SMilanka Ringwald } 1232d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1233747ec646SMilanka Ringwald } 1234cc61e7e9SMilanka Ringwald } 1235747ec646SMilanka Ringwald 12365ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){ 12375ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1238747ec646SMilanka Ringwald if (!connection){ 12399900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 124023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1241747ec646SMilanka Ringwald } 12420e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1243c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 124423edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12459974aee0SMilanka Ringwald } 12469974aee0SMilanka Ringwald 1247b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1248747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION; 124996dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1250d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1251747ec646SMilanka Ringwald } 1252747ec646SMilanka Ringwald 1253cec76c5bSMilanka 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){ 12545ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1255747ec646SMilanka Ringwald if (!connection){ 12569900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 125723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1258747ec646SMilanka Ringwald } 12590e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1260c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 1261485c0a4cSMilanka Ringwald log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state); 126223edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12639974aee0SMilanka Ringwald } 1264a3ce0109SMatthias Ringwald if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){ 1265a3ce0109SMatthias Ringwald log_info("configuration already started, config state %u", connection->configuration_state); 126623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1267a3ce0109SMatthias Ringwald } 1268747ec646SMilanka Ringwald 1269d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1270747ec646SMilanka Ringwald if (!stream_endpoint) { 12719900b7faSMilanka Ringwald log_error("No initiator stream endpoint for seid %d", local_seid); 127223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1273747ec646SMilanka Ringwald } 1274417b4996SMilanka Ringwald if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){ 1275485c0a4cSMilanka Ringwald log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state); 127623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1277417b4996SMilanka Ringwald } 1278a3ce0109SMatthias Ringwald 1279bdbc3ef6SMilanka Ringwald connection->active_stream_endpoint = (void*) stream_endpoint; 1280a3ce0109SMatthias Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED; 1281747ec646SMilanka Ringwald 1282b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 128396dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 12845bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1285f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1286f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1287747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION; 1288ffa6c160SMilanka Ringwald 128944e638f3SMatthias Ringwald log_debug("SE %p, initiator_config_state: 0x%02x", stream_endpoint, stream_endpoint->initiator_config_state); 12903a69f723SMatthias Ringwald 1291d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1292747ec646SMilanka Ringwald } 1293747ec646SMilanka Ringwald 1294cec76c5bSMilanka 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){ 12955ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1296747ec646SMilanka Ringwald if (!connection){ 12979900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 129823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1299747ec646SMilanka Ringwald } 1300747ec646SMilanka Ringwald //TODO: if opened only app capabilities, enable reconfigure for not opened 13010e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1302c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 130323edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 13049974aee0SMilanka Ringwald } 13059e42cfccSMilanka Ringwald 1306d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 130778d08d09SMilanka Ringwald if (!stream_endpoint) { 13084ccacc40SMilanka Ringwald log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid); 130923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 131078d08d09SMilanka Ringwald } 131178d08d09SMilanka Ringwald 1312485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 13138587e32cSMilanka Ringwald log_error("avdtp_reconfigure: no associated remote sep"); 131423edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 131578d08d09SMilanka Ringwald } 1316485c0a4cSMilanka Ringwald 1317b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 131896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 13195bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1320f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1321f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1322747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID; 1323d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1324747ec646SMilanka Ringwald } 1325747ec646SMilanka Ringwald 13268e7044f9SMatthias Ringwald void avdtp_set_preferred_sampling_frequeny(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){ 13278e7044f9SMatthias Ringwald stream_endpoint->preferred_sampling_frequency = sampling_frequency; 13288e7044f9SMatthias Ringwald } 13298e7044f9SMatthias Ringwald 1330*79654d96SMilanka Ringwald void avdtp_set_preferred_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t channel_mode){ 1331*79654d96SMilanka Ringwald stream_endpoint->preferred_channel_mode = channel_mode; 1332*79654d96SMilanka Ringwald } 1333*79654d96SMilanka Ringwald 1334*79654d96SMilanka Ringwald 133578d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){ 133678d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 133778d08d09SMilanka Ringwald uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap; 133878d08d09SMilanka Ringwald 133978d08d09SMilanka Ringwald uint8_t channel_mode = AVDTP_SBC_STEREO; 1340*79654d96SMilanka Ringwald // use preferred channel mode if possible 1341*79654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_JOINT_STEREO){ 1342*79654d96SMilanka Ringwald return AVDTP_SBC_JOINT_STEREO; 1343*79654d96SMilanka Ringwald } 1344*79654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_STEREO){ 1345*79654d96SMilanka Ringwald return AVDTP_SBC_STEREO; 1346*79654d96SMilanka Ringwald } 1347*79654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_DUAL_CHANNEL){ 1348*79654d96SMilanka Ringwald return AVDTP_SBC_DUAL_CHANNEL; 1349*79654d96SMilanka Ringwald } 1350*79654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_MONO){ 1351*79654d96SMilanka Ringwald return AVDTP_SBC_MONO; 1352*79654d96SMilanka Ringwald } 1353*79654d96SMilanka Ringwald 1354*79654d96SMilanka Ringwald 135578d08d09SMilanka Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 135678d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_JOINT_STEREO; 135778d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 135878d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_STEREO; 135978d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 136078d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_DUAL_CHANNEL; 136178d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_MONO){ 136278d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_MONO; 136378d08d09SMilanka Ringwald } 136478d08d09SMilanka Ringwald return channel_mode; 136578d08d09SMilanka Ringwald } 136678d08d09SMilanka Ringwald 136778d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){ 136878d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 136978d08d09SMilanka Ringwald uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap; 137078d08d09SMilanka Ringwald 137178d08d09SMilanka Ringwald uint8_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 137278d08d09SMilanka Ringwald if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){ 137378d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 137478d08d09SMilanka Ringwald } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){ 137578d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR; 137678d08d09SMilanka Ringwald } 137778d08d09SMilanka Ringwald return allocation_method; 137878d08d09SMilanka Ringwald } 137978d08d09SMilanka Ringwald 1380bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){ 1381bd1ecb8aSMilanka Ringwald if (!stream_endpoint) return 0; 1382bd1ecb8aSMilanka Ringwald return stream_endpoint->sep.seid; 1383bd1ecb8aSMilanka Ringwald } 138478d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){ 138567ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 138678d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 138778d08d09SMilanka Ringwald uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap; 138878d08d09SMilanka Ringwald 138978d08d09SMilanka Ringwald uint8_t subbands = AVDTP_SBC_SUBBANDS_8; 139078d08d09SMilanka Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 139178d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_8; 139278d08d09SMilanka Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 139378d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_4; 139478d08d09SMilanka Ringwald } 139578d08d09SMilanka Ringwald return subbands; 139678d08d09SMilanka Ringwald } 139778d08d09SMilanka Ringwald 139878d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){ 139967ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 140078d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 140178d08d09SMilanka Ringwald uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap; 140278d08d09SMilanka Ringwald 140378d08d09SMilanka Ringwald uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16; 140478d08d09SMilanka Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 140578d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_16; 140678d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 140778d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_12; 140878d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 140978d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_8; 141078d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 141178d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_4; 141278d08d09SMilanka Ringwald } 141378d08d09SMilanka Ringwald return block_length; 141478d08d09SMilanka Ringwald } 141578d08d09SMilanka Ringwald 141678d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){ 141767ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 141878d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 14198e7044f9SMatthias Ringwald uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap; 142078d08d09SMilanka Ringwald 14218e7044f9SMatthias Ringwald // use preferred sampling frequency if possible 14228e7044f9SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){ 14236ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 14248e7044f9SMatthias Ringwald } 14256ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){ 14266ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 14276ed344c3SMatthias Ringwald } 14286ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){ 14296ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 14306ed344c3SMatthias Ringwald } 14316ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){ 14326ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 14336ed344c3SMatthias Ringwald } 14346ed344c3SMatthias Ringwald 14358e7044f9SMatthias Ringwald // otherwise, use highest available 14366ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_48000){ 14376ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 143878d08d09SMilanka Ringwald } 14396ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_44100){ 14406ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 14416ed344c3SMatthias Ringwald } 14426ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_32000){ 14436ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 14446ed344c3SMatthias Ringwald } 14456ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_16000){ 14466ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 14476ed344c3SMatthias Ringwald } 14486ed344c3SMatthias Ringwald return AVDTP_SBC_44100; // some default 144978d08d09SMilanka Ringwald } 145078d08d09SMilanka Ringwald 145178d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){ 145267ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 145378d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 145478d08d09SMilanka Ringwald return btstack_min(media_codec[3], remote_max_bitpool_value); 145578d08d09SMilanka Ringwald } 145678d08d09SMilanka Ringwald 145778d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){ 145867ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 145978d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 146078d08d09SMilanka Ringwald return btstack_max(media_codec[2], remote_min_bitpool_value); 1461747ec646SMilanka Ringwald } 1462485c0a4cSMilanka Ringwald 1463485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){ 1464485c0a4cSMilanka Ringwald if (!stream_endpoint) return 0; 1465485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid == 0) return 0; 1466485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid > 0x3E) return 0; 1467485c0a4cSMilanka Ringwald return 1; 1468485c0a4cSMilanka Ringwald } 14698322fb3aSMatthias Ringwald 14708322fb3aSMatthias Ringwald void avdtp_init(void){ 14718322fb3aSMatthias Ringwald static bool l2cap_registered = false; 14728322fb3aSMatthias Ringwald if (!l2cap_registered){ 14738322fb3aSMatthias Ringwald l2cap_registered = true; 14748322fb3aSMatthias Ringwald l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, 0xffff, gap_get_security_level()); 14758322fb3aSMatthias Ringwald } 14768322fb3aSMatthias Ringwald } 1477