1747ec646SMilanka Ringwald /* 2747ec646SMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 3747ec646SMilanka Ringwald * 4747ec646SMilanka Ringwald * Redistribution and use in source and binary forms, with or without 5747ec646SMilanka Ringwald * modification, are permitted provided that the following conditions 6747ec646SMilanka Ringwald * are met: 7747ec646SMilanka Ringwald * 8747ec646SMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 9747ec646SMilanka Ringwald * notice, this list of conditions and the following disclaimer. 10747ec646SMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11747ec646SMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 12747ec646SMilanka Ringwald * documentation and/or other materials provided with the distribution. 13747ec646SMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 14747ec646SMilanka Ringwald * contributors may be used to endorse or promote products derived 15747ec646SMilanka Ringwald * from this software without specific prior written permission. 16747ec646SMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 17747ec646SMilanka Ringwald * personal benefit and not for any commercial purpose or for 18747ec646SMilanka Ringwald * monetary gain. 19747ec646SMilanka Ringwald * 20747ec646SMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21747ec646SMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22747ec646SMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23747ec646SMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24747ec646SMilanka Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25747ec646SMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26747ec646SMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27747ec646SMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28747ec646SMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29747ec646SMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30747ec646SMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31747ec646SMilanka Ringwald * SUCH DAMAGE. 32747ec646SMilanka Ringwald * 33747ec646SMilanka Ringwald * Please inquire about commercial licensing options at 34747ec646SMilanka Ringwald * [email protected] 35747ec646SMilanka Ringwald * 36747ec646SMilanka Ringwald */ 37747ec646SMilanka Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avdtp.c" 39ab2c6ae4SMatthias Ringwald 40747ec646SMilanka Ringwald 41747ec646SMilanka Ringwald #include <stdint.h> 42747ec646SMilanka Ringwald #include <string.h> 43747ec646SMilanka Ringwald 4484e3541eSMilanka Ringwald #include "bluetooth_psm.h" 4584e3541eSMilanka Ringwald #include "bluetooth_sdp.h" 4684e3541eSMilanka Ringwald #include "btstack_debug.h" 4784e3541eSMilanka Ringwald #include "btstack_event.h" 4884e3541eSMilanka Ringwald #include "btstack_memory.h" 494cb889a5SMilanka Ringwald #include "classic/avdtp.h" 504cb889a5SMilanka Ringwald #include "classic/avdtp_acceptor.h" 514cb889a5SMilanka Ringwald #include "classic/avdtp_initiator.h" 5284e3541eSMilanka Ringwald #include "classic/avdtp_util.h" 5384e3541eSMilanka Ringwald #include "classic/sdp_client.h" 5484e3541eSMilanka Ringwald #include "classic/sdp_util.h" 55747ec646SMilanka Ringwald 5636da8747SMilanka Ringwald avdtp_context_t * avdtp_source_context = NULL; 5736da8747SMilanka Ringwald avdtp_context_t * avdtp_sink_context = NULL; 58a1fb0563SMilanka Ringwald 59d8e15394SMilanka Ringwald btstack_linked_list_t stream_endpoints; 60d8e15394SMilanka Ringwald 61a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_source_callback; 62a1fb0563SMilanka Ringwald static btstack_packet_handler_t avdtp_sink_callback; 63a1fb0563SMilanka Ringwald 64ca2c9990SMilanka Ringwald static uint16_t sdp_query_context_avdtp_cid = 0; 65f0c39502SMilanka Ringwald 66560b3f31SMilanka Ringwald static uint16_t stream_endpoints_id_counter = 0; 67560b3f31SMilanka Ringwald 685ace758fSMilanka Ringwald static btstack_linked_list_t connections; 695ace758fSMilanka Ringwald static uint16_t initiator_transaction_id_counter = 0; 705ace758fSMilanka Ringwald 71692c0605SMilanka Ringwald static int record_id = -1; 72fa1ee4d3SMilanka Ringwald static uint8_t attribute_value[45]; 73692c0605SMilanka Ringwald static const unsigned int attribute_value_buffer_size = sizeof(attribute_value); 74747ec646SMilanka Ringwald 75951d2774SMatthias Ringwald static void (*avdtp_sink_handle_media_data)(uint8_t local_seid, uint8_t *packet, uint16_t size); 76951d2774SMatthias Ringwald 77af121d54SMilanka Ringwald static uint16_t avdtp_cid_counter = 0; 78747ec646SMilanka Ringwald 79692c0605SMilanka Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 80692c0605SMilanka Ringwald 81f751daa3SMatthias Ringwald btstack_packet_handler_t 82f751daa3SMatthias Ringwald avdtp_packet_handler_for_stream_endpoint(const avdtp_stream_endpoint_t *stream_endpoint) { 83f751daa3SMatthias Ringwald return (stream_endpoint->sep.type == AVDTP_SOURCE) ? avdtp_source_callback : avdtp_sink_callback; 84f751daa3SMatthias Ringwald } 85f751daa3SMatthias Ringwald 86f751daa3SMatthias Ringwald static void avdtp_streaming_emit_connection_established(avdtp_stream_endpoint_t *stream_endpoint, uint8_t status) { 87f751daa3SMatthias Ringwald uint8_t event[14]; 88f751daa3SMatthias Ringwald int pos = 0; 89f751daa3SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 90f751daa3SMatthias Ringwald event[pos++] = sizeof(event) - 2; 91f751daa3SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED; 92f751daa3SMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 93f751daa3SMatthias Ringwald pos += 2; 94f751daa3SMatthias Ringwald reverse_bd_addr(stream_endpoint->connection->remote_addr, &event[pos]); 95f751daa3SMatthias Ringwald pos += 6; 96f751daa3SMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint); 97f751daa3SMatthias Ringwald event[pos++] = avdtp_remote_seid(stream_endpoint); 98f751daa3SMatthias Ringwald event[pos++] = status; 99f751daa3SMatthias Ringwald 100f751daa3SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 101f751daa3SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 102f751daa3SMatthias Ringwald } 103f751daa3SMatthias Ringwald 104f751daa3SMatthias Ringwald static void avdtp_streaming_emit_connection_released(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t local_seid) { 105f751daa3SMatthias Ringwald uint8_t event[6]; 106f751daa3SMatthias Ringwald int pos = 0; 107f751daa3SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 108f751daa3SMatthias Ringwald event[pos++] = sizeof(event) - 2; 109f751daa3SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED; 110f751daa3SMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 111f751daa3SMatthias Ringwald pos += 2; 112f751daa3SMatthias Ringwald event[pos++] = local_seid; 113f751daa3SMatthias Ringwald 114f751daa3SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 115f751daa3SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 116f751daa3SMatthias Ringwald } 117f751daa3SMatthias Ringwald 118f751daa3SMatthias Ringwald void avdtp_streaming_emit_can_send_media_packet_now(avdtp_stream_endpoint_t *stream_endpoint, uint16_t sequence_number) { 119f751daa3SMatthias Ringwald uint8_t event[8]; 120f751daa3SMatthias Ringwald int pos = 0; 121f751daa3SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 122f751daa3SMatthias Ringwald event[pos++] = sizeof(event) - 2; 123f751daa3SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW; 124f751daa3SMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 125f751daa3SMatthias Ringwald pos += 2; 126f751daa3SMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint); 127f751daa3SMatthias Ringwald little_endian_store_16(event, pos, sequence_number); 128f751daa3SMatthias Ringwald pos += 2; 129f751daa3SMatthias Ringwald 130f751daa3SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 131f751daa3SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 132f751daa3SMatthias Ringwald } 133f751daa3SMatthias Ringwald 1342d9d000fSMatthias Ringwald 1352d9d000fSMatthias Ringwald void avdtp_signaling_emit_delay(uint16_t avdtp_cid, uint8_t local_seid, uint16_t delay) { 1362d9d000fSMatthias Ringwald uint8_t event[8]; 1372d9d000fSMatthias Ringwald int pos = 0; 1382d9d000fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1392d9d000fSMatthias Ringwald event[pos++] = sizeof(event) - 2; 1402d9d000fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT; 1412d9d000fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 1422d9d000fSMatthias Ringwald pos += 2; 1432d9d000fSMatthias Ringwald event[pos++] = local_seid; 1442d9d000fSMatthias Ringwald little_endian_store_16(event, pos, delay); 1452d9d000fSMatthias Ringwald pos += 2; 1462d9d000fSMatthias Ringwald (*avdtp_source_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 1472d9d000fSMatthias Ringwald } 1482d9d000fSMatthias Ringwald 14961fb88e1SMatthias Ringwald void avdtp_emit_configuration(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, 15061fb88e1SMatthias Ringwald avdtp_capabilities_t *configuration, uint16_t configured_service_categories) { 15161fb88e1SMatthias Ringwald 15261fb88e1SMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 15361fb88e1SMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 15461fb88e1SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 15561fb88e1SMatthias Ringwald 15661fb88e1SMatthias Ringwald if (get_bit16(configured_service_categories, AVDTP_MEDIA_CODEC)){ 15761fb88e1SMatthias Ringwald switch (configuration->media_codec.media_codec_type){ 15861fb88e1SMatthias Ringwald case AVDTP_CODEC_SBC: 159*0fbfe070SMatthias Ringwald avdtp_signaling_emit_media_codec_sbc_configuration( 160*0fbfe070SMatthias Ringwald stream_endpoint, avdtp_cid, 161*0fbfe070SMatthias Ringwald configuration->media_codec.media_type, 162*0fbfe070SMatthias Ringwald configuration->media_codec.media_codec_information); 16361fb88e1SMatthias Ringwald break; 16461fb88e1SMatthias Ringwald default: 16561fb88e1SMatthias Ringwald avdtp_signaling_emit_media_codec_other_configuration(packet_handler, avdtp_cid, local_seid, remote_seid, configuration->media_codec); 16661fb88e1SMatthias Ringwald break; 16761fb88e1SMatthias Ringwald } 16861fb88e1SMatthias Ringwald } 16961fb88e1SMatthias Ringwald } 17061fb88e1SMatthias Ringwald 171*0fbfe070SMatthias Ringwald static inline void 172*0fbfe070SMatthias Ringwald avdtp_signaling_emit_media_codec_sbc(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, 173*0fbfe070SMatthias Ringwald avdtp_media_type_t media_type, const uint8_t *media_codec_information, 174*0fbfe070SMatthias Ringwald uint8_t reconfigure) { 175*0fbfe070SMatthias Ringwald 176*0fbfe070SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 177*0fbfe070SMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 178*0fbfe070SMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 179*0fbfe070SMatthias Ringwald 180*0fbfe070SMatthias Ringwald uint8_t event[16 + 2]; 181*0fbfe070SMatthias Ringwald int pos = 0; 182*0fbfe070SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 183*0fbfe070SMatthias Ringwald event[pos++] = sizeof(event) - 2; 184*0fbfe070SMatthias Ringwald 185*0fbfe070SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION; 186*0fbfe070SMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 187*0fbfe070SMatthias Ringwald pos += 2; 188*0fbfe070SMatthias Ringwald event[pos++] = local_seid; 189*0fbfe070SMatthias Ringwald event[pos++] = remote_seid; 190*0fbfe070SMatthias Ringwald event[pos++] = reconfigure; 191*0fbfe070SMatthias Ringwald 192*0fbfe070SMatthias Ringwald 193*0fbfe070SMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[0] >> 4; 194*0fbfe070SMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x0F; 195*0fbfe070SMatthias Ringwald uint8_t block_length_bitmap = media_codec_information[1] >> 4; 196*0fbfe070SMatthias Ringwald uint8_t subbands_bitmap = (media_codec_information[1] & 0x0F) >> 2; 197*0fbfe070SMatthias Ringwald 198*0fbfe070SMatthias Ringwald uint8_t num_channels = 0; 199*0fbfe070SMatthias Ringwald if ((channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO) || 200*0fbfe070SMatthias Ringwald (channel_mode_bitmap & AVDTP_SBC_STEREO) || 201*0fbfe070SMatthias Ringwald (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL)) { 202*0fbfe070SMatthias Ringwald num_channels = 2; 203*0fbfe070SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_MONO) { 204*0fbfe070SMatthias Ringwald num_channels = 1; 205*0fbfe070SMatthias Ringwald } 206*0fbfe070SMatthias Ringwald 207*0fbfe070SMatthias Ringwald uint16_t sampling_frequency = 0; 208*0fbfe070SMatthias Ringwald if (sampling_frequency_bitmap & AVDTP_SBC_48000) { 209*0fbfe070SMatthias Ringwald sampling_frequency = 48000; 210*0fbfe070SMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_44100) { 211*0fbfe070SMatthias Ringwald sampling_frequency = 44100; 212*0fbfe070SMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_32000) { 213*0fbfe070SMatthias Ringwald sampling_frequency = 32000; 214*0fbfe070SMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_16000) { 215*0fbfe070SMatthias Ringwald sampling_frequency = 16000; 216*0fbfe070SMatthias Ringwald } 217*0fbfe070SMatthias Ringwald 218*0fbfe070SMatthias Ringwald uint8_t subbands = 0; 219*0fbfe070SMatthias Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 220*0fbfe070SMatthias Ringwald subbands = 8; 221*0fbfe070SMatthias Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 222*0fbfe070SMatthias Ringwald subbands = 4; 223*0fbfe070SMatthias Ringwald } 224*0fbfe070SMatthias Ringwald 225*0fbfe070SMatthias Ringwald uint8_t block_length = 0; 226*0fbfe070SMatthias Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 227*0fbfe070SMatthias Ringwald block_length = 16; 228*0fbfe070SMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 229*0fbfe070SMatthias Ringwald block_length = 12; 230*0fbfe070SMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 231*0fbfe070SMatthias Ringwald block_length = 8; 232*0fbfe070SMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 233*0fbfe070SMatthias Ringwald block_length = 4; 234*0fbfe070SMatthias Ringwald } 235*0fbfe070SMatthias Ringwald 236*0fbfe070SMatthias Ringwald event[pos++] = media_type; 237*0fbfe070SMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 238*0fbfe070SMatthias Ringwald pos += 2; 239*0fbfe070SMatthias Ringwald 240*0fbfe070SMatthias Ringwald event[pos++] = channel_mode_bitmap; 241*0fbfe070SMatthias Ringwald event[pos++] = num_channels; 242*0fbfe070SMatthias Ringwald event[pos++] = block_length; 243*0fbfe070SMatthias Ringwald event[pos++] = subbands; 244*0fbfe070SMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03; 245*0fbfe070SMatthias Ringwald event[pos++] = media_codec_information[2]; 246*0fbfe070SMatthias Ringwald event[pos++] = media_codec_information[3]; 247*0fbfe070SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 248*0fbfe070SMatthias Ringwald } 249*0fbfe070SMatthias Ringwald 250*0fbfe070SMatthias Ringwald void avdtp_signaling_emit_media_codec_sbc_configuration(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, 251*0fbfe070SMatthias Ringwald avdtp_media_type_t media_type, 252*0fbfe070SMatthias Ringwald const uint8_t *media_codec_information) { 253*0fbfe070SMatthias Ringwald avdtp_signaling_emit_media_codec_sbc(stream_endpoint, avdtp_cid, media_type, 254*0fbfe070SMatthias Ringwald media_codec_information, 0); 255*0fbfe070SMatthias Ringwald } 256*0fbfe070SMatthias Ringwald 257*0fbfe070SMatthias Ringwald void avdtp_signaling_emit_media_codec_sbc_reconfiguration(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, 258*0fbfe070SMatthias Ringwald avdtp_media_type_t media_type, 259*0fbfe070SMatthias Ringwald const uint8_t *media_codec_information) { 260*0fbfe070SMatthias Ringwald avdtp_signaling_emit_media_codec_sbc(stream_endpoint, avdtp_cid, media_type, 261*0fbfe070SMatthias Ringwald media_codec_information, 1); 262*0fbfe070SMatthias Ringwald } 263*0fbfe070SMatthias Ringwald 264f751daa3SMatthias Ringwald btstack_linked_list_t * avdtp_get_stream_endpoints(void){ 265f751daa3SMatthias Ringwald return &stream_endpoints; 266f751daa3SMatthias Ringwald } 26736da8747SMilanka Ringwald 2685ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_get_connection_for_bd_addr(bd_addr_t addr){ 2695ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 2705ace758fSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 2715ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2725ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 2735ace758fSMilanka Ringwald if (memcmp(addr, connection->remote_addr, 6) != 0) continue; 2745ace758fSMilanka Ringwald return connection; 275b0d75c91SMilanka Ringwald } 2765ace758fSMilanka Ringwald return NULL; 277b0d75c91SMilanka Ringwald } 278b0d75c91SMilanka Ringwald 2795ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_avdtp_cid(uint16_t avdtp_cid){ 2805ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 2815ace758fSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 2825ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2835ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 2845ace758fSMilanka Ringwald if (connection->avdtp_cid != avdtp_cid) continue; 2855ace758fSMilanka Ringwald return connection; 2865ace758fSMilanka Ringwald } 2875ace758fSMilanka Ringwald return NULL; 2885ace758fSMilanka Ringwald } 2895ace758fSMilanka Ringwald 2905ace758fSMilanka Ringwald 291d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_seid(uint16_t seid){ 2925ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 293d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 2945ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 2955ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 2965ace758fSMilanka Ringwald if (stream_endpoint->sep.seid == seid){ 2975ace758fSMilanka Ringwald return stream_endpoint; 2985ace758fSMilanka Ringwald } 2995ace758fSMilanka Ringwald } 3005ace758fSMilanka Ringwald return NULL; 3015ace758fSMilanka Ringwald } 3025ace758fSMilanka Ringwald 3035ace758fSMilanka Ringwald avdtp_connection_t * avdtp_get_connection_for_l2cap_signaling_cid(uint16_t l2cap_cid){ 3045ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 3055ace758fSMilanka Ringwald btstack_linked_list_iterator_init(&it, &connections); 3065ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3075ace758fSMilanka Ringwald avdtp_connection_t * connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it); 3085ace758fSMilanka Ringwald if (connection->l2cap_signaling_cid != l2cap_cid) continue; 3095ace758fSMilanka Ringwald return connection; 3105ace758fSMilanka Ringwald } 3115ace758fSMilanka Ringwald return NULL; 3125ace758fSMilanka Ringwald } 3135ace758fSMilanka Ringwald 3146f98b084SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_l2cap_cid(uint16_t l2cap_cid){ 3155ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 316d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 3175ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3185ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 3195ace758fSMilanka Ringwald if (stream_endpoint->l2cap_media_cid == l2cap_cid){ 3205ace758fSMilanka Ringwald return stream_endpoint; 3215ace758fSMilanka Ringwald } 3225ace758fSMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == l2cap_cid){ 3235ace758fSMilanka Ringwald return stream_endpoint; 3245ace758fSMilanka Ringwald } 3255ace758fSMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == l2cap_cid){ 3265ace758fSMilanka Ringwald return stream_endpoint; 3275ace758fSMilanka Ringwald } 3285ace758fSMilanka Ringwald } 3295ace758fSMilanka Ringwald return NULL; 3305ace758fSMilanka Ringwald } 3315ace758fSMilanka Ringwald 33219a000d1SMilanka Ringwald static avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_for_signaling_cid(uint16_t l2cap_cid){ 3335ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 334d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 3355ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3365ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 3375ace758fSMilanka Ringwald if (stream_endpoint->connection){ 3385ace758fSMilanka Ringwald if (stream_endpoint->connection->l2cap_signaling_cid == l2cap_cid){ 3395ace758fSMilanka Ringwald return stream_endpoint; 3405ace758fSMilanka Ringwald } 3415ace758fSMilanka Ringwald } 3425ace758fSMilanka Ringwald } 3435ace758fSMilanka Ringwald return NULL; 3445ace758fSMilanka Ringwald } 3455ace758fSMilanka Ringwald 3466f98b084SMilanka Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_with_seid(uint8_t seid){ 3475ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 348d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 3495ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3505ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 3515ace758fSMilanka Ringwald if (stream_endpoint->sep.seid == seid){ 3525ace758fSMilanka Ringwald return stream_endpoint; 3535ace758fSMilanka Ringwald } 3545ace758fSMilanka Ringwald } 3555ace758fSMilanka Ringwald return NULL; 3565ace758fSMilanka Ringwald } 3575ace758fSMilanka Ringwald 358054be048SMilanka Ringwald avdtp_stream_endpoint_t * avdtp_get_stream_endpoint_associated_with_acp_seid(uint16_t acp_seid){ 3595ace758fSMilanka Ringwald btstack_linked_list_iterator_t it; 360d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 3615ace758fSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 3625ace758fSMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 3635ace758fSMilanka Ringwald if (stream_endpoint->remote_sep.seid == acp_seid){ 3645ace758fSMilanka Ringwald return stream_endpoint; 3655ace758fSMilanka Ringwald } 3665ace758fSMilanka Ringwald } 3675ace758fSMilanka Ringwald return NULL; 3685ace758fSMilanka Ringwald } 3695ace758fSMilanka Ringwald 3705ace758fSMilanka Ringwald static uint16_t avdtp_get_next_initiator_transaction_label(void){ 3715ace758fSMilanka Ringwald initiator_transaction_id_counter++; 3725ace758fSMilanka Ringwald if (initiator_transaction_id_counter == 0){ 3735ace758fSMilanka Ringwald initiator_transaction_id_counter = 1; 3745ace758fSMilanka Ringwald } 3755ace758fSMilanka Ringwald return initiator_transaction_id_counter; 3765ace758fSMilanka Ringwald } 3775ace758fSMilanka Ringwald 3785ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_create_connection(bd_addr_t remote_addr, uint16_t cid){ 37936da8747SMilanka Ringwald avdtp_connection_t * connection = btstack_memory_avdtp_connection_get(); 38036da8747SMilanka Ringwald if (!connection){ 38136da8747SMilanka Ringwald log_error("Not enough memory to create connection"); 38236da8747SMilanka Ringwald return NULL; 38336da8747SMilanka Ringwald } 38436da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_IDLE; 3855ace758fSMilanka Ringwald connection->initiator_transaction_label = avdtp_get_next_initiator_transaction_label(); 38636da8747SMilanka Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_IDLE; 38736da8747SMilanka Ringwald connection->avdtp_cid = cid; 38836da8747SMilanka Ringwald (void)memcpy(connection->remote_addr, remote_addr, 6); 38936da8747SMilanka Ringwald 3905ace758fSMilanka Ringwald btstack_linked_list_add(&connections, (btstack_linked_item_t *) connection); 39136da8747SMilanka Ringwald return connection; 39236da8747SMilanka Ringwald } 39336da8747SMilanka Ringwald 39436da8747SMilanka Ringwald static uint16_t avdtp_get_next_cid(void){ 395af121d54SMilanka Ringwald if (avdtp_cid_counter == 0xffff) { 3964ccacc40SMilanka Ringwald avdtp_cid_counter = 1; 397af121d54SMilanka Ringwald } else { 398af121d54SMilanka Ringwald avdtp_cid_counter++; 3994ccacc40SMilanka Ringwald } 4004ccacc40SMilanka Ringwald return avdtp_cid_counter; 4014ccacc40SMilanka Ringwald } 4024ccacc40SMilanka Ringwald 403560b3f31SMilanka Ringwald static uint16_t avdtp_get_next_local_seid(void){ 404560b3f31SMilanka Ringwald if (stream_endpoints_id_counter == 0xffff) { 405560b3f31SMilanka Ringwald stream_endpoints_id_counter = 1; 406af121d54SMilanka Ringwald } else { 407560b3f31SMilanka Ringwald stream_endpoints_id_counter++; 4084ccacc40SMilanka Ringwald } 409560b3f31SMilanka Ringwald return stream_endpoints_id_counter; 4104ccacc40SMilanka Ringwald } 4114ccacc40SMilanka Ringwald 412ca2c9990SMilanka Ringwald static uint8_t avdtp_start_sdp_query(btstack_packet_handler_t packet_handler, avdtp_connection_t * connection) { 413b1549ed3SMilanka Ringwald connection->avdtp_l2cap_psm = 0; 414b1549ed3SMilanka Ringwald connection->avdtp_version = 0; 415b1549ed3SMilanka Ringwald connection->sink_supported = false; 416b1549ed3SMilanka Ringwald connection->source_supported = false; 417ca2c9990SMilanka Ringwald sdp_query_context_avdtp_cid = connection->avdtp_cid; 418b1549ed3SMilanka Ringwald 419b1549ed3SMilanka Ringwald return sdp_client_query_uuid16(packet_handler, (uint8_t *) connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP); 42084521ac1SMilanka Ringwald } 42184521ac1SMilanka Ringwald 422a1fb0563SMilanka Ringwald uint8_t avdtp_connect(bd_addr_t remote, avdtp_role_t role, uint16_t * avdtp_cid){ 42384521ac1SMilanka Ringwald // TODO: implement delayed SDP query 42484521ac1SMilanka Ringwald if (sdp_client_ready() == 0){ 42584521ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 42684521ac1SMilanka Ringwald } 42784521ac1SMilanka Ringwald 4285ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_bd_addr(remote); 42984521ac1SMilanka Ringwald if (connection){ 43084521ac1SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 4314567cc17SMilanka Ringwald } 43284521ac1SMilanka Ringwald 43336da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 4342ad6b656SMilanka Ringwald if (avdtp_cid != NULL) { 43584521ac1SMilanka Ringwald *avdtp_cid = cid; 4362ad6b656SMilanka Ringwald } 4372ad6b656SMilanka Ringwald 4385ace758fSMilanka Ringwald connection = avdtp_create_connection(remote, cid); 43936da8747SMilanka Ringwald if (!connection) return BTSTACK_MEMORY_ALLOC_FAILED; 44036da8747SMilanka Ringwald 44184521ac1SMilanka Ringwald connection->avdtp_cid = cid; 442b1549ed3SMilanka Ringwald 443b1549ed3SMilanka Ringwald switch (role){ 444149deddbSMilanka Ringwald case AVDTP_ROLE_SOURCE: 445149deddbSMilanka Ringwald connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE; 446149deddbSMilanka Ringwald break; 447149deddbSMilanka Ringwald case AVDTP_ROLE_SINK: 448149deddbSMilanka Ringwald connection->state = AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE; 449149deddbSMilanka Ringwald break; 450149deddbSMilanka Ringwald default: 451149deddbSMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 452149deddbSMilanka Ringwald } 453ca2c9990SMilanka Ringwald return avdtp_start_sdp_query(&avdtp_handle_sdp_client_query_result, connection); 454692c0605SMilanka Ringwald } 455747ec646SMilanka Ringwald 456a1fb0563SMilanka Ringwald 457a1fb0563SMilanka Ringwald void avdtp_register_sink_packet_handler(btstack_packet_handler_t callback){ 458a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 459a1fb0563SMilanka Ringwald avdtp_sink_callback = callback; 460a1fb0563SMilanka Ringwald } 461a1fb0563SMilanka Ringwald 462a1fb0563SMilanka Ringwald void avdtp_register_source_packet_handler(btstack_packet_handler_t callback){ 463a1fb0563SMilanka Ringwald btstack_assert(callback != NULL); 464a1fb0563SMilanka Ringwald avdtp_source_callback = callback; 465a1fb0563SMilanka Ringwald } 466a1fb0563SMilanka Ringwald 467747ec646SMilanka Ringwald void avdtp_register_media_transport_category(avdtp_stream_endpoint_t * stream_endpoint){ 468747ec646SMilanka Ringwald if (!stream_endpoint){ 4699900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 470747ec646SMilanka Ringwald return; 471747ec646SMilanka Ringwald } 472747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_TRANSPORT, 1); 473747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 474747ec646SMilanka Ringwald } 475747ec646SMilanka Ringwald 476747ec646SMilanka Ringwald void avdtp_register_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 477747ec646SMilanka Ringwald if (!stream_endpoint){ 4789900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 479747ec646SMilanka Ringwald return; 480747ec646SMilanka Ringwald } 481747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_REPORTING, 1); 482747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 483747ec646SMilanka Ringwald } 484747ec646SMilanka Ringwald 485747ec646SMilanka Ringwald void avdtp_register_delay_reporting_category(avdtp_stream_endpoint_t * stream_endpoint){ 486747ec646SMilanka Ringwald if (!stream_endpoint){ 4879900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 488747ec646SMilanka Ringwald return; 489747ec646SMilanka Ringwald } 490747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_DELAY_REPORTING, 1); 491747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 492747ec646SMilanka Ringwald } 493747ec646SMilanka Ringwald 494747ec646SMilanka Ringwald void avdtp_register_recovery_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t maximum_recovery_window_size, uint8_t maximum_number_media_packets){ 495747ec646SMilanka Ringwald if (!stream_endpoint){ 4969900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 497747ec646SMilanka Ringwald return; 498747ec646SMilanka Ringwald } 499747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_RECOVERY, 1); 500747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 501747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.recovery_type = 0x01; // 0x01 = RFC2733 502747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_recovery_window_size = maximum_recovery_window_size; 503747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.recovery.maximum_number_media_packets = maximum_number_media_packets; 504747ec646SMilanka Ringwald } 505747ec646SMilanka Ringwald 506747ec646SMilanka 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){ 507747ec646SMilanka Ringwald if (!stream_endpoint){ 5089900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 509747ec646SMilanka Ringwald return; 510747ec646SMilanka Ringwald } 511747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_CONTENT_PROTECTION, 1); 512747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 513747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type = cp_type; 5146535961aSMatthias Ringwald (void)memcpy(stream_endpoint->sep.capabilities.content_protection.cp_type_value, 5156535961aSMatthias Ringwald cp_type_value, 5166535961aSMatthias Ringwald btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN)); 51767ae582dSMilanka Ringwald stream_endpoint->sep.capabilities.content_protection.cp_type_value_len = btstack_min(cp_type_value_len, AVDTP_MAX_CONTENT_PROTECTION_TYPE_VALUE_LEN); 518747ec646SMilanka Ringwald } 519747ec646SMilanka Ringwald 520747ec646SMilanka Ringwald void avdtp_register_header_compression_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t back_ch, uint8_t media, uint8_t recovery){ 521747ec646SMilanka Ringwald if (!stream_endpoint){ 5229900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 523747ec646SMilanka Ringwald return; 524747ec646SMilanka Ringwald } 525747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_HEADER_COMPRESSION, 1); 526747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 527747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.back_ch = back_ch; 528747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.media = media; 529747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.header_compression.recovery = recovery; 530747ec646SMilanka Ringwald } 531747ec646SMilanka Ringwald 53278d08d09SMilanka Ringwald void avdtp_register_media_codec_category(avdtp_stream_endpoint_t * stream_endpoint, avdtp_media_type_t media_type, avdtp_media_codec_type_t media_codec_type, uint8_t * media_codec_info, uint16_t media_codec_info_len){ 533747ec646SMilanka Ringwald if (!stream_endpoint){ 5349900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 535747ec646SMilanka Ringwald return; 536747ec646SMilanka Ringwald } 537747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MEDIA_CODEC, 1); 538747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 539747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_type = media_type; 540747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_type = media_codec_type; 541747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information = media_codec_info; 542747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.media_codec.media_codec_information_len = media_codec_info_len; 543747ec646SMilanka Ringwald } 544747ec646SMilanka Ringwald 545747ec646SMilanka Ringwald void avdtp_register_multiplexing_category(avdtp_stream_endpoint_t * stream_endpoint, uint8_t fragmentation){ 546747ec646SMilanka Ringwald if (!stream_endpoint){ 5479900b7faSMilanka Ringwald log_error("Stream endpoint with given seid is not registered."); 548747ec646SMilanka Ringwald return; 549747ec646SMilanka Ringwald } 550747ec646SMilanka Ringwald uint16_t bitmap = store_bit16(stream_endpoint->sep.registered_service_categories, AVDTP_MULTIPLEXING, 1); 551747ec646SMilanka Ringwald stream_endpoint->sep.registered_service_categories = bitmap; 552747ec646SMilanka Ringwald stream_endpoint->sep.capabilities.multiplexing_mode.fragmentation = fragmentation; 553747ec646SMilanka Ringwald } 554747ec646SMilanka Ringwald 555951d2774SMatthias Ringwald void avdtp_register_media_handler(void (*callback)(uint8_t local_seid, uint8_t *packet, uint16_t size)){ 556951d2774SMatthias Ringwald avdtp_sink_handle_media_data = callback; 557951d2774SMatthias Ringwald } 558747ec646SMilanka Ringwald 559747ec646SMilanka Ringwald /* START: tracking can send now requests pro l2cap cid */ 560747ec646SMilanka Ringwald void avdtp_handle_can_send_now(avdtp_connection_t * connection, uint16_t l2cap_cid, avdtp_context_t * context){ 561747ec646SMilanka Ringwald if (connection->wait_to_send_acceptor){ 562c6bc5965SMilanka Ringwald log_debug("call avdtp_acceptor_stream_config_subsm_run"); 563747ec646SMilanka Ringwald connection->wait_to_send_acceptor = 0; 564747ec646SMilanka Ringwald avdtp_acceptor_stream_config_subsm_run(connection, context); 565747ec646SMilanka Ringwald } else if (connection->wait_to_send_initiator){ 566c6bc5965SMilanka Ringwald log_debug("call avdtp_initiator_stream_config_subsm_run"); 567747ec646SMilanka Ringwald connection->wait_to_send_initiator = 0; 568747ec646SMilanka Ringwald avdtp_initiator_stream_config_subsm_run(connection, context); 569747ec646SMilanka Ringwald } 570747ec646SMilanka Ringwald 571747ec646SMilanka Ringwald // re-register 572f01aeca4SMilanka Ringwald bool more_to_send = connection->wait_to_send_acceptor || connection->wait_to_send_initiator; 573f01aeca4SMilanka Ringwald log_debug("ask for more to send %d: acc-%d, ini-%d", more_to_send, connection->wait_to_send_acceptor, connection->wait_to_send_initiator); 574c6bc5965SMilanka Ringwald 575747ec646SMilanka Ringwald if (more_to_send){ 576747ec646SMilanka Ringwald l2cap_request_can_send_now_event(l2cap_cid); 577747ec646SMilanka Ringwald } 578747ec646SMilanka Ringwald } 579747ec646SMilanka Ringwald /* END: tracking can send now requests pro l2cap cid */ 580747ec646SMilanka Ringwald 581747ec646SMilanka Ringwald 582297feb5fSMilanka Ringwald avdtp_stream_endpoint_t * avdtp_create_stream_endpoint(avdtp_sep_type_t sep_type, avdtp_media_type_t media_type){ 583747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = btstack_memory_avdtp_stream_endpoint_get(); 5844567cc17SMilanka Ringwald if (!stream_endpoint){ 5859900b7faSMilanka Ringwald log_error("Not enough memory to create stream endpoint"); 5864567cc17SMilanka Ringwald return NULL; 5874567cc17SMilanka Ringwald } 588560b3f31SMilanka Ringwald stream_endpoint->sep.seid = avdtp_get_next_local_seid(); 589747ec646SMilanka Ringwald stream_endpoint->sep.media_type = media_type; 590747ec646SMilanka Ringwald stream_endpoint->sep.type = sep_type; 591d8e15394SMilanka Ringwald btstack_linked_list_add(avdtp_get_stream_endpoints(), (btstack_linked_item_t *) stream_endpoint); 592747ec646SMilanka Ringwald return stream_endpoint; 593747ec646SMilanka Ringwald } 594747ec646SMilanka Ringwald 595747ec646SMilanka Ringwald static void handle_l2cap_data_packet_for_signaling_connection(avdtp_connection_t * connection, uint8_t *packet, uint16_t size, avdtp_context_t * context){ 596c1c40ea1SMatthias Ringwald if (size < 2) return; 597c1c40ea1SMatthias Ringwald 598c1c40ea1SMatthias Ringwald uint16_t offset; 599c1c40ea1SMatthias Ringwald avdtp_message_type_t message_type = avdtp_get_signaling_packet_type(packet); 600c1c40ea1SMatthias Ringwald switch (message_type){ 601747ec646SMilanka Ringwald case AVDTP_CMD_MSG: 60250453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->acceptor_signaling_packet, packet, size); 603747ec646SMilanka Ringwald avdtp_acceptor_stream_config_subsm(connection, packet, size, offset, context); 604747ec646SMilanka Ringwald break; 605747ec646SMilanka Ringwald default: 60650453b92SMatthias Ringwald offset = avdtp_read_signaling_header(&connection->initiator_signaling_packet, packet, size); 607747ec646SMilanka Ringwald avdtp_initiator_stream_config_subsm(connection, packet, size, offset, context); 608747ec646SMilanka Ringwald break; 609747ec646SMilanka Ringwald } 610747ec646SMilanka Ringwald } 611747ec646SMilanka Ringwald 612b1549ed3SMilanka Ringwald static void avdtp_handle_sdp_client_query_attribute_value(avdtp_connection_t * connection, uint8_t *packet){ 613692c0605SMilanka Ringwald des_iterator_t des_list_it; 614692c0605SMilanka Ringwald des_iterator_t prot_it; 615692c0605SMilanka Ringwald 616692c0605SMilanka Ringwald // Handle new SDP record 617692c0605SMilanka Ringwald if (sdp_event_query_attribute_byte_get_record_id(packet) != record_id) { 618692c0605SMilanka Ringwald record_id = sdp_event_query_attribute_byte_get_record_id(packet); 6198587e32cSMilanka Ringwald // log_info("SDP Record: Nr: %d", record_id); 620692c0605SMilanka Ringwald } 621692c0605SMilanka Ringwald 622692c0605SMilanka Ringwald if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) { 623692c0605SMilanka Ringwald attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet); 624692c0605SMilanka Ringwald 625692c0605SMilanka Ringwald if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) { 626692c0605SMilanka Ringwald 627692c0605SMilanka Ringwald switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) { 628149deddbSMilanka Ringwald 629692c0605SMilanka Ringwald case BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST: 630692c0605SMilanka Ringwald if (de_get_element_type(attribute_value) != DE_DES) break; 631692c0605SMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 632692c0605SMilanka Ringwald uint8_t * element = des_iterator_get_element(&des_list_it); 633692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 634692c0605SMilanka Ringwald uint32_t uuid = de_get_uuid32(element); 635692c0605SMilanka Ringwald switch (uuid){ 636692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SOURCE: 637b1549ed3SMilanka Ringwald connection->source_supported = true; 638149deddbSMilanka Ringwald log_info("source_supported"); 639692c0605SMilanka Ringwald break; 640692c0605SMilanka Ringwald case BLUETOOTH_SERVICE_CLASS_AUDIO_SINK: 641b1549ed3SMilanka Ringwald connection->sink_supported = true; 642149deddbSMilanka Ringwald log_info("sink_supported"); 643692c0605SMilanka Ringwald break; 644692c0605SMilanka Ringwald default: 645692c0605SMilanka Ringwald break; 646692c0605SMilanka Ringwald } 647692c0605SMilanka Ringwald } 648692c0605SMilanka Ringwald break; 649692c0605SMilanka Ringwald 650149deddbSMilanka Ringwald case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST: 6518587e32cSMilanka Ringwald // log_info("SDP Attribute: 0x%04x", sdp_event_query_attribute_byte_get_attribute_id(packet)); 652692c0605SMilanka Ringwald for (des_iterator_init(&des_list_it, attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) { 653692c0605SMilanka Ringwald uint8_t *des_element; 654692c0605SMilanka Ringwald uint8_t *element; 655692c0605SMilanka Ringwald uint32_t uuid; 656692c0605SMilanka Ringwald 657692c0605SMilanka Ringwald if (des_iterator_get_type(&des_list_it) != DE_DES) continue; 658692c0605SMilanka Ringwald 659692c0605SMilanka Ringwald des_element = des_iterator_get_element(&des_list_it); 660692c0605SMilanka Ringwald des_iterator_init(&prot_it, des_element); 661692c0605SMilanka Ringwald element = des_iterator_get_element(&prot_it); 662692c0605SMilanka Ringwald 663692c0605SMilanka Ringwald if (de_get_element_type(element) != DE_UUID) continue; 664692c0605SMilanka Ringwald 665692c0605SMilanka Ringwald uuid = de_get_uuid32(element); 66614fd128cSMatthias Ringwald des_iterator_next(&prot_it); 667149deddbSMilanka Ringwald // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both 668692c0605SMilanka Ringwald switch (uuid){ 669692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_L2CAP: 670692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 671b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_l2cap_psm); 672692c0605SMilanka Ringwald break; 673692c0605SMilanka Ringwald case BLUETOOTH_PROTOCOL_AVDTP: 674692c0605SMilanka Ringwald if (!des_iterator_has_more(&prot_it)) continue; 675b1549ed3SMilanka Ringwald de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->avdtp_version); 676692c0605SMilanka Ringwald break; 677692c0605SMilanka Ringwald default: 678692c0605SMilanka Ringwald break; 679692c0605SMilanka Ringwald } 680692c0605SMilanka Ringwald } 681692c0605SMilanka Ringwald break; 682149deddbSMilanka Ringwald 683692c0605SMilanka Ringwald default: 684692c0605SMilanka Ringwald break; 685692c0605SMilanka Ringwald } 686692c0605SMilanka Ringwald } 687692c0605SMilanka Ringwald } else { 6888587e32cSMilanka Ringwald log_error("SDP attribute value buffer size exceeded: available %d, required %d", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet)); 689692c0605SMilanka Ringwald } 6906ed344c3SMatthias Ringwald 6916ed344c3SMatthias Ringwald } 6926ed344c3SMatthias Ringwald 6935ace758fSMilanka Ringwald static void avdtp_finalize_connection(avdtp_connection_t * connection){ 694ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 6955ace758fSMilanka Ringwald btstack_linked_list_remove(&connections, (btstack_linked_item_t*) connection); 696f0c39502SMilanka Ringwald btstack_memory_avdtp_connection_free(connection); 697f0c39502SMilanka Ringwald } 698f0c39502SMilanka Ringwald 699f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_failed(avdtp_connection_t * connection, uint8_t status){ 700a1fb0563SMilanka Ringwald printf("avdtp_handle_sdp_query_failed \n"); 701a1fb0563SMilanka Ringwald switch (connection->state){ 702a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 703a1fb0563SMilanka Ringwald avdtp_signaling_emit_connection_established(avdtp_source_callback, connection->avdtp_cid, connection->remote_addr, status); 704a1fb0563SMilanka Ringwald break; 705a1fb0563SMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 706a1fb0563SMilanka Ringwald avdtp_signaling_emit_connection_established(avdtp_sink_callback, connection->avdtp_cid, connection->remote_addr, status); 707a1fb0563SMilanka Ringwald break; 708a1fb0563SMilanka Ringwald default: 709a1fb0563SMilanka Ringwald return; 710a1fb0563SMilanka Ringwald } 7115ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 712ca2c9990SMilanka Ringwald sdp_query_context_avdtp_cid = 0; 713f0c39502SMilanka Ringwald log_info("SDP query failed with status 0x%02x.", status); 714f0c39502SMilanka Ringwald } 715f0c39502SMilanka Ringwald 716f0c39502SMilanka Ringwald static void avdtp_handle_sdp_query_succeeded(avdtp_connection_t * connection){ 717a1fb0563SMilanka Ringwald printf("avdtp_handle_sdp_query_succeeded \n"); 718f0c39502SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 719f0c39502SMilanka Ringwald } 720f0c39502SMilanka Ringwald 7216ed344c3SMatthias Ringwald static void avdtp_handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 722149deddbSMilanka Ringwald UNUSED(packet_type); 723149deddbSMilanka Ringwald UNUSED(channel); 724149deddbSMilanka Ringwald UNUSED(size); 725149deddbSMilanka Ringwald 726ca2c9990SMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(sdp_query_context_avdtp_cid); 7276ed344c3SMatthias Ringwald if (!connection) { 728ca2c9990SMilanka Ringwald log_error("SDP query, connection with 0x%02x cid not found", sdp_query_context_avdtp_cid); 7296ed344c3SMatthias Ringwald return; 7306ed344c3SMatthias Ringwald } 7316ed344c3SMatthias Ringwald 7326ed344c3SMatthias Ringwald uint8_t status; 733149deddbSMilanka Ringwald bool query_succeded = false; 734149deddbSMilanka Ringwald 735149deddbSMilanka Ringwald switch (connection->state){ 736149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SINK_COMPLETE: 7376ed344c3SMatthias Ringwald switch (hci_event_packet_get_type(packet)){ 7386ed344c3SMatthias Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 739b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 740149deddbSMilanka Ringwald return; 741692c0605SMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 7421e1ae2bcSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 743149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 744b1549ed3SMilanka Ringwald if (!connection->sink_supported) break; 745b1549ed3SMilanka Ringwald if (connection->avdtp_l2cap_psm == 0) break; 746149deddbSMilanka Ringwald query_succeded = true; 747149deddbSMilanka Ringwald break; 748149deddbSMilanka Ringwald default: 749149deddbSMilanka Ringwald btstack_assert(false); 7501e1ae2bcSMilanka Ringwald break; 7511e1ae2bcSMilanka Ringwald } 752149deddbSMilanka Ringwald break; 753149deddbSMilanka Ringwald case AVDTP_SIGNALING_W4_SDP_QUERY_FOR_REMOTE_SOURCE_COMPLETE: 754149deddbSMilanka Ringwald switch (hci_event_packet_get_type(packet)){ 755149deddbSMilanka Ringwald case SDP_EVENT_QUERY_ATTRIBUTE_VALUE: 756b1549ed3SMilanka Ringwald avdtp_handle_sdp_client_query_attribute_value(connection, packet); 757149deddbSMilanka Ringwald return; 758149deddbSMilanka Ringwald case SDP_EVENT_QUERY_COMPLETE: 759149deddbSMilanka Ringwald status = sdp_event_query_complete_get_status(packet); 760149deddbSMilanka Ringwald if (status != ERROR_CODE_SUCCESS) break; 761b1549ed3SMilanka Ringwald if (!connection->source_supported) break; 762b1549ed3SMilanka Ringwald if (connection->avdtp_l2cap_psm == 0) break; 763149deddbSMilanka Ringwald query_succeded = true; 764149deddbSMilanka Ringwald break; 765149deddbSMilanka Ringwald default: 766149deddbSMilanka Ringwald btstack_assert(false); 767974d4d6eSMilanka Ringwald break; 768974d4d6eSMilanka Ringwald } 7692f6083d0SMilanka Ringwald break; 770149deddbSMilanka Ringwald default: 771149deddbSMilanka Ringwald // bail out, we must have had an incoming connection in the meantime; 772149deddbSMilanka Ringwald return; 7732f6083d0SMilanka Ringwald } 774f0c39502SMilanka Ringwald 775149deddbSMilanka Ringwald if (query_succeded){ 776149deddbSMilanka Ringwald avdtp_handle_sdp_query_succeeded(connection); 777ed161adbSMilanka Ringwald l2cap_create_channel(avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 778149deddbSMilanka Ringwald } else { 779149deddbSMilanka Ringwald avdtp_handle_sdp_query_failed(connection, status); 780692c0605SMilanka Ringwald } 781692c0605SMilanka Ringwald } 782692c0605SMilanka Ringwald 7835ace758fSMilanka Ringwald static avdtp_connection_t * avdtp_handle_incoming_connection(avdtp_connection_t * connection, bd_addr_t event_addr, uint16_t local_cid){ 78436da8747SMilanka Ringwald if (connection == NULL){ 78536da8747SMilanka Ringwald uint16_t cid = avdtp_get_next_cid(); 7865ace758fSMilanka Ringwald connection = avdtp_create_connection(event_addr, cid); 78736da8747SMilanka Ringwald } 788692c0605SMilanka Ringwald 78936da8747SMilanka Ringwald if (connection) { 79036da8747SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 79136da8747SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 792ff53b162SMilanka Ringwald btstack_run_loop_remove_timer(&connection->retry_timer); 79336da8747SMilanka Ringwald } 79436da8747SMilanka Ringwald return connection; 79536da8747SMilanka Ringwald } 796f0c39502SMilanka Ringwald 797326e3662SMilanka Ringwald static avdtp_context_t * avdtp_get_active_contex(void){ 798326e3662SMilanka Ringwald // assume only one context is active 799326e3662SMilanka Ringwald avdtp_context_t * context = NULL; 800326e3662SMilanka Ringwald if (avdtp_sink_context != NULL){ 801326e3662SMilanka Ringwald context = avdtp_sink_context; 802326e3662SMilanka Ringwald } else { 803326e3662SMilanka Ringwald context = avdtp_source_context; 804326e3662SMilanka Ringwald } 805326e3662SMilanka Ringwald btstack_assert(context != NULL); 806326e3662SMilanka Ringwald return context; 807326e3662SMilanka Ringwald } 808326e3662SMilanka Ringwald 809ff53b162SMilanka Ringwald static void avdtp_retry_timer_timeout_handler(btstack_timer_source_t * timer){ 810326e3662SMilanka Ringwald uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer); 811326e3662SMilanka Ringwald 8125ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 813326e3662SMilanka Ringwald if (connection == NULL) return; 814326e3662SMilanka Ringwald 815ff53b162SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY){ 816326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED; 817326e3662SMilanka Ringwald l2cap_create_channel(&avdtp_packet_handler, connection->remote_addr, connection->avdtp_l2cap_psm, l2cap_max_mtu(), NULL); 818326e3662SMilanka Ringwald } 819326e3662SMilanka Ringwald } 820326e3662SMilanka Ringwald 821ff53b162SMilanka Ringwald static void avdtp_retry_timer_start(avdtp_connection_t * connection){ 822ff53b162SMilanka Ringwald btstack_run_loop_set_timer_handler(&connection->retry_timer, avdtp_retry_timer_timeout_handler); 823ff53b162SMilanka Ringwald btstack_run_loop_set_timer_context(&connection->retry_timer, (void *)(uintptr_t)connection->avdtp_cid); 824326e3662SMilanka Ringwald 825326e3662SMilanka Ringwald // add some jitter/randomness to reconnect delay 826326e3662SMilanka Ringwald uint32_t timeout = 100 + (btstack_run_loop_get_time_ms() & 0x7F); 827ff53b162SMilanka Ringwald btstack_run_loop_set_timer(&connection->retry_timer, timeout); 828ff53b162SMilanka Ringwald btstack_run_loop_add_timer(&connection->retry_timer); 829326e3662SMilanka Ringwald } 830326e3662SMilanka Ringwald 831326e3662SMilanka Ringwald 832326e3662SMilanka Ringwald void avdtp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 833747ec646SMilanka Ringwald bd_addr_t event_addr; 834747ec646SMilanka Ringwald uint16_t psm; 835747ec646SMilanka Ringwald uint16_t local_cid; 8361e1ae2bcSMilanka Ringwald uint8_t status; 837326e3662SMilanka Ringwald uint16_t l2cap_mtu; 83836da8747SMilanka Ringwald 83936da8747SMilanka Ringwald bool accept_streaming_connection; 84036da8747SMilanka Ringwald bool outoing_signaling_active; 84136da8747SMilanka Ringwald bool decline_connection; 84284521ac1SMilanka Ringwald 843747ec646SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = NULL; 844747ec646SMilanka Ringwald avdtp_connection_t * connection = NULL; 84536da8747SMilanka Ringwald 846326e3662SMilanka Ringwald avdtp_context_t * context = avdtp_get_active_contex(); 847326e3662SMilanka Ringwald 848747ec646SMilanka Ringwald switch (packet_type) { 849747ec646SMilanka Ringwald case L2CAP_DATA_PACKET: 8505ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 851747ec646SMilanka Ringwald if (connection){ 852747ec646SMilanka Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size, context); 853747ec646SMilanka Ringwald break; 854747ec646SMilanka Ringwald } 855747ec646SMilanka Ringwald 8566f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 857747ec646SMilanka Ringwald if (!stream_endpoint){ 858747ec646SMilanka Ringwald if (!connection) break; 859747ec646SMilanka Ringwald handle_l2cap_data_packet_for_signaling_connection(connection, packet, size, context); 860747ec646SMilanka Ringwald break; 861747ec646SMilanka Ringwald } 862747ec646SMilanka Ringwald 8638c0f3635SMilanka Ringwald if (stream_endpoint->connection){ 8649413b167SMilanka Ringwald if (channel == stream_endpoint->connection->l2cap_signaling_cid){ 865025463b2SMatthias Ringwald handle_l2cap_data_packet_for_signaling_connection(stream_endpoint->connection, packet, size, context); 866747ec646SMilanka Ringwald break; 867747ec646SMilanka Ringwald } 8688c0f3635SMilanka Ringwald } 869747ec646SMilanka Ringwald 870747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_media_cid){ 871951d2774SMatthias Ringwald btstack_assert(avdtp_sink_handle_media_data); 872951d2774SMatthias Ringwald (*avdtp_sink_handle_media_data)(avdtp_local_seid(stream_endpoint), packet, size); 873747ec646SMilanka Ringwald break; 874747ec646SMilanka Ringwald } 875747ec646SMilanka Ringwald 876747ec646SMilanka Ringwald if (channel == stream_endpoint->l2cap_reporting_cid){ 8778587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED"); 878747ec646SMilanka Ringwald } else if (channel == stream_endpoint->l2cap_recovery_cid){ 8798587e32cSMilanka Ringwald log_info("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED"); 880747ec646SMilanka Ringwald } else { 881747ec646SMilanka Ringwald log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel); 882747ec646SMilanka Ringwald } 883747ec646SMilanka Ringwald break; 884747ec646SMilanka Ringwald 885747ec646SMilanka Ringwald case HCI_EVENT_PACKET: 886747ec646SMilanka Ringwald switch (hci_event_packet_get_type(packet)) { 88736da8747SMilanka Ringwald 888747ec646SMilanka Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 889747ec646SMilanka Ringwald l2cap_event_incoming_connection_get_address(packet, event_addr); 890747ec646SMilanka Ringwald local_cid = l2cap_event_incoming_connection_get_local_cid(packet); 89184521ac1SMilanka Ringwald 89236da8747SMilanka Ringwald outoing_signaling_active = false; 89336da8747SMilanka Ringwald accept_streaming_connection = false; 89436da8747SMilanka Ringwald 8955ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 89636da8747SMilanka Ringwald if (connection != NULL){ 8970d4a198eSMatthias Ringwald switch (connection->state){ 8980d4a198eSMatthias Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED: 89936da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 90036da8747SMilanka Ringwald outoing_signaling_active = true; 90136da8747SMilanka Ringwald connection->incoming_declined = true; 90236da8747SMilanka Ringwald break; 90336da8747SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 90436da8747SMilanka Ringwald outoing_signaling_active = true; 90536da8747SMilanka Ringwald accept_streaming_connection = true; 90636da8747SMilanka Ringwald break; 907f0c39502SMilanka Ringwald default: 908f0c39502SMilanka Ringwald break; 9090d4a198eSMatthias Ringwald } 910747ec646SMilanka Ringwald } 91136da8747SMilanka Ringwald log_info("incoming: %s, outoing_signaling_active %d, accept_streaming_connection %d", 91236da8747SMilanka Ringwald bd_addr_to_str(event_addr), outoing_signaling_active, accept_streaming_connection); 913747ec646SMilanka Ringwald 91436da8747SMilanka Ringwald decline_connection = outoing_signaling_active && !accept_streaming_connection; 91536da8747SMilanka Ringwald if (outoing_signaling_active == false){ 9165ace758fSMilanka Ringwald connection = avdtp_handle_incoming_connection(connection, event_addr, local_cid); 91736da8747SMilanka Ringwald if (connection == NULL){ 91836da8747SMilanka Ringwald decline_connection = true; 91936da8747SMilanka Ringwald } 92036da8747SMilanka Ringwald } else if (accept_streaming_connection){ 92136da8747SMilanka Ringwald if ((connection == NULL) || (connection->configuration_state != AVDTP_CONFIGURATION_STATE_REMOTE_CONFIGURED)) { 92236da8747SMilanka Ringwald decline_connection = true; 92336da8747SMilanka Ringwald } else { 924939e12adSMatthias Ringwald // now, we're only dealing with media connections that are created by remote side - we're acceptor here 9256f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_with_seid(connection->acceptor_local_seid); 92636da8747SMilanka Ringwald if ((stream_endpoint == NULL) || (stream_endpoint->l2cap_media_cid != 0) ) { 92736da8747SMilanka Ringwald decline_connection = true; 92836da8747SMilanka Ringwald } 92936da8747SMilanka Ringwald } 930747ec646SMilanka Ringwald } 931747ec646SMilanka Ringwald 93236da8747SMilanka Ringwald if (decline_connection){ 933a3ce0109SMatthias Ringwald l2cap_decline_connection(local_cid); 93436da8747SMilanka Ringwald } else { 935747ec646SMilanka Ringwald l2cap_accept_connection(local_cid); 93636da8747SMilanka Ringwald } 937747ec646SMilanka Ringwald break; 938747ec646SMilanka Ringwald 939747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 940a1fb0563SMilanka Ringwald btstack_assert(context != NULL); 941a5114819SMilanka Ringwald 942a0b8a58cSMilanka Ringwald psm = l2cap_event_channel_opened_get_psm(packet); 94384e3541eSMilanka Ringwald if (psm != BLUETOOTH_PSM_AVDTP){ 944355ac553SMilanka Ringwald log_info("Unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED "); 945a0b8a58cSMilanka Ringwald return; 946a0b8a58cSMilanka Ringwald } 947a0b8a58cSMilanka Ringwald 9481e1ae2bcSMilanka Ringwald status = l2cap_event_channel_opened_get_status(packet); 949747ec646SMilanka Ringwald // inform about new l2cap connection 950747ec646SMilanka Ringwald l2cap_event_channel_opened_get_address(packet, event_addr); 9517050d2caSMilanka Ringwald local_cid = l2cap_event_channel_opened_get_local_cid(packet); 952326e3662SMilanka Ringwald l2cap_mtu = l2cap_event_channel_opened_get_remote_mtu(packet); 9535ace758fSMilanka Ringwald connection = avdtp_get_connection_for_bd_addr(event_addr); 95436da8747SMilanka Ringwald if (connection == NULL){ 95536da8747SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: no connection found for %s", bd_addr_to_str(event_addr)); 956a0b8a58cSMilanka Ringwald break; 957a0b8a58cSMilanka Ringwald } 958a0b8a58cSMilanka Ringwald 959a5114819SMilanka Ringwald switch (connection->state){ 960a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_W4_L2CAP_CONNECTED: 961326e3662SMilanka Ringwald switch (status){ 962326e3662SMilanka Ringwald case ERROR_CODE_SUCCESS: 963326e3662SMilanka Ringwald connection->l2cap_signaling_cid = local_cid; 964326e3662SMilanka Ringwald connection->incoming_declined = false; 965326e3662SMilanka Ringwald connection->l2cap_mtu = l2cap_mtu; 966326e3662SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_OPENED; 967326e3662SMilanka Ringwald log_info("Connection opened l2cap_signaling_cid 0x%02x, avdtp_cid 0x%02x", connection->l2cap_signaling_cid, connection->avdtp_cid); 968326e3662SMilanka Ringwald avdtp_signaling_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, event_addr, status); 969326e3662SMilanka Ringwald return; 970326e3662SMilanka Ringwald case L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES: 971326e3662SMilanka Ringwald if (connection->incoming_declined == true) { 972326e3662SMilanka Ringwald log_info("Connection was declined, and the outgoing failed"); 973ff53b162SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W2_L2CAP_RETRY; 974326e3662SMilanka Ringwald connection->incoming_declined = false; 975ff53b162SMilanka Ringwald avdtp_retry_timer_start(connection); 976326e3662SMilanka Ringwald return; 977326e3662SMilanka Ringwald } 978326e3662SMilanka Ringwald break; 979326e3662SMilanka Ringwald default: 980326e3662SMilanka Ringwald log_info("Connection to %s failed. status code 0x%02x", bd_addr_to_str(event_addr), status); 981326e3662SMilanka Ringwald break; 982326e3662SMilanka Ringwald } 9835ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 984a5114819SMilanka Ringwald avdtp_signaling_emit_connection_established(context->avdtp_callback, connection->avdtp_cid, event_addr, status); 985a0b8a58cSMilanka Ringwald break; 986747ec646SMilanka Ringwald 987a5114819SMilanka Ringwald case AVDTP_SIGNALING_CONNECTION_OPENED: 98819a000d1SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_signaling_cid(connection->l2cap_signaling_cid); 989747ec646SMilanka Ringwald if (!stream_endpoint){ 9905bd73fa2SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: stream_endpoint not found for signaling cid 0x%02x", connection->l2cap_signaling_cid); 991747ec646SMilanka Ringwald return; 992747ec646SMilanka Ringwald } 993326e3662SMilanka Ringwald if (status != ERROR_CODE_SUCCESS){ 994355ac553SMilanka 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)); 995a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 996f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, status); 997a466d508SMilanka Ringwald break; 998a466d508SMilanka Ringwald } 999a5114819SMilanka Ringwald switch (stream_endpoint->state){ 1000a5114819SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED: 1001a466d508SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED; 1002a466d508SMilanka Ringwald stream_endpoint->l2cap_media_cid = l2cap_event_channel_opened_get_local_cid(packet); 1003a466d508SMilanka Ringwald stream_endpoint->media_con_handle = l2cap_event_channel_opened_get_handle(packet); 1004d1207cd8SMilanka Ringwald 1005355ac553SMilanka 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)); 1006f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, ERROR_CODE_SUCCESS); 1007a5114819SMilanka Ringwald break; 1008a5114819SMilanka Ringwald default: 1009a5114819SMilanka 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)); 1010f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_established(stream_endpoint, AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE); 1011a5114819SMilanka Ringwald break; 1012a5114819SMilanka Ringwald } 1013a5114819SMilanka Ringwald break; 1014a5114819SMilanka Ringwald 1015a5114819SMilanka Ringwald default: 1016326e3662SMilanka Ringwald log_info("L2CAP connection to %s ignored: status code 0x%02x, connection state %d", bd_addr_to_str(event_addr), status, connection->state); 1017a5114819SMilanka Ringwald break; 1018a5114819SMilanka Ringwald } 1019747ec646SMilanka Ringwald break; 1020747ec646SMilanka Ringwald 1021747ec646SMilanka Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 1022747ec646SMilanka Ringwald local_cid = l2cap_event_channel_closed_get_local_cid(packet); 10236f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(local_cid); 10245ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(local_cid); 102536da8747SMilanka Ringwald 1026f01aeca4SMilanka Ringwald log_info("Received L2CAP_EVENT_CHANNEL_CLOSED, cid 0x%2x, connection %p, stream_endpoint %p", local_cid, connection, stream_endpoint); 1027f01aeca4SMilanka Ringwald 1028a466d508SMilanka Ringwald if (stream_endpoint){ 1029a466d508SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == local_cid){ 1030a466d508SMilanka Ringwald connection = stream_endpoint->connection; 1031596b7fdcSMilanka Ringwald if (connection) { 1032f751daa3SMatthias Ringwald avdtp_streaming_emit_connection_released(stream_endpoint, 1033f751daa3SMatthias Ringwald connection->avdtp_cid, 1034f751daa3SMatthias Ringwald avdtp_local_seid(stream_endpoint)); 1035596b7fdcSMilanka Ringwald } 1036485c0a4cSMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 1037a466d508SMilanka Ringwald break; 1038a466d508SMilanka Ringwald } 1039a466d508SMilanka Ringwald if (stream_endpoint->l2cap_recovery_cid == local_cid){ 1040355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED recovery cid 0x%0x", local_cid); 1041a466d508SMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0; 1042a466d508SMilanka Ringwald break; 1043a466d508SMilanka Ringwald } 1044a466d508SMilanka Ringwald 1045a466d508SMilanka Ringwald if (stream_endpoint->l2cap_reporting_cid == local_cid){ 1046355ac553SMilanka Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED reporting cid 0x%0x", local_cid); 1047a466d508SMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0; 1048a466d508SMilanka Ringwald break; 1049a466d508SMilanka Ringwald } 1050a466d508SMilanka Ringwald } 1051596b7fdcSMilanka Ringwald 1052596b7fdcSMilanka Ringwald if (connection){ 1053596b7fdcSMilanka Ringwald btstack_linked_list_iterator_t it; 1054d8e15394SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1055596b7fdcSMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1056f01aeca4SMilanka Ringwald stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1057f01aeca4SMilanka Ringwald if (stream_endpoint->connection == connection){ 1058f01aeca4SMilanka Ringwald avdtp_reset_stream_endpoint(stream_endpoint); 1059596b7fdcSMilanka Ringwald } 1060596b7fdcSMilanka Ringwald } 1061485c0a4cSMilanka Ringwald avdtp_signaling_emit_connection_released(context->avdtp_callback, connection->avdtp_cid); 10625ace758fSMilanka Ringwald avdtp_finalize_connection(connection); 1063596b7fdcSMilanka Ringwald break; 1064596b7fdcSMilanka Ringwald } 1065596b7fdcSMilanka Ringwald 1066747ec646SMilanka Ringwald break; 1067747ec646SMilanka Ringwald 1068747ec646SMilanka Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE: 1069747ec646SMilanka Ringwald break; 1070747ec646SMilanka Ringwald 1071747ec646SMilanka Ringwald case L2CAP_EVENT_CAN_SEND_NOW: 1072c6bc5965SMilanka Ringwald log_debug("avdtp_packet_handler, L2CAP_EVENT_CAN_SEND_NOW l2cap_cid 0x%02x", channel); 10735ace758fSMilanka Ringwald connection = avdtp_get_connection_for_l2cap_signaling_cid(channel); 1074747ec646SMilanka Ringwald if (!connection) { 10756f98b084SMilanka Ringwald stream_endpoint = avdtp_get_stream_endpoint_for_l2cap_cid(channel); 1076747ec646SMilanka Ringwald if (!stream_endpoint->connection) break; 1077747ec646SMilanka Ringwald connection = stream_endpoint->connection; 1078747ec646SMilanka Ringwald } 1079747ec646SMilanka Ringwald avdtp_handle_can_send_now(connection, channel, context); 1080747ec646SMilanka Ringwald break; 1081747ec646SMilanka Ringwald default: 1082355ac553SMilanka Ringwald log_info("Unknown HCI event type %02x", hci_event_packet_get_type(packet)); 1083747ec646SMilanka Ringwald break; 1084747ec646SMilanka Ringwald } 1085747ec646SMilanka Ringwald break; 1086747ec646SMilanka Ringwald 1087747ec646SMilanka Ringwald default: 1088747ec646SMilanka Ringwald // other packet type 1089747ec646SMilanka Ringwald break; 1090747ec646SMilanka Ringwald } 1091747ec646SMilanka Ringwald } 1092747ec646SMilanka Ringwald 1093b401ff59SMilanka Ringwald uint8_t avdtp_disconnect(uint16_t avdtp_cid){ 10945ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 10952ad6b656SMilanka Ringwald if (!connection) return AVDTP_CONNECTION_DOES_NOT_EXIST; 1096b401ff59SMilanka Ringwald 1097a466d508SMilanka Ringwald if (connection->state == AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED) return ERROR_CODE_SUCCESS; 1098747ec646SMilanka Ringwald 1099f01aeca4SMilanka Ringwald btstack_linked_list_iterator_t it; 1100f01aeca4SMilanka Ringwald btstack_linked_list_iterator_init(&it, avdtp_get_stream_endpoints()); 1101f01aeca4SMilanka Ringwald 1102f01aeca4SMilanka Ringwald while (btstack_linked_list_iterator_has_next(&it)){ 1103f01aeca4SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = (avdtp_stream_endpoint_t *)btstack_linked_list_iterator_next(&it); 1104f01aeca4SMilanka Ringwald if (stream_endpoint->connection != connection) continue; 1105f01aeca4SMilanka Ringwald 1106f01aeca4SMilanka Ringwald switch (stream_endpoint->state){ 1107f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_OPENED: 1108f01aeca4SMilanka Ringwald case AVDTP_STREAM_ENDPOINT_STREAMING: 1109f01aeca4SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_DISCONNECTED; 1110f01aeca4SMilanka Ringwald l2cap_disconnect(stream_endpoint->l2cap_media_cid, 0); 1111f01aeca4SMilanka Ringwald break; 1112f01aeca4SMilanka Ringwald default: 1113f01aeca4SMilanka Ringwald break; 1114f01aeca4SMilanka Ringwald } 1115f01aeca4SMilanka Ringwald } 1116f01aeca4SMilanka Ringwald 1117f01aeca4SMilanka Ringwald connection->state = AVDTP_SIGNALING_CONNECTION_W4_L2CAP_DISCONNECTED; 1118f01aeca4SMilanka Ringwald l2cap_disconnect(connection->l2cap_signaling_cid, 0); 11194ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1120747ec646SMilanka Ringwald } 1121747ec646SMilanka Ringwald 1122297feb5fSMilanka Ringwald uint8_t avdtp_open_stream(uint16_t avdtp_cid, uint8_t local_seid, uint8_t remote_seid){ 11235ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1124747ec646SMilanka Ringwald if (!connection){ 11258587e32cSMilanka Ringwald log_error("avdtp_media_connect: no connection for signaling cid 0x%02x found", avdtp_cid); 11264ccacc40SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 1127747ec646SMilanka Ringwald } 1128747ec646SMilanka Ringwald 1129747ec646SMilanka Ringwald if (connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) { 11308587e32cSMilanka Ringwald log_error("avdtp_media_connect: wrong connection state %d", connection->state); 11314ccacc40SMilanka Ringwald return AVDTP_CONNECTION_IN_WRONG_STATE; 1132747ec646SMilanka Ringwald } 1133747ec646SMilanka Ringwald 11346f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 1135747ec646SMilanka Ringwald if (!stream_endpoint) { 11366b0ee1d0SMilanka Ringwald log_error("avdtp_media_connect: no stream_endpoint with seid %d found", local_seid); 11374ccacc40SMilanka Ringwald return AVDTP_SEID_DOES_NOT_EXIST; 1138747ec646SMilanka Ringwald } 1139747ec646SMilanka Ringwald 1140485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid != remote_seid){ 1141485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep with seid %d registered with the stream endpoint", remote_seid); 1142485c0a4cSMilanka Ringwald return AVDTP_SEID_DOES_NOT_EXIST; 1143485c0a4cSMilanka Ringwald } 1144485c0a4cSMilanka Ringwald 11454ccacc40SMilanka Ringwald if (stream_endpoint->state < AVDTP_STREAM_ENDPOINT_CONFIGURED) return AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE; 1146747ec646SMilanka Ringwald 1147747ec646SMilanka Ringwald connection->initiator_transaction_label++; 114896dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 11495bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1150747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_OPEN_STREAM; 1151747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM; 11529413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 11534ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1154747ec646SMilanka Ringwald } 1155747ec646SMilanka Ringwald 1156297feb5fSMilanka Ringwald uint8_t avdtp_start_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11575ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 115846e6b063SMilanka Ringwald if (!connection){ 11594ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 11604ccacc40SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 116146e6b063SMilanka Ringwald } 11625cfe7f4cSMilanka Ringwald 11636f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 11644ccacc40SMilanka Ringwald if (!stream_endpoint) { 11654ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no stream_endpoint with seid %d found", local_seid); 11664ccacc40SMilanka Ringwald return AVDTP_SEID_DOES_NOT_EXIST; 11674ccacc40SMilanka Ringwald } 11684ccacc40SMilanka Ringwald 11694ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 11704ccacc40SMilanka Ringwald log_error("avdtp_start_stream: no media connection for stream_endpoint with seid %d found", local_seid); 11714ccacc40SMilanka Ringwald return AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST; 11724ccacc40SMilanka Ringwald } 11734ccacc40SMilanka Ringwald 1174485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 1175485c0a4cSMilanka Ringwald log_error("avdtp_media_connect: no remote sep registered with the stream endpoint"); 1176485c0a4cSMilanka Ringwald return AVDTP_SEID_DOES_NOT_EXIST; 11774ccacc40SMilanka Ringwald } 11784ccacc40SMilanka Ringwald 1179440d8d82SMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->start_stream == 1){ 1180440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1181440d8d82SMilanka Ringwald } 1182440d8d82SMilanka Ringwald 118360ec20d0SMilanka Ringwald stream_endpoint->start_stream = 1; 11845bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 118596dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 11869413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 11874ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1188747ec646SMilanka Ringwald } 1189747ec646SMilanka Ringwald 1190297feb5fSMilanka Ringwald uint8_t avdtp_stop_stream(uint16_t avdtp_cid, uint8_t local_seid){ 11915ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1192747ec646SMilanka Ringwald if (!connection){ 11934ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 11944ccacc40SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 1195747ec646SMilanka Ringwald } 11964ccacc40SMilanka Ringwald 11976f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 11984ccacc40SMilanka Ringwald if (!stream_endpoint) { 11994ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no stream_endpoint with seid %d found", local_seid); 12004ccacc40SMilanka Ringwald return AVDTP_SEID_DOES_NOT_EXIST; 12014ccacc40SMilanka Ringwald } 12024ccacc40SMilanka Ringwald 12034ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 12044ccacc40SMilanka Ringwald log_error("avdtp_stop_stream: no media connection for stream_endpoint with seid %d found", local_seid); 12054ccacc40SMilanka Ringwald return AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST; 12064ccacc40SMilanka Ringwald } 1207485c0a4cSMilanka Ringwald 1208485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->stop_stream){ 1209440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1210485c0a4cSMilanka Ringwald } 12114ccacc40SMilanka Ringwald 121260ec20d0SMilanka Ringwald stream_endpoint->stop_stream = 1; 12135bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 121496dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 12159413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 12164ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1217747ec646SMilanka Ringwald } 1218747ec646SMilanka Ringwald 1219297feb5fSMilanka Ringwald uint8_t avdtp_abort_stream(uint16_t avdtp_cid, uint8_t local_seid){ 12205ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 122160ec20d0SMilanka Ringwald if (!connection){ 12224ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 12234ccacc40SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 1224747ec646SMilanka Ringwald } 12254ccacc40SMilanka Ringwald 12266f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 12274ccacc40SMilanka Ringwald if (!stream_endpoint) { 12284ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no stream_endpoint with seid %d found", local_seid); 12294ccacc40SMilanka Ringwald return AVDTP_SEID_DOES_NOT_EXIST; 12304ccacc40SMilanka Ringwald } 12314ccacc40SMilanka Ringwald 12324ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 12334ccacc40SMilanka Ringwald log_error("avdtp_abort_stream: no media connection for stream_endpoint with seid %d found", local_seid); 12344ccacc40SMilanka Ringwald return AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST; 12354ccacc40SMilanka Ringwald } 1236485c0a4cSMilanka Ringwald 1237485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->abort_stream){ 1238440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1239485c0a4cSMilanka Ringwald } 12404ccacc40SMilanka Ringwald 124160ec20d0SMilanka Ringwald stream_endpoint->abort_stream = 1; 12425bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 124396dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 12449413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 12454ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1246747ec646SMilanka Ringwald } 1247747ec646SMilanka Ringwald 1248297feb5fSMilanka Ringwald uint8_t avdtp_suspend_stream(uint16_t avdtp_cid, uint8_t local_seid){ 12495ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1250747ec646SMilanka Ringwald if (!connection){ 12514ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no connection for signaling cid 0x%02x found", avdtp_cid); 12524ccacc40SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 125360ec20d0SMilanka Ringwald } 12546f98b084SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_with_seid(local_seid); 12554ccacc40SMilanka Ringwald if (!stream_endpoint) { 12564ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no stream_endpoint with seid %d found", local_seid); 12574ccacc40SMilanka Ringwald return AVDTP_SEID_DOES_NOT_EXIST; 12584ccacc40SMilanka Ringwald } 12594ccacc40SMilanka Ringwald 12604ccacc40SMilanka Ringwald if (stream_endpoint->l2cap_media_cid == 0){ 12614ccacc40SMilanka Ringwald log_error("avdtp_suspend_stream: no media connection for stream_endpoint with seid %d found", local_seid); 12624ccacc40SMilanka Ringwald return AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST; 12634ccacc40SMilanka Ringwald } 1264485c0a4cSMilanka Ringwald 1265485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint) || stream_endpoint->suspend_stream){ 1266440d8d82SMilanka Ringwald return ERROR_CODE_COMMAND_DISALLOWED; 1267485c0a4cSMilanka Ringwald } 12684ccacc40SMilanka Ringwald 126960ec20d0SMilanka Ringwald stream_endpoint->suspend_stream = 1; 12705bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 127196dcd0f4SMatthias Ringwald connection->initiator_remote_seid = stream_endpoint->remote_sep.seid; 12729413b167SMilanka Ringwald avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 12734ccacc40SMilanka Ringwald return ERROR_CODE_SUCCESS; 1274747ec646SMilanka Ringwald } 1275747ec646SMilanka Ringwald 12765ace758fSMilanka Ringwald uint8_t avdtp_discover_stream_endpoints(uint16_t avdtp_cid){ 12775ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1278747ec646SMilanka Ringwald if (!connection){ 12798587e32cSMilanka Ringwald log_error("avdtp_discover_stream_endpoints: no connection for signaling cid 0x%02x found", avdtp_cid); 12809974aee0SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 12819974aee0SMilanka Ringwald } 12820e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1283c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 12849974aee0SMilanka Ringwald return AVDTP_CONNECTION_IN_WRONG_STATE; 1285747ec646SMilanka Ringwald } 1286ec3d71e3SMilanka Ringwald 1287747ec646SMilanka Ringwald connection->initiator_transaction_label++; 1288747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_DISCOVER_SEPS; 12899974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1290747ec646SMilanka Ringwald } 1291747ec646SMilanka Ringwald 1292747ec646SMilanka Ringwald 12935ace758fSMilanka Ringwald uint8_t avdtp_get_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 12945ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1295747ec646SMilanka Ringwald if (!connection){ 12969900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 12979974aee0SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 1298747ec646SMilanka Ringwald } 12990e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1300c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 13019974aee0SMilanka Ringwald return AVDTP_CONNECTION_IN_WRONG_STATE; 13029974aee0SMilanka Ringwald } 13039974aee0SMilanka Ringwald 1304747ec646SMilanka Ringwald connection->initiator_transaction_label++; 1305747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CAPABILITIES; 130696dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 13079974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1308747ec646SMilanka Ringwald } 1309747ec646SMilanka Ringwald 1310747ec646SMilanka Ringwald 13115ace758fSMilanka Ringwald uint8_t avdtp_get_all_capabilities(uint16_t avdtp_cid, uint8_t remote_seid){ 13125ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1313747ec646SMilanka Ringwald if (!connection){ 13149900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 13159974aee0SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 1316747ec646SMilanka Ringwald } 13170e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1318c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 13199974aee0SMilanka Ringwald return AVDTP_CONNECTION_IN_WRONG_STATE; 13209974aee0SMilanka Ringwald } 13219974aee0SMilanka Ringwald 1322747ec646SMilanka Ringwald connection->initiator_transaction_label++; 1323747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_ALL_CAPABILITIES; 132496dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 13259974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1326747ec646SMilanka Ringwald } 1327747ec646SMilanka Ringwald 13285ace758fSMilanka Ringwald uint8_t avdtp_get_configuration(uint16_t avdtp_cid, uint8_t remote_seid){ 13295ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1330747ec646SMilanka Ringwald if (!connection){ 13319900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 13329974aee0SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 1333747ec646SMilanka Ringwald } 13340e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1335c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 13369974aee0SMilanka Ringwald return AVDTP_CONNECTION_IN_WRONG_STATE; 13379974aee0SMilanka Ringwald } 13389974aee0SMilanka Ringwald 1339747ec646SMilanka Ringwald connection->initiator_transaction_label++; 1340747ec646SMilanka Ringwald connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_W2_GET_CONFIGURATION; 134196dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 13429974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1343747ec646SMilanka Ringwald } 1344747ec646SMilanka Ringwald 1345cec76c5bSMilanka 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){ 13465ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1347747ec646SMilanka Ringwald if (!connection){ 13489900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 13499974aee0SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 1350747ec646SMilanka Ringwald } 13510e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1352c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 1353485c0a4cSMilanka Ringwald log_error("connection in wrong state, %d, initiator state %d", connection->state, connection->initiator_connection_state); 13549974aee0SMilanka Ringwald return AVDTP_CONNECTION_IN_WRONG_STATE; 13559974aee0SMilanka Ringwald } 1356a3ce0109SMatthias Ringwald if (connection->configuration_state != AVDTP_CONFIGURATION_STATE_IDLE){ 1357a3ce0109SMatthias Ringwald log_info("configuration already started, config state %u", connection->configuration_state); 1358a3ce0109SMatthias Ringwald return AVDTP_CONNECTION_IN_WRONG_STATE; 1359a3ce0109SMatthias Ringwald } 1360747ec646SMilanka Ringwald 1361d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 1362747ec646SMilanka Ringwald if (!stream_endpoint) { 13639900b7faSMilanka Ringwald log_error("No initiator stream endpoint for seid %d", local_seid); 13649974aee0SMilanka Ringwald return AVDTP_STREAM_ENDPOINT_DOES_NOT_EXIST; 1365747ec646SMilanka Ringwald } 1366417b4996SMilanka Ringwald if (stream_endpoint->state >= AVDTP_STREAM_ENDPOINT_CONFIGURED){ 1367485c0a4cSMilanka Ringwald log_error("Stream endpoint seid %d in wrong state %d", local_seid, stream_endpoint->state); 1368417b4996SMilanka Ringwald return AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE; 1369417b4996SMilanka Ringwald } 1370a3ce0109SMatthias Ringwald 1371bdbc3ef6SMilanka Ringwald connection->active_stream_endpoint = (void*) stream_endpoint; 1372a3ce0109SMatthias Ringwald connection->configuration_state = AVDTP_CONFIGURATION_STATE_LOCAL_INITIATED; 1373747ec646SMilanka Ringwald 1374747ec646SMilanka Ringwald connection->initiator_transaction_label++; 137596dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 13765bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1377f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1378f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1379747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_SET_CONFIGURATION; 1380ffa6c160SMilanka Ringwald 1381ffa6c160SMilanka Ringwald // cache media codec information for SBC 1382ffa6c160SMilanka Ringwald stream_endpoint->media_codec_type = configuration.media_codec.media_codec_type; 1383ffa6c160SMilanka Ringwald if (configuration.media_codec.media_codec_type == AVDTP_CODEC_SBC){ 1384ffa6c160SMilanka Ringwald stream_endpoint->media_type = configuration.media_codec.media_type; 13856535961aSMatthias Ringwald (void)memcpy(stream_endpoint->media_codec_sbc_info, 13866535961aSMatthias Ringwald configuration.media_codec.media_codec_information, 4); 1387ffa6c160SMilanka Ringwald } 13889974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1389747ec646SMilanka Ringwald } 1390747ec646SMilanka Ringwald 1391cec76c5bSMilanka 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){ 13925ace758fSMilanka Ringwald avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid); 1393747ec646SMilanka Ringwald if (!connection){ 13949900b7faSMilanka Ringwald log_error("No connection for AVDTP cid 0x%02x found", avdtp_cid); 13959974aee0SMilanka Ringwald return AVDTP_CONNECTION_DOES_NOT_EXIST; 1396747ec646SMilanka Ringwald } 1397747ec646SMilanka Ringwald //TODO: if opened only app capabilities, enable reconfigure for not opened 13980e588213SMatthias Ringwald if ((connection->state != AVDTP_SIGNALING_CONNECTION_OPENED) || 1399c1ab6cc1SMatthias Ringwald (connection->initiator_connection_state != AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE)) { 14009974aee0SMilanka Ringwald return AVDTP_CONNECTION_IN_WRONG_STATE; 14019974aee0SMilanka Ringwald } 14029e42cfccSMilanka Ringwald 1403d8e15394SMilanka Ringwald avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid); 140478d08d09SMilanka Ringwald if (!stream_endpoint) { 14054ccacc40SMilanka Ringwald log_error("avdtp_reconfigure: no initiator stream endpoint for seid %d", local_seid); 14069974aee0SMilanka Ringwald return AVDTP_STREAM_ENDPOINT_DOES_NOT_EXIST; 140778d08d09SMilanka Ringwald } 140878d08d09SMilanka Ringwald 1409485c0a4cSMilanka Ringwald if (!is_avdtp_remote_seid_registered(stream_endpoint)){ 14108587e32cSMilanka Ringwald log_error("avdtp_reconfigure: no associated remote sep"); 14119974aee0SMilanka Ringwald return AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE; 141278d08d09SMilanka Ringwald } 1413485c0a4cSMilanka Ringwald 1414747ec646SMilanka Ringwald connection->initiator_transaction_label++; 141596dcd0f4SMatthias Ringwald connection->initiator_remote_seid = remote_seid; 14165bd73fa2SMatthias Ringwald connection->initiator_local_seid = local_seid; 1417f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration_bitmap = configured_services_bitmap; 1418f53d6fa7SMilanka Ringwald stream_endpoint->remote_configuration = configuration; 1419747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_W2_RECONFIGURE_STREAM_WITH_SEID; 14209974aee0SMilanka Ringwald return avdtp_request_can_send_now_initiator(connection, connection->l2cap_signaling_cid); 1421747ec646SMilanka Ringwald } 1422747ec646SMilanka Ringwald 14238e7044f9SMatthias Ringwald void avdtp_set_preferred_sampling_frequeny(avdtp_stream_endpoint_t * stream_endpoint, uint32_t sampling_frequency){ 14248e7044f9SMatthias Ringwald stream_endpoint->preferred_sampling_frequency = sampling_frequency; 14258e7044f9SMatthias Ringwald } 14268e7044f9SMatthias Ringwald 142778d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_channel_mode(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_channel_mode_bitmap){ 142878d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 142978d08d09SMilanka Ringwald uint8_t channel_mode_bitmap = (media_codec[0] & 0x0F) & remote_channel_mode_bitmap; 143078d08d09SMilanka Ringwald 143178d08d09SMilanka Ringwald uint8_t channel_mode = AVDTP_SBC_STEREO; 143278d08d09SMilanka Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 143378d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_JOINT_STEREO; 143478d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 143578d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_STEREO; 143678d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 143778d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_DUAL_CHANNEL; 143878d08d09SMilanka Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_MONO){ 143978d08d09SMilanka Ringwald channel_mode = AVDTP_SBC_MONO; 144078d08d09SMilanka Ringwald } 144178d08d09SMilanka Ringwald return channel_mode; 144278d08d09SMilanka Ringwald } 144378d08d09SMilanka Ringwald 144478d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_allocation_method(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_allocation_method_bitmap){ 144578d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 144678d08d09SMilanka Ringwald uint8_t allocation_method_bitmap = (media_codec[1] & 0x03) & remote_allocation_method_bitmap; 144778d08d09SMilanka Ringwald 144878d08d09SMilanka Ringwald uint8_t allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 144978d08d09SMilanka Ringwald if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS){ 145078d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_LOUDNESS; 145178d08d09SMilanka Ringwald } else if (allocation_method_bitmap & AVDTP_SBC_ALLOCATION_METHOD_SNR){ 145278d08d09SMilanka Ringwald allocation_method = AVDTP_SBC_ALLOCATION_METHOD_SNR; 145378d08d09SMilanka Ringwald } 145478d08d09SMilanka Ringwald return allocation_method; 145578d08d09SMilanka Ringwald } 145678d08d09SMilanka Ringwald 1457bd1ecb8aSMilanka Ringwald uint8_t avdtp_stream_endpoint_seid(avdtp_stream_endpoint_t * stream_endpoint){ 1458bd1ecb8aSMilanka Ringwald if (!stream_endpoint) return 0; 1459bd1ecb8aSMilanka Ringwald return stream_endpoint->sep.seid; 1460bd1ecb8aSMilanka Ringwald } 146178d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_subbands(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_subbands_bitmap){ 146267ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 146378d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 146478d08d09SMilanka Ringwald uint8_t subbands_bitmap = ((media_codec[1] >> 2) & 0x03) & remote_subbands_bitmap; 146578d08d09SMilanka Ringwald 146678d08d09SMilanka Ringwald uint8_t subbands = AVDTP_SBC_SUBBANDS_8; 146778d08d09SMilanka Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 146878d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_8; 146978d08d09SMilanka Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 147078d08d09SMilanka Ringwald subbands = AVDTP_SBC_SUBBANDS_4; 147178d08d09SMilanka Ringwald } 147278d08d09SMilanka Ringwald return subbands; 147378d08d09SMilanka Ringwald } 147478d08d09SMilanka Ringwald 147578d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_block_length(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_block_length_bitmap){ 147667ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 147778d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 147878d08d09SMilanka Ringwald uint8_t block_length_bitmap = (media_codec[1] >> 4) & remote_block_length_bitmap; 147978d08d09SMilanka Ringwald 148078d08d09SMilanka Ringwald uint8_t block_length = AVDTP_SBC_BLOCK_LENGTH_16; 148178d08d09SMilanka Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 148278d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_16; 148378d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 148478d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_12; 148578d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 148678d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_8; 148778d08d09SMilanka Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 148878d08d09SMilanka Ringwald block_length = AVDTP_SBC_BLOCK_LENGTH_4; 148978d08d09SMilanka Ringwald } 149078d08d09SMilanka Ringwald return block_length; 149178d08d09SMilanka Ringwald } 149278d08d09SMilanka Ringwald 149378d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_sampling_frequency(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_sampling_frequency_bitmap){ 149467ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 149578d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 14968e7044f9SMatthias Ringwald uint8_t supported_sampling_frequency_bitmap = (media_codec[0] >> 4) & remote_sampling_frequency_bitmap; 149778d08d09SMilanka Ringwald 14988e7044f9SMatthias Ringwald // use preferred sampling frequency if possible 14998e7044f9SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 48000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_48000)){ 15006ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 15018e7044f9SMatthias Ringwald } 15026ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 44100) && (supported_sampling_frequency_bitmap & AVDTP_SBC_44100)){ 15036ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 15046ed344c3SMatthias Ringwald } 15056ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 32000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_32000)){ 15066ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 15076ed344c3SMatthias Ringwald } 15086ed344c3SMatthias Ringwald if ((stream_endpoint->preferred_sampling_frequency == 16000) && (supported_sampling_frequency_bitmap & AVDTP_SBC_16000)){ 15096ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 15106ed344c3SMatthias Ringwald } 15116ed344c3SMatthias Ringwald 15128e7044f9SMatthias Ringwald // otherwise, use highest available 15136ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_48000){ 15146ed344c3SMatthias Ringwald return AVDTP_SBC_48000; 151578d08d09SMilanka Ringwald } 15166ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_44100){ 15176ed344c3SMatthias Ringwald return AVDTP_SBC_44100; 15186ed344c3SMatthias Ringwald } 15196ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_32000){ 15206ed344c3SMatthias Ringwald return AVDTP_SBC_32000; 15216ed344c3SMatthias Ringwald } 15226ed344c3SMatthias Ringwald if (supported_sampling_frequency_bitmap & AVDTP_SBC_16000){ 15236ed344c3SMatthias Ringwald return AVDTP_SBC_16000; 15246ed344c3SMatthias Ringwald } 15256ed344c3SMatthias Ringwald return AVDTP_SBC_44100; // some default 152678d08d09SMilanka Ringwald } 152778d08d09SMilanka Ringwald 152878d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_max_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_max_bitpool_value){ 152967ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 153078d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 153178d08d09SMilanka Ringwald return btstack_min(media_codec[3], remote_max_bitpool_value); 153278d08d09SMilanka Ringwald } 153378d08d09SMilanka Ringwald 153478d08d09SMilanka Ringwald uint8_t avdtp_choose_sbc_min_bitpool_value(avdtp_stream_endpoint_t * stream_endpoint, uint8_t remote_min_bitpool_value){ 153567ae582dSMilanka Ringwald if (!stream_endpoint) return 0; 153678d08d09SMilanka Ringwald uint8_t * media_codec = stream_endpoint->sep.capabilities.media_codec.media_codec_information; 153778d08d09SMilanka Ringwald return btstack_max(media_codec[2], remote_min_bitpool_value); 1538747ec646SMilanka Ringwald } 1539485c0a4cSMilanka Ringwald 1540485c0a4cSMilanka Ringwald uint8_t is_avdtp_remote_seid_registered(avdtp_stream_endpoint_t * stream_endpoint){ 1541485c0a4cSMilanka Ringwald if (!stream_endpoint) return 0; 1542485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid == 0) return 0; 1543485c0a4cSMilanka Ringwald if (stream_endpoint->remote_sep.seid > 0x3E) return 0; 1544485c0a4cSMilanka Ringwald return 1; 1545485c0a4cSMilanka Ringwald } 1546