BUG=3153 R=pbos@webrtc.org Review URL: https://webrtc-codereview.appspot.com/11179004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5853 4adac7df-926f-26a2-2b94-8c16560cd09d
263 lines
9.0 KiB
C++
263 lines
9.0 KiB
C++
/*
|
|
* Copyright (c) 2012 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/vie_channel_group.h"
|
|
|
|
#include "webrtc/common.h"
|
|
#include "webrtc/experiments.h"
|
|
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
|
|
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
|
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
|
|
#include "webrtc/modules/utility/interface/process_thread.h"
|
|
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
|
#include "webrtc/system_wrappers/interface/logging.h"
|
|
#include "webrtc/system_wrappers/interface/thread_annotations.h"
|
|
#include "webrtc/video_engine/call_stats.h"
|
|
#include "webrtc/video_engine/encoder_state_feedback.h"
|
|
#include "webrtc/video_engine/vie_channel.h"
|
|
#include "webrtc/video_engine/vie_encoder.h"
|
|
#include "webrtc/video_engine/vie_remb.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
static const uint32_t kTimeOffsetSwitchThreshold = 30;
|
|
|
|
class WrappingBitrateEstimator : public RemoteBitrateEstimator {
|
|
public:
|
|
WrappingBitrateEstimator(int engine_id, RemoteBitrateObserver* observer,
|
|
Clock* clock, ProcessThread* process_thread,
|
|
const Config& config)
|
|
: observer_(observer),
|
|
clock_(clock),
|
|
process_thread_(process_thread),
|
|
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
|
|
engine_id_(engine_id),
|
|
min_bitrate_bps_(config.Get<RemoteBitrateEstimatorMinRate>().min_rate),
|
|
rate_control_type_(kMimdControl),
|
|
rbe_(RemoteBitrateEstimatorFactory().Create(observer_,
|
|
clock_,
|
|
rate_control_type_,
|
|
min_bitrate_bps_)),
|
|
using_absolute_send_time_(false),
|
|
packets_since_absolute_send_time_(0) {
|
|
assert(process_thread_ != NULL);
|
|
process_thread_->RegisterModule(rbe_.get());
|
|
}
|
|
virtual ~WrappingBitrateEstimator() {
|
|
process_thread_->DeRegisterModule(rbe_.get());
|
|
}
|
|
|
|
virtual void IncomingPacket(int64_t arrival_time_ms,
|
|
int payload_size,
|
|
const RTPHeader& header) {
|
|
CriticalSectionScoped cs(crit_sect_.get());
|
|
PickEstimatorFromHeader(header);
|
|
rbe_->IncomingPacket(arrival_time_ms, payload_size, header);
|
|
}
|
|
|
|
virtual int32_t Process() {
|
|
assert(false && "Not supposed to register the WrappingBitrateEstimator!");
|
|
return 0;
|
|
}
|
|
|
|
virtual int32_t TimeUntilNextProcess() {
|
|
assert(false && "Not supposed to register the WrappingBitrateEstimator!");
|
|
return 0;
|
|
}
|
|
|
|
virtual void OnRttUpdate(uint32_t rtt) {
|
|
CriticalSectionScoped cs(crit_sect_.get());
|
|
rbe_->OnRttUpdate(rtt);
|
|
}
|
|
|
|
virtual void RemoveStream(unsigned int ssrc) {
|
|
CriticalSectionScoped cs(crit_sect_.get());
|
|
rbe_->RemoveStream(ssrc);
|
|
}
|
|
|
|
virtual bool LatestEstimate(std::vector<unsigned int>* ssrcs,
|
|
unsigned int* bitrate_bps) const {
|
|
CriticalSectionScoped cs(crit_sect_.get());
|
|
return rbe_->LatestEstimate(ssrcs, bitrate_bps);
|
|
}
|
|
|
|
virtual bool GetStats(ReceiveBandwidthEstimatorStats* output) const {
|
|
CriticalSectionScoped cs(crit_sect_.get());
|
|
return rbe_->GetStats(output);
|
|
}
|
|
|
|
void SetConfig(const webrtc::Config& config) {
|
|
CriticalSectionScoped cs(crit_sect_.get());
|
|
RateControlType new_control_type =
|
|
config.Get<AimdRemoteRateControl>().enabled ? kAimdControl :
|
|
kMimdControl;
|
|
if (new_control_type != rate_control_type_) {
|
|
rate_control_type_ = new_control_type;
|
|
PickEstimator();
|
|
}
|
|
}
|
|
|
|
private:
|
|
void PickEstimatorFromHeader(const RTPHeader& header)
|
|
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) {
|
|
if (header.extension.hasAbsoluteSendTime) {
|
|
// If we see AST in header, switch RBE strategy immediately.
|
|
if (!using_absolute_send_time_) {
|
|
LOG(LS_INFO) <<
|
|
"WrappingBitrateEstimator: Switching to absolute send time RBE.";
|
|
using_absolute_send_time_ = true;
|
|
PickEstimator();
|
|
}
|
|
packets_since_absolute_send_time_ = 0;
|
|
} else {
|
|
// When we don't see AST, wait for a few packets before going back to TOF.
|
|
if (using_absolute_send_time_) {
|
|
++packets_since_absolute_send_time_;
|
|
if (packets_since_absolute_send_time_ >= kTimeOffsetSwitchThreshold) {
|
|
LOG(LS_INFO) << "WrappingBitrateEstimator: Switching to transmission "
|
|
<< "time offset RBE.";
|
|
using_absolute_send_time_ = false;
|
|
PickEstimator();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Instantiate RBE for Time Offset or Absolute Send Time extensions.
|
|
void PickEstimator() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) {
|
|
process_thread_->DeRegisterModule(rbe_.get());
|
|
if (using_absolute_send_time_) {
|
|
rbe_.reset(AbsoluteSendTimeRemoteBitrateEstimatorFactory().Create(
|
|
observer_, clock_, rate_control_type_, min_bitrate_bps_));
|
|
} else {
|
|
rbe_.reset(RemoteBitrateEstimatorFactory().Create(
|
|
observer_, clock_, rate_control_type_, min_bitrate_bps_));
|
|
}
|
|
process_thread_->RegisterModule(rbe_.get());
|
|
}
|
|
|
|
RemoteBitrateObserver* observer_;
|
|
Clock* clock_;
|
|
ProcessThread* process_thread_;
|
|
scoped_ptr<CriticalSectionWrapper> crit_sect_;
|
|
const int engine_id_;
|
|
const uint32_t min_bitrate_bps_;
|
|
RateControlType rate_control_type_;
|
|
scoped_ptr<RemoteBitrateEstimator> rbe_;
|
|
bool using_absolute_send_time_;
|
|
uint32_t packets_since_absolute_send_time_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(WrappingBitrateEstimator);
|
|
};
|
|
} // namespace
|
|
|
|
ChannelGroup::ChannelGroup(int engine_id,
|
|
ProcessThread* process_thread,
|
|
const Config* config)
|
|
: remb_(new VieRemb()),
|
|
bitrate_controller_(
|
|
BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
|
|
true)),
|
|
call_stats_(new CallStats()),
|
|
encoder_state_feedback_(new EncoderStateFeedback()),
|
|
config_(config),
|
|
own_config_(),
|
|
process_thread_(process_thread) {
|
|
if (!config) {
|
|
own_config_.reset(new Config);
|
|
config_ = own_config_.get();
|
|
}
|
|
assert(config_); // Must have a valid config pointer here.
|
|
remote_bitrate_estimator_.reset(
|
|
new WrappingBitrateEstimator(engine_id,
|
|
remb_.get(),
|
|
Clock::GetRealTimeClock(),
|
|
process_thread,
|
|
*config_)),
|
|
call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get());
|
|
|
|
process_thread->RegisterModule(call_stats_.get());
|
|
process_thread->RegisterModule(bitrate_controller_.get());
|
|
}
|
|
|
|
ChannelGroup::~ChannelGroup() {
|
|
process_thread_->DeRegisterModule(bitrate_controller_.get());
|
|
process_thread_->DeRegisterModule(call_stats_.get());
|
|
call_stats_->DeregisterStatsObserver(remote_bitrate_estimator_.get());
|
|
assert(channels_.empty());
|
|
assert(!remb_->InUse());
|
|
}
|
|
|
|
void ChannelGroup::AddChannel(int channel_id) {
|
|
channels_.insert(channel_id);
|
|
}
|
|
|
|
void ChannelGroup::RemoveChannel(int channel_id, unsigned int ssrc) {
|
|
channels_.erase(channel_id);
|
|
remote_bitrate_estimator_->RemoveStream(ssrc);
|
|
}
|
|
|
|
bool ChannelGroup::HasChannel(int channel_id) {
|
|
return channels_.find(channel_id) != channels_.end();
|
|
}
|
|
|
|
bool ChannelGroup::Empty() {
|
|
return channels_.empty();
|
|
}
|
|
|
|
BitrateController* ChannelGroup::GetBitrateController() {
|
|
return bitrate_controller_.get();
|
|
}
|
|
|
|
RemoteBitrateEstimator* ChannelGroup::GetRemoteBitrateEstimator() {
|
|
return remote_bitrate_estimator_.get();
|
|
}
|
|
|
|
CallStats* ChannelGroup::GetCallStats() {
|
|
return call_stats_.get();
|
|
}
|
|
|
|
EncoderStateFeedback* ChannelGroup::GetEncoderStateFeedback() {
|
|
return encoder_state_feedback_.get();
|
|
}
|
|
|
|
bool ChannelGroup::SetChannelRembStatus(int channel_id, bool sender,
|
|
bool receiver, ViEChannel* channel) {
|
|
// Update the channel state.
|
|
if (sender || receiver) {
|
|
if (!channel->EnableRemb(true)) {
|
|
return false;
|
|
}
|
|
} else {
|
|
channel->EnableRemb(false);
|
|
}
|
|
// Update the REMB instance with necessary RTP modules.
|
|
RtpRtcp* rtp_module = channel->rtp_rtcp();
|
|
if (sender) {
|
|
remb_->AddRembSender(rtp_module);
|
|
} else {
|
|
remb_->RemoveRembSender(rtp_module);
|
|
}
|
|
if (receiver) {
|
|
remb_->AddReceiveChannel(rtp_module);
|
|
} else {
|
|
remb_->RemoveReceiveChannel(rtp_module);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void ChannelGroup::SetBandwidthEstimationConfig(const webrtc::Config& config) {
|
|
WrappingBitrateEstimator* estimator =
|
|
static_cast<WrappingBitrateEstimator*>(remote_bitrate_estimator_.get());
|
|
estimator->SetConfig(config);
|
|
}
|
|
} // namespace webrtc
|