Bug 1363667 - P2 - adding csrc-audio-level rtp header ext;r?mjf draft
authorNico Grunbaum
Tue, 22 Aug 2017 10:08:54 -0700
changeset 675247 a8b23ecfe8a3370f8b334071bc449c8afec8d561
parent 675246 00a6cb94ad70d28b101f3dd5b73af7d47d200d0f
child 675248 d211abaff5fefb6384ad56cdcadee0b185cd937f
child 675767 dcabf9e0eab3f3fa26a9da972876c8dcf11521b0
push id83079
push userna-g@nostrum.com
push dateThu, 05 Oct 2017 02:18:41 +0000
reviewersmjf
bugs1363667
milestone58.0a1
Bug 1363667 - P2 - adding csrc-audio-level rtp header ext;r?mjf MozReview-Commit-ID: Atg8O3GUj9J
media/webrtc/trunk/webrtc/common_types.cc
media/webrtc/trunk/webrtc/common_types.h
media/webrtc/trunk/webrtc/config.cc
media/webrtc/trunk/webrtc/config.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
--- a/media/webrtc/trunk/webrtc/common_types.cc
+++ b/media/webrtc/trunk/webrtc/common_types.cc
@@ -45,17 +45,18 @@ RTPHeaderExtension::RTPHeaderExtension()
       hasAbsoluteSendTime(false),
       absoluteSendTime(0),
       hasTransportSequenceNumber(false),
       transportSequenceNumber(0),
       hasAudioLevel(false),
       voiceActivity(false),
       audioLevel(0),
       hasVideoRotation(false),
