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