implement flow control to avoid dropping packets in btif_media_task.
implment flow conrol to save CPU usage and avoid dropping
packet in btif_media_task when overflow and cpu preemption happen.
when the packet count in the queue is above high watermark, we will
stopping adding packets, when the packet count in the queue is below
low watermark, we will start adding packets again.
bug:8252054
Change-Id: I3b7795dffbe5f2ae455e239a0234533f6cbb4403
diff --git a/btif/src/btif_media_task.c b/btif/src/btif_media_task.c
index 3649f77..d4d85f2 100755
--- a/btif/src/btif_media_task.c
+++ b/btif/src/btif_media_task.c
@@ -177,8 +177,11 @@
but due to link flow control or thread preemption in lower
layers we might need to temporarily buffer up data */
-/* 24 frames is equivalent to 6.89*24*2.9 ~= 480 ms @ 44.1 khz, 20 ms mediatick */
-#define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ 24
+/* 18 frames is equivalent to 6.89*18*2.9 ~= 360 ms @ 44.1 khz, 20 ms mediatick */
+#define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ 18
+#define A2DP_PACKET_COUNT_LOW_WATERMARK 5
+#define MAX_PCM_FRAME_NUM_PER_TICK 40
+#define RESET_RATE_COUNTER_THRESHOLD_MS 2000
//#define BTIF_MEDIA_VERBOSE_ENABLED
@@ -201,6 +204,10 @@
INT32 aa_feed_residue;
UINT32 counter;
UINT32 bytes_per_tick; /* pcm bytes read each media task tick */
+ UINT32 max_counter_exit;
+ UINT32 max_counter_enter;
+ UINT32 overflow_count;
+ BOOLEAN overflow;
} tBTIF_AV_MEDIA_FEEDINGS_PCM_STATE;
@@ -1775,6 +1782,11 @@
*******************************************************************************/
static void btif_media_task_feeding_state_reset(void)
{
+ APPL_TRACE_WARNING3("overflow %d, enter %d, exit %d",
+ btif_media_cb.media_feeding_state.pcm.overflow_count,
+ btif_media_cb.media_feeding_state.pcm.max_counter_enter,
+ btif_media_cb.media_feeding_state.pcm.max_counter_exit);
+
/* By default, just clear the entire state */
memset(&btif_media_cb.media_feeding_state, 0, sizeof(btif_media_cb.media_feeding_state));
@@ -1855,7 +1867,7 @@
*******************************************************************************/
static UINT8 btif_get_num_aa_frame(void)
{
- UINT8 result=0;
+ UINT32 result=0;
switch (btif_media_cb.TxTranscoding)
{
@@ -1868,11 +1880,24 @@
btif_media_cb.media_feeding_state.pcm.counter +=
btif_media_cb.media_feeding_state.pcm.bytes_per_tick;
+ if ((!btif_media_cb.media_feeding_state.pcm.overflow) ||
+ (btif_media_cb.TxAaQ.count < A2DP_PACKET_COUNT_LOW_WATERMARK)) {
+ if (btif_media_cb.media_feeding_state.pcm.overflow) {
+ btif_media_cb.media_feeding_state.pcm.overflow = FALSE;
- /* calculate nbr of frames pending for this media tick */
- result = btif_media_cb.media_feeding_state.pcm.counter/pcm_bytes_per_frame;
- btif_media_cb.media_feeding_state.pcm.counter -= result*pcm_bytes_per_frame;
-
+ if (btif_media_cb.media_feeding_state.pcm.counter >
+ btif_media_cb.media_feeding_state.pcm.max_counter_exit) {
+ btif_media_cb.media_feeding_state.pcm.max_counter_exit =
+ btif_media_cb.media_feeding_state.pcm.counter;
+ }
+ }
+ /* calculate nbr of frames pending for this media tick */
+ result = btif_media_cb.media_feeding_state.pcm.counter/pcm_bytes_per_frame;
+ if (result > MAX_PCM_FRAME_NUM_PER_TICK) result = MAX_PCM_FRAME_NUM_PER_TICK;
+ btif_media_cb.media_feeding_state.pcm.counter -= result*pcm_bytes_per_frame;
+ } else {
+ result = 0;
+ }
VERBOSE("WRITE %d FRAMES", result);
}
break;
@@ -1888,7 +1913,7 @@
APPL_TRACE_DEBUG1("btif_get_num_aa_frame returns %d", result);
#endif
- return result;
+ return (UINT8)result;
}
/*******************************************************************************
@@ -2185,6 +2210,32 @@
{
GKI_freebuf(p_buf);
}
+
+ if (btif_media_cb.TxAaQ.count >= MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) {
+ UINT32 reset_rate_bytes = btif_media_cb.media_feeding_state.pcm.bytes_per_tick *
+ (RESET_RATE_COUNTER_THRESHOLD_MS / BTIF_MEDIA_TIME_TICK);
+ btif_media_cb.media_feeding_state.pcm.overflow = TRUE;
+ btif_media_cb.media_feeding_state.pcm.counter += nb_frame *
+ btif_media_cb.encoder.s16NumOfSubBands *
+ btif_media_cb.encoder.s16NumOfBlocks *
+ btif_media_cb.media_feeding.cfg.pcm.num_channel *
+ btif_media_cb.media_feeding.cfg.pcm.bit_per_sample / 8;
+
+ btif_media_cb.media_feeding_state.pcm.overflow_count++;
+ if (btif_media_cb.media_feeding_state.pcm.counter >
+ btif_media_cb.media_feeding_state.pcm.max_counter_enter) {
+ btif_media_cb.media_feeding_state.pcm.max_counter_enter =
+ btif_media_cb.media_feeding_state.pcm.counter;
+ }
+
+ if (btif_media_cb.media_feeding_state.pcm.counter > reset_rate_bytes) {
+ btif_media_cb.media_feeding_state.pcm.counter = 0;
+ APPL_TRACE_WARNING0("btif_media_aa_prep_sbc_2_send:reset rate counter");
+ }
+
+ /* no more pcm to read */
+ nb_frame = 0;
+ }
}
}
@@ -2204,13 +2255,6 @@
VERBOSE("btif_media_aa_prep_2_send : %d frames (queue %d)", nb_frame,
btif_media_cb.TxAaQ.count);
- while (btif_media_cb.TxAaQ.count >= MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ)
- {
- APPL_TRACE_WARNING1("btif_media_aa_prep_2_send congestion buf count %d",
- btif_media_cb.TxAaQ.count);
- GKI_freebuf(GKI_dequeue(&(btif_media_cb.TxAaQ)));
- }
-
switch (btif_media_cb.TxTranscoding)
{
case BTIF_MEDIA_TRSCD_PCM_2_SBC:
@@ -2240,8 +2284,10 @@
/* get the number of frame to send */
nb_frame_2_send = btif_get_num_aa_frame();
- /* format and Q buffer to send */
- btif_media_aa_prep_2_send(nb_frame_2_send);
+ if (nb_frame_2_send != 0) {
+ /* format and Q buffer to send */
+ btif_media_aa_prep_2_send(nb_frame_2_send);
+ }
/* send it */
VERBOSE("btif_media_send_aa_frame : send %d frames", nb_frame_2_send);