Add NACK and RPSI packet types to RTCP packet builder.
Fixes bug found when parsing received RPSI packet. BUG=2450 R=mflodman@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/17419004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6194 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
2db9f45038
commit
a826006132
@ -13,9 +13,28 @@
|
|||||||
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
||||||
#include "webrtc/system_wrappers/interface/logging.h"
|
#include "webrtc/system_wrappers/interface/logging.h"
|
||||||
|
|
||||||
|
using webrtc::RTCPUtility::PT_BYE;
|
||||||
|
using webrtc::RTCPUtility::PT_PSFB;
|
||||||
|
using webrtc::RTCPUtility::PT_RR;
|
||||||
|
using webrtc::RTCPUtility::PT_RTPFB;
|
||||||
|
using webrtc::RTCPUtility::PT_SR;
|
||||||
|
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketBYE;
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketPSFBFIR;
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketPSFBFIRItem;
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketPSFBRPSI;
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketReportBlockItem;
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketRR;
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketRTPFBNACK;
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketRTPFBNACKItem;
|
||||||
|
using webrtc::RTCPUtility::RTCPPacketSR;
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace rtcp {
|
namespace rtcp {
|
||||||
namespace {
|
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, uint16_t* offset, uint8_t value) {
|
||||||
buffer[(*offset)++] = value;
|
buffer[(*offset)++] = value;
|
||||||
}
|
}
|
||||||
@ -32,9 +51,34 @@ void AssignUWord32(uint8_t* buffer, uint16_t* offset, uint32_t value) {
|
|||||||
*offset += 4;
|
*offset += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t BlockToHeaderLength(uint16_t length_in_bytes) {
|
||||||
|
// Length in 32-bit words minus 1.
|
||||||
|
assert(length_in_bytes > 0);
|
||||||
|
assert(length_in_bytes % 4 == 0);
|
||||||
|
return (length_in_bytes / 4) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
|
// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
|
||||||
//
|
//
|
||||||
// Sender report
|
// RTP header format.
|
||||||
|
// 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| RC/FMT | PT | length |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
void CreateHeader(uint8_t count_or_format, // Depends on packet type.
|
||||||
|
uint8_t packet_type,
|
||||||
|
uint16_t length,
|
||||||
|
uint8_t* buffer,
|
||||||
|
uint16_t* pos) {
|
||||||
|
const uint8_t kVersion = 2;
|
||||||
|
AssignUWord8(buffer, pos, (kVersion << 6) + count_or_format);
|
||||||
|
AssignUWord8(buffer, pos, packet_type);
|
||||||
|
AssignUWord16(buffer, pos, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sender report (SR) (RFC 3550).
|
||||||
// 0 1 2 3
|
// 0 1 2 3
|
||||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
// 0 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
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@ -53,13 +97,11 @@ void AssignUWord32(uint8_t* buffer, uint16_t* offset, uint32_t value) {
|
|||||||
// | sender's octet count |
|
// | sender's octet count |
|
||||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
|
||||||
void CreateSenderReport(const RTCPUtility::RTCPPacketSR& sr,
|
void CreateSenderReport(const RTCPPacketSR& sr,
|
||||||
|
uint16_t length,
|
||||||
uint8_t* buffer,
|
uint8_t* buffer,
|
||||||
uint16_t* pos) {
|
uint16_t* pos) {
|
||||||
const uint16_t kLength = 6 + (6 * sr.NumberOfReportBlocks);
|
CreateHeader(sr.NumberOfReportBlocks, PT_SR, length, buffer, pos);
|
||||||
AssignUWord8(buffer, pos, 0x80 + sr.NumberOfReportBlocks);
|
|
||||||
AssignUWord8(buffer, pos, RTCPUtility::PT_SR);
|
|
||||||
AssignUWord16(buffer, pos, kLength);
|
|
||||||
AssignUWord32(buffer, pos, sr.SenderSSRC);
|
AssignUWord32(buffer, pos, sr.SenderSSRC);
|
||||||
AssignUWord32(buffer, pos, sr.NTPMostSignificant);
|
AssignUWord32(buffer, pos, sr.NTPMostSignificant);
|
||||||
AssignUWord32(buffer, pos, sr.NTPLeastSignificant);
|
AssignUWord32(buffer, pos, sr.NTPLeastSignificant);
|
||||||
@ -68,7 +110,7 @@ void CreateSenderReport(const RTCPUtility::RTCPPacketSR& sr,
|
|||||||
AssignUWord32(buffer, pos, sr.SenderOctetCount);
|
AssignUWord32(buffer, pos, sr.SenderOctetCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receiver report, header (RFC 3550).
|
// Receiver report (RR), header (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
|
// 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
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@ -77,13 +119,11 @@ void CreateSenderReport(const RTCPUtility::RTCPPacketSR& sr,
|
|||||||
// | SSRC of packet sender |
|
// | SSRC of packet sender |
|
||||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
|
||||||
void CreateReceiverReport(const RTCPUtility::RTCPPacketRR& rr,
|
void CreateReceiverReport(const RTCPPacketRR& rr,
|
||||||
|
uint16_t length,
|
||||||
uint8_t* buffer,
|
uint8_t* buffer,
|
||||||
uint16_t* pos) {
|
uint16_t* pos) {
|
||||||
const uint16_t kLength = 1 + (6 * rr.NumberOfReportBlocks);
|
CreateHeader(rr.NumberOfReportBlocks, PT_RR, length, buffer, pos);
|
||||||
AssignUWord8(buffer, pos, 0x80 + rr.NumberOfReportBlocks);
|
|
||||||
AssignUWord8(buffer, pos, RTCPUtility::PT_RR);
|
|
||||||
AssignUWord16(buffer, pos, kLength);
|
|
||||||
AssignUWord32(buffer, pos, rr.SenderSSRC);
|
AssignUWord32(buffer, pos, rr.SenderSSRC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,10 +144,9 @@ void CreateReceiverReport(const RTCPUtility::RTCPPacketRR& rr,
|
|||||||
// | delay since last SR (DLSR) |
|
// | delay since last SR (DLSR) |
|
||||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
|
||||||
void CreateReportBlock(
|
void CreateReportBlock(const RTCPPacketReportBlockItem& report_block,
|
||||||
const RTCPUtility::RTCPPacketReportBlockItem& report_block,
|
uint8_t* buffer,
|
||||||
uint8_t* buffer,
|
uint16_t* pos) {
|
||||||
uint16_t* pos) {
|
|
||||||
AssignUWord32(buffer, pos, report_block.SSRC);
|
AssignUWord32(buffer, pos, report_block.SSRC);
|
||||||
AssignUWord8(buffer, pos, report_block.FractionLost);
|
AssignUWord8(buffer, pos, report_block.FractionLost);
|
||||||
AssignUWord24(buffer, pos, report_block.CumulativeNumOfPacketsLost);
|
AssignUWord24(buffer, pos, report_block.CumulativeNumOfPacketsLost);
|
||||||
@ -130,14 +169,12 @@ void CreateReportBlock(
|
|||||||
// (opt) | length | reason for leaving ...
|
// (opt) | length | reason for leaving ...
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
void CreateBye(const RTCPUtility::RTCPPacketBYE& bye,
|
void CreateBye(const RTCPPacketBYE& bye,
|
||||||
const std::vector<uint32_t>& csrcs,
|
const std::vector<uint32_t>& csrcs,
|
||||||
|
uint16_t length,
|
||||||
uint8_t* buffer,
|
uint8_t* buffer,
|
||||||
uint16_t* pos) {
|
uint16_t* pos) {
|
||||||
const uint8_t kNumSsrcAndCsrcs = 1 + csrcs.size();
|
CreateHeader(length, PT_BYE, length, buffer, pos);
|
||||||
AssignUWord8(buffer, pos, 0x80 + kNumSsrcAndCsrcs);
|
|
||||||
AssignUWord8(buffer, pos, RTCPUtility::PT_BYE);
|
|
||||||
AssignUWord16(buffer, pos, kNumSsrcAndCsrcs);
|
|
||||||
AssignUWord32(buffer, pos, bye.SenderSSRC);
|
AssignUWord32(buffer, pos, bye.SenderSSRC);
|
||||||
for (std::vector<uint32_t>::const_iterator it = csrcs.begin();
|
for (std::vector<uint32_t>::const_iterator it = csrcs.begin();
|
||||||
it != csrcs.end(); ++it) {
|
it != csrcs.end(); ++it) {
|
||||||
@ -161,6 +198,64 @@ void CreateBye(const RTCPUtility::RTCPPacketBYE& bye,
|
|||||||
// : Feedback Control Information (FCI) :
|
// : Feedback Control Information (FCI) :
|
||||||
// :
|
// :
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// Generic NACK (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
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | PID | BLP |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
void CreateNack(const RTCPPacketRTPFBNACK& nack,
|
||||||
|
const std::vector<RTCPPacketRTPFBNACKItem>& nack_fields,
|
||||||
|
uint16_t length,
|
||||||
|
uint8_t* buffer,
|
||||||
|
uint16_t* pos) {
|
||||||
|
const uint8_t kFmt = 1;
|
||||||
|
CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
|
||||||
|
AssignUWord32(buffer, pos, nack.SenderSSRC);
|
||||||
|
AssignUWord32(buffer, pos, nack.MediaSSRC);
|
||||||
|
for (std::vector<RTCPPacketRTPFBNACKItem>::const_iterator
|
||||||
|
it = nack_fields.begin(); it != nack_fields.end(); ++it) {
|
||||||
|
AssignUWord16(buffer, pos, (*it).PacketID);
|
||||||
|
AssignUWord16(buffer, pos, (*it).BitMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference picture selection indication (RPSI) (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
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | PB |0| Payload Type| Native RPSI bit string |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | defined per codec ... | Padding (0) |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
void CreateRpsi(const RTCPPacketPSFBRPSI& rpsi,
|
||||||
|
uint8_t padding_bytes,
|
||||||
|
uint16_t length,
|
||||||
|
uint8_t* buffer,
|
||||||
|
uint16_t* pos) {
|
||||||
|
// Native bit string should be a multiple of 8 bits.
|
||||||
|
assert(rpsi.NumberOfValidBits % 8 == 0);
|
||||||
|
const uint8_t kFmt = 3;
|
||||||
|
CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
|
||||||
|
AssignUWord32(buffer, pos, rpsi.SenderSSRC);
|
||||||
|
AssignUWord32(buffer, pos, rpsi.MediaSSRC);
|
||||||
|
AssignUWord8(buffer, pos, padding_bytes * 8);
|
||||||
|
AssignUWord8(buffer, pos, rpsi.PayloadType);
|
||||||
|
memcpy(buffer + *pos, rpsi.NativeBitString, rpsi.NumberOfValidBits / 8);
|
||||||
|
*pos += rpsi.NumberOfValidBits / 8;
|
||||||
|
memset(buffer + *pos, 0, padding_bytes);
|
||||||
|
*pos += padding_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
// Full intra request (FIR) (RFC 5104).
|
// Full intra request (FIR) (RFC 5104).
|
||||||
//
|
//
|
||||||
// FCI:
|
// FCI:
|
||||||
@ -173,27 +268,26 @@ void CreateBye(const RTCPUtility::RTCPPacketBYE& bye,
|
|||||||
// | Seq nr. | Reserved |
|
// | Seq nr. | Reserved |
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
void CreateFirRequest(const RTCPUtility::RTCPPacketPSFBFIR& fir,
|
void CreateFir(const RTCPPacketPSFBFIR& fir,
|
||||||
const RTCPUtility::RTCPPacketPSFBFIRItem& fir_item,
|
const RTCPPacketPSFBFIRItem& fir_item,
|
||||||
uint8_t* buffer,
|
uint16_t length,
|
||||||
uint16_t* pos) {
|
uint8_t* buffer,
|
||||||
const uint16_t kLength = 4;
|
uint16_t* pos) {
|
||||||
const uint8_t kFmt = 4;
|
const uint8_t kFmt = 4;
|
||||||
AssignUWord8(buffer, pos, 0x80 + kFmt);
|
CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
|
||||||
AssignUWord8(buffer, pos, RTCPUtility::PT_PSFB);
|
|
||||||
AssignUWord16(buffer, pos, kLength);
|
|
||||||
AssignUWord32(buffer, pos, fir.SenderSSRC);
|
AssignUWord32(buffer, pos, fir.SenderSSRC);
|
||||||
AssignUWord32(buffer, pos, 0);
|
AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
|
||||||
AssignUWord32(buffer, pos, fir_item.SSRC);
|
AssignUWord32(buffer, pos, fir_item.SSRC);
|
||||||
AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
|
AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
|
||||||
AssignUWord24(buffer, pos, 0);
|
AssignUWord24(buffer, pos, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendReportBlocks(const std::vector<ReportBlock*>& report_blocks,
|
template <typename T>
|
||||||
uint8_t* buffer,
|
void AppendBlocks(const std::vector<T*>& blocks,
|
||||||
uint16_t* pos) {
|
uint8_t* buffer,
|
||||||
for (std::vector<ReportBlock*>::const_iterator it = report_blocks.begin();
|
uint16_t* pos) {
|
||||||
it != report_blocks.end(); ++it) {
|
for (typename std::vector<T*>::const_iterator it = blocks.begin();
|
||||||
|
it != blocks.end(); ++it) {
|
||||||
(*it)->Create(buffer, pos);
|
(*it)->Create(buffer, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,8 +330,8 @@ void SenderReport::Create(uint8_t* packet,
|
|||||||
LOG(LS_WARNING) << "Max packet size reached.";
|
LOG(LS_WARNING) << "Max packet size reached.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CreateSenderReport(sr_, packet, len);
|
CreateSenderReport(sr_, BlockToHeaderLength(Length()), packet, len);
|
||||||
AppendReportBlocks(report_blocks_, packet, len);
|
AppendBlocks(report_blocks_, packet, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SenderReport::WithReportBlock(ReportBlock* block) {
|
void SenderReport::WithReportBlock(ReportBlock* block) {
|
||||||
@ -257,8 +351,8 @@ void ReceiverReport::Create(uint8_t* packet,
|
|||||||
LOG(LS_WARNING) << "Max packet size reached.";
|
LOG(LS_WARNING) << "Max packet size reached.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CreateReceiverReport(rr_, packet, len);
|
CreateReceiverReport(rr_, BlockToHeaderLength(Length()), packet, len);
|
||||||
AppendReportBlocks(report_blocks_, packet, len);
|
AppendBlocks(report_blocks_, packet, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiverReport::WithReportBlock(ReportBlock* block) {
|
void ReceiverReport::WithReportBlock(ReportBlock* block) {
|
||||||
@ -271,12 +365,16 @@ void ReceiverReport::WithReportBlock(ReportBlock* block) {
|
|||||||
rr_.NumberOfReportBlocks = report_blocks_.size();
|
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 {
|
void Bye::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||||
if (*len + Length() > max_len) {
|
if (*len + Length() > max_len) {
|
||||||
LOG(LS_WARNING) << "Max packet size reached.";
|
LOG(LS_WARNING) << "Max packet size reached.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CreateBye(bye_, csrcs_, packet, len);
|
CreateBye(bye_, csrcs_, BlockToHeaderLength(Length()), packet, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bye::WithCsrc(uint32_t csrc) {
|
void Bye::WithCsrc(uint32_t csrc) {
|
||||||
@ -287,16 +385,81 @@ void Bye::WithCsrc(uint32_t csrc) {
|
|||||||
csrcs_.push_back(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) {
|
||||||
|
LOG(LS_WARNING) << "Max packet size reached.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CreateNack(nack_, nack_fields_, BlockToHeaderLength(Length()), packet, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nack::WithList(const uint16_t* nack_list, int length) {
|
||||||
|
assert(nack_list);
|
||||||
|
assert(nack_fields_.empty());
|
||||||
|
int i = 0;
|
||||||
|
while (i < length) {
|
||||||
|
uint16_t pid = nack_list[i++];
|
||||||
|
// Bitmask specifies losses in any of the 16 packets following the pid.
|
||||||
|
uint16_t bitmask = 0;
|
||||||
|
while (i < length) {
|
||||||
|
int shift = static_cast<uint16_t>(nack_list[i] - pid) - 1;
|
||||||
|
if (shift >= 0 && shift <= 15) {
|
||||||
|
bitmask |= (1 << shift);
|
||||||
|
++i;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RTCPUtility::RTCPPacketRTPFBNACKItem item;
|
||||||
|
item.PacketID = pid;
|
||||||
|
item.BitMask = bitmask;
|
||||||
|
nack_fields_.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rpsi::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||||
|
assert(rpsi_.NumberOfValidBits > 0);
|
||||||
|
if (*len + Length() > max_len) {
|
||||||
|
LOG(LS_WARNING) << "Max packet size reached.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CreateRpsi(rpsi_, padding_bytes_, BlockToHeaderLength(Length()), packet, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rpsi::WithPictureId(uint64_t picture_id) {
|
||||||
|
const uint32_t kPidBits = 7;
|
||||||
|
const uint64_t k7MsbZeroMask = 0x1ffffffffffffff;
|
||||||
|
uint8_t required_bytes = 0;
|
||||||
|
uint64_t shifted_pid = picture_id;
|
||||||
|
do {
|
||||||
|
++required_bytes;
|
||||||
|
shifted_pid = (shifted_pid >> kPidBits) & k7MsbZeroMask;
|
||||||
|
} while (shifted_pid > 0);
|
||||||
|
|
||||||
|
// Convert picture id to native bit string (natively defined by the video
|
||||||
|
// codec).
|
||||||
|
int pos = 0;
|
||||||
|
for (int i = required_bytes - 1; i > 0; i--) {
|
||||||
|
rpsi_.NativeBitString[pos++] =
|
||||||
|
0x80 | static_cast<uint8_t>(picture_id >> (i * kPidBits));
|
||||||
|
}
|
||||||
|
rpsi_.NativeBitString[pos++] = static_cast<uint8_t>(picture_id & 0x7f);
|
||||||
|
rpsi_.NumberOfValidBits = pos * 8;
|
||||||
|
|
||||||
|
// Calculate padding bytes (to reach next 32-bit boundary, 1, 2 or 3 bytes).
|
||||||
|
padding_bytes_ = 4 - ((2 + required_bytes) % 4);
|
||||||
|
if (padding_bytes_ == 4) {
|
||||||
|
padding_bytes_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Fir::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
void Fir::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||||
if (*len + Length() > max_len) {
|
if (*len + Length() > max_len) {
|
||||||
LOG(LS_WARNING) << "Max packet size reached.";
|
LOG(LS_WARNING) << "Max packet size reached.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CreateFirRequest(fir_, fir_item_, packet, len);
|
CreateFir(fir_, fir_item_, BlockToHeaderLength(Length()), packet, len);
|
||||||
}
|
|
||||||
|
|
||||||
void ReportBlock::Create(uint8_t* packet, uint16_t* len) const {
|
|
||||||
CreateReportBlock(report_block_, packet, len);
|
|
||||||
}
|
}
|
||||||
} // namespace rtcp
|
} // namespace rtcp
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -244,7 +244,7 @@ class ReportBlock {
|
|||||||
report_block_.DelayLastSR = delay_last_sr;
|
report_block_.DelayLastSR = delay_last_sr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Create(uint8_t* array, uint16_t* cur_pos) const;
|
void Create(uint8_t* packet, uint16_t* len) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RTCPUtility::RTCPPacketReportBlockItem report_block_;
|
RTCPUtility::RTCPPacketReportBlockItem report_block_;
|
||||||
@ -285,7 +285,7 @@ class Bye : public RtcpPacket {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t Length() const {
|
uint16_t Length() const {
|
||||||
const uint16_t kByeBlockLen = 8 + 4*csrcs_.size();
|
const uint16_t kByeBlockLen = 8 + 4 * csrcs_.size();
|
||||||
return kByeBlockLen;
|
return kByeBlockLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,6 +309,98 @@ class Bye : public RtcpPacket {
|
|||||||
// : Feedback Control Information (FCI) :
|
// : Feedback Control Information (FCI) :
|
||||||
// :
|
// :
|
||||||
|
|
||||||
|
// Generic NACK (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
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | PID | BLP |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
class Nack : public RtcpPacket {
|
||||||
|
public:
|
||||||
|
Nack()
|
||||||
|
: RtcpPacket() {
|
||||||
|
memset(&nack_, 0, sizeof(nack_));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Nack() {}
|
||||||
|
|
||||||
|
void From(uint32_t ssrc) {
|
||||||
|
nack_.SenderSSRC = ssrc;
|
||||||
|
}
|
||||||
|
void To(uint32_t ssrc) {
|
||||||
|
nack_.MediaSSRC = ssrc;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t Length() const {
|
||||||
|
const uint16_t kNackBlockLen = 4 * (3 + nack_fields_.size());
|
||||||
|
return kNackBlockLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTCPUtility::RTCPPacketRTPFBNACK nack_;
|
||||||
|
std::vector<RTCPUtility::RTCPPacketRTPFBNACKItem> nack_fields_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Nack);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reference picture selection indication (RPSI) (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
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | PB |0| Payload Type| Native RPSI bit string |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | defined per codec ... | Padding (0) |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
class Rpsi : public RtcpPacket {
|
||||||
|
public:
|
||||||
|
Rpsi()
|
||||||
|
: RtcpPacket(),
|
||||||
|
padding_bytes_(0) {
|
||||||
|
memset(&rpsi_, 0, sizeof(rpsi_));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Rpsi() {}
|
||||||
|
|
||||||
|
void From(uint32_t ssrc) {
|
||||||
|
rpsi_.SenderSSRC = ssrc;
|
||||||
|
}
|
||||||
|
void To(uint32_t ssrc) {
|
||||||
|
rpsi_.MediaSSRC = ssrc;
|
||||||
|
}
|
||||||
|
void WithPayloadType(uint8_t payload) {
|
||||||
|
assert(payload <= 0x7f);
|
||||||
|
rpsi_.PayloadType = payload;
|
||||||
|
}
|
||||||
|
void WithPictureId(uint64_t picture_id);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const
|
||||||
|
OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t Length() const {
|
||||||
|
const uint16_t kRpsiBlockLen =
|
||||||
|
12 + 2 + (rpsi_.NumberOfValidBits / 8) + padding_bytes_;
|
||||||
|
return kRpsiBlockLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t padding_bytes_;
|
||||||
|
RTCPUtility::RTCPPacketPSFBRPSI rpsi_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Rpsi);
|
||||||
|
};
|
||||||
|
|
||||||
// Full intra request (FIR) (RFC 5104).
|
// Full intra request (FIR) (RFC 5104).
|
||||||
//
|
//
|
||||||
|
@ -18,11 +18,13 @@
|
|||||||
using webrtc::rtcp::Bye;
|
using webrtc::rtcp::Bye;
|
||||||
using webrtc::rtcp::Empty;
|
using webrtc::rtcp::Empty;
|
||||||
using webrtc::rtcp::Fir;
|
using webrtc::rtcp::Fir;
|
||||||
using webrtc::rtcp::SenderReport;
|
using webrtc::rtcp::Nack;
|
||||||
using webrtc::rtcp::RawPacket;
|
using webrtc::rtcp::RawPacket;
|
||||||
using webrtc::rtcp::ReceiverReport;
|
using webrtc::rtcp::ReceiverReport;
|
||||||
using webrtc::rtcp::ReportBlock;
|
using webrtc::rtcp::ReportBlock;
|
||||||
|
using webrtc::rtcp::Rpsi;
|
||||||
using webrtc::test::RtcpPacketParser;
|
using webrtc::test::RtcpPacketParser;
|
||||||
|
using webrtc::rtcp::SenderReport;
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -152,6 +154,121 @@ TEST(RtcpPacketTest, SrWithTwoReportBlocks) {
|
|||||||
EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc + 1));
|
EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(RtcpPacketTest, Nack) {
|
||||||
|
Nack nack;
|
||||||
|
const uint16_t kList[] = {0, 1, 3, 8, 16};
|
||||||
|
const uint16_t kListLength = sizeof(kList) / sizeof(kList[0]);
|
||||||
|
nack.From(kSenderSsrc);
|
||||||
|
nack.To(kRemoteSsrc);
|
||||||
|
nack.WithList(kList, kListLength);
|
||||||
|
RawPacket packet = nack.Build();
|
||||||
|
RtcpPacketParser parser;
|
||||||
|
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||||
|
EXPECT_EQ(1, parser.nack()->num_packets());
|
||||||
|
EXPECT_EQ(kSenderSsrc, parser.nack()->Ssrc());
|
||||||
|
EXPECT_EQ(kRemoteSsrc, parser.nack()->MediaSsrc());
|
||||||
|
EXPECT_EQ(1, parser.nack_item()->num_packets());
|
||||||
|
std::vector<uint16_t> seqs = parser.nack_item()->last_nack_list();
|
||||||
|
EXPECT_EQ(kListLength, seqs.size());
|
||||||
|
for (size_t i = 0; i < kListLength; ++i) {
|
||||||
|
EXPECT_EQ(kList[i], seqs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RtcpPacketTest, NackWithWrap) {
|
||||||
|
Nack nack;
|
||||||
|
const uint16_t kList[] = {65500, 65516, 65534, 65535, 0, 1, 3, 20, 100};
|
||||||
|
const uint16_t kListLength = sizeof(kList) / sizeof(kList[0]);
|
||||||
|
nack.From(kSenderSsrc);
|
||||||
|
nack.To(kRemoteSsrc);
|
||||||
|
nack.WithList(kList, kListLength);
|
||||||
|
RawPacket packet = nack.Build();
|
||||||
|
RtcpPacketParser parser;
|
||||||
|
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||||
|
EXPECT_EQ(1, parser.nack()->num_packets());
|
||||||
|
EXPECT_EQ(kSenderSsrc, parser.nack()->Ssrc());
|
||||||
|
EXPECT_EQ(kRemoteSsrc, parser.nack()->MediaSsrc());
|
||||||
|
EXPECT_EQ(4, parser.nack_item()->num_packets());
|
||||||
|
std::vector<uint16_t> seqs = parser.nack_item()->last_nack_list();
|
||||||
|
EXPECT_EQ(kListLength, seqs.size());
|
||||||
|
for (size_t i = 0; i < kListLength; ++i) {
|
||||||
|
EXPECT_EQ(kList[i], seqs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RtcpPacketTest, Rpsi) {
|
||||||
|
Rpsi rpsi;
|
||||||
|
// 1000001 (7 bits = 1 byte in native string).
|
||||||
|
const uint64_t kPictureId = 0x41;
|
||||||
|
const uint16_t kNumberOfValidBytes = 1;
|
||||||
|
rpsi.WithPayloadType(100);
|
||||||
|
rpsi.WithPictureId(kPictureId);
|
||||||
|
|
||||||
|
RawPacket packet = rpsi.Build();
|
||||||
|
RtcpPacketParser parser;
|
||||||
|
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||||
|
EXPECT_EQ(100, parser.rpsi()->PayloadType());
|
||||||
|
EXPECT_EQ(kNumberOfValidBytes * 8, parser.rpsi()->NumberOfValidBits());
|
||||||
|
EXPECT_EQ(kPictureId, parser.rpsi()->PictureId());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RtcpPacketTest, RpsiWithTwoByteNativeString) {
|
||||||
|
Rpsi rpsi;
|
||||||
|
// |1 0000001 (7 bits = 1 byte in native string).
|
||||||
|
const uint64_t kPictureId = 0x81;
|
||||||
|
const uint16_t kNumberOfValidBytes = 2;
|
||||||
|
rpsi.WithPictureId(kPictureId);
|
||||||
|
|
||||||
|
RawPacket packet = rpsi.Build();
|
||||||
|
RtcpPacketParser parser;
|
||||||
|
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||||
|
EXPECT_EQ(kNumberOfValidBytes * 8, parser.rpsi()->NumberOfValidBits());
|
||||||
|
EXPECT_EQ(kPictureId, parser.rpsi()->PictureId());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RtcpPacketTest, RpsiWithThreeByteNativeString) {
|
||||||
|
Rpsi rpsi;
|
||||||
|
// 10000|00 100000|0 1000000 (7 bits = 1 byte in native string).
|
||||||
|
const uint64_t kPictureId = 0x102040;
|
||||||
|
const uint16_t kNumberOfValidBytes = 3;
|
||||||
|
rpsi.WithPictureId(kPictureId);
|
||||||
|
|
||||||
|
RawPacket packet = rpsi.Build();
|
||||||
|
RtcpPacketParser parser;
|
||||||
|
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||||
|
EXPECT_EQ(kNumberOfValidBytes * 8, parser.rpsi()->NumberOfValidBits());
|
||||||
|
EXPECT_EQ(kPictureId, parser.rpsi()->PictureId());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RtcpPacketTest, RpsiWithFourByteNativeString) {
|
||||||
|
Rpsi rpsi;
|
||||||
|
// 1000|001 00001|01 100001|1 1000010 (7 bits = 1 byte in native string).
|
||||||
|
const uint64_t kPictureId = 0x84161C2;
|
||||||
|
const uint16_t kNumberOfValidBytes = 4;
|
||||||
|
rpsi.WithPictureId(kPictureId);
|
||||||
|
|
||||||
|
RawPacket packet = rpsi.Build();
|
||||||
|
RtcpPacketParser parser;
|
||||||
|
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||||
|
EXPECT_EQ(kNumberOfValidBytes * 8, parser.rpsi()->NumberOfValidBits());
|
||||||
|
EXPECT_EQ(kPictureId, parser.rpsi()->PictureId());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RtcpPacketTest, RpsiWithMaxPictureId) {
|
||||||
|
Rpsi rpsi;
|
||||||
|
// 1 1111111| 1111111 1|111111 11|11111 111|1111 1111|111 11111|
|
||||||
|
// 11 111111|1 1111111 (7 bits = 1 byte in native string).
|
||||||
|
const uint64_t kPictureId = 0xffffffffffffffff;
|
||||||
|
const uint16_t kNumberOfValidBytes = 10;
|
||||||
|
rpsi.WithPictureId(kPictureId);
|
||||||
|
|
||||||
|
RawPacket packet = rpsi.Build();
|
||||||
|
RtcpPacketParser parser;
|
||||||
|
parser.Parse(packet.buffer(), packet.buffer_length());
|
||||||
|
EXPECT_EQ(kNumberOfValidBytes * 8, parser.rpsi()->NumberOfValidBits());
|
||||||
|
EXPECT_EQ(kPictureId, parser.rpsi()->PictureId());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(RtcpPacketTest, Fir) {
|
TEST(RtcpPacketTest, Fir) {
|
||||||
Fir fir;
|
Fir fir;
|
||||||
fir.From(kSenderSsrc);
|
fir.From(kSenderSsrc);
|
||||||
|
@ -1266,31 +1266,27 @@ RTCPUtility::RTCPParserV2::ParseFBCommon(const RTCPCommonHeader& header)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool RTCPUtility::RTCPParserV2::ParseRPSIItem() {
|
||||||
RTCPUtility::RTCPParserV2::ParseRPSIItem()
|
|
||||||
{
|
// RFC 4585 6.3.3. Reference Picture Selection Indication (RPSI).
|
||||||
// RFC 4585 6.3.3. Reference Picture Selection Indication (RPSI)
|
//
|
||||||
/*
|
// 0 1 2 3
|
||||||
0 1 2 3
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
0 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
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// | PB |0| Payload Type| Native RPSI bit string |
|
||||||
| PB |0| Payload Type| Native RPSI bit string |
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// | defined per codec ... | Padding (0) |
|
||||||
| defined per codec ... | Padding (0) |
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
||||||
*/
|
|
||||||
|
|
||||||
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
|
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
|
||||||
|
|
||||||
if (length < 4)
|
if (length < 4) {
|
||||||
{
|
|
||||||
_state = State_TopLevel;
|
_state = State_TopLevel;
|
||||||
|
|
||||||
EndCurrentBlock();
|
EndCurrentBlock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(length > 2+RTCP_RPSI_DATA_SIZE)
|
if (length > 2 + RTCP_RPSI_DATA_SIZE) {
|
||||||
{
|
|
||||||
_state = State_TopLevel;
|
_state = State_TopLevel;
|
||||||
|
|
||||||
EndCurrentBlock();
|
EndCurrentBlock();
|
||||||
@ -1299,12 +1295,14 @@ RTCPUtility::RTCPParserV2::ParseRPSIItem()
|
|||||||
|
|
||||||
_packetType = kRtcpPsfbRpsiCode;
|
_packetType = kRtcpPsfbRpsiCode;
|
||||||
|
|
||||||
uint8_t paddingBits = *_ptrRTCPData++;
|
uint8_t padding_bits = *_ptrRTCPData++;
|
||||||
_packet.RPSI.PayloadType = *_ptrRTCPData++;
|
_packet.RPSI.PayloadType = *_ptrRTCPData++;
|
||||||
|
|
||||||
memcpy(_packet.RPSI.NativeBitString, _ptrRTCPData, length-2);
|
memcpy(_packet.RPSI.NativeBitString, _ptrRTCPData, length - 2);
|
||||||
|
_ptrRTCPData += length - 2;
|
||||||
|
|
||||||
_packet.RPSI.NumberOfValidBits = uint16_t(length-2)*8 - paddingBits;
|
_packet.RPSI.NumberOfValidBits =
|
||||||
|
static_cast<uint16_t>(length - 2) * 8 - padding_bits;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,25 +23,54 @@ void RtcpPacketParser::Parse(const void *data, int len) {
|
|||||||
for (RTCPUtility::RTCPPacketTypes type = parser.Begin();
|
for (RTCPUtility::RTCPPacketTypes type = parser.Begin();
|
||||||
type != RTCPUtility::kRtcpNotValidCode;
|
type != RTCPUtility::kRtcpNotValidCode;
|
||||||
type = parser.Iterate()) {
|
type = parser.Iterate()) {
|
||||||
if (type == RTCPUtility::kRtcpSrCode) {
|
switch (type) {
|
||||||
sender_report_.Set(parser.Packet().SR);
|
case RTCPUtility::kRtcpSrCode:
|
||||||
} else if (type == RTCPUtility::kRtcpRrCode) {
|
sender_report_.Set(parser.Packet().SR);
|
||||||
receiver_report_.Set(parser.Packet().RR);
|
break;
|
||||||
} else if (type == RTCPUtility::kRtcpByeCode) {
|
case RTCPUtility::kRtcpRrCode:
|
||||||
bye_.Set(parser.Packet().BYE);
|
receiver_report_.Set(parser.Packet().RR);
|
||||||
} else if (type == RTCPUtility::kRtcpReportBlockItemCode) {
|
break;
|
||||||
report_block_.Set(parser.Packet().ReportBlockItem);
|
case RTCPUtility::kRtcpByeCode:
|
||||||
++report_blocks_per_ssrc_[parser.Packet().ReportBlockItem.SSRC];
|
bye_.Set(parser.Packet().BYE);
|
||||||
} else if (type == RTCPUtility::kRtcpPsfbFirCode) {
|
break;
|
||||||
fir_.Set(parser.Packet().FIR);
|
case RTCPUtility::kRtcpReportBlockItemCode:
|
||||||
} else if (type == webrtc::RTCPUtility::kRtcpPsfbFirItemCode) {
|
report_block_.Set(parser.Packet().ReportBlockItem);
|
||||||
fir_item_.Set(parser.Packet().FIRItem);
|
++report_blocks_per_ssrc_[parser.Packet().ReportBlockItem.SSRC];
|
||||||
} else if (type == RTCPUtility::kRtcpRtpfbNackCode) {
|
break;
|
||||||
nack_.Set(parser.Packet().NACK);
|
case RTCPUtility::kRtcpPsfbRpsiCode:
|
||||||
} else if (type == RTCPUtility::kRtcpRtpfbNackItemCode) {
|
rpsi_.Set(parser.Packet().RPSI);
|
||||||
nack_item_.Set(parser.Packet().NACKItem);
|
break;
|
||||||
|
case RTCPUtility::kRtcpPsfbFirCode:
|
||||||
|
fir_.Set(parser.Packet().FIR);
|
||||||
|
break;
|
||||||
|
case RTCPUtility::kRtcpPsfbFirItemCode:
|
||||||
|
fir_item_.Set(parser.Packet().FIRItem);
|
||||||
|
break;
|
||||||
|
case RTCPUtility::kRtcpRtpfbNackCode:
|
||||||
|
nack_.Set(parser.Packet().NACK);
|
||||||
|
nack_item_.Clear();
|
||||||
|
break;
|
||||||
|
case RTCPUtility::kRtcpRtpfbNackItemCode:
|
||||||
|
nack_item_.Set(parser.Packet().NACKItem);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Rpsi::PictureId() const {
|
||||||
|
assert(num_packets_ > 0);
|
||||||
|
uint16_t num_bytes = rpsi_.NumberOfValidBits / 8;
|
||||||
|
assert(num_bytes > 0);
|
||||||
|
uint64_t picture_id = 0;
|
||||||
|
for (uint16_t i = 0; i < num_bytes - 1; ++i) {
|
||||||
|
picture_id += (rpsi_.NativeBitString[i] & 0x7f);
|
||||||
|
picture_id <<= 7;
|
||||||
|
}
|
||||||
|
picture_id += (rpsi_.NativeBitString[num_bytes - 1] & 0x7f);
|
||||||
|
return picture_id;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -23,167 +23,192 @@ namespace test {
|
|||||||
|
|
||||||
class RtcpPacketParser;
|
class RtcpPacketParser;
|
||||||
|
|
||||||
class SenderReport {
|
class PacketType {
|
||||||
public:
|
public:
|
||||||
SenderReport() : num_packets_(0) {}
|
virtual ~PacketType() {}
|
||||||
~SenderReport() {}
|
|
||||||
|
|
||||||
int num_packets() { return num_packets_; }
|
int num_packets() const { return num_packets_; }
|
||||||
uint32_t Ssrc() { return sr_.SenderSSRC; }
|
|
||||||
uint32_t NtpSec() { return sr_.NTPMostSignificant; }
|
protected:
|
||||||
uint32_t NtpFrac() { return sr_.NTPLeastSignificant; }
|
PacketType() : num_packets_(0) {}
|
||||||
uint32_t RtpTimestamp() { return sr_.RTPTimestamp; }
|
|
||||||
uint32_t PacketCount() { return sr_.SenderPacketCount; }
|
int num_packets_;
|
||||||
uint32_t OctetCount() { return sr_.SenderOctetCount; }
|
};
|
||||||
|
|
||||||
|
class SenderReport : public PacketType {
|
||||||
|
public:
|
||||||
|
SenderReport() {}
|
||||||
|
virtual ~SenderReport() {}
|
||||||
|
|
||||||
|
uint32_t Ssrc() const { return sr_.SenderSSRC; }
|
||||||
|
uint32_t NtpSec() const { return sr_.NTPMostSignificant; }
|
||||||
|
uint32_t NtpFrac() const { return sr_.NTPLeastSignificant; }
|
||||||
|
uint32_t RtpTimestamp() const { return sr_.RTPTimestamp; }
|
||||||
|
uint32_t PacketCount() const { return sr_.SenderPacketCount; }
|
||||||
|
uint32_t OctetCount() const { return sr_.SenderOctetCount; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RtcpPacketParser;
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
void Set(const RTCPUtility::RTCPPacketSR& sr) {
|
void Set(const RTCPUtility::RTCPPacketSR& sr) {
|
||||||
sr_ = sr;
|
sr_ = sr;
|
||||||
++num_packets_;
|
++num_packets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_packets_;
|
|
||||||
RTCPUtility::RTCPPacketSR sr_;
|
RTCPUtility::RTCPPacketSR sr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReceiverReport {
|
class ReceiverReport : public PacketType {
|
||||||
public:
|
public:
|
||||||
ReceiverReport() : num_packets_(0) {}
|
ReceiverReport() {}
|
||||||
~ReceiverReport() {}
|
virtual ~ReceiverReport() {}
|
||||||
|
|
||||||
int num_packets() { return num_packets_; }
|
uint32_t Ssrc() const { return rr_.SenderSSRC; }
|
||||||
uint32_t Ssrc() { return rr_.SenderSSRC; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RtcpPacketParser;
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
void Set(const RTCPUtility::RTCPPacketRR& rr) {
|
void Set(const RTCPUtility::RTCPPacketRR& rr) {
|
||||||
rr_ = rr;
|
rr_ = rr;
|
||||||
++num_packets_;
|
++num_packets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_packets_;
|
|
||||||
RTCPUtility::RTCPPacketRR rr_;
|
RTCPUtility::RTCPPacketRR rr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReportBlock {
|
class ReportBlock : public PacketType {
|
||||||
public:
|
public:
|
||||||
ReportBlock() : num_packets_(0) {}
|
ReportBlock() {}
|
||||||
~ReportBlock() {}
|
virtual ~ReportBlock() {}
|
||||||
|
|
||||||
int num_packets() { return num_packets_; }
|
uint32_t Ssrc() const { return rb_.SSRC; }
|
||||||
uint32_t Ssrc() { return rb_.SSRC; }
|
uint8_t FractionLost() const { return rb_.FractionLost; }
|
||||||
uint8_t FractionLost() { return rb_.FractionLost; }
|
uint32_t CumPacketLost() const { return rb_.CumulativeNumOfPacketsLost; }
|
||||||
uint32_t CumPacketLost() { return rb_.CumulativeNumOfPacketsLost; }
|
uint32_t ExtHighestSeqNum() const { return rb_.ExtendedHighestSequenceNumber;}
|
||||||
uint32_t ExtHighestSeqNum() { return rb_.ExtendedHighestSequenceNumber; }
|
uint32_t Jitter() const { return rb_.Jitter; }
|
||||||
uint32_t Jitter() { return rb_.Jitter; }
|
uint32_t LastSr() const { return rb_.LastSR; }
|
||||||
uint32_t LastSr() { return rb_.LastSR; }
|
uint32_t DelayLastSr()const { return rb_.DelayLastSR; }
|
||||||
uint32_t DelayLastSr() { return rb_.DelayLastSR; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RtcpPacketParser;
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
void Set(const RTCPUtility::RTCPPacketReportBlockItem& rb) {
|
void Set(const RTCPUtility::RTCPPacketReportBlockItem& rb) {
|
||||||
rb_ = rb;
|
rb_ = rb;
|
||||||
++num_packets_;
|
++num_packets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_packets_;
|
|
||||||
RTCPUtility::RTCPPacketReportBlockItem rb_;
|
RTCPUtility::RTCPPacketReportBlockItem rb_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Bye {
|
class Bye : public PacketType {
|
||||||
public:
|
public:
|
||||||
Bye() : num_packets_(0) {}
|
Bye() {}
|
||||||
~Bye() {}
|
virtual ~Bye() {}
|
||||||
|
|
||||||
int num_packets() { return num_packets_; }
|
uint32_t Ssrc() const { return bye_.SenderSSRC; }
|
||||||
uint32_t Ssrc() { return bye_.SenderSSRC; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RtcpPacketParser;
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
void Set(const RTCPUtility::RTCPPacketBYE& bye) {
|
void Set(const RTCPUtility::RTCPPacketBYE& bye) {
|
||||||
bye_ = bye;
|
bye_ = bye;
|
||||||
++num_packets_;
|
++num_packets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_packets_;
|
|
||||||
RTCPUtility::RTCPPacketBYE bye_;
|
RTCPUtility::RTCPPacketBYE bye_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Fir {
|
class Rpsi : public PacketType {
|
||||||
public:
|
public:
|
||||||
Fir() : num_packets_(0) {}
|
Rpsi() {}
|
||||||
~Fir() {}
|
virtual ~Rpsi() {}
|
||||||
|
|
||||||
int num_packets() { return num_packets_; }
|
uint32_t Ssrc() const { return rpsi_.SenderSSRC; }
|
||||||
uint32_t Ssrc() { return fir_.SenderSSRC; }
|
uint32_t MediaSsrc() const { return rpsi_.MediaSSRC; }
|
||||||
|
uint8_t PayloadType() const { return rpsi_.PayloadType; }
|
||||||
|
uint16_t NumberOfValidBits() const { return rpsi_.NumberOfValidBits; }
|
||||||
|
uint64_t PictureId() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RtcpPacketParser;
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
|
void Set(const RTCPUtility::RTCPPacketPSFBRPSI& rpsi) {
|
||||||
|
rpsi_ = rpsi;
|
||||||
|
++num_packets_;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTCPUtility::RTCPPacketPSFBRPSI rpsi_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Fir : public PacketType {
|
||||||
|
public:
|
||||||
|
Fir() {}
|
||||||
|
virtual ~Fir() {}
|
||||||
|
|
||||||
|
uint32_t Ssrc() const { return fir_.SenderSSRC; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
void Set(const RTCPUtility::RTCPPacketPSFBFIR& fir) {
|
void Set(const RTCPUtility::RTCPPacketPSFBFIR& fir) {
|
||||||
fir_ = fir;
|
fir_ = fir;
|
||||||
++num_packets_;
|
++num_packets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_packets_;
|
|
||||||
RTCPUtility::RTCPPacketPSFBFIR fir_;
|
RTCPUtility::RTCPPacketPSFBFIR fir_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FirItem {
|
class FirItem : public PacketType {
|
||||||
public:
|
public:
|
||||||
FirItem() : num_packets_(0) {}
|
FirItem() {}
|
||||||
~FirItem() {}
|
virtual ~FirItem() {}
|
||||||
|
|
||||||
int num_packets() { return num_packets_; }
|
uint32_t Ssrc() const { return fir_item_.SSRC; }
|
||||||
uint32_t Ssrc() { return fir_item_.SSRC; }
|
uint8_t SeqNum() const { return fir_item_.CommandSequenceNumber; }
|
||||||
uint8_t SeqNum() { return fir_item_.CommandSequenceNumber; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RtcpPacketParser;
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
void Set(const RTCPUtility::RTCPPacketPSFBFIRItem& fir_item) {
|
void Set(const RTCPUtility::RTCPPacketPSFBFIRItem& fir_item) {
|
||||||
fir_item_ = fir_item;
|
fir_item_ = fir_item;
|
||||||
++num_packets_;
|
++num_packets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_packets_;
|
|
||||||
RTCPUtility::RTCPPacketPSFBFIRItem fir_item_;
|
RTCPUtility::RTCPPacketPSFBFIRItem fir_item_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Nack {
|
class Nack : public PacketType {
|
||||||
public:
|
public:
|
||||||
Nack() : num_packets_(0) {}
|
Nack() {}
|
||||||
~Nack() {}
|
virtual ~Nack() {}
|
||||||
|
|
||||||
int num_packets() { return num_packets_; }
|
uint32_t Ssrc() const { return nack_.SenderSSRC; }
|
||||||
uint32_t Ssrc() { return nack_.SenderSSRC; }
|
uint32_t MediaSsrc() const { return nack_.MediaSSRC; }
|
||||||
uint32_t MediaSsrc() { return nack_.MediaSSRC; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RtcpPacketParser;
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
void Set(const RTCPUtility::RTCPPacketRTPFBNACK& nack) {
|
void Set(const RTCPUtility::RTCPPacketRTPFBNACK& nack) {
|
||||||
nack_ = nack;
|
nack_ = nack;
|
||||||
++num_packets_;
|
++num_packets_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_packets_;
|
|
||||||
RTCPUtility::RTCPPacketRTPFBNACK nack_;
|
RTCPUtility::RTCPPacketRTPFBNACK nack_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NackItem {
|
class NackItem : public PacketType {
|
||||||
public:
|
public:
|
||||||
NackItem() : num_packets_(0) {}
|
NackItem() {}
|
||||||
~NackItem() {}
|
virtual ~NackItem() {}
|
||||||
|
|
||||||
int num_packets() { return num_packets_; }
|
std::vector<uint16_t> last_nack_list() const {
|
||||||
std::vector<uint16_t> last_nack_list() {
|
|
||||||
assert(num_packets_ > 0);
|
|
||||||
return last_nack_list_;
|
return last_nack_list_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class RtcpPacketParser;
|
friend class RtcpPacketParser;
|
||||||
|
|
||||||
void Set(const RTCPUtility::RTCPPacketRTPFBNACKItem& nack_item) {
|
void Set(const RTCPUtility::RTCPPacketRTPFBNACKItem& nack_item) {
|
||||||
last_nack_list_.clear();
|
|
||||||
last_nack_list_.push_back(nack_item.PacketID);
|
last_nack_list_.push_back(nack_item.PacketID);
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
if (nack_item.BitMask & (1 << i)) {
|
if (nack_item.BitMask & (1 << i)) {
|
||||||
@ -192,12 +217,11 @@ class NackItem {
|
|||||||
}
|
}
|
||||||
++num_packets_;
|
++num_packets_;
|
||||||
}
|
}
|
||||||
|
void Clear() { last_nack_list_.clear(); }
|
||||||
|
|
||||||
int num_packets_;
|
|
||||||
std::vector<uint16_t> last_nack_list_;
|
std::vector<uint16_t> last_nack_list_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class RtcpPacketParser {
|
class RtcpPacketParser {
|
||||||
public:
|
public:
|
||||||
RtcpPacketParser();
|
RtcpPacketParser();
|
||||||
@ -209,6 +233,7 @@ class RtcpPacketParser {
|
|||||||
ReceiverReport* receiver_report() { return &receiver_report_; }
|
ReceiverReport* receiver_report() { return &receiver_report_; }
|
||||||
ReportBlock* report_block() { return &report_block_; }
|
ReportBlock* report_block() { return &report_block_; }
|
||||||
Bye* bye() { return &bye_; }
|
Bye* bye() { return &bye_; }
|
||||||
|
Rpsi* rpsi() { return &rpsi_; }
|
||||||
Fir* fir() { return &fir_; }
|
Fir* fir() { return &fir_; }
|
||||||
FirItem* fir_item() { return &fir_item_; }
|
FirItem* fir_item() { return &fir_item_; }
|
||||||
Nack* nack() { return &nack_; }
|
Nack* nack() { return &nack_; }
|
||||||
@ -223,6 +248,7 @@ class RtcpPacketParser {
|
|||||||
ReceiverReport receiver_report_;
|
ReceiverReport receiver_report_;
|
||||||
ReportBlock report_block_;
|
ReportBlock report_block_;
|
||||||
Bye bye_;
|
Bye bye_;
|
||||||
|
Rpsi rpsi_;
|
||||||
Fir fir_;
|
Fir fir_;
|
||||||
FirItem fir_item_;
|
FirItem fir_item_;
|
||||||
Nack nack_;
|
Nack nack_;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user