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, &param);
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