git-svn-id: http://webrtc.googlecode.com/svn/trunk@1219 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
asapersson@webrtc.org 2011-12-16 14:31:37 +00:00
parent 9775a30859
commit 5249cc8f77
26 changed files with 1408 additions and 50 deletions

View File

@ -27,6 +27,11 @@ struct RTPHeader
WebRtc_UWord16 headerLength;
};
struct RTPHeaderExtension
{
WebRtc_Word32 transmissionTimeOffset;
};
struct RTPAudioHeader
{
WebRtc_UWord8 numEnergy; // number of valid entries in arrOfEnergy
@ -118,6 +123,7 @@ struct WebRtcRTPHeader
RTPHeader header;
FrameType frameType;
RTPTypeHeader type;
RTPHeaderExtension extension;
};
class RTPFragmentationHeader

View File

@ -207,7 +207,7 @@ public:
WebRtc_Word8* plType) = 0;
/*
* Remove a registerd payload type from list of accepted payloads
* Remove a registered payload type from list of accepted payloads
*
* payloadType - payload type of codec
*
@ -216,6 +216,18 @@ public:
virtual WebRtc_Word32 DeRegisterReceivePayload(
const WebRtc_Word8 payloadType) = 0;
/*
* (De)register RTP header extension type and id.
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 RegisterReceiveRtpHeaderExtension(
const RTPExtensionType type,
const WebRtc_UWord8 id) = 0;
virtual WebRtc_Word32 DeregisterReceiveRtpHeaderExtension(
const RTPExtensionType type) = 0;
/*
* Get last received remote timestamp
*/
@ -407,6 +419,18 @@ public:
*/
virtual WebRtc_Word32 DeRegisterSendPayload(const WebRtc_Word8 payloadType) = 0;
/*
* (De)register RTP header extension type and id.
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 RegisterSendRtpHeaderExtension(
const RTPExtensionType type,
const WebRtc_UWord8 id) = 0;
virtual WebRtc_Word32 DeregisterSendRtpHeaderExtension(
const RTPExtensionType type) = 0;
/*
* get start timestamp
*/
@ -735,17 +759,25 @@ public:
/*
* (REMB) Receiver Estimated Max Bitrate
*/
virtual bool REMB() const = 0;;
virtual bool REMB() const = 0;
virtual WebRtc_Word32 SetREMBStatus(const bool enable) = 0;
virtual WebRtc_Word32 SetREMBData(const WebRtc_UWord32 bitrate,
const WebRtc_UWord8 numberOfSSRC,
const WebRtc_UWord32* SSRC) = 0;
/*
* (IJ) Extended jitter report.
*/
virtual bool IJ() const = 0;
virtual WebRtc_Word32 SetIJStatus(const bool enable) = 0;
/*
* (TMMBR) Temporary Max Media Bit Rate
*/
virtual bool TMMBR() const = 0;
virtual bool TMMBR() const = 0;
/*
*

View File

@ -39,6 +39,12 @@ enum RTPAliveType
kRtpAlive = 2
};
enum RTPExtensionType
{
NONE,
TRANSMISSION_TIME_OFFSET
};
enum RTCPAppSubTypes
{
kAppSubtypeBwe = 0x00
@ -60,7 +66,8 @@ enum RTCPPacketType
kRtcpApp = 0x0800,
kRtcpSli = 0x4000,
kRtcpRpsi = 0x8000,
kRtcpRemb = 0x10000
kRtcpRemb = 0x10000,
kRtcpTransmissionTimeOffset = 0x20000
};
enum KeyFrameRequestMethod

View File

@ -356,6 +356,9 @@ RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation,
case RTCPUtility::kRtcpPsfbRpsiCode:
HandleRPSI(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpExtendedIjCode:
HandleIJ(*rtcpParser, rtcpPacketInformation);
break;
case RTCPUtility::kRtcpPsfbFirCode:
HandleFIR(*rtcpParser, rtcpPacketInformation);
break;
@ -1151,6 +1154,30 @@ RTCPReceiver::HandlePsfbApp(RTCPUtility::RTCPParserV2& rtcpParser,
}
}
// no need for critsect we have _criticalSectionRTCPReceiver
void
RTCPReceiver::HandleIJ(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)
{
const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
while (pktType == RTCPUtility::kRtcpExtendedIjItemCode)
{
HandleIJItem(rtcpPacket, rtcpPacketInformation);
pktType = rtcpParser.Iterate();
}
}
void
RTCPReceiver::HandleIJItem(const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPPacketInformation& rtcpPacketInformation)
{
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
rtcpPacketInformation.interArrivalJitter =
rtcpPacket.ExtendedJitterReportItem.Jitter;
}
void
RTCPReceiver::HandleREMBItem(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPPacketInformation& rtcpPacketInformation)

View File

@ -151,6 +151,12 @@ protected:
void HandleREMBItem(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
void HandleIJ(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
void HandleIJItem(const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
void HandleTMMBR(RTCPUtility::RTCPParserV2& rtcpParser,
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);

View File

@ -30,6 +30,7 @@ RTCPPacketInformation::RTCPPacketInformation() :
roundTripTime(0),
lastReceivedExtendedHighSeqNum(0),
jitter(0),
interArrivalJitter(0),
sliPictureId(0),
rpsiPictureId(0),
VoIPMetric(NULL)

View File

@ -57,6 +57,8 @@ public:
WebRtc_UWord32 lastReceivedExtendedHighSeqNum;
WebRtc_UWord32 jitter;
WebRtc_UWord32 interArrivalJitter;
WebRtc_UWord8 sliPictureId;
WebRtc_UWord64 rpsiPictureId;
WebRtc_UWord32 receiverEstimatedMaxBitrate;

View File

@ -41,6 +41,7 @@ RTCPSender::RTCPSender(const WebRtc_Word32 id,
_REMB(false),
_sendREMB(false),
_TMMBR(false),
_IJ(false),
_nextTimeToSendRTCP(0),
_SSRC(0),
_remoteSSRC(0),
@ -129,6 +130,7 @@ RTCPSender::Init()
_sending = false;
_sendTMMBN = false;
_TMMBR = false;
_IJ = false;
_REMB = false;
_sendREMB = false;
_SSRC = 0;
@ -282,6 +284,21 @@ RTCPSender::SetTMMBRStatus(const bool enable)
return 0;
}
bool
RTCPSender::IJ() const
{
CriticalSectionScoped lock(_criticalSectionRTCPSender);
return _IJ;
}
WebRtc_Word32
RTCPSender::SetIJStatus(const bool enable)
{
CriticalSectionScoped lock(_criticalSectionRTCPSender);
_IJ = enable;
return 0;
}
void
RTCPSender::SetSSRC( const WebRtc_UWord32 ssrc)
{
@ -828,6 +845,57 @@ RTCPSender::BuildRR(WebRtc_UWord8* rtcpbuffer,
return 0;
}
// From RFC 5450: Transmission Time Offsets in RTP Streams.
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// hdr |V=2|P| RC | PT=IJ=195 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | inter-arrival jitter |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// . .
// . .
// . .
// | inter-arrival jitter |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// If present, this RTCP packet must be placed after a receiver report
// (inside a compound RTCP packet), and MUST have the same value for RC
// (reception report count) as the receiver report.
WebRtc_Word32
RTCPSender::BuildExtendedJitterReport(
WebRtc_UWord8* rtcpbuffer,
WebRtc_UWord32& pos,
const WebRtc_UWord32 jitterTransmissionTimeOffset)
{
if (_reportBlocks.Size() > 0)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Not implemented.");
return 0;
}
// sanity
if(pos + 8 >= IP_PACKET_SIZE)
{
return -2;
}
// add picture loss indicator
WebRtc_UWord8 RC = 1;
rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + RC;
rtcpbuffer[pos++]=(WebRtc_UWord8)195;
// Used fixed length of 2
rtcpbuffer[pos++]=(WebRtc_UWord8)0;
rtcpbuffer[pos++]=(WebRtc_UWord8)(1);
// Add inter-arrival jitter
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
jitterTransmissionTimeOffset);
pos += 4;
return 0;
}
WebRtc_Word32
RTCPSender::BuildPLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
{
@ -1567,7 +1635,6 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
WebRtc_UWord32 pos = 0;
WebRtc_UWord8 rtcpbuffer[IP_PACKET_SIZE];
do // only to be able to use break :) (and the critsect must be inside its own scope)
{
// collect the received information
@ -1576,6 +1643,7 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
WebRtc_UWord32 NTPsec = 0;
WebRtc_UWord32 NTPfrac = 0;
bool rtcpCompound = false;
WebRtc_UWord32 jitterTransmissionOffset = 0;
{
CriticalSectionScoped lock(_criticalSectionRTCPSender);
@ -1597,7 +1665,8 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
if(_rtpRtcp.ReportBlockStatistics(&received.fractionLost,
&received.cumulativeLost,
&received.extendedHighSeqNum,
&received.jitter) == 0)
&received.jitter,
&jitterTransmissionOffset) == 0)
{
hasReceived = true;
@ -1673,6 +1742,10 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
{
rtcpPacketTypeFlags |= kRtcpRr;
}
if (_IJ && hasReceived)
{
rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
}
} else if(_method == kRtcpNonCompound)
{
if(rtcpPacketTypeFlags & kRtcpReport)
@ -1783,6 +1856,22 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
}
}
}
if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset)
{
// If present, this RTCP packet must be placed after a
// receiver report.
buildVal = BuildExtendedJitterReport(rtcpbuffer,
pos,
jitterTransmissionOffset);
if(buildVal == -1)
{
return -1; // error
}
else if(buildVal == -2)
{
break; // out of buffer
}
}
if(rtcpPacketTypeFlags & kRtcpPli)
{
buildVal = BuildPLI(rtcpbuffer, pos);

View File

@ -97,6 +97,13 @@ public:
WebRtc_Word32 RequestTMMBR(const WebRtc_UWord32 estimatedBW,
const WebRtc_UWord32 packetOH);
/*
* Extended jitter report
*/
bool IJ() const;
WebRtc_Word32 SetIJStatus(const bool enable);
/*
*
*/
@ -146,6 +153,11 @@ private:
const WebRtc_UWord32 NTPfrac,
const RTCPReportBlock* received = NULL);
WebRtc_Word32 BuildExtendedJitterReport(
WebRtc_UWord8* rtcpbuffer,
WebRtc_UWord32& pos,
const WebRtc_UWord32 jitterTransmissionTimeOffset);
WebRtc_Word32 BuildSDEC(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos);
WebRtc_Word32 BuildPLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos);
WebRtc_Word32 BuildREMB(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos);
@ -188,6 +200,7 @@ private:
bool _REMB;
bool _sendREMB;
bool _TMMBR;
bool _IJ;
WebRtc_UWord32 _nextTimeToSendRTCP;

