Implementing a packet router class, used to route RTP packets to the
sending RTP module for the specified simulcast layer a frame belongs to.
This CL also removes the corresponding functionality from the RTP RTCP
module and fixes lint warnings in the files touched.

BUG=769
TEST=New unittest and manual tests
R=stefan@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#8267}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8267 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index bfc8266..8bde0a8 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -13,6 +13,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include <set>
+
 #include "webrtc/common_types.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/system_wrappers/interface/trace.h"
@@ -491,74 +493,21 @@
     size_t payload_size,
     const RTPFragmentationHeader* fragmentation,
     const RTPVideoHeader* rtp_video_hdr) {
-  rtcp_sender_.SetLastRtpTime(time_stamp, capture_time_ms);
+  assert(!IsDefaultModule());
 
-  if (!IsDefaultModule()) {
-    // Don't send RTCP from default module.
-    if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) {
+  rtcp_sender_.SetLastRtpTime(time_stamp, capture_time_ms);
+  if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) {
       rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport);
-    }
-    return rtp_sender_.SendOutgoingData(frame_type,
-                                        payload_type,
-                                        time_stamp,
-                                        capture_time_ms,
-                                        payload_data,
-                                        payload_size,
-                                        fragmentation,
-                                        NULL,
-                                        &(rtp_video_hdr->codecHeader));
   }
-  int32_t ret_val = -1;
-  CriticalSectionScoped lock(critical_section_module_ptrs_.get());
-  if (simulcast_) {
-    if (rtp_video_hdr == NULL) {
-      return -1;
-    }
-    int idx = 0;
-    std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
-    for (; idx < rtp_video_hdr->simulcastIdx; ++it) {
-      if (it == child_modules_.end()) {
-        return -1;
-      }
-      if ((*it)->SendingMedia()) {
-        ++idx;
-      }
-    }
-    for (; it != child_modules_.end(); ++it) {
-      if ((*it)->SendingMedia()) {
-        break;
-      }
-      ++idx;
-    }
-    if (it == child_modules_.end()) {
-      return -1;
-    }
-    return (*it)->SendOutgoingData(frame_type,
-                                   payload_type,
-                                   time_stamp,
-                                   capture_time_ms,
-                                   payload_data,
-                                   payload_size,
-                                   fragmentation,
-                                   rtp_video_hdr);
-  } else {
-    std::vector<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
-    // Send to all "child" modules
-    while (it != child_modules_.end()) {
-      if ((*it)->SendingMedia()) {
-        ret_val = (*it)->SendOutgoingData(frame_type,
-                                          payload_type,
-                                          time_stamp,
-                                          capture_time_ms,
-                                          payload_data,
-                                          payload_size,
-                                          fragmentation,
-                                          rtp_video_hdr);
-      }
-      it++;
-    }
-  }
-  return ret_val;
+  return rtp_sender_.SendOutgoingData(frame_type,
+                                      payload_type,
+                                      time_stamp,
+                                      capture_time_ms,
+                                      payload_data,
+                                      payload_size,
+                                      fragmentation,
+                                      NULL,
+                                      &(rtp_video_hdr->codecHeader));
 }
 
 bool ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc,
@@ -1346,4 +1295,4 @@
   return !child_modules_.empty();
 }
 
-}  // Namespace webrtc
+}  // namespace webrtc
diff --git a/webrtc/video_engine/BUILD.gn b/webrtc/video_engine/BUILD.gn
index 889e054..99c16ac 100644
--- a/webrtc/video_engine/BUILD.gn
+++ b/webrtc/video_engine/BUILD.gn
@@ -29,6 +29,8 @@
     "encoder_state_feedback.h",
     "overuse_frame_detector.cc",
     "overuse_frame_detector.h",
+    "payload_router.cc",
+    "payload_router.h",
     "report_block_stats.cc",
     "report_block_stats.h",
     "stream_synchronization.cc",
