Refactor NACK list creation to build the NACK list as packets arrive.

Also fixes a timer bug related to NACKing in the RTP module which could cause packets to only be NACKed twice if there's frequent packet losses.

Note that I decided to remove any selective NACKing for now as I don't think the gain of doing it is big enough compared to the added complexity. The same reasoning for empty packets. None of them will be retransmitted by a smart sender since the sender would know that they aren't needed.

BUG=1420
TEST=video_coding_unittests, vie_auto_test, video_coding_integrationtests, trybots

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3599 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org
2013-03-04 15:24:40 +00:00
parent 17b867ae00
commit a64300af50
22 changed files with 451 additions and 818 deletions

View File

@ -63,7 +63,7 @@ int32_t VCMReceiver::Initialize() {
CriticalSectionScoped cs(crit_sect_);
Reset();
if (!master_) {
SetNackMode(kNoNack);
SetNackMode(kNoNack, -1, -1);
}
return VCM_OK;
}
@ -72,7 +72,8 @@ void VCMReceiver::UpdateRtt(uint32_t rtt) {
jitter_buffer_.UpdateRtt(rtt);
}
int32_t VCMReceiver::InsertPacket(const VCMPacket& packet, uint16_t frame_width,
int32_t VCMReceiver::InsertPacket(const VCMPacket& packet,
uint16_t frame_width,
uint16_t frame_height) {
// Find an empty frame.
VCMEncodedFrame* buffer = NULL;
@ -243,7 +244,7 @@ VCMEncodedFrame* VCMReceiver::FrameForDecoding(
// No time to wait for a complete frame, check if we have an incomplete.
const bool dual_receiver_enabled_and_passive = (dual_receiver != NULL &&
dual_receiver->State() == kPassive &&
dual_receiver->NackMode() == kNackInfinite);
dual_receiver->NackMode() == kNack);
if (dual_receiver_enabled_and_passive &&
!jitter_buffer_.CompleteSequenceWithNextFrame()) {
// Jitter buffer state might get corrupt with this frame.
@ -269,7 +270,7 @@ VCMEncodedFrame* VCMReceiver::FrameForDecoding(
// No time left to wait, we must decode this frame now.
const bool dual_receiver_enabled_and_passive = (dual_receiver != NULL &&
dual_receiver->State() == kPassive &&
dual_receiver->NackMode() == kNackInfinite);
dual_receiver->NackMode() == kNack);
if (dual_receiver_enabled_and_passive &&
!jitter_buffer_.CompleteSequenceWithNextFrame()) {
// Jitter buffer state might get corrupt with this frame.
@ -306,7 +307,7 @@ VCMEncodedFrame* VCMReceiver::FrameForRendering(uint16_t max_wait_time_ms,
// Get an incomplete frame.
const bool dual_receiver_enabled_and_passive = (dual_receiver != NULL &&
dual_receiver->State() == kPassive &&
dual_receiver->NackMode() == kNackInfinite);
dual_receiver->NackMode() == kNack);
if (dual_receiver_enabled_and_passive &&
!jitter_buffer_.CompleteSequenceWithNextFrame()) {
// Jitter buffer state might get corrupt with this frame.
@ -340,10 +341,13 @@ uint32_t VCMReceiver::DiscardedPackets() const {
return jitter_buffer_.num_discarded_packets();
}
void VCMReceiver::SetNackMode(VCMNackMode nackMode) {
void VCMReceiver::SetNackMode(VCMNackMode nackMode,
int low_rtt_nack_threshold_ms,
int high_rtt_nack_threshold_ms) {
CriticalSectionScoped cs(crit_sect_);
// Default to always having NACK enabled in hybrid mode.
jitter_buffer_.SetNackMode(nackMode, kLowRttNackMs, -1);
jitter_buffer_.SetNackMode(nackMode, low_rtt_nack_threshold_ms,
high_rtt_nack_threshold_ms);
if (!master_) {
state_ = kPassive; // The dual decoder defaults to passive.
}
@ -361,24 +365,21 @@ VCMNackMode VCMReceiver::NackMode() const {
}
VCMNackStatus VCMReceiver::NackList(uint16_t* nack_list,
uint16_t* size) {
bool extended = false;
uint16_t nack_list_size = 0;
uint16_t* internal_nack_list = jitter_buffer_.CreateNackList(&nack_list_size,
&extended);
if (internal_nack_list == NULL && nack_list_size == 0xffff) {
uint16_t size,
uint16_t* nack_list_length) {
bool request_key_frame = false;
uint16_t* internal_nack_list = jitter_buffer_.GetNackList(
nack_list_length, &request_key_frame);
if (request_key_frame) {
// This combination is used to trigger key frame requests.
*size = 0;
return kNackKeyFrameRequest;
}
if (nack_list_size > *size) {
*size = nack_list_size;
if (*nack_list_length > size) {
return kNackNeedMoreMemory;
}
if (internal_nack_list != NULL && nack_list_size > 0) {
memcpy(nack_list, internal_nack_list, nack_list_size * sizeof(uint16_t));
if (internal_nack_list != NULL && *nack_list_length > 0) {
memcpy(nack_list, internal_nack_list, *nack_list_length * sizeof(uint16_t));
}
*size = nack_list_size;
return kNackOk;
}