View File

@ -0,0 +1,178 @@
/*
* Copyright (c) 2011 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 RTCPSender.
*/
#include <gtest/gtest.h>
#include "common_types.h"
#include "rtp_utility.h"
#include "rtcp_sender.h"
#include "rtcp_receiver.h"
#include "rtp_rtcp_impl.h"
namespace webrtc {
void CreateRtpPacket(const bool marker_bit, const WebRtc_UWord8 payload,
const WebRtc_UWord16 seq_num, const WebRtc_UWord32 timestamp,
const WebRtc_UWord32 ssrc, WebRtc_UWord8* array,
WebRtc_UWord16* cur_pos) {
ASSERT_TRUE(payload <= 127);
array[(*cur_pos)++] = 0x80;
array[(*cur_pos)++] = payload | (marker_bit ? 0x80 : 0);
array[(*cur_pos)++] = seq_num >> 8;
array[(*cur_pos)++] = seq_num;
array[(*cur_pos)++] = timestamp >> 24;
array[(*cur_pos)++] = timestamp >> 16;
array[(*cur_pos)++] = timestamp >> 8;
array[(*cur_pos)++] = timestamp;
array[(*cur_pos)++] = ssrc >> 24;
array[(*cur_pos)++] = ssrc >> 16;
array[(*cur_pos)++] = ssrc >> 8;
array[(*cur_pos)++] = ssrc;
// VP8 payload header
array[(*cur_pos)++] = 0x90; // X bit = 1
array[(*cur_pos)++] = 0x20; // T bit = 1
array[(*cur_pos)++] = 0x00; // TID = 0
array[(*cur_pos)++] = 0x00; // Key frame
array[(*cur_pos)++] = 0x00;
array[(*cur_pos)++] = 0x00;
array[(*cur_pos)++] = 0x9d;
array[(*cur_pos)++] = 0x01;
array[(*cur_pos)++] = 0x2a;
array[(*cur_pos)++] = 128;
array[(*cur_pos)++] = 0;
array[(*cur_pos)++] = 96;
array[(*cur_pos)++] = 0;
}
class TestTransport : public Transport,
public RtpData {
public:
TestTransport(RTCPReceiver* rtcp_receiver) :
rtcp_receiver_(rtcp_receiver) {
}
virtual int SendPacket(int /*ch*/, const void* /*data*/, int /*len*/) {
return -1;
}
virtual int SendRTCPPacket(int /*ch*/, const void *packet, int packet_len) {
RTCPUtility::RTCPParserV2 rtcpParser((WebRtc_UWord8*)packet,
(WebRtc_Word32)packet_len,
true); // Allow non-compound RTCP
EXPECT_EQ(true, rtcpParser.IsValid());
RTCPHelp::RTCPPacketInformation rtcpPacketInformation;
EXPECT_EQ(0, rtcp_receiver_->IncomingRTCPPacket(rtcpPacketInformation,
&rtcpParser));
rtcp_packet_info_ = rtcpPacketInformation;
return packet_len;
}
virtual int OnReceivedPayloadData(const WebRtc_UWord8* payloadData,
const WebRtc_UWord16 payloadSize,
const WebRtcRTPHeader* rtpHeader)
{return 0;}
RTCPReceiver* rtcp_receiver_;
RTCPHelp::RTCPPacketInformation rtcp_packet_info_;
};
class RtcpSenderTest : public ::testing::Test {
protected:
RtcpSenderTest() {
rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(0, false,
ModuleRTPUtility::GetSystemClock());
rtcp_sender_ = new RTCPSender(0, false, ModuleRTPUtility::GetSystemClock(),
rtp_rtcp_impl_);
rtcp_receiver_ = new RTCPReceiver(0, ModuleRTPUtility::GetSystemClock(),
rtp_rtcp_impl_);
test_transport_ = new TestTransport(rtcp_receiver_);
// Initialize
EXPECT_EQ(0, rtcp_sender_->Init());
EXPECT_EQ(0, rtcp_sender_->RegisterSendTransport(test_transport_));
EXPECT_EQ(0, rtp_rtcp_impl_->RegisterIncomingDataCallback(test_transport_));
}
~RtcpSenderTest() {
delete rtcp_sender_;
delete rtcp_receiver_;
delete rtp_rtcp_impl_;
delete test_transport_;
}
ModuleRtpRtcpImpl* rtp_rtcp_impl_;
RTCPSender* rtcp_sender_;
RTCPReceiver* rtcp_receiver_;
TestTransport* test_transport_;
enum {kMaxPacketLength = 1500};
uint8_t packet_[kMaxPacketLength];
};
TEST_F(RtcpSenderTest, RtcpOff) {
EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpOff));
EXPECT_EQ(-1, rtcp_sender_->SendRTCP(kRtcpSr));
}
TEST_F(RtcpSenderTest, IJStatus) {
ASSERT_FALSE(rtcp_sender_->IJ());
EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true));
ASSERT_TRUE(rtcp_sender_->IJ());
}
TEST_F(RtcpSenderTest, TestCompound) {
const bool marker_bit = false;
const WebRtc_UWord8 payload = 100;
const WebRtc_UWord16 seq_num = 11111;
const WebRtc_UWord32 timestamp = 1234567;
const WebRtc_UWord32 ssrc = 0x11111111;
WebRtc_UWord16 packet_length = 0;
CreateRtpPacket(marker_bit, payload, seq_num, timestamp, ssrc, packet_,
&packet_length);
EXPECT_EQ(25, packet_length);
VideoCodec codec_inst;
strncpy(codec_inst.plName, "VP8", webrtc::kPayloadNameSize - 1);
codec_inst.codecType = webrtc::kVideoCodecVP8;
codec_inst.plType = payload;
EXPECT_EQ(0, rtp_rtcp_impl_->RegisterReceivePayload(codec_inst));
// Make sure RTP packet has been received.
EXPECT_EQ(0, rtp_rtcp_impl_->IncomingPacket(packet_, packet_length));
EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true));
EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr));
// Transmission time offset packet should be received.
ASSERT_TRUE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags &
kRtcpTransmissionTimeOffset);
}
TEST_F(RtcpSenderTest, TestCompound_NoRtpReceived) {
EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true));
EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr));
// Transmission time offset packet should not be received.
ASSERT_FALSE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags &
kRtcpTransmissionTimeOffset);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
} // namespace webrtc

