diff options
author | asapersson@webrtc.org <asapersson@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2014-06-16 14:09:28 +0000 |
---|---|---|
committer | asapersson@webrtc.org <asapersson@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2014-06-16 14:09:28 +0000 |
commit | 847dfa535730a30d57cf26d788d31070b70a02af (patch) | |
tree | 5c84330013805ff5b8b8e9d3d1dcfd00a5effba1 | |
parent | e82b71dedcaaa6db0181ba52ac020fde19552189 (diff) | |
download | webrtc-847dfa535730a30d57cf26d788d31070b70a02af.tar.gz |
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/webrtc@6449 4adac7df-926f-26a2-2b94-8c16560cd09d
-rw-r--r-- | modules/rtp_rtcp/source/rtcp_packet.cc | 382 | ||||
-rw-r--r-- | modules/rtp_rtcp/source/rtcp_packet.h | 467 | ||||
-rw-r--r-- | modules/rtp_rtcp/source/rtcp_packet_unittest.cc | 189 | ||||
-rw-r--r-- | test/rtcp_packet_parser.cc | 33 | ||||
-rw-r--r-- | test/rtcp_packet_parser.h | 174 |
5 files changed, 1042 insertions, 203 deletions
diff --git a/modules/rtp_rtcp/source/rtcp_packet.cc b/modules/rtp_rtcp/source/rtcp_packet.cc index 51c86aaa..a4cdfd95 100644 --- a/modules/rtp_rtcp/source/rtcp_packet.cc +++ b/modules/rtp_rtcp/source/rtcp_packet.cc @@ -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, - 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); +void CreateReportBlocks(const std::vector<RTCPPacketReportBlockItem>& blocks, + uint8_t* buffer, + 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 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; + } + 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); } -void Bye::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const { - if (*len + Length() > max_len) { +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(Length()), packet, len); + 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 { +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; + } + 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 (*len + Length() > max_len) { + if (*length + BlockLength() > max_length) { LOG(LS_WARNING) << "Max packet size reached."; return; } - CreateNack(nack_, nack_fields_, BlockToHeaderLength(Length()), packet, len); + 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 diff --git a/modules/rtp_rtcp/source/rtcp_packet.h b/modules/rtp_rtcp/source/rtcp_packet.h index 641bd7fd..f60e848b 100644 --- a/modules/rtp_rtcp/source/rtcp_packet.h +++ b/modules/rtp_rtcp/source/rtcp_packet.h @@ -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_; }; +// Transmission Time Offsets in RTP Streams (RFC 5450). // -// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// hdr |V=2|P| RC | PT=IJ=195 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | inter-arrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// . . +// . . +// . . +// | inter-arrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // -// 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) | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// 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); + + protected: + virtual void Create( + uint8_t* packet, size_t* length, size_t max_length) const OVERRIDE; + + private: + enum { kMaxNumberOfIjItems = 0x1f }; + + size_t BlockLength() const { + return kHeaderLength + 4 * ij_items_.size(); } - void Create(uint8_t* packet, uint16_t* len) const; + 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: - RTCPUtility::RTCPPacketReportBlockItem report_block_; + 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_; @@ -366,8 +611,8 @@ class Nack : public RtcpPacket { class Rpsi : public RtcpPacket { public: Rpsi() - : RtcpPacket(), - padding_bytes_(0) { + : RtcpPacket(), + padding_bytes_(0) { memset(&rpsi_, 0, sizeof(rpsi_)); } @@ -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_; @@ -417,7 +661,7 @@ class Rpsi : public RtcpPacket { class Fir : public RtcpPacket { public: Fir() - : RtcpPacket() { + : RtcpPacket() { memset(&fir_, 0, sizeof(fir_)); memset(&fir_item_, 0, sizeof(fir_item_)); } @@ -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 diff --git a/modules/rtp_rtcp/source/rtcp_packet_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet_unittest.cc index d7ae9142..aa25c2e5 100644 --- a/modules/rtp_rtcp/source/rtcp_packet_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_packet_unittest.cc @@ -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; diff --git a/test/rtcp_packet_parser.cc b/test/rtcp_packet_parser.cc index 9ae8543d..69c50d1b 100644 --- a/test/rtcp_packet_parser.cc +++ b/test/rtcp_packet_parser.cc @@ -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; diff --git a/test/rtcp_packet_parser.h b/test/rtcp_packet_parser.h index 4db58c35..a09674f3 100644 --- a/test/rtcp_packet_parser.h +++ b/test/rtcp_packet_parser.h @@ -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_; |