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 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH 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" 50c70720c6SMatthias Ringwald #include "classic/avdtp_util.h" 514cb889a5SMilanka Ringwald #include "classic/avdtp_acceptor.h" 524cb889a5SMilanka Ringwald #include "classic/avdtp_initiator.h" 5384e3541eSMilanka Ringwald #include "classic/avdtp_util.h" 5484e3541eSMilanka Ringwald #include "classic/sdp_client.h" 5584e3541eSMilanka Ringwald #include "classic/sdp_util.h" 56747ec646SMilanka Ringwald 57137e2954SMatthias Ringwald // higher layer callbacks 58a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_source_callback; 59a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_sink_callback; 60137e2954SMatthias Ringwald 61137e2954SMatthias Ringwald static void (*avdtp_sink_handle_media_data)(uint8_t local_seid, uint8_t *packet, uint16_t size); 62137e2954SMatthias Ringwald 636a737fb6SMatthias Ringwald static uint8_t (*avdtp_sink_media_config_validator)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size); 646a737fb6SMatthias Ringwald static uint8_t (*avdtp_source_media_config_validator)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size); 65a1fb0563SMilanka Ringwald 66137e2954SMatthias Ringwald // sdp query 676a737fb6SMatthias Ringwald static btstack_context_callback_registration_t avdtp_handle_sdp_client_query_request; 68137e2954SMatthias Ringwald static uint16_t avdtp_sdp_query_context_avdtp_cid = 0; 69f0c39502SMilanka Ringwald 70137e2954SMatthias Ringwald // registered stream endpoints 71137e2954SMatthias Ringwald static btstack_linked_list_t avdtp_stream_endpoints; 72137e2954SMatthias Ringwald static uint16_t avdtp_stream_endpoints_id_counter = 0; 73560b3f31SMilanka Ringwald 74137e2954SMatthias Ringwald static bool avdtp_l2cap_registered; 755ace758fSMilanka Ringwald 76137e2954SMatthias Ringwald static btstack_linked_list_t avdtp_connections; 77137e2954SMatthias Ringwald static uint16_t avdtp_transaction_id_counter = 0; 78747ec646SMilanka Ringwald 79137e2954SMatthias Ringwald static int avdtp_record_id; 80137e2954SMatthias Ringwald static uint8_t avdtp_attribute_value[45]; 81137e2954SMatthias Ringwald static const unsigned int avdtp_attribute_value_buffer_size = sizeof(avdtp_attribute_value); 82951d2774SMatthias Ringwald 83af121d54SMilanka Ringwald static uint16_t avdtp_cid_counter = 0; 84747ec646SMilanka Ringwald 85692c0605SMilanka Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 86692c0605SMilanka Ringwald 87f751daa3SMatthias Ringwald btstack_packet_handler_t 88f751daa3SMatthias Ringwald avdtp_packet_handler_for_stream_endpoint(const avdtp_stream_endpoint_t *stream_endpoint) { 89f751daa3SMatthias Ringwald return (stream_endpoint->sep.type == AVDTP_SOURCE) ? avdtp_source_callback : avdtp_sink_callback; 90f751daa3SMatthias Ringwald } 91f751daa3SMatthias Ringwald 92c69f4ba5SMatthias Ringwald void avdtp_emit_sink_and_source(uint8_t * packet, uint16_t size){ 93c69f4ba5SMatthias Ringwald if (avdtp_source_callback != NULL){ 94c69f4ba5SMatthias Ringwald (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size); 95c69f4ba5SMatthias Ringwald } 96c69f4ba5SMatthias Ringwald if (avdtp_sink_callback != NULL){ 97c69f4ba5SMatthias Ringwald (*avdtp_sink_callback)(HCI_EVENT_PACKET, 0, packet, size); 98c69f4ba5SMatthias Ringwald } 99c69f4ba5SMatthias Ringwald } 100c69f4ba5SMatthias Ringwald 1014b7d40bbSMatthias Ringwald void avdtp_emit_source(uint8_t * packet, uint16_t size){ 1024b7d40bbSMatthias Ringwald if (avdtp_source_callback != NULL){ 1034b7d40bbSMatthias Ringwald (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, packet, size); 104f751daa3SMatthias Ringwald } 105f08f4934SMatthias Ringwald } 106f08f4934SMatthias Ringwald 107f751daa3SMatthias Ringwald btstack_linked_list_t * avdtp_get_stream_endpoints(void){ 108137e2954SMatthias Ringwald return &avdtp_stream_endpoints; 109f751daa3SMatthias Ringwald } 11036da8747SMilanka Ringwald 11162c4ec82SMilanka Ringwald btstack_linked_list_t * avdtp_get_connections(void){ 112137e2954SMatthias Ringwald return &avdtp_connections; 11362c4ec82SMilanka Ringwald } 11462c4ec82SMilanka Ringwald 1153ec98973SMatthias Ringwald avdtp_connection_t * avdtp_get_connection_for_bd_addr(bd_addr_t addr){ 1165ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 117137e2954SMatthias Ringwald btstack_linked_list_iterator_init(&it, &avdtp_connections); 1185ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1195ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 1205ace758fSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 1215ace758fSMilanka Ringwald return connection; 122b0d75c91SMilanka Ringwald } 1235ace758fSMilanka Ringwald return NULL; 124b0d75c91SMilanka Ringwald } 125b0d75c91SMilanka Ringwald 1265ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_avdtp_cid(uint16_t avdtp_cid){ 1275ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 128137e2954SMatthias Ringwald btstack_linked_list_iterator_init(&it, &avdtp_connections); 1295ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1305ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 1315ace758fSMilanka Ringwald if (connection->avdtp_cid != avdtp_cid) continue; 1325ace758fSMilanka Ringwald return connection; 1335ace758fSMilanka Ringwald } 1345ace758fSMilanka Ringwald return NULL; 1355ace758fSMilanka Ringwald } 1365ace758fSMilanka Ringwald 1375ace758fSMilanka Ringwald 1383338afc0SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_seid(uint16_t seid){ 1395ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 140d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1415ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1425ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1435ace758fSMilanka Ringwald if (stream_endpoint->sep.seid == seid){ 1445ace758fSMilanka Ringwald return stream_endpoint; 1455ace758fSMilanka Ringwald } 1465ace758fSMilanka Ringwald } 1475ace758fSMilanka Ringwald return NULL; 1485ace758fSMilanka Ringwald } 1495ace758fSMilanka Ringwald 150f24f7543SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_source_stream_endpoint_for_media_codec(avdtp_media_codec_type_t codec_type){ 151f24f7543SMatthias Ringwald btstack_linked_list_iterator_t it; 152f24f7543SMatthias Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 153f24f7543SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 154f24f7543SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 155f24f7543SMatthias Ringwald if (stream_endpoint->sep.type != AVDTP_SOURCE) continue; 15684cef9b8SMatthias Ringwald if (stream_endpoint->sep.media_type != AVDTP_AUDIO) continue; 157f24f7543SMatthias Ringwald if (stream_endpoint->sep.capabilities.media_codec.media_codec_type != codec_type) continue; 1587982528cSMatthias Ringwald if (stream_endpoint->sep.in_use) continue; 159f24f7543SMatthias Ringwald return stream_endpoint; 160f24f7543SMatthias Ringwald } 161f24f7543SMatthias Ringwald return NULL; 162f24f7543SMatthias Ringwald } 163f24f7543SMatthias Ringwald 16484cef9b8SMatthias Ringwald avdtp_stream_endpoint_t * avdtp_get_source_stream_endpoint_for_media_codec_other(uint32_t vendor_id, uint16_t codec_id){ 16584cef9b8SMatthias Ringwald btstack_linked_list_iterator_t it; 16684cef9b8SMatthias Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 16784cef9b8SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 16884cef9b8SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 16984cef9b8SMatthias Ringwald if (stream_endpoint->sep.type != AVDTP_SOURCE) continue; 17084cef9b8SMatthias Ringwald if (stream_endpoint->sep.media_type != AVDTP_AUDIO) continue; 1717982528cSMatthias Ringwald if (stream_endpoint->sep.in_use) continue; 17284cef9b8SMatthias Ringwald if (stream_endpoint->sep.capabilities.media_codec.media_codec_type != AVDTP_CODEC_NON_A2DP) continue; 17384cef9b8SMatthias Ringwald if (stream_endpoint->sep.capabilities.media_codec.media_codec_information_len < 6) continue; 17484cef9b8SMatthias Ringwald if (little_endian_read_32(stream_endpoint->sep.capabilities.media_codec.media_codec_information, 0) != vendor_id) continue; 175a9207bf9SBjoern Hartmann if (little_endian_read_16(stream_endpoint->sep.capabilities.media_codec.media_codec_information, 4) != codec_id) continue; 17684cef9b8SMatthias Ringwald return stream_endpoint; 17784cef9b8SMatthias Ringwald } 17884cef9b8SMatthias Ringwald return NULL; 17984cef9b8SMatthias Ringwald } 18084cef9b8SMatthias Ringwald 181f24f7543SMatthias Ringwald 1825ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid){ 1835ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 184137e2954SMatthias Ringwald btstack_linked_list_iterator_init(&it, &avdtp_connections); 1855ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1865ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 1875ace758fSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 1885ace758fSMilanka Ringwald return connection; 1895ace758fSMilanka Ringwald } 1905ace758fSMilanka Ringwald return NULL; 1915ace758fSMilanka Ringwald } 1925ace758fSMilanka Ringwald 1936f98b084SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid){ 1945ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 195d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1965ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1975ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1985ace758fSMilanka Ringwald if (stream_endpoint->l2cap_media_cid == l2cap_cid){ 1995ace758fSMilanka Ringwald return stream_endpoint; 2005ace758fSMilanka Ringwald } 2015ace758fSMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == l2cap_cid){ 2025ace758fSMilanka Ringwald return stream_endpoint; 2035ace758fSMilanka Ringwald } 2045ace758fSMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == l2cap_cid){ 2055ace758fSMilanka Ringwald return stream_endpoint; 2065ace758fSMilanka Ringwald } 2075ace758fSMilanka Ringwald } 2085ace758fSMilanka Ringwald return NULL; 2095ace758fSMilanka Ringwald } 2105ace758fSMilanka Ringwald 21119a000d1SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_signaling_cid(uint16_t l2cap_cid){ 2125ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 213d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 2145ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2155ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 2165ace758fSMilanka Ringwald if (stream_endpoint->connection){ 2175ace758fSMilanka Ringwald if (stream_endpoint->connection->l2cap_signaling_cid == l2cap_cid){ 2185ace758fSMilanka Ringwald return stream_endpoint; 2195ace758fSMilanka Ringwald } 2205ace758fSMilanka Ringwald } 2215ace758fSMilanka Ringwald } 2225ace758fSMilanka Ringwald return NULL; 2235ace758fSMilanka Ringwald } 2245ace758fSMilanka Ringwald 225b1935866SMilanka Ringwald uint16_t avdtp_get_next_transaction_label(void){ 226137e2954SMatthias Ringwald avdtp_transaction_id_counter++; 227137e2954SMatthias Ringwald if (avdtp_transaction_id_counter == 16){ 228137e2954SMatthias Ringwald avdtp_transaction_id_counter = 1; 2295ace758fSMilanka Ringwald } 230137e2954SMatthias Ringwald return avdtp_transaction_id_counter; 2315ace758fSMilanka Ringwald } 2325ace758fSMilanka Ringwald 2335ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_create_connection(bd_addr_t remote_addr, uint16_t cid){ 23436da8747SMilanka Ringwald avdtp_connection_t * connection = btstack_memory_avdtp_connection_get(); 23536da8747SMilanka Ringwald if (!connection){ 23636da8747SMilanka Ringwald log_error("Not enough memory to create connection"); 23736da8747SMilanka Ringwald return NULL; 23836da8747SMilanka Ringwald } 23936da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_IDLE; 240b1935866SMilanka Ringwald connection->initiator_transaction_label = avdtp_get_next_transaction_label(); 24136da8747SMilanka Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE; 24262c4ec82SMilanka Ringwald connection->a2dp_source_discover_seps = false; 24336da8747SMilanka Ringwald connection->avdtp_cid = cid; 24436da8747SMilanka Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 24536da8747SMilanka Ringwald 246137e2954SMatthias Ringwald btstack_linked_list_add(&avdtp_connections, (btstack_linked_item_t *) connection); 24736da8747SMilanka Ringwald return connection; 24836da8747SMilanka Ringwald } 24936da8747SMilanka Ringwald 25036da8747SMilanka Ringwald static uint16_t avdtp_get_next_cid(void){ 251af121d54SMilanka Ringwald if (avdtp_cid_counter == 0xffff) { 2524ccacc40SMilanka Ringwald avdtp_cid_counter = 1; 253af121d54SMilanka Ringwald } else { 254af121d54SMilanka Ringwald avdtp_cid_counter++; 2554ccacc40SMilanka Ringwald } 2564ccacc40SMilanka Ringwald return avdtp_cid_counter; 2574ccacc40SMilanka Ringwald } 2584ccacc40SMilanka Ringwald 259560b3f31SMilanka Ringwald static uint16_t avdtp_get_next_local_seid(void){ 260137e2954SMatthias Ringwald if (avdtp_stream_endpoints_id_counter == 0xffff) { 261137e2954SMatthias Ringwald avdtp_stream_endpoints_id_counter = 1; 262af121d54SMilanka Ringwald } else { 263137e2954SMatthias Ringwald avdtp_stream_endpoints_id_counter++; 2644ccacc40SMilanka Ringwald } 265137e2954SMatthias Ringwald return avdtp_stream_endpoints_id_counter; 2664ccacc40SMilanka Ringwald } 2674ccacc40SMilanka Ringwald 2685797104aSMilanka Ringwald static void avdtp_handle_start_sdp_client_query(void * context){ 2695797104aSMilanka Ringwald UNUSED(context); 270b1549ed3SMilanka Ringwald 2715797104aSMilanka Ringwald btstack_linked_list_iterator_t it; 272137e2954SMatthias Ringwald btstack_linked_list_iterator_init(&it, &avdtp_connections); 2735797104aSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2745797104aSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 2755797104aSMilanka Ringwald 2765797104aSMilanka Ringwald switch (connection->state){ 2775797104aSMilanka Ringwald case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE: 2785797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE; 2795797104aSMilanka Ringwald break; 2805797104aSMilanka Ringwald case AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK: 2815797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE; 2825797104aSMilanka Ringwald break; 283cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 284*e71e31feSMatthias Ringwald switch (connection->initiator_connection_state ){ 285*e71e31feSMatthias Ringwald case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES_FROM_REMOTE_SINK: 286*e71e31feSMatthias Ringwald case AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES_FROM_REMOTE_SOURCE: 287cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_SDP_QUERY_COMPLETE_THEN_GET_ALL_CAPABILITIES; 288cc61e7e9SMilanka Ringwald break; 2895797104aSMilanka Ringwald default: 2905797104aSMilanka Ringwald continue; 2915797104aSMilanka Ringwald } 292*e71e31feSMatthias Ringwald break; 293*e71e31feSMatthias Ringwald default: 294*e71e31feSMatthias Ringwald continue; 295*e71e31feSMatthias Ringwald } 296137e2954SMatthias Ringwald avdtp_sdp_query_context_avdtp_cid = connection->avdtp_cid; 297137e2954SMatthias Ringwald avdtp_record_id = -1; 2985797104aSMilanka Ringwald sdp_client_query_uuid16(&avdtp_handle_sdp_client_query_result, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP); 2995797104aSMilanka Ringwald return; 3005797104aSMilanka Ringwald } 30184521ac1SMilanka Ringwald } 30284521ac1SMilanka Ringwald 303a1fb0563SMilanka Ringwald uint8_t avdtp_connect(bd_addr_t remote, avdtp_role_t role, uint16_t * avdtp_cid){ 3045ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_bd_addr(remote); 30584521ac1SMilanka Ringwald if (connection){ 30684521ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 3074567cc17SMilanka Ringwald } 30884521ac1SMilanka Ringwald 30936da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 3102ad6b656SMilanka Ringwald if (avdtp_cid != NULL) { 31184521ac1SMilanka Ringwald *avdtp_cid = cid; 3122ad6b656SMilanka Ringwald } 3132ad6b656SMilanka Ringwald 3145ace758fSMilanka Ringwald connection = avdtp_create_connection(remote, cid); 31536da8747SMilanka Ringwald if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED; 31636da8747SMilanka Ringwald 31784521ac1SMilanka Ringwald connection->avdtp_cid = cid; 318b1549ed3SMilanka Ringwald 3195797104aSMilanka Ringwald connection->avdtp_l2cap_psm = 0; 3205797104aSMilanka Ringwald connection->avdtp_version = 0; 3215797104aSMilanka Ringwald connection->sink_supported = false; 3225797104aSMilanka Ringwald connection->source_supported = false; 3235797104aSMilanka Ringwald 324b1549ed3SMilanka Ringwald switch (role){ 325149deddbSMilanka Ringwald case AVDTP_ROLE_SOURCE: 3265797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SINK; 327149deddbSMilanka Ringwald break; 328149deddbSMilanka Ringwald case AVDTP_ROLE_SINK: 3295797104aSMilanka Ringwald connection->state = AVDTP_SIGNALING_W2_SEND_SDP_QUERY_FOR_REMOTE_SOURCE; 330149deddbSMilanka Ringwald break; 331149deddbSMilanka Ringwald default: 3325797104aSMilanka Ringwald btstack_assert(false); 333149deddbSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 334149deddbSMilanka Ringwald } 3355797104aSMilanka Ringwald 3365797104aSMilanka Ringwald avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query; 3375797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 3385797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 3395797104aSMilanka Ringwald return ERROR_CODE_SUCCESS; 340692c0605SMilanka Ringwald } 341747ec646SMilanka Ringwald 342a1fb0563SMilanka Ringwald 343a1fb0563SMilanka Ringwald void avdtp_register_sink_packet_handler(btstack_packet_handler_t callback){ 344a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 345a1fb0563SMilanka Ringwald avdtp_sink_callback = callback; 346a1fb0563SMilanka Ringwald } 347a1fb0563SMilanka Ringwald 348a1fb0563SMilanka Ringwald void avdtp_register_source_packet_handler(btstack_packet_handler_t callback){ 349a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 350a1fb0563SMilanka Ringwald avdtp_source_callback = callback; 351a1fb0563SMilanka Ringwald } 352a1fb0563SMilanka Ringwald 353747ec646SMilanka Ringwald void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){ 354747ec646SMilanka Ringwald if (!stream_endpoint){ 3559900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 356747ec646SMilanka Ringwald return; 357747ec646SMilanka Ringwald } 358747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1); 359747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 360747ec646SMilanka Ringwald } 361747ec646SMilanka Ringwald 362747ec646SMilanka Ringwald void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 363747ec646SMilanka Ringwald if (!stream_endpoint){ 3649900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 365747ec646SMilanka Ringwald return; 366747ec646SMilanka Ringwald } 367747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_REPORTING, 1); 368747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 369747ec646SMilanka Ringwald } 370747ec646SMilanka Ringwald 371747ec646SMilanka Ringwald void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 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_DELAY_REPORTING, 1); 377747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 378747ec646SMilanka Ringwald } 379747ec646SMilanka Ringwald 380747ec646SMilanka Ringwald void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){ 381747ec646SMilanka Ringwald if (!stream_endpoint){ 3829900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 383747ec646SMilanka Ringwald return; 384747ec646SMilanka Ringwald } 385747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_RECOVERY, 1); 386747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 387747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.recovery_type = 0x01; // 0x01 = RFC2733 388747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_recovery_window_size = maximum_recovery_window_size; 389747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_number_media_packets = maximum_number_media_packets; 390747ec646SMilanka Ringwald } 391747ec646SMilanka Ringwald 392747ec646SMilanka 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){ 393747ec646SMilanka Ringwald if (!stream_endpoint){ 3949900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 395747ec646SMilanka Ringwald return; 396747ec646SMilanka Ringwald } 397747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_CONTENT_PROTECTION, 1); 398747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 399747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type = cp_type; 4006535961aSMatthias Ringwald (void)memcpy(stream_endpoint->sep.capabilities.content_protection.cp_type_value, 4016535961aSMatthias Ringwald cp_type_value, 4026535961aSMatthias Ringwald btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN)); 40367ae582dSMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type_value_len = btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN); 404747ec646SMilanka Ringwald } 405747ec646SMilanka Ringwald 406747ec646SMilanka Ringwald void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery){ 407747ec646SMilanka Ringwald if (!stream_endpoint){ 4089900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 409747ec646SMilanka Ringwald return; 410747ec646SMilanka Ringwald } 411747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_HEADER_COMPRESSION, 1); 412747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 413747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.back_ch = back_ch; 414747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.media = media; 415747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.recovery = recovery; 416747ec646SMilanka Ringwald } 417747ec646SMilanka Ringwald 4183e6cf581SMatthias Ringwald void avdtp_register_media_codec_category(avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, const uint8_t *media_codec_info, uint16_t media_codec_info_len){ 419747ec646SMilanka Ringwald if (!stream_endpoint){ 4209900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 421747ec646SMilanka Ringwald return; 422747ec646SMilanka Ringwald } 423747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1); 424747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 425747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_type = media_type; 426747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type; 4273e6cf581SMatthias Ringwald // @todo should be stored in struct as const 4283e6cf581SMatthias Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information = (uint8_t*) media_codec_info; 429747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information_len = media_codec_info_len; 430747ec646SMilanka Ringwald } 431747ec646SMilanka Ringwald 432747ec646SMilanka Ringwald void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation){ 433747ec646SMilanka Ringwald if (!stream_endpoint){ 4349900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 435747ec646SMilanka Ringwald return; 436747ec646SMilanka Ringwald } 437747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MULTIPLEXING, 1); 438747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 439747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.multiplexing_mode.fragmentation = fragmentation; 440747ec646SMilanka Ringwald } 441747ec646SMilanka Ringwald 442951d2774SMatthias Ringwald void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size)){ 443951d2774SMatthias Ringwald avdtp_sink_handle_media_data = callback; 444951d2774SMatthias Ringwald } 445747ec646SMilanka Ringwald 4466a737fb6SMatthias Ringwald void avdtp_sink_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size)){ 4476a737fb6SMatthias Ringwald avdtp_sink_media_config_validator = callback; 4486a737fb6SMatthias Ringwald } 4496a737fb6SMatthias Ringwald 4506a737fb6SMatthias Ringwald void avdtp_source_register_media_config_validator(uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size)){ 4516a737fb6SMatthias Ringwald avdtp_source_media_config_validator = callback; 4521ef2d533SMatthias Ringwald } 4531ef2d533SMatthias Ringwald 454c70720c6SMatthias Ringwald uint8_t avdtp_validate_media_configuration(const avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, 455c70720c6SMatthias Ringwald uint8_t reconfigure, const adtvp_media_codec_capabilities_t *media_codec) { 4566a737fb6SMatthias Ringwald uint8_t (*callback)(const avdtp_stream_endpoint_t * stream_endpoint, const uint8_t * event, uint16_t size); 4576a737fb6SMatthias Ringwald if (stream_endpoint->sep.type == AVDTP_SOURCE){ 4586a737fb6SMatthias Ringwald callback = avdtp_source_media_config_validator; 4596a737fb6SMatthias Ringwald } else { 4606a737fb6SMatthias Ringwald callback = avdtp_sink_media_config_validator; 4616a737fb6SMatthias Ringwald } 4626a737fb6SMatthias Ringwald if (callback == NULL) { 4636a737fb6SMatthias Ringwald // config valid 4641ef2d533SMatthias Ringwald return 0; 4651ef2d533SMatthias Ringwald } 466c70720c6SMatthias Ringwald uint8_t event[AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN]; 467c70720c6SMatthias Ringwald uint16_t size = avdtp_setup_media_codec_config_event(event, sizeof(event), stream_endpoint, avdtp_cid, reconfigure, media_codec); 4686a737fb6SMatthias Ringwald return (*callback)(stream_endpoint, event, size); 4691ef2d533SMatthias Ringwald } 4701ef2d533SMatthias Ringwald 471d80ccd43SMatthias Ringwald /* START: tracking can send now requests per l2cap cid */ 472d80ccd43SMatthias Ringwald static void avdtp_handle_can_send_now(uint16_t l2cap_cid) { 473d80ccd43SMatthias Ringwald 474d80ccd43SMatthias Ringwald log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", l2cap_cid); 475d80ccd43SMatthias Ringwald 476d80ccd43SMatthias Ringwald // get signaling connection for l2cap cid 477d80ccd43SMatthias Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_l2cap_signaling_cid(l2cap_cid); 478d80ccd43SMatthias Ringwald 479d80ccd43SMatthias Ringwald if (connection != NULL) { 480747ec646SMilanka Ringwald if (connection->wait_to_send_acceptor) { 481d80ccd43SMatthias Ringwald log_debug("call avdtp_acceptor_stream_config_subsm_run %p", connection); 482d80ccd43SMatthias Ringwald connection->wait_to_send_acceptor = false; 48377092f3eSMatthias Ringwald avdtp_acceptor_stream_config_subsm_run(connection); 484747ec646SMilanka Ringwald } else if (connection->wait_to_send_initiator) { 485d80ccd43SMatthias Ringwald log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling %p", connection); 486d80ccd43SMatthias Ringwald connection->wait_to_send_initiator = false; 487d80ccd43SMatthias Ringwald avdtp_initiator_stream_config_subsm_handle_can_send_now_signaling(connection); 488d80ccd43SMatthias Ringwald } 489d80ccd43SMatthias Ringwald bool more_to_send = connection->wait_to_send_acceptor || connection->wait_to_send_initiator; 490d80ccd43SMatthias Ringwald if (more_to_send){ 491d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(l2cap_cid); 492d80ccd43SMatthias Ringwald } 493d80ccd43SMatthias Ringwald return; 494747ec646SMilanka Ringwald } 495747ec646SMilanka Ringwald 496d80ccd43SMatthias Ringwald // get stream endpoint connection for l2cap cid 497d80ccd43SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(l2cap_cid); 498d80ccd43SMatthias Ringwald if (stream_endpoint != NULL) { 499d80ccd43SMatthias Ringwald log_debug("call avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint %p", stream_endpoint); 500d80ccd43SMatthias Ringwald if (stream_endpoint->request_can_send_now) { 501d0676819SMatthias Ringwald stream_endpoint->request_can_send_now = false; 502d80ccd43SMatthias Ringwald avdtp_initiator_stream_config_subsm_handle_can_send_now_stream_endpoint(stream_endpoint); 503d80ccd43SMatthias Ringwald } 504d0676819SMatthias Ringwald if (stream_endpoint->request_can_send_now){ 505747ec646SMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 506747ec646SMilanka Ringwald } 507747ec646SMilanka Ringwald } 508d80ccd43SMatthias Ringwald } 509d80ccd43SMatthias Ringwald /* END: tracking can send now requests per l2cap cid */ 510747ec646SMilanka Ringwald 511747ec646SMilanka Ringwald 512297feb5fSMilanka Ringwald avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){ 513747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = btstack_memory_avdtp_stream_endpoint_get(); 5144567cc17SMilanka Ringwald if (!stream_endpoint){ 5159900b7faSMilanka Ringwald log_error("Not enough memory to create stream endpoint"); 5164567cc17SMilanka Ringwald return NULL; 5174567cc17SMilanka Ringwald } 518560b3f31SMilanka Ringwald stream_endpoint->sep.seid = avdtp_get_next_local_seid(); 519747ec646SMilanka Ringwald stream_endpoint->sep.media_type = media_type; 520747ec646SMilanka Ringwald stream_endpoint->sep.type = sep_type; 521d8e15394SMilanka Ringwald btstack_linked_list_add(avdtp_get_stream_endpoints(), (btstack_linked_item_t *) stream_endpoint); 522747ec646SMilanka Ringwald return stream_endpoint; 523747ec646SMilanka Ringwald } 524747ec646SMilanka Ringwald 52517ddf501SMatthias Ringwald void avdtp_finalize_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ 52617ddf501SMatthias Ringwald btstack_linked_list_remove(avdtp_get_stream_endpoints(), (btstack_linked_item_t* ) stream_endpoint); 52717ddf501SMatthias Ringwald btstack_memory_avdtp_stream_endpoint_free(stream_endpoint); 52817ddf501SMatthias Ringwald } 52917ddf501SMatthias Ringwald 53077092f3eSMatthias Ringwald static void 53177092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t *connection, uint8_t *packet, uint16_t size) { 532c1c40ea1SMatthias Ringwald if (size < 2) return; 533c1c40ea1SMatthias Ringwald 534c1c40ea1SMatthias Ringwald uint16_t offset; 535c1c40ea1SMatthias Ringwald avdtp_message_type_t message_type = avdtp_get_signaling_packet_type(packet); 536c1c40ea1SMatthias Ringwald switch (message_type){ 537747ec646SMilanka Ringwald case AVDTP_CMD_MSG: 53850453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->acceptor_signaling_packet, packet, size); 53977092f3eSMatthias Ringwald avdtp_acceptor_stream_config_subsm(connection, packet, size, offset); 540747ec646SMilanka Ringwald break; 541747ec646SMilanka Ringwald default: 54250453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->initiator_signaling_packet, packet, size); 54377092f3eSMatthias Ringwald avdtp_initiator_stream_config_subsm(connection, packet, size, offset); 544747ec646SMilanka Ringwald break; 545747ec646SMilanka Ringwald } 546747ec646SMilanka Ringwald } 547747ec646SMilanka Ringwald 548b1549ed3SMilanka Ringwald static void avdtp_handle_sdp_client_query_attribute_value(avdtp_connection_t * connection, uint8_t *packet){ 549692c0605SMilanka Ringwald des_iterator_t des_list_it; 550692c0605SMilanka Ringwald des_iterator_t prot_it; 551692c0605SMilanka Ringwald 552692c0605SMilanka Ringwald // Handle new SDP record 553137e2954SMatthias Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != avdtp_record_id) { 554137e2954SMatthias Ringwald avdtp_record_id = sdp_event_query_attribute_byte_get_record_id(packet); 5558587e32cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 556692c0605SMilanka Ringwald } 557692c0605SMilanka Ringwald 558137e2954SMatthias Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= avdtp_attribute_value_buffer_size) { 559137e2954SMatthias Ringwald avdtp_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 560692c0605SMilanka Ringwald 561692c0605SMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 562692c0605SMilanka Ringwald 563692c0605SMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 564149deddbSMilanka Ringwald 565692c0605SMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 566137e2954SMatthias Ringwald if (de_get_element_type(avdtp_attribute_value) != DE_DES) break; 567137e2954SMatthias Ringwald for (des_iterator_init(&des_list_it, avdtp_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 568692c0605SMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 569692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 570692c0605SMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 571692c0605SMilanka Ringwald switch (uuid){ 572692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE: 573b1549ed3SMilanka Ringwald connection->source_supported = true; 574149deddbSMilanka Ringwald log_info("source_supported"); 575692c0605SMilanka Ringwald break; 576692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK: 577b1549ed3SMilanka Ringwald connection->sink_supported = true; 578149deddbSMilanka Ringwald log_info("sink_supported"); 579692c0605SMilanka Ringwald break; 580692c0605SMilanka Ringwald default: 581692c0605SMilanka Ringwald break; 582692c0605SMilanka Ringwald } 583692c0605SMilanka Ringwald } 584692c0605SMilanka Ringwald break; 585692c0605SMilanka Ringwald 586149deddbSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 5878587e32cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 588137e2954SMatthias Ringwald for (des_iterator_init(&des_list_it, avdtp_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 589692c0605SMilanka Ringwald uint8_t *des_element; 590692c0605SMilanka Ringwald uint8_t *element; 591692c0605SMilanka Ringwald uint32_t uuid; 592692c0605SMilanka Ringwald 593692c0605SMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 594692c0605SMilanka Ringwald 595692c0605SMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 596692c0605SMilanka Ringwald des_iterator_init(&prot_it, des_element); 597692c0605SMilanka Ringwald element = des_iterator_get_element(&prot_it); 598692c0605SMilanka Ringwald 599692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 600692c0605SMilanka Ringwald 601692c0605SMilanka Ringwald uuid = de_get_uuid32(element); 60214fd128cSMatthias Ringwald des_iterator_next(&prot_it); 603149deddbSMilanka Ringwald // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both 604692c0605SMilanka Ringwald switch (uuid){ 605692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 606692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 607b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_l2cap_psm); 608692c0605SMilanka Ringwald break; 609692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_AVDTP: 610692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 611b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_version); 612cc61e7e9SMilanka Ringwald log_info("avdtp version 0x%02x", connection->avdtp_version); 613692c0605SMilanka Ringwald break; 614692c0605SMilanka Ringwald default: 615692c0605SMilanka Ringwald break; 616692c0605SMilanka Ringwald } 617692c0605SMilanka Ringwald } 618692c0605SMilanka Ringwald break; 619149deddbSMilanka Ringwald 620692c0605SMilanka Ringwald default: 621692c0605SMilanka Ringwald break; 622692c0605SMilanka Ringwald } 623692c0605SMilanka Ringwald } 624692c0605SMilanka Ringwald } else { 625137e2954SMatthias Ringwald log_error("SDP attribute value buffer size exceeded: available %d, required %d", avdtp_attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); 626692c0605SMilanka Ringwald } 6276ed344c3SMatthias Ringwald 6286ed344c3SMatthias Ringwald } 6296ed344c3SMatthias Ringwald 6305ace758fSMilanka Ringwald static void avdtp_finalize_connection(avdtp_connection_t * connection){ 631ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 632137e2954SMatthias Ringwald btstack_linked_list_remove(&avdtp_connections, (btstack_linked_item_t*) connection); 633f0c39502SMilanka Ringwald btstack_memory_avdtp_connection_free(connection); 634f0c39502SMilanka Ringwald } 635f0c39502SMilanka Ringwald 636f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_failed(avdtp_connection_t * connection, uint8_t status){ 637a1fb0563SMilanka Ringwald switch (connection->state){ 638a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 639a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 640146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, connection->remote_addr, connection->con_handle, status); 641a1fb0563SMilanka Ringwald break; 642cc61e7e9SMilanka Ringwald 643cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 644cc61e7e9SMilanka Ringwald // SDP query failed: try query that must be supported 645cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 646d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 647a1fb0563SMilanka Ringwald return; 648cc61e7e9SMilanka Ringwald 649cc61e7e9SMilanka Ringwald default: 650cc61e7e9SMilanka Ringwald btstack_assert(false); 651cc61e7e9SMilanka Ringwald break; 652a1fb0563SMilanka Ringwald } 6535ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 654137e2954SMatthias Ringwald avdtp_sdp_query_context_avdtp_cid = 0; 655f0c39502SMilanka Ringwald log_info("SDP query failed with status 0x%02x.", status); 656f0c39502SMilanka Ringwald } 657f0c39502SMilanka Ringwald 658f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){ 659cc61e7e9SMilanka Ringwald log_info("avdtp_handle_sdp_query_succeeded: state %d", connection->state); 660cc61e7e9SMilanka Ringwald 661cc61e7e9SMilanka Ringwald switch (connection->state){ 662cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 663cc61e7e9SMilanka Ringwald if (connection->avdtp_version < 0x0103){ 664cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 665cc61e7e9SMilanka Ringwald } else { 666cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 667cc61e7e9SMilanka Ringwald } 668d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 669cc61e7e9SMilanka Ringwald break; 670cc61e7e9SMilanka Ringwald default: 671f0c39502SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 672cc61e7e9SMilanka Ringwald l2cap_create_channel(avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 673cc61e7e9SMilanka Ringwald break; 674cc61e7e9SMilanka Ringwald } 675f0c39502SMilanka Ringwald } 676f0c39502SMilanka Ringwald 6776ed344c3SMatthias Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 678149deddbSMilanka Ringwald UNUSED(packet_type); 679149deddbSMilanka Ringwald UNUSED(channel); 680149deddbSMilanka Ringwald UNUSED(size); 681149deddbSMilanka Ringwald 682137e2954SMatthias Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_sdp_query_context_avdtp_cid); 6836ed344c3SMatthias Ringwald if (!connection) { 684137e2954SMatthias Ringwald log_error("SDP query, connection with 0x%02x cid not found", avdtp_sdp_query_context_avdtp_cid); 6856ed344c3SMatthias Ringwald return; 6866ed344c3SMatthias Ringwald } 6876ed344c3SMatthias Ringwald 688722c03bdSMatthias Ringwald uint8_t status = ERROR_CODE_SUCCESS; 689149deddbSMilanka Ringwald switch (connection->state){ 690149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 6916ed344c3SMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 6926ed344c3SMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 693b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 694149deddbSMilanka Ringwald return; 695692c0605SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 6961e1ae2bcSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 697149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 698cc92f22bSMatthias Ringwald if (!connection->sink_supported || (connection->avdtp_l2cap_psm == 0)) { 699cc92f22bSMatthias Ringwald status = SDP_SERVICE_NOT_FOUND; 700722c03bdSMatthias Ringwald break; 701722c03bdSMatthias Ringwald } 702149deddbSMilanka Ringwald break; 703149deddbSMilanka Ringwald default: 704149deddbSMilanka Ringwald btstack_assert(false); 705722c03bdSMatthias Ringwald return; 7061e1ae2bcSMilanka Ringwald } 707149deddbSMilanka Ringwald break; 708149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 709149deddbSMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 710149deddbSMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 711b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 712149deddbSMilanka Ringwald return; 713149deddbSMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 714149deddbSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 715149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 716cc92f22bSMatthias Ringwald if (!connection->source_supported || (connection->avdtp_l2cap_psm == 0)) { 717cc92f22bSMatthias Ringwald status = SDP_SERVICE_NOT_FOUND; 718722c03bdSMatthias Ringwald break; 719722c03bdSMatthias Ringwald } 720149deddbSMilanka Ringwald break; 721149deddbSMilanka Ringwald default: 722149deddbSMilanka Ringwald btstack_assert(false); 723722c03bdSMatthias Ringwald return; 724974d4d6eSMilanka Ringwald } 7252f6083d0SMilanka Ringwald break; 726cc61e7e9SMilanka Ringwald 727cc61e7e9SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 728cc61e7e9SMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 729cc61e7e9SMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 730cc61e7e9SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 731cc61e7e9SMilanka Ringwald return; 732cc61e7e9SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 733cc92f22bSMatthias Ringwald // without suitable SDP Record, avdtp version v0.0 is assumed 734cc61e7e9SMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 735cc61e7e9SMilanka Ringwald break; 736cc61e7e9SMilanka Ringwald default: 737cc61e7e9SMilanka Ringwald btstack_assert(false); 738cc61e7e9SMilanka Ringwald return; 739cc61e7e9SMilanka Ringwald } 740cc61e7e9SMilanka Ringwald break; 741cc61e7e9SMilanka Ringwald 742149deddbSMilanka Ringwald default: 74308cb850dSMilanka Ringwald // bail out, we must have had an incoming connection in the meantime; just trigger next sdp query on complete 74408cb850dSMilanka Ringwald if (hci_event_packet_get_type(packet) == SDP_EVENT_QUERY_COMPLETE){ 74508cb850dSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 74608cb850dSMilanka Ringwald } 747149deddbSMilanka Ringwald return; 7482f6083d0SMilanka Ringwald } 749f0c39502SMilanka Ringwald 750722c03bdSMatthias Ringwald if (status == ERROR_CODE_SUCCESS){ 751149deddbSMilanka Ringwald avdtp_handle_sdp_query_succeeded(connection); 752149deddbSMilanka Ringwald } else { 753149deddbSMilanka Ringwald avdtp_handle_sdp_query_failed(connection, status); 754692c0605SMilanka Ringwald } 7555797104aSMilanka Ringwald 7565797104aSMilanka Ringwald // register the SDP Query request to check if there is another connection waiting for the query 7575797104aSMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 7585797104aSMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 759692c0605SMilanka Ringwald } 760692c0605SMilanka Ringwald 761146fc0fbSMilanka 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){ 76236da8747SMilanka Ringwald if (connection == NULL){ 76336da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 7645ace758fSMilanka Ringwald connection = avdtp_create_connection(event_addr, cid); 76536da8747SMilanka Ringwald } 766692c0605SMilanka Ringwald 76736da8747SMilanka Ringwald if (connection) { 76836da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 76936da8747SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 770146fc0fbSMilanka Ringwald connection->con_handle = con_handle; 771ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 77236da8747SMilanka Ringwald } 77336da8747SMilanka Ringwald return connection; 77436da8747SMilanka Ringwald } 775f0c39502SMilanka Ringwald 776ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 777326e3662SMilanka Ringwald uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 778326e3662SMilanka Ringwald 7795ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 780326e3662SMilanka Ringwald if (connection == NULL) return; 781326e3662SMilanka Ringwald 782ff53b162SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){ 783326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 784326e3662SMilanka Ringwald l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 785326e3662SMilanka Ringwald } 786326e3662SMilanka Ringwald } 787326e3662SMilanka Ringwald 788ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){ 789ff53b162SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler); 790ff53b162SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid); 791326e3662SMilanka Ringwald 792326e3662SMilanka Ringwald // add some jitter/randomness to reconnect delay 793326e3662SMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 794ff53b162SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 795ff53b162SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 796326e3662SMilanka Ringwald } 797326e3662SMilanka Ringwald 79839a45651SMatthias Ringwald static void avdtp_handle_close_media_channel(avdtp_stream_endpoint_t * stream_endpoint){ 79939a45651SMatthias Ringwald avdtp_connection_t * connection = stream_endpoint->connection; 80039a45651SMatthias Ringwald btstack_assert(connection != NULL); 80139a45651SMatthias Ringwald avdtp_streaming_emit_connection_released(stream_endpoint, connection->avdtp_cid, avdtp_local_seid(stream_endpoint)); 80239a45651SMatthias Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 80339a45651SMatthias Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE; 80439a45651SMatthias Ringwald } 80539a45651SMatthias Ringwald 80639a45651SMatthias Ringwald static void avdtp_handle_close_recovery_channel(avdtp_stream_endpoint_t * stream_endpoint){ 80739a45651SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", stream_endpoint->l2cap_recovery_cid); 80839a45651SMatthias Ringwald stream_endpoint->l2cap_recovery_cid = 0; 80939a45651SMatthias Ringwald } 81039a45651SMatthias Ringwald 81139a45651SMatthias Ringwald static void avdtp_handle_close_reporting_channel(avdtp_stream_endpoint_t * stream_endpoint){ 81239a45651SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", stream_endpoint->l2cap_reporting_cid); 81339a45651SMatthias Ringwald stream_endpoint->l2cap_reporting_cid = 0; 81439a45651SMatthias Ringwald } 81539a45651SMatthias Ringwald 816326e3662SMilanka Ringwald 817326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 818747ec646SMilanka Ringwald bd_addr_t event_addr; 819747ec646SMilanka Ringwald uint16_t psm; 820747ec646SMilanka Ringwald uint16_t local_cid; 8211e1ae2bcSMilanka Ringwald uint8_t status; 822326e3662SMilanka Ringwald uint16_t l2cap_mtu; 823146fc0fbSMilanka Ringwald hci_con_handle_t con_handle; 82436da8747SMilanka Ringwald 82536da8747SMilanka Ringwald bool accept_streaming_connection; 82636da8747SMilanka Ringwald bool outoing_signaling_active; 82736da8747SMilanka Ringwald bool decline_connection; 82884521ac1SMilanka Ringwald 829747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = NULL; 830747ec646SMilanka Ringwald avdtp_connection_t * connection = NULL; 83136da8747SMilanka Ringwald 832747ec646SMilanka Ringwald switch (packet_type) { 833747ec646SMilanka Ringwald case L2CAP_DATA_PACKET: 8345ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 835747ec646SMilanka Ringwald if (connection){ 83677092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 837747ec646SMilanka Ringwald break; 838747ec646SMilanka Ringwald } 839747ec646SMilanka Ringwald 8406f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 841747ec646SMilanka Ringwald if (!stream_endpoint){ 842747ec646SMilanka Ringwald if (!connection) break; 84377092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); 844747ec646SMilanka Ringwald break; 845747ec646SMilanka Ringwald } 846747ec646SMilanka Ringwald 8478c0f3635SMilanka Ringwald if (stream_endpoint->connection){ 8489413b167SMilanka Ringwald if (channel == stream_endpoint->connection->l2cap_signaling_cid){ 84977092f3eSMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size); 850747ec646SMilanka Ringwald break; 851747ec646SMilanka Ringwald } 8528c0f3635SMilanka Ringwald } 853747ec646SMilanka Ringwald 854747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_media_cid){ 855951d2774SMatthias Ringwald btstack_assert(avdtp_sink_handle_media_data); 856951d2774SMatthias Ringwald (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size); 857747ec646SMilanka Ringwald break; 858747ec646SMilanka Ringwald } 859747ec646SMilanka Ringwald 860747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_reporting_cid){ 8618587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED"); 862747ec646SMilanka Ringwald } else if (channel == stream_endpoint->l2cap_recovery_cid){ 8638587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED"); 864747ec646SMilanka Ringwald } else { 865747ec646SMilanka Ringwald log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel); 866747ec646SMilanka Ringwald } 867747ec646SMilanka Ringwald break; 868747ec646SMilanka Ringwald 869747ec646SMilanka Ringwald case HCI_EVENT_PACKET: 870747ec646SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 87136da8747SMilanka Ringwald 872747ec646SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 873747ec646SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 874747ec646SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 875146fc0fbSMilanka Ringwald con_handle = l2cap_event_incoming_connection_get_handle(packet); 87636da8747SMilanka Ringwald outoing_signaling_active = false; 87736da8747SMilanka Ringwald accept_streaming_connection = false; 87836da8747SMilanka Ringwald 8795ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 88036da8747SMilanka Ringwald if (connection != NULL){ 8810d4a198eSMatthias Ringwald switch (connection->state){ 8820d4a198eSMatthias Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED: 88336da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 88436da8747SMilanka Ringwald outoing_signaling_active = true; 88536da8747SMilanka Ringwald connection->incoming_declined = true; 88636da8747SMilanka Ringwald break; 88736da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 88836da8747SMilanka Ringwald outoing_signaling_active = true; 88936da8747SMilanka Ringwald accept_streaming_connection = true; 89036da8747SMilanka Ringwald break; 891f0c39502SMilanka Ringwald default: 892f0c39502SMilanka Ringwald break; 8930d4a198eSMatthias Ringwald } 894747ec646SMilanka Ringwald } 89536da8747SMilanka Ringwald log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d", 89636da8747SMilanka Ringwald bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection); 897747ec646SMilanka Ringwald 89836da8747SMilanka Ringwald decline_connection = outoing_signaling_active && !accept_streaming_connection; 89936da8747SMilanka Ringwald if (outoing_signaling_active == false){ 900146fc0fbSMilanka Ringwald connection = avdtp_handle_incoming_connection(connection, event_addr, con_handle, local_cid); 90136da8747SMilanka Ringwald if (connection == NULL){ 90236da8747SMilanka Ringwald decline_connection = true; 90336da8747SMilanka Ringwald } 90436da8747SMilanka Ringwald } else if (accept_streaming_connection){ 90536da8747SMilanka Ringwald if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) { 90636da8747SMilanka Ringwald decline_connection = true; 90736da8747SMilanka Ringwald } else { 908939e12adSMatthias Ringwald // now, we're only dealing with media connections that are created by remote side - we're acceptor here 9093338afc0SMatthias Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_seid(connection->acceptor_local_seid); 91036da8747SMilanka Ringwald if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) { 91136da8747SMilanka Ringwald decline_connection = true; 91236da8747SMilanka Ringwald } 91336da8747SMilanka Ringwald } 914747ec646SMilanka Ringwald } 915747ec646SMilanka Ringwald 91636da8747SMilanka Ringwald if (decline_connection){ 917a3ce0109SMatthias Ringwald l2cap_decline_connection(local_cid); 91836da8747SMilanka Ringwald } else { 919747ec646SMilanka Ringwald l2cap_accept_connection(local_cid); 92036da8747SMilanka Ringwald } 921747ec646SMilanka Ringwald break; 922747ec646SMilanka Ringwald 923747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 924a5114819SMilanka Ringwald 925a0b8a58cSMilanka Ringwald psm = l2cap_event_channel_opened_get_psm(packet); 92684e3541eSMilanka Ringwald if (psm != BLUETOOTH_PSM_AVDTP){ 927355ac553SMilanka Ringwald log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED "); 928a0b8a58cSMilanka Ringwald return; 929a0b8a58cSMilanka Ringwald } 930a0b8a58cSMilanka Ringwald 9311e1ae2bcSMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 932747ec646SMilanka Ringwald // inform about new l2cap connection 933747ec646SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 9347050d2caSMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 935326e3662SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 9365ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 93736da8747SMilanka Ringwald if (connection == NULL){ 93836da8747SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr)); 939a0b8a58cSMilanka Ringwald break; 940a0b8a58cSMilanka Ringwald } 941a0b8a58cSMilanka Ringwald 942146fc0fbSMilanka Ringwald con_handle = l2cap_event_channel_opened_get_handle(packet); 943146fc0fbSMilanka Ringwald 944a5114819SMilanka Ringwald switch (connection->state){ 945a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 946326e3662SMilanka Ringwald switch (status){ 947326e3662SMilanka Ringwald case ERROR_CODE_SUCCESS: 948326e3662SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 949326e3662SMilanka Ringwald connection->incoming_declined = false; 950326e3662SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 951146fc0fbSMilanka Ringwald connection->con_handle = con_handle; 952326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_OPENED; 953146fc0fbSMilanka 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); 954146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status); 955326e3662SMilanka Ringwald return; 956326e3662SMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 957326e3662SMilanka Ringwald if (connection->incoming_declined == true) { 958326e3662SMilanka Ringwald log_info("Connection was declined, and the outgoing failed"); 959ff53b162SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY; 960326e3662SMilanka Ringwald connection->incoming_declined = false; 961ff53b162SMilanka Ringwald avdtp_retry_timer_start(connection); 962326e3662SMilanka Ringwald return; 963326e3662SMilanka Ringwald } 964326e3662SMilanka Ringwald break; 965326e3662SMilanka Ringwald default: 966326e3662SMilanka Ringwald log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 967326e3662SMilanka Ringwald break; 968326e3662SMilanka Ringwald } 969146fc0fbSMilanka Ringwald avdtp_signaling_emit_connection_established(connection->avdtp_cid, event_addr, con_handle, status); 970f82b60efSMilanka Ringwald avdtp_finalize_connection(connection); 971a0b8a58cSMilanka Ringwald break; 972747ec646SMilanka Ringwald 973a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 97419a000d1SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid); 975747ec646SMilanka Ringwald if (!stream_endpoint){ 9765bd73fa2SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid); 977747ec646SMilanka Ringwald return; 978747ec646SMilanka Ringwald } 979326e3662SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 980355ac553SMilanka 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)); 981a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 982f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, status); 983a466d508SMilanka Ringwald break; 984a466d508SMilanka Ringwald } 985a5114819SMilanka Ringwald switch (stream_endpoint->state){ 986a5114819SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED: 987a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED; 988a466d508SMilanka Ringwald stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet); 989a466d508SMilanka Ringwald stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet); 990d1207cd8SMilanka Ringwald 991355ac553SMilanka 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)); 992f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS); 993a5114819SMilanka Ringwald break; 994a5114819SMilanka Ringwald default: 995a5114819SMilanka 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)); 99623edb87eSMilanka Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_COMMAND_DISALLOWED); 997a5114819SMilanka Ringwald break; 998a5114819SMilanka Ringwald } 999a5114819SMilanka Ringwald break; 1000a5114819SMilanka Ringwald 1001a5114819SMilanka Ringwald default: 1002326e3662SMilanka Ringwald log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state); 1003a5114819SMilanka Ringwald break; 1004a5114819SMilanka Ringwald } 1005747ec646SMilanka Ringwald break; 1006747ec646SMilanka Ringwald 1007747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 1008747ec646SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 10096f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid); 10105ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid); 101136da8747SMilanka Ringwald 1012f01aeca4SMilanka Ringwald log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint); 1013f01aeca4SMilanka Ringwald 1014a466d508SMilanka Ringwald if (stream_endpoint){ 1015a466d508SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == local_cid){ 101639a45651SMatthias Ringwald avdtp_handle_close_media_channel(stream_endpoint); 1017a466d508SMilanka Ringwald break; 1018a466d508SMilanka Ringwald } 1019a466d508SMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == local_cid){ 102039a45651SMatthias Ringwald avdtp_handle_close_recovery_channel(stream_endpoint); 1021a466d508SMilanka Ringwald break; 1022a466d508SMilanka Ringwald } 1023a466d508SMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == local_cid){ 102439a45651SMatthias Ringwald avdtp_handle_close_reporting_channel(stream_endpoint); 1025a466d508SMilanka Ringwald break; 1026a466d508SMilanka Ringwald } 1027a466d508SMilanka Ringwald } 1028596b7fdcSMilanka Ringwald 1029596b7fdcSMilanka Ringwald if (connection){ 1030535ff088SMatthias Ringwald // closing signaling channel invalidates all other channels as well 1031596b7fdcSMilanka Ringwald btstack_linked_list_iterator_t it; 1032d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1033596b7fdcSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1034f01aeca4SMilanka Ringwald stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1035f01aeca4SMilanka Ringwald if (stream_endpoint->connection == connection){ 1036535ff088SMatthias Ringwald avdtp_handle_close_recovery_channel(stream_endpoint); 1037535ff088SMatthias Ringwald avdtp_handle_close_reporting_channel(stream_endpoint); 1038535ff088SMatthias Ringwald avdtp_handle_close_media_channel(stream_endpoint); 1039f01aeca4SMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 1040596b7fdcSMilanka Ringwald } 1041596b7fdcSMilanka Ringwald } 1042c69f4ba5SMatthias Ringwald avdtp_signaling_emit_connection_released(connection->avdtp_cid); 10435ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 1044596b7fdcSMilanka Ringwald break; 1045596b7fdcSMilanka Ringwald } 1046747ec646SMilanka Ringwald break; 1047747ec646SMilanka Ringwald 1048747ec646SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 1049c6bc5965SMilanka Ringwald log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel); 1050d80ccd43SMatthias Ringwald avdtp_handle_can_send_now(channel); 1051747ec646SMilanka Ringwald break; 1052747ec646SMilanka Ringwald default: 1053355ac553SMilanka Ringwald log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet)); 1054747ec646SMilanka Ringwald break; 1055747ec646SMilanka Ringwald } 1056747ec646SMilanka Ringwald break; 1057747ec646SMilanka Ringwald 1058747ec646SMilanka Ringwald default: 1059747ec646SMilanka Ringwald // other packet type 1060747ec646SMilanka Ringwald break; 1061747ec646SMilanka Ringwald } 1062747ec646SMilanka Ringwald } 1063747ec646SMilanka Ringwald 1064b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){ 10655ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 106623edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1067b401ff59SMilanka Ringwald 1068a466d508SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS; 1069747ec646SMilanka Ringwald 1070f01aeca4SMilanka Ringwald btstack_linked_list_iterator_t it; 1071f01aeca4SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1072f01aeca4SMilanka Ringwald 1073f01aeca4SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1074f01aeca4SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1075f01aeca4SMilanka Ringwald if (stream_endpoint->connection != connection) continue; 1076f01aeca4SMilanka Ringwald 1077f01aeca4SMilanka Ringwald switch (stream_endpoint->state){ 1078f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_OPENED: 1079f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_STREAMING: 1080f01aeca4SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED; 1081b93f8966SMatthias Ringwald l2cap_disconnect(stream_endpoint->l2cap_media_cid); 1082f01aeca4SMilanka Ringwald break; 1083f01aeca4SMilanka Ringwald default: 1084f01aeca4SMilanka Ringwald break; 1085f01aeca4SMilanka Ringwald } 1086f01aeca4SMilanka Ringwald } 1087f01aeca4SMilanka Ringwald 1088f01aeca4SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED; 1089b93f8966SMatthias Ringwald l2cap_disconnect(connection->l2cap_signaling_cid); 10904ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1091747ec646SMilanka Ringwald } 1092747ec646SMilanka Ringwald 109348ce193cSMilanka Ringwald 109448ce193cSMilanka Ringwald #ifdef ENABLE_AVDTP_ACCEPTOR_EXPLICIT_START_STREAM_CONFIRMATION 109548ce193cSMilanka Ringwald static uint8_t avdtp_handle_explicit_start_stream_confirmation(uint16_t avdtp_cid, uint8_t local_seid, bool accept_stream_requested){ 109648ce193cSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 109748ce193cSMilanka Ringwald if (!connection){ 109848ce193cSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 109948ce193cSMilanka Ringwald } 110048ce193cSMilanka Ringwald 110148ce193cSMilanka Ringwald if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) { 110248ce193cSMilanka Ringwald log_error("avdtp_media_connect: wrong connection state %d", connection->state); 110348ce193cSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 110448ce193cSMilanka Ringwald } 110548ce193cSMilanka Ringwald 110648ce193cSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 110748ce193cSMilanka Ringwald if (!stream_endpoint) { 110848ce193cSMilanka Ringwald log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid); 110948ce193cSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 111048ce193cSMilanka Ringwald } 111148ce193cSMilanka Ringwald 111248ce193cSMilanka Ringwald if (stream_endpoint->acceptor_config_state != AVDTP_ACCEPTOR_W4_USER_CONFIRM_START_STREAM){ 111348ce193cSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 111448ce193cSMilanka Ringwald } 111548ce193cSMilanka Ringwald 111648ce193cSMilanka Ringwald if (accept_stream_requested){ 111748ce193cSMilanka Ringwald stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_ACCEPT_START_STREAM; 111848ce193cSMilanka Ringwald } else { 111948ce193cSMilanka Ringwald stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_W2_REJECT_START_STREAM; 112048ce193cSMilanka Ringwald } 112148ce193cSMilanka Ringwald avdtp_request_can_send_now_acceptor(connection); 112248ce193cSMilanka Ringwald return ERROR_CODE_SUCCESS; 112348ce193cSMilanka Ringwald } 112448ce193cSMilanka Ringwald 112548ce193cSMilanka Ringwald uint8_t avdtp_start_stream_accept(uint16_t avdtp_cid, uint8_t local_seid){ 112648ce193cSMilanka Ringwald return avdtp_handle_explicit_start_stream_confirmation(avdtp_cid, local_seid, true); 112748ce193cSMilanka Ringwald } 112848ce193cSMilanka Ringwald 112948ce193cSMilanka Ringwald uint8_t avdtp_start_stream_reject(uint16_t avdtp_cid, uint8_t local_seid){ 113048ce193cSMilanka Ringwald return avdtp_handle_explicit_start_stream_confirmation(avdtp_cid, local_seid, false); 113148ce193cSMilanka Ringwald } 113248ce193cSMilanka Ringwald #endif 113348ce193cSMilanka Ringwald 1134297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){ 11355ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1136747ec646SMilanka Ringwald if (!connection){ 113723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1138747ec646SMilanka Ringwald } 1139747ec646SMilanka Ringwald 1140747ec646SMilanka Ringwald if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) { 11418587e32cSMilanka Ringwald log_error("avdtp_media_connect: wrong connection state %d", connection->state); 114223edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1143747ec646SMilanka Ringwald } 1144747ec646SMilanka Ringwald 11453338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1146747ec646SMilanka Ringwald if (!stream_endpoint) { 11476b0ee1d0SMilanka Ringwald log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid); 114823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1149747ec646SMilanka Ringwald } 1150747ec646SMilanka Ringwald 1151485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid != remote_seid){ 1152485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid); 115323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1154485c0a4cSMilanka Ringwald } 1155485c0a4cSMilanka Ringwald 115623edb87eSMilanka Ringwald if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return ERROR_CODE_COMMAND_DISALLOWED; 1157747ec646SMilanka Ringwald 1158b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 115996dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 11605bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1161747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM; 1162747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM; 1163d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 11644ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1165747ec646SMilanka Ringwald } 1166747ec646SMilanka Ringwald 1167297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11685ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 116946e6b063SMilanka Ringwald if (!connection){ 117023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 117146e6b063SMilanka Ringwald } 11725cfe7f4cSMilanka Ringwald 11733338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 11744ccacc40SMilanka Ringwald if (!stream_endpoint) { 11754ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid); 117623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11774ccacc40SMilanka Ringwald } 11784ccacc40SMilanka Ringwald 11794ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11804ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid); 118123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11824ccacc40SMilanka Ringwald } 11834ccacc40SMilanka Ringwald 1184485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 1185485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep registered with the stream endpoint"); 118623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 11874ccacc40SMilanka Ringwald } 11884ccacc40SMilanka Ringwald 1189440d8d82SMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){ 1190440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1191440d8d82SMilanka Ringwald } 1192440d8d82SMilanka Ringwald 11934e7bc04fSMilanka Ringwald if (stream_endpoint->start_stream == 1) { 11944e7bc04fSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 11954e7bc04fSMilanka Ringwald } 11964e7bc04fSMilanka Ringwald 119760ec20d0SMilanka Ringwald stream_endpoint->start_stream = 1; 11985bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 119996dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1200d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 12014ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1202747ec646SMilanka Ringwald } 1203747ec646SMilanka Ringwald 1204297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){ 12055ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1206747ec646SMilanka Ringwald if (!connection){ 120723edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1208747ec646SMilanka Ringwald } 12094ccacc40SMilanka Ringwald 12103338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 12114ccacc40SMilanka Ringwald if (!stream_endpoint) { 12124ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid); 121323edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 12144ccacc40SMilanka Ringwald } 12154ccacc40SMilanka Ringwald 12164ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 12174ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid); 121823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 12194ccacc40SMilanka Ringwald } 1220485c0a4cSMilanka Ringwald 1221fa4419dbSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->close_stream){ 1222440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1223485c0a4cSMilanka Ringwald } 12244ccacc40SMilanka Ringwald 12254e7bc04fSMilanka Ringwald if (stream_endpoint->close_stream == 1) { 12264e7bc04fSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12274e7bc04fSMilanka Ringwald } 12284e7bc04fSMilanka Ringwald 1229fa4419dbSMilanka Ringwald stream_endpoint->close_stream = 1; 12305bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 123196dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1232d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 12334ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1234747ec646SMilanka Ringwald } 1235747ec646SMilanka Ringwald 1236297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){ 12375ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 123860ec20d0SMilanka Ringwald if (!connection){ 123923edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1240747ec646SMilanka Ringwald } 12414ccacc40SMilanka Ringwald 12423338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 12434ccacc40SMilanka Ringwald if (!stream_endpoint) { 12444ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid); 124523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 12464ccacc40SMilanka Ringwald } 12474ccacc40SMilanka Ringwald 12484ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 12494ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid); 125023edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 12514ccacc40SMilanka Ringwald } 1252485c0a4cSMilanka Ringwald 1253485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){ 1254440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1255485c0a4cSMilanka Ringwald } 12564ccacc40SMilanka Ringwald 12574e7bc04fSMilanka Ringwald if (stream_endpoint->abort_stream == 1) { 12584e7bc04fSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12594e7bc04fSMilanka Ringwald } 12604e7bc04fSMilanka Ringwald 126160ec20d0SMilanka Ringwald stream_endpoint->abort_stream = 1; 12625bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 126396dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1264d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 12654ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1266747ec646SMilanka Ringwald } 1267747ec646SMilanka Ringwald 1268297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){ 12695ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1270747ec646SMilanka Ringwald if (!connection){ 127123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 127260ec20d0SMilanka Ringwald } 12733338afc0SMatthias Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 12744ccacc40SMilanka Ringwald if (!stream_endpoint) { 12754ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid); 127623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 12774ccacc40SMilanka Ringwald } 12784ccacc40SMilanka Ringwald 12794ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 12804ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid); 128123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 12824ccacc40SMilanka Ringwald } 1283485c0a4cSMilanka Ringwald 1284485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){ 1285440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1286485c0a4cSMilanka Ringwald } 12874ccacc40SMilanka Ringwald 12884e7bc04fSMilanka Ringwald if (stream_endpoint->suspend_stream == 1) { 12894e7bc04fSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 12904e7bc04fSMilanka Ringwald } 12914e7bc04fSMilanka Ringwald 129260ec20d0SMilanka Ringwald stream_endpoint->suspend_stream = 1; 12935bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 129496dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 1295d80ccd43SMatthias Ringwald avdtp_request_can_send_now_initiator(connection); 12964ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1297747ec646SMilanka Ringwald } 1298747ec646SMilanka Ringwald 12995ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){ 13005ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1301747ec646SMilanka Ringwald if (!connection){ 130223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 13039974aee0SMilanka Ringwald } 13040e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1305c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 130623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1307747ec646SMilanka Ringwald } 1308ec3d71e3SMilanka Ringwald 1309b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1310747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS; 1311d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1312747ec646SMilanka Ringwald } 1313747ec646SMilanka Ringwald 1314747ec646SMilanka Ringwald 13155ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 13165ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1317747ec646SMilanka Ringwald if (!connection){ 131823edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1319747ec646SMilanka Ringwald } 13200e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1321c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 132223edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 13239974aee0SMilanka Ringwald } 13249974aee0SMilanka Ringwald 1325b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1326747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 132796dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1328d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1329747ec646SMilanka Ringwald } 1330747ec646SMilanka Ringwald 1331747ec646SMilanka Ringwald 1332a145558fSMatthias Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_role_t role) { 13335ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1334747ec646SMilanka Ringwald if (!connection){ 133523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1336747ec646SMilanka Ringwald } 13370e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1338c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 133923edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 13409974aee0SMilanka Ringwald } 13419974aee0SMilanka Ringwald 1342b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 134396dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1344cc61e7e9SMilanka Ringwald 1345cc61e7e9SMilanka Ringwald if (connection->avdtp_version == 0){ 1346*e71e31feSMatthias Ringwald switch(role){ 1347*e71e31feSMatthias Ringwald case AVDTP_ROLE_SINK: 1348*e71e31feSMatthias Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES_FROM_REMOTE_SOURCE; 1349*e71e31feSMatthias Ringwald break; 1350*e71e31feSMatthias Ringwald case AVDTP_ROLE_SOURCE: 1351*e71e31feSMatthias Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_SEND_SDP_QUERY_THEN_GET_ALL_CAPABILITIES_FROM_REMOTE_SINK; 1352*e71e31feSMatthias Ringwald break; 1353*e71e31feSMatthias Ringwald default: 1354*e71e31feSMatthias Ringwald btstack_unreachable(); 1355*e71e31feSMatthias Ringwald break; 1356*e71e31feSMatthias Ringwald } 1357cc61e7e9SMilanka Ringwald avdtp_handle_sdp_client_query_request.callback = &avdtp_handle_start_sdp_client_query; 1358cc61e7e9SMilanka Ringwald // ignore ERROR_CODE_COMMAND_DISALLOWED because in that case, we already have requested an SDP callback 1359cc61e7e9SMilanka Ringwald (void) sdp_client_register_query_callback(&avdtp_handle_sdp_client_query_request); 1360cc61e7e9SMilanka Ringwald return ERROR_CODE_SUCCESS; 1361cc61e7e9SMilanka Ringwald } else { 1362cc61e7e9SMilanka Ringwald // AVDTP version lower then 1.3 supports only get capabilities command 1363cc61e7e9SMilanka Ringwald if (connection->avdtp_version < 0x103){ 1364cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 1365cc61e7e9SMilanka Ringwald } else { 1366cc61e7e9SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 1367cc61e7e9SMilanka Ringwald } 1368d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1369747ec646SMilanka Ringwald } 1370cc61e7e9SMilanka Ringwald } 1371747ec646SMilanka Ringwald 13725ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){ 13735ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1374747ec646SMilanka Ringwald if (!connection){ 137523edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1376747ec646SMilanka Ringwald } 13770e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1378c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 137923edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 13809974aee0SMilanka Ringwald } 13819974aee0SMilanka Ringwald 1382b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 1383747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION; 138496dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 1385d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1386747ec646SMilanka Ringwald } 1387747ec646SMilanka Ringwald 1388cec76c5bSMilanka 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){ 13895ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1390747ec646SMilanka Ringwald if (!connection){ 139123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1392747ec646SMilanka Ringwald } 13930e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1394c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 1395485c0a4cSMilanka Ringwald log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state); 139623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 13979974aee0SMilanka Ringwald } 1398a3ce0109SMatthias Ringwald if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){ 1399a3ce0109SMatthias Ringwald log_info("configuration already started, config state %u", connection->configuration_state); 140023edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1401a3ce0109SMatthias Ringwald } 1402747ec646SMilanka Ringwald 1403d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1404747ec646SMilanka Ringwald if (!stream_endpoint) { 14059900b7faSMilanka Ringwald log_error("No initiator stream endpoint for seid %d", local_seid); 140623edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1407747ec646SMilanka Ringwald } 1408417b4996SMilanka Ringwald if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){ 1409485c0a4cSMilanka Ringwald log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state); 141023edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1411417b4996SMilanka Ringwald } 1412a3ce0109SMatthias Ringwald 1413bdbc3ef6SMilanka Ringwald connection->active_stream_endpoint = (void*) stream_endpoint; 1414a3ce0109SMatthias Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED; 1415747ec646SMilanka Ringwald 1416b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 141796dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 14185bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1419f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1420f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1421747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION; 1422ffa6c160SMilanka Ringwald 142344e638f3SMatthias Ringwald log_debug("SE %p, initiator_config_state: 0x%02x", stream_endpoint, stream_endpoint->initiator_config_state); 14243a69f723SMatthias Ringwald 1425d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1426747ec646SMilanka Ringwald } 1427747ec646SMilanka Ringwald 1428cec76c5bSMilanka 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){ 14295ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1430747ec646SMilanka Ringwald if (!connection){ 143123edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1432747ec646SMilanka Ringwald } 1433747ec646SMilanka Ringwald //TODO: if opened only app capabilities, enable reconfigure for not opened 14340e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1435c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 143623edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 14379974aee0SMilanka Ringwald } 14389e42cfccSMilanka Ringwald 1439d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 144078d08d09SMilanka Ringwald if (!stream_endpoint) { 14414ccacc40SMilanka Ringwald log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid); 144223edb87eSMilanka Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 144378d08d09SMilanka Ringwald } 144478d08d09SMilanka Ringwald 1445485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 14468587e32cSMilanka Ringwald log_error("avdtp_reconfigure: no associated remote sep"); 144723edb87eSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 144878d08d09SMilanka Ringwald } 1449485c0a4cSMilanka Ringwald 1450b1935866SMilanka Ringwald connection->initiator_transaction_label= avdtp_get_next_transaction_label(); 145196dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 14525bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1453f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1454f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1455747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID; 1456d80ccd43SMatthias Ringwald return avdtp_request_can_send_now_initiator(connection); 1457747ec646SMilanka Ringwald } 1458747ec646SMilanka Ringwald 1459093c3dfdSMatthias Ringwald void avdtp_set_preferred_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){ 14608e7044f9SMatthias Ringwald stream_endpoint->preferred_sampling_frequency = sampling_frequency; 14618e7044f9SMatthias Ringwald } 14628e7044f9SMatthias Ringwald 146379654d96SMilanka Ringwald void avdtp_set_preferred_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t channel_mode){ 146479654d96SMilanka Ringwald stream_endpoint->preferred_channel_mode = channel_mode; 146579654d96SMilanka Ringwald } 146679654d96SMilanka Ringwald 146779654d96SMilanka Ringwald 146880dc0088SMatthias Ringwald avdtp_channel_mode_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){ 146978d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 147078d08d09SMilanka Ringwald uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap; 147178d08d09SMilanka Ringwald 147279654d96SMilanka Ringwald // use preferred channel mode if possible 147379654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_JOINT_STEREO){ 147480dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_JOINT_STEREO; 147579654d96SMilanka Ringwald } 147679654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_STEREO){ 147780dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_STEREO; 147879654d96SMilanka Ringwald } 147979654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_DUAL_CHANNEL){ 148080dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 148179654d96SMilanka Ringwald } 148279654d96SMilanka Ringwald if (stream_endpoint->preferred_channel_mode == AVDTP_SBC_MONO){ 148380dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_MONO; 148479654d96SMilanka Ringwald } 148579654d96SMilanka Ringwald 148679654d96SMilanka Ringwald 148778d08d09SMilanka Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 148880dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_JOINT_STEREO; 148978d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 149080dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_STEREO; 149178d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 149280dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 149378d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_MONO){ 149480dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_MONO; 149578d08d09SMilanka Ringwald } 149680dc0088SMatthias Ringwald return AVDTP_CHANNEL_MODE_JOINT_STEREO; 149778d08d09SMilanka Ringwald } 149878d08d09SMilanka Ringwald 149980dc0088SMatthias Ringwald avdtp_sbc_allocation_method_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){ 150078d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 1501b5bbcbf4SMatthias Ringwald uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap; 150278d08d09SMilanka Ringwald 1503b5bbcbf4SMatthias Ringwald avdtp_sbc_allocation_method_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 150478d08d09SMilanka Ringwald if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){ 150578d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 150678d08d09SMilanka Ringwald } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){ 150778d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR; 150878d08d09SMilanka Ringwald } 150978d08d09SMilanka Ringwald return allocation_method; 151078d08d09SMilanka Ringwald } 151178d08d09SMilanka Ringwald 1512bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){ 1513bd1ecb8aSMilanka Ringwald if (!stream_endpoint) return 0; 1514bd1ecb8aSMilanka Ringwald return stream_endpoint->sep.seid; 1515bd1ecb8aSMilanka Ringwald } 151678d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){ 151767ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 151878d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 151978d08d09SMilanka Ringwald uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap; 152078d08d09SMilanka Ringwald 152178d08d09SMilanka Ringwald uint8_t subbands = AVDTP_SBC_SUBBANDS_8; 152278d08d09SMilanka Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 152378d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_8; 152478d08d09SMilanka Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 152578d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_4; 152678d08d09SMilanka Ringwald } 152778d08d09SMilanka Ringwald return subbands; 152878d08d09SMilanka Ringwald } 152978d08d09SMilanka Ringwald 153078d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){ 153167ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 153278d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 153378d08d09SMilanka Ringwald uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap; 153478d08d09SMilanka Ringwald 153578d08d09SMilanka Ringwald uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16; 153678d08d09SMilanka Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 153778d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_16; 153878d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 153978d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_12; 154078d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 154178d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_8; 154278d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 154378d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_4; 154478d08d09SMilanka Ringwald } 154578d08d09SMilanka Ringwald return block_length; 154678d08d09SMilanka Ringwald } 154778d08d09SMilanka Ringwald 154880dc0088SMatthias Ringwald uint16_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){ 154967ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 155078d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 15518e7044f9SMatthias Ringwald uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap; 155278d08d09SMilanka Ringwald 15538e7044f9SMatthias Ringwald // use preferred sampling frequency if possible 15548e7044f9SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){ 155580dc0088SMatthias Ringwald return stream_endpoint->preferred_sampling_frequency; 15568e7044f9SMatthias Ringwald } 15576ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){ 155880dc0088SMatthias Ringwald return stream_endpoint->preferred_sampling_frequency; 15596ed344c3SMatthias Ringwald } 15606ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){ 156180dc0088SMatthias Ringwald return stream_endpoint->preferred_sampling_frequency; 15626ed344c3SMatthias Ringwald } 15636ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){ 156480dc0088SMatthias Ringwald return stream_endpoint->preferred_sampling_frequency; 15656ed344c3SMatthias Ringwald } 15666ed344c3SMatthias Ringwald 15678e7044f9SMatthias Ringwald // otherwise, use highest available 15686ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_48000){ 156980dc0088SMatthias Ringwald return 48000; 157078d08d09SMilanka Ringwald } 15716ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_44100){ 157280dc0088SMatthias Ringwald return 44100; 15736ed344c3SMatthias Ringwald } 15746ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_32000){ 157580dc0088SMatthias Ringwald return 32000; 15766ed344c3SMatthias Ringwald } 15776ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_16000){ 157880dc0088SMatthias Ringwald return 16000; 15796ed344c3SMatthias Ringwald } 158080dc0088SMatthias Ringwald return 44100; // some default 158178d08d09SMilanka Ringwald } 158278d08d09SMilanka Ringwald 158378d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){ 158467ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 158578d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 158678d08d09SMilanka Ringwald return btstack_min(media_codec[3], remote_max_bitpool_value); 158778d08d09SMilanka Ringwald } 158878d08d09SMilanka Ringwald 158978d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){ 159067ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 159178d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 159278d08d09SMilanka Ringwald return btstack_max(media_codec[2], remote_min_bitpool_value); 1593747ec646SMilanka Ringwald } 1594485c0a4cSMilanka Ringwald 1595485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){ 1596485c0a4cSMilanka Ringwald if (!stream_endpoint) return 0; 1597485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid == 0) return 0; 1598485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid > 0x3E) return 0; 1599485c0a4cSMilanka Ringwald return 1; 1600485c0a4cSMilanka Ringwald } 16018322fb3aSMatthias Ringwald 16028322fb3aSMatthias Ringwald void avdtp_init(void){ 1603137e2954SMatthias Ringwald if (!avdtp_l2cap_registered){ 1604137e2954SMatthias Ringwald avdtp_l2cap_registered = true; 16058322fb3aSMatthias Ringwald l2cap_register_service(&avdtp_packet_handler, BLUETOOTH_PSM_AVDTP, 0xffff, gap_get_security_level()); 16068322fb3aSMatthias Ringwald } 16078322fb3aSMatthias Ringwald } 160857fb24ffSMatthias Ringwald 160957fb24ffSMatthias Ringwald void avdtp_deinit(void){ 161057fb24ffSMatthias Ringwald avdtp_sink_handle_media_data = NULL; 16116a737fb6SMatthias Ringwald avdtp_sink_media_config_validator = NULL; 16126a737fb6SMatthias Ringwald avdtp_source_media_config_validator = NULL; 1613137e2954SMatthias Ringwald avdtp_source_callback = NULL; 1614137e2954SMatthias Ringwald avdtp_sink_callback = NULL; 161557fb24ffSMatthias Ringwald 1616137e2954SMatthias Ringwald avdtp_sdp_query_context_avdtp_cid = 0; 1617137e2954SMatthias Ringwald 1618137e2954SMatthias Ringwald avdtp_stream_endpoints = NULL; 1619137e2954SMatthias Ringwald avdtp_stream_endpoints_id_counter = 0; 1620137e2954SMatthias Ringwald 1621137e2954SMatthias Ringwald avdtp_l2cap_registered = false; 1622137e2954SMatthias Ringwald 1623137e2954SMatthias Ringwald avdtp_connections = NULL; 1624137e2954SMatthias Ringwald avdtp_transaction_id_counter = 0; 1625137e2954SMatthias Ringwald 1626137e2954SMatthias Ringwald avdtp_record_id = 0; 162757fb24ffSMatthias Ringwald avdtp_cid_counter = 0; 162857fb24ffSMatthias Ringwald } 1629