Simplify pacer interface.

New interface uses two bitrates (max/min). The pace multiplier is also
removed from the interface and instead utilized outside. Min bitrate
will be filled with padding if there's not enough media to transmit.

Also fixes a bug in minimum transmission bitrate that made it ignore
REMBs. A regression test has been added to catch it.

BUG=3014
R=mflodman@webrtc.org, stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5723 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org
2014-03-19 10:59:52 +00:00
parent f577ae9eac
commit 709e29742e
8 changed files with 147 additions and 106 deletions

View File

@@ -56,8 +56,7 @@ class PacedSender : public Module {
static const int kDefaultMaxQueueLengthMs = 2000; static const int kDefaultMaxQueueLengthMs = 2000;
PacedSender(Callback* callback, int target_bitrate_kbps, PacedSender(Callback* callback, int max_bitrate_kbps, int min_bitrate_kbps);
float pace_multiplier);
virtual ~PacedSender(); virtual ~PacedSender();
@@ -72,13 +71,9 @@ class PacedSender : public Module {
// Resume sending packets. // Resume sending packets.
void Resume(); void Resume();
// Set the pacing target bitrate and the bitrate up to which we are allowed to // Set target bitrates for the pacer. Padding packets will be utilized to
// pad. We will send padding packets to increase the total bitrate until we // reach |min_bitrate| unless enough media packets are available.
// reach |pad_up_to_bitrate_kbps|. If the media bitrate is above void UpdateBitrate(int max_bitrate_kbps, int min_bitrate_kbps);
// |pad_up_to_bitrate_kbps| no padding will be sent.
void UpdateBitrate(int target_bitrate_kbps,
int max_padding_bitrate_kbps,
int pad_up_to_bitrate_kbps);
// Returns true if we send the packet now, else it will add the packet // Returns true if we send the packet now, else it will add the packet
// information to the queue and call TimeToSendPacket when it's time to send. // information to the queue and call TimeToSendPacket when it's time to send.
@@ -120,7 +115,6 @@ class PacedSender : public Module {
void UpdateMediaBytesSent(int num_bytes); void UpdateMediaBytesSent(int num_bytes);
Callback* callback_; Callback* callback_;
const float pace_multiplier_;
bool enabled_; bool enabled_;
bool paused_; bool paused_;
int max_queue_length_ms_; int max_queue_length_ms_;
@@ -129,12 +123,9 @@ class PacedSender : public Module {
// we can pace out during the current interval. // we can pace out during the current interval.
scoped_ptr<paced_sender::IntervalBudget> media_budget_; scoped_ptr<paced_sender::IntervalBudget> media_budget_;
// This is the padding budget, keeping track of how many bits of padding we're // This is the padding budget, keeping track of how many bits of padding we're
// allowed to send out during the current interval. // allowed to send out during the current interval. This budget will be
// utilized when there's no media to send.
scoped_ptr<paced_sender::IntervalBudget> padding_budget_; scoped_ptr<paced_sender::IntervalBudget> padding_budget_;
// Media and padding share this budget, therefore no padding will be sent if
// media uses all of this budget. This is used to avoid padding above a given
// bitrate.
scoped_ptr<paced_sender::IntervalBudget> pad_up_to_bitrate_budget_;
TickTime time_last_update_; TickTime time_last_update_;
TickTime time_last_send_; TickTime time_last_send_;

View File

@@ -120,19 +120,16 @@ class IntervalBudget {
}; };
} // namespace paced_sender } // namespace paced_sender
PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps, PacedSender::PacedSender(Callback* callback,
float pace_multiplier) int max_bitrate_kbps,
int min_bitrate_kbps)
: callback_(callback), : callback_(callback),
pace_multiplier_(pace_multiplier),
enabled_(false), enabled_(false),
paused_(false), paused_(false),
max_queue_length_ms_(kDefaultMaxQueueLengthMs), max_queue_length_ms_(kDefaultMaxQueueLengthMs),
critsect_(CriticalSectionWrapper::CreateCriticalSection()), critsect_(CriticalSectionWrapper::CreateCriticalSection()),
media_budget_(new paced_sender::IntervalBudget( media_budget_(new paced_sender::IntervalBudget(max_bitrate_kbps)),
pace_multiplier_ * target_bitrate_kbps)), padding_budget_(new paced_sender::IntervalBudget(min_bitrate_kbps)),
padding_budget_(new paced_sender::IntervalBudget(0)),
// No padding until UpdateBitrate is called.
pad_up_to_bitrate_budget_(new paced_sender::IntervalBudget(0)),
time_last_update_(TickTime::Now()), time_last_update_(TickTime::Now()),
capture_time_ms_last_queued_(0), capture_time_ms_last_queued_(0),
capture_time_ms_last_sent_(0), capture_time_ms_last_sent_(0),
@@ -165,13 +162,11 @@ bool PacedSender::Enabled() const {
return enabled_; return enabled_;
} }
void PacedSender::UpdateBitrate(int target_bitrate_kbps, void PacedSender::UpdateBitrate(int max_bitrate_kbps,
int max_padding_bitrate_kbps, int min_bitrate_kbps) {
int pad_up_to_bitrate_kbps) {
CriticalSectionScoped cs(critsect_.get()); CriticalSectionScoped cs(critsect_.get());
media_budget_->set_target_rate_kbps(pace_multiplier_ * target_bitrate_kbps); media_budget_->set_target_rate_kbps(max_bitrate_kbps);
padding_budget_->set_target_rate_kbps(max_padding_bitrate_kbps); padding_budget_->set_target_rate_kbps(min_bitrate_kbps);
pad_up_to_bitrate_budget_->set_target_rate_kbps(pad_up_to_bitrate_kbps);
} }
bool PacedSender::SendPacket(Priority priority, uint32_t ssrc, bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
@@ -273,17 +268,13 @@ int32_t PacedSender::Process() {
if (high_priority_packets_->empty() && if (high_priority_packets_->empty() &&
normal_priority_packets_->empty() && normal_priority_packets_->empty() &&
low_priority_packets_->empty() && low_priority_packets_->empty() &&
padding_budget_->bytes_remaining() > 0 && padding_budget_->bytes_remaining() > 0) {
pad_up_to_bitrate_budget_->bytes_remaining() > 0) { int padding_needed = padding_budget_->bytes_remaining();
int padding_needed = std::min(
padding_budget_->bytes_remaining(),
pad_up_to_bitrate_budget_->bytes_remaining());
critsect_->Leave(); critsect_->Leave();
int bytes_sent = callback_->TimeToSendPadding(padding_needed); int bytes_sent = callback_->TimeToSendPadding(padding_needed);
critsect_->Enter(); critsect_->Enter();
media_budget_->UseBudget(bytes_sent); media_budget_->UseBudget(bytes_sent);
padding_budget_->UseBudget(bytes_sent); padding_budget_->UseBudget(bytes_sent);
pad_up_to_bitrate_budget_->UseBudget(bytes_sent);
} }
} }
return 0; return 0;
@@ -324,7 +315,6 @@ bool PacedSender::SendPacketFromList(paced_sender::PacketList* packet_list)
void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) { void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) {
media_budget_->IncreaseBudget(delta_time_ms); media_budget_->IncreaseBudget(delta_time_ms);
padding_budget_->IncreaseBudget(delta_time_ms); padding_budget_->IncreaseBudget(delta_time_ms);
pad_up_to_bitrate_budget_->IncreaseBudget(delta_time_ms);
} }
// MUST have critsect_ when calling. // MUST have critsect_ when calling.
@@ -388,7 +378,7 @@ paced_sender::Packet PacedSender::GetNextPacketFromList(
void PacedSender::UpdateMediaBytesSent(int num_bytes) { void PacedSender::UpdateMediaBytesSent(int num_bytes) {
time_last_send_ = TickTime::Now(); time_last_send_ = TickTime::Now();
media_budget_->UseBudget(num_bytes); media_budget_->UseBudget(num_bytes);
pad_up_to_bitrate_budget_->UseBudget(num_bytes); padding_budget_->UseBudget(num_bytes);
} }
} // namespace webrtc } // namespace webrtc

