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 "l2cap.h" 488ef7100fSMilanka Ringwald 49f9a5036aSMatthias Ringwald /* 50f9a5036aSMatthias Ringwald 51f9a5036aSMatthias Ringwald List of AVDTP_SUBEVENTs sorted by packet handler 52f9a5036aSMatthias Ringwald 53f9a5036aSMatthias Ringwald 54f9a5036aSMatthias Ringwald Sink + Source: 55f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED 56f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED 57f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_SEP_FOUND 58f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_ACCEPT 59f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_REJECT 60f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT 61f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY 62f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY 63f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY 64f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY 65f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY 66f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY 67f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY 68f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY 69f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY 70f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE 71f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE 72f9a5036aSMatthias Ringwald 73f9a5036aSMatthias Ringwald Source: 74f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT 75f9a5036aSMatthias Ringwald 76f9a5036aSMatthias Ringwald Sink or Source based on SEP Type: 77f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED 78f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED 79f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW 80f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION 81f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION 82f9a5036aSMatthias Ringwald 83f9a5036aSMatthias Ringwald */ 84f9a5036aSMatthias Ringwald 85ee230fc4SMilanka Ringwald static const char * avdtp_si_name[] = { 86ee230fc4SMilanka Ringwald "ERROR", 87ee230fc4SMilanka Ringwald "AVDTP_SI_DISCOVER", 88ee230fc4SMilanka Ringwald "AVDTP_SI_GET_CAPABILITIES", 89ee230fc4SMilanka Ringwald "AVDTP_SI_SET_CONFIGURATION", 90ee230fc4SMilanka Ringwald "AVDTP_SI_GET_CONFIGURATION", 91ee230fc4SMilanka Ringwald "AVDTP_SI_RECONFIGURE", 92ee230fc4SMilanka Ringwald "AVDTP_SI_OPEN", 93ee230fc4SMilanka Ringwald "AVDTP_SI_START", 94ee230fc4SMilanka Ringwald "AVDTP_SI_CLOSE", 95ee230fc4SMilanka Ringwald "AVDTP_SI_SUSPEND", 96ee230fc4SMilanka Ringwald "AVDTP_SI_ABORT", 97ee230fc4SMilanka Ringwald "AVDTP_SI_SECURITY_CONTROL", 98ee230fc4SMilanka Ringwald "AVDTP_SI_GET_ALL_CAPABILITIES", 99ee230fc4SMilanka Ringwald "AVDTP_SI_DELAY_REPORT" 100ee230fc4SMilanka Ringwald }; 101ee230fc4SMilanka Ringwald const char * avdtp_si2str(uint16_t index){ 102c1e2cdaaSaroldxd if ((index <= 0) || (index >= sizeof(avdtp_si_name)/sizeof(avdtp_si_name[0]) )) return avdtp_si_name[0]; 103ee230fc4SMilanka Ringwald return avdtp_si_name[index]; 104ee230fc4SMilanka Ringwald } 105ee230fc4SMilanka Ringwald 106485c0a4cSMilanka Ringwald void avdtp_reset_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ 107485c0a4cSMilanka Ringwald stream_endpoint->media_con_handle = 0; 108485c0a4cSMilanka Ringwald stream_endpoint->l2cap_media_cid = 0; 109485c0a4cSMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0; 110485c0a4cSMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0; 111485c0a4cSMilanka Ringwald 112747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 113747ec646SMilanka Ringwald stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE; 114747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE; 115485c0a4cSMilanka Ringwald 116b3b67de4SMilanka Ringwald stream_endpoint->connection = NULL; 117b3b67de4SMilanka Ringwald 118747ec646SMilanka Ringwald stream_endpoint->sep.in_use = 0; 119485c0a4cSMilanka Ringwald memset(&stream_endpoint->remote_sep, 0, sizeof(avdtp_sep_t)); 120485c0a4cSMilanka Ringwald 121485c0a4cSMilanka Ringwald stream_endpoint->remote_capabilities_bitmap = 0; 122b3b67de4SMilanka Ringwald memset(&stream_endpoint->remote_capabilities, 0, sizeof(avdtp_capabilities_t)); 123485c0a4cSMilanka Ringwald stream_endpoint->remote_configuration_bitmap = 0; 124b3b67de4SMilanka Ringwald memset(&stream_endpoint->remote_configuration, 0, sizeof(avdtp_capabilities_t)); 125b3b67de4SMilanka Ringwald 12682767773SMatthias Ringwald // temporary SBC config used by A2DP Source 127ec9b5b0fSMatthias Ringwald memset(stream_endpoint->media_codec_info, 0, 8); 128485c0a4cSMilanka Ringwald 129485c0a4cSMilanka Ringwald stream_endpoint->media_disconnect = 0; 130485c0a4cSMilanka Ringwald stream_endpoint->media_connect = 0; 131485c0a4cSMilanka Ringwald stream_endpoint->start_stream = 0; 132fa4419dbSMilanka Ringwald stream_endpoint->close_stream = 0; 133d0676819SMatthias Ringwald stream_endpoint->request_can_send_now = false; 134485c0a4cSMilanka Ringwald stream_endpoint->abort_stream = 0; 135485c0a4cSMilanka Ringwald stream_endpoint->suspend_stream = 0; 136485c0a4cSMilanka Ringwald stream_endpoint->sequence_number = 0; 137747ec646SMilanka Ringwald } 138747ec646SMilanka Ringwald 1398ef7100fSMilanka Ringwald int get_bit16(uint16_t bitmap, int position){ 1408ef7100fSMilanka Ringwald return (bitmap >> position) & 1; 1418ef7100fSMilanka Ringwald } 1428ef7100fSMilanka Ringwald 143ea6072afSMilanka Ringwald uint16_t store_bit16(uint16_t bitmap, int position, uint8_t value){ 1448ef7100fSMilanka Ringwald if (value){ 1458ef7100fSMilanka Ringwald bitmap |= 1 << position; 1468ef7100fSMilanka Ringwald } else { 1478ef7100fSMilanka Ringwald bitmap &= ~ (1 << position); 1488ef7100fSMilanka Ringwald } 1498ef7100fSMilanka Ringwald return bitmap; 1508ef7100fSMilanka Ringwald } 1518ef7100fSMilanka Ringwald 152335dba6aSMatthias Ringwald avdtp_message_type_t avdtp_get_signaling_message_type(uint8_t * packet){ 153c1c40ea1SMatthias Ringwald return (avdtp_message_type_t) (packet[0] & 0x03); 154c1c40ea1SMatthias Ringwald } 155c1c40ea1SMatthias Ringwald 1563d79ed3bSMatthias Ringwald // returns 0 if header incomplete 1578ef7100fSMilanka Ringwald int avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header, uint8_t * packet, uint16_t size){ 1588ef7100fSMilanka Ringwald int pos = 0; 1593d79ed3bSMatthias Ringwald if (size < 2) return 0; 1608ef7100fSMilanka Ringwald signaling_header->transaction_label = packet[pos] >> 4; 1618ef7100fSMilanka Ringwald signaling_header->packet_type = (avdtp_packet_type_t)((packet[pos] >> 2) & 0x03); 1628ef7100fSMilanka Ringwald signaling_header->message_type = (avdtp_message_type_t) (packet[pos] & 0x03); 1638ef7100fSMilanka Ringwald pos++; 1648ef7100fSMilanka Ringwald memset(signaling_header->command, 0, sizeof(signaling_header->command)); 1658ef7100fSMilanka Ringwald switch (signaling_header->packet_type){ 1668ef7100fSMilanka Ringwald case AVDTP_SINGLE_PACKET: 1678ef7100fSMilanka Ringwald signaling_header->num_packets = 0; 1688ef7100fSMilanka Ringwald signaling_header->offset = 0; 1698ef7100fSMilanka Ringwald signaling_header->size = 0; 1708ef7100fSMilanka Ringwald break; 1718ef7100fSMilanka Ringwald case AVDTP_END_PACKET: 1728ef7100fSMilanka Ringwald signaling_header->num_packets = 0; 1738ef7100fSMilanka Ringwald break; 1748ef7100fSMilanka Ringwald case AVDTP_START_PACKET: 1758ef7100fSMilanka Ringwald signaling_header->num_packets = packet[pos++]; 1763d79ed3bSMatthias Ringwald if (pos < 3) return 0; 1778ef7100fSMilanka Ringwald signaling_header->size = 0; 1788ef7100fSMilanka Ringwald signaling_header->offset = 0; 1798ef7100fSMilanka Ringwald break; 1808ef7100fSMilanka Ringwald case AVDTP_CONTINUE_PACKET: 1818ef7100fSMilanka Ringwald if (signaling_header->num_packets <= 0) { 1828587e32cSMilanka Ringwald log_info(" ERROR: wrong num fragmented packets\n"); 1838ef7100fSMilanka Ringwald break; 1848ef7100fSMilanka Ringwald } 1858ef7100fSMilanka Ringwald signaling_header->num_packets--; 1868ef7100fSMilanka Ringwald break; 1877bbeb3adSMilanka Ringwald default: 1887bbeb3adSMilanka Ringwald btstack_assert(false); 1897bbeb3adSMilanka Ringwald break; 1908ef7100fSMilanka Ringwald } 191b0920f25SMilanka Ringwald signaling_header->signal_identifier = (avdtp_signal_identifier_t)(packet[pos++] & 0x3f); 1928ef7100fSMilanka Ringwald return pos; 1938ef7100fSMilanka Ringwald } 1948ef7100fSMilanka Ringwald 19550d5c6caSMatthias Ringwald static bool avdtp_is_basic_capability(int service_category){ 19650d5c6caSMatthias Ringwald return (AVDTP_MEDIA_TRANSPORT <= service_category) && (service_category <= AVDTP_MEDIA_CODEC); 19750d5c6caSMatthias Ringwald } 19850d5c6caSMatthias Ringwald 19950d5c6caSMatthias Ringwald int avdtp_pack_service_capabilities(uint8_t *buffer, int size, avdtp_capabilities_t caps, avdtp_service_category_t category) { 2008ef7100fSMilanka Ringwald UNUSED(size); 2018ef7100fSMilanka Ringwald 2028ef7100fSMilanka Ringwald int i; 2038ef7100fSMilanka Ringwald // pos = 0 reserved for length 2048ef7100fSMilanka Ringwald int pos = 1; 2058ef7100fSMilanka Ringwald switch(category){ 2068ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 2078ef7100fSMilanka Ringwald case AVDTP_REPORTING: 2088ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 2098ef7100fSMilanka Ringwald break; 2108ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 2118ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.recovery_type; // 0x01=RFC2733 2128ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.maximum_recovery_window_size; 2138ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.maximum_number_media_packets; 2148ef7100fSMilanka Ringwald break; 2158ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 2168ef7100fSMilanka Ringwald buffer[pos++] = caps.content_protection.cp_type_value_len + 2; 2178ef7100fSMilanka Ringwald big_endian_store_16(buffer, pos, caps.content_protection.cp_type); 2188ef7100fSMilanka Ringwald pos += 2; 2196535961aSMatthias Ringwald (void)memcpy(buffer + pos, caps.content_protection.cp_type_value, 2206535961aSMatthias Ringwald caps.content_protection.cp_type_value_len); 22174b2411bSMilanka Ringwald pos += caps.content_protection.cp_type_value_len; 2228ef7100fSMilanka Ringwald break; 2238ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 2248ef7100fSMilanka Ringwald buffer[pos++] = (caps.header_compression.back_ch << 7) | (caps.header_compression.media << 6) | (caps.header_compression.recovery << 5); 2258ef7100fSMilanka Ringwald break; 2268ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 2278ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.fragmentation << 7; 2288ef7100fSMilanka Ringwald for (i=0; i<caps.multiplexing_mode.transport_identifiers_num; i++){ 2298ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.transport_session_identifiers[i] << 7; 2308ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.tcid[i] << 7; 2318ef7100fSMilanka Ringwald // media, reporting. recovery 2328ef7100fSMilanka Ringwald } 2338ef7100fSMilanka Ringwald break; 2348ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 2358ef7100fSMilanka Ringwald buffer[pos++] = ((uint8_t)caps.media_codec.media_type) << 4; 2368ef7100fSMilanka Ringwald buffer[pos++] = (uint8_t)caps.media_codec.media_codec_type; 2378ef7100fSMilanka Ringwald for (i = 0; i<caps.media_codec.media_codec_information_len; i++){ 2388ef7100fSMilanka Ringwald buffer[pos++] = caps.media_codec.media_codec_information[i]; 2398ef7100fSMilanka Ringwald } 2408ef7100fSMilanka Ringwald break; 2418ef7100fSMilanka Ringwald default: 2428ef7100fSMilanka Ringwald break; 2438ef7100fSMilanka Ringwald } 2448ef7100fSMilanka Ringwald buffer[0] = pos - 1; // length 2458ef7100fSMilanka Ringwald return pos; 2468ef7100fSMilanka Ringwald } 2478ef7100fSMilanka Ringwald 248390aa582SMatthias 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){ 2498ef7100fSMilanka Ringwald connection->error_code = 0; 2508ef7100fSMilanka Ringwald 25176827215SMatthias Ringwald if ((category == AVDTP_SERVICE_CATEGORY_INVALID_0) || (category > AVDTP_DELAY_REPORTING)){ 2528587e32cSMilanka Ringwald log_info(" ERROR: BAD SERVICE CATEGORY %d\n", category); 2538ef7100fSMilanka Ringwald connection->reject_service_category = category; 2545b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_SERV_CATEGORY; 2558ef7100fSMilanka Ringwald return 1; 2568ef7100fSMilanka Ringwald } 2578ef7100fSMilanka Ringwald 258390aa582SMatthias Ringwald if (signal_identifier == AVDTP_SI_RECONFIGURE){ 2590e588213SMatthias Ringwald if ( (category != AVDTP_CONTENT_PROTECTION) && (category != AVDTP_MEDIA_CODEC)){ 2608587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, INVALID_CAPABILITIES\n"); 2618ef7100fSMilanka Ringwald connection->reject_service_category = category; 2625b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_INVALID_CAPABILITIES; 2638ef7100fSMilanka Ringwald return 1; 2648ef7100fSMilanka Ringwald } 2658ef7100fSMilanka Ringwald } 2668ef7100fSMilanka Ringwald 2678ef7100fSMilanka Ringwald switch(category){ 2688ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 2698ef7100fSMilanka Ringwald if (cap_len != 0){ 2708587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n"); 2718ef7100fSMilanka Ringwald connection->reject_service_category = category; 2725b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_MEDIA_TRANSPORT_FORMAT; 2738ef7100fSMilanka Ringwald return 1; 2748ef7100fSMilanka Ringwald } 2758ef7100fSMilanka Ringwald break; 2768ef7100fSMilanka Ringwald case AVDTP_REPORTING: 2778ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 2788ef7100fSMilanka Ringwald if (cap_len != 0){ 2798587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_LENGTH\n"); 2808ef7100fSMilanka Ringwald connection->reject_service_category = category; 2815b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_LENGTH; 2828ef7100fSMilanka Ringwald return 1; 2838ef7100fSMilanka Ringwald } 2848ef7100fSMilanka Ringwald break; 2858ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 286f6f3c903SMilanka Ringwald if (cap_len != 3){ 2878587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n"); 2888ef7100fSMilanka Ringwald connection->reject_service_category = category; 2895b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_RECOVERY_FORMAT; 2908ef7100fSMilanka Ringwald return 1; 2918ef7100fSMilanka Ringwald } 2928ef7100fSMilanka Ringwald break; 2938ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 2948ef7100fSMilanka Ringwald if (cap_len < 2){ 2958587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_CP_FORMAT\n"); 2968ef7100fSMilanka Ringwald connection->reject_service_category = category; 2975b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_CP_FORMAT; 2988ef7100fSMilanka Ringwald return 1; 2998ef7100fSMilanka Ringwald } 3008ef7100fSMilanka Ringwald break; 3018ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 302f6f3c903SMilanka Ringwald // TODO: find error code for bad header compression 303f6f3c903SMilanka Ringwald if (cap_len != 1){ 304f6f3c903SMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_HEADER_COMPRESSION\n"); 305f6f3c903SMilanka Ringwald connection->reject_service_category = category; 3065b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_RECOVERY_FORMAT; 307f6f3c903SMilanka Ringwald return 1; 308f6f3c903SMilanka Ringwald } 3098ef7100fSMilanka Ringwald break; 3108ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 3118ef7100fSMilanka Ringwald break; 3128ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 3138ef7100fSMilanka Ringwald break; 3148ef7100fSMilanka Ringwald default: 3158ef7100fSMilanka Ringwald break; 3168ef7100fSMilanka Ringwald } 3178ef7100fSMilanka Ringwald return 0; 3188ef7100fSMilanka Ringwald } 3198ef7100fSMilanka Ringwald 320afc28e0aSMatthias 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){ 321f6f3c903SMilanka Ringwald 322f6f3c903SMilanka Ringwald int i; 3238ef7100fSMilanka Ringwald 3248ef7100fSMilanka Ringwald uint16_t registered_service_categories = 0; 325f6f3c903SMilanka Ringwald uint16_t to_process = size; 326f6f3c903SMilanka Ringwald 327f6f3c903SMilanka Ringwald while (to_process >= 2){ 328f6f3c903SMilanka Ringwald 329f6f3c903SMilanka Ringwald avdtp_service_category_t category = (avdtp_service_category_t) packet[0]; 330f6f3c903SMilanka Ringwald uint8_t cap_len = packet[1]; 331f6f3c903SMilanka Ringwald packet += 2; 332f6f3c903SMilanka Ringwald to_process -= 2; 333f6f3c903SMilanka Ringwald 334f6f3c903SMilanka Ringwald if (cap_len > to_process){ 3358ef7100fSMilanka Ringwald connection->reject_service_category = category; 3365b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_LENGTH; 3378ef7100fSMilanka Ringwald return 0; 3388ef7100fSMilanka Ringwald } 33967ae582dSMilanka Ringwald 340afc28e0aSMatthias Ringwald if (avdtp_unpack_service_capabilities_has_errors(connection, signal_identifier, category, cap_len)) return 0; 34167ae582dSMilanka Ringwald 342f6f3c903SMilanka Ringwald int category_valid = 1; 34367ae582dSMilanka Ringwald 344f6f3c903SMilanka Ringwald uint8_t * data = packet; 345f6f3c903SMilanka Ringwald uint16_t pos = 0; 346f6f3c903SMilanka Ringwald 3478ef7100fSMilanka Ringwald switch(category){ 3488ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 349f6f3c903SMilanka Ringwald caps->recovery.recovery_type = data[pos++]; 350f6f3c903SMilanka Ringwald caps->recovery.maximum_recovery_window_size = data[pos++]; 351f6f3c903SMilanka Ringwald caps->recovery.maximum_number_media_packets = data[pos++]; 3528ef7100fSMilanka Ringwald break; 3538ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 354f6f3c903SMilanka Ringwald caps->content_protection.cp_type = big_endian_read_16(data, 0); 3558ef7100fSMilanka Ringwald caps->content_protection.cp_type_value_len = cap_len - 2; 3568ef7100fSMilanka Ringwald // connection->reject_service_category = category; 3578ef7100fSMilanka Ringwald // connection->error_code = UNSUPPORTED_CONFIGURATION; 3588ef7100fSMilanka Ringwald // support for content protection goes here 3598ef7100fSMilanka Ringwald break; 3608ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 361f6f3c903SMilanka Ringwald caps->header_compression.back_ch = (data[0] >> 7) & 1; 362f6f3c903SMilanka Ringwald caps->header_compression.media = (data[0] >> 6) & 1; 363f6f3c903SMilanka Ringwald caps->header_compression.recovery = (data[0] >> 5) & 1; 3648ef7100fSMilanka Ringwald break; 3658ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 366f6f3c903SMilanka Ringwald caps->multiplexing_mode.fragmentation = (data[pos++] >> 7) & 1; 3678ef7100fSMilanka Ringwald // read [tsid, tcid] for media, reporting. recovery respectively 3688ef7100fSMilanka Ringwald caps->multiplexing_mode.transport_identifiers_num = 3; 3698ef7100fSMilanka Ringwald for (i=0; i<caps->multiplexing_mode.transport_identifiers_num; i++){ 370f6f3c903SMilanka Ringwald caps->multiplexing_mode.transport_session_identifiers[i] = (data[pos++] >> 7) & 1; 371f6f3c903SMilanka Ringwald caps->multiplexing_mode.tcid[i] = (data[pos++] >> 7) & 1; 3728ef7100fSMilanka Ringwald } 3738ef7100fSMilanka Ringwald break; 3748ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 375f6f3c903SMilanka Ringwald caps->media_codec.media_type = (avdtp_media_type_t)(data[pos++] >> 4); 376f6f3c903SMilanka Ringwald caps->media_codec.media_codec_type = (avdtp_media_codec_type_t)(data[pos++]); 3778ef7100fSMilanka Ringwald caps->media_codec.media_codec_information_len = cap_len - 2; 3784c7a1d3aSMatthias Ringwald caps->media_codec.media_codec_information = &data[pos++]; 3798ef7100fSMilanka Ringwald break; 3808ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 3818ef7100fSMilanka Ringwald case AVDTP_REPORTING: 3828ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 3838ef7100fSMilanka Ringwald break; 3848ef7100fSMilanka Ringwald default: 385f6f3c903SMilanka Ringwald category_valid = 0; 3868ef7100fSMilanka Ringwald break; 3878ef7100fSMilanka Ringwald } 3888ef7100fSMilanka Ringwald 389f6f3c903SMilanka Ringwald if (category_valid) { 3908ef7100fSMilanka Ringwald registered_service_categories = store_bit16(registered_service_categories, category, 1); 3918ef7100fSMilanka Ringwald } 392f6f3c903SMilanka Ringwald 393f6f3c903SMilanka Ringwald packet += cap_len; 394f6f3c903SMilanka Ringwald to_process -= cap_len; 39567ae582dSMilanka Ringwald } 396f6f3c903SMilanka Ringwald 3978ef7100fSMilanka Ringwald return registered_service_categories; 3988ef7100fSMilanka Ringwald } 3998ef7100fSMilanka Ringwald 40050d5c6caSMatthias 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){ 4018ef7100fSMilanka Ringwald if (signaling_packet->offset) return; 40250d5c6caSMatthias Ringwald bool basic_capabilities_only = false; 4038ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_RESPONSE_ACCEPT_MSG; 4048ef7100fSMilanka Ringwald int i; 405747ec646SMilanka Ringwald 406747ec646SMilanka Ringwald signaling_packet->size = 0; 407747ec646SMilanka Ringwald memset(signaling_packet->command, 0 , sizeof(signaling_packet->command)); 408747ec646SMilanka Ringwald 4098ef7100fSMilanka Ringwald switch (identifier) { 4108ef7100fSMilanka Ringwald case AVDTP_SI_GET_CAPABILITIES: 41150d5c6caSMatthias Ringwald basic_capabilities_only = true; 4128ef7100fSMilanka Ringwald break; 4138ef7100fSMilanka Ringwald case AVDTP_SI_GET_ALL_CAPABILITIES: 4148ef7100fSMilanka Ringwald break; 4158ef7100fSMilanka Ringwald case AVDTP_SI_SET_CONFIGURATION: 416747ec646SMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->acp_seid << 2; 4178ef7100fSMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->int_seid << 2; 4188ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_CMD_MSG; 4198ef7100fSMilanka Ringwald break; 4208ef7100fSMilanka Ringwald case AVDTP_SI_RECONFIGURE: 421747ec646SMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->acp_seid << 2; 4228ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_CMD_MSG; 4238ef7100fSMilanka Ringwald break; 4248ef7100fSMilanka Ringwald default: 4258ef7100fSMilanka Ringwald log_error("avdtp_prepare_capabilities wrong identifier %d", identifier); 4268ef7100fSMilanka Ringwald break; 4278ef7100fSMilanka Ringwald } 4288ef7100fSMilanka Ringwald 42950d5c6caSMatthias Ringwald for (i = AVDTP_MEDIA_TRANSPORT; i <= AVDTP_DELAY_REPORTING; i++){ 43050d5c6caSMatthias Ringwald int registered_category = get_bit16(service_categories, i); 4312bb3471fSMilanka Ringwald if (!registered_category && (identifier == AVDTP_SI_SET_CONFIGURATION)){ 432747ec646SMilanka Ringwald // TODO: introduce bitmap of mandatory categories 43350d5c6caSMatthias Ringwald if (i == AVDTP_MEDIA_TRANSPORT){ 43450d5c6caSMatthias Ringwald registered_category = true; 435747ec646SMilanka Ringwald } 436747ec646SMilanka Ringwald } 43750d5c6caSMatthias Ringwald // AVDTP_SI_GET_CAPABILITIES reports only basic capabilities (i.e., it skips non-basic categories) 43850d5c6caSMatthias Ringwald if (basic_capabilities_only && !avdtp_is_basic_capability(i)){ 43950d5c6caSMatthias Ringwald registered_category = false; 44050d5c6caSMatthias Ringwald } 44150d5c6caSMatthias Ringwald 442747ec646SMilanka Ringwald if (registered_category){ 4438ef7100fSMilanka Ringwald // service category 4448ef7100fSMilanka Ringwald signaling_packet->command[signaling_packet->size++] = i; 44550d5c6caSMatthias Ringwald signaling_packet->size += avdtp_pack_service_capabilities(signaling_packet->command + signaling_packet->size, 44650d5c6caSMatthias Ringwald sizeof(signaling_packet->command) - signaling_packet->size, capabilities, (avdtp_service_category_t) i); 4478ef7100fSMilanka Ringwald } 4488ef7100fSMilanka Ringwald } 449b0920f25SMilanka Ringwald signaling_packet->signal_identifier = (avdtp_signal_identifier_t)identifier; 4508ef7100fSMilanka Ringwald signaling_packet->transaction_label = transaction_label; 4518ef7100fSMilanka Ringwald } 4528ef7100fSMilanka Ringwald 4538ef7100fSMilanka Ringwald int avdtp_signaling_create_fragment(uint16_t cid, avdtp_signaling_packet_t * signaling_packet, uint8_t * out_buffer) { 4548ef7100fSMilanka Ringwald int mtu = l2cap_get_remote_mtu_for_local_cid(cid); 4558ef7100fSMilanka Ringwald int data_len = 0; 4568ef7100fSMilanka Ringwald 4578ef7100fSMilanka Ringwald uint16_t offset = signaling_packet->offset; 4588ef7100fSMilanka Ringwald uint16_t pos = 1; 4598ef7100fSMilanka Ringwald 4608ef7100fSMilanka Ringwald if (offset == 0){ 461c1ab6cc1SMatthias Ringwald if (signaling_packet->size <= (mtu - 2)){ 4628ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_SINGLE_PACKET; 4638ef7100fSMilanka Ringwald out_buffer[pos++] = signaling_packet->signal_identifier; 4648ef7100fSMilanka Ringwald data_len = signaling_packet->size; 4658ef7100fSMilanka Ringwald } else { 4668ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_START_PACKET; 4678ef7100fSMilanka Ringwald out_buffer[pos++] = (mtu + signaling_packet->size)/ (mtu-1); 4688ef7100fSMilanka Ringwald out_buffer[pos++] = signaling_packet->signal_identifier; 4698ef7100fSMilanka Ringwald data_len = mtu - 3; 4708ef7100fSMilanka Ringwald signaling_packet->offset = data_len; 4718ef7100fSMilanka Ringwald } 4728ef7100fSMilanka Ringwald } else { 4738ef7100fSMilanka Ringwald int remaining_bytes = signaling_packet->size - offset; 474c1ab6cc1SMatthias Ringwald if (remaining_bytes <= (mtu - 1)){ 4758ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_END_PACKET; 4768ef7100fSMilanka Ringwald data_len = remaining_bytes; 4778ef7100fSMilanka Ringwald signaling_packet->offset = 0; 4788ef7100fSMilanka Ringwald } else{ 4798ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_CONTINUE_PACKET; 4808ef7100fSMilanka Ringwald data_len = mtu - 1; 4818ef7100fSMilanka Ringwald signaling_packet->offset += data_len; 4828ef7100fSMilanka Ringwald } 4838ef7100fSMilanka Ringwald } 4848ef7100fSMilanka Ringwald out_buffer[0] = avdtp_header(signaling_packet->transaction_label, signaling_packet->packet_type, signaling_packet->message_type); 4856535961aSMatthias Ringwald (void)memcpy(out_buffer + pos, signaling_packet->command + offset, 4866535961aSMatthias Ringwald data_len); 4878ef7100fSMilanka Ringwald pos += data_len; 4888ef7100fSMilanka Ringwald return pos; 4898ef7100fSMilanka Ringwald } 4908ef7100fSMilanka Ringwald 4918ef7100fSMilanka Ringwald 492146fc0fbSMilanka Ringwald void avdtp_signaling_emit_connection_established(uint16_t avdtp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status) { 493146fc0fbSMilanka Ringwald uint8_t event[14]; 4948ef7100fSMilanka Ringwald int pos = 0; 4958ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 4968ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 4978ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED; 498f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 4998ef7100fSMilanka Ringwald pos += 2; 5008ef7100fSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 5018ef7100fSMilanka Ringwald pos += 6; 502146fc0fbSMilanka Ringwald little_endian_store_16(event, pos, con_handle); 503146fc0fbSMilanka Ringwald pos += 2; 5048ef7100fSMilanka Ringwald event[pos++] = status; 505c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5068ef7100fSMilanka Ringwald } 5078ef7100fSMilanka Ringwald 508c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_connection_released(uint16_t avdtp_cid) { 50934b22aacSMilanka Ringwald uint8_t event[5]; 51034b22aacSMilanka Ringwald int pos = 0; 51134b22aacSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 51234b22aacSMilanka Ringwald event[pos++] = sizeof(event) - 2; 51334b22aacSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED; 51434b22aacSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 51534b22aacSMilanka Ringwald pos += 2; 516c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 51734b22aacSMilanka Ringwald } 51834b22aacSMilanka Ringwald 519c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_sep(uint16_t avdtp_cid, avdtp_sep_t sep) { 5208ef7100fSMilanka Ringwald uint8_t event[9]; 5218ef7100fSMilanka Ringwald int pos = 0; 5228ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5238ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5248ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_FOUND; 525f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5268ef7100fSMilanka Ringwald pos += 2; 5278ef7100fSMilanka Ringwald event[pos++] = sep.seid; 5288ef7100fSMilanka Ringwald event[pos++] = sep.in_use; 5298ef7100fSMilanka Ringwald event[pos++] = sep.media_type; 5308ef7100fSMilanka Ringwald event[pos++] = sep.type; 531c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5328ef7100fSMilanka Ringwald } 5338ef7100fSMilanka Ringwald 534c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_sep_done(uint16_t avdtp_cid) { 535485c0a4cSMilanka Ringwald uint8_t event[5]; 536485c0a4cSMilanka Ringwald int pos = 0; 537485c0a4cSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 538485c0a4cSMilanka Ringwald event[pos++] = sizeof(event) - 2; 539485c0a4cSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE; 540485c0a4cSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 541485c0a4cSMilanka Ringwald pos += 2; 542c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 543485c0a4cSMilanka Ringwald } 544485c0a4cSMilanka Ringwald 545c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_accept(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 54663274943SMilanka Ringwald uint8_t event[8]; 5478ef7100fSMilanka Ringwald int pos = 0; 5488ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5498ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5508ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT; 551f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5528ef7100fSMilanka Ringwald pos += 2; 5534ccacc40SMilanka Ringwald event[pos++] = local_seid; 55463274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 5558ef7100fSMilanka Ringwald event[pos++] = identifier; 556c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5578ef7100fSMilanka Ringwald } 5588ef7100fSMilanka Ringwald 55946b99c89SMatthias 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){ 56046b99c89SMatthias Ringwald uint8_t event[8]; 56146b99c89SMatthias Ringwald int pos = 0; 56246b99c89SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 56346b99c89SMatthias Ringwald event[pos++] = sizeof(event) - 2; 56446b99c89SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT; 56546b99c89SMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 56646b99c89SMatthias Ringwald pos += 2; 56746b99c89SMatthias Ringwald event[pos++] = local_seid; 56846b99c89SMatthias Ringwald event[pos++] = is_initiator ? 1 : 0; 56946b99c89SMatthias Ringwald event[pos++] = identifier; 57046b99c89SMatthias Ringwald 57146b99c89SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 57246b99c89SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 57346b99c89SMatthias Ringwald } 57446b99c89SMatthias Ringwald 575c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_reject(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 57663274943SMilanka Ringwald uint8_t event[8]; 5778ef7100fSMilanka Ringwald int pos = 0; 5788ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5798ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5808ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_REJECT; 581f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5828ef7100fSMilanka Ringwald pos += 2; 5834ccacc40SMilanka Ringwald event[pos++] = local_seid; 58463274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 5858ef7100fSMilanka Ringwald event[pos++] = identifier; 586c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5878ef7100fSMilanka Ringwald } 5888ef7100fSMilanka Ringwald 589c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_general_reject(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 59063274943SMilanka Ringwald uint8_t event[8]; 5918ef7100fSMilanka Ringwald int pos = 0; 5928ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5938ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5948ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT; 595f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5968ef7100fSMilanka Ringwald pos += 2; 5974ccacc40SMilanka Ringwald event[pos++] = local_seid; 59863274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 5998ef7100fSMilanka Ringwald event[pos++] = identifier; 600c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6018ef7100fSMilanka Ringwald } 6028ef7100fSMilanka Ringwald 6034b7d40bbSMatthias Ringwald static inline void 6041159d239SMatthias Ringwald avdtp_signaling_emit_capability(uint8_t capability_subevent_id, uint16_t avdtp_cid, uint8_t remote_seid) { 6051159d239SMatthias Ringwald uint8_t event[6]; 6064b7d40bbSMatthias Ringwald int pos = 0; 6074b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6084b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 6094b7d40bbSMatthias Ringwald event[pos++] = capability_subevent_id; 6104b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 6114b7d40bbSMatthias Ringwald pos += 2; 6124b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 6134b7d40bbSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6144b7d40bbSMatthias Ringwald } 6154b7d40bbSMatthias Ringwald 6161159d239SMatthias 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) { 6175ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 6181159d239SMatthias Ringwald uint8_t event[14]; 6198ef7100fSMilanka Ringwald int pos = 0; 6208ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6218ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 6228ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY; 623f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 6248ef7100fSMilanka Ringwald pos += 2; 6254ccacc40SMilanka Ringwald event[pos++] = remote_seid; 6268ef7100fSMilanka Ringwald event[pos++] = media_codec.media_type; 6275ce3497fSMatthias Ringwald event[pos++] = media_codec_information[0] >> 4; 6285ce3497fSMatthias Ringwald event[pos++] = media_codec_information[0] & 0x0F; 6295ce3497fSMatthias Ringwald event[pos++] = media_codec_information[1] >> 4; 6305ce3497fSMatthias Ringwald event[pos++] = (media_codec_information[1] & 0x0F) >> 2; 6315ce3497fSMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03; 6325ce3497fSMatthias Ringwald event[pos++] = media_codec_information[2]; 6335ce3497fSMatthias Ringwald event[pos++] = media_codec_information[3]; 6345ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6355ce3497fSMatthias Ringwald } 6365ce3497fSMatthias Ringwald 6375ce3497fSMatthias 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) { 6385ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 6395ce3497fSMatthias Ringwald uint8_t event[15]; 6405ce3497fSMatthias Ringwald int pos = 0; 6415ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6425ce3497fSMatthias Ringwald event[pos++] = sizeof(event) - 2; 6435ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CAPABILITY; 6445ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 6455ce3497fSMatthias Ringwald pos += 2; 6465ce3497fSMatthias Ringwald event[pos++] = remote_seid; 6475ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 6485ce3497fSMatthias Ringwald 6495ce3497fSMatthias Ringwald uint8_t layer_bitmap = media_codec_information[0] >> 5; 6505ce3497fSMatthias Ringwald uint8_t crc = (media_codec_information[0] >> 4) & 0x01; 6515ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x07; 6525ce3497fSMatthias Ringwald uint8_t mpf = (media_codec_information[1] >> 6) & 0x01; 6535ce3497fSMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[1] & 0x3F; 6545ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[2] >> 7) & 0x01; 6555ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[3] & 0x3f) << 8) | media_codec.media_codec_information[4]; 6565ce3497fSMatthias Ringwald 6575ce3497fSMatthias Ringwald event[pos++] = layer_bitmap; 6585ce3497fSMatthias Ringwald event[pos++] = crc; 6595ce3497fSMatthias Ringwald event[pos++] = channel_mode_bitmap; 6605ce3497fSMatthias Ringwald event[pos++] = mpf; 6615ce3497fSMatthias Ringwald event[pos++] = sampling_frequency_bitmap; 6625ce3497fSMatthias Ringwald event[pos++] = vbr; 6635ce3497fSMatthias Ringwald little_endian_store_16(event, pos, bit_rate_index_bitmap); // bit rate index 6645ce3497fSMatthias Ringwald pos += 2; 6655ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6665ce3497fSMatthias Ringwald } 6675ce3497fSMatthias Ringwald 6685ce3497fSMatthias 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) { 6695ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 6705ce3497fSMatthias Ringwald uint8_t event[15]; 6715ce3497fSMatthias Ringwald int pos = 0; 6725ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6735ce3497fSMatthias Ringwald event[pos++] = sizeof(event) - 2; 6745ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CAPABILITY; 6755ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 6765ce3497fSMatthias Ringwald pos += 2; 6775ce3497fSMatthias Ringwald event[pos++] = remote_seid; 6785ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 6795ce3497fSMatthias Ringwald 6801da18615SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 1; 6811da18615SMilanka Ringwald uint8_t drc = media_codec_information[0] & 0x01; 6825ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] << 4) | (media_codec_information[2] >> 4); 6831da18615SMilanka Ringwald uint8_t channels_bitmap = media_codec_information[2] & 0x0F; 6845ce3497fSMatthias Ringwald uint32_t bit_rate_bitmap = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 6855ce3497fSMatthias Ringwald uint8_t vbr = media_codec_information[3] >> 7; 6865ce3497fSMatthias Ringwald 6875ce3497fSMatthias Ringwald event[pos++] = object_type_bitmap; 6881da18615SMilanka Ringwald event[pos++] = drc; 6891da18615SMilanka Ringwald 6905ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency_bitmap); 6915ce3497fSMatthias Ringwald pos += 2; 6925ce3497fSMatthias Ringwald event[pos++] = channels_bitmap; 6935ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate_bitmap); 6945ce3497fSMatthias Ringwald pos += 3; 6955ce3497fSMatthias Ringwald event[pos++] = vbr; 6965ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6975ce3497fSMatthias Ringwald } 6985ce3497fSMatthias Ringwald 6995ce3497fSMatthias 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) { 7005ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 7015ce3497fSMatthias Ringwald uint8_t event[16]; 7025ce3497fSMatthias Ringwald int pos = 0; 7035ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 70473048ce6SMatthias Ringwald pos++; // set later 7055ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY; 7065ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 7075ce3497fSMatthias Ringwald pos += 2; 7085ce3497fSMatthias Ringwald event[pos++] = remote_seid; 7095ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 7105ce3497fSMatthias Ringwald 7115ce3497fSMatthias Ringwald uint8_t version = media_codec_information[0] >> 5; 7125ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] >> 2) & 0x07; 713ab2445a0SMatthias Ringwald uint8_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03; 7145ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[1] >> 3) & 0x01; 7155ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3]; 7165ce3497fSMatthias Ringwald uint16_t maximum_sul = (media_codec_information[4] << 8) | media_codec_information[5]; 7175ce3497fSMatthias Ringwald 7185ce3497fSMatthias Ringwald event[pos++] = version; 7195ce3497fSMatthias Ringwald event[pos++] = channel_mode_bitmap; 7205ce3497fSMatthias Ringwald event[pos++] = sampling_frequency_bitmap; 7215ce3497fSMatthias Ringwald event[pos++] = vbr; 7225ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate_index_bitmap); 7235ce3497fSMatthias Ringwald pos += 3; 7245ce3497fSMatthias Ringwald little_endian_store_16(event, pos, maximum_sul); 72573048ce6SMatthias Ringwald pos += 2; 72673048ce6SMatthias Ringwald event[1] = pos - 2; 727c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 7288ef7100fSMilanka Ringwald } 7298ef7100fSMilanka Ringwald 73024d5fe84SMilanka 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) { 73124d5fe84SMilanka Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 73224d5fe84SMilanka Ringwald uint8_t event[18]; 73324d5fe84SMilanka Ringwald int pos = 0; 73424d5fe84SMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 73524d5fe84SMilanka Ringwald pos++; // set later 73624d5fe84SMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CAPABILITY; 73724d5fe84SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 73824d5fe84SMilanka Ringwald pos += 2; 73924d5fe84SMilanka Ringwald event[pos++] = remote_seid; 74024d5fe84SMilanka Ringwald event[pos++] = media_codec.media_type; 74124d5fe84SMilanka Ringwald 74224d5fe84SMilanka Ringwald uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) | 74324d5fe84SMilanka Ringwald (media_codec_information[1] << 12) | 74424d5fe84SMilanka Ringwald (media_codec_information[2] << 4) | 74524d5fe84SMilanka Ringwald (media_codec_information[3] >> 4); 74624d5fe84SMilanka Ringwald 74724d5fe84SMilanka Ringwald uint8_t channels_bitmap = (media_codec_information[3] >> 2) & 0x03; 74824d5fe84SMilanka Ringwald uint8_t vbr = (media_codec_information[4] >> 7) & 0x01; 74924d5fe84SMilanka Ringwald 75024d5fe84SMilanka Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[4]) & 0xEF) << 16 | (media_codec_information[5] << 8) | media_codec_information[6]; 75124d5fe84SMilanka Ringwald 75224d5fe84SMilanka Ringwald event[pos++] = media_codec_information[0] >> 6; 75324d5fe84SMilanka Ringwald little_endian_store_32(event, pos, sampling_frequency_bitmap); 75424d5fe84SMilanka Ringwald pos += 4; 75524d5fe84SMilanka Ringwald event[pos++] = channels_bitmap; 75624d5fe84SMilanka Ringwald event[pos++] = sampling_frequency_bitmap; 75724d5fe84SMilanka Ringwald event[pos++] = vbr; 75824d5fe84SMilanka Ringwald little_endian_store_24(event, pos, bit_rate_index_bitmap); 75924d5fe84SMilanka Ringwald pos += 3; 76024d5fe84SMilanka Ringwald event[1] = pos - 2; 76124d5fe84SMilanka Ringwald avdtp_emit_sink_and_source(event, pos); 76224d5fe84SMilanka Ringwald } 76324d5fe84SMilanka Ringwald 76424d5fe84SMilanka Ringwald 7651159d239SMatthias 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) { 766924216b2SMatthias Ringwald uint8_t event[AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH + 11]; 76767ae582dSMilanka Ringwald int pos = 0; 76867ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 76973048ce6SMatthias Ringwald pos++; // set later 7704b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY; 77167ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 77267ae582dSMilanka Ringwald pos += 2; 77367ae582dSMilanka Ringwald event[pos++] = remote_seid; 7744b7d40bbSMatthias Ringwald event[pos++] = media_codec.media_type; 7754b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, media_codec.media_codec_type); 7764b7d40bbSMatthias Ringwald pos += 2; 7774b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, media_codec.media_codec_information_len); 7784b7d40bbSMatthias Ringwald pos += 2; 779924216b2SMatthias Ringwald uint32_t media_codec_info_len = btstack_min(media_codec.media_codec_information_len, AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH); 7805403525eSMatthias Ringwald (void)memcpy(event + pos, media_codec.media_codec_information, media_codec_info_len); 7815403525eSMatthias Ringwald pos += media_codec_info_len; 78273048ce6SMatthias Ringwald event[1] = pos - 2; 783c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 78467ae582dSMilanka Ringwald } 78567ae582dSMilanka Ringwald 786c69f4ba5SMatthias Ringwald static void 7871159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 7881159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY, avdtp_cid, 789c69f4ba5SMatthias Ringwald remote_seid); 79067ae582dSMilanka Ringwald } 79167ae582dSMilanka Ringwald 7921159d239SMatthias Ringwald static void avdtp_signaling_emit_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 7931159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY, avdtp_cid, remote_seid); 79467ae582dSMilanka Ringwald } 79567ae582dSMilanka Ringwald 796c69f4ba5SMatthias Ringwald static void 7971159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 7981159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY, avdtp_cid, 799c69f4ba5SMatthias Ringwald remote_seid); 80067ae582dSMilanka Ringwald } 80167ae582dSMilanka Ringwald 8021159d239SMatthias Ringwald static void avdtp_signaling_emit_recovery_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_recovery_capabilities_t *recovery) { 8031159d239SMatthias Ringwald uint8_t event[9]; 80467ae582dSMilanka Ringwald int pos = 0; 80567ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 80667ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 80767ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY; 80867ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 80967ae582dSMilanka Ringwald pos += 2; 81067ae582dSMilanka Ringwald event[pos++] = remote_seid; 81167ae582dSMilanka Ringwald event[pos++] = recovery->recovery_type; 81267ae582dSMilanka Ringwald event[pos++] = recovery->maximum_recovery_window_size; 81367ae582dSMilanka Ringwald event[pos++] = recovery->maximum_number_media_packets; 814c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 81567ae582dSMilanka Ringwald } 81667ae582dSMilanka Ringwald 81773048ce6SMatthias Ringwald #define MAX_CONTENT_PROTECTION_VALUE_LEN 32 818c69f4ba5SMatthias Ringwald static void 8191159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_content_protection_t *content_protection) { 82073048ce6SMatthias Ringwald uint8_t event[10 + MAX_CONTENT_PROTECTION_VALUE_LEN]; 82167ae582dSMilanka Ringwald int pos = 0; 82267ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 82373048ce6SMatthias Ringwald pos++; // set later 82467ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY; 82567ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 82667ae582dSMilanka Ringwald pos += 2; 82767ae582dSMilanka Ringwald event[pos++] = remote_seid; 82867ae582dSMilanka Ringwald 82967ae582dSMilanka Ringwald little_endian_store_16(event, pos, content_protection->cp_type); 83067ae582dSMilanka Ringwald pos += 2; 83173048ce6SMatthias Ringwald 83273048ce6SMatthias Ringwald // drop cp protection value if longer than expected 83373048ce6SMatthias Ringwald if (content_protection->cp_type_value_len <= MAX_CONTENT_PROTECTION_VALUE_LEN){ 83467ae582dSMilanka Ringwald little_endian_store_16(event, pos, content_protection->cp_type_value_len); 83567ae582dSMilanka Ringwald pos += 2; 83673048ce6SMatthias Ringwald (void)memcpy(event + pos, content_protection->cp_type_value, content_protection->cp_type_value_len); 83773048ce6SMatthias Ringwald pos += content_protection->cp_type_value_len; 83873048ce6SMatthias Ringwald } else { 83973048ce6SMatthias Ringwald little_endian_store_16(event, pos, 0); 84073048ce6SMatthias Ringwald pos += 2; 84167ae582dSMilanka Ringwald } 84273048ce6SMatthias Ringwald event[1] = pos - 2; 843c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 84467ae582dSMilanka Ringwald } 84567ae582dSMilanka Ringwald 84667ae582dSMilanka Ringwald 847c69f4ba5SMatthias Ringwald static void 8481159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_header_compression_capabilities_t *header_compression) { 8491159d239SMatthias Ringwald uint8_t event[9]; 85067ae582dSMilanka Ringwald int pos = 0; 85167ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 85267ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 85367ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY; 85467ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 85567ae582dSMilanka Ringwald pos += 2; 85667ae582dSMilanka Ringwald event[pos++] = remote_seid; 85767ae582dSMilanka Ringwald event[pos++] = header_compression->back_ch; 85867ae582dSMilanka Ringwald event[pos++] = header_compression->media; 85967ae582dSMilanka Ringwald event[pos++] = header_compression->recovery; 860c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 86167ae582dSMilanka Ringwald } 86267ae582dSMilanka Ringwald 863c69f4ba5SMatthias Ringwald static void 8641159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_multiplexing_mode_capabilities_t *multiplexing_mode) { 8651159d239SMatthias Ringwald uint8_t event[14]; 86667ae582dSMilanka Ringwald int pos = 0; 86767ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 86867ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 86967ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY; 87067ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 87167ae582dSMilanka Ringwald pos += 2; 87267ae582dSMilanka Ringwald event[pos++] = remote_seid; 87367ae582dSMilanka Ringwald 87467ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->fragmentation; 87567ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->transport_identifiers_num; 87667ae582dSMilanka Ringwald 87767ae582dSMilanka Ringwald int i; 87867ae582dSMilanka Ringwald for (i = 0; i < 3; i++){ 87967ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->transport_session_identifiers[i]; 88067ae582dSMilanka Ringwald } 88167ae582dSMilanka Ringwald for (i = 0; i < 3; i++){ 88267ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->tcid[i]; 88367ae582dSMilanka Ringwald } 884c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 88567ae582dSMilanka Ringwald } 88667ae582dSMilanka Ringwald 8871159d239SMatthias Ringwald static void avdtp_signaling_emit_capability_done(uint16_t avdtp_cid, uint8_t remote_seid) { 8881159d239SMatthias Ringwald uint8_t event[6]; 889f08f4934SMatthias Ringwald int pos = 0; 890f08f4934SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 891f08f4934SMatthias Ringwald event[pos++] = sizeof(event) - 2; 892f08f4934SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE; 893f08f4934SMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 894f08f4934SMatthias Ringwald pos += 2; 895f08f4934SMatthias Ringwald event[pos++] = remote_seid; 896c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 897f08f4934SMatthias Ringwald } 898f08f4934SMatthias Ringwald 8990928ecceSMatthias Ringwald static void avdtp_signaling_emit_media_codec_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec){ 9000928ecceSMatthias Ringwald switch (media_codec.media_codec_type){ 9010928ecceSMatthias Ringwald case AVDTP_CODEC_SBC: 9020928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_sbc_capability(avdtp_cid, remote_seid, media_codec); 9030928ecceSMatthias Ringwald break; 9040928ecceSMatthias Ringwald case AVDTP_CODEC_MPEG_1_2_AUDIO: 9050928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_mpeg_audio_capability(avdtp_cid, remote_seid, media_codec); 9060928ecceSMatthias Ringwald break; 9070928ecceSMatthias Ringwald case AVDTP_CODEC_MPEG_2_4_AAC: 9080928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_mpeg_aac_capability(avdtp_cid, remote_seid, media_codec); 9090928ecceSMatthias Ringwald break; 9100928ecceSMatthias Ringwald case AVDTP_CODEC_ATRAC_FAMILY: 9110928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_atrac_capability(avdtp_cid, remote_seid, media_codec); 9120928ecceSMatthias Ringwald break; 91324d5fe84SMilanka Ringwald case AVDTP_CODEC_MPEG_D_USAC: 91424d5fe84SMilanka Ringwald avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(avdtp_cid, remote_seid, media_codec); 91524d5fe84SMilanka Ringwald break; 9160928ecceSMatthias Ringwald default: 9170928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_other_capability(avdtp_cid, remote_seid, media_codec); 9180928ecceSMatthias Ringwald break; 9190928ecceSMatthias Ringwald } 9200928ecceSMatthias Ringwald } 9210928ecceSMatthias Ringwald 9224b7d40bbSMatthias Ringwald // emit events for all capabilities incl. final done event 9231159d239SMatthias Ringwald void avdtp_signaling_emit_capabilities(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_capabilities_t *capabilities, 924c69f4ba5SMatthias Ringwald uint16_t registered_service_categories) { 92567ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MEDIA_CODEC)){ 9260928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_capability(avdtp_cid, remote_seid, capabilities->media_codec); 92767ae582dSMilanka Ringwald } 92867ae582dSMilanka Ringwald 92967ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MEDIA_TRANSPORT)){ 9301159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(avdtp_cid, remote_seid); 93167ae582dSMilanka Ringwald } 93267ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_REPORTING)){ 9331159d239SMatthias Ringwald avdtp_signaling_emit_reporting_capability(avdtp_cid, remote_seid); 93467ae582dSMilanka Ringwald } 93567ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_RECOVERY)){ 9361159d239SMatthias Ringwald avdtp_signaling_emit_recovery_capability(avdtp_cid, remote_seid, &capabilities->recovery); 93767ae582dSMilanka Ringwald } 93867ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_CONTENT_PROTECTION)){ 9391159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(avdtp_cid, remote_seid, 940c69f4ba5SMatthias Ringwald &capabilities->content_protection); 94167ae582dSMilanka Ringwald } 94267ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_HEADER_COMPRESSION)){ 9431159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(avdtp_cid, remote_seid, 944c69f4ba5SMatthias Ringwald &capabilities->header_compression); 94567ae582dSMilanka Ringwald } 94667ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MULTIPLEXING)){ 9471159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(avdtp_cid, remote_seid, 948c69f4ba5SMatthias Ringwald &capabilities->multiplexing_mode); 94967ae582dSMilanka Ringwald } 95067ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_DELAY_REPORTING)){ 9511159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(avdtp_cid, remote_seid); 95267ae582dSMilanka Ringwald } 9531159d239SMatthias Ringwald avdtp_signaling_emit_capability_done(avdtp_cid, remote_seid); 95467ae582dSMilanka Ringwald } 95567ae582dSMilanka Ringwald 956186e1970SMatthias Ringwald static uint16_t 957186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_sbc_config_event(uint8_t *event, uint16_t size, 958a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 959186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 960186e1970SMatthias Ringwald const uint8_t *media_codec_information) { 961186e1970SMatthias Ringwald 962924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN); 963186e1970SMatthias Ringwald 9644b7d40bbSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 9654b7d40bbSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 9664b7d40bbSMatthias Ringwald 9674b7d40bbSMatthias Ringwald int pos = 0; 9684b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 969924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN - 2; 9704b7d40bbSMatthias Ringwald 9714b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION; 9724b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 9734b7d40bbSMatthias Ringwald pos += 2; 9744b7d40bbSMatthias Ringwald event[pos++] = local_seid; 9754b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 9764b7d40bbSMatthias Ringwald event[pos++] = reconfigure; 977186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_SBC; 9784b7d40bbSMatthias Ringwald 9794b7d40bbSMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[0] >> 4; 9804b7d40bbSMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x0F; 9814b7d40bbSMatthias Ringwald uint8_t block_length_bitmap = media_codec_information[1] >> 4; 9824b7d40bbSMatthias Ringwald uint8_t subbands_bitmap = (media_codec_information[1] & 0x0F) >> 2; 9834b7d40bbSMatthias Ringwald 9844b7d40bbSMatthias Ringwald uint8_t num_channels = 0; 985a3868652SMatthias Ringwald avdtp_channel_mode_t channel_mode; 986a3868652SMatthias Ringwald 987a3868652SMatthias Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 988a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 9894b7d40bbSMatthias Ringwald num_channels = 2; 990a3868652SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 991a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_STEREO; 992a3868652SMatthias Ringwald num_channels = 2; 993a3868652SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 994a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 995a3868652SMatthias Ringwald num_channels = 2; 996a3868652SMatthias Ringwald } else { 997a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 9984b7d40bbSMatthias Ringwald num_channels = 1; 9994b7d40bbSMatthias Ringwald } 10004b7d40bbSMatthias Ringwald 10014b7d40bbSMatthias Ringwald uint16_t sampling_frequency = 0; 10024b7d40bbSMatthias Ringwald if (sampling_frequency_bitmap & AVDTP_SBC_48000) { 10034b7d40bbSMatthias Ringwald sampling_frequency = 48000; 10044b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_44100) { 10054b7d40bbSMatthias Ringwald sampling_frequency = 44100; 10064b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_32000) { 10074b7d40bbSMatthias Ringwald sampling_frequency = 32000; 10084b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_16000) { 10094b7d40bbSMatthias Ringwald sampling_frequency = 16000; 10104b7d40bbSMatthias Ringwald } 10114b7d40bbSMatthias Ringwald 10124b7d40bbSMatthias Ringwald uint8_t subbands = 0; 10134b7d40bbSMatthias Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 10144b7d40bbSMatthias Ringwald subbands = 8; 10154b7d40bbSMatthias Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 10164b7d40bbSMatthias Ringwald subbands = 4; 10174b7d40bbSMatthias Ringwald } 10184b7d40bbSMatthias Ringwald 10194b7d40bbSMatthias Ringwald uint8_t block_length = 0; 10204b7d40bbSMatthias Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 10214b7d40bbSMatthias Ringwald block_length = 16; 10224b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 10234b7d40bbSMatthias Ringwald block_length = 12; 10244b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 10254b7d40bbSMatthias Ringwald block_length = 8; 10264b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 10274b7d40bbSMatthias Ringwald block_length = 4; 10284b7d40bbSMatthias Ringwald } 10294b7d40bbSMatthias Ringwald 10304b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 10314b7d40bbSMatthias Ringwald pos += 2; 10324b7d40bbSMatthias Ringwald 1033a3868652SMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 10344b7d40bbSMatthias Ringwald event[pos++] = num_channels; 10354b7d40bbSMatthias Ringwald event[pos++] = block_length; 10364b7d40bbSMatthias Ringwald event[pos++] = subbands; 10374b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03; 10384b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[2]; 10394b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[3]; 1040186e1970SMatthias Ringwald 1041924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN); 1042186e1970SMatthias Ringwald 1043186e1970SMatthias Ringwald return pos; 10445ce3497fSMatthias Ringwald } 10455ce3497fSMatthias Ringwald 1046186e1970SMatthias Ringwald static uint16_t 1047186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpeg_audio_config_event(uint8_t *event, uint16_t size, 1048a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1049186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 10505ce3497fSMatthias Ringwald const uint8_t *media_codec_information) { 10515ce3497fSMatthias Ringwald 1052924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN); 1053186e1970SMatthias Ringwald 10545ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 10555ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 10565ce3497fSMatthias Ringwald 1057186e1970SMatthias Ringwald uint16_t pos = 0; 10585ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1059924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN - 2; 10605ce3497fSMatthias Ringwald 10615ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION; 10625ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 10635ce3497fSMatthias Ringwald pos += 2; 10645ce3497fSMatthias Ringwald event[pos++] = local_seid; 10655ce3497fSMatthias Ringwald event[pos++] = remote_seid; 10665ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1067186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_MPEG_1_2_AUDIO; 10685ce3497fSMatthias Ringwald 10695ce3497fSMatthias Ringwald uint8_t layer_bitmap = media_codec_information[0] >> 5; 10705ce3497fSMatthias Ringwald uint8_t crc = (media_codec_information[0] >> 4) & 0x01; 10715ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] & 0x07); 10725ce3497fSMatthias Ringwald uint8_t mpf = (media_codec_information[1] >> 6) & 0x01; 10735ce3497fSMatthias Ringwald uint8_t sampling_frequency_bitmap = (media_codec_information[1] & 0x3F); 10745ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[2] >> 7) & 0x01; 10755ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[2] & 0x3f) << 8) | media_codec_information[3]; 10765ce3497fSMatthias Ringwald 10775ce3497fSMatthias Ringwald uint8_t layer = 0; 10785ce3497fSMatthias Ringwald if (layer_bitmap & 0x04){ 10795ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_1; 10805ce3497fSMatthias Ringwald } else if (layer_bitmap & 0x02){ 10815ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_2; 10825ce3497fSMatthias Ringwald } else if (layer_bitmap & 0x01){ 10835ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_3; 10845ce3497fSMatthias Ringwald } 10855ce3497fSMatthias Ringwald 10865ce3497fSMatthias Ringwald uint8_t num_channels = 0; 10875ce3497fSMatthias Ringwald avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 10885ce3497fSMatthias Ringwald if (channel_mode_bitmap & 0x08){ 10895ce3497fSMatthias Ringwald num_channels = 1; 10905ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 10915ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x04){ 10925ce3497fSMatthias Ringwald num_channels = 2; 10935ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 10945ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 10955ce3497fSMatthias Ringwald num_channels = 2; 10965ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_STEREO; 10975ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 10985ce3497fSMatthias Ringwald num_channels = 2; 10995ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 11005ce3497fSMatthias Ringwald } 11015ce3497fSMatthias Ringwald 11025ce3497fSMatthias Ringwald uint16_t sampling_frequency = 0; 11035ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & 0x01) { 11045ce3497fSMatthias Ringwald sampling_frequency = 48000; 11055ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x02) { 11065ce3497fSMatthias Ringwald sampling_frequency = 44100; 11075ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x04) { 11085ce3497fSMatthias Ringwald sampling_frequency = 32000; 11095ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x08) { 11105ce3497fSMatthias Ringwald sampling_frequency = 24000; 11115ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x10) { 11125ce3497fSMatthias Ringwald sampling_frequency = 22050; 11135ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x20) { 11145ce3497fSMatthias Ringwald sampling_frequency = 16000; 11155ce3497fSMatthias Ringwald } 11165ce3497fSMatthias Ringwald 11175ce3497fSMatthias Ringwald uint8_t bitrate_index = 0; 11185ce3497fSMatthias Ringwald uint8_t i; 11195ce3497fSMatthias Ringwald for (i=0;i<14;i++){ 11205ce3497fSMatthias Ringwald if (bit_rate_index_bitmap & (1U << i)) { 11215ce3497fSMatthias Ringwald bitrate_index = i; 11225ce3497fSMatthias Ringwald } 11235ce3497fSMatthias Ringwald } 11245ce3497fSMatthias Ringwald 11255ce3497fSMatthias Ringwald event[pos++] = (uint8_t) layer; 11265ce3497fSMatthias Ringwald event[pos++] = crc; 11275ce3497fSMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 11285ce3497fSMatthias Ringwald event[pos++] = num_channels; 11295ce3497fSMatthias Ringwald event[pos++] = mpf; 11305ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 11315ce3497fSMatthias Ringwald pos += 2; 11325ce3497fSMatthias Ringwald event[pos++] = vbr; 11335ce3497fSMatthias Ringwald event[pos++] = bitrate_index; 11345ce3497fSMatthias Ringwald 1135924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN); 1136186e1970SMatthias Ringwald 1137186e1970SMatthias Ringwald return pos; 11385ce3497fSMatthias Ringwald } 11395ce3497fSMatthias Ringwald 1140186e1970SMatthias Ringwald static uint16_t 1141186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpec_aac_config_event(uint8_t *event, uint16_t size, 1142a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1143186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 11445ce3497fSMatthias Ringwald const uint8_t *media_codec_information) { 11455ce3497fSMatthias Ringwald 114624d5fe84SMilanka Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN); 1147186e1970SMatthias Ringwald 11485ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 11495ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 11505ce3497fSMatthias Ringwald 1151186e1970SMatthias Ringwald uint16_t pos = 0; 11525ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1153924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN - 2; 11545ce3497fSMatthias Ringwald 11555ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION; 11565ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 11575ce3497fSMatthias Ringwald pos += 2; 11585ce3497fSMatthias Ringwald event[pos++] = local_seid; 11595ce3497fSMatthias Ringwald event[pos++] = remote_seid; 11605ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1161186e1970SMatthias Ringwald event[pos++] =AVDTP_CODEC_MPEG_2_4_AAC; 11625ce3497fSMatthias Ringwald 11631da18615SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 1; 11641da18615SMilanka Ringwald uint8_t drc = media_codec_information[0] & 0x01; 11655ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] << 4) | (media_codec_information[2] >> 4); 11661da18615SMilanka Ringwald uint8_t channels_bitmap = media_codec_information[2] & 0x0F; 11675ce3497fSMatthias Ringwald uint8_t vbr = media_codec_information[3] >> 7; 11685ce3497fSMatthias Ringwald uint32_t bit_rate = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 11695ce3497fSMatthias Ringwald 11705ce3497fSMatthias Ringwald uint8_t object_type = 0; 11711da18615SMilanka Ringwald if (object_type_bitmap & 0x01){ 11721da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AAC_ELDv2; 11731da18615SMilanka Ringwald } else if (object_type_bitmap & 0x02){ 11741da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AACv2; 11751da18615SMilanka Ringwald } else if (object_type_bitmap & 0x04){ 11761da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AAC; 11771da18615SMilanka Ringwald } else if (object_type_bitmap & 0x08){ 11785ce3497fSMatthias Ringwald object_type = AVDTP_AAC_MPEG4_SCALABLE; 11791da18615SMilanka Ringwald } else if (object_type_bitmap & 0x10){ 11801da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_LTP; 11811da18615SMilanka Ringwald } else if (object_type_bitmap & 0x20){ 11821da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_LC; 11831da18615SMilanka Ringwald } else if (object_type_bitmap & 0x40){ 11841da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG2_LC; 11855ce3497fSMatthias Ringwald } 11865ce3497fSMatthias Ringwald 11875ce3497fSMatthias Ringwald uint32_t sampling_frequency = 0; 11885ce3497fSMatthias Ringwald uint8_t i; 11895ce3497fSMatthias Ringwald const uint32_t aac_sampling_frequency_table[] = { 11905ce3497fSMatthias Ringwald 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 11915ce3497fSMatthias Ringwald }; 11925ce3497fSMatthias Ringwald for (i=0;i<12;i++){ 11935ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & (1U << i)) { 11945ce3497fSMatthias Ringwald sampling_frequency = aac_sampling_frequency_table[i]; 11955ce3497fSMatthias Ringwald } 11965ce3497fSMatthias Ringwald } 11975ce3497fSMatthias Ringwald 11985ce3497fSMatthias Ringwald uint8_t num_channels = 0; 11991da18615SMilanka Ringwald if (channels_bitmap & 0x08){ 12005ce3497fSMatthias Ringwald num_channels = 1; 12011da18615SMilanka Ringwald } else if (channels_bitmap & 0x04){ 12025ce3497fSMatthias Ringwald num_channels = 2; 12031da18615SMilanka Ringwald } else if (channels_bitmap & 0x02){ 12041da18615SMilanka Ringwald num_channels = 6; 12051da18615SMilanka Ringwald } else if (channels_bitmap & 0x01){ 12061da18615SMilanka Ringwald num_channels = 8; 12075ce3497fSMatthias Ringwald } 12085ce3497fSMatthias Ringwald 12095ce3497fSMatthias Ringwald event[pos++] = object_type; 12101da18615SMilanka Ringwald event[pos++] = drc; 12115ce3497fSMatthias Ringwald little_endian_store_24(event, pos, sampling_frequency); 12125ce3497fSMatthias Ringwald pos += 3; 12135ce3497fSMatthias Ringwald event[pos++] = num_channels; 12145ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate); 12155ce3497fSMatthias Ringwald pos += 3; 12165ce3497fSMatthias Ringwald event[pos++] = vbr; 12175ce3497fSMatthias Ringwald 1218924216b2SMatthias Ringwald btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN == pos); 1219186e1970SMatthias Ringwald 1220186e1970SMatthias Ringwald return pos; 12215ce3497fSMatthias Ringwald } 12225ce3497fSMatthias Ringwald 122324d5fe84SMilanka Ringwald static uint16_t 122424d5fe84SMilanka Ringwald avdtp_signaling_setup_media_codec_mpegd_config_event(uint8_t *event, uint16_t size, 122524d5fe84SMilanka Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 122624d5fe84SMilanka Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 122724d5fe84SMilanka Ringwald const uint8_t *media_codec_information) { 122824d5fe84SMilanka Ringwald 122924d5fe84SMilanka Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN); 123024d5fe84SMilanka Ringwald 123124d5fe84SMilanka Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 123224d5fe84SMilanka Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 123324d5fe84SMilanka Ringwald 123424d5fe84SMilanka Ringwald uint16_t pos = 0; 123524d5fe84SMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 123624d5fe84SMilanka Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN - 2; 123724d5fe84SMilanka Ringwald 123824d5fe84SMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CONFIGURATION; 123924d5fe84SMilanka Ringwald 124024d5fe84SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 124124d5fe84SMilanka Ringwald pos += 2; 124224d5fe84SMilanka Ringwald event[pos++] = local_seid; 124324d5fe84SMilanka Ringwald event[pos++] = remote_seid; 124424d5fe84SMilanka Ringwald event[pos++] = reconfigure; 124524d5fe84SMilanka Ringwald event[pos++] = AVDTP_CODEC_MPEG_D_USAC; 124624d5fe84SMilanka Ringwald 124724d5fe84SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 6; 124824d5fe84SMilanka Ringwald uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) | 124924d5fe84SMilanka Ringwald (media_codec_information[1] << 12) | 125024d5fe84SMilanka Ringwald (media_codec_information[2] << 4) | 125124d5fe84SMilanka Ringwald (media_codec_information[3] >> 4); 125224d5fe84SMilanka Ringwald 125324d5fe84SMilanka Ringwald uint8_t channels_bitmap = (media_codec_information[3] >> 2) & 0x03; 125424d5fe84SMilanka Ringwald uint8_t vbr = (media_codec_information[4] >> 7) & 0x01; 125524d5fe84SMilanka Ringwald 125624d5fe84SMilanka Ringwald uint32_t bit_rate = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 125724d5fe84SMilanka Ringwald 125824d5fe84SMilanka Ringwald uint8_t object_type = 0; 125924d5fe84SMilanka Ringwald if (object_type_bitmap & 0x10){ 126024d5fe84SMilanka Ringwald object_type = AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC; 126124d5fe84SMilanka Ringwald } else { 126224d5fe84SMilanka Ringwald object_type = AVDTP_USAC_OBJECT_TYPE_RFU; 126324d5fe84SMilanka Ringwald } 126424d5fe84SMilanka Ringwald 126524d5fe84SMilanka Ringwald uint32_t sampling_frequency = 0; 126624d5fe84SMilanka Ringwald uint8_t i; 126724d5fe84SMilanka Ringwald const uint32_t usac_sampling_frequency_table[] = { 126824d5fe84SMilanka Ringwald 96000, 88200, 76800, 70560, 126924d5fe84SMilanka Ringwald 64000, 58800, 48000, 44100, 38400, 35280, 32000, 29400, 127024d5fe84SMilanka Ringwald 24000, 22050, 19200, 17640, 16000, 14700, 12800, 12000, 127124d5fe84SMilanka Ringwald 11760, 11025, 9600, 8820, 8000, 7350 127224d5fe84SMilanka Ringwald }; 127324d5fe84SMilanka Ringwald for (i=0;i<26;i++){ 127424d5fe84SMilanka Ringwald if (sampling_frequency_bitmap & (1U << i)) { 127524d5fe84SMilanka Ringwald sampling_frequency = usac_sampling_frequency_table[i]; 127624d5fe84SMilanka Ringwald } 127724d5fe84SMilanka Ringwald } 127824d5fe84SMilanka Ringwald 127924d5fe84SMilanka Ringwald uint8_t num_channels = 0; 128024d5fe84SMilanka Ringwald if (channels_bitmap & 0x02){ 128124d5fe84SMilanka Ringwald num_channels = 1; 128224d5fe84SMilanka Ringwald } else if (channels_bitmap & 0x01){ 128324d5fe84SMilanka Ringwald num_channels = 2; 128424d5fe84SMilanka Ringwald } 128524d5fe84SMilanka Ringwald 128624d5fe84SMilanka Ringwald event[pos++] = object_type; 128724d5fe84SMilanka Ringwald little_endian_store_24(event, pos, sampling_frequency); 128824d5fe84SMilanka Ringwald pos += 3; 128924d5fe84SMilanka Ringwald event[pos++] = num_channels; 129024d5fe84SMilanka Ringwald event[pos++] = vbr; 129124d5fe84SMilanka Ringwald little_endian_store_24(event, pos, bit_rate); 129224d5fe84SMilanka Ringwald pos += 3; 129324d5fe84SMilanka Ringwald 129424d5fe84SMilanka Ringwald btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN == pos); 129524d5fe84SMilanka Ringwald 129624d5fe84SMilanka Ringwald return pos; 129724d5fe84SMilanka Ringwald } 129824d5fe84SMilanka Ringwald 1299186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_atrac_config_event(uint8_t *event, uint16_t size, 1300a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1301186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 1302186e1970SMatthias Ringwald const uint8_t *media_codec_information) { 1303924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN); 1304186e1970SMatthias Ringwald 13055ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 13065ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 13075ce3497fSMatthias Ringwald 1308186e1970SMatthias Ringwald uint16_t pos = 0; 13095ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1310924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN - 2; 13115ce3497fSMatthias Ringwald 13125ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION; 13135ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 13145ce3497fSMatthias Ringwald pos += 2; 13155ce3497fSMatthias Ringwald event[pos++] = local_seid; 13165ce3497fSMatthias Ringwald event[pos++] = remote_seid; 13175ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1318186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_ATRAC_FAMILY; 13195ce3497fSMatthias Ringwald 1320b5bbcbf4SMatthias Ringwald avdtp_atrac_version_t version = (avdtp_atrac_version_t) (media_codec_information[0] >> 5); 13215ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] >> 2) & 0x07; 13225ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03; 13235ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[1] >> 3) & 0x01; 13245ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3]; 13255ce3497fSMatthias Ringwald uint16_t maximum_sul = (media_codec_information[4] << 8) | media_codec_information[5]; 13265ce3497fSMatthias Ringwald 13275ce3497fSMatthias Ringwald uint8_t num_channels = 0; 13285ce3497fSMatthias Ringwald avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 13295ce3497fSMatthias Ringwald if (channel_mode_bitmap & 0x04){ 13305ce3497fSMatthias Ringwald num_channels = 1; 13315ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 13325ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 13335ce3497fSMatthias Ringwald num_channels = 2; 13345ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 13355ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x01){ 13365ce3497fSMatthias Ringwald num_channels = 2; 13375ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 13385ce3497fSMatthias Ringwald } 13395ce3497fSMatthias Ringwald 13405ce3497fSMatthias Ringwald uint16_t sampling_frequency = 0; 13415ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & 0x02){ 13425ce3497fSMatthias Ringwald sampling_frequency = 44100; 13435ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x01){ 13445ce3497fSMatthias Ringwald sampling_frequency = 48000; 13455ce3497fSMatthias Ringwald } 13465ce3497fSMatthias Ringwald 13475ce3497fSMatthias Ringwald // bit 0 = index 0x18, bit 19 = index 0 13485ce3497fSMatthias Ringwald uint8_t bit_rate_index = 0; 13495ce3497fSMatthias Ringwald uint8_t i; 13505ce3497fSMatthias Ringwald for (i=0;i <= 19;i++){ 13515ce3497fSMatthias Ringwald if (bit_rate_index_bitmap & (1U << i)) { 13525ce3497fSMatthias Ringwald bit_rate_index = 18 - i; 13535ce3497fSMatthias Ringwald } 13545ce3497fSMatthias Ringwald } 13555ce3497fSMatthias Ringwald 13565ce3497fSMatthias Ringwald event[pos++] = (uint8_t) version; 13575ce3497fSMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 13585ce3497fSMatthias Ringwald event[pos++] = num_channels; 13595ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 13605ce3497fSMatthias Ringwald pos += 2; 13615ce3497fSMatthias Ringwald event[pos++] = vbr; 13625ce3497fSMatthias Ringwald event[pos++] = bit_rate_index; 13635ce3497fSMatthias Ringwald little_endian_store_16(event, pos, maximum_sul); 13645ce3497fSMatthias Ringwald pos += 2; 13655ce3497fSMatthias Ringwald 1366924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN); 1367186e1970SMatthias Ringwald return pos; 13684b7d40bbSMatthias Ringwald } 13694b7d40bbSMatthias Ringwald 1370186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_other_config_event(uint8_t *event, uint16_t size, 1371a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1372186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 1373186e1970SMatthias Ringwald const adtvp_media_codec_capabilities_t *media_codec) { 1374924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN); 1375186e1970SMatthias Ringwald 13766c069ec9SMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 13776c069ec9SMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 13786c069ec9SMatthias Ringwald 1379186e1970SMatthias Ringwald uint16_t pos = 0; 13804b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 138173048ce6SMatthias Ringwald pos++; // set later 13824b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION; 13834b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 13844b7d40bbSMatthias Ringwald pos += 2; 13854b7d40bbSMatthias Ringwald event[pos++] = local_seid; 13864b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 13874b7d40bbSMatthias Ringwald event[pos++] = reconfigure; 1388e8a431c1SMatthias Ringwald event[pos++] = media_codec->media_type; 1389e8a431c1SMatthias Ringwald little_endian_store_16(event, pos, media_codec->media_codec_type); 13904b7d40bbSMatthias Ringwald pos += 2; 1391e8a431c1SMatthias Ringwald little_endian_store_16(event, pos, media_codec->media_codec_information_len); 13924b7d40bbSMatthias Ringwald pos += 2; 1393186e1970SMatthias Ringwald 1394186e1970SMatthias Ringwald btstack_assert(pos == 13); 1395186e1970SMatthias Ringwald 1396924216b2SMatthias Ringwald uint16_t media_codec_len = btstack_min(AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH, media_codec->media_codec_information_len); 1397e8a431c1SMatthias Ringwald (void)memcpy(event + pos, media_codec->media_codec_information, media_codec_len); 139873048ce6SMatthias Ringwald pos += media_codec_len; 139973048ce6SMatthias Ringwald event[1] = pos - 2; 1400186e1970SMatthias Ringwald return pos; 14014b7d40bbSMatthias Ringwald } 14024b7d40bbSMatthias Ringwald 14034b7d40bbSMatthias Ringwald void avdtp_signaling_emit_delay(uint16_t avdtp_cid, uint8_t local_seid, uint16_t delay) { 14044b7d40bbSMatthias Ringwald uint8_t event[8]; 14054b7d40bbSMatthias Ringwald int pos = 0; 14064b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14074b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14084b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT; 14094b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 14104b7d40bbSMatthias Ringwald pos += 2; 14114b7d40bbSMatthias Ringwald event[pos++] = local_seid; 14124b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, delay); 14134b7d40bbSMatthias Ringwald pos += 2; 14146e64e62bSMatthias Ringwald avdtp_emit_source(event, pos); 14154b7d40bbSMatthias Ringwald } 14164b7d40bbSMatthias Ringwald 1417a905535cSMatthias Ringwald uint16_t avdtp_setup_media_codec_config_event(uint8_t *event, uint16_t size, const avdtp_stream_endpoint_t *stream_endpoint, 1418924216b2SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 14192965b0e6SMatthias Ringwald const adtvp_media_codec_capabilities_t * media_codec) { 14202965b0e6SMatthias Ringwald switch (media_codec->media_codec_type){ 1421924216b2SMatthias Ringwald case AVDTP_CODEC_SBC: 1422924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_sbc_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14232965b0e6SMatthias Ringwald media_codec->media_codec_information); 1424924216b2SMatthias Ringwald case AVDTP_CODEC_MPEG_1_2_AUDIO: 1425924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_mpeg_audio_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14262965b0e6SMatthias Ringwald media_codec->media_codec_information); 1427924216b2SMatthias Ringwald case AVDTP_CODEC_MPEG_2_4_AAC: 1428924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_mpec_aac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14292965b0e6SMatthias Ringwald media_codec->media_codec_information); 1430924216b2SMatthias Ringwald case AVDTP_CODEC_ATRAC_FAMILY: 1431924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_atrac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14322965b0e6SMatthias Ringwald media_codec->media_codec_information); 143324d5fe84SMilanka Ringwald case AVDTP_CODEC_MPEG_D_USAC: 143424d5fe84SMilanka Ringwald return avdtp_signaling_setup_media_codec_mpegd_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 143524d5fe84SMilanka Ringwald media_codec->media_codec_information); 1436924216b2SMatthias Ringwald default: 1437924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_other_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14382965b0e6SMatthias Ringwald media_codec); 1439924216b2SMatthias Ringwald } 1440924216b2SMatthias Ringwald } 1441924216b2SMatthias Ringwald 14426c5b303cSMatthias Ringwald void avdtp_signaling_emit_configuration(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t reconfigure, 14434b7d40bbSMatthias Ringwald avdtp_capabilities_t *configuration, uint16_t configured_service_categories) { 14444b7d40bbSMatthias Ringwald 14454b7d40bbSMatthias Ringwald if (get_bit16(configured_service_categories, AVDTP_MEDIA_CODEC)){ 1446186e1970SMatthias Ringwald uint16_t pos = 0; 1447186e1970SMatthias Ringwald // assume MEDIA_CONFIG_OTHER_EVENT_LEN is larger than all other events 1448924216b2SMatthias Ringwald uint8_t event[AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN]; 1449924216b2SMatthias Ringwald pos = avdtp_setup_media_codec_config_event(event, sizeof(event), stream_endpoint, avdtp_cid, reconfigure, 14502965b0e6SMatthias Ringwald &configuration->media_codec); 1451186e1970SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 1452186e1970SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 14534b7d40bbSMatthias Ringwald } 14544b7d40bbSMatthias Ringwald } 14554b7d40bbSMatthias Ringwald 14564b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_established(avdtp_stream_endpoint_t *stream_endpoint, uint8_t status) { 14574b7d40bbSMatthias Ringwald uint8_t event[14]; 14584b7d40bbSMatthias Ringwald int pos = 0; 14594b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14604b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14614b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED; 14624b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 14634b7d40bbSMatthias Ringwald pos += 2; 14644b7d40bbSMatthias Ringwald reverse_bd_addr(stream_endpoint->connection->remote_addr, &event[pos]); 14654b7d40bbSMatthias Ringwald pos += 6; 14664b7d40bbSMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint); 14674b7d40bbSMatthias Ringwald event[pos++] = avdtp_remote_seid(stream_endpoint); 14684b7d40bbSMatthias Ringwald event[pos++] = status; 14694b7d40bbSMatthias Ringwald 14704b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 14716e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 14724b7d40bbSMatthias Ringwald } 14734b7d40bbSMatthias Ringwald 14744b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_released(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t local_seid) { 14754b7d40bbSMatthias Ringwald uint8_t event[6]; 14764b7d40bbSMatthias Ringwald int pos = 0; 14774b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14784b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14794b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED; 14804b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 14814b7d40bbSMatthias Ringwald pos += 2; 14824b7d40bbSMatthias Ringwald event[pos++] = local_seid; 14834b7d40bbSMatthias Ringwald 14844b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 14856e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 14864b7d40bbSMatthias Ringwald } 14874b7d40bbSMatthias Ringwald 14884b7d40bbSMatthias Ringwald void avdtp_streaming_emit_can_send_media_packet_now(avdtp_stream_endpoint_t *stream_endpoint, uint16_t sequence_number) { 14894b7d40bbSMatthias Ringwald uint8_t event[8]; 14904b7d40bbSMatthias Ringwald int pos = 0; 14914b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14924b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14934b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW; 14944b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 14954b7d40bbSMatthias Ringwald pos += 2; 14964b7d40bbSMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint); 14974b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, sequence_number); 14984b7d40bbSMatthias Ringwald pos += 2; 14996e64e62bSMatthias Ringwald event[1] = pos - 2; 15004b7d40bbSMatthias Ringwald 15014b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 15026e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 15034b7d40bbSMatthias Ringwald } 15044b7d40bbSMatthias Ringwald 1505d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_acceptor(avdtp_connection_t *connection) { 150623edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1507d80ccd43SMatthias Ringwald connection->wait_to_send_acceptor = true; 1508d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(connection->l2cap_signaling_cid); 15099974aee0SMilanka Ringwald return ERROR_CODE_SUCCESS; 15108ef7100fSMilanka Ringwald } 15119974aee0SMilanka Ringwald 1512d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_initiator(avdtp_connection_t *connection) { 151323edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1514d80ccd43SMatthias Ringwald connection->wait_to_send_initiator = true; 1515d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(connection->l2cap_signaling_cid); 15169974aee0SMilanka Ringwald return ERROR_CODE_SUCCESS; 15178ef7100fSMilanka Ringwald } 15189974aee0SMilanka Ringwald 1519a905535cSMatthias Ringwald uint8_t avdtp_local_seid(const avdtp_stream_endpoint_t * stream_endpoint){ 15204ccacc40SMilanka Ringwald if (!stream_endpoint) return 0; 15214ccacc40SMilanka Ringwald return stream_endpoint->sep.seid; 15224ccacc40SMilanka Ringwald 15234ccacc40SMilanka Ringwald } 15244ccacc40SMilanka Ringwald 1525a905535cSMatthias Ringwald uint8_t avdtp_remote_seid(const avdtp_stream_endpoint_t * stream_endpoint){ 1526485c0a4cSMilanka Ringwald if (!stream_endpoint) return AVDTP_INVALID_SEP_SEID; 1527485c0a4cSMilanka Ringwald return stream_endpoint->remote_sep.seid; 15284ccacc40SMilanka Ringwald } 1529ef5ad9d6SMilanka Ringwald 1530fdd788feSMatthias Ringwald // helper to set/get configuration 1531*ea8aa208SMilanka Ringwald uint8_t avdtp_config_sbc_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz){ 1532*ea8aa208SMilanka Ringwald uint8_t sampling_frequency_bitmap = 0; 1533*ea8aa208SMilanka Ringwald const uint16_t sbc_sampling_frequency_table[] = { 1534*ea8aa208SMilanka Ringwald 48000, 44100, 32000, 16000 1535*ea8aa208SMilanka Ringwald }; 1536*ea8aa208SMilanka Ringwald 1537*ea8aa208SMilanka Ringwald uint8_t i; 1538*ea8aa208SMilanka Ringwald for (i=0;i<4;i++){ 1539*ea8aa208SMilanka Ringwald if (sampling_frequency_hz == sbc_sampling_frequency_table[i]){ 1540*ea8aa208SMilanka Ringwald sampling_frequency_bitmap = 1 << i; 1541fdd788feSMatthias Ringwald break; 1542fdd788feSMatthias Ringwald } 1543*ea8aa208SMilanka Ringwald } 1544*ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1545*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1546*ea8aa208SMilanka Ringwald } 1547*ea8aa208SMilanka Ringwald config[0] = (config[0] & 0x0f) | (uint8_t)(sampling_frequency_bitmap << 4); 1548*ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS; 1549fdd788feSMatthias Ringwald } 1550fdd788feSMatthias Ringwald 1551*ea8aa208SMilanka Ringwald uint8_t avdtp_config_sbc_store(uint8_t * config, const avdtp_configuration_sbc_t * configuration){ 1552*ea8aa208SMilanka Ringwald if (configuration->channel_mode > AVDTP_CHANNEL_MODE_JOINT_STEREO){ 1553*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1554*ea8aa208SMilanka Ringwald } 1555*ea8aa208SMilanka Ringwald if (configuration->allocation_method > AVDTP_SBC_ALLOCATION_METHOD_SNR){ 1556*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1557*ea8aa208SMilanka Ringwald } 1558*ea8aa208SMilanka Ringwald switch (configuration->block_length){ 1559*ea8aa208SMilanka Ringwald case 4: 1560*ea8aa208SMilanka Ringwald case 8: 1561*ea8aa208SMilanka Ringwald case 12: 1562*ea8aa208SMilanka Ringwald case 16: 1563fdd788feSMatthias Ringwald break; 1564fdd788feSMatthias Ringwald default: 1565*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1566fdd788feSMatthias Ringwald } 1567*ea8aa208SMilanka Ringwald switch (configuration->subbands){ 1568*ea8aa208SMilanka Ringwald case 4: 1569*ea8aa208SMilanka Ringwald case 8: 1570*ea8aa208SMilanka Ringwald break; 1571*ea8aa208SMilanka Ringwald default: 1572*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1573*ea8aa208SMilanka Ringwald } 1574*ea8aa208SMilanka Ringwald if ((configuration->min_bitpool_value < 2) || (configuration->min_bitpool_value > 250) || (configuration->min_bitpool_value > configuration->max_bitpool_value)){ 1575*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1576*ea8aa208SMilanka Ringwald } 1577*ea8aa208SMilanka Ringwald if ((configuration->max_bitpool_value < 2) || (configuration->max_bitpool_value > 250)){ 1578*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1579*ea8aa208SMilanka Ringwald } 1580*ea8aa208SMilanka Ringwald config[0] = 1 << (3 - (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO)); 15818691a66cSMatthias Ringwald config[1] = (configuration->block_length << 4) | (configuration->subbands << 2) | configuration->allocation_method; 15828691a66cSMatthias Ringwald config[2] = configuration->min_bitpool_value; 15838691a66cSMatthias Ringwald config[3] = configuration->max_bitpool_value; 1584*ea8aa208SMilanka Ringwald return avdtp_config_sbc_set_sampling_frequency(config, configuration->sampling_frequency); 1585fdd788feSMatthias Ringwald } 1586fdd788feSMatthias Ringwald 1587*ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_audio_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1588*ea8aa208SMilanka Ringwald uint8_t sampling_frequency_bitmap = 0; 1589*ea8aa208SMilanka Ringwald const uint16_t mpeg_sampling_frequency_table[] = { 1590*ea8aa208SMilanka Ringwald 48000, 44100, 32000, 24000, 22040, 16000 1591*ea8aa208SMilanka Ringwald }; 1592*ea8aa208SMilanka Ringwald 1593*ea8aa208SMilanka Ringwald uint8_t i; 1594*ea8aa208SMilanka Ringwald for (i=0;i<6;i++){ 1595*ea8aa208SMilanka Ringwald if (sampling_frequency_hz == mpeg_sampling_frequency_table[i]){ 1596*ea8aa208SMilanka Ringwald sampling_frequency_bitmap = 1 << i; 1597f9e215c7SMatthias Ringwald break; 1598fdd788feSMatthias Ringwald } 1599*ea8aa208SMilanka Ringwald } 1600*ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1601*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1602*ea8aa208SMilanka Ringwald } 1603*ea8aa208SMilanka Ringwald config[1] = (config[1] & 0xE0) | sampling_frequency_bitmap; 1604*ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS; 1605fdd788feSMatthias Ringwald } 1606fdd788feSMatthias Ringwald 1607*ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_audio_store(uint8_t * config, const avdtp_configuration_mpeg_audio_t * configuration){ 1608*ea8aa208SMilanka Ringwald if (configuration->layer > AVDTP_MPEG_LAYER_3){ 1609*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1610*ea8aa208SMilanka Ringwald } 1611*ea8aa208SMilanka Ringwald if (configuration->channel_mode > AVDTP_CHANNEL_MODE_JOINT_STEREO){ 1612*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1613*ea8aa208SMilanka Ringwald } 1614*ea8aa208SMilanka Ringwald uint16_t bit_rate_mask = 1 << configuration->bit_rate_index; 1615*ea8aa208SMilanka Ringwald if (bit_rate_mask == 0){ 1616*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1617*ea8aa208SMilanka Ringwald } 1618*ea8aa208SMilanka Ringwald 16198691a66cSMatthias Ringwald config[0] = (1 << (7 - (configuration->layer - AVDTP_MPEG_LAYER_1))) | ((configuration->crc & 0x01) << 4) | (1 << (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO)); 16208691a66cSMatthias Ringwald config[1] = ((configuration->media_payload_format & 0x01) << 6) ; 16211da18615SMilanka Ringwald config[2] = ((configuration->vbr & 0x01) << 7) | ((bit_rate_mask >> 7) & 0x3f); 1622fdd788feSMatthias Ringwald config[3] = bit_rate_mask & 0xff; 1623*ea8aa208SMilanka Ringwald return avdtp_config_mpeg_audio_set_sampling_frequency(config, configuration->sampling_frequency); 1624fdd788feSMatthias Ringwald } 1625fdd788feSMatthias Ringwald 1626*ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1627fdd788feSMatthias Ringwald uint16_t sampling_frequency_bitmap = 0; 1628fdd788feSMatthias Ringwald uint8_t i; 1629fdd788feSMatthias Ringwald const uint32_t aac_sampling_frequency_table[] = { 1630fdd788feSMatthias Ringwald 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 1631fdd788feSMatthias Ringwald }; 1632fdd788feSMatthias Ringwald for (i=0;i<12;i++){ 1633fdd788feSMatthias Ringwald if (sampling_frequency_hz == aac_sampling_frequency_table[i]){ 1634fdd788feSMatthias Ringwald sampling_frequency_bitmap = 1 << i; 1635fdd788feSMatthias Ringwald break; 1636fdd788feSMatthias Ringwald } 1637fdd788feSMatthias Ringwald } 1638*ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1639*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1640*ea8aa208SMilanka Ringwald } 1641*ea8aa208SMilanka Ringwald 1642fdd788feSMatthias Ringwald config[1] = sampling_frequency_bitmap >> 4; 1643fdd788feSMatthias Ringwald config[2] = ((sampling_frequency_bitmap & 0x0f) << 4) | (config[2] & 0x0f); 1644*ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS; 1645fdd788feSMatthias Ringwald } 1646fdd788feSMatthias Ringwald 1647c83b8b89SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_store(uint8_t * config, const avdtp_configuration_mpeg_aac_t * configuration) { 16480737c3bfSMilanka Ringwald config[0] = (1 << (7 -(configuration->object_type - AVDTP_AAC_MPEG2_LC))) | (configuration->drc?1u:0u); 1649fdd788feSMatthias Ringwald uint8_t channels_bitmap = 0; 16508691a66cSMatthias Ringwald switch (configuration->channels){ 1651fdd788feSMatthias Ringwald case 1: 16520737c3bfSMilanka Ringwald channels_bitmap = 0x08; 1653fdd788feSMatthias Ringwald break; 1654fdd788feSMatthias Ringwald case 2: 16550737c3bfSMilanka Ringwald channels_bitmap = 0x04; 16560737c3bfSMilanka Ringwald break; 16570737c3bfSMilanka Ringwald case 6: 16580737c3bfSMilanka Ringwald channels_bitmap = 0x02; 16590737c3bfSMilanka Ringwald break; 16600737c3bfSMilanka Ringwald case 8: 1661fdd788feSMatthias Ringwald channels_bitmap = 0x01; 1662fdd788feSMatthias Ringwald break; 1663fdd788feSMatthias Ringwald default: 1664c83b8b89SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1665fdd788feSMatthias Ringwald } 1666c83b8b89SMilanka Ringwald config[2] = channels_bitmap; 16678691a66cSMatthias Ringwald config[3] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f); 16688691a66cSMatthias Ringwald config[4] = (configuration->bit_rate >> 8) & 0xff; 16698691a66cSMatthias Ringwald config[5] = configuration->bit_rate & 0xff; 1670*ea8aa208SMilanka Ringwald return avdtp_config_mpeg_aac_set_sampling_frequency(config, configuration->sampling_frequency); 1671*ea8aa208SMilanka Ringwald } 1672*ea8aa208SMilanka Ringwald 1673*ea8aa208SMilanka Ringwald uint8_t avdtp_config_atrac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1674*ea8aa208SMilanka Ringwald uint8_t sampling_frequency_bitmap = 0; 1675*ea8aa208SMilanka Ringwald uint8_t i; 1676*ea8aa208SMilanka Ringwald const uint32_t atrac_sampling_frequency_table[] = { 1677*ea8aa208SMilanka Ringwald 48000, 44100 1678*ea8aa208SMilanka Ringwald }; 1679*ea8aa208SMilanka Ringwald for (i=0;i<2;i++){ 1680*ea8aa208SMilanka Ringwald if (sampling_frequency_hz == atrac_sampling_frequency_table[i]){ 1681*ea8aa208SMilanka Ringwald sampling_frequency_bitmap = 1 << i; 1682*ea8aa208SMilanka Ringwald break; 1683*ea8aa208SMilanka Ringwald } 1684*ea8aa208SMilanka Ringwald } 1685*ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1686*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1687*ea8aa208SMilanka Ringwald } 1688*ea8aa208SMilanka Ringwald 1689*ea8aa208SMilanka Ringwald config[1] = (config[1] & 0xCF) | (uint8_t)(sampling_frequency_bitmap << 4); 1690c83b8b89SMilanka Ringwald return ERROR_CODE_SUCCESS; 1691fdd788feSMatthias Ringwald } 1692fdd788feSMatthias Ringwald 1693*ea8aa208SMilanka Ringwald uint8_t avdtp_config_atrac_store(uint8_t * config, const avdtp_configuration_atrac_t * configuration){ 1694a3868652SMatthias Ringwald uint8_t channel_mode_bitmap = 0; 16958691a66cSMatthias Ringwald switch (configuration->channel_mode){ 1696fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_MONO: 1697a3868652SMatthias Ringwald channel_mode_bitmap = 4; 1698fdd788feSMatthias Ringwald break; 1699fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_DUAL_CHANNEL: 1700a3868652SMatthias Ringwald channel_mode_bitmap = 2; 1701fdd788feSMatthias Ringwald break; 1702fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_JOINT_STEREO: 1703a3868652SMatthias Ringwald channel_mode_bitmap = 1; 1704fdd788feSMatthias Ringwald break; 1705fdd788feSMatthias Ringwald default: 1706*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1707fdd788feSMatthias Ringwald } 17088691a66cSMatthias Ringwald config[0] = ((configuration->version - AVDTP_ATRAC_VERSION_1 + 1) << 5) | (channel_mode_bitmap << 2); 17098691a66cSMatthias Ringwald uint32_t bit_rate_bitmap = 1 << (0x18 - configuration->bit_rate_index); 17108691a66cSMatthias Ringwald config[1] = ((configuration->vbr & 0x01) << 3) | ((bit_rate_bitmap >> 16) & 0x07); 1711fdd788feSMatthias Ringwald config[2] = (bit_rate_bitmap >> 8) & 0xff; 1712fdd788feSMatthias Ringwald config[3] = bit_rate_bitmap & 0xff; 17138691a66cSMatthias Ringwald config[4] = configuration->maximum_sul >> 8; 17148691a66cSMatthias Ringwald config[5] = configuration->maximum_sul & 0xff; 1715fdd788feSMatthias Ringwald config[6] = 0; 1716*ea8aa208SMilanka Ringwald return avdtp_config_atrac_set_sampling_frequency(config, configuration->sampling_frequency); 1717fdd788feSMatthias Ringwald } 171824d5fe84SMilanka Ringwald 1719*ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpegd_usac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1720*ea8aa208SMilanka Ringwald uint32_t sampling_frequency_bitmap = 0; 172124d5fe84SMilanka Ringwald uint8_t i; 172224d5fe84SMilanka Ringwald const uint32_t usac_sampling_frequency_table[] = { 172324d5fe84SMilanka Ringwald 96000, 88200, 76800, 70560, 172424d5fe84SMilanka Ringwald 64000, 58800, 48000, 44100, 38400, 35280, 32000, 29400, 172524d5fe84SMilanka Ringwald 24000, 22050, 19200, 17640, 16000, 14700, 12800, 12000, 172624d5fe84SMilanka Ringwald 11760, 11025, 9600, 8820, 8000, 7350 172724d5fe84SMilanka Ringwald }; 172824d5fe84SMilanka Ringwald for (i=0;i<26;i++){ 172924d5fe84SMilanka Ringwald if (sampling_frequency_hz == usac_sampling_frequency_table[i]){ 173024d5fe84SMilanka Ringwald sampling_frequency_bitmap = 1 << i; 173124d5fe84SMilanka Ringwald break; 173224d5fe84SMilanka Ringwald } 173324d5fe84SMilanka Ringwald } 1734*ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1735*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1736*ea8aa208SMilanka Ringwald } 1737*ea8aa208SMilanka Ringwald config[0] = (config[0] & 0xC0) | (uint8_t)(sampling_frequency_bitmap >> 20); 1738*ea8aa208SMilanka Ringwald config[1] = (uint8_t) (sampling_frequency_bitmap >> 12); 1739*ea8aa208SMilanka Ringwald config[2] = (uint8_t) (sampling_frequency_bitmap >> 4); 174024d5fe84SMilanka Ringwald config[3] = (sampling_frequency_bitmap & 0x0f) << 4; 1741*ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS; 174224d5fe84SMilanka Ringwald } 174324d5fe84SMilanka Ringwald 1744*ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpegd_usac_store(uint8_t * config, const avdtp_configuration_mpegd_usac_t * configuration) { 1745*ea8aa208SMilanka Ringwald if (configuration->object_type != AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC){ 1746*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1747*ea8aa208SMilanka Ringwald } 1748*ea8aa208SMilanka Ringwald config[0] = 0x80; 174924d5fe84SMilanka Ringwald 175024d5fe84SMilanka Ringwald uint8_t channels_bitmap = 0; 175124d5fe84SMilanka Ringwald switch (configuration->channels){ 175224d5fe84SMilanka Ringwald case 1: 175324d5fe84SMilanka Ringwald channels_bitmap = 0x08; 175424d5fe84SMilanka Ringwald break; 175524d5fe84SMilanka Ringwald case 2: 175624d5fe84SMilanka Ringwald channels_bitmap = 0x04; 175724d5fe84SMilanka Ringwald break; 175824d5fe84SMilanka Ringwald default: 1759*ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 176024d5fe84SMilanka Ringwald } 176124d5fe84SMilanka Ringwald config[3] = config[3] | channels_bitmap; 176224d5fe84SMilanka Ringwald config[4] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f); 176324d5fe84SMilanka Ringwald config[5] = (configuration->bit_rate >> 8) & 0xff; 176424d5fe84SMilanka Ringwald config[6] = configuration->bit_rate & 0xff; 1765*ea8aa208SMilanka Ringwald return avdtp_config_mpegd_usac_set_sampling_frequency(config, configuration->sampling_frequency); 176624d5fe84SMilanka Ringwald }