xref: /btstack/src/classic/a2dp.c (revision ea8aa2085ae3e25931720f7e568374a0866ebf9b)
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 #define BTSTACK_FILE__ "a2dp.c"
39 
40 #include <stdint.h>
41 #include <string.h>
42 #include "a2dp.h"
43 #include "l2cap.h"
44 #include "classic/sdp_util.h"
45 #include "classic/avdtp_source.h"
46 #include "classic/a2dp_source.h"
47 #include "btstack_event.h"
48 #include "bluetooth_sdp.h"
49 #include "bluetooth_psm.h"
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 
a2dp_init(void)80 void a2dp_init(void) {
81 }
82 
a2dp_deinit(void)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 
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)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, 0x0104);
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 
a2dp_subevent_id_for_avdtp_subevent_id(uint8_t subevent)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 
a2dp_replace_subevent_id_and_emit(btstack_packet_handler_t callback,uint8_t * packet,uint16_t size,uint8_t subevent_id)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 
a2dp_register_source_packet_handler(btstack_packet_handler_t callback)197 void a2dp_register_source_packet_handler(btstack_packet_handler_t callback){
198     btstack_assert(callback != NULL);
199     a2dp_source_callback = callback;
200 }
201 
a2dp_register_sink_packet_handler(btstack_packet_handler_t callback)202 void a2dp_register_sink_packet_handler(btstack_packet_handler_t callback){
203     btstack_assert(callback != NULL);
204     a2dp_sink_callback = callback;
205 }
206 
a2dp_replace_subevent_id_and_emit_source(uint8_t * packet,uint16_t size,uint8_t subevent_id)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 
a2dp_replace_subevent_id_and_emit_sink(uint8_t * packet,uint16_t size,uint8_t subevent_id)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 
a2dp_replace_subevent_id_and_emit_for_role(avdtp_role_t role,uint8_t * packet,uint16_t size,uint8_t subevent_id)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 
a2dp_emit_role(avdtp_role_t role,uint8_t * packet,uint16_t size)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 
a2dp_emit_stream_event_for_role(avdtp_role_t role,uint16_t cid,uint8_t local_seid,uint8_t subevent_id)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 
a2dp_emit_stream_reconfigured_role(avdtp_role_t role,uint16_t cid,uint8_t local_seid,uint8_t status)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 
a2dp_emit_streaming_connection_failed_for_role(avdtp_role_t role,avdtp_connection_t * connection,uint8_t status)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 
a2dp_config_process_for_role(avdtp_role_t role,avdtp_connection_t * connection)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 
a2dp_config_process_timer_handler(btstack_timer_source_t * timer)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 
a2dp_config_process_timer_start(uint16_t avdtp_cid)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 
a2dp_config_process_timer_restart(void)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 
a2dp_config_process_timer_stop(void)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
a2dp_config_process_start_discovering_seps(avdtp_role_t role,avdtp_connection_t * connection)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 
a2dp_config_process_discover_seps_with_next_waiting_connection(void)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 
a2dp_config_process_ready_for_sep_discovery(avdtp_role_t role,avdtp_connection_t * connection)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 
a2dp_config_process_handle_media_configuration(avdtp_role_t role,const uint8_t * packet,uint8_t local_seid)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 
a2dp_config_process_set_config(avdtp_role_t role,avdtp_connection_t * connection)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
a2dp_config_process_handle_media_capability(avdtp_role_t role,uint16_t cid,uint8_t a2dp_subevent_id,uint8_t * packet,uint16_t size)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 
a2dp_config_process_config_init(avdtp_role_t role,avdtp_connection_t * connection,uint8_t local_seid,uint8_t remote_seid,avdtp_media_codec_type_t codec_type)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 }
a2dp_config_process_avdtp_event_handler(avdtp_role_t role,uint8_t * packet,uint16_t size)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     bool outgoing_active;
498 
499     switch (hci_event_avdtp_meta_get_subevent_code(packet)){
500         case AVDTP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED:
501             cid = avdtp_subevent_signaling_connection_established_get_avdtp_cid(packet);
502             connection = avdtp_get_connection_for_avdtp_cid(cid);
503             btstack_assert(connection != NULL);
504             config_process = a2dp_config_process_for_role(role, connection);
505 
506             status = avdtp_subevent_signaling_connection_established_get_status(packet);
507             if (status != ERROR_CODE_SUCCESS){
508                 // notify about connection error only if we're initiator
509                 if (config_process->outgoing_active){
510                     log_info("A2DP signaling connection failed status 0x%02x", status);
511                     config_process->outgoing_active = false;
512                     a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED);
513                     // also emit streaming connection failed
514                     a2dp_emit_streaming_connection_failed_for_role(role, connection, status);
515                 }
516                 break;
517             }
518             log_info("A2DP signaling connection established avdtp_cid 0x%02x", cid);
519             config_process->state = A2DP_CONNECTED;
520 
521             // notify app
522             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_CONNECTION_ESTABLISHED);
523 
524             // Windows 10 as Source starts SEP discovery after 1500 ms, but only if it did not get a Discover command
525             // If BTstack is configured for both roles, we need to avoid sending Discover command in Source Role for outgoing Sink connections
526 
527             // For this, we trigger SEP discovery if:
528             // a) this is an outgoing connection
529             // b) this connection wasn't caused by an outgoing connection of the other role
530             if (role == AVDTP_ROLE_SOURCE){
531                 if (connection->a2dp_source_config_process.outgoing_active || !connection->a2dp_sink_config_process.outgoing_active){
532                     a2dp_config_process_ready_for_sep_discovery(AVDTP_ROLE_SOURCE, connection);
533                 }
534             } else {
535                 if (connection->a2dp_sink_config_process.outgoing_active || !connection->a2dp_source_config_process.outgoing_active){
536                     a2dp_config_process_ready_for_sep_discovery(AVDTP_ROLE_SINK, connection);
537                 }
538             }
539             break;
540 
541         case AVDTP_SUBEVENT_SIGNALING_SEP_FOUND:
542             cid = avdtp_subevent_signaling_sep_found_get_avdtp_cid(packet);
543             connection = avdtp_get_connection_for_avdtp_cid(cid);
544             btstack_assert(connection != NULL);
545             config_process = a2dp_config_process_for_role(role, connection);
546 
547             if (config_process->state == A2DP_DISCOVER_SEPS) {
548                 avdtp_sep_t sep;
549                 memset(&sep, 0, sizeof(avdtp_sep_t));
550                 sep.seid       = avdtp_subevent_signaling_sep_found_get_remote_seid(packet);;
551                 sep.in_use     = avdtp_subevent_signaling_sep_found_get_in_use(packet);
552                 sep.media_type = (avdtp_media_type_t) avdtp_subevent_signaling_sep_found_get_media_type(packet);
553                 sep.type       = (avdtp_sep_type_t) avdtp_subevent_signaling_sep_found_get_sep_type(packet);
554                 log_info("A2DP Found sep: remote seid 0x%02x, in_use %d, media type %d, sep type %s, index %d",
555                          sep.seid, sep.in_use, sep.media_type, sep.type == AVDTP_SOURCE ? "source" : "sink",
556                          a2dp_config_process_sep_discovery_count);
557                 avdtp_sep_type_t matching_type = (role == AVDTP_ROLE_SOURCE) ? AVDTP_SINK : AVDTP_SOURCE;
558                 if ((sep.type == matching_type) && (sep.in_use == false)) {
559                     a2dp_config_process_sep_discovery_seps[a2dp_config_process_sep_discovery_count++] = sep;
560                 }
561             }
562             break;
563 
564         case AVDTP_SUBEVENT_SIGNALING_SEP_DICOVERY_DONE:
565             cid = avdtp_subevent_signaling_sep_dicovery_done_get_avdtp_cid(packet);
566             connection = avdtp_get_connection_for_avdtp_cid(cid);
567             btstack_assert(connection != NULL);
568             config_process = a2dp_config_process_for_role(role, connection);
569 
570             if (config_process->state != A2DP_DISCOVER_SEPS) break;
571 
572             if (a2dp_config_process_sep_discovery_count > 0){
573                 config_process->state = A2DP_GET_CAPABILITIES;
574                 a2dp_config_process_sep_discovery_index = 0;
575                 config_process->have_config = false;
576             } else {
577                 if (config_process->outgoing_active){
578                     config_process->outgoing_active = false;
579                     connection = avdtp_get_connection_for_avdtp_cid(cid);
580                     btstack_assert(connection != NULL);
581                     a2dp_emit_streaming_connection_failed_for_role(role, connection, ERROR_CODE_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND);
582                 }
583 
584                 // continue
585                 config_process->state = A2DP_CONNECTED;
586                 a2dp_config_process_sep_discovery_cid = 0;
587                 a2dp_config_process_discover_seps_with_next_waiting_connection();
588             }
589             break;
590 
591         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY:
592             cid = avdtp_subevent_signaling_media_codec_sbc_capability_get_avdtp_cid(packet);
593             connection = avdtp_get_connection_for_avdtp_cid(cid);
594             btstack_assert(connection != NULL);
595             config_process = a2dp_config_process_for_role(role, connection);
596 
597             if (config_process->state != A2DP_GET_CAPABILITIES) break;
598 
599             // forward codec capability
600             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CAPABILITY);
601 
602 #ifndef ENABLE_A2DP_EXPLICIT_CONFIG
603             // select SEP if none configured yet
604             if (config_process->have_config == false){
605                 // find SBC stream endpoint
606                 avdtp_sep_type_t required_sep_type = (role == AVDTP_ROLE_SOURCE) ? AVDTP_SOURCE : AVDTP_SINK;
607                 avdtp_stream_endpoint_t * stream_endpoint = avdtp_get_source_stream_endpoint_for_media_codec_and_type(AVDTP_CODEC_SBC, required_sep_type);
608                 if (stream_endpoint != NULL){
609                     // choose SBC config params
610                     avdtp_configuration_sbc_t configuration;
611                     configuration.sampling_frequency = avdtp_choose_sbc_sampling_frequency(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_sampling_frequency_bitmap(packet));
612                     configuration.channel_mode       = avdtp_choose_sbc_channel_mode(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_channel_mode_bitmap(packet));
613                     configuration.block_length       = avdtp_choose_sbc_block_length(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_block_length_bitmap(packet));
614                     configuration.subbands           = avdtp_choose_sbc_subbands(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_subbands_bitmap(packet));
615                     configuration.allocation_method  = avdtp_choose_sbc_allocation_method(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_allocation_method_bitmap(packet));
616                     configuration.max_bitpool_value  = avdtp_choose_sbc_max_bitpool_value(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_max_bitpool_value(packet));
617                     configuration.min_bitpool_value  = avdtp_choose_sbc_min_bitpool_value(stream_endpoint, avdtp_subevent_signaling_media_codec_sbc_capability_get_min_bitpool_value(packet));
618 
619                     // and pre-select this endpoint
620                     local_seid = avdtp_stream_endpoint_seid(stream_endpoint);
621                     remote_seid = avdtp_subevent_signaling_media_codec_sbc_capability_get_remote_seid(packet);
622                     a2dp_config_process_set_sbc(role, cid, local_seid, remote_seid, &configuration);
623                 }
624             }
625 #endif
626             break;
627             // forward codec capability
628         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CAPABILITY:
629             cid = avdtp_subevent_signaling_media_codec_mpeg_audio_capability_get_avdtp_cid(packet);
630             a2dp_config_process_handle_media_capability(role, cid,
631                                                         A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CAPABILITY,
632                                                         packet, size);
633             break;
634         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CAPABILITY:
635             cid = avdtp_subevent_signaling_media_codec_mpeg_aac_capability_get_avdtp_cid(packet);
636             a2dp_config_process_handle_media_capability(role, cid,
637                                                         A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CAPABILITY,
638                                                         packet, size);
639             break;
640         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY:
641             cid = avdtp_subevent_signaling_media_codec_atrac_capability_get_avdtp_cid(packet);
642             a2dp_config_process_handle_media_capability(role, cid, A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CAPABILITY,
643                                                         packet,
644                                                         size);
645             break;
646         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY:
647             cid = avdtp_subevent_signaling_media_codec_other_capability_get_avdtp_cid(packet);
648             a2dp_config_process_handle_media_capability(role, cid, A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CAPABILITY,
649                                                         packet,
650                                                         size);
651             break;
652 
653             // not forwarded
654         case AVDTP_SUBEVENT_SIGNALING_MEDIA_TRANSPORT_CAPABILITY:
655         case AVDTP_SUBEVENT_SIGNALING_REPORTING_CAPABILITY:
656         case AVDTP_SUBEVENT_SIGNALING_RECOVERY_CAPABILITY:
657         case AVDTP_SUBEVENT_SIGNALING_CONTENT_PROTECTION_CAPABILITY:
658         case AVDTP_SUBEVENT_SIGNALING_HEADER_COMPRESSION_CAPABILITY:
659         case AVDTP_SUBEVENT_SIGNALING_MULTIPLEXING_CAPABILITY:
660             break;
661 
662         case AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY:
663             cid = avdtp_subevent_signaling_delay_reporting_capability_get_avdtp_cid(packet);
664             connection = avdtp_get_connection_for_avdtp_cid(cid);
665             btstack_assert(connection != NULL);
666             config_process = a2dp_config_process_for_role(role, connection);
667             log_info("received AVDTP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY, cid 0x%02x, state %d", cid, config_process->state);
668 
669             if (config_process->state != A2DP_GET_CAPABILITIES) break;
670 
671             // store delay reporting capability
672             a2dp_config_process_sep_discovery_seps[a2dp_config_process_sep_discovery_index].registered_service_categories |= 1 << AVDTP_DELAY_REPORTING;
673 
674             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_DELAY_REPORTING_CAPABILITY);
675             break;
676 
677         case AVDTP_SUBEVENT_SIGNALING_CAPABILITIES_DONE:
678             cid = avdtp_subevent_signaling_capabilities_done_get_avdtp_cid(packet);
679             connection = avdtp_get_connection_for_avdtp_cid(cid);
680             btstack_assert(connection != NULL);
681             config_process = a2dp_config_process_for_role(role, connection);
682 
683             if (config_process->state != A2DP_GET_CAPABILITIES) break;
684 
685             // forward capabilities done for endpoint
686             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_CAPABILITIES_DONE);
687 
688             // endpoint was not suitable, check next one if possible
689             a2dp_config_process_sep_discovery_index++;
690 
691             if (a2dp_config_process_sep_discovery_index >= a2dp_config_process_sep_discovery_count){
692 
693                 // emit 'all capabilities for all seps reported'
694                 uint8_t event[6];
695                 uint8_t pos = 0;
696                 event[pos++] = HCI_EVENT_A2DP_META;
697                 event[pos++] = sizeof(event) - 2;
698                 event[pos++] = A2DP_SUBEVENT_SIGNALING_CAPABILITIES_COMPLETE;
699                 little_endian_store_16(event, pos, cid);
700                 a2dp_emit_role(role, event, sizeof(event));
701 
702                 // do we have a valid config?
703                 if (config_process->have_config){
704                     config_process->state = A2DP_SET_CONFIGURATION;
705                     config_process->have_config = false;
706                     break;
707                 }
708 
709 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
710                 config_process->state = A2DP_DISCOVERY_DONE;
711                 // TODO call a2dp_discover_seps_with_next_waiting_connection?
712                 break;
713 #endif
714 
715                 // we didn't find a suitable SBC stream endpoint, sorry.
716                 if (config_process->outgoing_active){
717                     config_process->outgoing_active = false;
718                     connection = avdtp_get_connection_for_avdtp_cid(cid);
719                     btstack_assert(connection != NULL);
720                     a2dp_emit_streaming_connection_failed_for_role(role, connection,
721                                                                  ERROR_CODE_CONNECTION_REJECTED_DUE_TO_NO_SUITABLE_CHANNEL_FOUND);
722                 }
723                 config_process->state = A2DP_CONNECTED;
724                 a2dp_config_process_sep_discovery_cid = 0;
725                 a2dp_config_process_discover_seps_with_next_waiting_connection();
726             }
727             break;
728 
729             // forward codec configuration
730         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION:
731             local_seid = avdtp_subevent_signaling_media_codec_sbc_configuration_get_local_seid(packet);
732             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
733             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
734                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_SBC_CONFIGURATION);
735             break;
736         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION:
737             local_seid = avdtp_subevent_signaling_media_codec_mpeg_audio_configuration_get_local_seid(packet);
738             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
739             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
740                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AUDIO_CONFIGURATION);
741             break;
742         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION:
743             local_seid = avdtp_subevent_signaling_media_codec_mpeg_aac_configuration_get_local_seid(packet);
744             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
745             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
746                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_MPEG_AAC_CONFIGURATION);
747             break;
748         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION:
749             local_seid = avdtp_subevent_signaling_media_codec_atrac_configuration_get_local_seid(packet);
750             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
751             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
752                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_ATRAC_CONFIGURATION);
753             break;
754         case AVDTP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION:
755             local_seid = avdtp_subevent_signaling_media_codec_sbc_configuration_get_local_seid(packet);
756             a2dp_config_process_handle_media_configuration(role, packet, local_seid);
757             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size,
758                                                      A2DP_SUBEVENT_SIGNALING_MEDIA_CODEC_OTHER_CONFIGURATION);
759             break;
760         case AVDTP_SUBEVENT_STREAMING_CONNECTION_ESTABLISHED:
761             cid = avdtp_subevent_streaming_connection_established_get_avdtp_cid(packet);
762             connection = avdtp_get_connection_for_avdtp_cid(cid);
763             btstack_assert(connection != NULL);
764 
765             config_process = a2dp_config_process_for_role(role, connection);
766             outgoing_active = config_process->outgoing_active;
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                 config_process->state = A2DP_CONNECTED;
772                 // suppress event if streaming wasn't requested by us
773                 if (outgoing_active == false){
774                     break;
775                 }
776             } else {
777                 log_info("A2DP source streaming connection established --- avdtp_cid 0x%02x, local seid 0x%02x, remote seid 0x%02x", cid,
778                          avdtp_subevent_streaming_connection_established_get_local_seid(packet),
779                          avdtp_subevent_streaming_connection_established_get_remote_seid(packet));
780                 config_process->state = A2DP_STREAMING_OPENED;
781             }
782             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_STREAM_ESTABLISHED);
783             break;
784 
785         case AVDTP_SUBEVENT_SIGNALING_ACCEPT:
786             cid = avdtp_subevent_signaling_accept_get_avdtp_cid(packet);
787             connection = avdtp_get_connection_for_avdtp_cid(cid);
788             btstack_assert(connection != NULL);
789             config_process = a2dp_config_process_for_role(role, connection);
790 
791             // restart set config timer while remote is active for current cid
792             if (a2dp_config_process_set_config_timer_active &&
793                 (avdtp_subevent_signaling_accept_get_is_initiator(packet) == 0) &&
794                 (cid == a2dp_config_process_sep_discovery_cid)){
795 
796                 a2dp_config_process_timer_restart();
797                 break;
798             }
799 
800             signal_identifier = avdtp_subevent_signaling_accept_get_signal_identifier(packet);
801 
802             log_info("A2DP cmd %s accepted, global state %d, cid 0x%02x", avdtp_si2str(signal_identifier), config_process->state, cid);
803 
804             switch (config_process->state){
805                 case A2DP_GET_CAPABILITIES:
806                     remote_seid = a2dp_config_process_sep_discovery_seps[a2dp_config_process_sep_discovery_index].seid;
807                     log_info("A2DP get capabilities for remote seid 0x%02x", remote_seid);
808                     avdtp_get_all_capabilities(cid, remote_seid, role);
809                     return;
810 
811                 case A2DP_SET_CONFIGURATION:
812                     a2dp_config_process_set_config(role, connection);
813                     return;
814 
815                 case A2DP_W2_OPEN_STREAM_WITH_SEID:
816                     log_info("A2DP open stream ... local seid 0x%02x, active remote seid 0x%02x",
817                              avdtp_stream_endpoint_seid(connection->a2dp_source_config_process.local_stream_endpoint),
818                              config_process->local_stream_endpoint->remote_sep.seid);
819                     config_process->state = A2DP_W4_OPEN_STREAM_WITH_SEID;
820                     avdtp_open_stream(cid,
821                                      avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
822                                      config_process->local_stream_endpoint->remote_sep.seid);
823                     break;
824 
825                 case A2DP_W2_RECONFIGURE_WITH_SEID:
826                     log_info("A2DP reconfigured ... local seid 0x%02x, active remote seid 0x%02x",
827                              avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
828                              config_process->local_stream_endpoint->remote_sep.seid);
829                     a2dp_emit_stream_reconfigured_role(role, cid, avdtp_stream_endpoint_seid(
830                             config_process->local_stream_endpoint), ERROR_CODE_SUCCESS);
831                     config_process->state = A2DP_STREAMING_OPENED;
832                     break;
833 
834                 case A2DP_STREAMING_OPENED:
835                     switch (signal_identifier){
836                         case  AVDTP_SI_START:
837                             a2dp_emit_stream_event_for_role(role, cid, avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
838                                                           A2DP_SUBEVENT_STREAM_STARTED);
839                             break;
840                         case AVDTP_SI_SUSPEND:
841                             a2dp_emit_stream_event_for_role(role, cid, avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
842                                                           A2DP_SUBEVENT_STREAM_SUSPENDED);
843                             break;
844                         case AVDTP_SI_ABORT:
845                         case AVDTP_SI_CLOSE:
846                             a2dp_emit_stream_event_for_role(role, cid, avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
847                                                           A2DP_SUBEVENT_STREAM_STOPPED);
848                             break;
849 #ifdef ENABLE_AVDTP_ACCEPTOR_EXPLICIT_START_STREAM_CONFIRMATION
850                         case AVDTP_SI_ACCEPT_START:
851                             a2dp_emit_stream_event_for_role(role, cid, avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
852                                                             A2DP_SUBEVENT_START_STREAM_REQUESTED);
853                             break;
854 #endif
855                         default:
856                             break;
857                     }
858                     break;
859 
860                 default:
861                     break;
862             }
863             break;
864 
865         case AVDTP_SUBEVENT_SIGNALING_REJECT:
866             cid = avdtp_subevent_signaling_reject_get_avdtp_cid(packet);
867             connection = avdtp_get_connection_for_avdtp_cid(cid);
868             btstack_assert(connection != NULL);
869             config_process = a2dp_config_process_for_role(role, connection);
870 
871             if (avdtp_subevent_signaling_reject_get_is_initiator(packet) == 0) break;
872 
873             switch (config_process->state) {
874                 case A2DP_W2_RECONFIGURE_WITH_SEID:
875                     log_info("A2DP reconfigure failed ... local seid 0x%02x, active remote seid 0x%02x",
876                              avdtp_stream_endpoint_seid(config_process->local_stream_endpoint),
877                              config_process->local_stream_endpoint->remote_sep.seid);
878                     a2dp_emit_stream_reconfigured_role(role, cid, avdtp_stream_endpoint_seid(
879                             config_process->local_stream_endpoint), ERROR_CODE_UNSPECIFIED_ERROR);
880                     config_process->state = A2DP_STREAMING_OPENED;
881                     break;
882                 default:
883                     config_process->state = A2DP_CONNECTED;
884                     break;
885             }
886 
887             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_COMMAND_REJECTED);
888             break;
889 
890         case AVDTP_SUBEVENT_SIGNALING_GENERAL_REJECT:
891             cid = avdtp_subevent_signaling_general_reject_get_avdtp_cid(packet);
892             connection = avdtp_get_connection_for_avdtp_cid(cid);
893             btstack_assert(connection != NULL);
894             config_process = a2dp_config_process_for_role(role, connection);
895 
896             if (avdtp_subevent_signaling_general_reject_get_is_initiator(packet) == 0) break;
897 
898             config_process->state = A2DP_CONNECTED;
899             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_COMMAND_REJECTED);
900             break;
901 
902         case AVDTP_SUBEVENT_STREAMING_CONNECTION_RELEASED:
903             cid = avdtp_subevent_streaming_connection_released_get_avdtp_cid(packet);
904             connection = avdtp_get_connection_for_avdtp_cid(cid);
905             btstack_assert(connection != NULL);
906             config_process = a2dp_config_process_for_role(role, connection);
907 
908             config_process->state = A2DP_CONFIGURED;
909             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_STREAM_RELEASED);
910             break;
911 
912         case AVDTP_SUBEVENT_SIGNALING_CONNECTION_RELEASED:
913             cid = avdtp_subevent_signaling_connection_released_get_avdtp_cid(packet);
914             connection = avdtp_get_connection_for_avdtp_cid(cid);
915             btstack_assert(connection != NULL);
916             config_process = a2dp_config_process_for_role(role, connection);
917 
918             // connect/release are passed on to app
919             if (a2dp_config_process_sep_discovery_cid == cid){
920                 a2dp_config_process_timer_stop();
921                 config_process->stream_endpoint_configured = false;
922                 config_process->local_stream_endpoint = NULL;
923 
924                 config_process->state = A2DP_IDLE;
925                 a2dp_config_process_sep_discovery_cid = 0;
926             }
927             a2dp_replace_subevent_id_and_emit_for_role(role, packet, size, A2DP_SUBEVENT_SIGNALING_CONNECTION_RELEASED);
928             break;
929 
930         default:
931             break;
932     }
933 }
934 
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)935 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){
936     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
937     if (connection == NULL){
938         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
939     }
940     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
941 
942     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_SBC);
943     if (status != ERROR_CODE_SUCCESS) {
944         return status;
945     }
946 
947     // set config in reserved buffer
948     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *) config_process->local_stream_endpoint->media_codec_info;
949     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = 4;
950     status = avdtp_config_sbc_store(config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information, configuration);
951     if (status != ERROR_CODE_SUCCESS) {
952         return status;
953     }
954 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
955     a2dp_config_process_set_config(role, connection);
956 #endif
957 
958     return ERROR_CODE_SUCCESS;
959 }
960 
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)961 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){
962     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
963     if (connection == NULL){
964         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
965     }
966     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
967 
968     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_MPEG_1_2_AUDIO);
969     if (status != ERROR_CODE_SUCCESS) {
970         return status;
971     }
972 
973     // set config in reserved buffer
974     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *)config_process->local_stream_endpoint->media_codec_info;
975     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = 4;
976     status = avdtp_config_mpeg_audio_store(config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information, configuration);
977     if (status != ERROR_CODE_SUCCESS) {
978         return status;
979     }
980 
981 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
982     a2dp_config_process_set_config(role, connection);
983 #endif
984 
985     return ERROR_CODE_SUCCESS;
986 }
987 
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)988 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){
989     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
990     if (connection == NULL){
991         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
992     }
993     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
994 
995     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_MPEG_2_4_AAC);
996     if (status != ERROR_CODE_SUCCESS) {
997         return status;
998     }
999     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *) config_process->local_stream_endpoint->media_codec_info;
1000     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = 6;
1001     status = avdtp_config_mpeg_aac_store(config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information, configuration);
1002     if (status != ERROR_CODE_SUCCESS){
1003         return status;
1004     }
1005 
1006 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
1007     a2dp_config_process_set_config(role, connection);
1008 #endif
1009 
1010     return ERROR_CODE_SUCCESS;
1011 }
1012 
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)1013 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){
1014     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
1015     if (connection == NULL){
1016         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1017     }
1018     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
1019 
1020     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_ATRAC_FAMILY);
1021     if (status != ERROR_CODE_SUCCESS) {
1022         return status;
1023     }
1024 
1025     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *) config_process->local_stream_endpoint->media_codec_info;
1026     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = 7;
1027     status = avdtp_config_atrac_store(config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information, configuration);
1028     if (status != ERROR_CODE_SUCCESS) {
1029         return status;
1030     }
1031 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
1032     a2dp_config_process_set_config(role, connection);
1033 #endif
1034 
1035     return ERROR_CODE_SUCCESS;
1036 }
1037 
a2dp_config_process_set_other(avdtp_role_t role,uint16_t a2dp_cid,uint8_t local_seid,uint8_t remote_seid,const uint8_t * media_codec_information,uint8_t media_codec_information_len)1038 uint8_t a2dp_config_process_set_other(avdtp_role_t role, uint16_t a2dp_cid,  uint8_t local_seid, uint8_t remote_seid,
1039                                      const uint8_t * media_codec_information, uint8_t media_codec_information_len){
1040     avdtp_connection_t * connection = avdtp_get_connection_for_avdtp_cid(a2dp_cid);
1041     if (connection == NULL){
1042         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
1043     }
1044     a2dp_config_process_t * config_process = a2dp_config_process_for_role(role, connection);
1045 
1046     uint8_t status = a2dp_config_process_config_init(role, connection, local_seid, remote_seid, AVDTP_CODEC_NON_A2DP);
1047     if (status != 0) {
1048         return status;
1049     }
1050 
1051     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information = (uint8_t *) media_codec_information;
1052     config_process->local_stream_endpoint->remote_configuration.media_codec.media_codec_information_len = media_codec_information_len;
1053 
1054 #ifdef ENABLE_A2DP_EXPLICIT_CONFIG
1055         a2dp_config_process_set_config(role, connection);
1056 #endif
1057 
1058     return status;
1059 }
1060