View File

@@ -59,8 +59,8 @@ class PacedSenderTest : public ::testing::Test {
srand(0); srand(0);
TickTime::UseFakeClock(123456); TickTime::UseFakeClock(123456);
// Need to initialize PacedSender after we initialize clock. // Need to initialize PacedSender after we initialize clock.
send_bucket_.reset(new PacedSender(&callback_, kTargetBitrate, send_bucket_.reset(
kPaceMultiplier)); new PacedSender(&callback_, kPaceMultiplier * kTargetBitrate, 0));
send_bucket_->SetStatus(true); send_bucket_->SetStatus(true);
} }
@@ -209,7 +209,7 @@ TEST_F(PacedSenderTest, Padding) {
uint32_t ssrc = 12345; uint32_t ssrc = 12345;
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate, kTargetBitrate); send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate);
// Due to the multiplicative factor we can send 3 packets not 2 packets. // Due to the multiplicative factor we can send 3 packets not 2 packets.
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
TickTime::MillisecondTimestamp(), 250, false); TickTime::MillisecondTimestamp(), 250, false);
@@ -235,7 +235,7 @@ TEST_F(PacedSenderTest, Padding) {
TEST_F(PacedSenderTest, NoPaddingWhenDisabled) { TEST_F(PacedSenderTest, NoPaddingWhenDisabled) {
send_bucket_->SetStatus(false); send_bucket_->SetStatus(false);
send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate, kTargetBitrate); send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate);
// No padding is expected since the pacer is disabled. // No padding is expected since the pacer is disabled.
EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0); EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0);
EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess()); EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess());
@@ -255,7 +255,7 @@ TEST_F(PacedSenderTest, VerifyPaddingUpToBitrate) {
int64_t capture_time_ms = 56789; int64_t capture_time_ms = 56789;
const int kTimeStep = 5; const int kTimeStep = 5;
const int64_t kBitrateWindow = 100; const int64_t kBitrateWindow = 100;
send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate, kTargetBitrate); send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate);
int64_t start_time = TickTime::MillisecondTimestamp(); int64_t start_time = TickTime::MillisecondTimestamp();
while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) { while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) {
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
@@ -267,27 +267,6 @@ TEST_F(PacedSenderTest, VerifyPaddingUpToBitrate) {
} }
} }
TEST_F(PacedSenderTest, VerifyMaxPaddingBitrate) {
uint32_t ssrc = 12345;
uint16_t sequence_number = 1234;
int64_t capture_time_ms = 56789;
const int kTimeStep = 5;
const int64_t kBitrateWindow = 100;
const int kTargetBitrate = 1500;
const int kMaxPaddingBitrate = 800;
send_bucket_->UpdateBitrate(kTargetBitrate, kMaxPaddingBitrate,
kTargetBitrate);
int64_t start_time = TickTime::MillisecondTimestamp();
while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) {
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
capture_time_ms, 250, false);
TickTime::AdvanceFakeClock(kTimeStep);
EXPECT_CALL(callback_, TimeToSendPadding(500)).Times(1).
WillOnce(Return(250));
send_bucket_->Process();
}
}
TEST_F(PacedSenderTest, VerifyAverageBitrateVaryingMediaPayload) { TEST_F(PacedSenderTest, VerifyAverageBitrateVaryingMediaPayload) {
uint32_t ssrc = 12345; uint32_t ssrc = 12345;
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
@@ -295,10 +274,10 @@ TEST_F(PacedSenderTest, VerifyAverageBitrateVaryingMediaPayload) {
const int kTimeStep = 5; const int kTimeStep = 5;
const int64_t kBitrateWindow = 10000; const int64_t kBitrateWindow = 10000;
PacedSenderPadding callback; PacedSenderPadding callback;
send_bucket_.reset(new PacedSender(&callback, kTargetBitrate, send_bucket_.reset(
kPaceMultiplier)); new PacedSender(&callback, kPaceMultiplier * kTargetBitrate, 0));
send_bucket_->SetStatus(true); send_bucket_->SetStatus(true);
send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate, kTargetBitrate); send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate);
int64_t start_time = TickTime::MillisecondTimestamp(); int64_t start_time = TickTime::MillisecondTimestamp();
int media_bytes = 0; int media_bytes = 0;
while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) { while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) {
@@ -497,7 +476,7 @@ TEST_F(PacedSenderTest, MaxQueueLength) {
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
EXPECT_EQ(0, send_bucket_->QueueInMs()); EXPECT_EQ(0, send_bucket_->QueueInMs());
send_bucket_->UpdateBitrate(30, 0, 0); send_bucket_->UpdateBitrate(kPaceMultiplier * 30, 0);
for (int i = 0; i < 30; ++i) { for (int i = 0; i < 30; ++i) {
SendAndExpectPacket(PacedSender::kNormalPriority, SendAndExpectPacket(PacedSender::kNormalPriority,
ssrc, ssrc,
@@ -526,7 +505,7 @@ TEST_F(PacedSenderTest, QueueTimeGrowsOverTime) {
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
EXPECT_EQ(0, send_bucket_->QueueInMs()); EXPECT_EQ(0, send_bucket_->QueueInMs());
send_bucket_->UpdateBitrate(30, 0, 0); send_bucket_->UpdateBitrate(kPaceMultiplier * 30, 0);
SendAndExpectPacket(PacedSender::kNormalPriority, SendAndExpectPacket(PacedSender::kNormalPriority,
ssrc, ssrc,
sequence_number, sequence_number,

View File

@@ -398,7 +398,7 @@ TEST_F(CallPerfTest, RegisterCpuOveruseObserver) {
void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) { void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
static const int kMaxEncodeBitrateKbps = 30; static const int kMaxEncodeBitrateKbps = 30;
static const int kMinTransmitBitrateKbps = 150; static const int kMinTransmitBitrateBps = 150000;
static const int kMinAcceptableTransmitBitrate = 130; static const int kMinAcceptableTransmitBitrate = 130;
static const int kMaxAcceptableTransmitBitrate = 170; static const int kMaxAcceptableTransmitBitrate = 170;
static const int kNumBitrateObservationsInRange = 100; static const int kNumBitrateObservationsInRange = 100;
@@ -475,9 +475,9 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
send_config.pacing = true; send_config.pacing = true;
if (pad_to_min_bitrate) { if (pad_to_min_bitrate) {
send_config.rtp.min_transmit_bitrate_kbps = kMinTransmitBitrateKbps; send_config.rtp.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
} else { } else {
assert(send_config.rtp.min_transmit_bitrate_kbps == 0); assert(send_config.rtp.min_transmit_bitrate_bps == 0);
} }
VideoReceiveStream::Config receive_config = VideoReceiveStream::Config receive_config =

View File

@@ -50,9 +50,9 @@ VideoSendStream::VideoSendStream(newapi::Transport* transport,
config_.pacing = true; config_.pacing = true;
rtp_rtcp_->SetTransmissionSmoothingStatus(channel_, config_.pacing); rtp_rtcp_->SetTransmissionSmoothingStatus(channel_, config_.pacing);
assert(config_.rtp.min_transmit_bitrate_kbps >= 0); assert(config_.rtp.min_transmit_bitrate_bps >= 0);
rtp_rtcp_->SetMinTransmitBitrate(channel_, rtp_rtcp_->SetMinTransmitBitrate(channel_,
config_.rtp.min_transmit_bitrate_kbps); config_.rtp.min_transmit_bitrate_bps / 1000);
for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) { for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
const std::string& extension = config_.rtp.extensions[i].name; const std::string& extension = config_.rtp.extensions[i].name;

View File

@@ -15,6 +15,7 @@
#include "webrtc/common_video/interface/i420_video_frame.h" #include "webrtc/common_video/interface/i420_video_frame.h"
#include "webrtc/frame_callback.h" #include "webrtc/frame_callback.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
@@ -23,12 +24,13 @@
#include "webrtc/system_wrappers/interface/sleep.h" #include "webrtc/system_wrappers/interface/sleep.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h" #include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/test/direct_transport.h" #include "webrtc/test/direct_transport.h"
#include "webrtc/test/configurable_frame_size_encoder.h"
#include "webrtc/test/encoder_settings.h" #include "webrtc/test/encoder_settings.h"
#include "webrtc/test/fake_encoder.h" #include "webrtc/test/fake_encoder.h"
#include "webrtc/test/configurable_frame_size_encoder.h"
#include "webrtc/test/frame_generator_capturer.h" #include "webrtc/test/frame_generator_capturer.h"
#include "webrtc/test/null_transport.h" #include "webrtc/test/null_transport.h"
#include "webrtc/test/rtp_rtcp_observer.h" #include "webrtc/test/rtp_rtcp_observer.h"
#include "webrtc/test/testsupport/perf_test.h"
#include "webrtc/video/transport_adapter.h" #include "webrtc/video/transport_adapter.h"
#include "webrtc/video_send_stream.h" #include "webrtc/video_send_stream.h"
@@ -1117,4 +1119,94 @@ TEST_F(VideoSendStreamTest, ProducesStats) {
call->DestroyVideoSendStream(send_stream_); call->DestroyVideoSendStream(send_stream_);
} }
// This test first observes "high" bitrate use at which point it sends a REMB to
// indicate that it should be lowered significantly. The test then observes that
// the bitrate observed is sinking well below the min-transmit-bitrate threshold
// to verify that the min-transmit bitrate respects incoming REMB.
TEST_F(VideoSendStreamTest, MinTransmitBitrateRespectsRemb) {
static const int kMinTransmitBitrateBps = 400000;
static const int kHighBitrateBps = 200000;
static const int kRembBitrateBps = 80000;
static const int kRembRespectedBitrateBps = 100000;
class BitrateObserver: public test::RtpRtcpObserver, public PacketReceiver {
public:
BitrateObserver()
: RtpRtcpObserver(30 * 1000),
feedback_transport_(ReceiveTransport()),
send_stream_(NULL),
bitrate_capped_(false) {
RtpRtcp::Configuration config;
feedback_transport_.Enable();
config.outgoing_transport = &feedback_transport_;
rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
rtp_rtcp_->SetREMBStatus(true);
rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
}
void SetSendStream(VideoSendStream* send_stream) {
send_stream_ = send_stream;
}
private:
virtual bool DeliverPacket(const uint8_t* packet, size_t length) {
if (RtpHeaderParser::IsRtcp(packet, static_cast<int>(length)))
return true;
RTPHeader header;
if (!parser_->Parse(packet, static_cast<int>(length), &header))
return true;
assert(send_stream_ != NULL);
VideoSendStream::Stats stats = send_stream_->GetStats();
if (!stats.substreams.empty()) {
EXPECT_EQ(1u, stats.substreams.size());
int bitrate_bps = stats.substreams.begin()->second.bitrate_bps;
test::PrintResult(
"bitrate_stats_",
"min_transmit_bitrate_low_remb",
"bitrate_bps",
static_cast<size_t>(bitrate_bps),
"bps",
false);
if (bitrate_bps > kHighBitrateBps) {
rtp_rtcp_->SetREMBData(kRembBitrateBps, 1, &header.ssrc);
rtp_rtcp_->Process();
bitrate_capped_ = true;
} else if (bitrate_capped_ &&
bitrate_bps < kRembRespectedBitrateBps) {
observation_complete_->Set();
}
}
return true;
}
scoped_ptr<RtpRtcp> rtp_rtcp_;
internal::TransportAdapter feedback_transport_;
VideoSendStream* send_stream_;
bool bitrate_capped_;
} observer;
Call::Config call_config(observer.SendTransport());
scoped_ptr<Call> call(Call::Create(call_config));
observer.SetReceivers(&observer, call->Receiver());
VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1);
send_config.rtp.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
send_stream_ = call->CreateVideoSendStream(send_config);
observer.SetSendStream(send_stream_);
scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
test::FrameGeneratorCapturer::Create(
send_stream_->Input(), 320, 240, 30, Clock::GetRealTimeClock()));
send_stream_->StartSending();
frame_generator_capturer->Start();
EXPECT_EQ(kEventSignaled, observer.Wait())
<< "Timeout while waiting for low bitrate stats after REMB.";
observer.StopSending();
frame_generator_capturer->Stop();
send_stream_->StopSending();
call->DestroyVideoSendStream(send_stream_);
}
} // namespace webrtc } // namespace webrtc

View File

@@ -465,8 +465,8 @@ int32_t ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) {
if (pad_up_to_bitrate_kbps < min_transmit_bitrate_kbps_) if (pad_up_to_bitrate_kbps < min_transmit_bitrate_kbps_)
pad_up_to_bitrate_kbps = min_transmit_bitrate_kbps_; pad_up_to_bitrate_kbps = min_transmit_bitrate_kbps_;
paced_sender_->UpdateBitrate( paced_sender_->UpdateBitrate(kPaceMultiplier * video_codec.startBitrate,
video_codec.startBitrate, pad_up_to_bitrate_kbps, pad_up_to_bitrate_kbps); pad_up_to_bitrate_kbps);
return 0; return 0;
} }
@@ -1066,58 +1066,47 @@ void ViEEncoder::OnNetworkChanged(const uint32_t bitrate_bps,
// Find the max amount of padding we can allow ourselves to send at this // Find the max amount of padding we can allow ourselves to send at this
// point, based on which streams are currently active and what our current // point, based on which streams are currently active and what our current
// available bandwidth is. // available bandwidth is.
int max_padding_bitrate_kbps = 0;
int pad_up_to_bitrate_kbps = 0; int pad_up_to_bitrate_kbps = 0;
if (send_codec.numberOfSimulcastStreams == 0) { if (send_codec.numberOfSimulcastStreams == 0) {
max_padding_bitrate_kbps = send_codec.minBitrate;
pad_up_to_bitrate_kbps = send_codec.minBitrate; pad_up_to_bitrate_kbps = send_codec.minBitrate;
} else { } else {
int i = send_codec.numberOfSimulcastStreams - 1;
for (std::vector<uint32_t>::reverse_iterator it = stream_bitrates.rbegin();
it != stream_bitrates.rend(); ++it) {
if (*it > 0) {
max_padding_bitrate_kbps = std::min((*it + 500) / 1000,
stream_configs[i].minBitrate);
break;
}
--i;
}
pad_up_to_bitrate_kbps = pad_up_to_bitrate_kbps =
stream_configs[send_codec.numberOfSimulcastStreams - 1].minBitrate; stream_configs[send_codec.numberOfSimulcastStreams - 1].minBitrate;
for (int i = 0; i < send_codec.numberOfSimulcastStreams - 1; ++i) { for (int i = 0; i < send_codec.numberOfSimulcastStreams - 1; ++i) {
pad_up_to_bitrate_kbps += stream_configs[i].targetBitrate; pad_up_to_bitrate_kbps += stream_configs[i].targetBitrate;
} }
} }
if (video_is_suspended || send_codec.numberOfSimulcastStreams > 1) {
pad_up_to_bitrate_kbps = std::min(bitrate_kbps, pad_up_to_bitrate_kbps); // Disable padding if only sending one stream and video isn't suspended and
} else { // min-transmit bitrate isn't used (applied later).
// Disable padding if only sending one stream and video isn't suspended. if (!video_is_suspended && send_codec.numberOfSimulcastStreams <= 1)
pad_up_to_bitrate_kbps = 0; pad_up_to_bitrate_kbps = 0;
}
{ {
// The amount of padding should decay to zero if no frames are being
// captured.
CriticalSectionScoped cs(data_cs_.get()); CriticalSectionScoped cs(data_cs_.get());
// The amount of padding should decay to zero if no frames are being
// captured unless a min-transmit bitrate is used.
int64_t now_ms = TickTime::MillisecondTimestamp(); int64_t now_ms = TickTime::MillisecondTimestamp();
if (now_ms - time_of_last_incoming_frame_ms_ > kStopPaddingThresholdMs) if (now_ms - time_of_last_incoming_frame_ms_ > kStopPaddingThresholdMs)
max_padding_bitrate_kbps = 0; pad_up_to_bitrate_kbps = 0;
}
{ // Pad up to min bitrate.
CriticalSectionScoped cs(data_cs_.get());
if (pad_up_to_bitrate_kbps < min_transmit_bitrate_kbps_) if (pad_up_to_bitrate_kbps < min_transmit_bitrate_kbps_)
pad_up_to_bitrate_kbps = min_transmit_bitrate_kbps_; pad_up_to_bitrate_kbps = min_transmit_bitrate_kbps_;
if (max_padding_bitrate_kbps < min_transmit_bitrate_kbps_)
max_padding_bitrate_kbps = min_transmit_bitrate_kbps_; // Padding may never exceed bitrate estimate.
paced_sender_->UpdateBitrate( if (pad_up_to_bitrate_kbps > bitrate_kbps)
bitrate_kbps, max_padding_bitrate_kbps, pad_up_to_bitrate_kbps); pad_up_to_bitrate_kbps = bitrate_kbps;
paced_sender_->UpdateBitrate(kPaceMultiplier * bitrate_kbps,
pad_up_to_bitrate_kbps);
default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates); default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates);
if (video_suspended_ == video_is_suspended) if (video_suspended_ == video_is_suspended)
return; return;
video_suspended_ = video_is_suspended; video_suspended_ = video_is_suspended;
} }
// State changed, inform codec observer.
// Video suspend-state changed, inform codec observer.
CriticalSectionScoped crit(callback_cs_.get()); CriticalSectionScoped crit(callback_cs_.get());
if (codec_observer_) { if (codec_observer_) {
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,

View File

@@ -86,7 +86,7 @@ class VideoSendStream {
struct Rtp { struct Rtp {
Rtp() Rtp()
: max_packet_size(kDefaultMaxPacketSize), : max_packet_size(kDefaultMaxPacketSize),
min_transmit_bitrate_kbps(0) {} min_transmit_bitrate_bps(0) {}
std::vector<uint32_t> ssrcs; std::vector<uint32_t> ssrcs;
@@ -96,7 +96,7 @@ class VideoSendStream {
// Padding will be used up to this bitrate regardless of the bitrate // Padding will be used up to this bitrate regardless of the bitrate
// produced by the encoder. Padding above what's actually produced by the // produced by the encoder. Padding above what's actually produced by the
// encoder helps maintaining a higher bitrate estimate. // encoder helps maintaining a higher bitrate estimate.
int min_transmit_bitrate_kbps; int min_transmit_bitrate_bps;
// RTP header extensions to use for this send stream. // RTP header extensions to use for this send stream.
std::vector<RtpExtension> extensions; std::vector<RtpExtension> extensions;