Implement the mixer-to-client per CSRC audio level extension (RFC 6465).

This is loosely based on the similar implementation in gecko.

Bug: webrtc:9965
Change-Id: I5203a05e1c34ca6f97bd1b143790f95ff245e340
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219791
Reviewed-by: Tommi <tommi@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Doudou Kisabaka <doudouk@google.com>
Cr-Commit-Position: refs/heads/master@{#34102}
diff --git a/api/rtp_parameters.h b/api/rtp_parameters.h
index 7fe9f2b..3ecaaf8 100644
--- a/api/rtp_parameters.h
+++ b/api/rtp_parameters.h
@@ -357,6 +357,11 @@
   static constexpr char kVideoFrameTrackingIdUri[] =
       "http://www.webrtc.org/experiments/rtp-hdrext/video-frame-tracking-id";
 
+  // Header extension for Mixer-to-Client audio levels per CSRC as defined in
+  // https://tools.ietf.org/html/rfc6465
+  static constexpr char kCsrcAudioLevelsUri[] =
+      "urn:ietf:params:rtp-hdrext:csrc-audio-level";
+
   // Inclusive min and max IDs for two-byte header extensions and one-byte
   // header extensions, per RFC8285 Section 4.2-4.3.
   static constexpr int kMinId = 1;
diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
index d255320..59c0f29 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -57,6 +57,7 @@
   kRtpExtensionNone,
   kRtpExtensionTransmissionTimeOffset,
   kRtpExtensionAudioLevel,
+  kRtpExtensionCsrcAudioLevel,
   kRtpExtensionInbandComfortNoise,
   kRtpExtensionAbsoluteSendTime,
   kRtpExtensionAbsoluteCaptureTime,
diff --git a/modules/rtp_rtcp/source/rtp_header_extension_map.cc b/modules/rtp_rtcp/source/rtp_header_extension_map.cc
index aebe884..0b5ba47 100644
--- a/modules/rtp_rtcp/source/rtp_header_extension_map.cc
+++ b/modules/rtp_rtcp/source/rtp_header_extension_map.cc
@@ -34,6 +34,7 @@
 constexpr ExtensionInfo kExtensions[] = {
     CreateExtensionInfo<TransmissionOffset>(),
     CreateExtensionInfo<AudioLevel>(),
+    CreateExtensionInfo<CsrcAudioLevel>(),
     CreateExtensionInfo<AbsoluteSendTime>(),
     CreateExtensionInfo<AbsoluteCaptureTimeExtension>(),
     CreateExtensionInfo<VideoOrientation>(),
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.cc b/modules/rtp_rtcp/source/rtp_header_extensions.cc
index 1c3073e..1dd4f54 100644
--- a/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -13,6 +13,7 @@
 #include <string.h>
 
 #include <cmath>
+#include <cstdint>
 #include <limits>
 
 #include "modules/rtp_rtcp/include/rtp_cvo.h"
@@ -186,6 +187,60 @@
   return true;
 }
 
+// An RTP Header Extension for Mixer-to-Client Audio Level Indication
+//
+// https://tools.ietf.org/html/rfc6465
+//
+// The form of the audio level extension 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |  ID   | len=2 |0|   level 1   |0|   level 2   |0|   level 3   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// Sample Audio Level Encoding Using the One-Byte Header Format
+//
+//  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=3     |0|   level 1   |0|   level 2   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |0|   level 3   |    0 (pad)    |               ...             |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// Sample Audio Level Encoding Using the Two-Byte Header Format
+constexpr RTPExtensionType CsrcAudioLevel::kId;
+constexpr uint8_t CsrcAudioLevel::kMaxValueSizeBytes;
+constexpr const char CsrcAudioLevel::kUri[];
+
+bool CsrcAudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
+                           std::vector<uint8_t>* csrc_audio_levels) {
+  if (data.size() > kRtpCsrcSize) {
+    return false;
+  }
+  csrc_audio_levels->resize(data.size());
+  for (size_t i = 0; i < data.size(); i++) {
+    (*csrc_audio_levels)[i] = data[i] & 0x7F;
+  }
+  return true;
+}
+
+size_t CsrcAudioLevel::ValueSize(
+    rtc::ArrayView<const uint8_t> csrc_audio_levels) {
+  return csrc_audio_levels.size();
+}
+
+bool CsrcAudioLevel::Write(rtc::ArrayView<uint8_t> data,
+                           rtc::ArrayView<const uint8_t> csrc_audio_levels) {
+  RTC_CHECK_LE(csrc_audio_levels.size(), kRtpCsrcSize);
+  if (csrc_audio_levels.size() != data.size()) {
+    return false;
+  }
+  for (size_t i = 0; i < csrc_audio_levels.size(); i++) {
+    data[i] = csrc_audio_levels[i] & 0x7F;
+  }
+  return true;
+}
+
 // From RFC 5450: Transmission Time Offsets in RTP Streams.
 //
 // The transmission time is signaled to the receiver in-band using the
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.h b/modules/rtp_rtcp/source/rtp_header_extensions.h
index f6e7a57..b47824a 100644
--- a/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -14,6 +14,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <vector>
 
 #include "api/array_view.h"
 #include "api/rtp_headers.h"
