Add RTCP packet types to packet builder:
REMB, TMMBR, TMMBN and extended reports: RRTR, DLRR, VoIP metric. BUG=2450 R=mflodman@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/9299005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6537 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
6568e97d10
commit
3b84b3a58c
@ -13,6 +13,10 @@
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
|
||||
using webrtc::RTCPUtility::kBtDlrr;
|
||||
using webrtc::RTCPUtility::kBtReceiverReferenceTime;
|
||||
using webrtc::RTCPUtility::kBtVoipMetric;
|
||||
|
||||
using webrtc::RTCPUtility::PT_APP;
|
||||
using webrtc::RTCPUtility::PT_BYE;
|
||||
using webrtc::RTCPUtility::PT_IJ;
|
||||
@ -69,6 +73,24 @@ void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
|
||||
*offset += 4;
|
||||
}
|
||||
|
||||
void ComputeMantissaAnd6bitBase2Exponent(uint32_t input_base10,
|
||||
uint8_t bits_mantissa,
|
||||
uint32_t* mantissa,
|
||||
uint8_t* exp) {
|
||||
// input_base10 = mantissa * 2^exp
|
||||
assert(bits_mantissa <= 32);
|
||||
uint32_t mantissa_max = (1 << bits_mantissa) - 1;
|
||||
uint8_t exponent = 0;
|
||||
for (uint32_t i = 0; i < 64; ++i) {
|
||||
if (input_base10 <= (mantissa_max << i)) {
|
||||
exponent = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*exp = exponent;
|
||||
*mantissa = (input_base10 >> exponent);
|
||||
}
|
||||
|
||||
size_t BlockToHeaderLength(size_t length_in_bytes) {
|
||||
// Length in 32-bit words minus 1.
|
||||
assert(length_in_bytes > 0);
|
||||
@ -440,6 +462,264 @@ void CreateFir(const RTCPPacketPSFBFIR& fir,
|
||||
AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
|
||||
AssignUWord24(buffer, pos, 0);
|
||||
}
|
||||
|
||||
void CreateTmmbrItem(const RTCPPacketRTPFBTMMBRItem& tmmbr_item,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
uint32_t bitrate_bps = tmmbr_item.MaxTotalMediaBitRate * 1000;
|
||||
uint32_t mantissa = 0;
|
||||
uint8_t exp = 0;
|
||||
ComputeMantissaAnd6bitBase2Exponent(bitrate_bps, 17, &mantissa, &exp);
|
||||
|
||||
AssignUWord32(buffer, pos, tmmbr_item.SSRC);
|
||||
AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 15) & 0x03));
|
||||
AssignUWord8(buffer, pos, mantissa >> 7);
|
||||
AssignUWord8(buffer, pos, (mantissa << 1) +
|
||||
((tmmbr_item.MeasuredOverhead >> 8) & 0x01));
|
||||
AssignUWord8(buffer, pos, tmmbr_item.MeasuredOverhead);
|
||||
}
|
||||
|
||||
// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104).
|
||||
//
|
||||
// FCI:
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | MxTBR Exp | MxTBR Mantissa |Measured Overhead|
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateTmmbr(const RTCPPacketRTPFBTMMBR& tmmbr,
|
||||
const RTCPPacketRTPFBTMMBRItem& tmmbr_item,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
const uint8_t kFmt = 3;
|
||||
CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, tmmbr.SenderSSRC);
|
||||
AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
|
||||
CreateTmmbrItem(tmmbr_item, buffer, pos);
|
||||
}
|
||||
|
||||
// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104).
|
||||
//
|
||||
// FCI:
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | MxTBR Exp | MxTBR Mantissa |Measured Overhead|
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateTmmbn(const RTCPPacketRTPFBTMMBN& tmmbn,
|
||||
const std::vector<RTCPPacketRTPFBTMMBRItem>& tmmbn_items,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
const uint8_t kFmt = 4;
|
||||
CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, tmmbn.SenderSSRC);
|
||||
AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
|
||||
for (uint8_t i = 0; i < tmmbn_items.size(); ++i) {
|
||||
CreateTmmbrItem(tmmbn_items[i], buffer, pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |V=2|P| FMT=15 | PT=206 | length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC of packet sender |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC of media source |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Unique identifier 'R' 'E' 'M' 'B' |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Num SSRC | BR Exp | BR Mantissa |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC feedback |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ... |
|
||||
|
||||
void CreateRemb(const RTCPPacketPSFBAPP& remb,
|
||||
const RTCPPacketPSFBREMBItem& remb_item,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
uint32_t mantissa = 0;
|
||||
uint8_t exp = 0;
|
||||
ComputeMantissaAnd6bitBase2Exponent(remb_item.BitRate, 18, &mantissa, &exp);
|
||||
|
||||
const uint8_t kFmt = 15;
|
||||
CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, remb.SenderSSRC);
|
||||
AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
|
||||
AssignUWord8(buffer, pos, 'R');
|
||||
AssignUWord8(buffer, pos, 'E');
|
||||
AssignUWord8(buffer, pos, 'M');
|
||||
AssignUWord8(buffer, pos, 'B');
|
||||
AssignUWord8(buffer, pos, remb_item.NumberOfSSRCs);
|
||||
AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 16) & 0x03));
|
||||
AssignUWord8(buffer, pos, mantissa >> 8);
|
||||
AssignUWord8(buffer, pos, mantissa);
|
||||
for (uint8_t i = 0; i < remb_item.NumberOfSSRCs; ++i) {
|
||||
AssignUWord32(buffer, pos, remb_item.SSRCs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
|
||||
//
|
||||
// Format for XR packets:
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |V=2|P|reserved | PT=XR=207 | length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// : report blocks :
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateXrHeader(const RTCPPacketXR& header,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
CreateHeader(0U, PT_XR, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, header.OriginatorSSRC);
|
||||
}
|
||||
|
||||
void CreateXrBlockHeader(uint8_t block_type,
|
||||
uint16_t block_length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
AssignUWord8(buffer, pos, block_type);
|
||||
AssignUWord8(buffer, pos, 0);
|
||||
AssignUWord16(buffer, pos, block_length);
|
||||
}
|
||||
|
||||
// Receiver Reference Time 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | BT=4 | reserved | block length = 2 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | NTP timestamp, most significant word |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | NTP timestamp, least significant word |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateRrtr(const std::vector<RTCPPacketXRReceiverReferenceTimeItem>& rrtrs,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
const uint16_t kBlockLength = 2;
|
||||
for (std::vector<RTCPPacketXRReceiverReferenceTimeItem>::const_iterator it =
|
||||
rrtrs.begin(); it != rrtrs.end(); ++it) {
|
||||
CreateXrBlockHeader(kBtReceiverReferenceTime, kBlockLength, buffer, pos);
|
||||
AssignUWord32(buffer, pos, (*it).NTPMostSignificant);
|
||||
AssignUWord32(buffer, pos, (*it).NTPLeastSignificant);
|
||||
}
|
||||
}
|
||||
|
||||
// DLRR 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | BT=5 | reserved | block length |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | SSRC_1 (SSRC of first receiver) | sub-
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
|
||||
// | last RR (LRR) | 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | delay since last RR (DLRR) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | SSRC_2 (SSRC of second receiver) | sub-
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
|
||||
// : ... : 2
|
||||
|
||||
void CreateDlrr(const std::vector<Xr::DlrrBlock>& dlrrs,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
for (std::vector<Xr::DlrrBlock>::const_iterator it = dlrrs.begin();
|
||||
it != dlrrs.end(); ++it) {
|
||||
if ((*it).empty()) {
|
||||
continue;
|
||||
}
|
||||
uint16_t block_length = 3 * (*it).size();
|
||||
CreateXrBlockHeader(kBtDlrr, block_length, buffer, pos);
|
||||
for (Xr::DlrrBlock::const_iterator it_block = (*it).begin();
|
||||
it_block != (*it).end(); ++it_block) {
|
||||
AssignUWord32(buffer, pos, (*it_block).SSRC);
|
||||
AssignUWord32(buffer, pos, (*it_block).LastRR);
|
||||
AssignUWord32(buffer, pos, (*it_block).DelayLastRR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | BT=7 | reserved | block length = 8 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC of source |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | loss rate | discard rate | burst density | gap density |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | burst duration | gap duration |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | round trip delay | end system delay |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | signal level | noise level | RERL | Gmin |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | R factor | ext. R factor | MOS-LQ | MOS-CQ |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | RX config | reserved | JB nominal |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | JB maximum | JB abs max |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateVoipMetric(const std::vector<RTCPPacketXRVOIPMetricItem>& metrics,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
const uint16_t kBlockLength = 8;
|
||||
for (std::vector<RTCPPacketXRVOIPMetricItem>::const_iterator it =
|
||||
metrics.begin(); it != metrics.end(); ++it) {
|
||||
CreateXrBlockHeader(kBtVoipMetric, kBlockLength, buffer, pos);
|
||||
AssignUWord32(buffer, pos, (*it).SSRC);
|
||||
AssignUWord8(buffer, pos, (*it).lossRate);
|
||||
AssignUWord8(buffer, pos, (*it).discardRate);
|
||||
AssignUWord8(buffer, pos, (*it).burstDensity);
|
||||
AssignUWord8(buffer, pos, (*it).gapDensity);
|
||||
AssignUWord16(buffer, pos, (*it).burstDuration);
|
||||
AssignUWord16(buffer, pos, (*it).gapDuration);
|
||||
AssignUWord16(buffer, pos, (*it).roundTripDelay);
|
||||
AssignUWord16(buffer, pos, (*it).endSystemDelay);
|
||||
AssignUWord8(buffer, pos, (*it).signalLevel);
|
||||
AssignUWord8(buffer, pos, (*it).noiseLevel);
|
||||
AssignUWord8(buffer, pos, (*it).RERL);
|
||||
AssignUWord8(buffer, pos, (*it).Gmin);
|
||||
AssignUWord8(buffer, pos, (*it).Rfactor);
|
||||
AssignUWord8(buffer, pos, (*it).extRfactor);
|
||||
AssignUWord8(buffer, pos, (*it).MOSLQ);
|
||||
AssignUWord8(buffer, pos, (*it).MOSCQ);
|
||||
AssignUWord8(buffer, pos, (*it).RXconfig);
|
||||
AssignUWord8(buffer, pos, 0);
|
||||
AssignUWord16(buffer, pos, (*it).JBnominal);
|
||||
AssignUWord16(buffer, pos, (*it).JBmax);
|
||||
AssignUWord16(buffer, pos, (*it).JBabsMax);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void RtcpPacket::Append(RtcpPacket* packet) {
|
||||
@ -691,5 +971,120 @@ void Fir::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
CreateFir(fir_, fir_item_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
}
|
||||
|
||||
void Remb::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateRemb(remb_, remb_item_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
}
|
||||
|
||||
void Remb::AppliesTo(uint32_t ssrc) {
|
||||
if (remb_item_.NumberOfSSRCs >= kMaxNumberOfSsrcs) {
|
||||
LOG(LS_WARNING) << "Max number of REMB feedback SSRCs reached.";
|
||||
return;
|
||||
}
|
||||
remb_item_.SSRCs[remb_item_.NumberOfSSRCs++] = ssrc;
|
||||
}
|
||||
|
||||
void Tmmbr::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateTmmbr(tmmbr_, tmmbr_item_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
}
|
||||
|
||||
void Tmmbn::WithTmmbr(uint32_t ssrc, uint32_t bitrate_kbps, uint16_t overhead) {
|
||||
assert(overhead <= 0x1ff);
|
||||
if (tmmbn_items_.size() >= kMaxNumberOfTmmbrs) {
|
||||
LOG(LS_WARNING) << "Max TMMBN size reached.";
|
||||
return;
|
||||
}
|
||||
RTCPPacketRTPFBTMMBRItem tmmbn_item;
|
||||
tmmbn_item.SSRC = ssrc;
|
||||
tmmbn_item.MaxTotalMediaBitRate = bitrate_kbps;
|
||||
tmmbn_item.MeasuredOverhead = overhead;
|
||||
tmmbn_items_.push_back(tmmbn_item);
|
||||
}
|
||||
|
||||
void Tmmbn::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateTmmbn(tmmbn_, tmmbn_items_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
}
|
||||
|
||||
void Xr::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateXrHeader(xr_header_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
CreateRrtr(rrtr_blocks_, packet, length);
|
||||
CreateDlrr(dlrr_blocks_, packet, length);
|
||||
CreateVoipMetric(voip_metric_blocks_, packet, length);
|
||||
}
|
||||
|
||||
void Xr::WithRrtr(Rrtr* rrtr) {
|
||||
assert(rrtr);
|
||||
if (rrtr_blocks_.size() >= kMaxNumberOfRrtrBlocks) {
|
||||
LOG(LS_WARNING) << "Max RRTR blocks reached.";
|
||||
return;
|
||||
}
|
||||
rrtr_blocks_.push_back(rrtr->rrtr_block_);
|
||||
}
|
||||
|
||||
void Xr::WithDlrr(Dlrr* dlrr) {
|
||||
assert(dlrr);
|
||||
if (dlrr_blocks_.size() >= kMaxNumberOfDlrrBlocks) {
|
||||
LOG(LS_WARNING) << "Max DLRR blocks reached.";
|
||||
return;
|
||||
}
|
||||
dlrr_blocks_.push_back(dlrr->dlrr_block_);
|
||||
}
|
||||
|
||||
void Xr::WithVoipMetric(VoipMetric* voip_metric) {
|
||||
assert(voip_metric);
|
||||
if (voip_metric_blocks_.size() >= kMaxNumberOfVoipMetricBlocks) {
|
||||
LOG(LS_WARNING) << "Max Voip Metric blocks reached.";
|
||||
return;
|
||||
}
|
||||
voip_metric_blocks_.push_back(voip_metric->metric_);
|
||||
}
|
||||
|
||||
size_t Xr::DlrrLength() const {
|
||||
const size_t kBlockHeaderLen = 4;
|
||||
const size_t kSubBlockLen = 12;
|
||||
size_t length = 0;
|
||||
for (std::vector<DlrrBlock>::const_iterator it = dlrr_blocks_.begin();
|
||||
it != dlrr_blocks_.end(); ++it) {
|
||||
if (!(*it).empty()) {
|
||||
length += kBlockHeaderLen + kSubBlockLen * (*it).size();
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void Dlrr::WithDlrrItem(uint32_t ssrc,
|
||||
uint32_t last_rr,
|
||||
uint32_t delay_last_rr) {
|
||||
if (dlrr_block_.size() >= kMaxNumberOfDlrrItems) {
|
||||
LOG(LS_WARNING) << "Max DLRR items reached.";
|
||||
return;
|
||||
}
|
||||
RTCPPacketXRDLRRReportBlockItem dlrr;
|
||||
dlrr.SSRC = ssrc;
|
||||
dlrr.LastRR = last_rr;
|
||||
dlrr.DelayLastRR = delay_last_rr;
|
||||
dlrr_block_.push_back(dlrr);
|
||||
}
|
||||
|
||||
} // namespace rtcp
|
||||
} // namespace webrtc
|
||||
|
@ -26,7 +26,10 @@ namespace rtcp {
|
||||
enum { kCommonFbFmtLength = 12 };
|
||||
enum { kReportBlockLength = 24 };
|
||||
|
||||
class Dlrr;
|
||||
class RawPacket;
|
||||
class Rrtr;
|
||||
class VoipMetric;
|
||||
|
||||
// Class for building RTCP packets.
|
||||
//
|
||||
@ -82,12 +85,16 @@ class RtcpPacket {
|
||||
|
||||
class Empty : public RtcpPacket {
|
||||
public:
|
||||
Empty() {}
|
||||
Empty() : RtcpPacket() {}
|
||||
|
||||
virtual ~Empty() {}
|
||||
|
||||
protected:
|
||||
virtual void Create(uint8_t* packet, size_t* length, size_t max_length) const;
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(Empty);
|
||||
};
|
||||
|
||||
// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
|
||||
@ -212,6 +219,8 @@ class SenderReport : public RtcpPacket {
|
||||
|
||||
RTCPUtility::RTCPPacketSR sr_;
|
||||
std::vector<RTCPUtility::RTCPPacketReportBlockItem> report_blocks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SenderReport);
|
||||
};
|
||||
|
||||
//
|
||||
@ -254,6 +263,8 @@ class ReceiverReport : public RtcpPacket {
|
||||
|
||||
RTCPUtility::RTCPPacketRR rr_;
|
||||
std::vector<RTCPUtility::RTCPPacketReportBlockItem> report_blocks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ReceiverReport);
|
||||
};
|
||||
|
||||
// Transmission Time Offsets in RTP Streams (RFC 5450).
|
||||
@ -394,6 +405,8 @@ class Bye : public RtcpPacket {
|
||||
|
||||
RTCPUtility::RTCPPacketBYE bye_;
|
||||
std::vector<uint32_t> csrcs_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Bye);
|
||||
};
|
||||
|
||||
// Application-Defined packet (APP) (RFC 3550).
|
||||
@ -660,8 +673,7 @@ class Rpsi : public RtcpPacket {
|
||||
|
||||
class Fir : public RtcpPacket {
|
||||
public:
|
||||
Fir()
|
||||
: RtcpPacket() {
|
||||
Fir() : RtcpPacket() {
|
||||
memset(&fir_, 0, sizeof(fir_));
|
||||
memset(&fir_item_, 0, sizeof(fir_item_));
|
||||
}
|
||||
@ -692,6 +704,354 @@ class Fir : public RtcpPacket {
|
||||
RTCPUtility::RTCPPacketPSFBFIRItem fir_item_;
|
||||
};
|
||||
|
||||
// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104).
|
||||
//
|
||||
// FCI:
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | MxTBR Exp | MxTBR Mantissa |Measured Overhead|
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class Tmmbr : public RtcpPacket {
|
||||
public:
|
||||
Tmmbr() : RtcpPacket() {
|
||||
memset(&tmmbr_, 0, sizeof(tmmbr_));
|
||||
memset(&tmmbr_item_, 0, sizeof(tmmbr_item_));
|
||||
}
|
||||
|
||||
virtual ~Tmmbr() {}
|
||||
|
||||
void From(uint32_t ssrc) {
|
||||
tmmbr_.SenderSSRC = ssrc;
|
||||
}
|
||||
void To(uint32_t ssrc) {
|
||||
tmmbr_item_.SSRC = ssrc;
|
||||
}
|
||||
void WithBitrateKbps(uint32_t bitrate_kbps) {
|
||||
tmmbr_item_.MaxTotalMediaBitRate = bitrate_kbps;
|
||||
}
|
||||
void WithOverhead(uint16_t overhead) {
|
||||
assert(overhead <= 0x1ff);
|
||||
tmmbr_item_.MeasuredOverhead = overhead;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
size_t BlockLength() const {
|
||||
const size_t kFciLen = 8;
|
||||
return kCommonFbFmtLength + kFciLen;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketRTPFBTMMBR tmmbr_;
|
||||
RTCPUtility::RTCPPacketRTPFBTMMBRItem tmmbr_item_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Tmmbr);
|
||||
};
|
||||
|
||||
// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104).
|
||||
//
|
||||
// FCI:
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | MxTBR Exp | MxTBR Mantissa |Measured Overhead|
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class Tmmbn : public RtcpPacket {
|
||||
public:
|
||||
Tmmbn() : RtcpPacket() {
|
||||
memset(&tmmbn_, 0, sizeof(tmmbn_));
|
||||
}
|
||||
|
||||
virtual ~Tmmbn() {}
|
||||
|
||||
void From(uint32_t ssrc) {
|
||||
tmmbn_.SenderSSRC = ssrc;
|
||||
}
|
||||
void WithTmmbr(uint32_t ssrc, uint32_t bitrate_kbps, uint16_t overhead);
|
||||
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
enum { kMaxNumberOfTmmbrs = 50 };
|
||||
|
||||
size_t BlockLength() const {
|
||||
const size_t kFciLen = 8;
|
||||
return kCommonFbFmtLength + kFciLen * tmmbn_items_.size();
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketRTPFBTMMBN tmmbn_;
|
||||
std::vector<RTCPUtility::RTCPPacketRTPFBTMMBRItem> tmmbn_items_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Tmmbn);
|
||||
};
|
||||
|
||||
// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |V=2|P| FMT=15 | PT=206 | length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC of packet sender |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC of media source |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Unique identifier 'R' 'E' 'M' 'B' |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Num SSRC | BR Exp | BR Mantissa |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC feedback |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ...
|
||||
|
||||
class Remb : public RtcpPacket {
|
||||
public:
|
||||
Remb() : RtcpPacket() {
|
||||
memset(&remb_, 0, sizeof(remb_));
|
||||
memset(&remb_item_, 0, sizeof(remb_item_));
|
||||
}
|
||||
|
||||
virtual ~Remb() {}
|
||||
|
||||
void From(uint32_t ssrc) {
|
||||
remb_.SenderSSRC = ssrc;
|
||||
}
|
||||
void AppliesTo(uint32_t ssrc);
|
||||
|
||||
void WithBitrateBps(uint32_t bitrate_bps) {
|
||||
remb_item_.BitRate = bitrate_bps;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
enum { kMaxNumberOfSsrcs = 0xff };
|
||||
|
||||
size_t BlockLength() const {
|
||||
return (remb_item_.NumberOfSSRCs + 5) * 4;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketPSFBAPP remb_;
|
||||
RTCPUtility::RTCPPacketPSFBREMBItem remb_item_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Remb);
|
||||
};
|
||||
|
||||
// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
|
||||
//
|
||||
// Format for XR packets:
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |V=2|P|reserved | PT=XR=207 | length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// : report blocks :
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class Xr : public RtcpPacket {
|
||||
public:
|
||||
typedef std::vector<RTCPUtility::RTCPPacketXRDLRRReportBlockItem> DlrrBlock;
|
||||
Xr() : RtcpPacket() {
|
||||
memset(&xr_header_, 0, sizeof(xr_header_));
|
||||
}
|
||||
|
||||
virtual ~Xr() {}
|
||||
|
||||
void From(uint32_t ssrc) {
|
||||
xr_header_.OriginatorSSRC = ssrc;
|
||||
}
|
||||
void WithRrtr(Rrtr* rrtr);
|
||||
void WithDlrr(Dlrr* dlrr);
|
||||
void WithVoipMetric(VoipMetric* voip_metric);
|
||||
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
enum { kMaxNumberOfRrtrBlocks = 50 };
|
||||
enum { kMaxNumberOfDlrrBlocks = 50 };
|
||||
enum { kMaxNumberOfVoipMetricBlocks = 50 };
|
||||
|
||||
size_t BlockLength() const {
|
||||
const size_t kXrHeaderLength = 8;
|
||||
return kXrHeaderLength + RrtrLength() + DlrrLength() + VoipMetricLength();
|
||||
}
|
||||
|
||||
size_t RrtrLength() const {
|
||||
const size_t kRrtrBlockLength = 12;
|
||||
return kRrtrBlockLength * rrtr_blocks_.size();
|
||||
}
|
||||
|
||||
size_t DlrrLength() const;
|
||||
|
||||
size_t VoipMetricLength() const {
|
||||
const size_t kVoipMetricBlockLength = 36;
|
||||
return kVoipMetricBlockLength * voip_metric_blocks_.size();
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketXR xr_header_;
|
||||
std::vector<RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem> rrtr_blocks_;
|
||||
std::vector<DlrrBlock> dlrr_blocks_;
|
||||
std::vector<RTCPUtility::RTCPPacketXRVOIPMetricItem> voip_metric_blocks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Xr);
|
||||
};
|
||||
|
||||
// Receiver Reference Time 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | BT=4 | reserved | block length = 2 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | NTP timestamp, most significant word |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | NTP timestamp, least significant word |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class Rrtr {
|
||||
public:
|
||||
Rrtr() {
|
||||
memset(&rrtr_block_, 0, sizeof(rrtr_block_));
|
||||
}
|
||||
~Rrtr() {}
|
||||
|
||||
void WithNtpSec(uint32_t sec) {
|
||||
rrtr_block_.NTPMostSignificant = sec;
|
||||
}
|
||||
void WithNtpFrac(uint32_t frac) {
|
||||
rrtr_block_.NTPLeastSignificant = frac;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Xr;
|
||||
RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem rrtr_block_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Rrtr);
|
||||
};
|
||||
|
||||
// DLRR 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | BT=5 | reserved | block length |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | SSRC_1 (SSRC of first receiver) | sub-
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
|
||||
// | last RR (LRR) | 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | delay since last RR (DLRR) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | SSRC_2 (SSRC of second receiver) | sub-
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
|
||||
// : ... : 2
|
||||
|
||||
class Dlrr {
|
||||
public:
|
||||
Dlrr() {}
|
||||
~Dlrr() {}
|
||||
|
||||
void WithDlrrItem(uint32_t ssrc, uint32_t last_rr, uint32_t delay_last_rr);
|
||||
|
||||
private:
|
||||
friend class Xr;
|
||||
enum { kMaxNumberOfDlrrItems = 100 };
|
||||
|
||||
std::vector<RTCPUtility::RTCPPacketXRDLRRReportBlockItem> dlrr_block_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Dlrr);
|
||||
};
|
||||
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | BT=7 | reserved | block length = 8 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC of source |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | loss rate | discard rate | burst density | gap density |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | burst duration | gap duration |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | round trip delay | end system delay |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | signal level | noise level | RERL | Gmin |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | R factor | ext. R factor | MOS-LQ | MOS-CQ |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | RX config | reserved | JB nominal |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | JB maximum | JB abs max |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class VoipMetric {
|
||||
public:
|
||||
VoipMetric() {
|
||||
memset(&metric_, 0, sizeof(metric_));
|
||||
}
|
||||
~VoipMetric() {}
|
||||
|
||||
void To(uint32_t ssrc) { metric_.SSRC = ssrc; }
|
||||
void LossRate(uint8_t loss_rate) { metric_.lossRate = loss_rate; }
|
||||
void DiscardRate(uint8_t discard_rate) { metric_.discardRate = discard_rate; }
|
||||
void BurstDensity(uint8_t burst_density) {
|
||||
metric_.burstDensity = burst_density;
|
||||
}
|
||||
void GapDensity(uint8_t gap_density) { metric_.gapDensity = gap_density; }
|
||||
void BurstDuration(uint16_t burst_duration) {
|
||||
metric_.burstDuration = burst_duration;
|
||||
}
|
||||
void GapDuration(uint16_t gap_duration) {
|
||||
metric_.gapDuration = gap_duration;
|
||||
}
|
||||
void RoundTripDelay(uint16_t round_trip_delay) {
|
||||
metric_.roundTripDelay = round_trip_delay;
|
||||
}
|
||||
void EndSystemDelay(uint16_t end_system_delay) {
|
||||
metric_.endSystemDelay = end_system_delay;
|
||||
}
|
||||
void SignalLevel(uint8_t signal_level) { metric_.signalLevel = signal_level; }
|
||||
void NoiseLevel(uint8_t noise_level) { metric_.noiseLevel = noise_level; }
|
||||
void Rerl(uint8_t rerl) { metric_.RERL = rerl; }
|
||||
void Gmin(uint8_t gmin) { metric_.Gmin = gmin; }
|
||||
void Rfactor(uint8_t rfactor) { metric_.Rfactor = rfactor; }
|
||||
void ExtRfactor(uint8_t extrfactor) { metric_.extRfactor = extrfactor; }
|
||||
void MosLq(uint8_t moslq) { metric_.MOSLQ = moslq; }
|
||||
void MosCq(uint8_t moscq) { metric_.MOSCQ = moscq; }
|
||||
void RxConfig(uint8_t rxconfig) { metric_.RXconfig = rxconfig; }
|
||||
void JbNominal(uint16_t jbnominal) { metric_.JBnominal = jbnominal; }
|
||||
void JbMax(uint16_t jbmax) { metric_.JBmax = jbmax; }
|
||||
void JbAbsMax(uint16_t jbabsmax) { metric_.JBabsMax = jbabsmax; }
|
||||
|
||||
private:
|
||||
friend class Xr;
|
||||
RTCPUtility::RTCPPacketXRVOIPMetricItem metric_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(VoipMetric);
|
||||
};
|
||||
|
||||
// Class holding a RTCP packet.
|
||||
//
|
||||
// Takes a built rtcp packet.
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
using webrtc::rtcp::App;
|
||||
using webrtc::rtcp::Bye;
|
||||
using webrtc::rtcp::Dlrr;
|
||||
using webrtc::rtcp::Empty;
|
||||
using webrtc::rtcp::Fir;
|
||||
using webrtc::rtcp::Ij;
|
||||
@ -27,8 +28,15 @@ using webrtc::rtcp::SenderReport;
|
||||
using webrtc::rtcp::Sli;
|
||||
using webrtc::rtcp::RawPacket;
|
||||
using webrtc::rtcp::ReceiverReport;
|
||||
using webrtc::rtcp::Remb;
|
||||
using webrtc::rtcp::ReportBlock;
|
||||
using webrtc::rtcp::Rpsi;
|
||||
using webrtc::rtcp::Rrtr;
|
||||
using webrtc::rtcp::SenderReport;
|
||||
using webrtc::rtcp::Tmmbn;
|
||||
using webrtc::rtcp::Tmmbr;
|
||||
using webrtc::rtcp::VoipMetric;
|
||||
using webrtc::rtcp::Xr;
|
||||
using webrtc::test::RtcpPacketParser;
|
||||
|
||||
namespace webrtc {
|
||||
@ -589,4 +597,307 @@ TEST(RtcpPacketTest, BuildWithTooSmallBuffer_LastBlockFits) {
|
||||
EXPECT_EQ(0, parser.report_block()->num_packets());
|
||||
EXPECT_EQ(1, parser.fir()->num_packets());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, Remb) {
|
||||
Remb remb;
|
||||
remb.From(kSenderSsrc);
|
||||
remb.AppliesTo(kRemoteSsrc);
|
||||
remb.AppliesTo(kRemoteSsrc + 1);
|
||||
remb.AppliesTo(kRemoteSsrc + 2);
|
||||
remb.WithBitrateBps(261011);
|
||||
|
||||
RawPacket packet = remb.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.psfb_app()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.psfb_app()->Ssrc());
|
||||
EXPECT_EQ(1, parser.remb_item()->num_packets());
|
||||
EXPECT_EQ(261011, parser.remb_item()->last_bitrate_bps());
|
||||
std::vector<uint32_t> ssrcs = parser.remb_item()->last_ssrc_list();
|
||||
EXPECT_EQ(kRemoteSsrc, ssrcs[0]);
|
||||
EXPECT_EQ(kRemoteSsrc + 1, ssrcs[1]);
|
||||
EXPECT_EQ(kRemoteSsrc + 2, ssrcs[2]);
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, Tmmbr) {
|
||||
Tmmbr tmmbr;
|
||||
tmmbr.From(kSenderSsrc);
|
||||
tmmbr.To(kRemoteSsrc);
|
||||
tmmbr.WithBitrateKbps(312);
|
||||
tmmbr.WithOverhead(60);
|
||||
|
||||
RawPacket packet = tmmbr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.tmmbr()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.tmmbr()->Ssrc());
|
||||
EXPECT_EQ(1, parser.tmmbr_item()->num_packets());
|
||||
EXPECT_EQ(312U, parser.tmmbr_item()->BitrateKbps());
|
||||
EXPECT_EQ(60U, parser.tmmbr_item()->Overhead());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, TmmbnWithNoItem) {
|
||||
Tmmbn tmmbn;
|
||||
tmmbn.From(kSenderSsrc);
|
||||
|
||||
RawPacket packet = tmmbn.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.tmmbn()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.tmmbn()->Ssrc());
|
||||
EXPECT_EQ(0, parser.tmmbn_items()->num_packets());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, TmmbnWithOneItem) {
|
||||
Tmmbn tmmbn;
|
||||
tmmbn.From(kSenderSsrc);
|
||||
tmmbn.WithTmmbr(kRemoteSsrc, 312, 60);
|
||||
|
||||
RawPacket packet = tmmbn.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.tmmbn()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.tmmbn()->Ssrc());
|
||||
EXPECT_EQ(1, parser.tmmbn_items()->num_packets());
|
||||
EXPECT_EQ(kRemoteSsrc, parser.tmmbn_items()->Ssrc(0));
|
||||
EXPECT_EQ(312U, parser.tmmbn_items()->BitrateKbps(0));
|
||||
EXPECT_EQ(60U, parser.tmmbn_items()->Overhead(0));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, TmmbnWithTwoItems) {
|
||||
Tmmbn tmmbn;
|
||||
tmmbn.From(kSenderSsrc);
|
||||
tmmbn.WithTmmbr(kRemoteSsrc, 312, 60);
|
||||
tmmbn.WithTmmbr(kRemoteSsrc + 1, 1288, 40);
|
||||
|
||||
RawPacket packet = tmmbn.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.tmmbn()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.tmmbn()->Ssrc());
|
||||
EXPECT_EQ(2, parser.tmmbn_items()->num_packets());
|
||||
EXPECT_EQ(kRemoteSsrc, parser.tmmbn_items()->Ssrc(0));
|
||||
EXPECT_EQ(312U, parser.tmmbn_items()->BitrateKbps(0));
|
||||
EXPECT_EQ(60U, parser.tmmbn_items()->Overhead(0));
|
||||
EXPECT_EQ(kRemoteSsrc + 1, parser.tmmbn_items()->Ssrc(1));
|
||||
EXPECT_EQ(1288U, parser.tmmbn_items()->BitrateKbps(1));
|
||||
EXPECT_EQ(40U, parser.tmmbn_items()->Overhead(1));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, XrWithNoReportBlocks) {
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, XrWithRrtr) {
|
||||
Rrtr rrtr;
|
||||
rrtr.WithNtpSec(0x11111111);
|
||||
rrtr.WithNtpFrac(0x22222222);
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
xr.WithRrtr(&rrtr);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
EXPECT_EQ(1, parser.rrtr()->num_packets());
|
||||
EXPECT_EQ(0x11111111U, parser.rrtr()->NtpSec());
|
||||
EXPECT_EQ(0x22222222U, parser.rrtr()->NtpFrac());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, XrWithTwoRrtrBlocks) {
|
||||
Rrtr rrtr1;
|
||||
rrtr1.WithNtpSec(0x11111111);
|
||||
rrtr1.WithNtpFrac(0x22222222);
|
||||
Rrtr rrtr2;
|
||||
rrtr2.WithNtpSec(0x33333333);
|
||||
rrtr2.WithNtpFrac(0x44444444);
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
xr.WithRrtr(&rrtr1);
|
||||
xr.WithRrtr(&rrtr2);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
EXPECT_EQ(2, parser.rrtr()->num_packets());
|
||||
EXPECT_EQ(0x33333333U, parser.rrtr()->NtpSec());
|
||||
EXPECT_EQ(0x44444444U, parser.rrtr()->NtpFrac());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, XrWithDlrrWithOneSubBlock) {
|
||||
Dlrr dlrr;
|
||||
dlrr.WithDlrrItem(0x11111111, 0x22222222, 0x33333333);
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
xr.WithDlrr(&dlrr);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
EXPECT_EQ(1, parser.dlrr()->num_packets());
|
||||
EXPECT_EQ(1, parser.dlrr_items()->num_packets());
|
||||
EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
|
||||
EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
|
||||
EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, XrWithDlrrWithTwoSubBlocks) {
|
||||
Dlrr dlrr;
|
||||
dlrr.WithDlrrItem(0x11111111, 0x22222222, 0x33333333);
|
||||
dlrr.WithDlrrItem(0x44444444, 0x55555555, 0x66666666);
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
xr.WithDlrr(&dlrr);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
EXPECT_EQ(1, parser.dlrr()->num_packets());
|
||||
EXPECT_EQ(2, parser.dlrr_items()->num_packets());
|
||||
EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
|
||||
EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
|
||||
EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
|
||||
EXPECT_EQ(0x44444444U, parser.dlrr_items()->Ssrc(1));
|
||||
EXPECT_EQ(0x55555555U, parser.dlrr_items()->LastRr(1));
|
||||
EXPECT_EQ(0x66666666U, parser.dlrr_items()->DelayLastRr(1));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, XrWithTwoDlrrBlocks) {
|
||||
Dlrr dlrr1;
|
||||
dlrr1.WithDlrrItem(0x11111111, 0x22222222, 0x33333333);
|
||||
Dlrr dlrr2;
|
||||
dlrr2.WithDlrrItem(0x44444444, 0x55555555, 0x66666666);
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
xr.WithDlrr(&dlrr1);
|
||||
xr.WithDlrr(&dlrr2);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
EXPECT_EQ(2, parser.dlrr()->num_packets());
|
||||
EXPECT_EQ(2, parser.dlrr_items()->num_packets());
|
||||
EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
|
||||
EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
|
||||
EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
|
||||
EXPECT_EQ(0x44444444U, parser.dlrr_items()->Ssrc(1));
|
||||
EXPECT_EQ(0x55555555U, parser.dlrr_items()->LastRr(1));
|
||||
EXPECT_EQ(0x66666666U, parser.dlrr_items()->DelayLastRr(1));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, XrWithVoipMetric) {
|
||||
VoipMetric metric;
|
||||
metric.To(kRemoteSsrc);
|
||||
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);
|
||||
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
xr.WithVoipMetric(&metric);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
EXPECT_EQ(1, parser.voip_metric()->num_packets());
|
||||
EXPECT_EQ(kRemoteSsrc, parser.voip_metric()->Ssrc());
|
||||
EXPECT_EQ(1, parser.voip_metric()->LossRate());
|
||||
EXPECT_EQ(2, parser.voip_metric()->DiscardRate());
|
||||
EXPECT_EQ(3, parser.voip_metric()->BurstDensity());
|
||||
EXPECT_EQ(4, parser.voip_metric()->GapDensity());
|
||||
EXPECT_EQ(0x1111, parser.voip_metric()->BurstDuration());
|
||||
EXPECT_EQ(0x2222, parser.voip_metric()->GapDuration());
|
||||
EXPECT_EQ(0x3333, parser.voip_metric()->RoundTripDelay());
|
||||
EXPECT_EQ(0x4444, parser.voip_metric()->EndSystemDelay());
|
||||
EXPECT_EQ(5, parser.voip_metric()->SignalLevel());
|
||||
EXPECT_EQ(6, parser.voip_metric()->NoiseLevel());
|
||||
EXPECT_EQ(7, parser.voip_metric()->Rerl());
|
||||
EXPECT_EQ(8, parser.voip_metric()->Gmin());
|
||||
EXPECT_EQ(9, parser.voip_metric()->Rfactor());
|
||||
EXPECT_EQ(10, parser.voip_metric()->ExtRfactor());
|
||||
EXPECT_EQ(11, parser.voip_metric()->MosLq());
|
||||
EXPECT_EQ(12, parser.voip_metric()->MosCq());
|
||||
EXPECT_EQ(13, parser.voip_metric()->RxConfig());
|
||||
EXPECT_EQ(0x5555, parser.voip_metric()->JbNominal());
|
||||
EXPECT_EQ(0x6666, parser.voip_metric()->JbMax());
|
||||
EXPECT_EQ(0x7777, parser.voip_metric()->JbAbsMax());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, XrWithMultipleReportBlocks) {
|
||||
Rrtr rrtr;
|
||||
Dlrr dlrr;
|
||||
dlrr.WithDlrrItem(1, 2, 3);
|
||||
VoipMetric metric;
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
xr.WithRrtr(&rrtr);
|
||||
xr.WithDlrr(&dlrr);
|
||||
xr.WithVoipMetric(&metric);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
EXPECT_EQ(1, parser.rrtr()->num_packets());
|
||||
EXPECT_EQ(1, parser.dlrr()->num_packets());
|
||||
EXPECT_EQ(1, parser.dlrr_items()->num_packets());
|
||||
EXPECT_EQ(1, parser.voip_metric()->num_packets());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, DlrrWithoutItemNotIncludedInPacket) {
|
||||
Rrtr rrtr;
|
||||
Dlrr dlrr;
|
||||
VoipMetric metric;
|
||||
Xr xr;
|
||||
xr.From(kSenderSsrc);
|
||||
xr.WithRrtr(&rrtr);
|
||||
xr.WithDlrr(&dlrr);
|
||||
xr.WithVoipMetric(&metric);
|
||||
|
||||
RawPacket packet = xr.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.xr_header()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
|
||||
EXPECT_EQ(1, parser.rrtr()->num_packets());
|
||||
EXPECT_EQ(0, parser.dlrr()->num_packets());
|
||||
EXPECT_EQ(1, parser.voip_metric()->num_packets());
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
@ -80,6 +80,41 @@ void RtcpPacketParser::Parse(const void *data, int len) {
|
||||
case RTCPUtility::kRtcpRtpfbNackItemCode:
|
||||
nack_item_.Set(parser.Packet().NACKItem);
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbAppCode:
|
||||
psfb_app_.Set(parser.Packet().PSFBAPP);
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbRembItemCode:
|
||||
remb_item_.Set(parser.Packet().REMBItem);
|
||||
break;
|
||||
case RTCPUtility::kRtcpRtpfbTmmbrCode:
|
||||
tmmbr_.Set(parser.Packet().TMMBR);
|
||||
break;
|
||||
case RTCPUtility::kRtcpRtpfbTmmbrItemCode:
|
||||
tmmbr_item_.Set(parser.Packet().TMMBRItem);
|
||||
break;
|
||||
case RTCPUtility::kRtcpRtpfbTmmbnCode:
|
||||
tmmbn_.Set(parser.Packet().TMMBN);
|
||||
tmmbn_items_.Clear();
|
||||
break;
|
||||
case RTCPUtility::kRtcpRtpfbTmmbnItemCode:
|
||||
tmmbn_items_.Set(parser.Packet().TMMBNItem);
|
||||
break;
|
||||
case RTCPUtility::kRtcpXrHeaderCode:
|
||||
xr_header_.Set(parser.Packet().XR);
|
||||
dlrr_items_.Clear();
|
||||
break;
|
||||
case RTCPUtility::kRtcpXrReceiverReferenceTimeCode:
|
||||
rrtr_.Set(parser.Packet().XRReceiverReferenceTimeItem);
|
||||
break;
|
||||
case RTCPUtility::kRtcpXrDlrrReportBlockCode:
|
||||
dlrr_.Set();
|
||||
break;
|
||||
case RTCPUtility::kRtcpXrDlrrReportBlockItemCode:
|
||||
dlrr_items_.Set(parser.Packet().XRDLRRReportBlockItem);
|
||||
break;
|
||||
case RTCPUtility::kRtcpXrVoipMetricCode:
|
||||
voip_metric_.Set(parser.Packet().XRVOIPMetricItem);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -378,6 +378,254 @@ class NackItem : public PacketType {
|
||||
std::vector<uint16_t> last_nack_list_;
|
||||
};
|
||||
|
||||
class PsfbApp : public PacketType {
|
||||
public:
|
||||
PsfbApp() {}
|
||||
virtual ~PsfbApp() {}
|
||||
|
||||
uint32_t Ssrc() const { return psfb_app_.SenderSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketPSFBAPP& psfb_app) {
|
||||
psfb_app_ = psfb_app;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketPSFBAPP psfb_app_;
|
||||
};
|
||||
|
||||
class RembItem : public PacketType {
|
||||
public:
|
||||
RembItem() : last_bitrate_bps_(0) {}
|
||||
virtual ~RembItem() {}
|
||||
|
||||
int last_bitrate_bps() const { return last_bitrate_bps_; }
|
||||
std::vector<uint32_t> last_ssrc_list() {
|
||||
return last_ssrc_list_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketPSFBREMBItem& remb_item) {
|
||||
last_bitrate_bps_ = remb_item.BitRate;
|
||||
last_ssrc_list_.clear();
|
||||
last_ssrc_list_.insert(
|
||||
last_ssrc_list_.end(),
|
||||
remb_item.SSRCs,
|
||||
remb_item.SSRCs + remb_item.NumberOfSSRCs);
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
uint32_t last_bitrate_bps_;
|
||||
std::vector<uint32_t> last_ssrc_list_;
|
||||
};
|
||||
|
||||
class Tmmbr : public PacketType {
|
||||
public:
|
||||
Tmmbr() {}
|
||||
virtual ~Tmmbr() {}
|
||||
|
||||
uint32_t Ssrc() const { return tmmbr_.SenderSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketRTPFBTMMBR& tmmbr) {
|
||||
tmmbr_ = tmmbr;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketRTPFBTMMBR tmmbr_;
|
||||
};
|
||||
|
||||
class TmmbrItem : public PacketType {
|
||||
public:
|
||||
TmmbrItem() {}
|
||||
virtual ~TmmbrItem() {}
|
||||
|
||||
uint32_t Ssrc() const { return tmmbr_item_.SSRC; }
|
||||
uint32_t BitrateKbps() const { return tmmbr_item_.MaxTotalMediaBitRate; }
|
||||
uint32_t Overhead() const { return tmmbr_item_.MeasuredOverhead; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketRTPFBTMMBRItem& tmmbr_item) {
|
||||
tmmbr_item_ = tmmbr_item;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketRTPFBTMMBRItem tmmbr_item_;
|
||||
};
|
||||
|
||||
|
||||
class Tmmbn : public PacketType {
|
||||
public:
|
||||
Tmmbn() {}
|
||||
virtual ~Tmmbn() {}
|
||||
|
||||
uint32_t Ssrc() const { return tmmbn_.SenderSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketRTPFBTMMBN& tmmbn) {
|
||||
tmmbn_ = tmmbn;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketRTPFBTMMBN tmmbn_;
|
||||
};
|
||||
|
||||
class TmmbnItems : public PacketType {
|
||||
public:
|
||||
TmmbnItems() {}
|
||||
virtual ~TmmbnItems() {}
|
||||
|
||||
uint32_t Ssrc(uint8_t num) const {
|
||||
assert(num < tmmbns_.size());
|
||||
return tmmbns_[num].SSRC;
|
||||
}
|
||||
uint32_t BitrateKbps(uint8_t num) const {
|
||||
assert(num < tmmbns_.size());
|
||||
return tmmbns_[num].MaxTotalMediaBitRate;
|
||||
}
|
||||
uint32_t Overhead(uint8_t num) const {
|
||||
assert(num < tmmbns_.size());
|
||||
return tmmbns_[num].MeasuredOverhead;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketRTPFBTMMBNItem& tmmbn_item) {
|
||||
tmmbns_.push_back(tmmbn_item);
|
||||
++num_packets_;
|
||||
}
|
||||
void Clear() { tmmbns_.clear(); }
|
||||
|
||||
std::vector<RTCPUtility::RTCPPacketRTPFBTMMBNItem> tmmbns_;
|
||||
};
|
||||
|
||||
class XrHeader : public PacketType {
|
||||
public:
|
||||
XrHeader() {}
|
||||
virtual ~XrHeader() {}
|
||||
|
||||
uint32_t Ssrc() const { return xr_header_.OriginatorSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketXR& xr_header) {
|
||||
xr_header_ = xr_header;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketXR xr_header_;
|
||||
};
|
||||
|
||||
class Rrtr : public PacketType {
|
||||
public:
|
||||
Rrtr() {}
|
||||
virtual ~Rrtr() {}
|
||||
|
||||
uint32_t NtpSec() const { return rrtr_.NTPMostSignificant; }
|
||||
uint32_t NtpFrac() const { return rrtr_.NTPLeastSignificant; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem& rrtr) {
|
||||
rrtr_ = rrtr;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem rrtr_;
|
||||
};
|
||||
|
||||
class Dlrr : public PacketType {
|
||||
public:
|
||||
Dlrr() {}
|
||||
virtual ~Dlrr() {}
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set() { ++num_packets_; }
|
||||
};
|
||||
|
||||
class DlrrItems : public PacketType {
|
||||
public:
|
||||
DlrrItems() {}
|
||||
virtual ~DlrrItems() {}
|
||||
|
||||
uint32_t Ssrc(uint8_t num) const {
|
||||
assert(num < dlrrs_.size());
|
||||
return dlrrs_[num].SSRC;
|
||||
}
|
||||
uint32_t LastRr(uint8_t num) const {
|
||||
assert(num < dlrrs_.size());
|
||||
return dlrrs_[num].LastRR;
|
||||
}
|
||||
uint32_t DelayLastRr(uint8_t num) const {
|
||||
assert(num < dlrrs_.size());
|
||||
return dlrrs_[num].DelayLastRR;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketXRDLRRReportBlockItem& dlrr) {
|
||||
dlrrs_.push_back(dlrr);
|
||||
++num_packets_;
|
||||
}
|
||||
void Clear() { dlrrs_.clear(); }
|
||||
|
||||
std::vector<RTCPUtility::RTCPPacketXRDLRRReportBlockItem> dlrrs_;
|
||||
};
|
||||
|
||||
class VoipMetric : public PacketType {
|
||||
public:
|
||||
VoipMetric() {}
|
||||
virtual ~VoipMetric() {}
|
||||
|
||||
uint32_t Ssrc() const { return voip_metric_.SSRC; }
|
||||
uint8_t LossRate() { return voip_metric_.lossRate; }
|
||||
uint8_t DiscardRate() { return voip_metric_.discardRate; }
|
||||
uint8_t BurstDensity() { return voip_metric_.burstDensity; }
|
||||
uint8_t GapDensity() { return voip_metric_.gapDensity; }
|
||||
uint16_t BurstDuration() { return voip_metric_.burstDuration; }
|
||||
uint16_t GapDuration() { return voip_metric_.gapDuration; }
|
||||
uint16_t RoundTripDelay() { return voip_metric_.roundTripDelay; }
|
||||
uint16_t EndSystemDelay() { return voip_metric_.endSystemDelay; }
|
||||
uint8_t SignalLevel() { return voip_metric_.signalLevel; }
|
||||
uint8_t NoiseLevel() { return voip_metric_.noiseLevel; }
|
||||
uint8_t Rerl() { return voip_metric_.RERL; }
|
||||
uint8_t Gmin() { return voip_metric_.Gmin; }
|
||||
uint8_t Rfactor() { return voip_metric_.Rfactor; }
|
||||
uint8_t ExtRfactor() { return voip_metric_.extRfactor; }
|
||||
uint8_t MosLq() { return voip_metric_.MOSLQ; }
|
||||
uint8_t MosCq() { return voip_metric_.MOSCQ; }
|
||||
uint8_t RxConfig() { return voip_metric_.RXconfig; }
|
||||
uint16_t JbNominal() { return voip_metric_.JBnominal; }
|
||||
uint16_t JbMax() { return voip_metric_.JBmax; }
|
||||
uint16_t JbAbsMax() { return voip_metric_.JBabsMax; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketXRVOIPMetricItem& voip_metric) {
|
||||
voip_metric_ = voip_metric;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketXRVOIPMetricItem voip_metric_;
|
||||
};
|
||||
|
||||
class RtcpPacketParser {
|
||||
public:
|
||||
RtcpPacketParser();
|
||||
@ -403,6 +651,17 @@ class RtcpPacketParser {
|
||||
FirItem* fir_item() { return &fir_item_; }
|
||||
Nack* nack() { return &nack_; }
|
||||
NackItem* nack_item() { return &nack_item_; }
|
||||
PsfbApp* psfb_app() { return &psfb_app_; }
|
||||
RembItem* remb_item() { return &remb_item_; }
|
||||
Tmmbr* tmmbr() { return &tmmbr_; }
|
||||
TmmbrItem* tmmbr_item() { return &tmmbr_item_; }
|
||||
Tmmbn* tmmbn() { return &tmmbn_; }
|
||||
TmmbnItems* tmmbn_items() { return &tmmbn_items_; }
|
||||
XrHeader* xr_header() { return &xr_header_; }
|
||||
Rrtr* rrtr() { return &rrtr_; }
|
||||
Dlrr* dlrr() { return &dlrr_; }
|
||||
DlrrItems* dlrr_items() { return &dlrr_items_; }
|
||||
VoipMetric* voip_metric() { return &voip_metric_; }
|
||||
|
||||
int report_blocks_per_ssrc(uint32_t ssrc) {
|
||||
return report_blocks_per_ssrc_[ssrc];
|
||||
@ -427,6 +686,17 @@ class RtcpPacketParser {
|
||||
FirItem fir_item_;
|
||||
Nack nack_;
|
||||
NackItem nack_item_;
|
||||
PsfbApp psfb_app_;
|
||||
RembItem remb_item_;
|
||||
Tmmbr tmmbr_;
|
||||
TmmbrItem tmmbr_item_;
|
||||
Tmmbn tmmbn_;
|
||||
TmmbnItems tmmbn_items_;
|
||||
XrHeader xr_header_;
|
||||
Rrtr rrtr_;
|
||||
Dlrr dlrr_;
|
||||
DlrrItems dlrr_items_;
|
||||
VoipMetric voip_metric_;
|
||||
|
||||
std::map<uint32_t, int> report_blocks_per_ssrc_;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user