Add RTCP packet class.

Adds packet types: sr, rr, bye, fir.

BUG=2450
R=mflodman@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/8079004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5592 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
asapersson@webrtc.org 2014-02-21 08:14:45 +00:00
parent c0907eff42
commit 0f2809a5ac
8 changed files with 1308 additions and 1 deletions

View File

@ -99,6 +99,7 @@
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
'<(webrtc_root)/test/test.gyp:test_support_main',
'<(webrtc_root)/test/test.gyp:frame_generator',
'<(webrtc_root)/test/test.gyp:rtcp_packet_parser',
],
'sources': [
'audio_coding/main/acm2/acm_receiver_unittest.cc',
@ -203,8 +204,9 @@
'rtp_rtcp/source/producer_fec_unittest.cc',
'rtp_rtcp/source/receive_statistics_unittest.cc',
'rtp_rtcp/source/rtcp_format_remb_unittest.cc',
'rtp_rtcp/source/rtcp_sender_unittest.cc',
'rtp_rtcp/source/rtcp_packet_unittest.cc',
'rtp_rtcp/source/rtcp_receiver_unittest.cc',
'rtp_rtcp/source/rtcp_sender_unittest.cc',
'rtp_rtcp/source/rtp_fec_unittest.cc',
'rtp_rtcp/source/rtp_format_vp8_unittest.cc',
'rtp_rtcp/source/rtp_format_vp8_test_helper.cc',

View File

@ -0,0 +1,309 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
namespace rtcp {
namespace {
void AssignUWord8(uint8_t* buffer, uint16_t* offset, uint8_t value) {
buffer[(*offset)++] = value;
}
void AssignUWord16(uint8_t* buffer, uint16_t* offset, uint16_t value) {
ModuleRTPUtility::AssignUWord16ToBuffer(buffer + *offset, value);
*offset += 2;
}
void AssignUWord24(uint8_t* buffer, uint16_t* offset, uint32_t value) {
ModuleRTPUtility::AssignUWord24ToBuffer(buffer + *offset, value);
*offset += 3;
}
void AssignUWord32(uint8_t* buffer, uint16_t* offset, uint32_t value) {
ModuleRTPUtility::AssignUWord32ToBuffer(buffer + *offset, value);
*offset += 4;
}
// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
//
// Sender report
// 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 | PT=SR=200 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC of sender |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | NTP timestamp, most significant word |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | NTP timestamp, least significant word |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | RTP timestamp |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | sender's packet count |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | sender's octet count |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
void CreateSenderReport(const RTCPUtility::RTCPPacketSR& sr,
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);
AssignUWord32(buffer, pos, sr.SenderSSRC);
AssignUWord32(buffer, pos, sr.NTPMostSignificant);
AssignUWord32(buffer, pos, sr.NTPLeastSignificant);
AssignUWord32(buffer, pos, sr.RTPTimestamp);
AssignUWord32(buffer, pos, sr.SenderPacketCount);
AssignUWord32(buffer, pos, sr.SenderOctetCount);
}
// Receiver report, 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P| RC | PT=RR=201 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC of packet sender |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
void CreateReceiverReport(const RTCPUtility::RTCPPacketRR& rr,
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);
AssignUWord32(buffer, pos, rr.SenderSSRC);
}
// Report block (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
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | SSRC_1 (SSRC of first source) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | fraction lost | cumulative number of packets lost |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | extended highest sequence number received |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | interarrival jitter |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | last SR (LSR) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | delay since last SR (DLSR) |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
void CreateReportBlock(
const RTCPUtility::RTCPPacketReportBlockItem& report_block,
uint8_t* buffer,
uint16_t* pos) {
AssignUWord32(buffer, pos, report_block.SSRC);
AssignUWord8(buffer, pos, report_block.FractionLost);
AssignUWord24(buffer, pos, report_block.CumulativeNumOfPacketsLost);
AssignUWord32(buffer, pos, report_block.ExtendedHighestSequenceNumber);
AssignUWord32(buffer, pos, report_block.Jitter);
AssignUWord32(buffer, pos, report_block.LastSR);
AssignUWord32(buffer, pos, report_block.DelayLastSR);
}
// Bye packet (BYE) (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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P| SC | PT=BYE=203 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC/CSRC |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : ... :
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// (opt) | length | reason for leaving ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void CreateBye(const RTCPUtility::RTCPPacketBYE& bye,
const std::vector<uint32_t>& csrcs,
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);
AssignUWord32(buffer, pos, bye.SenderSSRC);
for (std::vector<uint32_t>::const_iterator it = csrcs.begin();
it != csrcs.end(); ++it) {
AssignUWord32(buffer, pos, *it);
}
}
// RFC 4585: Feedback format.
//
// Common packet 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| FMT | PT | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC of packet sender |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC of media source |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : Feedback Control Information (FCI) :
// :
//
// Full intra request (FIR) (RFC 5104).
//
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | 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;
const uint8_t kFmt = 4;
AssignUWord8(buffer, pos, 0x80 + kFmt);
AssignUWord8(buffer, pos, RTCPUtility::PT_PSFB);
AssignUWord16(buffer, pos, kLength);
AssignUWord32(buffer, pos, fir.SenderSSRC);
AssignUWord32(buffer, pos, 0);
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) {
(*it)->Create(buffer, pos);
}
}
} // namespace
void RtcpPacket::Append(RtcpPacket* packet) {
assert(packet);
appended_packets_.push_back(packet);
}
RawPacket RtcpPacket::Build() const {
uint16_t len = 0;
uint8_t packet[IP_PACKET_SIZE];
CreateAndAddAppended(packet, &len, IP_PACKET_SIZE);
return RawPacket(packet, len);
}
void RtcpPacket::Build(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
*len = 0;
CreateAndAddAppended(packet, len, max_len);
}
void RtcpPacket::CreateAndAddAppended(uint8_t* packet,
uint16_t* len,
uint16_t max_len) const {
Create(packet, len, max_len);
for (std::vector<RtcpPacket*>::const_iterator it = appended_packets_.begin();
it != appended_packets_.end(); ++it) {
(*it)->CreateAndAddAppended(packet, len, max_len);
}
}
void Empty::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
}
void SenderReport::Create(uint8_t* packet,
uint16_t* len,
uint16_t max_len) const {
if (*len + Length() > max_len) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Max packet size reached, skipped SR.");
return;
}
CreateSenderReport(sr_, packet, len);
AppendReportBlocks(report_blocks_, packet, len);
}
void SenderReport::WithReportBlock(ReportBlock* block) {
assert(block);
if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Max report block size reached.");
return;
}
report_blocks_.push_back(block);
sr_.NumberOfReportBlocks = report_blocks_.size();
}
void ReceiverReport::Create(uint8_t* packet,
uint16_t* len,
uint16_t max_len) const {
if (*len + Length() > max_len) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Max packet size reached, skipped RR.");
return;
}
CreateReceiverReport(rr_, packet, len);
AppendReportBlocks(report_blocks_, packet, len);
}
void ReceiverReport::WithReportBlock(ReportBlock* block) {
assert(block);
if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Max report block size reached.");
return;
}
report_blocks_.push_back(block);
rr_.NumberOfReportBlocks = report_blocks_.size();
}
void Bye::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
if (*len + Length() > max_len) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Max packet size reached, skipped BYE.");
return;
}
CreateBye(bye_, csrcs_, packet, len);
}
void Bye::WithCsrc(uint32_t csrc) {
if (csrcs_.size() >= kMaxNumberOfCsrcs) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Max CSRC size reached.");
return;
}
csrcs_.push_back(csrc);
}
void Fir::Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const {
if (*len + Length() > max_len) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Max packet size reached, skipped FIR.");
return;
}
CreateFirRequest(fir_, fir_item_, packet, len);
}
void ReportBlock::Create(uint8_t* packet, uint16_t* len) const {
CreateReportBlock(report_block_, packet, len);
}
} // namespace rtcp
} // namespace webrtc

