Wire up bandwidth stats to the new API and webrtcvideoengine2.

Adds stats to verify bandwidth and pacer stats.

BUG=1788
R=mflodman@webrtc.org, pbos@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7634 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc
index d79f71d..5062fb9 100644
--- a/talk/media/webrtc/webrtcvideoengine2.cc
+++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -1202,7 +1202,21 @@
 
 void WebRtcVideoChannel2::FillBandwidthEstimationStats(
     VideoMediaInfo* video_media_info) {
-  // TODO(pbos): Implement.
+  BandwidthEstimationInfo bwe_info;
+  webrtc::Call::Stats stats = call_->GetStats();
+  bwe_info.available_send_bandwidth = stats.send_bandwidth_bps;
+  bwe_info.available_recv_bandwidth = stats.recv_bandwidth_bps;
+  bwe_info.bucket_delay = stats.pacer_delay_ms;
+
+  // Get send stream bitrate stats.
+  rtc::CritScope stream_lock(&stream_crit_);
+  for (std::map<uint32, WebRtcVideoSendStream*>::iterator stream =
+           send_streams_.begin();
+       stream != send_streams_.end();
+       ++stream) {
+    stream->second->FillBandwidthEstimationInfo(&bwe_info);
+  }
+  video_media_info->bw_estimations.push_back(bwe_info);
 }
 
 bool WebRtcVideoChannel2::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
@@ -1842,12 +1856,12 @@
   info.framerate_input = stats.input_frame_rate;
   info.framerate_sent = stats.encode_frame_rate;
 
-  for (std::map<uint32_t, webrtc::StreamStats>::iterator it =
+  for (std::map<uint32_t, webrtc::SsrcStats>::iterator it =
            stats.substreams.begin();
        it != stats.substreams.end();
        ++it) {
     // TODO(pbos): Wire up additional stats, such as padding bytes.
-    webrtc::StreamStats stream_stats = it->second;
+    webrtc::SsrcStats stream_stats = it->second;
     info.bytes_sent += stream_stats.rtp_stats.bytes +
                        stream_stats.rtp_stats.header_bytes +
                        stream_stats.rtp_stats.padding_bytes;
@@ -1857,7 +1871,7 @@
 
   if (!stats.substreams.empty()) {
     // TODO(pbos): Report fraction lost per SSRC.
-    webrtc::StreamStats first_stream_stats = stats.substreams.begin()->second;
+    webrtc::SsrcStats first_stream_stats = stats.substreams.begin()->second;
     info.fraction_lost =
         static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) /
         (1 << 8);
@@ -1884,6 +1898,23 @@
   return info;
 }
 
+void WebRtcVideoChannel2::WebRtcVideoSendStream::FillBandwidthEstimationInfo(
+    BandwidthEstimationInfo* bwe_info) {
+  rtc::CritScope cs(&lock_);
+  if (stream_ == NULL) {
+    return;
+  }
+  webrtc::VideoSendStream::Stats stats = stream_->GetStats();
+  for (std::map<uint32_t, webrtc::SsrcStats>::iterator it =
+           stats.substreams.begin();
+       it != stats.substreams.end();
+       ++it) {
+    bwe_info->transmit_bitrate += it->second.total_bitrate_bps;
+    bwe_info->retransmit_bitrate += it->second.retransmit_bitrate_bps;
+  }
+  bwe_info->actual_enc_bitrate = stats.media_bitrate_bps;
+}
+
 void WebRtcVideoChannel2::WebRtcVideoSendStream::OnCpuResolutionRequest(
     CoordinatedVideoAdapter::AdaptRequest adapt_request) {
   rtc::CritScope cs(&lock_);
diff --git a/talk/media/webrtc/webrtcvideoengine2.h b/talk/media/webrtc/webrtcvideoengine2.h
index 0b812ef..299ac35 100644
--- a/talk/media/webrtc/webrtcvideoengine2.h
+++ b/talk/media/webrtc/webrtcvideoengine2.h
@@ -315,6 +315,7 @@
     void Stop();
 
     VideoSenderInfo GetVideoSenderInfo();
+    void FillBandwidthEstimationInfo(BandwidthEstimationInfo* bwe_info);
 
     void OnCpuResolutionRequest(
         CoordinatedVideoAdapter::AdaptRequest adapt_request);
diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
index 0b85723..afea370 100644
--- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -294,12 +294,9 @@
   return NULL;
 }
 
-uint32_t FakeCall::SendBitrateEstimate() {
-  return 0;
-}
-
-uint32_t FakeCall::ReceiveBitrateEstimate() {
-  return 0;
+webrtc::Call::Stats FakeCall::GetStats() const {
+  webrtc::Call::Stats stats;
+  return stats;
 }
 
 void FakeCall::SignalNetworkState(webrtc::Call::NetworkState state) {
diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.h b/talk/media/webrtc/webrtcvideoengine2_unittest.h
index 3b62289..48c4f64 100644
--- a/talk/media/webrtc/webrtcvideoengine2_unittest.h
+++ b/talk/media/webrtc/webrtcvideoengine2_unittest.h
@@ -127,8 +127,7 @@
       webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
   virtual webrtc::PacketReceiver* Receiver() OVERRIDE;
 
-  virtual uint32_t SendBitrateEstimate() OVERRIDE;
-  virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
+  virtual webrtc::Call::Stats GetStats() const OVERRIDE;
 
   virtual void SignalNetworkState(webrtc::Call::NetworkState state) OVERRIDE;
 
diff --git a/webrtc/call.h b/webrtc/call.h
index f21425f..c6596f8 100644
--- a/webrtc/call.h
+++ b/webrtc/call.h
@@ -88,6 +88,14 @@
     int stream_start_bitrate_bps;
   };
 
+  struct Stats {
+    Stats() : send_bandwidth_bps(0), recv_bandwidth_bps(0), pacer_delay_ms(0) {}
+
+    int send_bandwidth_bps;
+    int recv_bandwidth_bps;
+    int pacer_delay_ms;
+  };
+
   static Call* Create(const Call::Config& config);
 
   static Call* Create(const Call::Config& config,
@@ -109,13 +117,9 @@
   // Call instance exists.
   virtual PacketReceiver* Receiver() = 0;
 
-  // Returns the estimated total send bandwidth. Note: this can differ from the
-  // actual encoded bitrate.
-  virtual uint32_t SendBitrateEstimate() = 0;
-
-  // Returns the total estimated receive bandwidth for the call. Note: this can
-  // differ from the actual receive bitrate.
-  virtual uint32_t ReceiveBitrateEstimate() = 0;
+  // Returns the call statistics, such as estimated send and receive bandwidth,
+  // pacing delay, etc.
+  virtual Stats GetStats() const = 0;
 
   virtual void SignalNetworkState(NetworkState state) = 0;
 
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index 7bcfd6d..0b4af26 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -271,7 +271,9 @@
  public:
   virtual ~BitrateStatisticsObserver() {}
 
-  virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) = 0;
+  virtual void Notify(const BitrateStatistics& total_stats,
+                      const BitrateStatistics& retransmit_stats,
+                      uint32_t ssrc) = 0;
 };
 
 // Callback, used to notify an observer whenever frame counts have been updated
diff --git a/webrtc/config.h b/webrtc/config.h
index 8ea2828..ee1097f 100644
--- a/webrtc/config.h
+++ b/webrtc/config.h
@@ -33,16 +33,19 @@
   int extended_max_sequence_number;
 };
 
