Add interface to signal a network down event.

- In real-time mode encoding will be paused until the network is back up.
- In buffering mode the encoder will keep encoding, and packets will be
  buffered at the sender. When the buffer grows above the target delay
  encoding will be paused.
- Fixes a couple of issues related to pacing which was found with the new test.
- Introduces different max bitrates for pacing and for encoding. This allows
  the pacer to faster get rid of the queue after a network down event.

(Work based on issue 1237004)

BUG=1524
TESTS=trybots,vie_auto_test

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3730 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org
2013-03-27 16:36:01 +00:00
parent 686001dd96
commit bfacda60be
14 changed files with 263 additions and 61 deletions

View File

@ -64,6 +64,9 @@ class PacedSender : public Module {
bool SendPacket(Priority priority, uint32_t ssrc, uint16_t sequence_number,
int64_t capture_time_ms, int bytes);
// Returns the time since the oldest queued packet was captured.
int QueueInMs() const;
// Returns the number of milliseconds until the module want a worker thread
// to call Process.
virtual int32_t TimeUntilNextProcess();
@ -85,6 +88,9 @@ class PacedSender : public Module {
int64_t capture_time_ms_;
int bytes_;
};
typedef std::list<Packet> PacketList;
// Checks if next packet in line can be transmitted. Returns true on success.
bool GetNextPacket(uint32_t* ssrc, uint16_t* sequence_number,
int64_t* capture_time_ms);
@ -109,9 +115,9 @@ class PacedSender : public Module {
TickTime time_last_update_;
TickTime time_last_send_;
std::list<Packet> high_priority_packets_;
std::list<Packet> normal_priority_packets_;
std::list<Packet> low_priority_packets_;
PacketList high_priority_packets_;
PacketList normal_priority_packets_;
PacketList low_priority_packets_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_PACED_SENDER_H_

View File

@ -82,6 +82,9 @@ bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
UpdateState(bytes);
return true; // We can send now.
}
if (capture_time_ms < 0) {
capture_time_ms = TickTime::MillisecondTimestamp();
}
if (paused_) {
// Queue all packets when we are paused.
switch (priority) {
@ -135,6 +138,28 @@ bool PacedSender::SendPacket(Priority priority, uint32_t ssrc,
return false;
}
int PacedSender::QueueInMs() const {
CriticalSectionScoped cs(critsect_.get());
int64_t now_ms = TickTime::MillisecondTimestamp();
int64_t oldest_packet_capture_time = now_ms;
if (!high_priority_packets_.empty()) {
oldest_packet_capture_time = std::min(
oldest_packet_capture_time,
high_priority_packets_.front().capture_time_ms_);
}
if (!normal_priority_packets_.empty()) {
oldest_packet_capture_time = std::min(
oldest_packet_capture_time,
normal_priority_packets_.front().capture_time_ms_);
}
if (!low_priority_packets_.empty()) {
oldest_packet_capture_time = std::min(
oldest_packet_capture_time,
low_priority_packets_.front().capture_time_ms_);
}
return now_ms - oldest_packet_capture_time;
}
int32_t PacedSender::TimeUntilNextProcess() {
CriticalSectionScoped cs(critsect_.get());
int64_t elapsed_time_ms =

View File

@ -185,8 +185,11 @@ TEST_F(PacedSenderTest, Pause) {
uint32_t ssrc_low_priority = 12345;
uint32_t ssrc = 12346;
uint16_t sequence_number = 1234;
int64_t capture_time_ms = 56789;
int64_t second_capture_time_ms = 67890;
int64_t capture_time_ms = TickTime::MillisecondTimestamp();
TickTime::AdvanceFakeClock(10000);
int64_t second_capture_time_ms = TickTime::MillisecondTimestamp();
EXPECT_EQ(0, send_bucket_->QueueInMs());
// Due to the multiplicative factor we can send 3 packets not 2 packets.
EXPECT_TRUE(send_bucket_->SendPacket(PacedSender::kLowPriority,
@ -208,6 +211,9 @@ TEST_F(PacedSenderTest, Pause) {
EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kHighPriority,
ssrc, sequence_number++, capture_time_ms, 250));
EXPECT_EQ(TickTime::MillisecondTimestamp() - capture_time_ms,
send_bucket_->QueueInMs());
// Expect no packet to come out while paused.
EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0);
EXPECT_CALL(callback_, TimeToSendPacket(_, _, _)).Times(0);
@ -235,6 +241,7 @@ TEST_F(PacedSenderTest, Pause) {
TickTime::AdvanceFakeClock(5);
EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess());
EXPECT_EQ(0, send_bucket_->Process());
EXPECT_EQ(0, send_bucket_->QueueInMs());
}
} // namespace test

View File

@ -987,15 +987,25 @@ void ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc,
(*it)->rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms);
return;
}
it++;
++it;
}
} else {
bool have_child_modules(child_modules_.empty() ? false : true);
bool have_child_modules = !child_modules_.empty();
if (!have_child_modules) {
// Don't send from default module.
if (SendingMedia() && ssrc == rtp_sender_.SSRC()) {
rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms);
}
} else {
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
while (it != child_modules_.end()) {
if ((*it)->SendingMedia() && ssrc == (*it)->rtp_sender_.SSRC()) {
(*it)->rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms);
return;
}
++it;
}
}
}
}

