Restart VideoReceiveStreams in WebRtcVideoEngine2.

Puts VideoReceiveStreams in a wrapper, WebRtcVideoReceiveStream that
contain their state (configs). WebRtcVideoRenderer (the wrapper between
webrtc::VideoRenderer and cricket::VideoRenderer) has also been merged
into WebRtcVideoReceiveStream.

Implements and tests setting codecs with new FEC settings as well as RTP
header extensions on already existing receive streams.

BUG=1788
R=pthatcher@webrtc.org, wu@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk/talk@6727 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/media/webrtc/webrtcvideoengine2.cc b/media/webrtc/webrtcvideoengine2.cc
index 32c93cf..03c5e14 100644
--- a/media/webrtc/webrtcvideoengine2.cc
+++ b/media/webrtc/webrtcvideoengine2.cc
@@ -638,50 +638,6 @@
   const webrtc::I420VideoFrame* const frame_;
 };
 
-WebRtcVideoRenderer::WebRtcVideoRenderer()
-    : last_width_(-1), last_height_(-1), renderer_(NULL) {}
-
-void WebRtcVideoRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
-                                      int time_to_render_ms) {
-  talk_base::CritScope crit(&lock_);
-  if (renderer_ == NULL) {
-    LOG(LS_WARNING) << "VideoReceiveStream not connected to a VideoRenderer.";
-    return;
-  }
-
-  if (frame.width() != last_width_ || frame.height() != last_height_) {
-    SetSize(frame.width(), frame.height());
-  }
-
-  LOG(LS_VERBOSE) << "RenderFrame: (" << frame.width() << "x" << frame.height()
-                  << ")";
-
-  const WebRtcVideoRenderFrame render_frame(&frame);
-  renderer_->RenderFrame(&render_frame);
-}
-
-void WebRtcVideoRenderer::SetRenderer(cricket::VideoRenderer* renderer) {
-  talk_base::CritScope crit(&lock_);
-  renderer_ = renderer;
-  if (renderer_ != NULL && last_width_ != -1) {
-    SetSize(last_width_, last_height_);
-  }
-}
-
-VideoRenderer* WebRtcVideoRenderer::GetRenderer() {
-  talk_base::CritScope crit(&lock_);
-  return renderer_;
-}
-
-void WebRtcVideoRenderer::SetSize(int width, int height) {
-  talk_base::CritScope crit(&lock_);
-  if (!renderer_->SetSize(width, height, 0)) {
-    LOG(LS_ERROR) << "Could not set renderer size.";
-  }
-  last_width_ = width;
-  last_height_ = height;
-}
-
 // WebRtcVideoChannel2
 
 WebRtcVideoChannel2::WebRtcVideoChannel2(
@@ -720,18 +676,10 @@
     delete it->second;
   }
 
-  for (std::map<uint32, webrtc::VideoReceiveStream*>::iterator it =
+  for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
            receive_streams_.begin();
        it != receive_streams_.end();
        ++it) {
-    assert(it->second != NULL);
-    call_->DestroyVideoReceiveStream(it->second);
-  }
-
-  for (std::map<uint32, WebRtcVideoRenderer*>::iterator it = renderers_.begin();
-       it != renderers_.end();
-       ++it) {
-    assert(it->second != NULL);
     delete it->second;
   }
 }
@@ -812,6 +760,14 @@
   }
 
   recv_codecs_ = mapped_codecs;
+
+  for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
+           receive_streams_.begin();
+       it != receive_streams_.end();
+       ++it) {
+    it->second->SetRecvCodecs(recv_codecs_);
+  }
+
   return true;
 }
 
@@ -832,7 +788,13 @@
   send_codec_.Set(supported_codecs.front());
   LOG(LS_INFO) << "Using codec: " << supported_codecs.front().codec.ToString();
 
-  SetCodecForAllSendStreams(supported_codecs.front());
+  for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
+           send_streams_.begin();
+       it != send_streams_.end();
+       ++it) {
+    assert(it->second != NULL);
+    it->second->SetCodec(supported_codecs.front());
+  }
 
   return true;
 }
@@ -974,87 +936,52 @@
   }
 
   webrtc::VideoReceiveStream::Config config;
