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);