Add SDES, APP, IJ, SLI and PLI packet types to RTCP packet class.
BUG=2450 R=mflodman@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/19559004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6449 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
27626a6256
commit
4b12d40008
@ -13,21 +13,39 @@
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
|
||||
using webrtc::RTCPUtility::PT_APP;
|
||||
using webrtc::RTCPUtility::PT_BYE;
|
||||
using webrtc::RTCPUtility::PT_IJ;
|
||||
using webrtc::RTCPUtility::PT_PSFB;
|
||||
using webrtc::RTCPUtility::PT_RR;
|
||||
using webrtc::RTCPUtility::PT_RTPFB;
|
||||
using webrtc::RTCPUtility::PT_SDES;
|
||||
using webrtc::RTCPUtility::PT_SR;
|
||||
using webrtc::RTCPUtility::PT_XR;
|
||||
|
||||
using webrtc::RTCPUtility::RTCPPacketAPP;
|
||||
using webrtc::RTCPUtility::RTCPPacketBYE;
|
||||
using webrtc::RTCPUtility::RTCPPacketPSFBAPP;
|
||||
using webrtc::RTCPUtility::RTCPPacketPSFBFIR;
|
||||
using webrtc::RTCPUtility::RTCPPacketPSFBFIRItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketPSFBPLI;
|
||||
using webrtc::RTCPUtility::RTCPPacketPSFBREMBItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketPSFBRPSI;
|
||||
using webrtc::RTCPUtility::RTCPPacketPSFBSLI;
|
||||
using webrtc::RTCPUtility::RTCPPacketPSFBSLIItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketReportBlockItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketRR;
|
||||
using webrtc::RTCPUtility::RTCPPacketRTPFBNACK;
|
||||
using webrtc::RTCPUtility::RTCPPacketRTPFBNACKItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBN;
|
||||
using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBNItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBR;
|
||||
using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBRItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketSR;
|
||||
using webrtc::RTCPUtility::RTCPPacketXRDLRRReportBlockItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem;
|
||||
using webrtc::RTCPUtility::RTCPPacketXR;
|
||||
using webrtc::RTCPUtility::RTCPPacketXRVOIPMetricItem;
|
||||
|
||||
namespace webrtc {
|
||||
namespace rtcp {
|
||||
@ -35,23 +53,23 @@ namespace {
|
||||
// Unused SSRC of media source, set to 0.
|
||||
const uint32_t kUnusedMediaSourceSsrc0 = 0;
|
||||
|
||||
void AssignUWord8(uint8_t* buffer, uint16_t* offset, uint8_t value) {
|
||||
void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) {
|
||||
buffer[(*offset)++] = value;
|
||||
}
|
||||
void AssignUWord16(uint8_t* buffer, uint16_t* offset, uint16_t value) {
|
||||
void AssignUWord16(uint8_t* buffer, size_t* offset, uint16_t value) {
|
||||
ModuleRTPUtility::AssignUWord16ToBuffer(buffer + *offset, value);
|
||||
*offset += 2;
|
||||
}
|
||||
void AssignUWord24(uint8_t* buffer, uint16_t* offset, uint32_t value) {
|
||||
void AssignUWord24(uint8_t* buffer, size_t* offset, uint32_t value) {
|
||||
ModuleRTPUtility::AssignUWord24ToBuffer(buffer + *offset, value);
|
||||
*offset += 3;
|
||||
}
|
||||
void AssignUWord32(uint8_t* buffer, uint16_t* offset, uint32_t value) {
|
||||
void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
|
||||
ModuleRTPUtility::AssignUWord32ToBuffer(buffer + *offset, value);
|
||||
*offset += 4;
|
||||
}
|
||||
|
||||
uint16_t BlockToHeaderLength(uint16_t length_in_bytes) {
|
||||
size_t BlockToHeaderLength(size_t length_in_bytes) {
|
||||
// Length in 32-bit words minus 1.
|
||||
assert(length_in_bytes > 0);
|
||||
assert(length_in_bytes % 4 == 0);
|
||||
@ -69,9 +87,10 @@ uint16_t BlockToHeaderLength(uint16_t length_in_bytes) {
|
||||
|
||||
void CreateHeader(uint8_t count_or_format, // Depends on packet type.
|
||||
uint8_t packet_type,
|
||||
uint16_t length,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
size_t* pos) {
|
||||
assert(length <= 0xffff);
|
||||
const uint8_t kVersion = 2;
|
||||
AssignUWord8(buffer, pos, (kVersion << 6) + count_or_format);
|
||||
AssignUWord8(buffer, pos, packet_type);
|
||||
@ -98,9 +117,9 @@ void CreateHeader(uint8_t count_or_format, // Depends on packet type.
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|
||||
void CreateSenderReport(const RTCPPacketSR& sr,
|
||||
uint16_t length,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
size_t* pos) {
|
||||
CreateHeader(sr.NumberOfReportBlocks, PT_SR, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, sr.SenderSSRC);
|
||||
AssignUWord32(buffer, pos, sr.NTPMostSignificant);
|
||||
@ -120,9 +139,9 @@ void CreateSenderReport(const RTCPPacketSR& sr,
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|
||||
void CreateReceiverReport(const RTCPPacketRR& rr,
|
||||
uint16_t length,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
size_t* pos) {
|
||||
CreateHeader(rr.NumberOfReportBlocks, PT_RR, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, rr.SenderSSRC);
|
||||
}
|
||||
@ -144,16 +163,89 @@ void CreateReceiverReport(const RTCPPacketRR& rr,
|
||||
// | delay since last SR (DLSR) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|
||||
void CreateReportBlock(const RTCPPacketReportBlockItem& report_block,
|
||||
void CreateReportBlocks(const std::vector<RTCPPacketReportBlockItem>& blocks,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
AssignUWord32(buffer, pos, report_block.SSRC);
|
||||
AssignUWord8(buffer, pos, report_block.FractionLost);
|
||||
AssignUWord24(buffer, pos, report_block.CumulativeNumOfPacketsLost);
|
||||
AssignUWord32(buffer, pos, report_block.ExtendedHighestSequenceNumber);
|
||||
AssignUWord32(buffer, pos, report_block.Jitter);
|
||||
AssignUWord32(buffer, pos, report_block.LastSR);
|
||||
AssignUWord32(buffer, pos, report_block.DelayLastSR);
|
||||
size_t* pos) {
|
||||
for (std::vector<RTCPPacketReportBlockItem>::const_iterator
|
||||
it = blocks.begin(); it != blocks.end(); ++it) {
|
||||
AssignUWord32(buffer, pos, (*it).SSRC);
|
||||
AssignUWord8(buffer, pos, (*it).FractionLost);
|
||||
AssignUWord24(buffer, pos, (*it).CumulativeNumOfPacketsLost);
|
||||
AssignUWord32(buffer, pos, (*it).ExtendedHighestSequenceNumber);
|
||||
AssignUWord32(buffer, pos, (*it).Jitter);
|
||||
AssignUWord32(buffer, pos, (*it).LastSR);
|
||||
AssignUWord32(buffer, pos, (*it).DelayLastSR);
|
||||
}
|
||||
}
|
||||
|
||||
// Transmission Time Offsets in RTP Streams (RFC 5450).
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// hdr |V=2|P| RC | PT=IJ=195 | length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | inter-arrival jitter |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// . .
|
||||
// . .
|
||||
// . .
|
||||
// | inter-arrival jitter |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateIj(const std::vector<uint32_t>& ij_items,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
size_t length = ij_items.size();
|
||||
CreateHeader(length, PT_IJ, length, buffer, pos);
|
||||
for (std::vector<uint32_t>::const_iterator it = ij_items.begin();
|
||||
it != ij_items.end(); ++it) {
|
||||
AssignUWord32(buffer, pos, *it);
|
||||
}
|
||||
}
|
||||
|
||||
// Source Description (SDES) (RFC 3550).
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// header |V=2|P| SC | PT=SDES=202 | length |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// chunk | SSRC/CSRC_1 |
|
||||
// 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SDES items |
|
||||
// | ... |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// chunk | SSRC/CSRC_2 |
|
||||
// 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SDES items |
|
||||
// | ... |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// Canonical End-Point Identifier SDES Item (CNAME)
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | CNAME=1 | length | user and domain name ...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
CreateHeader(chunks.size(), PT_SDES, length, buffer, pos);
|
||||
const uint8_t kSdesItemType = 1;
|
||||
for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
|
||||
it != chunks.end(); ++it) {
|
||||
AssignUWord32(buffer, pos, (*it).ssrc);
|
||||
AssignUWord8(buffer, pos, kSdesItemType);
|
||||
AssignUWord8(buffer, pos, (*it).name.length());
|
||||
memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
|
||||
*pos += (*it).name.length();
|
||||
memset(buffer + *pos, 0, (*it).null_octets);
|
||||
*pos += (*it).null_octets;
|
||||
}
|
||||
}
|
||||
|
||||
// Bye packet (BYE) (RFC 3550).
|
||||
@ -171,9 +263,9 @@ void CreateReportBlock(const RTCPPacketReportBlockItem& report_block,
|
||||
|
||||
void CreateBye(const RTCPPacketBYE& bye,
|
||||
const std::vector<uint32_t>& csrcs,
|
||||
uint16_t length,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
size_t* pos) {
|
||||
CreateHeader(length, PT_BYE, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, bye.SenderSSRC);
|
||||
for (std::vector<uint32_t>::const_iterator it = csrcs.begin();
|
||||
@ -182,6 +274,32 @@ void CreateBye(const RTCPPacketBYE& bye,
|
||||
}
|
||||
}
|
||||
|
||||
// Application-Defined packet (APP) (RFC 3550).
|
||||
//
|
||||
// 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| subtype | PT=APP=204 | length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC/CSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | name (ASCII) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | application-dependent data ...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateApp(const RTCPPacketAPP& app,
|
||||
uint32_t ssrc,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
CreateHeader(app.SubType, PT_APP, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, ssrc);
|
||||
AssignUWord32(buffer, pos, app.Name);
|
||||
memcpy(buffer + *pos, app.Data, app.Size);
|
||||
*pos += app.Size;
|
||||
}
|
||||
|
||||
// RFC 4585: Feedback format.
|
||||
//
|
||||
// Common packet format:
|
||||
@ -199,6 +317,47 @@ void CreateBye(const RTCPPacketBYE& bye,
|
||||
// :
|
||||
//
|
||||
|
||||
// Picture loss indication (PLI) (RFC 4585).
|
||||
//
|
||||
// FCI: no feedback control information.
|
||||
|
||||
void CreatePli(const RTCPPacketPSFBPLI& pli,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
const uint8_t kFmt = 1;
|
||||
CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, pli.SenderSSRC);
|
||||
AssignUWord32(buffer, pos, pli.MediaSSRC);
|
||||
}
|
||||
|
||||
// Slice loss indication (SLI) (RFC 4585).
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | First | Number | PictureID |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateSli(const RTCPPacketPSFBSLI& sli,
|
||||
const RTCPPacketPSFBSLIItem& sli_item,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
size_t* pos) {
|
||||
const uint8_t kFmt = 2;
|
||||
CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, sli.SenderSSRC);
|
||||
AssignUWord32(buffer, pos, sli.MediaSSRC);
|
||||
|
||||
AssignUWord8(buffer, pos, sli_item.FirstMB >> 5);
|
||||
AssignUWord8(buffer, pos, (sli_item.FirstMB << 3) +
|
||||
((sli_item.NumberOfMB >> 10) & 0x07));
|
||||
AssignUWord8(buffer, pos, sli_item.NumberOfMB >> 2);
|
||||
AssignUWord8(buffer, pos, (sli_item.NumberOfMB << 6) + sli_item.PictureId);
|
||||
}
|
||||
|
||||
// Generic NACK (RFC 4585).
|
||||
//
|
||||
// FCI:
|
||||
@ -211,9 +370,9 @@ void CreateBye(const RTCPPacketBYE& bye,
|
||||
|
||||
void CreateNack(const RTCPPacketRTPFBNACK& nack,
|
||||
const std::vector<RTCPPacketRTPFBNACKItem>& nack_fields,
|
||||
uint16_t length,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
size_t* pos) {
|
||||
const uint8_t kFmt = 1;
|
||||
CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, nack.SenderSSRC);
|
||||
@ -239,9 +398,9 @@ void CreateNack(const RTCPPacketRTPFBNACK& nack,
|
||||
|
||||
void CreateRpsi(const RTCPPacketPSFBRPSI& rpsi,
|
||||
uint8_t padding_bytes,
|
||||
uint16_t length,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
size_t* pos) {
|
||||
// Native bit string should be a multiple of 8 bits.
|
||||
assert(rpsi.NumberOfValidBits % 8 == 0);
|
||||
const uint8_t kFmt = 3;
|
||||
@ -270,9 +429,9 @@ void CreateRpsi(const RTCPPacketPSFBRPSI& rpsi,
|
||||
|
||||
void CreateFir(const RTCPPacketPSFBFIR& fir,
|
||||
const RTCPPacketPSFBFIRItem& fir_item,
|
||||
uint16_t length,
|
||||
size_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
size_t* pos) {
|
||||
const uint8_t kFmt = 4;
|
||||
CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, fir.SenderSSRC);
|
||||
@ -281,16 +440,6 @@ void CreateFir(const RTCPPacketPSFBFIR& fir,
|
||||
AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
|
||||
AssignUWord24(buffer, pos, 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AppendBlocks(const std::vector<T*>& blocks,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
for (typename std::vector<T*>::const_iterator it = blocks.begin();
|
||||
it != blocks.end(); ++it) {
|
||||
(*it)->Create(buffer, pos);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void RtcpPacket::Append(RtcpPacket* packet) {
|
||||
@ -299,39 +448,41 @@ void RtcpPacket::Append(RtcpPacket* packet) {
|
||||
}
|
||||
|
||||
RawPacket RtcpPacket::Build() const {
|
||||
uint16_t len = 0;
|
||||
size_t length = 0;
|
||||
uint8_t packet[IP_PACKET_SIZE];
|
||||
CreateAndAddAppended(packet, &len, IP_PACKET_SIZE);
|
||||
return RawPacket(packet, len);
|
||||
CreateAndAddAppended(packet, &length, IP_PACKET_SIZE);
|
||||
return RawPacket(packet, length);
|
||||
}
|
||||
|
||||
void RtcpPacket::Build(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||
*len = 0;
|
||||
CreateAndAddAppended(packet, len, max_len);
|
||||
void RtcpPacket::Build(uint8_t* packet,
|
||||
size_t* length,
|
||||
size_t max_length) const {
|
||||
*length = 0;
|
||||
CreateAndAddAppended(packet, length, max_length);
|
||||
}
|
||||
|
||||
void RtcpPacket::CreateAndAddAppended(uint8_t* packet,
|
||||
uint16_t* len,
|
||||
uint16_t max_len) const {
|
||||
Create(packet, len, max_len);
|
||||
size_t* length,
|
||||
size_t max_length) const {
|
||||
Create(packet, length, max_length);
|
||||
for (std::vector<RtcpPacket*>::const_iterator it = appended_packets_.begin();
|
||||
it != appended_packets_.end(); ++it) {
|
||||
(*it)->CreateAndAddAppended(packet, len, max_len);
|
||||
(*it)->CreateAndAddAppended(packet, length, max_length);
|
||||
}
|
||||
}
|
||||
|
||||
void Empty::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||
void Empty::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
}
|
||||
|
||||
void SenderReport::Create(uint8_t* packet,
|
||||
uint16_t* len,
|
||||
uint16_t max_len) const {
|
||||
if (*len + Length() > max_len) {
|
||||
size_t* length,
|
||||
size_t max_length) const {
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateSenderReport(sr_, BlockToHeaderLength(Length()), packet, len);
|
||||
AppendBlocks(report_blocks_, packet, len);
|
||||
CreateSenderReport(sr_, BlockToHeaderLength(BlockLength()), packet, length);
|
||||
CreateReportBlocks(report_blocks_, packet, length);
|
||||
}
|
||||
|
||||
void SenderReport::WithReportBlock(ReportBlock* block) {
|
||||
@ -340,19 +491,19 @@ void SenderReport::WithReportBlock(ReportBlock* block) {
|
||||
LOG(LS_WARNING) << "Max report blocks reached.";
|
||||
return;
|
||||
}
|
||||
report_blocks_.push_back(block);
|
||||
report_blocks_.push_back(block->report_block_);
|
||||
sr_.NumberOfReportBlocks = report_blocks_.size();
|
||||
}
|
||||
|
||||
void ReceiverReport::Create(uint8_t* packet,
|
||||
uint16_t* len,
|
||||
uint16_t max_len) const {
|
||||
if (*len + Length() > max_len) {
|
||||
size_t* length,
|
||||
size_t max_length) const {
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateReceiverReport(rr_, BlockToHeaderLength(Length()), packet, len);
|
||||
AppendBlocks(report_blocks_, packet, len);
|
||||
CreateReceiverReport(rr_, BlockToHeaderLength(BlockLength()), packet, length);
|
||||
CreateReportBlocks(report_blocks_, packet, length);
|
||||
}
|
||||
|
||||
void ReceiverReport::WithReportBlock(ReportBlock* block) {
|
||||
@ -361,20 +512,71 @@ void ReceiverReport::WithReportBlock(ReportBlock* block) {
|
||||
LOG(LS_WARNING) << "Max report blocks reached.";
|
||||
return;
|
||||
}
|
||||
report_blocks_.push_back(block);
|
||||
report_blocks_.push_back(block->report_block_);
|
||||
rr_.NumberOfReportBlocks = report_blocks_.size();
|
||||
}
|
||||
|
||||
void ReportBlock::Create(uint8_t* packet, uint16_t* len) const {
|
||||
CreateReportBlock(report_block_, packet, len);
|
||||
}
|
||||
|
||||
void Bye::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||
if (*len + Length() > max_len) {
|
||||
void Ij::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;
|
||||
}
|
||||
CreateBye(bye_, csrcs_, BlockToHeaderLength(Length()), packet, len);
|
||||
CreateIj(ij_items_, packet, length);
|
||||
}
|
||||
|
||||
void Ij::WithJitterItem(uint32_t jitter) {
|
||||
if (ij_items_.size() >= kMaxNumberOfIjItems) {
|
||||
LOG(LS_WARNING) << "Max inter-arrival jitter items reached.";
|
||||
return;
|
||||
}
|
||||
ij_items_.push_back(jitter);
|
||||
}
|
||||
|
||||
void Sdes::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
assert(!chunks_.empty());
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateSdes(chunks_, BlockToHeaderLength(BlockLength()), packet, length);
|
||||
}
|
||||
|
||||
void Sdes::WithCName(uint32_t ssrc, std::string cname) {
|
||||
assert(cname.length() <= 0xff);
|
||||
if (chunks_.size() >= kMaxNumberOfChunks) {
|
||||
LOG(LS_WARNING) << "Max SDES chunks reached.";
|
||||
return;
|
||||
}
|
||||
// In each chunk, the list of items must be terminated by one or more null
|
||||
// octets. The next chunk must start on a 32-bit boundary.
|
||||
// CNAME (1 byte) | length (1 byte) | name | padding.
|
||||
int null_octets = 4 - ((2 + cname.length()) % 4);
|
||||
Chunk chunk;
|
||||
chunk.ssrc = ssrc;
|
||||
chunk.name = cname;
|
||||
chunk.null_octets = null_octets;
|
||||
chunks_.push_back(chunk);
|
||||
}
|
||||
|
||||
size_t Sdes::BlockLength() const {
|
||||
// Header (4 bytes).
|
||||
// Chunk:
|
||||
// SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
|
||||
size_t length = kHeaderLength;
|
||||
for (std::vector<Chunk>::const_iterator it = chunks_.begin();
|
||||
it != chunks_.end(); ++it) {
|
||||
length += 6 + (*it).name.length() + (*it).null_octets;
|
||||
}
|
||||
assert(length % 4 == 0);
|
||||
return length;
|
||||
}
|
||||
|
||||
void Bye::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;
|
||||
}
|
||||
CreateBye(bye_, csrcs_, BlockToHeaderLength(BlockLength()), packet, length);
|
||||
}
|
||||
|
||||
void Bye::WithCsrc(uint32_t csrc) {
|
||||
@ -385,13 +587,39 @@ void Bye::WithCsrc(uint32_t csrc) {
|
||||
csrcs_.push_back(csrc);
|
||||
}
|
||||
|
||||
void Nack::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||
assert(!nack_fields_.empty());
|
||||
if (*len + Length() > max_len) {
|
||||
void App::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;
|
||||
}
|
||||
CreateNack(nack_, nack_fields_, BlockToHeaderLength(Length()), packet, len);
|
||||
CreateApp(app_, ssrc_, BlockToHeaderLength(BlockLength()), packet, length);
|
||||
}
|
||||
|
||||
void Pli::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;
|
||||
}
|
||||
CreatePli(pli_, BlockToHeaderLength(BlockLength()), packet, length);
|
||||
}
|
||||
|
||||
void Sli::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;
|
||||
}
|
||||
CreateSli(sli_, sli_item_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
}
|
||||
|
||||
void Nack::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
assert(!nack_fields_.empty());
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateNack(nack_, nack_fields_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
}
|
||||
|
||||
void Nack::WithList(const uint16_t* nack_list, int length) {
|
||||
@ -418,13 +646,14 @@ void Nack::WithList(const uint16_t* nack_list, int length) {
|
||||
}
|
||||
}
|
||||
|
||||
void Rpsi::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||
void Rpsi::Create(uint8_t* packet, size_t* length, size_t max_length) const {
|
||||
assert(rpsi_.NumberOfValidBits > 0);
|
||||
if (*len + Length() > max_len) {
|
||||
if (*length + BlockLength() > max_length) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateRpsi(rpsi_, padding_bytes_, BlockToHeaderLength(Length()), packet, len);
|
||||
CreateRpsi(rpsi_, padding_bytes_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
}
|
||||
|
||||
void Rpsi::WithPictureId(uint64_t picture_id) {
|
||||
@ -454,12 +683,13 @@ void Rpsi::WithPictureId(uint64_t picture_id) {
|
||||
}
|
||||
}
|
||||
|
||||
void Fir::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||
if (*len + Length() > max_len) {
|
||||
void Fir::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;
|
||||
}
|
||||
CreateFir(fir_, fir_item_, BlockToHeaderLength(Length()), packet, len);
|
||||
CreateFir(fir_, fir_item_, BlockToHeaderLength(BlockLength()), packet,
|
||||
length);
|
||||
}
|
||||
} // namespace rtcp
|
||||
} // namespace webrtc
|
||||
|
@ -12,6 +12,8 @@
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_RTCP_PACKET_H_
|
||||
#define WEBRTC_MODULES_RTP_RTCP_RTCP_PACKET_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
|
||||
@ -21,8 +23,10 @@
|
||||
namespace webrtc {
|
||||
namespace rtcp {
|
||||
|
||||
enum { kCommonFbFmtLength = 12 };
|
||||
enum { kReportBlockLength = 24 };
|
||||
|
||||
class RawPacket;
|
||||
class ReportBlock;
|
||||
|
||||
// Class for building RTCP packets.
|
||||
//
|
||||
@ -40,9 +44,9 @@ class ReportBlock;
|
||||
// fir.To(234)
|
||||
// fir.WithCommandSeqNum(123);
|
||||
//
|
||||
// uint16_t len = 0; // Builds an intra frame request
|
||||
// size_t length = 0; // Builds an intra frame request
|
||||
// uint8_t packet[kPacketSize]; // with sequence number 123.
|
||||
// fir.Build(packet, &len, kPacketSize);
|
||||
// fir.Build(packet, &length, kPacketSize);
|
||||
//
|
||||
// RawPacket packet = fir.Build(); // Returns a RawPacket holding
|
||||
// // the built rtcp packet.
|
||||
@ -59,18 +63,20 @@ class RtcpPacket {
|
||||
|
||||
RawPacket Build() const;
|
||||
|
||||
void Build(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
|
||||
void Build(uint8_t* packet, size_t* length, size_t max_length) const;
|
||||
|
||||
protected:
|
||||
RtcpPacket() {}
|
||||
RtcpPacket() : kHeaderLength(4) {}
|
||||
|
||||
virtual void Create(
|
||||
uint8_t* packet, uint16_t* len, uint16_t max_len) const = 0;
|
||||
uint8_t* packet, size_t* length, size_t max_length) const = 0;
|
||||
|
||||
void CreateAndAddAppended(
|
||||
uint8_t* packet, uint16_t* len, uint16_t max_len) const;
|
||||
const size_t kHeaderLength;
|
||||
|
||||
private:
|
||||
void CreateAndAddAppended(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const;
|
||||
|
||||
std::vector<RtcpPacket*> appended_packets_;
|
||||
};
|
||||
|
||||
@ -81,11 +87,66 @@ class Empty : public RtcpPacket {
|
||||
virtual ~Empty() {}
|
||||
|
||||
protected:
|
||||
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
|
||||
virtual void Create(uint8_t* packet, size_t* length, size_t max_length) const;
|
||||
};
|
||||
|
||||
//// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
|
||||
// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
|
||||
//
|
||||
// RTCP report block (RFC 3550).
|
||||
//
|
||||
// 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_1 (SSRC of first source) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | fraction lost | cumulative number of packets lost |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | extended highest sequence number received |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | interarrival jitter |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | last SR (LSR) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | delay since last SR (DLSR) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|
||||
class ReportBlock {
|
||||
public:
|
||||
ReportBlock() {
|
||||
// TODO(asapersson): Consider adding a constructor to struct.
|
||||
memset(&report_block_, 0, sizeof(report_block_));
|
||||
}
|
||||
|
||||
~ReportBlock() {}
|
||||
|
||||
void To(uint32_t ssrc) {
|
||||
report_block_.SSRC = ssrc;
|
||||
}
|
||||
void WithFractionLost(uint8_t fraction_lost) {
|
||||
report_block_.FractionLost = fraction_lost;
|
||||
}
|
||||
void WithCumulativeLost(uint32_t cumulative_lost) {
|
||||
report_block_.CumulativeNumOfPacketsLost = cumulative_lost;
|
||||
}
|
||||
void WithExtHighestSeqNum(uint32_t ext_highest_seq_num) {
|
||||
report_block_.ExtendedHighestSequenceNumber = ext_highest_seq_num;
|
||||
}
|
||||
void WithJitter(uint32_t jitter) {
|
||||
report_block_.Jitter = jitter;
|
||||
}
|
||||
void WithLastSr(uint32_t last_sr) {
|
||||
report_block_.LastSR = last_sr;
|
||||
}
|
||||
void WithDelayLastSr(uint32_t delay_last_sr) {
|
||||
report_block_.DelayLastSR = delay_last_sr;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class SenderReport;
|
||||
friend class ReceiverReport;
|
||||
RTCPUtility::RTCPPacketReportBlockItem report_block_;
|
||||
};
|
||||
|
||||
// RTCP sender report (RFC 3550).
|
||||
//
|
||||
// 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
|
||||
@ -109,8 +170,7 @@ class Empty : public RtcpPacket {
|
||||
|
||||
class SenderReport : public RtcpPacket {
|
||||
public:
|
||||
SenderReport()
|
||||
: RtcpPacket() {
|
||||
SenderReport() : RtcpPacket() {
|
||||
memset(&sr_, 0, sizeof(sr_));
|
||||
}
|
||||
|
||||
@ -136,20 +196,22 @@ class SenderReport : public RtcpPacket {
|
||||
}
|
||||
void WithReportBlock(ReportBlock* block);
|
||||
|
||||
enum { kMaxNumberOfReportBlocks = 0x1f };
|
||||
|
||||
protected:
|
||||
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
uint16_t Length() const {
|
||||
const uint16_t kSrBlockLen = 28;
|
||||
const uint16_t kReportBlockLen = 24;
|
||||
return kSrBlockLen + report_blocks_.size() * kReportBlockLen;
|
||||
enum { kMaxNumberOfReportBlocks = 0x1f };
|
||||
|
||||
size_t BlockLength() const {
|
||||
const size_t kSrHeaderLength = 8;
|
||||
const size_t kSenderInfoLength = 20;
|
||||
return kSrHeaderLength + kSenderInfoLength +
|
||||
report_blocks_.size() * kReportBlockLength;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketSR sr_;
|
||||
std::vector<ReportBlock*> report_blocks_;
|
||||
std::vector<RTCPUtility::RTCPPacketReportBlockItem> report_blocks_;
|
||||
};
|
||||
|
||||
//
|
||||
@ -167,8 +229,7 @@ class SenderReport : public RtcpPacket {
|
||||
|
||||
class ReceiverReport : public RtcpPacket {
|
||||
public:
|
||||
ReceiverReport()
|
||||
: RtcpPacket() {
|
||||
ReceiverReport() : RtcpPacket() {
|
||||
memset(&rr_, 0, sizeof(rr_));
|
||||
}
|
||||
|
||||
@ -179,75 +240,117 @@ class ReceiverReport : public RtcpPacket {
|
||||
}
|
||||
void WithReportBlock(ReportBlock* block);
|
||||
|
||||
enum { kMaxNumberOfReportBlocks = 0x1f };
|
||||
|
||||
protected:
|
||||
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
uint16_t Length() const {
|
||||
const uint16_t kRrBlockLen = 8;
|
||||
const uint16_t kReportBlockLen = 24;
|
||||
return kRrBlockLen + report_blocks_.size() * kReportBlockLen;
|
||||
enum { kMaxNumberOfReportBlocks = 0x1f };
|
||||
|
||||
size_t BlockLength() const {
|
||||
const size_t kRrHeaderLength = 8;
|
||||
return kRrHeaderLength + report_blocks_.size() * kReportBlockLength;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketRR rr_;
|
||||
std::vector<ReportBlock*> report_blocks_;
|
||||
std::vector<RTCPUtility::RTCPPacketReportBlockItem> report_blocks_;
|
||||
};
|
||||
|
||||
//
|
||||
// RTCP report block (RFC 3550).
|
||||
// Transmission Time Offsets in RTP Streams (RFC 5450).
|
||||
//
|
||||
// 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_1 (SSRC of first source) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | fraction lost | cumulative number of packets lost |
|
||||
// hdr |V=2|P| RC | PT=IJ=195 | length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | extended highest sequence number received |
|
||||
// | inter-arrival jitter |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | interarrival jitter |
|
||||
// . .
|
||||
// . .
|
||||
// . .
|
||||
// | inter-arrival jitter |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | last SR (LSR) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | delay since last SR (DLSR) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// If present, this RTCP packet must be placed after a receiver report
|
||||
// (inside a compound RTCP packet), and MUST have the same value for RC
|
||||
// (reception report count) as the receiver report.
|
||||
|
||||
class ReportBlock {
|
||||
class Ij : public RtcpPacket {
|
||||
public:
|
||||
ReportBlock() {
|
||||
memset(&report_block_, 0, sizeof(report_block_));
|
||||
}
|
||||
Ij() : RtcpPacket() {}
|
||||
|
||||
~ReportBlock() {}
|
||||
virtual ~Ij() {}
|
||||
|
||||
void To(uint32_t ssrc) {
|
||||
report_block_.SSRC = ssrc;
|
||||
}
|
||||
void WithFractionLost(uint8_t fraction_lost) {
|
||||
report_block_.FractionLost = fraction_lost;
|
||||
}
|
||||
void WithCumPacketsLost(uint32_t cum_packets_lost) {
|
||||
report_block_.CumulativeNumOfPacketsLost = cum_packets_lost;
|
||||
}
|
||||
void WithExtHighestSeqNum(uint32_t ext_highest_seq_num) {
|
||||
report_block_.ExtendedHighestSequenceNumber = ext_highest_seq_num;
|
||||
}
|
||||
void WithJitter(uint32_t jitter) {
|
||||
report_block_.Jitter = jitter;
|
||||
}
|
||||
void WithLastSr(uint32_t last_sr) {
|
||||
report_block_.LastSR = last_sr;
|
||||
}
|
||||
void WithDelayLastSr(uint32_t delay_last_sr) {
|
||||
report_block_.DelayLastSR = delay_last_sr;
|
||||
}
|
||||
void WithJitterItem(uint32_t jitter);
|
||||
|
||||
void Create(uint8_t* packet, uint16_t* len) const;
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
RTCPUtility::RTCPPacketReportBlockItem report_block_;
|
||||
enum { kMaxNumberOfIjItems = 0x1f };
|
||||
|
||||
size_t BlockLength() const {
|
||||
return kHeaderLength + 4 * ij_items_.size();
|
||||
}
|
||||
|
||||
std::vector<uint32_t> ij_items_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Ij);
|
||||
};
|
||||
|
||||
// Source Description (SDES) (RFC 3550).
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// header |V=2|P| SC | PT=SDES=202 | length |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// chunk | SSRC/CSRC_1 |
|
||||
// 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SDES items |
|
||||
// | ... |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// chunk | SSRC/CSRC_2 |
|
||||
// 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SDES items |
|
||||
// | ... |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// Canonical End-Point Identifier SDES Item (CNAME)
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | CNAME=1 | length | user and domain name ...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class Sdes : public RtcpPacket {
|
||||
public:
|
||||
Sdes() : RtcpPacket() {}
|
||||
|
||||
virtual ~Sdes() {}
|
||||
|
||||
void WithCName(uint32_t ssrc, std::string cname);
|
||||
|
||||
struct Chunk {
|
||||
uint32_t ssrc;
|
||||
std::string name;
|
||||
int null_octets;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
enum { kMaxNumberOfChunks = 0x1f };
|
||||
|
||||
size_t BlockLength() const;
|
||||
|
||||
std::vector<Chunk> chunks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Sdes);
|
||||
};
|
||||
|
||||
//
|
||||
@ -266,8 +369,7 @@ class ReportBlock {
|
||||
|
||||
class Bye : public RtcpPacket {
|
||||
public:
|
||||
Bye()
|
||||
: RtcpPacket() {
|
||||
Bye() : RtcpPacket() {
|
||||
memset(&bye_, 0, sizeof(bye_));
|
||||
}
|
||||
|
||||
@ -278,21 +380,79 @@ class Bye : public RtcpPacket {
|
||||
}
|
||||
void WithCsrc(uint32_t csrc);
|
||||
|
||||
enum { kMaxNumberOfCsrcs = 0x1f - 1 };
|
||||
|
||||
protected:
|
||||
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
uint16_t Length() const {
|
||||
const uint16_t kByeBlockLen = 8 + 4 * csrcs_.size();
|
||||
return kByeBlockLen;
|
||||
enum { kMaxNumberOfCsrcs = 0x1f - 1 };
|
||||
|
||||
size_t BlockLength() const {
|
||||
size_t source_count = 1 + csrcs_.size();
|
||||
return kHeaderLength + 4 * source_count;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketBYE bye_;
|
||||
std::vector<uint32_t> csrcs_;
|
||||
};
|
||||
|
||||
// Application-Defined packet (APP) (RFC 3550).
|
||||
//
|
||||
// 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| subtype | PT=APP=204 | length |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | SSRC/CSRC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | name (ASCII) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | application-dependent data ...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class App : public RtcpPacket {
|
||||
public:
|
||||
App()
|
||||
: RtcpPacket(),
|
||||
ssrc_(0) {
|
||||
memset(&app_, 0, sizeof(app_));
|
||||
}
|
||||
|
||||
virtual ~App() {}
|
||||
|
||||
void From(uint32_t ssrc) {
|
||||
ssrc_ = ssrc;
|
||||
}
|
||||
void WithSubType(uint8_t subtype) {
|
||||
assert(subtype <= 0x1f);
|
||||
app_.SubType = subtype;
|
||||
}
|
||||
void WithName(uint32_t name) {
|
||||
app_.Name = name;
|
||||
}
|
||||
void WithData(const uint8_t* data, uint16_t data_length) {
|
||||
assert(data);
|
||||
assert(data_length <= kRtcpAppCode_DATA_SIZE);
|
||||
assert(data_length % 4 == 0);
|
||||
memcpy(app_.Data, data, data_length);
|
||||
app_.Size = data_length;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
size_t BlockLength() const {
|
||||
return 12 + app_.Size;
|
||||
}
|
||||
|
||||
uint32_t ssrc_;
|
||||
RTCPUtility::RTCPPacketAPP app_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(App);
|
||||
};
|
||||
|
||||
// RFC 4585: Feedback format.
|
||||
//
|
||||
// Common packet format:
|
||||
@ -309,6 +469,92 @@ class Bye : public RtcpPacket {
|
||||
// : Feedback Control Information (FCI) :
|
||||
// :
|
||||
|
||||
// Picture loss indication (PLI) (RFC 4585).
|
||||
//
|
||||
// FCI: no feedback control information.
|
||||
|
||||
class Pli : public RtcpPacket {
|
||||
public:
|
||||
Pli() : RtcpPacket() {
|
||||
memset(&pli_, 0, sizeof(pli_));
|
||||
}
|
||||
|
||||
virtual ~Pli() {}
|
||||
|
||||
void From(uint32_t ssrc) {
|
||||
pli_.SenderSSRC = ssrc;
|
||||
}
|
||||
void To(uint32_t ssrc) {
|
||||
pli_.MediaSSRC = ssrc;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
size_t BlockLength() const {
|
||||
return kCommonFbFmtLength;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketPSFBPLI pli_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Pli);
|
||||
};
|
||||
|
||||
// Slice loss indication (SLI) (RFC 4585).
|
||||
//
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | First | Number | PictureID |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
class Sli : public RtcpPacket {
|
||||
public:
|
||||
Sli() : RtcpPacket() {
|
||||
memset(&sli_, 0, sizeof(sli_));
|
||||
memset(&sli_item_, 0, sizeof(sli_item_));
|
||||
}
|
||||
|
||||
virtual ~Sli() {}
|
||||
|
||||
void From(uint32_t ssrc) {
|
||||
sli_.SenderSSRC = ssrc;
|
||||
}
|
||||
void To(uint32_t ssrc) {
|
||||
sli_.MediaSSRC = ssrc;
|
||||
}
|
||||
void WithFirstMb(uint16_t first_mb) {
|
||||
assert(first_mb <= 0x1fff);
|
||||
sli_item_.FirstMB = first_mb;
|
||||
}
|
||||
void WithNumberOfMb(uint16_t number_mb) {
|
||||
assert(number_mb <= 0x1fff);
|
||||
sli_item_.NumberOfMB = number_mb;
|
||||
}
|
||||
void WithPictureId(uint8_t picture_id) {
|
||||
assert(picture_id <= 0x3f);
|
||||
sli_item_.PictureId = picture_id;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
size_t BlockLength() const {
|
||||
const size_t kFciLength = 4;
|
||||
return kCommonFbFmtLength + kFciLength;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketPSFBSLI sli_;
|
||||
RTCPUtility::RTCPPacketPSFBSLIItem sli_item_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Sli);
|
||||
};
|
||||
|
||||
// Generic NACK (RFC 4585).
|
||||
//
|
||||
// FCI:
|
||||
@ -320,8 +566,7 @@ class Bye : public RtcpPacket {
|
||||
|
||||
class Nack : public RtcpPacket {
|
||||
public:
|
||||
Nack()
|
||||
: RtcpPacket() {
|
||||
Nack() : RtcpPacket() {
|
||||
memset(&nack_, 0, sizeof(nack_));
|
||||
}
|
||||
|
||||
@ -336,13 +581,13 @@ class Nack : public RtcpPacket {
|
||||
void WithList(const uint16_t* nack_list, int length);
|
||||
|
||||
protected:
|
||||
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const
|
||||
OVERRIDE;
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
uint16_t Length() const {
|
||||
const uint16_t kNackBlockLen = 4 * (3 + nack_fields_.size());
|
||||
return kNackBlockLen;
|
||||
size_t BlockLength() const {
|
||||
size_t fci_length = 4 * nack_fields_.size();
|
||||
return kCommonFbFmtLength + fci_length;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketRTPFBNACK nack_;
|
||||
@ -386,14 +631,13 @@ class Rpsi : public RtcpPacket {
|
||||
void WithPictureId(uint64_t picture_id);
|
||||
|
||||
protected:
|
||||
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const
|
||||
OVERRIDE;
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
uint16_t Length() const {
|
||||
const uint16_t kRpsiBlockLen =
|
||||
12 + 2 + (rpsi_.NumberOfValidBits / 8) + padding_bytes_;
|
||||
return kRpsiBlockLen;
|
||||
size_t BlockLength() const {
|
||||
size_t fci_length = 2 + (rpsi_.NumberOfValidBits / 8) + padding_bytes_;
|
||||
return kCommonFbFmtLength + fci_length;
|
||||
}
|
||||
|
||||
uint8_t padding_bytes_;
|
||||
@ -435,12 +679,13 @@ class Fir : public RtcpPacket {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
|
||||
virtual void Create(
|
||||
uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE;
|
||||
|
||||
private:
|
||||
uint16_t Length() const {
|
||||
const uint16_t kFirBlockLen = 20;
|
||||
return kFirBlockLen;
|
||||
size_t BlockLength() const {
|
||||
const size_t kFciLength = 8;
|
||||
return kCommonFbFmtLength + kFciLength;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketPSFBFIR fir_;
|
||||
@ -450,7 +695,7 @@ class Fir : public RtcpPacket {
|
||||
// Class holding a RTCP packet.
|
||||
//
|
||||
// Takes a built rtcp packet.
|
||||
// RawPacket raw_packet(buffer, len);
|
||||
// RawPacket raw_packet(buffer, length);
|
||||
//
|
||||
// To access the raw packet:
|
||||
// raw_packet.buffer(); - pointer to the raw packet
|
||||
@ -458,22 +703,22 @@ class Fir : public RtcpPacket {
|
||||
|
||||
class RawPacket {
|
||||
public:
|
||||
RawPacket(const uint8_t* buffer, uint16_t len) {
|
||||
assert(len <= IP_PACKET_SIZE);
|
||||
memcpy(packet_, buffer, len);
|
||||
packet_length_ = len;
|
||||
RawPacket(const uint8_t* packet, size_t length) {
|
||||
assert(length <= IP_PACKET_SIZE);
|
||||
memcpy(buffer_, packet, length);
|
||||
buffer_length_ = length;
|
||||
}
|
||||
|
||||
const uint8_t* buffer() {
|
||||
return packet_;
|
||||
return buffer_;
|
||||
}
|
||||
uint16_t buffer_length() const {
|
||||
return packet_length_;
|
||||
size_t buffer_length() const {
|
||||
return buffer_length_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint16_t packet_length_;
|
||||
uint8_t packet_[IP_PACKET_SIZE];
|
||||
size_t buffer_length_;
|
||||
uint8_t buffer_[IP_PACKET_SIZE];
|
||||
};
|
||||
|
||||
} // namespace rtcp
|
||||
|
@ -15,16 +15,21 @@
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
|
||||
#include "webrtc/test/rtcp_packet_parser.h"
|
||||
|
||||
using webrtc::rtcp::App;
|
||||
using webrtc::rtcp::Bye;
|
||||
using webrtc::rtcp::Empty;
|
||||
using webrtc::rtcp::Fir;
|
||||
using webrtc::rtcp::Ij;
|
||||
using webrtc::rtcp::Nack;
|
||||
using webrtc::rtcp::Pli;
|
||||
using webrtc::rtcp::Sdes;
|
||||
using webrtc::rtcp::SenderReport;
|
||||
using webrtc::rtcp::Sli;
|
||||
using webrtc::rtcp::RawPacket;
|
||||
using webrtc::rtcp::ReceiverReport;
|
||||
using webrtc::rtcp::ReportBlock;
|
||||
using webrtc::rtcp::Rpsi;
|
||||
using webrtc::test::RtcpPacketParser;
|
||||
using webrtc::rtcp::SenderReport;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -47,7 +52,7 @@ TEST(RtcpPacketTest, RrWithOneReportBlock) {
|
||||
ReportBlock rb;
|
||||
rb.To(kRemoteSsrc);
|
||||
rb.WithFractionLost(55);
|
||||
rb.WithCumPacketsLost(0x111111);
|
||||
rb.WithCumulativeLost(0x111111);
|
||||
rb.WithExtHighestSeqNum(0x22222222);
|
||||
rb.WithJitter(0x33333333);
|
||||
rb.WithLastSr(0x44444444);
|
||||
@ -154,6 +159,164 @@ TEST(RtcpPacketTest, SrWithTwoReportBlocks) {
|
||||
EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc + 1));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, IjNoItem) {
|
||||
Ij ij;
|
||||
|
||||
RawPacket packet = ij.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.ij()->num_packets());
|
||||
EXPECT_EQ(0, parser.ij_item()->num_packets());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, IjOneItem) {
|
||||
Ij ij;
|
||||
ij.WithJitterItem(0x11111111);
|
||||
|
||||
RawPacket packet = ij.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.ij()->num_packets());
|
||||
EXPECT_EQ(1, parser.ij_item()->num_packets());
|
||||
EXPECT_EQ(0x11111111U, parser.ij_item()->Jitter());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, IjTwoItems) {
|
||||
Ij ij;
|
||||
ij.WithJitterItem(0x11111111);
|
||||
ij.WithJitterItem(0x22222222);
|
||||
|
||||
RawPacket packet = ij.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.ij()->num_packets());
|
||||
EXPECT_EQ(2, parser.ij_item()->num_packets());
|
||||
EXPECT_EQ(0x22222222U, parser.ij_item()->Jitter());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, AppWithNoData) {
|
||||
App app;
|
||||
app.WithSubType(30);
|
||||
uint32_t name = 'n' << 24;
|
||||
name += 'a' << 16;
|
||||
name += 'm' << 8;
|
||||
name += 'e';
|
||||
app.WithName(name);
|
||||
|
||||
RawPacket packet = app.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.app()->num_packets());
|
||||
EXPECT_EQ(30U, parser.app()->SubType());
|
||||
EXPECT_EQ(name, parser.app()->Name());
|
||||
EXPECT_EQ(0, parser.app_item()->num_packets());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, App) {
|
||||
App app;
|
||||
app.From(kSenderSsrc);
|
||||
app.WithSubType(30);
|
||||
uint32_t name = 'n' << 24;
|
||||
name += 'a' << 16;
|
||||
name += 'm' << 8;
|
||||
name += 'e';
|
||||
app.WithName(name);
|
||||
const char kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'};
|
||||
const size_t kDataLength = sizeof(kData) / sizeof(kData[0]);
|
||||
app.WithData((const uint8_t*)kData, kDataLength);
|
||||
|
||||
RawPacket packet = app.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.app()->num_packets());
|
||||
EXPECT_EQ(30U, parser.app()->SubType());
|
||||
EXPECT_EQ(name, parser.app()->Name());
|
||||
EXPECT_EQ(1, parser.app_item()->num_packets());
|
||||
EXPECT_EQ(kDataLength, parser.app_item()->DataLength());
|
||||
EXPECT_EQ(0, strncmp(kData, (const char*)parser.app_item()->Data(),
|
||||
parser.app_item()->DataLength()));
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, SdesWithOneChunk) {
|
||||
Sdes sdes;
|
||||
sdes.WithCName(kSenderSsrc, "alice@host");
|
||||
|
||||
RawPacket packet = sdes.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.sdes()->num_packets());
|
||||
EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
|
||||
EXPECT_EQ("alice@host", parser.sdes_chunk()->Cname());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, SdesWithMultipleChunks) {
|
||||
Sdes sdes;
|
||||
sdes.WithCName(kSenderSsrc, "a");
|
||||
sdes.WithCName(kSenderSsrc + 1, "ab");
|
||||
sdes.WithCName(kSenderSsrc + 2, "abc");
|
||||
sdes.WithCName(kSenderSsrc + 3, "abcd");
|
||||
sdes.WithCName(kSenderSsrc + 4, "abcde");
|
||||
sdes.WithCName(kSenderSsrc + 5, "abcdef");
|
||||
|
||||
RawPacket packet = sdes.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.sdes()->num_packets());
|
||||
EXPECT_EQ(6, parser.sdes_chunk()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc + 5, parser.sdes_chunk()->Ssrc());
|
||||
EXPECT_EQ("abcdef", parser.sdes_chunk()->Cname());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, CnameItemWithEmptyString) {
|
||||
Sdes sdes;
|
||||
sdes.WithCName(kSenderSsrc, "");
|
||||
|
||||
RawPacket packet = sdes.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.sdes()->num_packets());
|
||||
EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
|
||||
EXPECT_EQ("", parser.sdes_chunk()->Cname());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, Pli) {
|
||||
Pli pli;
|
||||
pli.From(kSenderSsrc);
|
||||
pli.To(kRemoteSsrc);
|
||||
|
||||
RawPacket packet = pli.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.pli()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.pli()->Ssrc());
|
||||
EXPECT_EQ(kRemoteSsrc, parser.pli()->MediaSsrc());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, Sli) {
|
||||
const uint16_t kFirstMb = 7777;
|
||||
const uint16_t kNumberOfMb = 6666;
|
||||
const uint8_t kPictureId = 60;
|
||||
Sli sli;
|
||||
sli.From(kSenderSsrc);
|
||||
sli.To(kRemoteSsrc);
|
||||
sli.WithFirstMb(kFirstMb);
|
||||
sli.WithNumberOfMb(kNumberOfMb);
|
||||
sli.WithPictureId(kPictureId);
|
||||
|
||||
RawPacket packet = sli.Build();
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||
EXPECT_EQ(1, parser.sli()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser.sli()->Ssrc());
|
||||
EXPECT_EQ(kRemoteSsrc, parser.sli()->MediaSsrc());
|
||||
EXPECT_EQ(1, parser.sli_item()->num_packets());
|
||||
EXPECT_EQ(kFirstMb, parser.sli_item()->FirstMb());
|
||||
EXPECT_EQ(kNumberOfMb, parser.sli_item()->NumberOfMb());
|
||||
EXPECT_EQ(kPictureId, parser.sli_item()->PictureId());
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, Nack) {
|
||||
Nack nack;
|
||||
const uint16_t kList[] = {0, 1, 3, 8, 16};
|
||||
@ -373,11 +536,11 @@ TEST(RtcpPacketTest, BuildWithInputBuffer) {
|
||||
rr.WithReportBlock(&rb);
|
||||
rr.Append(&fir);
|
||||
|
||||
const uint16_t kRrLength = 8;
|
||||
const uint16_t kReportBlockLength = 24;
|
||||
const uint16_t kFirLength = 20;
|
||||
const size_t kRrLength = 8;
|
||||
const size_t kReportBlockLength = 24;
|
||||
const size_t kFirLength = 20;
|
||||
|
||||
uint16_t len = 0;
|
||||
size_t len = 0;
|
||||
uint8_t packet[kRrLength + kReportBlockLength + kFirLength];
|
||||
rr.Build(packet, &len, kRrLength + kReportBlockLength + kFirLength);
|
||||
|
||||
@ -394,16 +557,16 @@ TEST(RtcpPacketTest, BuildWithTooSmallBuffer) {
|
||||
rr.From(kSenderSsrc);
|
||||
rr.WithReportBlock(&rb);
|
||||
|
||||
const uint16_t kRrLength = 8;
|
||||
const uint16_t kReportBlockLength = 24;
|
||||
const size_t kRrLength = 8;
|
||||
const size_t kReportBlockLength = 24;
|
||||
|
||||
// No packet.
|
||||
uint16_t len = 0;
|
||||
size_t len = 0;
|
||||
uint8_t packet[kRrLength + kReportBlockLength - 1];
|
||||
rr.Build(packet, &len, kRrLength + kReportBlockLength - 1);
|
||||
RtcpPacketParser parser;
|
||||
parser.Parse(packet, len);
|
||||
EXPECT_EQ(0, len);
|
||||
EXPECT_EQ(0U, len);
|
||||
}
|
||||
|
||||
TEST(RtcpPacketTest, BuildWithTooSmallBuffer_LastBlockFits) {
|
||||
@ -414,10 +577,10 @@ TEST(RtcpPacketTest, BuildWithTooSmallBuffer_LastBlockFits) {
|
||||
rr.WithReportBlock(&rb);
|
||||
rr.Append(&fir);
|
||||
|
||||
const uint16_t kRrLength = 8;
|
||||
const uint16_t kReportBlockLength = 24;
|
||||
const size_t kRrLength = 8;
|
||||
const size_t kReportBlockLength = 24;
|
||||
|
||||
uint16_t len = 0;
|
||||
size_t len = 0;
|
||||
uint8_t packet[kRrLength + kReportBlockLength - 1];
|
||||
rr.Build(packet, &len, kRrLength + kReportBlockLength - 1);
|
||||
RtcpPacketParser parser;
|
||||
|
@ -30,13 +30,40 @@ void RtcpPacketParser::Parse(const void *data, int len) {
|
||||
case RTCPUtility::kRtcpRrCode:
|
||||
receiver_report_.Set(parser.Packet().RR);
|
||||
break;
|
||||
case RTCPUtility::kRtcpByeCode:
|
||||
bye_.Set(parser.Packet().BYE);
|
||||
break;
|
||||
case RTCPUtility::kRtcpReportBlockItemCode:
|
||||
report_block_.Set(parser.Packet().ReportBlockItem);
|
||||
++report_blocks_per_ssrc_[parser.Packet().ReportBlockItem.SSRC];
|
||||
break;
|
||||
case RTCPUtility::kRtcpSdesCode:
|
||||
sdes_.Set();
|
||||
break;
|
||||
case RTCPUtility::kRtcpSdesChunkCode:
|
||||
sdes_chunk_.Set(parser.Packet().CName);
|
||||
break;
|
||||
case RTCPUtility::kRtcpByeCode:
|
||||
bye_.Set(parser.Packet().BYE);
|
||||
break;
|
||||
case RTCPUtility::kRtcpAppCode:
|
||||
app_.Set(parser.Packet().APP);
|
||||
break;
|
||||
case RTCPUtility::kRtcpAppItemCode:
|
||||
app_item_.Set(parser.Packet().APP);
|
||||
break;
|
||||
case RTCPUtility::kRtcpExtendedIjCode:
|
||||
ij_.Set();
|
||||
break;
|
||||
case RTCPUtility::kRtcpExtendedIjItemCode:
|
||||
ij_item_.Set(parser.Packet().ExtendedJitterReportItem);
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbPliCode:
|
||||
pli_.Set(parser.Packet().PLI);
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbSliCode:
|
||||
sli_.Set(parser.Packet().SLI);
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbSliItemCode:
|
||||
sli_item_.Set(parser.Packet().SLIItem);
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbRpsiCode:
|
||||
rpsi_.Set(parser.Packet().RPSI);
|
||||
break;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#define WEBRTC_TEST_RTCP_PACKET_PARSER_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
|
||||
@ -100,6 +101,65 @@ class ReportBlock : public PacketType {
|
||||
RTCPUtility::RTCPPacketReportBlockItem rb_;
|
||||
};
|
||||
|
||||
class Ij : public PacketType {
|
||||
public:
|
||||
Ij() {}
|
||||
virtual ~Ij() {}
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set() { ++num_packets_; }
|
||||
};
|
||||
|
||||
class IjItem : public PacketType {
|
||||
public:
|
||||
IjItem() {}
|
||||
virtual ~IjItem() {}
|
||||
|
||||
uint32_t Jitter() const { return ij_item_.Jitter; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketExtendedJitterReportItem& ij_item) {
|
||||
ij_item_ = ij_item;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketExtendedJitterReportItem ij_item_;
|
||||
};
|
||||
|
||||
class Sdes : public PacketType {
|
||||
public:
|
||||
Sdes() {}
|
||||
virtual ~Sdes() {}
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set() { ++num_packets_; }
|
||||
};
|
||||
|
||||
class SdesChunk : public PacketType {
|
||||
public:
|
||||
SdesChunk() {}
|
||||
virtual ~SdesChunk() {}
|
||||
|
||||
uint32_t Ssrc() const { return cname_.SenderSSRC; }
|
||||
std::string Cname() const { return cname_.CName; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketSDESCName& cname) {
|
||||
cname_ = cname;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketSDESCName cname_;
|
||||
};
|
||||
|
||||
class Bye : public PacketType {
|
||||
public:
|
||||
Bye() {}
|
||||
@ -140,6 +200,102 @@ class Rpsi : public PacketType {
|
||||
RTCPUtility::RTCPPacketPSFBRPSI rpsi_;
|
||||
};
|
||||
|
||||
class App : public PacketType {
|
||||
public:
|
||||
App() {}
|
||||
virtual ~App() {}
|
||||
|
||||
uint8_t SubType() const { return app_.SubType; }
|
||||
uint32_t Name() const { return app_.Name; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketAPP& app) {
|
||||
app_ = app;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketAPP app_;
|
||||
};
|
||||
|
||||
class AppItem : public PacketType {
|
||||
public:
|
||||
AppItem() {}
|
||||
virtual ~AppItem() {}
|
||||
|
||||
uint8_t* Data() { return app_item_.Data; }
|
||||
uint16_t DataLength() const { return app_item_.Size; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketAPP& app) {
|
||||
app_item_ = app;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketAPP app_item_;
|
||||
};
|
||||
|
||||
class Pli : public PacketType {
|
||||
public:
|
||||
Pli() {}
|
||||
virtual ~Pli() {}
|
||||
|
||||
uint32_t Ssrc() const { return pli_.SenderSSRC; }
|
||||
uint32_t MediaSsrc() const { return pli_.MediaSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketPSFBPLI& pli) {
|
||||
pli_ = pli;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketPSFBPLI pli_;
|
||||
};
|
||||
|
||||
class Sli : public PacketType {
|
||||
public:
|
||||
Sli() {}
|
||||
virtual ~Sli() {}
|
||||
|
||||
uint32_t Ssrc() const { return sli_.SenderSSRC; }
|
||||
uint32_t MediaSsrc() const { return sli_.MediaSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketPSFBSLI& sli) {
|
||||
sli_ = sli;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketPSFBSLI sli_;
|
||||
};
|
||||
|
||||
class SliItem : public PacketType {
|
||||
public:
|
||||
SliItem() {}
|
||||
virtual ~SliItem() {}
|
||||
|
||||
uint16_t FirstMb() const { return sli_item_.FirstMB; }
|
||||
uint16_t NumberOfMb() const { return sli_item_.NumberOfMB; }
|
||||
uint8_t PictureId() const { return sli_item_.PictureId; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketPSFBSLIItem& sli_item) {
|
||||
sli_item_ = sli_item;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
RTCPUtility::RTCPPacketPSFBSLIItem sli_item_;
|
||||
};
|
||||
|
||||
class Fir : public PacketType {
|
||||
public:
|
||||
Fir() {}
|
||||
@ -232,7 +388,16 @@ class RtcpPacketParser {
|
||||
SenderReport* sender_report() { return &sender_report_; }
|
||||
ReceiverReport* receiver_report() { return &receiver_report_; }
|
||||
ReportBlock* report_block() { return &report_block_; }
|
||||
Sdes* sdes() { return &sdes_; }
|
||||
SdesChunk* sdes_chunk() { return &sdes_chunk_; }
|
||||
Bye* bye() { return &bye_; }
|
||||
App* app() { return &app_; }
|
||||
AppItem* app_item() { return &app_item_; }
|
||||
Ij* ij() { return &ij_; }
|
||||
IjItem* ij_item() { return &ij_item_; }
|
||||
Pli* pli() { return &pli_; }
|
||||
Sli* sli() { return &sli_; }
|
||||
SliItem* sli_item() { return &sli_item_; }
|
||||
Rpsi* rpsi() { return &rpsi_; }
|
||||
Fir* fir() { return &fir_; }
|
||||
FirItem* fir_item() { return &fir_item_; }
|
||||
@ -247,7 +412,16 @@ class RtcpPacketParser {
|
||||
SenderReport sender_report_;
|
||||
ReceiverReport receiver_report_;
|
||||
ReportBlock report_block_;
|
||||
Sdes sdes_;
|
||||
SdesChunk sdes_chunk_;
|
||||
Bye bye_;
|
||||
App app_;
|
||||
AppItem app_item_;
|
||||
Ij ij_;
|
||||
IjItem ij_item_;
|
||||
Pli pli_;
|
||||
Sli sli_;
|
||||
SliItem sli_item_;
|
||||
Rpsi rpsi_;
|
||||
Fir fir_;
|
||||
FirItem fir_item_;
|
||||
|
Loading…
Reference in New Issue
Block a user