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:
parent
c0907eff42
commit
0f2809a5ac
@ -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',
|
||||
|
309
webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
Normal file
309
webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
Normal 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
|
389
webrtc/modules/rtp_rtcp/source/rtcp_packet.h
Normal file
389
webrtc/modules/rtp_rtcp/source/rtcp_packet.h
Normal 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_
|
312
webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
Normal file
312
webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc
Normal 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
|
@ -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',
|
||||
|
47
webrtc/test/rtcp_packet_parser.cc
Normal file
47
webrtc/test/rtcp_packet_parser.cc
Normal 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
|
235
webrtc/test/rtcp_packet_parser.h
Normal file
235
webrtc/test/rtcp_packet_parser.h
Normal 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_
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user