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
This commit is contained in:
mflodman@webrtc.org 2015-02-06 13:10:19 +00:00
parent 10a9e924eb
commit 02270cd718
11 changed files with 349 additions and 72 deletions

View File

@ -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 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData(
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 @@ bool ModuleRtpRtcpImpl::IsDefaultModule() const {
return !child_modules_.empty();
}
} // Namespace webrtc
} // namespace webrtc

View File

@ -29,6 +29,8 @@ source_set("video_engine_core") {
"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",

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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',

View File

@ -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 @@ ViEChannel::ViEChannel(int32_t channel_id,
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 @@ int32_t ViEChannel::Init() {
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 @@ ViEChannel::~ViEChannel() {
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 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
// 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 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
(*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 @@ void ViEChannel::EnableTMMBR(bool enable) {
}
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 @@ int32_t ViEChannel::StartSend() {
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 @@ RtpRtcp* ViEChannel::rtp_rtcp() {
return rtp_rtcp_.get();
}
PayloadRouter* ViEChannel::send_payload_router() {
return send_payload_router_.get();
}
CallStatsObserver* ViEChannel::GetStatsObserver() {
return stats_observer_.get();
}

View File

@ -38,6 +38,7 @@ class CriticalSectionWrapper;
class EncodedImageCallback;
class I420FrameCallback;
class PacedSender;
class PayloadRouter;
class ProcessThread;
class ReceiveStatisticsProxy;
class ReportBlockStats;
@ -301,6 +302,7 @@ class ViEChannel
// Gets the modules used by the channel.
RtpRtcp* rtp_rtcp();
PayloadRouter* send_payload_router();
CallStatsObserver* GetStatsObserver();
@ -467,6 +469,8 @@ class ViEChannel
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_;

View File

@ -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 @@ int ViEChannelManager::CreateChannel(int* channel_id,
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 @@ int ViEChannelManager::CreateChannel(int* channel_id,
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;

View File

@ -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 @@ ViEEncoder::ViEEncoder(int32_t engine_id,
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 @@ bool ViEEncoder::Init() {
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 @@ RtpRtcp* ViEEncoder::SendRtpRtcpModule() {
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 @@ int32_t ViEEncoder::SendData(
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(

View File

@ -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 Config;
class CriticalSectionWrapper;
class EncodedImageCallback;
class PacedSender;
class PayloadRouter;
class ProcessThread;
class QMVideoSettingsCallback;
class RtpRtcp;
@ -62,6 +64,9 @@ class ViEEncoder
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 @@ class ViEEncoder
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_;