View File

@ -100,6 +100,9 @@ RTCPUtility::RTCPParserV2::Iterate()
case State_BYEItem:
IterateBYEItem();
break;
case State_ExtendedJitterItem:
IterateExtendedJitterItem();
break;
case State_RTPFB_NACKItem:
IterateNACKItem();
break;
@ -196,6 +199,13 @@ RTCPUtility::RTCPParserV2::IterateTopLevel()
}
return;
}
case PT_IJ:
{
// number of Report blocks
_numberOfBlocks = header.IC;
ParseIJ();
return;
}
case PT_RTPFB: // Fall through!
case PT_PSFB:
{
@ -266,6 +276,16 @@ RTCPUtility::RTCPParserV2::IterateBYEItem()
}
}
void
RTCPUtility::RTCPParserV2::IterateExtendedJitterItem()
{
const bool success = ParseIJItem();
if (!success)
{
Iterate();
}
}
void
RTCPUtility::RTCPParserV2::IterateNACKItem()
{
@ -587,6 +607,62 @@ RTCPUtility::RTCPParserV2::ParseReportBlockItem()
return true;
}
/* From RFC 5450: Transmission Time Offsets in RTP Streams.
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
hdr |V=2|P| RC | PT=IJ=195 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| inter-arrival jitter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. .
. .
. .
| inter-arrival jitter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
bool
RTCPUtility::RTCPParserV2::ParseIJ()
{
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
if (length < 4)
{
return false;
}
_ptrRTCPData += 4; // Skip header
_packetType = kRtcpExtendedIjCode;
// State transition
_state = State_ExtendedJitterItem;
return true;
}
bool
RTCPUtility::RTCPParserV2::ParseIJItem()
{
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
if (length < 4 || _numberOfBlocks <= 0)
{
_state = State_TopLevel;
EndCurrentBlock();
return false;
}
_packet.ExtendedJitterReportItem.Jitter = *_ptrRTCPData++ << 24;
_packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++ << 16;
_packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++ << 8;
_packet.ExtendedJitterReportItem.Jitter += *_ptrRTCPData++;
_numberOfBlocks--;
_packetType = kRtcpExtendedIjItemCode;
return true;
}
bool
RTCPUtility::RTCPParserV2::ParseSDES()
{

View File

@ -67,6 +67,12 @@ namespace RTCPUtility {
WebRtc_UWord8 CNameLength;
};
struct RTCPPacketExtendedJitterReportItem
{
// RFC 5450
WebRtc_UWord32 Jitter;
};
struct RTCPPacketBYE
{
WebRtc_UWord32 SenderSSRC;
@ -203,6 +209,8 @@ namespace RTCPUtility {
RTCPPacketSDESCName CName;
RTCPPacketBYE BYE;
RTCPPacketExtendedJitterReportItem ExtendedJitterReportItem;
RTCPPacketRTPFBNACK NACK;
RTCPPacketRTPFBNACKItem NACKItem;
@ -238,6 +246,10 @@ namespace RTCPUtility {
kRtcpSdesChunkCode,
kRtcpByeCode,
// RFC5450
kRtcpExtendedIjCode,
kRtcpExtendedIjItemCode,
// RFC4585
kRtcpRtpfbNackCode,
kRtcpRtpfbNackItemCode,
@ -290,6 +302,7 @@ namespace RTCPUtility {
enum RTCPPT
{
PT_IJ = 195,
PT_SR = 200,
PT_RR = 201,
PT_SDES = 202,
@ -329,6 +342,7 @@ namespace RTCPUtility {
State_ReportBlockItem, // SR/RR report block
State_SDESChunk, // SDES chunk
State_BYEItem, // BYE item
State_ExtendedJitterItem, // Extended jitter report item
State_RTPFB_NACKItem, // NACK FCI item
State_RTPFB_TMMBRItem, // TMMBR FCI item
State_RTPFB_TMMBNItem, // TMMBN FCI item
@ -346,6 +360,7 @@ namespace RTCPUtility {
void IterateReportBlockItem();
void IterateSDESChunk();
void IterateBYEItem();
void IterateExtendedJitterItem();
void IterateNACKItem();
void IterateTMMBRItem();
void IterateTMMBNItem();
@ -370,6 +385,9 @@ namespace RTCPUtility {
bool ParseBYE();
bool ParseBYEItem();
bool ParseIJ();
bool ParseIJItem();
bool ParseXR();
bool ParseXRItem();
bool ParseXRVOIPMetricItem();

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2011 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 <cassert>
#include "common_types.h"
#include "rtp_header_extension.h"
namespace webrtc {
RtpHeaderExtensionMap::RtpHeaderExtensionMap() {
}
RtpHeaderExtensionMap::~RtpHeaderExtensionMap() {
Erase();
}
void RtpHeaderExtensionMap::Erase() {
while (extensionMap_.Size() != 0) {
MapItem* item = extensionMap_.First();
assert(item);
HeaderExtension* extension = (HeaderExtension*)item->GetItem();
extensionMap_.Erase(item);
delete extension;
}
}
WebRtc_Word32 RtpHeaderExtensionMap::Register(const RTPExtensionType type,
const WebRtc_UWord8 id) {
if (id < 1 || id > 14) {
return -1;
}
MapItem* item = extensionMap_.Find(id);
if (item != NULL) {
return -1;
}
HeaderExtension* extension = new HeaderExtension(type);
extensionMap_.Insert(id, extension);
return 0;
}
WebRtc_Word32 RtpHeaderExtensionMap::Deregister(const RTPExtensionType type) {
WebRtc_UWord8 id;
if (GetId(type, &id) != 0) {
return -1;
}
MapItem* item = extensionMap_.Find(id);
if (item == NULL) {
return -1;
}
HeaderExtension* extension = (HeaderExtension*)item->GetItem();
extensionMap_.Erase(item);
delete extension;
return 0;
}
WebRtc_Word32 RtpHeaderExtensionMap::GetType(const WebRtc_UWord8 id,
RTPExtensionType* type) const {
assert(type);
MapItem* item = extensionMap_.Find(id);
if (item == NULL) {
return -1;
}
HeaderExtension* extension = (HeaderExtension*)item->GetItem();
*type = extension->type;
return 0;
}
WebRtc_Word32 RtpHeaderExtensionMap::GetId(const RTPExtensionType type,
WebRtc_UWord8* id) const {
assert(id);
MapItem* item = extensionMap_.First();
while (item != NULL) {
HeaderExtension* extension = (HeaderExtension*)item->GetItem();
if (extension->type == type) {
*id = item->GetId();
return 0;
}
item = extensionMap_.Next(item);
}
return -1;
}
WebRtc_UWord16 RtpHeaderExtensionMap::GetTotalLengthInBytes() const
{
// Get length for each extension block.
WebRtc_UWord16 length = 0;
MapItem* item = extensionMap_.First();
while (item != NULL) {
HeaderExtension* extension = (HeaderExtension*)item->GetItem();
length += extension->length;
item = extensionMap_.Next(item);
}
// Add RTP extension header length.
if (length > 0) {
length += RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES;
}
return length;
}
WebRtc_Word32 RtpHeaderExtensionMap::Size() const {
return extensionMap_.Size();
}
RTPExtensionType RtpHeaderExtensionMap::First() const {
MapItem* item = extensionMap_.First();
if (item == NULL) {
return NONE;
}
HeaderExtension* extension = (HeaderExtension*)item->GetItem();
return extension->type;
}
RTPExtensionType RtpHeaderExtensionMap::Next(RTPExtensionType type) const
{
WebRtc_UWord8 id;
if (GetId(type, &id) != 0) {
return NONE;
}
MapItem* item = extensionMap_.Find(id);
if (item == NULL) {
return NONE;
}
item = extensionMap_.Next(item);
if (item == NULL) {
return NONE;
}
HeaderExtension* extension = (HeaderExtension*)item->GetItem();
return extension->type;
}
void RtpHeaderExtensionMap::GetCopy(RtpHeaderExtensionMap* map) const {
assert(map);
MapItem* item = extensionMap_.First();
while (item != NULL) {
HeaderExtension* extension = (HeaderExtension*)item->GetItem();
map->Register(extension->type, item->GetId());
item = extensionMap_.Next(item);
}
}
} // namespace webrtc

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2011 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_RTP_HEADER_EXTENSION_H_
#define WEBRTC_MODULES_RTP_RTCP_RTP_HEADER_EXTENSION_H_
#include "map_wrapper.h"
#include "rtp_rtcp_defines.h"
#include "typedefs.h"
namespace webrtc {
enum {RTP_ONE_BYTE_HEADER_EXTENSION = 0xbede};
enum ExtensionLength {
RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES = 4,
TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES = 4
};
struct HeaderExtension {
HeaderExtension(RTPExtensionType extension_type)
: type(extension_type),
length(0) {
if (type == TRANSMISSION_TIME_OFFSET) {
length = TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES;
}
}
const RTPExtensionType type;
WebRtc_UWord8 length;
};
class RtpHeaderExtensionMap {
public:
RtpHeaderExtensionMap();
~RtpHeaderExtensionMap();
void Erase();
WebRtc_Word32 Register(const RTPExtensionType type, const WebRtc_UWord8 id);
WebRtc_Word32 Deregister(const RTPExtensionType type);
WebRtc_Word32 GetType(const WebRtc_UWord8 id, RTPExtensionType* type) const;
WebRtc_Word32 GetId(const RTPExtensionType type, WebRtc_UWord8* id) const;
WebRtc_UWord16 GetTotalLengthInBytes() const;
void GetCopy(RtpHeaderExtensionMap* map) const;
WebRtc_Word32 Size() const;
RTPExtensionType First() const;
RTPExtensionType Next(RTPExtensionType type) const;
private:
MapWrapper extensionMap_;
};
}
#endif // WEBRTC_MODULES_RTP_RTCP_RTP_HEADER_EXTENSION_H_

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2011 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 RtpHeaderExtensionMap.
*/
#include <gtest/gtest.h>
#include "rtp_header_extension.h"
#include "rtp_rtcp_defines.h"
#include "typedefs.h"
namespace webrtc {
class RtpHeaderExtensionTest : public ::testing::Test {
protected:
RtpHeaderExtensionTest() {}
~RtpHeaderExtensionTest() {}
RtpHeaderExtensionMap map_;
enum {kId = 3};
};
TEST_F(RtpHeaderExtensionTest, Register) {
EXPECT_EQ(0, map_.Size());
EXPECT_EQ(0, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
EXPECT_EQ(1, map_.Size());
EXPECT_EQ(0, map_.Deregister(TRANSMISSION_TIME_OFFSET));
EXPECT_EQ(0, map_.Size());
}
TEST_F(RtpHeaderExtensionTest, RegisterIllegalArg) {
// Valid range for id: [1-14].
EXPECT_EQ(-1, map_.Register(TRANSMISSION_TIME_OFFSET, 0));
EXPECT_EQ(-1, map_.Register(TRANSMISSION_TIME_OFFSET, 15));
}
TEST_F(RtpHeaderExtensionTest, DeregisterIllegalArg) {
// Not registered.
EXPECT_EQ(-1, map_.Deregister(TRANSMISSION_TIME_OFFSET));
}
TEST_F(RtpHeaderExtensionTest, NonUniqueId) {
EXPECT_EQ(0, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
EXPECT_EQ(-1, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
}
TEST_F(RtpHeaderExtensionTest, GetLength) {
EXPECT_EQ(0, map_.GetTotalLengthInBytes());
EXPECT_EQ(0, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
EXPECT_EQ(RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES +
TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES,
map_.GetTotalLengthInBytes());
}
TEST_F(RtpHeaderExtensionTest, GetType) {
RTPExtensionType typeOut;
EXPECT_EQ(-1, map_.GetType(kId, &typeOut));
EXPECT_EQ(0, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
EXPECT_EQ(0, map_.GetType(kId, &typeOut));
EXPECT_EQ(TRANSMISSION_TIME_OFFSET, typeOut);
}
TEST_F(RtpHeaderExtensionTest, GetId) {
WebRtc_UWord8 idOut;
EXPECT_EQ(-1, map_.GetId(TRANSMISSION_TIME_OFFSET, &idOut));
EXPECT_EQ(0, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
EXPECT_EQ(0, map_.GetId(TRANSMISSION_TIME_OFFSET, &idOut));
EXPECT_EQ(kId, idOut);
}
TEST_F(RtpHeaderExtensionTest, IterateTypes) {
EXPECT_EQ(NONE, map_.First());
EXPECT_EQ(NONE, map_.Next(TRANSMISSION_TIME_OFFSET));
EXPECT_EQ(0, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
EXPECT_EQ(TRANSMISSION_TIME_OFFSET, map_.First());
EXPECT_EQ(NONE, map_.Next(TRANSMISSION_TIME_OFFSET));
}
TEST_F(RtpHeaderExtensionTest, GetCopy) {
EXPECT_EQ(0, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
RtpHeaderExtensionMap mapOut;
map_.GetCopy(&mapOut);
EXPECT_EQ(1, mapOut.Size());
EXPECT_EQ(TRANSMISSION_TIME_OFFSET, mapOut.First());
}
TEST_F(RtpHeaderExtensionTest, Erase) {
EXPECT_EQ(0, map_.Register(TRANSMISSION_TIME_OFFSET, kId));
EXPECT_EQ(1, map_.Size());
map_.Erase();
EXPECT_EQ(0, map_.Size());
}
} // namespace webrtc

View File

@ -48,6 +48,7 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id,
_redPayloadType(-1),
_payloadTypeMap(),
_rtpHeaderExtensionMap(),
_SSRC(0),
_numCSRCs(0),
_currentRemoteCSRC(),
@ -59,9 +60,11 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id,
_jitterQ4(0),
_jitterMaxQ4(0),
_cumulativeLoss(0),
_jitterQ4TransmissionTimeOffset(0),
_localTimeLastReceivedTimestamp(0),
_lastReceivedTimestamp(0),
_lastReceivedSequenceNumber(0),
_lastReceivedTransmissionTimeOffset(0),
_receivedSeqFirst(0),
_receivedSeqMax(0),
@ -79,6 +82,7 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id,
_lastReportCumulativeLost(0),
_lastReportExtendedHighSeqNum(0),
_lastReportJitter(0),
_lastReportJitterTransmissionTimeOffset(0),
_nackMethod(kNackOff)
{
@ -150,12 +154,14 @@ RTPReceiver::Init()
_jitterQ4 = 0;
_jitterMaxQ4 = 0;
_cumulativeLoss = 0;
_jitterQ4TransmissionTimeOffset = 0;
_useSSRCFilter = false;
_SSRCFilter = 0;
_localTimeLastReceivedTimestamp = 0;
_lastReceivedTimestamp = 0;
_lastReceivedSequenceNumber = 0;
_lastReceivedTransmissionTimeOffset = 0;
_receivedSeqFirst = 0;
_receivedSeqMax = 0;
@ -173,6 +179,9 @@ RTPReceiver::Init()
_lastReportCumulativeLost = 0;
_lastReportExtendedHighSeqNum = 0;
_lastReportJitter = 0;
_lastReportJitterTransmissionTimeOffset = 0;
_rtpHeaderExtensionMap.Erase();
// clear db
bool loop = true;
@ -683,6 +692,27 @@ RTPReceiver::RemotePayload(WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
return -1;
}
WebRtc_Word32
RTPReceiver::RegisterRtpHeaderExtension(const RTPExtensionType type,
const WebRtc_UWord8 id)
{
CriticalSectionScoped cs(_criticalSectionRTPReceiver);
return _rtpHeaderExtensionMap.Register(type, id);
}
WebRtc_Word32
RTPReceiver::DeregisterRtpHeaderExtension(const RTPExtensionType type)
{
CriticalSectionScoped cs(_criticalSectionRTPReceiver);
return _rtpHeaderExtensionMap.Deregister(type);
}
void RTPReceiver::GetHeaderExtensionMapCopy(RtpHeaderExtensionMap* map) const
{
CriticalSectionScoped cs(_criticalSectionRTPReceiver);
_rtpHeaderExtensionMap.GetCopy(map);
}
NACKMethod
RTPReceiver::NACK() const
{
@ -852,6 +882,8 @@ RTPReceiver::IncomingRTPPacket(WebRtcRTPHeader* rtpHeader,
_lastReceivedTimestamp = rtpHeader->header.timestamp;
}
_lastReceivedSequenceNumber = rtpHeader->header.sequenceNumber;
_lastReceivedTransmissionTimeOffset =
rtpHeader->extension.transmissionTimeOffset;
}
}
return retVal;
@ -931,6 +963,26 @@ RTPReceiver::UpdateStatistics(const WebRtcRTPHeader* rtpHeader,
WebRtc_Word32 jitterDiffQ4 = (timeDiffSamples << 4) - _jitterQ4;
_jitterQ4 += ((jitterDiffQ4 + 8) >> 4);
}
// Extended jitter report, RFC 5450.
// Actual network jitter, excluding the source-introduced jitter.
WebRtc_Word32 timeDiffSamplesExt =
(RTPtime - _localTimeLastReceivedTimestamp) -
((rtpHeader->header.timestamp +
rtpHeader->extension.transmissionTimeOffset) -
(_lastReceivedTimestamp +
_lastReceivedTransmissionTimeOffset));
timeDiffSamplesExt = abs(timeDiffSamplesExt);
if(timeDiffSamplesExt < 450000) // Use 5 secs video freq as border
{
// note we calculate in Q4 to avoid using float
WebRtc_Word32 jitterDiffQ4TransmissionTimeOffset =
(timeDiffSamplesExt << 4) - _jitterQ4TransmissionTimeOffset;
_jitterQ4TransmissionTimeOffset +=
((jitterDiffQ4TransmissionTimeOffset + 8) >> 4);
}
}
_localTimeLastReceivedTimestamp = RTPtime;
} else
@ -1130,6 +1182,7 @@ RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtpHeader)
_lastReceivedTimestamp = 0;
_lastReceivedSequenceNumber = 0;
_lastReceivedTransmissionTimeOffset = 0;
if (_SSRC) // do we have a SSRC? then the stream is restarted
{
@ -1461,9 +1514,11 @@ RTPReceiver::ResetStatistics()
_lastReportCumulativeLost = 0;
_lastReportExtendedHighSeqNum = 0;
_lastReportJitter = 0;
_lastReportJitterTransmissionTimeOffset = 0;
_jitterQ4 = 0;
_jitterMaxQ4 = 0;
_cumulativeLoss = 0;
_jitterQ4TransmissionTimeOffset = 0;
_receivedSeqWraps = 0;
_receivedSeqMax = 0;
_receivedSeqFirst = 0;
@ -1492,6 +1547,7 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter,
WebRtc_UWord32 *max_jitter,
WebRtc_UWord32 *jitter_transmission_time_offset,
bool reset) const
{
WebRtc_Word32 missing;
@ -1500,6 +1556,7 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
ext_max,
jitter,
max_jitter,
jitter_transmission_time_offset,
&missing,
reset);
}
@ -1510,6 +1567,7 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter,
WebRtc_UWord32 *max_jitter,
WebRtc_UWord32 *jitter_transmission_time_offset,
WebRtc_Word32 *missing,
bool reset) const
{
@ -1555,6 +1613,11 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
// and needs to be scaled by 1/16
*max_jitter = (_jitterMaxQ4 >> 4);
}
if(jitter_transmission_time_offset)
{
*jitter_transmission_time_offset =
_lastReportJitterTransmissionTimeOffset;
}
return 0;
}
@ -1636,6 +1699,13 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
// and needs to be scaled by 1/16
*max_jitter = (_jitterMaxQ4 >> 4);
}
if(jitter_transmission_time_offset)
{
// note that the internal jitter value is in Q4
// and needs to be scaled by 1/16
*jitter_transmission_time_offset =
(_jitterQ4TransmissionTimeOffset >> 4);
}
if(reset)
{
// store this report
@ -1643,6 +1713,8 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
_lastReportCumulativeLost = _cumulativeLoss; // 24 bits valid
_lastReportExtendedHighSeqNum = (_receivedSeqWraps<<16) + _receivedSeqMax;
_lastReportJitter = (_jitterQ4 >> 4);
_lastReportJitterTransmissionTimeOffset =
(_jitterQ4TransmissionTimeOffset >> 4);
// only for report blocks in RTCP SR and RR
_lastReportInorderPackets = _receivedInorderPacketCount;

View File

@ -14,7 +14,9 @@
#include "typedefs.h"
#include "rtp_utility.h"
#include "rtp_header_extension.h"
#include "rtp_rtcp.h"
#include "rtp_rtcp_defines.h"
#include "rtp_receiver_audio.h"
#include "rtp_receiver_video.h"
#include "rtcp_receiver_help.h"
@ -109,15 +111,17 @@ public:
WebRtc_Word32 Statistics(WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *cum_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter, // will be moved from JB
WebRtc_UWord32 *jitter, // will be moved from JB
WebRtc_UWord32 *max_jitter,
WebRtc_UWord32 *jitter_transmission_time_offset,
bool reset = false) const;
WebRtc_Word32 Statistics(WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *cum_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter, // will be moved from JB
WebRtc_UWord32 *jitter, // will be moved from JB
WebRtc_UWord32 *max_jitter,
WebRtc_UWord32 *jitter_transmission_time_offset,
WebRtc_Word32 *missing,
bool reset = false) const;
@ -134,6 +138,13 @@ public:
WebRtc_UWord32 ByteCountReceived() const;
WebRtc_Word32 RegisterRtpHeaderExtension(const RTPExtensionType type,
const WebRtc_UWord8 id);
WebRtc_Word32 DeregisterRtpHeaderExtension(const RTPExtensionType type);
void GetHeaderExtensionMapCopy(RtpHeaderExtensionMap* map) const;
virtual WebRtc_UWord32 PayloadTypeToPayload(const WebRtc_UWord8 payloadType,
ModuleRTPUtility::Payload*& payload) const;
@ -192,7 +203,8 @@ private:
WebRtc_Word8 _redPayloadType;
//
MapWrapper _payloadTypeMap;
MapWrapper _payloadTypeMap;
RtpHeaderExtensionMap _rtpHeaderExtensionMap;
// SSRCs
WebRtc_UWord32 _SSRC;
@ -201,17 +213,19 @@ private:
WebRtc_UWord8 _numEnergy;
WebRtc_UWord8 _currentRemoteEnergy[kRtpCsrcSize];
bool _useSSRCFilter;
bool _useSSRCFilter;
WebRtc_UWord32 _SSRCFilter;
// stats on received RTP packets
WebRtc_UWord32 _jitterQ4;
mutable WebRtc_UWord32 _jitterMaxQ4;
mutable WebRtc_UWord32 _cumulativeLoss;
WebRtc_UWord32 _jitterQ4TransmissionTimeOffset;
WebRtc_UWord32 _localTimeLastReceivedTimestamp;
WebRtc_UWord32 _lastReceivedTimestamp;
WebRtc_UWord16 _lastReceivedSequenceNumber;
WebRtc_Word32 _lastReceivedTransmissionTimeOffset;
WebRtc_UWord16 _receivedSeqFirst;
WebRtc_UWord16 _receivedSeqMax;
WebRtc_UWord16 _receivedSeqWraps;
@ -230,6 +244,7 @@ private:
mutable WebRtc_UWord32 _lastReportCumulativeLost; // 24 bits valid
mutable WebRtc_UWord32 _lastReportExtendedHighSeqNum;
mutable WebRtc_UWord32 _lastReportJitter;
mutable WebRtc_UWord32 _lastReportJitterTransmissionTimeOffset;
// NACK
NACKMethod _nackMethod;

View File

@ -41,6 +41,8 @@
'rtcp_sender.h',
'rtcp_utility.cc',
'rtcp_utility.h',
'rtp_header_extension.cc',
'rtp_header_extension.h',
'rtp_receiver.cc',
'rtp_receiver.h',
'rtp_sender.cc',

View File

@ -790,7 +790,10 @@ ModuleRtpRtcpImpl::IncomingPacket(const WebRtc_UWord8* incomingPacket,
WebRtcRTPHeader rtpHeader;
memset(&rtpHeader, 0, sizeof(rtpHeader));
const bool validRTPHeader = rtpParser.Parse(rtpHeader);
RtpHeaderExtensionMap map;
_rtpReceiver.GetHeaderExtensionMapCopy(&map);
const bool validRTPHeader = rtpParser.Parse(rtpHeader, &map);
if(!validRTPHeader)
{
WEBRTC_TRACE(kTraceDebug,
@ -1668,7 +1671,11 @@ ModuleRtpRtcpImpl::StatisticsRTP(WebRtc_UWord8 *fraction_lost,
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "StatisticsRTP()");
WebRtc_Word32 retVal =_rtpReceiver.Statistics(fraction_lost,cum_lost,ext_max,jitter, max_jitter,(_rtcpSender.Status() == kRtcpOff));
WebRtc_UWord32 jitter_transmission_time_offset = 0;
WebRtc_Word32 retVal =_rtpReceiver.Statistics(fraction_lost, cum_lost,
ext_max, jitter, max_jitter, &jitter_transmission_time_offset,
(_rtcpSender.Status() == kRtcpOff));
if(retVal == -1)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "StatisticsRTP() no statisitics availble");
@ -1696,17 +1703,21 @@ ModuleRtpRtcpImpl::DataCountersRTP(WebRtc_UWord32 *bytesSent,
}
WebRtc_Word32
ModuleRtpRtcpImpl::ReportBlockStatistics(WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *cum_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter)
ModuleRtpRtcpImpl::ReportBlockStatistics(
WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *cum_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter,
WebRtc_UWord32 *jitter_transmission_time_offset)
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ReportBlockStatistics()");
WebRtc_Word32 missing = 0;
WebRtc_Word32 ret = _rtpReceiver.Statistics(fraction_lost,
cum_lost,ext_max,
cum_lost,
ext_max,
jitter,
NULL,
jitter_transmission_time_offset,
&missing,
true);
@ -1793,6 +1804,52 @@ WebRtc_Word32 ModuleRtpRtcpImpl::SetREMBData(const WebRtc_UWord32 bitrate,
return _rtcpSender.SetREMBData(bitrate, numberOfSSRC, SSRC);
}
/*
* (IJ) Extended jitter report.
*/
bool ModuleRtpRtcpImpl::IJ() const
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "IJ()");
return _rtcpSender.IJ();
}
WebRtc_Word32 ModuleRtpRtcpImpl::SetIJStatus(const bool enable)
{
WEBRTC_TRACE(kTraceModuleCall,
kTraceRtpRtcp,
_id,
"SetIJStatus(%s)", enable ? "true" : "false");
return _rtcpSender.SetIJStatus(enable);
}
WebRtc_Word32 ModuleRtpRtcpImpl::RegisterSendRtpHeaderExtension(
const RTPExtensionType type,
const WebRtc_UWord8 id)
{
return _rtpSender.RegisterRtpHeaderExtension(type, id);
}
WebRtc_Word32 ModuleRtpRtcpImpl::DeregisterSendRtpHeaderExtension(
const RTPExtensionType type)
{
return _rtpSender.DeregisterRtpHeaderExtension(type);
}
WebRtc_Word32 ModuleRtpRtcpImpl::RegisterReceiveRtpHeaderExtension(
const RTPExtensionType type,
const WebRtc_UWord8 id)
{
return _rtpReceiver.RegisterRtpHeaderExtension(type, id);
}
WebRtc_Word32 ModuleRtpRtcpImpl::DeregisterReceiveRtpHeaderExtension(
const RTPExtensionType type)
{
return _rtpReceiver.DeregisterRtpHeaderExtension(type);
}
/*
* (TMMBR) Temporary Max Media Bit Rate
*/

View File

@ -97,6 +97,14 @@ public:
virtual WebRtc_Word32 DeRegisterReceivePayload(
const WebRtc_Word8 payloadType);
// register RTP header extension
virtual WebRtc_Word32 RegisterReceiveRtpHeaderExtension(
const RTPExtensionType type,
const WebRtc_UWord8 id);
virtual WebRtc_Word32 DeregisterReceiveRtpHeaderExtension(
const RTPExtensionType type);
// get the currently configured SSRC filter
virtual WebRtc_Word32 SSRCFilter(WebRtc_UWord32& allowedSSRC) const;
@ -166,6 +174,14 @@ public:
virtual WebRtc_Word8 SendPayloadType() const;
// register RTP header extension
virtual WebRtc_Word32 RegisterSendRtpHeaderExtension(
const RTPExtensionType type,
const WebRtc_UWord8 id);
virtual WebRtc_Word32 DeregisterSendRtpHeaderExtension(
const RTPExtensionType type);
// get start timestamp
virtual WebRtc_UWord32 StartTimestamp() const;
@ -289,10 +305,12 @@ public:
WebRtc_UWord32 *bytesReceived,
WebRtc_UWord32 *packetsReceived) const;
virtual WebRtc_Word32 ReportBlockStatistics(WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *cum_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter);
virtual WebRtc_Word32 ReportBlockStatistics(
WebRtc_UWord8 *fraction_lost,
WebRtc_UWord32 *cum_lost,
WebRtc_UWord32 *ext_max,
WebRtc_UWord32 *jitter,
WebRtc_UWord32 *jitter_transmission_time_offset);
// Get received RTCP report, sender info
virtual WebRtc_Word32 RemoteRTCPStat( RTCPSenderInfo* senderInfo);
@ -317,6 +335,14 @@ public:
virtual WebRtc_Word32 SetREMBData(const WebRtc_UWord32 bitrate,
const WebRtc_UWord8 numberOfSSRC,
const WebRtc_UWord32* SSRC);
/*
* (IJ) Extended jitter report.
*/
virtual bool IJ() const;
virtual WebRtc_Word32 SetIJStatus(const bool enable);
/*
* (TMMBR) Temporary Max Media Bit Rate
*/

View File

@ -24,6 +24,9 @@
'rtp_format_vp8_unittest.cc',
'rtcp_format_remb_unittest.cc',
'rtp_utility_test.cc',
'rtp_header_extension_test.cc',
'rtp_sender_test.cc',
'rtcp_sender_test.cc',
],
},
],

