1 /*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*****************************************************************************
8 *
9 * Filename: btc_avk.c
10 *
11 * Description: AV implementation
12 *
13 *****************************************************************************/
14 #include "common/bt_target.h"
15 #include <string.h>
16 #include "common/bt_trace.h"
17 #include "common/bt_defs.h"
18 #include "osi/allocator.h"
19 #include "stack/btu.h"
20 #include "bta/bta_av_api.h"
21 #include "btc/btc_dm.h"
22 #include "btc/btc_common.h"
23 #include "btc/btc_manage.h"
24 #include "btc_av.h"
25 #include "btc_avrc.h"
26 #include "btc/btc_util.h"
27 #include "btc/btc_profile_queue.h"
28 #include "btc_a2dp.h"
29 #include "btc_a2dp_control.h"
30 #include "btc_a2dp_sink.h"
31 #include "btc_a2dp_source.h"
32 #include "esp_a2dp_api.h"
33 #include "osi/alarm.h"
34
35 #if BTC_AV_INCLUDED
36
37 // global variable to inidcate avrc is initialized with a2dp
38 bool g_av_with_rc;
39 // global variable to indicate a2dp is initialized
40 bool g_a2dp_on_init;
41 // global variable to indicate a2dp is deinitialized
42 bool g_a2dp_on_deinit;
43 // global variable to indicate a2dp source deinitialization is ongoing
44 bool g_a2dp_source_ongoing_deinit;
45 // global variable to indicate a2dp sink deinitialization is ongoing
46 bool g_a2dp_sink_ongoing_deinit;
47
48
49 /*****************************************************************************
50 ** Constants & Macros
51 ******************************************************************************/
52 #define BTC_AV_SERVICE_NAME "Advanced Audio"
53
54 #define BTC_TIMEOUT_AV_OPEN_ON_RC_SECS 2
55
56 typedef enum {
57 BTC_AV_STATE_IDLE = 0x0,
58 BTC_AV_STATE_OPENING,
59 BTC_AV_STATE_OPENED,
60 BTC_AV_STATE_STARTED,
61 BTC_AV_STATE_CLOSING
62 } btc_av_state_t;
63
64 /* Should not need dedicated suspend state as actual actions are no
65 different than open state. Suspend flags are needed however to prevent
66 media task from trying to restart stream during remote suspend or while
67 we are in the process of a local suspend */
68
69 #define BTC_AV_FLAG_LOCAL_SUSPEND_PENDING 0x1
70 #define BTC_AV_FLAG_REMOTE_SUSPEND 0x2
71 #define BTC_AV_FLAG_PENDING_START 0x4
72 #define BTC_AV_FLAG_PENDING_STOP 0x8
73
74 /*****************************************************************************
75 ** Local type definitions
76 ******************************************************************************/
77
78 typedef struct {
79 int service_id;
80 tBTA_AV_HNDL bta_handle;
81 bt_bdaddr_t peer_bda;
82 btc_sm_handle_t sm_handle;
83 UINT8 flags;
84 tBTA_AV_EDR edr;
85 UINT8 peer_sep; /* sep type of peer device */
86 #if BTC_AV_SRC_INCLUDED
87 osi_alarm_t *tle_av_open_on_rc;
88 #endif /* BTC_AV_SRC_INCLUDED */
89 } btc_av_cb_t;
90
91 typedef struct {
92 bt_bdaddr_t target_bda;
93 uint16_t uuid;
94 } btc_av_connect_req_t;
95
96 typedef struct {
97 bt_bdaddr_t target_bda;
98 } btc_av_disconn_req_t;
99
100 /*****************************************************************************
101 ** Static variables
102 ******************************************************************************/
103
104 #if A2D_DYNAMIC_MEMORY == FALSE
105 static btc_av_cb_t btc_av_cb = {0};
106 #else
107 static btc_av_cb_t *btc_av_cb_ptr = NULL;
108 #define btc_av_cb (*btc_av_cb_ptr)
109 #endif ///A2D_DYNAMIC_MEMORY == FALSE
110
111 /* both interface and media task needs to be ready to alloc incoming request */
112 #define CHECK_BTAV_INIT() do \
113 { \
114 assert (btc_av_cb.sm_handle != NULL); \
115 } while (0)
116
117
118 /* Helper macro to avoid code duplication in the state machine handlers */
119 #define CHECK_RC_EVENT(e, d) \
120 case BTA_AV_RC_OPEN_EVT: \
121 case BTA_AV_RC_CLOSE_EVT: \
122 case BTA_AV_REMOTE_CMD_EVT: \
123 case BTA_AV_VENDOR_CMD_EVT: \
124 case BTA_AV_META_MSG_EVT: \
125 case BTA_AV_RC_FEAT_EVT: \
126 case BTA_AV_REMOTE_RSP_EVT: \
127 { \
128 btc_rc_handler(e, d);\
129 }break; \
130
131 static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *data);
132 static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *data);
133 static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *data);
134 static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *data);
135 static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *data);
136 static void clean_up(int service_id);
137
138 #if BTC_AV_SRC_INCLUDED
139 static bt_status_t btc_a2d_src_init(void);
140 static bt_status_t btc_a2d_src_connect(bt_bdaddr_t *remote_bda);
141 static void btc_a2d_src_deinit(void);
142 #endif /* BTC_AV_SRC_INCLUDED */
143
144 #if BTC_AV_SINK_INCLUDED
145 static bt_status_t btc_a2d_sink_init(void);
146 static bt_status_t btc_a2d_sink_connect(bt_bdaddr_t *remote_bda);
147 static void btc_a2d_sink_deinit(void);
148 #endif /* BTC_AV_SINK_INCLUDED */
149
150 static const btc_sm_handler_t btc_av_state_handlers[] = {
151 btc_av_state_idle_handler,
152 btc_av_state_opening_handler,
153 btc_av_state_opened_handler,
154 btc_av_state_started_handler,
155 btc_av_state_closing_handler
156 };
157
158 static void btc_av_event_free_data(btc_sm_event_t event, void *p_data);
159
160 /*************************************************************************
161 ** Extern functions
162 *************************************************************************/
163
164 extern tBTA_AV_CO_FUNCTS bta_av_a2d_cos;
165 extern tBTA_AVRC_CO_FUNCTS bta_avrc_cos;
166 /*****************************************************************************
167 ** Local helper functions
168 ******************************************************************************/
btc_a2d_cb_to_app(esp_a2d_cb_event_t event,esp_a2d_cb_param_t * param)169 static inline void btc_a2d_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
170 {
171 esp_a2d_cb_t btc_a2d_cb = (esp_a2d_cb_t)btc_profile_cb_get(BTC_PID_A2DP);
172 if (btc_a2d_cb) {
173 btc_a2d_cb(event, param);
174 }
175 }
176
dump_av_sm_state_name(btc_av_state_t state)177 UNUSED_ATTR static const char *dump_av_sm_state_name(btc_av_state_t state)
178 {
179 switch (state) {
180 CASE_RETURN_STR(BTC_AV_STATE_IDLE)
181 CASE_RETURN_STR(BTC_AV_STATE_OPENING)
182 CASE_RETURN_STR(BTC_AV_STATE_OPENED)
183 CASE_RETURN_STR(BTC_AV_STATE_STARTED)
184 CASE_RETURN_STR(BTC_AV_STATE_CLOSING)
185 default: return "UNKNOWN_STATE";
186 }
187 }
188
dump_av_sm_event_name(btc_av_sm_event_t event)189 UNUSED_ATTR static const char *dump_av_sm_event_name(btc_av_sm_event_t event)
190 {
191 switch ((int)event) {
192 CASE_RETURN_STR(BTA_AV_ENABLE_EVT)
193 CASE_RETURN_STR(BTA_AV_REGISTER_EVT)
194 CASE_RETURN_STR(BTA_AV_OPEN_EVT)
195 CASE_RETURN_STR(BTA_AV_CLOSE_EVT)
196 CASE_RETURN_STR(BTA_AV_START_EVT)
197 CASE_RETURN_STR(BTA_AV_STOP_EVT)
198 CASE_RETURN_STR(BTA_AV_PROTECT_REQ_EVT)
199 CASE_RETURN_STR(BTA_AV_PROTECT_RSP_EVT)
200 CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT)
201 CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT)
202 CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT)
203 CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT)
204 CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT)
205 CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT)
206 CASE_RETURN_STR(BTA_AV_RECONFIG_EVT)
207 CASE_RETURN_STR(BTA_AV_SUSPEND_EVT)
208 CASE_RETURN_STR(BTA_AV_PENDING_EVT)
209 CASE_RETURN_STR(BTA_AV_META_MSG_EVT)
210 CASE_RETURN_STR(BTA_AV_REJECT_EVT)
211 CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT)
212 CASE_RETURN_STR(BTC_SM_ENTER_EVT)
213 CASE_RETURN_STR(BTC_SM_EXIT_EVT)
214 CASE_RETURN_STR(BTC_AV_CONNECT_REQ_EVT)
215 CASE_RETURN_STR(BTC_AV_DISCONNECT_REQ_EVT)
216 CASE_RETURN_STR(BTC_AV_START_STREAM_REQ_EVT)
217 CASE_RETURN_STR(BTC_AV_STOP_STREAM_REQ_EVT)
218 CASE_RETURN_STR(BTC_AV_SUSPEND_STREAM_REQ_EVT)
219 CASE_RETURN_STR(BTC_AV_SINK_CONFIG_REQ_EVT)
220 default: return "UNKNOWN_EVENT";
221 }
222 }
223
224 /****************************************************************************
225 ** Local helper functions
226 *****************************************************************************/
227 #if BTC_AV_SRC_INCLUDED
228 /*******************************************************************************
229 **
230 ** Function btc_initiate_av_open_tmr_hdlr
231 **
232 ** Description Timer to trigger AV open if the remote headset establishes
233 ** RC connection w/o AV connection. The timer is needed to IOP
234 ** with headsets that do establish AV after RC connection.
235 **
236 ** Returns void
237 **
238 *******************************************************************************/
btc_initiate_av_open_tmr_hdlr(void * arg)239 static void btc_initiate_av_open_tmr_hdlr(void *arg)
240 {
241 UNUSED(arg);
242 BD_ADDR peer_addr;
243 btc_av_connect_req_t connect_req;
244 /* is there at least one RC connection - There should be */
245 if (btc_rc_get_connected_peer(peer_addr)) {
246 BTC_TRACE_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__);
247 /* In case of AVRCP connection request, we will initiate SRC connection */
248 memcpy(connect_req.target_bda.address, peer_addr, sizeof(bt_bdaddr_t));
249 connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE;
250 btc_dispatch_sm_event(BTC_AV_CONNECT_REQ_EVT, &connect_req, sizeof(btc_av_connect_req_t));
251 } else {
252 BTC_TRACE_ERROR("%s No connected RC peers", __FUNCTION__);
253 }
254 }
255 #endif /* BTC_AV_SRC_INCLUDED */
256
257 /*****************************************************************************
258 ** Static functions
259 ******************************************************************************/
btc_report_connection_state(esp_a2d_connection_state_t state,bt_bdaddr_t * bd_addr,int disc_rsn)260 static void btc_report_connection_state(esp_a2d_connection_state_t state, bt_bdaddr_t *bd_addr, int disc_rsn)
261 {
262 // todo: add callback for SRC
263 esp_a2d_cb_param_t param;
264 memset(¶m, 0, sizeof(esp_a2d_cb_param_t));
265
266 param.conn_stat.state = state;
267 if (bd_addr) {
268 memcpy(param.conn_stat.remote_bda, bd_addr, sizeof(esp_bd_addr_t));
269 }
270 if (state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
271 param.conn_stat.disc_rsn = (disc_rsn == 0) ? ESP_A2D_DISC_RSN_NORMAL :
272 ESP_A2D_DISC_RSN_ABNORMAL;
273 }
274 btc_a2d_cb_to_app(ESP_A2D_CONNECTION_STATE_EVT, ¶m);
275 }
276
btc_report_audio_state(esp_a2d_audio_state_t state,bt_bdaddr_t * bd_addr)277 static void btc_report_audio_state(esp_a2d_audio_state_t state, bt_bdaddr_t *bd_addr)
278 {
279 // todo: add callback for SRC
280 esp_a2d_cb_param_t param;
281 memset(¶m, 0, sizeof(esp_a2d_cb_param_t));
282
283 param.audio_stat.state = state;
284 if (bd_addr) {
285 memcpy(param.audio_stat.remote_bda, bd_addr, sizeof(esp_bd_addr_t));
286 }
287 btc_a2d_cb_to_app(ESP_A2D_AUDIO_STATE_EVT, ¶m);
288 }
289
290 /*****************************************************************************
291 **
292 ** Function btc_av_state_idle_handler
293 **
294 ** Description State managing disconnected AV link
295 **
296 ** Returns TRUE if event was processed, FALSE otherwise
297 **
298 *******************************************************************************/
299
btc_av_state_idle_handler(btc_sm_event_t event,void * p_data)300 static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data)
301 {
302 BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
303 dump_av_sm_event_name(event), btc_av_cb.flags);
304
305 switch (event) {
306 case BTC_SM_ENTER_EVT:
307 /* clear the peer_bda */
308 memset(&btc_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t));
309 btc_av_cb.flags = 0;
310 btc_av_cb.edr = 0;
311 btc_a2dp_on_idle();
312 break;
313
314 case BTC_SM_EXIT_EVT:
315 break;
316
317 case BTA_AV_ENABLE_EVT:
318 break;
319
320 case BTA_AV_REGISTER_EVT:
321 btc_av_cb.bta_handle = ((tBTA_AV *)p_data)->registr.hndl;
322 break;
323
324 case BTA_AV_PENDING_EVT:
325 case BTC_AV_CONNECT_REQ_EVT: {
326 if (event == BTC_AV_CONNECT_REQ_EVT) {
327 memcpy(&btc_av_cb.peer_bda, &((btc_av_connect_req_t *)p_data)->target_bda,
328 sizeof(bt_bdaddr_t));
329 if (g_av_with_rc) {
330 BTA_AvOpen(btc_av_cb.peer_bda.address, btc_av_cb.bta_handle,
331 TRUE, BTA_SEC_AUTHENTICATE, ((btc_av_connect_req_t *)p_data)->uuid);
332 } else {
333 BTA_AvOpen(btc_av_cb.peer_bda.address, btc_av_cb.bta_handle,
334 FALSE, BTA_SEC_AUTHENTICATE, ((btc_av_connect_req_t *)p_data)->uuid);
335 }
336 } else if (event == BTA_AV_PENDING_EVT) {
337 bdcpy(btc_av_cb.peer_bda.address, ((tBTA_AV *)p_data)->pend.bd_addr);
338 UINT16 uuid = (btc_av_cb.service_id == BTA_A2DP_SOURCE_SERVICE_ID) ? UUID_SERVCLASS_AUDIO_SOURCE :
339 UUID_SERVCLASS_AUDIO_SINK;
340 if (g_av_with_rc) {
341 BTA_AvOpen(btc_av_cb.peer_bda.address, btc_av_cb.bta_handle,
342 TRUE, BTA_SEC_AUTHENTICATE, uuid);
343 } else {
344 BTA_AvOpen(btc_av_cb.peer_bda.address, btc_av_cb.bta_handle,
345 FALSE, BTA_SEC_AUTHENTICATE, uuid);
346 }
347 }
348 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_OPENING);
349 } break;
350
351 case BTC_AV_DISCONNECT_REQ_EVT:
352 BTC_TRACE_WARNING("No Link At All.");
353 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &((btc_av_disconn_req_t *)p_data)->target_bda, 0);
354 break;
355
356 case BTA_AV_RC_OPEN_EVT:
357 /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So
358 * as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore,
359 * we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state.
360 * We initiate the AV connection after a small 3s timeout to avoid any collisions from the
361 * headsets, as some headsets initiate the AVRC connection first and then
362 * immediately initiate the AV connection
363 *
364 * TODO: We may need to do this only on an AVRCP Play. FixMe
365 */
366 #if BTC_AV_SRC_INCLUDED
367 BTC_TRACE_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV");
368 btc_av_cb.tle_av_open_on_rc = osi_alarm_new("AVconn", btc_initiate_av_open_tmr_hdlr, NULL, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000);
369 osi_alarm_set(btc_av_cb.tle_av_open_on_rc, BTC_TIMEOUT_AV_OPEN_ON_RC_SECS * 1000);
370 #endif /* BTC_AV_SRC_INCLUDED */
371 btc_rc_handler(event, p_data);
372 break;
373
374 case BTA_AV_REMOTE_CMD_EVT:
375 case BTA_AV_VENDOR_CMD_EVT:
376 case BTA_AV_META_MSG_EVT:
377 case BTA_AV_RC_FEAT_EVT:
378 case BTA_AV_REMOTE_RSP_EVT:
379 btc_rc_handler(event, (tBTA_AV *)p_data);
380 break;
381
382 case BTA_AV_RC_CLOSE_EVT:
383 #if BTC_AV_SRC_INCLUDED
384 if (btc_av_cb.tle_av_open_on_rc) {
385 osi_alarm_free(btc_av_cb.tle_av_open_on_rc);
386 btc_av_cb.tle_av_open_on_rc = NULL;
387 }
388 #endif /* BTC_AV_SRC_INCLUDED */
389 btc_rc_handler(event, p_data);
390 break;
391
392 default:
393 BTC_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__,
394 dump_av_sm_event_name(event));
395 return FALSE;
396 }
397
398 return TRUE;
399 }
400 /*****************************************************************************
401 **
402 ** Function btc_av_state_opening_handler
403 **
404 ** Description Intermediate state managing events during establishment
405 ** of avdtp channel
406 **
407 ** Returns TRUE if event was processed, FALSE otherwise
408 **
409 *******************************************************************************/
410
btc_av_state_opening_handler(btc_sm_event_t event,void * p_data)411 static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data)
412 {
413 BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
414 dump_av_sm_event_name(event), btc_av_cb.flags);
415
416 switch (event) {
417 case BTC_SM_ENTER_EVT:
418 /* inform the application that we are entering connecting state */
419 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_CONNECTING, &(btc_av_cb.peer_bda), 0);
420 break;
421
422 case BTC_SM_EXIT_EVT:
423 break;
424
425 case BTA_AV_REJECT_EVT:
426 BTC_TRACE_WARNING(" Received BTA_AV_REJECT_EVT \n");
427 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), 0);
428 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
429 break;
430
431 case BTA_AV_OPEN_EVT: {
432 tBTA_AV *p_bta_data = (tBTA_AV *)p_data;
433 esp_a2d_connection_state_t conn_stat;
434 btc_sm_state_t av_state;
435 BTC_TRACE_DEBUG("status:%d, edr 0x%x, peer sep %d\n", p_bta_data->open.status,
436 p_bta_data->open.edr, p_bta_data->open.sep);
437
438 if (p_bta_data->open.status == BTA_AV_SUCCESS) {
439 btc_av_cb.edr = p_bta_data->open.edr;
440 btc_av_cb.peer_sep = p_bta_data->open.sep;
441
442 conn_stat = ESP_A2D_CONNECTION_STATE_CONNECTED;
443 av_state = BTC_AV_STATE_OPENED;
444 } else {
445 BTC_TRACE_WARNING("BTA_AV_OPEN_EVT::FAILED status: %d\n", p_bta_data->open.status);
446
447 conn_stat = ESP_A2D_CONNECTION_STATE_DISCONNECTED;
448 av_state = BTC_AV_STATE_IDLE;
449 }
450 /* inform the application of the event */
451 btc_report_connection_state(conn_stat, &(btc_av_cb.peer_bda), 0);
452 /* change state to open/idle based on the status */
453 btc_sm_change_state(btc_av_cb.sm_handle, av_state);
454
455 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
456 /* if queued PLAY command, send it now */
457 /* necessary to add this?
458 btc_rc_check_handle_pending_play(p_bta_data->open.bd_addr,
459 (p_bta_data->open.status == BTA_AV_SUCCESS));
460 */
461 } else if (btc_av_cb.peer_sep == AVDT_TSEP_SRC &&
462 (p_bta_data->open.status == BTA_AV_SUCCESS)) {
463 /* Bring up AVRCP connection too if AVRC Initialized */
464 if(g_av_with_rc) {
465 BTA_AvOpenRc(btc_av_cb.bta_handle);
466 } else {
467 BTC_TRACE_WARNING("AVRC not Init, not using it.");
468 }
469 }
470 btc_queue_advance();
471 } break;
472
473 case BTC_AV_SINK_CONFIG_REQ_EVT: {
474 if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) {
475 esp_a2d_cb_param_t param;
476 memcpy(param.audio_cfg.remote_bda, &btc_av_cb.peer_bda, sizeof(esp_bd_addr_t));
477 memcpy(¶m.audio_cfg.mcc, p_data, sizeof(esp_a2d_mcc_t));
478 btc_a2d_cb_to_app(ESP_A2D_AUDIO_CFG_EVT, ¶m);
479 }
480 } break;
481
482 case BTC_AV_CONNECT_REQ_EVT:
483 // Check for device, if same device which moved to opening then ignore callback
484 if (memcmp ((bt_bdaddr_t *)p_data, &(btc_av_cb.peer_bda),
485 sizeof(btc_av_cb.peer_bda)) == 0) {
486 BTC_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Connect Req\n", __func__);
487 btc_queue_advance();
488 break;
489 } else {
490 BTC_TRACE_DEBUG("%s: Moved from idle by Incoming Connection request\n", __func__);
491 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, (bt_bdaddr_t *)p_data, 0);
492 btc_queue_advance();
493 break;
494 }
495
496 case BTA_AV_PENDING_EVT:
497 // Check for device, if same device which moved to opening then ignore callback
498 if (memcmp (((tBTA_AV *)p_data)->pend.bd_addr, &(btc_av_cb.peer_bda),
499 sizeof(btc_av_cb.peer_bda)) == 0) {
500 BTC_TRACE_DEBUG("%s: Same device moved to Opening state,ignore Pending Req\n", __func__);
501 break;
502 } else {
503 BTC_TRACE_DEBUG("%s: Moved from idle by outgoing Connection request\n", __func__);
504 BTA_AvDisconnect(((tBTA_AV *)p_data)->pend.bd_addr);
505 break;
506 }
507
508 CHECK_RC_EVENT(event, p_data);
509
510 default:
511 BTC_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__, dump_av_sm_event_name(event));
512 return FALSE;
513 }
514 return TRUE;
515 }
516
517
518 /*****************************************************************************
519 **
520 ** Function btc_av_state_closing_handler
521 **
522 ** Description Intermediate state managing events during closing
523 ** of avdtp channel
524 **
525 ** Returns TRUE if event was processed, FALSE otherwise
526 **
527 *******************************************************************************/
528
btc_av_state_closing_handler(btc_sm_event_t event,void * p_data)529 static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *p_data)
530 {
531 BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
532 dump_av_sm_event_name(event), btc_av_cb.flags);
533
534 switch (event) {
535 case BTC_SM_ENTER_EVT:
536 #if BTC_AV_SRC_INCLUDED
537 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
538 /* immediately stop transmission of frames */
539 btc_a2dp_source_set_tx_flush(TRUE);
540 /* wait for audioflinger to stop a2dp */
541 }
542 #endif /* BTC_AV_SRC_INCLUDED */
543 #if BTC_AV_SINK_INCLUDED
544 if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) {
545 btc_a2dp_sink_set_rx_flush(TRUE);
546 }
547 #endif /* BTC_AV_SINK_INCLUDED */
548 break;
549
550 case BTA_AV_STOP_EVT:
551 case BTC_AV_STOP_STREAM_REQ_EVT:
552 #if BTC_AV_SRC_INCLUDED
553 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
554 /* immediately flush any pending tx frames while suspend is pending */
555 btc_a2dp_source_set_tx_flush(TRUE);
556 }
557 #endif /* BTC_AV_SRC_INCLUDED */
558 #if BTC_AV_SINK_INCLUDED
559 if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) {
560 btc_a2dp_sink_set_rx_flush(TRUE);
561 }
562 #endif /* BTC_AV_SINK_INCLUDED */
563 btc_a2dp_on_stopped(NULL);
564 break;
565
566 case BTC_SM_EXIT_EVT:
567 break;
568
569 case BTA_AV_CLOSE_EVT: {
570 tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data;
571 /* inform the application that we are disconnecting */
572 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), close->disc_rsn);
573 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
574 break;
575 }
576
577 /* Handle the RC_CLOSE event for the cleanup */
578 case BTA_AV_RC_CLOSE_EVT:
579 btc_rc_handler(event, (tBTA_AV *)p_data);
580 break;
581
582 default:
583 BTC_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__, dump_av_sm_event_name(event));
584 return FALSE;
585 }
586 return TRUE;
587 }
588
589 /*****************************************************************************
590 **
591 ** Function btc_av_state_opened_handler
592 **
593 ** Description Handles AV events while AVDTP is in OPEN state
594 **
595 ** Returns TRUE if event was processed, FALSE otherwise
596 **
597 *******************************************************************************/
btc_av_state_opened_handler(btc_sm_event_t event,void * p_data)598 static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data)
599 {
600 tBTA_AV *p_av = (tBTA_AV *)p_data;
601
602 BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
603 dump_av_sm_event_name(event), btc_av_cb.flags);
604
605 if ( (event == BTA_AV_REMOTE_CMD_EVT) && (btc_av_cb.flags & BTC_AV_FLAG_REMOTE_SUSPEND) &&
606 (p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY) ) {
607 BTC_TRACE_DEBUG("%s: Resetting remote suspend flag on RC PLAY\n", __FUNCTION__);
608 btc_av_cb.flags &= ~BTC_AV_FLAG_REMOTE_SUSPEND;
609 }
610
611 switch (event) {
612 case BTC_SM_ENTER_EVT:
613 btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_STOP;
614 btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_START;
615 break;
616
617 case BTC_SM_EXIT_EVT:
618 btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_START;
619 break;
620
621 case BTC_AV_START_STREAM_REQ_EVT:
622 #if BTC_AV_SRC_INCLUDED
623 if (btc_av_cb.peer_sep != AVDT_TSEP_SRC) {
624 btc_a2dp_source_setup_codec();
625 }
626 #endif /* BTC_AV_SRC_INCLUDED */
627 BTA_AvStart();
628 btc_av_cb.flags |= BTC_AV_FLAG_PENDING_START;
629 break;
630
631 case BTA_AV_START_EVT: {
632 BTC_TRACE_DEBUG("BTA_AV_START_EVT status %d, suspending %d, init %d\n",
633 p_av->start.status, p_av->start.suspending, p_av->start.initiator);
634
635 if ((p_av->start.status == BTA_SUCCESS) && (p_av->start.suspending == TRUE)) {
636 return TRUE;
637 }
638 #if BTC_AV_SRC_INCLUDED
639 /* if remote tries to start a2dp when DUT is a2dp source
640 * then suspend. In case a2dp is sink and call is active
641 * then disconnect the AVDTP channel
642 */
643 if (!(btc_av_cb.flags & BTC_AV_FLAG_PENDING_START)) {
644 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
645 BTC_TRACE_DEBUG("%s: trigger suspend as remote initiated!!", __FUNCTION__);
646 btc_dispatch_sm_event(BTC_AV_SUSPEND_STREAM_REQ_EVT, NULL, 0);
647 }
648 }
649 /* In case peer is A2DP SRC we do not want to ack commands on UIPC*/
650 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
651 if (btc_a2dp_on_started(&p_av->start,
652 ((btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) != 0))) {
653 /* only clear pending flag after acknowledgement */
654 btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_START;
655 }
656 }
657 #endif /* BTC_AV_SRC_INCLUDED */
658 /* remain in open state if status failed */
659 if (p_av->start.status != BTA_AV_SUCCESS) {
660 return FALSE;
661 }
662 #if BTC_AV_SINK_INCLUDED
663 if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) {
664 btc_a2dp_sink_set_rx_flush(FALSE); /* remove flush state, ready for streaming*/
665 }
666 #endif /* BTC_AV_SINK_INCLUDED */
667 #if BTC_AV_SRC_INCLUDED
668 /* change state to started, send acknowledgement if start is pending */
669 if (btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) {
670 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
671 btc_a2dp_on_started(NULL, TRUE);
672 }
673 /* pending start flag will be cleared when exit current state */
674 }
675 #endif /* BTC_AV_SRC_INCLUDED */
676 /* wait for audio path to open */
677 btc_a2dp_control_datapath_ctrl(BTC_AV_DATAPATH_OPEN_EVT);
678
679 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_STARTED);
680
681 } break;
682
683 case BTC_AV_DISCONNECT_REQ_EVT:
684 BTA_AvClose(btc_av_cb.bta_handle);
685 if (btc_av_cb.peer_sep == AVDT_TSEP_SRC && g_av_with_rc == true) {
686 BTA_AvCloseRc(btc_av_cb.bta_handle);
687 }
688
689 /* inform the application that we are disconnecting */
690 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btc_av_cb.peer_bda), 0);
691 break;
692
693 case BTA_AV_CLOSE_EVT: {
694 /* avdtp link is closed */
695 btc_a2dp_on_stopped(NULL);
696 tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data;
697 /* inform the application that we are disconnected */
698 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda),
699 close->disc_rsn);
700
701 if (btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) {
702 btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
703 /* pending start flag will be cleared when exit current state */
704 }
705
706 /* change state to idle, send acknowledgement if start is pending */
707 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
708
709 if (g_a2dp_source_ongoing_deinit) {
710 clean_up(BTA_A2DP_SOURCE_SERVICE_ID);
711 } else if (g_a2dp_sink_ongoing_deinit) {
712 clean_up(BTA_A2DP_SINK_SERVICE_ID);
713 }
714 break;
715 }
716
717 case BTA_AV_RECONFIG_EVT:
718 if ((btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) &&
719 (p_av->reconfig.status == BTA_AV_SUCCESS)) {
720 BTC_TRACE_WARNING("reconfig done BTA_AVstart()\n");
721 BTA_AvStart();
722 } else if (btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) {
723 btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_START;
724 btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
725 }
726 break;
727
728 case BTC_AV_CONNECT_REQ_EVT:
729 if (memcmp (&((btc_av_connect_req_t *)p_data)->target_bda, &(btc_av_cb.peer_bda),
730 sizeof(btc_av_cb.peer_bda)) == 0) {
731 BTC_TRACE_DEBUG("%s: Ignore BTC_AVCONNECT_REQ_EVT for same device\n", __func__);
732 } else {
733 BTC_TRACE_DEBUG("%s: Moved to opened by Other Incoming Conn req\n", __func__);
734 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED,
735 (bt_bdaddr_t *)p_data, ESP_A2D_DISC_RSN_NORMAL);
736 }
737 btc_queue_advance();
738 break;
739
740 CHECK_RC_EVENT(event, p_data);
741
742 default:
743 BTC_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__,
744 dump_av_sm_event_name(event));
745 return FALSE;
746
747 }
748 return TRUE;
749 }
750
751 /*****************************************************************************
752 **
753 ** Function btc_av_state_started_handler
754 **
755 ** Description Handles AV events while A2DP stream is started
756 **
757 ** Returns TRUE if event was processed, FALSE otherwise
758 **
759 *******************************************************************************/
760
btc_av_state_started_handler(btc_sm_event_t event,void * p_data)761 static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data)
762 {
763 tBTA_AV *p_av = (tBTA_AV *)p_data;
764
765 BTC_TRACE_DEBUG("%s event: %s flags %x\n", __FUNCTION__,
766 dump_av_sm_event_name(event), btc_av_cb.flags);
767
768 switch (event) {
769 case BTC_SM_ENTER_EVT:
770
771 /* we are again in started state, clear any remote suspend flags */
772 btc_av_cb.flags &= ~BTC_AV_FLAG_REMOTE_SUSPEND;
773
774 btc_report_audio_state(ESP_A2D_AUDIO_STATE_STARTED, &(btc_av_cb.peer_bda));
775
776 /* increase the a2dp consumer task priority temporarily when start
777 ** audio playing, to avoid overflow the audio packet queue. */
778 // adjust_priority_a2dp(TRUE);
779
780 break;
781
782 case BTC_SM_EXIT_EVT:
783 /* restore the a2dp consumer task priority when stop audio playing. */
784 // adjust_priority_a2dp(FALSE);
785
786 break;
787
788 case BTC_AV_START_STREAM_REQ_EVT:
789 #if BTC_AV_SRC_INCLUDED
790 /* we were remotely started, just ack back the local request */
791 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
792 btc_a2dp_on_started(NULL, TRUE);
793 }
794 #endif /* BTC_AV_SRC_INCLUDED */
795 break;
796
797 /* fixme -- use suspend = true always to work around issue with BTA AV */
798 case BTC_AV_STOP_STREAM_REQ_EVT:
799 case BTC_AV_SUSPEND_STREAM_REQ_EVT:
800
801 /* set pending flag to ensure btc task is not trying to restart
802 stream while suspend is in progress */
803 btc_av_cb.flags |= BTC_AV_FLAG_LOCAL_SUSPEND_PENDING;
804
805 /* if we were remotely suspended but suspend locally, local suspend
806 always overrides */
807 btc_av_cb.flags &= ~BTC_AV_FLAG_REMOTE_SUSPEND;
808 #if BTC_AV_SRC_INCLUDED
809 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
810 /* immediately stop transmission of frames while suspend is pending */
811 btc_a2dp_source_set_tx_flush(TRUE);
812 }
813 #endif /* BTC_AV_SRC_INCLUDED */
814 #if BTC_AV_SINK_INCLUDED
815 if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) {
816 btc_a2dp_sink_set_rx_flush(TRUE);
817 btc_a2dp_on_stopped(NULL);
818 }
819 #endif /* BTC_AV_SINK_INCLUDED */
820 BTA_AvStop(TRUE);
821 break;
822
823 case BTC_AV_DISCONNECT_REQ_EVT:
824
825 /* request avdtp to close */
826 BTA_AvClose(btc_av_cb.bta_handle);
827 if (btc_av_cb.peer_sep == AVDT_TSEP_SRC && g_av_with_rc == true) {
828 BTA_AvCloseRc(btc_av_cb.bta_handle);
829 }
830
831 /* inform the application that we are disconnecting */
832 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btc_av_cb.peer_bda), 0);
833
834 /* wait in closing state until fully closed */
835 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_CLOSING);
836 break;
837
838 case BTA_AV_SUSPEND_EVT:
839
840 BTC_TRACE_DEBUG("BTA_AV_SUSPEND_EVT status %d, init %d\n",
841 p_av->suspend.status, p_av->suspend.initiator);
842
843 /* a2dp suspended, stop media task until resumed */
844 btc_a2dp_on_suspended(&p_av->suspend);
845
846 /* if not successful, remain in current state */
847 if (p_av->suspend.status != BTA_AV_SUCCESS) {
848 btc_av_cb.flags &= ~BTC_AV_FLAG_LOCAL_SUSPEND_PENDING;
849 #if BTC_AV_SRC_INCLUDED
850 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) {
851 /* suspend failed, reset back tx flush state */
852 btc_a2dp_source_set_tx_flush(FALSE);
853 }
854 #endif /* BTC_AV_SRC_INCLUDED */
855 return FALSE;
856 }
857
858 if (p_av->suspend.initiator != TRUE) {
859 /* remote suspend, notify HAL and await audioflinger to
860 suspend/stop stream */
861
862 /* set remote suspend flag to block media task from restarting
863 stream only if we did not already initiate a local suspend */
864 if ((btc_av_cb.flags & BTC_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0) {
865 btc_av_cb.flags |= BTC_AV_FLAG_REMOTE_SUSPEND;
866 }
867
868 btc_report_audio_state(ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND, &(btc_av_cb.peer_bda));
869 } else {
870 btc_report_audio_state(ESP_A2D_AUDIO_STATE_STOPPED, &(btc_av_cb.peer_bda));
871 }
872
873 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_OPENED);
874
875 /* suspend completed and state changed, clear pending status */
876 btc_av_cb.flags &= ~BTC_AV_FLAG_LOCAL_SUSPEND_PENDING;
877 break;
878
879 case BTA_AV_STOP_EVT:
880
881 btc_av_cb.flags |= BTC_AV_FLAG_PENDING_STOP;
882 btc_a2dp_on_stopped(&p_av->suspend);
883
884 btc_report_audio_state(ESP_A2D_AUDIO_STATE_STOPPED, &(btc_av_cb.peer_bda));
885
886 /* if stop was successful, change state to open */
887 if (p_av->suspend.status == BTA_AV_SUCCESS) {
888 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_OPENED);
889 }
890 break;
891
892 case BTA_AV_CLOSE_EVT:
893 btc_av_cb.flags |= BTC_AV_FLAG_PENDING_STOP;
894
895 /* avdtp link is closed */
896 btc_a2dp_on_stopped(NULL);
897 tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data;
898 /* inform the application that we are disconnected */
899 btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda),
900 close->disc_rsn);
901 btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE);
902
903 if (g_a2dp_source_ongoing_deinit) {
904 clean_up(BTA_A2DP_SOURCE_SERVICE_ID);
905 } else if (g_a2dp_sink_ongoing_deinit) {
906 clean_up(BTA_A2DP_SINK_SERVICE_ID);
907 }
908 break;
909
910 CHECK_RC_EVENT(event, p_data);
911
912 default:
913 BTC_TRACE_WARNING("%s : unhandled event:%s\n", __FUNCTION__,
914 dump_av_sm_event_name(event));
915 return FALSE;
916
917 }
918 return TRUE;
919 }
920
921 /*****************************************************************************
922 ** Local event handlers
923 ******************************************************************************/
924
btc_av_event_deep_copy(btc_msg_t * msg,void * p_dest,void * p_src)925 void btc_av_event_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
926 {
927 tBTA_AV *av_src = (tBTA_AV *)p_src;
928 tBTA_AV *av_dest = (tBTA_AV *)p_dest;
929
930 // First copy the structure
931 memcpy(p_dest, p_src, sizeof(tBTA_AV));
932
933 switch (msg->act) {
934 case BTA_AV_META_MSG_EVT:
935 if (av_src->meta_msg.p_data && av_src->meta_msg.len) {
936 av_dest->meta_msg.p_data = osi_calloc(av_src->meta_msg.len);
937 assert(av_dest->meta_msg.p_data);
938 memcpy(av_dest->meta_msg.p_data, av_src->meta_msg.p_data, av_src->meta_msg.len);
939 }
940
941 if (av_src->meta_msg.p_msg) {
942 av_dest->meta_msg.p_msg = osi_calloc(sizeof(tAVRC_MSG));
943 assert(av_dest->meta_msg.p_msg);
944 memcpy(av_dest->meta_msg.p_msg, av_src->meta_msg.p_msg, sizeof(tAVRC_MSG));
945
946 if (av_src->meta_msg.p_msg->vendor.p_vendor_data &&
947 av_src->meta_msg.p_msg->vendor.vendor_len) {
948 av_dest->meta_msg.p_msg->vendor.p_vendor_data = osi_calloc(
949 av_src->meta_msg.p_msg->vendor.vendor_len);
950 assert(av_dest->meta_msg.p_msg->vendor.p_vendor_data);
951 memcpy(av_dest->meta_msg.p_msg->vendor.p_vendor_data,
952 av_src->meta_msg.p_msg->vendor.p_vendor_data,
953 av_src->meta_msg.p_msg->vendor.vendor_len);
954 }
955 }
956 break;
957
958 default:
959 break;
960 }
961 }
962
btc_av_event_free_data(btc_sm_event_t event,void * p_data)963 static void btc_av_event_free_data(btc_sm_event_t event, void *p_data)
964 {
965 switch (event) {
966 case BTA_AV_META_MSG_EVT: {
967 tBTA_AV *av = (tBTA_AV *)p_data;
968 if (av->meta_msg.p_data) {
969 osi_free(av->meta_msg.p_data);
970 }
971
972 if (av->meta_msg.p_msg) {
973 if (av->meta_msg.p_msg->vendor.p_vendor_data) {
974 osi_free(av->meta_msg.p_msg->vendor.p_vendor_data);
975 }
976 osi_free(av->meta_msg.p_msg);
977 }
978 }
979 break;
980
981 default:
982 break;
983 }
984 }
985
986 /*******************************************************************************
987 **
988 ** Function btc_av_init
989 **
990 ** Description Initializes btc AV if not already done
991 **
992 ** Returns bt_status_t
993 **
994 *******************************************************************************/
btc_av_init(int service_id)995 static bt_status_t btc_av_init(int service_id)
996 {
997
998 #if A2D_DYNAMIC_MEMORY == TRUE
999 if (btc_av_cb_ptr != NULL) {
1000 return BT_STATUS_FAIL;
1001 }
1002
1003 if ((btc_av_cb_ptr = (btc_av_cb_t *)osi_malloc(sizeof(btc_av_cb_t))) == NULL) {
1004 APPL_TRACE_ERROR("%s malloc failed!", __func__);
1005 return BT_STATUS_NOMEM;
1006 }
1007 memset((void *)btc_av_cb_ptr, 0, sizeof(btc_av_cb_t));
1008 #endif
1009
1010 if (btc_av_cb.sm_handle == NULL) {
1011 btc_av_cb.service_id = service_id;
1012 bool stat = false;
1013 if (service_id == BTA_A2DP_SOURCE_SERVICE_ID) {
1014 #if BTC_AV_SRC_INCLUDED
1015 stat = btc_a2dp_source_startup();
1016 #endif
1017 } else if (service_id == BTA_A2DP_SINK_SERVICE_ID) {
1018 #if BTC_AV_SINK_INCLUDED
1019 stat = btc_a2dp_sink_startup();
1020 #endif
1021 }
1022
1023 if (!stat) {
1024 #if A2D_DYNAMIC_MEMORY == TRUE
1025 osi_free(btc_av_cb_ptr);
1026 btc_av_cb_ptr = NULL;
1027 #endif
1028 g_a2dp_on_init = false;
1029 g_a2dp_on_deinit = true;
1030 g_a2dp_source_ongoing_deinit = false;
1031 g_a2dp_sink_ongoing_deinit = false;
1032 goto av_init_fail;
1033 }
1034
1035 /* Also initialize the AV state machine */
1036 btc_av_cb.sm_handle =
1037 btc_sm_init((const btc_sm_handler_t *)btc_av_state_handlers, BTC_AV_STATE_IDLE);
1038
1039 if (service_id == BTA_A2DP_SINK_SERVICE_ID) {
1040 btc_dm_enable_service(BTA_A2DP_SINK_SERVICE_ID);
1041 } else {
1042 btc_dm_enable_service(BTA_A2DP_SOURCE_SERVICE_ID);
1043 }
1044
1045 btc_a2dp_on_init();
1046 g_a2dp_on_init = true;
1047 g_a2dp_on_deinit = false;
1048 g_a2dp_source_ongoing_deinit = false;
1049 g_a2dp_sink_ongoing_deinit = false;
1050
1051 esp_a2d_cb_param_t param;
1052 memset(¶m, 0, sizeof(esp_a2d_cb_param_t));
1053 param.a2d_prof_stat.init_state = ESP_A2D_INIT_SUCCESS;
1054 btc_a2d_cb_to_app(ESP_A2D_PROF_STATE_EVT, ¶m);
1055 return BT_STATUS_SUCCESS;
1056 }
1057
1058 av_init_fail:
1059 return BT_STATUS_FAIL;
1060 }
1061
1062 /*******************************************************************************
1063 **
1064 ** Function connect
1065 **
1066 ** Description Establishes the AV signalling channel with the remote headset
1067 **
1068 ** Returns bt_status_t
1069 **
1070 *******************************************************************************/
1071
connect_int(bt_bdaddr_t * bd_addr,uint16_t uuid)1072 static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid)
1073 {
1074 btc_av_connect_req_t connect_req;
1075 memcpy(&connect_req.target_bda, bd_addr, sizeof(bt_bdaddr_t));
1076 connect_req.uuid = uuid;
1077 BTC_TRACE_DEBUG("%s\n", __FUNCTION__);
1078
1079 btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_CONNECT_REQ_EVT, (char *)&connect_req);
1080
1081 return BT_STATUS_SUCCESS;
1082 }
1083
1084 /*******************************************************************************
1085 **
1086 ** Function clean_up
1087 **
1088 ** Description Shuts down the AV interface and does the cleanup
1089 **
1090 ** Returns None
1091 **
1092 *******************************************************************************/
clean_up(int service_id)1093 static void clean_up(int service_id)
1094 {
1095 BTC_TRACE_DEBUG("%s\n", __FUNCTION__);
1096
1097 if (service_id == BTA_A2DP_SOURCE_SERVICE_ID) {
1098 #if BTC_AV_SRC_INCLUDED
1099 btc_a2dp_source_shutdown();
1100 if (btc_av_cb.tle_av_open_on_rc) {
1101 osi_alarm_free(btc_av_cb.tle_av_open_on_rc);
1102 btc_av_cb.tle_av_open_on_rc = NULL;
1103 }
1104 #endif /* BTC_AV_SRC_INCLUDED */
1105 btc_dm_disable_service(BTA_A2DP_SOURCE_SERVICE_ID);
1106 }
1107
1108 if (service_id == BTA_A2DP_SINK_SERVICE_ID) {
1109 #if BTC_AV_SINK_INCLUDED
1110 btc_a2dp_sink_shutdown();
1111 #endif /* BTC_AV_SINK_INCLUDED */
1112 btc_dm_disable_service(BTA_A2DP_SINK_SERVICE_ID);
1113 }
1114
1115 /* Also shut down the AV state machine */
1116 btc_sm_shutdown(btc_av_cb.sm_handle);
1117 btc_av_cb.sm_handle = NULL;
1118
1119 #if A2D_DYNAMIC_MEMORY == TRUE
1120 osi_free(btc_av_cb_ptr);
1121 btc_av_cb_ptr = NULL;
1122 #endif
1123 g_a2dp_on_init = false;
1124 g_a2dp_on_deinit = true;
1125 g_a2dp_source_ongoing_deinit = false;
1126 g_a2dp_sink_ongoing_deinit = false;
1127
1128 esp_a2d_cb_param_t param;
1129 memset(¶m, 0, sizeof(esp_a2d_cb_param_t));
1130 param.a2d_prof_stat.init_state = ESP_A2D_DEINIT_SUCCESS;
1131 btc_a2d_cb_to_app(ESP_A2D_PROF_STATE_EVT, ¶m);
1132 }
1133
1134 /*******************************************************************************
1135 **
1136 ** Function btc_av_get_sm_handle
1137 **
1138 ** Description Fetches current av SM handle
1139 **
1140 ** Returns None
1141 **
1142 *******************************************************************************/
1143
btc_av_get_sm_handle(void)1144 btc_sm_handle_t btc_av_get_sm_handle(void)
1145 {
1146 return btc_av_cb.sm_handle;
1147 }
1148
1149 /*******************************************************************************
1150 **
1151 ** Function btc_av_stream_ready
1152 **
1153 ** Description Checks whether AV is ready for starting a stream
1154 **
1155 ** Returns None
1156 **
1157 *******************************************************************************/
1158
btc_av_stream_ready(void)1159 BOOLEAN btc_av_stream_ready(void)
1160 {
1161 btc_sm_state_t state = btc_sm_get_state(btc_av_cb.sm_handle);
1162
1163 BTC_TRACE_DEBUG("btc_av_stream_ready : sm hdl %d, state %d, flags %x\n",
1164 (int)btc_av_cb.sm_handle, state, btc_av_cb.flags);
1165
1166 /* check if we are remotely suspended or stop is pending */
1167 if (btc_av_cb.flags & (BTC_AV_FLAG_REMOTE_SUSPEND | BTC_AV_FLAG_PENDING_STOP)) {
1168 return FALSE;
1169 }
1170
1171 return (state == BTC_AV_STATE_OPENED);
1172 }
1173
1174 /*******************************************************************************
1175 **
1176 ** Function btc_av_stream_started_ready
1177 **
1178 ** Description Checks whether AV ready for media start in streaming state
1179 **
1180 ** Returns None
1181 **
1182 *******************************************************************************/
1183
btc_av_stream_started_ready(void)1184 BOOLEAN btc_av_stream_started_ready(void)
1185 {
1186 btc_sm_state_t state = btc_sm_get_state(btc_av_cb.sm_handle);
1187
1188 BTC_TRACE_DEBUG("btc_av_stream_started : sm hdl %d, state %d, flags %x\n",
1189 (int)btc_av_cb.sm_handle, state, btc_av_cb.flags);
1190
1191 /* disallow media task to start if we have pending actions */
1192 if (btc_av_cb.flags & (BTC_AV_FLAG_LOCAL_SUSPEND_PENDING | BTC_AV_FLAG_REMOTE_SUSPEND
1193 | BTC_AV_FLAG_PENDING_STOP)) {
1194 return FALSE;
1195 }
1196
1197 return (state == BTC_AV_STATE_STARTED);
1198 }
1199
1200 /*******************************************************************************
1201 **
1202 ** Function btc_dispatch_sm_event
1203 **
1204 ** Description Send event to AV statemachine
1205 **
1206 ** Returns None
1207 **
1208 *******************************************************************************/
1209
1210 /* used to pass events to AV statemachine from other tasks */
btc_dispatch_sm_event(btc_av_sm_event_t event,void * p_data,int len)1211 void btc_dispatch_sm_event(btc_av_sm_event_t event, void *p_data, int len)
1212 {
1213 btc_msg_t msg;
1214 msg.sig = BTC_SIG_API_CALL;
1215 msg.pid = BTC_PID_A2DP;
1216 msg.act = event;
1217 btc_transfer_context(&msg, p_data, len, NULL);
1218 }
1219
bte_av_callback(tBTA_AV_EVT event,tBTA_AV * p_data)1220 static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data)
1221 {
1222 bt_status_t stat;
1223 btc_msg_t msg;
1224
1225 msg.sig = BTC_SIG_API_CB;
1226 msg.pid = BTC_PID_A2DP;
1227 msg.act = (uint8_t) event;
1228 stat = btc_transfer_context(&msg, p_data, sizeof(tBTA_AV), btc_av_event_deep_copy);
1229
1230 if (stat) {
1231 BTC_TRACE_ERROR("%s transfer failed\n", __func__);
1232 }
1233 }
1234
1235 #if BTC_AV_SINK_INCLUDED
bte_av_media_callback(tBTA_AV_EVT event,tBTA_AV_MEDIA * p_data)1236 static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
1237 {
1238 btc_sm_state_t state;
1239 UINT8 que_len;
1240 tA2D_STATUS a2d_status;
1241 tA2D_SBC_CIE sbc_cie;
1242
1243 if (event == BTA_AV_MEDIA_DATA_EVT) { /* Switch to BTC_MEDIA context */
1244 state = btc_sm_get_state(btc_av_cb.sm_handle);
1245 if ( (state == BTC_AV_STATE_STARTED) || /* send SBC packets only in Started State */
1246 (state == BTC_AV_STATE_OPENED) ) {
1247 que_len = btc_a2dp_sink_enque_buf((BT_HDR *)p_data);
1248 BTC_TRACE_DEBUG(" Packets in Que %d\n", que_len);
1249 } else {
1250 return;
1251 }
1252 }
1253
1254 if (event == BTA_AV_MEDIA_SINK_CFG_EVT) {
1255 /* send a command to BT Media Task */
1256 btc_a2dp_sink_reset_decoder((UINT8 *)p_data);
1257
1258 /* currently only supportes SBC */
1259 a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)p_data, FALSE);
1260 if (a2d_status == A2D_SUCCESS) {
1261 btc_msg_t msg;
1262 btc_av_args_t arg;
1263
1264 msg.sig = BTC_SIG_API_CB;
1265 msg.pid = BTC_PID_A2DP;
1266 msg.act = BTC_AV_SINK_CONFIG_REQ_EVT;
1267
1268 memset(&arg, 0, sizeof(btc_av_args_t));
1269 arg.mcc.type = ESP_A2D_MCT_SBC;
1270 memcpy(arg.mcc.cie.sbc, (uint8_t *)p_data + 3, ESP_A2D_CIE_LEN_SBC);
1271 btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL);
1272 } else {
1273 BTC_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status);
1274 }
1275 }
1276 UNUSED(que_len);
1277 }
1278 #else
bte_av_media_callback(tBTA_AV_EVT event,tBTA_AV_MEDIA * p_data)1279 static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data)
1280 {
1281 UNUSED(event);
1282 UNUSED(p_data);
1283 BTC_TRACE_WARNING("%s : event %u\n", __func__, event);
1284 }
1285 #endif
1286
1287 /*******************************************************************************
1288 **
1289 ** Function btc_av_execute_service
1290 **
1291 ** Description Initializes/Shuts down the service
1292 **
1293 ** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
1294 **
1295 *******************************************************************************/
btc_av_execute_service(BOOLEAN b_enable,UINT8 tsep)1296 bt_status_t btc_av_execute_service(BOOLEAN b_enable, UINT8 tsep)
1297 {
1298 if (b_enable) {
1299 /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not
1300 * handle this request in order to allow incoming connections to succeed.
1301 * We need to put this back once support for this is added */
1302
1303 /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not
1304 * auto-suspend av streaming on AG events(SCO or Call). The suspend shall
1305 * be initiated by the app/audioflinger layers */
1306 if (g_av_with_rc) {
1307 BTC_TRACE_WARNING("A2DP Enable with AVRC")
1308 BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_NO_SCO_SSPD |
1309 BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR |
1310 BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL,
1311 bte_av_callback);
1312 BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos, &bta_avrc_cos, tsep);
1313 } else {
1314 BTC_TRACE_WARNING("A2DP Enable without AVRC")
1315 BTA_AvEnable(BTA_SEC_AUTHENTICATE, BTA_AV_FEAT_NO_SCO_SSPD, bte_av_callback);
1316 BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos, NULL, tsep);
1317 }
1318 } else {
1319 BTA_AvDeregister(btc_av_cb.bta_handle);
1320 BTA_AvDisable();
1321 }
1322 return BT_STATUS_SUCCESS;
1323 }
1324
1325 /*******************************************************************************
1326 **
1327 ** Function btc_av_source_execute_service
1328 **
1329 ** Description Initializes/Shuts down the A2DP source service
1330 **
1331 ** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
1332 **
1333 *******************************************************************************/
btc_av_source_execute_service(BOOLEAN b_enable)1334 bt_status_t btc_av_source_execute_service(BOOLEAN b_enable)
1335 {
1336 return btc_av_execute_service(b_enable, AVDT_TSEP_SRC);
1337 }
1338
1339 /*******************************************************************************
1340 **
1341 ** Function btc_av_sink_execute_service
1342 **
1343 ** Description Initializes/Shuts down the service
1344 **
1345 ** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
1346 **
1347 *******************************************************************************/
btc_av_sink_execute_service(BOOLEAN b_enable)1348 bt_status_t btc_av_sink_execute_service(BOOLEAN b_enable)
1349 {
1350 bt_status_t ret = btc_av_execute_service(b_enable, AVDT_TSEP_SNK);
1351 if (ret != BT_STATUS_SUCCESS) {
1352 return ret;
1353 }
1354 #if (BTA_AV_SINK_INCLUDED == TRUE)
1355 BTA_AvEnable_Sink(b_enable);
1356 #endif
1357 return BT_STATUS_SUCCESS;
1358 }
1359
1360 /*******************************************************************************
1361 **
1362 ** Function btc_av_is_connected
1363 **
1364 ** Description Checks if av has a connected sink
1365 **
1366 ** Returns BOOLEAN
1367 **
1368 *******************************************************************************/
btc_av_is_connected(void)1369 BOOLEAN btc_av_is_connected(void)
1370 {
1371 btc_sm_state_t state = btc_sm_get_state(btc_av_cb.sm_handle);
1372 return ((state == BTC_AV_STATE_OPENED) || (state == BTC_AV_STATE_STARTED));
1373 }
1374
1375 /*******************************************************************************
1376 *
1377 * Function btc_av_get_service_id
1378 *
1379 * Description Get the current AV service ID.
1380 *
1381 * Returns The stream endpoint type: either BTA_A2DP_SOURCE_SERVICE_ID or
1382 * BTA_A2DP_SINK_SERVICE_ID.
1383 *
1384 ******************************************************************************/
btc_av_get_service_id(void)1385 uint8_t btc_av_get_service_id(void)
1386 {
1387 return btc_av_cb.service_id;
1388 }
1389
1390 /*******************************************************************************
1391 *
1392 * Function btc_av_get_peer_sep
1393 *
1394 * Description Get the stream endpoint type.
1395 *
1396 * Returns The stream endpoint type: either AVDT_TSEP_SRC or
1397 * AVDT_TSEP_SNK.
1398 *
1399 ******************************************************************************/
1400
btc_av_get_peer_sep(void)1401 uint8_t btc_av_get_peer_sep(void)
1402 {
1403 return btc_av_cb.peer_sep;
1404 }
1405 /*******************************************************************************
1406 **
1407 ** Function btc_av_is_peer_edr
1408 **
1409 ** Description Check if the connected a2dp device supports
1410 ** EDR or not. Only when connected this function
1411 ** will accurately provide a true capability of
1412 ** remote peer. If not connected it will always be false.
1413 **
1414 ** Returns TRUE if remote device is capable of EDR
1415 **
1416 *******************************************************************************/
btc_av_is_peer_edr(void)1417 BOOLEAN btc_av_is_peer_edr(void)
1418 {
1419 BTC_ASSERTC(btc_av_is_connected(), "No active a2dp connection\n", 0);
1420
1421 if (btc_av_cb.edr) {
1422 return TRUE;
1423 } else {
1424 return FALSE;
1425 }
1426 }
1427
1428 /******************************************************************************
1429 **
1430 ** Function btc_av_clear_remote_suspend_flag
1431 **
1432 ** Description Clears btc_av_cb.flags if BTC_AV_FLAG_REMOTE_SUSPEND is set
1433 **
1434 ** Returns void
1435 ******************************************************************************/
btc_av_clear_remote_suspend_flag(void)1436 void btc_av_clear_remote_suspend_flag(void)
1437 {
1438 BTC_TRACE_DEBUG("%s: flag :%x\n", __func__, btc_av_cb.flags);
1439 btc_av_cb.flags &= ~BTC_AV_FLAG_REMOTE_SUSPEND;
1440 }
1441
btc_a2dp_call_handler(btc_msg_t * msg)1442 void btc_a2dp_call_handler(btc_msg_t *msg)
1443 {
1444 btc_av_args_t *arg = (btc_av_args_t *)(msg->arg);
1445 switch (msg->act) {
1446 #if BTC_AV_SINK_INCLUDED
1447 case BTC_AV_SINK_CONFIG_REQ_EVT: {
1448 btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, (void *)(msg->arg));
1449 break;
1450 }
1451 case BTC_AV_SINK_API_INIT_EVT: {
1452 btc_a2d_sink_init();
1453 // todo: callback to application
1454 break;
1455 }
1456 case BTC_AV_SINK_API_DEINIT_EVT: {
1457 btc_a2d_sink_deinit();
1458 // todo: callback to application
1459 break;
1460 }
1461 case BTC_AV_SINK_API_CONNECT_EVT: {
1462 btc_a2d_sink_connect(&arg->connect);
1463 // todo: callback to application
1464 break;
1465 }
1466 case BTC_AV_SINK_API_DISCONNECT_EVT: {
1467 CHECK_BTAV_INIT();
1468 btc_av_disconn_req_t disconn_req;
1469 memcpy(&disconn_req.target_bda, &arg->disconn, sizeof(bt_bdaddr_t));
1470 btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_DISCONNECT_REQ_EVT, &disconn_req);
1471 break;
1472 }
1473 case BTC_AV_SINK_API_REG_DATA_CB_EVT: {
1474 btc_a2dp_sink_reg_data_cb(arg->data_cb);
1475 break;
1476 }
1477 #endif /* BTC_AV_SINK_INCLUDED */
1478 #if BTC_AV_SRC_INCLUDED
1479 case BTC_AV_SRC_API_INIT_EVT: {
1480 btc_a2d_src_init();
1481 break;
1482 }
1483 case BTC_AV_SRC_API_DEINIT_EVT: {
1484 btc_a2d_src_deinit();
1485 break;
1486 }
1487 case BTC_AV_SRC_API_CONNECT_EVT: {
1488 btc_a2d_src_connect(&arg->src_connect);
1489 break;
1490 }
1491 case BTC_AV_SRC_API_DISCONNECT_EVT: {
1492 CHECK_BTAV_INIT();
1493 btc_av_disconn_req_t disconn_req;
1494 memcpy(&disconn_req.target_bda, &arg->src_disconn, sizeof(bt_bdaddr_t));
1495 btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_DISCONNECT_REQ_EVT, &disconn_req);
1496 break;
1497 }
1498 case BTC_AV_SRC_API_REG_DATA_CB_EVT: {
1499 btc_a2dp_src_reg_data_cb(arg->src_data_cb);
1500 break;
1501 }
1502 #endif /* BTC_AV_SRC_INCLUDED */
1503 case BTC_AV_API_MEDIA_CTRL_EVT: {
1504 btc_a2dp_control_media_ctrl(arg->ctrl);
1505 break;
1506 }
1507 case BTC_AV_CONNECT_REQ_EVT:
1508 btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, (char *)msg->arg);
1509 break;
1510 // case BTC_AV_DISCONNECT_REQ_EVT:
1511 case BTC_AV_START_STREAM_REQ_EVT:
1512 case BTC_AV_STOP_STREAM_REQ_EVT:
1513 case BTC_AV_SUSPEND_STREAM_REQ_EVT: {
1514 btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, NULL);
1515 break;
1516 }
1517 default:
1518 BTC_TRACE_WARNING("%s : unhandled event: %d\n", __FUNCTION__, msg->act);
1519 }
1520 }
1521
btc_a2dp_cb_handler(btc_msg_t * msg)1522 void btc_a2dp_cb_handler(btc_msg_t *msg)
1523 {
1524 btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, (void *)(msg->arg));
1525 btc_av_event_free_data(msg->act, msg->arg);
1526 }
1527
1528 #if BTC_AV_SINK_INCLUDED
1529
1530 /*******************************************************************************
1531 **
1532 ** Function init_sink
1533 **
1534 ** Description Initializes the AV interface for sink mode
1535 **
1536 ** Returns bt_status_t
1537 **
1538 *******************************************************************************/
btc_a2d_sink_init(void)1539 static bt_status_t btc_a2d_sink_init(void)
1540 {
1541 BTC_TRACE_DEBUG("%s()\n", __func__);
1542
1543 return btc_av_init(BTA_A2DP_SINK_SERVICE_ID);
1544 }
1545
btc_a2d_sink_connect(bt_bdaddr_t * remote_bda)1546 static bt_status_t btc_a2d_sink_connect(bt_bdaddr_t *remote_bda)
1547 {
1548 BTC_TRACE_DEBUG("%s\n", __FUNCTION__);
1549 CHECK_BTAV_INIT();
1550
1551 return btc_queue_connect(UUID_SERVCLASS_AUDIO_SINK, remote_bda, connect_int);
1552 }
1553
btc_a2d_sink_deinit(void)1554 static void btc_a2d_sink_deinit(void)
1555 {
1556 g_a2dp_sink_ongoing_deinit = true;
1557 if (btc_av_is_connected()) {
1558 BTA_AvClose(btc_av_cb.bta_handle);
1559 if (btc_av_cb.peer_sep == AVDT_TSEP_SRC && g_av_with_rc == true) {
1560 BTA_AvCloseRc(btc_av_cb.bta_handle);
1561 }
1562 } else {
1563 clean_up(BTA_A2DP_SINK_SERVICE_ID);
1564 }
1565 }
1566
1567 #endif /* BTC_AV_SINK_INCLUDED */
1568
1569 #if BTC_AV_SRC_INCLUDED
1570
1571 /*******************************************************************************
1572 **
1573 ** Function btc_a2d_src_init
1574 **
1575 ** Description Initializes the AV interface for source mode
1576 **
1577 ** Returns bt_status_t
1578 **
1579 *******************************************************************************/
btc_a2d_src_init(void)1580 static bt_status_t btc_a2d_src_init(void)
1581 {
1582 BTC_TRACE_DEBUG("%s()\n", __func__);
1583
1584 return btc_av_init(BTA_A2DP_SOURCE_SERVICE_ID);
1585 }
1586
btc_a2d_src_deinit(void)1587 static void btc_a2d_src_deinit(void)
1588 {
1589 g_a2dp_source_ongoing_deinit = true;
1590 if (btc_av_is_connected()) {
1591 BTA_AvClose(btc_av_cb.bta_handle);
1592 if (btc_av_cb.peer_sep == AVDT_TSEP_SNK && g_av_with_rc == true) {
1593 BTA_AvCloseRc(btc_av_cb.bta_handle);
1594 }
1595 } else {
1596 clean_up(BTA_A2DP_SOURCE_SERVICE_ID);
1597 }
1598 }
1599
btc_a2d_src_connect(bt_bdaddr_t * remote_bda)1600 static bt_status_t btc_a2d_src_connect(bt_bdaddr_t *remote_bda)
1601 {
1602 BTC_TRACE_DEBUG("%s\n", __FUNCTION__);
1603 CHECK_BTAV_INIT();
1604
1605 return btc_queue_connect(UUID_SERVCLASS_AUDIO_SOURCE, remote_bda, connect_int);
1606 }
1607
1608 #endif /* BTC_AV_SRC_INCLUDED */
1609
1610 #endif /* #if BTC_AV_INCLUDED */
1611