View File

@ -0,0 +1,389 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*
*/
#ifndef WEBRTC_MODULES_RTP_RTCP_RTCP_PACKET_H_
#define WEBRTC_MODULES_RTP_RTCP_RTCP_PACKET_H_
#include <vector>
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/typedefs.h"
namespace webrtc {
namespace rtcp {
class RawPacket;
class ReportBlock;
// Class for building RTCP packets.
//
// Example:
// ReportBlock report_block;
// report_block.To(234)
// report_block.FractionLost(10);
//
// ReceiverReport rr;
// rr.From(123);
// rr.WithReportBlock(&report_block)
//
// Fir fir;
// fir.From(123);
// fir.To(234)
// fir.WithCommandSeqNum(123);
//
// uint16_t len = 0; // Builds an intra frame request
// uint8_t packet[kPacketSize]; // with sequence number 123.
// fir.Build(packet, &len, kPacketSize);
//
// RawPacket packet = fir.Build(); // Returns a RawPacket holding
// // the built rtcp packet.
//
// rr.Append(&fir) // Builds a compound RTCP packet with
// RawPacket packet = rr.Build(); // a receiver report, report block
// // and fir message.
class RtcpPacket {
public:
virtual ~RtcpPacket() {}
void Append(RtcpPacket* packet);
RawPacket Build() const;
void Build(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
protected:
RtcpPacket() {}
virtual void Create(
uint8_t* packet, uint16_t* len, uint16_t max_len) const = 0;
void CreateAndAddAppended(
uint8_t* packet, uint16_t* len, uint16_t max_len) const;
private:
std::vector<RtcpPacket*> appended_packets_;
};
class Empty : public RtcpPacket {
public:
Empty() {}
virtual ~Empty() {}
protected:
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
};
//// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
//
// RTCP sender report (RFC 3550).
//
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P| RC | PT=SR=200 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC of sender |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | NTP timestamp, most significant word |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | NTP timestamp, least significant word |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | RTP timestamp |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | sender's packet count |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | sender's octet count |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | report block(s) |
// | .... |
class SenderReport : public RtcpPacket {
public:
SenderReport()
: RtcpPacket() {
memset(&sr_, 0, sizeof(sr_));
}
virtual ~SenderReport() {}
void From(uint32_t ssrc) {
sr_.SenderSSRC = ssrc;
}
void WithNtpSec(uint32_t sec) {
sr_.NTPMostSignificant = sec;
}
void WithNtpFrac(uint32_t frac) {
sr_.NTPLeastSignificant = frac;
}
void WithRtpTimestamp(uint32_t rtp_timestamp) {
sr_.RTPTimestamp = rtp_timestamp;
}
void WithPacketCount(uint32_t packet_count) {
sr_.SenderPacketCount = packet_count;
}
void WithOctetCount(uint32_t octet_count) {
sr_.SenderOctetCount = octet_count;
}
void WithReportBlock(ReportBlock* block);
enum { kMaxNumberOfReportBlocks = 0x1f };
protected:
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
private:
uint16_t Length() const {
const uint16_t kSrBlockLen = 28;
const uint16_t kReportBlockLen = 24;
return kSrBlockLen + report_blocks_.size() * kReportBlockLen;
}
RTCPUtility::RTCPPacketSR sr_;
std::vector<ReportBlock*> report_blocks_;
};
//
// RTCP receiver report (RFC 3550).
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P| RC | PT=RR=201 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC of packet sender |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | report block(s) |
// | .... |
class ReceiverReport : public RtcpPacket {
public:
ReceiverReport()
: RtcpPacket() {
memset(&rr_, 0, sizeof(rr_));
}
virtual ~ReceiverReport() {}
void From(uint32_t ssrc) {
rr_.SenderSSRC = ssrc;
}
void WithReportBlock(ReportBlock* block);
enum { kMaxNumberOfReportBlocks = 0x1f };
protected:
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
private:
uint16_t Length() const {
const uint16_t kRrBlockLen = 8;
const uint16_t kReportBlockLen = 24;
return kRrBlockLen + report_blocks_.size() * kReportBlockLen;
}
RTCPUtility::RTCPPacketRR rr_;
std::vector<ReportBlock*> report_blocks_;
};
//
// RTCP report block (RFC 3550).
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | SSRC_1 (SSRC of first source) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | fraction lost | cumulative number of packets lost |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | extended highest sequence number received |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | interarrival jitter |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | last SR (LSR) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | delay since last SR (DLSR) |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
class ReportBlock {
public:
ReportBlock() {
memset(&report_block_, 0, sizeof(report_block_));
}
~ReportBlock() {}
void To(uint32_t ssrc) {
report_block_.SSRC = ssrc;
}
void WithFractionLost(uint8_t fraction_lost) {
report_block_.FractionLost = fraction_lost;
}
void WithCumPacketsLost(uint32_t cum_packets_lost) {
report_block_.CumulativeNumOfPacketsLost = cum_packets_lost;
}
void WithExtHighestSeqNum(uint32_t ext_highest_seq_num) {
report_block_.ExtendedHighestSequenceNumber = ext_highest_seq_num;
}
void WithJitter(uint32_t jitter) {
report_block_.Jitter = jitter;
}
void WithLastSr(uint32_t last_sr) {
report_block_.LastSR = last_sr;
}
void WithDelayLastSr(uint32_t delay_last_sr) {
report_block_.DelayLastSR = delay_last_sr;
}
void Create(uint8_t* array, uint16_t* cur_pos) const;
private:
RTCPUtility::RTCPPacketReportBlockItem report_block_;
};
//
// Bye packet (BYE) (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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P| SC | PT=BYE=203 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC/CSRC |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : ... :
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// (opt) | length | reason for leaving ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
class Bye : public RtcpPacket {
public:
Bye()
: RtcpPacket() {
memset(&bye_, 0, sizeof(bye_));
}
virtual ~Bye() {}
void From(uint32_t ssrc) {
bye_.SenderSSRC = ssrc;
}
void WithCsrc(uint32_t csrc);
enum { kMaxNumberOfCsrcs = 0x1f - 1 };
protected:
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
private:
uint16_t Length() const {
const uint16_t kByeBlockLen = 8 + 4*csrcs_.size();
return kByeBlockLen;
}
RTCPUtility::RTCPPacketBYE bye_;
std::vector<uint32_t> csrcs_;
};
// RFC 4585: Feedback format.
//
// Common packet 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| FMT | PT | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC of packet sender |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC of media source |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : Feedback Control Information (FCI) :
// :
// Full intra request (FIR) (RFC 5104).
//
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Seq nr. | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
class Fir : public RtcpPacket {
public:
Fir()
: RtcpPacket() {
memset(&fir_, 0, sizeof(fir_));
memset(&fir_item_, 0, sizeof(fir_item_));
}
virtual ~Fir() {}
void From(uint32_t ssrc) {
fir_.SenderSSRC = ssrc;
}
void To(uint32_t ssrc) {
fir_item_.SSRC = ssrc;
}
void WithCommandSeqNum(uint8_t seq_num) {
fir_item_.CommandSequenceNumber = seq_num;
}
protected:
virtual void Create(uint8_t* packet, uint16_t* len, uint16_t max_len) const;
private:
uint16_t Length() const {
const uint16_t kFirBlockLen = 20;
return kFirBlockLen;
}
RTCPUtility::RTCPPacketPSFBFIR fir_;
RTCPUtility::RTCPPacketPSFBFIRItem fir_item_;
};
// Class holding a RTCP packet.
//
// Takes a built rtcp packet.
// RawPacket raw_packet(buffer, len);
//
// To access the raw packet:
// raw_packet.buffer(); - pointer to the raw packet
// raw_packet.buffer_length(); - the length of the raw packet
class RawPacket {
public:
RawPacket(const uint8_t* buffer, uint16_t len) {
assert(len <= IP_PACKET_SIZE);
memcpy(packet_, buffer, len);
packet_length_ = len;
}
const uint8_t* buffer() {
return packet_;
}
uint16_t buffer_length() const {
return packet_length_;
}
private:
uint16_t packet_length_;
uint8_t packet_[IP_PACKET_SIZE];
};
} // namespace rtcp
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_RTCP_PACKET_H_

View File

@ -0,0 +1,312 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*
* This file includes unit tests for the RtcpPacket.
*/
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
#include "webrtc/test/rtcp_packet_parser.h"
using webrtc::rtcp::Bye;
using webrtc::rtcp::Empty;
using webrtc::rtcp::Fir;
using webrtc::rtcp::SenderReport;
using webrtc::rtcp::RawPacket;
using webrtc::rtcp::ReceiverReport;
using webrtc::rtcp::ReportBlock;
using webrtc::test::RtcpPacketParser;
namespace webrtc {
const uint32_t kSenderSsrc = 0x12345678;
const uint32_t kRemoteSsrc = 0x23456789;
TEST(RtcpPacketTest, Rr) {
ReceiverReport rr;
rr.From(kSenderSsrc);
RawPacket packet = rr.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.receiver_report()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.receiver_report()->Ssrc());
EXPECT_EQ(0, parser.report_block()->num_packets());
}
TEST(RtcpPacketTest, RrWithOneReportBlock) {
ReportBlock rb;
rb.To(kRemoteSsrc);
rb.WithFractionLost(55);
rb.WithCumPacketsLost(0x111111);
rb.WithExtHighestSeqNum(0x22222222);
rb.WithJitter(0x33333333);
rb.WithLastSr(0x44444444);
rb.WithDelayLastSr(0x55555555);
ReceiverReport rr;
rr.From(kSenderSsrc);
rr.WithReportBlock(&rb);
RawPacket packet = rr.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.receiver_report()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.receiver_report()->Ssrc());
EXPECT_EQ(1, parser.report_block()->num_packets());
EXPECT_EQ(kRemoteSsrc, parser.report_block()->Ssrc());
EXPECT_EQ(55U, parser.report_block()->FractionLost());
EXPECT_EQ(0x111111U, parser.report_block()->CumPacketLost());
EXPECT_EQ(0x22222222U, parser.report_block()->ExtHighestSeqNum());
EXPECT_EQ(0x33333333U, parser.report_block()->Jitter());
EXPECT_EQ(0x44444444U, parser.report_block()->LastSr());
EXPECT_EQ(0x55555555U, parser.report_block()->DelayLastSr());
}
TEST(RtcpPacketTest, RrWithTwoReportBlocks) {
ReportBlock rb1;
rb1.To(kRemoteSsrc);
ReportBlock rb2;
rb2.To(kRemoteSsrc + 1);
ReceiverReport rr;
rr.From(kSenderSsrc);
rr.WithReportBlock(&rb1);
rr.WithReportBlock(&rb2);
RawPacket packet = rr.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.receiver_report()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.receiver_report()->Ssrc());
EXPECT_EQ(2, parser.report_block()->num_packets());
EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc));
EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc + 1));
}
TEST(RtcpPacketTest, Sr) {
SenderReport sr;
sr.From(kSenderSsrc);
sr.WithNtpSec(0x11111111);
sr.WithNtpFrac(0x22222222);
sr.WithRtpTimestamp(0x33333333);
sr.WithPacketCount(0x44444444);
sr.WithOctetCount(0x55555555);
RawPacket packet = sr.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.sender_report()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.sender_report()->Ssrc());
EXPECT_EQ(0x11111111U, parser.sender_report()->NtpSec());
EXPECT_EQ(0x22222222U, parser.sender_report()->NtpFrac());
EXPECT_EQ(0x33333333U, parser.sender_report()->RtpTimestamp());
EXPECT_EQ(0x44444444U, parser.sender_report()->PacketCount());
EXPECT_EQ(0x55555555U, parser.sender_report()->OctetCount());
EXPECT_EQ(0, parser.report_block()->num_packets());
}
TEST(RtcpPacketTest, SrWithOneReportBlock) {
ReportBlock rb;
rb.To(kRemoteSsrc);
SenderReport sr;
sr.From(kSenderSsrc);
sr.WithReportBlock(&rb);
RawPacket packet = sr.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.sender_report()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.sender_report()->Ssrc());
EXPECT_EQ(1, parser.report_block()->num_packets());
EXPECT_EQ(kRemoteSsrc, parser.report_block()->Ssrc());
}
TEST(RtcpPacketTest, SrWithTwoReportBlocks) {
ReportBlock rb1;
rb1.To(kRemoteSsrc);
ReportBlock rb2;
rb2.To(kRemoteSsrc + 1);
SenderReport sr;
sr.From(kSenderSsrc);
sr.WithReportBlock(&rb1);
sr.WithReportBlock(&rb2);
RawPacket packet = sr.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.sender_report()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.sender_report()->Ssrc());
EXPECT_EQ(2, parser.report_block()->num_packets());
EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc));
EXPECT_EQ(1, parser.report_blocks_per_ssrc(kRemoteSsrc + 1));
}
TEST(RtcpPacketTest, Fir) {
Fir fir;
fir.From(kSenderSsrc);
fir.To(kRemoteSsrc);
fir.WithCommandSeqNum(123);
RawPacket packet = fir.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.fir()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.fir()->Ssrc());
EXPECT_EQ(1, parser.fir_item()->num_packets());
EXPECT_EQ(kRemoteSsrc, parser.fir_item()->Ssrc());
EXPECT_EQ(123U, parser.fir_item()->SeqNum());
}
TEST(RtcpPacketTest, AppendPacket) {
Fir fir;
ReportBlock rb;
ReceiverReport rr;
rr.From(kSenderSsrc);
rr.WithReportBlock(&rb);
rr.Append(&fir);
RawPacket packet = rr.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.receiver_report()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.receiver_report()->Ssrc());
EXPECT_EQ(1, parser.report_block()->num_packets());
EXPECT_EQ(1, parser.fir()->num_packets());
}
TEST(RtcpPacketTest, AppendPacketOnEmpty) {
Empty empty;
ReceiverReport rr;
rr.From(kSenderSsrc);
empty.Append(&rr);
RawPacket packet = empty.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.receiver_report()->num_packets());
EXPECT_EQ(0, parser.report_block()->num_packets());
}
TEST(RtcpPacketTest, AppendPacketWithOwnAppendedPacket) {
Fir fir;
Bye bye;
ReportBlock rb;
ReceiverReport rr;
rr.WithReportBlock(&rb);
rr.Append(&fir);
SenderReport sr;
sr.Append(&bye);
sr.Append(&rr);
RawPacket packet = sr.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.sender_report()->num_packets());
EXPECT_EQ(1, parser.receiver_report()->num_packets());
EXPECT_EQ(1, parser.report_block()->num_packets());
EXPECT_EQ(1, parser.bye()->num_packets());
EXPECT_EQ(1, parser.fir()->num_packets());
}
TEST(RtcpPacketTest, Bye) {
Bye bye;
bye.From(kSenderSsrc);
RawPacket packet = bye.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.bye()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.bye()->Ssrc());
}
TEST(RtcpPacketTest, ByeWithCsrcs) {
Fir fir;
Bye bye;
bye.From(kSenderSsrc);
bye.WithCsrc(0x22222222);
bye.WithCsrc(0x33333333);
bye.Append(&fir);
RawPacket packet = bye.Build();
RtcpPacketParser parser;
parser.Parse(packet.buffer(), packet.buffer_length());
EXPECT_EQ(1, parser.bye()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.bye()->Ssrc());
EXPECT_EQ(1, parser.fir()->num_packets());
}
TEST(RtcpPacketTest, BuildWithInputBuffer) {
Fir fir;
ReportBlock rb;
ReceiverReport rr;
rr.From(kSenderSsrc);
rr.WithReportBlock(&rb);
rr.Append(&fir);
const uint16_t kRrLength = 8;
const uint16_t kReportBlockLength = 24;
const uint16_t kFirLength = 20;
uint16_t len = 0;
uint8_t packet[kRrLength + kReportBlockLength + kFirLength];
rr.Build(packet, &len, kRrLength + kReportBlockLength + kFirLength);
RtcpPacketParser parser;
parser.Parse(packet, len);
EXPECT_EQ(1, parser.receiver_report()->num_packets());
EXPECT_EQ(1, parser.report_block()->num_packets());
EXPECT_EQ(1, parser.fir()->num_packets());
}
TEST(RtcpPacketTest, BuildWithTooSmallBuffer) {
ReportBlock rb;
ReceiverReport rr;
rr.From(kSenderSsrc);
rr.WithReportBlock(&rb);
const uint16_t kRrLength = 8;
const uint16_t kReportBlockLength = 24;
// No packet.
uint16_t len = 0;
uint8_t packet[kRrLength + kReportBlockLength - 1];
rr.Build(packet, &len, kRrLength + kReportBlockLength - 1);
RtcpPacketParser parser;
parser.Parse(packet, len);
EXPECT_EQ(0, len);
}
TEST(RtcpPacketTest, BuildWithTooSmallBuffer_LastBlockFits) {
Fir fir;
ReportBlock rb;
ReceiverReport rr;
rr.From(kSenderSsrc);
rr.WithReportBlock(&rb);
rr.Append(&fir);
const uint16_t kRrLength = 8;
const uint16_t kReportBlockLength = 24;
uint16_t len = 0;
uint8_t packet[kRrLength + kReportBlockLength - 1];
rr.Build(packet, &len, kRrLength + kReportBlockLength - 1);
RtcpPacketParser parser;
parser.Parse(packet, len);
EXPECT_EQ(0, parser.receiver_report()->num_packets());
EXPECT_EQ(0, parser.report_block()->num_packets());
EXPECT_EQ(1, parser.fir()->num_packets());
}
} // namespace webrtc