View File

@ -41,6 +41,9 @@ RTPSender::RTPSender(const WebRtc_Word32 id,
_payloadType(-1),
_payloadTypeMap(),
_rtpHeaderExtensionMap(),
_transmissionTimeOffset(0),
_keepAliveIsActive(false),
_keepAlivePayloadType(-1),
_keepAliveLastSent(0),
@ -176,6 +179,8 @@ RTPSender::Init(const WebRtc_UWord32 remoteSSRC)
_keepAlivePayloadType = -1;
_rtpHeaderExtensionMap.Erase();
bool loop = true;
do
{
@ -264,6 +269,42 @@ RTPSender::NackOverheadRate() const {
return _nackBitrate.BitrateLast();
}
WebRtc_Word32
RTPSender::SetTransmissionTimeOffset(
const WebRtc_Word32 transmissionTimeOffset)
{
if (transmissionTimeOffset > (0x800000 - 1) ||
transmissionTimeOffset < -(0x800000 - 1)) // Word24
{
return -1;
}
CriticalSectionScoped cs(_sendCritsect);
_transmissionTimeOffset = transmissionTimeOffset;
return 0;
}
WebRtc_Word32
RTPSender::RegisterRtpHeaderExtension(const RTPExtensionType type,
const WebRtc_UWord8 id)
{
CriticalSectionScoped cs(_sendCritsect);
return _rtpHeaderExtensionMap.Register(type, id);
}
WebRtc_Word32
RTPSender::DeregisterRtpHeaderExtension(const RTPExtensionType type)
{
CriticalSectionScoped cs(_sendCritsect);
return _rtpHeaderExtensionMap.Deregister(type);
}
WebRtc_UWord16
RTPSender::RtpHeaderExtensionTotalLength() const
{
CriticalSectionScoped cs(_sendCritsect);
return _rtpHeaderExtensionMap.GetTotalLengthInBytes();
}
//can be called multiple times
WebRtc_Word32
RTPSender::RegisterPayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
@ -1114,6 +1155,8 @@ RTPSender::RTPHeaderLength() const
{
rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
}
rtpHeaderLength += RtpHeaderExtensionTotalLength();
return rtpHeaderLength;
}
@ -1209,9 +1252,108 @@ RTPSender::BuildRTPheader(WebRtc_UWord8* dataBuffer,
_sequenceNumber++; // prepare for next packet
}
WebRtc_UWord16 len = BuildRTPHeaderExtension(dataBuffer + rtpHeaderLength);
if (len)
{
dataBuffer[0] |= 0x10; // set eXtension bit
rtpHeaderLength += len;
}
return rtpHeaderLength;
}
WebRtc_UWord16
RTPSender::BuildRTPHeaderExtension(WebRtc_UWord8* dataBuffer) const
{
if (_rtpHeaderExtensionMap.Size() <= 0) {
return 0;
}
/* RTP header extension, 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| defined by profile | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| header extension |
| .... |
*/
const WebRtc_UWord32 kPosLength = 2;
const WebRtc_UWord32 kHeaderLength = RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES;
// Add extension ID (0xBEDE).
ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer,
RTP_ONE_BYTE_HEADER_EXTENSION);
// Add extensions.
WebRtc_UWord16 total_block_length = 0;
RTPExtensionType type = _rtpHeaderExtensionMap.First();
while (type != NONE)
{
WebRtc_UWord8 block_length = 0;
if (type == TRANSMISSION_TIME_OFFSET)
{
block_length = BuildTransmissionTimeOffsetExtension(
dataBuffer + kHeaderLength + total_block_length);
}
total_block_length += block_length;
type = _rtpHeaderExtensionMap.Next(type);
}
if (total_block_length == 0)
{
// No extension added.
return 0;
}
// Set header length (in number of Word32, header excluded).
assert(total_block_length % 4 == 0);
ModuleRTPUtility::AssignUWord16ToBuffer(dataBuffer + kPosLength,
total_block_length / 4);
// Total added length.
return kHeaderLength + total_block_length;
}
WebRtc_UWord8
RTPSender::BuildTransmissionTimeOffsetExtension(WebRtc_UWord8* dataBuffer) const
{
// From RFC 5450: Transmission Time Offsets in RTP Streams.
//
// The transmission time is signaled to the receiver in-band using the
// general mechanism for RTP header extensions [RFC5285]. The payload
// of this extension (the transmitted value) is a 24-bit signed integer.
// When added to the RTP timestamp of the packet, it represents the
// "effective" RTP transmission time of the packet, on the RTP
// timescale.
//
// The form of the transmission offset extension block:
//
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=2 | transmission offset |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Get id defined by user.
WebRtc_UWord8 id;
if (_rtpHeaderExtensionMap.GetId(TRANSMISSION_TIME_OFFSET, &id) != 0) {
// Not registered.
return 0;
}
int pos = 0;
const WebRtc_UWord8 len = 2;
dataBuffer[pos++] = (id << 4) + len;
ModuleRTPUtility::AssignUWord24ToBuffer(dataBuffer + pos,
_transmissionTimeOffset);
pos += 3;
assert(pos == TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES);
return TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES;
}
WebRtc_Word32
RTPSender::RegisterSendTransport(Transport* transport)
{

View File

@ -12,11 +12,13 @@
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
#include "rtp_rtcp_config.h" // misc. defines (e.g. MAX_PACKET_LENGTH)
#include "rtp_rtcp_defines.h"
#include "common_types.h" // Encryption
#include "ssrc_database.h"
#include "list_wrapper.h"
#include "map_wrapper.h"
#include "Bitrate.h"
#include "rtp_header_extension.h"
#include "video_codec_information.h"
#include <cassert>
@ -139,6 +141,24 @@ public:
VideoCodecInformation* codecInfo = NULL,
const RTPVideoTypeHeader* rtpTypeHdr = NULL);
/*
* RTP header extension
*/
WebRtc_Word32 SetTransmissionTimeOffset(
const WebRtc_Word32 transmissionTimeOffset);
WebRtc_Word32 RegisterRtpHeaderExtension(const RTPExtensionType type,
const WebRtc_UWord8 id);
WebRtc_Word32 DeregisterRtpHeaderExtension(const RTPExtensionType type);
WebRtc_UWord16 RtpHeaderExtensionTotalLength() const;
WebRtc_UWord16 BuildRTPHeaderExtension(WebRtc_UWord8* dataBuffer) const;
WebRtc_UWord8 BuildTransmissionTimeOffsetExtension(
WebRtc_UWord8* dataBuffer) const;
/*
* NACK
*/
@ -270,7 +290,7 @@ private:
CriticalSectionWrapper* _sendCritsect;
CriticalSectionWrapper* _transportCritsect;
Transport* _transport;
Transport* _transport;
bool _sendingMedia;
@ -281,6 +301,9 @@ private:
WebRtc_Word8 _payloadType;
MapWrapper _payloadTypeMap;
RtpHeaderExtensionMap _rtpHeaderExtensionMap;
WebRtc_Word32 _transmissionTimeOffset;
bool _keepAliveIsActive;
WebRtc_Word8 _keepAlivePayloadType;
WebRtc_UWord32 _keepAliveLastSent;
@ -305,13 +328,13 @@ private:
WebRtc_UWord32 _payloadBytesSent;
// RTP variables
bool _startTimeStampForced;
bool _startTimeStampForced;
WebRtc_UWord32 _startTimeStamp;
SSRCDatabase& _ssrcDB;
SSRCDatabase& _ssrcDB;
WebRtc_UWord32 _remoteSSRC;
bool _sequenceNumberForced;
bool _sequenceNumberForced;
WebRtc_UWord16 _sequenceNumber;
bool _ssrcForced;
bool _ssrcForced;
WebRtc_UWord32 _ssrc;
WebRtc_UWord32 _timeStamp;
WebRtc_UWord8 _CSRCs;

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2011 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 RTPSender.
*/
#include <gtest/gtest.h>
#include "rtp_header_extension.h"
#include "rtp_rtcp_defines.h"
#include "rtp_sender.h"
#include "rtp_utility.h"
#include "typedefs.h"
namespace webrtc {
class RtpSenderTest : public ::testing::Test {
protected:
RtpSenderTest()
: rtp_sender_(new RTPSender(0, false, ModuleRTPUtility::GetSystemClock())),
kMarkerBit(true),
kType(TRANSMISSION_TIME_OFFSET) {
EXPECT_EQ(0, rtp_sender_->SetSequenceNumber(kSeqNum));
}
~RtpSenderTest() {
delete rtp_sender_;
}
RTPSender* rtp_sender_;
const bool kMarkerBit;
RTPExtensionType kType;
enum {kId = 1};
enum {kTypeLength = TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES};
enum {kPayload = 100};
enum {kTimestamp = 10};
enum {kSeqNum = 33};
enum {kTimeOffset = 22222};
enum {kMaxPacketLength = 1500};
uint8_t packet_[kMaxPacketLength];
void VerifyRTPHeaderCommon(const WebRtcRTPHeader& rtp_header) {
EXPECT_EQ(kMarkerBit, rtp_header.header.markerBit);
EXPECT_EQ(kPayload, rtp_header.header.payloadType);
EXPECT_EQ(kSeqNum, rtp_header.header.sequenceNumber);
EXPECT_EQ(kTimestamp, rtp_header.header.timestamp);
EXPECT_EQ(rtp_sender_->SSRC(), rtp_header.header.ssrc);
EXPECT_EQ(0, rtp_header.header.numCSRCs);
EXPECT_EQ(0, rtp_header.header.paddingLength);
}
};
TEST_F(RtpSenderTest, RegisterRtpHeaderExtension) {
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
EXPECT_EQ(RTP_ONE_BYTE_HEADER_LENGTH_IN_BYTES + kTypeLength,
rtp_sender_->RtpHeaderExtensionTotalLength());
EXPECT_EQ(0, rtp_sender_->DeregisterRtpHeaderExtension(kType));
EXPECT_EQ(0, rtp_sender_->RtpHeaderExtensionTotalLength());
}
TEST_F(RtpSenderTest, BuildRTPPacket) {
WebRtc_Word32 length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp);
EXPECT_EQ(12, length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtpParser(packet_, length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
const bool valid_rtp_header = rtpParser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtpParser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.header.headerLength);
EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset);
}
TEST_F(RtpSenderTest, BuildRTPPacketWithExtension) {
EXPECT_EQ(0, rtp_sender_->SetTransmissionTimeOffset(kTimeOffset));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(kType, kId));
WebRtc_Word32 length = rtp_sender_->BuildRTPheader(packet_,
kPayload,
kMarkerBit,
kTimestamp);
EXPECT_EQ(12 + rtp_sender_->RtpHeaderExtensionTotalLength(), length);
// Verify
webrtc::ModuleRTPUtility::RTPHeaderParser rtpParser(packet_, length);
webrtc::WebRtcRTPHeader rtp_header;
RtpHeaderExtensionMap map;
map.Register(kType, kId);
const bool valid_rtp_header = rtpParser.Parse(rtp_header, &map);
ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtpParser.RTCP());
VerifyRTPHeaderCommon(rtp_header);
EXPECT_EQ(length, rtp_header.header.headerLength);
EXPECT_EQ(kTimeOffset, rtp_header.extension.transmissionTimeOffset);
// Parse without map extension
webrtc::WebRtcRTPHeader rtp_header2;
const bool valid_rtp_header2 = rtpParser.Parse(rtp_header2, NULL);
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
EXPECT_EQ(length, rtp_header2.header.headerLength);
EXPECT_EQ(0, rtp_header2.extension.transmissionTimeOffset);
}
} // namespace webrtc

