API to control target delay in NetEq jitter buffer. NetEq maintains the given delay unless channel conditions require a higher delay.

TEST=unit-test, manual, trybots.
R=henrik.lundin@webrtc.org, henrika@webrtc.org, mflodman@webrtc.org, mikhal@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/1384005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4087 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_coding/neteq/automode.c b/webrtc/modules/audio_coding/neteq/automode.c
index edee98e..ea6fa8d 100644
--- a/webrtc/modules/audio_coding/neteq/automode.c
+++ b/webrtc/modules/audio_coding/neteq/automode.c
@@ -216,6 +216,14 @@
             streamingMode);
         if (tempvar > 0)
         {
+            int high_lim_delay;
+            /* Convert the minimum delay from milliseconds to packets in Q8.
+             * |fsHz| is sampling rate in Hertz, and |inst->packetSpeechLenSamp|
+             * is the number of samples per packet (according to the last
+             * decoding).
+             */
+            int32_t minimum_delay_q8 = ((inst->minimum_delay_ms *
+                (fsHz / 1000)) << 8) / inst->packetSpeechLenSamp;
             inst->optBufLevel = tempvar;
 
             if (streamingMode != 0)
@@ -224,6 +232,13 @@
                     inst->maxCSumIatQ8);
             }
 
+            /* The required delay. */
+            inst->required_delay_q8 = inst->optBufLevel;
+
+            // Maintain the target delay.
+            inst->optBufLevel = WEBRTC_SPL_MAX(inst->optBufLevel,
+                                               minimum_delay_q8);
+
             /*********/
             /* Limit */
             /*********/
@@ -238,8 +253,12 @@
             maxBufLen = WEBRTC_SPL_LSHIFT_W32(maxBufLen, 8); /* shift to Q8 */
 
             /* Enforce upper limit; 75% of maxBufLen */
-            inst->optBufLevel = WEBRTC_SPL_MIN( inst->optBufLevel,
-                (maxBufLen >> 1) + (maxBufLen >> 2) ); /* 1/2 + 1/4 = 75% */
+            /* 1/2 + 1/4 = 75% */
+            high_lim_delay = (maxBufLen >> 1) + (maxBufLen >> 2);
+            inst->optBufLevel = WEBRTC_SPL_MIN(inst->optBufLevel,
+                                               high_lim_delay);
+            inst->required_delay_q8 = WEBRTC_SPL_MIN(inst->required_delay_q8,
+                                                     high_lim_delay);
         }
         else
         {
@@ -700,6 +719,7 @@
      */
     inst->optBufLevel = WEBRTC_SPL_MIN(4,
         (maxBufLenPackets >> 1) + (maxBufLenPackets >> 1)); /* 75% of maxBufLenPackets */
+    inst->required_delay_q8 = inst->optBufLevel;
     inst->levelFiltFact = 253;
 
     /*
diff --git a/webrtc/modules/audio_coding/neteq/automode.h b/webrtc/modules/audio_coding/neteq/automode.h
index 5996a51..49878c0 100644
--- a/webrtc/modules/audio_coding/neteq/automode.h
+++ b/webrtc/modules/audio_coding/neteq/automode.h
@@ -89,6 +89,12 @@
      reached 0 */
     int16_t extraDelayMs; /* extra delay for sync with video */
 
+    int minimum_delay_ms; /* Desired delay, NetEq maintains this amount of
+     delay unless jitter statistics suggests a higher value. */
+    int required_delay_q8; /* Smallest delay required. This is computed
+     according to inter-arrival time and playout mode. It has the same unit
+     as |optBufLevel|. */
+
     /* Peak-detection */
     /* vector with the latest peak periods (peak spacing in samples) */
     uint32_t peakPeriodSamp[NUM_PEAKS];
diff --git a/webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_internal.h b/webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_internal.h
index 4eefce0..021704c 100644
--- a/webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_internal.h
+++ b/webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_internal.h
@@ -309,6 +309,19 @@
                              WebRtcNetEQ_RTPInfo* rtp_info,
                              uint32_t receive_timestamp);
 