-  config.rtp.remote_ssrc = ssrc;
-  config.rtp.local_ssrc = rtcp_receiver_report_ssrc_;
+  ConfigureReceiverRtp(&config, sp);
+  receive_streams_[ssrc] =
+      new WebRtcVideoReceiveStream(call_.get(), config, recv_codecs_);
+
+  return true;
+}
+
+void WebRtcVideoChannel2::ConfigureReceiverRtp(
+    webrtc::VideoReceiveStream::Config* config,
+    const StreamParams& sp) const {
+  uint32 ssrc = sp.first_ssrc();
+
+  config->rtp.remote_ssrc = ssrc;
+  config->rtp.local_ssrc = rtcp_receiver_report_ssrc_;
 
   if (IsNackEnabled(recv_codecs_.begin()->codec)) {
-    config.rtp.nack.rtp_history_ms = kNackHistoryMs;
+    config->rtp.nack.rtp_history_ms = kNackHistoryMs;
   }
-  config.rtp.remb = true;
-  config.rtp.extensions = recv_rtp_extensions_;
+  config->rtp.remb = true;
+  config->rtp.extensions = recv_rtp_extensions_;
   // TODO(pbos): This protection is against setting the same local ssrc as
   // remote which is not permitted by the lower-level API. RTCP requires a
   // corresponding sender SSRC. Figure out what to do when we don't have
   // (receive-only) or know a good local SSRC.
-  if (config.rtp.remote_ssrc == config.rtp.local_ssrc) {
-    if (config.rtp.local_ssrc != kDefaultRtcpReceiverReportSsrc) {
-      config.rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc;
+  if (config->rtp.remote_ssrc == config->rtp.local_ssrc) {
+    if (config->rtp.local_ssrc != kDefaultRtcpReceiverReportSsrc) {
+      config->rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc;
     } else {
-      config.rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc + 1;
+      config->rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc + 1;
     }
   }
-  bool default_renderer_used = false;
-  for (std::map<uint32, WebRtcVideoRenderer*>::iterator it = renderers_.begin();
-       it != renderers_.end();
-       ++it) {
-    if (it->second->GetRenderer() == default_renderer_) {
-      default_renderer_used = true;
+
+  for (size_t i = 0; i < recv_codecs_.size(); ++i) {
+    if (recv_codecs_[i].codec.id == kDefaultVideoCodecPref.payload_type) {
+      config->rtp.fec = recv_codecs_[i].fec;
+      uint32 rtx_ssrc;
+      if (recv_codecs_[i].rtx_payload_type != -1 &&
+          sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
+        config->rtp.rtx[kDefaultVideoCodecPref.payload_type].ssrc = rtx_ssrc;
+        config->rtp.rtx[kDefaultVideoCodecPref.payload_type].payload_type =
+            recv_codecs_[i].rtx_payload_type;
+      }
       break;
     }
   }
 
-  assert(renderers_[ssrc] == NULL);
-  renderers_[ssrc] = new WebRtcVideoRenderer();
-  if (!default_renderer_used) {
-    renderers_[ssrc]->SetRenderer(default_renderer_);
-  }
-  config.renderer = renderers_[ssrc];
-
-  {
-    // TODO(pbos): Base receive codecs off recv_codecs_ and set up using a
-    // DecoderFactory similar to send side. Pending webrtc:2854.
-    // Also set up default codecs if there's nothing in recv_codecs_.
-    webrtc::VideoCodec codec;
-    memset(&codec, 0, sizeof(codec));
-
-    codec.plType = kDefaultVideoCodecPref.payload_type;
-    talk_base::strcpyn(codec.plName, ARRAY_SIZE(codec.plName),
-        kDefaultVideoCodecPref.name);
-    codec.codecType = webrtc::kVideoCodecVP8;
-    codec.codecSpecific.VP8.resilience = webrtc::kResilientStream;
-    codec.codecSpecific.VP8.numberOfTemporalLayers = 1;
-    codec.codecSpecific.VP8.denoisingOn = true;
-    codec.codecSpecific.VP8.errorConcealmentOn = false;
-    codec.codecSpecific.VP8.automaticResizeOn = false;
-    codec.codecSpecific.VP8.frameDroppingOn = true;
-    codec.codecSpecific.VP8.keyFrameInterval = 3000;
-    // Bitrates don't matter and are ignored for the receiver. This is put in to
-    // have the current underlying implementation accept the VideoCodec.
-    codec.minBitrate = codec.startBitrate = codec.maxBitrate = 300;
-    config.codecs.push_back(codec);
-    for (size_t i = 0; i < recv_codecs_.size(); ++i) {
-      if (recv_codecs_[i].codec.id == codec.plType) {
-        config.rtp.fec = recv_codecs_[i].fec;
-        uint32 rtx_ssrc;
-        if (recv_codecs_[i].rtx_payload_type != -1 &&
-            sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
-          config.rtp.rtx[codec.plType].ssrc = rtx_ssrc;
-          config.rtp.rtx[codec.plType].payload_type =
-              recv_codecs_[i].rtx_payload_type;
-        }
-        break;
-      }
-    }
-  }
-
-  webrtc::VideoReceiveStream* receive_stream =
-      call_->CreateVideoReceiveStream(config);
-  assert(receive_stream != NULL);
-
-  receive_streams_[ssrc] = receive_stream;
-  receive_stream->Start();
-
-  return true;
 }
 
 bool WebRtcVideoChannel2::RemoveRecvStream(uint32 ssrc) {
@@ -1063,21 +990,15 @@
     ssrc = default_recv_ssrc_;
   }
 
-  std::map<uint32, webrtc::VideoReceiveStream*>::iterator stream =
+  std::map<uint32, WebRtcVideoReceiveStream*>::iterator stream =
       receive_streams_.find(ssrc);
   if (stream == receive_streams_.end()) {
     LOG(LS_ERROR) << "Stream not found for ssrc: " << ssrc;
     return false;
   }
-  call_->DestroyVideoReceiveStream(stream->second);
+  delete stream->second;
   receive_streams_.erase(stream);
 
-  std::map<uint32, WebRtcVideoRenderer*>::iterator renderer =
-      renderers_.find(ssrc);
-  assert(renderer != renderers_.end());
-  delete renderer->second;
-  renderers_.erase(renderer);
-
   if (ssrc == default_recv_ssrc_) {
     default_recv_ssrc_ = 0;
   }
@@ -1088,16 +1009,19 @@
 bool WebRtcVideoChannel2::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
   LOG(LS_INFO) << "SetRenderer: ssrc:" << ssrc << " "
                << (renderer ? "(ptr)" : "NULL");
-  bool is_default_ssrc = false;
   if (ssrc == 0) {
-    is_default_ssrc = true;
+    if (default_recv_ssrc_!= 0) {
+      receive_streams_[default_recv_ssrc_]->SetRenderer(renderer);
+    }
     ssrc = default_recv_ssrc_;
     default_renderer_ = renderer;
+    return true;
   }
 
-  std::map<uint32, WebRtcVideoRenderer*>::iterator it = renderers_.find(ssrc);
-  if (it == renderers_.end()) {
-    return is_default_ssrc;
+  std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
+      receive_streams_.find(ssrc);
+  if (it == receive_streams_.end()) {
+    return false;
   }
 
   it->second->SetRenderer(renderer);
@@ -1113,8 +1037,9 @@
     return true;
   }
 
-  std::map<uint32, WebRtcVideoRenderer*>::iterator it = renderers_.find(ssrc);
-  if (it == renderers_.end()) {
+  std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
+      receive_streams_.find(ssrc);
+  if (it == receive_streams_.end()) {
     return false;
   }
   *renderer = it->second->GetRenderer();
@@ -1179,6 +1104,7 @@
   sp.ssrcs.push_back(ssrc);
   LOG(LS_INFO) << "Creating default receive stream for SSRC=" << ssrc << ".";
   AddRecvStream(sp);
+  SetRenderer(0, default_renderer_);
 
   if (call_->Receiver()->DeliverPacket(
           reinterpret_cast<const uint8_t*>(packet->data()), packet->length()) !=
@@ -1226,6 +1152,14 @@
     webrtc_extensions.push_back(webrtc_extension);
   }
   recv_rtp_extensions_ = webrtc_extensions;
+
+  for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
+           receive_streams_.begin();
+       it != receive_streams_.end();
+       ++it) {
+    it->second->SetRtpExtensions(recv_rtp_extensions_);
+  }
+
   return true;
 }
 
@@ -1241,6 +1175,12 @@
     webrtc_extensions.push_back(webrtc_extension);
   }
   send_rtp_extensions_ = webrtc_extensions;
+  for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
+           send_streams_.begin();
+       it != send_streams_.end();
+       ++it) {
+    it->second->SetRtpExtensions(send_rtp_extensions_);
+  }
   return true;
 }
 