@@ -77,6 +78,20 @@
                     uint8_t audio_level);
 };
 
+class CsrcAudioLevel {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionCsrcAudioLevel;
+  static constexpr uint8_t kMaxValueSizeBytes = 15;
+  static constexpr const char kUri[] =
+      "urn:ietf:params:rtp-hdrext:csrc-audio-level";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    std::vector<uint8_t>* csrc_audio_levels);
+  static size_t ValueSize(rtc::ArrayView<const uint8_t> csrc_audio_levels);
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    rtc::ArrayView<const uint8_t> csrc_audio_levels);
+};
+
 class TransmissionOffset {
  public:
   using value_type = int32_t;
diff --git a/modules/rtp_rtcp/source/rtp_packet.cc b/modules/rtp_rtcp/source/rtp_packet.cc
index 84769d0..ce13b7d 100644
--- a/modules/rtp_rtcp/source/rtp_packet.cc
+++ b/modules/rtp_rtcp/source/rtp_packet.cc
@@ -186,6 +186,7 @@
         break;
       }
       case RTPExtensionType::kRtpExtensionAudioLevel:
+      case RTPExtensionType::kRtpExtensionCsrcAudioLevel:
       case RTPExtensionType::kRtpExtensionAbsoluteCaptureTime:
       case RTPExtensionType::kRtpExtensionColorSpace:
       case RTPExtensionType::kRtpExtensionGenericFrameDescriptor00:
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index 8435e5f..80c319f 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -104,6 +104,7 @@
   switch (type) {
     case kRtpExtensionTransmissionTimeOffset:
     case kRtpExtensionAudioLevel:
+    case kRtpExtensionCsrcAudioLevel:
     case kRtpExtensionAbsoluteSendTime:
     case kRtpExtensionTransportSequenceNumber:
     case kRtpExtensionTransportSequenceNumber02:
diff --git a/modules/rtp_rtcp/source/rtp_utility.cc b/modules/rtp_rtcp/source/rtp_utility.cc
index a22785f..d7df183 100644
--- a/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/modules/rtp_rtcp/source/rtp_utility.cc
@@ -364,6 +364,10 @@
           header->extension.hasTransmissionTimeOffset = true;
           break;
         }
+        case kRtpExtensionCsrcAudioLevel: {
+          RTC_LOG(LS_WARNING) << "Csrc audio level extension not supported";
+          return;
+        }
         case kRtpExtensionAudioLevel: {
           if (len != 0) {
             RTC_LOG(LS_WARNING) << "Incorrect audio level len: " << len;
diff --git a/test/fuzzers/rtp_packet_fuzzer.cc b/test/fuzzers/rtp_packet_fuzzer.cc
index 9e8fd6f..5f649fe 100644
--- a/test/fuzzers/rtp_packet_fuzzer.cc
+++ b/test/fuzzers/rtp_packet_fuzzer.cc
@@ -9,6 +9,7 @@
  */
 
 #include <bitset>
+#include <vector>
 
 #include "absl/types/optional.h"
 #include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
@@ -76,6 +77,11 @@
         uint8_t audio_level;
         packet.GetExtension<AudioLevel>(&voice_activity, &audio_level);
         break;
+      case kRtpExtensionCsrcAudioLevel: {
+        std::vector<uint8_t> audio_levels;
+        packet.GetExtension<CsrcAudioLevel>(&audio_levels);
+        break;
+      }
       case kRtpExtensionAbsoluteSendTime:
         uint32_t sendtime;
         packet.GetExtension<AbsoluteSendTime>(&sendtime);