+/*
+ * Set a minimum latency for the jitter buffer. The overall delay is the max of
+ * |minimum_delay_ms| and the latency that is internally computed based on the
+ * inter-arrival times.
+ */
+int WebRtcNetEQ_SetMinimumDelay(void *inst, int minimum_delay_ms);
+
+/*
+ * Get the least required delay in milliseconds given inter-arrival times
+ * and playout mode.
+ */
+int WebRtcNetEQ_GetRequiredDelayMs(const void* inst);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/webrtc/modules/audio_coding/neteq/mcu_reset.c b/webrtc/modules/audio_coding/neteq/mcu_reset.c
index 3aae4ce..c8a4cd7 100644
--- a/webrtc/modules/audio_coding/neteq/mcu_reset.c
+++ b/webrtc/modules/audio_coding/neteq/mcu_reset.c
@@ -32,7 +32,9 @@
     inst->main_inst = NULL;
     inst->one_desc = 0;
     inst->BufferStat_inst.Automode_inst.extraDelayMs = 0;
+    inst->BufferStat_inst.Automode_inst.minimum_delay_ms = 0;
     inst->NetEqPlayoutMode = kPlayoutOn;
+    inst->av_sync = 0;
 
     WebRtcNetEQ_DbReset(&inst->codec_DB_inst);
     memset(&inst->PayloadSplit_inst, 0, sizeof(SplitInfo_t));
diff --git a/webrtc/modules/audio_coding/neteq/webrtc_neteq.c b/webrtc/modules/audio_coding/neteq/webrtc_neteq.c
index 31940c8..8347925 100644
--- a/webrtc/modules/audio_coding/neteq/webrtc_neteq.c
+++ b/webrtc/modules/audio_coding/neteq/webrtc_neteq.c
@@ -437,6 +437,7 @@
     NetEqMainInst->MCUinst.first_packet = 1;
     NetEqMainInst->MCUinst.one_desc = 0;
     NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.extraDelayMs = 0;
+    NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.minimum_delay_ms = 0;
     NetEqMainInst->MCUinst.NoOfExpandCalls = 0;
     NetEqMainInst->MCUinst.fs = fs;
 
@@ -529,6 +530,19 @@
     return (0);
 }
 
+int WebRtcNetEQ_SetMinimumDelay(void *inst, int minimum_delay_ms) {
+  MainInst_t *NetEqMainInst = (MainInst_t*) inst;
+  if (NetEqMainInst == NULL)
+    return -1;
+  if (minimum_delay_ms < 0 || minimum_delay_ms > 10000) {
+      NetEqMainInst->ErrorCode = -FAULTY_DELAYVALUE;
+      return -1;
+  }
+  NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst.minimum_delay_ms =
+      minimum_delay_ms;
+  return 0;
+}
+
 int WebRtcNetEQ_SetPlayoutMode(void *inst, enum WebRtcNetEQPlayoutMode playoutMode)
 {
     MainInst_t *NetEqMainInst = (MainInst_t*) inst;
@@ -1213,7 +1227,7 @@
     /* Get optimal buffer size */
     /***************************/
 
-    if (NetEqMainInst->MCUinst.fs != 0 && NetEqMainInst->MCUinst.fs <= WEBRTC_SPL_WORD16_MAX)
+    if (NetEqMainInst->MCUinst.fs != 0)
     {
         /* preferredBufferSize = Bopt * packSizeSamples / (fs/1000) */
         stats->preferredBufferSize
@@ -1693,3 +1707,25 @@
   }
   return SYNC_PAYLOAD_LEN_BYTES;
 }
+
+int WebRtcNetEQ_GetRequiredDelayMs(const void* inst) {
+  const MainInst_t* NetEqMainInst = (MainInst_t*)inst;
+  const AutomodeInst_t* auto_mode = (NetEqMainInst == NULL) ? NULL :
+      &NetEqMainInst->MCUinst.BufferStat_inst.Automode_inst;
+
+  /* Instance sanity */
+  if (NetEqMainInst == NULL || auto_mode == NULL)
+    return 0;
+
+  if (NetEqMainInst->MCUinst.fs == 0)
+    return 0;  // Sampling rate not initialized.
+
+  /* |required_delay_q8| has the unit of packets in Q8 domain, therefore,
+   * the corresponding delay is
+   * required_delay_ms = (1000 * required_delay_q8 * samples_per_packet /
+   *     sample_rate_hz) / 256;
+   */
+  return (auto_mode->required_delay_q8 *
+      ((auto_mode->packetSpeechLenSamp * 1000) / NetEqMainInst->MCUinst.fs) +
+      128) >> 8;
+}