18ef7100fSMilanka Ringwald /*
28ef7100fSMilanka Ringwald * Copyright (C) 2016 BlueKitchen GmbH
38ef7100fSMilanka Ringwald *
48ef7100fSMilanka Ringwald * Redistribution and use in source and binary forms, with or without
58ef7100fSMilanka Ringwald * modification, are permitted provided that the following conditions
68ef7100fSMilanka Ringwald * are met:
78ef7100fSMilanka Ringwald *
88ef7100fSMilanka Ringwald * 1. Redistributions of source code must retain the above copyright
98ef7100fSMilanka Ringwald * notice, this list of conditions and the following disclaimer.
108ef7100fSMilanka Ringwald * 2. Redistributions in binary form must reproduce the above copyright
118ef7100fSMilanka Ringwald * notice, this list of conditions and the following disclaimer in the
128ef7100fSMilanka Ringwald * documentation and/or other materials provided with the distribution.
138ef7100fSMilanka Ringwald * 3. Neither the name of the copyright holders nor the names of
148ef7100fSMilanka Ringwald * contributors may be used to endorse or promote products derived
158ef7100fSMilanka Ringwald * from this software without specific prior written permission.
168ef7100fSMilanka Ringwald * 4. Any redistribution, use, or modification is done solely for
178ef7100fSMilanka Ringwald * personal benefit and not for any commercial purpose or for
188ef7100fSMilanka Ringwald * monetary gain.
198ef7100fSMilanka Ringwald *
208ef7100fSMilanka Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
218ef7100fSMilanka Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
228ef7100fSMilanka Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
258ef7100fSMilanka Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
268ef7100fSMilanka Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
278ef7100fSMilanka Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
288ef7100fSMilanka Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
298ef7100fSMilanka Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
308ef7100fSMilanka Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
318ef7100fSMilanka Ringwald * SUCH DAMAGE.
328ef7100fSMilanka Ringwald *
338ef7100fSMilanka Ringwald * Please inquire about commercial licensing options at
348ef7100fSMilanka Ringwald * [email protected]
358ef7100fSMilanka Ringwald *
368ef7100fSMilanka Ringwald */
378ef7100fSMilanka Ringwald
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "avdtp_util.c"
39ab2c6ae4SMatthias Ringwald
408ef7100fSMilanka Ringwald #include <stdint.h>
418ef7100fSMilanka Ringwald #include <string.h>
428ef7100fSMilanka Ringwald
437c76cd61SMatthias Ringwald #include "classic/avdtp.h"
447c76cd61SMatthias Ringwald #include "classic/avdtp_util.h"
457c76cd61SMatthias Ringwald
467c76cd61SMatthias Ringwald #include "btstack_debug.h"
477c76cd61SMatthias Ringwald #include "l2cap.h"
488ef7100fSMilanka Ringwald
49f9a5036aSMatthias Ringwald /*
50f9a5036aSMatthias Ringwald
51f9a5036aSMatthias Ringwald List of AVDTP_SUBEVENTs sorted by packet handler
52f9a5036aSMatthias Ringwald
53f9a5036aSMatthias Ringwald
54f9a5036aSMatthias Ringwald Sink + Source:
55f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED
56f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED
57f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_SEP_FOUND
58f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_ACCEPT
59f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_REJECT
60f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT
61f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY
62f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY
63f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY
64f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY
65f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY
66f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY
67f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY
68f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY
69f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY
70f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE
71f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE
72f9a5036aSMatthias Ringwald
73f9a5036aSMatthias Ringwald Source:
74f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT
75f9a5036aSMatthias Ringwald
76f9a5036aSMatthias Ringwald Sink or Source based on SEP Type:
77f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED
78f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED
79f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW
80f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION
81f9a5036aSMatthias Ringwald - AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION
82f9a5036aSMatthias Ringwald
83f9a5036aSMatthias Ringwald */
84f9a5036aSMatthias Ringwald
85ee230fc4SMilanka Ringwald static const char * avdtp_si_name[] = {
86ee230fc4SMilanka Ringwald "ERROR",
87ee230fc4SMilanka Ringwald "AVDTP_SI_DISCOVER",
88ee230fc4SMilanka Ringwald "AVDTP_SI_GET_CAPABILITIES",
89ee230fc4SMilanka Ringwald "AVDTP_SI_SET_CONFIGURATION",
90ee230fc4SMilanka Ringwald "AVDTP_SI_GET_CONFIGURATION",
91ee230fc4SMilanka Ringwald "AVDTP_SI_RECONFIGURE",
92ee230fc4SMilanka Ringwald "AVDTP_SI_OPEN",
93ee230fc4SMilanka Ringwald "AVDTP_SI_START",
94ee230fc4SMilanka Ringwald "AVDTP_SI_CLOSE",
95ee230fc4SMilanka Ringwald "AVDTP_SI_SUSPEND",
96ee230fc4SMilanka Ringwald "AVDTP_SI_ABORT",
97ee230fc4SMilanka Ringwald "AVDTP_SI_SECURITY_CONTROL",
98ee230fc4SMilanka Ringwald "AVDTP_SI_GET_ALL_CAPABILITIES",
99ee230fc4SMilanka Ringwald "AVDTP_SI_DELAY_REPORT"
100ee230fc4SMilanka Ringwald };
101588a837aSMilanka Ringwald
avdtp_si2str(uint16_t index)102ee230fc4SMilanka Ringwald const char * avdtp_si2str(uint16_t index){
103c1e2cdaaSaroldxd if ((index <= 0) || (index >= sizeof(avdtp_si_name)/sizeof(avdtp_si_name[0]) )) return avdtp_si_name[0];
104ee230fc4SMilanka Ringwald return avdtp_si_name[index];
105ee230fc4SMilanka Ringwald }
106ee230fc4SMilanka Ringwald
107588a837aSMilanka Ringwald
108588a837aSMilanka Ringwald static const uint32_t usac_sampling_frequency_table[] = {
109588a837aSMilanka Ringwald 96000, 88200, 76800, 70560,
110588a837aSMilanka Ringwald 64000, 58800, 48000, 44100, 38400, 35280, 32000, 29400,
111588a837aSMilanka Ringwald 24000, 22050, 19200, 17640, 16000, 14700, 12800, 12000,
112588a837aSMilanka Ringwald 11760, 11025, 9600, 8820, 8000, 7350
113588a837aSMilanka Ringwald };
114588a837aSMilanka Ringwald static const uint8_t usac_sampling_frequency_table_size = sizeof(usac_sampling_frequency_table)/sizeof(uint32_t);
115588a837aSMilanka Ringwald
116588a837aSMilanka Ringwald static const uint32_t mpeg_sampling_frequency_table[] = {
117588a837aSMilanka Ringwald 48000, 44100, 32000, 24000, 22040, 16000
118588a837aSMilanka Ringwald };
119588a837aSMilanka Ringwald static const uint8_t mpeg_sampling_frequency_table_size = sizeof(mpeg_sampling_frequency_table)/sizeof(uint32_t);
120588a837aSMilanka Ringwald
121588a837aSMilanka Ringwald static const uint32_t sbc_sampling_frequency_table[] = {
122588a837aSMilanka Ringwald 48000, 44100, 32000, 16000
123588a837aSMilanka Ringwald };
124588a837aSMilanka Ringwald static const uint8_t sbc_sampling_frequency_table_size = sizeof(sbc_sampling_frequency_table)/sizeof(uint32_t);
125588a837aSMilanka Ringwald
126588a837aSMilanka Ringwald static const uint32_t atrac_sampling_frequency_table[] = {
127588a837aSMilanka Ringwald 48000, 44100
128588a837aSMilanka Ringwald };
129588a837aSMilanka Ringwald static const uint8_t atrac_sampling_frequency_table_size = sizeof(atrac_sampling_frequency_table)/sizeof(uint32_t);
130588a837aSMilanka Ringwald
131588a837aSMilanka Ringwald static const uint32_t aac_sampling_frequency_table[] = {
132588a837aSMilanka Ringwald 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
133588a837aSMilanka Ringwald };
134588a837aSMilanka Ringwald static const uint8_t aac_sampling_frequency_table_size = sizeof(aac_sampling_frequency_table)/sizeof(uint32_t);
135588a837aSMilanka Ringwald
avdtp_config_get_sampling_frequency_bitmap_from_table(uint16_t sampling_frequency_hz,const uint32_t * table,uint8_t table_size)136588a837aSMilanka Ringwald static uint32_t avdtp_config_get_sampling_frequency_bitmap_from_table(uint16_t sampling_frequency_hz, const uint32_t * table, uint8_t table_size) {
137588a837aSMilanka Ringwald uint8_t i;
138588a837aSMilanka Ringwald for (i = 0; i < table_size; i++){
139588a837aSMilanka Ringwald if (sampling_frequency_hz == table[i]){
140588a837aSMilanka Ringwald return 1 << i;
141588a837aSMilanka Ringwald }
142588a837aSMilanka Ringwald }
143588a837aSMilanka Ringwald return 0;
144588a837aSMilanka Ringwald }
145588a837aSMilanka Ringwald
avdtp_config_get_sampling_frequency_from_table(uint16_t sampling_frequency_bitmap,const uint32_t * table,uint8_t table_size)146588a837aSMilanka Ringwald static uint32_t avdtp_config_get_sampling_frequency_from_table(uint16_t sampling_frequency_bitmap, const uint32_t * table, uint8_t table_size) {
147588a837aSMilanka Ringwald uint8_t i;
148588a837aSMilanka Ringwald for (i = 0; i < table_size; i++){
149588a837aSMilanka Ringwald if (sampling_frequency_bitmap & (1U << i)) {
150588a837aSMilanka Ringwald return table[i];
151588a837aSMilanka Ringwald }
152588a837aSMilanka Ringwald }
153588a837aSMilanka Ringwald return 0;
154588a837aSMilanka Ringwald }
155588a837aSMilanka Ringwald
156588a837aSMilanka Ringwald
avdtp_reset_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint)157485c0a4cSMilanka Ringwald void avdtp_reset_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint){
158485c0a4cSMilanka Ringwald stream_endpoint->media_con_handle = 0;
159485c0a4cSMilanka Ringwald stream_endpoint->l2cap_media_cid = 0;
160485c0a4cSMilanka Ringwald stream_endpoint->l2cap_reporting_cid = 0;
161485c0a4cSMilanka Ringwald stream_endpoint->l2cap_recovery_cid = 0;
162485c0a4cSMilanka Ringwald
163747ec646SMilanka Ringwald stream_endpoint->state = AVDTP_STREAM_ENDPOINT_IDLE;
164747ec646SMilanka Ringwald stream_endpoint->acceptor_config_state = AVDTP_ACCEPTOR_STREAM_CONFIG_IDLE;
165747ec646SMilanka Ringwald stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE;
166485c0a4cSMilanka Ringwald
167b3b67de4SMilanka Ringwald stream_endpoint->connection = NULL;
168b3b67de4SMilanka Ringwald
169747ec646SMilanka Ringwald stream_endpoint->sep.in_use = 0;
170485c0a4cSMilanka Ringwald memset(&stream_endpoint->remote_sep, 0, sizeof(avdtp_sep_t));
171485c0a4cSMilanka Ringwald
172485c0a4cSMilanka Ringwald stream_endpoint->remote_capabilities_bitmap = 0;
173b3b67de4SMilanka Ringwald memset(&stream_endpoint->remote_capabilities, 0, sizeof(avdtp_capabilities_t));
174485c0a4cSMilanka Ringwald stream_endpoint->remote_configuration_bitmap = 0;
175b3b67de4SMilanka Ringwald memset(&stream_endpoint->remote_configuration, 0, sizeof(avdtp_capabilities_t));
176b3b67de4SMilanka Ringwald
17782767773SMatthias Ringwald // temporary SBC config used by A2DP Source
178ec9b5b0fSMatthias Ringwald memset(stream_endpoint->media_codec_info, 0, 8);
179485c0a4cSMilanka Ringwald
180485c0a4cSMilanka Ringwald stream_endpoint->media_disconnect = 0;
181485c0a4cSMilanka Ringwald stream_endpoint->media_connect = 0;
182485c0a4cSMilanka Ringwald stream_endpoint->start_stream = 0;
183fa4419dbSMilanka Ringwald stream_endpoint->close_stream = 0;
184d0676819SMatthias Ringwald stream_endpoint->request_can_send_now = false;
185485c0a4cSMilanka Ringwald stream_endpoint->abort_stream = 0;
186485c0a4cSMilanka Ringwald stream_endpoint->suspend_stream = 0;
187485c0a4cSMilanka Ringwald stream_endpoint->sequence_number = 0;
188747ec646SMilanka Ringwald }
189747ec646SMilanka Ringwald
get_bit16(uint16_t bitmap,int position)1908ef7100fSMilanka Ringwald int get_bit16(uint16_t bitmap, int position){
1918ef7100fSMilanka Ringwald return (bitmap >> position) & 1;
1928ef7100fSMilanka Ringwald }
1938ef7100fSMilanka Ringwald
store_bit16(uint16_t bitmap,int position,uint8_t value)194ea6072afSMilanka Ringwald uint16_t store_bit16(uint16_t bitmap, int position, uint8_t value){
1958ef7100fSMilanka Ringwald if (value){
1968ef7100fSMilanka Ringwald bitmap |= 1 << position;
1978ef7100fSMilanka Ringwald } else {
1988ef7100fSMilanka Ringwald bitmap &= ~ (1 << position);
1998ef7100fSMilanka Ringwald }
2008ef7100fSMilanka Ringwald return bitmap;
2018ef7100fSMilanka Ringwald }
2028ef7100fSMilanka Ringwald
avdtp_get_signaling_message_type(uint8_t * packet)203335dba6aSMatthias Ringwald avdtp_message_type_t avdtp_get_signaling_message_type(uint8_t * packet){
204c1c40ea1SMatthias Ringwald return (avdtp_message_type_t) (packet[0] & 0x03);
205c1c40ea1SMatthias Ringwald }
206c1c40ea1SMatthias Ringwald
2073d79ed3bSMatthias Ringwald // returns 0 if header incomplete
avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header,uint8_t * packet,uint16_t size)2088ef7100fSMilanka Ringwald int avdtp_read_signaling_header(avdtp_signaling_packet_t * signaling_header, uint8_t * packet, uint16_t size){
2098ef7100fSMilanka Ringwald int pos = 0;
2103d79ed3bSMatthias Ringwald if (size < 2) return 0;
2118ef7100fSMilanka Ringwald signaling_header->transaction_label = packet[pos] >> 4;
2128ef7100fSMilanka Ringwald signaling_header->packet_type = (avdtp_packet_type_t)((packet[pos] >> 2) & 0x03);
2138ef7100fSMilanka Ringwald signaling_header->message_type = (avdtp_message_type_t) (packet[pos] & 0x03);
2148ef7100fSMilanka Ringwald pos++;
2158ef7100fSMilanka Ringwald memset(signaling_header->command, 0, sizeof(signaling_header->command));
2168ef7100fSMilanka Ringwald switch (signaling_header->packet_type){
2178ef7100fSMilanka Ringwald case AVDTP_SINGLE_PACKET:
2188ef7100fSMilanka Ringwald signaling_header->num_packets = 0;
2198ef7100fSMilanka Ringwald signaling_header->offset = 0;
2208ef7100fSMilanka Ringwald signaling_header->size = 0;
2218ef7100fSMilanka Ringwald break;
2228ef7100fSMilanka Ringwald case AVDTP_END_PACKET:
2238ef7100fSMilanka Ringwald signaling_header->num_packets = 0;
2248ef7100fSMilanka Ringwald break;
2258ef7100fSMilanka Ringwald case AVDTP_START_PACKET:
2268ef7100fSMilanka Ringwald signaling_header->num_packets = packet[pos++];
2273d79ed3bSMatthias Ringwald if (pos < 3) return 0;
2288ef7100fSMilanka Ringwald signaling_header->size = 0;
2298ef7100fSMilanka Ringwald signaling_header->offset = 0;
2308ef7100fSMilanka Ringwald break;
2318ef7100fSMilanka Ringwald case AVDTP_CONTINUE_PACKET:
2328ef7100fSMilanka Ringwald if (signaling_header->num_packets <= 0) {
2338587e32cSMilanka Ringwald log_info(" ERROR: wrong num fragmented packets\n");
2348ef7100fSMilanka Ringwald break;
2358ef7100fSMilanka Ringwald }
2368ef7100fSMilanka Ringwald signaling_header->num_packets--;
2378ef7100fSMilanka Ringwald break;
2387bbeb3adSMilanka Ringwald default:
2397bbeb3adSMilanka Ringwald btstack_assert(false);
2407bbeb3adSMilanka Ringwald break;
2418ef7100fSMilanka Ringwald }
242b0920f25SMilanka Ringwald signaling_header->signal_identifier = (avdtp_signal_identifier_t)(packet[pos++] & 0x3f);
2438ef7100fSMilanka Ringwald return pos;
2448ef7100fSMilanka Ringwald }
2458ef7100fSMilanka Ringwald
avdtp_is_basic_capability(int service_category)24650d5c6caSMatthias Ringwald static bool avdtp_is_basic_capability(int service_category){
24750d5c6caSMatthias Ringwald return (AVDTP_MEDIA_TRANSPORT <= service_category) && (service_category <= AVDTP_MEDIA_CODEC);
24850d5c6caSMatthias Ringwald }
24950d5c6caSMatthias Ringwald
avdtp_pack_service_capabilities(uint8_t * buffer,int size,avdtp_capabilities_t caps,avdtp_service_category_t category)25050d5c6caSMatthias Ringwald int avdtp_pack_service_capabilities(uint8_t *buffer, int size, avdtp_capabilities_t caps, avdtp_service_category_t category) {
2518ef7100fSMilanka Ringwald UNUSED(size);
2528ef7100fSMilanka Ringwald
2538ef7100fSMilanka Ringwald int i;
2548ef7100fSMilanka Ringwald // pos = 0 reserved for length
2558ef7100fSMilanka Ringwald int pos = 1;
2568ef7100fSMilanka Ringwald switch(category){
2578ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT:
2588ef7100fSMilanka Ringwald case AVDTP_REPORTING:
2598ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING:
2608ef7100fSMilanka Ringwald break;
2618ef7100fSMilanka Ringwald case AVDTP_RECOVERY:
2628ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.recovery_type; // 0x01=RFC2733
2638ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.maximum_recovery_window_size;
2648ef7100fSMilanka Ringwald buffer[pos++] = caps.recovery.maximum_number_media_packets;
2658ef7100fSMilanka Ringwald break;
2668ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION:
2678ef7100fSMilanka Ringwald buffer[pos++] = caps.content_protection.cp_type_value_len + 2;
2688ef7100fSMilanka Ringwald big_endian_store_16(buffer, pos, caps.content_protection.cp_type);
2698ef7100fSMilanka Ringwald pos += 2;
2706535961aSMatthias Ringwald (void)memcpy(buffer + pos, caps.content_protection.cp_type_value,
2716535961aSMatthias Ringwald caps.content_protection.cp_type_value_len);
27274b2411bSMilanka Ringwald pos += caps.content_protection.cp_type_value_len;
2738ef7100fSMilanka Ringwald break;
2748ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION:
2758ef7100fSMilanka Ringwald buffer[pos++] = (caps.header_compression.back_ch << 7) | (caps.header_compression.media << 6) | (caps.header_compression.recovery << 5);
2768ef7100fSMilanka Ringwald break;
2778ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING:
2788ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.fragmentation << 7;
2798ef7100fSMilanka Ringwald for (i=0; i<caps.multiplexing_mode.transport_identifiers_num; i++){
2808ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.transport_session_identifiers[i] << 7;
2818ef7100fSMilanka Ringwald buffer[pos++] = caps.multiplexing_mode.tcid[i] << 7;
2828ef7100fSMilanka Ringwald // media, reporting. recovery
2838ef7100fSMilanka Ringwald }
2848ef7100fSMilanka Ringwald break;
2858ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC:
2868ef7100fSMilanka Ringwald buffer[pos++] = ((uint8_t)caps.media_codec.media_type) << 4;
2878ef7100fSMilanka Ringwald buffer[pos++] = (uint8_t)caps.media_codec.media_codec_type;
2888ef7100fSMilanka Ringwald for (i = 0; i<caps.media_codec.media_codec_information_len; i++){
2898ef7100fSMilanka Ringwald buffer[pos++] = caps.media_codec.media_codec_information[i];
2908ef7100fSMilanka Ringwald }
2918ef7100fSMilanka Ringwald break;
2928ef7100fSMilanka Ringwald default:
2938ef7100fSMilanka Ringwald break;
2948ef7100fSMilanka Ringwald }
2958ef7100fSMilanka Ringwald buffer[0] = pos - 1; // length
2968ef7100fSMilanka Ringwald return pos;
2978ef7100fSMilanka Ringwald }
2988ef7100fSMilanka Ringwald
avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * connection,avdtp_signal_identifier_t signal_identifier,avdtp_service_category_t category,uint8_t cap_len)299390aa582SMatthias Ringwald static int avdtp_unpack_service_capabilities_has_errors(avdtp_connection_t * connection, avdtp_signal_identifier_t signal_identifier, avdtp_service_category_t category, uint8_t cap_len){
3008ef7100fSMilanka Ringwald connection->error_code = 0;
3018ef7100fSMilanka Ringwald
30276827215SMatthias Ringwald if ((category == AVDTP_SERVICE_CATEGORY_INVALID_0) || (category > AVDTP_DELAY_REPORTING)){
3038587e32cSMilanka Ringwald log_info(" ERROR: BAD SERVICE CATEGORY %d\n", category);
3048ef7100fSMilanka Ringwald connection->reject_service_category = category;
3055b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_SERV_CATEGORY;
3068ef7100fSMilanka Ringwald return 1;
3078ef7100fSMilanka Ringwald }
3088ef7100fSMilanka Ringwald
309390aa582SMatthias Ringwald if (signal_identifier == AVDTP_SI_RECONFIGURE){
3100e588213SMatthias Ringwald if ( (category != AVDTP_CONTENT_PROTECTION) && (category != AVDTP_MEDIA_CODEC)){
3118587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, INVALID_CAPABILITIES\n");
3128ef7100fSMilanka Ringwald connection->reject_service_category = category;
3135b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_INVALID_CAPABILITIES;
3148ef7100fSMilanka Ringwald return 1;
3158ef7100fSMilanka Ringwald }
3168ef7100fSMilanka Ringwald }
3178ef7100fSMilanka Ringwald
3188ef7100fSMilanka Ringwald switch(category){
3198ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT:
3208ef7100fSMilanka Ringwald if (cap_len != 0){
3218587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
3228ef7100fSMilanka Ringwald connection->reject_service_category = category;
3235b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_MEDIA_TRANSPORT_FORMAT;
3248ef7100fSMilanka Ringwald return 1;
3258ef7100fSMilanka Ringwald }
3268ef7100fSMilanka Ringwald break;
3278ef7100fSMilanka Ringwald case AVDTP_REPORTING:
3288ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING:
3298ef7100fSMilanka Ringwald if (cap_len != 0){
3308587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_LENGTH\n");
3318ef7100fSMilanka Ringwald connection->reject_service_category = category;
3325b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_LENGTH;
3338ef7100fSMilanka Ringwald return 1;
3348ef7100fSMilanka Ringwald }
3358ef7100fSMilanka Ringwald break;
3368ef7100fSMilanka Ringwald case AVDTP_RECOVERY:
337f6f3c903SMilanka Ringwald if (cap_len != 3){
3388587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_MEDIA_TRANSPORT\n");
3398ef7100fSMilanka Ringwald connection->reject_service_category = category;
3405b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_RECOVERY_FORMAT;
3418ef7100fSMilanka Ringwald return 1;
3428ef7100fSMilanka Ringwald }
3438ef7100fSMilanka Ringwald break;
3448ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION:
3458ef7100fSMilanka Ringwald if (cap_len < 2){
3468587e32cSMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_CP_FORMAT\n");
3478ef7100fSMilanka Ringwald connection->reject_service_category = category;
3485b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_CP_FORMAT;
3498ef7100fSMilanka Ringwald return 1;
3508ef7100fSMilanka Ringwald }
3518ef7100fSMilanka Ringwald break;
3528ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION:
353f6f3c903SMilanka Ringwald // TODO: find error code for bad header compression
354f6f3c903SMilanka Ringwald if (cap_len != 1){
355f6f3c903SMilanka Ringwald log_info(" ERROR: REJECT CATEGORY, BAD_HEADER_COMPRESSION\n");
356f6f3c903SMilanka Ringwald connection->reject_service_category = category;
3575b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_RECOVERY_FORMAT;
358f6f3c903SMilanka Ringwald return 1;
359f6f3c903SMilanka Ringwald }
3608ef7100fSMilanka Ringwald break;
3618ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING:
3628ef7100fSMilanka Ringwald break;
3638ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC:
3648ef7100fSMilanka Ringwald break;
3658ef7100fSMilanka Ringwald default:
3668ef7100fSMilanka Ringwald break;
3678ef7100fSMilanka Ringwald }
3688ef7100fSMilanka Ringwald return 0;
3698ef7100fSMilanka Ringwald }
3708ef7100fSMilanka Ringwald
avdtp_unpack_service_capabilities(avdtp_connection_t * connection,avdtp_signal_identifier_t signal_identifier,avdtp_capabilities_t * caps,uint8_t * packet,uint16_t size)371afc28e0aSMatthias Ringwald uint16_t avdtp_unpack_service_capabilities(avdtp_connection_t * connection, avdtp_signal_identifier_t signal_identifier, avdtp_capabilities_t * caps, uint8_t * packet, uint16_t size){
372f6f3c903SMilanka Ringwald
373f6f3c903SMilanka Ringwald int i;
3748ef7100fSMilanka Ringwald
3758ef7100fSMilanka Ringwald uint16_t registered_service_categories = 0;
376f6f3c903SMilanka Ringwald uint16_t to_process = size;
377f6f3c903SMilanka Ringwald
378f6f3c903SMilanka Ringwald while (to_process >= 2){
379f6f3c903SMilanka Ringwald
380f6f3c903SMilanka Ringwald avdtp_service_category_t category = (avdtp_service_category_t) packet[0];
381f6f3c903SMilanka Ringwald uint8_t cap_len = packet[1];
382f6f3c903SMilanka Ringwald packet += 2;
383f6f3c903SMilanka Ringwald to_process -= 2;
384f6f3c903SMilanka Ringwald
385f6f3c903SMilanka Ringwald if (cap_len > to_process){
3868ef7100fSMilanka Ringwald connection->reject_service_category = category;
3875b391ed7SMatthias Ringwald connection->error_code = AVDTP_ERROR_CODE_BAD_LENGTH;
3888ef7100fSMilanka Ringwald return 0;
3898ef7100fSMilanka Ringwald }
39067ae582dSMilanka Ringwald
391afc28e0aSMatthias Ringwald if (avdtp_unpack_service_capabilities_has_errors(connection, signal_identifier, category, cap_len)) return 0;
39267ae582dSMilanka Ringwald
393f6f3c903SMilanka Ringwald int category_valid = 1;
39467ae582dSMilanka Ringwald
395f6f3c903SMilanka Ringwald uint8_t * data = packet;
396f6f3c903SMilanka Ringwald uint16_t pos = 0;
397f6f3c903SMilanka Ringwald
3988ef7100fSMilanka Ringwald switch(category){
3998ef7100fSMilanka Ringwald case AVDTP_RECOVERY:
400f6f3c903SMilanka Ringwald caps->recovery.recovery_type = data[pos++];
401f6f3c903SMilanka Ringwald caps->recovery.maximum_recovery_window_size = data[pos++];
402f6f3c903SMilanka Ringwald caps->recovery.maximum_number_media_packets = data[pos++];
4038ef7100fSMilanka Ringwald break;
4048ef7100fSMilanka Ringwald case AVDTP_CONTENT_PROTECTION:
405f6f3c903SMilanka Ringwald caps->content_protection.cp_type = big_endian_read_16(data, 0);
4068ef7100fSMilanka Ringwald caps->content_protection.cp_type_value_len = cap_len - 2;
4078ef7100fSMilanka Ringwald // connection->reject_service_category = category;
4088ef7100fSMilanka Ringwald // connection->error_code = UNSUPPORTED_CONFIGURATION;
4098ef7100fSMilanka Ringwald // support for content protection goes here
4108ef7100fSMilanka Ringwald break;
4118ef7100fSMilanka Ringwald case AVDTP_HEADER_COMPRESSION:
412f6f3c903SMilanka Ringwald caps->header_compression.back_ch = (data[0] >> 7) & 1;
413f6f3c903SMilanka Ringwald caps->header_compression.media = (data[0] >> 6) & 1;
414f6f3c903SMilanka Ringwald caps->header_compression.recovery = (data[0] >> 5) & 1;
4158ef7100fSMilanka Ringwald break;
4168ef7100fSMilanka Ringwald case AVDTP_MULTIPLEXING:
417f6f3c903SMilanka Ringwald caps->multiplexing_mode.fragmentation = (data[pos++] >> 7) & 1;
4188ef7100fSMilanka Ringwald // read [tsid, tcid] for media, reporting. recovery respectively
4198ef7100fSMilanka Ringwald caps->multiplexing_mode.transport_identifiers_num = 3;
4208ef7100fSMilanka Ringwald for (i=0; i<caps->multiplexing_mode.transport_identifiers_num; i++){
421f6f3c903SMilanka Ringwald caps->multiplexing_mode.transport_session_identifiers[i] = (data[pos++] >> 7) & 1;
422f6f3c903SMilanka Ringwald caps->multiplexing_mode.tcid[i] = (data[pos++] >> 7) & 1;
4238ef7100fSMilanka Ringwald }
4248ef7100fSMilanka Ringwald break;
4258ef7100fSMilanka Ringwald case AVDTP_MEDIA_CODEC:
426f6f3c903SMilanka Ringwald caps->media_codec.media_type = (avdtp_media_type_t)(data[pos++] >> 4);
427f6f3c903SMilanka Ringwald caps->media_codec.media_codec_type = (avdtp_media_codec_type_t)(data[pos++]);
4288ef7100fSMilanka Ringwald caps->media_codec.media_codec_information_len = cap_len - 2;
4294c7a1d3aSMatthias Ringwald caps->media_codec.media_codec_information = &data[pos++];
4308ef7100fSMilanka Ringwald break;
4318ef7100fSMilanka Ringwald case AVDTP_MEDIA_TRANSPORT:
4328ef7100fSMilanka Ringwald case AVDTP_REPORTING:
4338ef7100fSMilanka Ringwald case AVDTP_DELAY_REPORTING:
4348ef7100fSMilanka Ringwald break;
4358ef7100fSMilanka Ringwald default:
436f6f3c903SMilanka Ringwald category_valid = 0;
4378ef7100fSMilanka Ringwald break;
4388ef7100fSMilanka Ringwald }
4398ef7100fSMilanka Ringwald
440f6f3c903SMilanka Ringwald if (category_valid) {
4418ef7100fSMilanka Ringwald registered_service_categories = store_bit16(registered_service_categories, category, 1);
4428ef7100fSMilanka Ringwald }
443f6f3c903SMilanka Ringwald
444f6f3c903SMilanka Ringwald packet += cap_len;
445f6f3c903SMilanka Ringwald to_process -= cap_len;
44667ae582dSMilanka Ringwald }
447f6f3c903SMilanka Ringwald
4488ef7100fSMilanka Ringwald return registered_service_categories;
4498ef7100fSMilanka Ringwald }
4508ef7100fSMilanka Ringwald
avdtp_prepare_capabilities(avdtp_signaling_packet_t * signaling_packet,uint8_t transaction_label,uint16_t service_categories,avdtp_capabilities_t capabilities,uint8_t identifier)45150d5c6caSMatthias Ringwald void avdtp_prepare_capabilities(avdtp_signaling_packet_t * signaling_packet, uint8_t transaction_label, uint16_t service_categories, avdtp_capabilities_t capabilities, uint8_t identifier){
4528ef7100fSMilanka Ringwald if (signaling_packet->offset) return;
45350d5c6caSMatthias Ringwald bool basic_capabilities_only = false;
4548ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_RESPONSE_ACCEPT_MSG;
4558ef7100fSMilanka Ringwald int i;
456747ec646SMilanka Ringwald
457747ec646SMilanka Ringwald signaling_packet->size = 0;
458747ec646SMilanka Ringwald memset(signaling_packet->command, 0 , sizeof(signaling_packet->command));
459747ec646SMilanka Ringwald
4608ef7100fSMilanka Ringwald switch (identifier) {
4618ef7100fSMilanka Ringwald case AVDTP_SI_GET_CAPABILITIES:
46250d5c6caSMatthias Ringwald basic_capabilities_only = true;
4638ef7100fSMilanka Ringwald break;
4648ef7100fSMilanka Ringwald case AVDTP_SI_GET_ALL_CAPABILITIES:
4658ef7100fSMilanka Ringwald break;
4668ef7100fSMilanka Ringwald case AVDTP_SI_SET_CONFIGURATION:
467747ec646SMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->acp_seid << 2;
4688ef7100fSMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->int_seid << 2;
4698ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_CMD_MSG;
4708ef7100fSMilanka Ringwald break;
4718ef7100fSMilanka Ringwald case AVDTP_SI_RECONFIGURE:
472747ec646SMilanka Ringwald signaling_packet->command[signaling_packet->size++] = signaling_packet->acp_seid << 2;
4738ef7100fSMilanka Ringwald signaling_packet->message_type = AVDTP_CMD_MSG;
4748ef7100fSMilanka Ringwald break;
4758ef7100fSMilanka Ringwald default:
4768ef7100fSMilanka Ringwald log_error("avdtp_prepare_capabilities wrong identifier %d", identifier);
4778ef7100fSMilanka Ringwald break;
4788ef7100fSMilanka Ringwald }
4798ef7100fSMilanka Ringwald
48050d5c6caSMatthias Ringwald for (i = AVDTP_MEDIA_TRANSPORT; i <= AVDTP_DELAY_REPORTING; i++){
48150d5c6caSMatthias Ringwald int registered_category = get_bit16(service_categories, i);
4822bb3471fSMilanka Ringwald if (!registered_category && (identifier == AVDTP_SI_SET_CONFIGURATION)){
483747ec646SMilanka Ringwald // TODO: introduce bitmap of mandatory categories
48450d5c6caSMatthias Ringwald if (i == AVDTP_MEDIA_TRANSPORT){
48550d5c6caSMatthias Ringwald registered_category = true;
486747ec646SMilanka Ringwald }
487747ec646SMilanka Ringwald }
48850d5c6caSMatthias Ringwald // AVDTP_SI_GET_CAPABILITIES reports only basic capabilities (i.e., it skips non-basic categories)
48950d5c6caSMatthias Ringwald if (basic_capabilities_only && !avdtp_is_basic_capability(i)){
49050d5c6caSMatthias Ringwald registered_category = false;
49150d5c6caSMatthias Ringwald }
49250d5c6caSMatthias Ringwald
493747ec646SMilanka Ringwald if (registered_category){
4948ef7100fSMilanka Ringwald // service category
4958ef7100fSMilanka Ringwald signaling_packet->command[signaling_packet->size++] = i;
49650d5c6caSMatthias Ringwald signaling_packet->size += avdtp_pack_service_capabilities(signaling_packet->command + signaling_packet->size,
49750d5c6caSMatthias Ringwald sizeof(signaling_packet->command) - signaling_packet->size, capabilities, (avdtp_service_category_t) i);
4988ef7100fSMilanka Ringwald }
4998ef7100fSMilanka Ringwald }
500b0920f25SMilanka Ringwald signaling_packet->signal_identifier = (avdtp_signal_identifier_t)identifier;
5018ef7100fSMilanka Ringwald signaling_packet->transaction_label = transaction_label;
5028ef7100fSMilanka Ringwald }
5038ef7100fSMilanka Ringwald
avdtp_signaling_create_fragment(uint16_t cid,avdtp_signaling_packet_t * signaling_packet,uint8_t * out_buffer)5048ef7100fSMilanka Ringwald int avdtp_signaling_create_fragment(uint16_t cid, avdtp_signaling_packet_t * signaling_packet, uint8_t * out_buffer) {
5058ef7100fSMilanka Ringwald int mtu = l2cap_get_remote_mtu_for_local_cid(cid);
5068ef7100fSMilanka Ringwald int data_len = 0;
5078ef7100fSMilanka Ringwald
5088ef7100fSMilanka Ringwald uint16_t offset = signaling_packet->offset;
5098ef7100fSMilanka Ringwald uint16_t pos = 1;
5108ef7100fSMilanka Ringwald
5118ef7100fSMilanka Ringwald if (offset == 0){
512c1ab6cc1SMatthias Ringwald if (signaling_packet->size <= (mtu - 2)){
5138ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_SINGLE_PACKET;
5148ef7100fSMilanka Ringwald out_buffer[pos++] = signaling_packet->signal_identifier;
5158ef7100fSMilanka Ringwald data_len = signaling_packet->size;
5168ef7100fSMilanka Ringwald } else {
5178ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_START_PACKET;
5188ef7100fSMilanka Ringwald out_buffer[pos++] = (mtu + signaling_packet->size)/ (mtu-1);
5198ef7100fSMilanka Ringwald out_buffer[pos++] = signaling_packet->signal_identifier;
5208ef7100fSMilanka Ringwald data_len = mtu - 3;
5218ef7100fSMilanka Ringwald signaling_packet->offset = data_len;
5228ef7100fSMilanka Ringwald }
5238ef7100fSMilanka Ringwald } else {
5248ef7100fSMilanka Ringwald int remaining_bytes = signaling_packet->size - offset;
525c1ab6cc1SMatthias Ringwald if (remaining_bytes <= (mtu - 1)){
5268ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_END_PACKET;
5278ef7100fSMilanka Ringwald data_len = remaining_bytes;
5288ef7100fSMilanka Ringwald signaling_packet->offset = 0;
5298ef7100fSMilanka Ringwald } else{
5308ef7100fSMilanka Ringwald signaling_packet->packet_type = AVDTP_CONTINUE_PACKET;
5318ef7100fSMilanka Ringwald data_len = mtu - 1;
5328ef7100fSMilanka Ringwald signaling_packet->offset += data_len;
5338ef7100fSMilanka Ringwald }
5348ef7100fSMilanka Ringwald }
5358ef7100fSMilanka Ringwald out_buffer[0] = avdtp_header(signaling_packet->transaction_label, signaling_packet->packet_type, signaling_packet->message_type);
5366535961aSMatthias Ringwald (void)memcpy(out_buffer + pos, signaling_packet->command + offset,
5376535961aSMatthias Ringwald data_len);
5388ef7100fSMilanka Ringwald pos += data_len;
5398ef7100fSMilanka Ringwald return pos;
5408ef7100fSMilanka Ringwald }
5418ef7100fSMilanka Ringwald
5428ef7100fSMilanka Ringwald
avdtp_signaling_emit_connection_established(uint16_t avdtp_cid,bd_addr_t addr,hci_con_handle_t con_handle,uint8_t status)543146fc0fbSMilanka Ringwald void avdtp_signaling_emit_connection_established(uint16_t avdtp_cid, bd_addr_t addr, hci_con_handle_t con_handle, uint8_t status) {
544146fc0fbSMilanka Ringwald uint8_t event[14];
5458ef7100fSMilanka Ringwald int pos = 0;
5468ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
5478ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2;
5488ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED;
549f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
5508ef7100fSMilanka Ringwald pos += 2;
5518ef7100fSMilanka Ringwald reverse_bd_addr(addr,&event[pos]);
5528ef7100fSMilanka Ringwald pos += 6;
553146fc0fbSMilanka Ringwald little_endian_store_16(event, pos, con_handle);
554146fc0fbSMilanka Ringwald pos += 2;
5558ef7100fSMilanka Ringwald event[pos++] = status;
556c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
5578ef7100fSMilanka Ringwald }
5588ef7100fSMilanka Ringwald
avdtp_signaling_emit_connection_released(uint16_t avdtp_cid)559c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_connection_released(uint16_t avdtp_cid) {
56034b22aacSMilanka Ringwald uint8_t event[5];
56134b22aacSMilanka Ringwald int pos = 0;
56234b22aacSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
56334b22aacSMilanka Ringwald event[pos++] = sizeof(event) - 2;
56434b22aacSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED;
56534b22aacSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
56634b22aacSMilanka Ringwald pos += 2;
567c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
56834b22aacSMilanka Ringwald }
56934b22aacSMilanka Ringwald
avdtp_signaling_emit_sep(uint16_t avdtp_cid,avdtp_sep_t sep)570c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_sep(uint16_t avdtp_cid, avdtp_sep_t sep) {
5718ef7100fSMilanka Ringwald uint8_t event[9];
5728ef7100fSMilanka Ringwald int pos = 0;
5738ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
5748ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2;
5758ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_FOUND;
576f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
5778ef7100fSMilanka Ringwald pos += 2;
5788ef7100fSMilanka Ringwald event[pos++] = sep.seid;
5798ef7100fSMilanka Ringwald event[pos++] = sep.in_use;
5808ef7100fSMilanka Ringwald event[pos++] = sep.media_type;
5818ef7100fSMilanka Ringwald event[pos++] = sep.type;
582c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
5838ef7100fSMilanka Ringwald }
5848ef7100fSMilanka Ringwald
avdtp_signaling_emit_sep_done(uint16_t avdtp_cid)585c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_sep_done(uint16_t avdtp_cid) {
586485c0a4cSMilanka Ringwald uint8_t event[5];
587485c0a4cSMilanka Ringwald int pos = 0;
588485c0a4cSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
589485c0a4cSMilanka Ringwald event[pos++] = sizeof(event) - 2;
590485c0a4cSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE;
591485c0a4cSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
592485c0a4cSMilanka Ringwald pos += 2;
593c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
594485c0a4cSMilanka Ringwald }
595485c0a4cSMilanka Ringwald
avdtp_signaling_emit_accept(uint16_t avdtp_cid,uint8_t local_seid,avdtp_signal_identifier_t identifier,bool is_initiator)596c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_accept(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) {
59763274943SMilanka Ringwald uint8_t event[8];
5988ef7100fSMilanka Ringwald int pos = 0;
5998ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
6008ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2;
6018ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT;
602f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
6038ef7100fSMilanka Ringwald pos += 2;
6044ccacc40SMilanka Ringwald event[pos++] = local_seid;
60563274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0;
6068ef7100fSMilanka Ringwald event[pos++] = identifier;
607c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
6088ef7100fSMilanka Ringwald }
6098ef7100fSMilanka Ringwald
avdtp_signaling_emit_accept_for_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint,uint8_t local_seid,avdtp_signal_identifier_t identifier,bool is_initiator)61046b99c89SMatthias Ringwald void avdtp_signaling_emit_accept_for_stream_endpoint(avdtp_stream_endpoint_t * stream_endpoint, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator){
61146b99c89SMatthias Ringwald uint8_t event[8];
61246b99c89SMatthias Ringwald int pos = 0;
61346b99c89SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
61446b99c89SMatthias Ringwald event[pos++] = sizeof(event) - 2;
61546b99c89SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_ACCEPT;
61646b99c89SMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid);
61746b99c89SMatthias Ringwald pos += 2;
61846b99c89SMatthias Ringwald event[pos++] = local_seid;
61946b99c89SMatthias Ringwald event[pos++] = is_initiator ? 1 : 0;
62046b99c89SMatthias Ringwald event[pos++] = identifier;
62146b99c89SMatthias Ringwald
62246b99c89SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
62346b99c89SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
62446b99c89SMatthias Ringwald }
62546b99c89SMatthias Ringwald
avdtp_signaling_emit_reject(uint16_t avdtp_cid,uint8_t local_seid,avdtp_signal_identifier_t identifier,bool is_initiator)626c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_reject(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) {
62763274943SMilanka Ringwald uint8_t event[8];
6288ef7100fSMilanka Ringwald int pos = 0;
6298ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
6308ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2;
6318ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_REJECT;
632f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
6338ef7100fSMilanka Ringwald pos += 2;
6344ccacc40SMilanka Ringwald event[pos++] = local_seid;
63563274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0;
6368ef7100fSMilanka Ringwald event[pos++] = identifier;
637c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
6388ef7100fSMilanka Ringwald }
6398ef7100fSMilanka Ringwald
avdtp_signaling_emit_general_reject(uint16_t avdtp_cid,uint8_t local_seid,avdtp_signal_identifier_t identifier,bool is_initiator)640c69f4ba5SMatthias Ringwald void avdtp_signaling_emit_general_reject(uint16_t avdtp_cid, uint8_t local_seid, avdtp_signal_identifier_t identifier, bool is_initiator) {
64163274943SMilanka Ringwald uint8_t event[8];
6428ef7100fSMilanka Ringwald int pos = 0;
6438ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
6448ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2;
6458ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT;
646f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
6478ef7100fSMilanka Ringwald pos += 2;
6484ccacc40SMilanka Ringwald event[pos++] = local_seid;
64963274943SMilanka Ringwald event[pos++] = is_initiator ? 1 : 0;
6508ef7100fSMilanka Ringwald event[pos++] = identifier;
651c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
6528ef7100fSMilanka Ringwald }
6538ef7100fSMilanka Ringwald
6544b7d40bbSMatthias Ringwald static inline void
avdtp_signaling_emit_capability(uint8_t capability_subevent_id,uint16_t avdtp_cid,uint8_t remote_seid)6551159d239SMatthias Ringwald avdtp_signaling_emit_capability(uint8_t capability_subevent_id, uint16_t avdtp_cid, uint8_t remote_seid) {
6561159d239SMatthias Ringwald uint8_t event[6];
6574b7d40bbSMatthias Ringwald int pos = 0;
6584b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
6594b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2;
6604b7d40bbSMatthias Ringwald event[pos++] = capability_subevent_id;
6614b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
6624b7d40bbSMatthias Ringwald pos += 2;
6634b7d40bbSMatthias Ringwald event[pos++] = remote_seid;
6644b7d40bbSMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
6654b7d40bbSMatthias Ringwald }
6664b7d40bbSMatthias Ringwald
avdtp_signaling_emit_media_codec_sbc_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)6671159d239SMatthias Ringwald static void avdtp_signaling_emit_media_codec_sbc_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) {
6685ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information;
6691159d239SMatthias Ringwald uint8_t event[14];
6708ef7100fSMilanka Ringwald int pos = 0;
6718ef7100fSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
6728ef7100fSMilanka Ringwald event[pos++] = sizeof(event) - 2;
6738ef7100fSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY;
674f9bca1f3SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
6758ef7100fSMilanka Ringwald pos += 2;
6764ccacc40SMilanka Ringwald event[pos++] = remote_seid;
6778ef7100fSMilanka Ringwald event[pos++] = media_codec.media_type;
6785ce3497fSMatthias Ringwald event[pos++] = media_codec_information[0] >> 4;
6795ce3497fSMatthias Ringwald event[pos++] = media_codec_information[0] & 0x0F;
6805ce3497fSMatthias Ringwald event[pos++] = media_codec_information[1] >> 4;
6815ce3497fSMatthias Ringwald event[pos++] = (media_codec_information[1] & 0x0F) >> 2;
6825ce3497fSMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03;
6835ce3497fSMatthias Ringwald event[pos++] = media_codec_information[2];
6845ce3497fSMatthias Ringwald event[pos++] = media_codec_information[3];
6855ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
6865ce3497fSMatthias Ringwald }
6875ce3497fSMatthias Ringwald
avdtp_signaling_emit_media_codec_mpeg_audio_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)6885ce3497fSMatthias Ringwald static void avdtp_signaling_emit_media_codec_mpeg_audio_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) {
6895ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information;
6905ce3497fSMatthias Ringwald uint8_t event[15];
6915ce3497fSMatthias Ringwald int pos = 0;
6925ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
6935ce3497fSMatthias Ringwald event[pos++] = sizeof(event) - 2;
6945ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CAPABILITY;
6955ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
6965ce3497fSMatthias Ringwald pos += 2;
6975ce3497fSMatthias Ringwald event[pos++] = remote_seid;
6985ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type;
6995ce3497fSMatthias Ringwald
7005ce3497fSMatthias Ringwald uint8_t layer_bitmap = media_codec_information[0] >> 5;
7015ce3497fSMatthias Ringwald uint8_t crc = (media_codec_information[0] >> 4) & 0x01;
7025ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x07;
7035ce3497fSMatthias Ringwald uint8_t mpf = (media_codec_information[1] >> 6) & 0x01;
7045ce3497fSMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[1] & 0x3F;
7055ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[2] >> 7) & 0x01;
7065ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[3] & 0x3f) << 8) | media_codec.media_codec_information[4];
7075ce3497fSMatthias Ringwald
7085ce3497fSMatthias Ringwald event[pos++] = layer_bitmap;
7095ce3497fSMatthias Ringwald event[pos++] = crc;
7105ce3497fSMatthias Ringwald event[pos++] = channel_mode_bitmap;
7115ce3497fSMatthias Ringwald event[pos++] = mpf;
7125ce3497fSMatthias Ringwald event[pos++] = sampling_frequency_bitmap;
7135ce3497fSMatthias Ringwald event[pos++] = vbr;
7145ce3497fSMatthias Ringwald little_endian_store_16(event, pos, bit_rate_index_bitmap); // bit rate index
7155ce3497fSMatthias Ringwald pos += 2;
7165ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
7175ce3497fSMatthias Ringwald }
7185ce3497fSMatthias Ringwald
avdtp_signaling_emit_media_codec_mpeg_aac_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)7195ce3497fSMatthias Ringwald static void avdtp_signaling_emit_media_codec_mpeg_aac_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) {
7205ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information;
721*b182b7f4SMilanka Ringwald uint8_t event[16];
7225ce3497fSMatthias Ringwald int pos = 0;
7235ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
7245ce3497fSMatthias Ringwald event[pos++] = sizeof(event) - 2;
7255ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CAPABILITY;
7265ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
7275ce3497fSMatthias Ringwald pos += 2;
7285ce3497fSMatthias Ringwald event[pos++] = remote_seid;
7295ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type;
7305ce3497fSMatthias Ringwald
7311da18615SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 1;
7321da18615SMilanka Ringwald uint8_t drc = media_codec_information[0] & 0x01;
7335ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] << 4) | (media_codec_information[2] >> 4);
7341da18615SMilanka Ringwald uint8_t channels_bitmap = media_codec_information[2] & 0x0F;
7355ce3497fSMatthias Ringwald uint32_t bit_rate_bitmap = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5];
7365ce3497fSMatthias Ringwald uint8_t vbr = media_codec_information[3] >> 7;
7375ce3497fSMatthias Ringwald
7385ce3497fSMatthias Ringwald event[pos++] = object_type_bitmap;
7395ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency_bitmap);
7405ce3497fSMatthias Ringwald pos += 2;
7415ce3497fSMatthias Ringwald event[pos++] = channels_bitmap;
7425ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate_bitmap);
7435ce3497fSMatthias Ringwald pos += 3;
7445ce3497fSMatthias Ringwald event[pos++] = vbr;
745b7aa6976SMilanka Ringwald event[pos++] = drc;
7465ce3497fSMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
7475ce3497fSMatthias Ringwald }
7485ce3497fSMatthias Ringwald
avdtp_signaling_emit_media_codec_atrac_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)7495ce3497fSMatthias Ringwald static void avdtp_signaling_emit_media_codec_atrac_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) {
7505ce3497fSMatthias Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information;
7515ce3497fSMatthias Ringwald uint8_t event[16];
7525ce3497fSMatthias Ringwald int pos = 0;
7535ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
75473048ce6SMatthias Ringwald pos++; // set later
7555ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY;
7565ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
7575ce3497fSMatthias Ringwald pos += 2;
7585ce3497fSMatthias Ringwald event[pos++] = remote_seid;
7595ce3497fSMatthias Ringwald event[pos++] = media_codec.media_type;
7605ce3497fSMatthias Ringwald
7615ce3497fSMatthias Ringwald uint8_t version = media_codec_information[0] >> 5;
7625ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] >> 2) & 0x07;
763ab2445a0SMatthias Ringwald uint8_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03;
7645ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[1] >> 3) & 0x01;
7655ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3];
7665ce3497fSMatthias Ringwald uint16_t maximum_sul = (media_codec_information[4] << 8) | media_codec_information[5];
7675ce3497fSMatthias Ringwald
7685ce3497fSMatthias Ringwald event[pos++] = version;
7695ce3497fSMatthias Ringwald event[pos++] = channel_mode_bitmap;
7705ce3497fSMatthias Ringwald event[pos++] = sampling_frequency_bitmap;
7715ce3497fSMatthias Ringwald event[pos++] = vbr;
7725ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate_index_bitmap);
7735ce3497fSMatthias Ringwald pos += 3;
7745ce3497fSMatthias Ringwald little_endian_store_16(event, pos, maximum_sul);
77573048ce6SMatthias Ringwald pos += 2;
77673048ce6SMatthias Ringwald event[1] = pos - 2;
777c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
7788ef7100fSMilanka Ringwald }
7798ef7100fSMilanka Ringwald
avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)78024d5fe84SMilanka Ringwald static void avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) {
78124d5fe84SMilanka Ringwald const uint8_t * media_codec_information = media_codec.media_codec_information;
78224d5fe84SMilanka Ringwald uint8_t event[18];
78324d5fe84SMilanka Ringwald int pos = 0;
78424d5fe84SMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
78524d5fe84SMilanka Ringwald pos++; // set later
78624d5fe84SMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CAPABILITY;
78724d5fe84SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
78824d5fe84SMilanka Ringwald pos += 2;
78924d5fe84SMilanka Ringwald event[pos++] = remote_seid;
79024d5fe84SMilanka Ringwald event[pos++] = media_codec.media_type;
79124d5fe84SMilanka Ringwald
79224d5fe84SMilanka Ringwald uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) |
79324d5fe84SMilanka Ringwald (media_codec_information[1] << 12) |
79424d5fe84SMilanka Ringwald (media_codec_information[2] << 4) |
79524d5fe84SMilanka Ringwald (media_codec_information[3] >> 4);
79624d5fe84SMilanka Ringwald
79724d5fe84SMilanka Ringwald uint8_t channels_bitmap = (media_codec_information[3] >> 2) & 0x03;
79824d5fe84SMilanka Ringwald uint8_t vbr = (media_codec_information[4] >> 7) & 0x01;
79924d5fe84SMilanka Ringwald
80024d5fe84SMilanka Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[4]) & 0xEF) << 16 | (media_codec_information[5] << 8) | media_codec_information[6];
80124d5fe84SMilanka Ringwald
80224d5fe84SMilanka Ringwald event[pos++] = media_codec_information[0] >> 6;
80324d5fe84SMilanka Ringwald little_endian_store_32(event, pos, sampling_frequency_bitmap);
80424d5fe84SMilanka Ringwald pos += 4;
80524d5fe84SMilanka Ringwald event[pos++] = channels_bitmap;
80624d5fe84SMilanka Ringwald event[pos++] = sampling_frequency_bitmap;
80724d5fe84SMilanka Ringwald event[pos++] = vbr;
80824d5fe84SMilanka Ringwald little_endian_store_24(event, pos, bit_rate_index_bitmap);
80924d5fe84SMilanka Ringwald pos += 3;
81024d5fe84SMilanka Ringwald event[1] = pos - 2;
81124d5fe84SMilanka Ringwald avdtp_emit_sink_and_source(event, pos);
81224d5fe84SMilanka Ringwald }
81324d5fe84SMilanka Ringwald
81424d5fe84SMilanka Ringwald
avdtp_signaling_emit_media_codec_other_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)8151159d239SMatthias Ringwald static void avdtp_signaling_emit_media_codec_other_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec) {
816924216b2SMatthias Ringwald uint8_t event[AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH + 11];
81767ae582dSMilanka Ringwald int pos = 0;
81867ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
81973048ce6SMatthias Ringwald pos++; // set later
8204b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY;
82167ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
82267ae582dSMilanka Ringwald pos += 2;
82367ae582dSMilanka Ringwald event[pos++] = remote_seid;
8244b7d40bbSMatthias Ringwald event[pos++] = media_codec.media_type;
8254b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, media_codec.media_codec_type);
8264b7d40bbSMatthias Ringwald pos += 2;
8274b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, media_codec.media_codec_information_len);
8284b7d40bbSMatthias Ringwald pos += 2;
829924216b2SMatthias Ringwald uint32_t media_codec_info_len = btstack_min(media_codec.media_codec_information_len, AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH);
8305403525eSMatthias Ringwald (void)memcpy(event + pos, media_codec.media_codec_information, media_codec_info_len);
8315403525eSMatthias Ringwald pos += media_codec_info_len;
83273048ce6SMatthias Ringwald event[1] = pos - 2;
833c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
83467ae582dSMilanka Ringwald }
83567ae582dSMilanka Ringwald
836c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_media_transport_capability(uint16_t avdtp_cid,uint8_t remote_seid)8371159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(uint16_t avdtp_cid, uint8_t remote_seid) {
8381159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY, avdtp_cid,
839c69f4ba5SMatthias Ringwald remote_seid);
84067ae582dSMilanka Ringwald }
84167ae582dSMilanka Ringwald
avdtp_signaling_emit_reporting_capability(uint16_t avdtp_cid,uint8_t remote_seid)8421159d239SMatthias Ringwald static void avdtp_signaling_emit_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) {
8431159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY, avdtp_cid, remote_seid);
84467ae582dSMilanka Ringwald }
84567ae582dSMilanka Ringwald
846c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_delay_reporting_capability(uint16_t avdtp_cid,uint8_t remote_seid)8471159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(uint16_t avdtp_cid, uint8_t remote_seid) {
8481159d239SMatthias Ringwald avdtp_signaling_emit_capability(AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY, avdtp_cid,
849c69f4ba5SMatthias Ringwald remote_seid);
85067ae582dSMilanka Ringwald }
85167ae582dSMilanka Ringwald
avdtp_signaling_emit_recovery_capability(uint16_t avdtp_cid,uint8_t remote_seid,avdtp_recovery_capabilities_t * recovery)8521159d239SMatthias Ringwald static void avdtp_signaling_emit_recovery_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_recovery_capabilities_t *recovery) {
8531159d239SMatthias Ringwald uint8_t event[9];
85467ae582dSMilanka Ringwald int pos = 0;
85567ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
85667ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2;
85767ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY;
85867ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
85967ae582dSMilanka Ringwald pos += 2;
86067ae582dSMilanka Ringwald event[pos++] = remote_seid;
86167ae582dSMilanka Ringwald event[pos++] = recovery->recovery_type;
86267ae582dSMilanka Ringwald event[pos++] = recovery->maximum_recovery_window_size;
86367ae582dSMilanka Ringwald event[pos++] = recovery->maximum_number_media_packets;
864c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
86567ae582dSMilanka Ringwald }
86667ae582dSMilanka Ringwald
86773048ce6SMatthias Ringwald #define MAX_CONTENT_PROTECTION_VALUE_LEN 32
868c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_content_protection_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_content_protection_t * content_protection)8691159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_content_protection_t *content_protection) {
87073048ce6SMatthias Ringwald uint8_t event[10 + MAX_CONTENT_PROTECTION_VALUE_LEN];
87167ae582dSMilanka Ringwald int pos = 0;
87267ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
87373048ce6SMatthias Ringwald pos++; // set later
87467ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY;
87567ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
87667ae582dSMilanka Ringwald pos += 2;
87767ae582dSMilanka Ringwald event[pos++] = remote_seid;
87867ae582dSMilanka Ringwald
87967ae582dSMilanka Ringwald little_endian_store_16(event, pos, content_protection->cp_type);
88067ae582dSMilanka Ringwald pos += 2;
88173048ce6SMatthias Ringwald
88273048ce6SMatthias Ringwald // drop cp protection value if longer than expected
88373048ce6SMatthias Ringwald if (content_protection->cp_type_value_len <= MAX_CONTENT_PROTECTION_VALUE_LEN){
88467ae582dSMilanka Ringwald little_endian_store_16(event, pos, content_protection->cp_type_value_len);
88567ae582dSMilanka Ringwald pos += 2;
88673048ce6SMatthias Ringwald (void)memcpy(event + pos, content_protection->cp_type_value, content_protection->cp_type_value_len);
88773048ce6SMatthias Ringwald pos += content_protection->cp_type_value_len;
88873048ce6SMatthias Ringwald } else {
88973048ce6SMatthias Ringwald little_endian_store_16(event, pos, 0);
89073048ce6SMatthias Ringwald pos += 2;
89167ae582dSMilanka Ringwald }
89273048ce6SMatthias Ringwald event[1] = pos - 2;
893c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
89467ae582dSMilanka Ringwald }
89567ae582dSMilanka Ringwald
89667ae582dSMilanka Ringwald
897c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_header_compression_capability(uint16_t avdtp_cid,uint8_t remote_seid,avdtp_header_compression_capabilities_t * header_compression)8981159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_header_compression_capabilities_t *header_compression) {
8991159d239SMatthias Ringwald uint8_t event[9];
90067ae582dSMilanka Ringwald int pos = 0;
90167ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
90267ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2;
90367ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY;
90467ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
90567ae582dSMilanka Ringwald pos += 2;
90667ae582dSMilanka Ringwald event[pos++] = remote_seid;
90767ae582dSMilanka Ringwald event[pos++] = header_compression->back_ch;
90867ae582dSMilanka Ringwald event[pos++] = header_compression->media;
90967ae582dSMilanka Ringwald event[pos++] = header_compression->recovery;
910c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
91167ae582dSMilanka Ringwald }
91267ae582dSMilanka Ringwald
913c69f4ba5SMatthias Ringwald static void
avdtp_signaling_emit_content_multiplexing_capability(uint16_t avdtp_cid,uint8_t remote_seid,avdtp_multiplexing_mode_capabilities_t * multiplexing_mode)9141159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_multiplexing_mode_capabilities_t *multiplexing_mode) {
9151159d239SMatthias Ringwald uint8_t event[14];
91667ae582dSMilanka Ringwald int pos = 0;
91767ae582dSMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
91867ae582dSMilanka Ringwald event[pos++] = sizeof(event) - 2;
91967ae582dSMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY;
92067ae582dSMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
92167ae582dSMilanka Ringwald pos += 2;
92267ae582dSMilanka Ringwald event[pos++] = remote_seid;
92367ae582dSMilanka Ringwald
92467ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->fragmentation;
92567ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->transport_identifiers_num;
92667ae582dSMilanka Ringwald
92767ae582dSMilanka Ringwald int i;
92867ae582dSMilanka Ringwald for (i = 0; i < 3; i++){
92967ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->transport_session_identifiers[i];
93067ae582dSMilanka Ringwald }
93167ae582dSMilanka Ringwald for (i = 0; i < 3; i++){
93267ae582dSMilanka Ringwald event[pos++] = multiplexing_mode->tcid[i];
93367ae582dSMilanka Ringwald }
934c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
93567ae582dSMilanka Ringwald }
93667ae582dSMilanka Ringwald
avdtp_signaling_emit_capability_done(uint16_t avdtp_cid,uint8_t remote_seid)9371159d239SMatthias Ringwald static void avdtp_signaling_emit_capability_done(uint16_t avdtp_cid, uint8_t remote_seid) {
9381159d239SMatthias Ringwald uint8_t event[6];
939f08f4934SMatthias Ringwald int pos = 0;
940f08f4934SMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
941f08f4934SMatthias Ringwald event[pos++] = sizeof(event) - 2;
942f08f4934SMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE;
943f08f4934SMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
944f08f4934SMatthias Ringwald pos += 2;
945f08f4934SMatthias Ringwald event[pos++] = remote_seid;
946c69f4ba5SMatthias Ringwald avdtp_emit_sink_and_source(event, pos);
947f08f4934SMatthias Ringwald }
948f08f4934SMatthias Ringwald
avdtp_signaling_emit_media_codec_capability(uint16_t avdtp_cid,uint8_t remote_seid,adtvp_media_codec_capabilities_t media_codec)9490928ecceSMatthias Ringwald static void avdtp_signaling_emit_media_codec_capability(uint16_t avdtp_cid, uint8_t remote_seid, adtvp_media_codec_capabilities_t media_codec){
9500928ecceSMatthias Ringwald switch (media_codec.media_codec_type){
9510928ecceSMatthias Ringwald case AVDTP_CODEC_SBC:
9520928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_sbc_capability(avdtp_cid, remote_seid, media_codec);
9530928ecceSMatthias Ringwald break;
9540928ecceSMatthias Ringwald case AVDTP_CODEC_MPEG_1_2_AUDIO:
9550928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_mpeg_audio_capability(avdtp_cid, remote_seid, media_codec);
9560928ecceSMatthias Ringwald break;
9570928ecceSMatthias Ringwald case AVDTP_CODEC_MPEG_2_4_AAC:
9580928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_mpeg_aac_capability(avdtp_cid, remote_seid, media_codec);
9590928ecceSMatthias Ringwald break;
9600928ecceSMatthias Ringwald case AVDTP_CODEC_ATRAC_FAMILY:
9610928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_atrac_capability(avdtp_cid, remote_seid, media_codec);
9620928ecceSMatthias Ringwald break;
96324d5fe84SMilanka Ringwald case AVDTP_CODEC_MPEG_D_USAC:
96424d5fe84SMilanka Ringwald avdtp_signaling_emit_media_codec_mpeg_d_usac_capability(avdtp_cid, remote_seid, media_codec);
96524d5fe84SMilanka Ringwald break;
9660928ecceSMatthias Ringwald default:
9670928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_other_capability(avdtp_cid, remote_seid, media_codec);
9680928ecceSMatthias Ringwald break;
9690928ecceSMatthias Ringwald }
9700928ecceSMatthias Ringwald }
9710928ecceSMatthias Ringwald
9724b7d40bbSMatthias Ringwald // emit events for all capabilities incl. final done event
avdtp_signaling_emit_capabilities(uint16_t avdtp_cid,uint8_t remote_seid,avdtp_capabilities_t * capabilities,uint16_t registered_service_categories)9731159d239SMatthias Ringwald void avdtp_signaling_emit_capabilities(uint16_t avdtp_cid, uint8_t remote_seid, avdtp_capabilities_t *capabilities,
974c69f4ba5SMatthias Ringwald uint16_t registered_service_categories) {
97567ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MEDIA_CODEC)){
9760928ecceSMatthias Ringwald avdtp_signaling_emit_media_codec_capability(avdtp_cid, remote_seid, capabilities->media_codec);
97767ae582dSMilanka Ringwald }
97867ae582dSMilanka Ringwald
97967ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MEDIA_TRANSPORT)){
9801159d239SMatthias Ringwald avdtp_signaling_emit_media_transport_capability(avdtp_cid, remote_seid);
98167ae582dSMilanka Ringwald }
98267ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_REPORTING)){
9831159d239SMatthias Ringwald avdtp_signaling_emit_reporting_capability(avdtp_cid, remote_seid);
98467ae582dSMilanka Ringwald }
98567ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_RECOVERY)){
9861159d239SMatthias Ringwald avdtp_signaling_emit_recovery_capability(avdtp_cid, remote_seid, &capabilities->recovery);
98767ae582dSMilanka Ringwald }
98867ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_CONTENT_PROTECTION)){
9891159d239SMatthias Ringwald avdtp_signaling_emit_content_protection_capability(avdtp_cid, remote_seid,
990c69f4ba5SMatthias Ringwald &capabilities->content_protection);
99167ae582dSMilanka Ringwald }
99267ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_HEADER_COMPRESSION)){
9931159d239SMatthias Ringwald avdtp_signaling_emit_header_compression_capability(avdtp_cid, remote_seid,
994c69f4ba5SMatthias Ringwald &capabilities->header_compression);
99567ae582dSMilanka Ringwald }
99667ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_MULTIPLEXING)){
9971159d239SMatthias Ringwald avdtp_signaling_emit_content_multiplexing_capability(avdtp_cid, remote_seid,
998c69f4ba5SMatthias Ringwald &capabilities->multiplexing_mode);
99967ae582dSMilanka Ringwald }
100067ae582dSMilanka Ringwald if (get_bit16(registered_service_categories, AVDTP_DELAY_REPORTING)){
10011159d239SMatthias Ringwald avdtp_signaling_emit_delay_reporting_capability(avdtp_cid, remote_seid);
100267ae582dSMilanka Ringwald }
10031159d239SMatthias Ringwald avdtp_signaling_emit_capability_done(avdtp_cid, remote_seid);
100467ae582dSMilanka Ringwald }
100567ae582dSMilanka Ringwald
1006186e1970SMatthias Ringwald static uint16_t
avdtp_signaling_setup_media_codec_sbc_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)1007186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_sbc_config_event(uint8_t *event, uint16_t size,
1008a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint,
1009186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure,
1010186e1970SMatthias Ringwald const uint8_t *media_codec_information) {
1011186e1970SMatthias Ringwald
1012924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN);
1013186e1970SMatthias Ringwald
10144b7d40bbSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint);
10154b7d40bbSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
10164b7d40bbSMatthias Ringwald
10174b7d40bbSMatthias Ringwald int pos = 0;
10184b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
1019924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN - 2;
10204b7d40bbSMatthias Ringwald
10214b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION;
10224b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
10234b7d40bbSMatthias Ringwald pos += 2;
10244b7d40bbSMatthias Ringwald event[pos++] = local_seid;
10254b7d40bbSMatthias Ringwald event[pos++] = remote_seid;
10264b7d40bbSMatthias Ringwald event[pos++] = reconfigure;
1027186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_SBC;
10284b7d40bbSMatthias Ringwald
10294b7d40bbSMatthias Ringwald uint8_t sampling_frequency_bitmap = media_codec_information[0] >> 4;
10304b7d40bbSMatthias Ringwald uint8_t channel_mode_bitmap = media_codec_information[0] & 0x0F;
10314b7d40bbSMatthias Ringwald uint8_t block_length_bitmap = media_codec_information[1] >> 4;
10324b7d40bbSMatthias Ringwald uint8_t subbands_bitmap = (media_codec_information[1] & 0x0F) >> 2;
10334b7d40bbSMatthias Ringwald
10344b7d40bbSMatthias Ringwald uint8_t num_channels = 0;
1035a3868652SMatthias Ringwald avdtp_channel_mode_t channel_mode;
1036a3868652SMatthias Ringwald
1037a3868652SMatthias Ringwald if (channel_mode_bitmap & AVDTP_SBC_JOINT_STEREO){
1038a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
10394b7d40bbSMatthias Ringwald num_channels = 2;
1040a3868652SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_STEREO){
1041a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_STEREO;
1042a3868652SMatthias Ringwald num_channels = 2;
1043a3868652SMatthias Ringwald } else if (channel_mode_bitmap & AVDTP_SBC_DUAL_CHANNEL){
1044a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
1045a3868652SMatthias Ringwald num_channels = 2;
1046a3868652SMatthias Ringwald } else {
1047a3868652SMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO;
10484b7d40bbSMatthias Ringwald num_channels = 1;
10494b7d40bbSMatthias Ringwald }
10504b7d40bbSMatthias Ringwald
10514b7d40bbSMatthias Ringwald uint16_t sampling_frequency = 0;
10524b7d40bbSMatthias Ringwald if (sampling_frequency_bitmap & AVDTP_SBC_48000) {
10534b7d40bbSMatthias Ringwald sampling_frequency = 48000;
10544b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_44100) {
10554b7d40bbSMatthias Ringwald sampling_frequency = 44100;
10564b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_32000) {
10574b7d40bbSMatthias Ringwald sampling_frequency = 32000;
10584b7d40bbSMatthias Ringwald } else if (sampling_frequency_bitmap & AVDTP_SBC_16000) {
10594b7d40bbSMatthias Ringwald sampling_frequency = 16000;
10604b7d40bbSMatthias Ringwald }
10614b7d40bbSMatthias Ringwald
10624b7d40bbSMatthias Ringwald uint8_t subbands = 0;
10634b7d40bbSMatthias Ringwald if (subbands_bitmap & AVDTP_SBC_SUBBANDS_8){
10644b7d40bbSMatthias Ringwald subbands = 8;
10654b7d40bbSMatthias Ringwald } else if (subbands_bitmap & AVDTP_SBC_SUBBANDS_4){
10664b7d40bbSMatthias Ringwald subbands = 4;
10674b7d40bbSMatthias Ringwald }
10684b7d40bbSMatthias Ringwald
10694b7d40bbSMatthias Ringwald uint8_t block_length = 0;
10704b7d40bbSMatthias Ringwald if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_16){
10714b7d40bbSMatthias Ringwald block_length = 16;
10724b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_12){
10734b7d40bbSMatthias Ringwald block_length = 12;
10744b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_8){
10754b7d40bbSMatthias Ringwald block_length = 8;
10764b7d40bbSMatthias Ringwald } else if (block_length_bitmap & AVDTP_SBC_BLOCK_LENGTH_4){
10774b7d40bbSMatthias Ringwald block_length = 4;
10784b7d40bbSMatthias Ringwald }
10794b7d40bbSMatthias Ringwald
10804b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency);
10814b7d40bbSMatthias Ringwald pos += 2;
10824b7d40bbSMatthias Ringwald
1083a3868652SMatthias Ringwald event[pos++] = (uint8_t) channel_mode;
10844b7d40bbSMatthias Ringwald event[pos++] = num_channels;
10854b7d40bbSMatthias Ringwald event[pos++] = block_length;
10864b7d40bbSMatthias Ringwald event[pos++] = subbands;
10874b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[1] & 0x03;
10884b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[2];
10894b7d40bbSMatthias Ringwald event[pos++] = media_codec_information[3];
1090186e1970SMatthias Ringwald
1091924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_SBC_EVENT_LEN);
1092186e1970SMatthias Ringwald
1093186e1970SMatthias Ringwald return pos;
10945ce3497fSMatthias Ringwald }
10955ce3497fSMatthias Ringwald
1096186e1970SMatthias Ringwald static uint16_t
avdtp_signaling_setup_media_codec_mpeg_audio_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)1097186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpeg_audio_config_event(uint8_t *event, uint16_t size,
1098a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint,
1099186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure,
11005ce3497fSMatthias Ringwald const uint8_t *media_codec_information) {
11015ce3497fSMatthias Ringwald
1102924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN);
1103186e1970SMatthias Ringwald
11045ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint);
11055ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
11065ce3497fSMatthias Ringwald
1107186e1970SMatthias Ringwald uint16_t pos = 0;
11085ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
1109924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN - 2;
11105ce3497fSMatthias Ringwald
11115ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION;
11125ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
11135ce3497fSMatthias Ringwald pos += 2;
11145ce3497fSMatthias Ringwald event[pos++] = local_seid;
11155ce3497fSMatthias Ringwald event[pos++] = remote_seid;
11165ce3497fSMatthias Ringwald event[pos++] = reconfigure;
1117186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_MPEG_1_2_AUDIO;
11185ce3497fSMatthias Ringwald
11195ce3497fSMatthias Ringwald uint8_t layer_bitmap = media_codec_information[0] >> 5;
11205ce3497fSMatthias Ringwald uint8_t crc = (media_codec_information[0] >> 4) & 0x01;
11215ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] & 0x07);
11225ce3497fSMatthias Ringwald uint8_t mpf = (media_codec_information[1] >> 6) & 0x01;
11235ce3497fSMatthias Ringwald uint8_t sampling_frequency_bitmap = (media_codec_information[1] & 0x3F);
11245ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[2] >> 7) & 0x01;
11255ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[2] & 0x3f) << 8) | media_codec_information[3];
11265ce3497fSMatthias Ringwald
11275ce3497fSMatthias Ringwald uint8_t layer = 0;
11285ce3497fSMatthias Ringwald if (layer_bitmap & 0x04){
11295ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_1;
11305ce3497fSMatthias Ringwald } else if (layer_bitmap & 0x02){
11315ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_2;
11325ce3497fSMatthias Ringwald } else if (layer_bitmap & 0x01){
11335ce3497fSMatthias Ringwald layer = AVDTP_MPEG_LAYER_3;
11345ce3497fSMatthias Ringwald }
11355ce3497fSMatthias Ringwald
11365ce3497fSMatthias Ringwald uint8_t num_channels = 0;
11375ce3497fSMatthias Ringwald avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
11385ce3497fSMatthias Ringwald if (channel_mode_bitmap & 0x08){
11395ce3497fSMatthias Ringwald num_channels = 1;
11405ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO;
11415ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x04){
11425ce3497fSMatthias Ringwald num_channels = 2;
11435ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
11445ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){
11455ce3497fSMatthias Ringwald num_channels = 2;
11465ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_STEREO;
11475ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){
11485ce3497fSMatthias Ringwald num_channels = 2;
11495ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
11505ce3497fSMatthias Ringwald }
11515ce3497fSMatthias Ringwald
11525ce3497fSMatthias Ringwald uint16_t sampling_frequency = 0;
11535ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & 0x01) {
11545ce3497fSMatthias Ringwald sampling_frequency = 48000;
11555ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x02) {
11565ce3497fSMatthias Ringwald sampling_frequency = 44100;
11575ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x04) {
11585ce3497fSMatthias Ringwald sampling_frequency = 32000;
11595ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x08) {
11605ce3497fSMatthias Ringwald sampling_frequency = 24000;
11615ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x10) {
11625ce3497fSMatthias Ringwald sampling_frequency = 22050;
11635ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x20) {
11645ce3497fSMatthias Ringwald sampling_frequency = 16000;
11655ce3497fSMatthias Ringwald }
11665ce3497fSMatthias Ringwald
11675ce3497fSMatthias Ringwald uint8_t bitrate_index = 0;
11685ce3497fSMatthias Ringwald uint8_t i;
11695ce3497fSMatthias Ringwald for (i=0;i<14;i++){
11705ce3497fSMatthias Ringwald if (bit_rate_index_bitmap & (1U << i)) {
11715ce3497fSMatthias Ringwald bitrate_index = i;
11725ce3497fSMatthias Ringwald }
11735ce3497fSMatthias Ringwald }
11745ce3497fSMatthias Ringwald
11755ce3497fSMatthias Ringwald event[pos++] = (uint8_t) layer;
11765ce3497fSMatthias Ringwald event[pos++] = crc;
11775ce3497fSMatthias Ringwald event[pos++] = (uint8_t) channel_mode;
11785ce3497fSMatthias Ringwald event[pos++] = num_channels;
11795ce3497fSMatthias Ringwald event[pos++] = mpf;
11805ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency);
11815ce3497fSMatthias Ringwald pos += 2;
11825ce3497fSMatthias Ringwald event[pos++] = vbr;
11835ce3497fSMatthias Ringwald event[pos++] = bitrate_index;
11845ce3497fSMatthias Ringwald
1185924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_MPEG_AUDIO_EVENT_LEN);
1186186e1970SMatthias Ringwald
1187186e1970SMatthias Ringwald return pos;
11885ce3497fSMatthias Ringwald }
11895ce3497fSMatthias Ringwald
1190186e1970SMatthias Ringwald static uint16_t
avdtp_signaling_setup_media_codec_mpec_aac_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)1191186e1970SMatthias Ringwald avdtp_signaling_setup_media_codec_mpec_aac_config_event(uint8_t *event, uint16_t size,
1192a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint,
1193186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure,
11945ce3497fSMatthias Ringwald const uint8_t *media_codec_information) {
11955ce3497fSMatthias Ringwald
119624d5fe84SMilanka Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN);
1197186e1970SMatthias Ringwald
11985ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint);
11995ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
12005ce3497fSMatthias Ringwald
1201186e1970SMatthias Ringwald uint16_t pos = 0;
12025ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
1203924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN - 2;
12045ce3497fSMatthias Ringwald
12055ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION;
12065ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
12075ce3497fSMatthias Ringwald pos += 2;
12085ce3497fSMatthias Ringwald event[pos++] = local_seid;
12095ce3497fSMatthias Ringwald event[pos++] = remote_seid;
12105ce3497fSMatthias Ringwald event[pos++] = reconfigure;
1211186e1970SMatthias Ringwald event[pos++] =AVDTP_CODEC_MPEG_2_4_AAC;
12125ce3497fSMatthias Ringwald
12131da18615SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 1;
12141da18615SMilanka Ringwald uint8_t drc = media_codec_information[0] & 0x01;
12155ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] << 4) | (media_codec_information[2] >> 4);
12161da18615SMilanka Ringwald uint8_t channels_bitmap = media_codec_information[2] & 0x0F;
12175ce3497fSMatthias Ringwald uint8_t vbr = media_codec_information[3] >> 7;
12185ce3497fSMatthias Ringwald uint32_t bit_rate = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5];
12195ce3497fSMatthias Ringwald
12205ce3497fSMatthias Ringwald uint8_t object_type = 0;
12211da18615SMilanka Ringwald if (object_type_bitmap & 0x01){
12221da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AAC_ELDv2;
12231da18615SMilanka Ringwald } else if (object_type_bitmap & 0x02){
12241da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AACv2;
12251da18615SMilanka Ringwald } else if (object_type_bitmap & 0x04){
12261da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_HE_AAC;
12271da18615SMilanka Ringwald } else if (object_type_bitmap & 0x08){
12285ce3497fSMatthias Ringwald object_type = AVDTP_AAC_MPEG4_SCALABLE;
12291da18615SMilanka Ringwald } else if (object_type_bitmap & 0x10){
12301da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_LTP;
12311da18615SMilanka Ringwald } else if (object_type_bitmap & 0x20){
12321da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG4_LC;
12331da18615SMilanka Ringwald } else if (object_type_bitmap & 0x40){
12341da18615SMilanka Ringwald object_type = AVDTP_AAC_MPEG2_LC;
12355ce3497fSMatthias Ringwald }
12365ce3497fSMatthias Ringwald
1237588a837aSMilanka Ringwald uint32_t sampling_frequency = avdtp_config_get_sampling_frequency_from_table(sampling_frequency_bitmap, aac_sampling_frequency_table, aac_sampling_frequency_table_size);
12385ce3497fSMatthias Ringwald
12395ce3497fSMatthias Ringwald uint8_t num_channels = 0;
12401da18615SMilanka Ringwald if (channels_bitmap & 0x08){
12415ce3497fSMatthias Ringwald num_channels = 1;
12421da18615SMilanka Ringwald } else if (channels_bitmap & 0x04){
12435ce3497fSMatthias Ringwald num_channels = 2;
12441da18615SMilanka Ringwald } else if (channels_bitmap & 0x02){
12451da18615SMilanka Ringwald num_channels = 6;
12461da18615SMilanka Ringwald } else if (channels_bitmap & 0x01){
12471da18615SMilanka Ringwald num_channels = 8;
12485ce3497fSMatthias Ringwald }
12495ce3497fSMatthias Ringwald
12505ce3497fSMatthias Ringwald event[pos++] = object_type;
12515ce3497fSMatthias Ringwald little_endian_store_24(event, pos, sampling_frequency);
12525ce3497fSMatthias Ringwald pos += 3;
12535ce3497fSMatthias Ringwald event[pos++] = num_channels;
12545ce3497fSMatthias Ringwald little_endian_store_24(event, pos, bit_rate);
12555ce3497fSMatthias Ringwald pos += 3;
12565ce3497fSMatthias Ringwald event[pos++] = vbr;
1257b7aa6976SMilanka Ringwald event[pos++] = drc;
12585ce3497fSMatthias Ringwald
1259924216b2SMatthias Ringwald btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_AAC_EVENT_LEN == pos);
1260186e1970SMatthias Ringwald
1261186e1970SMatthias Ringwald return pos;
12625ce3497fSMatthias Ringwald }
12635ce3497fSMatthias Ringwald
126424d5fe84SMilanka Ringwald static uint16_t
avdtp_signaling_setup_media_codec_mpegd_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)126524d5fe84SMilanka Ringwald avdtp_signaling_setup_media_codec_mpegd_config_event(uint8_t *event, uint16_t size,
126624d5fe84SMilanka Ringwald const avdtp_stream_endpoint_t *stream_endpoint,
126724d5fe84SMilanka Ringwald uint16_t avdtp_cid, uint8_t reconfigure,
126824d5fe84SMilanka Ringwald const uint8_t *media_codec_information) {
126924d5fe84SMilanka Ringwald
127024d5fe84SMilanka Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN);
127124d5fe84SMilanka Ringwald
127224d5fe84SMilanka Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint);
127324d5fe84SMilanka Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
127424d5fe84SMilanka Ringwald
127524d5fe84SMilanka Ringwald uint16_t pos = 0;
127624d5fe84SMilanka Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
127724d5fe84SMilanka Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN - 2;
127824d5fe84SMilanka Ringwald
127924d5fe84SMilanka Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_D_USAC_CONFIGURATION;
128024d5fe84SMilanka Ringwald
128124d5fe84SMilanka Ringwald little_endian_store_16(event, pos, avdtp_cid);
128224d5fe84SMilanka Ringwald pos += 2;
128324d5fe84SMilanka Ringwald event[pos++] = local_seid;
128424d5fe84SMilanka Ringwald event[pos++] = remote_seid;
128524d5fe84SMilanka Ringwald event[pos++] = reconfigure;
128624d5fe84SMilanka Ringwald event[pos++] = AVDTP_CODEC_MPEG_D_USAC;
128724d5fe84SMilanka Ringwald
128824d5fe84SMilanka Ringwald uint8_t object_type_bitmap = media_codec_information[0] >> 6;
128924d5fe84SMilanka Ringwald uint32_t sampling_frequency_bitmap = ((media_codec_information[0] & 0x3F) << 20) |
129024d5fe84SMilanka Ringwald (media_codec_information[1] << 12) |
129124d5fe84SMilanka Ringwald (media_codec_information[2] << 4) |
129224d5fe84SMilanka Ringwald (media_codec_information[3] >> 4);
129324d5fe84SMilanka Ringwald
129424d5fe84SMilanka Ringwald uint8_t channels_bitmap = (media_codec_information[3] >> 2) & 0x03;
129524d5fe84SMilanka Ringwald uint8_t vbr = (media_codec_information[4] >> 7) & 0x01;
129624d5fe84SMilanka Ringwald
129724d5fe84SMilanka Ringwald uint32_t bit_rate = ((media_codec_information[3] & 0x7f) << 16) | (media_codec_information[4] << 8) | media_codec_information[5];
129824d5fe84SMilanka Ringwald
129924d5fe84SMilanka Ringwald uint8_t object_type = 0;
130024d5fe84SMilanka Ringwald if (object_type_bitmap & 0x10){
130124d5fe84SMilanka Ringwald object_type = AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC;
130224d5fe84SMilanka Ringwald } else {
130324d5fe84SMilanka Ringwald object_type = AVDTP_USAC_OBJECT_TYPE_RFU;
130424d5fe84SMilanka Ringwald }
130524d5fe84SMilanka Ringwald
1306588a837aSMilanka Ringwald uint32_t sampling_frequency = avdtp_config_get_sampling_frequency_from_table(sampling_frequency_bitmap, usac_sampling_frequency_table, usac_sampling_frequency_table_size );
130724d5fe84SMilanka Ringwald
130824d5fe84SMilanka Ringwald uint8_t num_channels = 0;
130924d5fe84SMilanka Ringwald if (channels_bitmap & 0x02){
131024d5fe84SMilanka Ringwald num_channels = 1;
131124d5fe84SMilanka Ringwald } else if (channels_bitmap & 0x01){
131224d5fe84SMilanka Ringwald num_channels = 2;
131324d5fe84SMilanka Ringwald }
131424d5fe84SMilanka Ringwald
131524d5fe84SMilanka Ringwald event[pos++] = object_type;
131624d5fe84SMilanka Ringwald little_endian_store_24(event, pos, sampling_frequency);
131724d5fe84SMilanka Ringwald pos += 3;
131824d5fe84SMilanka Ringwald event[pos++] = num_channels;
131924d5fe84SMilanka Ringwald event[pos++] = vbr;
132024d5fe84SMilanka Ringwald little_endian_store_24(event, pos, bit_rate);
132124d5fe84SMilanka Ringwald pos += 3;
132224d5fe84SMilanka Ringwald
132324d5fe84SMilanka Ringwald btstack_assert(AVDTP_MEDIA_CONFIG_MPEG_D_USAC_EVENT_LEN == pos);
132424d5fe84SMilanka Ringwald
132524d5fe84SMilanka Ringwald return pos;
132624d5fe84SMilanka Ringwald }
132724d5fe84SMilanka Ringwald
avdtp_signaling_setup_media_codec_atrac_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const uint8_t * media_codec_information)1328186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_atrac_config_event(uint8_t *event, uint16_t size,
1329a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint,
1330186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure,
1331186e1970SMatthias Ringwald const uint8_t *media_codec_information) {
1332924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN);
1333186e1970SMatthias Ringwald
13345ce3497fSMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint);
13355ce3497fSMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
13365ce3497fSMatthias Ringwald
1337186e1970SMatthias Ringwald uint16_t pos = 0;
13385ce3497fSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
1339924216b2SMatthias Ringwald event[pos++] = AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN - 2;
13405ce3497fSMatthias Ringwald
13415ce3497fSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION;
13425ce3497fSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
13435ce3497fSMatthias Ringwald pos += 2;
13445ce3497fSMatthias Ringwald event[pos++] = local_seid;
13455ce3497fSMatthias Ringwald event[pos++] = remote_seid;
13465ce3497fSMatthias Ringwald event[pos++] = reconfigure;
1347186e1970SMatthias Ringwald event[pos++] = AVDTP_CODEC_ATRAC_FAMILY;
13485ce3497fSMatthias Ringwald
1349b5bbcbf4SMatthias Ringwald avdtp_atrac_version_t version = (avdtp_atrac_version_t) (media_codec_information[0] >> 5);
13505ce3497fSMatthias Ringwald uint8_t channel_mode_bitmap = (media_codec_information[0] >> 2) & 0x07;
13515ce3497fSMatthias Ringwald uint16_t sampling_frequency_bitmap = (media_codec_information[1] >> 4) & 0x03;
13525ce3497fSMatthias Ringwald uint8_t vbr = (media_codec_information[1] >> 3) & 0x01;
13535ce3497fSMatthias Ringwald uint16_t bit_rate_index_bitmap = ((media_codec_information[1]) & 0x07) << 16 | (media_codec_information[2] << 8) | media_codec_information[3];
13545ce3497fSMatthias Ringwald uint16_t maximum_sul = (media_codec_information[4] << 8) | media_codec_information[5];
13555ce3497fSMatthias Ringwald
13565ce3497fSMatthias Ringwald uint8_t num_channels = 0;
13575ce3497fSMatthias Ringwald avdtp_channel_mode_t channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
13585ce3497fSMatthias Ringwald if (channel_mode_bitmap & 0x04){
13595ce3497fSMatthias Ringwald num_channels = 1;
13605ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_MONO;
13615ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x02){
13625ce3497fSMatthias Ringwald num_channels = 2;
13635ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_DUAL_CHANNEL;
13645ce3497fSMatthias Ringwald } else if (channel_mode_bitmap & 0x01){
13655ce3497fSMatthias Ringwald num_channels = 2;
13665ce3497fSMatthias Ringwald channel_mode = AVDTP_CHANNEL_MODE_JOINT_STEREO;
13675ce3497fSMatthias Ringwald }
13685ce3497fSMatthias Ringwald
13695ce3497fSMatthias Ringwald uint16_t sampling_frequency = 0;
13705ce3497fSMatthias Ringwald if (sampling_frequency_bitmap & 0x02){
13715ce3497fSMatthias Ringwald sampling_frequency = 44100;
13725ce3497fSMatthias Ringwald } else if (sampling_frequency_bitmap & 0x01){
13735ce3497fSMatthias Ringwald sampling_frequency = 48000;
13745ce3497fSMatthias Ringwald }
13755ce3497fSMatthias Ringwald
13765ce3497fSMatthias Ringwald // bit 0 = index 0x18, bit 19 = index 0
13775ce3497fSMatthias Ringwald uint8_t bit_rate_index = 0;
13785ce3497fSMatthias Ringwald uint8_t i;
13795ce3497fSMatthias Ringwald for (i=0;i <= 19;i++){
13805ce3497fSMatthias Ringwald if (bit_rate_index_bitmap & (1U << i)) {
13815ce3497fSMatthias Ringwald bit_rate_index = 18 - i;
13825ce3497fSMatthias Ringwald }
13835ce3497fSMatthias Ringwald }
13845ce3497fSMatthias Ringwald
13855ce3497fSMatthias Ringwald event[pos++] = (uint8_t) version;
13865ce3497fSMatthias Ringwald event[pos++] = (uint8_t) channel_mode;
13875ce3497fSMatthias Ringwald event[pos++] = num_channels;
13885ce3497fSMatthias Ringwald little_endian_store_16(event, pos, sampling_frequency);
13895ce3497fSMatthias Ringwald pos += 2;
13905ce3497fSMatthias Ringwald event[pos++] = vbr;
13915ce3497fSMatthias Ringwald event[pos++] = bit_rate_index;
13925ce3497fSMatthias Ringwald little_endian_store_16(event, pos, maximum_sul);
13935ce3497fSMatthias Ringwald pos += 2;
13945ce3497fSMatthias Ringwald
1395924216b2SMatthias Ringwald btstack_assert(pos == AVDTP_MEDIA_CONFIG_ATRAC_EVENT_LEN);
1396186e1970SMatthias Ringwald return pos;
13974b7d40bbSMatthias Ringwald }
13984b7d40bbSMatthias Ringwald
avdtp_signaling_setup_media_codec_other_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const adtvp_media_codec_capabilities_t * media_codec)1399186e1970SMatthias Ringwald static uint16_t avdtp_signaling_setup_media_codec_other_config_event(uint8_t *event, uint16_t size,
1400a905535cSMatthias Ringwald const avdtp_stream_endpoint_t *stream_endpoint,
1401186e1970SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure,
1402186e1970SMatthias Ringwald const adtvp_media_codec_capabilities_t *media_codec) {
1403924216b2SMatthias Ringwald btstack_assert(size >= AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN);
1404186e1970SMatthias Ringwald
14056c069ec9SMatthias Ringwald uint8_t local_seid = avdtp_local_seid(stream_endpoint);
14066c069ec9SMatthias Ringwald uint8_t remote_seid = avdtp_remote_seid(stream_endpoint);
14076c069ec9SMatthias Ringwald
1408186e1970SMatthias Ringwald uint16_t pos = 0;
14094b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
141073048ce6SMatthias Ringwald pos++; // set later
14114b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION;
14124b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
14134b7d40bbSMatthias Ringwald pos += 2;
14144b7d40bbSMatthias Ringwald event[pos++] = local_seid;
14154b7d40bbSMatthias Ringwald event[pos++] = remote_seid;
14164b7d40bbSMatthias Ringwald event[pos++] = reconfigure;
1417e8a431c1SMatthias Ringwald event[pos++] = media_codec->media_type;
1418e8a431c1SMatthias Ringwald little_endian_store_16(event, pos, media_codec->media_codec_type);
14194b7d40bbSMatthias Ringwald pos += 2;
1420e8a431c1SMatthias Ringwald little_endian_store_16(event, pos, media_codec->media_codec_information_len);
14214b7d40bbSMatthias Ringwald pos += 2;
1422186e1970SMatthias Ringwald
1423186e1970SMatthias Ringwald btstack_assert(pos == 13);
1424186e1970SMatthias Ringwald
1425924216b2SMatthias Ringwald uint16_t media_codec_len = btstack_min(AVDTP_MAX_MEDIA_CODEC_INFORMATION_LENGTH, media_codec->media_codec_information_len);
1426e8a431c1SMatthias Ringwald (void)memcpy(event + pos, media_codec->media_codec_information, media_codec_len);
142773048ce6SMatthias Ringwald pos += media_codec_len;
142873048ce6SMatthias Ringwald event[1] = pos - 2;
1429186e1970SMatthias Ringwald return pos;
14304b7d40bbSMatthias Ringwald }
14314b7d40bbSMatthias Ringwald
avdtp_signaling_emit_delay(uint16_t avdtp_cid,uint8_t local_seid,uint16_t delay)14324b7d40bbSMatthias Ringwald void avdtp_signaling_emit_delay(uint16_t avdtp_cid, uint8_t local_seid, uint16_t delay) {
14334b7d40bbSMatthias Ringwald uint8_t event[8];
14344b7d40bbSMatthias Ringwald int pos = 0;
14354b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
14364b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2;
14374b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_SIGNALING_DELAY_REPORT;
14384b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
14394b7d40bbSMatthias Ringwald pos += 2;
14404b7d40bbSMatthias Ringwald event[pos++] = local_seid;
14414b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, delay);
14424b7d40bbSMatthias Ringwald pos += 2;
14436e64e62bSMatthias Ringwald avdtp_emit_source(event, pos);
14444b7d40bbSMatthias Ringwald }
14454b7d40bbSMatthias Ringwald
avdtp_setup_media_codec_config_event(uint8_t * event,uint16_t size,const avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,const adtvp_media_codec_capabilities_t * media_codec)1446a905535cSMatthias Ringwald uint16_t avdtp_setup_media_codec_config_event(uint8_t *event, uint16_t size, const avdtp_stream_endpoint_t *stream_endpoint,
1447924216b2SMatthias Ringwald uint16_t avdtp_cid, uint8_t reconfigure,
14482965b0e6SMatthias Ringwald const adtvp_media_codec_capabilities_t * media_codec) {
14492965b0e6SMatthias Ringwald switch (media_codec->media_codec_type){
1450924216b2SMatthias Ringwald case AVDTP_CODEC_SBC:
1451924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_sbc_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14522965b0e6SMatthias Ringwald media_codec->media_codec_information);
1453924216b2SMatthias Ringwald case AVDTP_CODEC_MPEG_1_2_AUDIO:
1454924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_mpeg_audio_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14552965b0e6SMatthias Ringwald media_codec->media_codec_information);
1456924216b2SMatthias Ringwald case AVDTP_CODEC_MPEG_2_4_AAC:
1457924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_mpec_aac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14582965b0e6SMatthias Ringwald media_codec->media_codec_information);
1459924216b2SMatthias Ringwald case AVDTP_CODEC_ATRAC_FAMILY:
1460924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_atrac_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14612965b0e6SMatthias Ringwald media_codec->media_codec_information);
146224d5fe84SMilanka Ringwald case AVDTP_CODEC_MPEG_D_USAC:
146324d5fe84SMilanka Ringwald return avdtp_signaling_setup_media_codec_mpegd_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
146424d5fe84SMilanka Ringwald media_codec->media_codec_information);
1465924216b2SMatthias Ringwald default:
1466924216b2SMatthias Ringwald return avdtp_signaling_setup_media_codec_other_config_event(event, size, stream_endpoint, avdtp_cid, reconfigure,
14672965b0e6SMatthias Ringwald media_codec);
1468924216b2SMatthias Ringwald }
1469924216b2SMatthias Ringwald }
1470924216b2SMatthias Ringwald
avdtp_signaling_emit_configuration(avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t reconfigure,avdtp_capabilities_t * configuration,uint16_t configured_service_categories)14716c5b303cSMatthias Ringwald void avdtp_signaling_emit_configuration(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t reconfigure,
14724b7d40bbSMatthias Ringwald avdtp_capabilities_t *configuration, uint16_t configured_service_categories) {
14734b7d40bbSMatthias Ringwald
14744b7d40bbSMatthias Ringwald if (get_bit16(configured_service_categories, AVDTP_MEDIA_CODEC)){
1475186e1970SMatthias Ringwald uint16_t pos = 0;
1476186e1970SMatthias Ringwald // assume MEDIA_CONFIG_OTHER_EVENT_LEN is larger than all other events
1477924216b2SMatthias Ringwald uint8_t event[AVDTP_MEDIA_CONFIG_OTHER_EVENT_LEN];
1478924216b2SMatthias Ringwald pos = avdtp_setup_media_codec_config_event(event, sizeof(event), stream_endpoint, avdtp_cid, reconfigure,
14792965b0e6SMatthias Ringwald &configuration->media_codec);
1480186e1970SMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
1481186e1970SMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
14824b7d40bbSMatthias Ringwald }
14834b7d40bbSMatthias Ringwald }
14844b7d40bbSMatthias Ringwald
avdtp_streaming_emit_connection_established(avdtp_stream_endpoint_t * stream_endpoint,uint8_t status)14854b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_established(avdtp_stream_endpoint_t *stream_endpoint, uint8_t status) {
14864b7d40bbSMatthias Ringwald uint8_t event[14];
14874b7d40bbSMatthias Ringwald int pos = 0;
14884b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
14894b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2;
14904b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED;
14914b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid);
14924b7d40bbSMatthias Ringwald pos += 2;
14934b7d40bbSMatthias Ringwald reverse_bd_addr(stream_endpoint->connection->remote_addr, &event[pos]);
14944b7d40bbSMatthias Ringwald pos += 6;
14954b7d40bbSMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint);
14964b7d40bbSMatthias Ringwald event[pos++] = avdtp_remote_seid(stream_endpoint);
14974b7d40bbSMatthias Ringwald event[pos++] = status;
14984b7d40bbSMatthias Ringwald
14994b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
15006e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
15014b7d40bbSMatthias Ringwald }
15024b7d40bbSMatthias Ringwald
avdtp_streaming_emit_connection_released(avdtp_stream_endpoint_t * stream_endpoint,uint16_t avdtp_cid,uint8_t local_seid)15034b7d40bbSMatthias Ringwald void avdtp_streaming_emit_connection_released(avdtp_stream_endpoint_t *stream_endpoint, uint16_t avdtp_cid, uint8_t local_seid) {
15044b7d40bbSMatthias Ringwald uint8_t event[6];
15054b7d40bbSMatthias Ringwald int pos = 0;
15064b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
15074b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2;
15084b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED;
15094b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, avdtp_cid);
15104b7d40bbSMatthias Ringwald pos += 2;
15114b7d40bbSMatthias Ringwald event[pos++] = local_seid;
15124b7d40bbSMatthias Ringwald
15134b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
15146e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
15154b7d40bbSMatthias Ringwald }
15164b7d40bbSMatthias Ringwald
avdtp_streaming_emit_can_send_media_packet_now(avdtp_stream_endpoint_t * stream_endpoint,uint16_t sequence_number)15174b7d40bbSMatthias Ringwald void avdtp_streaming_emit_can_send_media_packet_now(avdtp_stream_endpoint_t *stream_endpoint, uint16_t sequence_number) {
15184b7d40bbSMatthias Ringwald uint8_t event[8];
15194b7d40bbSMatthias Ringwald int pos = 0;
15204b7d40bbSMatthias Ringwald event[pos++] = HCI_EVENT_AVDTP_META;
15214b7d40bbSMatthias Ringwald event[pos++] = sizeof(event) - 2;
15224b7d40bbSMatthias Ringwald event[pos++] = AVDTP_SUBEVENT_STREAMING_CAN_SEND_MEDIA_PACKET_NOW;
15234b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, stream_endpoint->connection->avdtp_cid);
15244b7d40bbSMatthias Ringwald pos += 2;
15254b7d40bbSMatthias Ringwald event[pos++] = avdtp_local_seid(stream_endpoint);
15264b7d40bbSMatthias Ringwald little_endian_store_16(event, pos, sequence_number);
15274b7d40bbSMatthias Ringwald pos += 2;
15286e64e62bSMatthias Ringwald event[1] = pos - 2;
15294b7d40bbSMatthias Ringwald
15304b7d40bbSMatthias Ringwald btstack_packet_handler_t packet_handler = avdtp_packet_handler_for_stream_endpoint(stream_endpoint);
15316e64e62bSMatthias Ringwald (*packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
15324b7d40bbSMatthias Ringwald }
15334b7d40bbSMatthias Ringwald
avdtp_request_can_send_now_acceptor(avdtp_connection_t * connection)1534d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_acceptor(avdtp_connection_t *connection) {
153523edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1536d80ccd43SMatthias Ringwald connection->wait_to_send_acceptor = true;
1537d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(connection->l2cap_signaling_cid);
15389974aee0SMilanka Ringwald return ERROR_CODE_SUCCESS;
15398ef7100fSMilanka Ringwald }
15409974aee0SMilanka Ringwald
avdtp_request_can_send_now_initiator(avdtp_connection_t * connection)1541d80ccd43SMatthias Ringwald uint8_t avdtp_request_can_send_now_initiator(avdtp_connection_t *connection) {
154223edb87eSMilanka Ringwald if (!connection) return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1543d80ccd43SMatthias Ringwald connection->wait_to_send_initiator = true;
1544d80ccd43SMatthias Ringwald l2cap_request_can_send_now_event(connection->l2cap_signaling_cid);
15459974aee0SMilanka Ringwald return ERROR_CODE_SUCCESS;
15468ef7100fSMilanka Ringwald }
15479974aee0SMilanka Ringwald
avdtp_local_seid(const avdtp_stream_endpoint_t * stream_endpoint)1548a905535cSMatthias Ringwald uint8_t avdtp_local_seid(const avdtp_stream_endpoint_t * stream_endpoint){
15494ccacc40SMilanka Ringwald if (!stream_endpoint) return 0;
15504ccacc40SMilanka Ringwald return stream_endpoint->sep.seid;
15514ccacc40SMilanka Ringwald
15524ccacc40SMilanka Ringwald }
15534ccacc40SMilanka Ringwald
avdtp_remote_seid(const avdtp_stream_endpoint_t * stream_endpoint)1554a905535cSMatthias Ringwald uint8_t avdtp_remote_seid(const avdtp_stream_endpoint_t * stream_endpoint){
1555485c0a4cSMilanka Ringwald if (!stream_endpoint) return AVDTP_INVALID_SEP_SEID;
1556485c0a4cSMilanka Ringwald return stream_endpoint->remote_sep.seid;
15574ccacc40SMilanka Ringwald }
1558ef5ad9d6SMilanka Ringwald
1559fdd788feSMatthias Ringwald // helper to set/get configuration
avdtp_config_sbc_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1560ea8aa208SMilanka Ringwald uint8_t avdtp_config_sbc_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz){
1561588a837aSMilanka Ringwald uint8_t sampling_frequency_bitmap = (uint8_t)avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, sbc_sampling_frequency_table, sbc_sampling_frequency_table_size);
1562ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){
1563ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1564ea8aa208SMilanka Ringwald }
1565ea8aa208SMilanka Ringwald config[0] = (config[0] & 0x0f) | (uint8_t)(sampling_frequency_bitmap << 4);
1566ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS;
1567fdd788feSMatthias Ringwald }
1568fdd788feSMatthias Ringwald
avdtp_config_sbc_store(uint8_t * config,const avdtp_configuration_sbc_t * configuration)1569ea8aa208SMilanka Ringwald uint8_t avdtp_config_sbc_store(uint8_t * config, const avdtp_configuration_sbc_t * configuration){
1570ea8aa208SMilanka Ringwald if (configuration->channel_mode > AVDTP_CHANNEL_MODE_JOINT_STEREO){
1571ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1572ea8aa208SMilanka Ringwald }
1573ea8aa208SMilanka Ringwald if (configuration->allocation_method > AVDTP_SBC_ALLOCATION_METHOD_SNR){
1574ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1575ea8aa208SMilanka Ringwald }
1576858500b1SMilanka Ringwald
1577858500b1SMilanka Ringwald switch ((avdtp_sbc_block_length_t)configuration->block_length){
1578858500b1SMilanka Ringwald case AVDTP_SBC_BLOCK_LENGTH_4:
1579858500b1SMilanka Ringwald case AVDTP_SBC_BLOCK_LENGTH_8:
1580858500b1SMilanka Ringwald case AVDTP_SBC_BLOCK_LENGTH_12:
1581858500b1SMilanka Ringwald case AVDTP_SBC_BLOCK_LENGTH_16:
1582fdd788feSMatthias Ringwald break;
1583fdd788feSMatthias Ringwald default:
1584ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1585fdd788feSMatthias Ringwald }
1586858500b1SMilanka Ringwald switch ((avdtp_sbc_subbands_t)configuration->subbands){
1587858500b1SMilanka Ringwald case AVDTP_SBC_SUBBANDS_4:
1588858500b1SMilanka Ringwald case AVDTP_SBC_SUBBANDS_8:
1589ea8aa208SMilanka Ringwald break;
1590ea8aa208SMilanka Ringwald default:
1591ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1592ea8aa208SMilanka Ringwald }
1593ea8aa208SMilanka Ringwald if ((configuration->min_bitpool_value < 2) || (configuration->min_bitpool_value > 250) || (configuration->min_bitpool_value > configuration->max_bitpool_value)){
1594ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1595ea8aa208SMilanka Ringwald }
1596ea8aa208SMilanka Ringwald if ((configuration->max_bitpool_value < 2) || (configuration->max_bitpool_value > 250)){
1597ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1598ea8aa208SMilanka Ringwald }
1599ea8aa208SMilanka Ringwald config[0] = 1 << (3 - (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO));
16008691a66cSMatthias Ringwald config[1] = (configuration->block_length << 4) | (configuration->subbands << 2) | configuration->allocation_method;
16018691a66cSMatthias Ringwald config[2] = configuration->min_bitpool_value;
16028691a66cSMatthias Ringwald config[3] = configuration->max_bitpool_value;
1603ea8aa208SMilanka Ringwald return avdtp_config_sbc_set_sampling_frequency(config, configuration->sampling_frequency);
1604fdd788feSMatthias Ringwald }
1605fdd788feSMatthias Ringwald
avdtp_config_mpeg_audio_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1606ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_audio_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) {
1607588a837aSMilanka Ringwald uint8_t sampling_frequency_bitmap = (uint8_t)avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, mpeg_sampling_frequency_table, mpeg_sampling_frequency_table_size);
1608ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){
1609ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1610ea8aa208SMilanka Ringwald }
1611ea8aa208SMilanka Ringwald config[1] = (config[1] & 0xE0) | sampling_frequency_bitmap;
1612ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS;
1613fdd788feSMatthias Ringwald }
1614fdd788feSMatthias Ringwald
avdtp_config_mpeg_audio_store(uint8_t * config,const avdtp_configuration_mpeg_audio_t * configuration)1615ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_audio_store(uint8_t * config, const avdtp_configuration_mpeg_audio_t * configuration){
1616ea8aa208SMilanka Ringwald if (configuration->layer > AVDTP_MPEG_LAYER_3){
1617ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1618ea8aa208SMilanka Ringwald }
1619ea8aa208SMilanka Ringwald if (configuration->channel_mode > AVDTP_CHANNEL_MODE_JOINT_STEREO){
1620ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1621ea8aa208SMilanka Ringwald }
1622ea8aa208SMilanka Ringwald uint16_t bit_rate_mask = 1 << configuration->bit_rate_index;
1623ea8aa208SMilanka Ringwald if (bit_rate_mask == 0){
1624ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1625ea8aa208SMilanka Ringwald }
1626ea8aa208SMilanka Ringwald
16278691a66cSMatthias Ringwald config[0] = (1 << (7 - (configuration->layer - AVDTP_MPEG_LAYER_1))) | ((configuration->crc & 0x01) << 4) | (1 << (configuration->channel_mode - AVDTP_CHANNEL_MODE_MONO));
16288691a66cSMatthias Ringwald config[1] = ((configuration->media_payload_format & 0x01) << 6) ;
16291da18615SMilanka Ringwald config[2] = ((configuration->vbr & 0x01) << 7) | ((bit_rate_mask >> 7) & 0x3f);
1630fdd788feSMatthias Ringwald config[3] = bit_rate_mask & 0xff;
1631ea8aa208SMilanka Ringwald return avdtp_config_mpeg_audio_set_sampling_frequency(config, configuration->sampling_frequency);
1632fdd788feSMatthias Ringwald }
1633fdd788feSMatthias Ringwald
avdtp_config_mpeg_aac_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1634ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) {
1635588a837aSMilanka Ringwald uint16_t sampling_frequency_bitmap = (uint16_t)avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, aac_sampling_frequency_table, aac_sampling_frequency_table_size);
1636ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){
1637ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1638ea8aa208SMilanka Ringwald }
1639ea8aa208SMilanka Ringwald
1640fdd788feSMatthias Ringwald config[1] = sampling_frequency_bitmap >> 4;
1641fdd788feSMatthias Ringwald config[2] = ((sampling_frequency_bitmap & 0x0f) << 4) | (config[2] & 0x0f);
1642ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS;
1643fdd788feSMatthias Ringwald }
1644fdd788feSMatthias Ringwald
avdtp_config_mpeg_aac_store(uint8_t * config,const avdtp_configuration_mpeg_aac_t * configuration)1645c83b8b89SMilanka Ringwald uint8_t avdtp_config_mpeg_aac_store(uint8_t * config, const avdtp_configuration_mpeg_aac_t * configuration) {
16460737c3bfSMilanka Ringwald config[0] = (1 << (7 -(configuration->object_type - AVDTP_AAC_MPEG2_LC))) | (configuration->drc?1u:0u);
1647fdd788feSMatthias Ringwald uint8_t channels_bitmap = 0;
16488691a66cSMatthias Ringwald switch (configuration->channels){
1649fdd788feSMatthias Ringwald case 1:
16500737c3bfSMilanka Ringwald channels_bitmap = 0x08;
1651fdd788feSMatthias Ringwald break;
1652fdd788feSMatthias Ringwald case 2:
16530737c3bfSMilanka Ringwald channels_bitmap = 0x04;
16540737c3bfSMilanka Ringwald break;
16550737c3bfSMilanka Ringwald case 6:
16560737c3bfSMilanka Ringwald channels_bitmap = 0x02;
16570737c3bfSMilanka Ringwald break;
16580737c3bfSMilanka Ringwald case 8:
1659fdd788feSMatthias Ringwald channels_bitmap = 0x01;
1660fdd788feSMatthias Ringwald break;
1661fdd788feSMatthias Ringwald default:
1662c83b8b89SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1663fdd788feSMatthias Ringwald }
1664c83b8b89SMilanka Ringwald config[2] = channels_bitmap;
16658691a66cSMatthias Ringwald config[3] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f);
16668691a66cSMatthias Ringwald config[4] = (configuration->bit_rate >> 8) & 0xff;
16678691a66cSMatthias Ringwald config[5] = configuration->bit_rate & 0xff;
1668ea8aa208SMilanka Ringwald return avdtp_config_mpeg_aac_set_sampling_frequency(config, configuration->sampling_frequency);
1669ea8aa208SMilanka Ringwald }
1670ea8aa208SMilanka Ringwald
avdtp_config_atrac_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1671ea8aa208SMilanka Ringwald uint8_t avdtp_config_atrac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) {
1672588a837aSMilanka Ringwald uint8_t sampling_frequency_bitmap = (uint8_t)avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, atrac_sampling_frequency_table, atrac_sampling_frequency_table_size);
1673ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){
1674ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1675ea8aa208SMilanka Ringwald }
1676ea8aa208SMilanka Ringwald
1677ea8aa208SMilanka Ringwald config[1] = (config[1] & 0xCF) | (uint8_t)(sampling_frequency_bitmap << 4);
1678c83b8b89SMilanka Ringwald return ERROR_CODE_SUCCESS;
1679fdd788feSMatthias Ringwald }
1680fdd788feSMatthias Ringwald
avdtp_config_atrac_store(uint8_t * config,const avdtp_configuration_atrac_t * configuration)1681ea8aa208SMilanka Ringwald uint8_t avdtp_config_atrac_store(uint8_t * config, const avdtp_configuration_atrac_t * configuration){
1682a3868652SMatthias Ringwald uint8_t channel_mode_bitmap = 0;
16838691a66cSMatthias Ringwald switch (configuration->channel_mode){
1684fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_MONO:
1685a3868652SMatthias Ringwald channel_mode_bitmap = 4;
1686fdd788feSMatthias Ringwald break;
1687fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_DUAL_CHANNEL:
1688a3868652SMatthias Ringwald channel_mode_bitmap = 2;
1689fdd788feSMatthias Ringwald break;
1690fdd788feSMatthias Ringwald case AVDTP_CHANNEL_MODE_JOINT_STEREO:
1691a3868652SMatthias Ringwald channel_mode_bitmap = 1;
1692fdd788feSMatthias Ringwald break;
1693fdd788feSMatthias Ringwald default:
1694ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1695fdd788feSMatthias Ringwald }
16968691a66cSMatthias Ringwald config[0] = ((configuration->version - AVDTP_ATRAC_VERSION_1 + 1) << 5) | (channel_mode_bitmap << 2);
16978691a66cSMatthias Ringwald uint32_t bit_rate_bitmap = 1 << (0x18 - configuration->bit_rate_index);
16988691a66cSMatthias Ringwald config[1] = ((configuration->vbr & 0x01) << 3) | ((bit_rate_bitmap >> 16) & 0x07);
1699fdd788feSMatthias Ringwald config[2] = (bit_rate_bitmap >> 8) & 0xff;
1700fdd788feSMatthias Ringwald config[3] = bit_rate_bitmap & 0xff;
17018691a66cSMatthias Ringwald config[4] = configuration->maximum_sul >> 8;
17028691a66cSMatthias Ringwald config[5] = configuration->maximum_sul & 0xff;
1703fdd788feSMatthias Ringwald config[6] = 0;
1704ea8aa208SMilanka Ringwald return avdtp_config_atrac_set_sampling_frequency(config, configuration->sampling_frequency);
1705fdd788feSMatthias Ringwald }
170624d5fe84SMilanka Ringwald
avdtp_config_mpegd_usac_set_sampling_frequency(uint8_t * config,uint16_t sampling_frequency_hz)1707ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpegd_usac_set_sampling_frequency(uint8_t * config, uint16_t sampling_frequency_hz) {
1708588a837aSMilanka Ringwald uint32_t sampling_frequency_bitmap = avdtp_config_get_sampling_frequency_bitmap_from_table(sampling_frequency_hz, usac_sampling_frequency_table, usac_sampling_frequency_table_size);
1709ea8aa208SMilanka Ringwald if (sampling_frequency_bitmap == 0){
1710ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1711ea8aa208SMilanka Ringwald }
1712ea8aa208SMilanka Ringwald config[0] = (config[0] & 0xC0) | (uint8_t)(sampling_frequency_bitmap >> 20);
1713ea8aa208SMilanka Ringwald config[1] = (uint8_t) (sampling_frequency_bitmap >> 12);
1714ea8aa208SMilanka Ringwald config[2] = (uint8_t) (sampling_frequency_bitmap >> 4);
171524d5fe84SMilanka Ringwald config[3] = (sampling_frequency_bitmap & 0x0f) << 4;
1716ea8aa208SMilanka Ringwald return ERROR_CODE_SUCCESS;
171724d5fe84SMilanka Ringwald }
171824d5fe84SMilanka Ringwald
avdtp_config_mpegd_usac_store(uint8_t * config,const avdtp_configuration_mpegd_usac_t * configuration)1719ea8aa208SMilanka Ringwald uint8_t avdtp_config_mpegd_usac_store(uint8_t * config, const avdtp_configuration_mpegd_usac_t * configuration) {
1720ea8aa208SMilanka Ringwald if (configuration->object_type != AVDTP_USAC_OBJECT_TYPE_MPEG_D_DRC){
1721ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
1722ea8aa208SMilanka Ringwald }
1723ea8aa208SMilanka Ringwald config[0] = 0x80;
172424d5fe84SMilanka Ringwald
172524d5fe84SMilanka Ringwald uint8_t channels_bitmap = 0;
172624d5fe84SMilanka Ringwald switch (configuration->channels){
172724d5fe84SMilanka Ringwald case 1:
172824d5fe84SMilanka Ringwald channels_bitmap = 0x08;
172924d5fe84SMilanka Ringwald break;
173024d5fe84SMilanka Ringwald case 2:
173124d5fe84SMilanka Ringwald channels_bitmap = 0x04;
173224d5fe84SMilanka Ringwald break;
173324d5fe84SMilanka Ringwald default:
1734ea8aa208SMilanka Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
173524d5fe84SMilanka Ringwald }
173624d5fe84SMilanka Ringwald config[3] = config[3] | channels_bitmap;
173724d5fe84SMilanka Ringwald config[4] = ((configuration->vbr & 0x01) << 7) | ((configuration->bit_rate >> 16) & 0x7f);
173824d5fe84SMilanka Ringwald config[5] = (configuration->bit_rate >> 8) & 0xff;
173924d5fe84SMilanka Ringwald config[6] = configuration->bit_rate & 0xff;
1740ea8aa208SMilanka Ringwald return avdtp_config_mpegd_usac_set_sampling_frequency(config, configuration->sampling_frequency);
174124d5fe84SMilanka Ringwald }