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:
@ -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,10 +144,9 @@ void CreateReceiverReport(const RTCPUtility::RTCPPacketRR& rr,
|
||||
// | delay since last SR (DLSR) |
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
|
||||
void CreateReportBlock(
|
||||
const RTCPUtility::RTCPPacketReportBlockItem& report_block,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
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);
|
||||
@ -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,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
const uint16_t kLength = 4;
|
||||
void CreateFir(const RTCPPacketPSFBFIR& fir,
|
||||
const RTCPPacketPSFBFIRItem& fir_item,
|
||||
uint16_t length,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
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,
|
||||
uint8_t* buffer,
|
||||
uint16_t* pos) {
|
||||
for (std::vector<ReportBlock*>::const_iterator it = report_blocks.begin();
|
||||
it != report_blocks.end(); ++it) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user