Implements start bitrate for new video API.

Added  a new rampup test.

BUG=2879
R=pbos@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6443 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/call.h b/call.h
index 1771ad8..480d73e 100644
--- a/call.h
+++ b/call.h
@@ -61,7 +61,8 @@
         : webrtc_config(NULL),
           send_transport(send_transport),
           voice_engine(NULL),
-          overuse_callback(NULL) {}
+          overuse_callback(NULL),
+          start_bitrate_bps(-1) {}
 
     webrtc::Config* webrtc_config;
 
@@ -73,6 +74,11 @@
     // Callback for overuse and normal usage based on the jitter of incoming
     // captured frames. 'NULL' disables the callback.
     OveruseCallback* overuse_callback;
+
+    // Start bitrate used before a valid bitrate estimate is calculated. '-1'
+    // lets the call decide start bitrate.
+    // Note: This currently only affects video.
+    int start_bitrate_bps;
   };
 
   static Call* Create(const Call::Config& config);
diff --git a/video/call.cc b/video/call.cc
index 6103074..6daa8b0 100644
--- a/video/call.cc
+++ b/video/call.cc
@@ -131,6 +131,8 @@
 
 namespace internal {
 
+const int kDefaultVideoStreamBitrateBps = 300000;
+
 Call::Call(webrtc::VideoEngine* video_engine, const Call::Config& config)
     : config_(config),
       receive_lock_(RWLockWrapper::CreateRWLock()),
@@ -182,14 +184,18 @@
     const void* encoder_settings) {
   assert(config.rtp.ssrcs.size() > 0);
 
-  VideoSendStream* send_stream =
-      new VideoSendStream(config_.send_transport,
-                          overuse_observer_proxy_.get(),
-                          video_engine_,
-                          config,
-                          video_streams,
-                          encoder_settings,
-                          base_channel_id_);
+  // TODO(mflodman): Base the start bitrate on a current bandwidth estimate, if
+  // the call has already started.
+  VideoSendStream* send_stream = new VideoSendStream(
+      config_.send_transport,
+      overuse_observer_proxy_.get(),
+      video_engine_,
+      config,
+      video_streams,
+      encoder_settings,
+      base_channel_id_,
+      config_.start_bitrate_bps != -1 ? config_.start_bitrate_bps
+                                      : kDefaultVideoStreamBitrateBps);
 
   WriteLockScoped write_lock(*send_lock_);
   for (size_t i = 0; i < config.rtp.ssrcs.size(); ++i) {
diff --git a/video/loopback.cc b/video/loopback.cc
index ecc2089..ea65ebb 100644
--- a/video/loopback.cc
+++ b/video/loopback.cc
@@ -61,6 +61,8 @@
 
   test::DirectTransport transport;
   Call::Config call_config(&transport);
+  call_config.start_bitrate_bps =
+      static_cast<int>(flags::StartBitrate()) * 1000;
   scoped_ptr<Call> call(Call::Create(call_config));
 
   // Loopback, call sends to itself.
diff --git a/video/rampup_tests.cc b/video/rampup_tests.cc
index 86950ce..94f1c19 100644
--- a/video/rampup_tests.cc
+++ b/video/rampup_tests.cc
@@ -40,6 +40,7 @@
 namespace {
 static const int kTransmissionTimeOffsetExtensionId = 6;
 static const int kMaxPacketSize = 1500;
+static const unsigned int kSingleStreamTargetBps = 1000000;
 
 class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
  public:
@@ -57,6 +58,7 @@
             new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(false))),
         crit_(CriticalSectionWrapper::CreateCriticalSection()),
         expected_bitrate_bps_(0),
+        start_bitrate_bps_(0),
         rtx_media_ssrcs_(rtx_media_ssrcs),
         total_sent_(0),
         padding_sent_(0),
@@ -89,10 +91,25 @@
     expected_bitrate_bps_ = expected_bitrate_bps;
   }
 
