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