xref: /btstack/src/classic/avdtp_util.c (revision b182b7f477edf4fd11f1972d35a030e3cb206ff1)
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 
avdtp_si2str(uint16_t index)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 
avdtp_config_get_sampling_frequency_bitmap_from_table(uint16_t sampling_frequency_hz,const uint32_t * table,uint8_t table_size)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 
avdtp_config_get_sampling_frequency_from_table(uint16_t sampling_frequency_bitmap,const uint32_t * table,uint8_t table_size)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 
avdtp_reset_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint)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 
get_bit16(uint16_t bitmap,int position)1908ef7100fSMilanka Ringwald int get_bit16(uint16_t bitmap, int position){
1918ef7100fSMilanka Ringwald     return (bitmap >> position) & 1;
1928ef7100fSMilanka Ringwald }
1938ef7100fSMilanka Ringwald 
store_bit16(uint16_t bitmap,int position,uint8_t value)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 
avdtp_get_signaling_message_type(uint8_t * packet)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
avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header,uint8_t * packet,uint16_t size)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 
avdtp_is_basic_capability(int service_category)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 
avdtp_pack_service_capabilities(uint8_t * buffer,int size,avdtp_capabilities_t caps,avdtp_service_category_t category)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 
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)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 
avdtp_unpack_service_capabilities(avdtp_connection_t * connection,avdtp_signal_identifier_t signal_identifier,avdtp_capabilities_t * caps,uint8_t * packet,uint16_t size)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 
avdtp_prepare_capabilities(avdtp_signaling_packet_t * signaling_packet,uint8_t transaction_label,uint16_t service_categories,avdtp_capabilities_t capabilities,uint8_t identifier)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 
avdtp_signaling_create_fragment(uint16_t cid,avdtp_signaling_packet_t * signaling_packet,uint8_t * out_buffer)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 
avdtp_signaling_emit_connection_established(uint16_t avdtp_cid,bd_addr_t addr,hci_con_handle_t con_handle,uint8_t status)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 
avdtp_signaling_emit_connection_released(uint16_t avdtp_cid)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 
avdtp_signaling_emit_sep(uint16_t avdtp_cid,avdtp_sep_t sep)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 
avdtp_signaling_emit_sep_done(uint16_t avdtp_cid)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 
avdtp_signaling_emit_accept(uint16_t avdtp_cid,uint8_t local_seid,avdtp_signal_identifier_t identifier,bool is_initiator)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 
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)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 
avdtp_signaling_emit_reject(uint16_t avdtp_cid,uint8_t local_seid,avdtp_signal_identifier_t identifier,bool is_initiator)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 
avdtp_signaling_emit_general_reject(uint16_t avdtp_cid,uint8_t local_seid,avdtp_signal_identifier_t identifier,bool is_initiator)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
avdtp_signaling_emit_capability(uint8_t capability_subevent_id,uint16_t avdtp_cid,uint8_t remote_seid)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 
avdtp_signaling_emit_media_codec_sbc_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)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 
avdtp_signaling_emit_media_codec_mpeg_audio_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)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 
avdtp_signaling_emit_media_codec_mpeg_aac_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)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;
721*b182b7f4SMilanka Ringwald     uint8_t event[16];
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;
7395ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, sampling_frequency_bitmap);
7405ce3497fSMatthias Ringwald     pos += 2;
7415ce3497fSMatthias Ringwald     event[pos++] = channels_bitmap;
7425ce3497fSMatthias Ringwald     little_endian_store_24(event, pos, bit_rate_bitmap);
7435ce3497fSMatthias Ringwald     pos += 3;
7445ce3497fSMatthias Ringwald     event[pos++] = vbr;
745b7aa6976SMilanka Ringwald     event[pos++] =  drc;
7465ce3497fSMatthias Ringwald     avdtp_emit_sink_and_source(event, pos);
7475ce3497fSMatthias Ringwald }
7485ce3497fSMatthias Ringwald 
avdtp_signaling_emit_media_codec_atrac_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)7495ce3497fSMatthias 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) {
7505ce3497fSMatthias Ringwald     const uint8_t * media_codec_information = media_codec.media_codec_information;
7515ce3497fSMatthias Ringwald     uint8_t event[16];
7525ce3497fSMatthias Ringwald     int pos = 0;
7535ce3497fSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
75473048ce6SMatthias Ringwald     pos++; // set later
7555ce3497fSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY;
7565ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
7575ce3497fSMatthias Ringwald     pos += 2;
7585ce3497fSMatthias Ringwald     event[pos++] = remote_seid;
7595ce3497fSMatthias Ringwald     event[pos++] = media_codec.media_type;
7605ce3497fSMatthias Ringwald 
7615ce3497fSMatthias Ringwald     uint8_t  version                   =  media_codec_information[0] >> 5;
7625ce3497fSMatthias Ringwald     uint8_t  channel_mode_bitmap       = (media_codec_information[0] >> 2) & 0x07;
763ab2445a0SMatthias Ringwald     uint8_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03;
7645ce3497fSMatthias Ringwald     uint8_t  vbr                       = (media_codec_information[1] >> 3) & 0x01;
7655ce3497fSMatthias Ringwald     uint16_t bit_rate_index_bitmap     = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3];
7665ce3497fSMatthias Ringwald     uint16_t maximum_sul               = (media_codec_information[4] << 8) | media_codec_information[5];
7675ce3497fSMatthias Ringwald 
7685ce3497fSMatthias Ringwald     event[pos++] = version;
7695ce3497fSMatthias Ringwald     event[pos++] = channel_mode_bitmap;
7705ce3497fSMatthias Ringwald     event[pos++] = sampling_frequency_bitmap;
7715ce3497fSMatthias Ringwald     event[pos++] = vbr;
7725ce3497fSMatthias Ringwald     little_endian_store_24(event, pos, bit_rate_index_bitmap);
7735ce3497fSMatthias Ringwald     pos += 3;
7745ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, maximum_sul);
77573048ce6SMatthias Ringwald     pos += 2;
77673048ce6SMatthias Ringwald     event[1] = pos - 2;
777c69f4ba5SMatthias Ringwald     avdtp_emit_sink_and_source(event, pos);
7788ef7100fSMilanka Ringwald }
7798ef7100fSMilanka Ringwald 
avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)78024d5fe84SMilanka 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) {
78124d5fe84SMilanka Ringwald     const uint8_t * media_codec_information = media_codec.media_codec_information;
78224d5fe84SMilanka Ringwald     uint8_t event[18];
78324d5fe84SMilanka Ringwald     int pos = 0;
78424d5fe84SMilanka Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
78524d5fe84SMilanka Ringwald     pos++; // set later
78624d5fe84SMilanka Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CAPABILITY;
78724d5fe84SMilanka Ringwald     little_endian_store_16(event, pos, avdtp_cid);
78824d5fe84SMilanka Ringwald     pos += 2;
78924d5fe84SMilanka Ringwald     event[pos++] = remote_seid;
79024d5fe84SMilanka Ringwald     event[pos++] = media_codec.media_type;
79124d5fe84SMilanka Ringwald 
79224d5fe84SMilanka Ringwald     uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) |
79324d5fe84SMilanka Ringwald                                           (media_codec_information[1] << 12) |
79424d5fe84SMilanka Ringwald                                           (media_codec_information[2] << 4) |
79524d5fe84SMilanka Ringwald                                           (media_codec_information[3] >> 4);
79624d5fe84SMilanka Ringwald 
79724d5fe84SMilanka Ringwald     uint8_t  channels_bitmap            = (media_codec_information[3] >> 2) & 0x03;
79824d5fe84SMilanka Ringwald     uint8_t  vbr                        = (media_codec_information[4] >> 7) & 0x01;
79924d5fe84SMilanka Ringwald 
80024d5fe84SMilanka Ringwald     uint16_t bit_rate_index_bitmap     = ((media_codec_information[4]) & 0xEF) << 16 | (media_codec_information[5] << 8) | media_codec_information[6];
80124d5fe84SMilanka Ringwald 
80224d5fe84SMilanka Ringwald     event[pos++] = media_codec_information[0] >> 6;
80324d5fe84SMilanka Ringwald     little_endian_store_32(event, pos, sampling_frequency_bitmap);
80424d5fe84SMilanka Ringwald     pos += 4;
80524d5fe84SMilanka Ringwald     event[pos++] = channels_bitmap;
80624d5fe84SMilanka Ringwald     event[pos++] = sampling_frequency_bitmap;
80724d5fe84SMilanka Ringwald     event[pos++] = vbr;
80824d5fe84SMilanka Ringwald     little_endian_store_24(event, pos, bit_rate_index_bitmap);
80924d5fe84SMilanka Ringwald     pos += 3;
81024d5fe84SMilanka Ringwald     event[1] = pos - 2;
81124d5fe84SMilanka Ringwald     avdtp_emit_sink_and_source(event, pos);
81224d5fe84SMilanka Ringwald }
81324d5fe84SMilanka Ringwald 
81424d5fe84SMilanka Ringwald 
avdtp_signaling_emit_media_codec_other_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)8151159d239SMatthias 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) {
816924216b2SMatthias Ringwald     uint8_t event[AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH + 11];
81767ae582dSMilanka Ringwald     int pos = 0;
81867ae582dSMilanka Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
81973048ce6SMatthias Ringwald     pos++; // set later
8204b7d40bbSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY;
82167ae582dSMilanka Ringwald     little_endian_store_16(event, pos, avdtp_cid);
82267ae582dSMilanka Ringwald     pos += 2;
82367ae582dSMilanka Ringwald     event[pos++] = remote_seid;
8244b7d40bbSMatthias Ringwald     event[pos++] = media_codec.media_type;
8254b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, media_codec.media_codec_type);
8264b7d40bbSMatthias Ringwald     pos += 2;
8274b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, media_codec.media_codec_information_len);
8284b7d40bbSMatthias Ringwald     pos += 2;
829924216b2SMatthias Ringwald     uint32_t media_codec_info_len = btstack_min(media_codec.media_codec_information_len, AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH);
8305403525eSMatthias Ringwald     (void)memcpy(event + pos, media_codec.media_codec_information, media_codec_info_len);
8315403525eSMatthias Ringwald     pos += media_codec_info_len;
83273048ce6SMatthias Ringwald     event[1] = pos - 2;
833c69f4ba5SMatthias Ringwald     avdtp_emit_sink_and_source(event, pos);
83467ae582dSMilanka Ringwald }
83567ae582dSMilanka Ringwald 
836c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_media_transport_capability(uint16_t avdtp_cid,uint8_t remote_seid)8371159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(uint16_t avdtp_cid, uint8_t remote_seid) {
8381159d239SMatthias Ringwald 	avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY, avdtp_cid,
839c69f4ba5SMatthias Ringwald 									remote_seid);
84067ae582dSMilanka Ringwald }
84167ae582dSMilanka Ringwald 
avdtp_signaling_emit_reporting_capability(uint16_t avdtp_cid,uint8_t remote_seid)8421159d239SMatthias Ringwald static void avdtp_signaling_emit_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) {
8431159d239SMatthias Ringwald 	avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY, avdtp_cid, remote_seid);
84467ae582dSMilanka Ringwald }
84567ae582dSMilanka Ringwald 
846c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_delay_reporting_capability(uint16_t avdtp_cid,uint8_t remote_seid)8471159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) {
8481159d239SMatthias Ringwald 	avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY, avdtp_cid,
849c69f4ba5SMatthias Ringwald 									remote_seid);
85067ae582dSMilanka Ringwald }
85167ae582dSMilanka Ringwald 
avdtp_signaling_emit_recovery_capability(uint16_t avdtp_cid,uint8_t remote_seid,avdtp_recovery_capabilities_t * recovery)8521159d239SMatthias Ringwald static void avdtp_signaling_emit_recovery_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_recovery_capabilities_t *recovery) {
8531159d239SMatthias Ringwald     uint8_t event[9];
85467ae582dSMilanka Ringwald     int pos = 0;
85567ae582dSMilanka Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
85667ae582dSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
85767ae582dSMilanka Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY;
85867ae582dSMilanka Ringwald     little_endian_store_16(event, pos, avdtp_cid);
85967ae582dSMilanka Ringwald     pos += 2;
86067ae582dSMilanka Ringwald     event[pos++] = remote_seid;
86167ae582dSMilanka Ringwald     event[pos++] = recovery->recovery_type;
86267ae582dSMilanka Ringwald     event[pos++] = recovery->maximum_recovery_window_size;
86367ae582dSMilanka Ringwald     event[pos++] = recovery->maximum_number_media_packets;
864c69f4ba5SMatthias Ringwald     avdtp_emit_sink_and_source(event, pos);
86567ae582dSMilanka Ringwald }
86667ae582dSMilanka Ringwald 
86773048ce6SMatthias Ringwald #define MAX_CONTENT_PROTECTION_VALUE_LEN 32
868c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_content_protection_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_content_protection_t * content_protection)8691159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_content_protection_t *content_protection) {
87073048ce6SMatthias Ringwald     uint8_t event[10 + MAX_CONTENT_PROTECTION_VALUE_LEN];
87167ae582dSMilanka Ringwald     int pos = 0;
87267ae582dSMilanka Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
87373048ce6SMatthias Ringwald     pos++; // set later
87467ae582dSMilanka Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY;
87567ae582dSMilanka Ringwald     little_endian_store_16(event, pos, avdtp_cid);
87667ae582dSMilanka Ringwald     pos += 2;
87767ae582dSMilanka Ringwald     event[pos++] = remote_seid;
87867ae582dSMilanka Ringwald 
87967ae582dSMilanka Ringwald     little_endian_store_16(event, pos, content_protection->cp_type);
88067ae582dSMilanka Ringwald     pos += 2;
88173048ce6SMatthias Ringwald 
88273048ce6SMatthias Ringwald     // drop cp protection value if longer than expected
88373048ce6SMatthias Ringwald     if (content_protection->cp_type_value_len <= MAX_CONTENT_PROTECTION_VALUE_LEN){
88467ae582dSMilanka Ringwald         little_endian_store_16(event, pos, content_protection->cp_type_value_len);
88567ae582dSMilanka Ringwald         pos += 2;
88673048ce6SMatthias Ringwald         (void)memcpy(event + pos, content_protection->cp_type_value, content_protection->cp_type_value_len);
88773048ce6SMatthias Ringwald         pos += content_protection->cp_type_value_len;
88873048ce6SMatthias Ringwald     } else {
88973048ce6SMatthias Ringwald         little_endian_store_16(event, pos, 0);
89073048ce6SMatthias Ringwald         pos += 2;
89167ae582dSMilanka Ringwald     }
89273048ce6SMatthias Ringwald     event[1] = pos - 2;
893c69f4ba5SMatthias Ringwald     avdtp_emit_sink_and_source(event, pos);
89467ae582dSMilanka Ringwald }
89567ae582dSMilanka Ringwald 
89667ae582dSMilanka Ringwald 
897c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_header_compression_capability(uint16_t avdtp_cid,uint8_t remote_seid,avdtp_header_compression_capabilities_t * header_compression)8981159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_header_compression_capabilities_t *header_compression) {
8991159d239SMatthias Ringwald     uint8_t event[9];
90067ae582dSMilanka Ringwald     int pos = 0;
90167ae582dSMilanka Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
90267ae582dSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
90367ae582dSMilanka Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY;
90467ae582dSMilanka Ringwald     little_endian_store_16(event, pos, avdtp_cid);
90567ae582dSMilanka Ringwald     pos += 2;
90667ae582dSMilanka Ringwald     event[pos++] = remote_seid;
90767ae582dSMilanka Ringwald     event[pos++] = header_compression->back_ch;
90867ae582dSMilanka Ringwald     event[pos++] = header_compression->media;
90967ae582dSMilanka Ringwald     event[pos++] = header_compression->recovery;
910c69f4ba5SMatthias Ringwald     avdtp_emit_sink_and_source(event, pos);
91167ae582dSMilanka Ringwald }
91267ae582dSMilanka Ringwald 
913c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_content_multiplexing_capability(uint16_t avdtp_cid,uint8_t remote_seid,avdtp_multiplexing_mode_capabilities_t * multiplexing_mode)9141159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_multiplexing_mode_capabilities_t *multiplexing_mode) {
9151159d239SMatthias Ringwald     uint8_t event[14];
91667ae582dSMilanka Ringwald     int pos = 0;
91767ae582dSMilanka Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
91867ae582dSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
91967ae582dSMilanka Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY;
92067ae582dSMilanka Ringwald     little_endian_store_16(event, pos, avdtp_cid);
92167ae582dSMilanka Ringwald     pos += 2;
92267ae582dSMilanka Ringwald     event[pos++] = remote_seid;
92367ae582dSMilanka Ringwald 
92467ae582dSMilanka Ringwald     event[pos++] = multiplexing_mode->fragmentation;
92567ae582dSMilanka Ringwald     event[pos++] = multiplexing_mode->transport_identifiers_num;
92667ae582dSMilanka Ringwald 
92767ae582dSMilanka Ringwald     int i;
92867ae582dSMilanka Ringwald     for (i = 0; i < 3; i++){
92967ae582dSMilanka Ringwald         event[pos++] = multiplexing_mode->transport_session_identifiers[i];
93067ae582dSMilanka Ringwald     }
93167ae582dSMilanka Ringwald     for (i = 0; i < 3; i++){
93267ae582dSMilanka Ringwald         event[pos++] = multiplexing_mode->tcid[i];
93367ae582dSMilanka Ringwald     }
934c69f4ba5SMatthias Ringwald     avdtp_emit_sink_and_source(event, pos);
93567ae582dSMilanka Ringwald }
93667ae582dSMilanka Ringwald 
avdtp_signaling_emit_capability_done(uint16_t avdtp_cid,uint8_t remote_seid)9371159d239SMatthias Ringwald static void avdtp_signaling_emit_capability_done(uint16_t avdtp_cid, uint8_t remote_seid) {
9381159d239SMatthias Ringwald     uint8_t event[6];
939f08f4934SMatthias Ringwald     int pos = 0;
940f08f4934SMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
941f08f4934SMatthias Ringwald     event[pos++] = sizeof(event) - 2;
942f08f4934SMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE;
943f08f4934SMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
944f08f4934SMatthias Ringwald     pos += 2;
945f08f4934SMatthias Ringwald     event[pos++] = remote_seid;
946c69f4ba5SMatthias Ringwald     avdtp_emit_sink_and_source(event, pos);
947f08f4934SMatthias Ringwald }
948f08f4934SMatthias Ringwald 
avdtp_signaling_emit_media_codec_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)9490928ecceSMatthias Ringwald static void avdtp_signaling_emit_media_codec_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec){
9500928ecceSMatthias Ringwald     switch (media_codec.media_codec_type){
9510928ecceSMatthias Ringwald         case AVDTP_CODEC_SBC:
9520928ecceSMatthias Ringwald             avdtp_signaling_emit_media_codec_sbc_capability(avdtp_cid, remote_seid, media_codec);
9530928ecceSMatthias Ringwald             break;
9540928ecceSMatthias Ringwald         case AVDTP_CODEC_MPEG_1_2_AUDIO:
9550928ecceSMatthias Ringwald             avdtp_signaling_emit_media_codec_mpeg_audio_capability(avdtp_cid, remote_seid, media_codec);
9560928ecceSMatthias Ringwald             break;
9570928ecceSMatthias Ringwald         case AVDTP_CODEC_MPEG_2_4_AAC:
9580928ecceSMatthias Ringwald             avdtp_signaling_emit_media_codec_mpeg_aac_capability(avdtp_cid, remote_seid, media_codec);
9590928ecceSMatthias Ringwald             break;
9600928ecceSMatthias Ringwald         case AVDTP_CODEC_ATRAC_FAMILY:
9610928ecceSMatthias Ringwald             avdtp_signaling_emit_media_codec_atrac_capability(avdtp_cid, remote_seid, media_codec);
9620928ecceSMatthias Ringwald             break;
96324d5fe84SMilanka Ringwald         case AVDTP_CODEC_MPEG_D_USAC:
96424d5fe84SMilanka Ringwald             avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(avdtp_cid, remote_seid, media_codec);
96524d5fe84SMilanka Ringwald             break;
9660928ecceSMatthias Ringwald         default:
9670928ecceSMatthias Ringwald             avdtp_signaling_emit_media_codec_other_capability(avdtp_cid, remote_seid, media_codec);
9680928ecceSMatthias Ringwald             break;
9690928ecceSMatthias Ringwald     }
9700928ecceSMatthias Ringwald }
9710928ecceSMatthias Ringwald 
9724b7d40bbSMatthias Ringwald // emit events for all capabilities incl. final done event
avdtp_signaling_emit_capabilities(uint16_t avdtp_cid,uint8_t remote_seid,avdtp_capabilities_t * capabilities,uint16_t registered_service_categories)9731159d239SMatthias Ringwald void avdtp_signaling_emit_capabilities(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_capabilities_t *capabilities,
974c69f4ba5SMatthias Ringwald 									   uint16_t registered_service_categories) {
97567ae582dSMilanka Ringwald     if (get_bit16(registered_service_categories, AVDTP_MEDIA_CODEC)){
9760928ecceSMatthias Ringwald         avdtp_signaling_emit_media_codec_capability(avdtp_cid, remote_seid, capabilities->media_codec);
97767ae582dSMilanka Ringwald     }
97867ae582dSMilanka Ringwald 
97967ae582dSMilanka Ringwald     if (get_bit16(registered_service_categories, AVDTP_MEDIA_TRANSPORT)){
9801159d239SMatthias Ringwald 		avdtp_signaling_emit_media_transport_capability(avdtp_cid, remote_seid);
98167ae582dSMilanka Ringwald     }
98267ae582dSMilanka Ringwald     if (get_bit16(registered_service_categories, AVDTP_REPORTING)){
9831159d239SMatthias Ringwald 		avdtp_signaling_emit_reporting_capability(avdtp_cid, remote_seid);
98467ae582dSMilanka Ringwald     }
98567ae582dSMilanka Ringwald     if (get_bit16(registered_service_categories, AVDTP_RECOVERY)){
9861159d239SMatthias Ringwald 		avdtp_signaling_emit_recovery_capability(avdtp_cid, remote_seid, &capabilities->recovery);
98767ae582dSMilanka Ringwald     }
98867ae582dSMilanka Ringwald     if (get_bit16(registered_service_categories, AVDTP_CONTENT_PROTECTION)){
9891159d239SMatthias Ringwald 		avdtp_signaling_emit_content_protection_capability(avdtp_cid, remote_seid,
990c69f4ba5SMatthias Ringwald 														   &capabilities->content_protection);
99167ae582dSMilanka Ringwald     }
99267ae582dSMilanka Ringwald     if (get_bit16(registered_service_categories, AVDTP_HEADER_COMPRESSION)){
9931159d239SMatthias Ringwald 		avdtp_signaling_emit_header_compression_capability(avdtp_cid, remote_seid,
994c69f4ba5SMatthias Ringwald 														   &capabilities->header_compression);
99567ae582dSMilanka Ringwald     }
99667ae582dSMilanka Ringwald     if (get_bit16(registered_service_categories, AVDTP_MULTIPLEXING)){
9971159d239SMatthias Ringwald 		avdtp_signaling_emit_content_multiplexing_capability(avdtp_cid, remote_seid,
998c69f4ba5SMatthias Ringwald 															 &capabilities->multiplexing_mode);
99967ae582dSMilanka Ringwald     }
100067ae582dSMilanka Ringwald     if (get_bit16(registered_service_categories, AVDTP_DELAY_REPORTING)){
10011159d239SMatthias Ringwald 		avdtp_signaling_emit_delay_reporting_capability(avdtp_cid, remote_seid);
100267ae582dSMilanka Ringwald     }
10031159d239SMatthias Ringwald 	avdtp_signaling_emit_capability_done(avdtp_cid, remote_seid);
100467ae582dSMilanka Ringwald }
100567ae582dSMilanka Ringwald 
1006186e1970SMatthias Ringwald static uint16_t
avdtp_signaling_setup_media_codec_sbc_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)1007186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_sbc_config_event(uint8_t *event, uint16_t size,
1008a905535cSMatthias Ringwald                                                    const avdtp_stream_endpoint_t *stream_endpoint,
1009186e1970SMatthias Ringwald                                                    uint16_t avdtp_cid, uint8_t reconfigure,
1010186e1970SMatthias Ringwald                                                    const uint8_t *media_codec_information) {
1011186e1970SMatthias Ringwald 
1012924216b2SMatthias Ringwald     btstack_assert(size >= AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN);
1013186e1970SMatthias Ringwald 
10144b7d40bbSMatthias Ringwald     uint8_t local_seid = avdtp_local_seid(stream_endpoint);
10154b7d40bbSMatthias Ringwald     uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
10164b7d40bbSMatthias Ringwald 
10174b7d40bbSMatthias Ringwald     int pos = 0;
10184b7d40bbSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
1019924216b2SMatthias Ringwald     event[pos++] = AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN - 2;
10204b7d40bbSMatthias Ringwald 
10214b7d40bbSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION;
10224b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
10234b7d40bbSMatthias Ringwald     pos += 2;
10244b7d40bbSMatthias Ringwald     event[pos++] = local_seid;
10254b7d40bbSMatthias Ringwald     event[pos++] = remote_seid;
10264b7d40bbSMatthias Ringwald     event[pos++] = reconfigure;
1027186e1970SMatthias Ringwald     event[pos++] = AVDTP_CODEC_SBC;
10284b7d40bbSMatthias Ringwald 
10294b7d40bbSMatthias Ringwald     uint8_t sampling_frequency_bitmap = media_codec_information[0] >> 4;
10304b7d40bbSMatthias Ringwald     uint8_t channel_mode_bitmap = media_codec_information[0] & 0x0F;
10314b7d40bbSMatthias Ringwald     uint8_t block_length_bitmap = media_codec_information[1] >> 4;
10324b7d40bbSMatthias Ringwald     uint8_t subbands_bitmap = (media_codec_information[1] & 0x0F) >> 2;
10334b7d40bbSMatthias Ringwald 
10344b7d40bbSMatthias Ringwald     uint8_t num_channels = 0;
1035a3868652SMatthias Ringwald     avdtp_channel_mode_t channel_mode;
1036a3868652SMatthias Ringwald 
1037a3868652SMatthias Ringwald     if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){
1038a3868652SMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
10394b7d40bbSMatthias Ringwald         num_channels = 2;
1040a3868652SMatthias Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){
1041a3868652SMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_STEREO;
1042a3868652SMatthias Ringwald         num_channels = 2;
1043a3868652SMatthias Ringwald     } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){
1044a3868652SMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
1045a3868652SMatthias Ringwald         num_channels = 2;
1046a3868652SMatthias Ringwald     } else {
1047a3868652SMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_MONO;
10484b7d40bbSMatthias Ringwald         num_channels = 1;
10494b7d40bbSMatthias Ringwald     }
10504b7d40bbSMatthias Ringwald 
10514b7d40bbSMatthias Ringwald     uint16_t sampling_frequency = 0;
10524b7d40bbSMatthias Ringwald     if (sampling_frequency_bitmap & AVDTP_SBC_48000) {
10534b7d40bbSMatthias Ringwald         sampling_frequency = 48000;
10544b7d40bbSMatthias Ringwald     } else if (sampling_frequency_bitmap & AVDTP_SBC_44100) {
10554b7d40bbSMatthias Ringwald         sampling_frequency = 44100;
10564b7d40bbSMatthias Ringwald     } else if (sampling_frequency_bitmap & AVDTP_SBC_32000) {
10574b7d40bbSMatthias Ringwald         sampling_frequency = 32000;
10584b7d40bbSMatthias Ringwald     } else if (sampling_frequency_bitmap & AVDTP_SBC_16000) {
10594b7d40bbSMatthias Ringwald         sampling_frequency = 16000;
10604b7d40bbSMatthias Ringwald     }
10614b7d40bbSMatthias Ringwald 
10624b7d40bbSMatthias Ringwald     uint8_t subbands = 0;
10634b7d40bbSMatthias Ringwald     if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){
10644b7d40bbSMatthias Ringwald         subbands = 8;
10654b7d40bbSMatthias Ringwald     } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){
10664b7d40bbSMatthias Ringwald         subbands = 4;
10674b7d40bbSMatthias Ringwald     }
10684b7d40bbSMatthias Ringwald 
10694b7d40bbSMatthias Ringwald     uint8_t block_length = 0;
10704b7d40bbSMatthias Ringwald     if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){
10714b7d40bbSMatthias Ringwald         block_length = 16;
10724b7d40bbSMatthias Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){
10734b7d40bbSMatthias Ringwald         block_length = 12;
10744b7d40bbSMatthias Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){
10754b7d40bbSMatthias Ringwald         block_length = 8;
10764b7d40bbSMatthias Ringwald     } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){
10774b7d40bbSMatthias Ringwald         block_length = 4;
10784b7d40bbSMatthias Ringwald     }
10794b7d40bbSMatthias Ringwald 
10804b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, sampling_frequency);
10814b7d40bbSMatthias Ringwald     pos += 2;
10824b7d40bbSMatthias Ringwald 
1083a3868652SMatthias Ringwald     event[pos++] = (uint8_t) channel_mode;
10844b7d40bbSMatthias Ringwald     event[pos++] = num_channels;
10854b7d40bbSMatthias Ringwald     event[pos++] = block_length;
10864b7d40bbSMatthias Ringwald     event[pos++] = subbands;
10874b7d40bbSMatthias Ringwald     event[pos++] = media_codec_information[1] & 0x03;
10884b7d40bbSMatthias Ringwald     event[pos++] = media_codec_information[2];
10894b7d40bbSMatthias Ringwald     event[pos++] = media_codec_information[3];
1090186e1970SMatthias Ringwald 
1091924216b2SMatthias Ringwald     btstack_assert(pos == AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN);
1092186e1970SMatthias Ringwald 
1093186e1970SMatthias Ringwald     return pos;
10945ce3497fSMatthias Ringwald }
10955ce3497fSMatthias Ringwald 
1096186e1970SMatthias Ringwald static uint16_t
avdtp_signaling_setup_media_codec_mpeg_audio_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)1097186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpeg_audio_config_event(uint8_t *event, uint16_t size,
1098a905535cSMatthias Ringwald                                                           const avdtp_stream_endpoint_t *stream_endpoint,
1099186e1970SMatthias Ringwald                                                           uint16_t avdtp_cid, uint8_t reconfigure,
11005ce3497fSMatthias Ringwald                                                           const uint8_t *media_codec_information) {
11015ce3497fSMatthias Ringwald 
1102924216b2SMatthias Ringwald     btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN);
1103186e1970SMatthias Ringwald 
11045ce3497fSMatthias Ringwald     uint8_t local_seid = avdtp_local_seid(stream_endpoint);
11055ce3497fSMatthias Ringwald     uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
11065ce3497fSMatthias Ringwald 
1107186e1970SMatthias Ringwald     uint16_t pos = 0;
11085ce3497fSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
1109924216b2SMatthias Ringwald     event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN - 2;
11105ce3497fSMatthias Ringwald 
11115ce3497fSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION;
11125ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
11135ce3497fSMatthias Ringwald     pos += 2;
11145ce3497fSMatthias Ringwald     event[pos++] = local_seid;
11155ce3497fSMatthias Ringwald     event[pos++] = remote_seid;
11165ce3497fSMatthias Ringwald     event[pos++] = reconfigure;
1117186e1970SMatthias Ringwald     event[pos++] = AVDTP_CODEC_MPEG_1_2_AUDIO;
11185ce3497fSMatthias Ringwald 
11195ce3497fSMatthias Ringwald     uint8_t layer_bitmap              =   media_codec_information[0] >> 5;
11205ce3497fSMatthias Ringwald     uint8_t crc                       =  (media_codec_information[0] >> 4) & 0x01;
11215ce3497fSMatthias Ringwald     uint8_t channel_mode_bitmap       =  (media_codec_information[0] & 0x07);
11225ce3497fSMatthias Ringwald     uint8_t mpf                       =  (media_codec_information[1] >> 6) & 0x01;
11235ce3497fSMatthias Ringwald     uint8_t sampling_frequency_bitmap =  (media_codec_information[1] & 0x3F);
11245ce3497fSMatthias Ringwald     uint8_t vbr                       =  (media_codec_information[2] >> 7) & 0x01;
11255ce3497fSMatthias Ringwald     uint16_t bit_rate_index_bitmap    = ((media_codec_information[2] & 0x3f) << 8) | media_codec_information[3];
11265ce3497fSMatthias Ringwald 
11275ce3497fSMatthias Ringwald     uint8_t layer = 0;
11285ce3497fSMatthias Ringwald     if (layer_bitmap & 0x04){
11295ce3497fSMatthias Ringwald         layer = AVDTP_MPEG_LAYER_1;
11305ce3497fSMatthias Ringwald     } else if (layer_bitmap & 0x02){
11315ce3497fSMatthias Ringwald         layer = AVDTP_MPEG_LAYER_2;
11325ce3497fSMatthias Ringwald     } else if (layer_bitmap & 0x01){
11335ce3497fSMatthias Ringwald         layer = AVDTP_MPEG_LAYER_3;
11345ce3497fSMatthias Ringwald     }
11355ce3497fSMatthias Ringwald 
11365ce3497fSMatthias Ringwald     uint8_t num_channels = 0;
11375ce3497fSMatthias Ringwald     avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
11385ce3497fSMatthias Ringwald     if (channel_mode_bitmap & 0x08){
11395ce3497fSMatthias Ringwald         num_channels = 1;
11405ce3497fSMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_MONO;
11415ce3497fSMatthias Ringwald     } else if (channel_mode_bitmap & 0x04){
11425ce3497fSMatthias Ringwald         num_channels = 2;
11435ce3497fSMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
11445ce3497fSMatthias Ringwald     } else if (channel_mode_bitmap & 0x02){
11455ce3497fSMatthias Ringwald         num_channels = 2;
11465ce3497fSMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_STEREO;
11475ce3497fSMatthias Ringwald     } else if (channel_mode_bitmap & 0x02){
11485ce3497fSMatthias Ringwald         num_channels = 2;
11495ce3497fSMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
11505ce3497fSMatthias Ringwald     }
11515ce3497fSMatthias Ringwald 
11525ce3497fSMatthias Ringwald     uint16_t sampling_frequency = 0;
11535ce3497fSMatthias Ringwald     if (sampling_frequency_bitmap & 0x01) {
11545ce3497fSMatthias Ringwald         sampling_frequency = 48000;
11555ce3497fSMatthias Ringwald     } else if (sampling_frequency_bitmap & 0x02) {
11565ce3497fSMatthias Ringwald         sampling_frequency = 44100;
11575ce3497fSMatthias Ringwald     } else if (sampling_frequency_bitmap & 0x04) {
11585ce3497fSMatthias Ringwald         sampling_frequency = 32000;
11595ce3497fSMatthias Ringwald     } else if (sampling_frequency_bitmap & 0x08) {
11605ce3497fSMatthias Ringwald         sampling_frequency = 24000;
11615ce3497fSMatthias Ringwald     } else if (sampling_frequency_bitmap & 0x10) {
11625ce3497fSMatthias Ringwald         sampling_frequency = 22050;
11635ce3497fSMatthias Ringwald     } else if (sampling_frequency_bitmap & 0x20) {
11645ce3497fSMatthias Ringwald         sampling_frequency = 16000;
11655ce3497fSMatthias Ringwald     }
11665ce3497fSMatthias Ringwald 
11675ce3497fSMatthias Ringwald     uint8_t bitrate_index = 0;
11685ce3497fSMatthias Ringwald     uint8_t i;
11695ce3497fSMatthias Ringwald     for (i=0;i<14;i++){
11705ce3497fSMatthias Ringwald         if (bit_rate_index_bitmap & (1U << i)) {
11715ce3497fSMatthias Ringwald             bitrate_index = i;
11725ce3497fSMatthias Ringwald         }
11735ce3497fSMatthias Ringwald     }
11745ce3497fSMatthias Ringwald 
11755ce3497fSMatthias Ringwald     event[pos++] = (uint8_t) layer;
11765ce3497fSMatthias Ringwald     event[pos++] = crc;
11775ce3497fSMatthias Ringwald     event[pos++] = (uint8_t) channel_mode;
11785ce3497fSMatthias Ringwald     event[pos++] = num_channels;
11795ce3497fSMatthias Ringwald     event[pos++] = mpf;
11805ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, sampling_frequency);
11815ce3497fSMatthias Ringwald     pos += 2;
11825ce3497fSMatthias Ringwald     event[pos++] = vbr;
11835ce3497fSMatthias Ringwald     event[pos++] = bitrate_index;
11845ce3497fSMatthias Ringwald 
1185924216b2SMatthias Ringwald     btstack_assert(pos == AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN);
1186186e1970SMatthias Ringwald 
1187186e1970SMatthias Ringwald     return pos;
11885ce3497fSMatthias Ringwald }
11895ce3497fSMatthias Ringwald 
1190186e1970SMatthias Ringwald static uint16_t
avdtp_signaling_setup_media_codec_mpec_aac_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)1191186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpec_aac_config_event(uint8_t *event, uint16_t size,
1192a905535cSMatthias Ringwald                                                         const avdtp_stream_endpoint_t *stream_endpoint,
1193186e1970SMatthias Ringwald                                                         uint16_t avdtp_cid, uint8_t reconfigure,
11945ce3497fSMatthias Ringwald                                                         const uint8_t *media_codec_information) {
11955ce3497fSMatthias Ringwald 
119624d5fe84SMilanka Ringwald     btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN);
1197186e1970SMatthias Ringwald 
11985ce3497fSMatthias Ringwald     uint8_t local_seid = avdtp_local_seid(stream_endpoint);
11995ce3497fSMatthias Ringwald     uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
12005ce3497fSMatthias Ringwald 
1201186e1970SMatthias Ringwald     uint16_t pos = 0;
12025ce3497fSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
1203924216b2SMatthias Ringwald     event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN - 2;
12045ce3497fSMatthias Ringwald 
12055ce3497fSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION;
12065ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
12075ce3497fSMatthias Ringwald     pos += 2;
12085ce3497fSMatthias Ringwald     event[pos++] = local_seid;
12095ce3497fSMatthias Ringwald     event[pos++] = remote_seid;
12105ce3497fSMatthias Ringwald     event[pos++] = reconfigure;
1211186e1970SMatthias Ringwald     event[pos++] =AVDTP_CODEC_MPEG_2_4_AAC;
12125ce3497fSMatthias Ringwald 
12131da18615SMilanka Ringwald     uint8_t  object_type_bitmap        =   media_codec_information[0] >> 1;
12141da18615SMilanka Ringwald     uint8_t  drc                       =   media_codec_information[0] & 0x01;
12155ce3497fSMatthias Ringwald     uint16_t sampling_frequency_bitmap =  (media_codec_information[1] << 4) | (media_codec_information[2] >> 4);
12161da18615SMilanka Ringwald     uint8_t  channels_bitmap           =   media_codec_information[2] & 0x0F;
12175ce3497fSMatthias Ringwald     uint8_t  vbr                       =   media_codec_information[3] >> 7;
12185ce3497fSMatthias Ringwald     uint32_t bit_rate                  = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5];
12195ce3497fSMatthias Ringwald 
12205ce3497fSMatthias Ringwald     uint8_t object_type = 0;
12211da18615SMilanka Ringwald     if (object_type_bitmap & 0x01){
12221da18615SMilanka Ringwald         object_type = AVDTP_AAC_MPEG4_HE_AAC_ELDv2;
12231da18615SMilanka Ringwald     } else if (object_type_bitmap & 0x02){
12241da18615SMilanka Ringwald         object_type = AVDTP_AAC_MPEG4_HE_AACv2;
12251da18615SMilanka Ringwald     } else if (object_type_bitmap & 0x04){
12261da18615SMilanka Ringwald         object_type = AVDTP_AAC_MPEG4_HE_AAC;
12271da18615SMilanka Ringwald     } else if (object_type_bitmap & 0x08){
12285ce3497fSMatthias Ringwald         object_type = AVDTP_AAC_MPEG4_SCALABLE;
12291da18615SMilanka Ringwald     } else if (object_type_bitmap & 0x10){
12301da18615SMilanka Ringwald         object_type = AVDTP_AAC_MPEG4_LTP;
12311da18615SMilanka Ringwald     } else if (object_type_bitmap & 0x20){
12321da18615SMilanka Ringwald         object_type = AVDTP_AAC_MPEG4_LC;
12331da18615SMilanka Ringwald     } else if (object_type_bitmap & 0x40){
12341da18615SMilanka Ringwald         object_type = AVDTP_AAC_MPEG2_LC;
12355ce3497fSMatthias Ringwald     }
12365ce3497fSMatthias Ringwald 
1237588a837aSMilanka Ringwald     uint32_t sampling_frequency = avdtp_config_get_sampling_frequency_from_table(sampling_frequency_bitmap, aac_sampling_frequency_table, aac_sampling_frequency_table_size);
12385ce3497fSMatthias Ringwald 
12395ce3497fSMatthias Ringwald     uint8_t num_channels = 0;
12401da18615SMilanka Ringwald     if (channels_bitmap & 0x08){
12415ce3497fSMatthias Ringwald         num_channels = 1;
12421da18615SMilanka Ringwald     } else if (channels_bitmap & 0x04){
12435ce3497fSMatthias Ringwald         num_channels = 2;
12441da18615SMilanka Ringwald     } else if (channels_bitmap & 0x02){
12451da18615SMilanka Ringwald         num_channels = 6;
12461da18615SMilanka Ringwald     } else if (channels_bitmap & 0x01){
12471da18615SMilanka Ringwald         num_channels = 8;
12485ce3497fSMatthias Ringwald     }
12495ce3497fSMatthias Ringwald 
12505ce3497fSMatthias Ringwald     event[pos++] = object_type;
12515ce3497fSMatthias Ringwald     little_endian_store_24(event, pos, sampling_frequency);
12525ce3497fSMatthias Ringwald     pos += 3;
12535ce3497fSMatthias Ringwald     event[pos++] = num_channels;
12545ce3497fSMatthias Ringwald     little_endian_store_24(event, pos, bit_rate);
12555ce3497fSMatthias Ringwald     pos += 3;
12565ce3497fSMatthias Ringwald     event[pos++] = vbr;
1257b7aa6976SMilanka Ringwald     event[pos++] = drc;
12585ce3497fSMatthias Ringwald 
1259924216b2SMatthias Ringwald     btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN == pos);
1260186e1970SMatthias Ringwald 
1261186e1970SMatthias Ringwald     return pos;
12625ce3497fSMatthias Ringwald }
12635ce3497fSMatthias Ringwald 
126424d5fe84SMilanka Ringwald static uint16_t
avdtp_signaling_setup_media_codec_mpegd_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)126524d5fe84SMilanka Ringwald avdtp_signaling_setup_media_codec_mpegd_config_event(uint8_t *event, uint16_t size,
126624d5fe84SMilanka Ringwald                                                         const avdtp_stream_endpoint_t *stream_endpoint,
126724d5fe84SMilanka Ringwald                                                         uint16_t avdtp_cid, uint8_t reconfigure,
126824d5fe84SMilanka Ringwald                                                         const uint8_t *media_codec_information) {
126924d5fe84SMilanka Ringwald 
127024d5fe84SMilanka Ringwald     btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN);
127124d5fe84SMilanka Ringwald 
127224d5fe84SMilanka Ringwald     uint8_t local_seid = avdtp_local_seid(stream_endpoint);
127324d5fe84SMilanka Ringwald     uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
127424d5fe84SMilanka Ringwald 
127524d5fe84SMilanka Ringwald     uint16_t pos = 0;
127624d5fe84SMilanka Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
127724d5fe84SMilanka Ringwald     event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN - 2;
127824d5fe84SMilanka Ringwald 
127924d5fe84SMilanka Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CONFIGURATION;
128024d5fe84SMilanka Ringwald 
128124d5fe84SMilanka Ringwald     little_endian_store_16(event, pos, avdtp_cid);
128224d5fe84SMilanka Ringwald     pos += 2;
128324d5fe84SMilanka Ringwald     event[pos++] = local_seid;
128424d5fe84SMilanka Ringwald     event[pos++] = remote_seid;
128524d5fe84SMilanka Ringwald     event[pos++] = reconfigure;
128624d5fe84SMilanka Ringwald     event[pos++] = AVDTP_CODEC_MPEG_D_USAC;
128724d5fe84SMilanka Ringwald 
128824d5fe84SMilanka Ringwald     uint8_t  object_type_bitmap        =   media_codec_information[0] >> 6;
128924d5fe84SMilanka Ringwald     uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) |
129024d5fe84SMilanka Ringwald                                          (media_codec_information[1] << 12) |
129124d5fe84SMilanka Ringwald                                          (media_codec_information[2] << 4) |
129224d5fe84SMilanka Ringwald                                          (media_codec_information[3] >> 4);
129324d5fe84SMilanka Ringwald 
129424d5fe84SMilanka Ringwald     uint8_t  channels_bitmap            = (media_codec_information[3] >> 2) & 0x03;
129524d5fe84SMilanka Ringwald     uint8_t  vbr                        = (media_codec_information[4] >> 7) & 0x01;
129624d5fe84SMilanka Ringwald 
129724d5fe84SMilanka Ringwald     uint32_t bit_rate                  = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5];
129824d5fe84SMilanka Ringwald 
129924d5fe84SMilanka Ringwald     uint8_t object_type = 0;
130024d5fe84SMilanka Ringwald     if (object_type_bitmap & 0x10){
130124d5fe84SMilanka Ringwald         object_type = AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC;
130224d5fe84SMilanka Ringwald     } else {
130324d5fe84SMilanka Ringwald         object_type = AVDTP_USAC_OBJECT_TYPE_RFU;
130424d5fe84SMilanka Ringwald     }
130524d5fe84SMilanka Ringwald 
1306588a837aSMilanka Ringwald     uint32_t sampling_frequency = avdtp_config_get_sampling_frequency_from_table(sampling_frequency_bitmap, usac_sampling_frequency_table, usac_sampling_frequency_table_size );
130724d5fe84SMilanka Ringwald 
130824d5fe84SMilanka Ringwald     uint8_t num_channels = 0;
130924d5fe84SMilanka Ringwald     if (channels_bitmap & 0x02){
131024d5fe84SMilanka Ringwald         num_channels = 1;
131124d5fe84SMilanka Ringwald     } else if (channels_bitmap & 0x01){
131224d5fe84SMilanka Ringwald         num_channels = 2;
131324d5fe84SMilanka Ringwald     }
131424d5fe84SMilanka Ringwald 
131524d5fe84SMilanka Ringwald     event[pos++] = object_type;
131624d5fe84SMilanka Ringwald     little_endian_store_24(event, pos, sampling_frequency);
131724d5fe84SMilanka Ringwald     pos += 3;
131824d5fe84SMilanka Ringwald     event[pos++] = num_channels;
131924d5fe84SMilanka Ringwald     event[pos++] = vbr;
132024d5fe84SMilanka Ringwald     little_endian_store_24(event, pos, bit_rate);
132124d5fe84SMilanka Ringwald     pos += 3;
132224d5fe84SMilanka Ringwald 
132324d5fe84SMilanka Ringwald     btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN == pos);
132424d5fe84SMilanka Ringwald 
132524d5fe84SMilanka Ringwald     return pos;
132624d5fe84SMilanka Ringwald }
132724d5fe84SMilanka Ringwald 
avdtp_signaling_setup_media_codec_atrac_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)1328186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_atrac_config_event(uint8_t *event, uint16_t size,
1329a905535cSMatthias Ringwald                                                                      const avdtp_stream_endpoint_t *stream_endpoint,
1330186e1970SMatthias Ringwald                                                                      uint16_t avdtp_cid, uint8_t reconfigure,
1331186e1970SMatthias Ringwald                                                                      const uint8_t *media_codec_information) {
1332924216b2SMatthias Ringwald     btstack_assert(size >= AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN);
1333186e1970SMatthias Ringwald 
13345ce3497fSMatthias Ringwald     uint8_t local_seid = avdtp_local_seid(stream_endpoint);
13355ce3497fSMatthias Ringwald     uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
13365ce3497fSMatthias Ringwald 
1337186e1970SMatthias Ringwald     uint16_t pos = 0;
13385ce3497fSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
1339924216b2SMatthias Ringwald     event[pos++] = AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN - 2;
13405ce3497fSMatthias Ringwald 
13415ce3497fSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION;
13425ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
13435ce3497fSMatthias Ringwald     pos += 2;
13445ce3497fSMatthias Ringwald     event[pos++] = local_seid;
13455ce3497fSMatthias Ringwald     event[pos++] = remote_seid;
13465ce3497fSMatthias Ringwald     event[pos++] = reconfigure;
1347186e1970SMatthias Ringwald     event[pos++] = AVDTP_CODEC_ATRAC_FAMILY;
13485ce3497fSMatthias Ringwald 
1349b5bbcbf4SMatthias Ringwald     avdtp_atrac_version_t  version     = (avdtp_atrac_version_t) (media_codec_information[0] >> 5);
13505ce3497fSMatthias Ringwald     uint8_t  channel_mode_bitmap       = (media_codec_information[0] >> 2) & 0x07;
13515ce3497fSMatthias Ringwald     uint16_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03;
13525ce3497fSMatthias Ringwald     uint8_t  vbr                       = (media_codec_information[1] >> 3) & 0x01;
13535ce3497fSMatthias Ringwald     uint16_t bit_rate_index_bitmap     = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3];
13545ce3497fSMatthias Ringwald     uint16_t maximum_sul               = (media_codec_information[4] << 8) | media_codec_information[5];
13555ce3497fSMatthias Ringwald 
13565ce3497fSMatthias Ringwald     uint8_t num_channels = 0;
13575ce3497fSMatthias Ringwald     avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
13585ce3497fSMatthias Ringwald     if (channel_mode_bitmap & 0x04){
13595ce3497fSMatthias Ringwald         num_channels = 1;
13605ce3497fSMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_MONO;
13615ce3497fSMatthias Ringwald     } else if (channel_mode_bitmap & 0x02){
13625ce3497fSMatthias Ringwald         num_channels = 2;
13635ce3497fSMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
13645ce3497fSMatthias Ringwald     } else if (channel_mode_bitmap & 0x01){
13655ce3497fSMatthias Ringwald         num_channels = 2;
13665ce3497fSMatthias Ringwald         channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
13675ce3497fSMatthias Ringwald     }
13685ce3497fSMatthias Ringwald 
13695ce3497fSMatthias Ringwald     uint16_t sampling_frequency = 0;
13705ce3497fSMatthias Ringwald     if (sampling_frequency_bitmap & 0x02){
13715ce3497fSMatthias Ringwald         sampling_frequency = 44100;
13725ce3497fSMatthias Ringwald     } else if (sampling_frequency_bitmap & 0x01){
13735ce3497fSMatthias Ringwald         sampling_frequency = 48000;
13745ce3497fSMatthias Ringwald     }
13755ce3497fSMatthias Ringwald 
13765ce3497fSMatthias Ringwald     // bit 0 = index 0x18, bit 19 = index 0
13775ce3497fSMatthias Ringwald     uint8_t bit_rate_index = 0;
13785ce3497fSMatthias Ringwald     uint8_t i;
13795ce3497fSMatthias Ringwald     for (i=0;i <= 19;i++){
13805ce3497fSMatthias Ringwald         if (bit_rate_index_bitmap & (1U << i)) {
13815ce3497fSMatthias Ringwald             bit_rate_index = 18 - i;
13825ce3497fSMatthias Ringwald         }
13835ce3497fSMatthias Ringwald     }
13845ce3497fSMatthias Ringwald 
13855ce3497fSMatthias Ringwald     event[pos++] = (uint8_t) version;
13865ce3497fSMatthias Ringwald     event[pos++] = (uint8_t) channel_mode;
13875ce3497fSMatthias Ringwald     event[pos++] = num_channels;
13885ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, sampling_frequency);
13895ce3497fSMatthias Ringwald     pos += 2;
13905ce3497fSMatthias Ringwald     event[pos++] = vbr;
13915ce3497fSMatthias Ringwald     event[pos++] = bit_rate_index;
13925ce3497fSMatthias Ringwald     little_endian_store_16(event, pos, maximum_sul);
13935ce3497fSMatthias Ringwald     pos += 2;
13945ce3497fSMatthias Ringwald 
1395924216b2SMatthias Ringwald     btstack_assert(pos == AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN);
1396186e1970SMatthias Ringwald     return pos;
13974b7d40bbSMatthias Ringwald }
13984b7d40bbSMatthias Ringwald 
avdtp_signaling_setup_media_codec_other_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const adtvp_media_codec_capabilities_t * media_codec)1399186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_other_config_event(uint8_t *event, uint16_t size,
1400a905535cSMatthias Ringwald                                                                      const avdtp_stream_endpoint_t *stream_endpoint,
1401186e1970SMatthias Ringwald                                                                      uint16_t avdtp_cid, uint8_t reconfigure,
1402186e1970SMatthias Ringwald                                                                      const adtvp_media_codec_capabilities_t *media_codec) {
1403924216b2SMatthias Ringwald     btstack_assert(size >= AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN);
1404186e1970SMatthias Ringwald 
14056c069ec9SMatthias Ringwald     uint8_t local_seid = avdtp_local_seid(stream_endpoint);
14066c069ec9SMatthias Ringwald     uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
14076c069ec9SMatthias Ringwald 
1408186e1970SMatthias Ringwald     uint16_t pos = 0;
14094b7d40bbSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
141073048ce6SMatthias Ringwald     pos++;  // set later
14114b7d40bbSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION;
14124b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
14134b7d40bbSMatthias Ringwald     pos += 2;
14144b7d40bbSMatthias Ringwald     event[pos++] = local_seid;
14154b7d40bbSMatthias Ringwald     event[pos++] = remote_seid;
14164b7d40bbSMatthias Ringwald     event[pos++] = reconfigure;
1417e8a431c1SMatthias Ringwald     event[pos++] = media_codec->media_type;
1418e8a431c1SMatthias Ringwald     little_endian_store_16(event, pos, media_codec->media_codec_type);
14194b7d40bbSMatthias Ringwald     pos += 2;
1420e8a431c1SMatthias Ringwald     little_endian_store_16(event, pos, media_codec->media_codec_information_len);
14214b7d40bbSMatthias Ringwald     pos += 2;
1422186e1970SMatthias Ringwald 
1423186e1970SMatthias Ringwald     btstack_assert(pos == 13);
1424186e1970SMatthias Ringwald 
1425924216b2SMatthias Ringwald     uint16_t media_codec_len = btstack_min(AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH, media_codec->media_codec_information_len);
1426e8a431c1SMatthias Ringwald     (void)memcpy(event + pos, media_codec->media_codec_information, media_codec_len);
142773048ce6SMatthias Ringwald     pos += media_codec_len;
142873048ce6SMatthias Ringwald     event[1] = pos - 2;
1429186e1970SMatthias Ringwald     return pos;
14304b7d40bbSMatthias Ringwald }
14314b7d40bbSMatthias Ringwald 
avdtp_signaling_emit_delay(uint16_t avdtp_cid,uint8_t local_seid,uint16_t delay)14324b7d40bbSMatthias Ringwald void avdtp_signaling_emit_delay(uint16_t avdtp_cid, uint8_t local_seid, uint16_t delay) {
14334b7d40bbSMatthias Ringwald     uint8_t event[8];
14344b7d40bbSMatthias Ringwald     int pos = 0;
14354b7d40bbSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
14364b7d40bbSMatthias Ringwald     event[pos++] = sizeof(event) - 2;
14374b7d40bbSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT;
14384b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
14394b7d40bbSMatthias Ringwald     pos += 2;
14404b7d40bbSMatthias Ringwald     event[pos++] = local_seid;
14414b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, delay);
14424b7d40bbSMatthias Ringwald     pos += 2;
14436e64e62bSMatthias Ringwald     avdtp_emit_source(event, pos);
14444b7d40bbSMatthias Ringwald }
14454b7d40bbSMatthias Ringwald 
avdtp_setup_media_codec_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const adtvp_media_codec_capabilities_t * media_codec)1446a905535cSMatthias Ringwald uint16_t avdtp_setup_media_codec_config_event(uint8_t *event, uint16_t size, const avdtp_stream_endpoint_t *stream_endpoint,
1447924216b2SMatthias Ringwald                                               uint16_t avdtp_cid, uint8_t reconfigure,
14482965b0e6SMatthias Ringwald                                               const adtvp_media_codec_capabilities_t * media_codec) {
14492965b0e6SMatthias Ringwald     switch (media_codec->media_codec_type){
1450924216b2SMatthias Ringwald         case AVDTP_CODEC_SBC:
1451924216b2SMatthias Ringwald             return avdtp_signaling_setup_media_codec_sbc_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14522965b0e6SMatthias Ringwald                                                                      media_codec->media_codec_information);
1453924216b2SMatthias Ringwald         case AVDTP_CODEC_MPEG_1_2_AUDIO:
1454924216b2SMatthias Ringwald             return avdtp_signaling_setup_media_codec_mpeg_audio_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14552965b0e6SMatthias Ringwald                                                                              media_codec->media_codec_information);
1456924216b2SMatthias Ringwald         case AVDTP_CODEC_MPEG_2_4_AAC:
1457924216b2SMatthias Ringwald             return avdtp_signaling_setup_media_codec_mpec_aac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14582965b0e6SMatthias Ringwald                                                                            media_codec->media_codec_information);
1459924216b2SMatthias Ringwald         case AVDTP_CODEC_ATRAC_FAMILY:
1460924216b2SMatthias Ringwald             return avdtp_signaling_setup_media_codec_atrac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14612965b0e6SMatthias Ringwald                                                                         media_codec->media_codec_information);
146224d5fe84SMilanka Ringwald         case AVDTP_CODEC_MPEG_D_USAC:
146324d5fe84SMilanka Ringwald             return avdtp_signaling_setup_media_codec_mpegd_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
146424d5fe84SMilanka Ringwald                                                                         media_codec->media_codec_information);
1465924216b2SMatthias Ringwald         default:
1466924216b2SMatthias Ringwald             return avdtp_signaling_setup_media_codec_other_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14672965b0e6SMatthias Ringwald                                                                         media_codec);
1468924216b2SMatthias Ringwald     }
1469924216b2SMatthias Ringwald }
1470924216b2SMatthias Ringwald 
avdtp_signaling_emit_configuration(avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,avdtp_capabilities_t * configuration,uint16_t configured_service_categories)14716c5b303cSMatthias Ringwald void avdtp_signaling_emit_configuration(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t reconfigure,
14724b7d40bbSMatthias Ringwald                                         avdtp_capabilities_t *configuration, uint16_t configured_service_categories) {
14734b7d40bbSMatthias Ringwald 
14744b7d40bbSMatthias Ringwald     if (get_bit16(configured_service_categories, AVDTP_MEDIA_CODEC)){
1475186e1970SMatthias Ringwald         uint16_t pos = 0;
1476186e1970SMatthias Ringwald         // assume MEDIA_CONFIG_OTHER_EVENT_LEN is larger than all other events
1477924216b2SMatthias Ringwald         uint8_t event[AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN];
1478924216b2SMatthias Ringwald         pos = avdtp_setup_media_codec_config_event(event, sizeof(event), stream_endpoint, avdtp_cid, reconfigure,
14792965b0e6SMatthias Ringwald                                                    &configuration->media_codec);
1480186e1970SMatthias Ringwald         btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
1481186e1970SMatthias Ringwald         (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
14824b7d40bbSMatthias Ringwald     }
14834b7d40bbSMatthias Ringwald }
14844b7d40bbSMatthias Ringwald 
avdtp_streaming_emit_connection_established(avdtp_stream_endpoint_t * stream_endpoint,uint8_t status)14854b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_established(avdtp_stream_endpoint_t *stream_endpoint, uint8_t status) {
14864b7d40bbSMatthias Ringwald     uint8_t event[14];
14874b7d40bbSMatthias Ringwald     int pos = 0;
14884b7d40bbSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
14894b7d40bbSMatthias Ringwald     event[pos++] = sizeof(event) - 2;
14904b7d40bbSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED;
14914b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid);
14924b7d40bbSMatthias Ringwald     pos += 2;
14934b7d40bbSMatthias Ringwald     reverse_bd_addr(stream_endpoint->connection->remote_addr, &event[pos]);
14944b7d40bbSMatthias Ringwald     pos += 6;
14954b7d40bbSMatthias Ringwald     event[pos++] = avdtp_local_seid(stream_endpoint);
14964b7d40bbSMatthias Ringwald     event[pos++] = avdtp_remote_seid(stream_endpoint);
14974b7d40bbSMatthias Ringwald     event[pos++] = status;
14984b7d40bbSMatthias Ringwald 
14994b7d40bbSMatthias Ringwald     btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
15006e64e62bSMatthias Ringwald     (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
15014b7d40bbSMatthias Ringwald }
15024b7d40bbSMatthias Ringwald 
avdtp_streaming_emit_connection_released(avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t local_seid)15034b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_released(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t local_seid) {
15044b7d40bbSMatthias Ringwald     uint8_t event[6];
15054b7d40bbSMatthias Ringwald     int pos = 0;
15064b7d40bbSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
15074b7d40bbSMatthias Ringwald     event[pos++] = sizeof(event) - 2;
15084b7d40bbSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED;
15094b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, avdtp_cid);
15104b7d40bbSMatthias Ringwald     pos += 2;
15114b7d40bbSMatthias Ringwald     event[pos++] = local_seid;
15124b7d40bbSMatthias Ringwald 
15134b7d40bbSMatthias Ringwald     btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
15146e64e62bSMatthias Ringwald     (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
15154b7d40bbSMatthias Ringwald }
15164b7d40bbSMatthias Ringwald 
avdtp_streaming_emit_can_send_media_packet_now(avdtp_stream_endpoint_t * stream_endpoint,uint16_t sequence_number)15174b7d40bbSMatthias Ringwald void avdtp_streaming_emit_can_send_media_packet_now(avdtp_stream_endpoint_t *stream_endpoint, uint16_t sequence_number) {
15184b7d40bbSMatthias Ringwald     uint8_t event[8];
15194b7d40bbSMatthias Ringwald     int pos = 0;
15204b7d40bbSMatthias Ringwald     event[pos++] = HCI_EVENT_AVDTP_META;
15214b7d40bbSMatthias Ringwald     event[pos++] = sizeof(event) - 2;
15224b7d40bbSMatthias Ringwald     event[pos++] = AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW;
15234b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid);
15244b7d40bbSMatthias Ringwald     pos += 2;
15254b7d40bbSMatthias Ringwald     event[pos++] = avdtp_local_seid(stream_endpoint);
15264b7d40bbSMatthias Ringwald     little_endian_store_16(event, pos, sequence_number);
15274b7d40bbSMatthias Ringwald     pos += 2;
15286e64e62bSMatthias Ringwald     event[1] = pos - 2;
15294b7d40bbSMatthias Ringwald 
15304b7d40bbSMatthias Ringwald     btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
15316e64e62bSMatthias Ringwald     (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
15324b7d40bbSMatthias Ringwald }
15334b7d40bbSMatthias Ringwald 
avdtp_request_can_send_now_acceptor(avdtp_connection_t * connection)1534d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_acceptor(avdtp_connection_t *connection) {
153523edb87eSMilanka Ringwald     if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1536d80ccd43SMatthias Ringwald     connection->wait_to_send_acceptor = true;
1537d80ccd43SMatthias Ringwald     l2cap_request_can_send_now_event(connection->l2cap_signaling_cid);
15389974aee0SMilanka Ringwald     return ERROR_CODE_SUCCESS;
15398ef7100fSMilanka Ringwald }
15409974aee0SMilanka Ringwald 
avdtp_request_can_send_now_initiator(avdtp_connection_t * connection)1541d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_initiator(avdtp_connection_t *connection) {
154223edb87eSMilanka Ringwald     if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1543d80ccd43SMatthias Ringwald     connection->wait_to_send_initiator = true;
1544d80ccd43SMatthias Ringwald     l2cap_request_can_send_now_event(connection->l2cap_signaling_cid);
15459974aee0SMilanka Ringwald     return ERROR_CODE_SUCCESS;
15468ef7100fSMilanka Ringwald }
15479974aee0SMilanka Ringwald 
avdtp_local_seid(const avdtp_stream_endpoint_t * stream_endpoint)1548a905535cSMatthias Ringwald uint8_t avdtp_local_seid(const avdtp_stream_endpoint_t * stream_endpoint){
15494ccacc40SMilanka Ringwald     if (!stream_endpoint) return 0;
15504ccacc40SMilanka Ringwald     return stream_endpoint->sep.seid;
15514ccacc40SMilanka Ringwald 
15524ccacc40SMilanka Ringwald }
15534ccacc40SMilanka Ringwald 
avdtp_remote_seid(const avdtp_stream_endpoint_t * stream_endpoint)1554a905535cSMatthias Ringwald uint8_t avdtp_remote_seid(const avdtp_stream_endpoint_t * stream_endpoint){
1555485c0a4cSMilanka Ringwald     if (!stream_endpoint) return AVDTP_INVALID_SEP_SEID;
1556485c0a4cSMilanka Ringwald     return stream_endpoint->remote_sep.seid;
15574ccacc40SMilanka Ringwald }
1558ef5ad9d6SMilanka Ringwald 
1559fdd788feSMatthias Ringwald // helper to set/get configuration
avdtp_config_sbc_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1560ea8aa208SMilanka Ringwald uint8_t avdtp_config_sbc_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz){
1561588a837aSMilanka 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);
1562ea8aa208SMilanka Ringwald      if (sampling_frequency_bitmap == 0){
1563ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1564ea8aa208SMilanka Ringwald     }
1565ea8aa208SMilanka Ringwald     config[0] = (config[0] & 0x0f) | (uint8_t)(sampling_frequency_bitmap << 4);
1566ea8aa208SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1567fdd788feSMatthias Ringwald }
1568fdd788feSMatthias Ringwald 
avdtp_config_sbc_store(uint8_t * config,const avdtp_configuration_sbc_t * configuration)1569ea8aa208SMilanka Ringwald uint8_t avdtp_config_sbc_store(uint8_t * config, const avdtp_configuration_sbc_t * configuration){
1570ea8aa208SMilanka Ringwald     if (configuration->channel_mode > AVDTP_CHANNEL_MODE_JOINT_STEREO){
1571ea8aa208SMilanka Ringwald        return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1572ea8aa208SMilanka Ringwald     }
1573ea8aa208SMilanka Ringwald     if (configuration->allocation_method > AVDTP_SBC_ALLOCATION_METHOD_SNR){
1574ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1575ea8aa208SMilanka Ringwald     }
1576858500b1SMilanka Ringwald 
1577858500b1SMilanka Ringwald     switch ((avdtp_sbc_block_length_t)configuration->block_length){
1578858500b1SMilanka Ringwald         case AVDTP_SBC_BLOCK_LENGTH_4:
1579858500b1SMilanka Ringwald         case AVDTP_SBC_BLOCK_LENGTH_8:
1580858500b1SMilanka Ringwald         case AVDTP_SBC_BLOCK_LENGTH_12:
1581858500b1SMilanka Ringwald         case AVDTP_SBC_BLOCK_LENGTH_16:
1582fdd788feSMatthias Ringwald             break;
1583fdd788feSMatthias Ringwald         default:
1584ea8aa208SMilanka Ringwald             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1585fdd788feSMatthias Ringwald     }
1586858500b1SMilanka Ringwald     switch ((avdtp_sbc_subbands_t)configuration->subbands){
1587858500b1SMilanka Ringwald         case AVDTP_SBC_SUBBANDS_4:
1588858500b1SMilanka Ringwald         case AVDTP_SBC_SUBBANDS_8:
1589ea8aa208SMilanka Ringwald             break;
1590ea8aa208SMilanka Ringwald         default:
1591ea8aa208SMilanka Ringwald             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1592ea8aa208SMilanka Ringwald     }
1593ea8aa208SMilanka Ringwald     if ((configuration->min_bitpool_value < 2) || (configuration->min_bitpool_value > 250) || (configuration->min_bitpool_value > configuration->max_bitpool_value)){
1594ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1595ea8aa208SMilanka Ringwald     }
1596ea8aa208SMilanka Ringwald     if ((configuration->max_bitpool_value < 2) || (configuration->max_bitpool_value > 250)){
1597ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1598ea8aa208SMilanka Ringwald     }
1599ea8aa208SMilanka Ringwald     config[0] = 1 << (3 - (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO));
16008691a66cSMatthias Ringwald     config[1] = (configuration->block_length << 4) | (configuration->subbands << 2) | configuration->allocation_method;
16018691a66cSMatthias Ringwald     config[2] = configuration->min_bitpool_value;
16028691a66cSMatthias Ringwald     config[3] = configuration->max_bitpool_value;
1603ea8aa208SMilanka Ringwald     return avdtp_config_sbc_set_sampling_frequency(config, configuration->sampling_frequency);
1604fdd788feSMatthias Ringwald }
1605fdd788feSMatthias Ringwald 
avdtp_config_mpeg_audio_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1606ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_audio_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) {
1607588a837aSMilanka 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);
1608ea8aa208SMilanka Ringwald     if (sampling_frequency_bitmap == 0){
1609ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1610ea8aa208SMilanka Ringwald     }
1611ea8aa208SMilanka Ringwald     config[1] = (config[1] & 0xE0) | sampling_frequency_bitmap;
1612ea8aa208SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1613fdd788feSMatthias Ringwald }
1614fdd788feSMatthias Ringwald 
avdtp_config_mpeg_audio_store(uint8_t * config,const avdtp_configuration_mpeg_audio_t * configuration)1615ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_audio_store(uint8_t * config, const avdtp_configuration_mpeg_audio_t * configuration){
1616ea8aa208SMilanka Ringwald     if (configuration->layer > AVDTP_MPEG_LAYER_3){
1617ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1618ea8aa208SMilanka Ringwald     }
1619ea8aa208SMilanka Ringwald     if (configuration->channel_mode > AVDTP_CHANNEL_MODE_JOINT_STEREO){
1620ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1621ea8aa208SMilanka Ringwald     }
1622ea8aa208SMilanka Ringwald     uint16_t bit_rate_mask = 1 << configuration->bit_rate_index;
1623ea8aa208SMilanka Ringwald     if (bit_rate_mask == 0){
1624ea8aa208SMilanka Ringwald         return  ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1625ea8aa208SMilanka Ringwald     }
1626ea8aa208SMilanka Ringwald 
16278691a66cSMatthias Ringwald     config[0] = (1 << (7 - (configuration->layer - AVDTP_MPEG_LAYER_1))) | ((configuration->crc & 0x01) << 4) | (1 << (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO));
16288691a66cSMatthias Ringwald     config[1] = ((configuration->media_payload_format & 0x01) << 6) ;
16291da18615SMilanka Ringwald     config[2] = ((configuration->vbr & 0x01) << 7) | ((bit_rate_mask >> 7) & 0x3f);
1630fdd788feSMatthias Ringwald     config[3] = bit_rate_mask & 0xff;
1631ea8aa208SMilanka Ringwald     return avdtp_config_mpeg_audio_set_sampling_frequency(config, configuration->sampling_frequency);
1632fdd788feSMatthias Ringwald }
1633fdd788feSMatthias Ringwald 
avdtp_config_mpeg_aac_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1634ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) {
1635588a837aSMilanka 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);
1636ea8aa208SMilanka Ringwald     if (sampling_frequency_bitmap == 0){
1637ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1638ea8aa208SMilanka Ringwald     }
1639ea8aa208SMilanka Ringwald 
1640fdd788feSMatthias Ringwald     config[1] = sampling_frequency_bitmap >> 4;
1641fdd788feSMatthias Ringwald     config[2] = ((sampling_frequency_bitmap & 0x0f) << 4) | (config[2] & 0x0f);
1642ea8aa208SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1643fdd788feSMatthias Ringwald }
1644fdd788feSMatthias Ringwald 
avdtp_config_mpeg_aac_store(uint8_t * config,const avdtp_configuration_mpeg_aac_t * configuration)1645c83b8b89SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_store(uint8_t * config, const avdtp_configuration_mpeg_aac_t * configuration) {
16460737c3bfSMilanka Ringwald     config[0] = (1 << (7 -(configuration->object_type - AVDTP_AAC_MPEG2_LC))) | (configuration->drc?1u:0u);
1647fdd788feSMatthias Ringwald     uint8_t channels_bitmap = 0;
16488691a66cSMatthias Ringwald     switch (configuration->channels){
1649fdd788feSMatthias Ringwald         case 1:
16500737c3bfSMilanka Ringwald             channels_bitmap = 0x08;
1651fdd788feSMatthias Ringwald             break;
1652fdd788feSMatthias Ringwald         case 2:
16530737c3bfSMilanka Ringwald             channels_bitmap = 0x04;
16540737c3bfSMilanka Ringwald             break;
16550737c3bfSMilanka Ringwald         case 6:
16560737c3bfSMilanka Ringwald             channels_bitmap = 0x02;
16570737c3bfSMilanka Ringwald             break;
16580737c3bfSMilanka Ringwald         case 8:
1659fdd788feSMatthias Ringwald             channels_bitmap = 0x01;
1660fdd788feSMatthias Ringwald             break;
1661fdd788feSMatthias Ringwald         default:
1662c83b8b89SMilanka Ringwald            return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1663fdd788feSMatthias Ringwald     }
1664c83b8b89SMilanka Ringwald     config[2] = channels_bitmap;
16658691a66cSMatthias Ringwald     config[3] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f);
16668691a66cSMatthias Ringwald     config[4] = (configuration->bit_rate >> 8) & 0xff;
16678691a66cSMatthias Ringwald     config[5] =  configuration->bit_rate & 0xff;
1668ea8aa208SMilanka Ringwald     return avdtp_config_mpeg_aac_set_sampling_frequency(config, configuration->sampling_frequency);
1669ea8aa208SMilanka Ringwald }
1670ea8aa208SMilanka Ringwald 
avdtp_config_atrac_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1671ea8aa208SMilanka Ringwald uint8_t avdtp_config_atrac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) {
1672588a837aSMilanka 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);
1673ea8aa208SMilanka Ringwald     if (sampling_frequency_bitmap == 0){
1674ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1675ea8aa208SMilanka Ringwald     }
1676ea8aa208SMilanka Ringwald 
1677ea8aa208SMilanka Ringwald     config[1] = (config[1] & 0xCF) | (uint8_t)(sampling_frequency_bitmap << 4);
1678c83b8b89SMilanka Ringwald     return ERROR_CODE_SUCCESS;
1679fdd788feSMatthias Ringwald }
1680fdd788feSMatthias Ringwald 
avdtp_config_atrac_store(uint8_t * config,const avdtp_configuration_atrac_t * configuration)1681ea8aa208SMilanka Ringwald uint8_t avdtp_config_atrac_store(uint8_t * config, const avdtp_configuration_atrac_t * configuration){
1682a3868652SMatthias Ringwald     uint8_t channel_mode_bitmap = 0;
16838691a66cSMatthias Ringwald     switch (configuration->channel_mode){
1684fdd788feSMatthias Ringwald         case AVDTP_CHANNEL_MODE_MONO:
1685a3868652SMatthias Ringwald             channel_mode_bitmap = 4;
1686fdd788feSMatthias Ringwald             break;
1687fdd788feSMatthias Ringwald         case AVDTP_CHANNEL_MODE_DUAL_CHANNEL:
1688a3868652SMatthias Ringwald             channel_mode_bitmap = 2;
1689fdd788feSMatthias Ringwald             break;
1690fdd788feSMatthias Ringwald         case AVDTP_CHANNEL_MODE_JOINT_STEREO:
1691a3868652SMatthias Ringwald             channel_mode_bitmap = 1;
1692fdd788feSMatthias Ringwald             break;
1693fdd788feSMatthias Ringwald         default:
1694ea8aa208SMilanka Ringwald             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1695fdd788feSMatthias Ringwald     }
16968691a66cSMatthias Ringwald     config[0] = ((configuration->version - AVDTP_ATRAC_VERSION_1 + 1) << 5) | (channel_mode_bitmap << 2);
16978691a66cSMatthias Ringwald     uint32_t bit_rate_bitmap = 1 << (0x18 - configuration->bit_rate_index);
16988691a66cSMatthias Ringwald     config[1] = ((configuration->vbr & 0x01) << 3) | ((bit_rate_bitmap >> 16) & 0x07);
1699fdd788feSMatthias Ringwald     config[2] = (bit_rate_bitmap >> 8) & 0xff;
1700fdd788feSMatthias Ringwald     config[3] = bit_rate_bitmap & 0xff;
17018691a66cSMatthias Ringwald     config[4] = configuration->maximum_sul >> 8;
17028691a66cSMatthias Ringwald     config[5] = configuration->maximum_sul & 0xff;
1703fdd788feSMatthias Ringwald     config[6] = 0;
1704ea8aa208SMilanka Ringwald     return avdtp_config_atrac_set_sampling_frequency(config, configuration->sampling_frequency);
1705fdd788feSMatthias Ringwald }
170624d5fe84SMilanka Ringwald 
avdtp_config_mpegd_usac_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1707ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpegd_usac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) {
1708588a837aSMilanka 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);
1709ea8aa208SMilanka Ringwald     if (sampling_frequency_bitmap == 0){
1710ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1711ea8aa208SMilanka Ringwald     }
1712ea8aa208SMilanka Ringwald     config[0] = (config[0] & 0xC0) | (uint8_t)(sampling_frequency_bitmap >> 20);
1713ea8aa208SMilanka Ringwald     config[1] = (uint8_t) (sampling_frequency_bitmap >> 12);
1714ea8aa208SMilanka Ringwald     config[2] = (uint8_t) (sampling_frequency_bitmap >> 4);
171524d5fe84SMilanka Ringwald     config[3] = (sampling_frequency_bitmap & 0x0f) << 4;
1716ea8aa208SMilanka Ringwald     return ERROR_CODE_SUCCESS;
171724d5fe84SMilanka Ringwald }
171824d5fe84SMilanka Ringwald 
avdtp_config_mpegd_usac_store(uint8_t * config,const avdtp_configuration_mpegd_usac_t * configuration)1719ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpegd_usac_store(uint8_t * config, const avdtp_configuration_mpegd_usac_t * configuration) {
1720ea8aa208SMilanka Ringwald     if (configuration->object_type != AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC){
1721ea8aa208SMilanka Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1722ea8aa208SMilanka Ringwald     }
1723ea8aa208SMilanka Ringwald     config[0] = 0x80;
172424d5fe84SMilanka Ringwald 
172524d5fe84SMilanka Ringwald     uint8_t channels_bitmap = 0;
172624d5fe84SMilanka Ringwald     switch (configuration->channels){
172724d5fe84SMilanka Ringwald         case 1:
172824d5fe84SMilanka Ringwald             channels_bitmap = 0x08;
172924d5fe84SMilanka Ringwald             break;
173024d5fe84SMilanka Ringwald         case 2:
173124d5fe84SMilanka Ringwald             channels_bitmap = 0x04;
173224d5fe84SMilanka Ringwald             break;
173324d5fe84SMilanka Ringwald         default:
1734ea8aa208SMilanka Ringwald             return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
173524d5fe84SMilanka Ringwald     }
173624d5fe84SMilanka Ringwald     config[3] = config[3] | channels_bitmap;
173724d5fe84SMilanka Ringwald     config[4] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f);
173824d5fe84SMilanka Ringwald     config[5] = (configuration->bit_rate >> 8) & 0xff;
173924d5fe84SMilanka Ringwald     config[6] =  configuration->bit_rate & 0xff;
1740ea8aa208SMilanka Ringwald     return avdtp_config_mpegd_usac_set_sampling_frequency(config, configuration->sampling_frequency);
174124d5fe84SMilanka Ringwald }