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; 626*cc92f22bSMatthias Ringwald if (!connection->sink_supported || (connection->avdtp_l2cap_psm == 0)) { 627*cc92f22bSMatthias Ringwald status = SDP_SERVICE_NOT_FOUND; 628722c03bdSMatthias Ringwald break; 629722c03bdSMatthias Ringwald } 630149deddbSMilanka Ringwald break; 631149deddbSMilanka Ringwald default: 632149deddbSMilanka Ringwald btstack_assert(false); 633722c03bdSMatthias Ringwald return; 6341e1ae2bcSMilanka Ringwald } 635149deddbSMilanka Ringwald break; 636149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 637149deddbSMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 638149deddbSMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 639b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 640149deddbSMilanka Ringwald return; 641149deddbSMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 642149deddbSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 643149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 644*cc92f22bSMatthias Ringwald if (!connection->source_supported || (connection->avdtp_l2cap_psm == 0)) { 645*cc92f22bSMatthias Ringwald status = SDP_SERVICE_NOT_FOUND; 646722c03bdSMatthias Ringwald break; 647722c03bdSMatthias Ringwald } 648149deddbSMilanka Ringwald break; 649149deddbSMilanka Ringwald default: 650149deddbSMilanka Ringwald btstack_assert(false); 651722c03bdSMatthias Ringwald return; 652974d4d6eSMilanka Ringwald } 6532f6083d0SMilanka Ringwald break; 654cc61e7e9SMilanka Ringwald 655cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 656cc61e7e9SMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 657cc61e7e9SMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 658cc61e7e9SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 659cc61e7e9SMilanka Ringwald return; 660cc61e7e9SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 661*cc92f22bSMatthias Ringwald // without suitable SDP Record, avdtp version v0.0 is assumed 662cc61e7e9SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 663cc61e7e9SMilanka Ringwald break; 664cc61e7e9SMilanka Ringwald default: 665cc61e7e9SMilanka Ringwald btstack_assert(false); 666cc61e7e9SMilanka Ringwald return; 667cc61e7e9SMilanka Ringwald } 668cc61e7e9SMilanka Ringwald break; 669cc61e7e9SMilanka Ringwald 670149deddbSMilanka Ringwald default: 67108cb850dSMilanka Ringwald // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete 67208cb850dSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 67308cb850dSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 67408cb850dSMilanka Ringwald } 675149deddbSMilanka Ringwald return; 6762f6083d0SMilanka Ringwald } 677f0c39502SMilanka Ringwald 678722c03bdSMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 679149deddbSMilanka Ringwald avdtp_handle_sdp_query_succeeded(connection); 680149deddbSMilanka Ringwald } else { 681149deddbSMilanka Ringwald avdtp_handle_sdp_query_failed(connection, status); 682692c0605SMilanka Ringwald } 6835797104aSMilanka Ringwald 6845797104aSMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 6855797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 6865797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 687692c0605SMilanka Ringwald } 688692c0605SMilanka Ringwald 689146fc0fbSMilanka 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){ 69036da8747SMilanka Ringwald if (connection == NULL){ 69136da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 6925ace758fSMilanka Ringwald connection = avdtp_create_connection(event_addr, cid); 69336da8747SMilanka Ringwald } 694692c0605SMilanka Ringwald 69536da8747SMilanka Ringwald if (connection) { 69636da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 69736da8747SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 698146fc0fbSMilanka Ringwald connection->con_handle = con_handle; 699ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 70036da8747SMilanka Ringwald } 70136da8747SMilanka Ringwald return connection; 70236da8747SMilanka Ringwald } 703f0c39502SMilanka Ringwald 704ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 705326e3662SMilanka Ringwald uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 706326e3662SMilanka Ringwald 7075ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 708326e3662SMilanka Ringwald if (connection == NULL) return; 709326e3662SMilanka Ringwald 710ff53b162SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){ 711326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 712326e3662SMilanka Ringwald l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 713326e3662SMilanka Ringwald } 714326e3662SMilanka Ringwald } 715326e3662SMilanka Ringwald 716ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){ 717ff53b162SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler); 718ff53b162SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid); 719326e3662SMilanka Ringwald 720326e3662SMilanka Ringwald // add some jitter/randomness to reconnect delay 721326e3662SMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 722ff53b162SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 723ff53b162SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 724326e3662SMilanka Ringwald } 725326e3662SMilanka Ringwald 726326e3662SMilanka Ringwald 727326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 728747ec646SMilanka Ringwald bd_addr_t event_addr; 729747ec646SMilanka Ringwald uint16_t psm; 730747ec646SMilanka Ringwald uint16_t local_cid; 7311e1ae2bcSMilanka Ringwald uint8_t status; 732326e3662SMilanka Ringwald uint16_t l2cap_mtu; 733146fc0fbSMilanka Ringwald hci_con_handle_t con_handle; 73436da8747SMilanka Ringwald 73536da8747SMilanka Ringwald bool accept_streaming_connection; 73636da8747SMilanka Ringwald bool outoing_signaling_active; 73736da8747SMilanka Ringwald bool decline_connection; 73884521ac1SMilanka Ringwald 739747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = NULL; 740747ec646SMilanka Ringwald avdtp_connection_t * connection = NULL; 74136da8747SMilanka Ringwald 742747ec646SMilanka Ringwald switch (packet_type) { 743747ec646SMilanka Ringwald case L2CAP_DATA_PACKET: 7445ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 745747ec646SMilanka Ringwald if (connection){ 74677092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 747747ec646SMilanka Ringwald break; 748747ec646SMilanka Ringwald } 749747ec646SMilanka Ringwald 7506f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 751747ec646SMilanka Ringwald if (!stream_endpoint){ 752747ec646SMilanka Ringwald if (!connection) break; 75377092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 754747ec646SMilanka Ringwald break; 755747ec646SMilanka Ringwald } 756747ec646SMilanka Ringwald 7578c0f3635SMilanka Ringwald if (stream_endpoint->connection){ 7589413b167SMilanka Ringwald if (channel == stream_endpoint->connection->l2cap_signaling_cid){ 75977092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size); 760747ec646SMilanka Ringwald break; 761747ec646SMilanka Ringwald } 7628c0f3635SMilanka Ringwald } 763747ec646SMilanka Ringwald 764747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_media_cid){ 765951d2774SMatthias Ringwald btstack_assert(avdtp_sink_handle_media_data); 766951d2774SMatthias Ringwald (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size); 767747ec646SMilanka Ringwald break; 768747ec646SMilanka Ringwald } 769747ec646SMilanka Ringwald 770747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_reporting_cid){ 7718587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED"); 772747ec646SMilanka Ringwald } else if (channel == stream_endpoint->l2cap_recovery_cid){ 7738587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED"); 774747ec646SMilanka Ringwald } else { 775747ec646SMilanka Ringwald log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel); 776747ec646SMilanka Ringwald } 777747ec646SMilanka Ringwald break; 778747ec646SMilanka Ringwald 779747ec646SMilanka Ringwald case HCI_EVENT_PACKET: 780747ec646SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 78136da8747SMilanka Ringwald 782747ec646SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 783747ec646SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 784747ec646SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 785146fc0fbSMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 78636da8747SMilanka Ringwald outoing_signaling_active = false; 78736da8747SMilanka Ringwald accept_streaming_connection = false; 78836da8747SMilanka Ringwald 7895ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 79036da8747SMilanka Ringwald if (connection != NULL){ 7910d4a198eSMatthias Ringwald switch (connection->state){ 7920d4a198eSMatthias Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED: 79336da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 79436da8747SMilanka Ringwald outoing_signaling_active = true; 79536da8747SMilanka Ringwald connection->incoming_declined = true; 79636da8747SMilanka Ringwald break; 79736da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 79836da8747SMilanka Ringwald outoing_signaling_active = true; 79936da8747SMilanka Ringwald accept_streaming_connection = true; 80036da8747SMilanka Ringwald break; 801f0c39502SMilanka Ringwald default: 802f0c39502SMilanka Ringwald break; 8030d4a198eSMatthias Ringwald } 804747ec646SMilanka Ringwald } 80536da8747SMilanka Ringwald log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d", 80636da8747SMilanka Ringwald bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection); 807747ec646SMilanka Ringwald 80836da8747SMilanka Ringwald decline_connection = outoing_signaling_active && !accept_streaming_connection; 80936da8747SMilanka Ringwald if (outoing_signaling_active == false){ 810146fc0fbSMilanka Ringwald connection = avdtp_handle_incoming_connection(connection, event_addr, con_handle, local_cid); 81136da8747SMilanka Ringwald if (connection == NULL){ 81236da8747SMilanka Ringwald decline_connection = true; 81336da8747SMilanka Ringwald } 81436da8747SMilanka Ringwald } else if (accept_streaming_connection){ 81536da8747SMilanka Ringwald if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) { 81636da8747SMilanka Ringwald decline_connection = true; 81736da8747SMilanka Ringwald } else { 818939e12adSMatthias Ringwald // now, we're only dealing with media connections that are created by remote side - we're acceptor here 8193338afc0SMatthias Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_seid(connection->acceptor_local_seid); 82036da8747SMilanka Ringwald if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) { 82136da8747SMilanka Ringwald decline_connection = true; 82236da8747SMilanka Ringwald } 82336da8747SMilanka Ringwald } 824747ec646SMilanka Ringwald } 825747ec646SMilanka Ringwald 82636da8747SMilanka Ringwald if (decline_connection){ 827a3ce0109SMatthias Ringwald l2cap_decline_connection(local_cid); 82836da8747SMilanka Ringwald } else { 829747ec646SMilanka Ringwald l2cap_accept_connection(local_cid); 83036da8747SMilanka Ringwald } 831747ec646SMilanka Ringwald break; 832747ec646SMilanka Ringwald 833747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 834a5114819SMilanka Ringwald 835a0b8a58cSMilanka Ringwald psm = l2cap_event_channel_opened_get_psm(packet); 83684e3541eSMilanka Ringwald if (psm != BLUETOOTH_PSM_AVDTP){ 837355ac553SMilanka Ringwald log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED "); 838a0b8a58cSMilanka Ringwald return; 839a0b8a58cSMilanka Ringwald } 840a0b8a58cSMilanka Ringwald 8411e1ae2bcSMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 842747ec646SMilanka Ringwald // inform about new l2cap connection 843747ec646SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 8447050d2caSMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 845326e3662SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 8465ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 84736da8747SMilanka Ringwald if (connection == NULL){ 84836da8747SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr)); 849a0b8a58cSMilanka Ringwald break; 850a0b8a58cSMilanka Ringwald } 851a0b8a58cSMilanka Ringwald 852146fc0fbSMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 853146fc0fbSMilanka Ringwald 854a5114819SMilanka Ringwald switch (connection->state){ 855a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 856326e3662SMilanka Ringwald switch (status){ 857326e3662SMilanka Ringwald case ERROR_CODE_SUCCESS: 858326e3662SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 859326e3662SMilanka Ringwald connection->incoming_declined = false; 860326e3662SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 861146fc0fbSMilanka Ringwald connection->con_handle = con_handle; 862326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_OPENED; 863146fc0fbSMilanka 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); 864146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status); 865326e3662SMilanka Ringwald return; 866326e3662SMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 867326e3662SMilanka Ringwald if (connection->incoming_declined == true) { 868326e3662SMilanka Ringwald log_info("Connection was declined, and the outgoing failed"); 869ff53b162SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY; 870326e3662SMilanka Ringwald connection->incoming_declined = false; 871ff53b162SMilanka Ringwald avdtp_retry_timer_start(connection); 872326e3662SMilanka Ringwald return; 873326e3662SMilanka Ringwald } 874326e3662SMilanka Ringwald break; 875326e3662SMilanka Ringwald default: 876326e3662SMilanka Ringwald log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 877326e3662SMilanka Ringwald break; 878326e3662SMilanka Ringwald } 879146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status); 880f82b60efSMilanka Ringwald avdtp_finalize_connection(connection); 881a0b8a58cSMilanka Ringwald break; 882747ec646SMilanka Ringwald 883a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 88419a000d1SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid); 885747ec646SMilanka Ringwald if (!stream_endpoint){ 8865bd73fa2SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid); 887747ec646SMilanka Ringwald return; 888747ec646SMilanka Ringwald } 889326e3662SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 890355ac553SMilanka 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)); 891a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 892f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, status); 893a466d508SMilanka Ringwald break; 894a466d508SMilanka Ringwald } 895a5114819SMilanka Ringwald switch (stream_endpoint->state){ 896a5114819SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED: 897a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED; 898a466d508SMilanka Ringwald stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet); 899a466d508SMilanka Ringwald stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet); 900d1207cd8SMilanka Ringwald 901355ac553SMilanka 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)); 902f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS); 903a5114819SMilanka Ringwald break; 904a5114819SMilanka Ringwald default: 905a5114819SMilanka 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)); 90623edb87eSMilanka Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_COMMAND_DISALLOWED); 907a5114819SMilanka Ringwald break; 908a5114819SMilanka Ringwald } 909a5114819SMilanka Ringwald break; 910a5114819SMilanka Ringwald 911a5114819SMilanka Ringwald default: 912326e3662SMilanka Ringwald log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state); 913a5114819SMilanka Ringwald break; 914a5114819SMilanka Ringwald } 915747ec646SMilanka Ringwald break; 916747ec646SMilanka Ringwald 917747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 918747ec646SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 9196f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid); 9205ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid); 92136da8747SMilanka Ringwald 922f01aeca4SMilanka Ringwald log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint); 923f01aeca4SMilanka Ringwald 924a466d508SMilanka Ringwald if (stream_endpoint){ 925a466d508SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == local_cid){ 926a466d508SMilanka Ringwald connection = stream_endpoint->connection; 927596b7fdcSMilanka Ringwald if (connection) { 928f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_released(stream_endpoint, 929f751daa3SMatthias Ringwald connection->avdtp_cid, 930f751daa3SMatthias Ringwald avdtp_local_seid(stream_endpoint)); 931596b7fdcSMilanka Ringwald } 932485c0a4cSMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 9337f162947SMilanka Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE; 934a466d508SMilanka Ringwald break; 935a466d508SMilanka Ringwald } 936a466d508SMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == local_cid){ 937355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid); 938a466d508SMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0; 939a466d508SMilanka Ringwald break; 940a466d508SMilanka Ringwald } 941a466d508SMilanka Ringwald 942a466d508SMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == local_cid){ 943355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid); 944a466d508SMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0; 945a466d508SMilanka Ringwald break; 946a466d508SMilanka Ringwald } 947a466d508SMilanka Ringwald } 948596b7fdcSMilanka Ringwald 949596b7fdcSMilanka Ringwald if (connection){ 950596b7fdcSMilanka Ringwald btstack_linked_list_iterator_t it; 951d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 952596b7fdcSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 953f01aeca4SMilanka Ringwald stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 954f01aeca4SMilanka Ringwald if (stream_endpoint->connection == connection){ 955f01aeca4SMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 956596b7fdcSMilanka Ringwald } 957596b7fdcSMilanka Ringwald } 958c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_released(connection->avdtp_cid); 9595ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 960596b7fdcSMilanka Ringwald break; 961596b7fdcSMilanka Ringwald } 962747ec646SMilanka Ringwald break; 963747ec646SMilanka Ringwald 964747ec646SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 965c6bc5965SMilanka Ringwald log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel); 966d80ccd43SMatthias Ringwald avdtp_handle_can_send_now(channel); 967747ec646SMilanka Ringwald break; 968747ec646SMilanka Ringwald default: 969355ac553SMilanka Ringwald log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet)); 970747ec646SMilanka Ringwald break; 971747ec646SMilanka Ringwald } 972747ec646SMilanka Ringwald break; 973747ec646SMilanka Ringwald 974747ec646SMilanka Ringwald default: 975747ec646SMilanka Ringwald // other packet type 976747ec646SMilanka Ringwald break; 977747ec646SMilanka Ringwald } 978747ec646SMilanka Ringwald } 979747ec646SMilanka Ringwald 980b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){ 9815ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 98223edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 983b401ff59SMilanka Ringwald 984a466d508SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS; 985747ec646SMilanka Ringwald 986f01aeca4SMilanka Ringwald btstack_linked_list_iterator_t it; 987f01aeca4SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 988f01aeca4SMilanka Ringwald 989f01aeca4SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 990f01aeca4SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 991f01aeca4SMilanka Ringwald if (stream_endpoint->connection != connection) continue; 992f01aeca4SMilanka Ringwald 993f01aeca4SMilanka Ringwald switch (stream_endpoint->state){ 994f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_OPENED: 995f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_STREAMING: 996f01aeca4SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED; 997f01aeca4SMilanka Ringwald l2cap_disconnect(stream_endpoint->l2cap_media_cid, 0); 998f01aeca4SMilanka Ringwald break; 999f01aeca4SMilanka Ringwald default: 1000f01aeca4SMilanka Ringwald break; 1001f01aeca4SMilanka Ringwald } 1002f01aeca4SMilanka Ringwald } 1003f01aeca4SMilanka Ringwald 1004f01aeca4SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED; 1005f01aeca4SMilanka Ringwald l2cap_disconnect(connection->l2cap_signaling_cid, 0); 10064ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1007747ec646SMilanka Ringwald } 1008747ec646SMilanka Ringwald 1009297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){ 10105ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1011747ec646SMilanka Ringwald if (!connection){ 10128587e32cSMilanka Ringwald log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid); 101323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1014747ec646SMilanka Ringwald } 1015747ec646SMilanka Ringwald 1016747ec646SMilanka Ringwald if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) { 10178587e32cSMilanka Ringwald log_error("avdtp_media_connect: wrong connection state %d", connection->state); 101823edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1019747ec646SMilanka Ringwald } 1020747ec646SMilanka Ringwald 10213338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1022747ec646SMilanka Ringwald if (!stream_endpoint) { 10236b0ee1d0SMilanka Ringwald log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid); 102423edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1025747ec646SMilanka Ringwald } 1026747ec646SMilanka Ringwald 1027485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid != remote_seid){ 1028485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid); 102923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1030485c0a4cSMilanka Ringwald } 1031485c0a4cSMilanka Ringwald 103223edb87eSMilanka Ringwald if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return ERROR_CODE_COMMAND_DISALLOWED; 1033747ec646SMilanka Ringwald 1034b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 103596dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 10365bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1037747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM; 1038747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM; 1039d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 10404ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1041747ec646SMilanka Ringwald } 1042747ec646SMilanka Ringwald 1043297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10445ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 104546e6b063SMilanka Ringwald if (!connection){ 10464ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 104723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 104846e6b063SMilanka Ringwald } 10495cfe7f4cSMilanka Ringwald 10503338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 10514ccacc40SMilanka Ringwald if (!stream_endpoint) { 10524ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid); 105323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10544ccacc40SMilanka Ringwald } 10554ccacc40SMilanka Ringwald 10564ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 10574ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid); 105823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10594ccacc40SMilanka Ringwald } 10604ccacc40SMilanka Ringwald 1061485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 1062485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep registered with the stream endpoint"); 106323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10644ccacc40SMilanka Ringwald } 10654ccacc40SMilanka Ringwald 1066440d8d82SMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){ 1067440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1068440d8d82SMilanka Ringwald } 1069440d8d82SMilanka Ringwald 107060ec20d0SMilanka Ringwald stream_endpoint->start_stream = 1; 10715bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 107296dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1073d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 10744ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1075747ec646SMilanka Ringwald } 1076747ec646SMilanka Ringwald 1077297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){ 10785ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1079747ec646SMilanka Ringwald if (!connection){ 10804ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 108123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1082747ec646SMilanka Ringwald } 10834ccacc40SMilanka Ringwald 10843338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 10854ccacc40SMilanka Ringwald if (!stream_endpoint) { 10864ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid); 108723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10884ccacc40SMilanka Ringwald } 10894ccacc40SMilanka Ringwald 10904ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 10914ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid); 109223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 10934ccacc40SMilanka Ringwald } 1094485c0a4cSMilanka Ringwald 1095fa4419dbSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->close_stream){ 1096440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1097485c0a4cSMilanka Ringwald } 10984ccacc40SMilanka Ringwald 1099fa4419dbSMilanka Ringwald stream_endpoint->close_stream = 1; 11005bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 110196dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1102d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 11034ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1104747ec646SMilanka Ringwald } 1105747ec646SMilanka Ringwald 1106297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11075ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 110860ec20d0SMilanka Ringwald if (!connection){ 11094ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 111023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1111747ec646SMilanka Ringwald } 11124ccacc40SMilanka Ringwald 11133338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 11144ccacc40SMilanka Ringwald if (!stream_endpoint) { 11154ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid); 111623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11174ccacc40SMilanka Ringwald } 11184ccacc40SMilanka Ringwald 11194ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11204ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid); 112123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11224ccacc40SMilanka Ringwald } 1123485c0a4cSMilanka Ringwald 1124485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){ 1125440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1126485c0a4cSMilanka Ringwald } 11274ccacc40SMilanka Ringwald 112860ec20d0SMilanka Ringwald stream_endpoint->abort_stream = 1; 11295bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 113096dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1131d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 11324ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1133747ec646SMilanka Ringwald } 1134747ec646SMilanka Ringwald 1135297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11365ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1137747ec646SMilanka Ringwald if (!connection){ 11384ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 113923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 114060ec20d0SMilanka Ringwald } 11413338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 11424ccacc40SMilanka Ringwald if (!stream_endpoint) { 11434ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid); 114423edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11454ccacc40SMilanka Ringwald } 11464ccacc40SMilanka Ringwald 11474ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11484ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid); 114923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11504ccacc40SMilanka Ringwald } 1151485c0a4cSMilanka Ringwald 1152485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){ 1153440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1154485c0a4cSMilanka Ringwald } 11554ccacc40SMilanka Ringwald 115660ec20d0SMilanka Ringwald stream_endpoint->suspend_stream = 1; 11575bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 115896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1159d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 11604ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1161747ec646SMilanka Ringwald } 1162747ec646SMilanka Ringwald 11635ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){ 11645ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1165747ec646SMilanka Ringwald if (!connection){ 11668587e32cSMilanka Ringwald log_error("avdtp_discover_stream_endpoints: no connection for signaling cid 0x%02x found", avdtp_cid); 116723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11689974aee0SMilanka Ringwald } 11690e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1170c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 117123edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1172747ec646SMilanka Ringwald } 1173ec3d71e3SMilanka Ringwald 1174b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1175747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS; 1176d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1177747ec646SMilanka Ringwald } 1178747ec646SMilanka Ringwald 1179747ec646SMilanka Ringwald 11805ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 11815ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1182747ec646SMilanka Ringwald if (!connection){ 11839900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 118423edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1185747ec646SMilanka Ringwald } 11860e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1187c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 118823edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 11899974aee0SMilanka Ringwald } 11909974aee0SMilanka Ringwald 1191b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1192747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 119396dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1194d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1195747ec646SMilanka Ringwald } 1196747ec646SMilanka Ringwald 1197747ec646SMilanka Ringwald 11985ace758fSMilanka Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 11995ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1200747ec646SMilanka Ringwald if (!connection){ 12019900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 120223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1203747ec646SMilanka Ringwald } 12040e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1205c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 120623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12079974aee0SMilanka Ringwald } 12089974aee0SMilanka Ringwald 1209b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 121096dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1211cc61e7e9SMilanka Ringwald 1212cc61e7e9SMilanka Ringwald if (connection->avdtp_version == 0){ 1213cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES; 1214cc61e7e9SMilanka Ringwald avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query; 1215cc61e7e9SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 1216cc61e7e9SMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 1217cc61e7e9SMilanka Ringwald return ERROR_CODE_SUCCESS; 1218cc61e7e9SMilanka Ringwald } else { 1219cc61e7e9SMilanka Ringwald // AVDTP version lower then 1.3 supports only get capabilities command 1220cc61e7e9SMilanka Ringwald if (connection->avdtp_version < 0x103){ 1221cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 1222cc61e7e9SMilanka Ringwald } else { 1223cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 1224cc61e7e9SMilanka Ringwald } 1225d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1226747ec646SMilanka Ringwald } 1227cc61e7e9SMilanka Ringwald } 1228747ec646SMilanka Ringwald 12295ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){ 12305ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1231747ec646SMilanka Ringwald if (!connection){ 12329900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 123323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1234747ec646SMilanka Ringwald } 12350e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1236c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 123723edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12389974aee0SMilanka Ringwald } 12399974aee0SMilanka Ringwald 1240b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1241747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION; 124296dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1243d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1244747ec646SMilanka Ringwald } 1245747ec646SMilanka Ringwald 1246cec76c5bSMilanka 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){ 12475ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1248747ec646SMilanka Ringwald if (!connection){ 12499900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 125023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1251747ec646SMilanka Ringwald } 12520e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1253c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 1254485c0a4cSMilanka Ringwald log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state); 125523edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12569974aee0SMilanka Ringwald } 1257a3ce0109SMatthias Ringwald if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){ 1258a3ce0109SMatthias Ringwald log_info("configuration already started, config state %u", connection->configuration_state); 125923edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1260a3ce0109SMatthias Ringwald } 1261747ec646SMilanka Ringwald 1262d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1263747ec646SMilanka Ringwald if (!stream_endpoint) { 12649900b7faSMilanka Ringwald log_error("No initiator stream endpoint for seid %d", local_seid); 126523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1266747ec646SMilanka Ringwald } 1267417b4996SMilanka Ringwald if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){ 1268485c0a4cSMilanka Ringwald log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state); 126923edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1270417b4996SMilanka Ringwald } 1271a3ce0109SMatthias Ringwald 1272bdbc3ef6SMilanka Ringwald connection->active_stream_endpoint = (void*) stream_endpoint; 1273a3ce0109SMatthias Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED; 1274747ec646SMilanka Ringwald 1275b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 127696dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 12775bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1278f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1279f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1280747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION; 1281ffa6c160SMilanka Ringwald 128244e638f3SMatthias Ringwald log_debug("SE %p, initiator_config_state: 0x%02x", stream_endpoint, stream_endpoint->initiator_config_state); 12833a69f723SMatthias Ringwald 1284d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1285747ec646SMilanka Ringwald } 1286747ec646SMilanka Ringwald 1287cec76c5bSMilanka 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){ 12885ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1289747ec646SMilanka Ringwald if (!connection){ 12909900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 129123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1292747ec646SMilanka Ringwald } 1293747ec646SMilanka Ringwald //TODO: if opened only app capabilities, enable reconfigure for not opened 12940e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1295c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 129623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12979974aee0SMilanka Ringwald } 12989e42cfccSMilanka Ringwald 1299d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 130078d08d09SMilanka Ringwald if (!stream_endpoint) { 13014ccacc40SMilanka Ringwald log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid); 130223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 130378d08d09SMilanka Ringwald } 130478d08d09SMilanka Ringwald 1305485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 13068587e32cSMilanka Ringwald log_error("avdtp_reconfigure: no associated remote sep"); 130723edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 130878d08d09SMilanka Ringwald } 1309485c0a4cSMilanka Ringwald 1310b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 131196dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 13125bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1313f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1314f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1315747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID; 1316d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1317747ec646SMilanka Ringwald } 1318747ec646SMilanka Ringwald 13198e7044f9SMatthias Ringwald void avdtp_set_preferred_sampling_frequeny(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){ 13208e7044f9SMatthias Ringwald stream_endpoint->preferred_sampling_frequency = sampling_frequency; 13218e7044f9SMatthias Ringwald } 13228e7044f9SMatthias Ringwald 132379654d96SMilanka Ringwald void avdtp_set_preferred_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t channel_mode){ 132479654d96SMilanka Ringwald stream_endpoint->preferred_channel_mode = channel_mode; 132579654d96SMilanka Ringwald } 132679654d96SMilanka Ringwald 132779654d96SMilanka Ringwald 132878d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){ 132978d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 133078d08d09SMilanka Ringwald uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap; 133178d08d09SMilanka Ringwald 133278d08d09SMilanka Ringwald uint8_t channel_mode = AVDTP_SBC_STEREO; 133379654d96SMilanka Ringwald // use preferred channel mode if possible 133479654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_JOINT_STEREO){ 133579654d96SMilanka Ringwald return AVDTP_SBC_JOINT_STEREO; 133679654d96SMilanka Ringwald } 133779654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_STEREO){ 133879654d96SMilanka Ringwald return AVDTP_SBC_STEREO; 133979654d96SMilanka Ringwald } 134079654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_DUAL_CHANNEL){ 134179654d96SMilanka Ringwald return AVDTP_SBC_DUAL_CHANNEL; 134279654d96SMilanka Ringwald } 134379654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_MONO){ 134479654d96SMilanka Ringwald return AVDTP_SBC_MONO; 134579654d96SMilanka Ringwald } 134679654d96SMilanka Ringwald 134779654d96SMilanka Ringwald 134878d08d09SMilanka Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 134978d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_JOINT_STEREO; 135078d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 135178d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_STEREO; 135278d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 135378d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_DUAL_CHANNEL; 135478d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_MONO){ 135578d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_MONO; 135678d08d09SMilanka Ringwald } 135778d08d09SMilanka Ringwald return channel_mode; 135878d08d09SMilanka Ringwald } 135978d08d09SMilanka Ringwald 136078d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){ 136178d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 136278d08d09SMilanka Ringwald uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap; 136378d08d09SMilanka Ringwald 136478d08d09SMilanka Ringwald uint8_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 136578d08d09SMilanka Ringwald if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){ 136678d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 136778d08d09SMilanka Ringwald } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){ 136878d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR; 136978d08d09SMilanka Ringwald } 137078d08d09SMilanka Ringwald return allocation_method; 137178d08d09SMilanka Ringwald } 137278d08d09SMilanka Ringwald 1373bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){ 1374bd1ecb8aSMilanka Ringwald if (!stream_endpoint) return 0; 1375bd1ecb8aSMilanka Ringwald return stream_endpoint->sep.seid; 1376bd1ecb8aSMilanka Ringwald } 137778d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){ 137867ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 137978d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 138078d08d09SMilanka Ringwald uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap; 138178d08d09SMilanka Ringwald 138278d08d09SMilanka Ringwald uint8_t subbands = AVDTP_SBC_SUBBANDS_8; 138378d08d09SMilanka Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 138478d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_8; 138578d08d09SMilanka Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 138678d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_4; 138778d08d09SMilanka Ringwald } 138878d08d09SMilanka Ringwald return subbands; 138978d08d09SMilanka Ringwald } 139078d08d09SMilanka Ringwald 139178d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){ 139267ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 139378d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 139478d08d09SMilanka Ringwald uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap; 139578d08d09SMilanka Ringwald 139678d08d09SMilanka Ringwald uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16; 139778d08d09SMilanka Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 139878d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_16; 139978d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 140078d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_12; 140178d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 140278d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_8; 140378d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 140478d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_4; 140578d08d09SMilanka Ringwald } 140678d08d09SMilanka Ringwald return block_length; 140778d08d09SMilanka Ringwald } 140878d08d09SMilanka Ringwald 140978d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){ 141067ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 141178d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 14128e7044f9SMatthias Ringwald uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap; 141378d08d09SMilanka Ringwald 14148e7044f9SMatthias Ringwald // use preferred sampling frequency if possible 14158e7044f9SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){ 14166ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 14178e7044f9SMatthias Ringwald } 14186ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){ 14196ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 14206ed344c3SMatthias Ringwald } 14216ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){ 14226ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 14236ed344c3SMatthias Ringwald } 14246ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){ 14256ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 14266ed344c3SMatthias Ringwald } 14276ed344c3SMatthias Ringwald 14288e7044f9SMatthias Ringwald // otherwise, use highest available 14296ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_48000){ 14306ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 143178d08d09SMilanka Ringwald } 14326ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_44100){ 14336ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 14346ed344c3SMatthias Ringwald } 14356ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_32000){ 14366ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 14376ed344c3SMatthias Ringwald } 14386ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_16000){ 14396ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 14406ed344c3SMatthias Ringwald } 14416ed344c3SMatthias Ringwald return AVDTP_SBC_44100; // some default 144278d08d09SMilanka Ringwald } 144378d08d09SMilanka Ringwald 144478d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){ 144567ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 144678d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 144778d08d09SMilanka Ringwald return btstack_min(media_codec[3], remote_max_bitpool_value); 144878d08d09SMilanka Ringwald } 144978d08d09SMilanka Ringwald 145078d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){ 145167ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 145278d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 145378d08d09SMilanka Ringwald return btstack_max(media_codec[2], remote_min_bitpool_value); 1454747ec646SMilanka Ringwald } 1455485c0a4cSMilanka Ringwald 1456485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){ 1457485c0a4cSMilanka Ringwald if (!stream_endpoint) return 0; 1458485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid == 0) return 0; 1459485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid > 0x3E) return 0; 1460485c0a4cSMilanka Ringwald return 1; 1461485c0a4cSMilanka Ringwald } 14628322fb3aSMatthias Ringwald 14638322fb3aSMatthias Ringwald void avdtp_init(void){ 14648322fb3aSMatthias Ringwald static bool l2cap_registered = false; 14658322fb3aSMatthias Ringwald if (!l2cap_registered){ 14668322fb3aSMatthias Ringwald l2cap_registered = true; 14678322fb3aSMatthias Ringwald l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, 0xffff, gap_get_security_level()); 14688322fb3aSMatthias Ringwald } 14698322fb3aSMatthias Ringwald } 1470