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