xref: /btstack/src/classic/avdtp_util.c (revision 858500b1d84461433ceb8b01c0f0962272bc429f)
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 }