Parse next RTCP XR report block after an unsupported block type.

R=stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5114 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index c33cf23..25670f5 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -162,6 +162,17 @@
     }
   }
 
+  void AddXrUnknownBlock() {
+    Add8(6);             // Block type.
+    Add8(0);             // Reserved.
+    Add16(9);            // Length.
+    Add32(0);            // Receiver SSRC.
+    Add64(0, 0);         // Remaining fields (RFC 3611) are set to zero.
+    Add64(0, 0);
+    Add64(0, 0);
+    Add64(0, 0);
+  }
+
   void AddXrVoipBlock(uint32_t remote_ssrc, uint8_t loss) {
     Add8(7);             // Block type.
     Add8(0);             // Reserved.
@@ -452,6 +463,27 @@
   EXPECT_TRUE(rtcp_packet_info_.xr_dlrr_item);
 }
 
+TEST_F(RtcpReceiverTest, InjectXrPacketWithUnknownReportBlock) {
+  const uint8_t kLossRate = 123;
+  const uint32_t kSourceSsrc = 0x123456;
+  std::set<uint32_t> ssrcs;
+  ssrcs.insert(kSourceSsrc);
+  rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
+  std::vector<uint32_t> remote_ssrcs;
+  remote_ssrcs.push_back(kSourceSsrc);
+
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  p.AddXrVoipBlock(kSourceSsrc, kLossRate);
+  p.AddXrUnknownBlock();
+  p.AddXrReceiverReferenceTimeBlock(0x10203, 0x40506);
+
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  EXPECT_EQ(static_cast<unsigned int>(kRtcpXrReceiverReferenceTime +
+                                      kRtcpXrVoipMetric),
+            rtcp_packet_info_.rtcpPacketTypeFlags);
+}
+
 TEST(RtcpUtilityTest, MidNtp) {
   const uint32_t kNtpSec = 0x12345678;
   const uint32_t kNtpFrac = 0x23456789;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
index 8ab783f..705a38b 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
@@ -224,7 +224,7 @@
         }
         case PT_XR:
         {
-            const bool ok = ParseXR();
+            const bool ok = ParseXr();
             if (!ok)
             {
                 // Nothing supported found, continue to next block!
@@ -243,7 +243,7 @@
 void
 RTCPUtility::RTCPParserV2::IterateXrItem()
 {
-    const bool success = ParseXRItem();
+    const bool success = ParseXrItem();
     if (!success)
     {
         Iterate();
@@ -253,7 +253,7 @@
 void
 RTCPUtility::RTCPParserV2::IterateXrDlrrItem()
 {
-    const bool success = ParseXRDLRRReportBlockItem();
+    const bool success = ParseXrDlrrItem();
     if (!success)
     {
         Iterate();
@@ -851,7 +851,7 @@
     return true;
 }
 /*
-  0                   1                   2                   3
+    0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |V=2|P|reserved |   PT=XR=207   |             length            |
@@ -861,7 +861,7 @@
    :                         report blocks                         :
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
-bool RTCPUtility::RTCPParserV2::ParseXR()
+bool RTCPUtility::RTCPParserV2::ParseXr()
 {
     const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
     if (length < 8)
@@ -882,55 +882,47 @@
     return true;
 }
 
-/*
+/*  Extended report block format (RFC 3611).
+    BT: block type.
+    block length: length of report block in 32-bits words minus one (including
+                  the header).
     0                   1                   2                   3
-     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      BT       | type-specific |         block length          |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     :             type-specific block contents                      :
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
-bool
-RTCPUtility::RTCPParserV2::ParseXRItem()
-{
+bool RTCPUtility::RTCPParserV2::ParseXrItem() {
+  const int kBlockHeaderLengthInBytes = 4;
   const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
-
-  if (length < 4) {
+  if (length < kBlockHeaderLengthInBytes) {
     _state = State_TopLevel;
     EndCurrentBlock();
     return false;
   }
 
-  uint8_t blockType = *_ptrRTCPData++;
+  uint8_t block_type = *_ptrRTCPData++;
   _ptrRTCPData++;  // Ignore reserved.
 
-  uint16_t blockLength = *_ptrRTCPData++ << 8;
-  blockLength = *_ptrRTCPData++;
+  uint16_t block_length_in_4bytes = *_ptrRTCPData++ << 8;
+  block_length_in_4bytes += *_ptrRTCPData++;
 
-  if (blockType == 4 && blockLength == 2)
-  {
-    return ParseXRReceiverReferenceTimeItem();
+  switch (block_type) {
+    case kBtReceiverReferenceTime:
+      return ParseXrReceiverReferenceTimeItem(block_length_in_4bytes);
+    case kBtDlrr:
+      return ParseXrDlrr(block_length_in_4bytes);
+    case kBtVoipMetric:
+      return ParseXrVoipMetricItem(block_length_in_4bytes);
+    default:
+      return ParseXrUnsupportedBlockType(block_length_in_4bytes);
   }
-  else if (blockType == 5 && (blockLength % 3) == 0)
-  {
-    _packetType = kRtcpXrDlrrReportBlockCode;
-    _state = State_XR_DLLRItem;
-    _numberOfBlocks = blockLength / 3;
-    return true;
-  }
-  else if (blockType == 7 && blockLength == 8)
-  {
-    return ParseXRVOIPMetricItem();
-  }
-
-  // Not supported.
-  _state = State_TopLevel;
-  EndCurrentBlock();
-  return false;
 }
 
-/*  0                   1                   2                   3
+/*  Receiver Reference Time Report Block.
+    0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |     BT=4      |   reserved    |       block length = 2        |
@@ -940,37 +932,35 @@
    |             NTP timestamp, least significant word             |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
-
-bool RTCPUtility::RTCPParserV2::ParseXRReceiverReferenceTimeItem() {
+bool RTCPUtility::RTCPParserV2::ParseXrReceiverReferenceTimeItem(
+    int block_length_4bytes) {
+  const int kBlockLengthIn4Bytes = 2;
+  const int kBlockLengthInBytes = kBlockLengthIn4Bytes * 4;
   const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
-  if (length < 8) {
+  if (block_length_4bytes != kBlockLengthIn4Bytes ||
+      length < kBlockLengthInBytes) {
     _state = State_TopLevel;
     EndCurrentBlock();
     return false;
   }
 
-  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant =
-      *_ptrRTCPData++ << 24;
-  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant +=
-      *_ptrRTCPData++ << 16;
-  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant +=
-      *_ptrRTCPData++ << 8;
-  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant += *_ptrRTCPData++;
+  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant = *_ptrRTCPData++<<24;
+  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++<<16;
+  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++<<8;
+  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant+= *_ptrRTCPData++;
 
-  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant =
-      *_ptrRTCPData++ << 24;
-  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant +=
-      *_ptrRTCPData++ << 16;
-  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant +=
-      *_ptrRTCPData++ << 8;
-  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant += *_ptrRTCPData++;
+  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant = *_ptrRTCPData++<<24;
+  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++<<16;
+  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++<<8;
+  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant+= *_ptrRTCPData++;
 
   _packetType = kRtcpXrReceiverReferenceTimeCode;
   _state = State_XRItem;
   return true;
 }
 
-/*  0                   1                   2                   3
+/*  DLRR Report Block.
+    0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |     BT=5      |   reserved    |         block length          |
@@ -986,14 +976,28 @@
    :                               ...                             :   2
    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 */
+bool RTCPUtility::RTCPParserV2::ParseXrDlrr(int block_length_4bytes) {
+  const int kSubBlockLengthIn4Bytes = 3;
+  if (block_length_4bytes < 0 ||
+      (block_length_4bytes % kSubBlockLengthIn4Bytes) != 0) {
+    _state = State_TopLevel;
+    EndCurrentBlock();
+    return false;
+  }
+  _packetType = kRtcpXrDlrrReportBlockCode;
+  _state = State_XR_DLLRItem;
+  _numberOfBlocks = block_length_4bytes / kSubBlockLengthIn4Bytes;
+  return true;
+}
 
-bool RTCPUtility::RTCPParserV2::ParseXRDLRRReportBlockItem() {
-  const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
+bool RTCPUtility::RTCPParserV2::ParseXrDlrrItem() {
   if (_numberOfBlocks == 0) {
     _state = State_XRItem;
     return false;
   }
-  if (length < 12) {
+  const int kSubBlockLengthInBytes = 12;
+  const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
+  if (length < kSubBlockLengthInBytes) {
     _state = State_TopLevel;
     EndCurrentBlock();
     return false;
@@ -1019,8 +1023,8 @@
   _state = State_XR_DLLRItem;
   return true;
 }
-/*
- 0                   1                   2                   3
+/*  VoIP Metrics Report Block.
+    0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |     BT=7      |   reserved    |       block length = 8        |
@@ -1043,63 +1047,77 @@
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
 
-bool
-RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem()
-{
-    const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
+bool RTCPUtility::RTCPParserV2::ParseXrVoipMetricItem(int block_length_4bytes) {
+  const int kBlockLengthIn4Bytes = 8;
+  const int kBlockLengthInBytes = kBlockLengthIn4Bytes * 4;
+  const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
+  if (block_length_4bytes != kBlockLengthIn4Bytes ||
+      length < kBlockLengthInBytes) {
+    _state = State_TopLevel;
+    EndCurrentBlock();
+    return false;
+  }
 
-    if (length < 28)
-    {
-        _state = State_TopLevel;
-        EndCurrentBlock();
-        return false;
-    }
-    _packetType = kRtcpXrVoipMetricCode;
+  _packet.XRVOIPMetricItem.SSRC = *_ptrRTCPData++ << 24;
+  _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++ << 16;
+  _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++ << 8;
+  _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.SSRC = *_ptrRTCPData++ << 24;
-    _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++ << 16;
-    _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++ << 8;
-    _packet.XRVOIPMetricItem.SSRC += *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.lossRate = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.discardRate = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.burstDensity = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.gapDensity = *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.lossRate = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.discardRate = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.burstDensity = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.gapDensity = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.burstDuration = *_ptrRTCPData++ << 8;
+  _packet.XRVOIPMetricItem.burstDuration += *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.burstDuration = *_ptrRTCPData++ << 8;
-    _packet.XRVOIPMetricItem.burstDuration += *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.gapDuration = *_ptrRTCPData++ << 8;
+  _packet.XRVOIPMetricItem.gapDuration += *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.gapDuration = *_ptrRTCPData++ << 8;
-    _packet.XRVOIPMetricItem.gapDuration += *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.roundTripDelay = *_ptrRTCPData++ << 8;
+  _packet.XRVOIPMetricItem.roundTripDelay += *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.roundTripDelay = *_ptrRTCPData++ << 8;
-    _packet.XRVOIPMetricItem.roundTripDelay += *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.endSystemDelay = *_ptrRTCPData++ << 8;
+  _packet.XRVOIPMetricItem.endSystemDelay += *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.endSystemDelay = *_ptrRTCPData++ << 8;
-    _packet.XRVOIPMetricItem.endSystemDelay += *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.signalLevel = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.noiseLevel = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.RERL = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.Gmin = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.Rfactor = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.extRfactor = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.MOSLQ = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.MOSCQ = *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.RXconfig = *_ptrRTCPData++;
+  _ptrRTCPData++; // skip reserved
 
-    _packet.XRVOIPMetricItem.signalLevel = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.noiseLevel = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.RERL = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.Gmin = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.Rfactor = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.extRfactor = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.MOSLQ = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.MOSCQ = *_ptrRTCPData++;
-    _packet.XRVOIPMetricItem.RXconfig = *_ptrRTCPData++;
-    _ptrRTCPData++; // skip reserved
+  _packet.XRVOIPMetricItem.JBnominal = *_ptrRTCPData++ << 8;
+  _packet.XRVOIPMetricItem.JBnominal += *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.JBnominal = *_ptrRTCPData++ << 8;
-    _packet.XRVOIPMetricItem.JBnominal += *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.JBmax = *_ptrRTCPData++ << 8;
+  _packet.XRVOIPMetricItem.JBmax += *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.JBmax = *_ptrRTCPData++ << 8;
-    _packet.XRVOIPMetricItem.JBmax += *_ptrRTCPData++;
+  _packet.XRVOIPMetricItem.JBabsMax = *_ptrRTCPData++ << 8;
+  _packet.XRVOIPMetricItem.JBabsMax += *_ptrRTCPData++;
 
-    _packet.XRVOIPMetricItem.JBabsMax = *_ptrRTCPData++ << 8;
-    _packet.XRVOIPMetricItem.JBabsMax += *_ptrRTCPData++;
+  _packetType = kRtcpXrVoipMetricCode;
+  _state = State_XRItem;
+  return true;
+}
 
-    _state = State_XRItem;
-    return true;
+bool RTCPUtility::RTCPParserV2::ParseXrUnsupportedBlockType(
+    int block_length_4bytes) {
+  const int32_t kBlockLengthInBytes = block_length_4bytes * 4;
+  const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
+  if (length < kBlockLengthInBytes) {
+    _state = State_TopLevel;
+    EndCurrentBlock();
+    return false;
+  }
+  // Skip block.
+  _ptrRTCPData += kBlockLengthInBytes;
+  _state = State_XRItem;
+  return false;
 }
 
 bool
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
index c954f44..f0867a7 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
@@ -335,6 +335,13 @@
         PT_XR    = 207
     };
 
+    // Extended report blocks, RFC 3611.
+    enum RtcpXrBlockType {
+      kBtReceiverReferenceTime = 4,
+      kBtDlrr = 5,
+      kBtVoipMetric = 7
+    };
+
     bool RTCPParseCommonHeader( const uint8_t* ptrDataBegin,
                                 const uint8_t* ptrDataEnd,
                                 RTCPCommonHeader& parsedHeader);
@@ -413,11 +420,13 @@
         bool ParseIJ();
         bool ParseIJItem();
 
-        bool ParseXR();
-        bool ParseXRItem();
-        bool ParseXRReceiverReferenceTimeItem();
-        bool ParseXRDLRRReportBlockItem();
-        bool ParseXRVOIPMetricItem();
+        bool ParseXr();
+        bool ParseXrItem();
+        bool ParseXrReceiverReferenceTimeItem(int block_length_4bytes);
+        bool ParseXrDlrr(int block_length_4bytes);
+        bool ParseXrDlrrItem();
+        bool ParseXrVoipMetricItem(int block_length_4bytes);
+        bool ParseXrUnsupportedBlockType(int block_length_4bytes);
 
         bool ParseFBCommon(const RTCPCommonHeader& header);
         bool ParseNACKItem();