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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@74 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/video_coding/main/source/frame_buffer.cc b/modules/video_coding/main/source/frame_buffer.cc
index 6ea1f4b..bd8be3e 100644
--- a/modules/video_coding/main/source/frame_buffer.cc
+++ b/modules/video_coding/main/source/frame_buffer.cc
@@ -133,14 +133,19 @@
 
     if (kStateEmpty == _state)
     {
-        // This is the first packet inserted into this frame,
+        // This is the first packet (empty and/or data) inserted into this frame.
         // store some info and set some initial values.
         _timeStamp = packet.timestamp;
         _codec = packet.codec;
-        SetState(kStateIncomplete);
+        // for the first media packet
+        if (packet.frameType != kFrameEmpty)
+        {
+            SetState(kStateIncomplete);
+        }
     }
 
-    WebRtc_UWord32 requiredSizeBytes = Length() + packet.sizeBytes + (packet.insertStartCode?kH264StartCodeLengthBytes:0);
+    WebRtc_UWord32 requiredSizeBytes = Length() + packet.sizeBytes +
+                   (packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
     if (requiredSizeBytes >= _size)
     {
         const WebRtc_UWord32 increments = requiredSizeBytes / kBufferIncStepSizeBytes +
@@ -156,7 +161,7 @@
         }
     }
     WebRtc_Word64 retVal = _sessionInfo.InsertPacket(packet, _buffer);
-    if(retVal == -1)
+    if (retVal == -1)
     {
         return kSizeError;
     }
@@ -201,6 +206,17 @@
     return 0;
 }
 
+// Zero out all entries in list up to and including the (first) entry equal to
+// _lowSeqNum. Hybrid mode: 1. Don't NACK FEC packets 2. Make a smart decision
+// on whether to NACK or not
+
+WebRtc_Word32 VCMFrameBuffer::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
+                                                  WebRtc_Word32 num,
+                                                  float rttScore)
+{
+    return _sessionInfo.ZeroOutSeqNumHybrid(list, num, rttScore);
+}
+
 void VCMFrameBuffer::IncrementNackCount()
 {
     _nackCount++;
@@ -227,7 +243,6 @@
 {
     _length = 0;
     _timeStamp = 0;
-
     _sessionInfo.Reset();
     _frameCounted = false;
     _payloadType = 0;
@@ -237,7 +252,7 @@
     VCMEncodedFrame::Reset();
 }
 
-// Makes sure the session contain a decodable stream.
+// Makes sure the session contains a decodable stream.
 void
 VCMFrameBuffer::MakeSessionDecodable()
 {
@@ -275,7 +290,8 @@
 
     case kStateComplete:
         assert(_state == kStateEmpty ||
-               _state == kStateIncomplete);
+               _state == kStateIncomplete ||
+               _state == kStateDecodable);
 
         break;
 
@@ -286,11 +302,22 @@
 
     case kStateDecoding:
         // we can go to this state from state kStateComplete kStateIncomplete
-        assert(_state == kStateComplete || _state == kStateIncomplete);
+        assert(_state == kStateComplete || _state == kStateIncomplete ||
+               _state == kStateDecodable);
         // Transfer frame information to EncodedFrame and create any codec specific information
         RestructureFrameInformation();
         break;
 
+    case kStateDecodable:
+        if (_state == kStateComplete)
+        {
+            // if complete, obviously decodable, keep as is.
+            return;
+        }
+        assert(_state == kStateEmpty ||
+               _state == kStateIncomplete);
+        break;
+
     default:
         // Should never happen
         assert(!"FrameBuffer::SetState Incorrect frame buffer state as input");
diff --git a/modules/video_coding/main/source/frame_buffer.h b/modules/video_coding/main/source/frame_buffer.h
index 15d8f81..65c56a3 100644
--- a/modules/video_coding/main/source/frame_buffer.h
+++ b/modules/video_coding/main/source/frame_buffer.h
@@ -64,6 +64,10 @@
     // NACK
     // Zero out all entries in list up to and including the entry equal to _lowSeqNum
     WebRtc_Word32 ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 num);
+    // Hybrid extension: only NACK important packets, discard FEC packets
+    WebRtc_Word32 ZeroOutSeqNumHybrid(WebRtc_Word32* list,
+                                      WebRtc_Word32 num,
+                                      float rttScore);
     void IncrementNackCount();
     WebRtc_Word16 GetNackCount() const;
 
diff --git a/modules/video_coding/main/source/jitter_buffer.cc b/modules/video_coding/main/source/jitter_buffer.cc
index f7c85ea..b74adb0 100644
--- a/modules/video_coding/main/source/jitter_buffer.cc
+++ b/modules/video_coding/main/source/jitter_buffer.cc
@@ -16,6 +16,7 @@
 #include "jitter_buffer.h"
 #include "jitter_buffer_common.h"
 #include "jitter_estimator.h"
+#include "media_optimization.h" // hybrid NACK/FEC thresholds.
 #include "packet.h"
 
 #include "event.h"
@@ -46,11 +47,14 @@
 }
 
 bool
-VCMJitterBuffer::CompleteKeyFrameCriteria(VCMFrameBuffer* frame, const void* /*notUsed*/)
+VCMJitterBuffer::CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame,
+                                                   const void* /*notUsed*/)
 {
     const VCMFrameBufferStateEnum state = frame->GetState();
+    // We can decode key frame or decodable/complete frames.
     return (frame->FrameType() == kVideoFrameKey) &&
-           (state == kStateComplete);
+           ((state == kStateComplete)
+           || (state == kStateDecodable));
 }
 
 // Constructor
@@ -76,7 +80,8 @@
     _numConsecutiveOldFrames(0),
     _numConsecutiveOldPackets(0),
     _jitterEstimate(vcmId, receiverId),
-    _usingNACK(false),
+    _rttMs(0),
+    _nackMode(kNoNack),
     _NACKSeqNum(),
     _NACKSeqNumLength(0),
     _missingMarkerBits(false),
@@ -87,7 +92,7 @@
     _lastDecodedSeqNum = -1;
     memset(_NACKSeqNumInternal, -1, sizeof(_NACKSeqNumInternal));
 
-    for (int i=0; i< kStartNumberOfFrames; i++)
+    for (int i = 0; i< kStartNumberOfFrames; i++)
     {
         _frameBuffers[i] = new VCMFrameBuffer();
     }
@@ -130,7 +135,8 @@
         _jitterEstimate = rhs._jitterEstimate;
         _delayEstimate = rhs._delayEstimate;
         _waitingForCompletion = rhs._waitingForCompletion;
-        _usingNACK = rhs._usingNACK;
+        _nackMode = rhs._nackMode;
+        _rttMs = rhs._rttMs;
         _NACKSeqNumLength = rhs._NACKSeqNumLength;
         _missingMarkerBits = rhs._missingMarkerBits;
         _firstPacket = rhs._firstPacket;
@@ -138,7 +144,7 @@
         memcpy(_receiveStatistics, rhs._receiveStatistics, sizeof(_receiveStatistics));
         memcpy(_NACKSeqNumInternal, rhs._NACKSeqNumInternal, sizeof(_NACKSeqNumInternal));
         memcpy(_NACKSeqNum, rhs._NACKSeqNum, sizeof(_NACKSeqNum));
-        for (int i=0; i < kMaxNumberOfFrames; i++)
+        for (int i = 0; i < kMaxNumberOfFrames; i++)
         {
             if (_frameBuffers[i] != NULL)
             {
@@ -147,7 +153,7 @@
             }
         }
         while(_frameBuffersTSOrder.Erase(_frameBuffersTSOrder.First()) != -1) { }
-        for (int i=0; i < _maxNumberOfFrames; i++)
+        for (int i = 0; i < _maxNumberOfFrames; i++)
         {
             _frameBuffers[i] = new VCMFrameBuffer(*(rhs._frameBuffers[i]));
             if (_frameBuffers[i]->Length() > 0)
@@ -162,7 +168,8 @@
 }
 
 WebRtc_UWord32
-VCMJitterBuffer::LatestTimestamp(const WebRtc_UWord32 existingTimestamp, const WebRtc_UWord32 newTimestamp)
+VCMJitterBuffer::LatestTimestamp(const WebRtc_UWord32 existingTimestamp,
+                                 const WebRtc_UWord32 newTimestamp)
 {
     bool wrap = (newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) ||
                 (newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff);
@@ -185,7 +192,8 @@
 }
 
 // Start jitter buffer
-void VCMJitterBuffer::Start()
+void
+VCMJitterBuffer::Start()
 {
     CriticalSectionScoped cs(_critSect);
     _running = true;
@@ -205,12 +213,14 @@
     _waitingForCompletion.latestPacketTime = -1;
     _missingMarkerBits = false;
     _firstPacket = true;
+    _rttMs = 0;
     WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), "JB(0x%x): Jitter buffer: start", this);
 }
 
 
 // Stop jitter buffer
-void VCMJitterBuffer::Stop()
+void
+VCMJitterBuffer::Stop()
 {
     _critSect.Enter();
     _running = false;
@@ -231,21 +241,24 @@
     WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId), "JB(0x%x): Jitter buffer: stop", this);
 }
 
-bool VCMJitterBuffer::Running() const
+bool
+VCMJitterBuffer::Running() const
 {
     CriticalSectionScoped cs(_critSect);
     return _running;
 }
 
 // Flush jitter buffer
-void VCMJitterBuffer::Flush()
+void
+VCMJitterBuffer::Flush()
 {
     CriticalSectionScoped cs(_critSect);
     FlushInternal();
 }
 
 // Must be called under the critical section _critSect