-struct StreamStats {
-  StreamStats()
+struct SsrcStats {
+  SsrcStats()
       : key_frames(0),
         delta_frames(0),
-        bitrate_bps(0),
+        total_bitrate_bps(0),
+        retransmit_bitrate_bps(0),
         avg_delay_ms(0),
         max_delay_ms(0) {}
   uint32_t key_frames;
   uint32_t delta_frames;
-  int32_t bitrate_bps;
+  // TODO(holmer): Move bitrate_bps out to the webrtc::Call layer.
+  int total_bitrate_bps;
+  int retransmit_bitrate_bps;
   int avg_delay_ms;
   int max_delay_ms;
   StreamDataCounters rtp_stats;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
index 0438b9f..677f3fc 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -40,6 +40,57 @@
 
 }  // namespace
 
+class BitrateAggregator {
+ public:
+  explicit BitrateAggregator(BitrateStatisticsObserver* bitrate_callback)
+      : callback_(bitrate_callback),
+        total_bitrate_observer_(*this),
+        retransmit_bitrate_observer_(*this),
+        ssrc_(0) {}
+
+  void OnStatsUpdated() const {
+    if (callback_)
+      callback_->Notify(total_bitrate_observer_.statistics(),
+                        retransmit_bitrate_observer_.statistics(),
+                        ssrc_);
+  }
+
+  Bitrate::Observer* total_bitrate_observer() {
+    return &total_bitrate_observer_;
+  }
+  Bitrate::Observer* retransmit_bitrate_observer() {
+    return &retransmit_bitrate_observer_;
+  }
+
+  void set_ssrc(uint32_t ssrc) { ssrc_ = ssrc; }
+
+ private:
+  // We assume that these observers are called on the same thread, which is
+  // true for RtpSender as they are called on the Process thread.
+  class BitrateObserver : public Bitrate::Observer {
+   public:
+    explicit BitrateObserver(const BitrateAggregator& aggregator)
+        : aggregator_(aggregator) {}
+
+    // Implements Bitrate::Observer.
+    virtual void BitrateUpdated(const BitrateStatistics& stats) OVERRIDE {
+      statistics_ = stats;
+      aggregator_.OnStatsUpdated();
+    }
+
+    BitrateStatistics statistics() const { return statistics_; }
+
+   private:
+    BitrateStatistics statistics_;
+    const BitrateAggregator& aggregator_;
+  };
+
+  BitrateStatisticsObserver* const callback_;
+  BitrateObserver total_bitrate_observer_;
+  BitrateObserver retransmit_bitrate_observer_;
+  uint32_t ssrc_;
+};
+
 RTPSender::RTPSender(const int32_t id,
                      const bool audio,
                      Clock* clock,
@@ -54,7 +105,8 @@
       // TickTime.
       clock_delta_ms_(clock_->TimeInMilliseconds() -
                       TickTime::MillisecondTimestamp()),
-      bitrate_sent_(clock, this),
+      bitrates_(new BitrateAggregator(bitrate_callback)),
+      total_bitrate_sent_(clock, bitrates_->total_bitrate_observer()),
       id_(id),
       audio_configured_(audio),
       audio_(NULL),
@@ -74,12 +126,11 @@
       // NACK.
       nack_byte_count_times_(),
       nack_byte_count_(),
-      nack_bitrate_(clock, NULL),
+      nack_bitrate_(clock, bitrates_->retransmit_bitrate_observer()),
       packet_history_(clock),
       // Statistics
       statistics_crit_(CriticalSectionWrapper::CreateCriticalSection()),
       rtp_stats_callback_(NULL),
-      bitrate_callback_(bitrate_callback),
       frame_count_observer_(frame_count_observer),
       send_side_delay_observer_(send_side_delay_observer),
       // RTP variables
@@ -108,6 +159,7 @@
   srand(static_cast<uint32_t>(clock_->TimeInMilliseconds()));
   ssrc_ = ssrc_db_.CreateSSRC();  // Can't be 0.
   ssrc_rtx_ = ssrc_db_.CreateSSRC();  // Can't be 0.
+  bitrates_->set_ssrc(ssrc_);
   // Random start, 16 bits. Can't be 0.
   sequence_number_rtx_ = static_cast<uint16_t>(rand() + 1) & 0x7FFF;
   sequence_number_ = static_cast<uint16_t>(rand() + 1) & 0x7FFF;
@@ -149,7 +201,7 @@
 }
 
 uint16_t RTPSender::ActualSendBitrateKbit() const {
-  return (uint16_t)(bitrate_sent_.BitrateNow() / 1000);
+  return (uint16_t)(total_bitrate_sent_.BitrateNow() / 1000);
 }
 
 uint32_t RTPSender::VideoBitrateSent() const {
@@ -864,7 +916,7 @@
     counters = &rtp_stats_;
   }
 
-  bitrate_sent_.Update(size);
+  total_bitrate_sent_.Update(size);
   ++counters->packets;
   if (IsFecPacket(buffer, header)) {
     ++counters->fec_packets;
@@ -997,7 +1049,7 @@
 
 void RTPSender::ProcessBitrate() {
   CriticalSectionScoped cs(send_critsect_);
-  bitrate_sent_.Process();
+  total_bitrate_sent_.Process();
   nack_bitrate_.Process();
   if (audio_configured_) {
     return;
@@ -1420,6 +1472,7 @@
       // Generate a new SSRC.
       ssrc_db_.ReturnSSRC(ssrc_);
       ssrc_ = ssrc_db_.CreateSSRC();  // Can't be 0.
+      bitrates_->set_ssrc(ssrc_);
     }
     // Don't initialize seq number if SSRC passed externally.
     if (!sequence_number_forced_ && !ssrc_forced_) {
@@ -1470,6 +1523,7 @@
     return 0;
   }
   ssrc_ = ssrc_db_.CreateSSRC();  // Can't be 0.
+  bitrates_->set_ssrc(ssrc_);
   return ssrc_;
 }
 
@@ -1484,6 +1538,7 @@
   ssrc_db_.ReturnSSRC(ssrc_);
   ssrc_db_.RegisterSSRC(ssrc);
   ssrc_ = ssrc;
+  bitrates_->set_ssrc(ssrc_);
   if (!sequence_number_forced_) {
     sequence_number_ =
         rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);  // NOLINT
@@ -1681,17 +1736,8 @@
   return rtp_stats_callback_;
 }
 
-uint32_t RTPSender::BitrateSent() const { return bitrate_sent_.BitrateLast(); }
-
-void RTPSender::BitrateUpdated(const BitrateStatistics& stats) {
-  uint32_t ssrc;
-  {
-    CriticalSectionScoped ssrc_lock(send_critsect_);
-    ssrc = ssrc_;
-  }
-  if (bitrate_callback_) {
-    bitrate_callback_->Notify(stats, ssrc);
-  }
+uint32_t RTPSender::BitrateSent() const {
+  return total_bitrate_sent_.BitrateLast();
 }
 
 void RTPSender::SetRtpState(const RtpState& rtp_state) {
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h
index 780baa1f..6564d47 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h
@@ -31,6 +31,7 @@
 
 namespace webrtc {
 
+class BitrateAggregator;
 class CriticalSectionWrapper;
 class RTPSenderAudio;
 class RTPSenderVideo;
@@ -65,7 +66,7 @@
       PacedSender::Priority priority) = 0;
 };
 
-class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
+class RTPSender : public RTPSenderInterface {
  public:
   RTPSender(const int32_t id, const bool audio, Clock *clock,
             Transport *transport, RtpAudioFeedback *audio_feedback,
@@ -276,8 +277,6 @@
 
   uint32_t BitrateSent() const;
 
-  virtual void BitrateUpdated(const BitrateStatistics& stats) OVERRIDE;
-
   void SetRtpState(const RtpState& rtp_state);
   RtpState GetRtpState() const;
   void SetRtxRtpState(const RtpState& rtp_state);
@@ -337,7 +336,9 @@
 
   Clock* clock_;
   int64_t clock_delta_ms_;
-  Bitrate bitrate_sent_;
+
+  scoped_ptr<BitrateAggregator> bitrates_;
+  Bitrate total_bitrate_sent_;
 
   int32_t id_;
   const bool audio_configured_;
@@ -375,7 +376,6 @@
   StreamDataCounters rtp_stats_ GUARDED_BY(statistics_crit_);
   StreamDataCounters rtx_rtp_stats_ GUARDED_BY(statistics_crit_);
   StreamDataCountersCallback* rtp_stats_callback_ GUARDED_BY(statistics_crit_);
-  BitrateStatisticsObserver* const bitrate_callback_;
   FrameCountObserver* const frame_count_observer_;
   SendSideDelayObserver* const send_side_delay_observer_;
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 9c6a720..2a49477 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -855,20 +855,22 @@
 TEST_F(RtpSenderTest, BitrateCallbacks) {
   class TestCallback : public BitrateStatisticsObserver {
    public:
-    TestCallback()
-        : BitrateStatisticsObserver(), num_calls_(0), ssrc_(0), bitrate_() {}
+    TestCallback() : BitrateStatisticsObserver(), num_calls_(0), ssrc_(0) {}
     virtual ~TestCallback() {}
 
-    virtual void Notify(const BitrateStatistics& stats,
+    virtual void Notify(const BitrateStatistics& total_stats,
+                        const BitrateStatistics& retransmit_stats,
                         uint32_t ssrc) OVERRIDE {
       ++num_calls_;
       ssrc_ = ssrc;
-      bitrate_ = stats;
+      total_stats_ = total_stats;
+      retransmit_stats_ = retransmit_stats;
     }
 
     uint32_t num_calls_;
     uint32_t ssrc_;
-    BitrateStatistics bitrate_;
+    BitrateStatistics total_stats_;
+    BitrateStatistics retransmit_stats_;
   } callback;
   rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
                                   &mock_paced_sender_, &callback, NULL, NULL));
@@ -909,13 +911,15 @@
 
   const uint32_t expected_packet_rate = 1000 / kPacketInterval;
 
-  EXPECT_EQ(1U, callback.num_calls_);
+  // We get one call for every stats updated, thus two calls since both the
+  // stream stats and the retransmit stats are updated once.
+  EXPECT_EQ(2u, callback.num_calls_);
   EXPECT_EQ(ssrc, callback.ssrc_);
   EXPECT_EQ(start_time + (kNumPackets * kPacketInterval),
-            callback.bitrate_.timestamp_ms);
-  EXPECT_EQ(expected_packet_rate, callback.bitrate_.packet_rate);
+            callback.total_stats_.timestamp_ms);
+  EXPECT_EQ(expected_packet_rate, callback.total_stats_.packet_rate);
   EXPECT_EQ((kPacketOverhead + sizeof(payload)) * 8 * expected_packet_rate,
-            callback.bitrate_.bitrate_bps);
+            callback.total_stats_.bitrate_bps);
 
   rtp_sender_.reset();
 }
diff --git a/webrtc/modules/video_coding/main/source/media_optimization.cc b/webrtc/modules/video_coding/main/source/media_optimization.cc
index 0d9a4bd..5789480 100644
--- a/webrtc/modules/video_coding/main/source/media_optimization.cc
+++ b/webrtc/modules/video_coding/main/source/media_optimization.cc
@@ -542,7 +542,7 @@
       now_ms - encoded_frame_samples_.front().time_complete_ms);
   if (denom >= 1.0f) {
     avg_sent_bit_rate_bps_ =
-        static_cast<uint32_t>(framesize_sum * 8 * 1000 / denom + 0.5f);
+        static_cast<uint32_t>(framesize_sum * 8.0f * 1000.0f / denom + 0.5f);
   } else {
     avg_sent_bit_rate_bps_ = framesize_sum * 8;
   }
diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc
index 9551c82..0573c8a 100644
--- a/webrtc/test/fake_encoder.cc
+++ b/webrtc/test/fake_encoder.cc
@@ -51,7 +51,8 @@
   assert(config_.maxFramerate > 0);
   int time_since_last_encode_ms = 1000 / config_.maxFramerate;
   int64_t time_now_ms = clock_->TimeInMilliseconds();
-  if (last_encode_time_ms_ > 0) {
+  const bool first_encode = last_encode_time_ms_ == 0;
+  if (!first_encode) {
     // For all frames but the first we can estimate the display time by looking
     // at the display time of the previous frame.
     time_since_last_encode_ms = time_now_ms - last_encode_time_ms_;
@@ -80,6 +81,12 @@
     int stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
         bits_available;
     int stream_bytes = (stream_bits + 7) / 8;
+    if (first_encode) {
+      // The first frame is a key frame and should be larger.
+      // TODO(holmer): The FakeEncoder should store the bits_available between
+      // encodes so that it can compensate for oversized frames.
+      stream_bytes *= 10;
+    }
     if (static_cast<size_t>(stream_bytes) > sizeof(encoded_buffer_))
       stream_bytes = sizeof(encoded_buffer_);
 
@@ -96,7 +103,6 @@
     assert(callback_ != NULL);
     if (callback_->Encoded(encoded, &specifics, NULL) != 0)
       return -1;
-
     bits_available -= encoded._length * 8;
   }
   return 0;
diff --git a/webrtc/video/call.cc b/webrtc/video/call.cc
index b03b6c9..2b4f76f 100644
--- a/webrtc/video/call.cc
+++ b/webrtc/video/call.cc
@@ -114,8 +114,7 @@
   virtual void DestroyVideoReceiveStream(
       webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
 
-  virtual uint32_t SendBitrateEstimate() OVERRIDE;
-  virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
+  virtual Stats GetStats() const OVERRIDE;
 
   virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
                                        size_t length) OVERRIDE;
@@ -321,14 +320,26 @@
   delete receive_stream_impl;
 }
 
