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/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 rtcp {
|
||||
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) {
|
||||
buffer[(*offset)++] = value;
|
||||
}
|
||||
@ -32,9 +51,34 @@ void AssignUWord32(uint8_t* buffer, uint16_t* offset, uint32_t value) {
|
||||
*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.
|
||||
//
|
||||
// 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 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 |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|
||||
void CreateSenderReport(const RTCPUtility::RTCPPacketSR& sr,
|
||||
void CreateSenderReport(const RTCPPacketSR& sr,
|
||||
uint16_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
const uint16_t kLength = 6 + (6 * sr.NumberOfReportBlocks);
|
||||
AssignUWord8(buffer, pos, 0x80 + sr.NumberOfReportBlocks);
|
||||
AssignUWord8(buffer, pos, RTCPUtility::PT_SR);
|
||||
AssignUWord16(buffer, pos, kLength);
|
||||
CreateHeader(sr.NumberOfReportBlocks, PT_SR, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, sr.SenderSSRC);
|
||||
AssignUWord32(buffer, pos, sr.NTPMostSignificant);
|
||||
AssignUWord32(buffer, pos, sr.NTPLeastSignificant);
|
||||
@ -68,7 +110,7 @@ void CreateSenderReport(const RTCPUtility::RTCPPacketSR& sr,
|
||||
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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@ -77,13 +119,11 @@ void CreateSenderReport(const RTCPUtility::RTCPPacketSR& sr,
|
||||
// | SSRC of packet sender |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|
||||
void CreateReceiverReport(const RTCPUtility::RTCPPacketRR& rr,
|
||||
void CreateReceiverReport(const RTCPPacketRR& rr,
|
||||
uint16_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
const uint16_t kLength = 1 + (6 * rr.NumberOfReportBlocks);
|
||||
AssignUWord8(buffer, pos, 0x80 + rr.NumberOfReportBlocks);
|
||||
AssignUWord8(buffer, pos, RTCPUtility::PT_RR);
|
||||
AssignUWord16(buffer, pos, kLength);
|
||||
CreateHeader(rr.NumberOfReportBlocks, PT_RR, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, rr.SenderSSRC);
|
||||
}
|
||||
|
||||
@ -104,8 +144,7 @@ void CreateReceiverReport(const RTCPUtility::RTCPPacketRR& rr,
|
||||
// | delay since last SR (DLSR) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|
||||
void CreateReportBlock(
|
||||
const RTCPUtility::RTCPPacketReportBlockItem& report_block,
|
||||
void CreateReportBlock(const RTCPPacketReportBlockItem& report_block,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
AssignUWord32(buffer, pos, report_block.SSRC);
|
||||
@ -130,14 +169,12 @@ void CreateReportBlock(
|
||||
// (opt) | length | reason for leaving ...
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateBye(const RTCPUtility::RTCPPacketBYE& bye,
|
||||
void CreateBye(const RTCPPacketBYE& bye,
|
||||
const std::vector<uint32_t>& csrcs,
|
||||
uint16_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
const uint8_t kNumSsrcAndCsrcs = 1 + csrcs.size();
|
||||
AssignUWord8(buffer, pos, 0x80 + kNumSsrcAndCsrcs);
|
||||
AssignUWord8(buffer, pos, RTCPUtility::PT_BYE);
|
||||
AssignUWord16(buffer, pos, kNumSsrcAndCsrcs);
|
||||
CreateHeader(length, PT_BYE, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, bye.SenderSSRC);
|
||||
for (std::vector<uint32_t>::const_iterator it = csrcs.begin();
|
||||
it != csrcs.end(); ++it) {
|
||||
@ -161,6 +198,64 @@ void CreateBye(const RTCPUtility::RTCPPacketBYE& bye,
|
||||
// : 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).
|
||||
//
|
||||
// FCI:
|
||||
@ -173,27 +268,26 @@ void CreateBye(const RTCPUtility::RTCPPacketBYE& bye,
|
||||
// | Seq nr. | Reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
void CreateFirRequest(const RTCPUtility::RTCPPacketPSFBFIR& fir,
|
||||
const RTCPUtility::RTCPPacketPSFBFIRItem& fir_item,
|
||||
void CreateFir(const RTCPPacketPSFBFIR& fir,
|
||||
const RTCPPacketPSFBFIRItem& fir_item,
|
||||
uint16_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
const uint16_t kLength = 4;
|
||||
const uint8_t kFmt = 4;
|
||||
AssignUWord8(buffer, pos, 0x80 + kFmt);
|
||||
AssignUWord8(buffer, pos, RTCPUtility::PT_PSFB);
|
||||
AssignUWord16(buffer, pos, kLength);
|
||||
CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
|
||||
AssignUWord32(buffer, pos, fir.SenderSSRC);
|
||||
AssignUWord32(buffer, pos, 0);
|
||||
AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
|
||||
AssignUWord32(buffer, pos, fir_item.SSRC);
|
||||
AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
|
||||
AssignUWord24(buffer, pos, 0);
|
||||
}
|
||||
|
||||
void AppendReportBlocks(const std::vector<ReportBlock*>& report_blocks,
|
||||
template <typename T>
|
||||
void AppendBlocks(const std::vector<T*>& blocks,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
for (std::vector<ReportBlock*>::const_iterator it = report_blocks.begin();
|
||||
it != report_blocks.end(); ++it) {
|
||||
for (typename std::vector<T*>::const_iterator it = blocks.begin();
|
||||
it != blocks.end(); ++it) {
|
||||
(*it)->Create(buffer, pos);
|
||||
}
|
||||
}
|
||||
@ -236,8 +330,8 @@ void SenderReport::Create(uint8_t* packet,
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateSenderReport(sr_, packet, len);
|
||||
AppendReportBlocks(report_blocks_, packet, len);
|
||||
CreateSenderReport(sr_, BlockToHeaderLength(Length()), packet, len);
|
||||
AppendBlocks(report_blocks_, packet, len);
|
||||
}
|
||||
|
||||
void SenderReport::WithReportBlock(ReportBlock* block) {
|
||||
@ -257,8 +351,8 @@ void ReceiverReport::Create(uint8_t* packet,
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateReceiverReport(rr_, packet, len);
|
||||
AppendReportBlocks(report_blocks_, packet, len);
|
||||
CreateReceiverReport(rr_, BlockToHeaderLength(Length()), packet, len);
|
||||
AppendBlocks(report_blocks_, packet, len);
|
||||
}
|
||||
|
||||
void ReceiverReport::WithReportBlock(ReportBlock* block) {
|
||||
@ -271,12 +365,16 @@ void ReceiverReport::WithReportBlock(ReportBlock* block) {
|
||||
rr_.NumberOfReportBlocks = report_blocks_.size();
|
||||
}
|
||||
|
||||
void ReportBlock::Create(uint8_t* packet, uint16_t* len) const {
|
||||
CreateReportBlock(report_block_, packet, len);
|
||||
}
|
||||
|
||||
void Bye::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||
if (*len + Length() > max_len) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateBye(bye_, csrcs_, packet, len);
|
||||
CreateBye(bye_, csrcs_, BlockToHeaderLength(Length()), packet, len);
|
||||
}
|
||||
|
||||
void Bye::WithCsrc(uint32_t csrc) {
|
||||
@ -287,16 +385,81 @@ void Bye::WithCsrc(uint32_t csrc) {
|
||||
csrcs_.push_back(csrc);
|
||||
}
|
||||
|
||||
void Nack::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
|
||||
assert(!nack_fields_.empty());
|
||||
if (*len + Length() > max_len) {
|
||||
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 {
|
||||
if (*len + Length() > max_len) {
|
||||
LOG(LS_WARNING) << "Max packet size reached.";
|
||||
return;
|
||||
}
|
||||
CreateFirRequest(fir_, fir_item_, packet, len);
|
||||
}
|
||||
|
||||
void ReportBlock::Create(uint8_t* packet, uint16_t* len) const {
|
||||
CreateReportBlock(report_block_, packet, len);
|
||||
CreateFir(fir_, fir_item_, BlockToHeaderLength(Length()), packet, len);
|
||||
}
|
||||
} // namespace rtcp
|
||||
} // namespace webrtc
|
||||
|
@ -244,7 +244,7 @@ class ReportBlock {
|
||||
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:
|
||||
RTCPUtility::RTCPPacketReportBlockItem report_block_;
|
||||
@ -285,7 +285,7 @@ class Bye : public RtcpPacket {
|
||||
|
||||
private:
|
||||
uint16_t Length() const {
|
||||
const uint16_t kByeBlockLen = 8 + 4*csrcs_.size();
|
||||
const uint16_t kByeBlockLen = 8 + 4 * csrcs_.size();
|
||||
return kByeBlockLen;
|
||||
}
|
||||
|
||||
@ -309,6 +309,98 @@ class Bye : public RtcpPacket {
|
||||
// : 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).
|
||||
//
|
||||
|
@ -18,11 +18,13 @@
|
||||
using webrtc::rtcp::Bye;
|
||||
using webrtc::rtcp::Empty;
|
||||
using webrtc::rtcp::Fir;
|
||||
using webrtc::rtcp::SenderReport;
|
||||
using webrtc::rtcp::Nack;
|
||||
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 {
|
||||
|
||||
@ -152,6 +154,121 @@ TEST(RtcpPacketTest, SrWithTwoReportBlocks) {
|
||||
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) {
|
||||
Fir fir;
|
||||
fir.From(kSenderSsrc);
|
||||
|
@ -1266,31 +1266,27 @@ RTCPUtility::RTCPParserV2::ParseFBCommon(const RTCPCommonHeader& header)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RTCPUtility::RTCPParserV2::ParseRPSIItem()
|
||||
{
|
||||
// RFC 4585 6.3.3. Reference Picture Selection Indication (RPSI)
|
||||
/*
|
||||
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) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
bool RTCPUtility::RTCPParserV2::ParseRPSIItem() {
|
||||
|
||||
// RFC 4585 6.3.3. Reference Picture Selection Indication (RPSI).
|
||||
//
|
||||
// 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) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
|
||||
|
||||
if (length < 4)
|
||||
{
|
||||
if (length < 4) {
|
||||
_state = State_TopLevel;
|
||||
|
||||
EndCurrentBlock();
|
||||
return false;
|
||||
}
|
||||
if(length > 2+RTCP_RPSI_DATA_SIZE)
|
||||
{
|
||||
if (length > 2 + RTCP_RPSI_DATA_SIZE) {
|
||||
_state = State_TopLevel;
|
||||
|
||||
EndCurrentBlock();
|
||||
@ -1299,12 +1295,14 @@ RTCPUtility::RTCPParserV2::ParseRPSIItem()
|
||||
|
||||
_packetType = kRtcpPsfbRpsiCode;
|
||||
|
||||
uint8_t paddingBits = *_ptrRTCPData++;
|
||||
uint8_t padding_bits = *_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;
|
||||
}
|
||||
|
||||
|
@ -23,25 +23,54 @@ void RtcpPacketParser::Parse(const void *data, int len) {
|
||||
for (RTCPUtility::RTCPPacketTypes type = parser.Begin();
|
||||
type != RTCPUtility::kRtcpNotValidCode;
|
||||
type = parser.Iterate()) {
|
||||
if (type == RTCPUtility::kRtcpSrCode) {
|
||||
switch (type) {
|
||||
case RTCPUtility::kRtcpSrCode:
|
||||
sender_report_.Set(parser.Packet().SR);
|
||||
} else if (type == RTCPUtility::kRtcpRrCode) {
|
||||
break;
|
||||
case RTCPUtility::kRtcpRrCode:
|
||||
receiver_report_.Set(parser.Packet().RR);
|
||||
} else if (type == RTCPUtility::kRtcpByeCode) {
|
||||
break;
|
||||
case RTCPUtility::kRtcpByeCode:
|
||||
bye_.Set(parser.Packet().BYE);
|
||||
} else if (type == RTCPUtility::kRtcpReportBlockItemCode) {
|
||||
break;
|
||||
case RTCPUtility::kRtcpReportBlockItemCode:
|
||||
report_block_.Set(parser.Packet().ReportBlockItem);
|
||||
++report_blocks_per_ssrc_[parser.Packet().ReportBlockItem.SSRC];
|
||||
} else if (type == RTCPUtility::kRtcpPsfbFirCode) {
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbRpsiCode:
|
||||
rpsi_.Set(parser.Packet().RPSI);
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbFirCode:
|
||||
fir_.Set(parser.Packet().FIR);
|
||||
} else if (type == webrtc::RTCPUtility::kRtcpPsfbFirItemCode) {
|
||||
break;
|
||||
case RTCPUtility::kRtcpPsfbFirItemCode:
|
||||
fir_item_.Set(parser.Packet().FIRItem);
|
||||
} else if (type == RTCPUtility::kRtcpRtpfbNackCode) {
|
||||
break;
|
||||
case RTCPUtility::kRtcpRtpfbNackCode:
|
||||
nack_.Set(parser.Packet().NACK);
|
||||
} else if (type == RTCPUtility::kRtcpRtpfbNackItemCode) {
|
||||
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 webrtc
|
||||
|
@ -23,167 +23,192 @@ namespace test {
|
||||
|
||||
class RtcpPacketParser;
|
||||
|
||||
class SenderReport {
|
||||
class PacketType {
|
||||
public:
|
||||
SenderReport() : num_packets_(0) {}
|
||||
~SenderReport() {}
|
||||
virtual ~PacketType() {}
|
||||
|
||||
int num_packets() { return num_packets_; }
|
||||
uint32_t Ssrc() { return sr_.SenderSSRC; }
|
||||
uint32_t NtpSec() { return sr_.NTPMostSignificant; }
|
||||
uint32_t NtpFrac() { return sr_.NTPLeastSignificant; }
|
||||
uint32_t RtpTimestamp() { return sr_.RTPTimestamp; }
|
||||
uint32_t PacketCount() { return sr_.SenderPacketCount; }
|
||||
uint32_t OctetCount() { return sr_.SenderOctetCount; }
|
||||
int num_packets() const { return num_packets_; }
|
||||
|
||||
protected:
|
||||
PacketType() : num_packets_(0) {}
|
||||
|
||||
int num_packets_;
|
||||
};
|
||||
|
||||
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:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketSR& sr) {
|
||||
sr_ = sr;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
int num_packets_;
|
||||
RTCPUtility::RTCPPacketSR sr_;
|
||||
};
|
||||
|
||||
class ReceiverReport {
|
||||
class ReceiverReport : public PacketType {
|
||||
public:
|
||||
ReceiverReport() : num_packets_(0) {}
|
||||
~ReceiverReport() {}
|
||||
ReceiverReport() {}
|
||||
virtual ~ReceiverReport() {}
|
||||
|
||||
int num_packets() { return num_packets_; }
|
||||
uint32_t Ssrc() { return rr_.SenderSSRC; }
|
||||
uint32_t Ssrc() const { return rr_.SenderSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketRR& rr) {
|
||||
rr_ = rr;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
int num_packets_;
|
||||
RTCPUtility::RTCPPacketRR rr_;
|
||||
};
|
||||
|
||||
class ReportBlock {
|
||||
class ReportBlock : public PacketType {
|
||||
public:
|
||||
ReportBlock() : num_packets_(0) {}
|
||||
~ReportBlock() {}
|
||||
ReportBlock() {}
|
||||
virtual ~ReportBlock() {}
|
||||
|
||||
int num_packets() { return num_packets_; }
|
||||
uint32_t Ssrc() { return rb_.SSRC; }
|
||||
uint8_t FractionLost() { return rb_.FractionLost; }
|
||||
uint32_t CumPacketLost() { return rb_.CumulativeNumOfPacketsLost; }
|
||||
uint32_t ExtHighestSeqNum() { return rb_.ExtendedHighestSequenceNumber; }
|
||||
uint32_t Jitter() { return rb_.Jitter; }
|
||||
uint32_t LastSr() { return rb_.LastSR; }
|
||||
uint32_t DelayLastSr() { return rb_.DelayLastSR; }
|
||||
uint32_t Ssrc() const { return rb_.SSRC; }
|
||||
uint8_t FractionLost() const { return rb_.FractionLost; }
|
||||
uint32_t CumPacketLost() const { return rb_.CumulativeNumOfPacketsLost; }
|
||||
uint32_t ExtHighestSeqNum() const { return rb_.ExtendedHighestSequenceNumber;}
|
||||
uint32_t Jitter() const { return rb_.Jitter; }
|
||||
uint32_t LastSr() const { return rb_.LastSR; }
|
||||
uint32_t DelayLastSr()const { return rb_.DelayLastSR; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketReportBlockItem& rb) {
|
||||
rb_ = rb;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
int num_packets_;
|
||||
RTCPUtility::RTCPPacketReportBlockItem rb_;
|
||||
};
|
||||
|
||||
class Bye {
|
||||
class Bye : public PacketType {
|
||||
public:
|
||||
Bye() : num_packets_(0) {}
|
||||
~Bye() {}
|
||||
Bye() {}
|
||||
virtual ~Bye() {}
|
||||
|
||||
int num_packets() { return num_packets_; }
|
||||
uint32_t Ssrc() { return bye_.SenderSSRC; }
|
||||
uint32_t Ssrc() const { return bye_.SenderSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketBYE& bye) {
|
||||
bye_ = bye;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
int num_packets_;
|
||||
RTCPUtility::RTCPPacketBYE bye_;
|
||||
};
|
||||
|
||||
class Fir {
|
||||
class Rpsi : public PacketType {
|
||||
public:
|
||||
Fir() : num_packets_(0) {}
|
||||
~Fir() {}
|
||||
Rpsi() {}
|
||||
virtual ~Rpsi() {}
|
||||
|
||||
int num_packets() { return num_packets_; }
|
||||
uint32_t Ssrc() { return fir_.SenderSSRC; }
|
||||
uint32_t Ssrc() const { return rpsi_.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:
|
||||
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) {
|
||||
fir_ = fir;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
int num_packets_;
|
||||
RTCPUtility::RTCPPacketPSFBFIR fir_;
|
||||
};
|
||||
|
||||
class FirItem {
|
||||
class FirItem : public PacketType {
|
||||
public:
|
||||
FirItem() : num_packets_(0) {}
|
||||
~FirItem() {}
|
||||
FirItem() {}
|
||||
virtual ~FirItem() {}
|
||||
|
||||
int num_packets() { return num_packets_; }
|
||||
uint32_t Ssrc() { return fir_item_.SSRC; }
|
||||
uint8_t SeqNum() { return fir_item_.CommandSequenceNumber; }
|
||||
uint32_t Ssrc() const { return fir_item_.SSRC; }
|
||||
uint8_t SeqNum() const { return fir_item_.CommandSequenceNumber; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketPSFBFIRItem& fir_item) {
|
||||
fir_item_ = fir_item;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
int num_packets_;
|
||||
RTCPUtility::RTCPPacketPSFBFIRItem fir_item_;
|
||||
};
|
||||
|
||||
class Nack {
|
||||
class Nack : public PacketType {
|
||||
public:
|
||||
Nack() : num_packets_(0) {}
|
||||
~Nack() {}
|
||||
Nack() {}
|
||||
virtual ~Nack() {}
|
||||
|
||||
int num_packets() { return num_packets_; }
|
||||
uint32_t Ssrc() { return nack_.SenderSSRC; }
|
||||
uint32_t MediaSsrc() { return nack_.MediaSSRC; }
|
||||
uint32_t Ssrc() const { return nack_.SenderSSRC; }
|
||||
uint32_t MediaSsrc() const { return nack_.MediaSSRC; }
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketRTPFBNACK& nack) {
|
||||
nack_ = nack;
|
||||
++num_packets_;
|
||||
}
|
||||
|
||||
int num_packets_;
|
||||
RTCPUtility::RTCPPacketRTPFBNACK nack_;
|
||||
};
|
||||
|
||||
class NackItem {
|
||||
class NackItem : public PacketType {
|
||||
public:
|
||||
NackItem() : num_packets_(0) {}
|
||||
~NackItem() {}
|
||||
NackItem() {}
|
||||
virtual ~NackItem() {}
|
||||
|
||||
int num_packets() { return num_packets_; }
|
||||
std::vector<uint16_t> last_nack_list() {
|
||||
assert(num_packets_ > 0);
|
||||
std::vector<uint16_t> last_nack_list() const {
|
||||
return last_nack_list_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class RtcpPacketParser;
|
||||
|
||||
void Set(const RTCPUtility::RTCPPacketRTPFBNACKItem& nack_item) {
|
||||
last_nack_list_.clear();
|
||||
last_nack_list_.push_back(nack_item.PacketID);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (nack_item.BitMask & (1 << i)) {
|
||||
@ -192,12 +217,11 @@ class NackItem {
|
||||
}
|
||||
++num_packets_;
|
||||
}
|
||||
void Clear() { last_nack_list_.clear(); }
|
||||
|
||||
int num_packets_;
|
||||
std::vector<uint16_t> last_nack_list_;
|
||||
};
|
||||
|
||||
|
||||
class RtcpPacketParser {
|
||||
public:
|
||||
RtcpPacketParser();
|
||||
@ -209,6 +233,7 @@ class RtcpPacketParser {
|
||||
ReceiverReport* receiver_report() { return &receiver_report_; }
|
||||
ReportBlock* report_block() { return &report_block_; }
|
||||
Bye* bye() { return &bye_; }
|
||||
Rpsi* rpsi() { return &rpsi_; }
|
||||
Fir* fir() { return &fir_; }
|
||||
FirItem* fir_item() { return &fir_item_; }
|
||||
Nack* nack() { return &nack_; }
|
||||
@ -223,6 +248,7 @@ class RtcpPacketParser {
|
||||
ReceiverReport receiver_report_;
|
||||
ReportBlock report_block_;
|
||||
Bye bye_;
|
||||
Rpsi rpsi_;
|
||||
Fir fir_;
|
||||
FirItem fir_item_;
|
||||
Nack nack_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user