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}
This commit is contained in:
Doudou Kisabaka 2021-05-24 13:04:45 +02:00 committed by WebRTC LUCI CQ
parent 096ad02c02
commit ae0d117d51
9 changed files with 89 additions and 0 deletions

View File

@ -357,6 +357,11 @@ struct RTC_EXPORT RtpExtension {
static constexpr char kVideoFrameTrackingIdUri[] = static constexpr char kVideoFrameTrackingIdUri[] =
"http://www.webrtc.org/experiments/rtp-hdrext/video-frame-tracking-id"; "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 // Inclusive min and max IDs for two-byte header extensions and one-byte
// header extensions, per RFC8285 Section 4.2-4.3. // header extensions, per RFC8285 Section 4.2-4.3.
static constexpr int kMinId = 1; static constexpr int kMinId = 1;

View File

@ -57,6 +57,7 @@ enum RTPExtensionType : int {
kRtpExtensionNone, kRtpExtensionNone,
kRtpExtensionTransmissionTimeOffset, kRtpExtensionTransmissionTimeOffset,
kRtpExtensionAudioLevel, kRtpExtensionAudioLevel,
kRtpExtensionCsrcAudioLevel,
kRtpExtensionInbandComfortNoise, kRtpExtensionInbandComfortNoise,
kRtpExtensionAbsoluteSendTime, kRtpExtensionAbsoluteSendTime,
kRtpExtensionAbsoluteCaptureTime, kRtpExtensionAbsoluteCaptureTime,

View File

@ -34,6 +34,7 @@ constexpr ExtensionInfo CreateExtensionInfo() {
constexpr ExtensionInfo kExtensions[] = { constexpr ExtensionInfo kExtensions[] = {
CreateExtensionInfo<TransmissionOffset>(), CreateExtensionInfo<TransmissionOffset>(),
CreateExtensionInfo<AudioLevel>(), CreateExtensionInfo<AudioLevel>(),
CreateExtensionInfo<CsrcAudioLevel>(),
CreateExtensionInfo<AbsoluteSendTime>(), CreateExtensionInfo<AbsoluteSendTime>(),
CreateExtensionInfo<AbsoluteCaptureTimeExtension>(), CreateExtensionInfo<AbsoluteCaptureTimeExtension>(),
CreateExtensionInfo<VideoOrientation>(), CreateExtensionInfo<VideoOrientation>(),

View File

@ -13,6 +13,7 @@
#include <string.h> #include <string.h>
#include <cmath> #include <cmath>
#include <cstdint>
#include <limits> #include <limits>
#include "modules/rtp_rtcp/include/rtp_cvo.h" #include "modules/rtp_rtcp/include/rtp_cvo.h"
@ -186,6 +187,60 @@ bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
return true; 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. // From RFC 5450: Transmission Time Offsets in RTP Streams.
// //
// The transmission time is signaled to the receiver in-band using the // The transmission time is signaled to the receiver in-band using the

View File

@ -14,6 +14,7 @@
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <vector>
#include "api/array_view.h" #include "api/array_view.h"
#include "api/rtp_headers.h" #include "api/rtp_headers.h"
@ -77,6 +78,20 @@ class AudioLevel {
uint8_t audio_level); 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 { class TransmissionOffset {
public: public:
using value_type = int32_t; using value_type = int32_t;

View File

@ -186,6 +186,7 @@ void RtpPacket::ZeroMutableExtensions() {
break; break;
} }
case RTPExtensionType::kRtpExtensionAudioLevel: case RTPExtensionType::kRtpExtensionAudioLevel:
case RTPExtensionType::kRtpExtensionCsrcAudioLevel:
case RTPExtensionType::kRtpExtensionAbsoluteCaptureTime: case RTPExtensionType::kRtpExtensionAbsoluteCaptureTime:
case RTPExtensionType::kRtpExtensionColorSpace: case RTPExtensionType::kRtpExtensionColorSpace:
case RTPExtensionType::kRtpExtensionGenericFrameDescriptor00: case RTPExtensionType::kRtpExtensionGenericFrameDescriptor00:

View File

@ -104,6 +104,7 @@ bool IsNonVolatile(RTPExtensionType type) {
switch (type) { switch (type) {
case kRtpExtensionTransmissionTimeOffset: case kRtpExtensionTransmissionTimeOffset:
case kRtpExtensionAudioLevel: case kRtpExtensionAudioLevel:
case kRtpExtensionCsrcAudioLevel:
case kRtpExtensionAbsoluteSendTime: case kRtpExtensionAbsoluteSendTime:
case kRtpExtensionTransportSequenceNumber: case kRtpExtensionTransportSequenceNumber:
case kRtpExtensionTransportSequenceNumber02: case kRtpExtensionTransportSequenceNumber02:

View File

@ -364,6 +364,10 @@ void RtpHeaderParser::ParseOneByteExtensionHeader(
header->extension.hasTransmissionTimeOffset = true; header->extension.hasTransmissionTimeOffset = true;
break; break;
} }
case kRtpExtensionCsrcAudioLevel: {
RTC_LOG(LS_WARNING) << "Csrc audio level extension not supported";
return;
}
case kRtpExtensionAudioLevel: { case kRtpExtensionAudioLevel: {
if (len != 0) { if (len != 0) {
RTC_LOG(LS_WARNING) << "Incorrect audio level len: " << len; RTC_LOG(LS_WARNING) << "Incorrect audio level len: " << len;

View File

@ -9,6 +9,7 @@
*/ */
#include <bitset> #include <bitset>
#include <vector>
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" #include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
@ -76,6 +77,11 @@ void FuzzOneInput(const uint8_t* data, size_t size) {
uint8_t audio_level; uint8_t audio_level;
packet.GetExtension<AudioLevel>(&voice_activity, &audio_level); packet.GetExtension<AudioLevel>(&voice_activity, &audio_level);
break; break;
case kRtpExtensionCsrcAudioLevel: {
std::vector<uint8_t> audio_levels;
packet.GetExtension<CsrcAudioLevel>(&audio_levels);
break;
}
case kRtpExtensionAbsoluteSendTime: case kRtpExtensionAbsoluteSendTime:
uint32_t sendtime; uint32_t sendtime;
packet.GetExtension<AbsoluteSendTime>(&sendtime); packet.GetExtension<AbsoluteSendTime>(&sendtime);