Update stable to r5287.

git-svn-id: http://webrtc.googlecode.com/svn/stable/talk@5288 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/app/webrtc/statscollector.cc b/app/webrtc/statscollector.cc
index b00d19c..7e1e7ee 100644
--- a/app/webrtc/statscollector.cc
+++ b/app/webrtc/statscollector.cc
@@ -51,6 +51,8 @@
 const char StatsReport::kStatsValueNameBucketDelay[] = "googBucketDelay";
 const char StatsReport::kStatsValueNameBytesReceived[] = "bytesReceived";
 const char StatsReport::kStatsValueNameBytesSent[] = "bytesSent";
+const char StatsReport::kStatsValueNameBandwidthLimitedResolution[] =
+    "googBandwidthLimitedResolution";
 const char StatsReport::kStatsValueNameCaptureJitterMs[] =
     "googCaptureJitterMs";
 const char StatsReport::kStatsValueNameCaptureQueueDelayMsPerS[] =
@@ -59,6 +61,8 @@
 const char StatsReport::kStatsValueNameCodecName[] = "googCodecName";
 const char StatsReport::kStatsValueNameComponent[] = "googComponent";
 const char StatsReport::kStatsValueNameContentName[] = "googContentName";
+const char StatsReport::kStatsValueNameCpuLimitedResolution[] =
+    "googCpuLimitedResolution";
 const char StatsReport::kStatsValueNameDer[] = "googDerBase64";
 // Echo metrics from the audio processing module.
 const char StatsReport::kStatsValueNameEchoCancellationQualityMin[] =
@@ -135,6 +139,8 @@
 const char StatsReport::kStatsValueNameTrackId[] = "googTrackId";
 const char StatsReport::kStatsValueNameTypingNoiseState[] =
     "googTypingNoiseState";
+const char StatsReport::kStatsValueNameViewLimitedResolution[] =
+    "googViewLimitedResolution";
 const char StatsReport::kStatsValueNameWritable[] = "googWritable";
 
 const char StatsReport::kStatsReportTypeSession[] = "googLibjingleSession";
@@ -299,6 +305,12 @@
                    info.framerate_sent);
   report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
   report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
+  report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
+                     (info.adapt_reason & 0x1) > 0);
+  report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
+                     (info.adapt_reason & 0x2) > 0);
+  report->AddBoolean(StatsReport::kStatsValueNameViewLimitedResolution,
+                     (info.adapt_reason & 0x4) > 0);
   report->AddValue(StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms);
   report->AddValue(StatsReport::kStatsValueNameCaptureJitterMs,
                    info.capture_jitter_ms);
diff --git a/app/webrtc/statstypes.h b/app/webrtc/statstypes.h
index 6afc8d7..6890f9e 100644
--- a/app/webrtc/statstypes.h
+++ b/app/webrtc/statstypes.h
@@ -133,6 +133,9 @@
   static const char kStatsValueNameCaptureJitterMs[];
   static const char kStatsValueNameCaptureQueueDelayMsPerS[];
   static const char kStatsValueNameCodecName[];
+  static const char kStatsValueNameBandwidthLimitedResolution[];
+  static const char kStatsValueNameCpuLimitedResolution[];
+  static const char kStatsValueNameViewLimitedResolution[];
   static const char kStatsValueNameEchoCancellationQualityMin[];
   static const char kStatsValueNameEchoDelayMedian[];
   static const char kStatsValueNameEchoDelayStdDev[];
