18ef7100fSMilanka Ringwald /* 28ef7100fSMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH 38ef7100fSMilanka Ringwald * 48ef7100fSMilanka Ringwald * Redistribution and use in source and binary forms, with or without 58ef7100fSMilanka Ringwald * modification, are permitted provided that the following conditions 68ef7100fSMilanka Ringwald * are met: 78ef7100fSMilanka Ringwald * 88ef7100fSMilanka Ringwald * 1. Redistributions of source code must retain the above copyright 98ef7100fSMilanka Ringwald * notice, this list of conditions and the following disclaimer. 108ef7100fSMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright 118ef7100fSMilanka Ringwald * notice, this list of conditions and the following disclaimer in the 128ef7100fSMilanka Ringwald * documentation and/or other materials provided with the distribution. 138ef7100fSMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of 148ef7100fSMilanka Ringwald * contributors may be used to endorse or promote products derived 158ef7100fSMilanka Ringwald * from this software without specific prior written permission. 168ef7100fSMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for 178ef7100fSMilanka Ringwald * personal benefit and not for any commercial purpose or for 188ef7100fSMilanka Ringwald * monetary gain. 198ef7100fSMilanka Ringwald * 208ef7100fSMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 218ef7100fSMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 228ef7100fSMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 258ef7100fSMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 268ef7100fSMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 278ef7100fSMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 288ef7100fSMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 298ef7100fSMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 308ef7100fSMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 318ef7100fSMilanka Ringwald * SUCH DAMAGE. 328ef7100fSMilanka Ringwald * 338ef7100fSMilanka Ringwald * Please inquire about commercial licensing options at 348ef7100fSMilanka Ringwald * [email protected] 358ef7100fSMilanka Ringwald * 368ef7100fSMilanka Ringwald */ 378ef7100fSMilanka Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avdtp_util.c" 39ab2c6ae4SMatthias Ringwald 408ef7100fSMilanka Ringwald #include <stdint.h> 418ef7100fSMilanka Ringwald #include <string.h> 428ef7100fSMilanka Ringwald 437c76cd61SMatthias Ringwald #include "classic/avdtp.h" 447c76cd61SMatthias Ringwald #include "classic/avdtp_util.h" 457c76cd61SMatthias Ringwald 467c76cd61SMatthias Ringwald #include "btstack_debug.h" 477c76cd61SMatthias Ringwald #include "btstack_util.h" 487c76cd61SMatthias Ringwald #include "l2cap.h" 498ef7100fSMilanka Ringwald 50f9a5036aSMatthias Ringwald /* 51f9a5036aSMatthias Ringwald 52f9a5036aSMatthias Ringwald List of AVDTP_SUBEVENTs sorted by packet handler 53f9a5036aSMatthias Ringwald 54f9a5036aSMatthias Ringwald 55f9a5036aSMatthias Ringwald Sink + Source: 56f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED 57f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED 58f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_SEP_FOUND 59f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_ACCEPT 60f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_REJECT 61f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT 62f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY 63f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY 64f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY 65f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY 66f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY 67f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY 68f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY 69f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY 70f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY 71f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE 72f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE 73f9a5036aSMatthias Ringwald 74f9a5036aSMatthias Ringwald Source: 75f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT 76f9a5036aSMatthias Ringwald 77f9a5036aSMatthias Ringwald Sink or Source based on SEP Type: 78f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED 79f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED 80f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW 81f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION 82f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION 83f9a5036aSMatthias Ringwald 84f9a5036aSMatthias Ringwald */ 85f9a5036aSMatthias Ringwald 86ee230fc4SMilanka Ringwald static const char * avdtp_si_name[] = { 87ee230fc4SMilanka Ringwald "ERROR", 88ee230fc4SMilanka Ringwald "AVDTP_SI_DISCOVER", 89ee230fc4SMilanka Ringwald "AVDTP_SI_GET_CAPABILITIES", 90ee230fc4SMilanka Ringwald "AVDTP_SI_SET_CONFIGURATION", 91ee230fc4SMilanka Ringwald "AVDTP_SI_GET_CONFIGURATION", 92ee230fc4SMilanka Ringwald "AVDTP_SI_RECONFIGURE", 93ee230fc4SMilanka Ringwald "AVDTP_SI_OPEN", 94ee230fc4SMilanka Ringwald "AVDTP_SI_START", 95ee230fc4SMilanka Ringwald "AVDTP_SI_CLOSE", 96ee230fc4SMilanka Ringwald "AVDTP_SI_SUSPEND", 97ee230fc4SMilanka Ringwald "AVDTP_SI_ABORT", 98ee230fc4SMilanka Ringwald "AVDTP_SI_SECURITY_CONTROL", 99ee230fc4SMilanka Ringwald "AVDTP_SI_GET_ALL_CAPABILITIES", 100ee230fc4SMilanka Ringwald "AVDTP_SI_DELAY_REPORT" 101ee230fc4SMilanka Ringwald }; 102ee230fc4SMilanka Ringwald const char * avdtp_si2str(uint16_t index){ 103c1e2cdaaSaroldxd if ((index <= 0) || (index >= sizeof(avdtp_si_name)/sizeof(avdtp_si_name[0]) )) return avdtp_si_name[0]; 104ee230fc4SMilanka Ringwald return avdtp_si_name[index]; 105ee230fc4SMilanka Ringwald } 106ee230fc4SMilanka Ringwald 107485c0a4cSMilanka Ringwald void avdtp_reset_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ 108485c0a4cSMilanka Ringwald stream_endpoint->media_con_handle = 0; 109485c0a4cSMilanka Ringwald stream_endpoint->l2cap_media_cid = 0; 110485c0a4cSMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0; 111485c0a4cSMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0; 112485c0a4cSMilanka Ringwald 113747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 114747ec646SMilanka Ringwald stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE; 115747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE; 116485c0a4cSMilanka Ringwald 117b3b67de4SMilanka Ringwald stream_endpoint->connection = NULL; 118b3b67de4SMilanka Ringwald 119747ec646SMilanka Ringwald stream_endpoint->sep.in_use = 0; 120485c0a4cSMilanka Ringwald memset(&stream_endpoint->remote_sep, 0, sizeof(avdtp_sep_t)); 121485c0a4cSMilanka Ringwald 122485c0a4cSMilanka Ringwald stream_endpoint->remote_capabilities_bitmap = 0; 123b3b67de4SMilanka Ringwald memset(&stream_endpoint->remote_capabilities, 0, sizeof(avdtp_capabilities_t)); 124485c0a4cSMilanka Ringwald stream_endpoint->remote_configuration_bitmap = 0; 125b3b67de4SMilanka Ringwald memset(&stream_endpoint->remote_configuration, 0, sizeof(avdtp_capabilities_t)); 126b3b67de4SMilanka Ringwald 12782767773SMatthias Ringwald // temporary SBC config used by A2DP Source 128ec9b5b0fSMatthias Ringwald memset(stream_endpoint->media_codec_info, 0, 8); 129485c0a4cSMilanka Ringwald 130485c0a4cSMilanka Ringwald stream_endpoint->media_disconnect = 0; 131485c0a4cSMilanka Ringwald stream_endpoint->media_connect = 0; 132485c0a4cSMilanka Ringwald stream_endpoint->start_stream = 0; 133fa4419dbSMilanka Ringwald stream_endpoint->close_stream = 0; 134d0676819SMatthias Ringwald stream_endpoint->request_can_send_now = false; 135485c0a4cSMilanka Ringwald stream_endpoint->abort_stream = 0; 136485c0a4cSMilanka Ringwald stream_endpoint->suspend_stream = 0; 137485c0a4cSMilanka Ringwald stream_endpoint->sequence_number = 0; 138747ec646SMilanka Ringwald } 139747ec646SMilanka Ringwald 1408ef7100fSMilanka Ringwald int get_bit16(uint16_t bitmap, int position){ 1418ef7100fSMilanka Ringwald return (bitmap >> position) & 1; 1428ef7100fSMilanka Ringwald } 1438ef7100fSMilanka Ringwald 144ea6072afSMilanka Ringwald uint16_t store_bit16(uint16_t bitmap, int position, uint8_t value){ 1458ef7100fSMilanka Ringwald if (value){ 1468ef7100fSMilanka Ringwald bitmap |= 1 << position; 1478ef7100fSMilanka Ringwald } else { 1488ef7100fSMilanka Ringwald bitmap &= ~ (1 << position); 1498ef7100fSMilanka Ringwald } 1508ef7100fSMilanka Ringwald return bitmap; 1518ef7100fSMilanka Ringwald } 1528ef7100fSMilanka Ringwald 153335dba6aSMatthias Ringwald avdtp_message_type_t avdtp_get_signaling_message_type(uint8_t * packet){ 154c1c40ea1SMatthias Ringwald return (avdtp_message_type_t) (packet[0] & 0x03); 155c1c40ea1SMatthias Ringwald } 156c1c40ea1SMatthias Ringwald 1573d79ed3bSMatthias Ringwald // returns 0 if header incomplete 1588ef7100fSMilanka Ringwald int avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header, uint8_t * packet, uint16_t size){ 1598ef7100fSMilanka Ringwald int pos = 0; 1603d79ed3bSMatthias Ringwald if (size < 2) return 0; 1618ef7100fSMilanka Ringwald signaling_header->transaction_label = packet[pos] >> 4; 1628ef7100fSMilanka Ringwald signaling_header->packet_type = (avdtp_packet_type_t)((packet[pos] >> 2) & 0x03); 1638ef7100fSMilanka Ringwald signaling_header->message_type = (avdtp_message_type_t) (packet[pos] & 0x03); 1648ef7100fSMilanka Ringwald pos++; 1658ef7100fSMilanka Ringwald memset(signaling_header->command, 0, sizeof(signaling_header->command)); 1668ef7100fSMilanka Ringwald switch (signaling_header->packet_type){ 1678ef7100fSMilanka Ringwald case AVDTP_SINGLE_PACKET: 1688ef7100fSMilanka Ringwald signaling_header->num_packets = 0; 1698ef7100fSMilanka Ringwald signaling_header->offset = 0; 1708ef7100fSMilanka Ringwald signaling_header->size = 0; 1718ef7100fSMilanka Ringwald break; 1728ef7100fSMilanka Ringwald case AVDTP_END_PACKET: 1738ef7100fSMilanka Ringwald signaling_header->num_packets = 0; 1748ef7100fSMilanka Ringwald break; 1758ef7100fSMilanka Ringwald case AVDTP_START_PACKET: 1768ef7100fSMilanka Ringwald signaling_header->num_packets = packet[pos++]; 1773d79ed3bSMatthias Ringwald if (pos < 3) return 0; 1788ef7100fSMilanka Ringwald signaling_header->size = 0; 1798ef7100fSMilanka Ringwald signaling_header->offset = 0; 1808ef7100fSMilanka Ringwald break; 1818ef7100fSMilanka Ringwald case AVDTP_CONTINUE_PACKET: 1828ef7100fSMilanka Ringwald if (signaling_header->num_packets <= 0) { 1838587e32cSMilanka Ringwald log_info(" ERROR: wrong num fragmented packets\n"); 1848ef7100fSMilanka Ringwald break; 1858ef7100fSMilanka Ringwald } 1868ef7100fSMilanka Ringwald signaling_header->num_packets--; 1878ef7100fSMilanka Ringwald break; 1887bbeb3adSMilanka Ringwald default: 1897bbeb3adSMilanka Ringwald btstack_assert(false); 1907bbeb3adSMilanka Ringwald break; 1918ef7100fSMilanka Ringwald } 192b0920f25SMilanka Ringwald signaling_header->signal_identifier = (avdtp_signal_identifier_t)(packet[pos++] & 0x3f); 1938ef7100fSMilanka Ringwald return pos; 1948ef7100fSMilanka Ringwald } 1958ef7100fSMilanka Ringwald 19650d5c6caSMatthias Ringwald static bool avdtp_is_basic_capability(int service_category){ 19750d5c6caSMatthias Ringwald return (AVDTP_MEDIA_TRANSPORT <= service_category) && (service_category <= AVDTP_MEDIA_CODEC); 19850d5c6caSMatthias Ringwald } 19950d5c6caSMatthias Ringwald 20050d5c6caSMatthias Ringwald int avdtp_pack_service_capabilities(uint8_t *buffer, int size, avdtp_capabilities_t caps, avdtp_service_category_t category) { 2018ef7100fSMilanka Ringwald UNUSED(size); 2028ef7100fSMilanka Ringwald 2038ef7100fSMilanka Ringwald int i; 2048ef7100fSMilanka Ringwald // pos = 0 reserved for length 2058ef7100fSMilanka Ringwald int pos = 1; 2068ef7100fSMilanka Ringwald switch(category){ 2078ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 2088ef7100fSMilanka Ringwald case AVDTP_REPORTING: 2098ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 2108ef7100fSMilanka Ringwald break; 2118ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 2128ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.recovery_type; // 0x01=RFC2733 2138ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.maximum_recovery_window_size; 2148ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.maximum_number_media_packets; 2158ef7100fSMilanka Ringwald break; 2168ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 2178ef7100fSMilanka Ringwald buffer[pos++] = caps.content_protection.cp_type_value_len + 2; 2188ef7100fSMilanka Ringwald big_endian_store_16(buffer, pos, caps.content_protection.cp_type); 2198ef7100fSMilanka Ringwald pos += 2; 2206535961aSMatthias Ringwald (void)memcpy(buffer + pos, caps.content_protection.cp_type_value, 2216535961aSMatthias Ringwald caps.content_protection.cp_type_value_len); 22274b2411bSMilanka Ringwald pos += caps.content_protection.cp_type_value_len; 2238ef7100fSMilanka Ringwald break; 2248ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 2258ef7100fSMilanka Ringwald buffer[pos++] = (caps.header_compression.back_ch << 7) | (caps.header_compression.media << 6) | (caps.header_compression.recovery << 5); 2268ef7100fSMilanka Ringwald break; 2278ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 2288ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.fragmentation << 7; 2298ef7100fSMilanka Ringwald for (i=0; i<caps.multiplexing_mode.transport_identifiers_num; i++){ 2308ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.transport_session_identifiers[i] << 7; 2318ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.tcid[i] << 7; 2328ef7100fSMilanka Ringwald // media, reporting. recovery 2338ef7100fSMilanka Ringwald } 2348ef7100fSMilanka Ringwald break; 2358ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 2368ef7100fSMilanka Ringwald buffer[pos++] = ((uint8_t)caps.media_codec.media_type) << 4; 2378ef7100fSMilanka Ringwald buffer[pos++] = (uint8_t)caps.media_codec.media_codec_type; 2388ef7100fSMilanka Ringwald for (i = 0; i<caps.media_codec.media_codec_information_len; i++){ 2398ef7100fSMilanka Ringwald buffer[pos++] = caps.media_codec.media_codec_information[i]; 2408ef7100fSMilanka Ringwald } 2418ef7100fSMilanka Ringwald break; 2428ef7100fSMilanka Ringwald default: 2438ef7100fSMilanka Ringwald break; 2448ef7100fSMilanka Ringwald } 2458ef7100fSMilanka Ringwald buffer[0] = pos - 1; // length 2468ef7100fSMilanka Ringwald return pos; 2478ef7100fSMilanka Ringwald } 2488ef7100fSMilanka Ringwald 249390aa582SMatthias Ringwald static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * connection, avdtp_signal_identifier_t signal_identifier, avdtp_service_category_t category, uint8_t cap_len){ 2508ef7100fSMilanka Ringwald connection->error_code = 0; 2518ef7100fSMilanka Ringwald 25276827215SMatthias Ringwald if ((category == AVDTP_SERVICE_CATEGORY_INVALID_0) || (category > AVDTP_DELAY_REPORTING)){ 2538587e32cSMilanka Ringwald log_info(" ERROR: BAD SERVICE CATEGORY %d\n", category); 2548ef7100fSMilanka Ringwald connection->reject_service_category = category; 2555b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_SERV_CATEGORY; 2568ef7100fSMilanka Ringwald return 1; 2578ef7100fSMilanka Ringwald } 2588ef7100fSMilanka Ringwald 259390aa582SMatthias Ringwald if (signal_identifier == AVDTP_SI_RECONFIGURE){ 2600e588213SMatthias Ringwald if ( (category != AVDTP_CONTENT_PROTECTION) && (category != AVDTP_MEDIA_CODEC)){ 2618587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, INVALID_CAPABILITIES\n"); 2628ef7100fSMilanka Ringwald connection->reject_service_category = category; 2635b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_INVALID_CAPABILITIES; 2648ef7100fSMilanka Ringwald return 1; 2658ef7100fSMilanka Ringwald } 2668ef7100fSMilanka Ringwald } 2678ef7100fSMilanka Ringwald 2688ef7100fSMilanka Ringwald switch(category){ 2698ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 2708ef7100fSMilanka Ringwald if (cap_len != 0){ 2718587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n"); 2728ef7100fSMilanka Ringwald connection->reject_service_category = category; 2735b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_MEDIA_TRANSPORT_FORMAT; 2748ef7100fSMilanka Ringwald return 1; 2758ef7100fSMilanka Ringwald } 2768ef7100fSMilanka Ringwald break; 2778ef7100fSMilanka Ringwald case AVDTP_REPORTING: 2788ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 2798ef7100fSMilanka Ringwald if (cap_len != 0){ 2808587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_LENGTH\n"); 2818ef7100fSMilanka Ringwald connection->reject_service_category = category; 2825b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_LENGTH; 2838ef7100fSMilanka Ringwald return 1; 2848ef7100fSMilanka Ringwald } 2858ef7100fSMilanka Ringwald break; 2868ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 287f6f3c903SMilanka Ringwald if (cap_len != 3){ 2888587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n"); 2898ef7100fSMilanka Ringwald connection->reject_service_category = category; 2905b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_RECOVERY_FORMAT; 2918ef7100fSMilanka Ringwald return 1; 2928ef7100fSMilanka Ringwald } 2938ef7100fSMilanka Ringwald break; 2948ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 2958ef7100fSMilanka Ringwald if (cap_len < 2){ 2968587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_CP_FORMAT\n"); 2978ef7100fSMilanka Ringwald connection->reject_service_category = category; 2985b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_CP_FORMAT; 2998ef7100fSMilanka Ringwald return 1; 3008ef7100fSMilanka Ringwald } 3018ef7100fSMilanka Ringwald break; 3028ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 303f6f3c903SMilanka Ringwald // TODO: find error code for bad header compression 304f6f3c903SMilanka Ringwald if (cap_len != 1){ 305f6f3c903SMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_HEADER_COMPRESSION\n"); 306f6f3c903SMilanka Ringwald connection->reject_service_category = category; 3075b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_RECOVERY_FORMAT; 308f6f3c903SMilanka Ringwald return 1; 309f6f3c903SMilanka Ringwald } 3108ef7100fSMilanka Ringwald break; 3118ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 3128ef7100fSMilanka Ringwald break; 3138ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 3148ef7100fSMilanka Ringwald break; 3158ef7100fSMilanka Ringwald default: 3168ef7100fSMilanka Ringwald break; 3178ef7100fSMilanka Ringwald } 3188ef7100fSMilanka Ringwald return 0; 3198ef7100fSMilanka Ringwald } 3208ef7100fSMilanka Ringwald 321afc28e0aSMatthias Ringwald uint16_t avdtp_unpack_service_capabilities(avdtp_connection_t * connection, avdtp_signal_identifier_t signal_identifier, avdtp_capabilities_t * caps, uint8_t * packet, uint16_t size){ 322f6f3c903SMilanka Ringwald 323f6f3c903SMilanka Ringwald int i; 3248ef7100fSMilanka Ringwald 3258ef7100fSMilanka Ringwald uint16_t registered_service_categories = 0; 326f6f3c903SMilanka Ringwald uint16_t to_process = size; 327f6f3c903SMilanka Ringwald 328f6f3c903SMilanka Ringwald while (to_process >= 2){ 329f6f3c903SMilanka Ringwald 330f6f3c903SMilanka Ringwald avdtp_service_category_t category = (avdtp_service_category_t) packet[0]; 331f6f3c903SMilanka Ringwald uint8_t cap_len = packet[1]; 332f6f3c903SMilanka Ringwald packet += 2; 333f6f3c903SMilanka Ringwald to_process -= 2; 334f6f3c903SMilanka Ringwald 335f6f3c903SMilanka Ringwald if (cap_len > to_process){ 3368ef7100fSMilanka Ringwald connection->reject_service_category = category; 3375b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_LENGTH; 3388ef7100fSMilanka Ringwald return 0; 3398ef7100fSMilanka Ringwald } 34067ae582dSMilanka Ringwald 341afc28e0aSMatthias Ringwald if (avdtp_unpack_service_capabilities_has_errors(connection, signal_identifier, category, cap_len)) return 0; 34267ae582dSMilanka Ringwald 343f6f3c903SMilanka Ringwald int category_valid = 1; 34467ae582dSMilanka Ringwald 345f6f3c903SMilanka Ringwald uint8_t * data = packet; 346f6f3c903SMilanka Ringwald uint16_t pos = 0; 347f6f3c903SMilanka Ringwald 3488ef7100fSMilanka Ringwald switch(category){ 3498ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 350f6f3c903SMilanka Ringwald caps->recovery.recovery_type = data[pos++]; 351f6f3c903SMilanka Ringwald caps->recovery.maximum_recovery_window_size = data[pos++]; 352f6f3c903SMilanka Ringwald caps->recovery.maximum_number_media_packets = data[pos++]; 3538ef7100fSMilanka Ringwald break; 3548ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 355f6f3c903SMilanka Ringwald caps->content_protection.cp_type = big_endian_read_16(data, 0); 3568ef7100fSMilanka Ringwald caps->content_protection.cp_type_value_len = cap_len - 2; 3578ef7100fSMilanka Ringwald // connection->reject_service_category = category; 3588ef7100fSMilanka Ringwald // connection->error_code = UNSUPPORTED_CONFIGURATION; 3598ef7100fSMilanka Ringwald // support for content protection goes here 3608ef7100fSMilanka Ringwald break; 3618ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 362f6f3c903SMilanka Ringwald caps->header_compression.back_ch = (data[0] >> 7) & 1; 363f6f3c903SMilanka Ringwald caps->header_compression.media = (data[0] >> 6) & 1; 364f6f3c903SMilanka Ringwald caps->header_compression.recovery = (data[0] >> 5) & 1; 3658ef7100fSMilanka Ringwald break; 3668ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 367f6f3c903SMilanka Ringwald caps->multiplexing_mode.fragmentation = (data[pos++] >> 7) & 1; 3688ef7100fSMilanka Ringwald // read [tsid, tcid] for media, reporting. recovery respectively 3698ef7100fSMilanka Ringwald caps->multiplexing_mode.transport_identifiers_num = 3; 3708ef7100fSMilanka Ringwald for (i=0; i<caps->multiplexing_mode.transport_identifiers_num; i++){ 371f6f3c903SMilanka Ringwald caps->multiplexing_mode.transport_session_identifiers[i] = (data[pos++] >> 7) & 1; 372f6f3c903SMilanka Ringwald caps->multiplexing_mode.tcid[i] = (data[pos++] >> 7) & 1; 3738ef7100fSMilanka Ringwald } 3748ef7100fSMilanka Ringwald break; 3758ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 376f6f3c903SMilanka Ringwald caps->media_codec.media_type = (avdtp_media_type_t)(data[pos++] >> 4); 377f6f3c903SMilanka Ringwald caps->media_codec.media_codec_type = (avdtp_media_codec_type_t)(data[pos++]); 3788ef7100fSMilanka Ringwald caps->media_codec.media_codec_information_len = cap_len - 2; 3794c7a1d3aSMatthias Ringwald caps->media_codec.media_codec_information = &data[pos++]; 3808ef7100fSMilanka Ringwald break; 3818ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 3828ef7100fSMilanka Ringwald case AVDTP_REPORTING: 3838ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 3848ef7100fSMilanka Ringwald break; 3858ef7100fSMilanka Ringwald default: 386f6f3c903SMilanka Ringwald category_valid = 0; 3878ef7100fSMilanka Ringwald break; 3888ef7100fSMilanka Ringwald } 3898ef7100fSMilanka Ringwald 390f6f3c903SMilanka Ringwald if (category_valid) { 3918ef7100fSMilanka Ringwald registered_service_categories = store_bit16(registered_service_categories, category, 1); 3928ef7100fSMilanka Ringwald } 393f6f3c903SMilanka Ringwald 394f6f3c903SMilanka Ringwald packet += cap_len; 395f6f3c903SMilanka Ringwald to_process -= cap_len; 39667ae582dSMilanka Ringwald } 397f6f3c903SMilanka Ringwald 3988ef7100fSMilanka Ringwald return registered_service_categories; 3998ef7100fSMilanka Ringwald } 4008ef7100fSMilanka Ringwald 40150d5c6caSMatthias Ringwald void avdtp_prepare_capabilities(avdtp_signaling_packet_t * signaling_packet, uint8_t transaction_label, uint16_t service_categories, avdtp_capabilities_t capabilities, uint8_t identifier){ 4028ef7100fSMilanka Ringwald if (signaling_packet->offset) return; 40350d5c6caSMatthias Ringwald bool basic_capabilities_only = false; 4048ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_RESPONSE_ACCEPT_MSG; 4058ef7100fSMilanka Ringwald int i; 406747ec646SMilanka Ringwald 407747ec646SMilanka Ringwald signaling_packet->size = 0; 408747ec646SMilanka Ringwald memset(signaling_packet->command, 0 , sizeof(signaling_packet->command)); 409747ec646SMilanka Ringwald 4108ef7100fSMilanka Ringwald switch (identifier) { 4118ef7100fSMilanka Ringwald case AVDTP_SI_GET_CAPABILITIES: 41250d5c6caSMatthias Ringwald basic_capabilities_only = true; 4138ef7100fSMilanka Ringwald break; 4148ef7100fSMilanka Ringwald case AVDTP_SI_GET_ALL_CAPABILITIES: 4158ef7100fSMilanka Ringwald break; 4168ef7100fSMilanka Ringwald case AVDTP_SI_SET_CONFIGURATION: 417747ec646SMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->acp_seid << 2; 4188ef7100fSMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->int_seid << 2; 4198ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_CMD_MSG; 4208ef7100fSMilanka Ringwald break; 4218ef7100fSMilanka Ringwald case AVDTP_SI_RECONFIGURE: 422747ec646SMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->acp_seid << 2; 4238ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_CMD_MSG; 4248ef7100fSMilanka Ringwald break; 4258ef7100fSMilanka Ringwald default: 4268ef7100fSMilanka Ringwald log_error("avdtp_prepare_capabilities wrong identifier %d", identifier); 4278ef7100fSMilanka Ringwald break; 4288ef7100fSMilanka Ringwald } 4298ef7100fSMilanka Ringwald 43050d5c6caSMatthias Ringwald for (i = AVDTP_MEDIA_TRANSPORT; i <= AVDTP_DELAY_REPORTING; i++){ 43150d5c6caSMatthias Ringwald int registered_category = get_bit16(service_categories, i); 4322bb3471fSMilanka Ringwald if (!registered_category && (identifier == AVDTP_SI_SET_CONFIGURATION)){ 433747ec646SMilanka Ringwald // TODO: introduce bitmap of mandatory categories 43450d5c6caSMatthias Ringwald if (i == AVDTP_MEDIA_TRANSPORT){ 43550d5c6caSMatthias Ringwald registered_category = true; 436747ec646SMilanka Ringwald } 437747ec646SMilanka Ringwald } 43850d5c6caSMatthias Ringwald // AVDTP_SI_GET_CAPABILITIES reports only basic capabilities (i.e., it skips non-basic categories) 43950d5c6caSMatthias Ringwald if (basic_capabilities_only && !avdtp_is_basic_capability(i)){ 44050d5c6caSMatthias Ringwald registered_category = false; 44150d5c6caSMatthias Ringwald } 44250d5c6caSMatthias Ringwald 443747ec646SMilanka Ringwald if (registered_category){ 4448ef7100fSMilanka Ringwald // service category 4458ef7100fSMilanka Ringwald signaling_packet->command[signaling_packet->size++] = i; 44650d5c6caSMatthias Ringwald signaling_packet->size += avdtp_pack_service_capabilities(signaling_packet->command + signaling_packet->size, 44750d5c6caSMatthias Ringwald sizeof(signaling_packet->command) - signaling_packet->size, capabilities, (avdtp_service_category_t) i); 4488ef7100fSMilanka Ringwald } 4498ef7100fSMilanka Ringwald } 450b0920f25SMilanka Ringwald signaling_packet->signal_identifier = (avdtp_signal_identifier_t)identifier; 4518ef7100fSMilanka Ringwald signaling_packet->transaction_label = transaction_label; 4528ef7100fSMilanka Ringwald } 4538ef7100fSMilanka Ringwald 4548ef7100fSMilanka Ringwald int avdtp_signaling_create_fragment(uint16_t cid, avdtp_signaling_packet_t * signaling_packet, uint8_t * out_buffer) { 4558ef7100fSMilanka Ringwald int mtu = l2cap_get_remote_mtu_for_local_cid(cid); 4568ef7100fSMilanka Ringwald int data_len = 0; 4578ef7100fSMilanka Ringwald 4588ef7100fSMilanka Ringwald uint16_t offset = signaling_packet->offset; 4598ef7100fSMilanka Ringwald uint16_t pos = 1; 4608ef7100fSMilanka Ringwald 4618ef7100fSMilanka Ringwald if (offset == 0){ 462c1ab6cc1SMatthias Ringwald if (signaling_packet->size <= (mtu - 2)){ 4638ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_SINGLE_PACKET; 4648ef7100fSMilanka Ringwald out_buffer[pos++] = signaling_packet->signal_identifier; 4658ef7100fSMilanka Ringwald data_len = signaling_packet->size; 4668ef7100fSMilanka Ringwald } else { 4678ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_START_PACKET; 4688ef7100fSMilanka Ringwald out_buffer[pos++] = (mtu + signaling_packet->size)/ (mtu-1); 4698ef7100fSMilanka Ringwald out_buffer[pos++] = signaling_packet->signal_identifier; 4708ef7100fSMilanka Ringwald data_len = mtu - 3; 4718ef7100fSMilanka Ringwald signaling_packet->offset = data_len; 4728ef7100fSMilanka Ringwald } 4738ef7100fSMilanka Ringwald } else { 4748ef7100fSMilanka Ringwald int remaining_bytes = signaling_packet->size - offset; 475c1ab6cc1SMatthias Ringwald if (remaining_bytes <= (mtu - 1)){ 4768ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_END_PACKET; 4778ef7100fSMilanka Ringwald data_len = remaining_bytes; 4788ef7100fSMilanka Ringwald signaling_packet->offset = 0; 4798ef7100fSMilanka Ringwald } else{ 4808ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_CONTINUE_PACKET; 4818ef7100fSMilanka Ringwald data_len = mtu - 1; 4828ef7100fSMilanka Ringwald signaling_packet->offset += data_len; 4838ef7100fSMilanka Ringwald } 4848ef7100fSMilanka Ringwald } 4858ef7100fSMilanka Ringwald out_buffer[0] = avdtp_header(signaling_packet->transaction_label, signaling_packet->packet_type, signaling_packet->message_type); 4866535961aSMatthias Ringwald (void)memcpy(out_buffer + pos, signaling_packet->command + offset, 4876535961aSMatthias Ringwald data_len); 4888ef7100fSMilanka Ringwald pos += data_len; 4898ef7100fSMilanka Ringwald return pos; 4908ef7100fSMilanka Ringwald } 4918ef7100fSMilanka Ringwald 4928ef7100fSMilanka Ringwald 493146fc0fbSMilanka Ringwald void avdtp_signaling_emit_connection_established(uint16_t avdtp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status) { 494146fc0fbSMilanka Ringwald uint8_t event[14]; 4958ef7100fSMilanka Ringwald int pos = 0; 4968ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 4978ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 4988ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED; 499f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5008ef7100fSMilanka Ringwald pos += 2; 5018ef7100fSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 5028ef7100fSMilanka Ringwald pos += 6; 503146fc0fbSMilanka Ringwald little_endian_store_16(event, pos, con_handle); 504146fc0fbSMilanka Ringwald pos += 2; 5058ef7100fSMilanka Ringwald event[pos++] = status; 506c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5078ef7100fSMilanka Ringwald } 5088ef7100fSMilanka Ringwald 509c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_connection_released(uint16_t avdtp_cid) { 51034b22aacSMilanka Ringwald uint8_t event[5]; 51134b22aacSMilanka Ringwald int pos = 0; 51234b22aacSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 51334b22aacSMilanka Ringwald event[pos++] = sizeof(event) - 2; 51434b22aacSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED; 51534b22aacSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 51634b22aacSMilanka Ringwald pos += 2; 517c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 51834b22aacSMilanka Ringwald } 51934b22aacSMilanka Ringwald 520c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_sep(uint16_t avdtp_cid, avdtp_sep_t sep) { 5218ef7100fSMilanka Ringwald uint8_t event[9]; 5228ef7100fSMilanka Ringwald int pos = 0; 5238ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5248ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5258ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_FOUND; 526f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5278ef7100fSMilanka Ringwald pos += 2; 5288ef7100fSMilanka Ringwald event[pos++] = sep.seid; 5298ef7100fSMilanka Ringwald event[pos++] = sep.in_use; 5308ef7100fSMilanka Ringwald event[pos++] = sep.media_type; 5318ef7100fSMilanka Ringwald event[pos++] = sep.type; 532c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5338ef7100fSMilanka Ringwald } 5348ef7100fSMilanka Ringwald 535c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_sep_done(uint16_t avdtp_cid) { 536485c0a4cSMilanka Ringwald uint8_t event[5]; 537485c0a4cSMilanka Ringwald int pos = 0; 538485c0a4cSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 539485c0a4cSMilanka Ringwald event[pos++] = sizeof(event) - 2; 540485c0a4cSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE; 541485c0a4cSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 542485c0a4cSMilanka Ringwald pos += 2; 543c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 544485c0a4cSMilanka Ringwald } 545485c0a4cSMilanka Ringwald 546c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_accept(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 54763274943SMilanka Ringwald uint8_t event[8]; 5488ef7100fSMilanka Ringwald int pos = 0; 5498ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5508ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5518ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT; 552f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5538ef7100fSMilanka Ringwald pos += 2; 5544ccacc40SMilanka Ringwald event[pos++] = local_seid; 55563274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 5568ef7100fSMilanka Ringwald event[pos++] = identifier; 557c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5588ef7100fSMilanka Ringwald } 5598ef7100fSMilanka Ringwald 56046b99c89SMatthias Ringwald void avdtp_signaling_emit_accept_for_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator){ 56146b99c89SMatthias Ringwald uint8_t event[8]; 56246b99c89SMatthias Ringwald int pos = 0; 56346b99c89SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 56446b99c89SMatthias Ringwald event[pos++] = sizeof(event) - 2; 56546b99c89SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT; 56646b99c89SMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 56746b99c89SMatthias Ringwald pos += 2; 56846b99c89SMatthias Ringwald event[pos++] = local_seid; 56946b99c89SMatthias Ringwald event[pos++] = is_initiator ? 1 : 0; 57046b99c89SMatthias Ringwald event[pos++] = identifier; 57146b99c89SMatthias Ringwald 57246b99c89SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 57346b99c89SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 57446b99c89SMatthias Ringwald } 57546b99c89SMatthias Ringwald 576c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_reject(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 57763274943SMilanka Ringwald uint8_t event[8]; 5788ef7100fSMilanka Ringwald int pos = 0; 5798ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5808ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5818ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_REJECT; 582f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5838ef7100fSMilanka Ringwald pos += 2; 5844ccacc40SMilanka Ringwald event[pos++] = local_seid; 58563274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 5868ef7100fSMilanka Ringwald event[pos++] = identifier; 587c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5888ef7100fSMilanka Ringwald } 5898ef7100fSMilanka Ringwald 590c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_general_reject(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 59163274943SMilanka Ringwald uint8_t event[8]; 5928ef7100fSMilanka Ringwald int pos = 0; 5938ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5948ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5958ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT; 596f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5978ef7100fSMilanka Ringwald pos += 2; 5984ccacc40SMilanka Ringwald event[pos++] = local_seid; 59963274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 6008ef7100fSMilanka Ringwald event[pos++] = identifier; 601c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6028ef7100fSMilanka Ringwald } 6038ef7100fSMilanka Ringwald 6044b7d40bbSMatthias Ringwald static inline void 6051159d239SMatthias Ringwald avdtp_signaling_emit_capability(uint8_t capability_subevent_id, uint16_t avdtp_cid, uint8_t remote_seid) { 6061159d239SMatthias Ringwald uint8_t event[6]; 6074b7d40bbSMatthias Ringwald int pos = 0; 6084b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6094b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 6104b7d40bbSMatthias Ringwald event[pos++] = capability_subevent_id; 6114b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 6124b7d40bbSMatthias Ringwald pos += 2; 6134b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 6144b7d40bbSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6154b7d40bbSMatthias Ringwald } 6164b7d40bbSMatthias Ringwald 6171159d239SMatthias Ringwald static void avdtp_signaling_emit_media_codec_sbc_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) { 6185ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 6191159d239SMatthias Ringwald uint8_t event[14]; 6208ef7100fSMilanka Ringwald int pos = 0; 6218ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6228ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 6238ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY; 624f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 6258ef7100fSMilanka Ringwald pos += 2; 6264ccacc40SMilanka Ringwald event[pos++] = remote_seid; 6278ef7100fSMilanka Ringwald event[pos++] = media_codec.media_type; 6285ce3497fSMatthias Ringwald event[pos++] = media_codec_information[0] >> 4; 6295ce3497fSMatthias Ringwald event[pos++] = media_codec_information[0] & 0x0F; 6305ce3497fSMatthias Ringwald event[pos++] = media_codec_information[1] >> 4; 6315ce3497fSMatthias Ringwald event[pos++] = (media_codec_information[1] & 0x0F) >> 2; 6325ce3497fSMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03; 6335ce3497fSMatthias Ringwald event[pos++] = media_codec_information[2]; 6345ce3497fSMatthias Ringwald event[pos++] = media_codec_information[3]; 6355ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6365ce3497fSMatthias Ringwald } 6375ce3497fSMatthias Ringwald 6385ce3497fSMatthias Ringwald static void avdtp_signaling_emit_media_codec_mpeg_audio_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) { 6395ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 6405ce3497fSMatthias Ringwald uint8_t event[15]; 6415ce3497fSMatthias Ringwald int pos = 0; 6425ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6435ce3497fSMatthias Ringwald event[pos++] = sizeof(event) - 2; 6445ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CAPABILITY; 6455ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 6465ce3497fSMatthias Ringwald pos += 2; 6475ce3497fSMatthias Ringwald event[pos++] = remote_seid; 6485ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 6495ce3497fSMatthias Ringwald 6505ce3497fSMatthias Ringwald uint8_t layer_bitmap = media_codec_information[0] >> 5; 6515ce3497fSMatthias Ringwald uint8_t crc = (media_codec_information[0] >> 4) & 0x01; 6525ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x07; 6535ce3497fSMatthias Ringwald uint8_t mpf = (media_codec_information[1] >> 6) & 0x01; 6545ce3497fSMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[1] & 0x3F; 6555ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[2] >> 7) & 0x01; 6565ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[3] & 0x3f) << 8) | media_codec.media_codec_information[4]; 6575ce3497fSMatthias Ringwald 6585ce3497fSMatthias Ringwald event[pos++] = layer_bitmap; 6595ce3497fSMatthias Ringwald event[pos++] = crc; 6605ce3497fSMatthias Ringwald event[pos++] = channel_mode_bitmap; 6615ce3497fSMatthias Ringwald event[pos++] = mpf; 6625ce3497fSMatthias Ringwald event[pos++] = sampling_frequency_bitmap; 6635ce3497fSMatthias Ringwald event[pos++] = vbr; 6645ce3497fSMatthias Ringwald little_endian_store_16(event, pos, bit_rate_index_bitmap); // bit rate index 6655ce3497fSMatthias Ringwald pos += 2; 6665ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6675ce3497fSMatthias Ringwald } 6685ce3497fSMatthias Ringwald 6695ce3497fSMatthias Ringwald static void avdtp_signaling_emit_media_codec_mpeg_aac_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) { 6705ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 6715ce3497fSMatthias Ringwald uint8_t event[15]; 6725ce3497fSMatthias Ringwald int pos = 0; 6735ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6745ce3497fSMatthias Ringwald event[pos++] = sizeof(event) - 2; 6755ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CAPABILITY; 6765ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 6775ce3497fSMatthias Ringwald pos += 2; 6785ce3497fSMatthias Ringwald event[pos++] = remote_seid; 6795ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 6805ce3497fSMatthias Ringwald 6811da18615SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 1; 6821da18615SMilanka Ringwald uint8_t drc = media_codec_information[0] & 0x01; 6835ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] << 4) | (media_codec_information[2] >> 4); 6841da18615SMilanka Ringwald uint8_t channels_bitmap = media_codec_information[2] & 0x0F; 6855ce3497fSMatthias Ringwald uint32_t bit_rate_bitmap = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 6865ce3497fSMatthias Ringwald uint8_t vbr = media_codec_information[3] >> 7; 6875ce3497fSMatthias Ringwald 6885ce3497fSMatthias Ringwald event[pos++] = object_type_bitmap; 6891da18615SMilanka Ringwald event[pos++] = drc; 6901da18615SMilanka Ringwald 6915ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency_bitmap); 6925ce3497fSMatthias Ringwald pos += 2; 6935ce3497fSMatthias Ringwald event[pos++] = channels_bitmap; 6945ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate_bitmap); 6955ce3497fSMatthias Ringwald pos += 3; 6965ce3497fSMatthias Ringwald event[pos++] = vbr; 6975ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6985ce3497fSMatthias Ringwald } 6995ce3497fSMatthias Ringwald 7005ce3497fSMatthias Ringwald static void avdtp_signaling_emit_media_codec_atrac_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) { 7015ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 7025ce3497fSMatthias Ringwald uint8_t event[16]; 7035ce3497fSMatthias Ringwald int pos = 0; 7045ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 70573048ce6SMatthias Ringwald pos++; // set later 7065ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY; 7075ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 7085ce3497fSMatthias Ringwald pos += 2; 7095ce3497fSMatthias Ringwald event[pos++] = remote_seid; 7105ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 7115ce3497fSMatthias Ringwald 7125ce3497fSMatthias Ringwald uint8_t version = media_codec_information[0] >> 5; 7135ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] >> 2) & 0x07; 714ab2445a0SMatthias Ringwald uint8_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03; 7155ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[1] >> 3) & 0x01; 7165ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3]; 7175ce3497fSMatthias Ringwald uint16_t maximum_sul = (media_codec_information[4] << 8) | media_codec_information[5]; 7185ce3497fSMatthias Ringwald 7195ce3497fSMatthias Ringwald event[pos++] = version; 7205ce3497fSMatthias Ringwald event[pos++] = channel_mode_bitmap; 7215ce3497fSMatthias Ringwald event[pos++] = sampling_frequency_bitmap; 7225ce3497fSMatthias Ringwald event[pos++] = vbr; 7235ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate_index_bitmap); 7245ce3497fSMatthias Ringwald pos += 3; 7255ce3497fSMatthias Ringwald little_endian_store_16(event, pos, maximum_sul); 72673048ce6SMatthias Ringwald pos += 2; 72773048ce6SMatthias Ringwald event[1] = pos - 2; 728c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 7298ef7100fSMilanka Ringwald } 7308ef7100fSMilanka Ringwald 73124d5fe84SMilanka Ringwald static void avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) { 73224d5fe84SMilanka Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 73324d5fe84SMilanka Ringwald uint8_t event[18]; 73424d5fe84SMilanka Ringwald int pos = 0; 73524d5fe84SMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 73624d5fe84SMilanka Ringwald pos++; // set later 73724d5fe84SMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CAPABILITY; 73824d5fe84SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 73924d5fe84SMilanka Ringwald pos += 2; 74024d5fe84SMilanka Ringwald event[pos++] = remote_seid; 74124d5fe84SMilanka Ringwald event[pos++] = media_codec.media_type; 74224d5fe84SMilanka Ringwald 74324d5fe84SMilanka Ringwald uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) | 74424d5fe84SMilanka Ringwald (media_codec_information[1] << 12) | 74524d5fe84SMilanka Ringwald (media_codec_information[2] << 4) | 74624d5fe84SMilanka Ringwald (media_codec_information[3] >> 4); 74724d5fe84SMilanka Ringwald 74824d5fe84SMilanka Ringwald uint8_t channels_bitmap = (media_codec_information[3] >> 2) & 0x03; 74924d5fe84SMilanka Ringwald uint8_t vbr = (media_codec_information[4] >> 7) & 0x01; 75024d5fe84SMilanka Ringwald 75124d5fe84SMilanka Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[4]) & 0xEF) << 16 | (media_codec_information[5] << 8) | media_codec_information[6]; 75224d5fe84SMilanka Ringwald 75324d5fe84SMilanka Ringwald event[pos++] = media_codec_information[0] >> 6; 75424d5fe84SMilanka Ringwald little_endian_store_32(event, pos, sampling_frequency_bitmap); 75524d5fe84SMilanka Ringwald pos += 4; 75624d5fe84SMilanka Ringwald event[pos++] = channels_bitmap; 75724d5fe84SMilanka Ringwald event[pos++] = sampling_frequency_bitmap; 75824d5fe84SMilanka Ringwald event[pos++] = vbr; 75924d5fe84SMilanka Ringwald little_endian_store_24(event, pos, bit_rate_index_bitmap); 76024d5fe84SMilanka Ringwald pos += 3; 76124d5fe84SMilanka Ringwald event[1] = pos - 2; 76224d5fe84SMilanka Ringwald avdtp_emit_sink_and_source(event, pos); 76324d5fe84SMilanka Ringwald } 76424d5fe84SMilanka Ringwald 76524d5fe84SMilanka Ringwald 7661159d239SMatthias Ringwald static void avdtp_signaling_emit_media_codec_other_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) { 767924216b2SMatthias Ringwald uint8_t event[AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH + 11]; 76867ae582dSMilanka Ringwald int pos = 0; 76967ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 77073048ce6SMatthias Ringwald pos++; // set later 7714b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY; 77267ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 77367ae582dSMilanka Ringwald pos += 2; 77467ae582dSMilanka Ringwald event[pos++] = remote_seid; 7754b7d40bbSMatthias Ringwald event[pos++] = media_codec.media_type; 7764b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, media_codec.media_codec_type); 7774b7d40bbSMatthias Ringwald pos += 2; 7784b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, media_codec.media_codec_information_len); 7794b7d40bbSMatthias Ringwald pos += 2; 780924216b2SMatthias Ringwald uint32_t media_codec_info_len = btstack_min(media_codec.media_codec_information_len, AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH); 7815403525eSMatthias Ringwald (void)memcpy(event + pos, media_codec.media_codec_information, media_codec_info_len); 7825403525eSMatthias Ringwald pos += media_codec_info_len; 78373048ce6SMatthias Ringwald event[1] = pos - 2; 784c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 78567ae582dSMilanka Ringwald } 78667ae582dSMilanka Ringwald 787c69f4ba5SMatthias Ringwald static void 7881159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 7891159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY, avdtp_cid, 790c69f4ba5SMatthias Ringwald remote_seid); 79167ae582dSMilanka Ringwald } 79267ae582dSMilanka Ringwald 7931159d239SMatthias Ringwald static void avdtp_signaling_emit_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 7941159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY, avdtp_cid, remote_seid); 79567ae582dSMilanka Ringwald } 79667ae582dSMilanka Ringwald 797c69f4ba5SMatthias Ringwald static void 7981159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 7991159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY, avdtp_cid, 800c69f4ba5SMatthias Ringwald remote_seid); 80167ae582dSMilanka Ringwald } 80267ae582dSMilanka Ringwald 8031159d239SMatthias Ringwald static void avdtp_signaling_emit_recovery_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_recovery_capabilities_t *recovery) { 8041159d239SMatthias Ringwald uint8_t event[9]; 80567ae582dSMilanka Ringwald int pos = 0; 80667ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 80767ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 80867ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY; 80967ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 81067ae582dSMilanka Ringwald pos += 2; 81167ae582dSMilanka Ringwald event[pos++] = remote_seid; 81267ae582dSMilanka Ringwald event[pos++] = recovery->recovery_type; 81367ae582dSMilanka Ringwald event[pos++] = recovery->maximum_recovery_window_size; 81467ae582dSMilanka Ringwald event[pos++] = recovery->maximum_number_media_packets; 815c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 81667ae582dSMilanka Ringwald } 81767ae582dSMilanka Ringwald 81873048ce6SMatthias Ringwald #define MAX_CONTENT_PROTECTION_VALUE_LEN 32 819c69f4ba5SMatthias Ringwald static void 8201159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_content_protection_t *content_protection) { 82173048ce6SMatthias Ringwald uint8_t event[10 + MAX_CONTENT_PROTECTION_VALUE_LEN]; 82267ae582dSMilanka Ringwald int pos = 0; 82367ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 82473048ce6SMatthias Ringwald pos++; // set later 82567ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY; 82667ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 82767ae582dSMilanka Ringwald pos += 2; 82867ae582dSMilanka Ringwald event[pos++] = remote_seid; 82967ae582dSMilanka Ringwald 83067ae582dSMilanka Ringwald little_endian_store_16(event, pos, content_protection->cp_type); 83167ae582dSMilanka Ringwald pos += 2; 83273048ce6SMatthias Ringwald 83373048ce6SMatthias Ringwald // drop cp protection value if longer than expected 83473048ce6SMatthias Ringwald if (content_protection->cp_type_value_len <= MAX_CONTENT_PROTECTION_VALUE_LEN){ 83567ae582dSMilanka Ringwald little_endian_store_16(event, pos, content_protection->cp_type_value_len); 83667ae582dSMilanka Ringwald pos += 2; 83773048ce6SMatthias Ringwald (void)memcpy(event + pos, content_protection->cp_type_value, content_protection->cp_type_value_len); 83873048ce6SMatthias Ringwald pos += content_protection->cp_type_value_len; 83973048ce6SMatthias Ringwald } else { 84073048ce6SMatthias Ringwald little_endian_store_16(event, pos, 0); 84173048ce6SMatthias Ringwald pos += 2; 84267ae582dSMilanka Ringwald } 84373048ce6SMatthias Ringwald event[1] = pos - 2; 844c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 84567ae582dSMilanka Ringwald } 84667ae582dSMilanka Ringwald 84767ae582dSMilanka Ringwald 848c69f4ba5SMatthias Ringwald static void 8491159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_header_compression_capabilities_t *header_compression) { 8501159d239SMatthias Ringwald uint8_t event[9]; 85167ae582dSMilanka Ringwald int pos = 0; 85267ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 85367ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 85467ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY; 85567ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 85667ae582dSMilanka Ringwald pos += 2; 85767ae582dSMilanka Ringwald event[pos++] = remote_seid; 85867ae582dSMilanka Ringwald event[pos++] = header_compression->back_ch; 85967ae582dSMilanka Ringwald event[pos++] = header_compression->media; 86067ae582dSMilanka Ringwald event[pos++] = header_compression->recovery; 861c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 86267ae582dSMilanka Ringwald } 86367ae582dSMilanka Ringwald 864c69f4ba5SMatthias Ringwald static void 8651159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_multiplexing_mode_capabilities_t *multiplexing_mode) { 8661159d239SMatthias Ringwald uint8_t event[14]; 86767ae582dSMilanka Ringwald int pos = 0; 86867ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 86967ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 87067ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY; 87167ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 87267ae582dSMilanka Ringwald pos += 2; 87367ae582dSMilanka Ringwald event[pos++] = remote_seid; 87467ae582dSMilanka Ringwald 87567ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->fragmentation; 87667ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->transport_identifiers_num; 87767ae582dSMilanka Ringwald 87867ae582dSMilanka Ringwald int i; 87967ae582dSMilanka Ringwald for (i = 0; i < 3; i++){ 88067ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->transport_session_identifiers[i]; 88167ae582dSMilanka Ringwald } 88267ae582dSMilanka Ringwald for (i = 0; i < 3; i++){ 88367ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->tcid[i]; 88467ae582dSMilanka Ringwald } 885c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 88667ae582dSMilanka Ringwald } 88767ae582dSMilanka Ringwald 8881159d239SMatthias Ringwald static void avdtp_signaling_emit_capability_done(uint16_t avdtp_cid, uint8_t remote_seid) { 8891159d239SMatthias Ringwald uint8_t event[6]; 890f08f4934SMatthias Ringwald int pos = 0; 891f08f4934SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 892f08f4934SMatthias Ringwald event[pos++] = sizeof(event) - 2; 893f08f4934SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE; 894f08f4934SMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 895f08f4934SMatthias Ringwald pos += 2; 896f08f4934SMatthias Ringwald event[pos++] = remote_seid; 897c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 898f08f4934SMatthias Ringwald } 899f08f4934SMatthias Ringwald 9000928ecceSMatthias Ringwald static void avdtp_signaling_emit_media_codec_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec){ 9010928ecceSMatthias Ringwald switch (media_codec.media_codec_type){ 9020928ecceSMatthias Ringwald case AVDTP_CODEC_SBC: 9030928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_sbc_capability(avdtp_cid, remote_seid, media_codec); 9040928ecceSMatthias Ringwald break; 9050928ecceSMatthias Ringwald case AVDTP_CODEC_MPEG_1_2_AUDIO: 9060928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_mpeg_audio_capability(avdtp_cid, remote_seid, media_codec); 9070928ecceSMatthias Ringwald break; 9080928ecceSMatthias Ringwald case AVDTP_CODEC_MPEG_2_4_AAC: 9090928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_mpeg_aac_capability(avdtp_cid, remote_seid, media_codec); 9100928ecceSMatthias Ringwald break; 9110928ecceSMatthias Ringwald case AVDTP_CODEC_ATRAC_FAMILY: 9120928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_atrac_capability(avdtp_cid, remote_seid, media_codec); 9130928ecceSMatthias Ringwald break; 91424d5fe84SMilanka Ringwald case AVDTP_CODEC_MPEG_D_USAC: 91524d5fe84SMilanka Ringwald avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(avdtp_cid, remote_seid, media_codec); 91624d5fe84SMilanka Ringwald break; 9170928ecceSMatthias Ringwald default: 9180928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_other_capability(avdtp_cid, remote_seid, media_codec); 9190928ecceSMatthias Ringwald break; 9200928ecceSMatthias Ringwald } 9210928ecceSMatthias Ringwald } 9220928ecceSMatthias Ringwald 9234b7d40bbSMatthias Ringwald // emit events for all capabilities incl. final done event 9241159d239SMatthias Ringwald void avdtp_signaling_emit_capabilities(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_capabilities_t *capabilities, 925c69f4ba5SMatthias Ringwald uint16_t registered_service_categories) { 92667ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MEDIA_CODEC)){ 9270928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_capability(avdtp_cid, remote_seid, capabilities->media_codec); 92867ae582dSMilanka Ringwald } 92967ae582dSMilanka Ringwald 93067ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MEDIA_TRANSPORT)){ 9311159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(avdtp_cid, remote_seid); 93267ae582dSMilanka Ringwald } 93367ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_REPORTING)){ 9341159d239SMatthias Ringwald avdtp_signaling_emit_reporting_capability(avdtp_cid, remote_seid); 93567ae582dSMilanka Ringwald } 93667ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_RECOVERY)){ 9371159d239SMatthias Ringwald avdtp_signaling_emit_recovery_capability(avdtp_cid, remote_seid, &capabilities->recovery); 93867ae582dSMilanka Ringwald } 93967ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_CONTENT_PROTECTION)){ 9401159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(avdtp_cid, remote_seid, 941c69f4ba5SMatthias Ringwald &capabilities->content_protection); 94267ae582dSMilanka Ringwald } 94367ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_HEADER_COMPRESSION)){ 9441159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(avdtp_cid, remote_seid, 945c69f4ba5SMatthias Ringwald &capabilities->header_compression); 94667ae582dSMilanka Ringwald } 94767ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MULTIPLEXING)){ 9481159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(avdtp_cid, remote_seid, 949c69f4ba5SMatthias Ringwald &capabilities->multiplexing_mode); 95067ae582dSMilanka Ringwald } 95167ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_DELAY_REPORTING)){ 9521159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(avdtp_cid, remote_seid); 95367ae582dSMilanka Ringwald } 9541159d239SMatthias Ringwald avdtp_signaling_emit_capability_done(avdtp_cid, remote_seid); 95567ae582dSMilanka Ringwald } 95667ae582dSMilanka Ringwald 957186e1970SMatthias Ringwald static uint16_t 958186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_sbc_config_event(uint8_t *event, uint16_t size, 959a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 960186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 961186e1970SMatthias Ringwald const uint8_t *media_codec_information) { 962186e1970SMatthias Ringwald 963924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN); 964186e1970SMatthias Ringwald 9654b7d40bbSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 9664b7d40bbSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 9674b7d40bbSMatthias Ringwald 9684b7d40bbSMatthias Ringwald int pos = 0; 9694b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 970924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN - 2; 9714b7d40bbSMatthias Ringwald 9724b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION; 9734b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 9744b7d40bbSMatthias Ringwald pos += 2; 9754b7d40bbSMatthias Ringwald event[pos++] = local_seid; 9764b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 9774b7d40bbSMatthias Ringwald event[pos++] = reconfigure; 978186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_SBC; 9794b7d40bbSMatthias Ringwald 9804b7d40bbSMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[0] >> 4; 9814b7d40bbSMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x0F; 9824b7d40bbSMatthias Ringwald uint8_t block_length_bitmap = media_codec_information[1] >> 4; 9834b7d40bbSMatthias Ringwald uint8_t subbands_bitmap = (media_codec_information[1] & 0x0F) >> 2; 9844b7d40bbSMatthias Ringwald 9854b7d40bbSMatthias Ringwald uint8_t num_channels = 0; 986a3868652SMatthias Ringwald avdtp_channel_mode_t channel_mode; 987a3868652SMatthias Ringwald 988a3868652SMatthias Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 989a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 9904b7d40bbSMatthias Ringwald num_channels = 2; 991a3868652SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 992a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_STEREO; 993a3868652SMatthias Ringwald num_channels = 2; 994a3868652SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 995a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 996a3868652SMatthias Ringwald num_channels = 2; 997a3868652SMatthias Ringwald } else { 998a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 9994b7d40bbSMatthias Ringwald num_channels = 1; 10004b7d40bbSMatthias Ringwald } 10014b7d40bbSMatthias Ringwald 10024b7d40bbSMatthias Ringwald uint16_t sampling_frequency = 0; 10034b7d40bbSMatthias Ringwald if (sampling_frequency_bitmap & AVDTP_SBC_48000) { 10044b7d40bbSMatthias Ringwald sampling_frequency = 48000; 10054b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_44100) { 10064b7d40bbSMatthias Ringwald sampling_frequency = 44100; 10074b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_32000) { 10084b7d40bbSMatthias Ringwald sampling_frequency = 32000; 10094b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_16000) { 10104b7d40bbSMatthias Ringwald sampling_frequency = 16000; 10114b7d40bbSMatthias Ringwald } 10124b7d40bbSMatthias Ringwald 10134b7d40bbSMatthias Ringwald uint8_t subbands = 0; 10144b7d40bbSMatthias Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 10154b7d40bbSMatthias Ringwald subbands = 8; 10164b7d40bbSMatthias Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 10174b7d40bbSMatthias Ringwald subbands = 4; 10184b7d40bbSMatthias Ringwald } 10194b7d40bbSMatthias Ringwald 10204b7d40bbSMatthias Ringwald uint8_t block_length = 0; 10214b7d40bbSMatthias Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 10224b7d40bbSMatthias Ringwald block_length = 16; 10234b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 10244b7d40bbSMatthias Ringwald block_length = 12; 10254b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 10264b7d40bbSMatthias Ringwald block_length = 8; 10274b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 10284b7d40bbSMatthias Ringwald block_length = 4; 10294b7d40bbSMatthias Ringwald } 10304b7d40bbSMatthias Ringwald 10314b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 10324b7d40bbSMatthias Ringwald pos += 2; 10334b7d40bbSMatthias Ringwald 1034a3868652SMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 10354b7d40bbSMatthias Ringwald event[pos++] = num_channels; 10364b7d40bbSMatthias Ringwald event[pos++] = block_length; 10374b7d40bbSMatthias Ringwald event[pos++] = subbands; 10384b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03; 10394b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[2]; 10404b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[3]; 1041186e1970SMatthias Ringwald 1042924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN); 1043186e1970SMatthias Ringwald 1044186e1970SMatthias Ringwald return pos; 10455ce3497fSMatthias Ringwald } 10465ce3497fSMatthias Ringwald 1047186e1970SMatthias Ringwald static uint16_t 1048186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpeg_audio_config_event(uint8_t *event, uint16_t size, 1049a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1050186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 10515ce3497fSMatthias Ringwald const uint8_t *media_codec_information) { 10525ce3497fSMatthias Ringwald 1053924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN); 1054186e1970SMatthias Ringwald 10555ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 10565ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 10575ce3497fSMatthias Ringwald 1058186e1970SMatthias Ringwald uint16_t pos = 0; 10595ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1060924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN - 2; 10615ce3497fSMatthias Ringwald 10625ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION; 10635ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 10645ce3497fSMatthias Ringwald pos += 2; 10655ce3497fSMatthias Ringwald event[pos++] = local_seid; 10665ce3497fSMatthias Ringwald event[pos++] = remote_seid; 10675ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1068186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_MPEG_1_2_AUDIO; 10695ce3497fSMatthias Ringwald 10705ce3497fSMatthias Ringwald uint8_t layer_bitmap = media_codec_information[0] >> 5; 10715ce3497fSMatthias Ringwald uint8_t crc = (media_codec_information[0] >> 4) & 0x01; 10725ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] & 0x07); 10735ce3497fSMatthias Ringwald uint8_t mpf = (media_codec_information[1] >> 6) & 0x01; 10745ce3497fSMatthias Ringwald uint8_t sampling_frequency_bitmap = (media_codec_information[1] & 0x3F); 10755ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[2] >> 7) & 0x01; 10765ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[2] & 0x3f) << 8) | media_codec_information[3]; 10775ce3497fSMatthias Ringwald 10785ce3497fSMatthias Ringwald uint8_t layer = 0; 10795ce3497fSMatthias Ringwald if (layer_bitmap & 0x04){ 10805ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_1; 10815ce3497fSMatthias Ringwald } else if (layer_bitmap & 0x02){ 10825ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_2; 10835ce3497fSMatthias Ringwald } else if (layer_bitmap & 0x01){ 10845ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_3; 10855ce3497fSMatthias Ringwald } 10865ce3497fSMatthias Ringwald 10875ce3497fSMatthias Ringwald uint8_t num_channels = 0; 10885ce3497fSMatthias Ringwald avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 10895ce3497fSMatthias Ringwald if (channel_mode_bitmap & 0x08){ 10905ce3497fSMatthias Ringwald num_channels = 1; 10915ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 10925ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x04){ 10935ce3497fSMatthias Ringwald num_channels = 2; 10945ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 10955ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 10965ce3497fSMatthias Ringwald num_channels = 2; 10975ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_STEREO; 10985ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 10995ce3497fSMatthias Ringwald num_channels = 2; 11005ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 11015ce3497fSMatthias Ringwald } 11025ce3497fSMatthias Ringwald 11035ce3497fSMatthias Ringwald uint16_t sampling_frequency = 0; 11045ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & 0x01) { 11055ce3497fSMatthias Ringwald sampling_frequency = 48000; 11065ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x02) { 11075ce3497fSMatthias Ringwald sampling_frequency = 44100; 11085ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x04) { 11095ce3497fSMatthias Ringwald sampling_frequency = 32000; 11105ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x08) { 11115ce3497fSMatthias Ringwald sampling_frequency = 24000; 11125ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x10) { 11135ce3497fSMatthias Ringwald sampling_frequency = 22050; 11145ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x20) { 11155ce3497fSMatthias Ringwald sampling_frequency = 16000; 11165ce3497fSMatthias Ringwald } 11175ce3497fSMatthias Ringwald 11185ce3497fSMatthias Ringwald uint8_t bitrate_index = 0; 11195ce3497fSMatthias Ringwald uint8_t i; 11205ce3497fSMatthias Ringwald for (i=0;i<14;i++){ 11215ce3497fSMatthias Ringwald if (bit_rate_index_bitmap & (1U << i)) { 11225ce3497fSMatthias Ringwald bitrate_index = i; 11235ce3497fSMatthias Ringwald } 11245ce3497fSMatthias Ringwald } 11255ce3497fSMatthias Ringwald 11265ce3497fSMatthias Ringwald event[pos++] = (uint8_t) layer; 11275ce3497fSMatthias Ringwald event[pos++] = crc; 11285ce3497fSMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 11295ce3497fSMatthias Ringwald event[pos++] = num_channels; 11305ce3497fSMatthias Ringwald event[pos++] = mpf; 11315ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 11325ce3497fSMatthias Ringwald pos += 2; 11335ce3497fSMatthias Ringwald event[pos++] = vbr; 11345ce3497fSMatthias Ringwald event[pos++] = bitrate_index; 11355ce3497fSMatthias Ringwald 1136924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN); 1137186e1970SMatthias Ringwald 1138186e1970SMatthias Ringwald return pos; 11395ce3497fSMatthias Ringwald } 11405ce3497fSMatthias Ringwald 1141186e1970SMatthias Ringwald static uint16_t 1142186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpec_aac_config_event(uint8_t *event, uint16_t size, 1143a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1144186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 11455ce3497fSMatthias Ringwald const uint8_t *media_codec_information) { 11465ce3497fSMatthias Ringwald 114724d5fe84SMilanka Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN); 1148186e1970SMatthias Ringwald 11495ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 11505ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 11515ce3497fSMatthias Ringwald 1152186e1970SMatthias Ringwald uint16_t pos = 0; 11535ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1154924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN - 2; 11555ce3497fSMatthias Ringwald 11565ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION; 11575ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 11585ce3497fSMatthias Ringwald pos += 2; 11595ce3497fSMatthias Ringwald event[pos++] = local_seid; 11605ce3497fSMatthias Ringwald event[pos++] = remote_seid; 11615ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1162186e1970SMatthias Ringwald event[pos++] =AVDTP_CODEC_MPEG_2_4_AAC; 11635ce3497fSMatthias Ringwald 11641da18615SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 1; 11651da18615SMilanka Ringwald uint8_t drc = media_codec_information[0] & 0x01; 11665ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] << 4) | (media_codec_information[2] >> 4); 11671da18615SMilanka Ringwald uint8_t channels_bitmap = media_codec_information[2] & 0x0F; 11685ce3497fSMatthias Ringwald uint8_t vbr = media_codec_information[3] >> 7; 11695ce3497fSMatthias Ringwald uint32_t bit_rate = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 11705ce3497fSMatthias Ringwald 11715ce3497fSMatthias Ringwald uint8_t object_type = 0; 11721da18615SMilanka Ringwald if (object_type_bitmap & 0x01){ 11731da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AAC_ELDv2; 11741da18615SMilanka Ringwald } else if (object_type_bitmap & 0x02){ 11751da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AACv2; 11761da18615SMilanka Ringwald } else if (object_type_bitmap & 0x04){ 11771da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AAC; 11781da18615SMilanka Ringwald } else if (object_type_bitmap & 0x08){ 11795ce3497fSMatthias Ringwald object_type = AVDTP_AAC_MPEG4_SCALABLE; 11801da18615SMilanka Ringwald } else if (object_type_bitmap & 0x10){ 11811da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_LTP; 11821da18615SMilanka Ringwald } else if (object_type_bitmap & 0x20){ 11831da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_LC; 11841da18615SMilanka Ringwald } else if (object_type_bitmap & 0x40){ 11851da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG2_LC; 11865ce3497fSMatthias Ringwald } 11875ce3497fSMatthias Ringwald 11885ce3497fSMatthias Ringwald uint32_t sampling_frequency = 0; 11895ce3497fSMatthias Ringwald uint8_t i; 11905ce3497fSMatthias Ringwald const uint32_t aac_sampling_frequency_table[] = { 11915ce3497fSMatthias Ringwald 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 11925ce3497fSMatthias Ringwald }; 11935ce3497fSMatthias Ringwald for (i=0;i<12;i++){ 11945ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & (1U << i)) { 11955ce3497fSMatthias Ringwald sampling_frequency = aac_sampling_frequency_table[i]; 11965ce3497fSMatthias Ringwald } 11975ce3497fSMatthias Ringwald } 11985ce3497fSMatthias Ringwald 11995ce3497fSMatthias Ringwald uint8_t num_channels = 0; 12001da18615SMilanka Ringwald if (channels_bitmap & 0x08){ 12015ce3497fSMatthias Ringwald num_channels = 1; 12021da18615SMilanka Ringwald } else if (channels_bitmap & 0x04){ 12035ce3497fSMatthias Ringwald num_channels = 2; 12041da18615SMilanka Ringwald } else if (channels_bitmap & 0x02){ 12051da18615SMilanka Ringwald num_channels = 6; 12061da18615SMilanka Ringwald } else if (channels_bitmap & 0x01){ 12071da18615SMilanka Ringwald num_channels = 8; 12085ce3497fSMatthias Ringwald } 12095ce3497fSMatthias Ringwald 12105ce3497fSMatthias Ringwald event[pos++] = object_type; 12111da18615SMilanka Ringwald event[pos++] = drc; 12125ce3497fSMatthias Ringwald little_endian_store_24(event, pos, sampling_frequency); 12135ce3497fSMatthias Ringwald pos += 3; 12145ce3497fSMatthias Ringwald event[pos++] = num_channels; 12155ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate); 12165ce3497fSMatthias Ringwald pos += 3; 12175ce3497fSMatthias Ringwald event[pos++] = vbr; 12185ce3497fSMatthias Ringwald 1219924216b2SMatthias Ringwald btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN == pos); 1220186e1970SMatthias Ringwald 1221186e1970SMatthias Ringwald return pos; 12225ce3497fSMatthias Ringwald } 12235ce3497fSMatthias Ringwald 122424d5fe84SMilanka Ringwald static uint16_t 122524d5fe84SMilanka Ringwald avdtp_signaling_setup_media_codec_mpegd_config_event(uint8_t *event, uint16_t size, 122624d5fe84SMilanka Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 122724d5fe84SMilanka Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 122824d5fe84SMilanka Ringwald const uint8_t *media_codec_information) { 122924d5fe84SMilanka Ringwald 123024d5fe84SMilanka Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN); 123124d5fe84SMilanka Ringwald 123224d5fe84SMilanka Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 123324d5fe84SMilanka Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 123424d5fe84SMilanka Ringwald 123524d5fe84SMilanka Ringwald uint16_t pos = 0; 123624d5fe84SMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 123724d5fe84SMilanka Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN - 2; 123824d5fe84SMilanka Ringwald 123924d5fe84SMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CONFIGURATION; 124024d5fe84SMilanka Ringwald 124124d5fe84SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 124224d5fe84SMilanka Ringwald pos += 2; 124324d5fe84SMilanka Ringwald event[pos++] = local_seid; 124424d5fe84SMilanka Ringwald event[pos++] = remote_seid; 124524d5fe84SMilanka Ringwald event[pos++] = reconfigure; 124624d5fe84SMilanka Ringwald event[pos++] = AVDTP_CODEC_MPEG_D_USAC; 124724d5fe84SMilanka Ringwald 124824d5fe84SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 6; 124924d5fe84SMilanka Ringwald uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) | 125024d5fe84SMilanka Ringwald (media_codec_information[1] << 12) | 125124d5fe84SMilanka Ringwald (media_codec_information[2] << 4) | 125224d5fe84SMilanka Ringwald (media_codec_information[3] >> 4); 125324d5fe84SMilanka Ringwald 125424d5fe84SMilanka Ringwald uint8_t channels_bitmap = (media_codec_information[3] >> 2) & 0x03; 125524d5fe84SMilanka Ringwald uint8_t vbr = (media_codec_information[4] >> 7) & 0x01; 125624d5fe84SMilanka Ringwald 125724d5fe84SMilanka Ringwald uint32_t bit_rate = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 125824d5fe84SMilanka Ringwald 125924d5fe84SMilanka Ringwald uint8_t object_type = 0; 126024d5fe84SMilanka Ringwald if (object_type_bitmap & 0x10){ 126124d5fe84SMilanka Ringwald object_type = AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC; 126224d5fe84SMilanka Ringwald } else { 126324d5fe84SMilanka Ringwald object_type = AVDTP_USAC_OBJECT_TYPE_RFU; 126424d5fe84SMilanka Ringwald } 126524d5fe84SMilanka Ringwald 126624d5fe84SMilanka Ringwald uint32_t sampling_frequency = 0; 126724d5fe84SMilanka Ringwald uint8_t i; 126824d5fe84SMilanka Ringwald const uint32_t usac_sampling_frequency_table[] = { 126924d5fe84SMilanka Ringwald 96000, 88200, 76800, 70560, 127024d5fe84SMilanka Ringwald 64000, 58800, 48000, 44100, 38400, 35280, 32000, 29400, 127124d5fe84SMilanka Ringwald 24000, 22050, 19200, 17640, 16000, 14700, 12800, 12000, 127224d5fe84SMilanka Ringwald 11760, 11025, 9600, 8820, 8000, 7350 127324d5fe84SMilanka Ringwald }; 127424d5fe84SMilanka Ringwald for (i=0;i<26;i++){ 127524d5fe84SMilanka Ringwald if (sampling_frequency_bitmap & (1U << i)) { 127624d5fe84SMilanka Ringwald sampling_frequency = usac_sampling_frequency_table[i]; 127724d5fe84SMilanka Ringwald } 127824d5fe84SMilanka Ringwald } 127924d5fe84SMilanka Ringwald 128024d5fe84SMilanka Ringwald uint8_t num_channels = 0; 128124d5fe84SMilanka Ringwald if (channels_bitmap & 0x02){ 128224d5fe84SMilanka Ringwald num_channels = 1; 128324d5fe84SMilanka Ringwald } else if (channels_bitmap & 0x01){ 128424d5fe84SMilanka Ringwald num_channels = 2; 128524d5fe84SMilanka Ringwald } 128624d5fe84SMilanka Ringwald 128724d5fe84SMilanka Ringwald event[pos++] = object_type; 128824d5fe84SMilanka Ringwald little_endian_store_24(event, pos, sampling_frequency); 128924d5fe84SMilanka Ringwald pos += 3; 129024d5fe84SMilanka Ringwald event[pos++] = num_channels; 129124d5fe84SMilanka Ringwald event[pos++] = vbr; 129224d5fe84SMilanka Ringwald little_endian_store_24(event, pos, bit_rate); 129324d5fe84SMilanka Ringwald pos += 3; 129424d5fe84SMilanka Ringwald 129524d5fe84SMilanka Ringwald btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN == pos); 129624d5fe84SMilanka Ringwald 129724d5fe84SMilanka Ringwald return pos; 129824d5fe84SMilanka Ringwald } 129924d5fe84SMilanka Ringwald 1300186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_atrac_config_event(uint8_t *event, uint16_t size, 1301a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1302186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 1303186e1970SMatthias Ringwald const uint8_t *media_codec_information) { 1304924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN); 1305186e1970SMatthias Ringwald 13065ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 13075ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 13085ce3497fSMatthias Ringwald 1309186e1970SMatthias Ringwald uint16_t pos = 0; 13105ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1311924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN - 2; 13125ce3497fSMatthias Ringwald 13135ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION; 13145ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 13155ce3497fSMatthias Ringwald pos += 2; 13165ce3497fSMatthias Ringwald event[pos++] = local_seid; 13175ce3497fSMatthias Ringwald event[pos++] = remote_seid; 13185ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1319186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_ATRAC_FAMILY; 13205ce3497fSMatthias Ringwald 1321b5bbcbf4SMatthias Ringwald avdtp_atrac_version_t version = (avdtp_atrac_version_t) (media_codec_information[0] >> 5); 13225ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] >> 2) & 0x07; 13235ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03; 13245ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[1] >> 3) & 0x01; 13255ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3]; 13265ce3497fSMatthias Ringwald uint16_t maximum_sul = (media_codec_information[4] << 8) | media_codec_information[5]; 13275ce3497fSMatthias Ringwald 13285ce3497fSMatthias Ringwald uint8_t num_channels = 0; 13295ce3497fSMatthias Ringwald avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 13305ce3497fSMatthias Ringwald if (channel_mode_bitmap & 0x04){ 13315ce3497fSMatthias Ringwald num_channels = 1; 13325ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 13335ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 13345ce3497fSMatthias Ringwald num_channels = 2; 13355ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 13365ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x01){ 13375ce3497fSMatthias Ringwald num_channels = 2; 13385ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 13395ce3497fSMatthias Ringwald } 13405ce3497fSMatthias Ringwald 13415ce3497fSMatthias Ringwald uint16_t sampling_frequency = 0; 13425ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & 0x02){ 13435ce3497fSMatthias Ringwald sampling_frequency = 44100; 13445ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x01){ 13455ce3497fSMatthias Ringwald sampling_frequency = 48000; 13465ce3497fSMatthias Ringwald } 13475ce3497fSMatthias Ringwald 13485ce3497fSMatthias Ringwald // bit 0 = index 0x18, bit 19 = index 0 13495ce3497fSMatthias Ringwald uint8_t bit_rate_index = 0; 13505ce3497fSMatthias Ringwald uint8_t i; 13515ce3497fSMatthias Ringwald for (i=0;i <= 19;i++){ 13525ce3497fSMatthias Ringwald if (bit_rate_index_bitmap & (1U << i)) { 13535ce3497fSMatthias Ringwald bit_rate_index = 18 - i; 13545ce3497fSMatthias Ringwald } 13555ce3497fSMatthias Ringwald } 13565ce3497fSMatthias Ringwald 13575ce3497fSMatthias Ringwald event[pos++] = (uint8_t) version; 13585ce3497fSMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 13595ce3497fSMatthias Ringwald event[pos++] = num_channels; 13605ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 13615ce3497fSMatthias Ringwald pos += 2; 13625ce3497fSMatthias Ringwald event[pos++] = vbr; 13635ce3497fSMatthias Ringwald event[pos++] = bit_rate_index; 13645ce3497fSMatthias Ringwald little_endian_store_16(event, pos, maximum_sul); 13655ce3497fSMatthias Ringwald pos += 2; 13665ce3497fSMatthias Ringwald 1367924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN); 1368186e1970SMatthias Ringwald return pos; 13694b7d40bbSMatthias Ringwald } 13704b7d40bbSMatthias Ringwald 1371186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_other_config_event(uint8_t *event, uint16_t size, 1372a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1373186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 1374186e1970SMatthias Ringwald const adtvp_media_codec_capabilities_t *media_codec) { 1375924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN); 1376186e1970SMatthias Ringwald 13776c069ec9SMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 13786c069ec9SMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 13796c069ec9SMatthias Ringwald 1380186e1970SMatthias Ringwald uint16_t pos = 0; 13814b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 138273048ce6SMatthias Ringwald pos++; // set later 13834b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION; 13844b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 13854b7d40bbSMatthias Ringwald pos += 2; 13864b7d40bbSMatthias Ringwald event[pos++] = local_seid; 13874b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 13884b7d40bbSMatthias Ringwald event[pos++] = reconfigure; 1389e8a431c1SMatthias Ringwald event[pos++] = media_codec->media_type; 1390e8a431c1SMatthias Ringwald little_endian_store_16(event, pos, media_codec->media_codec_type); 13914b7d40bbSMatthias Ringwald pos += 2; 1392e8a431c1SMatthias Ringwald little_endian_store_16(event, pos, media_codec->media_codec_information_len); 13934b7d40bbSMatthias Ringwald pos += 2; 1394186e1970SMatthias Ringwald 1395186e1970SMatthias Ringwald btstack_assert(pos == 13); 1396186e1970SMatthias Ringwald 1397924216b2SMatthias Ringwald uint16_t media_codec_len = btstack_min(AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH, media_codec->media_codec_information_len); 1398e8a431c1SMatthias Ringwald (void)memcpy(event + pos, media_codec->media_codec_information, media_codec_len); 139973048ce6SMatthias Ringwald pos += media_codec_len; 140073048ce6SMatthias Ringwald event[1] = pos - 2; 1401186e1970SMatthias Ringwald return pos; 14024b7d40bbSMatthias Ringwald } 14034b7d40bbSMatthias Ringwald 14044b7d40bbSMatthias Ringwald void avdtp_signaling_emit_delay(uint16_t avdtp_cid, uint8_t local_seid, uint16_t delay) { 14054b7d40bbSMatthias Ringwald uint8_t event[8]; 14064b7d40bbSMatthias Ringwald int pos = 0; 14074b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14084b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14094b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT; 14104b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 14114b7d40bbSMatthias Ringwald pos += 2; 14124b7d40bbSMatthias Ringwald event[pos++] = local_seid; 14134b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, delay); 14144b7d40bbSMatthias Ringwald pos += 2; 14156e64e62bSMatthias Ringwald avdtp_emit_source(event, pos); 14164b7d40bbSMatthias Ringwald } 14174b7d40bbSMatthias Ringwald 1418a905535cSMatthias Ringwald uint16_t avdtp_setup_media_codec_config_event(uint8_t *event, uint16_t size, const avdtp_stream_endpoint_t *stream_endpoint, 1419924216b2SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 14202965b0e6SMatthias Ringwald const adtvp_media_codec_capabilities_t * media_codec) { 14212965b0e6SMatthias Ringwald switch (media_codec->media_codec_type){ 1422924216b2SMatthias Ringwald case AVDTP_CODEC_SBC: 1423924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_sbc_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14242965b0e6SMatthias Ringwald media_codec->media_codec_information); 1425924216b2SMatthias Ringwald case AVDTP_CODEC_MPEG_1_2_AUDIO: 1426924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_mpeg_audio_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14272965b0e6SMatthias Ringwald media_codec->media_codec_information); 1428924216b2SMatthias Ringwald case AVDTP_CODEC_MPEG_2_4_AAC: 1429924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_mpec_aac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14302965b0e6SMatthias Ringwald media_codec->media_codec_information); 1431924216b2SMatthias Ringwald case AVDTP_CODEC_ATRAC_FAMILY: 1432924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_atrac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14332965b0e6SMatthias Ringwald media_codec->media_codec_information); 143424d5fe84SMilanka Ringwald case AVDTP_CODEC_MPEG_D_USAC: 143524d5fe84SMilanka Ringwald return avdtp_signaling_setup_media_codec_mpegd_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 143624d5fe84SMilanka Ringwald media_codec->media_codec_information); 1437924216b2SMatthias Ringwald default: 1438924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_other_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14392965b0e6SMatthias Ringwald media_codec); 1440924216b2SMatthias Ringwald } 1441924216b2SMatthias Ringwald } 1442924216b2SMatthias Ringwald 14436c5b303cSMatthias Ringwald void avdtp_signaling_emit_configuration(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t reconfigure, 14444b7d40bbSMatthias Ringwald avdtp_capabilities_t *configuration, uint16_t configured_service_categories) { 14454b7d40bbSMatthias Ringwald 14464b7d40bbSMatthias Ringwald if (get_bit16(configured_service_categories, AVDTP_MEDIA_CODEC)){ 1447186e1970SMatthias Ringwald uint16_t pos = 0; 1448186e1970SMatthias Ringwald // assume MEDIA_CONFIG_OTHER_EVENT_LEN is larger than all other events 1449924216b2SMatthias Ringwald uint8_t event[AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN]; 1450924216b2SMatthias Ringwald pos = avdtp_setup_media_codec_config_event(event, sizeof(event), stream_endpoint, avdtp_cid, reconfigure, 14512965b0e6SMatthias Ringwald &configuration->media_codec); 1452186e1970SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 1453186e1970SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 14544b7d40bbSMatthias Ringwald } 14554b7d40bbSMatthias Ringwald } 14564b7d40bbSMatthias Ringwald 14574b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_established(avdtp_stream_endpoint_t *stream_endpoint, uint8_t status) { 14584b7d40bbSMatthias Ringwald uint8_t event[14]; 14594b7d40bbSMatthias Ringwald int pos = 0; 14604b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14614b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14624b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED; 14634b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 14644b7d40bbSMatthias Ringwald pos += 2; 14654b7d40bbSMatthias Ringwald reverse_bd_addr(stream_endpoint->connection->remote_addr, &event[pos]); 14664b7d40bbSMatthias Ringwald pos += 6; 14674b7d40bbSMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint); 14684b7d40bbSMatthias Ringwald event[pos++] = avdtp_remote_seid(stream_endpoint); 14694b7d40bbSMatthias Ringwald event[pos++] = status; 14704b7d40bbSMatthias Ringwald 14714b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 14726e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 14734b7d40bbSMatthias Ringwald } 14744b7d40bbSMatthias Ringwald 14754b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_released(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t local_seid) { 14764b7d40bbSMatthias Ringwald uint8_t event[6]; 14774b7d40bbSMatthias Ringwald int pos = 0; 14784b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14794b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14804b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED; 14814b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 14824b7d40bbSMatthias Ringwald pos += 2; 14834b7d40bbSMatthias Ringwald event[pos++] = local_seid; 14844b7d40bbSMatthias Ringwald 14854b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 14866e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 14874b7d40bbSMatthias Ringwald } 14884b7d40bbSMatthias Ringwald 14894b7d40bbSMatthias Ringwald void avdtp_streaming_emit_can_send_media_packet_now(avdtp_stream_endpoint_t *stream_endpoint, uint16_t sequence_number) { 14904b7d40bbSMatthias Ringwald uint8_t event[8]; 14914b7d40bbSMatthias Ringwald int pos = 0; 14924b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14934b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14944b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW; 14954b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 14964b7d40bbSMatthias Ringwald pos += 2; 14974b7d40bbSMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint); 14984b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, sequence_number); 14994b7d40bbSMatthias Ringwald pos += 2; 15006e64e62bSMatthias Ringwald event[1] = pos - 2; 15014b7d40bbSMatthias Ringwald 15024b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 15036e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 15044b7d40bbSMatthias Ringwald } 15054b7d40bbSMatthias Ringwald 1506d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_acceptor(avdtp_connection_t *connection) { 150723edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1508d80ccd43SMatthias Ringwald connection->wait_to_send_acceptor = true; 1509d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(connection->l2cap_signaling_cid); 15109974aee0SMilanka Ringwald return ERROR_CODE_SUCCESS; 15118ef7100fSMilanka Ringwald } 15129974aee0SMilanka Ringwald 1513d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_initiator(avdtp_connection_t *connection) { 151423edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1515d80ccd43SMatthias Ringwald connection->wait_to_send_initiator = true; 1516d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(connection->l2cap_signaling_cid); 15179974aee0SMilanka Ringwald return ERROR_CODE_SUCCESS; 15188ef7100fSMilanka Ringwald } 15199974aee0SMilanka Ringwald 1520a905535cSMatthias Ringwald uint8_t avdtp_local_seid(const avdtp_stream_endpoint_t * stream_endpoint){ 15214ccacc40SMilanka Ringwald if (!stream_endpoint) return 0; 15224ccacc40SMilanka Ringwald return stream_endpoint->sep.seid; 15234ccacc40SMilanka Ringwald 15244ccacc40SMilanka Ringwald } 15254ccacc40SMilanka Ringwald 1526a905535cSMatthias Ringwald uint8_t avdtp_remote_seid(const avdtp_stream_endpoint_t * stream_endpoint){ 1527485c0a4cSMilanka Ringwald if (!stream_endpoint) return AVDTP_INVALID_SEP_SEID; 1528485c0a4cSMilanka Ringwald return stream_endpoint->remote_sep.seid; 15294ccacc40SMilanka Ringwald } 1530ef5ad9d6SMilanka Ringwald 1531fdd788feSMatthias Ringwald // helper to set/get configuration 1532fdd788feSMatthias Ringwald void avdtp_config_sbc_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz){ 1533fdd788feSMatthias Ringwald avdtp_sbc_sampling_frequency_t sampling_frequency; 1534fdd788feSMatthias Ringwald switch (sampling_frequency_hz){ 1535fdd788feSMatthias Ringwald case 16000: 1536fdd788feSMatthias Ringwald sampling_frequency = AVDTP_SBC_16000; 1537fdd788feSMatthias Ringwald break; 1538fdd788feSMatthias Ringwald case 32000: 1539fdd788feSMatthias Ringwald sampling_frequency = AVDTP_SBC_32000; 1540fdd788feSMatthias Ringwald break; 1541fdd788feSMatthias Ringwald case 48000: 1542fdd788feSMatthias Ringwald sampling_frequency = AVDTP_SBC_48000; 1543fdd788feSMatthias Ringwald break; 1544fdd788feSMatthias Ringwald default: 1545fdd788feSMatthias Ringwald sampling_frequency = AVDTP_SBC_44100; 1546fdd788feSMatthias Ringwald break; 1547fdd788feSMatthias Ringwald } 1548fdd788feSMatthias Ringwald config[0] = (((uint8_t) sampling_frequency) << 4) | (config[0] & 0x0f); 1549fdd788feSMatthias Ringwald } 1550fdd788feSMatthias Ringwald 15518691a66cSMatthias Ringwald void avdtp_config_sbc_store(uint8_t * config, const avdtp_configuration_sbc_t * configuration){ 1552fdd788feSMatthias Ringwald avdtp_sbc_channel_mode_t sbc_channel_mode; 15538691a66cSMatthias Ringwald switch (configuration->channel_mode){ 1554fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_MONO: 1555fdd788feSMatthias Ringwald sbc_channel_mode = AVDTP_SBC_MONO; 1556fdd788feSMatthias Ringwald break; 1557fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_DUAL_CHANNEL: 1558fdd788feSMatthias Ringwald sbc_channel_mode = AVDTP_SBC_DUAL_CHANNEL; 1559fdd788feSMatthias Ringwald break; 1560fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_STEREO: 1561fdd788feSMatthias Ringwald sbc_channel_mode = AVDTP_SBC_STEREO; 1562fdd788feSMatthias Ringwald break; 1563fdd788feSMatthias Ringwald default: 1564fdd788feSMatthias Ringwald sbc_channel_mode = AVDTP_SBC_JOINT_STEREO; 1565fdd788feSMatthias Ringwald break; 1566fdd788feSMatthias Ringwald } 1567fdd788feSMatthias Ringwald config[0] = (uint8_t) sbc_channel_mode; 15688691a66cSMatthias Ringwald config[1] = (configuration->block_length << 4) | (configuration->subbands << 2) | configuration->allocation_method; 15698691a66cSMatthias Ringwald config[2] = configuration-> min_bitpool_value; 15708691a66cSMatthias Ringwald config[3] = configuration->max_bitpool_value; 15718691a66cSMatthias Ringwald avdtp_config_sbc_set_sampling_frequency(config, configuration->sampling_frequency); 1572fdd788feSMatthias Ringwald } 1573fdd788feSMatthias Ringwald 1574fdd788feSMatthias Ringwald void avdtp_config_mpeg_audio_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1575fdd788feSMatthias Ringwald uint8_t sampling_frequency_index = 0; 1576fdd788feSMatthias Ringwald switch (sampling_frequency_hz){ 1577fdd788feSMatthias Ringwald case 16000: 1578fdd788feSMatthias Ringwald sampling_frequency_index = 5; 1579fdd788feSMatthias Ringwald break; 1580fdd788feSMatthias Ringwald case 22040: 1581fdd788feSMatthias Ringwald sampling_frequency_index = 4; 1582fdd788feSMatthias Ringwald break; 1583fdd788feSMatthias Ringwald case 24000: 1584fdd788feSMatthias Ringwald sampling_frequency_index = 3; 1585fdd788feSMatthias Ringwald break; 1586fdd788feSMatthias Ringwald case 32000: 1587fdd788feSMatthias Ringwald sampling_frequency_index = 2; 1588fdd788feSMatthias Ringwald break; 1589fdd788feSMatthias Ringwald case 44100: 1590fdd788feSMatthias Ringwald sampling_frequency_index = 1; 1591fdd788feSMatthias Ringwald break; 1592fdd788feSMatthias Ringwald case 48000: 1593fdd788feSMatthias Ringwald sampling_frequency_index = 0; 1594fdd788feSMatthias Ringwald break; 1595f9e215c7SMatthias Ringwald default: 1596f9e215c7SMatthias Ringwald btstack_assert(false); 1597f9e215c7SMatthias Ringwald break; 1598fdd788feSMatthias Ringwald } 1599fdd788feSMatthias Ringwald config[1] = (config[1] & 0xC0) | (1 << sampling_frequency_index); 1600fdd788feSMatthias Ringwald } 1601fdd788feSMatthias Ringwald 16028691a66cSMatthias Ringwald void avdtp_config_mpeg_audio_store(uint8_t * config, const avdtp_configuration_mpeg_audio_t * configuration){ 16038691a66cSMatthias Ringwald config[0] = (1 << (7 - (configuration->layer - AVDTP_MPEG_LAYER_1))) | ((configuration->crc & 0x01) << 4) | (1 << (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO)); 16048691a66cSMatthias Ringwald config[1] = ((configuration->media_payload_format & 0x01) << 6) ; 16058691a66cSMatthias Ringwald uint16_t bit_rate_mask = 1 << configuration->bit_rate_index; 16061da18615SMilanka Ringwald config[2] = ((configuration->vbr & 0x01) << 7) | ((bit_rate_mask >> 7) & 0x3f); 1607fdd788feSMatthias Ringwald config[3] = bit_rate_mask & 0xff; 16088691a66cSMatthias Ringwald avdtp_config_mpeg_audio_set_sampling_frequency(config, configuration->sampling_frequency); 1609fdd788feSMatthias Ringwald } 1610fdd788feSMatthias Ringwald 1611fdd788feSMatthias Ringwald 1612fdd788feSMatthias Ringwald void avdtp_config_mpeg_aac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1613fdd788feSMatthias Ringwald uint16_t sampling_frequency_bitmap = 0; 1614fdd788feSMatthias Ringwald uint8_t i; 1615fdd788feSMatthias Ringwald const uint32_t aac_sampling_frequency_table[] = { 1616fdd788feSMatthias Ringwald 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 1617fdd788feSMatthias Ringwald }; 1618fdd788feSMatthias Ringwald for (i=0;i<12;i++){ 1619fdd788feSMatthias Ringwald if (sampling_frequency_hz == aac_sampling_frequency_table[i]){ 1620fdd788feSMatthias Ringwald sampling_frequency_bitmap = 1 << i; 1621fdd788feSMatthias Ringwald break; 1622fdd788feSMatthias Ringwald } 1623fdd788feSMatthias Ringwald } 1624fdd788feSMatthias Ringwald config[1] = sampling_frequency_bitmap >> 4; 1625fdd788feSMatthias Ringwald config[2] = ((sampling_frequency_bitmap & 0x0f) << 4) | (config[2] & 0x0f); 1626fdd788feSMatthias Ringwald } 1627fdd788feSMatthias Ringwald 1628*c83b8b89SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_store(uint8_t * config, const avdtp_configuration_mpeg_aac_t * configuration) { 16290737c3bfSMilanka Ringwald config[0] = (1 << (7 -(configuration->object_type - AVDTP_AAC_MPEG2_LC))) | (configuration->drc?1u:0u); 1630fdd788feSMatthias Ringwald uint8_t channels_bitmap = 0; 16318691a66cSMatthias Ringwald switch (configuration->channels){ 1632fdd788feSMatthias Ringwald case 1: 16330737c3bfSMilanka Ringwald channels_bitmap = 0x08; 1634fdd788feSMatthias Ringwald break; 1635fdd788feSMatthias Ringwald case 2: 16360737c3bfSMilanka Ringwald channels_bitmap = 0x04; 16370737c3bfSMilanka Ringwald break; 16380737c3bfSMilanka Ringwald case 6: 16390737c3bfSMilanka Ringwald channels_bitmap = 0x02; 16400737c3bfSMilanka Ringwald break; 16410737c3bfSMilanka Ringwald case 8: 1642fdd788feSMatthias Ringwald channels_bitmap = 0x01; 1643fdd788feSMatthias Ringwald break; 1644fdd788feSMatthias Ringwald default: 1645*c83b8b89SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1646fdd788feSMatthias Ringwald } 1647*c83b8b89SMilanka Ringwald config[2] = channels_bitmap; 16488691a66cSMatthias Ringwald config[3] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f); 16498691a66cSMatthias Ringwald config[4] = (configuration->bit_rate >> 8) & 0xff; 16508691a66cSMatthias Ringwald config[5] = configuration->bit_rate & 0xff; 16518691a66cSMatthias Ringwald avdtp_config_mpeg_aac_set_sampling_frequency(config, configuration->sampling_frequency); 1652*c83b8b89SMilanka Ringwald return ERROR_CODE_SUCCESS; 1653fdd788feSMatthias Ringwald } 1654fdd788feSMatthias Ringwald 1655fdd788feSMatthias Ringwald void avdtp_config_atrac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1656fdd788feSMatthias Ringwald uint8_t fs_bitmap = 0; 1657fdd788feSMatthias Ringwald switch (sampling_frequency_hz){ 1658fdd788feSMatthias Ringwald case 44100: 1659fdd788feSMatthias Ringwald fs_bitmap = 2; 1660fdd788feSMatthias Ringwald break; 1661fdd788feSMatthias Ringwald case 48000: 1662fdd788feSMatthias Ringwald fs_bitmap = 1; 1663fdd788feSMatthias Ringwald break; 1664fdd788feSMatthias Ringwald default: 1665fdd788feSMatthias Ringwald break; 1666fdd788feSMatthias Ringwald } 1667fdd788feSMatthias Ringwald config[1] = (fs_bitmap << 4) | (config[1] & 0x0F); 1668fdd788feSMatthias Ringwald } 1669fdd788feSMatthias Ringwald 16708691a66cSMatthias Ringwald void avdtp_config_atrac_store(uint8_t * config, const avdtp_configuration_atrac_t * configuration){ 1671a3868652SMatthias Ringwald uint8_t channel_mode_bitmap = 0; 16728691a66cSMatthias Ringwald switch (configuration->channel_mode){ 1673fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_MONO: 1674a3868652SMatthias Ringwald channel_mode_bitmap = 4; 1675fdd788feSMatthias Ringwald break; 1676fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_DUAL_CHANNEL: 1677a3868652SMatthias Ringwald channel_mode_bitmap = 2; 1678fdd788feSMatthias Ringwald break; 1679fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_JOINT_STEREO: 1680a3868652SMatthias Ringwald channel_mode_bitmap = 1; 1681fdd788feSMatthias Ringwald break; 1682fdd788feSMatthias Ringwald default: 1683fdd788feSMatthias Ringwald break; 1684fdd788feSMatthias Ringwald } 16858691a66cSMatthias Ringwald config[0] = ((configuration->version - AVDTP_ATRAC_VERSION_1 + 1) << 5) | (channel_mode_bitmap << 2); 16868691a66cSMatthias Ringwald uint32_t bit_rate_bitmap = 1 << (0x18 - configuration->bit_rate_index); 16878691a66cSMatthias Ringwald config[1] = ((configuration->vbr & 0x01) << 3) | ((bit_rate_bitmap >> 16) & 0x07); 1688fdd788feSMatthias Ringwald config[2] = (bit_rate_bitmap >> 8) & 0xff; 1689fdd788feSMatthias Ringwald config[3] = bit_rate_bitmap & 0xff; 16908691a66cSMatthias Ringwald config[4] = configuration->maximum_sul >> 8; 16918691a66cSMatthias Ringwald config[5] = configuration->maximum_sul & 0xff; 1692fdd788feSMatthias Ringwald config[6] = 0; 16938691a66cSMatthias Ringwald avdtp_config_atrac_set_sampling_frequency(config, configuration->sampling_frequency); 1694fdd788feSMatthias Ringwald } 169524d5fe84SMilanka Ringwald 169624d5fe84SMilanka Ringwald void avdtp_config_mpegd_usac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 169724d5fe84SMilanka Ringwald uint16_t sampling_frequency_bitmap = 0; 169824d5fe84SMilanka Ringwald uint8_t i; 169924d5fe84SMilanka Ringwald const uint32_t usac_sampling_frequency_table[] = { 170024d5fe84SMilanka Ringwald 96000, 88200, 76800, 70560, 170124d5fe84SMilanka Ringwald 64000, 58800, 48000, 44100, 38400, 35280, 32000, 29400, 170224d5fe84SMilanka Ringwald 24000, 22050, 19200, 17640, 16000, 14700, 12800, 12000, 170324d5fe84SMilanka Ringwald 11760, 11025, 9600, 8820, 8000, 7350 170424d5fe84SMilanka Ringwald }; 170524d5fe84SMilanka Ringwald for (i=0;i<26;i++){ 170624d5fe84SMilanka Ringwald if (sampling_frequency_hz == usac_sampling_frequency_table[i]){ 170724d5fe84SMilanka Ringwald sampling_frequency_bitmap = 1 << i; 170824d5fe84SMilanka Ringwald break; 170924d5fe84SMilanka Ringwald } 171024d5fe84SMilanka Ringwald } 171124d5fe84SMilanka Ringwald config[0] = (config[0] & 0xC0) | sampling_frequency_bitmap >> 20; 171224d5fe84SMilanka Ringwald config[1] = sampling_frequency_bitmap >> 12; 171324d5fe84SMilanka Ringwald config[2] = sampling_frequency_bitmap >> 4; 171424d5fe84SMilanka Ringwald config[3] = (sampling_frequency_bitmap & 0x0f) << 4; 171524d5fe84SMilanka Ringwald } 171624d5fe84SMilanka Ringwald 171724d5fe84SMilanka Ringwald void avdtp_config_mpegd_usac_store(uint8_t * config, const avdtp_configuration_mpegd_usac_t * configuration) { 171824d5fe84SMilanka Ringwald config[0] = 1 << (7 -(configuration->object_type - AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC)) & 0xC0; 171924d5fe84SMilanka Ringwald avdtp_config_mpegd_usac_set_sampling_frequency(config, configuration->sampling_frequency); 172024d5fe84SMilanka Ringwald 172124d5fe84SMilanka Ringwald uint8_t channels_bitmap = 0; 172224d5fe84SMilanka Ringwald switch (configuration->channels){ 172324d5fe84SMilanka Ringwald case 1: 172424d5fe84SMilanka Ringwald channels_bitmap = 0x08; 172524d5fe84SMilanka Ringwald break; 172624d5fe84SMilanka Ringwald case 2: 172724d5fe84SMilanka Ringwald channels_bitmap = 0x04; 172824d5fe84SMilanka Ringwald break; 172924d5fe84SMilanka Ringwald default: 173024d5fe84SMilanka Ringwald break; 173124d5fe84SMilanka Ringwald } 173224d5fe84SMilanka Ringwald config[3] = config[3] | channels_bitmap; 173324d5fe84SMilanka Ringwald config[4] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f); 173424d5fe84SMilanka Ringwald config[5] = (configuration->bit_rate >> 8) & 0xff; 173524d5fe84SMilanka Ringwald config[6] = configuration->bit_rate & 0xff; 173624d5fe84SMilanka Ringwald }