Bug 1363667 - P2 - Add RTP Sources RTP header extensions draft
authorNico Grunbaum
Tue, 14 Nov 2017 09:32:29 -0800
changeset 706487 65f3b9cb441e962084f1de05ec1e124a19d01dc9
parent 706486 724dff65f4b61fa7c498748a3dc7e7e2866d19ca
child 706488 1b855ef09588c73864adfaaf14427a8f4dfb031a
push id91808
push userna-g@nostrum.com
push dateSat, 02 Dec 2017 00:48:28 +0000
bugs1363667
milestone59.0a1
Bug 1363667 - P2 - Add RTP Sources RTP header extensions MozReview-Commit-ID: JVPR5OhHMOR
media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
media/webrtc/signaling/src/media-conduit/AudioConduit.h
media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
media/webrtc/signaling/src/media-conduit/VideoConduit.h
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/BUILD.gn
media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
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/signaling/src/jsep/JsepSessionImpl.cpp
+++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
@@ -2038,17 +2038,17 @@ JsepSessionImpl::SetupDefaultCodecs()
   // codecs.  Note: only uses the video codecs.
   red->UpdateRedundantEncodings(mSupportedCodecs.values);
 }
 
 void
 JsepSessionImpl::SetupDefaultRtpExtensions()
 {
   AddAudioRtpExtension(webrtc::RtpExtension::kAudioLevelUri,
-                       SdpDirectionAttribute::Direction::kSendonly);
+                       SdpDirectionAttribute::Direction::kSendrecv);
   AddAudioRtpExtension(webrtc::RtpExtension::kMIdUri,
                        SdpDirectionAttribute::Direction::kSendrecv);
   AddVideoRtpExtension(webrtc::RtpExtension::kAbsSendTimeUri,
                        SdpDirectionAttribute::Direction::kSendrecv);
   AddVideoRtpExtension(webrtc::RtpExtension::kTimestampOffsetUri,
                        SdpDirectionAttribute::Direction::kSendrecv);
   AddVideoRtpExtension(webrtc::RtpExtension::kMIdUri,
                        SdpDirectionAttribute::Direction::kSendrecv);
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -584,26 +584,37 @@ WebrtcAudioConduit::ConfigureRecvMediaCo
     return condError;
   }
 
   DumpCodecDB();
   return kMediaConduitNoError;
 }
 
 MediaConduitErrorCode