+  void set_start_bitrate_bps(unsigned int start_bitrate_bps) {
+    CriticalSectionScoped lock(crit_.get());
+    start_bitrate_bps_ = start_bitrate_bps;
+  }
+
   virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
                                        unsigned int bitrate) OVERRIDE {
     CriticalSectionScoped lock(crit_.get());
     assert(expected_bitrate_bps_ > 0);
+    if (start_bitrate_bps_ != 0) {
+      // For tests with an explicitly set start bitrate, verify the first
+      // bitrate estimate is close to the start bitrate and lower than the
+      // test target bitrate. This is to verify a call respects the configured
+      // start bitrate, but due to the BWE implementation we can't guarantee the
+      // first estimate really is as high as the start bitrate.
+      EXPECT_GT(bitrate, 0.9 * start_bitrate_bps_);
+      EXPECT_LT(bitrate, expected_bitrate_bps_);
+      start_bitrate_bps_ = 0;
+    }
     if (bitrate >= expected_bitrate_bps_) {
       // Just trigger if there was any rtx padding packet.
       if (rtx_media_ssrcs_.empty() || rtx_media_sent_ > 0) {
@@ -178,6 +195,7 @@
 
   const scoped_ptr<CriticalSectionWrapper> crit_;
   unsigned int expected_bitrate_bps_ GUARDED_BY(crit_);
+  unsigned int start_bitrate_bps_ GUARDED_BY(crit_);
   SsrcMap rtx_media_ssrcs_ GUARDED_BY(crit_);
   size_t total_sent_ GUARDED_BY(crit_);
   size_t padding_sent_ GUARDED_BY(crit_);
@@ -400,14 +418,16 @@
   size_t total_overuse_bytes_ GUARDED_BY(crit_);
   bool suspended_in_stats_ GUARDED_BY(crit_);
 };
-}
+}  // namespace
 
 class RampUpTest : public ::testing::Test {
  public:
   virtual void SetUp() { reserved_ssrcs_.clear(); }
 
  protected:
-  void RunRampUpTest(bool rtx, size_t num_streams) {
+  void RunRampUpTest(bool rtx,
+                     size_t num_streams,
+                     unsigned int start_bitrate_bps) {
     std::vector<uint32_t> ssrcs(GenerateSsrcs(num_streams, 100));
     std::vector<uint32_t> rtx_ssrcs(GenerateSsrcs(num_streams, 200));
     StreamObserver::SsrcMap rtx_ssrc_map;
@@ -421,6 +441,10 @@
                                    Clock::GetRealTimeClock());
 
     Call::Config call_config(&stream_observer);
+    if (start_bitrate_bps != 0) {
+      call_config.start_bitrate_bps = start_bitrate_bps;
+      stream_observer.set_start_bitrate_bps(start_bitrate_bps);
+    }
     scoped_ptr<Call> call(Call::Create(call_config));
     VideoSendStream::Config send_config = call->GetDefaultSendConfig();
 
@@ -451,10 +475,10 @@
 
     if (num_streams == 1) {
       // For single stream rampup until 1mbps
-      stream_observer.set_expected_bitrate_bps(1000000);
+      stream_observer.set_expected_bitrate_bps(kSingleStreamTargetBps);
     } else {
       // For multi stream rampup until all streams are being sent. That means
-      // enough birate to sent all the target streams plus the min bitrate of
+      // enough birate to send all the target streams plus the min bitrate of
       // the last one.
       int expected_bitrate_bps = video_streams.back().min_bitrate_bps;
       for (size_t i = 0; i < video_streams.size() - 1; ++i) {
@@ -564,15 +588,19 @@
 };
 
 TEST_F(RampUpTest, SingleStream) {
-  RunRampUpTest(false, 1);
+  RunRampUpTest(false, 1, 0);
 }
 
 TEST_F(RampUpTest, Simulcast) {
-  RunRampUpTest(false, 3);
+  RunRampUpTest(false, 3, 0);
 }
 
 TEST_F(RampUpTest, SimulcastWithRtx) {
-  RunRampUpTest(true, 3);
+  RunRampUpTest(true, 3, 0);
+}
+
+TEST_F(RampUpTest, SingleStreamWithHighStartBitrate) {
+  RunRampUpTest(false, 1, 0.9 * kSingleStreamTargetBps);
 }
 
 TEST_F(RampUpTest, UpDownUpOneStream) { RunRampUpDownUpTest(1, false); }
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index 170badc..f9bbd57 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -114,16 +114,19 @@
                                  const VideoSendStream::Config& config,
                                  const std::vector<VideoStream> video_streams,
                                  const void* encoder_settings,
-                                 int base_channel)
+                                 int base_channel,
+                                 int start_bitrate_bps)
     : transport_adapter_(transport),
       encoded_frame_proxy_(config.post_encode_callback),
       config_(config),
+      start_bitrate_bps_(start_bitrate_bps),
       external_codec_(NULL),
       channel_(-1),
       stats_proxy_(new SendStatisticsProxy(config, this)) {
   video_engine_base_ = ViEBase::GetInterface(video_engine);
   video_engine_base_->CreateChannel(channel_, base_channel);
   assert(channel_ != -1);
+  assert(start_bitrate_bps_ > 0);
 
   rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
   assert(rtp_rtcp_ != NULL);
@@ -350,13 +353,17 @@
     video_codec.qpMax = std::max(video_codec.qpMax,
                                  static_cast<unsigned int>(streams[i].max_qp));
   }
+  video_codec.startBitrate =
+      static_cast<unsigned int>(start_bitrate_bps_) / 1000;
 
   if (video_codec.minBitrate < kViEMinCodecBitrate)
     video_codec.minBitrate = kViEMinCodecBitrate;
   if (video_codec.maxBitrate < kViEMinCodecBitrate)
     video_codec.maxBitrate = kViEMinCodecBitrate;
-
-  video_codec.startBitrate = 300;
+  if (video_codec.startBitrate < video_codec.minBitrate)
+    video_codec.startBitrate = video_codec.minBitrate;
+  if (video_codec.startBitrate > video_codec.maxBitrate)
+    video_codec.startBitrate = video_codec.maxBitrate;
 
   if (video_codec.startBitrate < video_codec.minBitrate)
     video_codec.startBitrate = video_codec.minBitrate;
diff --git a/video/video_send_stream.h b/video/video_send_stream.h
index 125c7fd..ed77665 100644
--- a/video/video_send_stream.h
+++ b/video/video_send_stream.h
@@ -44,7 +44,8 @@
                   const VideoSendStream::Config& config,
                   const std::vector<VideoStream> video_streams,
                   const void* encoder_settings,
-                  int base_channel);
+                  int base_channel,
+                  int start_bitrate);
 
   virtual ~VideoSendStream();
 
@@ -73,6 +74,7 @@
   TransportAdapter transport_adapter_;
   EncodedFrameCallbackAdapter encoded_frame_proxy_;
   const VideoSendStream::Config config_;
+  const int start_bitrate_bps_;
 
   ViEBase* video_engine_base_;
   ViECapture* capture_;