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:
asapersson@webrtc.org 2014-06-16 14:09:28 +00:00
parent 27626a6256
commit 4b12d40008
5 changed files with 1046 additions and 207 deletions

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -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_;