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