Delete support for VoIP metrics (RFC 3611 4.7)
Bug: None Change-Id: I2f3cd622d3863fa88a9e1971894eced8eeb777e6 Reviewed-on: https://webrtc-review.googlesource.com/c/103805 Commit-Queue: Niels Moller <nisse@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Oskar Sundbom <ossu@webrtc.org> Reviewed-by: Henrik Andreassson <henrika@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25007}
This commit is contained in:
@ -67,30 +67,6 @@ class RTPFragmentationHeader {
|
||||
uint8_t* fragmentationPlType; // Payload type of each fragmentation
|
||||
};
|
||||
|
||||
struct RTCPVoIPMetric {
|
||||
// RFC 3611 4.7
|
||||
uint8_t lossRate;
|
||||
uint8_t discardRate;
|
||||
uint8_t burstDensity;
|
||||
uint8_t gapDensity;
|
||||
uint16_t burstDuration;
|
||||
uint16_t gapDuration;
|
||||
uint16_t roundTripDelay;
|
||||
uint16_t endSystemDelay;
|
||||
uint8_t signalLevel;
|
||||
uint8_t noiseLevel;
|
||||
uint8_t RERL;
|
||||
uint8_t Gmin;
|
||||
uint8_t Rfactor;
|
||||
uint8_t extRfactor;
|
||||
uint8_t MOSLQ;
|
||||
uint8_t MOSCQ;
|
||||
uint8_t RXconfig;
|
||||
uint16_t JBnominal;
|
||||
uint16_t JBmax;
|
||||
uint16_t JBabsMax;
|
||||
};
|
||||
|
||||
// Interface used by the CallStats class to distribute call statistics.
|
||||
// Callbacks will be triggered as soon as the class has been registered to a
|
||||
// CallStats object using RegisterStatsObserver.
|
||||
|
@ -40,7 +40,6 @@ rtc_source_set("rtp_rtcp_format") {
|
||||
"source/rtcp_packet/tmmbn.h",
|
||||
"source/rtcp_packet/tmmbr.h",
|
||||
"source/rtcp_packet/transport_feedback.h",
|
||||
"source/rtcp_packet/voip_metric.h",
|
||||
"source/rtp_generic_frame_descriptor.h",
|
||||
"source/rtp_generic_frame_descriptor_extension.h",
|
||||
"source/rtp_header_extensions.h",
|
||||
@ -75,7 +74,6 @@ rtc_source_set("rtp_rtcp_format") {
|
||||
"source/rtcp_packet/tmmbn.cc",
|
||||
"source/rtcp_packet/tmmbr.cc",
|
||||
"source/rtcp_packet/transport_feedback.cc",
|
||||
"source/rtcp_packet/voip_metric.cc",
|
||||
"source/rtp_generic_frame_descriptor.cc",
|
||||
"source/rtp_generic_frame_descriptor_extension.cc",
|
||||
"source/rtp_header_extension_map.cc",
|
||||
@ -380,7 +378,6 @@ if (rtc_include_tests) {
|
||||
"source/rtcp_packet/tmmbn_unittest.cc",
|
||||
"source/rtcp_packet/tmmbr_unittest.cc",
|
||||
"source/rtcp_packet/transport_feedback_unittest.cc",
|
||||
"source/rtcp_packet/voip_metric_unittest.cc",
|
||||
"source/rtcp_packet_unittest.cc",
|
||||
"source/rtcp_receiver_unittest.cc",
|
||||
"source/rtcp_sender_unittest.cc",
|
||||
|
@ -335,10 +335,6 @@ class RtpRtcp : public Module, public RtcpFeedbackSenderInterface {
|
||||
uint32_t name,
|
||||
const uint8_t* data,
|
||||
uint16_t length) = 0;
|
||||
// (XR) Sets VOIP metric.
|
||||
// Returns -1 on failure else 0.
|
||||
virtual int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) = 0;
|
||||
|
||||
// (XR) Sets Receiver Reference Time Report (RTTR) status.
|
||||
virtual void SetRtcpXrRrtrStatus(bool enable) = 0;
|
||||
|
||||
|
@ -130,7 +130,6 @@ enum RTCPPacketType : uint32_t {
|
||||
kRtcpTmmbr = 0x0100,
|
||||
kRtcpTmmbn = 0x0200,
|
||||
kRtcpSrReq = 0x0400,
|
||||
kRtcpXrVoipMetric = 0x0800,
|
||||
kRtcpApp = 0x1000,
|
||||
kRtcpRemb = 0x10000,
|
||||
kRtcpTransmissionTimeOffset = 0x20000,
|
||||
|
@ -148,7 +148,6 @@ class MockRtpRtcp : public RtpRtcp {
|
||||
uint32_t name,
|
||||
const uint8_t* data,
|
||||
uint16_t length));
|
||||
MOCK_METHOD1(SetRTCPVoIPMetrics, int32_t(const RTCPVoIPMetric* voip_metric));
|
||||
MOCK_METHOD1(SetRtcpXrRrtrStatus, void(bool enable));
|
||||
MOCK_CONST_METHOD0(RtcpXrRrtrStatus, bool());
|
||||
MOCK_METHOD2(SetRemb, void(int64_t bitrate, std::vector<uint32_t> ssrcs));
|
||||
|
@ -56,7 +56,6 @@ bool ExtendedReports::Parse(const CommonHeader& packet) {
|
||||
sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(packet.payload());
|
||||
rrtr_block_.reset();
|
||||
dlrr_block_.ClearItems();
|
||||
voip_metric_block_.reset();
|
||||
target_bitrate_ = absl::nullopt;
|
||||
|
||||
const uint8_t* current_block = packet.payload() + kXrBaseLength;
|
||||
@ -81,9 +80,6 @@ bool ExtendedReports::Parse(const CommonHeader& packet) {
|
||||
case Dlrr::kBlockType:
|
||||
ParseDlrrBlock(current_block, block_length);
|
||||
break;
|
||||
case VoipMetric::kBlockType:
|
||||
ParseVoipMetricBlock(current_block, block_length);
|
||||
break;
|
||||
case TargetBitrate::kBlockType:
|
||||
ParseTargetBitrateBlock(current_block, block_length);
|
||||
break;
|
||||
@ -114,12 +110,6 @@ bool ExtendedReports::AddDlrrItem(const ReceiveTimeInfo& time_info) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExtendedReports::SetVoipMetric(const VoipMetric& voip_metric) {
|
||||
if (voip_metric_block_)
|
||||
RTC_LOG(LS_WARNING) << "Voip metric already set, overwriting.";
|
||||
voip_metric_block_.emplace(voip_metric);
|
||||
}
|
||||
|
||||
void ExtendedReports::SetTargetBitrate(const TargetBitrate& bitrate) {
|
||||
if (target_bitrate_)
|
||||
RTC_LOG(LS_WARNING) << "TargetBitrate already set, overwriting.";
|
||||
@ -129,7 +119,7 @@ void ExtendedReports::SetTargetBitrate(const TargetBitrate& bitrate) {
|
||||
|
||||
size_t ExtendedReports::BlockLength() const {
|
||||
return kHeaderLength + kXrBaseLength + RrtrLength() + DlrrLength() +
|
||||
VoipMetricLength() + TargetBitrateLength();
|
||||
TargetBitrateLength();
|
||||
}
|
||||
|
||||
bool ExtendedReports::Create(uint8_t* packet,
|
||||
@ -153,10 +143,6 @@ bool ExtendedReports::Create(uint8_t* packet,
|
||||
dlrr_block_.Create(packet + *index);
|
||||
*index += dlrr_block_.BlockLength();
|
||||
}
|
||||
if (voip_metric_block_) {
|
||||
voip_metric_block_->Create(packet + *index);
|
||||
*index += VoipMetric::kLength;
|
||||
}
|
||||
if (target_bitrate_) {
|
||||
target_bitrate_->Create(packet + *index);
|
||||
*index += target_bitrate_->BlockLength();
|
||||
@ -197,22 +183,6 @@ void ExtendedReports::ParseDlrrBlock(const uint8_t* block,
|
||||
dlrr_block_.Parse(block, block_length);
|
||||
}
|
||||
|
||||
void ExtendedReports::ParseVoipMetricBlock(const uint8_t* block,
|
||||
uint16_t block_length) {
|
||||
if (block_length != VoipMetric::kBlockLength) {
|
||||
RTC_LOG(LS_WARNING) << "Incorrect voip metric block size " << block_length
|
||||
<< " Should be " << VoipMetric::kBlockLength;
|
||||
return;
|
||||
}
|
||||
if (voip_metric_block_) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Two Voip Metric blocks found in same Extended Report packet";
|
||||
return;
|
||||
}
|
||||
voip_metric_block_.emplace();
|
||||
voip_metric_block_->Parse(block);
|
||||
}
|
||||
|
||||
void ExtendedReports::ParseTargetBitrateBlock(const uint8_t* block,
|
||||
uint16_t block_length) {
|
||||
target_bitrate_.emplace();
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/dlrr.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/rrtr.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace rtcp {
|
||||
@ -40,15 +39,11 @@ class ExtendedReports : public RtcpPacket {
|
||||
|
||||
void SetRrtr(const Rrtr& rrtr);
|
||||
bool AddDlrrItem(const ReceiveTimeInfo& time_info);
|
||||
void SetVoipMetric(const VoipMetric& voip_metric);
|
||||
void SetTargetBitrate(const TargetBitrate& target_bitrate);
|
||||
|
||||
uint32_t sender_ssrc() const { return sender_ssrc_; }
|
||||
const absl::optional<Rrtr>& rrtr() const { return rrtr_block_; }
|
||||
const Dlrr& dlrr() const { return dlrr_block_; }
|
||||
const absl::optional<VoipMetric>& voip_metric() const {
|
||||
return voip_metric_block_;
|
||||
}
|
||||
const absl::optional<TargetBitrate>& target_bitrate() const {
|
||||
return target_bitrate_;
|
||||
}
|
||||
@ -65,9 +60,6 @@ class ExtendedReports : public RtcpPacket {
|
||||
|
||||
size_t RrtrLength() const { return rrtr_block_ ? Rrtr::kLength : 0; }
|
||||
size_t DlrrLength() const { return dlrr_block_.BlockLength(); }
|
||||
size_t VoipMetricLength() const {
|
||||
return voip_metric_block_ ? VoipMetric::kLength : 0;
|
||||
}
|
||||
size_t TargetBitrateLength() const;
|
||||
|
||||
void ParseRrtrBlock(const uint8_t* block, uint16_t block_length);
|
||||
@ -78,7 +70,6 @@ class ExtendedReports : public RtcpPacket {
|
||||
uint32_t sender_ssrc_;
|
||||
absl::optional<Rrtr> rrtr_block_;
|
||||
Dlrr dlrr_block_; // Dlrr without items treated same as no dlrr block.
|
||||
absl::optional<VoipMetric> voip_metric_block_;
|
||||
absl::optional<TargetBitrate> target_bitrate_;
|
||||
};
|
||||
} // namespace rtcp
|
||||
|
@ -23,31 +23,10 @@ using webrtc::rtcp::Dlrr;
|
||||
using webrtc::rtcp::ExtendedReports;
|
||||
using webrtc::rtcp::ReceiveTimeInfo;
|
||||
using webrtc::rtcp::Rrtr;
|
||||
using webrtc::rtcp::VoipMetric;
|
||||
|
||||
namespace webrtc {
|
||||
// Define comparision operators that shouldn't be needed in production,
|
||||
// but make testing matches more clear.
|
||||
bool operator==(const RTCPVoIPMetric& metric1, const RTCPVoIPMetric& metric2) {
|
||||
return metric1.lossRate == metric2.lossRate &&
|
||||
metric1.discardRate == metric2.discardRate &&
|
||||
metric1.burstDensity == metric2.burstDensity &&
|
||||
metric1.gapDensity == metric2.gapDensity &&
|
||||
metric1.burstDuration == metric2.burstDuration &&
|
||||
metric1.gapDuration == metric2.gapDuration &&
|
||||
metric1.roundTripDelay == metric2.roundTripDelay &&
|
||||
metric1.endSystemDelay == metric2.endSystemDelay &&
|
||||
metric1.signalLevel == metric2.signalLevel &&
|
||||
metric1.noiseLevel == metric2.noiseLevel &&
|
||||
metric1.RERL == metric2.RERL && metric1.Gmin == metric2.Gmin &&
|
||||
metric1.Rfactor == metric2.Rfactor &&
|
||||
metric1.extRfactor == metric2.extRfactor &&
|
||||
metric1.MOSLQ == metric2.MOSLQ && metric1.MOSCQ == metric2.MOSCQ &&
|
||||
metric1.RXconfig == metric2.RXconfig &&
|
||||
metric1.JBnominal == metric2.JBnominal &&
|
||||
metric1.JBmax == metric2.JBmax && metric1.JBabsMax == metric2.JBabsMax;
|
||||
}
|
||||
|
||||
namespace rtcp {
|
||||
bool operator==(const Rrtr& rrtr1, const Rrtr& rrtr2) {
|
||||
return rrtr1.ntp() == rrtr2.ntp();
|
||||
@ -57,11 +36,6 @@ bool operator==(const ReceiveTimeInfo& time1, const ReceiveTimeInfo& time2) {
|
||||
return time1.ssrc == time2.ssrc && time1.last_rr == time2.last_rr &&
|
||||
time1.delay_since_last_rr == time2.delay_since_last_rr;
|
||||
}
|
||||
|
||||
bool operator==(const VoipMetric& metric1, const VoipMetric& metric2) {
|
||||
return metric1.ssrc() == metric2.ssrc() &&
|
||||
metric1.voip_metric() == metric2.voip_metric();
|
||||
}
|
||||
} // namespace rtcp
|
||||
|
||||
namespace {
|
||||
@ -106,40 +80,6 @@ Rrtr RtcpPacketExtendedReportsTest::Rand<Rrtr>() {
|
||||
return rrtr;
|
||||
}
|
||||
|
||||
template <>
|
||||
RTCPVoIPMetric RtcpPacketExtendedReportsTest::Rand<RTCPVoIPMetric>() {
|
||||
RTCPVoIPMetric metric;
|
||||
metric.lossRate = Rand<uint8_t>();
|
||||
metric.discardRate = Rand<uint8_t>();
|
||||
metric.burstDensity = Rand<uint8_t>();
|
||||
metric.gapDensity = Rand<uint8_t>();
|
||||
metric.burstDuration = Rand<uint16_t>();
|
||||
metric.gapDuration = Rand<uint16_t>();
|
||||
metric.roundTripDelay = Rand<uint16_t>();
|
||||
metric.endSystemDelay = Rand<uint16_t>();
|
||||
metric.signalLevel = Rand<uint8_t>();
|
||||
metric.noiseLevel = Rand<uint8_t>();
|
||||
metric.RERL = Rand<uint8_t>();
|
||||
metric.Gmin = Rand<uint8_t>();
|
||||
metric.Rfactor = Rand<uint8_t>();
|
||||
metric.extRfactor = Rand<uint8_t>();
|
||||
metric.MOSLQ = Rand<uint8_t>();
|
||||
metric.MOSCQ = Rand<uint8_t>();
|
||||
metric.RXconfig = Rand<uint8_t>();
|
||||
metric.JBnominal = Rand<uint16_t>();
|
||||
metric.JBmax = Rand<uint16_t>();
|
||||
metric.JBabsMax = Rand<uint16_t>();
|
||||
return metric;
|
||||
}
|
||||
|
||||
template <>
|
||||
VoipMetric RtcpPacketExtendedReportsTest::Rand<VoipMetric>() {
|
||||
VoipMetric voip_metric;
|
||||
voip_metric.SetMediaSsrc(Rand<uint32_t>());
|
||||
voip_metric.SetVoipMetric(Rand<RTCPVoIPMetric>());
|
||||
return voip_metric;
|
||||
}
|
||||
|
||||
TEST_F(RtcpPacketExtendedReportsTest, CreateWithoutReportBlocks) {
|
||||
ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
@ -156,7 +96,6 @@ TEST_F(RtcpPacketExtendedReportsTest, ParseWithoutReportBlocks) {
|
||||
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
|
||||
EXPECT_FALSE(parsed.rrtr());
|
||||
EXPECT_FALSE(parsed.dlrr());
|
||||
EXPECT_FALSE(parsed.voip_metric());
|
||||
}
|
||||
|
||||
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithRrtrBlock) {
|
||||
@ -220,33 +159,14 @@ TEST_F(RtcpPacketExtendedReportsTest, CreateLimitsTheNumberOfDlrrSubBlocks) {
|
||||
SizeIs(ExtendedReports::kMaxNumberOfDlrrItems));
|
||||
}
|
||||
|
||||
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithVoipMetric) {
|
||||
const VoipMetric kVoipMetric = Rand<VoipMetric>();
|
||||
|
||||
ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
xr.SetVoipMetric(kVoipMetric);
|
||||
|
||||
rtc::Buffer packet = xr.Build();
|
||||
|
||||
ExtendedReports mparsed;
|
||||
EXPECT_TRUE(test::ParseSinglePacket(packet, &mparsed));
|
||||
const ExtendedReports& parsed = mparsed;
|
||||
|
||||
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
|
||||
EXPECT_EQ(kVoipMetric, parsed.voip_metric());
|
||||
}
|
||||
|
||||
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMaximumReportBlocks) {
|
||||
const Rrtr kRrtr = Rand<Rrtr>();
|
||||
const VoipMetric kVoipMetric = Rand<VoipMetric>();
|
||||
|
||||
ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
xr.SetRrtr(kRrtr);
|
||||
for (size_t i = 0; i < ExtendedReports::kMaxNumberOfDlrrItems; ++i)
|
||||
xr.AddDlrrItem(Rand<ReceiveTimeInfo>());
|
||||
xr.SetVoipMetric(kVoipMetric);
|
||||
|
||||
rtc::Buffer packet = xr.Build();
|
||||
|
||||
@ -258,7 +178,6 @@ TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMaximumReportBlocks) {
|
||||
EXPECT_EQ(kRrtr, parsed.rrtr());
|
||||
EXPECT_THAT(parsed.dlrr().sub_blocks(),
|
||||
ElementsAreArray(xr.dlrr().sub_blocks()));
|
||||
EXPECT_EQ(kVoipMetric, parsed.voip_metric());
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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 "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h"
|
||||
|
||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace rtcp {
|
||||
// VoIP Metrics Report Block (RFC 3611).
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 0 | BT=7 | reserved | block length = 8 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 4 | SSRC of source |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 8 | loss rate | discard rate | burst density | gap density |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 12 | burst duration | gap duration |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 16 | round trip delay | end system delay |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 20 | signal level | noise level | RERL | Gmin |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 24 | R factor | ext. R factor | MOS-LQ | MOS-CQ |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 28 | RX config | reserved | JB nominal |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// 32 | JB maximum | JB abs max |
|
||||
// 36 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
VoipMetric::VoipMetric() : ssrc_(0) {
|
||||
memset(&voip_metric_, 0, sizeof(voip_metric_));
|
||||
}
|
||||
|
||||
void VoipMetric::Parse(const uint8_t* buffer) {
|
||||
RTC_DCHECK(buffer[0] == kBlockType);
|
||||
// reserved = buffer[1];
|
||||
RTC_DCHECK(ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) == kBlockLength);
|
||||
ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
|
||||
voip_metric_.lossRate = buffer[8];
|
||||
voip_metric_.discardRate = buffer[9];
|
||||
voip_metric_.burstDensity = buffer[10];
|
||||
voip_metric_.gapDensity = buffer[11];
|
||||
voip_metric_.burstDuration = ByteReader<uint16_t>::ReadBigEndian(&buffer[12]);
|
||||
voip_metric_.gapDuration = ByteReader<uint16_t>::ReadBigEndian(&buffer[14]);
|
||||
voip_metric_.roundTripDelay =
|
||||
ByteReader<uint16_t>::ReadBigEndian(&buffer[16]);
|
||||
voip_metric_.endSystemDelay =
|
||||
ByteReader<uint16_t>::ReadBigEndian(&buffer[18]);
|
||||
voip_metric_.signalLevel = buffer[20];
|
||||
voip_metric_.noiseLevel = buffer[21];
|
||||
voip_metric_.RERL = buffer[22];
|
||||
voip_metric_.Gmin = buffer[23];
|
||||
voip_metric_.Rfactor = buffer[24];
|
||||
voip_metric_.extRfactor = buffer[25];
|
||||
voip_metric_.MOSLQ = buffer[26];
|
||||
voip_metric_.MOSCQ = buffer[27];
|
||||
voip_metric_.RXconfig = buffer[28];
|
||||
// reserved = buffer[29];
|
||||
voip_metric_.JBnominal = ByteReader<uint16_t>::ReadBigEndian(&buffer[30]);
|
||||
voip_metric_.JBmax = ByteReader<uint16_t>::ReadBigEndian(&buffer[32]);
|
||||
voip_metric_.JBabsMax = ByteReader<uint16_t>::ReadBigEndian(&buffer[34]);
|
||||
}
|
||||
|
||||
void VoipMetric::Create(uint8_t* buffer) const {
|
||||
const uint8_t kReserved = 0;
|
||||
buffer[0] = kBlockType;
|
||||
buffer[1] = kReserved;
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockLength);
|
||||
ByteWriter<uint32_t>::WriteBigEndian(&buffer[4], ssrc_);
|
||||
buffer[8] = voip_metric_.lossRate;
|
||||
buffer[9] = voip_metric_.discardRate;
|
||||
buffer[10] = voip_metric_.burstDensity;
|
||||
buffer[11] = voip_metric_.gapDensity;
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&buffer[12], voip_metric_.burstDuration);
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&buffer[14], voip_metric_.gapDuration);
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&buffer[16],
|
||||
voip_metric_.roundTripDelay);
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&buffer[18],
|
||||
voip_metric_.endSystemDelay);
|
||||
buffer[20] = voip_metric_.signalLevel;
|
||||
buffer[21] = voip_metric_.noiseLevel;
|
||||
buffer[22] = voip_metric_.RERL;
|
||||
buffer[23] = voip_metric_.Gmin;
|
||||
buffer[24] = voip_metric_.Rfactor;
|
||||
buffer[25] = voip_metric_.extRfactor;
|
||||
buffer[26] = voip_metric_.MOSLQ;
|
||||
buffer[27] = voip_metric_.MOSCQ;
|
||||
buffer[28] = voip_metric_.RXconfig;
|
||||
buffer[29] = kReserved;
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&buffer[30], voip_metric_.JBnominal);
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&buffer[32], voip_metric_.JBmax);
|
||||
ByteWriter<uint16_t>::WriteBigEndian(&buffer[34], voip_metric_.JBabsMax);
|
||||
}
|
||||
|
||||
} // namespace rtcp
|
||||
} // namespace webrtc
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_
|
||||
#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_
|
||||
|
||||
#include "modules/include/module_common_types.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace rtcp {
|
||||
|
||||
class VoipMetric {
|
||||
public:
|
||||
static const uint8_t kBlockType = 7;
|
||||
static const uint16_t kBlockLength = 8;
|
||||
static const size_t kLength = 4 * (kBlockLength + 1); // 36
|
||||
VoipMetric();
|
||||
VoipMetric(const VoipMetric&) = default;
|
||||
~VoipMetric() {}
|
||||
|
||||
VoipMetric& operator=(const VoipMetric&) = default;
|
||||
|
||||
void Parse(const uint8_t* buffer);
|
||||
|
||||
// Fills buffer with the VoipMetric.
|
||||
// Consumes VoipMetric::kLength bytes.
|
||||
void Create(uint8_t* buffer) const;
|
||||
|
||||
void SetMediaSsrc(uint32_t ssrc) { ssrc_ = ssrc; }
|
||||
void SetVoipMetric(const RTCPVoIPMetric& voip_metric) {
|
||||
voip_metric_ = voip_metric;
|
||||
}
|
||||
|
||||
uint32_t ssrc() const { return ssrc_; }
|
||||
const RTCPVoIPMetric& voip_metric() const { return voip_metric_; }
|
||||
|
||||
private:
|
||||
uint32_t ssrc_;
|
||||
RTCPVoIPMetric voip_metric_;
|
||||
};
|
||||
|
||||
} // namespace rtcp
|
||||
} // namespace webrtc
|
||||
#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_VOIP_METRIC_H_
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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 "modules/rtp_rtcp/source/rtcp_packet/voip_metric.h"
|
||||
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace rtcp {
|
||||
namespace {
|
||||
|
||||
const uint32_t kRemoteSsrc = 0x23456789;
|
||||
const uint8_t kBlock[] = {0x07, 0x00, 0x00, 0x08, 0x23, 0x45, 0x67, 0x89, 0x01,
|
||||
0x02, 0x03, 0x04, 0x11, 0x12, 0x22, 0x23, 0x33, 0x34,
|
||||
0x44, 0x45, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x00, 0x55, 0x56, 0x66, 0x67, 0x77, 0x78};
|
||||
const size_t kBlockSizeBytes = sizeof(kBlock);
|
||||
static_assert(
|
||||
kBlockSizeBytes == VoipMetric::kLength,
|
||||
"Size of manually created Voip Metric block should match class constant");
|
||||
|
||||
TEST(RtcpPacketVoipMetricTest, Create) {
|
||||
uint8_t buffer[VoipMetric::kLength];
|
||||
RTCPVoIPMetric metric;
|
||||
metric.lossRate = 1;
|
||||
metric.discardRate = 2;
|
||||
metric.burstDensity = 3;
|
||||
metric.gapDensity = 4;
|
||||
metric.burstDuration = 0x1112;
|
||||
metric.gapDuration = 0x2223;
|
||||
metric.roundTripDelay = 0x3334;
|
||||
metric.endSystemDelay = 0x4445;
|
||||
metric.signalLevel = 5;
|
||||
metric.noiseLevel = 6;
|
||||
metric.RERL = 7;
|
||||
metric.Gmin = 8;
|
||||
metric.Rfactor = 9;
|
||||
metric.extRfactor = 10;
|
||||
metric.MOSLQ = 11;
|
||||
metric.MOSCQ = 12;
|
||||
metric.RXconfig = 13;
|
||||
metric.JBnominal = 0x5556;
|
||||
metric.JBmax = 0x6667;
|
||||
metric.JBabsMax = 0x7778;
|
||||
VoipMetric metric_block;
|
||||
metric_block.SetMediaSsrc(kRemoteSsrc);
|
||||
metric_block.SetVoipMetric(metric);
|
||||
|
||||
metric_block.Create(buffer);
|
||||
EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketVoipMetricTest, Parse) {
|
||||
VoipMetric read_metric;
|
||||
read_metric.Parse(kBlock);
|
||||
|
||||
// Run checks on const object to ensure all accessors have const modifier.
|
||||
const VoipMetric& parsed = read_metric;
|
||||
|
||||
EXPECT_EQ(kRemoteSsrc, parsed.ssrc());
|
||||
EXPECT_EQ(1, parsed.voip_metric().lossRate);
|
||||
EXPECT_EQ(2, parsed.voip_metric().discardRate);
|
||||
EXPECT_EQ(3, parsed.voip_metric().burstDensity);
|
||||
EXPECT_EQ(4, parsed.voip_metric().gapDensity);
|
||||
EXPECT_EQ(0x1112, parsed.voip_metric().burstDuration);
|
||||
EXPECT_EQ(0x2223, parsed.voip_metric().gapDuration);
|
||||
EXPECT_EQ(0x3334, parsed.voip_metric().roundTripDelay);
|
||||
EXPECT_EQ(0x4445, parsed.voip_metric().endSystemDelay);
|
||||
EXPECT_EQ(5, parsed.voip_metric().signalLevel);
|
||||
EXPECT_EQ(6, parsed.voip_metric().noiseLevel);
|
||||
EXPECT_EQ(7, parsed.voip_metric().RERL);
|
||||
EXPECT_EQ(8, parsed.voip_metric().Gmin);
|
||||
EXPECT_EQ(9, parsed.voip_metric().Rfactor);
|
||||
EXPECT_EQ(10, parsed.voip_metric().extRfactor);
|
||||
EXPECT_EQ(11, parsed.voip_metric().MOSLQ);
|
||||
EXPECT_EQ(12, parsed.voip_metric().MOSCQ);
|
||||
EXPECT_EQ(13, parsed.voip_metric().RXconfig);
|
||||
EXPECT_EQ(0x5556, parsed.voip_metric().JBnominal);
|
||||
EXPECT_EQ(0x6667, parsed.voip_metric().JBmax);
|
||||
EXPECT_EQ(0x7778, parsed.voip_metric().JBabsMax);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace rtcp
|
||||
} // namespace webrtc
|
@ -689,31 +689,6 @@ TEST_F(RtcpReceiverTest, ExtendedReportsPacketWithZeroReportBlocksIgnored) {
|
||||
InjectRtcpPacket(xr);
|
||||
}
|
||||
|
||||
// VOiP reports are ignored.
|
||||
TEST_F(RtcpReceiverTest, InjectExtendedReportsVoipPacket) {
|
||||
const uint8_t kLossRate = 123;
|
||||
rtcp::VoipMetric voip_metric;
|
||||
voip_metric.SetMediaSsrc(kReceiverMainSsrc);
|
||||
RTCPVoIPMetric metric;
|
||||
metric.lossRate = kLossRate;
|
||||
voip_metric.SetVoipMetric(metric);
|
||||
rtcp::ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
xr.SetVoipMetric(voip_metric);
|
||||
|
||||
InjectRtcpPacket(xr);
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, ExtendedReportsVoipPacketNotToUsIgnored) {
|
||||
rtcp::VoipMetric voip_metric;
|
||||
voip_metric.SetMediaSsrc(kNotToUsSsrc);
|
||||
rtcp::ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
xr.SetVoipMetric(voip_metric);
|
||||
|
||||
InjectRtcpPacket(xr);
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, InjectExtendedReportsReceiverReferenceTimePacket) {
|
||||
const NtpTime kNtp(0x10203, 0x40506);
|
||||
rtcp::Rrtr rrtr;
|
||||
@ -792,13 +767,10 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithMultipleReportBlocks) {
|
||||
rtcp_receiver_.SetRtcpXrRrtrStatus(true);
|
||||
|
||||
rtcp::Rrtr rrtr;
|
||||
rtcp::VoipMetric metric;
|
||||
metric.SetMediaSsrc(kReceiverMainSsrc);
|
||||
rtcp::ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
xr.SetRrtr(rrtr);
|
||||
xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0x12345, 0x67890));
|
||||
xr.SetVoipMetric(metric);
|
||||
|
||||
InjectRtcpPacket(xr);
|
||||
|
||||
@ -813,13 +785,10 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithUnknownReportBlock) {
|
||||
rtcp_receiver_.SetRtcpXrRrtrStatus(true);
|
||||
|
||||
rtcp::Rrtr rrtr;
|
||||
rtcp::VoipMetric metric;
|
||||
metric.SetMediaSsrc(kReceiverMainSsrc);
|
||||
rtcp::ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
xr.SetRrtr(rrtr);
|
||||
xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0x12345, 0x67890));
|
||||
xr.SetVoipMetric(metric);
|
||||
|
||||
rtc::Buffer packet = xr.Build();
|
||||
// Modify the DLRR block to have an unsupported block type, from 5 to 6.
|
||||
|
@ -44,8 +44,8 @@
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
const uint32_t kRtcpAnyExtendedReports =
|
||||
kRtcpXrVoipMetric | kRtcpXrReceiverReferenceTime | kRtcpXrDlrrReportBlock |
|
||||
const uint32_t kRtcpAnyExtendedReports = kRtcpXrReceiverReferenceTime |
|
||||
kRtcpXrDlrrReportBlock |
|
||||
kRtcpXrTargetBitrate;
|
||||
} // namespace
|
||||
|
||||
@ -624,15 +624,6 @@ std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildExtendedReports(
|
||||
send_video_bitrate_allocation_ = false;
|
||||
}
|
||||
|
||||
if (xr_voip_metric_) {
|
||||
rtcp::VoipMetric voip;
|
||||
voip.SetMediaSsrc(remote_ssrc_);
|
||||
voip.SetVoipMetric(*xr_voip_metric_);
|
||||
xr_voip_metric_.reset();
|
||||
|
||||
xr->SetVoipMetric(voip);
|
||||
}
|
||||
|
||||
return std::move(xr);
|
||||
}
|
||||
|
||||
@ -843,15 +834,6 @@ int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(sprang): Remove support for VoIP metrics? (Not used in receiver.)
|
||||
int32_t RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) {
|
||||
rtc::CritScope lock(&critical_section_rtcp_sender_);
|
||||
xr_voip_metric_.emplace(*VoIPMetric);
|
||||
|
||||
SetFlag(kRtcpAnyExtendedReports, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
|
||||
rtc::CritScope lock(&critical_section_rtcp_sender_);
|
||||
xr_send_receiver_reference_time_enabled_ = enable;
|
||||
|
@ -124,7 +124,6 @@ class RTCPSender {
|
||||
uint32_t name,
|
||||
const uint8_t* data,
|
||||
uint16_t length);
|
||||
int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric);
|
||||
|
||||
void SendRtcpXrReceiverReferenceTime(bool enable);
|
||||
|
||||
@ -235,10 +234,6 @@ class RTCPSender {
|
||||
bool xr_send_receiver_reference_time_enabled_
|
||||
RTC_GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
||||
// XR VoIP metric
|
||||
absl::optional<RTCPVoIPMetric> xr_voip_metric_
|
||||
RTC_GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
||||
RtcpPacketTypeCounterObserver* const packet_type_counter_observer_;
|
||||
RtcpPacketTypeCounter packet_type_counter_
|
||||
RTC_GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
@ -399,58 +399,6 @@ TEST_F(RtcpSenderTest, RembIncludedInEachCompoundPacketAfterSet) {
|
||||
EXPECT_EQ(2, parser()->remb()->num_packets());
|
||||
}
|
||||
|
||||
TEST_F(RtcpSenderTest, SendXrWithVoipMetric) {
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
|
||||
RTCPVoIPMetric metric;
|
||||
metric.lossRate = 1;
|
||||
metric.discardRate = 2;
|
||||
metric.burstDensity = 3;
|
||||
metric.gapDensity = 4;
|
||||
metric.burstDuration = 0x1111;
|
||||
metric.gapDuration = 0x2222;
|
||||
metric.roundTripDelay = 0x3333;
|
||||
metric.endSystemDelay = 0x4444;
|
||||
metric.signalLevel = 5;
|
||||
metric.noiseLevel = 6;
|
||||
metric.RERL = 7;
|
||||
metric.Gmin = 8;
|
||||
metric.Rfactor = 9;
|
||||
metric.extRfactor = 10;
|
||||
metric.MOSLQ = 11;
|
||||
metric.MOSCQ = 12;
|
||||
metric.RXconfig = 13;
|
||||
metric.JBnominal = 0x5555;
|
||||
metric.JBmax = 0x6666;
|
||||
metric.JBabsMax = 0x7777;
|
||||
EXPECT_EQ(0, rtcp_sender_->SetRTCPVoIPMetrics(&metric));
|
||||
EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpXrVoipMetric));
|
||||
EXPECT_EQ(1, parser()->xr()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
|
||||
ASSERT_TRUE(parser()->xr()->voip_metric());
|
||||
EXPECT_EQ(kRemoteSsrc, parser()->xr()->voip_metric()->ssrc());
|
||||
const auto& parsed_metric = parser()->xr()->voip_metric()->voip_metric();
|
||||
EXPECT_EQ(metric.lossRate, parsed_metric.lossRate);
|
||||
EXPECT_EQ(metric.discardRate, parsed_metric.discardRate);
|
||||
EXPECT_EQ(metric.burstDensity, parsed_metric.burstDensity);
|
||||
EXPECT_EQ(metric.gapDensity, parsed_metric.gapDensity);
|
||||
EXPECT_EQ(metric.burstDuration, parsed_metric.burstDuration);
|
||||
EXPECT_EQ(metric.gapDuration, parsed_metric.gapDuration);
|
||||
EXPECT_EQ(metric.roundTripDelay, parsed_metric.roundTripDelay);
|
||||
EXPECT_EQ(metric.endSystemDelay, parsed_metric.endSystemDelay);
|
||||
EXPECT_EQ(metric.signalLevel, parsed_metric.signalLevel);
|
||||
EXPECT_EQ(metric.noiseLevel, parsed_metric.noiseLevel);
|
||||
EXPECT_EQ(metric.RERL, parsed_metric.RERL);
|
||||
EXPECT_EQ(metric.Gmin, parsed_metric.Gmin);
|
||||
EXPECT_EQ(metric.Rfactor, parsed_metric.Rfactor);
|
||||
EXPECT_EQ(metric.extRfactor, parsed_metric.extRfactor);
|
||||
EXPECT_EQ(metric.MOSLQ, parsed_metric.MOSLQ);
|
||||
EXPECT_EQ(metric.MOSCQ, parsed_metric.MOSCQ);
|
||||
EXPECT_EQ(metric.RXconfig, parsed_metric.RXconfig);
|
||||
EXPECT_EQ(metric.JBnominal, parsed_metric.JBnominal);
|
||||
EXPECT_EQ(metric.JBmax, parsed_metric.JBmax);
|
||||
EXPECT_EQ(metric.JBabsMax, parsed_metric.JBabsMax);
|
||||
}
|
||||
|
||||
TEST_F(RtcpSenderTest, SendXrWithDlrr) {
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
|
||||
RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
|
||||
@ -504,7 +452,6 @@ TEST_F(RtcpSenderTest, SendXrWithRrtr) {
|
||||
EXPECT_EQ(1, parser()->xr()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
|
||||
EXPECT_FALSE(parser()->xr()->dlrr());
|
||||
EXPECT_FALSE(parser()->xr()->voip_metric());
|
||||
ASSERT_TRUE(parser()->xr()->rrtr());
|
||||
EXPECT_EQ(ntp, parser()->xr()->rrtr()->ntp());
|
||||
}
|
||||
@ -658,10 +605,9 @@ TEST_F(RtcpSenderTest, ByeMustBeLast) {
|
||||
rtcp_sender_->SetTimestampOffset(kStartRtpTimestamp);
|
||||
rtcp_sender_->SetLastRtpTime(kRtpTimestamp, clock_.TimeInMilliseconds());
|
||||
|
||||
// Set up XR VoIP metric to be included with BYE
|
||||
// Set up REMB info to be included with BYE.
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
|
||||
RTCPVoIPMetric metric;
|
||||
EXPECT_EQ(0, rtcp_sender_->SetRTCPVoIPMetrics(&metric));
|
||||
rtcp_sender_->SetRemb(1234, {});
|
||||
EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye));
|
||||
}
|
||||
|
||||
|
@ -526,12 +526,6 @@ int32_t ModuleRtpRtcpImpl::SetRTCPApplicationSpecificData(
|
||||
return rtcp_sender_.SetApplicationSpecificData(sub_type, name, data, length);
|
||||
}
|
||||
|
||||
// (XR) VOIP metric.
|
||||
int32_t ModuleRtpRtcpImpl::SetRTCPVoIPMetrics(
|
||||
const RTCPVoIPMetric* voip_metric) {
|
||||
return rtcp_sender_.SetRTCPVoIPMetrics(voip_metric);
|
||||
}
|
||||
|
||||
void ModuleRtpRtcpImpl::SetRtcpXrRrtrStatus(bool enable) {
|
||||
rtcp_receiver_.SetRtcpXrRrtrStatus(enable);
|
||||
rtcp_sender_.SendRtcpXrReceiverReferenceTime(enable);
|
||||
|
@ -240,9 +240,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp {
|
||||
const uint8_t* data,
|
||||
uint16_t length) override;
|
||||
|
||||
// (XR) VOIP metric.
|
||||
int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) override;
|
||||
|
||||
// (XR) Receiver reference time report.
|
||||
void SetRtcpXrRrtrStatus(bool enable) override;
|
||||
|
||||
|
Reference in New Issue
Block a user