diff --git a/webrtc/video_engine/payload_router.cc b/webrtc/video_engine/payload_router.cc
new file mode 100644
index 0000000..f815d13
--- /dev/null
+++ b/webrtc/video_engine/payload_router.cc
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/video_engine/payload_router.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
+#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+
+namespace webrtc {
+
+PayloadRouter::PayloadRouter()
+    : crit_(CriticalSectionWrapper::CreateCriticalSection()),
+      active_(false) {}
+
+PayloadRouter::~PayloadRouter() {}
+
+void PayloadRouter::SetSendingRtpModules(
+    const std::list<RtpRtcp*>& rtp_modules) {
+  CriticalSectionScoped cs(crit_.get());
+  rtp_modules_.clear();
+  rtp_modules_.reserve(rtp_modules.size());
+  for (auto* rtp_module : rtp_modules) {
+    rtp_modules_.push_back(rtp_module);
+  }
+}
+
+void PayloadRouter::set_active(bool active) {
+  CriticalSectionScoped cs(crit_.get());
+  active_ = active;
+}
+
+bool PayloadRouter::active() {
+  CriticalSectionScoped cs(crit_.get());
+  return active_;
+}
+
+bool PayloadRouter::RoutePayload(FrameType frame_type,
+                                 int8_t payload_type,
+                                 uint32_t time_stamp,
+                                 int64_t capture_time_ms,
+                                 const uint8_t* payload_data,
+                                 size_t payload_size,
+                                 const RTPFragmentationHeader* fragmentation,
+                                 const RTPVideoHeader* rtp_video_hdr) {
+  CriticalSectionScoped cs(crit_.get());
+  DCHECK(rtp_video_hdr == NULL ||
+         rtp_video_hdr->simulcastIdx <= rtp_modules_.size());
+
+  if (!active_ || rtp_modules_.empty())
+    return false;
+
+  int stream_idx = 0;
+  if (rtp_video_hdr != NULL)
+    stream_idx = rtp_video_hdr->simulcastIdx;
+  return rtp_modules_[stream_idx]->SendOutgoingData(
+      frame_type, payload_type, time_stamp, capture_time_ms, payload_data,
+      payload_size, fragmentation, rtp_video_hdr) == 0 ? true : false;
+}
+
+}  // namespace webrtc
diff --git a/webrtc/video_engine/payload_router.h b/webrtc/video_engine/payload_router.h
new file mode 100644
index 0000000..3cc0bb0
--- /dev/null
+++ b/webrtc/video_engine/payload_router.h
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_VIDEO_ENGINE_PAYLOAD_ROUTER_H_
+#define WEBRTC_VIDEO_ENGINE_PAYLOAD_ROUTER_H_
+
+#include <list>
+#include <vector>
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/base/thread_annotations.h"
+#include "webrtc/common_types.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+
+namespace webrtc {
+
+class CriticalSectionWrapper;
+class RTPFragmentationHeader;
+class RtpRtcp;
+struct RTPVideoHeader;
+
+// PayloadRouter routes outgoing data to the correct sending RTP module, based
+// on the simulcast layer in RTPVideoHeader.
+class PayloadRouter {
+ public:
+  PayloadRouter();
+  ~PayloadRouter();
+
+  // Rtp modules are assumed to be sorted in simulcast index order.
+  void SetSendingRtpModules(const std::list<RtpRtcp*>& rtp_modules);
+
+  // PayloadRouter will only route packets if being active, all packets will be
+  // dropped otherwise.
+  void set_active(bool active);
+  bool active();
+
+  // Input parameters according to the signature of RtpRtcp::SendOutgoingData.
+  // Returns true if the packet was routed / sent, false otherwise.
+  bool RoutePayload(FrameType frame_type,
+                    int8_t payload_type,
+                    uint32_t time_stamp,
+                    int64_t capture_time_ms,
+                    const uint8_t* payload_data,
+                    size_t payload_size,
+                    const RTPFragmentationHeader* fragmentation,
+                    const RTPVideoHeader* rtp_video_hdr);
+
+ private:
+  scoped_ptr<CriticalSectionWrapper> crit_;
+
+  // Active sending RTP modules, in layer order.
+  std::vector<RtpRtcp*> rtp_modules_ GUARDED_BY(crit_.get());
+  bool active_ GUARDED_BY(crit_.get());
+
+  DISALLOW_COPY_AND_ASSIGN(PayloadRouter);
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_VIDEO_ENGINE_PAYLOAD_ROUTER_H_
diff --git a/webrtc/video_engine/payload_router_unittest.cc b/webrtc/video_engine/payload_router_unittest.cc
new file mode 100644
index 0000000..b4d20bf
--- /dev/null
+++ b/webrtc/video_engine/payload_router_unittest.cc
@@ -0,0 +1,131 @@
+/*
+ *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+
+#include <list>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
+#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/video_engine/payload_router.h"
+
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+namespace webrtc {
+
+class PayloadRouterTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    payload_router_.reset(new PayloadRouter());
+  }
+  scoped_ptr<PayloadRouter> payload_router_;
+};
+
+TEST_F(PayloadRouterTest, SendOnOneModule) {
+  MockRtpRtcp rtp;
+  std::list<RtpRtcp*> modules(1, &rtp);
+
+  payload_router_->SetSendingRtpModules(modules);
+
+  uint8_t payload = 'a';
+  FrameType frame_type = kVideoFrameKey;
+  int8_t payload_type = 96;
+
+  EXPECT_CALL(rtp, SendOutgoingData(frame_type, payload_type, 0, 0, _, 1, NULL,
+                                    NULL))
+      .Times(0);
+  EXPECT_FALSE(payload_router_->RoutePayload(frame_type, payload_type, 0, 0,
+                                             &payload, 1, NULL, NULL));
+
+  payload_router_->set_active(true);
+  EXPECT_CALL(rtp, SendOutgoingData(frame_type, payload_type, 0, 0, _, 1, NULL,
+                                    NULL))
+      .Times(1);
+  EXPECT_TRUE(payload_router_->RoutePayload(frame_type, payload_type, 0, 0,
+                                            &payload, 1, NULL, NULL));
+
+  payload_router_->set_active(false);
+  EXPECT_CALL(rtp, SendOutgoingData(frame_type, payload_type, 0, 0, _, 1, NULL,
+                                    NULL))
+      .Times(0);
+  EXPECT_FALSE(payload_router_->RoutePayload(frame_type, payload_type, 0, 0,
+                                             &payload, 1, NULL, NULL));
+
+  payload_router_->set_active(true);
+  EXPECT_CALL(rtp, SendOutgoingData(frame_type, payload_type, 0, 0, _, 1, NULL,
+                                    NULL))
+      .Times(1);
+  EXPECT_TRUE(payload_router_->RoutePayload(frame_type, payload_type, 0, 0,
+                                            &payload, 1, NULL, NULL));
+
+  modules.clear();
+  payload_router_->SetSendingRtpModules(modules);
+  EXPECT_CALL(rtp, SendOutgoingData(frame_type, payload_type, 0, 0, _, 1, NULL,
+                                    NULL))
+      .Times(0);
+  EXPECT_FALSE(payload_router_->RoutePayload(frame_type, payload_type, 0, 0,
+                                             &payload, 1, NULL, NULL));
+}
+
+TEST_F(PayloadRouterTest, SendSimulcast) {
+  MockRtpRtcp rtp_1;
+  MockRtpRtcp rtp_2;
+  std::list<RtpRtcp*> modules;
+  modules.push_back(&rtp_1);
+  modules.push_back(&rtp_2);
+
+  payload_router_->SetSendingRtpModules(modules);
+
+  uint8_t payload_1 = 'a';
+  FrameType frame_type_1 = kVideoFrameKey;
+  int8_t payload_type_1 = 96;
+  RTPVideoHeader rtp_hdr_1;
+  rtp_hdr_1.simulcastIdx = 0;
+
+  payload_router_->set_active(true);
+  EXPECT_CALL(rtp_1, SendOutgoingData(frame_type_1, payload_type_1, 0, 0, _, 1,
+                                      NULL, &rtp_hdr_1))
+      .Times(1);
+  EXPECT_CALL(rtp_2, SendOutgoingData(_, _, _, _, _, _, _, _))
+      .Times(0);
+  EXPECT_TRUE(payload_router_->RoutePayload(frame_type_1, payload_type_1, 0, 0,
+                                            &payload_1, 1, NULL, &rtp_hdr_1));
+
+  uint8_t payload_2 = 'b';
+  FrameType frame_type_2 = kVideoFrameDelta;
+  int8_t payload_type_2 = 97;
+  RTPVideoHeader rtp_hdr_2;
+  rtp_hdr_2.simulcastIdx = 1;
+  EXPECT_CALL(rtp_2, SendOutgoingData(frame_type_2, payload_type_2, 0, 0, _, 1,
+                                      NULL, &rtp_hdr_2))
+      .Times(1);
+  EXPECT_CALL(rtp_1, SendOutgoingData(_, _, _, _, _, _, _, _))
+      .Times(0);
+  EXPECT_TRUE(payload_router_->RoutePayload(frame_type_2, payload_type_2, 0, 0,
+                                            &payload_2, 1, NULL, &rtp_hdr_2));
+
+  payload_router_->set_active(false);
+  EXPECT_CALL(rtp_1, SendOutgoingData(_, _, _, _, _, _, _, _))
+      .Times(0);
+  EXPECT_CALL(rtp_2, SendOutgoingData(_, _, _, _, _, _, _, _))
+      .Times(0);
+  EXPECT_FALSE(payload_router_->RoutePayload(frame_type_1, payload_type_1, 0, 0,
+                                             &payload_1, 1, NULL, &rtp_hdr_1));
+  EXPECT_FALSE(payload_router_->RoutePayload(frame_type_2, payload_type_2, 0, 0,
+                                             &payload_2, 1, NULL, &rtp_hdr_2));
+}
+
+
+}  // namespace webrtc
diff --git a/webrtc/video_engine/video_engine_core.gypi b/webrtc/video_engine/video_engine_core.gypi
index 72e1c64..02726fb 100644
--- a/webrtc/video_engine/video_engine_core.gypi
+++ b/webrtc/video_engine/video_engine_core.gypi
@@ -49,6 +49,7 @@
         'call_stats.h',
         'encoder_state_feedback.h',
         'overuse_frame_detector.h',
+        'payload_router.h',
         'report_block_stats.h',
         'stream_synchronization.h',
         'vie_base_impl.h',
@@ -83,6 +84,7 @@
         'call_stats.cc',
         'encoder_state_feedback.cc',
         'overuse_frame_detector.cc',
+        'payload_router.cc',
         'report_block_stats.cc',
         'stream_synchronization.cc',
         'vie_base_impl.cc',
@@ -134,6 +136,7 @@
             'call_stats_unittest.cc',
             'encoder_state_feedback_unittest.cc',
             'overuse_frame_detector_unittest.cc',
+            'payload_router_unittest.cc',
             'report_block_stats_unittest.cc',
             'stream_synchronization_unittest.cc',
             'vie_capturer_unittest.cc',
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index 62cfd50..8057ca0 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -34,6 +34,7 @@
 #include "webrtc/video_engine/include/vie_errors.h"
 #include "webrtc/video_engine/include/vie_image_process.h"
 #include "webrtc/video_engine/include/vie_rtp_rtcp.h"
+#include "webrtc/video_engine/payload_router.h"
 #include "webrtc/video_engine/report_block_stats.h"
 #include "webrtc/video_engine/vie_defines.h"
 
@@ -79,6 +80,7 @@
       callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
       rtp_rtcp_cs_(CriticalSectionWrapper::CreateCriticalSection()),
       default_rtp_rtcp_(default_rtp_rtcp),
+      send_payload_router_(new PayloadRouter()),
       vcm_(VideoCodingModule::Create()),
       vie_receiver_(channel_id, vcm_, remote_bitrate_estimator, this),
       vie_sender_(channel_id),
@@ -131,6 +133,11 @@
   if (paced_sender_) {
     rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_);
   }
+  if (sender_) {
+     std::list<RtpRtcp*> send_rtp_modules(1, rtp_rtcp_.get());
+     send_payload_router_->SetSendingRtpModules(send_rtp_modules);
+     send_payload_router_->set_active(true);
+  }
   if (vcm_->InitializeReceiver() != 0) {
     return -1;
   }
@@ -173,6 +180,7 @@
   module_process_thread_.DeRegisterModule(rtp_rtcp_.get());
   module_process_thread_.DeRegisterModule(vcm_);
   module_process_thread_.DeRegisterModule(&vie_sync_);
+  send_payload_router_->SetSendingRtpModules(std::list<RtpRtcp*>());
   while (simulcast_rtp_rtcp_.size() > 0) {
     std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
     RtpRtcp* rtp_rtcp = *it;
@@ -322,6 +330,9 @@
   // Stop and Start the RTP module -> trigger new SSRC, if an SSRC hasn't been
   // set explicitly.
   bool restart_rtp = false;
+  bool router_was_active = send_payload_router_->active();
+  send_payload_router_->set_active(false);
+  send_payload_router_->SetSendingRtpModules(std::list<RtpRtcp*>());
   if (rtp_rtcp_->Sending() && new_stream) {
     restart_rtp = true;
     rtp_rtcp_->SetSendingStatus(false);
@@ -480,6 +491,16 @@
       (*it)->SetSendingMediaStatus(true);
     }
   }
+  // Update the packet router with the sending RTP RTCP modules.
+  std::list<RtpRtcp*> active_send_modules;
+  active_send_modules.push_back(rtp_rtcp_.get());
+  for (std::list<RtpRtcp*>::const_iterator cit = simulcast_rtp_rtcp_.begin();
+       cit != simulcast_rtp_rtcp_.end(); ++cit) {
+    active_send_modules.push_back(*cit);
+  }
+  send_payload_router_->SetSendingRtpModules(active_send_modules);
+  if (router_was_active)
+    send_payload_router_->set_active(true);
   return 0;
 }
 
@@ -854,7 +875,6 @@
 }
 
 int32_t ViEChannel::EnableKeyFrameRequestCallback(const bool enable) {
-
   CriticalSectionScoped cs(callback_cs_.get());
   if (enable && !codec_observer_) {
     LOG(LS_ERROR) << "No ViECodecObserver set.";
@@ -1344,11 +1364,13 @@
     rtp_rtcp->SetSendingMediaStatus(true);
     rtp_rtcp->SetSendingStatus(true);
   }
+  send_payload_router_->set_active(true);
   return 0;
 }
 
 int32_t ViEChannel::StopSend() {
   UpdateHistogramsAtStopSend();
+  send_payload_router_->set_active(false);
   CriticalSectionScoped cs(rtp_rtcp_cs_.get());
   rtp_rtcp_->SetSendingMediaStatus(false);
   for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
@@ -1478,6 +1500,10 @@
   return rtp_rtcp_.get();
 }
 
+PayloadRouter* ViEChannel::send_payload_router() {
+  return send_payload_router_.get();
+}
+
 CallStatsObserver* ViEChannel::GetStatsObserver() {
   return stats_observer_.get();
 }
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index bc91b3a..5640f23 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -38,6 +38,7 @@
 class EncodedImageCallback;
 class I420FrameCallback;
 class PacedSender;
+class PayloadRouter;
 class ProcessThread;
 class ReceiveStatisticsProxy;
 class ReportBlockStats;
@@ -301,6 +302,7 @@
 
   // Gets the modules used by the channel.
   RtpRtcp* rtp_rtcp();
+  PayloadRouter* send_payload_router();
 
   CallStatsObserver* GetStatsObserver();
 
@@ -467,6 +469,8 @@
   scoped_ptr<RtpRtcp> rtp_rtcp_;
   std::list<RtpRtcp*> simulcast_rtp_rtcp_;
   std::list<RtpRtcp*> removed_rtp_rtcp_;
+  scoped_ptr<PayloadRouter> send_payload_router_;
+
   VideoCodingModule* const vcm_;
   ViEReceiver vie_receiver_;
   ViESender vie_sender_;
diff --git a/webrtc/video_engine/vie_channel_manager.cc b/webrtc/video_engine/vie_channel_manager.cc
index aef167f..a2dca8a 100644
--- a/webrtc/video_engine/vie_channel_manager.cc
+++ b/webrtc/video_engine/vie_channel_manager.cc
@@ -10,6 +10,8 @@
 
 #include "webrtc/video_engine/vie_channel_manager.h"
 
+#include <vector>
+
 #include "webrtc/common.h"
 #include "webrtc/engine_configurations.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
@@ -114,6 +116,9 @@
     delete group;
     return -1;
   }
+  // Connect the encoder with the send packet router, to enable sending.
+  vie_encoder->SetSendPayloadRouter(
+      channel_map_[new_channel_id]->send_payload_router());
 
   // Add ViEEncoder to EncoderFeedBackObserver.
   unsigned int ssrc = 0;
@@ -174,6 +179,10 @@
       delete vie_encoder;
       vie_encoder = NULL;
     }
+    // Connect the encoder with the send packet router, to enable sending.
+    vie_encoder->SetSendPayloadRouter(
+        channel_map_[new_channel_id]->send_payload_router());
+
     // Register the ViEEncoder to get key frame requests for this channel.
     unsigned int ssrc = 0;
     int stream_idx = 0;
diff --git a/webrtc/video_engine/vie_encoder.cc b/webrtc/video_engine/vie_encoder.cc
index ca02002..b86c259 100644
--- a/webrtc/video_engine/vie_encoder.cc
+++ b/webrtc/video_engine/vie_encoder.cc
@@ -14,6 +14,7 @@
 
 #include <algorithm>
 
+#include "webrtc/base/checks.h"
 #include "webrtc/common_video/interface/video_image.h"
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
 #include "webrtc/frame_callback.h"
@@ -33,6 +34,7 @@
 #include "webrtc/video/send_statistics_proxy.h"
 #include "webrtc/video_engine/include/vie_codec.h"
 #include "webrtc/video_engine/include/vie_image_process.h"
+#include "webrtc/video_engine/payload_router.h"
 #include "webrtc/video_engine/vie_defines.h"
 
 namespace webrtc {
@@ -137,6 +139,7 @@
     vcm_(*webrtc::VideoCodingModule::Create()),
     vpm_(*webrtc::VideoProcessingModule::Create(ViEModuleId(engine_id,
                                                             channel_id))),
+    send_payload_router_(NULL),
     callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
     data_cs_(CriticalSectionWrapper::CreateCriticalSection()),
     bitrate_controller_(bitrate_controller),
@@ -228,6 +231,11 @@
   return true;
 }
 
+void ViEEncoder::SetSendPayloadRouter(PayloadRouter* send_payload_router) {
+  DCHECK(send_payload_router_ == NULL);
+  send_payload_router_ = send_payload_router;
+}
+
 ViEEncoder::~ViEEncoder() {
   UpdateHistograms();
   if (bitrate_controller_) {
@@ -504,8 +512,10 @@
 void ViEEncoder::DeliverFrame(int id,
                               I420VideoFrame* video_frame,
                               const std::vector<uint32_t>& csrcs) {
-  if (default_rtp_rtcp_->SendingMedia() == false) {
-    // We've paused or we have no channels attached, don't encode.
+  DCHECK(send_payload_router_ != NULL);
+  if (!default_rtp_rtcp_->SendingMedia() || !send_payload_router_->active()) {
+    // We've paused or we have no channels attached, don't waste resources on
+    // encoding.
     return;
   }
   {
@@ -731,15 +741,17 @@
     const EncodedImage& encoded_image,
     const webrtc::RTPFragmentationHeader& fragmentation_header,
     const RTPVideoHeader* rtp_video_hdr) {
+  DCHECK(send_payload_router_ != NULL);
+
   if (send_statistics_proxy_ != NULL) {
     send_statistics_proxy_->OnSendEncodedImage(encoded_image, rtp_video_hdr);
   }
-  // New encoded data, hand over to the rtp module.
-  return default_rtp_rtcp_->SendOutgoingData(
+
+  return send_payload_router_->RoutePayload(
       VCMEncodedFrame::ConvertFrameType(encoded_image._frameType), payload_type,
       encoded_image._timeStamp, encoded_image.capture_time_ms_,
       encoded_image._buffer, encoded_image._length, &fragmentation_header,
-      rtp_video_hdr);
+      rtp_video_hdr) ? 0 : -1;
 }
 
 int32_t ViEEncoder::ProtectionRequest(
diff --git a/webrtc/video_engine/vie_encoder.h b/webrtc/video_engine/vie_encoder.h
index ba7de53..d1723bc 100644
--- a/webrtc/video_engine/vie_encoder.h
+++ b/webrtc/video_engine/vie_encoder.h
@@ -13,6 +13,7 @@
 
 #include <list>
 #include <map>
+#include <vector>
 
 #include "webrtc/base/thread_annotations.h"
 #include "webrtc/common_types.h"
@@ -32,6 +33,7 @@
 class CriticalSectionWrapper;
 class EncodedImageCallback;
 class PacedSender;
+class PayloadRouter;
 class ProcessThread;
 class QMVideoSettingsCallback;
 class RtpRtcp;
@@ -62,6 +64,9 @@
 
   bool Init();
 
+  // This function is assumed to be called before any frames are delivered.
+  void SetSendPayloadRouter(PayloadRouter* send_payload_router);
+
   void SetNetworkTransmissionState(bool is_transmitting);
 
   // Returns the id of the owning channel.
@@ -201,6 +206,7 @@
   VideoCodingModule& vcm_;
   VideoProcessingModule& vpm_;
   scoped_ptr<RtpRtcp> default_rtp_rtcp_;
+  PayloadRouter* send_payload_router_;
   scoped_ptr<CriticalSectionWrapper> callback_cs_;
   scoped_ptr<CriticalSectionWrapper> data_cs_;
   scoped_ptr<BitrateObserver> bitrate_observer_;