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