Adding a send side API for streaming

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3457 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/video_engine/include/vie_rtp_rtcp.h b/webrtc/video_engine/include/vie_rtp_rtcp.h
index 73b444a..83b6f57 100644
--- a/webrtc/video_engine/include/vie_rtp_rtcp.h
+++ b/webrtc/video_engine/include/vie_rtp_rtcp.h
@@ -22,7 +22,7 @@
 #ifndef WEBRTC_VIDEO_ENGINE_INCLUDE_VIE_RTP_RTCP_H_
 #define WEBRTC_VIDEO_ENGINE_INCLUDE_VIE_RTP_RTCP_H_
 
-#include "common_types.h"
+#include "webrtc/common_types.h"
 
 namespace webrtc {
 
@@ -199,6 +199,12 @@
                                      const unsigned char payload_typeRED,
                                      const unsigned char payload_typeFEC) = 0;
 
+  // Enables send side support for delayed video streaming (actual delay will
+  // be exhibited on the receiver side).
+  // Target delay should be set to zero for real-time mode.
+  virtual int EnableSenderStreamingMode(int video_channel,
+                                        int target_delay_ms) = 0;
+
   // This function enables RTCP key frame requests.
   virtual int SetKeyFrameRequestMethod(
     const int video_channel, const ViEKeyFrameRequestMethod method) = 0;
diff --git a/webrtc/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc b/webrtc/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc
index d8bf8aa..64d5c2d 100644
--- a/webrtc/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc
+++ b/webrtc/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc
@@ -687,6 +687,21 @@
     EXPECT_EQ(0, ViE.rtp_rtcp->SetTransmissionSmoothingStatus(
         tbChannel.videoChannel, false));
 
+    // Streaming Mode.
+    EXPECT_EQ(-1, ViE.rtp_rtcp->EnableSenderStreamingMode(
+        invalid_channel_id, 0));
+    int invalid_delay = -1;
+    EXPECT_EQ(-1, ViE.rtp_rtcp->EnableSenderStreamingMode(
+        tbChannel.videoChannel, invalid_delay));
+    invalid_delay = 15000;
+    EXPECT_EQ(-1, ViE.rtp_rtcp->EnableSenderStreamingMode(
+        tbChannel.videoChannel, invalid_delay));
+    EXPECT_EQ(0, ViE.rtp_rtcp->EnableSenderStreamingMode(
+        tbChannel.videoChannel, 5000));
+    // Real-time mode.
+    EXPECT_EQ(0, ViE.rtp_rtcp->EnableSenderStreamingMode(
+        tbChannel.videoChannel, 0));
+
     //***************************************************************
     //  Testing finished. Tear down Video Engine
     //***************************************************************
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index 0c13709..b3e1b7e 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -35,6 +35,7 @@
 
 const int kMaxDecodeWaitTimeMs = 50;
 const int kInvalidRtpExtensionId = 0;
+static const int kMaxTargetDelayMs = 10000;
 
 // Helper class receiving statistics callbacks.
 class ChannelStatsObserver : public StatsObserver {
@@ -102,7 +103,8 @@
       color_enhancement_(false),
       file_recorder_(channel_id),
       mtu_(0),
-      sender_(sender) {
+      sender_(sender),
+      nack_history_size_sender_(kSendSidePacketHistorySize) {
   WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id, channel_id),
                "ViEChannel::ViEChannel(channel_id: %d, engine_id: %d)",
                channel_id, engine_id);
@@ -151,7 +153,7 @@
                  "%s: RTP::SetRTCPStatus failure", __FUNCTION__);
   }
   if (paced_sender_) {
-    if (rtp_rtcp_->SetStorePacketsStatus(true, kSendSidePacketHistorySize) !=
+    if (rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_) !=
         0) {
       WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
                    "%s:SetStorePacketsStatus failure", __FUNCTION__);
@@ -295,10 +297,10 @@
                      "%s: RTP::SetRTCPStatus failure", __FUNCTION__);
       }
       if (nack_method != kNackOff) {
-        rtp_rtcp->SetStorePacketsStatus(true, kSendSidePacketHistorySize);
+        rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_);
         rtp_rtcp->SetNACKStatus(nack_method, kMaxPacketAgeToNack);
       } else if (paced_sender_) {
-        rtp_rtcp->SetStorePacketsStatus(true, kSendSidePacketHistorySize);
+        rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_);
       }
       if (fec_enabled) {
         rtp_rtcp->SetGenericFECStatus(fec_enabled, payload_type_red,
@@ -628,7 +630,7 @@
     }
     WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
                  "%s: Using NACK method %d", __FUNCTION__, nackMethod);
-    rtp_rtcp_->SetStorePacketsStatus(true, kSendSidePacketHistorySize);
+    rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_);
 
     vcm_.RegisterPacketRequestCallback(this);
 
