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