@@ -1319,17 +1259,6 @@
   }
 }
 
-void WebRtcVideoChannel2::SetCodecForAllSendStreams(
-    const WebRtcVideoChannel2::VideoCodecSettings& codec) {
-  for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
-           send_streams_.begin();
-       it != send_streams_.end();
-       ++it) {
-    assert(it->second != NULL);
-    it->second->SetCodec(codec);
-  }
-}
-
 WebRtcVideoChannel2::WebRtcVideoSendStream::VideoSendStreamParameters::
     VideoSendStreamParameters(
         const webrtc::VideoSendStream::Config& config,
@@ -1577,6 +1506,13 @@
   delete old_encoder;
 }
 
+void WebRtcVideoChannel2::WebRtcVideoSendStream::SetRtpExtensions(
+    const std::vector<webrtc::RtpExtension>& rtp_extensions) {
+  talk_base::CritScope cs(&lock_);
+  parameters_.config.rtp.extensions = rtp_extensions;
+  RecreateWebRtcStream();
+}
+
 void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions(int width,
                                                                int height) {
   assert(!parameters_.video_streams.empty());
@@ -1626,6 +1562,115 @@
   }
 }
 
+WebRtcVideoChannel2::WebRtcVideoReceiveStream::WebRtcVideoReceiveStream(
+    webrtc::Call* call,
+    const webrtc::VideoReceiveStream::Config& config,
+    const std::vector<VideoCodecSettings>& recv_codecs)
+    : call_(call),
+      config_(config),
+      stream_(NULL),
+      last_width_(-1),
+      last_height_(-1),
+      renderer_(NULL) {
+  config_.renderer = this;
+  // SetRecvCodecs will also reset (start) the VideoReceiveStream.
+  SetRecvCodecs(recv_codecs);
+}
+
+WebRtcVideoChannel2::WebRtcVideoReceiveStream::~WebRtcVideoReceiveStream() {
+  call_->DestroyVideoReceiveStream(stream_);
+}
+
+void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRecvCodecs(
+    const std::vector<VideoCodecSettings>& recv_codecs) {
+  // TODO(pbos): Reconfigure RTX based on incoming recv_codecs.
+  // TODO(pbos): Base receive codecs off recv_codecs_ and set up using a
+  // DecoderFactory similar to send side. Pending webrtc:2854.
+  // Also set up default codecs if there's nothing in recv_codecs_.
+  webrtc::VideoCodec codec;
+  memset(&codec, 0, sizeof(codec));
+
+  codec.plType = kDefaultVideoCodecPref.payload_type;
+  strcpy(codec.plName, kDefaultVideoCodecPref.name);
+  codec.codecType = webrtc::kVideoCodecVP8;
+  codec.codecSpecific.VP8.resilience = webrtc::kResilientStream;
+  codec.codecSpecific.VP8.numberOfTemporalLayers = 1;
+  codec.codecSpecific.VP8.denoisingOn = true;
+  codec.codecSpecific.VP8.errorConcealmentOn = false;
+  codec.codecSpecific.VP8.automaticResizeOn = false;
+  codec.codecSpecific.VP8.frameDroppingOn = true;
+  codec.codecSpecific.VP8.keyFrameInterval = 3000;
+  // Bitrates don't matter and are ignored for the receiver. This is put in to
+  // have the current underlying implementation accept the VideoCodec.
+  codec.minBitrate = codec.startBitrate = codec.maxBitrate = 300;
+  config_.codecs.clear();
+  config_.codecs.push_back(codec);
+
+  config_.rtp.fec = recv_codecs.front().fec;
+
+  RecreateWebRtcStream();
+}
+
+void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRtpExtensions(
+    const std::vector<webrtc::RtpExtension>& extensions) {
+  config_.rtp.extensions = extensions;
+  RecreateWebRtcStream();
+}
+
+void WebRtcVideoChannel2::WebRtcVideoReceiveStream::RecreateWebRtcStream() {
+  if (stream_ != NULL) {
+    call_->DestroyVideoReceiveStream(stream_);
+  }
+  stream_ = call_->CreateVideoReceiveStream(config_);
+  stream_->Start();
+}
+
+void WebRtcVideoChannel2::WebRtcVideoReceiveStream::RenderFrame(
+    const webrtc::I420VideoFrame& frame,
+    int time_to_render_ms) {
+  talk_base::CritScope crit(&renderer_lock_);
+  if (renderer_ == NULL) {
+    LOG(LS_WARNING) << "VideoReceiveStream not connected to a VideoRenderer.";
+    return;
+  }
+
+  if (frame.width() != last_width_ || frame.height() != last_height_) {
+    SetSize(frame.width(), frame.height());
+  }
+
+  LOG(LS_VERBOSE) << "RenderFrame: (" << frame.width() << "x" << frame.height()
+                  << ")";
+
+  const WebRtcVideoRenderFrame render_frame(&frame);
+  renderer_->RenderFrame(&render_frame);
+}
+
+void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRenderer(
+    cricket::VideoRenderer* renderer) {
+  talk_base::CritScope crit(&renderer_lock_);
+  renderer_ = renderer;
+  if (renderer_ != NULL && last_width_ != -1) {
+    SetSize(last_width_, last_height_);
+  }
+}
+
+VideoRenderer* WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetRenderer() {
+  // TODO(pbos): Remove GetRenderer and all uses of it, it's thread-unsafe by
+  // design.
+  talk_base::CritScope crit(&renderer_lock_);
+  return renderer_;
+}
+
+void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetSize(int width,
+                                                            int height) {
+  talk_base::CritScope crit(&renderer_lock_);
+  if (!renderer_->SetSize(width, height, 0)) {
+    LOG(LS_ERROR) << "Could not set renderer size.";
+  }
+  last_width_ = width;
+  last_height_ = height;
+}
+
 WebRtcVideoChannel2::VideoCodecSettings::VideoCodecSettings()
     : rtx_payload_type(-1) {}
 