@@ -639,7 +641,7 @@
          it++) {
       RtpRtcp* rtp_rtcp = *it;
       rtp_rtcp->SetNACKStatus(nackMethod, kMaxPacketAgeToNack);
-      rtp_rtcp->SetStorePacketsStatus(true, kSendSidePacketHistorySize);
+      rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_);
     }
   } else {
     CriticalSectionScoped cs(rtp_rtcp_cs_.get());
@@ -721,6 +723,45 @@
   return ProcessFECRequest(enable, payload_typeRED, payload_typeFEC);
 }
 
+int ViEChannel::EnableSenderStreamingMode(int target_delay_ms) {
+  if ((target_delay_ms < 0) || (target_delay_ms > kMaxTargetDelayMs)) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
+                 "%s: Target streaming delay out of bounds: %d", __FUNCTION__,
+                 target_delay_ms);
+    return -1;
+  }
+  if (target_delay_ms == 0) {
+    // Real-time mode.
+    nack_history_size_sender_ = kSendSidePacketHistorySize;
+    vcm_.EnableFrameDropper(true);
+  } else {
+    // The max size of the nack list should be large enough to accommodate the
+    // the number of packets(frames) resulting from the increased delay.
+    // Roughly estimating for ~15 packets per frame @ 30fps.
+    nack_history_size_sender_ = target_delay_ms * 15 * 30 / 1000;
+    // Don't allow a number lower than the default value.
+    if (nack_history_size_sender_ < kSendSidePacketHistorySize) {
+      nack_history_size_sender_ = kSendSidePacketHistorySize;
+    }
+    // Disable external VCM frame-dropper. In streaming mode, we are more
+    // flexible with rate control constraints.
+    vcm_.EnableFrameDropper(false);
+  }
+  // Setting nack_history_size_.
+  // First disabling (forcing free) and then resetting to desired value.
+  if (rtp_rtcp_->SetStorePacketsStatus(false, 0) != 0) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
+                 "%s:SetStorePacketsStatus failure", __FUNCTION__);
+    return -1;
+  }
+  if (rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_) != 0) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
+                 "%s:SetStorePacketsStatus failure", __FUNCTION__);
+    return -1;
+  }
+  return 0;
+}
+
 WebRtc_Word32 ViEChannel::SetKeyFrameRequestMethod(
     const KeyFrameRequestMethod method) {
   WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index 4ff77f5..5eec802 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -116,6 +116,7 @@
   WebRtc_Word32 SetHybridNACKFECStatus(const bool enable,
                                        const unsigned char payload_typeRED,
                                        const unsigned char payload_typeFEC);
+  int EnableSenderStreamingMode(int target_delay_ms);
   WebRtc_Word32 SetKeyFrameRequestMethod(const KeyFrameRequestMethod method);
   bool EnableRemb(bool enable);
   int SetSendTimestampOffsetStatus(bool enable, int id);
@@ -422,6 +423,8 @@
   // User set MTU, -1 if not set.
   uint16_t mtu_;
   const bool sender_;
+
+  int nack_history_size_sender_;
 };
 
 }  // namespace webrtc
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
index 0c047d7..7bd6f6d 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
@@ -553,6 +553,33 @@
   return 0;
 }
 
+int ViERTP_RTCPImpl::EnableSenderStreamingMode(int video_channel,
+                                               int target_delay_ms) {
+  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
+               ViEId(shared_data_->instance_id(), video_channel),
+               "%s(channel: %d, target_delay: %d)",
+               __FUNCTION__, video_channel, target_delay_ms);
+  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+  ViEChannel* vie_channel = cs.Channel(video_channel);
+  if (!vie_channel) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo,
+                 ViEId(shared_data_->instance_id(), video_channel),
+                 "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
+    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
+    return -1;
+  }
+
+  // Update the channel's streaming mode settings.
+  if (vie_channel->EnableSenderStreamingMode(target_delay_ms) != 0) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo,
+                 ViEId(shared_data_->instance_id(), video_channel),
+                 "%s: failed for channel %d", __FUNCTION__, video_channel);
+    shared_data_->SetLastError(kViERtpRtcpUnknownError);
+    return -1;
+  }
+  return 0;
+}
+
 int ViERTP_RTCPImpl::SetKeyFrameRequestMethod(
   const int video_channel,
   const ViEKeyFrameRequestMethod method) {
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.h b/webrtc/video_engine/vie_rtp_rtcp_impl.h
index 577e085..210afcf 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.h
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.h
@@ -64,6 +64,8 @@
   virtual int SetHybridNACKFECStatus(const int video_channel, const bool enable,
                                      const unsigned char payload_typeRED,
                                      const unsigned char payload_typeFEC);
+  virtual int EnableSenderStreamingMode(int video_channel,
+                                        int target_delay_ms);
   virtual int SetKeyFrameRequestMethod(const int video_channel,
                                        const ViEKeyFrameRequestMethod method);
   virtual int SetTMMBRStatus(const int video_channel, const bool enable);