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 }; 101588a837aSMilanka Ringwald 102ee230fc4SMilanka Ringwald const char * avdtp_si2str(uint16_t index){ 103c1e2cdaaSaroldxd if ((index <= 0) || (index >= sizeof(avdtp_si_name)/sizeof(avdtp_si_name[0]) )) return avdtp_si_name[0]; 104ee230fc4SMilanka Ringwald return avdtp_si_name[index]; 105ee230fc4SMilanka Ringwald } 106ee230fc4SMilanka Ringwald 107588a837aSMilanka Ringwald 108588a837aSMilanka Ringwald static const uint32_t usac_sampling_frequency_table[] = { 109588a837aSMilanka Ringwald 96000, 88200, 76800, 70560, 110588a837aSMilanka Ringwald 64000, 58800, 48000, 44100, 38400, 35280, 32000, 29400, 111588a837aSMilanka Ringwald 24000, 22050, 19200, 17640, 16000, 14700, 12800, 12000, 112588a837aSMilanka Ringwald 11760, 11025, 9600, 8820, 8000, 7350 113588a837aSMilanka Ringwald }; 114588a837aSMilanka Ringwald static const uint8_t usac_sampling_frequency_table_size = sizeof(usac_sampling_frequency_table)/sizeof(uint32_t); 115588a837aSMilanka Ringwald 116588a837aSMilanka Ringwald static const uint32_t mpeg_sampling_frequency_table[] = { 117588a837aSMilanka Ringwald 48000, 44100, 32000, 24000, 22040, 16000 118588a837aSMilanka Ringwald }; 119588a837aSMilanka Ringwald static const uint8_t mpeg_sampling_frequency_table_size = sizeof(mpeg_sampling_frequency_table)/sizeof(uint32_t); 120588a837aSMilanka Ringwald 121588a837aSMilanka Ringwald static const uint32_t sbc_sampling_frequency_table[] = { 122588a837aSMilanka Ringwald 48000, 44100, 32000, 16000 123588a837aSMilanka Ringwald }; 124588a837aSMilanka Ringwald static const uint8_t sbc_sampling_frequency_table_size = sizeof(sbc_sampling_frequency_table)/sizeof(uint32_t); 125588a837aSMilanka Ringwald 126588a837aSMilanka Ringwald static const uint32_t atrac_sampling_frequency_table[] = { 127588a837aSMilanka Ringwald 48000, 44100 128588a837aSMilanka Ringwald }; 129588a837aSMilanka Ringwald static const uint8_t atrac_sampling_frequency_table_size = sizeof(atrac_sampling_frequency_table)/sizeof(uint32_t); 130588a837aSMilanka Ringwald 131588a837aSMilanka Ringwald static const uint32_t aac_sampling_frequency_table[] = { 132588a837aSMilanka Ringwald 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 133588a837aSMilanka Ringwald }; 134588a837aSMilanka Ringwald static const uint8_t aac_sampling_frequency_table_size = sizeof(aac_sampling_frequency_table)/sizeof(uint32_t); 135588a837aSMilanka Ringwald 136588a837aSMilanka Ringwald static uint32_t avdtp_config_get_sampling_frequency_bitmap_from_table(uint16_t sampling_frequency_hz, const uint32_t * table, uint8_t table_size) { 137588a837aSMilanka Ringwald uint8_t i; 138588a837aSMilanka Ringwald for (i = 0; i < table_size; i++){ 139588a837aSMilanka Ringwald if (sampling_frequency_hz == table[i]){ 140588a837aSMilanka Ringwald return 1 << i; 141588a837aSMilanka Ringwald } 142588a837aSMilanka Ringwald } 143588a837aSMilanka Ringwald return 0; 144588a837aSMilanka Ringwald } 145588a837aSMilanka Ringwald 146588a837aSMilanka Ringwald static uint32_t avdtp_config_get_sampling_frequency_from_table(uint16_t sampling_frequency_bitmap, const uint32_t * table, uint8_t table_size) { 147588a837aSMilanka Ringwald uint8_t i; 148588a837aSMilanka Ringwald for (i = 0; i < table_size; i++){ 149588a837aSMilanka Ringwald if (sampling_frequency_bitmap & (1U << i)) { 150588a837aSMilanka Ringwald return table[i]; 151588a837aSMilanka Ringwald } 152588a837aSMilanka Ringwald } 153588a837aSMilanka Ringwald return 0; 154588a837aSMilanka Ringwald } 155588a837aSMilanka Ringwald 156588a837aSMilanka Ringwald 157485c0a4cSMilanka Ringwald void avdtp_reset_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){ 158485c0a4cSMilanka Ringwald stream_endpoint->media_con_handle = 0; 159485c0a4cSMilanka Ringwald stream_endpoint->l2cap_media_cid = 0; 160485c0a4cSMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0; 161485c0a4cSMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0; 162485c0a4cSMilanka Ringwald 163747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE; 164747ec646SMilanka Ringwald stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE; 165747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE; 166485c0a4cSMilanka Ringwald 167b3b67de4SMilanka Ringwald stream_endpoint->connection = NULL; 168b3b67de4SMilanka Ringwald 169747ec646SMilanka Ringwald stream_endpoint->sep.in_use = 0; 170485c0a4cSMilanka Ringwald memset(&stream_endpoint->remote_sep, 0, sizeof(avdtp_sep_t)); 171485c0a4cSMilanka Ringwald 172485c0a4cSMilanka Ringwald stream_endpoint->remote_capabilities_bitmap = 0; 173b3b67de4SMilanka Ringwald memset(&stream_endpoint->remote_capabilities, 0, sizeof(avdtp_capabilities_t)); 174485c0a4cSMilanka Ringwald stream_endpoint->remote_configuration_bitmap = 0; 175b3b67de4SMilanka Ringwald memset(&stream_endpoint->remote_configuration, 0, sizeof(avdtp_capabilities_t)); 176b3b67de4SMilanka Ringwald 17782767773SMatthias Ringwald // temporary SBC config used by A2DP Source 178ec9b5b0fSMatthias Ringwald memset(stream_endpoint->media_codec_info, 0, 8); 179485c0a4cSMilanka Ringwald 180485c0a4cSMilanka Ringwald stream_endpoint->media_disconnect = 0; 181485c0a4cSMilanka Ringwald stream_endpoint->media_connect = 0; 182485c0a4cSMilanka Ringwald stream_endpoint->start_stream = 0; 183fa4419dbSMilanka Ringwald stream_endpoint->close_stream = 0; 184d0676819SMatthias Ringwald stream_endpoint->request_can_send_now = false; 185485c0a4cSMilanka Ringwald stream_endpoint->abort_stream = 0; 186485c0a4cSMilanka Ringwald stream_endpoint->suspend_stream = 0; 187485c0a4cSMilanka Ringwald stream_endpoint->sequence_number = 0; 188747ec646SMilanka Ringwald } 189747ec646SMilanka Ringwald 1908ef7100fSMilanka Ringwald int get_bit16(uint16_t bitmap, int position){ 1918ef7100fSMilanka Ringwald return (bitmap >> position) & 1; 1928ef7100fSMilanka Ringwald } 1938ef7100fSMilanka Ringwald 194ea6072afSMilanka Ringwald uint16_t store_bit16(uint16_t bitmap, int position, uint8_t value){ 1958ef7100fSMilanka Ringwald if (value){ 1968ef7100fSMilanka Ringwald bitmap |= 1 << position; 1978ef7100fSMilanka Ringwald } else { 1988ef7100fSMilanka Ringwald bitmap &= ~ (1 << position); 1998ef7100fSMilanka Ringwald } 2008ef7100fSMilanka Ringwald return bitmap; 2018ef7100fSMilanka Ringwald } 2028ef7100fSMilanka Ringwald 203335dba6aSMatthias Ringwald avdtp_message_type_t avdtp_get_signaling_message_type(uint8_t * packet){ 204c1c40ea1SMatthias Ringwald return (avdtp_message_type_t) (packet[0] & 0x03); 205c1c40ea1SMatthias Ringwald } 206c1c40ea1SMatthias Ringwald 2073d79ed3bSMatthias Ringwald // returns 0 if header incomplete 2088ef7100fSMilanka Ringwald int avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header, uint8_t * packet, uint16_t size){ 2098ef7100fSMilanka Ringwald int pos = 0; 2103d79ed3bSMatthias Ringwald if (size < 2) return 0; 2118ef7100fSMilanka Ringwald signaling_header->transaction_label = packet[pos] >> 4; 2128ef7100fSMilanka Ringwald signaling_header->packet_type = (avdtp_packet_type_t)((packet[pos] >> 2) & 0x03); 2138ef7100fSMilanka Ringwald signaling_header->message_type = (avdtp_message_type_t) (packet[pos] & 0x03); 2148ef7100fSMilanka Ringwald pos++; 2158ef7100fSMilanka Ringwald memset(signaling_header->command, 0, sizeof(signaling_header->command)); 2168ef7100fSMilanka Ringwald switch (signaling_header->packet_type){ 2178ef7100fSMilanka Ringwald case AVDTP_SINGLE_PACKET: 2188ef7100fSMilanka Ringwald signaling_header->num_packets = 0; 2198ef7100fSMilanka Ringwald signaling_header->offset = 0; 2208ef7100fSMilanka Ringwald signaling_header->size = 0; 2218ef7100fSMilanka Ringwald break; 2228ef7100fSMilanka Ringwald case AVDTP_END_PACKET: 2238ef7100fSMilanka Ringwald signaling_header->num_packets = 0; 2248ef7100fSMilanka Ringwald break; 2258ef7100fSMilanka Ringwald case AVDTP_START_PACKET: 2268ef7100fSMilanka Ringwald signaling_header->num_packets = packet[pos++]; 2273d79ed3bSMatthias Ringwald if (pos < 3) return 0; 2288ef7100fSMilanka Ringwald signaling_header->size = 0; 2298ef7100fSMilanka Ringwald signaling_header->offset = 0; 2308ef7100fSMilanka Ringwald break; 2318ef7100fSMilanka Ringwald case AVDTP_CONTINUE_PACKET: 2328ef7100fSMilanka Ringwald if (signaling_header->num_packets <= 0) { 2338587e32cSMilanka Ringwald log_info(" ERROR: wrong num fragmented packets\n"); 2348ef7100fSMilanka Ringwald break; 2358ef7100fSMilanka Ringwald } 2368ef7100fSMilanka Ringwald signaling_header->num_packets--; 2378ef7100fSMilanka Ringwald break; 2387bbeb3adSMilanka Ringwald default: 2397bbeb3adSMilanka Ringwald btstack_assert(false); 2407bbeb3adSMilanka Ringwald break; 2418ef7100fSMilanka Ringwald } 242b0920f25SMilanka Ringwald signaling_header->signal_identifier = (avdtp_signal_identifier_t)(packet[pos++] & 0x3f); 2438ef7100fSMilanka Ringwald return pos; 2448ef7100fSMilanka Ringwald } 2458ef7100fSMilanka Ringwald 24650d5c6caSMatthias Ringwald static bool avdtp_is_basic_capability(int service_category){ 24750d5c6caSMatthias Ringwald return (AVDTP_MEDIA_TRANSPORT <= service_category) && (service_category <= AVDTP_MEDIA_CODEC); 24850d5c6caSMatthias Ringwald } 24950d5c6caSMatthias Ringwald 25050d5c6caSMatthias Ringwald int avdtp_pack_service_capabilities(uint8_t *buffer, int size, avdtp_capabilities_t caps, avdtp_service_category_t category) { 2518ef7100fSMilanka Ringwald UNUSED(size); 2528ef7100fSMilanka Ringwald 2538ef7100fSMilanka Ringwald int i; 2548ef7100fSMilanka Ringwald // pos = 0 reserved for length 2558ef7100fSMilanka Ringwald int pos = 1; 2568ef7100fSMilanka Ringwald switch(category){ 2578ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 2588ef7100fSMilanka Ringwald case AVDTP_REPORTING: 2598ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 2608ef7100fSMilanka Ringwald break; 2618ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 2628ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.recovery_type; // 0x01=RFC2733 2638ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.maximum_recovery_window_size; 2648ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.maximum_number_media_packets; 2658ef7100fSMilanka Ringwald break; 2668ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 2678ef7100fSMilanka Ringwald buffer[pos++] = caps.content_protection.cp_type_value_len + 2; 2688ef7100fSMilanka Ringwald big_endian_store_16(buffer, pos, caps.content_protection.cp_type); 2698ef7100fSMilanka Ringwald pos += 2; 2706535961aSMatthias Ringwald (void)memcpy(buffer + pos, caps.content_protection.cp_type_value, 2716535961aSMatthias Ringwald caps.content_protection.cp_type_value_len); 27274b2411bSMilanka Ringwald pos += caps.content_protection.cp_type_value_len; 2738ef7100fSMilanka Ringwald break; 2748ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 2758ef7100fSMilanka Ringwald buffer[pos++] = (caps.header_compression.back_ch << 7) | (caps.header_compression.media << 6) | (caps.header_compression.recovery << 5); 2768ef7100fSMilanka Ringwald break; 2778ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 2788ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.fragmentation << 7; 2798ef7100fSMilanka Ringwald for (i=0; i<caps.multiplexing_mode.transport_identifiers_num; i++){ 2808ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.transport_session_identifiers[i] << 7; 2818ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.tcid[i] << 7; 2828ef7100fSMilanka Ringwald // media, reporting. recovery 2838ef7100fSMilanka Ringwald } 2848ef7100fSMilanka Ringwald break; 2858ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 2868ef7100fSMilanka Ringwald buffer[pos++] = ((uint8_t)caps.media_codec.media_type) << 4; 2878ef7100fSMilanka Ringwald buffer[pos++] = (uint8_t)caps.media_codec.media_codec_type; 2888ef7100fSMilanka Ringwald for (i = 0; i<caps.media_codec.media_codec_information_len; i++){ 2898ef7100fSMilanka Ringwald buffer[pos++] = caps.media_codec.media_codec_information[i]; 2908ef7100fSMilanka Ringwald } 2918ef7100fSMilanka Ringwald break; 2928ef7100fSMilanka Ringwald default: 2938ef7100fSMilanka Ringwald break; 2948ef7100fSMilanka Ringwald } 2958ef7100fSMilanka Ringwald buffer[0] = pos - 1; // length 2968ef7100fSMilanka Ringwald return pos; 2978ef7100fSMilanka Ringwald } 2988ef7100fSMilanka Ringwald 299390aa582SMatthias 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){ 3008ef7100fSMilanka Ringwald connection->error_code = 0; 3018ef7100fSMilanka Ringwald 30276827215SMatthias Ringwald if ((category == AVDTP_SERVICE_CATEGORY_INVALID_0) || (category > AVDTP_DELAY_REPORTING)){ 3038587e32cSMilanka Ringwald log_info(" ERROR: BAD SERVICE CATEGORY %d\n", category); 3048ef7100fSMilanka Ringwald connection->reject_service_category = category; 3055b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_SERV_CATEGORY; 3068ef7100fSMilanka Ringwald return 1; 3078ef7100fSMilanka Ringwald } 3088ef7100fSMilanka Ringwald 309390aa582SMatthias Ringwald if (signal_identifier == AVDTP_SI_RECONFIGURE){ 3100e588213SMatthias Ringwald if ( (category != AVDTP_CONTENT_PROTECTION) && (category != AVDTP_MEDIA_CODEC)){ 3118587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, INVALID_CAPABILITIES\n"); 3128ef7100fSMilanka Ringwald connection->reject_service_category = category; 3135b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_INVALID_CAPABILITIES; 3148ef7100fSMilanka Ringwald return 1; 3158ef7100fSMilanka Ringwald } 3168ef7100fSMilanka Ringwald } 3178ef7100fSMilanka Ringwald 3188ef7100fSMilanka Ringwald switch(category){ 3198ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 3208ef7100fSMilanka Ringwald if (cap_len != 0){ 3218587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n"); 3228ef7100fSMilanka Ringwald connection->reject_service_category = category; 3235b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_MEDIA_TRANSPORT_FORMAT; 3248ef7100fSMilanka Ringwald return 1; 3258ef7100fSMilanka Ringwald } 3268ef7100fSMilanka Ringwald break; 3278ef7100fSMilanka Ringwald case AVDTP_REPORTING: 3288ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 3298ef7100fSMilanka Ringwald if (cap_len != 0){ 3308587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_LENGTH\n"); 3318ef7100fSMilanka Ringwald connection->reject_service_category = category; 3325b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_LENGTH; 3338ef7100fSMilanka Ringwald return 1; 3348ef7100fSMilanka Ringwald } 3358ef7100fSMilanka Ringwald break; 3368ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 337f6f3c903SMilanka Ringwald if (cap_len != 3){ 3388587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n"); 3398ef7100fSMilanka Ringwald connection->reject_service_category = category; 3405b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_RECOVERY_FORMAT; 3418ef7100fSMilanka Ringwald return 1; 3428ef7100fSMilanka Ringwald } 3438ef7100fSMilanka Ringwald break; 3448ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 3458ef7100fSMilanka Ringwald if (cap_len < 2){ 3468587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_CP_FORMAT\n"); 3478ef7100fSMilanka Ringwald connection->reject_service_category = category; 3485b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_CP_FORMAT; 3498ef7100fSMilanka Ringwald return 1; 3508ef7100fSMilanka Ringwald } 3518ef7100fSMilanka Ringwald break; 3528ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 353f6f3c903SMilanka Ringwald // TODO: find error code for bad header compression 354f6f3c903SMilanka Ringwald if (cap_len != 1){ 355f6f3c903SMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_HEADER_COMPRESSION\n"); 356f6f3c903SMilanka Ringwald connection->reject_service_category = category; 3575b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_RECOVERY_FORMAT; 358f6f3c903SMilanka Ringwald return 1; 359f6f3c903SMilanka Ringwald } 3608ef7100fSMilanka Ringwald break; 3618ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 3628ef7100fSMilanka Ringwald break; 3638ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 3648ef7100fSMilanka Ringwald break; 3658ef7100fSMilanka Ringwald default: 3668ef7100fSMilanka Ringwald break; 3678ef7100fSMilanka Ringwald } 3688ef7100fSMilanka Ringwald return 0; 3698ef7100fSMilanka Ringwald } 3708ef7100fSMilanka Ringwald 371afc28e0aSMatthias 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){ 372f6f3c903SMilanka Ringwald 373f6f3c903SMilanka Ringwald int i; 3748ef7100fSMilanka Ringwald 3758ef7100fSMilanka Ringwald uint16_t registered_service_categories = 0; 376f6f3c903SMilanka Ringwald uint16_t to_process = size; 377f6f3c903SMilanka Ringwald 378f6f3c903SMilanka Ringwald while (to_process >= 2){ 379f6f3c903SMilanka Ringwald 380f6f3c903SMilanka Ringwald avdtp_service_category_t category = (avdtp_service_category_t) packet[0]; 381f6f3c903SMilanka Ringwald uint8_t cap_len = packet[1]; 382f6f3c903SMilanka Ringwald packet += 2; 383f6f3c903SMilanka Ringwald to_process -= 2; 384f6f3c903SMilanka Ringwald 385f6f3c903SMilanka Ringwald if (cap_len > to_process){ 3868ef7100fSMilanka Ringwald connection->reject_service_category = category; 3875b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_LENGTH; 3888ef7100fSMilanka Ringwald return 0; 3898ef7100fSMilanka Ringwald } 39067ae582dSMilanka Ringwald 391afc28e0aSMatthias Ringwald if (avdtp_unpack_service_capabilities_has_errors(connection, signal_identifier, category, cap_len)) return 0; 39267ae582dSMilanka Ringwald 393f6f3c903SMilanka Ringwald int category_valid = 1; 39467ae582dSMilanka Ringwald 395f6f3c903SMilanka Ringwald uint8_t * data = packet; 396f6f3c903SMilanka Ringwald uint16_t pos = 0; 397f6f3c903SMilanka Ringwald 3988ef7100fSMilanka Ringwald switch(category){ 3998ef7100fSMilanka Ringwald case AVDTP_RECOVERY: 400f6f3c903SMilanka Ringwald caps->recovery.recovery_type = data[pos++]; 401f6f3c903SMilanka Ringwald caps->recovery.maximum_recovery_window_size = data[pos++]; 402f6f3c903SMilanka Ringwald caps->recovery.maximum_number_media_packets = data[pos++]; 4038ef7100fSMilanka Ringwald break; 4048ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION: 405f6f3c903SMilanka Ringwald caps->content_protection.cp_type = big_endian_read_16(data, 0); 4068ef7100fSMilanka Ringwald caps->content_protection.cp_type_value_len = cap_len - 2; 4078ef7100fSMilanka Ringwald // connection->reject_service_category = category; 4088ef7100fSMilanka Ringwald // connection->error_code = UNSUPPORTED_CONFIGURATION; 4098ef7100fSMilanka Ringwald // support for content protection goes here 4108ef7100fSMilanka Ringwald break; 4118ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION: 412f6f3c903SMilanka Ringwald caps->header_compression.back_ch = (data[0] >> 7) & 1; 413f6f3c903SMilanka Ringwald caps->header_compression.media = (data[0] >> 6) & 1; 414f6f3c903SMilanka Ringwald caps->header_compression.recovery = (data[0] >> 5) & 1; 4158ef7100fSMilanka Ringwald break; 4168ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING: 417f6f3c903SMilanka Ringwald caps->multiplexing_mode.fragmentation = (data[pos++] >> 7) & 1; 4188ef7100fSMilanka Ringwald // read [tsid, tcid] for media, reporting. recovery respectively 4198ef7100fSMilanka Ringwald caps->multiplexing_mode.transport_identifiers_num = 3; 4208ef7100fSMilanka Ringwald for (i=0; i<caps->multiplexing_mode.transport_identifiers_num; i++){ 421f6f3c903SMilanka Ringwald caps->multiplexing_mode.transport_session_identifiers[i] = (data[pos++] >> 7) & 1; 422f6f3c903SMilanka Ringwald caps->multiplexing_mode.tcid[i] = (data[pos++] >> 7) & 1; 4238ef7100fSMilanka Ringwald } 4248ef7100fSMilanka Ringwald break; 4258ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC: 426f6f3c903SMilanka Ringwald caps->media_codec.media_type = (avdtp_media_type_t)(data[pos++] >> 4); 427f6f3c903SMilanka Ringwald caps->media_codec.media_codec_type = (avdtp_media_codec_type_t)(data[pos++]); 4288ef7100fSMilanka Ringwald caps->media_codec.media_codec_information_len = cap_len - 2; 4294c7a1d3aSMatthias Ringwald caps->media_codec.media_codec_information = &data[pos++]; 4308ef7100fSMilanka Ringwald break; 4318ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT: 4328ef7100fSMilanka Ringwald case AVDTP_REPORTING: 4338ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING: 4348ef7100fSMilanka Ringwald break; 4358ef7100fSMilanka Ringwald default: 436f6f3c903SMilanka Ringwald category_valid = 0; 4378ef7100fSMilanka Ringwald break; 4388ef7100fSMilanka Ringwald } 4398ef7100fSMilanka Ringwald 440f6f3c903SMilanka Ringwald if (category_valid) { 4418ef7100fSMilanka Ringwald registered_service_categories = store_bit16(registered_service_categories, category, 1); 4428ef7100fSMilanka Ringwald } 443f6f3c903SMilanka Ringwald 444f6f3c903SMilanka Ringwald packet += cap_len; 445f6f3c903SMilanka Ringwald to_process -= cap_len; 44667ae582dSMilanka Ringwald } 447f6f3c903SMilanka Ringwald 4488ef7100fSMilanka Ringwald return registered_service_categories; 4498ef7100fSMilanka Ringwald } 4508ef7100fSMilanka Ringwald 45150d5c6caSMatthias 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){ 4528ef7100fSMilanka Ringwald if (signaling_packet->offset) return; 45350d5c6caSMatthias Ringwald bool basic_capabilities_only = false; 4548ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_RESPONSE_ACCEPT_MSG; 4558ef7100fSMilanka Ringwald int i; 456747ec646SMilanka Ringwald 457747ec646SMilanka Ringwald signaling_packet->size = 0; 458747ec646SMilanka Ringwald memset(signaling_packet->command, 0 , sizeof(signaling_packet->command)); 459747ec646SMilanka Ringwald 4608ef7100fSMilanka Ringwald switch (identifier) { 4618ef7100fSMilanka Ringwald case AVDTP_SI_GET_CAPABILITIES: 46250d5c6caSMatthias Ringwald basic_capabilities_only = true; 4638ef7100fSMilanka Ringwald break; 4648ef7100fSMilanka Ringwald case AVDTP_SI_GET_ALL_CAPABILITIES: 4658ef7100fSMilanka Ringwald break; 4668ef7100fSMilanka Ringwald case AVDTP_SI_SET_CONFIGURATION: 467747ec646SMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->acp_seid << 2; 4688ef7100fSMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->int_seid << 2; 4698ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_CMD_MSG; 4708ef7100fSMilanka Ringwald break; 4718ef7100fSMilanka Ringwald case AVDTP_SI_RECONFIGURE: 472747ec646SMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->acp_seid << 2; 4738ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_CMD_MSG; 4748ef7100fSMilanka Ringwald break; 4758ef7100fSMilanka Ringwald default: 4768ef7100fSMilanka Ringwald log_error("avdtp_prepare_capabilities wrong identifier %d", identifier); 4778ef7100fSMilanka Ringwald break; 4788ef7100fSMilanka Ringwald } 4798ef7100fSMilanka Ringwald 48050d5c6caSMatthias Ringwald for (i = AVDTP_MEDIA_TRANSPORT; i <= AVDTP_DELAY_REPORTING; i++){ 48150d5c6caSMatthias Ringwald int registered_category = get_bit16(service_categories, i); 4822bb3471fSMilanka Ringwald if (!registered_category && (identifier == AVDTP_SI_SET_CONFIGURATION)){ 483747ec646SMilanka Ringwald // TODO: introduce bitmap of mandatory categories 48450d5c6caSMatthias Ringwald if (i == AVDTP_MEDIA_TRANSPORT){ 48550d5c6caSMatthias Ringwald registered_category = true; 486747ec646SMilanka Ringwald } 487747ec646SMilanka Ringwald } 48850d5c6caSMatthias Ringwald // AVDTP_SI_GET_CAPABILITIES reports only basic capabilities (i.e., it skips non-basic categories) 48950d5c6caSMatthias Ringwald if (basic_capabilities_only && !avdtp_is_basic_capability(i)){ 49050d5c6caSMatthias Ringwald registered_category = false; 49150d5c6caSMatthias Ringwald } 49250d5c6caSMatthias Ringwald 493747ec646SMilanka Ringwald if (registered_category){ 4948ef7100fSMilanka Ringwald // service category 4958ef7100fSMilanka Ringwald signaling_packet->command[signaling_packet->size++] = i; 49650d5c6caSMatthias Ringwald signaling_packet->size += avdtp_pack_service_capabilities(signaling_packet->command + signaling_packet->size, 49750d5c6caSMatthias Ringwald sizeof(signaling_packet->command) - signaling_packet->size, capabilities, (avdtp_service_category_t) i); 4988ef7100fSMilanka Ringwald } 4998ef7100fSMilanka Ringwald } 500b0920f25SMilanka Ringwald signaling_packet->signal_identifier = (avdtp_signal_identifier_t)identifier; 5018ef7100fSMilanka Ringwald signaling_packet->transaction_label = transaction_label; 5028ef7100fSMilanka Ringwald } 5038ef7100fSMilanka Ringwald 5048ef7100fSMilanka Ringwald int avdtp_signaling_create_fragment(uint16_t cid, avdtp_signaling_packet_t * signaling_packet, uint8_t * out_buffer) { 5058ef7100fSMilanka Ringwald int mtu = l2cap_get_remote_mtu_for_local_cid(cid); 5068ef7100fSMilanka Ringwald int data_len = 0; 5078ef7100fSMilanka Ringwald 5088ef7100fSMilanka Ringwald uint16_t offset = signaling_packet->offset; 5098ef7100fSMilanka Ringwald uint16_t pos = 1; 5108ef7100fSMilanka Ringwald 5118ef7100fSMilanka Ringwald if (offset == 0){ 512c1ab6cc1SMatthias Ringwald if (signaling_packet->size <= (mtu - 2)){ 5138ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_SINGLE_PACKET; 5148ef7100fSMilanka Ringwald out_buffer[pos++] = signaling_packet->signal_identifier; 5158ef7100fSMilanka Ringwald data_len = signaling_packet->size; 5168ef7100fSMilanka Ringwald } else { 5178ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_START_PACKET; 5188ef7100fSMilanka Ringwald out_buffer[pos++] = (mtu + signaling_packet->size)/ (mtu-1); 5198ef7100fSMilanka Ringwald out_buffer[pos++] = signaling_packet->signal_identifier; 5208ef7100fSMilanka Ringwald data_len = mtu - 3; 5218ef7100fSMilanka Ringwald signaling_packet->offset = data_len; 5228ef7100fSMilanka Ringwald } 5238ef7100fSMilanka Ringwald } else { 5248ef7100fSMilanka Ringwald int remaining_bytes = signaling_packet->size - offset; 525c1ab6cc1SMatthias Ringwald if (remaining_bytes <= (mtu - 1)){ 5268ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_END_PACKET; 5278ef7100fSMilanka Ringwald data_len = remaining_bytes; 5288ef7100fSMilanka Ringwald signaling_packet->offset = 0; 5298ef7100fSMilanka Ringwald } else{ 5308ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_CONTINUE_PACKET; 5318ef7100fSMilanka Ringwald data_len = mtu - 1; 5328ef7100fSMilanka Ringwald signaling_packet->offset += data_len; 5338ef7100fSMilanka Ringwald } 5348ef7100fSMilanka Ringwald } 5358ef7100fSMilanka Ringwald out_buffer[0] = avdtp_header(signaling_packet->transaction_label, signaling_packet->packet_type, signaling_packet->message_type); 5366535961aSMatthias Ringwald (void)memcpy(out_buffer + pos, signaling_packet->command + offset, 5376535961aSMatthias Ringwald data_len); 5388ef7100fSMilanka Ringwald pos += data_len; 5398ef7100fSMilanka Ringwald return pos; 5408ef7100fSMilanka Ringwald } 5418ef7100fSMilanka Ringwald 5428ef7100fSMilanka Ringwald 543146fc0fbSMilanka Ringwald void avdtp_signaling_emit_connection_established(uint16_t avdtp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status) { 544146fc0fbSMilanka Ringwald uint8_t event[14]; 5458ef7100fSMilanka Ringwald int pos = 0; 5468ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5478ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5488ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED; 549f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5508ef7100fSMilanka Ringwald pos += 2; 5518ef7100fSMilanka Ringwald reverse_bd_addr(addr,&event[pos]); 5528ef7100fSMilanka Ringwald pos += 6; 553146fc0fbSMilanka Ringwald little_endian_store_16(event, pos, con_handle); 554146fc0fbSMilanka Ringwald pos += 2; 5558ef7100fSMilanka Ringwald event[pos++] = status; 556c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5578ef7100fSMilanka Ringwald } 5588ef7100fSMilanka Ringwald 559c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_connection_released(uint16_t avdtp_cid) { 56034b22aacSMilanka Ringwald uint8_t event[5]; 56134b22aacSMilanka Ringwald int pos = 0; 56234b22aacSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 56334b22aacSMilanka Ringwald event[pos++] = sizeof(event) - 2; 56434b22aacSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED; 56534b22aacSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 56634b22aacSMilanka Ringwald pos += 2; 567c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 56834b22aacSMilanka Ringwald } 56934b22aacSMilanka Ringwald 570c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_sep(uint16_t avdtp_cid, avdtp_sep_t sep) { 5718ef7100fSMilanka Ringwald uint8_t event[9]; 5728ef7100fSMilanka Ringwald int pos = 0; 5738ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 5748ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 5758ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_FOUND; 576f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 5778ef7100fSMilanka Ringwald pos += 2; 5788ef7100fSMilanka Ringwald event[pos++] = sep.seid; 5798ef7100fSMilanka Ringwald event[pos++] = sep.in_use; 5808ef7100fSMilanka Ringwald event[pos++] = sep.media_type; 5818ef7100fSMilanka Ringwald event[pos++] = sep.type; 582c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 5838ef7100fSMilanka Ringwald } 5848ef7100fSMilanka Ringwald 585c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_sep_done(uint16_t avdtp_cid) { 586485c0a4cSMilanka Ringwald uint8_t event[5]; 587485c0a4cSMilanka Ringwald int pos = 0; 588485c0a4cSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 589485c0a4cSMilanka Ringwald event[pos++] = sizeof(event) - 2; 590485c0a4cSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE; 591485c0a4cSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 592485c0a4cSMilanka Ringwald pos += 2; 593c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 594485c0a4cSMilanka Ringwald } 595485c0a4cSMilanka Ringwald 596c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_accept(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 59763274943SMilanka Ringwald uint8_t event[8]; 5988ef7100fSMilanka Ringwald int pos = 0; 5998ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6008ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 6018ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT; 602f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 6038ef7100fSMilanka Ringwald pos += 2; 6044ccacc40SMilanka Ringwald event[pos++] = local_seid; 60563274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 6068ef7100fSMilanka Ringwald event[pos++] = identifier; 607c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6088ef7100fSMilanka Ringwald } 6098ef7100fSMilanka Ringwald 61046b99c89SMatthias 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){ 61146b99c89SMatthias Ringwald uint8_t event[8]; 61246b99c89SMatthias Ringwald int pos = 0; 61346b99c89SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 61446b99c89SMatthias Ringwald event[pos++] = sizeof(event) - 2; 61546b99c89SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT; 61646b99c89SMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 61746b99c89SMatthias Ringwald pos += 2; 61846b99c89SMatthias Ringwald event[pos++] = local_seid; 61946b99c89SMatthias Ringwald event[pos++] = is_initiator ? 1 : 0; 62046b99c89SMatthias Ringwald event[pos++] = identifier; 62146b99c89SMatthias Ringwald 62246b99c89SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 62346b99c89SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 62446b99c89SMatthias Ringwald } 62546b99c89SMatthias Ringwald 626c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_reject(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 62763274943SMilanka Ringwald uint8_t event[8]; 6288ef7100fSMilanka Ringwald int pos = 0; 6298ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6308ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 6318ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_REJECT; 632f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 6338ef7100fSMilanka Ringwald pos += 2; 6344ccacc40SMilanka Ringwald event[pos++] = local_seid; 63563274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 6368ef7100fSMilanka Ringwald event[pos++] = identifier; 637c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6388ef7100fSMilanka Ringwald } 6398ef7100fSMilanka Ringwald 640c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_general_reject(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) { 64163274943SMilanka Ringwald uint8_t event[8]; 6428ef7100fSMilanka Ringwald int pos = 0; 6438ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6448ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 6458ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT; 646f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 6478ef7100fSMilanka Ringwald pos += 2; 6484ccacc40SMilanka Ringwald event[pos++] = local_seid; 64963274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0; 6508ef7100fSMilanka Ringwald event[pos++] = identifier; 651c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6528ef7100fSMilanka Ringwald } 6538ef7100fSMilanka Ringwald 6544b7d40bbSMatthias Ringwald static inline void 6551159d239SMatthias Ringwald avdtp_signaling_emit_capability(uint8_t capability_subevent_id, uint16_t avdtp_cid, uint8_t remote_seid) { 6561159d239SMatthias Ringwald uint8_t event[6]; 6574b7d40bbSMatthias Ringwald int pos = 0; 6584b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6594b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 6604b7d40bbSMatthias Ringwald event[pos++] = capability_subevent_id; 6614b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 6624b7d40bbSMatthias Ringwald pos += 2; 6634b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 6644b7d40bbSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6654b7d40bbSMatthias Ringwald } 6664b7d40bbSMatthias Ringwald 6671159d239SMatthias 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) { 6685ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 6691159d239SMatthias Ringwald uint8_t event[14]; 6708ef7100fSMilanka Ringwald int pos = 0; 6718ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6728ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2; 6738ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY; 674f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 6758ef7100fSMilanka Ringwald pos += 2; 6764ccacc40SMilanka Ringwald event[pos++] = remote_seid; 6778ef7100fSMilanka Ringwald event[pos++] = media_codec.media_type; 6785ce3497fSMatthias Ringwald event[pos++] = media_codec_information[0] >> 4; 6795ce3497fSMatthias Ringwald event[pos++] = media_codec_information[0] & 0x0F; 6805ce3497fSMatthias Ringwald event[pos++] = media_codec_information[1] >> 4; 6815ce3497fSMatthias Ringwald event[pos++] = (media_codec_information[1] & 0x0F) >> 2; 6825ce3497fSMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03; 6835ce3497fSMatthias Ringwald event[pos++] = media_codec_information[2]; 6845ce3497fSMatthias Ringwald event[pos++] = media_codec_information[3]; 6855ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 6865ce3497fSMatthias Ringwald } 6875ce3497fSMatthias Ringwald 6885ce3497fSMatthias 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) { 6895ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 6905ce3497fSMatthias Ringwald uint8_t event[15]; 6915ce3497fSMatthias Ringwald int pos = 0; 6925ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 6935ce3497fSMatthias Ringwald event[pos++] = sizeof(event) - 2; 6945ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CAPABILITY; 6955ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 6965ce3497fSMatthias Ringwald pos += 2; 6975ce3497fSMatthias Ringwald event[pos++] = remote_seid; 6985ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 6995ce3497fSMatthias Ringwald 7005ce3497fSMatthias Ringwald uint8_t layer_bitmap = media_codec_information[0] >> 5; 7015ce3497fSMatthias Ringwald uint8_t crc = (media_codec_information[0] >> 4) & 0x01; 7025ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x07; 7035ce3497fSMatthias Ringwald uint8_t mpf = (media_codec_information[1] >> 6) & 0x01; 7045ce3497fSMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[1] & 0x3F; 7055ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[2] >> 7) & 0x01; 7065ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[3] & 0x3f) << 8) | media_codec.media_codec_information[4]; 7075ce3497fSMatthias Ringwald 7085ce3497fSMatthias Ringwald event[pos++] = layer_bitmap; 7095ce3497fSMatthias Ringwald event[pos++] = crc; 7105ce3497fSMatthias Ringwald event[pos++] = channel_mode_bitmap; 7115ce3497fSMatthias Ringwald event[pos++] = mpf; 7125ce3497fSMatthias Ringwald event[pos++] = sampling_frequency_bitmap; 7135ce3497fSMatthias Ringwald event[pos++] = vbr; 7145ce3497fSMatthias Ringwald little_endian_store_16(event, pos, bit_rate_index_bitmap); // bit rate index 7155ce3497fSMatthias Ringwald pos += 2; 7165ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 7175ce3497fSMatthias Ringwald } 7185ce3497fSMatthias Ringwald 7195ce3497fSMatthias 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) { 7205ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 7215ce3497fSMatthias Ringwald uint8_t event[15]; 7225ce3497fSMatthias Ringwald int pos = 0; 7235ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 7245ce3497fSMatthias Ringwald event[pos++] = sizeof(event) - 2; 7255ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CAPABILITY; 7265ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 7275ce3497fSMatthias Ringwald pos += 2; 7285ce3497fSMatthias Ringwald event[pos++] = remote_seid; 7295ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 7305ce3497fSMatthias Ringwald 7311da18615SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 1; 7321da18615SMilanka Ringwald uint8_t drc = media_codec_information[0] & 0x01; 7335ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] << 4) | (media_codec_information[2] >> 4); 7341da18615SMilanka Ringwald uint8_t channels_bitmap = media_codec_information[2] & 0x0F; 7355ce3497fSMatthias Ringwald uint32_t bit_rate_bitmap = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 7365ce3497fSMatthias Ringwald uint8_t vbr = media_codec_information[3] >> 7; 7375ce3497fSMatthias Ringwald 7385ce3497fSMatthias Ringwald event[pos++] = object_type_bitmap; 7391da18615SMilanka Ringwald event[pos++] = drc; 7401da18615SMilanka Ringwald 7415ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency_bitmap); 7425ce3497fSMatthias Ringwald pos += 2; 7435ce3497fSMatthias Ringwald event[pos++] = channels_bitmap; 7445ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate_bitmap); 7455ce3497fSMatthias Ringwald pos += 3; 7465ce3497fSMatthias Ringwald event[pos++] = vbr; 7475ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 7485ce3497fSMatthias Ringwald } 7495ce3497fSMatthias Ringwald 7505ce3497fSMatthias 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) { 7515ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 7525ce3497fSMatthias Ringwald uint8_t event[16]; 7535ce3497fSMatthias Ringwald int pos = 0; 7545ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 75573048ce6SMatthias Ringwald pos++; // set later 7565ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY; 7575ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 7585ce3497fSMatthias Ringwald pos += 2; 7595ce3497fSMatthias Ringwald event[pos++] = remote_seid; 7605ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type; 7615ce3497fSMatthias Ringwald 7625ce3497fSMatthias Ringwald uint8_t version = media_codec_information[0] >> 5; 7635ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] >> 2) & 0x07; 764ab2445a0SMatthias Ringwald uint8_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03; 7655ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[1] >> 3) & 0x01; 7665ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3]; 7675ce3497fSMatthias Ringwald uint16_t maximum_sul = (media_codec_information[4] << 8) | media_codec_information[5]; 7685ce3497fSMatthias Ringwald 7695ce3497fSMatthias Ringwald event[pos++] = version; 7705ce3497fSMatthias Ringwald event[pos++] = channel_mode_bitmap; 7715ce3497fSMatthias Ringwald event[pos++] = sampling_frequency_bitmap; 7725ce3497fSMatthias Ringwald event[pos++] = vbr; 7735ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate_index_bitmap); 7745ce3497fSMatthias Ringwald pos += 3; 7755ce3497fSMatthias Ringwald little_endian_store_16(event, pos, maximum_sul); 77673048ce6SMatthias Ringwald pos += 2; 77773048ce6SMatthias Ringwald event[1] = pos - 2; 778c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 7798ef7100fSMilanka Ringwald } 7808ef7100fSMilanka Ringwald 78124d5fe84SMilanka 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) { 78224d5fe84SMilanka Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information; 78324d5fe84SMilanka Ringwald uint8_t event[18]; 78424d5fe84SMilanka Ringwald int pos = 0; 78524d5fe84SMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 78624d5fe84SMilanka Ringwald pos++; // set later 78724d5fe84SMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CAPABILITY; 78824d5fe84SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 78924d5fe84SMilanka Ringwald pos += 2; 79024d5fe84SMilanka Ringwald event[pos++] = remote_seid; 79124d5fe84SMilanka Ringwald event[pos++] = media_codec.media_type; 79224d5fe84SMilanka Ringwald 79324d5fe84SMilanka Ringwald uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) | 79424d5fe84SMilanka Ringwald (media_codec_information[1] << 12) | 79524d5fe84SMilanka Ringwald (media_codec_information[2] << 4) | 79624d5fe84SMilanka Ringwald (media_codec_information[3] >> 4); 79724d5fe84SMilanka Ringwald 79824d5fe84SMilanka Ringwald uint8_t channels_bitmap = (media_codec_information[3] >> 2) & 0x03; 79924d5fe84SMilanka Ringwald uint8_t vbr = (media_codec_information[4] >> 7) & 0x01; 80024d5fe84SMilanka Ringwald 80124d5fe84SMilanka Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[4]) & 0xEF) << 16 | (media_codec_information[5] << 8) | media_codec_information[6]; 80224d5fe84SMilanka Ringwald 80324d5fe84SMilanka Ringwald event[pos++] = media_codec_information[0] >> 6; 80424d5fe84SMilanka Ringwald little_endian_store_32(event, pos, sampling_frequency_bitmap); 80524d5fe84SMilanka Ringwald pos += 4; 80624d5fe84SMilanka Ringwald event[pos++] = channels_bitmap; 80724d5fe84SMilanka Ringwald event[pos++] = sampling_frequency_bitmap; 80824d5fe84SMilanka Ringwald event[pos++] = vbr; 80924d5fe84SMilanka Ringwald little_endian_store_24(event, pos, bit_rate_index_bitmap); 81024d5fe84SMilanka Ringwald pos += 3; 81124d5fe84SMilanka Ringwald event[1] = pos - 2; 81224d5fe84SMilanka Ringwald avdtp_emit_sink_and_source(event, pos); 81324d5fe84SMilanka Ringwald } 81424d5fe84SMilanka Ringwald 81524d5fe84SMilanka Ringwald 8161159d239SMatthias 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) { 817924216b2SMatthias Ringwald uint8_t event[AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH + 11]; 81867ae582dSMilanka Ringwald int pos = 0; 81967ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 82073048ce6SMatthias Ringwald pos++; // set later 8214b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY; 82267ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 82367ae582dSMilanka Ringwald pos += 2; 82467ae582dSMilanka Ringwald event[pos++] = remote_seid; 8254b7d40bbSMatthias Ringwald event[pos++] = media_codec.media_type; 8264b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, media_codec.media_codec_type); 8274b7d40bbSMatthias Ringwald pos += 2; 8284b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, media_codec.media_codec_information_len); 8294b7d40bbSMatthias Ringwald pos += 2; 830924216b2SMatthias Ringwald uint32_t media_codec_info_len = btstack_min(media_codec.media_codec_information_len, AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH); 8315403525eSMatthias Ringwald (void)memcpy(event + pos, media_codec.media_codec_information, media_codec_info_len); 8325403525eSMatthias Ringwald pos += media_codec_info_len; 83373048ce6SMatthias Ringwald event[1] = pos - 2; 834c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 83567ae582dSMilanka Ringwald } 83667ae582dSMilanka Ringwald 837c69f4ba5SMatthias Ringwald static void 8381159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 8391159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY, avdtp_cid, 840c69f4ba5SMatthias Ringwald remote_seid); 84167ae582dSMilanka Ringwald } 84267ae582dSMilanka Ringwald 8431159d239SMatthias Ringwald static void avdtp_signaling_emit_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 8441159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY, avdtp_cid, remote_seid); 84567ae582dSMilanka Ringwald } 84667ae582dSMilanka Ringwald 847c69f4ba5SMatthias Ringwald static void 8481159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) { 8491159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY, avdtp_cid, 850c69f4ba5SMatthias Ringwald remote_seid); 85167ae582dSMilanka Ringwald } 85267ae582dSMilanka Ringwald 8531159d239SMatthias Ringwald static void avdtp_signaling_emit_recovery_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_recovery_capabilities_t *recovery) { 8541159d239SMatthias Ringwald uint8_t event[9]; 85567ae582dSMilanka Ringwald int pos = 0; 85667ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 85767ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 85867ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY; 85967ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 86067ae582dSMilanka Ringwald pos += 2; 86167ae582dSMilanka Ringwald event[pos++] = remote_seid; 86267ae582dSMilanka Ringwald event[pos++] = recovery->recovery_type; 86367ae582dSMilanka Ringwald event[pos++] = recovery->maximum_recovery_window_size; 86467ae582dSMilanka Ringwald event[pos++] = recovery->maximum_number_media_packets; 865c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 86667ae582dSMilanka Ringwald } 86767ae582dSMilanka Ringwald 86873048ce6SMatthias Ringwald #define MAX_CONTENT_PROTECTION_VALUE_LEN 32 869c69f4ba5SMatthias Ringwald static void 8701159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_content_protection_t *content_protection) { 87173048ce6SMatthias Ringwald uint8_t event[10 + MAX_CONTENT_PROTECTION_VALUE_LEN]; 87267ae582dSMilanka Ringwald int pos = 0; 87367ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 87473048ce6SMatthias Ringwald pos++; // set later 87567ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY; 87667ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 87767ae582dSMilanka Ringwald pos += 2; 87867ae582dSMilanka Ringwald event[pos++] = remote_seid; 87967ae582dSMilanka Ringwald 88067ae582dSMilanka Ringwald little_endian_store_16(event, pos, content_protection->cp_type); 88167ae582dSMilanka Ringwald pos += 2; 88273048ce6SMatthias Ringwald 88373048ce6SMatthias Ringwald // drop cp protection value if longer than expected 88473048ce6SMatthias Ringwald if (content_protection->cp_type_value_len <= MAX_CONTENT_PROTECTION_VALUE_LEN){ 88567ae582dSMilanka Ringwald little_endian_store_16(event, pos, content_protection->cp_type_value_len); 88667ae582dSMilanka Ringwald pos += 2; 88773048ce6SMatthias Ringwald (void)memcpy(event + pos, content_protection->cp_type_value, content_protection->cp_type_value_len); 88873048ce6SMatthias Ringwald pos += content_protection->cp_type_value_len; 88973048ce6SMatthias Ringwald } else { 89073048ce6SMatthias Ringwald little_endian_store_16(event, pos, 0); 89173048ce6SMatthias Ringwald pos += 2; 89267ae582dSMilanka Ringwald } 89373048ce6SMatthias Ringwald event[1] = pos - 2; 894c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 89567ae582dSMilanka Ringwald } 89667ae582dSMilanka Ringwald 89767ae582dSMilanka Ringwald 898c69f4ba5SMatthias Ringwald static void 8991159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_header_compression_capabilities_t *header_compression) { 9001159d239SMatthias Ringwald uint8_t event[9]; 90167ae582dSMilanka Ringwald int pos = 0; 90267ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 90367ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 90467ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY; 90567ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 90667ae582dSMilanka Ringwald pos += 2; 90767ae582dSMilanka Ringwald event[pos++] = remote_seid; 90867ae582dSMilanka Ringwald event[pos++] = header_compression->back_ch; 90967ae582dSMilanka Ringwald event[pos++] = header_compression->media; 91067ae582dSMilanka Ringwald event[pos++] = header_compression->recovery; 911c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 91267ae582dSMilanka Ringwald } 91367ae582dSMilanka Ringwald 914c69f4ba5SMatthias Ringwald static void 9151159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_multiplexing_mode_capabilities_t *multiplexing_mode) { 9161159d239SMatthias Ringwald uint8_t event[14]; 91767ae582dSMilanka Ringwald int pos = 0; 91867ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 91967ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2; 92067ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY; 92167ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 92267ae582dSMilanka Ringwald pos += 2; 92367ae582dSMilanka Ringwald event[pos++] = remote_seid; 92467ae582dSMilanka Ringwald 92567ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->fragmentation; 92667ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->transport_identifiers_num; 92767ae582dSMilanka Ringwald 92867ae582dSMilanka Ringwald int i; 92967ae582dSMilanka Ringwald for (i = 0; i < 3; i++){ 93067ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->transport_session_identifiers[i]; 93167ae582dSMilanka Ringwald } 93267ae582dSMilanka Ringwald for (i = 0; i < 3; i++){ 93367ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->tcid[i]; 93467ae582dSMilanka Ringwald } 935c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 93667ae582dSMilanka Ringwald } 93767ae582dSMilanka Ringwald 9381159d239SMatthias Ringwald static void avdtp_signaling_emit_capability_done(uint16_t avdtp_cid, uint8_t remote_seid) { 9391159d239SMatthias Ringwald uint8_t event[6]; 940f08f4934SMatthias Ringwald int pos = 0; 941f08f4934SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 942f08f4934SMatthias Ringwald event[pos++] = sizeof(event) - 2; 943f08f4934SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE; 944f08f4934SMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 945f08f4934SMatthias Ringwald pos += 2; 946f08f4934SMatthias Ringwald event[pos++] = remote_seid; 947c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos); 948f08f4934SMatthias Ringwald } 949f08f4934SMatthias Ringwald 9500928ecceSMatthias Ringwald static void avdtp_signaling_emit_media_codec_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec){ 9510928ecceSMatthias Ringwald switch (media_codec.media_codec_type){ 9520928ecceSMatthias Ringwald case AVDTP_CODEC_SBC: 9530928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_sbc_capability(avdtp_cid, remote_seid, media_codec); 9540928ecceSMatthias Ringwald break; 9550928ecceSMatthias Ringwald case AVDTP_CODEC_MPEG_1_2_AUDIO: 9560928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_mpeg_audio_capability(avdtp_cid, remote_seid, media_codec); 9570928ecceSMatthias Ringwald break; 9580928ecceSMatthias Ringwald case AVDTP_CODEC_MPEG_2_4_AAC: 9590928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_mpeg_aac_capability(avdtp_cid, remote_seid, media_codec); 9600928ecceSMatthias Ringwald break; 9610928ecceSMatthias Ringwald case AVDTP_CODEC_ATRAC_FAMILY: 9620928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_atrac_capability(avdtp_cid, remote_seid, media_codec); 9630928ecceSMatthias Ringwald break; 96424d5fe84SMilanka Ringwald case AVDTP_CODEC_MPEG_D_USAC: 96524d5fe84SMilanka Ringwald avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(avdtp_cid, remote_seid, media_codec); 96624d5fe84SMilanka Ringwald break; 9670928ecceSMatthias Ringwald default: 9680928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_other_capability(avdtp_cid, remote_seid, media_codec); 9690928ecceSMatthias Ringwald break; 9700928ecceSMatthias Ringwald } 9710928ecceSMatthias Ringwald } 9720928ecceSMatthias Ringwald 9734b7d40bbSMatthias Ringwald // emit events for all capabilities incl. final done event 9741159d239SMatthias Ringwald void avdtp_signaling_emit_capabilities(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_capabilities_t *capabilities, 975c69f4ba5SMatthias Ringwald uint16_t registered_service_categories) { 97667ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MEDIA_CODEC)){ 9770928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_capability(avdtp_cid, remote_seid, capabilities->media_codec); 97867ae582dSMilanka Ringwald } 97967ae582dSMilanka Ringwald 98067ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MEDIA_TRANSPORT)){ 9811159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(avdtp_cid, remote_seid); 98267ae582dSMilanka Ringwald } 98367ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_REPORTING)){ 9841159d239SMatthias Ringwald avdtp_signaling_emit_reporting_capability(avdtp_cid, remote_seid); 98567ae582dSMilanka Ringwald } 98667ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_RECOVERY)){ 9871159d239SMatthias Ringwald avdtp_signaling_emit_recovery_capability(avdtp_cid, remote_seid, &capabilities->recovery); 98867ae582dSMilanka Ringwald } 98967ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_CONTENT_PROTECTION)){ 9901159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(avdtp_cid, remote_seid, 991c69f4ba5SMatthias Ringwald &capabilities->content_protection); 99267ae582dSMilanka Ringwald } 99367ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_HEADER_COMPRESSION)){ 9941159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(avdtp_cid, remote_seid, 995c69f4ba5SMatthias Ringwald &capabilities->header_compression); 99667ae582dSMilanka Ringwald } 99767ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MULTIPLEXING)){ 9981159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(avdtp_cid, remote_seid, 999c69f4ba5SMatthias Ringwald &capabilities->multiplexing_mode); 100067ae582dSMilanka Ringwald } 100167ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_DELAY_REPORTING)){ 10021159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(avdtp_cid, remote_seid); 100367ae582dSMilanka Ringwald } 10041159d239SMatthias Ringwald avdtp_signaling_emit_capability_done(avdtp_cid, remote_seid); 100567ae582dSMilanka Ringwald } 100667ae582dSMilanka Ringwald 1007186e1970SMatthias Ringwald static uint16_t 1008186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_sbc_config_event(uint8_t *event, uint16_t size, 1009a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1010186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 1011186e1970SMatthias Ringwald const uint8_t *media_codec_information) { 1012186e1970SMatthias Ringwald 1013924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN); 1014186e1970SMatthias Ringwald 10154b7d40bbSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 10164b7d40bbSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 10174b7d40bbSMatthias Ringwald 10184b7d40bbSMatthias Ringwald int pos = 0; 10194b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1020924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN - 2; 10214b7d40bbSMatthias Ringwald 10224b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION; 10234b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 10244b7d40bbSMatthias Ringwald pos += 2; 10254b7d40bbSMatthias Ringwald event[pos++] = local_seid; 10264b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 10274b7d40bbSMatthias Ringwald event[pos++] = reconfigure; 1028186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_SBC; 10294b7d40bbSMatthias Ringwald 10304b7d40bbSMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[0] >> 4; 10314b7d40bbSMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x0F; 10324b7d40bbSMatthias Ringwald uint8_t block_length_bitmap = media_codec_information[1] >> 4; 10334b7d40bbSMatthias Ringwald uint8_t subbands_bitmap = (media_codec_information[1] & 0x0F) >> 2; 10344b7d40bbSMatthias Ringwald 10354b7d40bbSMatthias Ringwald uint8_t num_channels = 0; 1036a3868652SMatthias Ringwald avdtp_channel_mode_t channel_mode; 1037a3868652SMatthias Ringwald 1038a3868652SMatthias Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){ 1039a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 10404b7d40bbSMatthias Ringwald num_channels = 2; 1041a3868652SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){ 1042a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_STEREO; 1043a3868652SMatthias Ringwald num_channels = 2; 1044a3868652SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){ 1045a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 1046a3868652SMatthias Ringwald num_channels = 2; 1047a3868652SMatthias Ringwald } else { 1048a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 10494b7d40bbSMatthias Ringwald num_channels = 1; 10504b7d40bbSMatthias Ringwald } 10514b7d40bbSMatthias Ringwald 10524b7d40bbSMatthias Ringwald uint16_t sampling_frequency = 0; 10534b7d40bbSMatthias Ringwald if (sampling_frequency_bitmap & AVDTP_SBC_48000) { 10544b7d40bbSMatthias Ringwald sampling_frequency = 48000; 10554b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_44100) { 10564b7d40bbSMatthias Ringwald sampling_frequency = 44100; 10574b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_32000) { 10584b7d40bbSMatthias Ringwald sampling_frequency = 32000; 10594b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_16000) { 10604b7d40bbSMatthias Ringwald sampling_frequency = 16000; 10614b7d40bbSMatthias Ringwald } 10624b7d40bbSMatthias Ringwald 10634b7d40bbSMatthias Ringwald uint8_t subbands = 0; 10644b7d40bbSMatthias Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){ 10654b7d40bbSMatthias Ringwald subbands = 8; 10664b7d40bbSMatthias Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){ 10674b7d40bbSMatthias Ringwald subbands = 4; 10684b7d40bbSMatthias Ringwald } 10694b7d40bbSMatthias Ringwald 10704b7d40bbSMatthias Ringwald uint8_t block_length = 0; 10714b7d40bbSMatthias Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){ 10724b7d40bbSMatthias Ringwald block_length = 16; 10734b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){ 10744b7d40bbSMatthias Ringwald block_length = 12; 10754b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){ 10764b7d40bbSMatthias Ringwald block_length = 8; 10774b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){ 10784b7d40bbSMatthias Ringwald block_length = 4; 10794b7d40bbSMatthias Ringwald } 10804b7d40bbSMatthias Ringwald 10814b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 10824b7d40bbSMatthias Ringwald pos += 2; 10834b7d40bbSMatthias Ringwald 1084a3868652SMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 10854b7d40bbSMatthias Ringwald event[pos++] = num_channels; 10864b7d40bbSMatthias Ringwald event[pos++] = block_length; 10874b7d40bbSMatthias Ringwald event[pos++] = subbands; 10884b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03; 10894b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[2]; 10904b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[3]; 1091186e1970SMatthias Ringwald 1092924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN); 1093186e1970SMatthias Ringwald 1094186e1970SMatthias Ringwald return pos; 10955ce3497fSMatthias Ringwald } 10965ce3497fSMatthias Ringwald 1097186e1970SMatthias Ringwald static uint16_t 1098186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpeg_audio_config_event(uint8_t *event, uint16_t size, 1099a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1100186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 11015ce3497fSMatthias Ringwald const uint8_t *media_codec_information) { 11025ce3497fSMatthias Ringwald 1103924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN); 1104186e1970SMatthias Ringwald 11055ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 11065ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 11075ce3497fSMatthias Ringwald 1108186e1970SMatthias Ringwald uint16_t pos = 0; 11095ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1110924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN - 2; 11115ce3497fSMatthias Ringwald 11125ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION; 11135ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 11145ce3497fSMatthias Ringwald pos += 2; 11155ce3497fSMatthias Ringwald event[pos++] = local_seid; 11165ce3497fSMatthias Ringwald event[pos++] = remote_seid; 11175ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1118186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_MPEG_1_2_AUDIO; 11195ce3497fSMatthias Ringwald 11205ce3497fSMatthias Ringwald uint8_t layer_bitmap = media_codec_information[0] >> 5; 11215ce3497fSMatthias Ringwald uint8_t crc = (media_codec_information[0] >> 4) & 0x01; 11225ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] & 0x07); 11235ce3497fSMatthias Ringwald uint8_t mpf = (media_codec_information[1] >> 6) & 0x01; 11245ce3497fSMatthias Ringwald uint8_t sampling_frequency_bitmap = (media_codec_information[1] & 0x3F); 11255ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[2] >> 7) & 0x01; 11265ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[2] & 0x3f) << 8) | media_codec_information[3]; 11275ce3497fSMatthias Ringwald 11285ce3497fSMatthias Ringwald uint8_t layer = 0; 11295ce3497fSMatthias Ringwald if (layer_bitmap & 0x04){ 11305ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_1; 11315ce3497fSMatthias Ringwald } else if (layer_bitmap & 0x02){ 11325ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_2; 11335ce3497fSMatthias Ringwald } else if (layer_bitmap & 0x01){ 11345ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_3; 11355ce3497fSMatthias Ringwald } 11365ce3497fSMatthias Ringwald 11375ce3497fSMatthias Ringwald uint8_t num_channels = 0; 11385ce3497fSMatthias Ringwald avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 11395ce3497fSMatthias Ringwald if (channel_mode_bitmap & 0x08){ 11405ce3497fSMatthias Ringwald num_channels = 1; 11415ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 11425ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x04){ 11435ce3497fSMatthias Ringwald num_channels = 2; 11445ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 11455ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 11465ce3497fSMatthias Ringwald num_channels = 2; 11475ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_STEREO; 11485ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 11495ce3497fSMatthias Ringwald num_channels = 2; 11505ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 11515ce3497fSMatthias Ringwald } 11525ce3497fSMatthias Ringwald 11535ce3497fSMatthias Ringwald uint16_t sampling_frequency = 0; 11545ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & 0x01) { 11555ce3497fSMatthias Ringwald sampling_frequency = 48000; 11565ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x02) { 11575ce3497fSMatthias Ringwald sampling_frequency = 44100; 11585ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x04) { 11595ce3497fSMatthias Ringwald sampling_frequency = 32000; 11605ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x08) { 11615ce3497fSMatthias Ringwald sampling_frequency = 24000; 11625ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x10) { 11635ce3497fSMatthias Ringwald sampling_frequency = 22050; 11645ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x20) { 11655ce3497fSMatthias Ringwald sampling_frequency = 16000; 11665ce3497fSMatthias Ringwald } 11675ce3497fSMatthias Ringwald 11685ce3497fSMatthias Ringwald uint8_t bitrate_index = 0; 11695ce3497fSMatthias Ringwald uint8_t i; 11705ce3497fSMatthias Ringwald for (i=0;i<14;i++){ 11715ce3497fSMatthias Ringwald if (bit_rate_index_bitmap & (1U << i)) { 11725ce3497fSMatthias Ringwald bitrate_index = i; 11735ce3497fSMatthias Ringwald } 11745ce3497fSMatthias Ringwald } 11755ce3497fSMatthias Ringwald 11765ce3497fSMatthias Ringwald event[pos++] = (uint8_t) layer; 11775ce3497fSMatthias Ringwald event[pos++] = crc; 11785ce3497fSMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 11795ce3497fSMatthias Ringwald event[pos++] = num_channels; 11805ce3497fSMatthias Ringwald event[pos++] = mpf; 11815ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 11825ce3497fSMatthias Ringwald pos += 2; 11835ce3497fSMatthias Ringwald event[pos++] = vbr; 11845ce3497fSMatthias Ringwald event[pos++] = bitrate_index; 11855ce3497fSMatthias Ringwald 1186924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN); 1187186e1970SMatthias Ringwald 1188186e1970SMatthias Ringwald return pos; 11895ce3497fSMatthias Ringwald } 11905ce3497fSMatthias Ringwald 1191186e1970SMatthias Ringwald static uint16_t 1192186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpec_aac_config_event(uint8_t *event, uint16_t size, 1193a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1194186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 11955ce3497fSMatthias Ringwald const uint8_t *media_codec_information) { 11965ce3497fSMatthias Ringwald 119724d5fe84SMilanka Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN); 1198186e1970SMatthias Ringwald 11995ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 12005ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 12015ce3497fSMatthias Ringwald 1202186e1970SMatthias Ringwald uint16_t pos = 0; 12035ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1204924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN - 2; 12055ce3497fSMatthias Ringwald 12065ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION; 12075ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 12085ce3497fSMatthias Ringwald pos += 2; 12095ce3497fSMatthias Ringwald event[pos++] = local_seid; 12105ce3497fSMatthias Ringwald event[pos++] = remote_seid; 12115ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1212186e1970SMatthias Ringwald event[pos++] =AVDTP_CODEC_MPEG_2_4_AAC; 12135ce3497fSMatthias Ringwald 12141da18615SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 1; 12151da18615SMilanka Ringwald uint8_t drc = media_codec_information[0] & 0x01; 12165ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] << 4) | (media_codec_information[2] >> 4); 12171da18615SMilanka Ringwald uint8_t channels_bitmap = media_codec_information[2] & 0x0F; 12185ce3497fSMatthias Ringwald uint8_t vbr = media_codec_information[3] >> 7; 12195ce3497fSMatthias Ringwald uint32_t bit_rate = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 12205ce3497fSMatthias Ringwald 12215ce3497fSMatthias Ringwald uint8_t object_type = 0; 12221da18615SMilanka Ringwald if (object_type_bitmap & 0x01){ 12231da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AAC_ELDv2; 12241da18615SMilanka Ringwald } else if (object_type_bitmap & 0x02){ 12251da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AACv2; 12261da18615SMilanka Ringwald } else if (object_type_bitmap & 0x04){ 12271da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AAC; 12281da18615SMilanka Ringwald } else if (object_type_bitmap & 0x08){ 12295ce3497fSMatthias Ringwald object_type = AVDTP_AAC_MPEG4_SCALABLE; 12301da18615SMilanka Ringwald } else if (object_type_bitmap & 0x10){ 12311da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_LTP; 12321da18615SMilanka Ringwald } else if (object_type_bitmap & 0x20){ 12331da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_LC; 12341da18615SMilanka Ringwald } else if (object_type_bitmap & 0x40){ 12351da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG2_LC; 12365ce3497fSMatthias Ringwald } 12375ce3497fSMatthias Ringwald 1238588a837aSMilanka Ringwald uint32_t sampling_frequency = avdtp_config_get_sampling_frequency_from_table(sampling_frequency_bitmap, aac_sampling_frequency_table, aac_sampling_frequency_table_size); 12395ce3497fSMatthias Ringwald 12405ce3497fSMatthias Ringwald uint8_t num_channels = 0; 12411da18615SMilanka Ringwald if (channels_bitmap & 0x08){ 12425ce3497fSMatthias Ringwald num_channels = 1; 12431da18615SMilanka Ringwald } else if (channels_bitmap & 0x04){ 12445ce3497fSMatthias Ringwald num_channels = 2; 12451da18615SMilanka Ringwald } else if (channels_bitmap & 0x02){ 12461da18615SMilanka Ringwald num_channels = 6; 12471da18615SMilanka Ringwald } else if (channels_bitmap & 0x01){ 12481da18615SMilanka Ringwald num_channels = 8; 12495ce3497fSMatthias Ringwald } 12505ce3497fSMatthias Ringwald 12515ce3497fSMatthias Ringwald event[pos++] = object_type; 12521da18615SMilanka Ringwald event[pos++] = drc; 12535ce3497fSMatthias Ringwald little_endian_store_24(event, pos, sampling_frequency); 12545ce3497fSMatthias Ringwald pos += 3; 12555ce3497fSMatthias Ringwald event[pos++] = num_channels; 12565ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate); 12575ce3497fSMatthias Ringwald pos += 3; 12585ce3497fSMatthias Ringwald event[pos++] = vbr; 12595ce3497fSMatthias Ringwald 1260924216b2SMatthias Ringwald btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN == pos); 1261186e1970SMatthias Ringwald 1262186e1970SMatthias Ringwald return pos; 12635ce3497fSMatthias Ringwald } 12645ce3497fSMatthias Ringwald 126524d5fe84SMilanka Ringwald static uint16_t 126624d5fe84SMilanka Ringwald avdtp_signaling_setup_media_codec_mpegd_config_event(uint8_t *event, uint16_t size, 126724d5fe84SMilanka Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 126824d5fe84SMilanka Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 126924d5fe84SMilanka Ringwald const uint8_t *media_codec_information) { 127024d5fe84SMilanka Ringwald 127124d5fe84SMilanka Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN); 127224d5fe84SMilanka Ringwald 127324d5fe84SMilanka Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 127424d5fe84SMilanka Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 127524d5fe84SMilanka Ringwald 127624d5fe84SMilanka Ringwald uint16_t pos = 0; 127724d5fe84SMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 127824d5fe84SMilanka Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN - 2; 127924d5fe84SMilanka Ringwald 128024d5fe84SMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CONFIGURATION; 128124d5fe84SMilanka Ringwald 128224d5fe84SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid); 128324d5fe84SMilanka Ringwald pos += 2; 128424d5fe84SMilanka Ringwald event[pos++] = local_seid; 128524d5fe84SMilanka Ringwald event[pos++] = remote_seid; 128624d5fe84SMilanka Ringwald event[pos++] = reconfigure; 128724d5fe84SMilanka Ringwald event[pos++] = AVDTP_CODEC_MPEG_D_USAC; 128824d5fe84SMilanka Ringwald 128924d5fe84SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 6; 129024d5fe84SMilanka Ringwald uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) | 129124d5fe84SMilanka Ringwald (media_codec_information[1] << 12) | 129224d5fe84SMilanka Ringwald (media_codec_information[2] << 4) | 129324d5fe84SMilanka Ringwald (media_codec_information[3] >> 4); 129424d5fe84SMilanka Ringwald 129524d5fe84SMilanka Ringwald uint8_t channels_bitmap = (media_codec_information[3] >> 2) & 0x03; 129624d5fe84SMilanka Ringwald uint8_t vbr = (media_codec_information[4] >> 7) & 0x01; 129724d5fe84SMilanka Ringwald 129824d5fe84SMilanka Ringwald uint32_t bit_rate = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5]; 129924d5fe84SMilanka Ringwald 130024d5fe84SMilanka Ringwald uint8_t object_type = 0; 130124d5fe84SMilanka Ringwald if (object_type_bitmap & 0x10){ 130224d5fe84SMilanka Ringwald object_type = AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC; 130324d5fe84SMilanka Ringwald } else { 130424d5fe84SMilanka Ringwald object_type = AVDTP_USAC_OBJECT_TYPE_RFU; 130524d5fe84SMilanka Ringwald } 130624d5fe84SMilanka Ringwald 1307588a837aSMilanka Ringwald uint32_t sampling_frequency = avdtp_config_get_sampling_frequency_from_table(sampling_frequency_bitmap, usac_sampling_frequency_table, usac_sampling_frequency_table_size ); 130824d5fe84SMilanka Ringwald 130924d5fe84SMilanka Ringwald uint8_t num_channels = 0; 131024d5fe84SMilanka Ringwald if (channels_bitmap & 0x02){ 131124d5fe84SMilanka Ringwald num_channels = 1; 131224d5fe84SMilanka Ringwald } else if (channels_bitmap & 0x01){ 131324d5fe84SMilanka Ringwald num_channels = 2; 131424d5fe84SMilanka Ringwald } 131524d5fe84SMilanka Ringwald 131624d5fe84SMilanka Ringwald event[pos++] = object_type; 131724d5fe84SMilanka Ringwald little_endian_store_24(event, pos, sampling_frequency); 131824d5fe84SMilanka Ringwald pos += 3; 131924d5fe84SMilanka Ringwald event[pos++] = num_channels; 132024d5fe84SMilanka Ringwald event[pos++] = vbr; 132124d5fe84SMilanka Ringwald little_endian_store_24(event, pos, bit_rate); 132224d5fe84SMilanka Ringwald pos += 3; 132324d5fe84SMilanka Ringwald 132424d5fe84SMilanka Ringwald btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN == pos); 132524d5fe84SMilanka Ringwald 132624d5fe84SMilanka Ringwald return pos; 132724d5fe84SMilanka Ringwald } 132824d5fe84SMilanka Ringwald 1329186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_atrac_config_event(uint8_t *event, uint16_t size, 1330a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1331186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 1332186e1970SMatthias Ringwald const uint8_t *media_codec_information) { 1333924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN); 1334186e1970SMatthias Ringwald 13355ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 13365ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 13375ce3497fSMatthias Ringwald 1338186e1970SMatthias Ringwald uint16_t pos = 0; 13395ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 1340924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN - 2; 13415ce3497fSMatthias Ringwald 13425ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION; 13435ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 13445ce3497fSMatthias Ringwald pos += 2; 13455ce3497fSMatthias Ringwald event[pos++] = local_seid; 13465ce3497fSMatthias Ringwald event[pos++] = remote_seid; 13475ce3497fSMatthias Ringwald event[pos++] = reconfigure; 1348186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_ATRAC_FAMILY; 13495ce3497fSMatthias Ringwald 1350b5bbcbf4SMatthias Ringwald avdtp_atrac_version_t version = (avdtp_atrac_version_t) (media_codec_information[0] >> 5); 13515ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] >> 2) & 0x07; 13525ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03; 13535ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[1] >> 3) & 0x01; 13545ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3]; 13555ce3497fSMatthias Ringwald uint16_t maximum_sul = (media_codec_information[4] << 8) | media_codec_information[5]; 13565ce3497fSMatthias Ringwald 13575ce3497fSMatthias Ringwald uint8_t num_channels = 0; 13585ce3497fSMatthias Ringwald avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 13595ce3497fSMatthias Ringwald if (channel_mode_bitmap & 0x04){ 13605ce3497fSMatthias Ringwald num_channels = 1; 13615ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO; 13625ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){ 13635ce3497fSMatthias Ringwald num_channels = 2; 13645ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL; 13655ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x01){ 13665ce3497fSMatthias Ringwald num_channels = 2; 13675ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO; 13685ce3497fSMatthias Ringwald } 13695ce3497fSMatthias Ringwald 13705ce3497fSMatthias Ringwald uint16_t sampling_frequency = 0; 13715ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & 0x02){ 13725ce3497fSMatthias Ringwald sampling_frequency = 44100; 13735ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x01){ 13745ce3497fSMatthias Ringwald sampling_frequency = 48000; 13755ce3497fSMatthias Ringwald } 13765ce3497fSMatthias Ringwald 13775ce3497fSMatthias Ringwald // bit 0 = index 0x18, bit 19 = index 0 13785ce3497fSMatthias Ringwald uint8_t bit_rate_index = 0; 13795ce3497fSMatthias Ringwald uint8_t i; 13805ce3497fSMatthias Ringwald for (i=0;i <= 19;i++){ 13815ce3497fSMatthias Ringwald if (bit_rate_index_bitmap & (1U << i)) { 13825ce3497fSMatthias Ringwald bit_rate_index = 18 - i; 13835ce3497fSMatthias Ringwald } 13845ce3497fSMatthias Ringwald } 13855ce3497fSMatthias Ringwald 13865ce3497fSMatthias Ringwald event[pos++] = (uint8_t) version; 13875ce3497fSMatthias Ringwald event[pos++] = (uint8_t) channel_mode; 13885ce3497fSMatthias Ringwald event[pos++] = num_channels; 13895ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency); 13905ce3497fSMatthias Ringwald pos += 2; 13915ce3497fSMatthias Ringwald event[pos++] = vbr; 13925ce3497fSMatthias Ringwald event[pos++] = bit_rate_index; 13935ce3497fSMatthias Ringwald little_endian_store_16(event, pos, maximum_sul); 13945ce3497fSMatthias Ringwald pos += 2; 13955ce3497fSMatthias Ringwald 1396924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN); 1397186e1970SMatthias Ringwald return pos; 13984b7d40bbSMatthias Ringwald } 13994b7d40bbSMatthias Ringwald 1400186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_other_config_event(uint8_t *event, uint16_t size, 1401a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint, 1402186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 1403186e1970SMatthias Ringwald const adtvp_media_codec_capabilities_t *media_codec) { 1404924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN); 1405186e1970SMatthias Ringwald 14066c069ec9SMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint); 14076c069ec9SMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint); 14086c069ec9SMatthias Ringwald 1409186e1970SMatthias Ringwald uint16_t pos = 0; 14104b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 141173048ce6SMatthias Ringwald pos++; // set later 14124b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION; 14134b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 14144b7d40bbSMatthias Ringwald pos += 2; 14154b7d40bbSMatthias Ringwald event[pos++] = local_seid; 14164b7d40bbSMatthias Ringwald event[pos++] = remote_seid; 14174b7d40bbSMatthias Ringwald event[pos++] = reconfigure; 1418e8a431c1SMatthias Ringwald event[pos++] = media_codec->media_type; 1419e8a431c1SMatthias Ringwald little_endian_store_16(event, pos, media_codec->media_codec_type); 14204b7d40bbSMatthias Ringwald pos += 2; 1421e8a431c1SMatthias Ringwald little_endian_store_16(event, pos, media_codec->media_codec_information_len); 14224b7d40bbSMatthias Ringwald pos += 2; 1423186e1970SMatthias Ringwald 1424186e1970SMatthias Ringwald btstack_assert(pos == 13); 1425186e1970SMatthias Ringwald 1426924216b2SMatthias Ringwald uint16_t media_codec_len = btstack_min(AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH, media_codec->media_codec_information_len); 1427e8a431c1SMatthias Ringwald (void)memcpy(event + pos, media_codec->media_codec_information, media_codec_len); 142873048ce6SMatthias Ringwald pos += media_codec_len; 142973048ce6SMatthias Ringwald event[1] = pos - 2; 1430186e1970SMatthias Ringwald return pos; 14314b7d40bbSMatthias Ringwald } 14324b7d40bbSMatthias Ringwald 14334b7d40bbSMatthias Ringwald void avdtp_signaling_emit_delay(uint16_t avdtp_cid, uint8_t local_seid, uint16_t delay) { 14344b7d40bbSMatthias Ringwald uint8_t event[8]; 14354b7d40bbSMatthias Ringwald int pos = 0; 14364b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14374b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14384b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT; 14394b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 14404b7d40bbSMatthias Ringwald pos += 2; 14414b7d40bbSMatthias Ringwald event[pos++] = local_seid; 14424b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, delay); 14434b7d40bbSMatthias Ringwald pos += 2; 14446e64e62bSMatthias Ringwald avdtp_emit_source(event, pos); 14454b7d40bbSMatthias Ringwald } 14464b7d40bbSMatthias Ringwald 1447a905535cSMatthias Ringwald uint16_t avdtp_setup_media_codec_config_event(uint8_t *event, uint16_t size, const avdtp_stream_endpoint_t *stream_endpoint, 1448924216b2SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure, 14492965b0e6SMatthias Ringwald const adtvp_media_codec_capabilities_t * media_codec) { 14502965b0e6SMatthias Ringwald switch (media_codec->media_codec_type){ 1451924216b2SMatthias Ringwald case AVDTP_CODEC_SBC: 1452924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_sbc_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14532965b0e6SMatthias Ringwald media_codec->media_codec_information); 1454924216b2SMatthias Ringwald case AVDTP_CODEC_MPEG_1_2_AUDIO: 1455924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_mpeg_audio_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14562965b0e6SMatthias Ringwald media_codec->media_codec_information); 1457924216b2SMatthias Ringwald case AVDTP_CODEC_MPEG_2_4_AAC: 1458924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_mpec_aac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14592965b0e6SMatthias Ringwald media_codec->media_codec_information); 1460924216b2SMatthias Ringwald case AVDTP_CODEC_ATRAC_FAMILY: 1461924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_atrac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14622965b0e6SMatthias Ringwald media_codec->media_codec_information); 146324d5fe84SMilanka Ringwald case AVDTP_CODEC_MPEG_D_USAC: 146424d5fe84SMilanka Ringwald return avdtp_signaling_setup_media_codec_mpegd_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 146524d5fe84SMilanka Ringwald media_codec->media_codec_information); 1466924216b2SMatthias Ringwald default: 1467924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_other_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure, 14682965b0e6SMatthias Ringwald media_codec); 1469924216b2SMatthias Ringwald } 1470924216b2SMatthias Ringwald } 1471924216b2SMatthias Ringwald 14726c5b303cSMatthias Ringwald void avdtp_signaling_emit_configuration(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t reconfigure, 14734b7d40bbSMatthias Ringwald avdtp_capabilities_t *configuration, uint16_t configured_service_categories) { 14744b7d40bbSMatthias Ringwald 14754b7d40bbSMatthias Ringwald if (get_bit16(configured_service_categories, AVDTP_MEDIA_CODEC)){ 1476186e1970SMatthias Ringwald uint16_t pos = 0; 1477186e1970SMatthias Ringwald // assume MEDIA_CONFIG_OTHER_EVENT_LEN is larger than all other events 1478924216b2SMatthias Ringwald uint8_t event[AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN]; 1479924216b2SMatthias Ringwald pos = avdtp_setup_media_codec_config_event(event, sizeof(event), stream_endpoint, avdtp_cid, reconfigure, 14802965b0e6SMatthias Ringwald &configuration->media_codec); 1481186e1970SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 1482186e1970SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 14834b7d40bbSMatthias Ringwald } 14844b7d40bbSMatthias Ringwald } 14854b7d40bbSMatthias Ringwald 14864b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_established(avdtp_stream_endpoint_t *stream_endpoint, uint8_t status) { 14874b7d40bbSMatthias Ringwald uint8_t event[14]; 14884b7d40bbSMatthias Ringwald int pos = 0; 14894b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 14904b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 14914b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED; 14924b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 14934b7d40bbSMatthias Ringwald pos += 2; 14944b7d40bbSMatthias Ringwald reverse_bd_addr(stream_endpoint->connection->remote_addr, &event[pos]); 14954b7d40bbSMatthias Ringwald pos += 6; 14964b7d40bbSMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint); 14974b7d40bbSMatthias Ringwald event[pos++] = avdtp_remote_seid(stream_endpoint); 14984b7d40bbSMatthias Ringwald event[pos++] = status; 14994b7d40bbSMatthias Ringwald 15004b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 15016e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 15024b7d40bbSMatthias Ringwald } 15034b7d40bbSMatthias Ringwald 15044b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_released(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t local_seid) { 15054b7d40bbSMatthias Ringwald uint8_t event[6]; 15064b7d40bbSMatthias Ringwald int pos = 0; 15074b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 15084b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 15094b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED; 15104b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid); 15114b7d40bbSMatthias Ringwald pos += 2; 15124b7d40bbSMatthias Ringwald event[pos++] = local_seid; 15134b7d40bbSMatthias Ringwald 15144b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 15156e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 15164b7d40bbSMatthias Ringwald } 15174b7d40bbSMatthias Ringwald 15184b7d40bbSMatthias Ringwald void avdtp_streaming_emit_can_send_media_packet_now(avdtp_stream_endpoint_t *stream_endpoint, uint16_t sequence_number) { 15194b7d40bbSMatthias Ringwald uint8_t event[8]; 15204b7d40bbSMatthias Ringwald int pos = 0; 15214b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META; 15224b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2; 15234b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW; 15244b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid); 15254b7d40bbSMatthias Ringwald pos += 2; 15264b7d40bbSMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint); 15274b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, sequence_number); 15284b7d40bbSMatthias Ringwald pos += 2; 15296e64e62bSMatthias Ringwald event[1] = pos - 2; 15304b7d40bbSMatthias Ringwald 15314b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint); 15326e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos); 15334b7d40bbSMatthias Ringwald } 15344b7d40bbSMatthias Ringwald 1535d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_acceptor(avdtp_connection_t *connection) { 153623edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1537d80ccd43SMatthias Ringwald connection->wait_to_send_acceptor = true; 1538d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(connection->l2cap_signaling_cid); 15399974aee0SMilanka Ringwald return ERROR_CODE_SUCCESS; 15408ef7100fSMilanka Ringwald } 15419974aee0SMilanka Ringwald 1542d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_initiator(avdtp_connection_t *connection) { 154323edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; 1544d80ccd43SMatthias Ringwald connection->wait_to_send_initiator = true; 1545d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(connection->l2cap_signaling_cid); 15469974aee0SMilanka Ringwald return ERROR_CODE_SUCCESS; 15478ef7100fSMilanka Ringwald } 15489974aee0SMilanka Ringwald 1549a905535cSMatthias Ringwald uint8_t avdtp_local_seid(const avdtp_stream_endpoint_t * stream_endpoint){ 15504ccacc40SMilanka Ringwald if (!stream_endpoint) return 0; 15514ccacc40SMilanka Ringwald return stream_endpoint->sep.seid; 15524ccacc40SMilanka Ringwald 15534ccacc40SMilanka Ringwald } 15544ccacc40SMilanka Ringwald 1555a905535cSMatthias Ringwald uint8_t avdtp_remote_seid(const avdtp_stream_endpoint_t * stream_endpoint){ 1556485c0a4cSMilanka Ringwald if (!stream_endpoint) return AVDTP_INVALID_SEP_SEID; 1557485c0a4cSMilanka Ringwald return stream_endpoint->remote_sep.seid; 15584ccacc40SMilanka Ringwald } 1559ef5ad9d6SMilanka Ringwald 1560fdd788feSMatthias Ringwald // helper to set/get configuration 1561ea8aa208SMilanka Ringwald uint8_t avdtp_config_sbc_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz){ 1562588a837aSMilanka Ringwald uint8_t sampling_frequency_bitmap = (uint8_t)avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, sbc_sampling_frequency_table, sbc_sampling_frequency_table_size); 1563ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1564ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1565ea8aa208SMilanka Ringwald } 1566ea8aa208SMilanka Ringwald config[0] = (config[0] & 0x0f) | (uint8_t)(sampling_frequency_bitmap << 4); 1567ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS; 1568fdd788feSMatthias Ringwald } 1569fdd788feSMatthias Ringwald 1570ea8aa208SMilanka Ringwald uint8_t avdtp_config_sbc_store(uint8_t * config, const avdtp_configuration_sbc_t * configuration){ 1571ea8aa208SMilanka Ringwald if (configuration->channel_mode > AVDTP_CHANNEL_MODE_JOINT_STEREO){ 1572ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1573ea8aa208SMilanka Ringwald } 1574ea8aa208SMilanka Ringwald if (configuration->allocation_method > AVDTP_SBC_ALLOCATION_METHOD_SNR){ 1575ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1576ea8aa208SMilanka Ringwald } 1577*858500b1SMilanka Ringwald 1578*858500b1SMilanka Ringwald switch ((avdtp_sbc_block_length_t)configuration->block_length){ 1579*858500b1SMilanka Ringwald case AVDTP_SBC_BLOCK_LENGTH_4: 1580*858500b1SMilanka Ringwald case AVDTP_SBC_BLOCK_LENGTH_8: 1581*858500b1SMilanka Ringwald case AVDTP_SBC_BLOCK_LENGTH_12: 1582*858500b1SMilanka Ringwald case AVDTP_SBC_BLOCK_LENGTH_16: 1583fdd788feSMatthias Ringwald break; 1584fdd788feSMatthias Ringwald default: 1585ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1586fdd788feSMatthias Ringwald } 1587*858500b1SMilanka Ringwald switch ((avdtp_sbc_subbands_t)configuration->subbands){ 1588*858500b1SMilanka Ringwald case AVDTP_SBC_SUBBANDS_4: 1589*858500b1SMilanka Ringwald case AVDTP_SBC_SUBBANDS_8: 1590ea8aa208SMilanka Ringwald break; 1591ea8aa208SMilanka Ringwald default: 1592ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1593ea8aa208SMilanka Ringwald } 1594ea8aa208SMilanka Ringwald if ((configuration->min_bitpool_value < 2) || (configuration->min_bitpool_value > 250) || (configuration->min_bitpool_value > configuration->max_bitpool_value)){ 1595ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1596ea8aa208SMilanka Ringwald } 1597ea8aa208SMilanka Ringwald if ((configuration->max_bitpool_value < 2) || (configuration->max_bitpool_value > 250)){ 1598ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1599ea8aa208SMilanka Ringwald } 1600ea8aa208SMilanka Ringwald config[0] = 1 << (3 - (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO)); 16018691a66cSMatthias Ringwald config[1] = (configuration->block_length << 4) | (configuration->subbands << 2) | configuration->allocation_method; 16028691a66cSMatthias Ringwald config[2] = configuration->min_bitpool_value; 16038691a66cSMatthias Ringwald config[3] = configuration->max_bitpool_value; 1604ea8aa208SMilanka Ringwald return avdtp_config_sbc_set_sampling_frequency(config, configuration->sampling_frequency); 1605fdd788feSMatthias Ringwald } 1606fdd788feSMatthias Ringwald 1607ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_audio_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1608588a837aSMilanka Ringwald uint8_t sampling_frequency_bitmap = (uint8_t)avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, mpeg_sampling_frequency_table, mpeg_sampling_frequency_table_size); 1609ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1610ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1611ea8aa208SMilanka Ringwald } 1612ea8aa208SMilanka Ringwald config[1] = (config[1] & 0xE0) | sampling_frequency_bitmap; 1613ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS; 1614fdd788feSMatthias Ringwald } 1615fdd788feSMatthias Ringwald 1616ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_audio_store(uint8_t * config, const avdtp_configuration_mpeg_audio_t * configuration){ 1617ea8aa208SMilanka Ringwald if (configuration->layer > AVDTP_MPEG_LAYER_3){ 1618ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1619ea8aa208SMilanka Ringwald } 1620ea8aa208SMilanka Ringwald if (configuration->channel_mode > AVDTP_CHANNEL_MODE_JOINT_STEREO){ 1621ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1622ea8aa208SMilanka Ringwald } 1623ea8aa208SMilanka Ringwald uint16_t bit_rate_mask = 1 << configuration->bit_rate_index; 1624ea8aa208SMilanka Ringwald if (bit_rate_mask == 0){ 1625ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1626ea8aa208SMilanka Ringwald } 1627ea8aa208SMilanka Ringwald 16288691a66cSMatthias Ringwald config[0] = (1 << (7 - (configuration->layer - AVDTP_MPEG_LAYER_1))) | ((configuration->crc & 0x01) << 4) | (1 << (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO)); 16298691a66cSMatthias Ringwald config[1] = ((configuration->media_payload_format & 0x01) << 6) ; 16301da18615SMilanka Ringwald config[2] = ((configuration->vbr & 0x01) << 7) | ((bit_rate_mask >> 7) & 0x3f); 1631fdd788feSMatthias Ringwald config[3] = bit_rate_mask & 0xff; 1632ea8aa208SMilanka Ringwald return avdtp_config_mpeg_audio_set_sampling_frequency(config, configuration->sampling_frequency); 1633fdd788feSMatthias Ringwald } 1634fdd788feSMatthias Ringwald 1635ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1636588a837aSMilanka Ringwald uint16_t sampling_frequency_bitmap = (uint16_t)avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, aac_sampling_frequency_table, aac_sampling_frequency_table_size); 1637ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1638ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1639ea8aa208SMilanka Ringwald } 1640ea8aa208SMilanka Ringwald 1641fdd788feSMatthias Ringwald config[1] = sampling_frequency_bitmap >> 4; 1642fdd788feSMatthias Ringwald config[2] = ((sampling_frequency_bitmap & 0x0f) << 4) | (config[2] & 0x0f); 1643ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS; 1644fdd788feSMatthias Ringwald } 1645fdd788feSMatthias Ringwald 1646c83b8b89SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_store(uint8_t * config, const avdtp_configuration_mpeg_aac_t * configuration) { 16470737c3bfSMilanka Ringwald config[0] = (1 << (7 -(configuration->object_type - AVDTP_AAC_MPEG2_LC))) | (configuration->drc?1u:0u); 1648fdd788feSMatthias Ringwald uint8_t channels_bitmap = 0; 16498691a66cSMatthias Ringwald switch (configuration->channels){ 1650fdd788feSMatthias Ringwald case 1: 16510737c3bfSMilanka Ringwald channels_bitmap = 0x08; 1652fdd788feSMatthias Ringwald break; 1653fdd788feSMatthias Ringwald case 2: 16540737c3bfSMilanka Ringwald channels_bitmap = 0x04; 16550737c3bfSMilanka Ringwald break; 16560737c3bfSMilanka Ringwald case 6: 16570737c3bfSMilanka Ringwald channels_bitmap = 0x02; 16580737c3bfSMilanka Ringwald break; 16590737c3bfSMilanka Ringwald case 8: 1660fdd788feSMatthias Ringwald channels_bitmap = 0x01; 1661fdd788feSMatthias Ringwald break; 1662fdd788feSMatthias Ringwald default: 1663c83b8b89SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1664fdd788feSMatthias Ringwald } 1665c83b8b89SMilanka Ringwald config[2] = channels_bitmap; 16668691a66cSMatthias Ringwald config[3] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f); 16678691a66cSMatthias Ringwald config[4] = (configuration->bit_rate >> 8) & 0xff; 16688691a66cSMatthias Ringwald config[5] = configuration->bit_rate & 0xff; 1669ea8aa208SMilanka Ringwald return avdtp_config_mpeg_aac_set_sampling_frequency(config, configuration->sampling_frequency); 1670ea8aa208SMilanka Ringwald } 1671ea8aa208SMilanka Ringwald 1672ea8aa208SMilanka Ringwald uint8_t avdtp_config_atrac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1673588a837aSMilanka Ringwald uint8_t sampling_frequency_bitmap = (uint8_t)avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, atrac_sampling_frequency_table, atrac_sampling_frequency_table_size); 1674ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1675ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1676ea8aa208SMilanka Ringwald } 1677ea8aa208SMilanka Ringwald 1678ea8aa208SMilanka Ringwald config[1] = (config[1] & 0xCF) | (uint8_t)(sampling_frequency_bitmap << 4); 1679c83b8b89SMilanka Ringwald return ERROR_CODE_SUCCESS; 1680fdd788feSMatthias Ringwald } 1681fdd788feSMatthias Ringwald 1682ea8aa208SMilanka Ringwald uint8_t avdtp_config_atrac_store(uint8_t * config, const avdtp_configuration_atrac_t * configuration){ 1683a3868652SMatthias Ringwald uint8_t channel_mode_bitmap = 0; 16848691a66cSMatthias Ringwald switch (configuration->channel_mode){ 1685fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_MONO: 1686a3868652SMatthias Ringwald channel_mode_bitmap = 4; 1687fdd788feSMatthias Ringwald break; 1688fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_DUAL_CHANNEL: 1689a3868652SMatthias Ringwald channel_mode_bitmap = 2; 1690fdd788feSMatthias Ringwald break; 1691fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_JOINT_STEREO: 1692a3868652SMatthias Ringwald channel_mode_bitmap = 1; 1693fdd788feSMatthias Ringwald break; 1694fdd788feSMatthias Ringwald default: 1695ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1696fdd788feSMatthias Ringwald } 16978691a66cSMatthias Ringwald config[0] = ((configuration->version - AVDTP_ATRAC_VERSION_1 + 1) << 5) | (channel_mode_bitmap << 2); 16988691a66cSMatthias Ringwald uint32_t bit_rate_bitmap = 1 << (0x18 - configuration->bit_rate_index); 16998691a66cSMatthias Ringwald config[1] = ((configuration->vbr & 0x01) << 3) | ((bit_rate_bitmap >> 16) & 0x07); 1700fdd788feSMatthias Ringwald config[2] = (bit_rate_bitmap >> 8) & 0xff; 1701fdd788feSMatthias Ringwald config[3] = bit_rate_bitmap & 0xff; 17028691a66cSMatthias Ringwald config[4] = configuration->maximum_sul >> 8; 17038691a66cSMatthias Ringwald config[5] = configuration->maximum_sul & 0xff; 1704fdd788feSMatthias Ringwald config[6] = 0; 1705ea8aa208SMilanka Ringwald return avdtp_config_atrac_set_sampling_frequency(config, configuration->sampling_frequency); 1706fdd788feSMatthias Ringwald } 170724d5fe84SMilanka Ringwald 1708ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpegd_usac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) { 1709588a837aSMilanka Ringwald uint32_t sampling_frequency_bitmap = avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, usac_sampling_frequency_table, usac_sampling_frequency_table_size); 1710ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){ 1711ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1712ea8aa208SMilanka Ringwald } 1713ea8aa208SMilanka Ringwald config[0] = (config[0] & 0xC0) | (uint8_t)(sampling_frequency_bitmap >> 20); 1714ea8aa208SMilanka Ringwald config[1] = (uint8_t) (sampling_frequency_bitmap >> 12); 1715ea8aa208SMilanka Ringwald config[2] = (uint8_t) (sampling_frequency_bitmap >> 4); 171624d5fe84SMilanka Ringwald config[3] = (sampling_frequency_bitmap & 0x0f) << 4; 1717ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS; 171824d5fe84SMilanka Ringwald } 171924d5fe84SMilanka Ringwald 1720ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpegd_usac_store(uint8_t * config, const avdtp_configuration_mpegd_usac_t * configuration) { 1721ea8aa208SMilanka Ringwald if (configuration->object_type != AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC){ 1722ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 1723ea8aa208SMilanka Ringwald } 1724ea8aa208SMilanka Ringwald config[0] = 0x80; 172524d5fe84SMilanka Ringwald 172624d5fe84SMilanka Ringwald uint8_t channels_bitmap = 0; 172724d5fe84SMilanka Ringwald switch (configuration->channels){ 172824d5fe84SMilanka Ringwald case 1: 172924d5fe84SMilanka Ringwald channels_bitmap = 0x08; 173024d5fe84SMilanka Ringwald break; 173124d5fe84SMilanka Ringwald case 2: 173224d5fe84SMilanka Ringwald channels_bitmap = 0x04; 173324d5fe84SMilanka Ringwald break; 173424d5fe84SMilanka Ringwald default: 1735ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE; 173624d5fe84SMilanka Ringwald } 173724d5fe84SMilanka Ringwald config[3] = config[3] | channels_bitmap; 173824d5fe84SMilanka Ringwald config[4] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f); 173924d5fe84SMilanka Ringwald config[5] = (configuration->bit_rate >> 8) & 0xff; 174024d5fe84SMilanka Ringwald config[6] = configuration->bit_rate & 0xff; 1741ea8aa208SMilanka Ringwald return avdtp_config_mpegd_usac_set_sampling_frequency(config, configuration->sampling_frequency); 174224d5fe84SMilanka Ringwald }