-uint32_t Call::SendBitrateEstimate() {
-  // TODO(pbos): Return send-bitrate estimate
-  return 0;
-}
-
-uint32_t Call::ReceiveBitrateEstimate() {
-  // TODO(pbos): Return receive-bitrate estimate
-  return 0;
+Call::Stats Call::GetStats() const {
+  Stats stats;
+  // Ignoring return values.
+  uint32_t send_bandwidth = 0;
+  rtp_rtcp_->GetEstimatedSendBandwidth(base_channel_id_, &send_bandwidth);
+  stats.send_bandwidth_bps = send_bandwidth;
+  uint32_t recv_bandwidth = 0;
+  rtp_rtcp_->GetEstimatedReceiveBandwidth(base_channel_id_, &recv_bandwidth);
+  stats.recv_bandwidth_bps = recv_bandwidth;
+  {
+    ReadLockScoped read_lock(*send_crit_);
+    for (std::map<uint32_t, VideoSendStream*>::const_iterator it =
+             send_ssrcs_.begin();
+         it != send_ssrcs_.end();
+         ++it) {
+      stats.pacer_delay_ms =
+          std::max(it->second->GetPacerQueuingDelayMs(), stats.pacer_delay_ms);
+    }
+  }
+  return stats;
 }
 
 void Call::SignalNetworkState(NetworkState state) {
diff --git a/webrtc/video/call_perf_tests.cc b/webrtc/video/call_perf_tests.cc
index 9776fb7..9194b08 100644
--- a/webrtc/video/call_perf_tests.cc
+++ b/webrtc/video/call_perf_tests.cc
@@ -502,7 +502,8 @@
       VideoSendStream::Stats stats = send_stream_->GetStats();
       if (stats.substreams.size() > 0) {
         assert(stats.substreams.size() == 1);
-        int bitrate_kbps = stats.substreams.begin()->second.bitrate_bps / 1000;
+        int bitrate_kbps =
+            stats.substreams.begin()->second.total_bitrate_bps / 1000;
         if (bitrate_kbps > 0) {
           test::PrintResult(
               "bitrate_stats_",
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index 96249c3..80d8e19a 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -1202,6 +1202,53 @@
   RunBaseTest(&test);
 }
 
+TEST_F(EndToEndTest, VerifyBandwidthStats) {
+  class RtcpObserver : public test::EndToEndTest, public PacketReceiver {
+   public:
+    RtcpObserver()
+        : EndToEndTest(kDefaultTimeoutMs),
+          sender_call_(NULL),
+          receiver_call_(NULL),
+          has_seen_pacer_delay_(false) {}
+
+    virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
+                                         size_t length) OVERRIDE {
+      Call::Stats sender_stats = sender_call_->GetStats();
+      Call::Stats receiver_stats = receiver_call_->GetStats();
+      if (!has_seen_pacer_delay_)
+        has_seen_pacer_delay_ = sender_stats.pacer_delay_ms > 0;
+      if (sender_stats.send_bandwidth_bps > 0 &&
+          receiver_stats.recv_bandwidth_bps > 0 && has_seen_pacer_delay_)
+        observation_complete_->Set();
+      return receiver_call_->Receiver()->DeliverPacket(packet, length);
+    }
+
+    virtual void OnCallsCreated(Call* sender_call,
+                                Call* receiver_call) OVERRIDE {
+      sender_call_ = sender_call;
+      receiver_call_ = receiver_call;
+    }
+
+    virtual void PerformTest() OVERRIDE {
+      EXPECT_EQ(kEventSignaled, Wait()) << "Timed out while waiting for "
+                                           "non-zero bandwidth stats.";
+    }
+
+    virtual void SetReceivers(
+        PacketReceiver* send_transport_receiver,
+        PacketReceiver* receive_transport_receiver) OVERRIDE {
+      test::RtpRtcpObserver::SetReceivers(this, receive_transport_receiver);
+    }
+
+   private:
+    Call* sender_call_;
+    Call* receiver_call_;
+    bool has_seen_pacer_delay_;
+  } test;
+
+  RunBaseTest(&test);
+}
+
 void EndToEndTest::TestXrReceiverReferenceTimeReport(bool enable_rrtr) {
   static const int kNumRtcpReportPacketsToObserve = 5;
   class RtcpXrObserver : public test::EndToEndTest {
@@ -1434,7 +1481,7 @@
       // Make sure all fields have been populated.
 
       receive_stats_filled_["IncomingRate"] |=
-          stats.network_frame_rate != 0 || stats.bitrate_bps != 0;
+          stats.network_frame_rate != 0 || stats.total_bitrate_bps != 0;
 
       receive_stats_filled_["FrameCallback"] |= stats.decode_frame_rate != 0;
 
@@ -1465,7 +1512,7 @@
       send_stats_filled_["NumStreams"] |=
           stats.substreams.size() == expected_send_ssrcs_.size();
 
-      for (std::map<uint32_t, StreamStats>::const_iterator it =
+      for (std::map<uint32_t, SsrcStats>::const_iterator it =
                stats.substreams.begin();
            it != stats.substreams.end();
            ++it) {
@@ -1475,7 +1522,7 @@
         send_stats_filled_[CompoundKey("IncomingRate", it->first)] |=
             stats.input_frame_rate != 0;
 
-        const StreamStats& stream_stats = it->second;
+        const SsrcStats& stream_stats = it->second;
 
         send_stats_filled_[CompoundKey("StatisticsUpdated", it->first)] |=
             stream_stats.rtcp_stats.cumulative_lost != 0 ||
@@ -1490,7 +1537,7 @@
 
         send_stats_filled_[CompoundKey("BitrateStatisticsObserver",
                                        it->first)] |=
-            stream_stats.bitrate_bps != 0;
+            stream_stats.total_bitrate_bps != 0;
 
         send_stats_filled_[CompoundKey("FrameCountObserver", it->first)] |=
             stream_stats.delta_frames != 0 || stream_stats.key_frames != 0;
diff --git a/webrtc/video/receive_statistics_proxy.cc b/webrtc/video/receive_statistics_proxy.cc
index 3826283..ca0bcdf 100644
--- a/webrtc/video/receive_statistics_proxy.cc
+++ b/webrtc/video/receive_statistics_proxy.cc
@@ -58,10 +58,10 @@
 
 void ReceiveStatisticsProxy::IncomingRate(const int video_channel,
                                           const unsigned int framerate,
-                                          const unsigned int bitrate) {
+                                          const unsigned int bitrate_bps) {
   CriticalSectionScoped lock(crit_.get());
   stats_.network_frame_rate = framerate;
-  stats_.bitrate_bps = bitrate;
+  stats_.total_bitrate_bps = bitrate_bps;
 }
 
 void ReceiveStatisticsProxy::StatisticsUpdated(
diff --git a/webrtc/video/receive_statistics_proxy.h b/webrtc/video/receive_statistics_proxy.h
index b5fbf86..a1b6735 100644
--- a/webrtc/video/receive_statistics_proxy.h
+++ b/webrtc/video/receive_statistics_proxy.h
@@ -52,7 +52,7 @@
                                     const VideoCodec& video_codec) OVERRIDE {}
   virtual void IncomingRate(const int video_channel,
                             const unsigned int framerate,
-                            const unsigned int bitrate) OVERRIDE;
+                            const unsigned int bitrate_bps) OVERRIDE;
   virtual void DecoderTiming(int decode_ms,
                              int max_decode_ms,
                              int current_delay_ms,
diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc
index 1b6081d..f2df0ed 100644
--- a/webrtc/video/send_statistics_proxy.cc
+++ b/webrtc/video/send_statistics_proxy.cc
@@ -29,6 +29,7 @@
                                        const unsigned int bitrate) {
   CriticalSectionScoped lock(crit_.get());
   stats_.encode_frame_rate = framerate;
+  stats_.media_bitrate_bps = bitrate;
 }
 
 void SendStatisticsProxy::SuspendChange(int video_channel, bool is_suspended) {
@@ -47,8 +48,8 @@
   return stats_;
 }
 
-StreamStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
-  std::map<uint32_t, StreamStats>::iterator it = stats_.substreams.find(ssrc);
+SsrcStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
+  std::map<uint32_t, SsrcStats>::iterator it = stats_.substreams.find(ssrc);
   if (it != stats_.substreams.end())
     return &it->second;
 
@@ -66,7 +67,7 @@
 void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
                                             uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  StreamStats* stats = GetStatsEntry(ssrc);
+  SsrcStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
@@ -77,28 +78,30 @@
     const StreamDataCounters& counters,
     uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  StreamStats* stats = GetStatsEntry(ssrc);
+  SsrcStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
   stats->rtp_stats = counters;
 }
 
-void SendStatisticsProxy::Notify(const BitrateStatistics& bitrate,
+void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,
+                                 const BitrateStatistics& retransmit_stats,
                                  uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  StreamStats* stats = GetStatsEntry(ssrc);
+  SsrcStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
-  stats->bitrate_bps = bitrate.bitrate_bps;
+  stats->total_bitrate_bps = total_stats.bitrate_bps;
+  stats->retransmit_bitrate_bps = retransmit_stats.bitrate_bps;
 }
 
 void SendStatisticsProxy::FrameCountUpdated(FrameType frame_type,
                                             uint32_t frame_count,
                                             const unsigned int ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  StreamStats* stats = GetStatsEntry(ssrc);
+  SsrcStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
 
@@ -120,7 +123,7 @@
                                                int max_delay_ms,
                                                uint32_t ssrc) {
   CriticalSectionScoped lock(crit_.get());
-  StreamStats* stats = GetStatsEntry(ssrc);
+  SsrcStats* stats = GetStatsEntry(ssrc);
   if (stats == NULL)
     return;
   stats->avg_delay_ms = avg_delay_ms;
diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h
index ef459da..2f645b1 100644
--- a/webrtc/video/send_statistics_proxy.h
+++ b/webrtc/video/send_statistics_proxy.h
@@ -46,7 +46,9 @@
                                    uint32_t ssrc) OVERRIDE;
 
   // From BitrateStatisticsObserver.
-  virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) OVERRIDE;
+  virtual void Notify(const BitrateStatistics& total_stats,
+                      const BitrateStatistics& retransmit_stats,
+                      uint32_t ssrc) OVERRIDE;
 
   // From FrameCountObserver.
   virtual void FrameCountUpdated(FrameType frame_type,
@@ -75,7 +77,7 @@
                                     uint32_t ssrc) OVERRIDE;
 
  private:
-  StreamStats* GetStatsEntry(uint32_t ssrc) EXCLUSIVE_LOCKS_REQUIRED(crit_);
+  SsrcStats* GetStatsEntry(uint32_t ssrc) EXCLUSIVE_LOCKS_REQUIRED(crit_);
 
   const VideoSendStream::Config config_;
   scoped_ptr<CriticalSectionWrapper> crit_;
diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc
index f768452..d7750f8 100644
--- a/webrtc/video/send_statistics_proxy_unittest.cc
+++ b/webrtc/video/send_statistics_proxy_unittest.cc
@@ -44,22 +44,23 @@
   void ExpectEqual(VideoSendStream::Stats one, VideoSendStream::Stats other) {
     EXPECT_EQ(one.input_frame_rate, other.input_frame_rate);
     EXPECT_EQ(one.encode_frame_rate, other.encode_frame_rate);
+    EXPECT_EQ(one.media_bitrate_bps, other.media_bitrate_bps);
     EXPECT_EQ(one.suspended, other.suspended);
 
     EXPECT_EQ(one.substreams.size(), other.substreams.size());
-    for (std::map<uint32_t, StreamStats>::const_iterator it =
+    for (std::map<uint32_t, SsrcStats>::const_iterator it =
              one.substreams.begin();
          it != one.substreams.end();
          ++it) {
-      std::map<uint32_t, StreamStats>::const_iterator corresponding_it =
+      std::map<uint32_t, SsrcStats>::const_iterator corresponding_it =
           other.substreams.find(it->first);
       ASSERT_TRUE(corresponding_it != other.substreams.end());
-      const StreamStats& a = it->second;
-      const StreamStats& b = corresponding_it->second;
+      const SsrcStats& a = it->second;
+      const SsrcStats& b = corresponding_it->second;
 
       EXPECT_EQ(a.key_frames, b.key_frames);
       EXPECT_EQ(a.delta_frames, b.delta_frames);
-      EXPECT_EQ(a.bitrate_bps, b.bitrate_bps);
+      EXPECT_EQ(a.total_bitrate_bps, b.total_bitrate_bps);
       EXPECT_EQ(a.avg_delay_ms, b.avg_delay_ms);
       EXPECT_EQ(a.max_delay_ms, b.max_delay_ms);
 
@@ -84,7 +85,7 @@
   int avg_delay_ms_;
   int max_delay_ms_;
   VideoSendStream::Stats expected_;
-  typedef std::map<uint32_t, StreamStats>::const_iterator StreamIterator;
+  typedef std::map<uint32_t, SsrcStats>::const_iterator StreamIterator;
 };
 
 TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
@@ -93,7 +94,7 @@
        it != config_.rtp.ssrcs.end();
        ++it) {
     const uint32_t ssrc = *it;
-    StreamStats& ssrc_stats = expected_.substreams[ssrc];
+    SsrcStats& ssrc_stats = expected_.substreams[ssrc];
 
     // Add statistics with some arbitrary, but unique, numbers.
     uint32_t offset = ssrc * sizeof(RtcpStatistics);
@@ -107,7 +108,7 @@
        it != config_.rtp.rtx.ssrcs.end();
        ++it) {
     const uint32_t ssrc = *it;
-    StreamStats& ssrc_stats = expected_.substreams[ssrc];
+    SsrcStats& ssrc_stats = expected_.substreams[ssrc];
 
     // Add statistics with some arbitrary, but unique, numbers.
     uint32_t offset = ssrc * sizeof(RtcpStatistics);
@@ -121,17 +122,25 @@
   ExpectEqual(expected_, stats);
 }
 
-TEST_F(SendStatisticsProxyTest, FrameRates) {
+TEST_F(SendStatisticsProxyTest, CaptureFramerate) {
   const int capture_fps = 31;
-  const int encode_fps = 29;
 
   ViECaptureObserver* capture_observer = statistics_proxy_.get();
   capture_observer->CapturedFrameRate(0, capture_fps);
-  ViEEncoderObserver* encoder_observer = statistics_proxy_.get();
-  encoder_observer->OutgoingRate(0, encode_fps, 0);
 
   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
   EXPECT_EQ(capture_fps, stats.input_frame_rate);
+}
+
+TEST_F(SendStatisticsProxyTest, EncodedBitrateAndFramerate) {
+  const int media_bitrate_bps = 500;
+  const int encode_fps = 29;
+
+  ViEEncoderObserver* encoder_observer = statistics_proxy_.get();
+  encoder_observer->OutgoingRate(0, encode_fps, media_bitrate_bps);
+
+  VideoSendStream::Stats stats = statistics_proxy_->GetStats();
+  EXPECT_EQ(media_bitrate_bps, stats.media_bitrate_bps);
   EXPECT_EQ(encode_fps, stats.encode_frame_rate);
 }
 
@@ -156,8 +165,8 @@
        ++it) {
     const uint32_t ssrc = *it;
     // Add statistics with some arbitrary, but unique, numbers.
-    StreamStats& stats = expected_.substreams[ssrc];
-    uint32_t offset = ssrc * sizeof(StreamStats);
+    SsrcStats& stats = expected_.substreams[ssrc];
+    uint32_t offset = ssrc * sizeof(SsrcStats);
     stats.key_frames = offset;
     stats.delta_frames = offset + 1;
     observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
@@ -168,8 +177,8 @@
        ++it) {
     const uint32_t ssrc = *it;
     // Add statistics with some arbitrary, but unique, numbers.
-    StreamStats& stats = expected_.substreams[ssrc];
-    uint32_t offset = ssrc * sizeof(StreamStats);
+    SsrcStats& stats = expected_.substreams[ssrc];
+    uint32_t offset = ssrc * sizeof(SsrcStats);
     stats.key_frames = offset;
     stats.delta_frames = offset + 1;
     observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
@@ -223,21 +232,27 @@
        it != config_.rtp.ssrcs.end();
        ++it) {
     const uint32_t ssrc = *it;
-    BitrateStatistics bitrate;
+    BitrateStatistics total;
+    BitrateStatistics retransmit;
     // Use ssrc as bitrate_bps to get a unique value for each stream.
-    bitrate.bitrate_bps = ssrc;
-    observer->Notify(bitrate, ssrc);
-    expected_.substreams[ssrc].bitrate_bps = ssrc;
+    total.bitrate_bps = ssrc;
+    retransmit.bitrate_bps = ssrc + 1;
+    observer->Notify(total, retransmit, ssrc);
+    expected_.substreams[ssrc].total_bitrate_bps = total.bitrate_bps;
+    expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit.bitrate_bps;
   }
   for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
        it != config_.rtp.rtx.ssrcs.end();
        ++it) {
     const uint32_t ssrc = *it;
-    BitrateStatistics bitrate;
+    BitrateStatistics total;
+    BitrateStatistics retransmit;
     // Use ssrc as bitrate_bps to get a unique value for each stream.
-    bitrate.bitrate_bps = ssrc;
-    observer->Notify(bitrate, ssrc);
-    expected_.substreams[ssrc].bitrate_bps = ssrc;
+    total.bitrate_bps = ssrc;
+    retransmit.bitrate_bps = ssrc + 1;
+    observer->Notify(total, retransmit, ssrc);
+    expected_.substreams[ssrc].total_bitrate_bps = total.bitrate_bps;
+    expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit.bitrate_bps;
   }
 
   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
@@ -292,9 +307,10 @@
   rtp_callback->DataCountersUpdated(rtp_stats, exluded_ssrc);
 
   // From BitrateStatisticsObserver.
-  BitrateStatistics bitrate;
+  BitrateStatistics total;
+  BitrateStatistics retransmit;
   BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get();
-  bitrate_observer->Notify(bitrate, exluded_ssrc);
+  bitrate_observer->Notify(total, retransmit, exluded_ssrc);
 
   // From FrameCountObserver.
   FrameCountObserver* fps_observer = statistics_proxy_.get();
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index 28231b0..489cd14 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -492,5 +492,12 @@
     rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone);
 }
 
+int VideoSendStream::GetPacerQueuingDelayMs() const {
+  int pacer_delay_ms = 0;
+  if (rtp_rtcp_->GetPacerQueuingDelayMs(channel_, &pacer_delay_ms) != 0) {
+    return 0;
+  }
+  return pacer_delay_ms;
+}
 }  // namespace internal
 }  // namespace webrtc