diff --git a/media/webrtc/webrtcvideoengine2.h b/media/webrtc/webrtcvideoengine2.h
index 5122390..fe798b5 100644
--- a/media/webrtc/webrtcvideoengine2.h
+++ b/media/webrtc/webrtcvideoengine2.h
@@ -41,6 +41,7 @@
 #include "webrtc/transport.h"
 #include "webrtc/video_renderer.h"
 #include "webrtc/video_send_stream.h"
+#include "webrtc/video_receive_stream.h"
 
 namespace webrtc {
 class Call;
@@ -170,29 +171,6 @@
   WebRtcVideoEncoderFactory2 default_video_encoder_factory_;
 };
 
-// Adapter between webrtc::VideoRenderer and cricket::VideoRenderer.
-// The webrtc::VideoRenderer is set once, whereas the cricket::VideoRenderer can
-// be set after initialization. This adapter will also convert the incoming
-// webrtc::I420VideoFrame to a frame type that cricket::VideoRenderer can
-// render.
-class WebRtcVideoRenderer : public webrtc::VideoRenderer {
- public:
-  WebRtcVideoRenderer();
-
-  virtual void RenderFrame(const webrtc::I420VideoFrame& frame,
-                           int time_to_render_ms) OVERRIDE;
-
-  void SetRenderer(cricket::VideoRenderer* renderer);
-  cricket::VideoRenderer* GetRenderer();
-
- private:
-  void SetSize(int width, int height);
-  int last_width_;
-  int last_height_;
-  talk_base::CriticalSection lock_;
-  cricket::VideoRenderer* renderer_ GUARDED_BY(lock_);
-};
-
 class WebRtcVideoChannel2 : public talk_base::MessageHandler,
                             public VideoMediaChannel,
                             public webrtc::newapi::Transport {
@@ -261,6 +239,9 @@
   bool GetRenderer(uint32 ssrc, VideoRenderer** renderer);
 
  private:
+  void ConfigureReceiverRtp(webrtc::VideoReceiveStream::Config* config,
+                            const StreamParams& sp) const;
+
   struct VideoCodecSettings {
     VideoCodecSettings();
 
@@ -269,6 +250,8 @@
     int rtx_payload_type;
   };
 
+  // Wrapper for the sender part, this is where the capturer is connected and
+  // frames are then converted from cricket frames to webrtc frames.
   class WebRtcVideoSendStream : public sigslot::has_slots<> {
    public:
     WebRtcVideoSendStream(
@@ -282,6 +265,8 @@
     ~WebRtcVideoSendStream();
     void SetOptions(const VideoOptions& options);
     void SetCodec(const VideoCodecSettings& codec);
+    void SetRtpExtensions(
+        const std::vector<webrtc::RtpExtension>& rtp_extensions);
 
     void InputFrame(VideoCapturer* capturer, const VideoFrame* frame);
     bool SetCapturer(VideoCapturer* capturer);
@@ -332,6 +317,41 @@
     webrtc::I420VideoFrame video_frame_ GUARDED_BY(frame_lock_);
   };
 
+  // Wrapper for the receiver part, contains configs etc. that are needed to
+  // reconstruct the underlying VideoReceiveStream. Also serves as a wrapper
+  // between webrtc::VideoRenderer and cricket::VideoRenderer.
+  class WebRtcVideoReceiveStream : public webrtc::VideoRenderer {
+   public:
+    WebRtcVideoReceiveStream(
+        webrtc::Call*,
+        const webrtc::VideoReceiveStream::Config& config,
+        const std::vector<VideoCodecSettings>& recv_codecs);
+    ~WebRtcVideoReceiveStream();
+
+    void SetRecvCodecs(const std::vector<VideoCodecSettings>& recv_codecs);
+    void SetRtpExtensions(const std::vector<webrtc::RtpExtension>& extensions);
+
+    virtual void RenderFrame(const webrtc::I420VideoFrame& frame,
+                             int time_to_render_ms) OVERRIDE;
+
+    void SetRenderer(cricket::VideoRenderer* renderer);
+    cricket::VideoRenderer* GetRenderer();
+
+   private:
+    void SetSize(int width, int height);
+    void RecreateWebRtcStream();
+
+    webrtc::Call* const call_;
+
+    webrtc::VideoReceiveStream* stream_;
+    webrtc::VideoReceiveStream::Config config_;
+
+    talk_base::CriticalSection renderer_lock_;
+    cricket::VideoRenderer* renderer_ GUARDED_BY(renderer_lock_);
+    int last_width_;
+    int last_height_;
+  };
+
   void Construct(webrtc::Call* call, WebRtcVideoEngine2* engine);
 
   virtual bool SendRtp(const uint8_t* data, size_t len) OVERRIDE;
@@ -339,7 +359,7 @@
 
   void StartAllSendStreams();
   void StopAllSendStreams();
-  void SetCodecForAllSendStreams(const VideoCodecSettings& codec);
+
   static std::vector<VideoCodecSettings> MapCodecs(
       const std::vector<VideoCodec>& codecs);
   std::vector<VideoCodecSettings> FilterSupportedCodecs(
@@ -348,14 +368,13 @@
   uint32_t rtcp_receiver_report_ssrc_;
   bool sending_;
   talk_base::scoped_ptr<webrtc::Call> call_;
-  std::map<uint32, WebRtcVideoRenderer*> renderers_;
-  VideoRenderer* default_renderer_;
   uint32_t default_send_ssrc_;
   uint32_t default_recv_ssrc_;
+  VideoRenderer* default_renderer_;
 
   // Using primary-ssrc (first ssrc) as key.
   std::map<uint32, WebRtcVideoSendStream*> send_streams_;
-  std::map<uint32, webrtc::VideoReceiveStream*> receive_streams_;
+  std::map<uint32, WebRtcVideoReceiveStream*> receive_streams_;
 
   Settable<VideoCodecSettings> send_codec_;
   std::vector<webrtc::RtpExtension> send_rtp_extensions_;
diff --git a/media/webrtc/webrtcvideoengine2_unittest.cc b/media/webrtc/webrtcvideoengine2_unittest.cc
index 28abbd1..d272929 100644
--- a/media/webrtc/webrtcvideoengine2_unittest.cc
+++ b/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -621,6 +621,7 @@
 
   void TestSetSendRtpHeaderExtensions(const std::string& cricket_ext,
                                       const std::string& webrtc_ext) {
+    FakeCall* call = fake_channel_->GetFakeCall();
     // Enable extension.
     const int id = 1;
     std::vector<cricket::RtpHeaderExtension> extensions;
@@ -642,15 +643,25 @@
                     ->GetConfig()
                     .rtp.extensions.empty());
 
-    // Remove the extension id, verify that this doesn't reset extensions as
-    // they should be set before creating channels.
+    // Verify that existing RTP header extensions can be removed.
     std::vector<cricket::RtpHeaderExtension> empty_extensions;
     EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(empty_extensions));
-    EXPECT_FALSE(send_stream->GetConfig().rtp.extensions.empty());
+    ASSERT_EQ(1u, call->GetVideoSendStreams().size());
+    send_stream = call->GetVideoSendStreams()[0];
+    EXPECT_TRUE(send_stream->GetConfig().rtp.extensions.empty());
+
+    // Verify that adding receive RTP header extensions adds them for existing
+    // streams.
+    EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
+    send_stream = call->GetVideoSendStreams()[0];
+    ASSERT_EQ(1u, send_stream->GetConfig().rtp.extensions.size());
+    EXPECT_EQ(id, send_stream->GetConfig().rtp.extensions[0].id);
+    EXPECT_EQ(webrtc_ext, send_stream->GetConfig().rtp.extensions[0].name);
   }
 
   void TestSetRecvRtpHeaderExtensions(const std::string& cricket_ext,
                                       const std::string& webrtc_ext) {
+    FakeCall* call = fake_channel_->GetFakeCall();
     // Enable extension.
     const int id = 1;
     std::vector<cricket::RtpHeaderExtension> extensions;
@@ -666,17 +677,27 @@
     EXPECT_EQ(webrtc_ext, recv_stream->GetConfig().rtp.extensions[0].name);
     // Verify call with same set of extensions returns true.
     EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+
     // Verify that SetRecvRtpHeaderExtensions doesn't implicitly add them for
     // senders.
     EXPECT_TRUE(AddSendStream(cricket::StreamParams::CreateLegacy(123))
                     ->GetConfig()
                     .rtp.extensions.empty());
 
-    // Remove the extension id, verify that this doesn't reset extensions as
-    // they should be set before creating channels.
+    // Verify that existing RTP header extensions can be removed.
     std::vector<cricket::RtpHeaderExtension> empty_extensions;
-    EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(empty_extensions));
-    EXPECT_FALSE(recv_stream->GetConfig().rtp.extensions.empty());
+    EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(empty_extensions));
+    ASSERT_EQ(1u, call->GetVideoReceiveStreams().size());
+    recv_stream = call->GetVideoReceiveStreams()[0];
+    EXPECT_TRUE(recv_stream->GetConfig().rtp.extensions.empty());
+
+    // Verify that adding receive RTP header extensions adds them for existing
+    // streams.
+    EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
+    recv_stream = call->GetVideoReceiveStreams()[0];
+    ASSERT_EQ(1u, recv_stream->GetConfig().rtp.extensions.size());
+    EXPECT_EQ(id, recv_stream->GetConfig().rtp.extensions[0].id);
+    EXPECT_EQ(webrtc_ext, recv_stream->GetConfig().rtp.extensions[0].name);
   }
 
   talk_base::scoped_ptr<VideoMediaChannel> channel_;