-      videoRotation(kVideoRotation_0) {
+      videoRotation(kVideoRotation_0),
+      csrcAudioLevels() {
 }
 
 RTPHeaderExtension::RTPHeaderExtension(const RTPHeaderExtension& rhs) {
   *this = rhs;
 }
 
 RTPHeaderExtension&
 RTPHeaderExtension::operator=(const RTPHeaderExtension& rhs) {
--- a/media/webrtc/trunk/webrtc/common_types.h
+++ b/media/webrtc/trunk/webrtc/common_types.h
@@ -854,16 +854,27 @@ class StreamId {
   friend bool operator!=(const StreamId& lhs, const StreamId& rhs) {
     return !(lhs == rhs);
   }
 
  private:
   char value_[kMaxSize+1]; // mozilla: make sure we have space to null term.
 };
 
+// Audio level of CSRCs See:
+// https://tools.ietf.org/html/rfc6465
+struct CsrcAudioLevelList {
+  CsrcAudioLevelList() : numAudioLevels(0) { }
+  CsrcAudioLevelList(const CsrcAudioLevelList&) = default;
+  CsrcAudioLevelList& operator=(const CsrcAudioLevelList&) = default;
+  uint8_t numAudioLevels;
+  // arrOfAudioLevels has the same ordering as RTPHeader.arrOfCSRCs
+  uint8_t arrOfAudioLevels[kRtpCsrcSize];
+};
+
 struct RTPHeaderExtension {
   RTPHeaderExtension();
   RTPHeaderExtension(const RTPHeaderExtension& rhs);
   RTPHeaderExtension& operator=(const RTPHeaderExtension& rhs);
 
   bool hasTransmissionTimeOffset;
   int32_t transmissionTimeOffset;
   bool hasAbsoluteSendTime;
@@ -887,16 +898,17 @@ struct RTPHeaderExtension {
 
   // For identification of a stream when ssrc is not signaled. See
   // https://tools.ietf.org/html/draft-ietf-avtext-rid-09
   // TODO(danilchap): Update url from draft to release version.
   StreamId rtpStreamId;
   StreamId repairedRtpStreamId;
 
   StreamId mId;
+  CsrcAudioLevelList csrcAudioLevels;
 };
 
 struct RTPHeader {
   RTPHeader();
 
   bool markerBit;
   uint8_t payloadType;
   uint16_t sequenceNumber;
--- a/media/webrtc/trunk/webrtc/config.cc
+++ b/media/webrtc/trunk/webrtc/config.cc
@@ -79,22 +79,26 @@ const int RtpExtension::kRtpStreamIdDefa
 const char* RtpExtension::kRepairedRtpStreamIdUri =
     "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
 const int RtpExtension::kRepairedRtpStreamIdDefaultId = 8;
 
 const char* RtpExtension::kMIdUri =
     "urn:ietf:params:rtp-hdrext:sdes:mid";
 const int RtpExtension::kMIdDefaultId = 9;
 
+const char* RtpExtension::kCsrcAudioLevelUri =
+    "urn:ietf:params:rtp-hdrext:csrc-audio-level";
+const int RtpExtension::kCsrcAudioLevelDefaultId = 10;
+
 bool RtpExtension::IsSupportedForAudio(const std::string& uri) {
   return uri == webrtc::RtpExtension::kAudioLevelUri ||
          uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
          uri == webrtc::RtpExtension::kRtpStreamIdUri ||
-         uri == webrtc::RtpExtension::kRepairedRtpStreamIdUri ||
-         uri == webrtc::RtpExtension::kMIdUri;
+         uri == webrtc::RtpExtension::kMIdUri ||
+         uri == webrtc::RtpExtension::kCsrcAudioLevelUri;
 }
 
 bool RtpExtension::IsSupportedForVideo(const std::string& uri) {
   return uri == webrtc::RtpExtension::kTimestampOffsetUri ||
          uri == webrtc::RtpExtension::kAbsSendTimeUri ||
          uri == webrtc::RtpExtension::kVideoRotationUri ||
          uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
          uri == webrtc::RtpExtension::kPlayoutDelayUri ||
--- a/media/webrtc/trunk/webrtc/config.h
+++ b/media/webrtc/trunk/webrtc/config.h
@@ -102,16 +102,19 @@ struct RtpExtension {
   static const int kRtpStreamIdDefaultId;
 
   static const char* kRepairedRtpStreamIdUri;
   static const int kRepairedRtpStreamIdDefaultId;
 
   static const char* kMIdUri;
   static const int kMIdDefaultId;
 
+  static const char* kCsrcAudioLevelUri;
+  static const int kCsrcAudioLevelDefaultId;
+
   std::string uri;
   int id;
 };
 
 struct VideoStream {
   VideoStream();
   ~VideoStream();
   std::string ToString() const;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -73,16 +73,17 @@ enum RTPExtensionType {
   kRtpExtensionAudioLevel,
   kRtpExtensionAbsoluteSendTime,
   kRtpExtensionVideoRotation,
   kRtpExtensionTransportSequenceNumber,
   kRtpExtensionPlayoutDelay,
   kRtpExtensionRtpStreamId,
   kRtpExtensionRepairedRtpStreamId,
   kRtpExtensionMId,
+  kRtpExtensionCsrcAudioLevel,
   kRtpExtensionNumberOfExtensions  // Must be the last entity in the enum.
 };
 
 enum RTCPAppSubTypes { kAppSubtypeBwe = 0x00 };
 
 // TODO(sprang): Make this an enum class once rtcp_receiver has been cleaned up.
 enum RTCPPacketType : uint32_t {
   kRtcpReport = 0x0001,
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
@@ -36,16 +36,17 @@ constexpr ExtensionInfo kExtensions[] = 
     CreateExtensionInfo<AudioLevel>(),
     CreateExtensionInfo<AbsoluteSendTime>(),
     CreateExtensionInfo<VideoOrientation>(),
     CreateExtensionInfo<TransportSequenceNumber>(),
     CreateExtensionInfo<PlayoutDelayLimits>(),
     CreateExtensionInfo<RtpStreamId>(),
     CreateExtensionInfo<RepairedRtpStreamId>(),
     CreateExtensionInfo<MId>(),
+    CreateExtensionInfo<CsrcAudioLevel>(),
 };
 
 // Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual
 // number of known extensions.
 static_assert(arraysize(kExtensions) ==
                   static_cast<int>(kRtpExtensionNumberOfExtensions) - 1,
               "kExtensions expect to list all known extensions");
 
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -2,17 +2,16 @@
  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
-
 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
 
 #include "webrtc/base/checks.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 
 namespace webrtc {
@@ -311,9 +310,48 @@ bool MId::Parse(rtc::ArrayView<const uin
 size_t MId::ValueSize(const std::string& mid) {
   return RtpStreamId::ValueSize(mid);
 }
 
 bool MId::Write(uint8_t* data, const std::string& mid) {
   return RtpStreamId::Write(data, mid);
 }
 
+// CSRCAudioLevel
+//  Sample Audio Level Encoding Using the One-Byte Header Format
+//  Note that the range of len is 1 to 15 which is encoded as 0 to 14
+//  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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |  ID   | len=2 |0|   level 1   |0|   level 2   |0|   level 3   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+constexpr RTPExtensionType CsrcAudioLevel::kId;
+constexpr const char* CsrcAudioLevel::kUri;
+
+bool CsrcAudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
+                           CsrcAudioLevelList* csrcAudioLevels) {
+  if (data.size() < 1 || data.size() > kRtpCsrcSize)
+    return false;
+  csrcAudioLevels->numAudioLevels = data.size();
+  for(uint8_t i = 0; i < csrcAudioLevels->numAudioLevels; i++) {
+    // Ensure range is 0 to 127 inclusive
+    csrcAudioLevels->arrOfAudioLevels[i] = 0x7f & data[i];
+  }
+  return true;
+}
+
+size_t CsrcAudioLevel::ValueSize(const CsrcAudioLevelList& csrcAudioLevels) {
+  return csrcAudioLevels.numAudioLevels;
+}
+
+bool CsrcAudioLevel::Write(uint8_t* data,
+                           const CsrcAudioLevelList& csrcAudioLevels) {
+  RTC_DCHECK_GE(csrcAudioLevels.numAudioLevels, 0);
+  for(uint8_t i = 0; i < csrcAudioLevels.numAudioLevels; i++) {
+    data[i] = csrcAudioLevels.arrOfAudioLevels[i] & 0x7f;
+  }
+  // This extension if used must have at least one audio level
+  return csrcAudioLevels.numAudioLevels;
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -147,10 +147,22 @@ class MId {
   static size_t ValueSize(const StreamId& mid);
   static bool Write(uint8_t* data, const StreamId& mid);
 
   static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* mid);
   static size_t ValueSize(const std::string& mid);
   static bool Write(uint8_t* data, const std::string& mid);
 };
 
+class CsrcAudioLevel {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionCsrcAudioLevel;
+  static constexpr const char* kUri =
+      "urn:ietf:params:rtp-hdrext:csrc-audio-level";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    CsrcAudioLevelList* csrcAudioLevels);
+  static size_t ValueSize(const CsrcAudioLevelList& csrcAudioLevels);
+  static bool Write(uint8_t* data, const CsrcAudioLevelList& csrcAudioLevels);
+};
+
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
@@ -170,16 +170,17 @@ void Packet::GetHeader(RTPHeader* header
   header->extension.hasAudioLevel = GetExtension<AudioLevel>(
       &header->extension.voiceActivity, &header->extension.audioLevel);
   header->extension.hasVideoRotation =
       GetExtension<VideoOrientation>(&header->extension.videoRotation);
   GetExtension<RtpStreamId>(&header->extension.rtpStreamId);
   GetExtension<RepairedRtpStreamId>(&header->extension.repairedRtpStreamId);
   GetExtension<PlayoutDelayLimits>(&header->extension.playout_delay);
   GetExtension<MId>(&header->extension.mId);
+  GetExtension<CsrcAudioLevel>(&header->extension.csrcAudioLevels);
 }
 
 size_t Packet::headers_size() const {
   return payload_offset_;
 }
 
 size_t Packet::payload_size() const {
   return payload_size_;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -70,16 +70,28 @@ constexpr char kMId[] = "midval";
 constexpr uint8_t kPacketWithMid[] = {
     0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0xbe, 0xde, 0x00, 0x02,
     0xb5, 'm',  'i',  'd',
     'v',  'a',  'l',  0x00};
 
+constexpr uint8_t kCsrcAudioLevelExtensionId = 0xc;
+constexpr uint8_t kCsrcAudioLevelsSize = 4;
+constexpr uint8_t kCsrcAudioLevels[] = {0x7f, 0x00, 0x10, 0x08};
+constexpr uint8_t kPacketWithCsrcAudioLevels[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x02,
+    (kCsrcAudioLevelExtensionId << 4) | (kCsrcAudioLevelsSize - 1),
+          0x7f, 0x00, 0x10,
+    0x08, 0x00, 0x00, 0x00};
+
 constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465};
 constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'};
 constexpr uint8_t kPacketPaddingSize = 8;
 constexpr uint8_t kPacket[] = {
     0xb2, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0x34, 0x56, 0x78, 0x90,
@@ -159,16 +171,34 @@ TEST(RtpPacketTest, CreateWithDynamicSiz
   packet.SetPayloadType(kPayloadType);
   packet.SetSequenceNumber(kSeqNum);
   packet.SetTimestamp(kTimestamp);
   packet.SetSsrc(kSsrc);
   packet.SetExtension<RtpStreamId>(kMId);
   EXPECT_THAT(kPacketWithMid, ElementsAreArray(packet.data(), packet.size()));
 }
 
+TEST(RtpPacketTest, CreateWithDynamicSizedExtensionCsrcAudioLevel) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<CsrcAudioLevel>(kCsrcAudioLevelExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  CsrcAudioLevelList levels;
+  levels.numAudioLevels = kCsrcAudioLevelsSize;
+  for (uint8_t i = 0; i < kCsrcAudioLevelsSize; i++) {
+    levels.arrOfAudioLevels[i] = kCsrcAudioLevels[i];
+  }
+  packet.SetExtension<CsrcAudioLevel>(levels);
+  EXPECT_THAT(kPacketWithCsrcAudioLevels,
+    ElementsAreArray(packet.data(), packet.size()));
+}
+
 TEST(RtpPacketTest, TryToCreateWithEmptyRsid) {
   RtpPacketToSend::ExtensionManager extensions;
   extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
   RtpPacketToSend packet(&extensions);
   EXPECT_FALSE(packet.SetExtension<RtpStreamId>(""));
 }
 
 TEST(RtpPacketTest, TryToCreateWithLongRsid) {
@@ -448,21 +478,32 @@ TEST(RtpPacketTest, ParseDynamicSizeExte
     0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,  // Timestamp.
     0x12, 0x34, 0x56, 0x78,  // Ssrc.
     0xbe, 0xde, 0x00, 0x04,  // Extensions block of size 4x32bit words.
     0x21, 'H', 'D',          // Extension with id = 2, size = (1+1).
     0x12, 'r', 't', 'x',     // Extension with id = 1, size = (2+1).
     0x35, 'm', 'i', 'd', 'v', 'a', 'l', // Extension with id = 3, size = (5+1).
     0x00, 0x00};  // Extension padding.
+  const uint8_t kPacket4[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // Timestamp.
+    0x12, 0x34, 0x56, 0x78,  // Ssrc.
+    0xbe, 0xde, 0x00, 0x05,  // Extensions block of size 5x32bit words.
+    0x21, 'H', 'D',          // Extension with id = 2, size = (1+1).
+    0x12, 'r', 't', 'x',     // Extension with id = 1, size = (2+1).
+    0x35, 'm', 'i', 'd', 'v', 'a', 'l', // Extension with id = 3, size = (5+1).
+    0x43, 0x01, 0x10, 0x00,  // Extenstionwith id = 4, size = (3+1)
+    0x7f, 0x00}; // Extension 4 cont. 1 byte of padding.
   // clang-format on
   RtpPacketReceived::ExtensionManager extensions;
   extensions.Register<RtpStreamId>(1);
   extensions.Register<RepairedRtpStreamId>(2);
   extensions.Register<MId>(3);
+  extensions.Register<CsrcAudioLevel>(4);
   RtpPacketReceived packet(&extensions);
   ASSERT_TRUE(packet.Parse(kPacket1, sizeof(kPacket1)));
 
   std::string rsid;
   EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
   EXPECT_EQ(rsid, "rtx");
 
   std::string repaired_rsid;
@@ -479,16 +520,33 @@ TEST(RtpPacketTest, ParseDynamicSizeExte
   ASSERT_TRUE(packet.Parse(kPacket3, sizeof(kPacket3)));
   EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
   EXPECT_EQ(rsid, "rtx");
   EXPECT_TRUE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
   EXPECT_EQ(repaired_rsid, "HD");
   std::string mid;
   EXPECT_TRUE(packet.GetExtension<MId>(&mid));
   EXPECT_EQ(mid, "midval");
+
+  // Parse another packet with RtpStreamId, RepairedRtpStreamId, MId,
+  // CsrcAudioLevels
+  ASSERT_TRUE(packet.Parse(kPacket4, sizeof(kPacket4)));
+  EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
+  EXPECT_EQ(rsid, "rtx");
+  EXPECT_TRUE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+  EXPECT_EQ(repaired_rsid, "HD");
+  EXPECT_TRUE(packet.GetExtension<MId>(&mid));
+  EXPECT_EQ(mid, "midval");
+  CsrcAudioLevelList csrcAudioLevels;
+  EXPECT_TRUE(packet.GetExtension<CsrcAudioLevel>(&csrcAudioLevels));
+  EXPECT_EQ(csrcAudioLevels.numAudioLevels, 4);
+  EXPECT_EQ(csrcAudioLevels.arrOfAudioLevels[0], 0x01);
+  EXPECT_EQ(csrcAudioLevels.arrOfAudioLevels[1], 0x10);
+  EXPECT_EQ(csrcAudioLevels.arrOfAudioLevels[2], 0x00);
+  EXPECT_EQ(csrcAudioLevels.arrOfAudioLevels[3], 0x7f);
 }
 
 TEST(RtpPacketTest, RawExtensionFunctionsAcceptZeroIdAndReturnFalse) {
   RtpPacketReceived::ExtensionManager extensions;
   RtpPacketReceived packet(&extensions);
   // Use ExtensionManager to set kInvalidId to 0 to demonstrate natural way for
   // using zero value as a parameter to Packet::*RawExtension functions.
   const int kInvalidId = extensions.GetId(TransmissionOffset::kId);
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -42,16 +42,18 @@ RTPExtensionType StringToRtpExtensionTyp
   if (extension == RtpExtension::kPlayoutDelayUri)
     return kRtpExtensionPlayoutDelay;
   if (extension == RtpExtension::kRtpStreamIdUri)
     return kRtpExtensionRtpStreamId;
   if (extension == RtpExtension::kRepairedRtpStreamIdUri)
     return kRtpExtensionRepairedRtpStreamId;
   if (extension == RtpExtension::kMIdUri)
     return kRtpExtensionMId;
+  if (extension == RtpExtension::kCsrcAudioLevelUri)
+    return kRtpExtensionCsrcAudioLevel;
   RTC_NOTREACHED() << "Looking up unsupported RTP extension.";
   return kRtpExtensionNone;
 }
 
 RtpRtcp::Configuration::Configuration()
     : receive_statistics(NullObjectReceiveStatistics()) {}
 
 RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) {
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
@@ -464,16 +464,30 @@ void RtpHeaderParser::ParseOneByteExtens
           header->extension.repairedRtpStreamId.Set(
               rtc::MakeArrayView(ptr, len + 1));
           break;
         }
         case kRtpExtensionMId: {
           header->extension.mId.Set(rtc::MakeArrayView(ptr, len + 1));
           break;
         }
+        case kRtpExtensionCsrcAudioLevel: {
+          auto& levels = header->extension.csrcAudioLevels;
+          levels.numAudioLevels = static_cast<uint8_t>(len + 1);
+          if (levels.numAudioLevels > kRtpCsrcSize)  {
+            LOG(LS_WARNING) << "Incorrect number of CSRC audio levels: " <<
+                levels.numAudioLevels;
+            levels.numAudioLevels = 0;
+            return;
+          }
+          for (uint8_t i = 0; i < levels.numAudioLevels; i++) {
+            levels.arrOfAudioLevels[i] = ptr[i] & 0x7f;
+          }
+          break;
+        }
         default:
         case kRtpExtensionNone:
         case kRtpExtensionNumberOfExtensions: {
           RTC_NOTREACHED() << "Invalid extension type: " << type;
           return;
         }
       }
     }
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
@@ -143,48 +143,50 @@ TEST(RtpHeaderParser, ParseWithOverSized
 
   EXPECT_TRUE(parser.Parse(&header, &extensions));
 
   // Parse should ignore extension.
   EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
   EXPECT_EQ(sizeof(kPacket), header.headerLength);
 }
 
-TEST(RtpHeaderParser, ParseAll9Extensions) {
+TEST(RtpHeaderParser, ParseAll10Extensions) {
   const uint8_t kAudioLevel = 0x5a;
   // clang-format off
   const uint8_t kPacket[] = {
       0x90, kPayloadType, 0x00, kSeqNum,
       0x65, 0x43, 0x12, 0x78,  // kTimestamp.
       0x12, 0x34, 0x56, 0x78,  // kSsrc.
-      0xbe, 0xde, 0x00, 0x0a,  // Extension of size 10x32bit words.
+      0xbe, 0xde, 0x00, 0x0b,  // Extension of size 10x32bit words.
       0x40, 0x80|kAudioLevel,  // AudioLevel.
       0x22, 0x01, 0x56, 0xce,  // TransmissionOffset.
       0x62, 0x12, 0x34, 0x56,  // AbsoluteSendTime.
+      0x72, 0x7f, 0x01, 0x10,  // CsrcAudioLevel
       0x81, 0xce, 0xab,        // TransportSequenceNumber.
       0xa0, 0x03,              // VideoRotation.
       0xb2, 0x12, 0x48, 0x76,  // PlayoutDelayLimits.
       0xc2, 'r', 't', 'x',     // RtpStreamId
       0xd5, 's', 't', 'r', 'e', 'a', 'm',  // RepairedRtpStreamId
       0xe7, 'm', 'i', 'd', 'v', 'a', 'l', 'u', 'e', // MId
       0x00,                    // Padding to 32bit boundary.
   };
   // clang-format on
   ASSERT_EQ(sizeof(kPacket) % 4, 0u);
 
   RtpHeaderExtensionMap extensions;
-  extensions.Register<TransmissionOffset>(2);
-  extensions.Register<AudioLevel>(4);
-  extensions.Register<AbsoluteSendTime>(6);
-  extensions.Register<TransportSequenceNumber>(8);
-  extensions.Register<VideoOrientation>(0xa);
-  extensions.Register<PlayoutDelayLimits>(0xb);
-  extensions.Register<RtpStreamId>(0xc);
-  extensions.Register<RepairedRtpStreamId>(0xd);
-  extensions.Register<MId>(0xe);
+  EXPECT_TRUE(extensions.Register<TransmissionOffset>(2));
+  EXPECT_TRUE(extensions.Register<AudioLevel>(4));
+  EXPECT_TRUE(extensions.Register<AbsoluteSendTime>(6));
+  EXPECT_TRUE(extensions.Register<CsrcAudioLevel>(7));
+  EXPECT_TRUE(extensions.Register<TransportSequenceNumber>(8));
+  EXPECT_TRUE(extensions.Register<VideoOrientation>(0xa));
+  EXPECT_TRUE(extensions.Register<PlayoutDelayLimits>(0xb));
+  EXPECT_TRUE(extensions.Register<RtpStreamId>(0xc));
+  EXPECT_TRUE(extensions.Register<RepairedRtpStreamId>(0xd));
+  EXPECT_TRUE(extensions.Register<MId>(0xe));
   RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
   RTPHeader header;
 
   EXPECT_TRUE(parser.Parse(&header, &extensions));
 
   EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
   EXPECT_EQ(0x156ce, header.extension.transmissionTimeOffset);
 
@@ -203,16 +205,20 @@ TEST(RtpHeaderParser, ParseAll9Extension
 
   EXPECT_EQ(0x124 * PlayoutDelayLimits::kGranularityMs,
             header.extension.playout_delay.min_ms);
   EXPECT_EQ(0x876 * PlayoutDelayLimits::kGranularityMs,
             header.extension.playout_delay.max_ms);
   EXPECT_EQ(header.extension.rtpStreamId, StreamId("rtx"));
   EXPECT_EQ(header.extension.repairedRtpStreamId, StreamId("stream"));
   EXPECT_EQ(header.extension.mId, StreamId("midvalue"));
+  EXPECT_EQ(header.extension.csrcAudioLevels.numAudioLevels, 3);
+  EXPECT_EQ(header.extension.csrcAudioLevels.arrOfAudioLevels[0], 0x7f);
+  EXPECT_EQ(header.extension.csrcAudioLevels.arrOfAudioLevels[1], 0x01);
+  EXPECT_EQ(header.extension.csrcAudioLevels.arrOfAudioLevels[2], 0x10);
 }
 
 TEST(RtpHeaderParser, ParseMalformedRsidExtensions) {
   // clang-format off
   const uint8_t kPacket[] = {
       0x90, kPayloadType, 0x00, kSeqNum,
       0x65, 0x43, 0x12, 0x78,  // kTimestamp.
       0x12, 0x34, 0x56, 0x78,  // kSsrc.
--- a/media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
+++ b/media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
@@ -96,12 +96,17 @@ void FuzzOneInput(const uint8_t* data, s
         packet.GetExtension<RepairedRtpStreamId>(&rsid);
         break;
       }
       case kRtpExtensionMId: {
         std::string mid;
         packet.GetExtension<MId>(&mid);
         break;
       }
+      case kRtpExtensionCsrcAudioLevel: {
+        CsrcAudioLevelList levels;
+        packet.GetExtension<CsrcAudioLevel>(&levels);
+        break;
+      }
     }
   }
 }
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
+++ b/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
@@ -407,16 +407,24 @@ bool RtpStreamReceiver::DeliverRtp(const
       if (header.extension.hasAbsoluteSendTime)
         ss << ", abs send time: " << header.extension.absoluteSendTime;
       if (!header.extension.rtpStreamId.empty())
         ss << ", rid: " << header.extension.rtpStreamId.data();
       if (!header.extension.repairedRtpStreamId.empty())
         ss << ", repaired rid: " << header.extension.repairedRtpStreamId.data();
       if (!header.extension.mId.empty())
         ss << ", mid: " << header.extension.mId.data();
+      const auto& csrcLevels = header.extension.csrcAudioLevels;
+      if (csrcLevels.numAudioLevels) {
+        ss << ", csrc audio levels : {" << csrcLevels.arrOfAudioLevels[0];
+        for (uint8_t i = 1; i < csrcLevels.numAudioLevels; i++) {
+          ss << ", " << csrcLevels.arrOfAudioLevels[i];
+        }
+        ss << "}";
+      }
       LOG(LS_INFO) << ss.str();
       last_packet_log_ms_ = now_ms;
     }
   }
 
   remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_length,
                                             header);
   header.payload_type_frequency = kVideoPayloadTypeFrequency;