xref: /btstack/src/classic/a2dp.c (revision ced70f9bfeafe291ec597a3a9cc862e39e0da3ce)
1 /*
2  * Copyright (C) 2022 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #include <stdint.h>
39 #include <string.h>
40 #include "a2dp.h"
41 #include "l2cap.h"
42 #include "classic/sdp_util.h"
43 #include "classic/avdtp_source.h"
44 #include "classic/a2dp_source.h"
45 #include "btstack_event.h"
46 #include "bluetooth_sdp.h"
47 #include "bluetooth_psm.h"
48 
49 #define BTSTACK_FILE__ "a2dp.c"
50 
51 #include <stddef.h>
52 #include "bluetooth.h"
53 #include "classic/a2dp.h"
54 #include "classic/avdtp_util.h"
55 #include "btstack_debug.h"
56 
57 // ENABLE_A2DP_SOURCE_EXPLICIT_CONFIG has been replaced by ENABLE_A2DP_EXPLICIT_CONFIG which is valid for both roles
58 #ifdef  ENABLE_A2DP_SOURCE_EXPLICIT_CONFIG
59 #error "Please define ENABLE_A2DP_EXPLICIT_CONFIG instead of ENABLE_A2DP_SOURCE_EXPLICIT_CONFIG"
60 #endif
61 
62 #define AVDTP_MAX_SEP_NUM 10
63 #define A2DP_SET_CONFIG_DELAY_MS 200
64 
65 static void a2dp_config_process_discover_seps_with_next_waiting_connection(void);
66 
67 // higher layer callbacks
68 static btstack_packet_handler_t a2dp_source_callback;
69 static btstack_packet_handler_t a2dp_sink_callback;
70 
71 // config process - singletons using sep_discovery_cid is used as mutex
72 static avdtp_role_t             a2dp_config_process_role;
73 static uint16_t                 a2dp_config_process_sep_discovery_cid;
74 static uint16_t                 a2dp_config_process_sep_discovery_count;
75 static uint16_t                 a2dp_config_process_sep_discovery_index;
76 static avdtp_sep_t              a2dp_config_process_sep_discovery_seps[AVDTP_MAX_SEP_NUM];
77 static btstack_timer_source_t   a2dp_config_process_set_config_timer;
78 static bool                     a2dp_config_process_set_config_timer_active;
79 
80 void a2dp_init(void) {
81 }
82 
83 void a2dp_deinit(void){
84     a2dp_config_process_sep_discovery_cid = 0;
85     a2dp_source_callback = NULL;
86     a2dp_sink_callback = NULL;
87 }
88 
89 void a2dp_create_sdp_record(uint8_t * service,  uint32_t service_record_handle, uint16_t service_class_uuid, uint16_t supported_features, const char * service_name, const char * service_provider_name){
90     uint8_t* attribute;
91     de_create_sequence(service);
92 
93     // 0x0000 "Service Record Handle"
94     de_add_number(service, DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_RECORD_HANDLE);
95     de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle);
96 
97     // 0x0001 "Service Class ID List"
98     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_SERVICE_CLASS_ID_LIST);
99     attribute = de_push_sequence(service);
100     {
101         de_add_number(attribute, DE_UUID, DE_SIZE_16, service_class_uuid);
102     }
103     de_pop_sequence(service, attribute);
104 
105     // 0x0004 "Protocol Descriptor List"
106     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST);
107     attribute = de_push_sequence(service);
108     {
109         uint8_t* l2cpProtocol = de_push_sequence(attribute);
110         {
111             de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_L2CAP);
112             de_add_number(l2cpProtocol,  DE_UINT, DE_SIZE_16, BLUETOOTH_PSM_AVDTP);
113         }
114         de_pop_sequence(attribute, l2cpProtocol);
115 
116         uint8_t* avProtocol = de_push_sequence(attribute);
117         {
118             de_add_number(avProtocol,  DE_UUID, DE_SIZE_16, BLUETOOTH_PROTOCOL_AVDTP);  // avProtocol_service
119             de_add_number(avProtocol,  DE_UINT, DE_SIZE_16,  0x0103);  // version
120         }
121         de_pop_sequence(attribute, avProtocol);
122     }
123     de_pop_sequence(service, attribute);
124 
125     // 0x0005 "Public Browse Group"
126     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BROWSE_GROUP_LIST); // public browse group
127     attribute = de_push_sequence(service);
128     {
129         de_add_number(attribute,  DE_UUID, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_PUBLIC_BROWSE_ROOT);
130     }
131     de_pop_sequence(service, attribute);
132 
133     // 0x0009 "Bluetooth Profile Descriptor List"
134     de_add_number(service,  DE_UINT, DE_SIZE_16, BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
135     attribute = de_push_sequence(service);
136     {
137         uint8_t *a2dProfile = de_push_sequence(attribute);
138         {
139             de_add_number(a2dProfile,  DE_UUID, DE_SIZE_16, BLUETOOTH_SERVICE_CLASS_ADVANCED_AUDIO_DISTRIBUTION);
140             de_add_number(a2dProfile,  DE_UINT, DE_SIZE_16, 0x0103);
141         }
142         de_pop_sequence(attribute, a2dProfile);
143     }
144     de_pop_sequence(service, attribute);
145 
146 
147     // 0x0100 "Service Name"
148     if (strlen(service_name) > 0){
149         de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
150         de_add_data(service,  DE_STRING, (uint16_t) strlen(service_name), (uint8_t *) service_name);
151     }
152 
153     // 0x0100 "Provider Name"
154     if (strlen(service_provider_name) > 0) {
155         de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102);
156         de_add_data(service, DE_STRING, (uint16_t) strlen(service_provider_name), (uint8_t *) service_provider_name);
157     }
158 
159     // 0x0311 "Supported Features"
160     de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311);
161     de_add_number(service, DE_UINT, DE_SIZE_16, supported_features);
162 }
163 
164 uint8_t a2dp_subevent_id_for_avdtp_subevent_id(uint8_t subevent){
165     switch (subevent){
166         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:
167             return A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION;
168         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION:
169             return A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION;
170         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION:
171             return A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION;
172         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION:
173             return A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION;
174         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION:
175             return A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION;
176         default:
177             btstack_unreachable();
178             return 0;
179     }
180 }
181 
182 static void a2dp_replace_subevent_id_and_emit(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size, uint8_t subevent_id){
183     UNUSED(size);
184     btstack_assert(callback != NULL);
185     // cache orig event and subevent id
186     uint8_t orig_event_id    = packet[0];
187     uint8_t orig_subevent_id = packet[2];
188     // execute callback
189     packet[0] = HCI_EVENT_A2DP_META;
190     packet[2] = subevent_id;
191     (*callback)(HCI_EVENT_PACKET, 0, packet, size);
192     // restore id
193     packet[0] = orig_event_id;
194     packet[2] = orig_subevent_id;
195 }
196 
197 void a2dp_register_source_packet_handler(btstack_packet_handler_t callback){
198     btstack_assert(callback != NULL);
199     a2dp_source_callback = callback;
200 }
201 
202 void a2dp_register_sink_packet_handler(btstack_packet_handler_t callback){
203     btstack_assert(callback != NULL);
204     a2dp_sink_callback = callback;
205 }
206 
207 void a2dp_replace_subevent_id_and_emit_source(uint8_t * packet, uint16_t size, uint8_t subevent_id) {
208     a2dp_replace_subevent_id_and_emit(a2dp_source_callback, packet, size, subevent_id);
209 }
210 
211 void a2dp_replace_subevent_id_and_emit_sink(uint8_t *packet, uint16_t size, uint8_t subevent_id) {
212     a2dp_replace_subevent_id_and_emit(a2dp_sink_callback, packet, size, subevent_id);
213 }
214 
215 static void a2dp_replace_subevent_id_and_emit_for_role(avdtp_role_t role, uint8_t * packet, uint16_t size, uint8_t subevent_id) {
216     if (role == AVDTP_ROLE_SOURCE){
217         a2dp_replace_subevent_id_and_emit_source(packet, size, subevent_id);
218     } else {
219         a2dp_replace_subevent_id_and_emit_sink(packet, size, subevent_id);
220     }
221 }
222 
223 static void a2dp_emit_role(avdtp_role_t role, uint8_t * packet, uint16_t size){
224     if (role == AVDTP_ROLE_SOURCE){
225         (*a2dp_source_callback)(HCI_EVENT_PACKET, 0, packet, size);
226     } else {
227         (*a2dp_sink_callback)(HCI_EVENT_PACKET, 0, packet, size);
228     }
229 }
230 
231 static void a2dp_emit_stream_event_for_role(avdtp_role_t role, uint16_t cid, uint8_t local_seid, uint8_t subevent_id) {
232     uint8_t event[6];
233     int pos = 0;
234     event[pos++] = HCI_EVENT_A2DP_META;
235     event[pos++] = sizeof(event) - 2;
236     event[pos++] = subevent_id;
237     little_endian_store_16(event, pos, cid);
238     pos += 2;
239     event[pos++] = local_seid;
240     a2dp_emit_role(role, event, sizeof(event));
241 }
242 
243 static void a2dp_emit_stream_reconfigured_role(avdtp_role_t role, uint16_t cid, uint8_t local_seid, uint8_t status){
244     uint8_t event[7];
245     int pos = 0;
246     event[pos++] = HCI_EVENT_A2DP_META;
247     event[pos++] = sizeof(event) - 2;
248     event[pos++] = A2DP_SUBEVENT_STREAM_RECONFIGURED;
249     little_endian_store_16(event, pos, cid);
250     pos += 2;
251     event[pos++] = local_seid;
252     event[pos++] = status;
253     a2dp_emit_role(role, event, sizeof(event));
254 }
255 
256 static void a2dp_emit_streaming_connection_failed_for_role(avdtp_role_t role, avdtp_connection_t *connection, uint8_t status) {
257     uint8_t event[14];
258     int pos = 0;
259     event[pos++] = HCI_EVENT_A2DP_META;
260     event[pos++] = sizeof(event) - 2;
261     event[pos++] = A2DP_SUBEVENT_STREAM_ESTABLISHED;
262     little_endian_store_16(event, pos, connection->avdtp_cid);
263     pos += 2;
264     reverse_bd_addr(connection->remote_addr, &event[pos]);
265     pos += 6;
266     event[pos++] = 0;
267     event[pos++] = 0;
268     event[pos++] = status;
269     a2dp_emit_role(role, event, sizeof(event));
270 }
271 
272 static a2dp_config_process_t * a2dp_config_process_for_role(avdtp_role_t role, avdtp_connection_t *connection){
273     return (role == AVDTP_ROLE_SOURCE) ? &connection->a2dp_source_config_process : &connection->a2dp_sink_config_process;
274 }
275 
276 static void a2dp_config_process_timer_handler(btstack_timer_source_t * timer){
277     uint16_t avdtp_cid = (uint16_t)(uintptr_t) btstack_run_loop_get_timer_context(timer);
278     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(avdtp_cid);
279     btstack_run_loop_set_timer_context(&a2dp_config_process_set_config_timer, NULL);
280     a2dp_config_process_set_config_timer_active = false;
281 
282     log_info("Config timer fired, avdtp_cid 0x%02x", avdtp_cid);
283 
284     if (connection == NULL) {
285         a2dp_config_process_discover_seps_with_next_waiting_connection();
286         return;
287     }
288     a2dp_config_process_t * config_process = a2dp_config_process_for_role(a2dp_config_process_role, connection);
289     if (config_process->stream_endpoint_configured) {
290         a2dp_config_process_discover_seps_with_next_waiting_connection();
291         return;
292     }
293 
294     avdtp_discover_stream_endpoints(avdtp_cid);
295 }
296 
297 static void a2dp_config_process_timer_start(uint16_t avdtp_cid){
298     log_info("Config timer start for cid 0%02x", avdtp_cid);
299     a2dp_config_process_set_config_timer_active = true;
300     btstack_run_loop_remove_timer(&a2dp_config_process_set_config_timer);
301     btstack_run_loop_set_timer_handler(&a2dp_config_process_set_config_timer, a2dp_config_process_timer_handler);
302     btstack_run_loop_set_timer(&a2dp_config_process_set_config_timer, A2DP_SET_CONFIG_DELAY_MS);
303     btstack_run_loop_set_timer_context(&a2dp_config_process_set_config_timer, (void *)(uintptr_t)avdtp_cid);
304     btstack_run_loop_add_timer(&a2dp_config_process_set_config_timer);
305 }
306 
307 static void a2dp_config_process_timer_restart(void){
308     log_info("Config timer restart");
309     btstack_run_loop_remove_timer(&a2dp_config_process_set_config_timer);
310     btstack_run_loop_set_timer(&a2dp_config_process_set_config_timer, A2DP_SET_CONFIG_DELAY_MS);
311     btstack_run_loop_add_timer(&a2dp_config_process_set_config_timer);
312 }
313 
314 static void a2dp_config_process_timer_stop(void){
315     if (a2dp_config_process_set_config_timer_active == false) return;
316     log_info("Config timer stop");
317     btstack_run_loop_remove_timer(&a2dp_config_process_set_config_timer);
318     btstack_run_loop_set_timer_context(&a2dp_config_process_set_config_timer, NULL);
319     a2dp_config_process_set_config_timer_active = false;
320 }
321 
322 // Discover seps, both incoming and outgoing
323 static void a2dp_config_process_start_discovering_seps(avdtp_role_t role, avdtp_connection_t *connection) {
324     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
325 
326     config_process->state = A2DP_DISCOVER_SEPS;
327     config_process->discover_seps = false;
328 
329     a2dp_config_process_role = role;
330     a2dp_config_process_sep_discovery_index = 0;
331     a2dp_config_process_sep_discovery_count = 0;
332     memset(a2dp_config_process_sep_discovery_seps, 0, sizeof(avdtp_sep_t) * AVDTP_MAX_SEP_NUM);
333     a2dp_config_process_sep_discovery_cid = connection->avdtp_cid;
334 
335     // if we initiated the connection, start config right away, else wait a bit to give remote a chance to do it first
336     if (config_process->outgoing_active){
337         log_info("discover seps");
338         avdtp_discover_stream_endpoints(connection->avdtp_cid);
339     } else {
340         log_info("wait a bit, then discover seps");
341         a2dp_config_process_timer_start(connection->avdtp_cid);
342     }
343 }
344 
345 static void a2dp_config_process_discover_seps_with_next_waiting_connection(void){
346     btstack_assert(a2dp_config_process_sep_discovery_cid == 0);
347     btstack_linked_list_iterator_t it;
348     btstack_linked_list_iterator_init(&it, avdtp_get_connections());
349     while (btstack_linked_list_iterator_has_next(&it)){
350         avdtp_connection_t * next_connection = (avdtp_connection_t *)btstack_linked_list_iterator_next(&it);
351         if (next_connection->a2dp_source_config_process.discover_seps) {
352             a2dp_config_process_start_discovering_seps(AVDTP_ROLE_SOURCE, next_connection);
353         }
354         if (next_connection->a2dp_sink_config_process.discover_seps) {
355             a2dp_config_process_start_discovering_seps(AVDTP_ROLE_SINK, next_connection);
356         }
357     }
358 }
359 
360 void a2dp_config_process_ready_for_sep_discovery(avdtp_role_t role, avdtp_connection_t *connection) {
361     // start discover seps now if:
362     // - outgoing active: signaling for outgoing connection
363     // - outgoing not active: incoming connection and no sep discover ongoing
364 
365     // sep discovery active?
366     if (a2dp_config_process_sep_discovery_cid == 0){
367         a2dp_config_process_start_discovering_seps(role, connection);
368     } else {
369         // post-pone sep discovery
370         a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
371         config_process->discover_seps = true;
372     }
373 }
374 
375 static void a2dp_config_process_handle_media_configuration(avdtp_role_t role, const uint8_t *packet, uint8_t local_seid) {
376     uint16_t cid = avdtp_subevent_signaling_media_codec_sbc_configuration_get_avdtp_cid(packet);
377     avdtp_connection_t *connection = avdtp_get_connection_for_avdtp_cid(cid);
378     btstack_assert(connection != NULL);
379     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
380 
381     config_process->local_stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
382     // bail out if local seid invalid
383     if (config_process->local_stream_endpoint == NULL) return;
384 
385     // stop timer
386     if (a2dp_config_process_sep_discovery_cid == cid) {
387         a2dp_config_process_timer_stop();
388         a2dp_config_process_sep_discovery_cid = 0;
389     }
390 
391     config_process->stream_endpoint_configured = true;
392 
393     switch (config_process->state) {
394         case A2DP_W4_SET_CONFIGURATION:
395             // outgoing: discovery and config of remote sink sep successful, trigger stream open
396             config_process->state = A2DP_W2_OPEN_STREAM_WITH_SEID;
397             break;
398         case A2DP_DISCOVER_SEPS:
399         case A2DP_GET_CAPABILITIES:
400         case A2DP_W2_GET_ALL_CAPABILITIES:
401         case A2DP_DISCOVERY_DONE:
402         case A2DP_W4_GET_CONFIGURATION:
403             // incoming: wait for stream open
404             config_process->state = A2DP_W4_OPEN_STREAM_WITH_SEID;
405             break;
406         default:
407             // wait for configuration after sending reconfigure - keep state
408             break;
409     }
410 }
411 
412 void a2dp_config_process_set_config(avdtp_role_t role, avdtp_connection_t *connection) {
413     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
414     uint8_t local_seid  = avdtp_stream_endpoint_seid(config_process->local_stream_endpoint);
415     uint8_t remote_seid = config_process->local_stream_endpoint->set_config_remote_seid;
416     log_info("A2DP initiate set configuration locally and wait for response ... local seid 0x%02x, remote seid 0x%02x",
417              local_seid, remote_seid);
418     config_process->state = A2DP_W4_SET_CONFIGURATION;
419     avdtp_set_configuration(connection->avdtp_cid,
420                             local_seid,
421                             remote_seid,
422                             config_process->local_stream_endpoint->remote_configuration_bitmap,
423                             config_process->local_stream_endpoint->remote_configuration);
424 }
425 
426 static void
427 a2dp_config_process_handle_media_capability(avdtp_role_t role, uint16_t cid, uint8_t a2dp_subevent_id, uint8_t *packet, uint16_t size) {
428     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(cid);
429     btstack_assert(connection != NULL);
430     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
431     if (config_process->state != A2DP_GET_CAPABILITIES) return;
432     a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, a2dp_subevent_id);
433 }
434 
435 uint8_t a2dp_config_process_config_init(avdtp_role_t role, avdtp_connection_t *connection, uint8_t local_seid, uint8_t remote_seid,
436                                         avdtp_media_codec_type_t codec_type) {
437 
438     // check state
439     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
440     switch (config_process->state){
441         case A2DP_DISCOVERY_DONE:
442         case A2DP_GET_CAPABILITIES:
443             break;
444         default:
445             return ERROR_CODE_COMMAND_DISALLOWED;
446     }
447 
448     // lookup local stream endpoint
449     avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_stream_endpoint_for_seid(local_seid);
450     if (stream_endpoint == NULL){
451         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
452     }
453 
454     // lookup remote stream endpoint
455     avdtp_sep_t * remote_sep = NULL;
456     uint8_t i;
457     for (i=0; i < a2dp_config_process_sep_discovery_count; i++){
458         if (a2dp_config_process_sep_discovery_seps[i].seid == remote_seid){
459             remote_sep = &a2dp_config_process_sep_discovery_seps[i];
460         }
461     }
462     if (remote_sep == NULL){
463         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
464     }
465 
466     // set media configuration
467     stream_endpoint->remote_configuration_bitmap = store_bit16(stream_endpoint->remote_configuration_bitmap, AVDTP_MEDIA_CODEC, 1);
468     stream_endpoint->remote_configuration.media_codec.media_type = AVDTP_AUDIO;
469     stream_endpoint->remote_configuration.media_codec.media_codec_type = codec_type;
470     // remote seid to use
471     stream_endpoint->set_config_remote_seid = remote_seid;
472     // enable delay reporting if supported
473     if (remote_sep->registered_service_categories & (1<<AVDTP_DELAY_REPORTING)){
474         stream_endpoint->remote_configuration_bitmap = store_bit16(stream_endpoint->remote_configuration_bitmap, AVDTP_DELAY_REPORTING, 1);
475     }
476 
477     // suitable stream endpoint found, configure it
478     config_process->local_stream_endpoint = stream_endpoint;
479     config_process->have_config = true;
480 
481 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
482     if (config_process->state == A2DP_DISCOVERY_DONE){
483         config_process->state = A2DP_SET_CONFIGURATION;
484     }
485 #endif
486 
487     return ERROR_CODE_SUCCESS;
488 }
489 void a2dp_config_process_avdtp_event_handler(avdtp_role_t role, uint8_t *packet, uint16_t size) {
490     uint16_t cid;
491     avdtp_connection_t * connection;
492     a2dp_config_process_t * config_process;
493     uint8_t signal_identifier;
494     uint8_t status;
495     uint8_t local_seid;
496     uint8_t remote_seid;
497 
498     switch (hci_event_avdtp_meta_get_subevent_code(packet)){
499         case AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED:
500             cid = avdtp_subevent_signaling_connection_established_get_avdtp_cid(packet);
501             connection = avdtp_get_connection_for_avdtp_cid(cid);
502             btstack_assert(connection != NULL);
503             config_process = a2dp_config_process_for_role(role, connection);
504 
505             status = avdtp_subevent_signaling_connection_established_get_status(packet);
506             if (status != ERROR_CODE_SUCCESS){
507                 // notify about connection error only if we're initiator
508                 if (config_process->outgoing_active){
509                     log_info("A2DP signaling connection failed status 0x%02x", status);
510                     config_process->outgoing_active = false;
511                     a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED);
512                     // also emit streaming connection failed
513                     a2dp_emit_streaming_connection_failed_for_role(role, connection, status);
514                 }
515                 break;
516             }
517             log_info("A2DP signaling connection established avdtp_cid 0x%02x", cid);
518             config_process->state = A2DP_CONNECTED;
519 
520             // notify app
521             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED);
522 
523             // Windows 10 as Source starts SEP discovery after 1500 ms, but only if it did not get a Discover command
524             // If BTstack is configured for both roles, we need to avoid sending Discover command in Source Role for outgoing Sink connections
525 
526             // For this, we trigger SEP discovery if:
527             // a) this is an outgoing connection
528             // b) this connection wasn't caused by an outgoing connection of the other role
529             if (role == AVDTP_ROLE_SOURCE){
530                 if (connection->a2dp_source_config_process.outgoing_active || !connection->a2dp_sink_config_process.outgoing_active){
531                     a2dp_config_process_ready_for_sep_discovery(AVDTP_ROLE_SOURCE, connection);
532                 }
533             } else {
534                 if (connection->a2dp_sink_config_process.outgoing_active || !connection->a2dp_source_config_process.outgoing_active){
535                     a2dp_config_process_ready_for_sep_discovery(AVDTP_ROLE_SINK, connection);
536                 }
537             }
538             break;
539 
540         case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND:
541             cid = avdtp_subevent_signaling_sep_found_get_avdtp_cid(packet);
542             connection = avdtp_get_connection_for_avdtp_cid(cid);
543             btstack_assert(connection != NULL);
544             config_process = a2dp_config_process_for_role(role, connection);
545 
546             if (config_process->state == A2DP_DISCOVER_SEPS) {
547                 avdtp_sep_t sep;
548                 memset(&sep, 0, sizeof(avdtp_sep_t));
549                 sep.seid       = avdtp_subevent_signaling_sep_found_get_remote_seid(packet);;
550                 sep.in_use     = avdtp_subevent_signaling_sep_found_get_in_use(packet);
551                 sep.media_type = (avdtp_media_type_t) avdtp_subevent_signaling_sep_found_get_media_type(packet);
552                 sep.type       = (avdtp_sep_type_t) avdtp_subevent_signaling_sep_found_get_sep_type(packet);
553                 log_info("A2DP Found sep: remote seid 0x%02x, in_use %d, media type %d, sep type %s, index %d",
554                          sep.seid, sep.in_use, sep.media_type, sep.type == AVDTP_SOURCE ? "source" : "sink",
555                          a2dp_config_process_sep_discovery_count);
556                 avdtp_sep_type_t matching_type = (role == AVDTP_ROLE_SOURCE) ? AVDTP_SINK : AVDTP_SOURCE;
557                 if ((sep.type == matching_type) && (sep.in_use == false)) {
558                     a2dp_config_process_sep_discovery_seps[a2dp_config_process_sep_discovery_count++] = sep;
559                 }
560             }
561             break;
562 
563         case AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE:
564             cid = avdtp_subevent_signaling_sep_dicovery_done_get_avdtp_cid(packet);
565             connection = avdtp_get_connection_for_avdtp_cid(cid);
566             btstack_assert(connection != NULL);
567             config_process = a2dp_config_process_for_role(role, connection);
568 
569             if (config_process->state != A2DP_DISCOVER_SEPS) break;
570 
571             if (a2dp_config_process_sep_discovery_count > 0){
572                 config_process->state = A2DP_GET_CAPABILITIES;
573                 a2dp_config_process_sep_discovery_index = 0;
574                 config_process->have_config = false;
575             } else {
576                 if (config_process->outgoing_active){
577                     config_process->outgoing_active = false;
578                     connection = avdtp_get_connection_for_avdtp_cid(cid);
579                     btstack_assert(connection != NULL);
580                     a2dp_emit_streaming_connection_failed_for_role(role, connection, ERROR_CODE_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND);
581                 }
582 
583                 // continue
584                 config_process->state = A2DP_CONNECTED;
585                 a2dp_config_process_sep_discovery_cid = 0;
586                 a2dp_config_process_discover_seps_with_next_waiting_connection();
587             }
588             break;
589 
590         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY:
591             cid = avdtp_subevent_signaling_media_codec_sbc_capability_get_avdtp_cid(packet);
592             connection = avdtp_get_connection_for_avdtp_cid(cid);
593             btstack_assert(connection != NULL);
594             config_process = a2dp_config_process_for_role(role, connection);
595 
596             if (config_process->state != A2DP_GET_CAPABILITIES) break;
597 
598             // forward codec capability
599             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY);
600 
601 #ifndef ENABLE_A2DP_EXPLICIT_CONFIG
602             // select SEP if none configured yet
603             if (config_process->have_config == false){
604                 // find SBC stream endpoint
605                 avdtp_sep_type_t required_sep_type = (role == AVDTP_ROLE_SOURCE) ? AVDTP_SOURCE : AVDTP_SINK;
606                 avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_source_stream_endpoint_for_media_codec_and_type(AVDTP_CODEC_SBC, required_sep_type);
607                 if (stream_endpoint != NULL){
608                     // choose SBC config params
609                     avdtp_configuration_sbc_t configuration;
610                     configuration.sampling_frequency = avdtp_choose_sbc_sampling_frequency(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet));
611                     configuration.channel_mode       = avdtp_choose_sbc_channel_mode(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet));
612                     configuration.block_length       = avdtp_choose_sbc_block_length(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet));
613                     configuration.subbands           = avdtp_choose_sbc_subbands(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(packet));
614                     configuration.allocation_method  = avdtp_choose_sbc_allocation_method(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(packet));
615                     configuration.max_bitpool_value  = avdtp_choose_sbc_max_bitpool_value(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet));
616                     configuration.min_bitpool_value  = avdtp_choose_sbc_min_bitpool_value(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet));
617 
618                     // and pre-select this endpoint
619                     local_seid = avdtp_stream_endpoint_seid(stream_endpoint);
620                     remote_seid = avdtp_subevent_signaling_media_codec_sbc_capability_get_remote_seid(packet);
621                     a2dp_config_process_set_sbc(role, cid, local_seid, remote_seid, &configuration);
622                 }
623             }
624 #endif
625             break;
626             // forward codec capability
627         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CAPABILITY:
628             cid = avdtp_subevent_signaling_media_codec_mpeg_audio_capability_get_avdtp_cid(packet);
629             a2dp_config_process_handle_media_capability(role, cid,
630                                                         A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CAPABILITY,
631                                                         packet, size);
632             break;
633         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CAPABILITY:
634             cid = avdtp_subevent_signaling_media_codec_mpeg_aac_capability_get_avdtp_cid(packet);
635             a2dp_config_process_handle_media_capability(role, cid,
636                                                         A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CAPABILITY,
637                                                         packet, size);
638             break;
639         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY:
640             cid = avdtp_subevent_signaling_media_codec_atrac_capability_get_avdtp_cid(packet);
641             a2dp_config_process_handle_media_capability(role, cid, A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY,
642                                                         packet,
643                                                         size);
644             break;
645         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY:
646             cid = avdtp_subevent_signaling_media_codec_other_capability_get_avdtp_cid(packet);
647             a2dp_config_process_handle_media_capability(role, cid, A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY,
648                                                         packet,
649                                                         size);
650             break;
651 
652             // not forwarded
653         case AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY:
654         case AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY:
655         case AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY:
656         case AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY:
657         case AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY:
658         case AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY:
659             break;
660 
661         case AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY:
662             cid = avdtp_subevent_signaling_delay_reporting_capability_get_avdtp_cid(packet);
663             connection = avdtp_get_connection_for_avdtp_cid(cid);
664             btstack_assert(connection != NULL);
665             config_process = a2dp_config_process_for_role(role, connection);
666             log_info("received AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY, cid 0x%02x, state %d", cid, config_process->state);
667 
668             if (config_process->state != A2DP_GET_CAPABILITIES) break;
669 
670             // store delay reporting capability
671             a2dp_config_process_sep_discovery_seps[a2dp_config_process_sep_discovery_index].registered_service_categories |= 1 << AVDTP_DELAY_REPORTING;
672 
673             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY);
674             break;
675 
676         case AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE:
677             cid = avdtp_subevent_signaling_capabilities_done_get_avdtp_cid(packet);
678             connection = avdtp_get_connection_for_avdtp_cid(cid);
679             btstack_assert(connection != NULL);
680             config_process = a2dp_config_process_for_role(role, connection);
681 
682             if (config_process->state != A2DP_GET_CAPABILITIES) break;
683 
684             // forward capabilities done for endpoint
685             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_CAPABILITIES_DONE);
686 
687             // endpoint was not suitable, check next one if possible
688             a2dp_config_process_sep_discovery_index++;
689 
690             if (a2dp_config_process_sep_discovery_index >= a2dp_config_process_sep_discovery_count){
691 
692                 // emit 'all capabilities for all seps reported'
693                 uint8_t event[6];
694                 uint8_t pos = 0;
695                 event[pos++] = HCI_EVENT_A2DP_META;
696                 event[pos++] = sizeof(event) - 2;
697                 event[pos++] = A2DP_SUBEVENT_SIGNALING_CAPABILITIES_COMPLETE;
698                 little_endian_store_16(event, pos, cid);
699                 a2dp_emit_role(role, event, sizeof(event));
700 
701                 // do we have a valid config?
702                 if (config_process->have_config){
703                     config_process->state = A2DP_SET_CONFIGURATION;
704                     config_process->have_config = false;
705                     break;
706                 }
707 
708 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
709                 config_process->state = A2DP_DISCOVERY_DONE;
710                 // TODO call a2dp_discover_seps_with_next_waiting_connection?
711                 break;
712 #endif
713 
714                 // we didn't find a suitable SBC stream endpoint, sorry.
715                 if (config_process->outgoing_active){
716                     config_process->outgoing_active = false;
717                     connection = avdtp_get_connection_for_avdtp_cid(cid);
718                     btstack_assert(connection != NULL);
719                     a2dp_emit_streaming_connection_failed_for_role(role, connection,
720                                                                  ERROR_CODE_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND);
721                 }
722                 config_process->state = A2DP_CONNECTED;
723                 a2dp_config_process_sep_discovery_cid = 0;
724                 a2dp_config_process_discover_seps_with_next_waiting_connection();
725             }
726             break;
727 
728             // forward codec configuration
729         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:
730             local_seid = avdtp_subevent_signaling_media_codec_sbc_configuration_get_local_seid(packet);
731             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
732             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
733                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION);
734             break;
735         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION:
736             local_seid = avdtp_subevent_signaling_media_codec_mpeg_audio_configuration_get_local_seid(packet);
737             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
738             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
739                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION);
740             break;
741         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION:
742             local_seid = avdtp_subevent_signaling_media_codec_mpeg_aac_configuration_get_local_seid(packet);
743             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
744             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
745                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION);
746             break;
747         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION:
748             local_seid = avdtp_subevent_signaling_media_codec_atrac_configuration_get_local_seid(packet);
749             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
750             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
751                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION);
752             break;
753         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION:
754             local_seid = avdtp_subevent_signaling_media_codec_sbc_configuration_get_local_seid(packet);
755             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
756             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
757                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION);
758             break;
759         case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED:
760             cid = avdtp_subevent_streaming_connection_established_get_avdtp_cid(packet);
761             connection = avdtp_get_connection_for_avdtp_cid(cid);
762             btstack_assert(connection != NULL);
763             config_process = a2dp_config_process_for_role(role, connection);
764 
765             if (config_process->state != A2DP_W4_OPEN_STREAM_WITH_SEID) break;
766 
767             config_process->outgoing_active = false;
768             status = avdtp_subevent_streaming_connection_established_get_status(packet);
769             if (status != ERROR_CODE_SUCCESS){
770                 log_info("A2DP source streaming connection could not be established, avdtp_cid 0x%02x, status 0x%02x ---", cid, status);
771                 a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_STREAM_ESTABLISHED);
772                 break;
773             }
774 
775             log_info("A2DP source streaming connection established --- avdtp_cid 0x%02x, local seid 0x%02x, remote seid 0x%02x", cid,
776                      avdtp_subevent_streaming_connection_established_get_local_seid(packet),
777                      avdtp_subevent_streaming_connection_established_get_remote_seid(packet));
778             config_process->state = A2DP_STREAMING_OPENED;
779             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_STREAM_ESTABLISHED);
780             break;
781 
782         case AVDTP_SUBEVENT_SIGNALING_ACCEPT:
783             cid = avdtp_subevent_signaling_accept_get_avdtp_cid(packet);
784             connection = avdtp_get_connection_for_avdtp_cid(cid);
785             btstack_assert(connection != NULL);
786             config_process = a2dp_config_process_for_role(role, connection);
787 
788             // restart set config timer while remote is active for current cid
789             if (a2dp_config_process_set_config_timer_active &&
790                 (avdtp_subevent_signaling_accept_get_is_initiator(packet) == 0) &&
791                 (cid == a2dp_config_process_sep_discovery_cid)){
792 
793                 a2dp_config_process_timer_restart();
794                 break;
795             }
796 
797             signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet);
798 
799             log_info("A2DP cmd %s accepted, global state %d, cid 0x%02x", avdtp_si2str(signal_identifier), config_process->state, cid);
800 
801             switch (config_process->state){
802                 case A2DP_GET_CAPABILITIES:
803                     remote_seid = a2dp_config_process_sep_discovery_seps[a2dp_config_process_sep_discovery_index].seid;
804                     log_info("A2DP get capabilities for remote seid 0x%02x", remote_seid);
805                     avdtp_get_all_capabilities(cid, remote_seid, role);
806                     return;
807 
808                 case A2DP_SET_CONFIGURATION:
809                     a2dp_config_process_set_config(role, connection);
810                     return;
811 
812                 case A2DP_W2_OPEN_STREAM_WITH_SEID:
813                     log_info("A2DP open stream ... local seid 0x%02x, active remote seid 0x%02x",
814                              avdtp_stream_endpoint_seid(connection->a2dp_source_config_process.local_stream_endpoint),
815                              config_process->local_stream_endpoint->remote_sep.seid);
816                     config_process->state = A2DP_W4_OPEN_STREAM_WITH_SEID;
817                     avdtp_open_stream(cid,
818                                      avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
819                                      config_process->local_stream_endpoint->remote_sep.seid);
820                     break;
821 
822                 case A2DP_W2_RECONFIGURE_WITH_SEID:
823                     log_info("A2DP reconfigured ... local seid 0x%02x, active remote seid 0x%02x",
824                              avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
825                              config_process->local_stream_endpoint->remote_sep.seid);
826                     a2dp_emit_stream_reconfigured_role(role, cid, avdtp_stream_endpoint_seid(
827                             config_process->local_stream_endpoint), ERROR_CODE_SUCCESS);
828                     config_process->state = A2DP_STREAMING_OPENED;
829                     break;
830 
831                 case A2DP_STREAMING_OPENED:
832                     switch (signal_identifier){
833                         case  AVDTP_SI_START:
834                             a2dp_emit_stream_event_for_role(role, cid, avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
835                                                           A2DP_SUBEVENT_STREAM_STARTED);
836                             break;
837                         case AVDTP_SI_SUSPEND:
838                             a2dp_emit_stream_event_for_role(role, cid, avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
839                                                           A2DP_SUBEVENT_STREAM_SUSPENDED);
840                             break;
841                         case AVDTP_SI_ABORT:
842                         case AVDTP_SI_CLOSE:
843                             a2dp_emit_stream_event_for_role(role, cid, avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
844                                                           A2DP_SUBEVENT_STREAM_STOPPED);
845                             break;
846 #ifdef ENABLE_AVDTP_ACCEPTOR_EXPLICIT_START_STREAM_CONFIRMATION
847                         case AVDTP_SI_ACCEPT_START:
848                             a2dp_emit_stream_event_for_role(role, cid, avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
849                                                             A2DP_SUBEVENT_START_STREAM_REQUESTED);
850                             break;
851 #endif
852                         default:
853                             break;
854                     }
855                     break;
856 
857                 default:
858                     break;
859             }
860             break;
861 
862         case AVDTP_SUBEVENT_SIGNALING_REJECT:
863             cid = avdtp_subevent_signaling_reject_get_avdtp_cid(packet);
864             connection = avdtp_get_connection_for_avdtp_cid(cid);
865             btstack_assert(connection != NULL);
866             config_process = a2dp_config_process_for_role(role, connection);
867 
868             if (avdtp_subevent_signaling_reject_get_is_initiator(packet) == 0) break;
869 
870             switch (config_process->state) {
871                 case A2DP_W2_RECONFIGURE_WITH_SEID:
872                     log_info("A2DP reconfigure failed ... local seid 0x%02x, active remote seid 0x%02x",
873                              avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
874                              config_process->local_stream_endpoint->remote_sep.seid);
875                     a2dp_emit_stream_reconfigured_role(role, cid, avdtp_stream_endpoint_seid(
876                             config_process->local_stream_endpoint), ERROR_CODE_UNSPECIFIED_ERROR);
877                     config_process->state = A2DP_STREAMING_OPENED;
878                     break;
879                 default:
880                     config_process->state = A2DP_CONNECTED;
881                     break;
882             }
883 
884             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_COMMAND_REJECTED);
885             break;
886 
887         case AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT:
888             cid = avdtp_subevent_signaling_general_reject_get_avdtp_cid(packet);
889             connection = avdtp_get_connection_for_avdtp_cid(cid);
890             btstack_assert(connection != NULL);
891             config_process = a2dp_config_process_for_role(role, connection);
892 
893             if (avdtp_subevent_signaling_general_reject_get_is_initiator(packet) == 0) break;
894 
895             config_process->state = A2DP_CONNECTED;
896             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_COMMAND_REJECTED);
897             break;
898 
899         case AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED:
900             cid = avdtp_subevent_streaming_connection_released_get_avdtp_cid(packet);
901             connection = avdtp_get_connection_for_avdtp_cid(cid);
902             btstack_assert(connection != NULL);
903             config_process = a2dp_config_process_for_role(role, connection);
904 
905             config_process->state = A2DP_CONFIGURED;
906             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_STREAM_RELEASED);
907             break;
908 
909         case AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
910             cid = avdtp_subevent_signaling_connection_released_get_avdtp_cid(packet);
911             connection = avdtp_get_connection_for_avdtp_cid(cid);
912             btstack_assert(connection != NULL);
913             config_process = a2dp_config_process_for_role(role, connection);
914 
915             // connect/release are passed on to app
916             if (a2dp_config_process_sep_discovery_cid == cid){
917                 a2dp_config_process_timer_stop();
918                 config_process->stream_endpoint_configured = false;
919                 config_process->local_stream_endpoint = NULL;
920 
921                 config_process->state = A2DP_IDLE;
922                 a2dp_config_process_sep_discovery_cid = 0;
923             }
924             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED);
925             break;
926 
927         default:
928             break;
929     }
930 }
931 
932 uint8_t a2dp_config_process_set_sbc(avdtp_role_t role, uint16_t a2dp_cid, uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_sbc_t * configuration){
933     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
934     if (connection == NULL){
935         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
936     }
937     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
938 
939     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_SBC);
940     if (status != 0) {
941         return status;
942     }
943     // set config in reserved buffer
944     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *) config_process->local_stream_endpoint->media_codec_info;
945     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = 4;
946     avdtp_config_sbc_store(config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information, configuration);
947 
948 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
949     a2dp_config_process_set_config(role, connection);
950 #endif
951 
952     return ERROR_CODE_SUCCESS;
953 }
954 
955 uint8_t a2dp_config_process_set_mpeg_audio(avdtp_role_t role, uint16_t a2dp_cid, uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_mpeg_audio_t * configuration){
956     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
957     if (connection == NULL){
958         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
959     }
960     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
961 
962     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_MPEG_1_2_AUDIO);
963     if (status != 0) {
964         return status;
965     }
966 
967     // set config in reserved buffer
968     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *)config_process->local_stream_endpoint->media_codec_info;
969     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = 4;
970     avdtp_config_mpeg_audio_store(config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information, configuration);
971 
972 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
973     a2dp_config_process_set_config(role, connection);
974 #endif
975 
976     return ERROR_CODE_SUCCESS;
977 }
978 
979 uint8_t a2dp_config_process_set_mpeg_aac(avdtp_role_t role, uint16_t a2dp_cid,  uint8_t local_seid,  uint8_t remote_seid, const avdtp_configuration_mpeg_aac_t * configuration){
980     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
981     if (connection == NULL){
982         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
983     }
984     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
985 
986     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_MPEG_2_4_AAC);
987     if (status != 0) {
988         return status;
989     }
990     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *) config_process->local_stream_endpoint->media_codec_info;
991     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = 6;
992     avdtp_config_mpeg_aac_store(config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information, configuration);
993 
994 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
995     a2dp_config_process_set_config(role, connection);
996 #endif
997 
998     return ERROR_CODE_SUCCESS;
999 }
1000 
1001 uint8_t a2dp_config_process_set_atrac(avdtp_role_t role, uint16_t a2dp_cid, uint8_t local_seid, uint8_t remote_seid, const avdtp_configuration_atrac_t * configuration){
1002     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
1003     if (connection == NULL){
1004         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1005     }
1006     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
1007 
1008     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_ATRAC_FAMILY);
1009     if (status != 0) {
1010         return status;
1011     }
1012 
1013     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *) config_process->local_stream_endpoint->media_codec_info;
1014     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = 7;
1015     avdtp_config_atrac_store(config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information, configuration);
1016 
1017 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
1018     a2dp_config_process_set_config(role, connection);
1019 #endif
1020 
1021     return ERROR_CODE_SUCCESS;
1022 }
1023 
1024 uint8_t a2dp_config_process_set_other(avdtp_role_t role, uint16_t a2dp_cid,  uint8_t local_seid, uint8_t remote_seid,
1025                                      const uint8_t * media_codec_information, uint8_t media_codec_information_len){
1026     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
1027     if (connection == NULL){
1028         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1029     }
1030     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
1031 
1032     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_NON_A2DP);
1033     if (status != 0) {
1034         return status;
1035     }
1036 
1037     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *) media_codec_information;
1038     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = media_codec_information_len;
1039 
1040 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
1041         a2dp_config_process_set_config(role, connection);
1042 #endif
1043 
1044     return status;
1045 }
1046