View File

@ -673,7 +673,7 @@ WebRtc_Word32 RTPSender::SendToNetwork(
}
}
if (paced_sender_) {
if (paced_sender_ && storage != kDontStore) {
if (!paced_sender_->SendPacket(
PacedSender::kNormalPriority, rtp_header.header.ssrc,
rtp_header.header.sequenceNumber, capture_time_ms,

View File

@ -205,7 +205,7 @@ RTPSenderVideo::SendRTPIntraRequest()
ModuleRTPUtility::AssignUWord32ToBuffer(data+4, _rtpSender.SSRC());
return _rtpSender.SendToNetwork(data, 0, length, -1, kAllowRetransmission);
return _rtpSender.SendToNetwork(data, 0, length, -1, kDontStore);
}
WebRtc_Word32

View File

@ -94,6 +94,12 @@ VCMMediaOptimization::SetTargetRates(WebRtc_UWord32 target_bitrate,
WebRtc_UWord8 &fractionLost,
WebRtc_UWord32 roundTripTimeMs)
{
// TODO(holmer): Consider putting this threshold only on the video bitrate,
// and not on protection.
if (_maxBitRate > 0 &&
target_bitrate > static_cast<uint32_t>(_maxBitRate)) {
target_bitrate = _maxBitRate;
}
VCMProtectionMethod *selectedMethod = _lossProtLogic->SelectedMethod();
float target_bitrate_kbps = static_cast<float>(target_bitrate) / 1000.0f;
_lossProtLogic->UpdateBitRate(target_bitrate_kbps);

View File

@ -47,50 +47,47 @@ VideoCodingModuleImpl::VideoCodingModuleImpl(const WebRtc_Word32 id,
Clock* clock,
EventFactory* event_factory,
bool owns_event_factory)
:
_id(id),
clock_(clock),
_receiveCritSect(CriticalSectionWrapper::CreateCriticalSection()),
_receiverInited(false),
_timing(clock_, id, 1),
_dualTiming(clock_, id, 2, &_timing),
_receiver(&_timing, clock_, event_factory, id, 1, true),
_dualReceiver(&_dualTiming, clock_, event_factory, id, 2, false),
_decodedFrameCallback(_timing, clock_),
_dualDecodedFrameCallback(_dualTiming, clock_),
_frameTypeCallback(NULL),
_frameStorageCallback(NULL),
_receiveStatsCallback(NULL),
_packetRequestCallback(NULL),
_decoder(NULL),
_dualDecoder(NULL),
: _id(id),
clock_(clock),
_receiveCritSect(CriticalSectionWrapper::CreateCriticalSection()),
_receiverInited(false),
_timing(clock_, id, 1),
_dualTiming(clock_, id, 2, &_timing),
_receiver(&_timing, clock_, event_factory, id, 1, true),
_dualReceiver(&_dualTiming, clock_, event_factory, id, 2, false),
_decodedFrameCallback(_timing, clock_),
_dualDecodedFrameCallback(_dualTiming, clock_),
_frameTypeCallback(NULL),
_frameStorageCallback(NULL),
_receiveStatsCallback(NULL),
_packetRequestCallback(NULL),
_decoder(NULL),
_dualDecoder(NULL),
#ifdef DEBUG_DECODER_BIT_STREAM
_bitStreamBeforeDecoder(NULL),
_bitStreamBeforeDecoder(NULL),
#endif
_frameFromFile(),
_keyRequestMode(kKeyOnError),
_scheduleKeyRequest(false),
max_nack_list_size_(0),
_sendCritSect(CriticalSectionWrapper::CreateCriticalSection()),
_encoder(),
_encodedFrameCallback(),
_nextFrameTypes(1, kVideoFrameDelta),
_mediaOpt(id, clock_),
_sendCodecType(kVideoCodecUnknown),
_sendStatsCallback(NULL),
_encoderInputFile(NULL),
_codecDataBase(id),
_receiveStatsTimer(1000, clock_),
_sendStatsTimer(1000, clock_),
_retransmissionTimer(10, clock_),
_keyRequestTimer(500, clock_),
event_factory_(event_factory),
owns_event_factory_(owns_event_factory)
{
assert(clock_);
_frameFromFile(),
_keyRequestMode(kKeyOnError),
_scheduleKeyRequest(false),
max_nack_list_size_(0),
_sendCritSect(CriticalSectionWrapper::CreateCriticalSection()),
_encoder(),
_encodedFrameCallback(),
_nextFrameTypes(1, kVideoFrameDelta),
_mediaOpt(id, clock_),
_sendCodecType(kVideoCodecUnknown),
_sendStatsCallback(NULL),
_encoderInputFile(NULL),
_codecDataBase(id),
_receiveStatsTimer(1000, clock_),
_sendStatsTimer(1000, clock_),
_retransmissionTimer(10, clock_),
_keyRequestTimer(500, clock_),
event_factory_(event_factory),
owns_event_factory_(owns_event_factory) {
assert(clock_);
#ifdef DEBUG_DECODER_BIT_STREAM
_bitStreamBeforeDecoder = fopen("decoderBitStream.bit", "wb");
_bitStreamBeforeDecoder = fopen("decoderBitStream.bit", "wb");
#endif
}