1 /*
2 * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /******************************************************************************
8 **
9 ** Name: btc_a2dp_source.c
10 **
11 ******************************************************************************/
12 #include "common/bt_target.h"
13 #include "common/bt_trace.h"
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <unistd.h>
18 #include <time.h>
19 #include <sys/time.h>
20 #include "osi/allocator.h"
21 #include "osi/alarm.h"
22 #include "osi/thread.h"
23 #include "osi/mutex.h"
24 #include "osi/fixed_queue.h"
25 #include "stack/a2d_api.h"
26 #include "stack/a2d_sbc.h"
27 #include "bta/bta_av_api.h"
28 #include "bta/bta_av_sbc.h"
29 #include "bta/bta_av_ci.h"
30 #include "btc/btc_manage.h"
31 #include "btc/btc_common.h"
32 #include "btc_av_co.h"
33 #include "btc_a2dp.h"
34 #include "btc_a2dp_control.h"
35 #include "btc_a2dp_source.h"
36 #include "btc_av.h"
37 #include "btc/btc_util.h"
38 #include "esp_a2dp_api.h"
39 #include "sbc_encoder.h"
40 #include "osi/future.h"
41 #include <assert.h>
42
43 #if BTC_AV_SRC_INCLUDED
44
45 /*****************************************************************************
46 ** BQB global variables
47 *****************************************************************************/
48 #if A2D_SRC_BQB_INCLUDED
49 bool a2dp_src_bqb_set_sbc_encoder_flag = FALSE;
50 #endif /* A2D_SRC_BQB_INCLUDED */
51
52 /*****************************************************************************
53 ** Constants
54 *****************************************************************************/
55
56 /* BTC source command event definition */
57 enum {
58 BTC_MEDIA_TASK_INIT,
59 BTC_MEDIA_TASK_CLEAN_UP,
60 BTC_MEDIA_START_AA_TX,
61 BTC_MEDIA_STOP_AA_TX,
62 BTC_MEDIA_SBC_ENC_INIT,
63 BTC_MEDIA_SBC_ENC_UPDATE,
64 BTC_MEDIA_FLUSH_AA_TX,
65 BTC_MEDIA_AUDIO_FEEDING_INIT,
66 };
67
68 enum {
69 BTC_A2DP_SOURCE_STATE_OFF = 0,
70 BTC_A2DP_SOURCE_STATE_ON = 1,
71 BTC_A2DP_SOURCE_STATE_SHUTTING_DOWN = 2
72 };
73
74
75 /* Media task tick in milliseconds, must be set to multiple of
76 (1000/TICKS_PER_SEC) */
77 #define BTC_MEDIA_TIME_TICK_MS (30)
78 #define A2DP_DATA_READ_POLL_MS (BTC_MEDIA_TIME_TICK_MS / 2)
79
80 #ifndef MAX_PCM_FRAME_NUM_PER_TICK
81 #define MAX_PCM_FRAME_NUM_PER_TICK 21 // 14 for 20ms
82 #endif
83
84 #define BTC_MEDIA_AA_BUF_SIZE (4096+16)
85
86 #if (BTA_AV_CO_CP_SCMS_T == TRUE)
87 #define BTC_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE + 1)
88 #else
89 #define BTC_MEDIA_AA_SBC_OFFSET (AVDT_MEDIA_OFFSET + BTA_AV_SBC_HDR_SIZE)
90 #endif
91
92 #ifndef BTC_MEDIA_BITRATE_STEP
93 #define BTC_MEDIA_BITRATE_STEP 5
94 #endif
95
96 #ifndef BTC_A2DP_NON_EDR_MAX_RATE
97 #define BTC_A2DP_NON_EDR_MAX_RATE 229
98 #endif
99
100 /* Middle quality quality setting @ 44.1 khz */
101 #define DEFAULT_SBC_BITRATE 328
102
103 /*
104 * CONGESTION COMPENSATION CTRL ::
105 *
106 * Thus setting controls how many buffers we will hold in media task
107 * during temp link congestion. Together with the stack buffer queues
108 * it controls much temporary a2dp link congestion we can
109 * compensate for. It however also depends on the default run level of sinks
110 * jitterbuffers. Depending on type of sink this would vary.
111 * Ideally the (SRC) max tx buffer capacity should equal the sinks
112 * jitterbuffer runlevel including any intermediate buffers on the way
113 * towards the sinks codec.
114 */
115
116 /* fixme -- define this in pcm time instead of buffer count */
117
118 /* The typical runlevel of the tx queue size is ~1 buffer
119 but due to link flow control or thread preemption in lower
120 layers we might need to temporarily buffer up data */
121
122 /* 5 frames is equivalent to 6.89*5*2.9 ~= 100 ms @ 44.1 khz, 20 ms mediatick */
123 #define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (5)
124 #define MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ (27) // 18 for 20ms tick
125
126 #define BTC_A2DP_SRC_DATA_QUEUE_IDX (1)
127
128 typedef struct {
129 uint32_t sig;
130 void *param;
131 } a2dp_src_task_evt_t;
132
133 typedef struct {
134 UINT16 num_frames_to_be_processed;
135 UINT16 len;
136 UINT16 offset;
137 UINT16 layer_specific;
138 } tBT_SBC_HDR;
139
140 typedef struct {
141 UINT32 aa_frame_counter;
142 INT32 aa_feed_counter;
143 INT32 aa_feed_residue;
144 UINT32 counter;
145 UINT32 bytes_per_tick; /* pcm bytes read each media task tick */
146 } tBTC_AV_MEDIA_FEEDINGS_PCM_STATE;
147
148 typedef union {
149 tBTC_AV_MEDIA_FEEDINGS_PCM_STATE pcm;
150 } tBTC_AV_MEDIA_FEEDINGS_STATE;
151
152 typedef struct {
153 UINT8 TxTranscoding;
154 BOOLEAN tx_flush; /* discards any outgoing data when true */
155 BOOLEAN is_tx_timer;
156 UINT16 TxAaMtuSize;
157 UINT32 timestamp;
158 fixed_queue_t *TxAaQ;
159 tBTC_AV_FEEDING_MODE feeding_mode;
160 tBTC_AV_MEDIA_FEEDINGS_STATE media_feeding_state;
161 tBTC_AV_MEDIA_FEEDINGS media_feeding;
162 SBC_ENC_PARAMS encoder;
163 osi_alarm_t *media_alarm;
164 struct osi_event *poll_data;
165 } tBTC_A2DP_SOURCE_CB;
166
167 typedef struct {
168 tBTC_A2DP_SOURCE_CB btc_aa_src_cb;
169 osi_thread_t *btc_aa_src_task_hdl;
170 UINT64 last_frame_us;
171 } a2dp_source_local_param_t;
172
173 static void btc_a2dp_source_thread_init(UNUSED_ATTR void *context);
174 static void btc_a2dp_source_thread_cleanup(UNUSED_ATTR void *context);
175 static void btc_a2dp_source_flush_q(fixed_queue_t *p_q);
176
177 static void btc_a2dp_source_feeding_state_reset(void);
178 static void btc_a2dp_source_send_aa_frame(void);
179 static void btc_a2dp_source_aa_start_tx(void);
180 static void btc_a2dp_source_aa_stop_tx(void);
181 static void btc_a2dp_source_enc_init(BT_HDR *p_msg);
182 static void btc_a2dp_source_enc_update(BT_HDR *p_msg);
183 static void btc_a2dp_source_audio_feeding_init(BT_HDR *p_msg);
184 static void btc_a2dp_source_aa_tx_flush(void);
185 static void btc_a2dp_source_prep_2_send(UINT8 nb_frame);
186 static void btc_a2dp_source_handle_timer(UNUSED_ATTR void *context);
187 static void btc_a2dp_source_encoder_init(void);
188
189 static int btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_OFF;
190 static esp_a2d_source_data_cb_t btc_aa_src_data_cb = NULL;
191 #if A2D_DYNAMIC_MEMORY == FALSE
192 static a2dp_source_local_param_t a2dp_source_local_param;
193 #else
194 static a2dp_source_local_param_t *a2dp_source_local_param_ptr;
195 #define a2dp_source_local_param (*a2dp_source_local_param_ptr)
196 #endif ///A2D_DYNAMIC_MEMORY == FALSE
197
btc_a2dp_src_reg_data_cb(esp_a2d_source_data_cb_t callback)198 void btc_a2dp_src_reg_data_cb(esp_a2d_source_data_cb_t callback)
199 {
200 // todo: critical section protection
201 btc_aa_src_data_cb = callback;
202 }
203
btc_aa_src_data_read(uint8_t * data,int32_t len)204 static inline uint32_t btc_aa_src_data_read(uint8_t *data, int32_t len)
205 {
206 // todo: critical section protection
207 if (btc_aa_src_data_cb) {
208 return btc_aa_src_data_cb(data, len);
209 } else {
210 return 0;
211 }
212 }
213
214 /*****************************************************************************
215 ** Misc helper functions
216 *****************************************************************************/
btc_aa_cb_to_app(esp_a2d_cb_event_t event,esp_a2d_cb_param_t * param)217 static inline void btc_aa_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
218 {
219 esp_a2d_cb_t btc_aa_cb = (esp_a2d_cb_t)btc_profile_cb_get(BTC_PID_A2DP);
220 if (btc_aa_cb) {
221 btc_aa_cb(event, param);
222 }
223 }
224
225 /*****************************************************************************
226 ** BTC ADAPTATION
227 *****************************************************************************/
228
btc_a2dp_source_is_streaming(void)229 bool btc_a2dp_source_is_streaming(void)
230 {
231 return a2dp_source_local_param.btc_aa_src_cb.is_tx_timer == TRUE;
232 }
233
btc_a2dp_source_is_task_shutting_down(void)234 bool btc_a2dp_source_is_task_shutting_down(void)
235 {
236 return btc_a2dp_source_state == BTC_A2DP_SOURCE_STATE_SHUTTING_DOWN;
237 }
238
btc_a2dp_source_ctrl(uint32_t sig,void * param)239 static bool btc_a2dp_source_ctrl(uint32_t sig, void *param)
240 {
241 switch (sig) {
242 case BTC_MEDIA_TASK_INIT:
243 btc_a2dp_source_thread_init(NULL);
244 break;
245 case BTC_MEDIA_TASK_CLEAN_UP:
246 btc_a2dp_source_thread_cleanup(NULL);
247 break;
248 case BTC_MEDIA_START_AA_TX:
249 btc_a2dp_source_aa_start_tx();
250 break;
251 case BTC_MEDIA_STOP_AA_TX:
252 btc_a2dp_source_aa_stop_tx();
253 break;
254 case BTC_MEDIA_SBC_ENC_INIT:
255 btc_a2dp_source_enc_init(param);
256 break;
257 case BTC_MEDIA_SBC_ENC_UPDATE:
258 btc_a2dp_source_enc_update(param);
259 break;
260 case BTC_MEDIA_AUDIO_FEEDING_INIT:
261 btc_a2dp_source_audio_feeding_init(param);
262 break;
263 case BTC_MEDIA_FLUSH_AA_TX:
264 btc_a2dp_source_aa_tx_flush();
265 break;
266 default:
267 APPL_TRACE_WARNING("media task unhandled evt: 0x%x\n", sig);
268 }
269
270 if (param != NULL) {
271 osi_free(param);
272 }
273
274 return true;
275 }
276
btc_a2dp_source_startup(void)277 bool btc_a2dp_source_startup(void)
278 {
279 if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_OFF) {
280 APPL_TRACE_ERROR("warning : media task already running");
281 return false;
282 }
283
284 #if A2D_DYNAMIC_MEMORY == TRUE
285 if ((a2dp_source_local_param_ptr = (a2dp_source_local_param_t *)osi_malloc(sizeof(a2dp_source_local_param_t))) == NULL) {
286 APPL_TRACE_ERROR("%s malloc failed!", __func__);
287 return false;
288 }
289 memset((void *)a2dp_source_local_param_ptr, 0, sizeof(a2dp_source_local_param_t));
290 #endif
291
292 APPL_TRACE_EVENT("## A2DP SOURCE START MEDIA THREAD ##");
293
294 a2dp_source_local_param.btc_aa_src_task_hdl = btc_get_current_thread();
295
296 if (btc_a2dp_source_ctrl(BTC_MEDIA_TASK_INIT, NULL) == false) {
297 goto error_exit;
298 }
299
300 APPL_TRACE_EVENT("## A2DP SOURCE MEDIA THREAD STARTED ##\n");
301
302 return true;
303
304 error_exit:;
305 APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__);
306 a2dp_source_local_param.btc_aa_src_task_hdl = NULL;
307
308 #if A2D_DYNAMIC_MEMORY == TRUE
309 osi_free(a2dp_source_local_param_ptr);
310 a2dp_source_local_param_ptr = NULL;
311 #endif
312
313 return false;
314 }
315
btc_a2dp_source_shutdown(void)316 void btc_a2dp_source_shutdown(void)
317 {
318 APPL_TRACE_EVENT("## A2DP SOURCE STOP MEDIA THREAD ##\n");
319
320 // Exit thread
321 btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_SHUTTING_DOWN;
322 btc_a2dp_source_ctrl(BTC_MEDIA_TASK_CLEAN_UP, NULL);
323
324 a2dp_source_local_param.btc_aa_src_task_hdl = NULL;
325
326 #if A2D_DYNAMIC_MEMORY == TRUE
327 osi_free(a2dp_source_local_param_ptr);
328 a2dp_source_local_param_ptr = NULL;
329 #endif
330 }
331
332 /*****************************************************************************
333 **
334 ** Function btc_a2dp_source_on_idle
335 **
336 *******************************************************************************/
btc_a2dp_source_on_idle(void)337 void btc_a2dp_source_on_idle(void)
338 {
339 /* Make sure media task is stopped */
340 btc_a2dp_source_stop_audio_req();
341 }
342
343 /*****************************************************************************
344 **
345 ** Function btc_a2dp_source_on_stopped
346 **
347 *******************************************************************************/
btc_a2dp_source_on_stopped(tBTA_AV_SUSPEND * p_av)348 void btc_a2dp_source_on_stopped(tBTA_AV_SUSPEND *p_av)
349 {
350 /* allow using this api for other than suspend */
351 if (p_av != NULL) {
352 if (p_av->status != BTA_AV_SUCCESS) {
353 APPL_TRACE_EVENT("AV STOP FAILED (%d)", p_av->status);
354 if (p_av->initiator) {
355 btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
356 }
357 return;
358 }
359 }
360
361 /* ensure tx frames are immediately suspended */
362 a2dp_source_local_param.btc_aa_src_cb.tx_flush = 1;
363
364 /* request to stop media task */
365 btc_a2dp_source_tx_flush_req();
366 btc_a2dp_source_stop_audio_req();
367
368 /* once stream is fully stopped we will ack back */
369 }
370
371 /*****************************************************************************
372 **
373 ** Function btc_a2dp_source_on_suspended
374 **
375 **
376 *******************************************************************************/
377
btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND * p_av)378 void btc_a2dp_source_on_suspended(tBTA_AV_SUSPEND *p_av)
379 {
380 /* check for status failures */
381 if (p_av->status != BTA_AV_SUCCESS) {
382 if (p_av->initiator == TRUE) {
383 btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_FAILURE);
384 }
385 }
386
387 /* once stream is fully stopped we will ack back */
388
389 /* ensure tx frames are immediately flushed */
390 a2dp_source_local_param.btc_aa_src_cb.tx_flush = 1;
391
392 /* stop timer tick */
393 btc_a2dp_source_stop_audio_req();
394 }
395
time_now_us(void)396 static UINT64 time_now_us(void)
397 {
398 #if _POSIX_TIMERS
399 struct timespec ts_now;
400 clock_gettime(CLOCK_MONOTONIC, &ts_now);
401 return ((UINT64)ts_now.tv_sec * 1000000L) + ((UINT64)ts_now.tv_nsec / 1000);
402 #else
403 struct timeval ts_now;
404 gettimeofday(&ts_now, NULL);
405 return ((UINT64)ts_now.tv_sec * 1000000L) + ((UINT64)ts_now.tv_usec);
406 #endif
407 }
408
log_tstamps_us(char * comment)409 static void log_tstamps_us(char *comment)
410 {
411 static UINT64 prev_us = 0;
412 UINT64 now_us = time_now_us();
413 APPL_TRACE_DEBUG("[%s] ts %08llu, diff : %08llu, queue sz %d", comment, now_us, now_us - prev_us,
414 fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ));
415 prev_us = now_us;
416 UNUSED(prev_us);
417 }
418
419 /* when true media task discards any tx frames */
btc_a2dp_source_set_tx_flush(BOOLEAN enable)420 void btc_a2dp_source_set_tx_flush(BOOLEAN enable)
421 {
422 APPL_TRACE_EVENT("## DROP TX %d ##", enable);
423 a2dp_source_local_param.btc_aa_src_cb.tx_flush = enable;
424 }
425
426 /*****************************************************************************
427 **
428 ** Function btc_a2dp_source_setup_codec
429 **
430 ** Description
431 **
432 ** Returns
433 **
434 *******************************************************************************/
btc_a2dp_source_setup_codec(void)435 void btc_a2dp_source_setup_codec(void)
436 {
437 tBTC_AV_MEDIA_FEEDINGS media_feeding;
438 tBTC_AV_STATUS status;
439
440 APPL_TRACE_EVENT("## A2DP SETUP CODEC ##\n");
441
442 osi_mutex_global_lock();
443
444 /* for now hardcode 44.1 khz 16 bit stereo PCM format */
445 media_feeding.cfg.pcm.sampling_freq = 44100;
446 media_feeding.cfg.pcm.bit_per_sample = 16;
447 media_feeding.cfg.pcm.num_channel = 2;
448 media_feeding.format = BTC_AV_CODEC_PCM;
449
450 if (bta_av_co_audio_set_codec(&media_feeding, &status)) {
451 tBTC_MEDIA_INIT_AUDIO_FEEDING mfeed;
452
453 /* Init the encoding task */
454 btc_a2dp_source_encoder_init();
455
456 /* Build the media task configuration */
457 mfeed.feeding = media_feeding;
458 mfeed.feeding_mode = BTC_AV_FEEDING_ASYNCHRONOUS;
459 /* Send message to Media task to configure transcoding */
460 btc_a2dp_source_audio_feeding_init_req(&mfeed);
461 }
462
463 osi_mutex_global_unlock();
464 }
465
466
467 /*******************************************************************************
468 **
469 ** Function btc_a2dp_source_audio_readbuf
470 **
471 ** Description This function is called by the av_co to get the next buffer to send
472 **
473 **
474 ** Returns void
475 *******************************************************************************/
btc_a2dp_source_audio_readbuf(void)476 BT_HDR *btc_a2dp_source_audio_readbuf(void)
477 {
478 if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON){
479 return NULL;
480 }
481 return fixed_queue_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, 0);
482 }
483
484 /*******************************************************************************
485 **
486 ** Function btc_a2dp_source_start_audio_req
487 **
488 ** Description
489 **
490 ** Returns TRUE is success
491 **
492 *******************************************************************************/
btc_a2dp_source_start_audio_req(void)493 BOOLEAN btc_a2dp_source_start_audio_req(void)
494 {
495 btc_a2dp_source_ctrl(BTC_MEDIA_START_AA_TX, NULL);
496 return TRUE;
497 }
498
499 /*******************************************************************************
500 **
501 ** Function btc_a2dp_source_stop_audio_req
502 **
503 ** Description
504 **
505 ** Returns TRUE is success
506 **
507 *******************************************************************************/
btc_a2dp_source_stop_audio_req(void)508 BOOLEAN btc_a2dp_source_stop_audio_req(void)
509 {
510 /*
511 * Explicitly check whether the btc_aa_src_ctrl_queue is not NULL to
512 * avoid a race condition during shutdown of the Bluetooth stack.
513 * This race condition is triggered when A2DP audio is streaming on
514 * shutdown:
515 * "btc_a2dp_on_stopped() -> btc_a2dp_source_stop_audio_req()" is called
516 * to stop the particular audio stream, and this happens right after
517 * the "cleanup() -> btc_a2dp_stop_media_task()" processing during
518 * the shutdown of the Bluetooth stack.
519 */
520 #if 0
521 if (btc_aa_src_ctrl_queue != NULL) {
522 #endif
523 btc_a2dp_source_ctrl(BTC_MEDIA_STOP_AA_TX, NULL);
524 #if 0
525 }
526 #endif
527 return TRUE;
528 }
529
530 /*******************************************************************************
531 **
532 ** Function btc_a2dp_source_enc_init_req
533 **
534 ** Description
535 **
536 ** Returns TRUE is success
537 **
538 *******************************************************************************/
btc_a2dp_source_enc_init_req(tBTC_MEDIA_INIT_AUDIO * p_msg)539 BOOLEAN btc_a2dp_source_enc_init_req(tBTC_MEDIA_INIT_AUDIO *p_msg)
540 {
541 tBTC_MEDIA_INIT_AUDIO *p_buf;
542 if (NULL == (p_buf = osi_malloc(sizeof(tBTC_MEDIA_INIT_AUDIO)))) {
543 return FALSE;
544 }
545
546 memcpy(p_buf, p_msg, sizeof(tBTC_MEDIA_INIT_AUDIO));
547
548 btc_a2dp_source_ctrl(BTC_MEDIA_SBC_ENC_INIT, p_buf);
549
550 return TRUE;
551 }
552
553 /*******************************************************************************
554 **
555 ** Function btc_a2dp_source_enc_update_req
556 **
557 ** Description
558 **
559 ** Returns TRUE is success
560 **
561 *******************************************************************************/
btc_a2dp_source_enc_update_req(tBTC_MEDIA_UPDATE_AUDIO * p_msg)562 BOOLEAN btc_a2dp_source_enc_update_req(tBTC_MEDIA_UPDATE_AUDIO *p_msg)
563 {
564 tBTC_MEDIA_UPDATE_AUDIO *p_buf;
565 if (NULL == (p_buf = osi_malloc(sizeof(tBTC_MEDIA_UPDATE_AUDIO)))) {
566 return FALSE;
567 }
568
569 memcpy(p_buf, p_msg, sizeof(tBTC_MEDIA_UPDATE_AUDIO));
570 btc_a2dp_source_ctrl(BTC_MEDIA_SBC_ENC_UPDATE, p_buf);
571 return TRUE;
572 }
573
574 /*******************************************************************************
575 **
576 ** Function btc_a2dp_source_audio_feeding_init_req
577 **
578 ** Description
579 **
580 ** Returns TRUE is success
581 **
582 *******************************************************************************/
btc_a2dp_source_audio_feeding_init_req(tBTC_MEDIA_INIT_AUDIO_FEEDING * p_msg)583 BOOLEAN btc_a2dp_source_audio_feeding_init_req(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_msg)
584 {
585 tBTC_MEDIA_INIT_AUDIO_FEEDING *p_buf;
586 if (NULL == (p_buf = osi_malloc(sizeof(tBTC_MEDIA_INIT_AUDIO_FEEDING)))) {
587 return FALSE;
588 }
589
590 memcpy(p_buf, p_msg, sizeof(tBTC_MEDIA_INIT_AUDIO_FEEDING));
591 btc_a2dp_source_ctrl(BTC_MEDIA_AUDIO_FEEDING_INIT, p_buf);
592 return TRUE;
593 }
594
595 /*******************************************************************************
596 **
597 ** Function btc_a2dp_source_tx_flush_req
598 **
599 ** Description
600 **
601 ** Returns TRUE is success
602 **
603 *******************************************************************************/
btc_a2dp_source_tx_flush_req(void)604 BOOLEAN btc_a2dp_source_tx_flush_req(void)
605 {
606 /*
607 * Explicitly check whether the btc_aa_src_ctrl_queue is not NULL to
608 * avoid a race condition during shutdown of the Bluetooth stack.
609 * This race condition is triggered when A2DP audio is streaming on
610 * shutdown:
611 * "btc_a2dp_on_stopped() -> btc_a2dp_source_tx_flush_req()" is called
612 * to stop the particular audio stream, and this happens right after
613 * the "cleanup() -> btc_a2dp_stop_media_task()" processing during
614 * the shutdown of the Bluetooth stack.
615 */
616 #if 0
617 if (btc_aa_src_ctrl_queue != NULL) {
618 #endif
619 btc_a2dp_source_ctrl(BTC_MEDIA_FLUSH_AA_TX, NULL);
620 #if 0
621 }
622 #endif
623
624 return TRUE;
625 }
626
627 /*****************************************************************************
628 **
629 ** Function btc_source_report_delay_value
630 **
631 ** Description
632 **
633 ** Returns
634 **
635 *******************************************************************************/
btc_source_report_delay_value(UINT16 delay_value)636 void btc_source_report_delay_value(UINT16 delay_value)
637 {
638 esp_a2d_cb_param_t param;
639
640 #if A2D_DYNAMIC_MEMORY == TRUE
641 if (a2dp_source_local_param_ptr == NULL) {
642 return;
643 }
644 #endif
645
646 param.a2d_report_delay_value_stat.delay_value = delay_value;
647
648 btc_aa_cb_to_app(ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT, ¶m);
649 }
650
651 /*****************************************************************************
652 ** BTC ADAPTATION
653 *****************************************************************************/
btc_a2dp_source_get_sbc_rate(void)654 static UINT16 btc_a2dp_source_get_sbc_rate(void)
655 {
656 UINT16 rate = DEFAULT_SBC_BITRATE;
657
658 /* restrict bitrate if a2dp link is non-edr */
659 if (!btc_av_is_peer_edr()) {
660 rate = BTC_A2DP_NON_EDR_MAX_RATE;
661 APPL_TRACE_DEBUG("non-edr a2dp sink detected, restrict rate to %d", rate);
662 }
663 return rate;
664 }
665
btc_a2dp_source_encoder_init(void)666 static void btc_a2dp_source_encoder_init(void)
667 {
668 UINT16 minmtu;
669 tBTC_MEDIA_INIT_AUDIO msg;
670 tA2D_SBC_CIE sbc_config;
671
672 /* lookup table for converting channel mode */
673 UINT16 codec_mode_tbl[5] = { SBC_JOINT_STEREO, SBC_STEREO, SBC_DUAL, 0, SBC_MONO };
674
675 /* lookup table for converting number of blocks */
676 UINT16 codec_block_tbl[5] = { 16, 12, 8, 0, 4 };
677
678 /* lookup table to convert freq */
679 UINT16 freq_block_tbl[5] = { SBC_sf48000, SBC_sf44100, SBC_sf32000, 0, SBC_sf16000 };
680
681 APPL_TRACE_DEBUG("%s", __FUNCTION__);
682
683 /* Retrieve the current SBC configuration (default if currently not used) */
684 bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
685 msg.NumOfSubBands = (sbc_config.num_subbands == A2D_SBC_IE_SUBBAND_4) ? 4 : 8;
686 msg.NumOfBlocks = codec_block_tbl[sbc_config.block_len >> 5];
687 msg.AllocationMethod = (sbc_config.alloc_mthd == A2D_SBC_IE_ALLOC_MD_L) ? SBC_LOUDNESS : SBC_SNR;
688 msg.ChannelMode = codec_mode_tbl[sbc_config.ch_mode >> 1];
689 msg.SamplingFreq = freq_block_tbl[sbc_config.samp_freq >> 5];
690 msg.MtuSize = minmtu;
691
692 APPL_TRACE_EVENT("msg.ChannelMode %x", msg.ChannelMode);
693
694 /* Init the media task to encode SBC properly */
695 btc_a2dp_source_enc_init_req(&msg);
696 }
697
btc_a2dp_source_encoder_update(void)698 void btc_a2dp_source_encoder_update(void)
699 {
700 UINT16 minmtu;
701 tA2D_SBC_CIE sbc_config;
702 tBTC_MEDIA_UPDATE_AUDIO msg;
703 UINT8 pref_min;
704 UINT8 pref_max;
705
706 APPL_TRACE_DEBUG("%s", __FUNCTION__);
707
708 /* Retrieve the current SBC configuration (default if currently not used) */
709 bta_av_co_audio_get_sbc_config(&sbc_config, &minmtu);
710
711 APPL_TRACE_DEBUG("%s: Common min_bitpool:%d(0x%x) max_bitpool:%d(0x%x)", __FUNCTION__,
712 sbc_config.min_bitpool, sbc_config.min_bitpool,
713 sbc_config.max_bitpool, sbc_config.max_bitpool);
714
715 if (sbc_config.min_bitpool > sbc_config.max_bitpool) {
716 APPL_TRACE_ERROR("%s: ERROR min_bitpool > max_bitpool", __FUNCTION__);
717 }
718
719 /* check if remote sink has a preferred bitpool range */
720 if (bta_av_co_get_remote_bitpool_pref(&pref_min, &pref_max) == TRUE) {
721 /* adjust our preferred bitpool with the remote preference if within
722 our capable range */
723
724 if (pref_min < sbc_config.min_bitpool) {
725 pref_min = sbc_config.min_bitpool;
726 }
727
728 if (pref_max > sbc_config.max_bitpool) {
729 pref_max = sbc_config.max_bitpool;
730 }
731
732 msg.MinBitPool = pref_min;
733 msg.MaxBitPool = pref_max;
734
735 if ((pref_min != sbc_config.min_bitpool) || (pref_max != sbc_config.max_bitpool)) {
736 APPL_TRACE_EVENT("## adjusted our bitpool range to peer pref [%d:%d] ##",
737 pref_min, pref_max);
738 }
739 } else {
740 msg.MinBitPool = sbc_config.min_bitpool;
741 msg.MaxBitPool = sbc_config.max_bitpool;
742 }
743
744 msg.MinMtuSize = minmtu;
745
746 /* Update the media task to encode SBC properly */
747 btc_a2dp_source_enc_update_req(&msg);
748 }
749
750 /*******************************************************************************
751 **
752 ** Function btc_a2dp_source_enc_init
753 **
754 ** Description Initialize encoding task
755 **
756 ** Returns void
757 **
758 *******************************************************************************/
btc_a2dp_source_enc_init(BT_HDR * p_msg)759 static void btc_a2dp_source_enc_init(BT_HDR *p_msg)
760 {
761 tBTC_MEDIA_INIT_AUDIO *pInitAudio = (tBTC_MEDIA_INIT_AUDIO *) p_msg;
762
763 APPL_TRACE_DEBUG("btc_a2dp_source_enc_init");
764
765 a2dp_source_local_param.btc_aa_src_cb.timestamp = 0;
766
767 /* SBC encoder config (enforced even if not used) */
768 a2dp_source_local_param.btc_aa_src_cb.encoder.sbc_mode = SBC_MODE_STD;
769 a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode = pInitAudio->ChannelMode;
770 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands = pInitAudio->NumOfSubBands;
771 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks = pInitAudio->NumOfBlocks;
772 a2dp_source_local_param.btc_aa_src_cb.encoder.s16AllocationMethod = pInitAudio->AllocationMethod;
773 a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = pInitAudio->SamplingFreq;
774
775 a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate = btc_a2dp_source_get_sbc_rate();
776
777 /* Default transcoding is PCM to SBC, modified by feeding configuration */
778 a2dp_source_local_param.btc_aa_src_cb.TxTranscoding = BTC_MEDIA_TRSCD_PCM_2_SBC;
779 a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize = ((BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR))
780 < pInitAudio->MtuSize) ? (BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET
781 - sizeof(BT_HDR)) : pInitAudio->MtuSize;
782
783 APPL_TRACE_EVENT("btc_a2dp_source_enc_init mtu %d, peer mtu %d",
784 a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize, pInitAudio->MtuSize);
785 APPL_TRACE_EVENT(" ch mode %d, subnd %d, nb blk %d, alloc %d, rate %d, freq %d",
786 a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode, a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands,
787 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks,
788 a2dp_source_local_param.btc_aa_src_cb.encoder.s16AllocationMethod, a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate,
789 a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq);
790
791 /* Reset entirely the SBC encoder */
792 SBC_Encoder_Init(&(a2dp_source_local_param.btc_aa_src_cb.encoder));
793 APPL_TRACE_DEBUG("btc_a2dp_source_enc_init bit pool %d", a2dp_source_local_param.btc_aa_src_cb.encoder.s16BitPool);
794 }
795
796
797 /*******************************************************************************
798 **
799 ** Function btc_a2dp_source_enc_update
800 **
801 ** Description Update encoding task
802 **
803 ** Returns void
804 **
805 *******************************************************************************/
806
btc_a2dp_source_enc_update(BT_HDR * p_msg)807 static void btc_a2dp_source_enc_update(BT_HDR *p_msg)
808 {
809 tBTC_MEDIA_UPDATE_AUDIO *pUpdateAudio = (tBTC_MEDIA_UPDATE_AUDIO *) p_msg;
810 SBC_ENC_PARAMS *pstrEncParams = &a2dp_source_local_param.btc_aa_src_cb.encoder;
811 UINT16 s16SamplingFreq;
812 SINT16 s16BitPool = 0;
813 SINT16 s16BitRate;
814 SINT16 s16FrameLen;
815 UINT8 protect = 0;
816
817 APPL_TRACE_DEBUG("%s : minmtu %d, maxbp %d minbp %d", __FUNCTION__,
818 pUpdateAudio->MinMtuSize, pUpdateAudio->MaxBitPool, pUpdateAudio->MinBitPool);
819
820 /* Only update the bitrate and MTU size while timer is running to make sure it has been initialized */
821 //if (a2dp_source_local_param.btc_aa_src_cb.is_tx_timer)
822 {
823 a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize = ((BTC_MEDIA_AA_BUF_SIZE -
824 BTC_MEDIA_AA_SBC_OFFSET - sizeof(BT_HDR))
825 < pUpdateAudio->MinMtuSize) ? (BTC_MEDIA_AA_BUF_SIZE - BTC_MEDIA_AA_SBC_OFFSET
826 - sizeof(BT_HDR)) : pUpdateAudio->MinMtuSize;
827 /* Set the initial target bit rate */
828 pstrEncParams->u16BitRate = btc_a2dp_source_get_sbc_rate();
829
830 if (pstrEncParams->s16SamplingFreq == SBC_sf16000) {
831 s16SamplingFreq = 16000;
832 } else if (pstrEncParams->s16SamplingFreq == SBC_sf32000) {
833 s16SamplingFreq = 32000;
834 } else if (pstrEncParams->s16SamplingFreq == SBC_sf44100) {
835 s16SamplingFreq = 44100;
836 } else {
837 s16SamplingFreq = 48000;
838 }
839
840 do {
841 if (pstrEncParams->s16NumOfBlocks == 0 || pstrEncParams->s16NumOfSubBands == 0
842 || pstrEncParams->s16NumOfChannels == 0) {
843 APPL_TRACE_ERROR("%s - Avoiding division by zero...", __FUNCTION__);
844 APPL_TRACE_ERROR("%s - block=%d, subBands=%d, channels=%d", __FUNCTION__,
845 pstrEncParams->s16NumOfBlocks, pstrEncParams->s16NumOfSubBands,
846 pstrEncParams->s16NumOfChannels);
847 break;
848 }
849
850 if ((pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) ||
851 (pstrEncParams->s16ChannelMode == SBC_STEREO) ) {
852 s16BitPool = (SINT16)( (pstrEncParams->u16BitRate *
853 pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq)
854 - ( (32 + (4 * pstrEncParams->s16NumOfSubBands *
855 pstrEncParams->s16NumOfChannels)
856 + ( (pstrEncParams->s16ChannelMode - 2) *
857 pstrEncParams->s16NumOfSubBands ) )
858 / pstrEncParams->s16NumOfBlocks) );
859
860 s16FrameLen = 4 + (4 * pstrEncParams->s16NumOfSubBands *
861 pstrEncParams->s16NumOfChannels) / 8
862 + ( ((pstrEncParams->s16ChannelMode - 2) *
863 pstrEncParams->s16NumOfSubBands)
864 + (pstrEncParams->s16NumOfBlocks * s16BitPool) ) / 8;
865
866 s16BitRate = (8 * s16FrameLen * s16SamplingFreq)
867 / (pstrEncParams->s16NumOfSubBands *
868 pstrEncParams->s16NumOfBlocks * 1000);
869
870 if (s16BitRate > pstrEncParams->u16BitRate) {
871 s16BitPool--;
872 }
873
874 if (pstrEncParams->s16NumOfSubBands == 8) {
875 s16BitPool = (s16BitPool > 255) ? 255 : s16BitPool;
876 } else {
877 s16BitPool = (s16BitPool > 128) ? 128 : s16BitPool;
878 }
879 } else {
880 s16BitPool = (SINT16)( ((pstrEncParams->s16NumOfSubBands *
881 pstrEncParams->u16BitRate * 1000)
882 / (s16SamplingFreq * pstrEncParams->s16NumOfChannels))
883 - ( ( (32 / pstrEncParams->s16NumOfChannels) +
884 (4 * pstrEncParams->s16NumOfSubBands) )
885 / pstrEncParams->s16NumOfBlocks ) );
886
887 pstrEncParams->s16BitPool = (s16BitPool >
888 (16 * pstrEncParams->s16NumOfSubBands))
889 ? (16 * pstrEncParams->s16NumOfSubBands) : s16BitPool;
890 }
891
892 if (s16BitPool < 0) {
893 s16BitPool = 0;
894 }
895
896 APPL_TRACE_EVENT("bitpool candidate : %d (%d kbps)",
897 s16BitPool, pstrEncParams->u16BitRate);
898
899 if (s16BitPool > pUpdateAudio->MaxBitPool) {
900 APPL_TRACE_DEBUG("%s computed bitpool too large (%d)", __FUNCTION__, s16BitPool);
901 /* Decrease bitrate */
902 a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate -= BTC_MEDIA_BITRATE_STEP;
903 /* Record that we have decreased the bitrate */
904 protect |= 1;
905 } else if (s16BitPool < pUpdateAudio->MinBitPool) {
906 APPL_TRACE_WARNING("%s computed bitpool too small (%d)", __FUNCTION__, s16BitPool);
907
908 /* Increase bitrate */
909 UINT16 previous_u16BitRate = a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate;
910 a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate += BTC_MEDIA_BITRATE_STEP;
911 /* Record that we have increased the bitrate */
912 protect |= 2;
913 /* Check over-flow */
914 if (a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate < previous_u16BitRate) {
915 protect |= 3;
916 }
917 } else {
918 break;
919 }
920 /* In case we have already increased and decreased the bitrate, just stop */
921 if (protect == 3) {
922 APPL_TRACE_ERROR("%s could not find bitpool in range", __FUNCTION__);
923 break;
924 }
925 } while (1);
926
927 /* Finally update the bitpool in the encoder structure */
928 pstrEncParams->s16BitPool = s16BitPool;
929
930 APPL_TRACE_DEBUG("%s final bit rate %d, final bit pool %d", __FUNCTION__,
931 a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate, a2dp_source_local_param.btc_aa_src_cb.encoder.s16BitPool);
932
933 /* make sure we reinitialize encoder with new settings */
934 SBC_Encoder_Init(&(a2dp_source_local_param.btc_aa_src_cb.encoder));
935 }
936 }
937
938 #if A2D_SRC_BQB_INCLUDED
939 /*******************************************************************************
940 **
941 ** Function btc_a2dp_source_bqb_sbc_encoder_set
942 **
943 ** Description Set SBC encoder for bqb test cases A2DP/SRC/SET/BV-04-I and A2DP/SRC/SET/BV-06-I
944 **
945 ** Returns void
946 **
947 *******************************************************************************/
btc_a2dp_source_bqb_sbc_encoder_set(void)948 void btc_a2dp_source_bqb_sbc_encoder_set(void)
949 {
950 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands = 8;
951 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks = 8;
952 a2dp_source_local_param.btc_aa_src_cb.encoder.s16AllocationMethod = SBC_LOUDNESS;
953 a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode = SBC_MONO;
954 a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf44100;
955 SBC_Encoder_Init(&(a2dp_source_local_param.btc_aa_src_cb.encoder));
956 }
957 #endif /* A2D_SRC_BQB_INCLUDED */
958
959 /*******************************************************************************
960 **
961 ** Function btc_a2dp_source_pcm2sbc_init
962 **
963 ** Description Init encoding task for PCM to SBC according to feeding
964 **
965 ** Returns void
966 **
967 *******************************************************************************/
btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING * p_feeding)968 static void btc_a2dp_source_pcm2sbc_init(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feeding)
969 {
970 BOOLEAN reconfig_needed = FALSE;
971
972 APPL_TRACE_DEBUG("PCM feeding:");
973 APPL_TRACE_DEBUG("sampling_freq:%d", p_feeding->feeding.cfg.pcm.sampling_freq);
974 APPL_TRACE_DEBUG("num_channel:%d", p_feeding->feeding.cfg.pcm.num_channel);
975 APPL_TRACE_DEBUG("bit_per_sample:%d", p_feeding->feeding.cfg.pcm.bit_per_sample);
976
977 /* Check the PCM feeding sampling_freq */
978 switch (p_feeding->feeding.cfg.pcm.sampling_freq) {
979 case 8000:
980 case 12000:
981 case 16000:
982 case 24000:
983 case 32000:
984 case 48000:
985 /* For these sampling_freq the AV connection must be 48000 */
986 if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf48000) {
987 /* Reconfiguration needed at 48000 */
988 APPL_TRACE_DEBUG("SBC Reconfiguration needed at 48000");
989 a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf48000;
990 reconfig_needed = TRUE;
991 }
992 break;
993
994 case 11025:
995 case 22050:
996 case 44100:
997 /* For these sampling_freq the AV connection must be 44100 */
998 if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq != SBC_sf44100) {
999 /* Reconfiguration needed at 44100 */
1000 APPL_TRACE_DEBUG("SBC Reconfiguration needed at 44100");
1001 a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq = SBC_sf44100;
1002 reconfig_needed = TRUE;
1003 }
1004 break;
1005 default:
1006 APPL_TRACE_DEBUG("Feeding PCM sampling_freq unsupported");
1007 break;
1008 }
1009
1010 /* Some AV Headsets do not support Mono => always ask for Stereo */
1011 if (a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode == SBC_MONO) {
1012 APPL_TRACE_DEBUG("SBC Reconfiguration needed in Stereo");
1013 a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode = SBC_JOINT_STEREO;
1014 reconfig_needed = TRUE;
1015 }
1016
1017 if (reconfig_needed != FALSE) {
1018 APPL_TRACE_DEBUG("%s :: mtu %d", __FUNCTION__, a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize);
1019 APPL_TRACE_DEBUG("ch mode %d, nbsubd %d, nb %d, alloc %d, rate %d, freq %d",
1020 a2dp_source_local_param.btc_aa_src_cb.encoder.s16ChannelMode,
1021 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands, a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks,
1022 a2dp_source_local_param.btc_aa_src_cb.encoder.s16AllocationMethod, a2dp_source_local_param.btc_aa_src_cb.encoder.u16BitRate,
1023 a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq);
1024
1025 SBC_Encoder_Init(&(a2dp_source_local_param.btc_aa_src_cb.encoder));
1026 } else {
1027 APPL_TRACE_DEBUG("%s no SBC reconfig needed", __FUNCTION__);
1028 }
1029
1030 #if A2D_SRC_BQB_INCLUDED
1031 if (a2dp_src_bqb_set_sbc_encoder_flag) {
1032 btc_a2dp_source_bqb_sbc_encoder_set();
1033 }
1034 #endif /* A2D_SRC_BQB_INCLUDED */
1035 }
1036
1037 /*******************************************************************************
1038 **
1039 ** Function btc_a2dp_source_audio_feeding_init
1040 **
1041 ** Description Initialize the audio path according to the feeding format
1042 **
1043 ** Returns void
1044 **
1045 *******************************************************************************/
btc_a2dp_source_audio_feeding_init(BT_HDR * p_msg)1046 static void btc_a2dp_source_audio_feeding_init(BT_HDR *p_msg)
1047 {
1048 tBTC_MEDIA_INIT_AUDIO_FEEDING *p_feeding = (tBTC_MEDIA_INIT_AUDIO_FEEDING *) p_msg;
1049
1050 APPL_TRACE_DEBUG("%s format:%d", __FUNCTION__, p_feeding->feeding.format);
1051
1052 /* Save Media Feeding information */
1053 a2dp_source_local_param.btc_aa_src_cb.feeding_mode = p_feeding->feeding_mode;
1054 a2dp_source_local_param.btc_aa_src_cb.media_feeding = p_feeding->feeding;
1055
1056 /* Handle different feeding formats */
1057 switch (p_feeding->feeding.format) {
1058 case BTC_AV_CODEC_PCM:
1059 a2dp_source_local_param.btc_aa_src_cb.TxTranscoding = BTC_MEDIA_TRSCD_PCM_2_SBC;
1060 btc_a2dp_source_pcm2sbc_init(p_feeding);
1061 break;
1062
1063 default :
1064 APPL_TRACE_ERROR("unknown feeding format %d", p_feeding->feeding.format);
1065 break;
1066 }
1067 }
1068
1069 /*******************************************************************************
1070 **
1071 ** Function btc_a2dp_source_aa_tx_flush
1072 **
1073 ** Description
1074 **
1075 ** Returns void
1076 **
1077 *******************************************************************************/
btc_a2dp_source_aa_tx_flush(void)1078 static void btc_a2dp_source_aa_tx_flush(void)
1079 {
1080 /* Flush all enqueued music buffers (encoded) */
1081 APPL_TRACE_DEBUG("%s", __FUNCTION__);
1082
1083 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter = 0;
1084 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue = 0;
1085
1086 btc_a2dp_source_flush_q(a2dp_source_local_param.btc_aa_src_cb.TxAaQ);
1087
1088 btc_aa_src_data_read(NULL, -1);
1089 }
1090
1091 /*******************************************************************************
1092 **
1093 ** Function btc_get_num_aa_frame
1094 **
1095 ** Description
1096 **
1097 ** Returns The number of media frames in this time slice
1098 **
1099 *******************************************************************************/
btc_get_num_aa_frame(void)1100 static UINT8 btc_get_num_aa_frame(void)
1101 {
1102 UINT8 result = 0;
1103
1104 switch (a2dp_source_local_param.btc_aa_src_cb.TxTranscoding) {
1105 case BTC_MEDIA_TRSCD_PCM_2_SBC: {
1106 UINT32 pcm_bytes_per_frame = a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands *
1107 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks *
1108 a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel *
1109 a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
1110
1111 UINT32 us_this_tick = BTC_MEDIA_TIME_TICK_MS * 1000;
1112 UINT64 now_us = time_now_us();
1113 if (a2dp_source_local_param.last_frame_us != 0) {
1114 #if _POSIX_TIMERS
1115 us_this_tick = (now_us - a2dp_source_local_param.last_frame_us);
1116 #else
1117 // consider the case that the number of day increases and timeofday wraps around
1118 us_this_tick = (now_us > a2dp_source_local_param.last_frame_us) ? (now_us - a2dp_source_local_param.last_frame_us) :
1119 (now_us + 86400000000ull - a2dp_source_local_param.last_frame_us);
1120 #endif
1121 }
1122 a2dp_source_local_param.last_frame_us = now_us;
1123
1124 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter +=
1125 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick *
1126 us_this_tick / (BTC_MEDIA_TIME_TICK_MS * 1000);
1127
1128 /* calculate nbr of frames pending for this media tick */
1129 result = a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter / pcm_bytes_per_frame;
1130
1131 /* limit the frames to be sent */
1132 UINT32 frm_nb_threshold = MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ);
1133 if (frm_nb_threshold > MAX_PCM_FRAME_NUM_PER_TICK) {
1134 frm_nb_threshold = MAX_PCM_FRAME_NUM_PER_TICK;
1135 }
1136
1137 if (result > frm_nb_threshold) {
1138 APPL_TRACE_EVENT("Limit frms to send from %d to %d", result, frm_nb_threshold);
1139 result = frm_nb_threshold;
1140 }
1141 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter -= result * pcm_bytes_per_frame;
1142
1143 BTC_TRACE_VERBOSE("WRITE %d FRAMES", result);
1144 }
1145 break;
1146
1147 default:
1148 APPL_TRACE_ERROR("ERROR btc_get_num_aa_frame Unsupported transcoding format 0x%x",
1149 a2dp_source_local_param.btc_aa_src_cb.TxTranscoding);
1150 result = 0;
1151 break;
1152 }
1153
1154 return (UINT8)result;
1155 }
1156
1157 /*******************************************************************************
1158 **
1159 ** Function btc_media_aa_read_feeding
1160 **
1161 ** Description
1162 **
1163 ** Returns void
1164 **
1165 *******************************************************************************/
1166
btc_media_aa_read_feeding(void)1167 BOOLEAN btc_media_aa_read_feeding(void)
1168 {
1169 UINT16 blocm_x_subband = a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands * \
1170 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks;
1171 UINT32 read_size;
1172 UINT16 sbc_sampling = 48000;
1173 UINT32 src_samples;
1174 UINT16 bytes_needed = blocm_x_subband * a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfChannels * \
1175 a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
1176 static UINT16 up_sampled_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
1177 * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * 2];
1178 static UINT16 read_buffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS
1179 * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS];
1180 UINT32 src_size_used;
1181 UINT32 dst_size_used;
1182 BOOLEAN fract_needed;
1183 INT32 fract_max;
1184 INT32 fract_threshold;
1185 UINT32 nb_byte_read = 0;
1186
1187 /* Get the SBC sampling rate */
1188 switch (a2dp_source_local_param.btc_aa_src_cb.encoder.s16SamplingFreq) {
1189 case SBC_sf48000:
1190 sbc_sampling = 48000;
1191 break;
1192 case SBC_sf44100:
1193 sbc_sampling = 44100;
1194 break;
1195 case SBC_sf32000:
1196 sbc_sampling = 32000;
1197 break;
1198 case SBC_sf16000:
1199 sbc_sampling = 16000;
1200 break;
1201 }
1202
1203 if (sbc_sampling == a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq) {
1204 read_size = bytes_needed - a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue;
1205 nb_byte_read = btc_aa_src_data_read(
1206 ((uint8_t *)a2dp_source_local_param.btc_aa_src_cb.encoder.as16PcmBuffer) +
1207 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue,
1208 read_size);
1209 if (nb_byte_read == read_size) {
1210 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue = 0;
1211 return TRUE;
1212 } else {
1213 APPL_TRACE_WARNING("### UNDERFLOW :: ONLY READ %d BYTES OUT OF %d ###",
1214 nb_byte_read, read_size);
1215 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue += nb_byte_read;
1216 return FALSE;
1217 }
1218 }
1219
1220 /* Some Feeding PCM frequencies require to split the number of sample */
1221 /* to read. */
1222 /* E.g 128/6=21.3333 => read 22 and 21 and 21 => max = 2; threshold = 0*/
1223 fract_needed = FALSE; /* Default */
1224 switch (a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq) {
1225 case 32000:
1226 case 8000:
1227 fract_needed = TRUE;
1228 fract_max = 2; /* 0, 1 and 2 */
1229 fract_threshold = 0; /* Add one for the first */
1230 break;
1231 case 16000:
1232 fract_needed = TRUE;
1233 fract_max = 2; /* 0, 1 and 2 */
1234 fract_threshold = 1; /* Add one for the first two frames*/
1235 break;
1236 }
1237
1238 /* Compute number of sample to read from source */
1239 src_samples = blocm_x_subband;
1240 src_samples *= a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq;
1241 src_samples /= sbc_sampling;
1242
1243 /* The previous division may have a remainder not null */
1244 if (fract_needed) {
1245 if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter <= fract_threshold) {
1246 src_samples++; /* for every read before threshold add one sample */
1247 }
1248
1249 /* do nothing if counter >= threshold */
1250 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter++; /* one more read */
1251 if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter > fract_max) {
1252 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_counter = 0;
1253 }
1254 }
1255
1256 /* Compute number of bytes to read from source */
1257 read_size = src_samples;
1258 read_size *= a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel;
1259 read_size *= (a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8);
1260
1261 /* Read Data from data channel */
1262 nb_byte_read = btc_aa_src_data_read((uint8_t *)read_buffer, read_size);
1263
1264 if (nb_byte_read < read_size) {
1265 APPL_TRACE_WARNING("### UNDERRUN :: ONLY READ %d BYTES OUT OF %d ###",
1266 nb_byte_read, read_size);
1267
1268 if (nb_byte_read == 0) {
1269 return FALSE;
1270 }
1271
1272 if (a2dp_source_local_param.btc_aa_src_cb.feeding_mode == BTC_AV_FEEDING_ASYNCHRONOUS) {
1273 /* Fill the unfilled part of the read buffer with silence (0) */
1274 memset(((UINT8 *)read_buffer) + nb_byte_read, 0, read_size - nb_byte_read);
1275 nb_byte_read = read_size;
1276 }
1277 }
1278
1279 /* Initialize PCM up-sampling engine */
1280 bta_av_sbc_init_up_sample(a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq,
1281 sbc_sampling, a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample,
1282 a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel);
1283
1284 /* re-sample read buffer */
1285 /* The output PCM buffer will be stereo, 16 bit per sample */
1286 dst_size_used = bta_av_sbc_up_sample((UINT8 *)read_buffer,
1287 (UINT8 *)up_sampled_buffer + a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue,
1288 nb_byte_read,
1289 sizeof(up_sampled_buffer) - a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue,
1290 &src_size_used);
1291
1292 /* update the residue */
1293 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue += dst_size_used;
1294
1295 /* only copy the pcm sample when we have up-sampled enough PCM */
1296 if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue >= bytes_needed) {
1297 /* Copy the output pcm samples in SBC encoding buffer */
1298 memcpy((UINT8 *)a2dp_source_local_param.btc_aa_src_cb.encoder.as16PcmBuffer,
1299 (UINT8 *)up_sampled_buffer,
1300 bytes_needed);
1301 /* update the residue */
1302 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue -= bytes_needed;
1303
1304 if (a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue != 0) {
1305 memcpy((UINT8 *)up_sampled_buffer,
1306 (UINT8 *)up_sampled_buffer + bytes_needed,
1307 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue);
1308 }
1309 return TRUE;
1310 }
1311
1312 return FALSE;
1313 }
1314
1315 /*******************************************************************************
1316 **
1317 ** Function btc_media_aa_prep_sbc_2_send
1318 **
1319 ** Description
1320 **
1321 ** Returns void
1322 **
1323 *******************************************************************************/
btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)1324 static void btc_media_aa_prep_sbc_2_send(UINT8 nb_frame)
1325 {
1326 BT_HDR *p_buf;
1327 UINT16 blocm_x_subband = a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands *
1328 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks;
1329
1330 while (nb_frame) {
1331 if (NULL == (p_buf = osi_malloc(BTC_MEDIA_AA_BUF_SIZE))) {
1332 APPL_TRACE_ERROR ("ERROR btc_media_aa_prep_sbc_2_send no buffer TxCnt %d ",
1333 fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ));
1334 return;
1335 }
1336
1337 /* Init buffer */
1338 p_buf->offset = BTC_MEDIA_AA_SBC_OFFSET;
1339 p_buf->len = 0;
1340 p_buf->layer_specific = 0;
1341
1342 do {
1343 /* Write @ of allocated buffer in encoder.pu8Packet */
1344 a2dp_source_local_param.btc_aa_src_cb.encoder.pu8Packet = (UINT8 *) (p_buf + 1) + p_buf->offset + p_buf->len;
1345 /* Fill allocated buffer with 0 */
1346 memset(a2dp_source_local_param.btc_aa_src_cb.encoder.as16PcmBuffer, 0, blocm_x_subband
1347 * a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfChannels);
1348
1349 /* Read PCM data and upsample them if needed */
1350 if (btc_media_aa_read_feeding()) {
1351 /* SBC encode and descramble frame */
1352 SBC_Encoder(&(a2dp_source_local_param.btc_aa_src_cb.encoder));
1353
1354 /* Update SBC frame length */
1355 p_buf->len += a2dp_source_local_param.btc_aa_src_cb.encoder.u16PacketLength;
1356 nb_frame--;
1357 p_buf->layer_specific++;
1358 } else {
1359 APPL_TRACE_WARNING("btc_media_aa_prep_sbc_2_send underflow %d, %d",
1360 nb_frame, a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.aa_feed_residue);
1361 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.counter += nb_frame *
1362 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfSubBands *
1363 a2dp_source_local_param.btc_aa_src_cb.encoder.s16NumOfBlocks *
1364 a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel *
1365 a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
1366 /* no more pcm to read */
1367 nb_frame = 0;
1368
1369 /* break read loop if timer was stopped (media task stopped) */
1370 if ( a2dp_source_local_param.btc_aa_src_cb.is_tx_timer == FALSE ) {
1371 osi_free(p_buf);
1372 return;
1373 }
1374 }
1375
1376 } while (((p_buf->len + a2dp_source_local_param.btc_aa_src_cb.encoder.u16PacketLength) < a2dp_source_local_param.btc_aa_src_cb.TxAaMtuSize)
1377 && (p_buf->layer_specific < 0x0F) && nb_frame);
1378
1379 if (p_buf->len) {
1380 /* timestamp of the media packet header represent the TS of the first SBC frame
1381 i.e the timestamp before including this frame */
1382 *((UINT32 *) (p_buf + 1)) = a2dp_source_local_param.btc_aa_src_cb.timestamp;
1383
1384 a2dp_source_local_param.btc_aa_src_cb.timestamp += p_buf->layer_specific * blocm_x_subband;
1385
1386 if (a2dp_source_local_param.btc_aa_src_cb.tx_flush) {
1387 APPL_TRACE_DEBUG("### tx suspended, discarded frame ###");
1388
1389 if (fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ) > 0) {
1390 btc_a2dp_source_flush_q(a2dp_source_local_param.btc_aa_src_cb.TxAaQ);
1391 }
1392
1393 osi_free(p_buf);
1394 return;
1395 }
1396
1397 /* Enqueue the encoded SBC frame in AA Tx Queue */
1398 fixed_queue_enqueue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
1399 } else {
1400 osi_free(p_buf);
1401 }
1402 }
1403 }
1404
1405 /*******************************************************************************
1406 **
1407 ** Function btc_a2dp_source_prep_2_send
1408 **
1409 ** Description
1410 **
1411 ** Returns void
1412 **
1413 *******************************************************************************/
btc_a2dp_source_prep_2_send(UINT8 nb_frame)1414 static void btc_a2dp_source_prep_2_send(UINT8 nb_frame)
1415 {
1416 // Check for TX queue overflow
1417 if (nb_frame > MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ) {
1418 nb_frame = MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ;
1419 }
1420
1421 if (fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ) > (MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame)) {
1422 APPL_TRACE_WARNING("TX Q overflow: %d/%d",
1423 fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ), MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame);
1424 }
1425
1426 while (fixed_queue_length(a2dp_source_local_param.btc_aa_src_cb.TxAaQ) > (MAX_OUTPUT_A2DP_SRC_FRAME_QUEUE_SZ - nb_frame)) {
1427 osi_free(fixed_queue_dequeue(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, 0));
1428 }
1429
1430 // Transcode frame
1431
1432 switch (a2dp_source_local_param.btc_aa_src_cb.TxTranscoding) {
1433 case BTC_MEDIA_TRSCD_PCM_2_SBC:
1434 btc_media_aa_prep_sbc_2_send(nb_frame);
1435 break;
1436
1437 default:
1438 APPL_TRACE_ERROR("%s unsupported transcoding format 0x%x", __func__, a2dp_source_local_param.btc_aa_src_cb.TxTranscoding);
1439 break;
1440 }
1441 }
1442
1443 /*******************************************************************************
1444 **
1445 ** Function btc_a2dp_source_send_aa_frame
1446 **
1447 ** Description
1448 **
1449 ** Returns void
1450 **
1451 *******************************************************************************/
btc_a2dp_source_send_aa_frame(void)1452 static void btc_a2dp_source_send_aa_frame(void)
1453 {
1454 UINT8 nb_frame_2_send;
1455
1456 /* get the number of frame to send */
1457 nb_frame_2_send = btc_get_num_aa_frame();
1458
1459 if (nb_frame_2_send != 0) {
1460 /* format and Q buffer to send */
1461 btc_a2dp_source_prep_2_send(nb_frame_2_send);
1462 }
1463
1464 /* send it */
1465 BTC_TRACE_VERBOSE("%s: send %d frames", __FUNCTION__, nb_frame_2_send);
1466 bta_av_ci_src_data_ready(BTA_AV_CHNL_AUDIO);
1467 }
1468
btc_a2dp_source_handle_timer(UNUSED_ATTR void * context)1469 static void btc_a2dp_source_handle_timer(UNUSED_ATTR void *context)
1470 {
1471 log_tstamps_us("media task tx timer");
1472
1473 #if (BTA_AV_INCLUDED == TRUE)
1474 if (btc_a2dp_source_state != BTC_A2DP_SOURCE_STATE_ON || g_a2dp_source_ongoing_deinit){
1475 return;
1476 }
1477
1478 if (a2dp_source_local_param.btc_aa_src_cb.is_tx_timer == TRUE) {
1479 btc_a2dp_source_send_aa_frame();
1480 } else {
1481 APPL_TRACE_WARNING("Media task Scheduled after Suspend");
1482 }
1483 #endif
1484 }
1485
1486 /*******************************************************************************
1487 **
1488 ** Function btc_a2dp_source_feeding_state_reset
1489 **
1490 ** Description Reset the media feeding state
1491 **
1492 ** Returns void
1493 **
1494 *******************************************************************************/
btc_a2dp_source_feeding_state_reset(void)1495 static void btc_a2dp_source_feeding_state_reset(void)
1496 {
1497 /* By default, just clear the entire state */
1498 memset(&a2dp_source_local_param.btc_aa_src_cb.media_feeding_state, 0, sizeof(a2dp_source_local_param.btc_aa_src_cb.media_feeding_state));
1499
1500 if (a2dp_source_local_param.btc_aa_src_cb.TxTranscoding == BTC_MEDIA_TRSCD_PCM_2_SBC) {
1501 a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick =
1502 (a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.sampling_freq *
1503 a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.bit_per_sample / 8 *
1504 a2dp_source_local_param.btc_aa_src_cb.media_feeding.cfg.pcm.num_channel *
1505 BTC_MEDIA_TIME_TICK_MS) / 1000;
1506
1507 APPL_TRACE_EVENT("pcm bytes per tick %d",
1508 (int)a2dp_source_local_param.btc_aa_src_cb.media_feeding_state.pcm.bytes_per_tick);
1509 }
1510 }
1511
1512 /*******************************************************************************
1513 **
1514 ** Function btc_a2dp_source_aa_stop_tx
1515 **
1516 ** Description Stop media task encoding
1517 **
1518 ** Returns void
1519 **
1520 *******************************************************************************/
btc_a2dp_source_aa_stop_tx(void)1521 static void btc_a2dp_source_aa_stop_tx(void)
1522 {
1523 APPL_TRACE_DEBUG("%s is_tx_timer: %d", __func__, a2dp_source_local_param.btc_aa_src_cb.is_tx_timer);
1524
1525 const bool send_ack = (a2dp_source_local_param.btc_aa_src_cb.is_tx_timer != FALSE);
1526
1527 /* Stop the timer first */
1528 if (a2dp_source_local_param.btc_aa_src_cb.media_alarm) {
1529 osi_alarm_cancel(a2dp_source_local_param.btc_aa_src_cb.media_alarm);
1530 osi_alarm_free(a2dp_source_local_param.btc_aa_src_cb.media_alarm);
1531 }
1532 a2dp_source_local_param.btc_aa_src_cb.media_alarm = NULL;
1533 a2dp_source_local_param.btc_aa_src_cb.is_tx_timer = FALSE;
1534
1535 /* Try to send acknowldegment once the media stream is
1536 stopped. This will make sure that the A2DP HAL layer is
1537 un-blocked on wait for acknowledgment for the sent command.
1538 This resolves a corner cases AVDTP SUSPEND collision
1539 when the DUT and the remote device issue SUSPEND simultaneously
1540 and due to the processing of the SUSPEND request from the remote,
1541 the media path is torn down. If the A2DP HAL happens to wait
1542 for ACK for the initiated SUSPEND, it would never receive it casuing
1543 a block/wait. Due to this acknowledgement, the A2DP HAL is guranteed
1544 to get the ACK for any pending command in such cases. */
1545
1546 if (send_ack) {
1547 btc_a2dp_control_command_ack(ESP_A2D_MEDIA_CTRL_ACK_SUCCESS);
1548 }
1549
1550 /* audio engine stopped, reset tx suspended flag */
1551 a2dp_source_local_param.btc_aa_src_cb.tx_flush = 0;
1552 a2dp_source_local_param.last_frame_us = 0;
1553
1554 /* Reset the feeding state */
1555 btc_a2dp_source_feeding_state_reset();
1556 }
1557
1558 /*******************************************************************************
1559 **
1560 ** Function btc_a2dp_source_aa_start_tx
1561 **
1562 ** Description Start media task encoding
1563 **
1564 ** Returns void
1565 **
1566 *******************************************************************************/
btc_a2dp_source_alarm_cb(UNUSED_ATTR void * context)1567 static void btc_a2dp_source_alarm_cb(UNUSED_ATTR void *context)
1568 {
1569 if (a2dp_source_local_param.btc_aa_src_task_hdl) {
1570 osi_thread_post_event(a2dp_source_local_param.btc_aa_src_cb.poll_data, OSI_THREAD_MAX_TIMEOUT);
1571 } else {
1572 APPL_TRACE_DEBUG("[%s] A2DP ALREADY FREED", __func__);
1573 btc_a2dp_source_aa_stop_tx();
1574 }
1575 }
1576
btc_a2dp_source_aa_start_tx(void)1577 static void btc_a2dp_source_aa_start_tx(void)
1578 {
1579 APPL_TRACE_DEBUG("btc_a2dp_source_aa_start_tx is timer %d, feeding mode %d",
1580 a2dp_source_local_param.btc_aa_src_cb.is_tx_timer, a2dp_source_local_param.btc_aa_src_cb.feeding_mode);
1581
1582 a2dp_source_local_param.btc_aa_src_cb.is_tx_timer = TRUE;
1583 a2dp_source_local_param.last_frame_us = 0;
1584
1585 /* Reset the media feeding state */
1586 btc_a2dp_source_feeding_state_reset();
1587
1588 APPL_TRACE_EVENT("starting timer %dms", BTC_MEDIA_TIME_TICK_MS);
1589
1590 assert(a2dp_source_local_param.btc_aa_src_cb.media_alarm == NULL);
1591
1592 a2dp_source_local_param.btc_aa_src_cb.media_alarm = osi_alarm_new("aaTx", btc_a2dp_source_alarm_cb, NULL, BTC_MEDIA_TIME_TICK_MS);
1593
1594 if (!a2dp_source_local_param.btc_aa_src_cb.media_alarm) {
1595 BTC_TRACE_ERROR("%s unable to allocate media alarm.", __func__);
1596 return;
1597 }
1598
1599 osi_alarm_set_periodic(a2dp_source_local_param.btc_aa_src_cb.media_alarm, BTC_MEDIA_TIME_TICK_MS);
1600 }
1601
1602 /*******************************************************************************
1603 **
1604 ** Function btc_a2dp_source_flush_q
1605 **
1606 ** Description
1607 **
1608 ** Returns void
1609 **
1610 *******************************************************************************/
btc_a2dp_source_flush_q(fixed_queue_t * p_q)1611 static void btc_a2dp_source_flush_q(fixed_queue_t *p_q)
1612 {
1613 while (! fixed_queue_is_empty(p_q)) {
1614 osi_free(fixed_queue_dequeue(p_q, 0));
1615 }
1616 }
1617
btc_a2dp_source_thread_init(UNUSED_ATTR void * context)1618 static void btc_a2dp_source_thread_init(UNUSED_ATTR void *context)
1619 {
1620 APPL_TRACE_EVENT("%s\n", __func__);
1621 memset(&a2dp_source_local_param.btc_aa_src_cb, 0, sizeof(a2dp_source_local_param.btc_aa_src_cb));
1622
1623 btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_ON;
1624
1625 struct osi_event *poll_data = osi_event_create(btc_a2dp_source_handle_timer, NULL);
1626 assert(poll_data != NULL);
1627 osi_event_bind(poll_data, a2dp_source_local_param.btc_aa_src_task_hdl, BTC_A2DP_SRC_DATA_QUEUE_IDX);
1628 a2dp_source_local_param.btc_aa_src_cb.poll_data = poll_data;
1629
1630 a2dp_source_local_param.btc_aa_src_cb.TxAaQ = fixed_queue_new(QUEUE_SIZE_MAX);
1631
1632 btc_a2dp_control_init();
1633 }
1634
btc_a2dp_source_thread_cleanup(UNUSED_ATTR void * context)1635 static void btc_a2dp_source_thread_cleanup(UNUSED_ATTR void *context)
1636 {
1637 /* Clear media task flag */
1638 btc_a2dp_source_state = BTC_A2DP_SOURCE_STATE_OFF;
1639
1640 btc_a2dp_control_cleanup();
1641
1642 fixed_queue_free(a2dp_source_local_param.btc_aa_src_cb.TxAaQ, osi_free_func);
1643
1644 a2dp_source_local_param.btc_aa_src_cb.TxAaQ = NULL;
1645
1646 osi_event_delete(a2dp_source_local_param.btc_aa_src_cb.poll_data);
1647 a2dp_source_local_param.btc_aa_src_cb.poll_data = NULL;
1648 }
1649
1650 #endif /* BTC_AV_INCLUDED */
1651