View File

@ -507,10 +507,10 @@ ModuleRTPUtility::RTPHeaderParser::RTCP() const
RTCP = true;
break;
case 193:
case 195:
// not supported
// pass through and check for a potential RTP packet
break;
case 195:
case 200:
case 201:
case 202:
@ -526,7 +526,8 @@ ModuleRTPUtility::RTPHeaderParser::RTCP() const
}
bool
ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const
ModuleRTPUtility::RTPHeaderParser::Parse(
WebRtcRTPHeader& parsedPacket, RtpHeaderExtensionMap* ptrExtensionMap) const
{
const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
@ -588,8 +589,22 @@ ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const
parsedPacket.type.Audio.numEnergy = parsedPacket.header.numCSRCs;
parsedPacket.header.headerLength = 12 + CSRCocts;
// If in effect, MAY be omitted for those packets for which the offset
// is zero.
parsedPacket.extension.transmissionTimeOffset = 0;
if (X)
{
/* RTP header extension, 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| defined by profile | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| header extension |
| .... |
*/
const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
if (remain < 4)
{
@ -609,27 +624,13 @@ ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const
{
return false;
}
if(definedByProfile == RTP_AUDIO_LEVEL_UNIQUE_ID && XLen == 4)
if (definedByProfile == RTP_ONE_BYTE_HEADER_EXTENSION)
{
// --- Only used for debugging ---
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xBE | 0xDE | length=1 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ID | len=0 |V| level | 0x00 | 0x00 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
// Parse out the fields but only use it for debugging for now.
//const WebRtc_UWord8 ID = (*ptr & 0xf0) >> 4;
//const WebRtc_UWord8 len = (*ptr & 0x0f);
ptr++;
//const WebRtc_UWord8 V = (*ptr & 0x80) >> 7;
//const WebRtc_UWord8 level = (*ptr & 0x7f);
// DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u, level=%u", ID, len, V, level);
const WebRtc_UWord8* ptrRTPDataExtensionEnd = ptr + XLen;
ParseOneByteExtensionHeader(parsedPacket,
ptrExtensionMap,
ptrRTPDataExtensionEnd,
ptr);
}
parsedPacket.header.headerLength += XLen;
}
@ -637,6 +638,107 @@ ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const
return true;
}
void ModuleRTPUtility::RTPHeaderParser::ParseOneByteExtensionHeader(
WebRtcRTPHeader& parsedPacket,
const RtpHeaderExtensionMap* ptrExtensionMap,
const WebRtc_UWord8* ptrRTPDataExtensionEnd,
const WebRtc_UWord8* ptr) const
{
if (!ptrExtensionMap) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1, "No extension map.");
return;
}
while (ptrRTPDataExtensionEnd - ptr > 0)
{
// 0
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// | ID | len |
// +-+-+-+-+-+-+-+-+
const WebRtc_UWord8 id = (*ptr & 0xf0) >> 4;
const WebRtc_UWord8 len = (*ptr & 0x0f);
ptr++;
if (id == 15) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Ext id: 15 encountered, parsing terminated.");
return;
}
RTPExtensionType type;
if (ptrExtensionMap->GetType(id, &type) != 0) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Failed to find extension id: %d", id);
return;
}
switch (type)
{
case TRANSMISSION_TIME_OFFSET:
{
if (len != 2)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Incorrect transmission time offset len: %d", len);
return;
}
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=2 | transmission offset |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
WebRtc_Word32 transmissionTimeOffset = *ptr++ << 16;
transmissionTimeOffset += *ptr++ << 8;
transmissionTimeOffset += *ptr++;
parsedPacket.extension.transmissionTimeOffset = transmissionTimeOffset;
break;
}
//case RTP_AUDIO_LEVEL_ID;
//{
// --- Only used for debugging ---
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=0 |V| level | 0x00 | 0x00 |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Parse out the fields but only use it for debugging for now.
//const WebRtc_UWord8 V = (*ptr & 0x80) >> 7;
//const WebRtc_UWord8 level = (*ptr & 0x7f);
//DEBUG_PRINT("RTP_AUDIO_LEVEL_UNIQUE_ID: ID=%u, len=%u, V=%u, level=%u",
// ID, len, V, level);
//}
default:
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
"Extension type not implemented.");
return;
}
}
WebRtc_UWord8 num_bytes = ParsePaddingBytes(ptrRTPDataExtensionEnd, ptr);
ptr += num_bytes;
}
}
WebRtc_UWord8 ModuleRTPUtility::RTPHeaderParser::ParsePaddingBytes(
const WebRtc_UWord8* ptrRTPDataExtensionEnd,
const WebRtc_UWord8* ptr) const {
WebRtc_UWord8 num_zero_bytes = 0;
while (ptrRTPDataExtensionEnd - ptr > 0) {
if (*ptr != 0) {
return num_zero_bytes;
}
ptr++;
num_zero_bytes++;
}
return num_zero_bytes;
}
// RTP payload parser
ModuleRTPUtility::RTPPayloadParser::RTPPayloadParser(
const RtpVideoCodecTypes videoType,

View File

@ -14,6 +14,7 @@
#include <cstddef> // size_t, ptrdiff_t
#include "typedefs.h"
#include "rtp_header_extension.h"
#include "rtp_rtcp_config.h"
#include "rtp_rtcp_defines.h"
@ -118,10 +119,21 @@ namespace ModuleRTPUtility
const WebRtc_UWord32 rtpDataLength);
~RTPHeaderParser();
bool RTCP( ) const;
bool Parse( WebRtcRTPHeader& parsedPacket) const;
bool RTCP() const;
bool Parse(WebRtcRTPHeader& parsedPacket,
RtpHeaderExtensionMap* ptrExtensionMap = NULL) const;
private:
void ParseOneByteExtensionHeader(
WebRtcRTPHeader& parsedPacket,
const RtpHeaderExtensionMap* ptrExtensionMap,
const WebRtc_UWord8* ptrRTPDataExtensionEnd,
const WebRtc_UWord8* ptr) const;
WebRtc_UWord8 ParsePaddingBytes(
const WebRtc_UWord8* ptrRTPDataExtensionEnd,
const WebRtc_UWord8* ptr) const;
const WebRtc_UWord8* const _ptrRTPDataBegin;
const WebRtc_UWord8* const _ptrRTPDataEnd;
};