diff --git a/webrtc/video/video_send_stream.h b/webrtc/video/video_send_stream.h
index f787430..873785d 100644
--- a/webrtc/video/video_send_stream.h
+++ b/webrtc/video/video_send_stream.h
@@ -74,6 +74,8 @@
 
   void SignalNetworkState(Call::NetworkState state);
 
+  int GetPacerQueuingDelayMs() const;
+
  private:
   void ConfigureSsrcs();
   TransportAdapter transport_adapter_;
diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc
index b863957..3ab11274 100644
--- a/webrtc/video/video_send_stream_tests.cc
+++ b/webrtc/video/video_send_stream_tests.cc
@@ -962,8 +962,8 @@
                 config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc));
         // Check for data populated by various sources. RTCP excluded as this
         // data is received from remote side. Tested in call tests instead.
-        const StreamStats& entry = stats.substreams[ssrc];
-        if (entry.key_frames > 0u && entry.bitrate_bps > 0 &&
+        const SsrcStats& entry = stats.substreams[ssrc];
+        if (entry.key_frames > 0u && entry.total_bitrate_bps > 0 &&
             entry.rtp_stats.packets > 0u && entry.avg_delay_ms > 0 &&
             entry.max_delay_ms > 0) {
           return true;
@@ -1045,20 +1045,20 @@
       VideoSendStream::Stats stats = stream_->GetStats();
       if (!stats.substreams.empty()) {
         EXPECT_EQ(1u, stats.substreams.size());
-        int bitrate_bps = stats.substreams.begin()->second.bitrate_bps;
-        test::PrintResult(
-            "bitrate_stats_",
-            "min_transmit_bitrate_low_remb",
-            "bitrate_bps",
-            static_cast<size_t>(bitrate_bps),
-            "bps",
-            false);
-        if (bitrate_bps > kHighBitrateBps) {
+        int total_bitrate_bps =
+            stats.substreams.begin()->second.total_bitrate_bps;
+        test::PrintResult("bitrate_stats_",
+                          "min_transmit_bitrate_low_remb",
+                          "bitrate_bps",
+                          static_cast<size_t>(total_bitrate_bps),
+                          "bps",
+                          false);
+        if (total_bitrate_bps > kHighBitrateBps) {
           rtp_rtcp_->SetREMBData(kRembBitrateBps, 1, &header.ssrc);
           rtp_rtcp_->Process();
           bitrate_capped_ = true;
         } else if (bitrate_capped_ &&
-                   bitrate_bps < kRembRespectedBitrateBps) {
+                   total_bitrate_bps < kRembRespectedBitrateBps) {
           observation_complete_->Set();
         }
       }
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index 0327906..3b8d96a 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -415,10 +415,12 @@
 
   class RegisterableBitrateStatisticsObserver:
     public RegisterableCallback<BitrateStatisticsObserver> {
-    virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) {
+    virtual void Notify(const BitrateStatistics& total_stats,
+                        const BitrateStatistics& retransmit_stats,
+                        uint32_t ssrc) {
       CriticalSectionScoped cs(critsect_.get());
       if (callback_)
-        callback_->Notify(stats, ssrc);
+        callback_->Notify(total_stats, retransmit_stats, ssrc);
     }
   }
   send_bitrate_observer_;
diff --git a/webrtc/video_receive_stream.h b/webrtc/video_receive_stream.h
index 5ab898c..a8620d9 100644
--- a/webrtc/video_receive_stream.h
+++ b/webrtc/video_receive_stream.h
@@ -63,7 +63,7 @@
     int expected_delay_ms;
   };
 
-  struct Stats : public StreamStats {
+  struct Stats : public SsrcStats {
     Stats()
         : network_frame_rate(0),
           decode_frame_rate(0),
diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h
index aa5033a..a9aba94 100644
--- a/webrtc/video_send_stream.h
+++ b/webrtc/video_send_stream.h
@@ -41,11 +41,13 @@
     Stats()
         : input_frame_rate(0),
           encode_frame_rate(0),
+          media_bitrate_bps(0),
           suspended(false) {}
     int input_frame_rate;
     int encode_frame_rate;
+    int media_bitrate_bps;
     bool suspended;
-    std::map<uint32_t, StreamStats> substreams;
+    std::map<uint32_t, SsrcStats> substreams;
   };
 
   struct Config {