-WebrtcAudioConduit::EnableAudioLevelExtension(bool enabled, uint8_t id)
+WebrtcAudioConduit::EnableAudioLevelExtension(bool aEnabled,
+                                              uint8_t aId,
+                                              bool aDirectionIsSend)
 {
-  CSFLogDebug(LOGTAG,  "%s %d %d ", __FUNCTION__, enabled, id);
+  CSFLogDebug(LOGTAG,  "%s %d %d %d", __FUNCTION__, aEnabled, aId,
+              aDirectionIsSend);
 
-  if (mPtrVoERTP_RTCP->SetSendAudioLevelIndicationStatus(mChannel, enabled, id) == -1)
-  {
+  bool ret;
+  if (aDirectionIsSend) {
+    ret = mPtrVoERTP_RTCP->SetSendAudioLevelIndicationStatus(mChannel,
+                                                             aEnabled,
+                                                             aId) == -1;
+  } else {
+    ret = mPtrRTP->SetReceiveAudioLevelIndicationStatus(mChannel,
+                                                        aEnabled,
+                                                        aId) == -1;
+  }
+  if (ret) {
     CSFLogError(LOGTAG, "%s SetSendAudioLevelIndicationStatus Failed", __FUNCTION__);
     return kMediaConduitUnknownError;
   }
-
   return kMediaConduitNoError;
 }
 
 MediaConduitErrorCode
 WebrtcAudioConduit::EnableMIDExtension(bool enabled, uint8_t id)
 {
   CSFLogDebug(LOGTAG,  "%s %d %d ", __FUNCTION__, enabled, id);
 
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.h
@@ -87,21 +87,22 @@ public:
    * @result: On Success, the audio engine is configured with passed in codec for send
    *          Also the playout is enabled.
    *          On failure, audio engine transmit functionality is disabled.
    * NOTE: This API can be invoked multiple time. Invoking this API may involve restarting
    *        transmission sub-system on the engine.
    */
   virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
     const std::vector<AudioCodecConfig* >& codecConfigList) override;
-  /**
-   * Function to enable the audio level extension
-   * @param enabled: enable extension
-   */
-  virtual MediaConduitErrorCode EnableAudioLevelExtension(bool enabled, uint8_t id) override;
+
+  MediaConduitErrorCode
+  EnableAudioLevelExtension(bool aEnabled,
+                            uint8_t aId,
+                            bool aDirectionIsSend) override;
+
   virtual MediaConduitErrorCode EnableMIDExtension(bool enabled, uint8_t id) override;
 
   /**
    * Register External Transport to this Conduit. RTP and RTCP frames from the VoiceEngine
    * shall be passed to the registered transport for transporting externally.
    */
   virtual MediaConduitErrorCode SetTransmitterTransport(RefPtr<TransportInterface> aTransport) override;
 
--- a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
+++ b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
@@ -28,16 +28,18 @@
 #include <vector>
 
 namespace webrtc {
 class VideoFrame;
 }
 
 namespace mozilla {
 
+using RtpExtList = std::vector<webrtc::RtpExtension>;
+
 // Wrap the webrtc.org Call class adding mozilla add/ref support.
 class WebRtcCallWrapper : public RefCounted<WebRtcCallWrapper>
 {
 public:
   typedef webrtc::Call::Config Config;
 
   static RefPtr<WebRtcCallWrapper> Create()
   {
@@ -232,16 +234,27 @@ public:
 
   /* Sets the local SSRCs
    * @return true iff the local ssrcs == aSSRCs upon return
    * Note: this is an ordered list and {a,b,c} != {b,a,c}
    */
   virtual bool SetLocalSSRCs(const std::vector<unsigned int>& aSSRCs) = 0;
   virtual std::vector<unsigned int> GetLocalSSRCs() const = 0;
 
+  /**
+  * Adds negotiated RTP extensions
+  * XXX Move to MediaSessionConduit
+  */
+  virtual void
+  SetLocalRTPExtensions(bool aIsSend, const RtpExtList& extensions) = 0;
+  /**
+  * Returns the negotiated RTP extensions
+  */
+  virtual RtpExtList GetLocalRTPExtensions(bool aIsSend) const = 0;
+
   virtual bool GetRemoteSSRC(unsigned int* ssrc) = 0;
   virtual bool SetRemoteSSRC(unsigned int ssrc) = 0;
   virtual bool SetLocalCNAME(const char* cname) = 0;
 
   virtual bool SetLocalMID(const std::string& mid) = 0;
 
   /**
    * Functions returning stats needed by w3c stats model.
@@ -336,41 +349,34 @@ public:
 
   VideoSessionConduit() : mFrameRequestMethod(FrameRequestNone),
                           mUsingNackBasic(false),
                           mUsingTmmbr(false),
                           mUsingFEC(false) {}
 
   virtual ~VideoSessionConduit() {}
 
-  virtual Type type() const { return VIDEO; }
+  Type type() const override { return VIDEO; }
 
-  /**
-  * Adds negotiated RTP extensions
-  * XXX Move to MediaSessionConduit
-  */
-  virtual void SetLocalRTPExtensions(bool aIsSend,
-                                     const std::vector<webrtc::RtpExtension>& extensions) = 0;
+  void
+  SetLocalRTPExtensions(bool aIsSend,
+                        const RtpExtList& extensions) override = 0;
 
-  /**
-  * Returns the negotiated RTP extensions
-  */
-  virtual std::vector<webrtc::RtpExtension> GetLocalRTPExtensions(bool aIsSend) const = 0;
-
+  RtpExtList GetLocalRTPExtensions(bool aIsSend) const override = 0;
 
   /**
    * Function to attach Renderer end-point of the Media-Video conduit.
    * @param aRenderer : Reference to the concrete Video renderer implementation
    * Note: Multiple invocations of this API shall remove an existing renderer
    * and attaches the new to the Conduit.
    */
   virtual MediaConduitErrorCode AttachRenderer(RefPtr<mozilla::VideoRenderer> aRenderer) = 0;
   virtual void DetachRenderer() = 0;
 
-  virtual bool SetRemoteSSRC(unsigned int ssrc) = 0;
+  bool SetRemoteSSRC(unsigned int ssrc) override = 0;
 
   /**
    * Function to deliver a capture video frame for encoding and transport
    * @param video_frame: pointer to captured video-frame.
    * @param video_frame_length: size of the frame
    * @param width, height: dimensions of the frame
    * @param video_type: Type of the video frame - I420, RAW
    * @param captured_time: timestamp when the frame was captured.
@@ -455,19 +461,24 @@ public:
    *         media conduits
    * @result Concrete AudioSessionConduitObject or nullptr in the case
    *         of failure
    */
   static RefPtr<AudioSessionConduit> Create();
 
   virtual ~AudioSessionConduit() {}
 
-  virtual Type type() const { return AUDIO; }
+  Type type() const override { return AUDIO; }
 
+  void
+  SetLocalRTPExtensions(bool aIsSend,
+                        const RtpExtList& extensions) override {};
 
+  RtpExtList
+  GetLocalRTPExtensions(bool aIsSend) const override {return RtpExtList();}
   /**
    * Function to deliver externally captured audio sample for encoding and transport
    * @param audioData [in]: Pointer to array containing a frame of audio
    * @param lengthSamples [in]: Length of audio frame in samples in multiple of 10 milliseconds
   *                             Ex: Frame length is 160, 320, 440 for 16, 32, 44 kHz sampling rates
                                     respectively.
                                     audioData[] is lengthSamples in size
                                     say, for 16kz sampling rate, audioData[] should contain 160
@@ -518,22 +529,28 @@ public:
     * Function to configure list of receive codecs for the audio session
     * @param sendSessionConfig: CodecConfiguration
     * NOTE: See VideoConduit for more information
     */
   virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
                                 const std::vector<AudioCodecConfig* >& recvCodecConfigList) = 0;
    /**
     * Function to enable the audio level extension
-    * @param enabled: enable extension
-    * @param id: id to be used for this rtp header extension
-    * NOTE: See AudioConduit for more information
+    * @param aEnabled: enable extension
+    * @param aId: the RTP extension header ID to use
+    * @param aDirectionIsSend: indicates whether to set the extension on the
+    *                          sender or the receiver side
+    * returns an error if the extension could not be set
     */
-  virtual MediaConduitErrorCode EnableAudioLevelExtension(bool enabled, uint8_t id) = 0;
-  virtual MediaConduitErrorCode EnableMIDExtension(bool enabled, uint8_t id) = 0;
+  virtual MediaConduitErrorCode
+  EnableAudioLevelExtension(bool aEnabled,
+                            uint8_t aId,
+                            bool aDirectionIsSend) = 0;
+  virtual MediaConduitErrorCode
+  EnableMIDExtension(bool enabled, uint8_t id) = 0;
 
   virtual bool SetDtmfPayloadType(unsigned char type, int freq) = 0;
 
   virtual bool InsertDTMFTone(int channel, int eventCode, bool outOfBand,
                               int lengthMs, int attenuationDb) = 0;
 
 };
 }
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -318,27 +318,28 @@ WebrtcVideoConduit::~WebrtcVideoConduit(
 
   // Release AudioConduit first by dropping reference on MainThread, where it expects to be
   SyncTo(nullptr);
   Destroy();
 }
 
 void
 WebrtcVideoConduit::SetLocalRTPExtensions(bool aIsSend,
-  const std::vector<webrtc::RtpExtension> & aExtensions)
+                                          const RtpExtList & aExtensions)
 {
   auto& extList = aIsSend ? mSendStreamConfig.rtp.extensions :
                   mRecvStreamConfig.rtp.extensions;
   extList = aExtensions;
 }
 
