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:
@ -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_
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user