Default to always NACKing residual losses when having both FEC and NACK.

BUG=
TEST=

Review URL: http://webrtc-codereview.appspot.com/296002

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1047 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2011-11-29 11:33:31 +00:00
parent 4b80eb4fcd
commit 932ab18d32
6 changed files with 79 additions and 42 deletions

View File

@ -16,7 +16,6 @@
#include "jitter_buffer.h" #include "jitter_buffer.h"
#include "jitter_buffer_common.h" #include "jitter_buffer_common.h"
#include "jitter_estimator.h" #include "jitter_estimator.h"
#include "media_optimization.h" // hybrid NACK/FEC thresholds.
#include "packet.h" #include "packet.h"
#include "event.h" #include "event.h"
@ -86,6 +85,8 @@ VCMJitterBuffer::VCMJitterBuffer(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId,
_jitterEstimate(vcmId, receiverId), _jitterEstimate(vcmId, receiverId),
_rttMs(0), _rttMs(0),
_nackMode(kNoNack), _nackMode(kNoNack),
_lowRttNackThresholdMs(-1),
_highRttNackThresholdMs(-1),
_NACKSeqNum(), _NACKSeqNum(),
_NACKSeqNumLength(0), _NACKSeqNumLength(0),
_waitingForKeyFrame(false), _waitingForKeyFrame(false),
@ -870,8 +871,10 @@ VCMJitterBuffer::GetEstimatedJitterMsInternal()
WebRtc_UWord32 estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER; WebRtc_UWord32 estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER;
// Compute RTT multiplier for estimation // Compute RTT multiplier for estimation
// _lowRttNackThresholdMs == -1 means no FEC.
double rttMult = 1.0f; double rttMult = 1.0f;
if (_nackMode == kNackHybrid && _rttMs > kLowRttNackMs) if (_nackMode == kNackHybrid && (_lowRttNackThresholdMs >= 0 &&
static_cast<int>(_rttMs) > _lowRttNackThresholdMs))
{ {
// from here we count on FEC // from here we count on FEC
rttMult = 0.0f; rttMult = 0.0f;
@ -1775,10 +1778,18 @@ VCMJitterBuffer::GetNackMode() const
// Set NACK mode // Set NACK mode
void void
VCMJitterBuffer::SetNackMode(VCMNackMode mode) VCMJitterBuffer::SetNackMode(VCMNackMode mode,
int lowRttNackThresholdMs,
int highRttNackThresholdMs)
{ {
CriticalSectionScoped cs(_critSect); CriticalSectionScoped cs(_critSect);
_nackMode = mode; _nackMode = mode;
assert(lowRttNackThresholdMs >= -1 && highRttNackThresholdMs >= -1);
assert(highRttNackThresholdMs == -1 ||
lowRttNackThresholdMs <= highRttNackThresholdMs);
assert(lowRttNackThresholdMs > -1 || highRttNackThresholdMs == -1);
_lowRttNackThresholdMs = lowRttNackThresholdMs;
_highRttNackThresholdMs = highRttNackThresholdMs;
if (_nackMode == kNoNack) if (_nackMode == kNoNack)
{ {
_jitterEstimate.ResetNackCount(); _jitterEstimate.ResetNackCount();
@ -2037,7 +2048,8 @@ VCMJitterBuffer::WaitForNack()
} }
// else: hybrid mode, evaluate // else: hybrid mode, evaluate
// RTT high, don't wait // RTT high, don't wait
if (_rttMs >= kHighRttNackMs) if (_highRttNackThresholdMs >= 0 &&
_rttMs >= static_cast<unsigned int>(_highRttNackThresholdMs))
{ {
return false; return false;
} }
@ -2045,5 +2057,4 @@ VCMJitterBuffer::WaitForNack()
return true; return true;
} }
} // namespace webrtc
}

View File

@ -121,7 +121,15 @@ public:
void UpdateRtt(WebRtc_UWord32 rttMs); void UpdateRtt(WebRtc_UWord32 rttMs);
// NACK // NACK
void SetNackMode(VCMNackMode mode); // Enable/disable nack // Set the NACK mode. "highRttNackThreshold" is an RTT threshold in ms above
// which NACK will be disabled if the NACK mode is "kNackHybrid",
// -1 meaning that NACK is always enabled in the Hybrid mode.
// "lowRttNackThreshold" is an RTT threshold in ms below which we expect to
// rely on NACK only, and therefore are using larger buffers to have time to
// wait for retransmissions.
void SetNackMode(VCMNackMode mode,
int lowRttNackThresholdMs,
int highRttNackThresholdMs);
VCMNackMode GetNackMode() const; // Get nack mode VCMNackMode GetNackMode() const; // Get nack mode
// Get list of missing sequence numbers (size in number of elements) // Get list of missing sequence numbers (size in number of elements)
WebRtc_UWord16* GetNackList(WebRtc_UWord16& nackSize, WebRtc_UWord16* GetNackList(WebRtc_UWord16& nackSize,
@ -236,6 +244,8 @@ private:
// NACK // NACK
VCMNackMode _nackMode; VCMNackMode _nackMode;
int _lowRttNackThresholdMs;
int _highRttNackThresholdMs;
// Holds the internal nack list (the missing sequence numbers) // Holds the internal nack list (the missing sequence numbers)
WebRtc_Word32 _NACKSeqNumInternal[kNackHistoryLength]; WebRtc_Word32 _NACKSeqNumInternal[kNackHistoryLength];
WebRtc_UWord16 _NACKSeqNum[kNackHistoryLength]; WebRtc_UWord16 _NACKSeqNum[kNackHistoryLength];

View File

@ -49,10 +49,16 @@ VCMProtectionMethod::UpdateContentMetrics(const
_qmRobustness->UpdateContent(contentMetrics); _qmRobustness->UpdateContent(contentMetrics);
} }
VCMNackFecMethod::VCMNackFecMethod(): VCMNackFecMethod::VCMNackFecMethod(int lowRttNackThresholdMs,
VCMFecMethod() int highRttNackThresholdMs)
{ : VCMFecMethod(),
_type = kNackFec; _lowRttNackMs(lowRttNackThresholdMs),
_highRttNackMs(highRttNackThresholdMs) {
assert(lowRttNackThresholdMs >= -1 && highRttNackThresholdMs >= -1);
assert(highRttNackThresholdMs == -1 ||
lowRttNackThresholdMs <= highRttNackThresholdMs);
assert(lowRttNackThresholdMs > -1 || highRttNackThresholdMs == -1);
_type = kNackFec;
} }
VCMNackFecMethod::~VCMNackFecMethod() VCMNackFecMethod::~VCMNackFecMethod()
@ -60,13 +66,13 @@ VCMNackFecMethod::~VCMNackFecMethod()
// //
} }
bool bool
VCMNackFecMethod::ProtectionFactor(const VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
VCMProtectionParameters* parameters)
{ {
// Hybrid Nack FEC has three operational modes: // Hybrid Nack FEC has three operational modes:
// 1. Low RTT (below kLowRttNackMs) - Nack only: Set FEC rate // 1. Low RTT (below kLowRttNackMs) - Nack only: Set FEC rate
// (_protectionFactorD) to zero. // (_protectionFactorD) to zero. -1 means no FEC.
// 2. High RTT (above kHighRttNackMs) - FEC Only: Keep FEC factors. // 2. High RTT (above _highRttNackMs) - FEC Only: Keep FEC factors.
// -1 means always allow NACK.
// 3. Medium RTT values - Hybrid mode: We will only nack the // 3. Medium RTT values - Hybrid mode: We will only nack the
// residual following the decoding of the FEC (refer to JB logic). FEC // residual following the decoding of the FEC (refer to JB logic). FEC
// delta protection factor will be adjusted based on the RTT. // delta protection factor will be adjusted based on the RTT.
@ -76,7 +82,7 @@ VCMNackFecMethod::ProtectionFactor(const
// Compute the protection factors // Compute the protection factors
VCMFecMethod::ProtectionFactor(parameters); VCMFecMethod::ProtectionFactor(parameters);
if (parameters->rtt < kLowRttNackMs) if (_lowRttNackMs == -1 || parameters->rtt < _lowRttNackMs)
{ {
_protectionFactorD = 0; _protectionFactorD = 0;
VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD); VCMFecMethod::UpdateProtectionFactorD(_protectionFactorD);
@ -84,7 +90,7 @@ VCMNackFecMethod::ProtectionFactor(const
// When in Hybrid mode (RTT range), adjust FEC rates based on the // When in Hybrid mode (RTT range), adjust FEC rates based on the
// RTT (NACK effectiveness) - adjustment factor is in the range [0,1]. // RTT (NACK effectiveness) - adjustment factor is in the range [0,1].
else if (parameters->rtt < kHighRttNackMs) else if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
{ {
// TODO(mikhal): Disabling adjustment temporarily. // TODO(mikhal): Disabling adjustment temporarily.
// WebRtc_UWord16 rttIndex = (WebRtc_UWord16) parameters->rtt; // WebRtc_UWord16 rttIndex = (WebRtc_UWord16) parameters->rtt;
@ -103,8 +109,7 @@ VCMNackFecMethod::ProtectionFactor(const
} }
bool bool
VCMNackFecMethod::EffectivePacketLoss(const VCMNackFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
VCMProtectionParameters* parameters)
{ {
// Set the effective packet loss for encoder (based on FEC code). // Set the effective packet loss for encoder (based on FEC code).
// Compute the effective packet loss and residual packet loss due to FEC. // Compute the effective packet loss and residual packet loss due to FEC.
@ -125,7 +130,7 @@ VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
_efficiency = parameters->bitRate * fecRate * _corrFecCost; _efficiency = parameters->bitRate * fecRate * _corrFecCost;
// Add NACK cost, when applicable // Add NACK cost, when applicable
if (parameters->rtt < kHighRttNackMs) if (_highRttNackMs == -1 || parameters->rtt < _highRttNackMs)
{ {
// nackCost = (bitRate - nackCost) * (lossPr) // nackCost = (bitRate - nackCost) * (lossPr)
_efficiency += parameters->bitRate * _residualPacketLossFec / _efficiency += parameters->bitRate * _residualPacketLossFec /
@ -603,7 +608,8 @@ VCMLossProtectionLogic::SetMethod(enum VCMProtectionMethodEnum newMethodType)
} }
case kNackFec: case kNackFec:
{ {
newMethod = new VCMNackFecMethod(); // Default to always having NACK enabled for the hybrid mode.
newMethod = new VCMNackFecMethod(kLowRttNackMs, -1);
break; break;
} }
default: default:

View File

@ -49,7 +49,7 @@ struct VCMProtectionParameters
residualPacketLossFec(0.0f), codecWidth(0), codecHeight(0) residualPacketLossFec(0.0f), codecWidth(0), codecHeight(0)
{} {}
WebRtc_UWord32 rtt; int rtt;
float lossPr; float lossPr;
float bitRate; float bitRate;
float packetsPerFrame; float packetsPerFrame;
@ -195,13 +195,18 @@ public:
class VCMNackFecMethod : public VCMFecMethod class VCMNackFecMethod : public VCMFecMethod
{ {
public: public:
VCMNackFecMethod(); VCMNackFecMethod(int lowRttNackThresholdMs,
int highRttNackThresholdMs);
virtual ~VCMNackFecMethod(); virtual ~VCMNackFecMethod();
virtual bool UpdateParameters(const VCMProtectionParameters* parameters); virtual bool UpdateParameters(const VCMProtectionParameters* parameters);
// Get the effective packet loss for ER // Get the effective packet loss for ER
bool EffectivePacketLoss(const VCMProtectionParameters* parameters); bool EffectivePacketLoss(const VCMProtectionParameters* parameters);
// Get the protection factors // Get the protection factors
bool ProtectionFactor(const VCMProtectionParameters* parameters); bool ProtectionFactor(const VCMProtectionParameters* parameters);
private:
int _lowRttNackMs;
int _highRttNackMs;
}; };
class VCMLossProtectionLogic class VCMLossProtectionLogic

View File

@ -8,12 +8,14 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "video_coding.h" #include "receiver.h"
#include "trace.h"
#include "encoded_frame.h" #include "encoded_frame.h"
#include "internal_defines.h" #include "internal_defines.h"
#include "receiver.h" #include "media_opt_util.h"
#include "tick_time.h" #include "tick_time.h"
#include "trace.h"
#include "video_coding.h"
#include <assert.h> #include <assert.h>
@ -373,7 +375,8 @@ void
VCMReceiver::SetNackMode(VCMNackMode nackMode) VCMReceiver::SetNackMode(VCMNackMode nackMode)
{ {
CriticalSectionScoped cs(_critSect); CriticalSectionScoped cs(_critSect);
_jitterBuffer.SetNackMode(nackMode); // Default to always having NACK enabled in hybrid mode.
_jitterBuffer.SetNackMode(nackMode, kLowRttNackMs, -1);
if (!_master) if (!_master)
{ {
_state = kPassive; // The dual decoder defaults to passive _state = kPassive; // The dual decoder defaults to passive

View File

@ -8,20 +8,22 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "common_types.h"
#include "jitter_buffer.h"
#include "jitter_estimator.h"
#include "inter_frame_delay.h"
#include "packet.h"
#include "tick_time.h"
#include "../source/event.h"
#include "frame_buffer.h"
#include "jitter_estimate_test.h"
#include "test_util.h"
#include "test_macros.h"
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include "common_types.h"
#include "../source/event.h"
#include "frame_buffer.h"
#include "inter_frame_delay.h"
#include "jitter_buffer.h"
#include "jitter_estimate_test.h"
#include "jitter_estimator.h"
#include "media_opt_util.h"
#include "packet.h"
#include "test_util.h"
#include "test_macros.h"
#include "tick_time.h"
using namespace webrtc; using namespace webrtc;
int CheckOutFrame(VCMEncodedFrame* frameOut, unsigned int size, bool startCode) int CheckOutFrame(VCMEncodedFrame* frameOut, unsigned int size, bool startCode)
@ -1568,7 +1570,7 @@ int JitterBufferTest(CmdArgs& args)
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// | 3 | 4 | 5 | 6 | 7 | 9 | x | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | x | 21 |.....| 102 | // | 3 | 4 | 5 | 6 | 7 | 9 | x | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | x | 21 |.....| 102 |
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
jb.SetNackMode(kNackInfinite); jb.SetNackMode(kNackInfinite, -1, -1);
TEST(jb.GetNackMode() == kNackInfinite); TEST(jb.GetNackMode() == kNackInfinite);
@ -2039,7 +2041,7 @@ int JitterBufferTest(CmdArgs& args)
// testing that empty packets do not clog the jitter buffer // testing that empty packets do not clog the jitter buffer
// Set hybrid mode // Set hybrid mode
jb.SetNackMode(kNackHybrid); jb.SetNackMode(kNackHybrid, kLowRttNackMs, -1);
TEST(jb.GetNackMode() == kNackHybrid); TEST(jb.GetNackMode() == kNackHybrid);
int maxSize = 100; int maxSize = 100;
@ -2067,7 +2069,7 @@ int JitterBufferTest(CmdArgs& args)
testFrame = jb.GetFrame(packet); testFrame = jb.GetFrame(packet);
TEST(frameIn != 0); TEST(frameIn != 0);
jb.SetNackMode(kNoNack); jb.SetNackMode(kNoNack, -1, -1);
jb.Flush(); jb.Flush();
// Testing that 1 empty packet inserted last will not be set for decoding // Testing that 1 empty packet inserted last will not be set for decoding
@ -2103,7 +2105,7 @@ int JitterBufferTest(CmdArgs& args)
// Test incomplete NALU frames // Test incomplete NALU frames
jb.Flush(); jb.Flush();
jb.SetNackMode(kNoNack); jb.SetNackMode(kNoNack, -1, -1);
seqNum ++; seqNum ++;
timeStamp += 33*90; timeStamp += 33*90;
int insertedLength=0; int insertedLength=0;