@@ -1230,8 +1251,24 @@
   FAIL();  // TODO(pbos): Verify that the FEC parameters are set for all codecs.
 }
 
-TEST_F(WebRtcVideoChannel2Test, DISABLED_SetRecvCodecsWithoutFecDisablesFec) {
-  FAIL() << "Not implemented.";  // TODO(pbos): Implement.
+TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithoutFecDisablesFec) {
+  std::vector<VideoCodec> codecs;
+  codecs.push_back(kVp8Codec);
+  codecs.push_back(kUlpfecCodec);
+  ASSERT_TRUE(channel_->SetSendCodecs(codecs));
+
+  FakeVideoReceiveStream* stream = AddRecvStream();
+  webrtc::VideoReceiveStream::Config config = stream->GetConfig();
+
+  EXPECT_EQ(kUlpfecCodec.id, config.rtp.fec.ulpfec_payload_type);
+
+  codecs.pop_back();
+  ASSERT_TRUE(channel_->SetRecvCodecs(codecs));
+  stream = fake_channel_->GetFakeCall()->GetVideoReceiveStreams()[0];
+  ASSERT_TRUE(stream != NULL);
+  config = stream->GetConfig();
+  EXPECT_EQ(-1, config.rtp.fec.ulpfec_payload_type)
+      << "SetSendCodec without FEC should disable current FEC.";
 }
 
 TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectDuplicateFecPayloads) {