diff --git a/base/asyncpacketsocket.h b/base/asyncpacketsocket.h
index 8ee0a36..29ab55f 100644
--- a/base/asyncpacketsocket.h
+++ b/base/asyncpacketsocket.h
@@ -38,7 +38,7 @@
 // This structure will have the information about when packet is actually
 // received by socket.
 struct PacketTime {
-  PacketTime() : timestamp(0), not_before(0) {}
+  PacketTime() : timestamp(-1), not_before(-1) {}
   PacketTime(int64 timestamp, int64 not_before)
       : timestamp(timestamp), not_before(not_before) {
   }
diff --git a/media/webrtc/fakewebrtcvideoengine.h b/media/webrtc/fakewebrtcvideoengine.h
index 070c731..bb75c2a 100644
--- a/media/webrtc/fakewebrtcvideoengine.h
+++ b/media/webrtc/fakewebrtcvideoengine.h
@@ -339,12 +339,14 @@
   };
   class Capturer : public webrtc::ViEExternalCapture {
    public:
-    Capturer() : channel_id_(-1), denoising_(false), last_capture_time_(0) { }
+    Capturer() : channel_id_(-1), denoising_(false),
+                 last_capture_time_(0), incoming_frame_num_(0) { }
     int channel_id() const { return channel_id_; }
     void set_channel_id(int channel_id) { channel_id_ = channel_id; }
     bool denoising() const { return denoising_; }
     void set_denoising(bool denoising) { denoising_ = denoising; }
-    int64 last_capture_time() { return last_capture_time_; }
+    int64 last_capture_time() const { return last_capture_time_; }
+    int incoming_frame_num() const { return incoming_frame_num_; }
 
     // From ViEExternalCapture
     virtual int IncomingFrame(unsigned char* videoFrame,
@@ -359,6 +361,7 @@
         const webrtc::ViEVideoFrameI420& video_frame,
         unsigned long long captureTime) {
       last_capture_time_ = captureTime;
+      ++incoming_frame_num_;
       return 0;
     }
 
@@ -366,6 +369,7 @@
     int channel_id_;
     bool denoising_;
     int64 last_capture_time_;
+    int incoming_frame_num_;
   };
 
   FakeWebRtcVideoEngine(const cricket::VideoCodec* const* codecs,
@@ -408,6 +412,16 @@
 
   int GetLastCapturer() const { return last_capturer_; }
   int GetNumCapturers() const { return static_cast<int>(capturers_.size()); }
+  int GetIncomingFrameNum(int channel_id) const {
+    for (std::map<int, Capturer*>::const_iterator iter = capturers_.begin();
+         iter != capturers_.end(); ++iter) {
+      Capturer* capturer = iter->second;
+      if (capturer->channel_id() == channel_id) {
+        return capturer->incoming_frame_num();
+      }
+    }
+    return -1;
+  }
   void set_fail_alloc_capturer(bool fail_alloc_capturer) {
     fail_alloc_capturer_ = fail_alloc_capturer;
   }
diff --git a/media/webrtc/fakewebrtcvoiceengine.h b/media/webrtc/fakewebrtcvoiceengine.h
index 809816b..a68d65e 100644
--- a/media/webrtc/fakewebrtcvoiceengine.h
+++ b/media/webrtc/fakewebrtcvoiceengine.h
@@ -631,6 +631,13 @@
 
   // webrtc::VoENetEqStats
   WEBRTC_STUB(GetNetworkStatistics, (int, webrtc::NetworkStatistics&));
+#ifdef USE_WEBRTC_DEV_BRANCH
+  WEBRTC_FUNC_CONST(GetDecodingCallStatistics, (int channel,
+      webrtc::AudioDecodingCallStats*)) {
+    WEBRTC_CHECK_CHANNEL(channel);
+    return 0;
+  }
+#endif
 
   // webrtc::VoENetwork
   WEBRTC_FUNC(RegisterExternalTransport, (int channel,
diff --git a/media/webrtc/webrtcmediaengine.h b/media/webrtc/webrtcmediaengine.h
index 94e7a99..82abefa 100644
--- a/media/webrtc/webrtcmediaengine.h
+++ b/media/webrtc/webrtcmediaengine.h
@@ -145,6 +145,9 @@
   virtual void SetVideoLogging(int min_sev, const char* filter) OVERRIDE {
     delegate_->SetVideoLogging(min_sev, filter);
   }
+  virtual bool StartAecDump(FILE* file) OVERRIDE {
+    return delegate_->StartAecDump(file);
+  }
   virtual bool RegisterVoiceProcessor(
       uint32 ssrc, VoiceProcessor* video_processor,
       MediaProcessorDirection direction) OVERRIDE {
diff --git a/media/webrtc/webrtcvideoengine.cc b/media/webrtc/webrtcvideoengine.cc
index 1c1ccc3..88e09fc 100644
--- a/media/webrtc/webrtcvideoengine.cc
+++ b/media/webrtc/webrtcvideoengine.cc
@@ -2119,18 +2119,6 @@
 }
 
 WebRtcVideoChannelSendInfo* WebRtcVideoMediaChannel::GetSendChannel(
-    VideoCapturer* video_capturer) {
-  for (SendChannelMap::iterator iter = send_channels_.begin();
-       iter != send_channels_.end(); ++iter) {
-    WebRtcVideoChannelSendInfo* send_channel = iter->second;
-    if (send_channel->video_capturer() == video_capturer) {
-      return send_channel;
-    }
-  }
-  return NULL;
-}
-
-WebRtcVideoChannelSendInfo* WebRtcVideoMediaChannel::GetSendChannel(
     uint32 local_ssrc) {
   uint32 key;
   if (!GetSendChannelKey(local_ssrc, &key)) {
@@ -2159,6 +2147,18 @@
   return true;
 }
 
+int WebRtcVideoMediaChannel::GetSendChannelNum(VideoCapturer* capturer) {
+  int num = 0;
+  for (SendChannelMap::iterator iter = send_channels_.begin();
+       iter != send_channels_.end(); ++iter) {
+    WebRtcVideoChannelSendInfo* send_channel = iter->second;
+    if (send_channel->video_capturer() == capturer) {
+      ++num;
+    }
+  }
+  return num;
+}
+
 uint32 WebRtcVideoMediaChannel::GetDefaultChannelSsrc() {
   WebRtcVideoChannelSendInfo* send_channel = send_channels_[0];
   const StreamParams* sp = send_channel->stream_params();
@@ -2174,11 +2174,8 @@
     return false;
   }
   WebRtcVideoChannelSendInfo* send_channel = send_channels_[ssrc_key];
-  VideoCapturer* capturer = send_channel->video_capturer();
-  if (capturer != NULL) {
-    capturer->SignalVideoFrame.disconnect(this);
-    send_channel->set_video_capturer(NULL);
-  }
+  MaybeDisconnectCapturer(send_channel->video_capturer());
+  send_channel->set_video_capturer(NULL);
 
   int channel_id = send_channel->channel_id();
   int capture_id = send_channel->capture_id();
@@ -2217,7 +2214,7 @@
   if (capturer == NULL) {
     return false;
   }
-  capturer->SignalVideoFrame.disconnect(this);
+  MaybeDisconnectCapturer(capturer);
   send_channel->set_video_capturer(NULL);
   const int64 timestamp = send_channel->local_stream_info()->time_stamp();
   if (send_codec_) {
@@ -2468,14 +2465,10 @@
     return false;
   }
   VideoCapturer* old_capturer = send_channel->video_capturer();
-  if (old_capturer) {
-    old_capturer->SignalVideoFrame.disconnect(this);
-  }
+  MaybeDisconnectCapturer(old_capturer);
 
   send_channel->set_video_capturer(capturer);
-  capturer->SignalVideoFrame.connect(
-      this,
-      &WebRtcVideoMediaChannel::SendFrame);
+  MaybeConnectCapturer(capturer);
   if (!capturer->IsScreencast() && ratio_w_ != 0 && ratio_h_ != 0) {
     capturer->UpdateAspectRatio(ratio_w_, ratio_h_);
   }
@@ -2865,20 +2858,23 @@
   return true;
 }
 
-// TODO(zhurunz): Add unittests to test this function.
-// TODO(thorcarpenter): This is broken. One capturer registered on two ssrc
-// will not send any video to the second ssrc send channel. We should remove
-// GetSendChannel(capturer) and pass in an ssrc here.
 void WebRtcVideoMediaChannel::SendFrame(VideoCapturer* capturer,
                                         const VideoFrame* frame) {
-  // If there's send channel registers to the |capturer|, then only send the
-  // frame to that channel and return. Otherwise send the frame to the default
-  // channel, which currently taking frames from the engine.
-  WebRtcVideoChannelSendInfo* send_channel = GetSendChannel(capturer);
-  if (send_channel) {
-    SendFrame(send_channel, frame, capturer->IsScreencast());
+  // If the |capturer| is registered to any send channel, then send the frame
+  // to those send channels.
+  bool capturer_is_channel_owned = false;
+  for (SendChannelMap::iterator iter = send_channels_.begin();
+       iter != send_channels_.end(); ++iter) {
+    WebRtcVideoChannelSendInfo* send_channel = iter->second;
+    if (send_channel->video_capturer() == capturer) {
+      SendFrame(send_channel, frame, capturer->IsScreencast());
+      capturer_is_channel_owned = true;
+    }
+  }
+  if (capturer_is_channel_owned) {
     return;
   }
+
   // TODO(hellner): Remove below for loop once the captured frame no longer
   // come from the engine, i.e. the engine no longer owns a capturer.
   for (SendChannelMap::iterator iter = send_channels_.begin();
@@ -3754,6 +3750,19 @@
   return true;
 }
 
+void WebRtcVideoMediaChannel::MaybeConnectCapturer(VideoCapturer* capturer) {
+  if (capturer != NULL && GetSendChannelNum(capturer) == 1) {
+    capturer->SignalVideoFrame.connect(this,
+                                       &WebRtcVideoMediaChannel::SendFrame);
+  }
+}
+
+void WebRtcVideoMediaChannel::MaybeDisconnectCapturer(VideoCapturer* capturer) {
+  if (capturer != NULL && GetSendChannelNum(capturer) == 1) {
+    capturer->SignalVideoFrame.disconnect(this);
+  }
+}
+
 }  // namespace cricket
 
 #endif  // HAVE_WEBRTC_VIDEO
diff --git a/media/webrtc/webrtcvideoengine.h b/media/webrtc/webrtcvideoengine.h
index 6278461..289903a 100644
--- a/media/webrtc/webrtcvideoengine.h
+++ b/media/webrtc/webrtcvideoengine.h
@@ -366,11 +366,12 @@
   // If the local ssrc correspond to that of the default channel the key is 0.
   // For all other channels the returned key will be the same as the local ssrc.
   bool GetSendChannelKey(uint32 local_ssrc, uint32* key);
-  WebRtcVideoChannelSendInfo* GetSendChannel(VideoCapturer* video_capturer);
   WebRtcVideoChannelSendInfo* GetSendChannel(uint32 local_ssrc);
   // Creates a new unique key that can be used for inserting a new send channel
   // into |send_channels_|
   bool CreateSendChannelKey(uint32 local_ssrc, uint32* key);
+  // Get the number of the send channels |capturer| registered with.
+  int GetSendChannelNum(VideoCapturer* capturer);
 
   bool IsDefaultChannel(int channel_id) const {
     return channel_id == vie_channel_;
@@ -404,6 +405,13 @@
   bool SetLocalRtxSsrc(int channel_id, const StreamParams& send_params,
                        uint32 primary_ssrc, int stream_idx);
 
+  // Connect |capturer| to WebRtcVideoMediaChannel if it is only registered
+  // to one send channel, i.e. the first send channel.
+  void MaybeConnectCapturer(VideoCapturer* capturer);
+  // Disconnect |capturer| from WebRtcVideoMediaChannel if it is only registered
+  // to one send channel, i.e. the last send channel.
+  void MaybeDisconnectCapturer(VideoCapturer* capturer);
+
   // Global state.
   WebRtcVideoEngine* engine_;
   VoiceMediaChannel* voice_channel_;
diff --git a/media/webrtc/webrtcvideoengine_unittest.cc b/media/webrtc/webrtcvideoengine_unittest.cc
index 2b83cce..d5886a1 100644
--- a/media/webrtc/webrtcvideoengine_unittest.cc
+++ b/media/webrtc/webrtcvideoengine_unittest.cc
@@ -1216,6 +1216,53 @@
   EXPECT_FALSE(vie_.GetCaptureDenoising(capture_id));
 }
 
+TEST_F(WebRtcVideoEngineTestFake, MultipleSendStreamsWithOneCapturer) {
+  EXPECT_TRUE(SetupEngine());
+
+  // Start the capturer
+  cricket::FakeVideoCapturer capturer;
+  cricket::VideoFormat capture_format_vga = cricket::VideoFormat(640, 480,
+        cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420);
+  EXPECT_EQ(cricket::CS_RUNNING, capturer.Start(capture_format_vga));
+
+  // Add send streams and connect the capturer
+  for (unsigned int i = 0; i < sizeof(kSsrcs2)/sizeof(kSsrcs2[0]); ++i) {
+    EXPECT_TRUE(channel_->AddSendStream(
+        cricket::StreamParams::CreateLegacy(kSsrcs2[i])));
+    // Register the capturer to the ssrc.
+    EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[i], &capturer));
+  }
+
+  const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs2[0]);
+  ASSERT_NE(-1, channel0);
+  const int channel1 = vie_.GetChannelFromLocalSsrc(kSsrcs2[1]);
+  ASSERT_NE(-1, channel1);
+  ASSERT_NE(channel0, channel1);
+
+  // Set send codec.
+  std::vector<cricket::VideoCodec> codecs;
+  cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
+  codecs.push_back(send_codec);
+  EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+
+  EXPECT_TRUE(capturer.CaptureFrame());
+  EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel0));
+  EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel1));
+
+  EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs2[0]));
+  EXPECT_TRUE(capturer.CaptureFrame());
+  // channel0 is the default channel, so it won't be deleted.
+  // But it should be disconnected from the capturer.
+  EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel0));
+  EXPECT_EQ(2, vie_.GetIncomingFrameNum(channel1));
+
+  EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs2[1]));
+  EXPECT_TRUE(capturer.CaptureFrame());
+  EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel0));
+  // channel1 has already been deleted.
+  EXPECT_EQ(-1, vie_.GetIncomingFrameNum(channel1));
+}
+
 
 // Disabled since its flaky: b/11288120
 TEST_F(WebRtcVideoEngineTestFake, DISABLED_SendReceiveBitratesStats) {