-void VCMJitterBuffer::FlushInternal()
+void
+VCMJitterBuffer::FlushInternal()
 {
     // Erase all frames from the sorted list and set their state to free.
     _frameBuffersTSOrder.Flush();
@@ -292,7 +305,8 @@
 // Doing it here increases the degree of freedom for e.g. future
 // reconstructability of separate layers. Must be called under the
 // critical section _critSect.
-void VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
+void
+VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
 {
     if (frame == NULL)
     {
@@ -385,8 +399,7 @@
 
     // Only signal if this is the oldest frame.
     // Not necessary the case due to packet reordering or NACK.
-    if(!_usingNACK ||
-       (oldFrame != NULL && oldFrame == frame))
+    if (!WaitForNack() || (oldFrame != NULL && oldFrame == frame))
     {
         _frameEvent.Set();
     }
@@ -481,7 +494,7 @@
 
     _critSect.Enter();
 
-    for (int i=0; i<_maxNumberOfFrames; ++i)
+    for (int i = 0; i <_maxNumberOfFrames; ++i)
     {
         if (kStateFree == _frameBuffers[i]->GetState())
         {
@@ -512,7 +525,8 @@
 }
 
 // Must be called under the critical section _critSect.
-VCMFrameListItem* VCMJitterBuffer::FindOldestSequenceNum() const
+VCMFrameListItem*
+VCMJitterBuffer::FindOldestSequenceNum() const
 {
     WebRtc_UWord16 currentLow = 0xffff;
     VCMFrameBufferStateEnum state = kStateFree;
@@ -562,7 +576,8 @@
 // Must be called under critical section
 // Based on sequence number
 // Return NULL for lost packets
-VCMFrameListItem* VCMJitterBuffer::FindOldestCompleteContinuousFrame()
+VCMFrameListItem*
+VCMJitterBuffer::FindOldestCompleteContinuousFrame()
 {
     // if we have more than one frame done since last time, pick oldest
     VCMFrameBuffer* oldestFrame = NULL;
@@ -578,7 +593,8 @@
     {
         if (kStateComplete != oldestFrame->GetState())
         {
-            // Try to see if the frame is complete even though the state is not complete. Can happen if markerbit is not set.
+            // Try to see if the frame is complete even though the state is not
+            // complete. Can happen if markerbit is not set.
             if (!CheckForCompleteFrame(oldestFrameItem))
             {
                 oldestFrame = NULL;
@@ -590,7 +606,7 @@
             currentLow = oldestFrame->GetLowSeqNum();
         }
     }
-    if(oldestFrame == NULL)
+    if (oldestFrame == NULL)
     {
         // no complete frame no point to continue
         return NULL;
@@ -601,15 +617,16 @@
     // Use seqNum not timestamp since a full frame might be lost
     if (_lastDecodedSeqNum != -1)
     {
-        // it's not enough that we have complete frame we need the seq numbers to be continuous too
-        // for layers it's not enough that we have complete frame we need the layers to be continuous too
+        // it's not enough that we have complete frame we need the seq numbers
+        // to be continuous too for layers it's not enough that we have complete
+        // frame we need the layers to be continuous too
         currentLow = oldestFrame->GetLowSeqNum();
 
         WebRtc_UWord16 lastDecodedSeqNum = (WebRtc_UWord16)_lastDecodedSeqNum;
 
-        // we could have received the first packet of the last frame before a long period
-        // if drop, that case is handled by GetNackList
-        if ( ((WebRtc_UWord16)(lastDecodedSeqNum + 1)) != currentLow)
+        // we could have received the first packet of the last frame before a
+        // long period if drop, that case is handled by GetNackList
+        if (((WebRtc_UWord16)(lastDecodedSeqNum + 1)) != currentLow)
         {
             // wait since we want a complete continuous frame
             return NULL;
@@ -618,11 +635,12 @@
     return oldestFrameItem;
 }
 
-// Check if the oldest frame is complete even though it is not in a complete state.
+// Check if the oldest frame is complete even though it isn't complete.
 // This can happen when makerbit is not set
 // Must be called under the critical section _critSect.
 // Return false for lost packets
-bool VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
+bool
+VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
 {
     const VCMFrameListItem* nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameItem);
     VCMFrameBuffer* oldestFrame = NULL;
@@ -630,7 +648,7 @@
     {
         oldestFrame = oldestFrameItem->GetItem();
     }
-    if(nextFrameItem != NULL)
+    if (nextFrameItem != NULL)
     {
         // We have received at least one packet from a later frame.
         if(!oldestFrame->HaveLastPacket()) // If we don't have the markerbit
@@ -638,7 +656,7 @@
             VCMFrameBuffer* nextFrame = nextFrameItem->GetItem();
             // Verify that we have received the first packet of the next frame.
             // This is the only way we can be sure we're not missing the last packet.
-            if(nextFrame != NULL && nextFrame->GetLowSeqNum() ==
+            if (nextFrame != NULL && nextFrame->GetLowSeqNum() ==
                 static_cast<WebRtc_UWord16>(oldestFrame->GetHighSeqNum()+1)) // Sequence number is only 16 bit
             {
                 _missingMarkerBits = true;
@@ -648,7 +666,7 @@
                     UpdateFrameState(oldestFrame);
                 }
                 const VCMFrameBufferStateEnum state = oldestFrame->GetState();
-                if(state == kStateComplete)
+                if (state == kStateComplete)
                 {
                     if(oldestFrame->Length() > 0)
                     {
@@ -663,7 +681,8 @@
 }
 
 // Call from inside the critical section _critSect
-void VCMJitterBuffer::RecycleFrame(VCMFrameBuffer* frame)
+void
+VCMJitterBuffer::RecycleFrame(VCMFrameBuffer* frame)
 {
     if (frame == NULL)
     {
@@ -679,7 +698,8 @@
 
 
 // Calculate frame and bit rates
-WebRtc_Word32 VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
+WebRtc_Word32
+VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
 {
     CriticalSectionScoped cs(_critSect);
     const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
@@ -744,7 +764,8 @@
 }
 
 // Returns immediately or a X ms event hang waiting for a decodable frame, X decided by caller
-VCMEncodedFrame* VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
+VCMEncodedFrame*
+VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
 {
     if (!_running)
     {
@@ -853,38 +874,54 @@
     return oldestFrame;
 }
 
-WebRtc_UWord32 VCMJitterBuffer::GetEstimatedJitterMS()
+WebRtc_UWord32
+VCMJitterBuffer::GetEstimatedJitterMS()
 {
     CriticalSectionScoped cs(_critSect);
     return GetEstimatedJitterMsInternal();
 }
 
-WebRtc_UWord32 VCMJitterBuffer::GetEstimatedJitterMsInternal()
+WebRtc_UWord32
+VCMJitterBuffer::GetEstimatedJitterMsInternal()
 {
     WebRtc_UWord32 estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER;
-    estimate += static_cast<WebRtc_UWord32>(_jitterEstimate.GetJitterEstimate() + 0.5);
+
+    // compute RTT multiplier for estimation
+    double rttMult = 1.0f;
+    if (_nackMode == kNackHybrid && _rttMs > kLowRttNackMs)
+    {
+        // from here we count on FEC
+        rttMult = 0.0f;
+    }
+    estimate += static_cast<WebRtc_UWord32>
+                (_jitterEstimate.GetJitterEstimate(rttMult) + 0.5);
     if (_missingMarkerBits)
     {
-        // Since the incoming packets are all missing marker bits we have to wait until the first
-        // packet of the next frame arrives, before we can safely say that the frame is complete.
-        // Therefore we have to compensate the jitter buffer level with one frame period.
-
-        // TODO(holmer): The timestamp diff should probably be filtered (max filter) since
-        // the diff can alternate between e.g. 3000 and 6000 if we have a frame rate between
-        // 15 and 30 frames per seconds.
+        // Since the incoming packets are all missing marker bits we have to
+        // wait until the first packet of the next frame arrives, before we can
+        // safely say that the frame is complete. Therefore we have to compensate
+        // the jitter buffer level with one frame period.
+        // TODO(holmer): The timestamp diff should probably be filtered
+        // (max filter) since the diff can alternate between e.g. 3000 and 6000
+        // if we have a frame rate between 15 and 30 frames per seconds.
         estimate += _delayEstimate.CurrentTimeStampDiffMs();
     }
     return estimate;
 }
 
-void VCMJitterBuffer::UpdateRtt(WebRtc_UWord32 rttMs)
+void
+VCMJitterBuffer::UpdateRtt(WebRtc_UWord32 rttMs)
 {
     CriticalSectionScoped cs(_critSect);
+    _rttMs = rttMs;
     _jitterEstimate.UpdateRtt(rttMs);
 }
 
 // wait for the first packet in the next frame to arrive
-WebRtc_Word64 VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS, FrameType& incomingFrameType, WebRtc_Word64& renderTimeMs)
+WebRtc_Word64
+VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
+                                  FrameType& incomingFrameType,
+                                  WebRtc_Word64& renderTimeMs)
 {
     if (!_running)
     {
@@ -913,7 +950,6 @@
 
             CleanUpOldFrames();
             CleanUpSizeZeroFrames();
-
             oldestFrame = _frameBuffersTSOrder.FirstFrame();
         }else
         {
@@ -946,7 +982,8 @@
 // Will the packet sequence be complete if the next frame is grabbed for decoding right now?
 // That is, have we lost a frame between the last decoded frame and the next, or is the next
 // frame missing one or more packets?
-bool VCMJitterBuffer::CompleteSequenceWithNextFrame()
+bool
+VCMJitterBuffer::CompleteSequenceWithNextFrame()
 {
     CriticalSectionScoped cs(_critSect);
     // Finding oldest frame ready for decoder, but check sequence number and size
@@ -989,7 +1026,8 @@
 }
 
 // Returns immediately
-VCMEncodedFrame* VCMJitterBuffer::GetFrameForDecoding()
+VCMEncodedFrame*
+VCMJitterBuffer::GetFrameForDecoding()
 {
     CriticalSectionScoped cs(_critSect);
     if (!_running)
@@ -997,7 +1035,7 @@
         return NULL;
     }
 
-    if(_usingNACK)
+    if (WaitForNack())
     {
         return GetFrameForDecodingNACK();
     }
@@ -1061,6 +1099,7 @@
 {
     // when we use NACK we don't release non complete frames
     // unless we have a complete key frame.
+    // In hybrid mode, we may release decodable frames (non-complete)
 
     // Clean up old frames and empty frames
     CleanUpOldFrames();
@@ -1077,8 +1116,9 @@
     if (oldestFrame == NULL)
     {
         continuous = false;
-        // If we didn't find one we're good with a complete key frame.
-        oldestFrameListItem = _frameBuffersTSOrder.FindFrameListItem(CompleteKeyFrameCriteria);
+        // If we didn't find one we're good with a complete key/decodable frame.
+        oldestFrameListItem = _frameBuffersTSOrder.FindFrameListItem(
+                               CompleteDecodableKeyFrameCriteria);
         if (oldestFrameListItem != NULL)
         {
             oldestFrame = oldestFrameListItem->GetItem();
@@ -1089,7 +1129,7 @@
         }
     }
 
-    // We have a complete continuous frame, decode it.
+    // We have a complete/decodable continuous frame, decode it.
     // store seqnum
     _lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
     // store current time
@@ -1181,7 +1221,10 @@
 // Must be called under the critical section _critSect. Should never be called with
 // retransmitted frames, they must be filtered out before this function is called.
 void
-VCMJitterBuffer::UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs, WebRtc_UWord32 timestamp, WebRtc_UWord32 frameSize, bool incompleteFrame)
+VCMJitterBuffer::UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs,
+                                               WebRtc_UWord32 timestamp,
+                                               WebRtc_UWord32 frameSize,
+                                               bool incompleteFrame)
 {
     if (latestPacketTimeMs == -1)
     {
@@ -1217,17 +1260,18 @@
     highSeqNum = -1;
     lowSeqNum = _lastDecodedSeqNum;
 
-    // find higest seqnumbers
-    for (i=0; i<_maxNumberOfFrames; ++i)
+    // find highest seqnumbers
+    for (i = 0; i < _maxNumberOfFrames; ++i)
     {
         seqNum = _frameBuffers[i]->GetHighSeqNum();
 
-        // Ignore free frames
+        // Ignore free / empty frames
         VCMFrameBufferStateEnum state = _frameBuffers[i]->GetState();
-        if((kStateFree != state) &&
+
+        if ((kStateFree != state) &&
            (kStateEmpty != state) &&
            (kStateDecoding != state) &&
-           seqNum != -1)
+            seqNum != -1)
         {
             if (highSeqNum == -1)
             {
@@ -1260,9 +1304,10 @@
     int i = 0;
     WebRtc_Word32 lowSeqNum = -1;
     WebRtc_Word32 highSeqNum = -1;
-    listExtended=false;
+    listExtended = false;
 
-    if (!_usingNACK)
+    // don't create list, if we won't wait for it
+    if (!WaitForNack())
     {
         nackSize = 0;
         return NULL;
@@ -1277,11 +1322,10 @@
     // write a list of all seq num we have
     if (lowSeqNum == -1 || highSeqNum == -1)
     {
-        //This happens if we lose the first packet, nothing is poped
+        //This happens if we lose the first packet, nothing is popped
         if (highSeqNum == -1)
         {
             nackSize = 0;// we have not received any packets yet
-
         }
         else
         {
@@ -1371,7 +1415,8 @@
             // We have cleaned up the jb and found a key frame
             // The function itself has set last decoded seq.
             WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1,
-                    "\tKey frame found. _lastDecodedSeqNum[0] %d", _lastDecodedSeqNum);
+                    "\tKey frame found. _lastDecodedSeqNum[0] %d",
+                    _lastDecodedSeqNum);
             nackSize = 0;
         }
 
@@ -1379,27 +1424,51 @@
     }
 
     WebRtc_UWord16 seqNumberIterator = (WebRtc_UWord16)(lowSeqNum + 1);
-    for (i=0; i < numberOfSeqNum; i++)
+    for (i = 0; i < numberOfSeqNum; i++)
     {
         _NACKSeqNumInternal[i] = seqNumberIterator;
         seqNumberIterator++;
     }
-    // now we have a list of all seq numbers that could have been sent
+
+    // now we have a list of all sequence numbers that could have been sent
 
     // zero out the ones we have received
     for (i = 0; i < _maxNumberOfFrames; i++)
     {
         // loop all created frames
-        // We dont need to check if frame is decoding since lowSeqNum is based on _lastDecodedSeqNum
+        // We don't need to check if frame is decoding since lowSeqNum is based
+        // on _lastDecodedSeqNum
         // Ignore free frames
         VCMFrameBufferStateEnum state = _frameBuffers[i]->GetState();
+
         if ((kStateFree != state) &&
             (kStateEmpty != state) &&
             (kStateDecoding != state))
         {
-            _frameBuffers[i]->ZeroOutSeqNum(_NACKSeqNumInternal, numberOfSeqNum);
-            // used when the frame is being processed by the decoding thread
-            // dont need to use that info in this loop
+            // Reaching thus far means we are going to update the nack list
+            // When in hybrid mode, we also need to check empty frames, so as not
+            // to add empty packets to the nack list
+            if (_nackMode == kNackHybrid)
+            {
+                // build external rttScore based on RTT value
+                float rttScore = 1.0f;
+                _frameBuffers[i]->ZeroOutSeqNumHybrid(_NACKSeqNumInternal,
+                                                      numberOfSeqNum,
+                                                      rttScore);
+                if (_frameBuffers[i]->IsRetransmitted() == false)
+                {
+                    // if no retransmission required,set the state to decodable
+                    // meaning that we will not wait for NACK
+                    _frameBuffers[i]->SetState(kStateDecodable);
+                }
+            }
+            else
+            {
+                // used when the frame is being processed by the decoding thread
+                // don't need to use that info in this loop
+                _frameBuffers[i]->ZeroOutSeqNum(_NACKSeqNumInternal,
+                                                numberOfSeqNum);
+            }
         }
     }
 
@@ -1407,7 +1476,7 @@
     int emptyIndex = -1;
     for (i = 0; i < numberOfSeqNum; i++)
     {
-        if (_NACKSeqNumInternal[i] == -1)
+        if (_NACKSeqNumInternal[i] == -1 || _NACKSeqNumInternal[i] == -2 )
         {
             // this is empty
             if (emptyIndex == -1)
@@ -1442,36 +1511,39 @@
         nackSize = emptyIndex;
     }
     // convert to unsigned short 16 bit and store in a list to be used externally.
-    if(nackSize > _NACKSeqNumLength)
+    if (nackSize > _NACKSeqNumLength)
     {
-        listExtended=true; // Larger list means that the nack list has been extended since the last call.
+        // Larger list means that the nack list was extended since the last call.
+        listExtended = true;
     }
+
     for(WebRtc_UWord32 j = 0; j < nackSize; j++)
     {
-        // Check if the list has been extended since it was last created. I.e, new items have been added
-        if(_NACKSeqNumLength > j && !listExtended)
+        // Check if the list has been extended since it was last created. I.e,
+        // new items have been added
+        if (_NACKSeqNumLength > j && !listExtended)
         {
             WebRtc_UWord32 k = 0;
-            for(k = j; k < _NACKSeqNumLength; k++)
+            for (k = j; k < _NACKSeqNumLength; k++)
             {
                 // Found the item in the last list. I.e, no new items found yet.
-                if(_NACKSeqNum[k] == (WebRtc_UWord16)_NACKSeqNumInternal[j])
+                if (_NACKSeqNum[k] == (WebRtc_UWord16)_NACKSeqNumInternal[j])
                 {
                    break;
                 }
-
             }
-            if(k == _NACKSeqNumLength) // New item not found in last list.
+            if (k == _NACKSeqNumLength) // New item not found in last list.
             {
-                listExtended=true;
+                listExtended = true;
             }
         }
         else
         {
-            listExtended=true;
+            listExtended = true;
         }
         _NACKSeqNum[j] = (WebRtc_UWord16)_NACKSeqNumInternal[j];
     }
+
     _NACKSeqNumLength = nackSize;
 
     return _NACKSeqNum;
@@ -1511,35 +1583,39 @@
     VCMFrameBufferEnum ret = kSizeError;
     VCMFrameBuffer* frame = static_cast<VCMFrameBuffer*>(buffer);
 
-    if (_firstPacket)
+    // Empty packets may bias the jitter estimate (lacking size component),
+    // therefore don't let empty packet trigger the following updates:
+    if (packet.frameType != kFrameEmpty)
     {
-        // Now it's time to start estimating jitter
-        // reset the delay estimate.
-        _delayEstimate.Reset();
-        _firstPacket = false;
-    }
+        if (_firstPacket)
+        {
+            // Now it's time to start estimating jitter
+            // reset the delay estimate.
+            _delayEstimate.Reset();
+            _firstPacket = false;
+        }
 
-    if (_waitingForCompletion.timestamp == packet.timestamp)
-    {
-        // This can get bad if we have a lot of duplicate packets,
-        // we will then count some packet multiple times.
-        _waitingForCompletion.frameSize += packet.sizeBytes;
-        _waitingForCompletion.latestPacketTime = nowMs;
-    }
-    else if (_waitingForCompletion.latestPacketTime >= 0 &&
-             _waitingForCompletion.latestPacketTime + 2000 <= nowMs)
-    {
-        // A packet should never be more than two seconds late
-        UpdateJitterAndDelayEstimates(_waitingForCompletion, true);
-        _waitingForCompletion.latestPacketTime = -1;
-        _waitingForCompletion.frameSize = 0;
-        _waitingForCompletion.timestamp = 0;
+        if (_waitingForCompletion.timestamp == packet.timestamp)
+        {
+            // This can get bad if we have a lot of duplicate packets,
+            // we will then count some packet multiple times.
+            _waitingForCompletion.frameSize += packet.sizeBytes;
+            _waitingForCompletion.latestPacketTime = nowMs;
+        }
+        else if (_waitingForCompletion.latestPacketTime >= 0 &&
+                 _waitingForCompletion.latestPacketTime + 2000 <= nowMs)
+        {
+            // A packet should never be more than two seconds late
+            UpdateJitterAndDelayEstimates(_waitingForCompletion, true);
+            _waitingForCompletion.latestPacketTime = -1;
+            _waitingForCompletion.frameSize = 0;
+            _waitingForCompletion.timestamp = 0;
+        }
     }
 
     if (frame != NULL)
     {
         VCMFrameBufferStateEnum state = frame->GetState();
-
         if (state == kStateDecoding && packet.sizeBytes == 0)
         {
             // Filler packet, make sure we update the last decoded seq num
@@ -1655,7 +1731,7 @@
 {
     if (_NACKSeqNum && _NACKSeqNumLength > 0)
     {
-        for (WebRtc_UWord16 i=0; i < _NACKSeqNumLength; i++)
+        for (WebRtc_UWord16 i = 0; i < _NACKSeqNumLength; i++)
         {
             if (packet.seqNum == _NACKSeqNum[i])
             {
@@ -1667,18 +1743,20 @@
 }
 
 // Get nack status (enabled/disabled)
-bool VCMJitterBuffer::GetNackStatus()
+VCMNackMode
+VCMJitterBuffer::GetNackMode() const
 {
     CriticalSectionScoped cs(_critSect);
-    return _usingNACK;
+    return _nackMode;
 }
 
-// Enable/disable nack
-void VCMJitterBuffer::SetNackStatus(bool enable)
+// Set NACK mode
+void
+VCMJitterBuffer::SetNackMode(VCMNackMode mode)
 {
     CriticalSectionScoped cs(_critSect);
-    _usingNACK = enable;
-    if (!_usingNACK)
+    _nackMode = mode;
+    if (_nackMode == kNoNack)
     {
         _jitterEstimate.ResetNackCount();
     }
@@ -1808,7 +1886,7 @@
                 const WebRtc_Word32 frameHighSeqNum = ptrTempBuffer->GetHighSeqNum();
                 const WebRtc_Word32 frameLowSeqNum = ptrTempBuffer->GetLowSeqNum();
 
-                if ((frameLowSeqNum == (_lastDecodedSeqNum+ 1)) || // Frame is next in line
+                if ((frameLowSeqNum == (_lastDecodedSeqNum + 1)) || // Frame is next in line
                     ((frameLowSeqNum == 0) && (_lastDecodedSeqNum== 0xffff)))
                 {
                     // This frame follows the last decoded frame, release it.
@@ -1878,4 +1956,33 @@
     }
 }
 
+bool
+VCMJitterBuffer::WaitForNack()
+{
+     // NACK disabled -> can't wait
+     if (_nackMode == kNoNack)
+     {
+         return false;
+     }
+     // NACK only -> always wait
+     else if (_nackMode == kNackInfinite)
+     {
+         return true;
+     }
+     // else: hybrid mode, evaluate
+     // RTT high, don't wait
+     if (_rttMs >= kHighRttNackMs)
+     {
+         return false;
+     }
+     // RTT low, we can afford the wait
+     else if (_rttMs <= kLowRttNackMs)
+     {
+          return true;
+     }
+     // interim values - hybrid mode
+     return true;
+}
+
+
 }
diff --git a/modules/video_coding/main/source/jitter_buffer.h b/modules/video_coding/main/source/jitter_buffer.h
index 4ec1935..ab88f38 100644
--- a/modules/video_coding/main/source/jitter_buffer.h
+++ b/modules/video_coding/main/source/jitter_buffer.h
@@ -24,6 +24,13 @@
 namespace webrtc
 {
 
+enum VCMNackMode
+{
+    kNackInfinite,
+    kNackHybrid,
+    kNoNack
+};
+
 // forward declarations
 class VCMFrameBuffer;
 class VCMPacket;
@@ -90,7 +97,7 @@
     WebRtc_Word32 GetFrame(const VCMPacket& packet, VCMEncodedFrame*&);
     VCMEncodedFrame* GetFrame(const VCMPacket& packet); // deprecated
 
-    // Returns the time in ms when the latest packet was insterted into the frame.
+    // Returns the time in ms when the latest packet was inserted into the frame.
     // Retransmitted is set to true if any of the packets belonging to the frame
     // has been retransmitted.
     WebRtc_Word64 LastPacketTime(VCMEncodedFrame* frame, bool& retransmitted) const;
@@ -103,8 +110,8 @@
     void UpdateRtt(WebRtc_UWord32 rttMs);
 
     // NACK
-    void SetNackStatus(bool enable); // Enable/disable nack
-    bool GetNackStatus();            // Get nack status (enabled/disabled)
+    void SetNackMode(VCMNackMode mode); // Enable/disable nack
+    VCMNackMode GetNackMode() const;    // Get nack mode
     // Get list of missing sequence numbers (size in number of elements)
     WebRtc_UWord16* GetNackList(WebRtc_UWord16& nackSize, bool& listExtended);
 
@@ -162,18 +169,23 @@
 private:
 
     static bool FrameEqualTimestamp(VCMFrameBuffer* frame, const void* timestamp);
-    static bool CompleteKeyFrameCriteria(VCMFrameBuffer* frame, const void* notUsed);
+    static bool CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame,
+                                                  const void* notUsed);
+    // Decide whether should wait for NACK (mainly relevant for hybrid mode)
+    bool WaitForNack();
 
     WebRtc_Word32                 _vcmId;
     WebRtc_Word32                 _receiverId;
-    bool                          _running;     // If we are running (have started) or not
-    CriticalSectionWrapper&          _critSect;
+    // If we are running (have started) or not
+    bool                          _running;
+    CriticalSectionWrapper&       _critSect;
     bool                          _master;
     // Event to signal when we have a frame ready for decoder
     VCMEvent                      _frameEvent;
     // Event to signal when we have received a packet
     VCMEvent                      _packetEvent;
-    WebRtc_Word32                 _maxNumberOfFrames; // Number of allocated frames
+    // Number of allocated frames
+    WebRtc_Word32                 _maxNumberOfFrames;
     // Array of pointers to the frames in JB
     VCMFrameBuffer*               _frameBuffers[kMaxNumberOfFrames];
     VCMFrameListTimestampOrderAsc _frameBuffersTSOrder;
@@ -189,10 +201,12 @@
     WebRtc_UWord8           _receiveStatistics[4];
     // Latest calculated frame rates of incoming stream
     WebRtc_UWord8           _incomingFrameRate;
-    WebRtc_UWord32          _incomingFrameCount;   // Frame counter, reset in GetUpdate
+    // Frame counter, reset in GetUpdate
+    WebRtc_UWord32          _incomingFrameCount;
     // Real time for last _frameCount reset
     WebRtc_Word64           _timeLastIncomingFrameCount;
-    WebRtc_UWord32          _incomingBitCount;     // Received bits counter, reset in GetUpdate
+    // Received bits counter, reset in GetUpdate
+    WebRtc_UWord32          _incomingBitCount;
     WebRtc_UWord32          _incomingBitRate;
     WebRtc_UWord32          _dropCount;            // Frame drop counter
     // Number of frames in a row that have been too old
@@ -204,9 +218,10 @@
     // Calculates network delays used for jitter calculations
     VCMInterFrameDelay      _delayEstimate;
     VCMJitterSample         _waitingForCompletion;
+    WebRtc_UWord32          _rttMs;
 
     // NACK
-    bool                    _usingNACK; // If we are using nack
+    VCMNackMode             _nackMode;
     // Holds the internal nack list (the missing seqence numbers)
     WebRtc_Word32           _NACKSeqNumInternal[kNackHistoryLength];
     WebRtc_UWord16          _NACKSeqNum[kNackHistoryLength];
diff --git a/modules/video_coding/main/source/jitter_buffer_common.h b/modules/video_coding/main/source/jitter_buffer_common.h
index a90418f..6f7bcad 100644
--- a/modules/video_coding/main/source/jitter_buffer_common.h
+++ b/modules/video_coding/main/source/jitter_buffer_common.h
@@ -46,7 +46,8 @@
     kStateEmpty,              // frame popped by the RTP receiver
     kStateIncomplete,         // frame that have one or more packet(s) stored
     kStateComplete,           // frame that have all packets
-    kStateDecoding            // frame popped by the decoding thread
+    kStateDecoding,           // frame popped by the decoding thread
+    kStateDecodable           // Hybrid mode - frame can be decoded
 };
 
 enum { kH264StartCodeLengthBytes = 4};
diff --git a/modules/video_coding/main/source/jitter_estimator.cc b/modules/video_coding/main/source/jitter_estimator.cc
index 00dfe13..59c71f1 100644
--- a/modules/video_coding/main/source/jitter_estimator.cc
+++ b/modules/video_coding/main/source/jitter_estimator.cc
@@ -422,7 +422,7 @@
 // Returns the current filtered estimate if available,
 // otherwise tries to calculate an estimate.
 double
-VCMJitterEstimator::GetJitterEstimate()
+VCMJitterEstimator::GetJitterEstimate(double rttMultiplier)
 {
     double jitterMS = CalculateEstimate();
     if (_filterJitterEstimate > jitterMS)
@@ -431,7 +431,7 @@
     }
     if (_nackCount >= _nackLimit)
     {
-        return jitterMS + _rttFilter.RttMs();
+        return jitterMS + _rttFilter.RttMs() * rttMultiplier;
     }
     return jitterMS;
 }
diff --git a/modules/video_coding/main/source/jitter_estimator.h b/modules/video_coding/main/source/jitter_estimator.h
index 61263f0..1c5b071 100644
--- a/modules/video_coding/main/source/jitter_estimator.h
+++ b/modules/video_coding/main/source/jitter_estimator.h
@@ -41,9 +41,11 @@
 
     // Returns the current jitter estimate in milliseconds and adds
     // also adds an RTT dependent term in cases of retransmission.
+    //  Input:
+    //          - rttMultiplier  : RTT param multiplier (when applicable).
     //
     // Return value                   : Jitter estimate in milliseconds
-    double GetJitterEstimate();
+    double GetJitterEstimate(double rttMultiplier);
 
     // Updates the nack counter/timer.
     //
diff --git a/modules/video_coding/main/source/media_opt_util.cc b/modules/video_coding/main/source/media_opt_util.cc
index 181144d..1404793 100644
--- a/modules/video_coding/main/source/media_opt_util.cc
+++ b/modules/video_coding/main/source/media_opt_util.cc
@@ -18,105 +18,123 @@
 #include <math.h>
 #include <float.h>
 #include <limits.h>
-#include <stdio.h>
 
 namespace webrtc {
 
-bool
-VCMProtectionMethod::BetterThan(VCMProtectionMethod *pm)
+
+bool VCMProtectionMethod::BetterThan(VCMProtectionMethod *pm)
 {
-    if (pm == NULL)
-    {
-        return true;
-    }
-    return pm->_score > _score;
+  if (pm == NULL) {
+    return true;
+  }
+  return pm->_score > _score;
 }
 
-bool
-VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* /*parameters*/)
+bool VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* /*parameters*/)
 {
-
-   //use FEC model with modification with RTT for now
-
+    // use FEC model with modification with RTT for now
     return true;
 }
 
-bool
-VCMNackFecMethod::EffectivePacketLoss(const VCMProtectionParameters* /*parameters*/)
+bool VCMNackFecMethod::EffectivePacketLoss(const VCMProtectionParameters* /*parameters*/)
 {
-  //use FEC model with modification with RTT for now
-
-  return true;
+    // use FEC model with modification with RTT for now
+    return true;
 }
 
-
-bool
-VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+bool VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
 {
 
-     VCMFecMethod fecMethod;
-     VCMNackMethod nackMethod;
+    // Hybrid Nack FEC has three operational modes:
+    // 1. Low RTT - Nack only (Set FEC rates to zero)
+    // 2. High RTT - FEC Only
+    // 3. Medium RTT values - Hybrid ; in hybrid mode, we will only nack the residual
+    //              following the decoding of the FEC (and not in all cases, refer to JB logic)
+
+    // Low RTT - NACK only mode
+    if (parameters->rtt < kLowRttNackMs)
+    {
+        // Set the FEC parameters to 0
+        _protectionFactorK = 0;
+        _protectionFactorD = 0;
+
+        // assume packets will be restored via NACK
+        // TODO: relax this assumption?
+        _effectivePacketLoss = 0;
+        _score = _efficiency;
+        return true;
+    }
+    // otherwise: we count on FEC; if the RTT is below a threshold, then we can
+    // nack the residual, based on a decision made in the JB.
+    // TODO(mikhal): adapt the FEC rate based on the RTT, i.e. the the
+    // level on which we will rely on NACK, e.g. less as we approach upper threshold.
+    VCMFecMethod fecMethod;
 
     const WebRtc_UWord8 plossMax = 129;
-     WebRtc_UWord16 rttMax = nackMethod.MaxRttNack();
 
-    // We should reduce the NACK threshold for NackFec protection method,
-    // with FEC and ER, we should only use NACK for small RTT, to avoid delay
-     //But this parameter change should be shared with RTP and JB
-     //rttMax  = (WebRtc_UWord16) 0.5*rttMax;
+    // Compute the protection factor
+    fecMethod.ProtectionFactor(parameters);
 
-     //Compute the protection factor
-     fecMethod.ProtectionFactor(parameters);
+    // Compute the effective packet loss
+    fecMethod.EffectivePacketLoss(parameters);
 
-     //Compute the effective packet loss
-     fecMethod.EffectivePacketLoss(parameters);
+    WebRtc_UWord8 protFactorK = fecMethod._protectionFactorK;
+    WebRtc_UWord8 protFactorD = fecMethod._protectionFactorD;
+    WebRtc_UWord8 effPacketLoss = fecMethod._effectivePacketLoss;
+    float resPacketLoss = fecMethod._residualPacketLoss;
 
-     WebRtc_UWord8 protFactorK = fecMethod._protectionFactorK;
-     WebRtc_UWord8 protFactorD = fecMethod._protectionFactorD;
-     WebRtc_UWord8 effPacketLoss = fecMethod._effectivePacketLoss;
-     float resPacketLoss = fecMethod._residualPacketLoss;
-
+    // Correct FEC rates based on the RTT ( NACK effectiveness)
     WebRtc_Word16 rttIndex= (WebRtc_UWord16) parameters->rtt;
     float softnessRtt = 1.0;
-    if (parameters->rtt < rttMax)
+    if (parameters->rtt < kHighRttNackMs)
     {
-         softnessRtt = (float)VCMNackFecTable[rttIndex]/(float)4096.0;
+        // TODO(mikhal): update table
+         softnessRtt = (float)VCMNackFecTable[rttIndex] / (float)4096.0;
 
-         //soften ER with NACK on
-        //table depends on roundtrip time relative to rttMax (NACK Threshold)
-        _effectivePacketLoss = (WebRtc_UWord8)(effPacketLoss*softnessRtt);
+        // soften ER with NACK on
+        // table depends on RTT relative to rttMax (NACK Threshold)
+        _effectivePacketLoss = (WebRtc_UWord8)(effPacketLoss * softnessRtt);
 
-        //soften FEC with NACK on
-        //table depends on roundtrip time relative to rttMax (NACK Threshold)
+        // soften FEC with NACK on
+        // table depends on RTT relative to rttMax (NACK Threshold)
         _protectionFactorK = (WebRtc_UWord8) (protFactorK * softnessRtt);
         _protectionFactorD = (WebRtc_UWord8) (protFactorD * softnessRtt);
     }
+    // else - NACK is disabled, rely on FEC only
 
 
-    //make sure I frame protection is at least larger than P frame protection, and at least as high as received loss
-    WebRtc_UWord8 packetLoss = (WebRtc_UWord8)(255* parameters->lossPr);
-     _protectionFactorK = static_cast<WebRtc_UWord8>(VCM_MAX(packetLoss,VCM_MAX(_scaleProtKey*protFactorD,protFactorK)));
+    // make sure I frame protection is at least larger than P frame protection,
+    // and at least as high as received loss
+    WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
+    _protectionFactorK = static_cast<WebRtc_UWord8> (VCM_MAX(packetLoss,
+        VCM_MAX(_scaleProtKey * protFactorD, protFactorK)));
 
-    //check limit on amount of protection for I frame: 50% is max
-    if (_protectionFactorK  >= plossMax) _protectionFactorK  = plossMax - 1;
+    // check limit on amount of protection for I frame: 50% is max
+    if (_protectionFactorK >= plossMax)
+        _protectionFactorK = plossMax - 1;
 
-    //Bit cost for NackFec
+    // Bit cost for NackFec
 
-     // NACK cost: based on residual packet loss (since we should only NACK packet not recovered by FEC)
+    // NACK cost: based on residual packet loss (since we should only NACK packets
+    // not recovered by FEC)
     _efficiency = 0.0f;
-    if (parameters->rtt < rttMax)
+    if (parameters->rtt < kHighRttNackMs)
+    {
         _efficiency = parameters->bitRate * resPacketLoss / (1.0f + resPacketLoss);
-
-    //add FEC cost: ignore I frames for now
-    float fecRate = static_cast<float>(_protectionFactorD) / 255.0f;
-    if (fecRate >= 0.0f)
-         _efficiency += parameters->bitRate * fecRate;
-
+    } else
+    {
+        // efficiency based on FEC only
+        // add FEC cost: ignore I frames for now
+        float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
+        if (fecRate >= 0.0f)
+            _efficiency += parameters->bitRate * fecRate;
+    }
     _score = _efficiency;
 
-    //Protection/fec rates obtained above is defined relative to total number of packets (total rate: source+fec)
-    //FEC in RTP module assumes protection factor is defined relative to source number of packets
-    //so we should convert the factor to reduce mismatch between mediaOpt suggested rate and the actual rate
+    // Protection/fec rates obtained above are defined relative to total number of
+    // packets (total rate: source + fec) FEC in RTP module assumes protection
+    // factor is defined relative to source number of packets so we should convert
+    // the factor to reduce mismatch between mediaOpt's rate and the actual one
     WebRtc_UWord8 codeRate = protFactorK;
     _protectionFactorK = fecMethod.ConvertFECRate(codeRate);
     codeRate = protFactorD;
@@ -125,34 +143,30 @@
     return true;
 }
 
-
-bool
-VCMNackMethod::EffectivePacketLoss(WebRtc_UWord8 effPacketLoss, WebRtc_UWord16 rttTime)
+bool VCMNackMethod::EffectivePacketLoss(WebRtc_UWord8 effPacketLoss, WebRtc_UWord16 rttTime)
 {
 
     WebRtc_UWord16 rttMax = MaxRttNack();
 
-    //For large RTT, we should rely on some Error Resilience, so we set packetLossEnc = 0
-    //for RTT less than the NACK threshold
-    if (rttTime < rttMax )
-        effPacketLoss =  0;   //may want a softer transition here
+    // For large RTT, we should rely on some Error Resilience, so we set
+    // packetLossEnc = 0 for RTT less than the NACK threshold
+    if (rttTime < rttMax)
+      effPacketLoss = 0; //may want a softer transition here
 
-     _effectivePacketLoss = effPacketLoss;
+    _effectivePacketLoss = effPacketLoss;
 
     return true;
 
 }
-bool
-VCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
-{
 
-    //Compute the effective packet loss for ER
-    WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8)(255* parameters->lossPr);
+bool VCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+{
+    // Compute the effective packet loss for ER
+    WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
     WebRtc_UWord16 rttTime = (WebRtc_UWord16) parameters->rtt;
     EffectivePacketLoss(effPacketLoss, rttTime);
-    //
 
-    //Compute the NACK bit cost
+    // Compute the NACK bit cost
     _efficiency = parameters->bitRate * parameters->lossPr / (1.0f + parameters->lossPr);
     _score = _efficiency;
     if (parameters->rtt > _NACK_MAX_RTT)
@@ -164,145 +178,132 @@
     return true;
 }
 
-
-WebRtc_UWord8
-VCMFecMethod::BoostCodeRateKey(WebRtc_UWord8 packetFrameDelta, WebRtc_UWord8 packetFrameKey) const
+WebRtc_UWord8 VCMFecMethod::BoostCodeRateKey(WebRtc_UWord8 packetFrameDelta,
+                                             WebRtc_UWord8 packetFrameKey) const
 {
+  WebRtc_UWord8 boostRateKey = 2;
+  // default: ratio scales the FEC protection up for I frames
+  WebRtc_UWord8 ratio = 1;
 
-    WebRtc_UWord8 boostRateKey = 2;
-    //default: ratio scales the FEC protection up for I frames
-    WebRtc_UWord8 ratio = 1;
+  if (packetFrameDelta > 0)
+    ratio = (WebRtc_Word8) (packetFrameKey / packetFrameDelta);
 
-    if (packetFrameDelta > 0)
-        ratio = (WebRtc_Word8)( packetFrameKey / packetFrameDelta );
+  ratio = VCM_MAX(boostRateKey, ratio);
 
-    ratio = VCM_MAX(boostRateKey, ratio);
-
-    return ratio;
+  return ratio;
 
 }
 
-WebRtc_UWord8
-VCMFecMethod::ConvertFECRate(WebRtc_UWord8 codeRateRTP) const
+WebRtc_UWord8 VCMFecMethod::ConvertFECRate(WebRtc_UWord8 codeRateRTP) const
 {
-    return static_cast<WebRtc_UWord8>(VCM_MIN(255,(0.5 + 255.0*codeRateRTP/(float)(255 - codeRateRTP))));
+    return static_cast<WebRtc_UWord8> (VCM_MIN(255,(0.5 + 255.0*codeRateRTP/(float)(255 - codeRateRTP))));
 }
 
-//AvgRecoveryFEC: average recovery from FEC, assuming random packet loss model
-//Computed offline for a range of FEC code parameters and loss rates
-float
-VCMFecMethod::AvgRecoveryFEC(const VCMProtectionParameters* parameters) const
+// AvgRecoveryFEC: average recovery from FEC, assuming random packet loss model
+// Computed offline for a range of FEC code parameters and loss rates
+float VCMFecMethod::AvgRecoveryFEC(const VCMProtectionParameters* parameters) const
 {
+    // Total (avg) bits available per frame: total rate over actual/sent frame rate
+    // units are kbits/frame
+    const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16> (parameters->bitRate
+        / (parameters->frameRate));
 
-    //Total (avg) bits available per frame: total rate over actual/sent frame rate
-    //units are kbits/frame
-    const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16>(parameters->bitRate/(parameters->frameRate));
+    // Total (avg) number of packets per frame (source and fec):
+    const WebRtc_UWord8 avgTotPackets = 1 + (WebRtc_UWord8) ((float) bitRatePerFrame * 1000.0
+        / (float) (8.0 * _maxPayloadSize) + 0.5);
 
-    //Total (avg) number of packets per frame (source and fec):
-    const WebRtc_UWord8 avgTotPackets  = 1 + (WebRtc_UWord8)((float)bitRatePerFrame*1000.0/(float)(8.0*_maxPayloadSize) + 0.5);
-
-    //parameters for tables
+    // parameters for tables
     const WebRtc_UWord8 codeSize = 24;
     const WebRtc_UWord8 plossMax = 129;
     const WebRtc_UWord16 maxErTableSize = 38700;
-    //
 
-    //
-    //Get index for table
-    const float protectionFactor = (float)_protectionFactorD/(float)255;
-    WebRtc_UWord8 fecPacketsPerFrame =  (WebRtc_UWord8)(0.5 + protectionFactor*avgTotPackets);
+    // Get index for table
+    const float protectionFactor = (float) _protectionFactorD / (float) 255;
+    WebRtc_UWord8 fecPacketsPerFrame = (WebRtc_UWord8) (0.5 + protectionFactor * avgTotPackets);
     WebRtc_UWord8 sourcePacketsPerFrame = avgTotPackets - fecPacketsPerFrame;
 
-    if (fecPacketsPerFrame == 0)
-    {
-        return 0.0; //no protection, so avg. recov from FEC == 0
+    if (fecPacketsPerFrame == 0) {
+      return 0.0; // no protection, so avg. recov from FEC == 0
     }
 
-    //table defined up to codeSizexcodeSize code
-    if (sourcePacketsPerFrame > codeSize)
-    {
-        sourcePacketsPerFrame = codeSize;
+    // table defined up to codeSizexcodeSize code
+    if (sourcePacketsPerFrame > codeSize) {
+      sourcePacketsPerFrame = codeSize;
     }
 
-    //check: protection factor is maxed at 50%, so this should never happen
-    if (sourcePacketsPerFrame < 1)
-    {
-        assert("average number of source packets below 1\n");
+    // check: protection factor is maxed at 50%, so this should never happen
+    if (sourcePacketsPerFrame < 1) {
+      assert("average number of source packets below 1\n");
     }
 
-    //index for ER tables: up to codeSizexcodeSize mask
-    WebRtc_UWord16 codeIndexTable[codeSize*codeSize];
+    // index for ER tables: up to codeSizexcodeSize mask
+    WebRtc_UWord16 codeIndexTable[codeSize * codeSize];
     WebRtc_UWord16 k = -1;
-    for(WebRtc_UWord8 i=1;i<=codeSize;i++)
-    {
-        for(WebRtc_UWord8 j=1;j<=i;j++)
-        {
-            k += 1;
-            codeIndexTable[(j-1)*codeSize + i - 1] = k;
-        }
+    for (WebRtc_UWord8 i = 1; i <= codeSize; i++) {
+      for (WebRtc_UWord8 j = 1; j <= i; j++) {
+        k += 1;
+        codeIndexTable[(j - 1) * codeSize + i - 1] = k;
+      }
     }
 
-    const WebRtc_UWord8 lossRate = (WebRtc_UWord8) (255.0*parameters->lossPr + 0.5f);
+    const WebRtc_UWord8 lossRate = (WebRtc_UWord8) (255.0 * parameters->lossPr + 0.5f);
 
-    const WebRtc_UWord16 codeIndex = (fecPacketsPerFrame - 1)*codeSize + (sourcePacketsPerFrame - 1);
+    const WebRtc_UWord16 codeIndex = (fecPacketsPerFrame - 1) * codeSize
+        + (sourcePacketsPerFrame - 1);
     const WebRtc_UWord16 indexTable = codeIndexTable[codeIndex] * plossMax + lossRate;
 
-    const WebRtc_UWord16 codeIndex2 = (fecPacketsPerFrame)*codeSize + (sourcePacketsPerFrame);
-    WebRtc_UWord16 indexTable2 =  codeIndexTable[codeIndex2] * plossMax + lossRate;
+    const WebRtc_UWord16 codeIndex2 = (fecPacketsPerFrame) * codeSize + (sourcePacketsPerFrame);
+    WebRtc_UWord16 indexTable2 = codeIndexTable[codeIndex2] * plossMax + lossRate;
 
-    //checks on table index
-    if (indexTable >= maxErTableSize)
-    {
-        assert("ER table index too large\n");
+    // checks on table index
+    if (indexTable >= maxErTableSize) {
+      assert("ER table index too large\n");
     }
 
-    if (indexTable2 >= maxErTableSize)
-    {
-        indexTable2 = indexTable;
+    if (indexTable2 >= maxErTableSize) {
+      indexTable2 = indexTable;
     }
     //
 
-    //Get the average effective packet loss recovery from FEC
-    //this is from tables, computed using random loss model
+    // Get the average effective packet loss recovery from FEC
+    // this is from tables, computed using random loss model
     WebRtc_UWord8 avgFecRecov1 = 0;
     WebRtc_UWord8 avgFecRecov2 = 0;
     float avgFecRecov = 0;
 
-    if (fecPacketsPerFrame > 0)
-    {
-        avgFecRecov1 = VCMAvgFECRecoveryXOR[indexTable];
-        avgFecRecov2 = VCMAvgFECRecoveryXOR[indexTable2];
+    if (fecPacketsPerFrame > 0) {
+      avgFecRecov1 = VCMAvgFECRecoveryXOR[indexTable];
+      avgFecRecov2 = VCMAvgFECRecoveryXOR[indexTable2];
     }
 
-    //interpolate over two FEC codes
-    const float weightRpl = (float)(0.5 + protectionFactor*avgTotPackets) - (float)fecPacketsPerFrame;
-    avgFecRecov = (float)weightRpl * (float)avgFecRecov2 + (float)(1.0 - weightRpl) * (float)avgFecRecov1;
-
+    // interpolate over two FEC codes
+    const float weightRpl = (float) (0.5 + protectionFactor * avgTotPackets)
+        - (float) fecPacketsPerFrame;
+    avgFecRecov = (float) weightRpl * (float) avgFecRecov2 + (float) (1.0 - weightRpl)
+        * (float) avgFecRecov1;
 
     return avgFecRecov;
-
 }
 
-bool
-VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
+bool VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
 {
 
-    //FEC PROTECTION SETTINGS: varies with packet loss and bitrate
+    // FEC PROTECTION SETTINGS: varies with packet loss and bitrate
 
     const float bitRate = parameters->bitRate;
-    WebRtc_UWord8 packetLoss = (WebRtc_UWord8)(255* parameters->lossPr);
+    WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
 
-
-    //Size of tables
-    const WebRtc_UWord16 maxFecTableSize =  6450;
-    //Parameters for range of rate and packet loss for tables
+    // Size of tables
+    const WebRtc_UWord16 maxFecTableSize = 6450;
+    // Parameters for range of rate and packet loss for tables
     const WebRtc_UWord8 ratePar1 = 5;
     const WebRtc_UWord8 ratePar2 = 49;
     const WebRtc_UWord8 plossMax = 129;
 
     //
-    //Just for testing: for the case where we randomly lose slices instead of RTP packets and use SingleMode packetization in RTP module
-    //const WebRtc_UWord16 slice_size = 3000/6; //corresponds to rate=1000k with 4 cores
+    // Just for testing: for the case where we randomly lose slices instead of
+    // RTP packets and use SingleMode packetization in RTP module
+    // const WebRtc_UWord16 slice_size = 3000/6; //corresponds to rate=1000k with 4 cores
 
     //float slice_mtu = (float)_maxPayloadSize/(float)slice_size;
     const float slice_mtu = 1.0;
@@ -310,100 +311,95 @@
 
     //Total (avg) bits available per frame: total rate over actual/sent frame rate
     //units are kbits/frame
-    const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16>(slice_mtu*bitRate/(parameters->frameRate));
+    const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16> (slice_mtu * bitRate
+        / (parameters->frameRate));
 
     //Total (avg) number of packets per frame (source and fec):
-    const WebRtc_UWord8 avgTotPackets  = 1 + (WebRtc_UWord8)((float)bitRatePerFrame*1000.0/(float)(8.0*_maxPayloadSize) + 0.5);
+    const WebRtc_UWord8 avgTotPackets = 1 + (WebRtc_UWord8) ((float) bitRatePerFrame * 1000.0
+        / (float) (8.0 * _maxPayloadSize) + 0.5);
 
-    //TODO(marpan): Tune model for FEC Protection.
-    //Better modulation of protection with available bits/frame (or avgTotpackets) using weight factors
-    //FEC Tables include this effect already, but need to tune model off-line
+    // TODO(marpan): Tune model for FEC Protection.
+    // Better modulation of protection with available bits/frame
+    // (or avgTotpackets) using weight factors
+    // FEC Tables include this effect already, but need to tune model off-line
     float weight1 = 0.5;
     float weight2 = 0.5;
-    if (avgTotPackets > 4)
-    {
-        weight1 = 1.0;
-        weight2 = 0.;
+    if (avgTotPackets > 4) {
+      weight1 = 1.0;
+      weight2 = 0.;
     }
-    if (avgTotPackets > 6)
-    {
-        weight1 = 1.5;
-        weight2 = 0.;
-    }
-   //
-
-    //Fec rate parameters: for P and I frame
-    WebRtc_UWord8 codeRateDelta = 0;
-    WebRtc_UWord8 codeRateKey = 0;
-
-
-    //Get index for new table: the FEC protection depends on the (avergare) available bits/frame
-    //the range on the rate index corresponds to rates (bps) from 200k to 8000k, for 30fps
-    WebRtc_UWord8 rateIndexTable = (WebRtc_UWord8) VCM_MAX(VCM_MIN((bitRatePerFrame-ratePar1)/ratePar1,ratePar2),0);
-
-    // Restrict packet loss range to 50 for now%: current tables defined only up to 50%
-    if (packetLoss >= plossMax)
-    {
-        packetLoss = plossMax - 1;
-    }
-    WebRtc_UWord16 indexTable = rateIndexTable * plossMax + packetLoss;
-
-    //check on table index
-    if (indexTable >= maxFecTableSize)
-    {
-        assert("FEC table index too large\n");
+    if (avgTotPackets > 6) {
+      weight1 = 1.5;
+      weight2 = 0.;
     }
     //
 
-    //For Key frame: effectively at a higher rate, so we scale/boost the rate index.
-    //the boost factor may depend on several factors: ratio of packet number of I to P frames, how much protection placed on P frames, etc.
-    //default is 2
-    const WebRtc_UWord8 packetFrameDelta = (WebRtc_UWord8)(0.5 + parameters->packetsPerFrame);
+    // Fec rate parameters: for P and I frame
+    WebRtc_UWord8 codeRateDelta = 0;
+    WebRtc_UWord8 codeRateKey = 0;
+
+    // Get index for new table: the FEC protection depends on the (average) available bits/frame
+    // the range on the rate index corresponds to rates (bps) from 200k to 8000k, for 30fps
+    WebRtc_UWord8 rateIndexTable =
+        (WebRtc_UWord8) VCM_MAX(VCM_MIN((bitRatePerFrame-ratePar1)/ratePar1,ratePar2),0);
+
+    // Restrict packet loss range to 50 for now%: current tables defined only up to 50%
+    if (packetLoss >= plossMax) {
+      packetLoss = plossMax - 1;
+    }
+    WebRtc_UWord16 indexTable = rateIndexTable * plossMax + packetLoss;
+
+    // check on table index
+    if (indexTable >= maxFecTableSize) {
+      assert("FEC table index too large\n");
+    }
+    //
+
+    // For Key frame: effectively at a higher rate, so we scale/boost the rate
+    // index. The boost factor may depend on several factors: ratio of packet
+    // number of I to P frames, how much protection placed on P frames, etc.
+    // default is 2
+    const WebRtc_UWord8 packetFrameDelta = (WebRtc_UWord8) (0.5 + parameters->packetsPerFrame);
     const WebRtc_UWord8 packetFrameKey = (WebRtc_UWord8) (0.5 + parameters->packetsPerFrameKey);
     const WebRtc_UWord8 boostKey = BoostCodeRateKey(packetFrameDelta, packetFrameKey);
-    rateIndexTable = (WebRtc_UWord8) VCM_MAX(VCM_MIN(1+(boostKey*bitRatePerFrame-ratePar1)/ratePar1,ratePar2),0);
+    rateIndexTable
+        = (WebRtc_UWord8) VCM_MAX(VCM_MIN(1+(boostKey*bitRatePerFrame-ratePar1)/ratePar1,ratePar2),0);
     WebRtc_UWord16 indexTableKey = rateIndexTable * plossMax + packetLoss;
 
     indexTableKey = VCM_MIN(indexTableKey, maxFecTableSize);
 
-    codeRateDelta = VCMCodeRateXORTable[indexTable];  //protection factor for P fra
+    codeRateDelta = VCMCodeRateXORTable[indexTable]; //protection factor for P frame
     codeRateKey = VCMCodeRateXORTable[indexTableKey]; //protection factor for I frame
 
     //average with minimum protection level given by (average) total number of packets
-    if (packetLoss > 0)
-    {
-        codeRateDelta = static_cast<WebRtc_UWord8>((weight1*(float)codeRateDelta + weight2*255.0/(float)avgTotPackets));
+    if (packetLoss > 0) {
+      codeRateDelta = static_cast<WebRtc_UWord8> ((weight1 * (float) codeRateDelta + weight2 * 255.0
+          / (float) avgTotPackets));
     }
 
     //check limit on amount of protection for P frame; 50% is max
-    if (codeRateDelta >= plossMax)
-    {
-        codeRateDelta = plossMax - 1;
+    if (codeRateDelta >= plossMax) {
+      codeRateDelta = plossMax - 1;
     }
 
     //make sure I frame protection is at least larger than P frame protection, and at least as high as received loss
-    codeRateKey = static_cast<WebRtc_UWord8>(VCM_MAX(packetLoss,VCM_MAX(_scaleProtKey*codeRateDelta, codeRateKey)));
+    codeRateKey
+        = static_cast<WebRtc_UWord8> (VCM_MAX(packetLoss,VCM_MAX(_scaleProtKey*codeRateDelta, codeRateKey)));
 
     //check limit on amount of protection for I frame: 50% is max
-    if (codeRateKey >= plossMax)
-    {
-        codeRateKey = plossMax - 1;
+    if (codeRateKey >= plossMax) {
+      codeRateKey = plossMax - 1;
     }
 
     _protectionFactorK = codeRateKey;
     _protectionFactorD = codeRateDelta;
 
     // DONE WITH FEC PROTECTION SETTINGS
-
-
     return true;
 }
 
-
-bool
-VCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
+bool VCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
 {
-
     // ER SETTINGS:
     //Effective packet loss to encoder is based on RPL (residual packet loss)
     //this is a soft setting based on degree of FEC protection
@@ -411,7 +407,7 @@
     //note: received/input packet loss may be filtered according to FilteredLoss
 
     //The input packet loss:
-    WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8)(255*parameters->lossPr);
+    WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
 
     float scaleErRS = 0.5;
     float scaleErXOR = 0.5;
@@ -426,25 +422,22 @@
     avgFecRecov = AvgRecoveryFEC(parameters);
 
     //Residual Packet Loss:
-    _residualPacketLoss = (float)(effPacketLoss - avgFecRecov)/(float)255.0;
-
+    _residualPacketLoss = (float) (effPacketLoss - avgFecRecov) / (float) 255.0;
 
     //Effective Packet Loss for encoder:
     _effectivePacketLoss = 0;
-    if (effPacketLoss > 0)
-    {
-        _effectivePacketLoss = VCM_MAX((effPacketLoss - (WebRtc_UWord8)(scaleEr*avgFecRecov)),static_cast<WebRtc_UWord8>(minErLevel*255));
+    if (effPacketLoss > 0) {
+      _effectivePacketLoss = VCM_MAX((effPacketLoss -
+              (WebRtc_UWord8)(scaleEr * avgFecRecov)),
+          static_cast<WebRtc_UWord8>(minErLevel * 255));
     }
 
-
     // DONE WITH ER SETTING
 
-     return true;
+    return true;
 }
 
-
-bool
-VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+bool VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
 {
 
     // Compute the protection factor
@@ -453,27 +446,22 @@
     // Compute the effective packet loss
     EffectivePacketLoss(parameters);
 
-
     // Compute the bit cost
     // Ignore key frames for now.
-    float fecRate = static_cast<float>(_protectionFactorD) / 255.0f;
-    if (fecRate >= 0.0f)
-    {
-        // use this formula if the fecRate (protection factor) is defined relative to number of source packets
-        // this is the case for the previous tables:
-        // _efficiency = parameters->bitRate * ( 1.0 - 1.0 / (1.0 + fecRate));
+    float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
+    if (fecRate >= 0.0f) {
+      // use this formula if the fecRate (protection factor) is defined relative to number of source packets
+      // this is the case for the previous tables:
+      // _efficiency = parameters->bitRate * ( 1.0 - 1.0 / (1.0 + fecRate));
 
-        // in the new tables, the fecRate is defined relative to total number of packets (total rate),
-        // so overhead cost is:
-        _efficiency = parameters->bitRate * fecRate;
-    }
-    else
-    {
-        _efficiency = 0.0f;
+      // in the new tables, the fecRate is defined relative to total number of packets (total rate),
+      // so overhead cost is:
+      _efficiency = parameters->bitRate * fecRate;
+    } else {
+      _efficiency = 0.0f;
     }
     _score = _efficiency;
 
-
     // Protection/fec rates obtained above is defined relative to total number of packets (total rate: source+fec)
     // FEC in RTP module assumes protection factor is defined relative to source number of packets
     // so we should convert the factor to reduce mismatch between mediaOpt suggested rate and the actual rate
@@ -483,28 +471,24 @@
     return true;
 }
 
-bool
-VCMIntraReqMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+bool VCMIntraReqMethod::UpdateParameters(const VCMProtectionParameters* parameters)
 {
     float packetRate = parameters->packetsPerFrame * parameters->frameRate;
     // Assume that all lost packets cohere to different frames
     float lossRate = parameters->lossPr * packetRate;
-    if (parameters->keyFrameSize <= 1e-3)
-    {
-        _score = FLT_MAX;
-        return false;
+    if (parameters->keyFrameSize <= 1e-3) {
+      _score = FLT_MAX;
+      return false;
     }
     _efficiency = lossRate * parameters->keyFrameSize;
     _score = _efficiency;
-    if (parameters->lossPr >= 1.0f / parameters->keyFrameSize || parameters->rtt > _IREQ_MAX_RTT)
-    {
-        return false;
+    if (parameters->lossPr >= 1.0f / parameters->keyFrameSize || parameters->rtt > _IREQ_MAX_RTT) {
+      return false;
     }
     return true;
 }
 
-bool
-VCMPeriodicIntraMethod::UpdateParameters(const VCMProtectionParameters* /*parameters*/)
+bool VCMPeriodicIntraMethod::UpdateParameters(const VCMProtectionParameters* /*parameters*/)
 {
     // Periodic I-frames. The last thing we want to use.
     _efficiency = 0.0f;
@@ -512,21 +496,18 @@
     return true;
 }
 
-bool
-VCMMbIntraRefreshMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+bool VCMMbIntraRefreshMethod::UpdateParameters(const VCMProtectionParameters* parameters)
 {
     // Assume optimal for now.
     _efficiency = parameters->bitRate * parameters->lossPr / (1.0f + parameters->lossPr);
     _score = _efficiency;
-    if (parameters->bitRate < _MBREF_MIN_BITRATE)
-    {
-        return false;
+    if (parameters->bitRate < _MBREF_MIN_BITRATE) {
+      return false;
     }
     return true;
 }
 
-WebRtc_UWord16
-VCMNackMethod::MaxRttNack() const
+WebRtc_UWord16 VCMNackMethod::MaxRttNack() const
 {
     return _NACK_MAX_RTT;
 }
@@ -536,63 +517,52 @@
     ClearLossProtections();
 }
 
-void
-VCMLossProtectionLogic::ClearLossProtections()
+void VCMLossProtectionLogic::ClearLossProtections()
 {
     ListItem *item;
-    while ((item = _availableMethods.First()) != 0)
-    {
-        VCMProtectionMethod *method = static_cast<VCMProtectionMethod*>(item->GetItem());
-        if (method != NULL)
-        {
-            delete method;
-        }
-        _availableMethods.PopFront();
+    while ((item = _availableMethods.First()) != 0) {
+      VCMProtectionMethod *method = static_cast<VCMProtectionMethod*> (item->GetItem());
+      if (method != NULL) {
+        delete method;
+      }
+      _availableMethods.PopFront();
     }
     _selectedMethod = NULL;
 }
 
- bool
-VCMLossProtectionLogic::AddMethod(VCMProtectionMethod *newMethod)
+bool VCMLossProtectionLogic::AddMethod(VCMProtectionMethod *newMethod)
 {
     VCMProtectionMethod *method;
     ListItem *item;
-    if (newMethod == NULL)
-    {
-        return false;
+    if (newMethod == NULL) {
+      return false;
     }
-    for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item))
-    {
-        method = static_cast<VCMProtectionMethod *>(item->GetItem());
-        if (method != NULL && method->Type() == newMethod->Type())
-        {
-            return false;
-        }
+    for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item)) {
+      method = static_cast<VCMProtectionMethod *> (item->GetItem());
+      if (method != NULL && method->Type() == newMethod->Type()) {
+        return false;
+      }
     }
     _availableMethods.PushBack(newMethod);
     return true;
 
 }
-bool
-VCMLossProtectionLogic::RemoveMethod(VCMProtectionMethodEnum methodType)
+bool VCMLossProtectionLogic::RemoveMethod(VCMProtectionMethodEnum methodType)
 {
     VCMProtectionMethod *method;
     ListItem *item;
     bool foundAndRemoved = false;
-    for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item))
-    {
-        method = static_cast<VCMProtectionMethod *>(item->GetItem());
-        if (method != NULL && method->Type() == methodType)
-        {
-            if (_selectedMethod != NULL && _selectedMethod->Type() == method->Type())
-            {
-                _selectedMethod = NULL;
-            }
-            _availableMethods.Erase(item);
-            item = NULL;
-            delete method;
-            foundAndRemoved = true;
+    for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item)) {
+      method = static_cast<VCMProtectionMethod *> (item->GetItem());
+      if (method != NULL && method->Type() == methodType) {
+        if (_selectedMethod != NULL && _selectedMethod->Type() == method->Type()) {
+          _selectedMethod = NULL;
         }
+        _availableMethods.Erase(item);
+        item = NULL;
+        delete method;
+        foundAndRemoved = true;
+      }
     }
     return foundAndRemoved;
 }
@@ -602,224 +572,187 @@
 {
     VCMProtectionMethod *method;
     ListItem *item;
-    for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item))
-    {
-        method = static_cast<VCMProtectionMethod *>(item->GetItem());
-        if (method != NULL && method->Type() == methodType)
-        {
-            return method;
-        }
+    for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item)) {
+      method = static_cast<VCMProtectionMethod *> (item->GetItem());
+      if (method != NULL && method->Type() == methodType) {
+        return method;
+      }
     }
     return NULL;
 }
 
-float
-VCMLossProtectionLogic::HighestOverhead() const
+float VCMLossProtectionLogic::HighestOverhead() const
 {
     VCMProtectionMethod *method;
     ListItem *item;
     float highestOverhead = 0.0f;
-    for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item))
-    {
-        method = static_cast<VCMProtectionMethod *>(item->GetItem());
-        if (method != NULL && method->RequiredBitRate() > highestOverhead)
-        {
-            highestOverhead = method->RequiredBitRate();
-        }
+    for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item)) {
+      method = static_cast<VCMProtectionMethod *> (item->GetItem());
+      if (method != NULL && method->RequiredBitRate() > highestOverhead) {
+        highestOverhead = method->RequiredBitRate();
+      }
     }
     return highestOverhead;
 }
 
-void
-VCMLossProtectionLogic::UpdateRtt(WebRtc_UWord32 rtt)
+void VCMLossProtectionLogic::UpdateRtt(WebRtc_UWord32 rtt)
 {
     _rtt = rtt;
 }
 
-void
-VCMLossProtectionLogic::UpdateResidualPacketLoss(float residualPacketLoss)
-{
+void VCMLossProtectionLogic::UpdateResidualPacketLoss(float residualPacketLoss) {
     _residualPacketLoss = residualPacketLoss;
 }
 
-void
-VCMLossProtectionLogic::UpdateFecType(VCMFecTypes fecType)
+void VCMLossProtectionLogic::UpdateFecType(VCMFecTypes fecType)
 {
     _fecType = fecType;
 }
 
-void
-VCMLossProtectionLogic::UpdateLossPr(WebRtc_UWord8 lossPr255)
+void VCMLossProtectionLogic::UpdateLossPr(WebRtc_UWord8 lossPr255)
 {
-    WebRtc_UWord32 now = static_cast<WebRtc_UWord32>(VCMTickTime::MillisecondTimestamp());
+    WebRtc_UWord32 now = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
     UpdateMaxLossHistory(lossPr255, now);
-    _lossPr255.Apply(static_cast<float>(now - _lastPrUpdateT), static_cast<float>(lossPr255));
+    _lossPr255.Apply(static_cast<float> (now - _lastPrUpdateT), static_cast<float> (lossPr255));
     _lastPrUpdateT = now;
     _lossPr = _lossPr255.Value() / 255.0f;
 }
 
-void
-VCMLossProtectionLogic::UpdateMaxLossHistory(WebRtc_UWord8 lossPr255, WebRtc_Word64 now)
+void VCMLossProtectionLogic::UpdateMaxLossHistory(WebRtc_UWord8 lossPr255, WebRtc_Word64 now)
 {
-    if (_lossPrHistory[0].timeMs >= 0 &&
-        now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs)
-    {
-        if (lossPr255 > _shortMaxLossPr255)
-        {
-            _shortMaxLossPr255 = lossPr255;
-        }
+  if (_lossPrHistory[0].timeMs >= 0 && now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs) {
+    if (lossPr255 > _shortMaxLossPr255) {
+      _shortMaxLossPr255 = lossPr255;
     }
-    else
-    {
-        // Only add a new value to the history once a second
-        if(_lossPrHistory[0].timeMs == -1)
-        {
-            // First, no shift
-            _shortMaxLossPr255 = lossPr255;
-        }
-        else
-        {
-            // Shift
-            for(WebRtc_Word32 i = (kLossPrHistorySize - 2); i >= 0 ; i--)
-            {
-                _lossPrHistory[i+1].lossPr255 = _lossPrHistory[i].lossPr255;
-                _lossPrHistory[i+1].timeMs = _lossPrHistory[i].timeMs;
-            }
-        }
-        if (_shortMaxLossPr255 == 0)
-        {
-            _shortMaxLossPr255 = lossPr255;
-        }
-
-         _lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
-        _lossPrHistory[0].timeMs = now;
-        _shortMaxLossPr255 = 0;
-
+  } else {
+    // Only add a new value to the history once a second
+    if (_lossPrHistory[0].timeMs == -1) {
+      // First, no shift
+      _shortMaxLossPr255 = lossPr255;
+    } else {
+      // Shift
+      for (WebRtc_Word32 i = (kLossPrHistorySize - 2); i >= 0; i--) {
+        _lossPrHistory[i + 1].lossPr255 = _lossPrHistory[i].lossPr255;
+        _lossPrHistory[i + 1].timeMs = _lossPrHistory[i].timeMs;
+      }
     }
+    if (_shortMaxLossPr255 == 0) {
+      _shortMaxLossPr255 = lossPr255;
+    }
+
+    _lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
+    _lossPrHistory[0].timeMs = now;
+    _shortMaxLossPr255 = 0;
+
+  }
 }
 
-WebRtc_UWord8
-VCMLossProtectionLogic::MaxFilteredLossPr(WebRtc_Word64 nowMs) const
+WebRtc_UWord8 VCMLossProtectionLogic::MaxFilteredLossPr(WebRtc_Word64 nowMs) const
 {
     WebRtc_UWord8 maxFound = _shortMaxLossPr255;
-    if (_lossPrHistory[0].timeMs == -1)
-    {
-        return maxFound;
+    if (_lossPrHistory[0].timeMs == -1) {
+      return maxFound;
     }
-    for (WebRtc_Word32 i=0; i < kLossPrHistorySize; i++)
-    {
-        if (_lossPrHistory[i].timeMs == -1)
-        {
-            break;
-        }
-        if (nowMs - _lossPrHistory[i].timeMs > kLossPrHistorySize * kLossPrShortFilterWinMs)
-        {
-            // This sample (and all samples after this) is too old
-            break;
-        }
-        if (_lossPrHistory[i].lossPr255 > maxFound)
-        {
-            // This sample is the largest one this far into the history
-            maxFound = _lossPrHistory[i].lossPr255;
-        }
+    for (WebRtc_Word32 i = 0; i < kLossPrHistorySize; i++) {
+      if (_lossPrHistory[i].timeMs == -1) {
+        break;
+      }
+      if (nowMs - _lossPrHistory[i].timeMs > kLossPrHistorySize * kLossPrShortFilterWinMs) {
+        // This sample (and all samples after this) is too old
+        break;
+      }
+      if (_lossPrHistory[i].lossPr255 > maxFound) {
+        // This sample is the largest one this far into the history
+        maxFound = _lossPrHistory[i].lossPr255;
+      }
     }
     return maxFound;
 }
 
-WebRtc_UWord8
-VCMLossProtectionLogic::FilteredLoss() const
+WebRtc_UWord8 VCMLossProtectionLogic::FilteredLoss() const
 {
 
     //take the average received loss
     //return static_cast<WebRtc_UWord8>(_lossPr255.Value() + 0.5f);
 
+    //TODO: Update for hybrid
     //take the windowed max of the received loss
-    if (_selectedMethod != NULL && _selectedMethod->Type() == kFEC)
-    {
-        return MaxFilteredLossPr(static_cast<WebRtc_UWord32>(VCMTickTime::MillisecondTimestamp()));
-    }
-    else
-    {
-        return static_cast<WebRtc_UWord8>(_lossPr255.Value() + 0.5);
+    if (_selectedMethod != NULL && _selectedMethod->Type() == kFEC) {
+      return MaxFilteredLossPr(static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp()));
+    } else {
+      return static_cast<WebRtc_UWord8> (_lossPr255.Value() + 0.5);
     }
 
 }
 
-void
-VCMLossProtectionLogic::UpdateFilteredLossPr(WebRtc_UWord8 packetLossEnc)
+void VCMLossProtectionLogic::UpdateFilteredLossPr(WebRtc_UWord8 packetLossEnc)
 {
-   _lossPr = (float)packetLossEnc/(float)255.0;
+    _lossPr = (float) packetLossEnc / (float) 255.0;
 }
 
-void
-VCMLossProtectionLogic::UpdateBitRate(float bitRate)
+void VCMLossProtectionLogic::UpdateBitRate(float bitRate)
 {
     _bitRate = bitRate;
 }
 
-void
-VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets)
+void VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets)
 {
-    WebRtc_UWord32 now = static_cast<WebRtc_UWord32>(VCMTickTime::MillisecondTimestamp());
-    _packetsPerFrame.Apply(static_cast<float>(now - _lastPacketPerFrameUpdateT), nPackets);
+    WebRtc_UWord32 now = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
+    _packetsPerFrame.Apply(static_cast<float> (now - _lastPacketPerFrameUpdateT), nPackets);
     _lastPacketPerFrameUpdateT = now;
 }
 
-void
-VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets)
+void VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets)
 {
-    WebRtc_UWord32 now = static_cast<WebRtc_UWord32>(VCMTickTime::MillisecondTimestamp());
-    _packetsPerFrameKey.Apply(static_cast<float>(now - _lastPacketPerFrameUpdateTKey), nPackets);
+    WebRtc_UWord32 now = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
+    _packetsPerFrameKey.Apply(static_cast<float> (now - _lastPacketPerFrameUpdateTKey), nPackets);
     _lastPacketPerFrameUpdateTKey = now;
 }
 
-void
-VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
+void VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
 {
     _keyFrameSize = keyFrameSize;
 }
 
-bool
-VCMLossProtectionLogic::UpdateMethod(VCMProtectionMethod *newMethod /*=NULL */)
+bool VCMLossProtectionLogic::UpdateMethod(VCMProtectionMethod *newMethod /*=NULL */)
 {
-    _currentParameters.rtt     = _rtt;
-    _currentParameters.lossPr  = _lossPr;
+    _currentParameters.rtt = _rtt;
+    _currentParameters.lossPr = _lossPr;
     _currentParameters.bitRate = _bitRate;
-    _currentParameters.frameRate    = _frameRate; //should this be named actual frame rate?
+    _currentParameters.frameRate = _frameRate; //should this be named actual frame rate?
     _currentParameters.keyFrameSize = _keyFrameSize;
     _currentParameters.fecRateDelta = _fecRateDelta;
-    _currentParameters.fecRateKey   = _fecRateKey;
+    _currentParameters.fecRateKey = _fecRateKey;
     _currentParameters.packetsPerFrame = _packetsPerFrame.Value();
     _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.Value();
     _currentParameters.residualPacketLoss = _residualPacketLoss;
     _currentParameters.fecType = _fecType;
 
-    if (newMethod == NULL)
-    {
-        //_selectedMethod = _bestNotOkMethod = NULL;
-        VCMProtectionMethod *method;
-        ListItem *item;
-        for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item))
-        {
-            method = static_cast<VCMProtectionMethod *>(item->GetItem());
-            if (method != NULL)
-            {
-                if (method->Type() == kFEC)
-                {
-                    _selectedMethod = method;
-                }
-                method->UpdateParameters(&_currentParameters);
-            }
-        }
-        if (_selectedMethod != NULL && _selectedMethod->Type() != kFEC)
-        {
+    if (newMethod == NULL) {
+      //_selectedMethod = _bestNotOkMethod = NULL;
+      VCMProtectionMethod *method;
+      ListItem *item;
+      for (item = _availableMethods.First(); item != NULL; item = _availableMethods.Next(item)) {
+        method = static_cast<VCMProtectionMethod *> (item->GetItem());
+        if (method != NULL) {
+          if (method->Type() == kFEC) {
             _selectedMethod = method;
+          }
+          if (method->Type() == kNACK) {
+            _selectedMethod = method;
+          }
+          if (method->Type() == kNackFec) {
+            _selectedMethod = method;
+          }
+          method->UpdateParameters(&_currentParameters);
         }
-    }
-    else
-    {
-        _selectedMethod = newMethod;
-        _selectedMethod->UpdateParameters(&_currentParameters);
+      }
+      if (_selectedMethod != NULL && _selectedMethod->Type() != kFEC) {
+        _selectedMethod = method;
+      }
+    } else {
+      _selectedMethod = newMethod;
+      _selectedMethod->UpdateParameters(&_currentParameters);
     }
     return true;
 }
@@ -830,18 +763,16 @@
     return _selectedMethod;
 }
 
-void
-VCMLossProtectionLogic::Reset()
+void VCMLossProtectionLogic::Reset()
 {
-    _lastPrUpdateT = static_cast<WebRtc_UWord32>(VCMTickTime::MillisecondTimestamp());
-    _lastPacketPerFrameUpdateT = static_cast<WebRtc_UWord32>(VCMTickTime::MillisecondTimestamp());
+    _lastPrUpdateT = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
+    _lastPacketPerFrameUpdateT = static_cast<WebRtc_UWord32> (VCMTickTime::MillisecondTimestamp());
     _lossPr255.Reset(0.9999f);
     _packetsPerFrame.Reset(0.9999f);
     _fecRateDelta = _fecRateKey = 0;
-    for (WebRtc_Word32 i=0; i < kLossPrHistorySize; i++)
-    {
-        _lossPrHistory[i].lossPr255 = 0;
-        _lossPrHistory[i].timeMs = -1;
+    for (WebRtc_Word32 i = 0; i < kLossPrHistorySize; i++) {
+      _lossPrHistory[i].lossPr255 = 0;
+      _lossPrHistory[i].timeMs = -1;
     }
     _shortMaxLossPr255 = 0;
     ClearLossProtections();
diff --git a/modules/video_coding/main/source/media_opt_util.h b/modules/video_coding/main/source/media_opt_util.h
index 1faa4ea..00f00c1 100644
--- a/modules/video_coding/main/source/media_opt_util.h
+++ b/modules/video_coding/main/source/media_opt_util.h
@@ -34,6 +34,13 @@
     kXORFec
 };
 
+// Thresholds for hybrid NACK/FEC
+// common to media optimization and the jitter buffer.
+enum HybridNackTH {
+    kHighRttNackMs = 100,
+    kLowRttNackMs = 20
+};
+
 struct VCMProtectionParameters
 {
     VCMProtectionParameters() : rtt(0), lossPr(0), bitRate(0), packetsPerFrame(0),
@@ -134,16 +141,16 @@
     WebRtc_UWord8                        _effectivePacketLoss;
     WebRtc_UWord8                        _protectionFactorK;
     WebRtc_UWord8                        _protectionFactorD;
-    float                              _residualPacketLoss;
-    float                              _scaleProtKey;
+    float                                _residualPacketLoss;
+    float                                _scaleProtKey;
     WebRtc_Word32                        _maxPayloadSize;
 
 protected:
-    float                              _efficiency;
-    float                              _score;
+    float                                _efficiency;
+    float                                _score;
 
 private:
-    const enum VCMProtectionMethodEnum     _type;
+    const enum VCMProtectionMethodEnum   _type;
 
 };
 
diff --git a/modules/video_coding/main/source/media_optimization.cc b/modules/video_coding/main/source/media_optimization.cc
index 0586e67..b4ea203 100644
--- a/modules/video_coding/main/source/media_optimization.cc
+++ b/modules/video_coding/main/source/media_optimization.cc
@@ -100,7 +100,7 @@
     VCMFecTypes fecType = kXORFec;  // generic FEC
     _lossProtLogic->UpdateFecType(fecType);
 
-    //Get frame rate for encoder: this is the actual/sent frame rate
+    // Get frame rate for encoder: this is the actual/sent frame rate
     float actualFrameRate = SentFrameRate();
 
     // sanity
@@ -109,13 +109,16 @@
         actualFrameRate = 1.0;
     }
 
-    // Update frame rate for the loss protection logic class: frame rate should be the actual/sent rate
+    // Update frame rate for the loss protection logic class: frame rate should
+    // be the actual/sent rate
     _lossProtLogic->UpdateFrameRate(actualFrameRate);
 
     _fractionLost = fractionLost;
 
-    // The effective packet loss may be the received loss or filtered, i.e., average or max filter may be used.
-    //We should think about which filter is appropriate for low/high bit rates, low/high loss rates, etc.
+    // The effective packet loss may be the received loss or filtered, i.e.,
+    // average or max filter may be used.
+    // We should think about which filter is appropriate for low/high bit rates,
+    // low/high loss rates, etc.
     WebRtc_UWord8 packetLossEnc = _lossProtLogic->FilteredLoss();
 
     //For now use the filtered loss for computing the robustness settings
@@ -124,46 +127,48 @@
     // Rate cost of the protection methods
     _lossProtOverhead = 0;
 
-    if(selectedMethod)
+    if (selectedMethod && (selectedMethod->Type() == kFEC ||
+        selectedMethod->Type() == kNackFec ))
     {
 
-        //Update method will compute the robustness settings for the given protection method and the overhead cost
-        //the protection method is set by the user via SetVideoProtection.
-        //The robustness settings are: the effecitve packet loss for ER and the FEC protection settings
+        // Update method will compute the robustness settings for the given
+        // protection method and the overhead cost
+        // the protection method is set by the user via SetVideoProtection.
+        // The robustness settings are: the effective packet loss for ER and the
+        // FEC protection settings
         _lossProtLogic->UpdateMethod();
 
-        //Get the code rate for Key frames
+        // Get the code rate for Key frames
         const WebRtc_UWord8 codeRateKeyRTP  = selectedMethod->RequiredProtectionFactorK();
 
-        //Get the code rate for Delta frames
+        // Get the code rate for Delta frames
         const WebRtc_UWord8 codeRateDeltaRTP = selectedMethod->RequiredProtectionFactorD();
 
-        //Get the effective packet loss for ER
+        // Get the effective packet loss for ER
         packetLossEnc = selectedMethod->RequiredPacketLossER();
 
-        // Get the bit cost of protection method
-        _lossProtOverhead = static_cast<WebRtc_UWord32>(_lossProtLogic->HighestOverhead() + 0.5f);
-
-        //NACK is on for NACK and NackFec protection method: off for FEC method
-        bool nackStatus = true;
-        if (selectedMethod->Type() == kFEC)
-        {
-            nackStatus = false;
-        }
+        // NACK is on for NACK and NackFec protection method: off for FEC method
+        bool nackStatus = (selectedMethod->Type() == kNackFec ||
+                           selectedMethod->Type() == kNACK);
 
         if(_videoProtectionCallback)
         {
-            _videoProtectionCallback->ProtectionRequest(codeRateDeltaRTP ,codeRateKeyRTP, nackStatus);
+            _videoProtectionCallback->ProtectionRequest(codeRateDeltaRTP,
+                                                        codeRateKeyRTP,
+                                                        nackStatus);
         }
-
     }
 
+    // Get the bit cost of protection method
+    _lossProtOverhead = static_cast<WebRtc_UWord32>(_lossProtLogic->HighestOverhead() + 0.5f);
+
     // Update effective packet loss for encoder: note: fractionLost was passed as reference
     fractionLost = packetLossEnc;
 
     WebRtc_UWord32 nackBitRate=0;
     if(selectedMethod && _lossProtLogic->FindMethod(kNACK) != NULL)
     {
+        // TODO(mikhal): update frame dropper with bit rate including both nack and fec
         // Make sure we don't over-use the channel momentarily. This is
         // necessary for NACK since it can be very bursty.
         nackBitRate = (_lastBitRate * fractionLost) / 255;
@@ -178,7 +183,8 @@
         _frameDropper->SetRates(static_cast<float>(bitRate - _lossProtOverhead), 0);
     }
 
-    //This may be used for UpdateEncoderBitRate: lastBitRate is total rate, before compensation
+    // This may be used for UpdateEncoderBitRate: lastBitRate is total rate,
+    // before compensation
     _lastBitRate = _targetBitRate;
 
     //Source coding rate: total rate - protection overhead
@@ -187,7 +193,7 @@
     if (_enableQm)
     {
         //Update QM with rates
-        _qms->UpdateRates((float)_targetBitRate, _avgSentBitRateBps,_incomingFrameRate);
+        _qms->UpdateRates((float)_targetBitRate, _avgSentBitRateBps, _incomingFrameRate);
         //Check for QM selection
         bool selectQM = checkStatusForQMchange();
         if (selectQM)
@@ -203,7 +209,8 @@
 bool
 VCMMediaOptimization::DropFrame()
 {
-    _frameDropper->Leak((WebRtc_UWord32)(InputFrameRate() + 0.5f)); // leak appropriate number of bytes
+    // leak appropriate number of bytes
+    _frameDropper->Leak((WebRtc_UWord32)(InputFrameRate() + 0.5f));
     return _frameDropper->DropFrame();
 }
 
@@ -285,7 +292,7 @@
 bool
 VCMMediaOptimization::IsNackEnabled()
 {
-    return (_lossProtLogic->FindMethod(kFEC) != NULL);
+    return (_lossProtLogic->FindMethod(kNACK) != NULL);
 }
 
 void
@@ -490,7 +497,7 @@
 VCMMediaOptimization::RegisterVideoQMCallback(VCMQMSettingsCallback *videoQMSettings)
 {
     _videoQMSettingsCallback = videoQMSettings;
-    //Callback setting controls QM
+    // Callback setting controls QM
     if (_videoQMSettingsCallback != NULL)
     {
         _enableQm = true;
@@ -535,7 +542,7 @@
     // Check for updates to spatial/temporal modes
     QMUpdate(qm);
 
-    //Reset all the rate and related frame counters quantities
+    // Reset all the rate and related frame counters quantities
     _qms->ResetRates();
 
     // Reset counters
@@ -558,8 +565,10 @@
 
     bool status  = true;
 
-    // Check that we do not call QMSelect too often, and that we waited some time (to sample the metrics) from the event lastChangeTime
-    // lastChangeTime is the time where user changed the size/rate/frame rate (via SetEncodingData)
+    // Check that we do not call QMSelect too often, and that we waited some time
+    // (to sample the metrics) from the event lastChangeTime
+    // lastChangeTime is the time where user changed the size/rate/frame rate
+    // (via SetEncodingData)
     WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
     if ((now - _lastQMUpdateTime) < kQmMinIntervalMs ||
         (now  - _lastChangeTime) <  kQmMinIntervalMs)
@@ -574,7 +583,7 @@
 bool
 VCMMediaOptimization::QMUpdate(VCMQualityMode* qm)
 {
-    //Check for no change
+    // Check for no change
     if (qm->spatialHeightFact == 1 &&
         qm->spatialWidthFact == 1 &&
         qm->temporalFact == 1)
@@ -582,26 +591,26 @@
         return false;
     }
 
-    //Content metrics hold native values
+    // Content metrics hold native values
     VideoContentMetrics* cm = _content->Data();
 
-    //Temporal
+    // Temporal
     WebRtc_UWord32 frameRate  = static_cast<WebRtc_UWord32>(_incomingFrameRate + 0.5f);
-    //Check if go back up in temporal resolution
+    // Check if go back up in temporal resolution
     if (qm->temporalFact == 0)
     {
         frameRate = (WebRtc_UWord32) 2 * _incomingFrameRate;
     }
-    //go down in temporal resolution
+    // go down in temporal resolution
     else
     {
         frameRate = (WebRtc_UWord32)(_incomingFrameRate / qm->temporalFact + 1);
     }
 
-    //Spatial
+    // Spatial
     WebRtc_UWord32 height = _codecHeight;
     WebRtc_UWord32 width = _codecWidth;
-    //Check if go back up in spatial resolution
+    // Check if go back up in spatial resolution
     if (qm->spatialHeightFact == 0 && qm->spatialWidthFact == 0)
     {
        height = cm->nativeHeight;
@@ -617,7 +626,7 @@
                "Quality Mode Update: W = %d, H = %d, FR = %f",
                width, height, frameRate);
 
-    //Update VPM with new target frame rate and size
+    // Update VPM with new target frame rate and size
     _videoQMSettingsCallback->SetVideoQMSettings(frameRate, width, height);
 
     return true;
diff --git a/modules/video_coding/main/source/receiver.cc b/modules/video_coding/main/source/receiver.cc
index ae812d0..113d878 100644
--- a/modules/video_coding/main/source/receiver.cc
+++ b/modules/video_coding/main/source/receiver.cc
@@ -31,7 +31,6 @@
 _jitterBuffer(vcmId, receiverId, master),
 _timing(timing),
 _renderWaitEvent(*new VCMEvent()),
-_nackMode(kNoNack),
 _state(kPassive)
 {
 }
@@ -164,6 +163,7 @@
         }
 
         // Insert packet into jitter buffer
+        // both data and empty packets
         const VCMFrameBufferEnum ret = _jitterBuffer.InsertPacket(buffer, packet);
 
         if (ret < 0)
@@ -178,7 +178,8 @@
 }
 
 VCMEncodedFrame*
-VCMReceiver::FrameForDecoding(WebRtc_UWord16 maxWaitTimeMs, WebRtc_Word64& nextRenderTimeMs, bool renderTiming, VCMReceiver* dualReceiver)
+VCMReceiver::FrameForDecoding(WebRtc_UWord16 maxWaitTimeMs, WebRtc_Word64& nextRenderTimeMs,
+                              bool renderTiming, VCMReceiver* dualReceiver)
 {
     // No need to enter the critical section here since the jitter buffer
     // is thread-safe.
@@ -348,20 +349,7 @@
 VCMReceiver::SetNackMode(VCMNackMode nackMode)
 {
     CriticalSectionScoped cs(_critSect);
-    _nackMode = nackMode;
-    switch (_nackMode)
-    {
-    case kNackInfinite:
-        {
-            _jitterBuffer.SetNackStatus(true);
-            break;
-        }
-    case kNoNack:
-        {
-            _jitterBuffer.SetNackStatus(false);
-            break;
-        }
-    }
+    _jitterBuffer.SetNackMode(nackMode);
     if (!_master)
     {
         _state = kPassive; // The dual decoder defaults to passive
@@ -372,7 +360,7 @@
 VCMReceiver::NackMode() const
 {
     CriticalSectionScoped cs(_critSect);
-    return _nackMode;
+    return _jitterBuffer.GetNackMode();
 }
 
 VCMNackStatus
@@ -418,14 +406,6 @@
 VCMReceiver::CopyJitterBufferStateFromReceiver(const VCMReceiver& receiver)
 {
     _jitterBuffer = receiver._jitterBuffer;
-
-    {
-        CriticalSectionScoped cs(_critSect);
-        if (_nackMode != kNoNack)
-        {
-            _jitterBuffer.SetNackStatus(true);
-        }
-    }
 }
 
 VCMReceiverState
@@ -447,7 +427,7 @@
 void
 VCMReceiver::UpdateState(VCMEncodedFrame& frame)
 {
-    if (_nackMode == kNoNack)
+    if (_jitterBuffer.GetNackMode() == kNoNack)
     {
         // Dual decoder mode has not been enabled.
         return;
diff --git a/modules/video_coding/main/source/receiver.h b/modules/video_coding/main/source/receiver.h
index b99dccf..0ca6994 100644
--- a/modules/video_coding/main/source/receiver.h
+++ b/modules/video_coding/main/source/receiver.h
@@ -28,11 +28,6 @@
     kNackKeyFrameRequest
 };
 
-enum VCMNackMode
-{
-    kNackInfinite,
-    kNoNack
-};
 
 enum VCMReceiverState
 {
@@ -91,7 +86,6 @@
     VCMJitterBuffer         _jitterBuffer;
     VCMTiming&              _timing;
     VCMEvent&               _renderWaitEvent;
-    VCMNackMode             _nackMode;
     VCMReceiverState        _state;
 
     static WebRtc_Word32    _receiverIdCounter;
diff --git a/modules/video_coding/main/source/session_info.cc b/modules/video_coding/main/source/session_info.cc
index fb33867..5a56177 100644
--- a/modules/video_coding/main/source/session_info.cc
+++ b/modules/video_coding/main/source/session_info.cc
@@ -25,7 +25,9 @@
     _previousFrameLoss(false),
     _lowSeqNum(-1),
     _highSeqNum(-1),
-    _highestPacketIndex(0)
+    _highestPacketIndex(0),
+    _emptySeqNumLow(-1),
+    _emptySeqNumHigh(-1)
 {
     memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
     memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
@@ -50,6 +52,8 @@
 {
     _lowSeqNum = -1;
     _highSeqNum = -1;
+    _emptySeqNumLow = -1;
+    _emptySeqNumHigh = -1;
     _markerBit = false;
     _haveFirstPacket = false;
     _completeSession = false;
@@ -65,7 +69,7 @@
 WebRtc_UWord32 VCMSessionInfo::GetSessionLength()
 {
     WebRtc_UWord32 length = 0;
-    for (WebRtc_Word32 i=0; i<=_highestPacketIndex; ++i)
+    for (WebRtc_Word32 i = 0; i <= _highestPacketIndex; ++i)
     {
         length += _packetSizeBytes[i];
     }
@@ -89,7 +93,9 @@
     return true;
 }
 
-WebRtc_UWord32 VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer, WebRtc_Word32 packetIndex, const VCMPacket& packet)
+WebRtc_UWord32 VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
+                                            WebRtc_Word32 packetIndex,
+                                            const VCMPacket& packet)
 {
     WebRtc_UWord32 moveLength = 0;
     WebRtc_UWord32 returnLength = 0;
@@ -99,30 +105,33 @@
     WebRtc_UWord32 offset = 0;
     WebRtc_UWord32 packetSize = 0;
 
-    // Store this packet length. Add length since we could have data present already (e.g. multicall case).
+    // Store this packet length. Add length since we could have data present
+    // already (e.g. multicall case).
     if (packet.bits)
     {
         packetSize = packet.sizeBytes;
     }
     else
     {
-        packetSize = packet.sizeBytes + (packet.insertStartCode?kH264StartCodeLengthBytes:0);
+        packetSize = packet.sizeBytes +
+                     (packet.insertStartCode?kH264StartCodeLengthBytes:0);
     }
 
     _packetSizeBytes[packetIndex] += packetSize;
 
     // count only the one in our layer
-    for (i=0; i<packetIndex; ++i)
+    for (i = 0; i < packetIndex; ++i)
     {
         offset += _packetSizeBytes[i];
     }
-    for (i=packetIndex+1; i<=_highestPacketIndex; ++i)
+    for (i = packetIndex + 1; i <= _highestPacketIndex; ++i)
     {
         moveLength += _packetSizeBytes[i];
     }
     if (moveLength > 0)
     {
-        memmove((void*)(ptrStartOfLayer + offset + packetSize), ptrStartOfLayer + offset, moveLength);
+        memmove((void*)(ptrStartOfLayer + offset + packetSize),
+                        ptrStartOfLayer + offset, moveLength);
     }
 
     if (packet.bits)
@@ -145,7 +154,8 @@
             const unsigned char startCode[]      = {0, 0, 0, 1};
             if(packet.insertStartCode)
             {
-                memcpy((void*)(ptrStartOfLayer + offset), startCode, kH264StartCodeLengthBytes);
+                memcpy((void*)(ptrStartOfLayer + offset), startCode,
+                       kH264StartCodeLengthBytes);
             }
             memcpy((void*)(ptrStartOfLayer + offset
                 + (packet.insertStartCode?kH264StartCodeLengthBytes:0)),
@@ -158,6 +168,9 @@
     if (packet.isFirstPacket)
     {
         _haveFirstPacket = true;
+        //initializing FEC sequence numbers
+        _emptySeqNumHigh = -1;
+        _emptySeqNumLow = -1;
     }
     if (packet.markerBit)
     {
@@ -177,7 +190,7 @@
     {
         // do we have all packets in this session?
         bool completeSession = true;
-        for (int i=0; i<= _highestPacketIndex; ++i)
+        for (int i = 0; i<= _highestPacketIndex; ++i)
         {
             if (_naluCompleteness[i] == kNaluUnset)
             {
@@ -194,36 +207,41 @@
     return _completeSession;
 }
 
-
 // Find the start and end index of packetIndex packet.
 // startIndex -1 if start not found endIndex=-1 if end index not found
-void VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,WebRtc_Word32& startIndex, WebRtc_Word32& endIndex)
+void VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,
+                                    WebRtc_Word32& startIndex,
+                                    WebRtc_Word32& endIndex)
 {
 
         if(_naluCompleteness[packetIndex]==kNaluStart ||
              _naluCompleteness[packetIndex]==kNaluComplete)
         {
-            startIndex=packetIndex;
+            startIndex = packetIndex;
         }
         else // Need to find the start
         {
-            for(startIndex=packetIndex-1;startIndex>=0;--startIndex)
+            for(startIndex = packetIndex - 1; startIndex >= 0; --startIndex)
             {
 
-                if( (_naluCompleteness[startIndex]==kNaluComplete && _packetSizeBytes[startIndex]>0) ||(_naluCompleteness[startIndex]==kNaluEnd && startIndex>0)) // Found previous NALU.
+                if( (_naluCompleteness[startIndex] == kNaluComplete &&
+                    _packetSizeBytes[startIndex] > 0) ||
+                    // Found previous NALU.
+                    (_naluCompleteness[startIndex] == kNaluEnd && startIndex>0))
                 {
                     startIndex++;
                     break;
                 }
-                if( _naluCompleteness[startIndex]==kNaluStart) // This is where the NALU start.
+                // This is where the NALU start.
+                if( _naluCompleteness[startIndex] == kNaluStart)
                 {
                     break;
                 }
             }
         }
 
-        if(_naluCompleteness[packetIndex]==kNaluEnd ||
-             _naluCompleteness[packetIndex]==kNaluComplete)
+        if(_naluCompleteness[packetIndex] == kNaluEnd ||
+             _naluCompleteness[packetIndex] == kNaluComplete)
         {
             endIndex=packetIndex;
         }
@@ -232,7 +250,9 @@
             // Find the next NALU
             for(endIndex=packetIndex+1;endIndex<=_highestPacketIndex;++endIndex)
             {
-                if((_naluCompleteness[endIndex]==kNaluComplete && _packetSizeBytes[endIndex]>0) || _naluCompleteness[endIndex]==kNaluStart) // Found next NALU.
+                if((_naluCompleteness[endIndex]==kNaluComplete &&
+                    _packetSizeBytes[endIndex]>0) ||
+                    _naluCompleteness[endIndex]==kNaluStart) // Found next NALU.
                 {
                     endIndex--;
                     break;
@@ -242,40 +262,43 @@
                     break;
                 }
             }
-            if(endIndex>_highestPacketIndex)
-                endIndex=-1;
+            if(endIndex > _highestPacketIndex)
+                endIndex = -1;
         }
 }
 
 // Deletes all packets between startIndex and endIndex
-WebRtc_UWord32 VCMSessionInfo::DeletePackets(WebRtc_UWord8* ptrStartOfLayer,WebRtc_Word32 startIndex,WebRtc_Word32 endIndex)
+WebRtc_UWord32 VCMSessionInfo::DeletePackets(WebRtc_UWord8* ptrStartOfLayer,
+                                             WebRtc_Word32 startIndex,
+                                             WebRtc_Word32 endIndex)
 {
 
     //Get the number of bytes to delete.
     //Clear the size of these packets.
-    WebRtc_UWord32 bytesToDelete=0; /// The number of bytes to delete.
-    for(int j=startIndex;j<=endIndex;++j)
+    WebRtc_UWord32 bytesToDelete = 0; /// The number of bytes to delete.
+    for(int j = startIndex;j <= endIndex; ++j)
     {
-        bytesToDelete+=_packetSizeBytes[j];
+        bytesToDelete += _packetSizeBytes[j];
         _packetSizeBytes[j]=0;
     }
     if (bytesToDelete > 0)
     {
         // Get the offset we want to move to.
-        int destOffset=0;
-        for(int j=0;j<startIndex;j++)
+        int destOffset = 0;
+        for(int j = 0;j < startIndex;j++)
         {
-           destOffset+=_packetSizeBytes[j];
+           destOffset += _packetSizeBytes[j];
         }
 
         //Get the number of bytes to move
         WebRtc_UWord32 numberOfBytesToMove=0;
-        for (int j=endIndex+1; j<=_highestPacketIndex; ++j)
+        for (int j = endIndex + 1; j <= _highestPacketIndex; ++j)
         {
             numberOfBytesToMove += _packetSizeBytes[j];
         }
 
-        memmove((void*)(ptrStartOfLayer + destOffset),(void*)(ptrStartOfLayer + destOffset+bytesToDelete), numberOfBytesToMove);
+        memmove((void*)(ptrStartOfLayer + destOffset),(void*)(ptrStartOfLayer +
+            destOffset+bytesToDelete), numberOfBytesToMove);
 
     }
 
@@ -286,30 +309,30 @@
 // return the number of bytes deleted from the session. -1 if an error occurs
 WebRtc_UWord32 VCMSessionInfo::MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer)
 {
-    if(_lowSeqNum<0) // No packets in this session
+    if(_lowSeqNum < 0) // No packets in this session
         return 0;
 
-    WebRtc_Word32 startIndex=0;
-    WebRtc_Word32 endIndex=0;
-    int packetIndex=0;
-    WebRtc_UWord32 returnLength=0;
-    for (packetIndex=0; packetIndex<= _highestPacketIndex; ++packetIndex)
+    WebRtc_Word32 startIndex = 0;
+    WebRtc_Word32 endIndex = 0;
+    int packetIndex = 0;
+    WebRtc_UWord32 returnLength = 0;
+    for (packetIndex = 0; packetIndex <= _highestPacketIndex; ++packetIndex)
     {
         if (_naluCompleteness[packetIndex] == kNaluUnset) // Found a lost packet
         {
             FindNaluBorder(packetIndex,startIndex,endIndex);
-            if(startIndex==-1)
-                startIndex=0;
-            if(endIndex==-1)
-                endIndex=_highestPacketIndex;
+            if(startIndex == -1)
+                startIndex = 0;
+            if(endIndex == -1)
+                endIndex = _highestPacketIndex;
 
-            returnLength+=DeletePackets(ptrStartOfLayer,packetIndex,endIndex);
-            packetIndex=endIndex;
+            returnLength += DeletePackets(ptrStartOfLayer,packetIndex,endIndex);
+            packetIndex = endIndex;
         }// end lost packet
     }
 
     //Make sure the first packet is decodable (Either complete nalu or start of NALU)
-    if(_packetSizeBytes[0]>0)
+    if(_packetSizeBytes[0] > 0)
     {
         switch(_naluCompleteness[0])
         {
@@ -321,15 +344,16 @@
             case kNaluIncomplete: //Packet is not beginning or end of NALU
                 //Need to find the end of this fua NALU and delete all packets.
                 FindNaluBorder(0,startIndex,endIndex);
-                if(endIndex==-1) // No end found. Delete
+                if(endIndex == -1) // No end found. Delete
                 {
-                    endIndex=_highestPacketIndex;
+                    endIndex = _highestPacketIndex;
                 }
-                returnLength+=DeletePackets(ptrStartOfLayer,0,endIndex);//Delete this NALU.
+                //Delete this NALU.
+                returnLength += DeletePackets(ptrStartOfLayer,0,endIndex);
                 break;
             case kNaluEnd:    // Packet is the end of a NALU
-                //Need to delete this packet
-                returnLength+=DeletePackets(ptrStartOfLayer,0,0);//Delete this NALU.
+                //Delete this NALU
+                returnLength += DeletePackets(ptrStartOfLayer,0,0);
                 break;
             default:
                 assert(false);
@@ -339,9 +363,10 @@
     return returnLength;
 }
 
-WebRtc_Word32 VCMSessionInfo::ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 num)
+WebRtc_Word32 VCMSessionInfo::ZeroOutSeqNum(WebRtc_Word32* list,
+                                            WebRtc_Word32 numberOfSeqNum)
 {
-    if ((NULL == list) || (num < 1))
+    if ((NULL == list) || (numberOfSeqNum < 1))
     {
         return -1;
     }
@@ -353,7 +378,7 @@
 
     // Find end point (index of entry that equals _lowSeqNum)
     int index = 0;
-    for (; index <num; index++)
+    for (; index < numberOfSeqNum; index++)
     {
         if (list[index] == _lowSeqNum)
         {
@@ -364,7 +389,7 @@
 
     // Zero out between first entry and end point
     int i = 0;
-    while ( i <= _highestPacketIndex && index < num)
+    while ( i <= _highestPacketIndex && index < numberOfSeqNum)
     {
         if (_naluCompleteness[i] != kNaluUnset)
         {
@@ -384,6 +409,105 @@
     return 0;
 }
 
+WebRtc_Word32 VCMSessionInfo::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
+                                                  WebRtc_Word32 numberOfSeqNum,
+                                                  float rttScore)
+{
+    if ((NULL == list) || (numberOfSeqNum < 1))
+    {
+        return -1;
+    }
+    if (_lowSeqNum == -1)
+    {
+        // no packets in this frame
+        return 0;
+    }
+
+    WebRtc_Word32 index = 0;
+    // Find end point (index of entry that equals _lowSeqNum)
+    for (; index < numberOfSeqNum; index++)
+    {
+        if (list[index] == _lowSeqNum)
+        {
+            list[index] = -1;
+            break;
+        }
+    }
+
+    // TODO(mikhal): 1. update score based on RTT value 2. add partition data
+    // use the previous available
+    bool isBaseAvailable = false;
+    if ((index > 0) && (list[index] == -1))
+    {
+        // found first packet, for now let's go only one back
+        if ((list[index - 1] == -1) || (list[index - 1] == -2))
+        {
+            // this is indeed the first packet, as previous packet was populated
+            isBaseAvailable = true;
+        }
+    }
+    bool allowNack = false;
+    if (!_haveFirstPacket || !isBaseAvailable)
+    {
+        allowNack = true;
+    }
+
+    // Zero out between first entry and end point
+    int i = 0;
+    // Score place holder - based on RTT and partition (when available).
+    const float nackScoreTh = 0.25f;
+    WebRtc_Word32 highMediaPacket = _emptySeqNumLow > _lowSeqNum ?
+                                    _emptySeqNumLow - 1: _highSeqNum;
+
+    while (list[index] <= highMediaPacket && index < numberOfSeqNum)
+    {
+        if (_naluCompleteness[i] != kNaluUnset)
+        {
+            list[index] = -1;
+        }
+        else
+        {
+            // compute score of the packet
+            float score = 1.0f;
+            // multiply internal score (importance) by external score (RTT)
+            score *= rttScore;
+            if (score > nackScoreTh)
+            {
+                allowNack = true;
+            }
+            else
+            {
+                list[index] = -1;
+            }
+        }
+        i++;
+        index++;
+    }
+    // Empty packets follow the data packets, and therefore have a higher
+    // sequence number. We do not want to NACK empty packets.
+
+    if ((_emptySeqNumLow != -1) && (_emptySeqNumHigh != -1) &&
+        (index < numberOfSeqNum))
+    {
+        // first make sure that we are at least at the minimum value
+        // (if not we are missing last packet(s))
+        while (list[index] < _emptySeqNumLow && index < numberOfSeqNum)
+        {
+            index++;
+        }
+
+        // mark empty packets
+        while (list[index] <= _emptySeqNumHigh && index < numberOfSeqNum)
+        {
+            list[index] = -2;
+            index++;
+        }
+    }
+
+    _sessionNACK  = allowNack;
+    return 0;
+}
+
 WebRtc_Word32 VCMSessionInfo::GetHighestPacketIndex()
 {
     return _highestPacketIndex;
@@ -410,7 +534,7 @@
     // sanity
     if(packetIndex >= kMaxPacketsInJitterBuffer || packetIndex < 0)
     {
-        //not allowed
+        // not allowed
         assert(!"SessionInfo::UpdatePacketSize Error: invalid packetIndex");
         return;
     }
@@ -420,15 +544,17 @@
 void VCMSessionInfo::PrependPacketIndices(WebRtc_Word32 numberOfPacketIndices)
 {
     // sanity
-    if((numberOfPacketIndices + GetHighestPacketIndex() >= kMaxPacketsInJitterBuffer) || numberOfPacketIndices < 0)
+    if((numberOfPacketIndices + GetHighestPacketIndex() >= kMaxPacketsInJitterBuffer)
+        || numberOfPacketIndices < 0)
     {
-        //not allowed
+        // not allowed
         assert(!"SessionInfo::PrependPacketIndexes Error: invalid packetIndex");
         return;
     }
     // Works if we have new packets before packetIndex = 0
     int numOfPacketsToMove = GetHighestPacketIndex()+1;
-    memmove(&_packetSizeBytes[numberOfPacketIndices], &_packetSizeBytes[0], (numOfPacketsToMove)*sizeof(WebRtc_UWord16));
+    memmove(&_packetSizeBytes[numberOfPacketIndices], &_packetSizeBytes[0],
+            (numOfPacketsToMove)*sizeof(WebRtc_UWord16));
     memset(&_packetSizeBytes[0], 0, numberOfPacketIndices*sizeof(WebRtc_UWord16));
 
     _highestPacketIndex += (WebRtc_UWord16)numberOfPacketIndices;
@@ -439,11 +565,11 @@
     // sanity
     if(packetIndex >= kMaxPacketsInJitterBuffer || packetIndex < 0)
     {
-        //not allowed
+        // not allowed
         assert(!"SessionInfo::ClearPacketSize Error: invalid packetIndex");
         return;
     }
-    _packetSizeBytes[packetIndex] =0;
+    _packetSizeBytes[packetIndex] = 0;
 }
 
 WebRtc_UWord32 VCMSessionInfo::GetPacketSize(WebRtc_Word32 packetIndex)
@@ -464,20 +590,31 @@
     //not allowed
     assert(!packet.insertStartCode || !packet.bits);
 
+    if (packet.frameType == kFrameEmpty)
+    {
+        // update seq number as an empty packet
+        // empty packets will be counted twice: both empty and standard packets.
+        InformOfEmptyPacket(packet.seqNum);
+    }
     // Check if this is first packet (only valid for some codecs)
     if (packet.isFirstPacket)
     {
         // the first packet in the frame always signals the frametype
         _frameType = packet.frameType;
     }
+    else if (_frameType == kFrameEmpty && packet.frameType != kFrameEmpty)
+    {
+        // in case an empty packet came in first, update the frame type
+        _frameType = packet.frameType;
+    }
 
     // Check sequence number and update highest and lowest sequence numbers received.
     // Move data if this seq num is lower than previously lowest.
 
     if (packet.seqNum > _highSeqNum)
     {
-        // This packet's seq num is higher than previously highest seq num; normal case
-        // if we have a wrap, only update with wrapped values
+        // This packet's seq num is higher than previously highest seq num;
+        // normal case if we have a wrap, only update with wrapped values
         if (!(_highSeqNum < 0x00ff && packet.seqNum > 0xff00))
         {
             _highSeqNum = packet.seqNum;
@@ -488,7 +625,7 @@
         _highSeqNum = packet.seqNum;
     }
     int packetIndex = packet.seqNum - (WebRtc_UWord16)_lowSeqNum;
-    if(_lowSeqNum < 0x00ff && packet.seqNum > 0xff00)
+    if (_lowSeqNum < 0x00ff && packet.seqNum > 0xff00)
     {
         // negative wrap
         packetIndex = packet.seqNum - 0x10000 - _lowSeqNum;
@@ -498,7 +635,8 @@
         if (_lowSeqNum > 0xff00 && packet.seqNum < 0x00ff)
         {
             // we have a false detect due to the wrap
-            packetIndex = (0xffff - (WebRtc_UWord16)_lowSeqNum) + packet.seqNum + (WebRtc_UWord16)1;
+            packetIndex = (0xffff - (WebRtc_UWord16)_lowSeqNum) + packet.seqNum
+                          + (WebRtc_UWord16)1;
         } else
         {
             // This packet's seq num is lower than previously lowest seq num, but no wrap
@@ -562,7 +700,50 @@
     return InsertBuffer(ptrStartOfLayer, packetIndex, packet);
 }
 
-WebRtc_UWord32 VCMSessionInfo::PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer, VideoCodecType codec)
+
+WebRtc_Word32
+VCMSessionInfo::InformOfEmptyPacket(const WebRtc_UWord16 seqNum)
+{
+    // Empty packets may be FEC or filler packets. They are sequential and
+    // follow the data packets, therefore, we should only keep track of the high
+    // and low sequence numbers and may assume that the packets in between are
+    // empty packets belonging to the same frame (timestamp).
+
+    if (_emptySeqNumLow == -1 && _emptySeqNumHigh == -1)
+    {
+        _emptySeqNumLow = seqNum;
+        _emptySeqNumHigh = seqNum;
+    }
+    else
+    {
+        if (seqNum > _emptySeqNumHigh)
+        {
+            // This packet's seq num is higher than previously highest seq num;
+            // normal case if we have a wrap, only update with wrapped values
+            if (!(_emptySeqNumHigh < 0x00ff && seqNum > 0xff00))
+            {
+                _emptySeqNumHigh = seqNum;
+            }
+        }
+        else if (_emptySeqNumHigh > 0xff00 && seqNum < 0x00ff)
+        {
+             // wrap
+             _emptySeqNumHigh = seqNum;
+        }
+        if (_emptySeqNumLow < 0x00ff && seqNum > 0xff00)
+        {
+            // negative wrap
+            if (seqNum - 0x10000 - _emptySeqNumLow < 0)
+            {
+                _emptySeqNumLow = seqNum;
+            }
+        }
+    }
+    return 0;
+}
+
+WebRtc_UWord32
+VCMSessionInfo::PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer, VideoCodecType codec)
 {
     WebRtc_UWord32 currentPacketOffset = 0;
     WebRtc_UWord32 length = GetSessionLength();
@@ -573,7 +754,7 @@
         return length;
     }
     bool previousLost = false;
-    for (int i=0; i <= _highestPacketIndex; i++)
+    for (int i = 0; i <= _highestPacketIndex; i++)
     {
         if (_ORwithPrevByte[i])
         {
diff --git a/modules/video_coding/main/source/session_info.h b/modules/video_coding/main/source/session_info.h
index 7020581..adbcf43 100644
--- a/modules/video_coding/main/source/session_info.h
+++ b/modules/video_coding/main/source/session_info.h
@@ -26,10 +26,16 @@
 
     VCMSessionInfo(const VCMSessionInfo& rhs);
 
-    WebRtc_Word32 ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 num);
+    WebRtc_Word32 ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 numberOfSeqNum);
+    // Hybrid version: Zero out seq num for NACK list
+    // apply a score based on the packet location and the external rttScore
+    WebRtc_Word32 ZeroOutSeqNumHybrid(WebRtc_Word32* list,
+                                      WebRtc_Word32 numberOfSeqNum,
+                                      float rttScore);
     virtual void Reset();
 
     WebRtc_Word64 InsertPacket(const VCMPacket& packet, WebRtc_UWord8* ptrStartOfLayer);
+    WebRtc_Word32 InformOfEmptyPacket(const WebRtc_UWord16 seqNum);
 
     virtual bool IsSessionComplete();
     WebRtc_UWord32 MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer);
@@ -75,18 +81,20 @@
     bool _sessionNACK;          // If this session has been NACKed by JB
     bool _completeSession;
     webrtc::FrameType  _frameType;
-    bool           _previousFrameLoss;
+    bool               _previousFrameLoss;
 
-    WebRtc_Word32  _lowSeqNum;          // Lowest packet sequence number in a session
-    WebRtc_Word32  _highSeqNum;         // Highest packet sequence number in a session
+    WebRtc_Word32      _lowSeqNum;          // Lowest packet sequence number in a session
+    WebRtc_Word32      _highSeqNum;         // Highest packet sequence number in a session
 
     // Highest packet index in this frame
-    WebRtc_UWord16 _highestPacketIndex;
+    WebRtc_UWord16     _highestPacketIndex;
     // Length of packet (used for reordering)
-    WebRtc_UWord32 _packetSizeBytes[kMaxPacketsInJitterBuffer];
-    // Completness of packets. Used for deciding if the frame is decodable.
-    WebRtc_UWord8  _naluCompleteness[kMaxPacketsInJitterBuffer];
-    bool           _ORwithPrevByte[kMaxPacketsInJitterBuffer];
+    WebRtc_UWord32     _packetSizeBytes[kMaxPacketsInJitterBuffer];
+    // Completeness of packets. Used for deciding if the frame is decodable.
+    WebRtc_UWord8      _naluCompleteness[kMaxPacketsInJitterBuffer];
+    WebRtc_Word32      _emptySeqNumLow;
+    WebRtc_Word32      _emptySeqNumHigh;
+    bool               _ORwithPrevByte[kMaxPacketsInJitterBuffer];
 };
 
 } // namespace webrtc
diff --git a/modules/video_coding/main/source/video_coding_impl.cc b/modules/video_coding/main/source/video_coding_impl.cc
index 57e15c5..b3412d7 100644
--- a/modules/video_coding/main/source/video_coding_impl.cc
+++ b/modules/video_coding/main/source/video_coding_impl.cc
@@ -269,7 +269,7 @@
 {
     WebRtc_UWord32 timeUntilNextProcess = VCM_MIN(_receiveStatsTimer.TimeUntilProcess(),
                                                   _sendStatsTimer.TimeUntilProcess());
-    if ((_receiver.NackMode() == kNackInfinite) || (_dualReceiver.State() != kPassive))
+    if ((_receiver.NackMode() != kNoNack) || (_dualReceiver.State() != kPassive))
     {
         // We need a Process call more often if we are relying on retransmissions
         timeUntilNextProcess = VCM_MIN(timeUntilNextProcess,
@@ -576,6 +576,7 @@
 {
     WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
                "SetVideoProtection()");
+
     switch (videoProtection)
     {
 
@@ -664,16 +665,18 @@
     case kProtectionNackFEC:
         {
             {
+              // Receive side
                 CriticalSectionScoped cs(_receiveCritSect);
                 if (enable)
                 {
-                    _receiver.SetNackMode(kNackInfinite);
+                    _receiver.SetNackMode(kNackHybrid);
                 }
                 else
                 {
                     _receiver.SetNackMode(kNoNack);
                 }
             }
+            // Send Side
             {
                 CriticalSectionScoped cs(_sendCritSect);
                 _mediaOpt.EnableNackFEC(enable);
@@ -1298,7 +1301,7 @@
     // Collect sequence numbers from the default receiver
     // if in normal nack mode. Otherwise collect them from
     // the dual receiver if the dual receiver is receiving.
-    if (_receiver.NackMode() == kNackInfinite)
+    if (_receiver.NackMode() != kNoNack)
     {
         nackStatus = _receiver.NackList(nackList, size);
     }
diff --git a/modules/video_coding/main/test/jitter_buffer_test.cc b/modules/video_coding/main/test/jitter_buffer_test.cc
index c534f61..effc5b1 100644
--- a/modules/video_coding/main/test/jitter_buffer_test.cc
+++ b/modules/video_coding/main/test/jitter_buffer_test.cc
@@ -1461,9 +1461,9 @@
     //  ---------------------------------------------------------------------------------------------
     // | 3 | 4 | 5 | 6 | 7 | 9 | x | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | x | 21 |.....| 102 |
     //  ---------------------------------------------------------------------------------------------
-    jb.SetNackStatus(true);
+    jb.SetNackMode(kNackInfinite);
 
-    TEST(jb.GetNackStatus());
+    TEST(jb.GetNackMode() == kNackInfinite);
 
     // insert first packet
     timeStamp += 33*90;
@@ -1880,7 +1880,7 @@
     //Test incomplete NALU frames
 
     jb.Flush();
-    jb.SetNackStatus(false);
+    jb.SetNackMode(kNoNack);
     seqNum ++;
     timeStamp += 33*90;
     int insertedLength=0;