OSDN Git Service

implement flow control to avoid dropping packets in btif_media_task.
authorZhihai Xu <zhihaixu@google.com>
Thu, 19 Sep 2013 18:30:44 +0000 (11:30 -0700)
committerZhihai Xu <zhihaixu@google.com>
Mon, 16 Dec 2013 21:23:01 +0000 (13:23 -0800)
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

btif/src/btif_media_task.c

index 3649f77..d4d85f2 100755 (executable)
@@ -177,8 +177,11 @@ static UINT32 a2dp_media_task_stack[(A2DP_MEDIA_TASK_STACK_SIZE + 3) / 4];
    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 @@ typedef struct
     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_uipc_cback(BT_HDR *p_msg)
  *******************************************************************************/
 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 void btif_media_task_aa_stop_tx(void)
  *******************************************************************************/
 static UINT8 btif_get_num_aa_frame(void)
 {
-    UINT8 result=0;
+    UINT32 result=0;
 
     switch (btif_media_cb.TxTranscoding)
     {
@@ -1868,11 +1880,24 @@ static UINT8 btif_get_num_aa_frame(void)
 
             btif_media_cb.media_feeding_state.pcm.counter +=
                                 btif_media_cb.media_feeding_state.pcm.bytes_per_tick;
-
-            /* 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.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;
+
+                    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 @@ static UINT8 btif_get_num_aa_frame(void)
     APPL_TRACE_DEBUG1("btif_get_num_aa_frame returns %d", result);
 #endif
 
-    return result;
+    return (UINT8)result;
 }
 
 /*******************************************************************************
@@ -2185,6 +2210,32 @@ static void btif_media_aa_prep_sbc_2_send(UINT8 nb_frame)
         {
             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 @@ static void btif_media_aa_prep_2_send(UINT8 nb_frame)
     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 @@ static void btif_media_send_aa_frame(void)
     /* 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);