View File

@ -36,6 +36,8 @@
'rtp_rtcp_config.h',
'rtp_rtcp_impl.cc',
'rtp_rtcp_impl.h',
'rtcp_packet.cc',
'rtcp_packet.h',
'rtcp_receiver.cc',
'rtcp_receiver.h',
'rtcp_receiver_help.cc',

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/test/rtcp_packet_parser.h"
namespace webrtc {
namespace test {
RtcpPacketParser::RtcpPacketParser() {}
RtcpPacketParser::~RtcpPacketParser() {}
void RtcpPacketParser::Parse(const void *data, int len) {
const uint8_t* packet = static_cast<const uint8_t*>(data);
RTCPUtility::RTCPParserV2 parser(packet, len, true);
for (RTCPUtility::RTCPPacketTypes type = parser.Begin();
type != RTCPUtility::kRtcpNotValidCode;
type = parser.Iterate()) {
if (type == RTCPUtility::kRtcpSrCode) {
sender_report_.Set(parser.Packet().SR);
} else if (type == RTCPUtility::kRtcpRrCode) {
receiver_report_.Set(parser.Packet().RR);
} else if (type == RTCPUtility::kRtcpByeCode) {
bye_.Set(parser.Packet().BYE);
} else if (type == RTCPUtility::kRtcpReportBlockItemCode) {
report_block_.Set(parser.Packet().ReportBlockItem);
++report_blocks_per_ssrc_[parser.Packet().ReportBlockItem.SSRC];
} else if (type == RTCPUtility::kRtcpPsfbFirCode) {
fir_.Set(parser.Packet().FIR);
} else if (type == webrtc::RTCPUtility::kRtcpPsfbFirItemCode) {
fir_item_.Set(parser.Packet().FIRItem);
} else if (type == RTCPUtility::kRtcpRtpfbNackCode) {
nack_.Set(parser.Packet().NACK);
} else if (type == RTCPUtility::kRtcpRtpfbNackItemCode) {
nack_item_.Set(parser.Packet().NACKItem);
}
}
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,235 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*
*/
#ifndef WEBRTC_TEST_RTCP_PACKET_PARSER_H_
#define WEBRTC_TEST_RTCP_PACKET_PARSER_H_
#include <map>
#include <vector>
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/typedefs.h"
namespace webrtc {
namespace test {
class RtcpPacketParser;
class SenderReport {
public:
SenderReport() : num_packets_(0) {}
~SenderReport() {}
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; }
private:
friend class RtcpPacketParser;
void Set(const RTCPUtility::RTCPPacketSR& sr) {
sr_ = sr;
++num_packets_;
}
int num_packets_;
RTCPUtility::RTCPPacketSR sr_;
};
class ReceiverReport {
public:
ReceiverReport() : num_packets_(0) {}
~ReceiverReport() {}
int num_packets() { return num_packets_; }
uint32_t Ssrc() { 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 {
public:
ReportBlock() : num_packets_(0) {}
~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; }
private:
friend class RtcpPacketParser;
void Set(const RTCPUtility::RTCPPacketReportBlockItem& rb) {
rb_ = rb;
++num_packets_;
}
int num_packets_;
RTCPUtility::RTCPPacketReportBlockItem rb_;
};
class Bye {
public:
Bye() : num_packets_(0) {}
~Bye() {}
int num_packets() { return num_packets_; }
uint32_t Ssrc() { 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 {
public:
Fir() : num_packets_(0) {}
~Fir() {}
int num_packets() { return num_packets_; }
uint32_t Ssrc() { 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 {
public:
FirItem() : num_packets_(0) {}
~FirItem() {}
int num_packets() { return num_packets_; }
uint32_t Ssrc() { return fir_item_.SSRC; }
uint8_t SeqNum() { 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 {
public:
Nack() : num_packets_(0) {}
~Nack() {}
int num_packets() { return num_packets_; }
uint32_t Ssrc() { return nack_.SenderSSRC; }
uint32_t MediaSsrc() { 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 {
public:
NackItem() : num_packets_(0) {}
~NackItem() {}
int num_packets() { return num_packets_; }
std::vector<uint16_t> last_nack_list() {
assert(num_packets_ > 0);
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)) {
last_nack_list_.push_back(nack_item.PacketID + i + 1);
}
}
++num_packets_;
}
int num_packets_;
std::vector<uint16_t> last_nack_list_;
};
class RtcpPacketParser {
public:
RtcpPacketParser();
~RtcpPacketParser();
void Parse(const void *packet, int packet_len);
SenderReport* sender_report() { return &sender_report_; }
ReceiverReport* receiver_report() { return &receiver_report_; }
ReportBlock* report_block() { return &report_block_; }
Bye* bye() { return &bye_; }
Fir* fir() { return &fir_; }
FirItem* fir_item() { return &fir_item_; }
Nack* nack() { return &nack_; }
NackItem* nack_item() { return &nack_item_; }
int report_blocks_per_ssrc(uint32_t ssrc) {
return report_blocks_per_ssrc_[ssrc];
}
private:
SenderReport sender_report_;
ReceiverReport receiver_report_;
ReportBlock report_block_;
Bye bye_;
Fir fir_;
FirItem fir_item_;
Nack nack_;
NackItem nack_item_;
std::map<uint32_t, int> report_blocks_per_ssrc_;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_RTCP_PACKET_PARSER_H_

View File

@ -52,6 +52,17 @@
'<(webrtc_root)/common_video/common_video.gyp:common_video',
],
},
{
'target_name': 'rtcp_packet_parser',
'type': 'static_library',
'sources': [
'rtcp_packet_parser.cc',
'rtcp_packet_parser.h',
],
'dependencies': [
'<(webrtc_root)/modules/modules.gyp:rtp_rtcp',
],
},
{
'target_name': 'test_support',
'type': 'static_library',