-std::vector<webrtc::RtpExtension>
+RtpExtList
 WebrtcVideoConduit::GetLocalRTPExtensions(bool aIsSend) const
 {
-  return aIsSend ? mSendStreamConfig.rtp.extensions : mRecvStreamConfig.rtp.extensions;
+  return aIsSend ? mSendStreamConfig.rtp.extensions :
+                   mRecvStreamConfig.rtp.extensions;
 }
 
 bool WebrtcVideoConduit::SetLocalSSRCs(const std::vector<unsigned int> & aSSRCs)
 {
   // Special case: the local SSRCs are the same - do nothing.
   if (mSendStreamConfig.rtp.ssrcs == aSSRCs) {
     return true;
   }
@@ -542,27 +543,29 @@ ConfigureVideoEncoderSettings(const Vide
   if (aConfig->mName == "H264") {
     webrtc::VideoCodecH264 h264_settings =
         webrtc::VideoEncoder::GetDefaultH264Settings();
     h264_settings.frameDroppingOn = frame_dropping;
     h264_settings.packetizationMode = aConfig->mPacketizationMode;
     return new rtc::RefCountedObject<
         webrtc::VideoEncoderConfig::H264EncoderSpecificSettings>(h264_settings);
 
-  } else if (aConfig->mName == "VP8") {
+  }
+  if (aConfig->mName == "VP8") {
     webrtc::VideoCodecVP8 vp8_settings =
         webrtc::VideoEncoder::GetDefaultVp8Settings();
     vp8_settings.automaticResizeOn = automatic_resize;
     // VP8 denoising is enabled by default.
     vp8_settings.denoisingOn = codec_default_denoising ? true : denoising;
     vp8_settings.frameDroppingOn = frame_dropping;
     return new rtc::RefCountedObject<
         webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
 
-  } else if (aConfig->mName == "VP9") {
+  }
+  if (aConfig->mName == "VP9") {
     webrtc::VideoCodecVP9 vp9_settings =
         webrtc::VideoEncoder::GetDefaultVp9Settings();
     if (is_screencast) {
       // TODO(asapersson): Set to 2 for now since there is a DCHECK in
       // VideoSendStream::ReconfigureVideoEncoder.
       vp9_settings.numberOfSpatialLayers = 2;
     } else {
       vp9_settings.numberOfSpatialLayers = aConduit->SpatialLayers();
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -75,22 +75,21 @@ public:
   /* Default maximum bitrate for video streams. */
   static const uint32_t kDefaultMaxBitrate_bps;
 
   //VoiceEngine defined constant for Payload Name Size.
   static const unsigned int CODEC_PLNAME_SIZE;
 
   /**
   * Add rtp extensions to the the VideoSendStream
-  * TODO(@@NG) promote this the MediaConduitInterface when the VoE rework
-  * hits Webrtc.org.
   */
-  void SetLocalRTPExtensions(bool aIsSend,
-                             const std::vector<webrtc::RtpExtension>& extensions) override;
-  std::vector<webrtc::RtpExtension> GetLocalRTPExtensions(bool aIsSend) const override;
+  void
+  SetLocalRTPExtensions(bool aIsSend, const RtpExtList& extensions) override;
+
+  RtpExtList GetLocalRTPExtensions(bool aIsSend) const override;
 
   /**
    * Set up A/V sync between this (incoming) VideoConduit and an audio conduit.
    */
   void SyncTo(WebrtcAudioConduit *aConduit);
 
   /**
    * Function to attach Renderer end-point for the Media-Video conduit.
--- 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,27 @@ 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/BUILD.gn
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/BUILD.gn
@@ -9,16 +9,17 @@
 import("../../build/webrtc.gni")
 
 rtc_static_library("rtp_rtcp") {
   sources = [
     "include/flexfec_receiver.h",
     "include/flexfec_sender.h",
     "include/receive_statistics.h",
     "include/remote_ntp_time_estimator.h",
+    "include/rtp_audio_level_observer.h",
     "include/rtp_header_parser.h",
     "include/rtp_payload_registry.h",
     "include/rtp_receiver.h",
     "include/rtp_rtcp.h",
     "include/rtp_rtcp_defines.h",
     "include/ulpfec_receiver.h",
     "source/byte_io.h",
     "source/dtmf_queue.cc",
--- 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/rtp_rtcp.gypi
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
@@ -18,16 +18,17 @@
       ],
       'sources': [
         # Common
         'include/fec_receiver.h',
         'include/flexfec_receiver.h',
         'include/flexfec_sender.h',
         'include/receive_statistics.h',
         'include/remote_ntp_time_estimator.h',
+        'include/rtp_audio_level_observer.h',
         'include/rtp_header_parser.h',
         'include/rtp_payload_registry.h',
         'include/rtp_receiver.h',
         'include/rtp_rtcp.h',
         'include/rtp_rtcp_defines.h',
         'source/byte_io.h',
         'source/fec_private_tables_bursty.h',
         'source/fec_private_tables_random.h',
--- 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;