1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 /******************************************************************************
16  **
17  **  Name:          btc_a2dp_sink.c
18  **
19  ******************************************************************************/
20 #include "common/bt_target.h"
21 #include "common/bt_trace.h"
22 #include <string.h>
23 #include <stdint.h>
24 #include "common/bt_defs.h"
25 #include "osi/allocator.h"
26 #include "osi/mutex.h"
27 #include "osi/semaphore.h"
28 #include "osi/thread.h"
29 #include "osi/fixed_queue.h"
30 #include "stack/a2d_api.h"
31 #include "stack/a2d_sbc.h"
32 #include "bta/bta_av_api.h"
33 #include "bta/bta_av_ci.h"
34 #include "btc_av_co.h"
35 #include "btc_a2dp.h"
36 #include "btc_a2dp_control.h"
37 #include "btc_a2dp_sink.h"
38 #include "btc/btc_manage.h"
39 #include "btc_av.h"
40 #include "btc/btc_util.h"
41 #include "esp_a2dp_api.h"
42 #include "oi_codec_sbc.h"
43 #include "oi_status.h"
44 #include "osi/future.h"
45 #include <assert.h>
46 
47 #if (BTC_AV_SINK_INCLUDED == TRUE)
48 
49 extern osi_thread_t *btc_thread;
50 
51 /*****************************************************************************
52  **  Constants
53  *****************************************************************************/
54 
55 /* BTC media cmd event definition : BTC_MEDIA_TASK_CMD */
56 enum {
57     BTC_MEDIA_TASK_SINK_INIT,
58     BTC_MEDIA_TASK_SINK_CLEAN_UP,
59     BTC_MEDIA_FLUSH_AA_RX,
60     BTC_MEDIA_AUDIO_SINK_CFG_UPDATE,
61     BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK,
62 };
63 
64 enum {
65     BTC_A2DP_SINK_STATE_OFF = 0,
66     BTC_A2DP_SINK_STATE_ON = 1,
67     BTC_A2DP_SINK_STATE_SHUTTING_DOWN = 2
68 };
69 
70 /*
71  * CONGESTION COMPENSATION CTRL ::
72  *
73  * Thus setting controls how many buffers we will hold in media task
74  * during temp link congestion. Together with the stack buffer queues
75  * it controls much temporary a2dp link congestion we can
76  * compensate for. It however also depends on the default run level of sinks
77  * jitterbuffers. Depending on type of sink this would vary.
78  * Ideally the (SRC) max tx buffer capacity should equal the sinks
79  * jitterbuffer runlevel including any intermediate buffers on the way
80  * towards the sinks codec.
81  */
82 
83 /* fixme -- define this in pcm time instead of buffer count */
84 
85 /* The typical runlevel of the tx queue size is ~1 buffer
86    but due to link flow control or thread preemption in lower
87    layers we might need to temporarily buffer up data */
88 
89 /* 18 frames is equivalent to 6.89*18*2.9 ~= 360 ms @ 44.1 khz, 20 ms mediatick */
90 #define MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ     (25)
91 #define JITTER_BUFFER_WATER_LEVEL (5)
92 
93 typedef struct {
94     uint32_t sig;
95     void *param;
96 } a2dp_sink_task_evt_t;
97 
98 typedef struct {
99     UINT16 num_frames_to_be_processed;
100     UINT16 len;
101     UINT16 offset;
102     UINT16 layer_specific;
103 } tBT_SBC_HDR;
104 
105 typedef struct {
106     BOOLEAN rx_flush; /* discards any incoming data when true */
107     UINT8   channel_count;
108     osi_sem_t post_sem;
109     fixed_queue_t *RxSbcQ;
110     UINT32  sample_rate;
111 } tBTC_A2DP_SINK_CB;
112 
113 typedef struct {
114     tBTC_A2DP_SINK_CB   btc_aa_snk_cb;
115     osi_thread_t        *btc_aa_snk_task_hdl;
116     OI_CODEC_SBC_DECODER_CONTEXT    context;
117     OI_UINT32           contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)];
118     OI_INT16            pcmData[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS];
119 } a2dp_sink_local_param_t;
120 
121 static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context);
122 static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context);
123 static void btc_a2dp_sink_flush_q(fixed_queue_t *p_q);
124 static void btc_a2dp_sink_rx_flush(void);
125 static int btc_a2dp_sink_get_track_frequency(UINT8 frequency);
126 static int btc_a2dp_sink_get_track_channel_count(UINT8 channeltype);
127 /* Handle incoming media packets A2DP SINK streaming*/
128 static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg);
129 static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg);
130 static void btc_a2dp_sink_handle_clear_track(void);
131 static BOOLEAN btc_a2dp_sink_clear_track(void);
132 
133 static void btc_a2dp_sink_data_ready(void *context);
134 
135 static int btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_OFF;
136 static esp_a2d_sink_data_cb_t bt_aa_snk_data_cb = NULL;
137 #if A2D_DYNAMIC_MEMORY == FALSE
138 static a2dp_sink_local_param_t a2dp_sink_local_param;
139 #else
140 static a2dp_sink_local_param_t *a2dp_sink_local_param_ptr;
141 #define a2dp_sink_local_param (*a2dp_sink_local_param_ptr)
142 #endif ///A2D_DYNAMIC_MEMORY == FALSE
143 
btc_a2dp_sink_reg_data_cb(esp_a2d_sink_data_cb_t callback)144 void btc_a2dp_sink_reg_data_cb(esp_a2d_sink_data_cb_t callback)
145 {
146     // todo: critical section protection
147     bt_aa_snk_data_cb = callback;
148 }
149 
btc_a2d_data_cb_to_app(const uint8_t * data,uint32_t len)150 static inline void btc_a2d_data_cb_to_app(const uint8_t *data, uint32_t len)
151 {
152     // todo: critical section protection
153     if (bt_aa_snk_data_cb) {
154         bt_aa_snk_data_cb(data, len);
155     }
156 }
157 
158 /*****************************************************************************
159  **  Misc helper functions
160  *****************************************************************************/
btc_a2d_cb_to_app(esp_a2d_cb_event_t event,esp_a2d_cb_param_t * param)161 static inline void btc_a2d_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
162 {
163     esp_a2d_cb_t btc_aa_cb = (esp_a2d_cb_t)btc_profile_cb_get(BTC_PID_A2DP);
164     if (btc_aa_cb) {
165         btc_aa_cb(event, param);
166     }
167 }
168 
169 /*****************************************************************************
170  **  BTC ADAPTATION
171  *****************************************************************************/
172 
btc_a2dp_sink_ctrl(uint32_t sig,void * param)173 static bool btc_a2dp_sink_ctrl(uint32_t sig, void *param)
174 {
175     switch (sig) {
176     case BTC_MEDIA_TASK_SINK_INIT:
177         btc_a2dp_sink_thread_init(NULL);
178         break;
179     case BTC_MEDIA_TASK_SINK_CLEAN_UP:
180         btc_a2dp_sink_thread_cleanup(NULL);
181         break;
182     case BTC_MEDIA_AUDIO_SINK_CFG_UPDATE:
183         btc_a2dp_sink_handle_decoder_reset(param);
184         break;
185     case BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK:
186         btc_a2dp_sink_handle_clear_track();
187         break;
188     case BTC_MEDIA_FLUSH_AA_RX:
189         btc_a2dp_sink_rx_flush();
190         break;
191     default:
192         APPL_TRACE_WARNING("media task unhandled evt: 0x%x\n", sig);
193     }
194 
195     if (param != NULL) {
196         osi_free(param);
197     }
198 
199     return true;
200 }
201 
btc_a2dp_sink_startup(void)202 bool btc_a2dp_sink_startup(void)
203 {
204     if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_OFF) {
205         APPL_TRACE_ERROR("warning : media task already running");
206         return false;
207     }
208 
209 #if A2D_DYNAMIC_MEMORY == TRUE
210     if ((a2dp_sink_local_param_ptr = (a2dp_sink_local_param_t *)osi_malloc(sizeof(a2dp_sink_local_param_t))) == NULL) {
211         APPL_TRACE_ERROR("%s malloc failed!", __func__);
212         return false;
213     }
214     memset((void *)a2dp_sink_local_param_ptr, 0, sizeof(a2dp_sink_local_param_t));
215 #endif
216 
217     APPL_TRACE_EVENT("## A2DP SINK START MEDIA THREAD ##");
218 
219     a2dp_sink_local_param.btc_aa_snk_task_hdl = btc_thread;
220 
221     if (btc_a2dp_sink_ctrl(BTC_MEDIA_TASK_SINK_INIT, NULL) == false) {
222         goto error_exit;
223     }
224 
225     APPL_TRACE_EVENT("## A2DP SINK MEDIA THREAD STARTED ##\n");
226 
227     return true;
228 
229 error_exit:;
230     APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__);
231     a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL;
232 
233 #if A2D_DYNAMIC_MEMORY == TRUE
234     osi_free(a2dp_sink_local_param_ptr);
235     a2dp_sink_local_param_ptr = NULL;
236 #endif
237 
238     return false;
239 }
240 
btc_a2dp_sink_shutdown(void)241 void btc_a2dp_sink_shutdown(void)
242 {
243     APPL_TRACE_EVENT("## A2DP SINK STOP MEDIA THREAD ##\n");
244 
245     // Exit thread
246     btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_SHUTTING_DOWN;
247 
248     btc_a2dp_sink_ctrl(BTC_MEDIA_TASK_SINK_CLEAN_UP, NULL);
249 
250     a2dp_sink_local_param.btc_aa_snk_task_hdl = NULL;
251 
252 #if A2D_DYNAMIC_MEMORY == TRUE
253     osi_free(a2dp_sink_local_param_ptr);
254     a2dp_sink_local_param_ptr = NULL;
255 #endif
256 }
257 
258 /*****************************************************************************
259 **
260 ** Function        btc_a2dp_sink_on_idle
261 **
262 *******************************************************************************/
263 
btc_a2dp_sink_on_idle(void)264 void btc_a2dp_sink_on_idle(void)
265 {
266     a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
267     btc_a2dp_sink_rx_flush_req();
268     btc_a2dp_sink_clear_track();
269 
270     APPL_TRACE_DEBUG("Stopped BT track");
271 }
272 
273 /*****************************************************************************
274 **
275 ** Function        btc_a2dp_sink_on_stopped
276 **
277 *******************************************************************************/
278 
btc_a2dp_sink_on_stopped(tBTA_AV_SUSPEND * p_av)279 void btc_a2dp_sink_on_stopped(tBTA_AV_SUSPEND *p_av)
280 {
281     a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
282     btc_a2dp_sink_rx_flush_req();
283     btc_a2dp_control_set_datachnl_stat(FALSE);
284 }
285 
286 /*****************************************************************************
287 **
288 ** Function        btc_a2dp_on_suspended
289 **
290 *******************************************************************************/
291 
btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND * p_av)292 void btc_a2dp_sink_on_suspended(tBTA_AV_SUSPEND *p_av)
293 {
294     a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = TRUE;
295     btc_a2dp_sink_rx_flush_req();
296     return;
297 }
298 
btc_a2dp_sink_data_post(void)299 static void btc_a2dp_sink_data_post(void)
300 {
301     osi_thread_post(a2dp_sink_local_param.btc_aa_snk_task_hdl, btc_a2dp_sink_data_ready, NULL, 1, OSI_THREAD_MAX_TIMEOUT);
302 }
303 
304 /*******************************************************************************
305  **
306  ** Function         btc_a2dp_sink_clear_track
307  **
308  ** Description
309  **
310  ** Returns          TRUE is success
311  **
312  *******************************************************************************/
btc_a2dp_sink_clear_track(void)313 static BOOLEAN btc_a2dp_sink_clear_track(void)
314 {
315     return btc_a2dp_sink_ctrl(BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK, NULL);
316 }
317 
318 /* when true media task discards any rx frames */
btc_a2dp_sink_set_rx_flush(BOOLEAN enable)319 void btc_a2dp_sink_set_rx_flush(BOOLEAN enable)
320 {
321     APPL_TRACE_EVENT("## DROP RX %d ##\n", enable);
322     a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = enable;
323 }
324 
325 /*****************************************************************************
326 **
327 ** Function        btc_a2dp_sink_reset_decoder
328 **
329 ** Description
330 **
331 ** Returns
332 **
333 *******************************************************************************/
334 
btc_a2dp_sink_reset_decoder(UINT8 * p_av)335 void btc_a2dp_sink_reset_decoder(UINT8 *p_av)
336 {
337     APPL_TRACE_EVENT("btc reset decoder");
338     APPL_TRACE_DEBUG("btc reset decoder p_codec_info[%x:%x:%x:%x:%x:%x]\n",
339                      p_av[1], p_av[2], p_av[3],
340                      p_av[4], p_av[5], p_av[6]);
341 
342     tBTC_MEDIA_SINK_CFG_UPDATE *p_buf;
343     if (NULL == (p_buf = osi_malloc(sizeof(tBTC_MEDIA_SINK_CFG_UPDATE)))) {
344         APPL_TRACE_ERROR("btc reset decoder No Buffer ");
345         return;
346     }
347 
348     memcpy(p_buf->codec_info, p_av, AVDT_CODEC_SIZE);
349     btc_a2dp_sink_ctrl(BTC_MEDIA_AUDIO_SINK_CFG_UPDATE, p_buf);
350 }
351 
btc_a2dp_sink_data_ready(UNUSED_ATTR void * context)352 static void btc_a2dp_sink_data_ready(UNUSED_ATTR void *context)
353 {
354     tBT_SBC_HDR *p_msg;
355     int nb_of_msgs_to_process = 0;
356 
357     osi_sem_give(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem);
358     if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ)) {
359         APPL_TRACE_DEBUG("  QUE  EMPTY ");
360     } else {
361         if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) {
362             btc_a2dp_sink_flush_q(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
363             return;
364         }
365         nb_of_msgs_to_process = fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
366         APPL_TRACE_DEBUG("nb:%d", nb_of_msgs_to_process);
367         while (nb_of_msgs_to_process > 0) {
368             if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
369                 return;
370             }
371             p_msg = (tBT_SBC_HDR *)fixed_queue_dequeue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, 0);
372             if ( p_msg == NULL ) {
373                 APPL_TRACE_ERROR("Insufficient data in que ");
374                 break;
375             }
376             btc_a2dp_sink_handle_inc_media(p_msg);
377             osi_free(p_msg);
378             nb_of_msgs_to_process--;
379         }
380         APPL_TRACE_DEBUG(" Process Frames - ");
381     }
382 }
383 
384 /*******************************************************************************
385  **
386  ** Function         btc_a2dp_sink_handle_decoder_reset
387  **
388  ** Description
389  **
390  ** Returns          void
391  **
392  *******************************************************************************/
btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE * p_msg)393 static void btc_a2dp_sink_handle_decoder_reset(tBTC_MEDIA_SINK_CFG_UPDATE *p_msg)
394 {
395     tBTC_MEDIA_SINK_CFG_UPDATE *p_buf = p_msg;
396     tA2D_STATUS a2d_status;
397     tA2D_SBC_CIE sbc_cie;
398     OI_STATUS       status;
399     UINT32          freq_multiple = 48 * 20; /* frequency multiple for 20ms of data , initialize with 48K*/
400     UINT32          num_blocks = 16;
401     UINT32          num_subbands = 8;
402 
403     APPL_TRACE_EVENT("%s p_codec_info[%x:%x:%x:%x:%x:%x]\n", __FUNCTION__,
404                      p_buf->codec_info[1], p_buf->codec_info[2], p_buf->codec_info[3],
405                      p_buf->codec_info[4], p_buf->codec_info[5], p_buf->codec_info[6]);
406 
407     a2d_status = A2D_ParsSbcInfo(&sbc_cie, p_buf->codec_info, FALSE);
408     if (a2d_status != A2D_SUCCESS) {
409         APPL_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status);
410         return;
411     }
412 
413     a2dp_sink_local_param.btc_aa_snk_cb.sample_rate = btc_a2dp_sink_get_track_frequency(sbc_cie.samp_freq);
414     a2dp_sink_local_param.btc_aa_snk_cb.channel_count = btc_a2dp_sink_get_track_channel_count(sbc_cie.ch_mode);
415 
416     a2dp_sink_local_param.btc_aa_snk_cb.rx_flush = FALSE;
417     APPL_TRACE_EVENT("Reset to sink role");
418     status = OI_CODEC_SBC_DecoderReset(&a2dp_sink_local_param.context, a2dp_sink_local_param.contextData,
419                                         sizeof(a2dp_sink_local_param.contextData), 2, 2, FALSE, FALSE);
420     if (!OI_SUCCESS(status)) {
421         APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
422     }
423 
424     btc_a2dp_control_set_datachnl_stat(TRUE);
425 
426     switch (sbc_cie.samp_freq) {
427     case A2D_SBC_IE_SAMP_FREQ_16:
428         APPL_TRACE_DEBUG("\tsamp_freq:%d (16000)\n", sbc_cie.samp_freq);
429         freq_multiple = 16 * 20;
430         break;
431     case A2D_SBC_IE_SAMP_FREQ_32:
432         APPL_TRACE_DEBUG("\tsamp_freq:%d (32000)\n", sbc_cie.samp_freq);
433         freq_multiple = 32 * 20;
434         break;
435     case A2D_SBC_IE_SAMP_FREQ_44:
436         APPL_TRACE_DEBUG("\tsamp_freq:%d (44100)\n", sbc_cie.samp_freq);
437         freq_multiple = 441 * 2;
438         break;
439     case A2D_SBC_IE_SAMP_FREQ_48:
440         APPL_TRACE_DEBUG("\tsamp_freq:%d (48000)\n", sbc_cie.samp_freq);
441         freq_multiple = 48 * 20;
442         break;
443     default:
444         APPL_TRACE_DEBUG(" Unknown Frequency ");
445         break;
446     }
447 
448     switch (sbc_cie.ch_mode) {
449     case A2D_SBC_IE_CH_MD_MONO:
450         APPL_TRACE_DEBUG("\tch_mode:%d (Mono)\n", sbc_cie.ch_mode);
451         break;
452     case A2D_SBC_IE_CH_MD_DUAL:
453         APPL_TRACE_DEBUG("\tch_mode:%d (DUAL)\n", sbc_cie.ch_mode);
454         break;
455     case A2D_SBC_IE_CH_MD_STEREO:
456         APPL_TRACE_DEBUG("\tch_mode:%d (STEREO)\n", sbc_cie.ch_mode);
457         break;
458     case A2D_SBC_IE_CH_MD_JOINT:
459         APPL_TRACE_DEBUG("\tch_mode:%d (JOINT)\n", sbc_cie.ch_mode);
460         break;
461     default:
462         APPL_TRACE_DEBUG(" Unknown Mode ");
463         break;
464     }
465 
466     switch (sbc_cie.block_len) {
467     case A2D_SBC_IE_BLOCKS_4:
468         APPL_TRACE_DEBUG("\tblock_len:%d (4)\n", sbc_cie.block_len);
469         num_blocks = 4;
470         break;
471     case A2D_SBC_IE_BLOCKS_8:
472         APPL_TRACE_DEBUG("\tblock_len:%d (8)\n", sbc_cie.block_len);
473         num_blocks = 8;
474         break;
475     case A2D_SBC_IE_BLOCKS_12:
476         APPL_TRACE_DEBUG("\tblock_len:%d (12)\n", sbc_cie.block_len);
477         num_blocks = 12;
478         break;
479     case A2D_SBC_IE_BLOCKS_16:
480         APPL_TRACE_DEBUG("\tblock_len:%d (16)\n", sbc_cie.block_len);
481         num_blocks = 16;
482         break;
483     default:
484         APPL_TRACE_DEBUG(" Unknown BlockLen ");
485         break;
486     }
487 
488     switch (sbc_cie.num_subbands) {
489     case A2D_SBC_IE_SUBBAND_4:
490         APPL_TRACE_DEBUG("\tnum_subbands:%d (4)\n", sbc_cie.num_subbands);
491         num_subbands = 4;
492         break;
493     case A2D_SBC_IE_SUBBAND_8:
494         APPL_TRACE_DEBUG("\tnum_subbands:%d (8)\n", sbc_cie.num_subbands);
495         num_subbands = 8;
496         break;
497     default:
498         APPL_TRACE_DEBUG(" Unknown SubBands ");
499         break;
500     }
501 
502     switch (sbc_cie.alloc_mthd) {
503     case A2D_SBC_IE_ALLOC_MD_S:
504         APPL_TRACE_DEBUG("\talloc_mthd:%d (SNR)\n", sbc_cie.alloc_mthd);
505         break;
506     case A2D_SBC_IE_ALLOC_MD_L:
507         APPL_TRACE_DEBUG("\talloc_mthd:%d (Loudness)\n", sbc_cie.alloc_mthd);
508         break;
509     default:
510         APPL_TRACE_DEBUG(" Unknown Allocation Method");
511         break;
512     }
513 
514     APPL_TRACE_EVENT("\tBit pool Min:%d Max:%d\n", sbc_cie.min_bitpool, sbc_cie.max_bitpool);
515 
516     int frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1;
517     APPL_TRACE_EVENT(" Frames to be processed in 20 ms %d\n", frames_to_process);
518     UNUSED(frames_to_process);
519 }
520 
521 /*******************************************************************************
522  **
523  ** Function         btc_a2dp_sink_handle_inc_media
524  **
525  ** Description
526  **
527  ** Returns          void
528  **
529  *******************************************************************************/
btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR * p_msg)530 static void btc_a2dp_sink_handle_inc_media(tBT_SBC_HDR *p_msg)
531 {
532     UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1);
533     int count;
534     UINT32 pcmBytes, availPcmBytes;
535     OI_INT16 *pcmDataPointer = a2dp_sink_local_param.pcmData; /*Will be overwritten on next packet receipt*/
536     OI_STATUS status;
537     int num_sbc_frames = p_msg->num_frames_to_be_processed;
538     UINT32 sbc_frame_len = p_msg->len - 1;
539     availPcmBytes = sizeof(a2dp_sink_local_param.pcmData);
540 
541     /* XXX: Check if the below check is correct, we are checking for peer to be sink when we are sink */
542     if (btc_av_get_peer_sep() == AVDT_TSEP_SNK || (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush)) {
543         APPL_TRACE_DEBUG(" State Changed happened in this tick ");
544         return;
545     }
546 
547     // ignore data if no one is listening
548     if (!btc_a2dp_control_get_datachnl_stat()) {
549         return;
550     }
551 
552     APPL_TRACE_DEBUG("Number of sbc frames %d, frame_len %d\n", num_sbc_frames, sbc_frame_len);
553 
554     for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) {
555         pcmBytes = availPcmBytes;
556         status = OI_CODEC_SBC_DecodeFrame(&a2dp_sink_local_param.context, (const OI_BYTE **)&sbc_start_frame,
557                                           (OI_UINT32 *)&sbc_frame_len,
558                                           (OI_INT16 *)pcmDataPointer,
559                                           (OI_UINT32 *)&pcmBytes);
560         if (!OI_SUCCESS(status)) {
561             APPL_TRACE_ERROR("Decoding failure: %d\n", status);
562             break;
563         }
564         availPcmBytes -= pcmBytes;
565         pcmDataPointer += pcmBytes / 2;
566         p_msg->offset += (p_msg->len - 1) - sbc_frame_len;
567         p_msg->len = sbc_frame_len + 1;
568     }
569 
570     btc_a2d_data_cb_to_app((uint8_t *)a2dp_sink_local_param.pcmData, (sizeof(a2dp_sink_local_param.pcmData) - availPcmBytes));
571 }
572 
573 /*******************************************************************************
574  **
575  ** Function         btc_a2dp_sink_rx_flush_req
576  **
577  ** Description
578  **
579  ** Returns          TRUE is success
580  **
581  *******************************************************************************/
btc_a2dp_sink_rx_flush_req(void)582 BOOLEAN btc_a2dp_sink_rx_flush_req(void)
583 {
584     if (fixed_queue_is_empty(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) == TRUE) { /*  Que is already empty */
585         return TRUE;
586     }
587 
588     return btc_a2dp_sink_ctrl(BTC_MEDIA_FLUSH_AA_RX, NULL);
589 }
590 
591 /*******************************************************************************
592  **
593  ** Function         btc_a2dp_sink_rx_flush
594  **
595  ** Description
596  **
597  ** Returns          void
598  **
599  *******************************************************************************/
btc_a2dp_sink_rx_flush(void)600 static void btc_a2dp_sink_rx_flush(void)
601 {
602     /* Flush all enqueued SBC  buffers (encoded) */
603     APPL_TRACE_DEBUG("btc_a2dp_sink_rx_flush");
604 
605     btc_a2dp_sink_flush_q(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
606 }
607 
btc_a2dp_sink_get_track_frequency(UINT8 frequency)608 static int btc_a2dp_sink_get_track_frequency(UINT8 frequency)
609 {
610     int freq = 48000;
611     switch (frequency) {
612     case A2D_SBC_IE_SAMP_FREQ_16:
613         freq = 16000;
614         break;
615     case A2D_SBC_IE_SAMP_FREQ_32:
616         freq = 32000;
617         break;
618     case A2D_SBC_IE_SAMP_FREQ_44:
619         freq = 44100;
620         break;
621     case A2D_SBC_IE_SAMP_FREQ_48:
622         freq = 48000;
623         break;
624     }
625     return freq;
626 }
627 
btc_a2dp_sink_get_track_channel_count(UINT8 channeltype)628 static int btc_a2dp_sink_get_track_channel_count(UINT8 channeltype)
629 {
630     int count = 1;
631     switch (channeltype) {
632     case A2D_SBC_IE_CH_MD_MONO:
633         count = 1;
634         break;
635     case A2D_SBC_IE_CH_MD_DUAL:
636     case A2D_SBC_IE_CH_MD_STEREO:
637     case A2D_SBC_IE_CH_MD_JOINT:
638         count = 2;
639         break;
640     }
641     return count;
642 }
643 
644 /*******************************************************************************
645  **
646  ** Function         btc_a2dp_sink_enque_buf
647  **
648  ** Description      This function is called by the av_co to fill A2DP Sink Queue
649  **
650  **
651  ** Returns          size of the queue
652  *******************************************************************************/
btc_a2dp_sink_enque_buf(BT_HDR * p_pkt)653 UINT8 btc_a2dp_sink_enque_buf(BT_HDR *p_pkt)
654 {
655     tBT_SBC_HDR *p_msg;
656 
657     if (btc_a2dp_sink_state != BTC_A2DP_SINK_STATE_ON){
658         return 0;
659     }
660 
661     if (a2dp_sink_local_param.btc_aa_snk_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/
662         return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
663     }
664 
665     if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) >= MAX_OUTPUT_A2DP_SNK_FRAME_QUEUE_SZ) {
666         APPL_TRACE_WARNING("Pkt dropped\n");
667         return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
668     }
669 
670     APPL_TRACE_DEBUG("btc_a2dp_sink_enque_buf + ");
671 
672     /* allocate and Queue this buffer */
673     if ((p_msg = (tBT_SBC_HDR *) osi_malloc(sizeof(tBT_SBC_HDR) +
674                                             p_pkt->offset + p_pkt->len)) != NULL) {
675         memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len));
676         p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f;
677         APPL_TRACE_VERBOSE("btc_a2dp_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed);
678         fixed_queue_enqueue(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, p_msg, FIXED_QUEUE_MAX_TIMEOUT);
679         if (fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ) >= JITTER_BUFFER_WATER_LEVEL) {
680             if (osi_sem_take(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem, 0) == 0) {
681                 btc_a2dp_sink_data_post();
682             }
683         }
684     } else {
685         /* let caller deal with a failed allocation */
686         APPL_TRACE_WARNING("btc_a2dp_sink_enque_buf No Buffer left - ");
687     }
688     return fixed_queue_length(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ);
689 }
690 
btc_a2dp_sink_handle_clear_track(void)691 static void btc_a2dp_sink_handle_clear_track (void)
692 {
693     APPL_TRACE_DEBUG("%s", __FUNCTION__);
694 }
695 
696 /*******************************************************************************
697  **
698  ** Function         btc_a2dp_sink_flush_q
699  **
700  ** Description
701  **
702  ** Returns          void
703  **
704  *******************************************************************************/
btc_a2dp_sink_flush_q(fixed_queue_t * p_q)705 static void btc_a2dp_sink_flush_q(fixed_queue_t *p_q)
706 {
707     while (! fixed_queue_is_empty(p_q)) {
708         osi_free(fixed_queue_dequeue(p_q, 0));
709     }
710 }
711 
btc_a2dp_sink_thread_init(UNUSED_ATTR void * context)712 static void btc_a2dp_sink_thread_init(UNUSED_ATTR void *context)
713 {
714     APPL_TRACE_EVENT("%s\n", __func__);
715     memset(&a2dp_sink_local_param.btc_aa_snk_cb, 0, sizeof(a2dp_sink_local_param.btc_aa_snk_cb));
716 
717     btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_ON;
718     if (!a2dp_sink_local_param.btc_aa_snk_cb.post_sem) {
719         osi_sem_new(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem, 1, 1);
720     }
721     a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = fixed_queue_new(QUEUE_SIZE_MAX);
722 
723     btc_a2dp_control_init();
724 }
725 
btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void * context)726 static void btc_a2dp_sink_thread_cleanup(UNUSED_ATTR void *context)
727 {
728     btc_a2dp_control_set_datachnl_stat(FALSE);
729     /* Clear task flag */
730     btc_a2dp_sink_state = BTC_A2DP_SINK_STATE_OFF;
731 
732     btc_a2dp_control_cleanup();
733 
734     fixed_queue_free(a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ, osi_free_func);
735 
736     a2dp_sink_local_param.btc_aa_snk_cb.RxSbcQ = NULL;
737 
738     if (a2dp_sink_local_param.btc_aa_snk_cb.post_sem) {
739         osi_sem_free(&a2dp_sink_local_param.btc_aa_snk_cb.post_sem);
740         a2dp_sink_local_param.btc_aa_snk_cb.post_sem = NULL;
741     }
742 }
743 
744 #endif /* BTC_AV_SINK_INCLUDED */
745