Review URL: http://webrtc-codereview.appspot.com/295010
git-svn-id: http://webrtc.googlecode.com/svn/trunk@1219 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
9775a30859
commit
5249cc8f77
@ -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
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -30,6 +30,7 @@ RTCPPacketInformation::RTCPPacketInformation() :
|
||||
roundTripTime(0),
|
||||
lastReceivedExtendedHighSeqNum(0),
|
||||
jitter(0),
|
||||
interArrivalJitter(0),
|
||||
sliPictureId(0),
|
||||
rpsiPictureId(0),
|
||||
VoIPMetric(NULL)
|
||||
|
@ -57,6 +57,8 @@ public:
|
||||
WebRtc_UWord32 lastReceivedExtendedHighSeqNum;
|
||||
WebRtc_UWord32 jitter;
|
||||
|
||||
WebRtc_UWord32 interArrivalJitter;
|
||||
|
||||
WebRtc_UWord8 sliPictureId;
|
||||
WebRtc_UWord64 rpsiPictureId;
|
||||
WebRtc_UWord32 receiverEstimatedMaxBitrate;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
178
src/modules/rtp_rtcp/source/rtcp_sender_test.cc
Normal file
178
src/modules/rtp_rtcp/source/rtcp_sender_test.cc
Normal 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
|
@ -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()
|
||||
{
|
||||
|
@ -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();
|
||||
|
148
src/modules/rtp_rtcp/source/rtp_header_extension.cc
Normal file
148
src/modules/rtp_rtcp/source/rtp_header_extension.cc
Normal 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
|
69
src/modules/rtp_rtcp/source/rtp_header_extension.h
Normal file
69
src/modules/rtp_rtcp/source/rtp_header_extension.h
Normal 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_
|
108
src/modules/rtp_rtcp/source/rtp_header_extension_test.cc
Normal file
108
src/modules/rtp_rtcp/source/rtp_header_extension_test.cc
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
124
src/modules/rtp_rtcp/source/rtp_sender_test.cc
Normal file
124
src/modules/rtp_rtcp/source/rtp_sender_test.cc
Normal 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
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user