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:
@@ -27,6 +27,11 @@ struct RTPHeader
|
|||||||
WebRtc_UWord16 headerLength;
|
WebRtc_UWord16 headerLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RTPHeaderExtension
|
||||||
|
{
|
||||||
|
WebRtc_Word32 transmissionTimeOffset;
|
||||||
|
};
|
||||||
|
|
||||||
struct RTPAudioHeader
|
struct RTPAudioHeader
|
||||||
{
|
{
|
||||||
WebRtc_UWord8 numEnergy; // number of valid entries in arrOfEnergy
|
WebRtc_UWord8 numEnergy; // number of valid entries in arrOfEnergy
|
||||||
@@ -118,6 +123,7 @@ struct WebRtcRTPHeader
|
|||||||
RTPHeader header;
|
RTPHeader header;
|
||||||
FrameType frameType;
|
FrameType frameType;
|
||||||
RTPTypeHeader type;
|
RTPTypeHeader type;
|
||||||
|
RTPHeaderExtension extension;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RTPFragmentationHeader
|
class RTPFragmentationHeader
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ public:
|
|||||||
WebRtc_Word8* plType) = 0;
|
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
|
* payloadType - payload type of codec
|
||||||
*
|
*
|
||||||
@@ -216,6 +216,18 @@ public:
|
|||||||
virtual WebRtc_Word32 DeRegisterReceivePayload(
|
virtual WebRtc_Word32 DeRegisterReceivePayload(
|
||||||
const WebRtc_Word8 payloadType) = 0;
|
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
|
* Get last received remote timestamp
|
||||||
*/
|
*/
|
||||||
@@ -407,6 +419,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual WebRtc_Word32 DeRegisterSendPayload(const WebRtc_Word8 payloadType) = 0;
|
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
|
* get start timestamp
|
||||||
*/
|
*/
|
||||||
@@ -735,13 +759,21 @@ public:
|
|||||||
/*
|
/*
|
||||||
* (REMB) Receiver Estimated Max Bitrate
|
* (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 SetREMBStatus(const bool enable) = 0;
|
||||||
|
|
||||||
virtual WebRtc_Word32 SetREMBData(const WebRtc_UWord32 bitrate,
|
virtual WebRtc_Word32 SetREMBData(const WebRtc_UWord32 bitrate,
|
||||||
const WebRtc_UWord8 numberOfSSRC,
|
const WebRtc_UWord8 numberOfSSRC,
|
||||||
const WebRtc_UWord32* SSRC) = 0;
|
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
|
* (TMMBR) Temporary Max Media Bit Rate
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ enum RTPAliveType
|
|||||||
kRtpAlive = 2
|
kRtpAlive = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RTPExtensionType
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
TRANSMISSION_TIME_OFFSET
|
||||||
|
};
|
||||||
|
|
||||||
enum RTCPAppSubTypes
|
enum RTCPAppSubTypes
|
||||||
{
|
{
|
||||||
kAppSubtypeBwe = 0x00
|
kAppSubtypeBwe = 0x00
|
||||||
@@ -60,7 +66,8 @@ enum RTCPPacketType
|
|||||||
kRtcpApp = 0x0800,
|
kRtcpApp = 0x0800,
|
||||||
kRtcpSli = 0x4000,
|
kRtcpSli = 0x4000,
|
||||||
kRtcpRpsi = 0x8000,
|
kRtcpRpsi = 0x8000,
|
||||||
kRtcpRemb = 0x10000
|
kRtcpRemb = 0x10000,
|
||||||
|
kRtcpTransmissionTimeOffset = 0x20000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum KeyFrameRequestMethod
|
enum KeyFrameRequestMethod
|
||||||
|
|||||||
@@ -356,6 +356,9 @@ RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation,
|
|||||||
case RTCPUtility::kRtcpPsfbRpsiCode:
|
case RTCPUtility::kRtcpPsfbRpsiCode:
|
||||||
HandleRPSI(*rtcpParser, rtcpPacketInformation);
|
HandleRPSI(*rtcpParser, rtcpPacketInformation);
|
||||||
break;
|
break;
|
||||||
|
case RTCPUtility::kRtcpExtendedIjCode:
|
||||||
|
HandleIJ(*rtcpParser, rtcpPacketInformation);
|
||||||
|
break;
|
||||||
case RTCPUtility::kRtcpPsfbFirCode:
|
case RTCPUtility::kRtcpPsfbFirCode:
|
||||||
HandleFIR(*rtcpParser, rtcpPacketInformation);
|
HandleFIR(*rtcpParser, rtcpPacketInformation);
|
||||||
break;
|
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
|
void
|
||||||
RTCPReceiver::HandleREMBItem(RTCPUtility::RTCPParserV2& rtcpParser,
|
RTCPReceiver::HandleREMBItem(RTCPUtility::RTCPParserV2& rtcpParser,
|
||||||
RTCPPacketInformation& rtcpPacketInformation)
|
RTCPPacketInformation& rtcpPacketInformation)
|
||||||
|
|||||||
@@ -151,6 +151,12 @@ protected:
|
|||||||
void HandleREMBItem(RTCPUtility::RTCPParserV2& rtcpParser,
|
void HandleREMBItem(RTCPUtility::RTCPParserV2& rtcpParser,
|
||||||
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
|
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,
|
void HandleTMMBR(RTCPUtility::RTCPParserV2& rtcpParser,
|
||||||
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
|
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ RTCPPacketInformation::RTCPPacketInformation() :
|
|||||||
roundTripTime(0),
|
roundTripTime(0),
|
||||||
lastReceivedExtendedHighSeqNum(0),
|
lastReceivedExtendedHighSeqNum(0),
|
||||||
jitter(0),
|
jitter(0),
|
||||||
|
interArrivalJitter(0),
|
||||||
sliPictureId(0),
|
sliPictureId(0),
|
||||||
rpsiPictureId(0),
|
rpsiPictureId(0),
|
||||||
VoIPMetric(NULL)
|
VoIPMetric(NULL)
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ public:
|
|||||||
WebRtc_UWord32 lastReceivedExtendedHighSeqNum;
|
WebRtc_UWord32 lastReceivedExtendedHighSeqNum;
|
||||||
WebRtc_UWord32 jitter;
|
WebRtc_UWord32 jitter;
|
||||||
|
|
||||||
|
WebRtc_UWord32 interArrivalJitter;
|
||||||
|
|
||||||
WebRtc_UWord8 sliPictureId;
|
WebRtc_UWord8 sliPictureId;
|
||||||
WebRtc_UWord64 rpsiPictureId;
|
WebRtc_UWord64 rpsiPictureId;
|
||||||
WebRtc_UWord32 receiverEstimatedMaxBitrate;
|
WebRtc_UWord32 receiverEstimatedMaxBitrate;
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ RTCPSender::RTCPSender(const WebRtc_Word32 id,
|
|||||||
_REMB(false),
|
_REMB(false),
|
||||||
_sendREMB(false),
|
_sendREMB(false),
|
||||||
_TMMBR(false),
|
_TMMBR(false),
|
||||||
|
_IJ(false),
|
||||||
_nextTimeToSendRTCP(0),
|
_nextTimeToSendRTCP(0),
|
||||||
_SSRC(0),
|
_SSRC(0),
|
||||||
_remoteSSRC(0),
|
_remoteSSRC(0),
|
||||||
@@ -129,6 +130,7 @@ RTCPSender::Init()
|
|||||||
_sending = false;
|
_sending = false;
|
||||||
_sendTMMBN = false;
|
_sendTMMBN = false;
|
||||||
_TMMBR = false;
|
_TMMBR = false;
|
||||||
|
_IJ = false;
|
||||||
_REMB = false;
|
_REMB = false;
|
||||||
_sendREMB = false;
|
_sendREMB = false;
|
||||||
_SSRC = 0;
|
_SSRC = 0;
|
||||||
@@ -282,6 +284,21 @@ RTCPSender::SetTMMBRStatus(const bool enable)
|
|||||||
return 0;
|
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
|
void
|
||||||
RTCPSender::SetSSRC( const WebRtc_UWord32 ssrc)
|
RTCPSender::SetSSRC( const WebRtc_UWord32 ssrc)
|
||||||
{
|
{
|
||||||
@@ -828,6 +845,57 @@ RTCPSender::BuildRR(WebRtc_UWord8* rtcpbuffer,
|
|||||||
return 0;
|
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
|
WebRtc_Word32
|
||||||
RTCPSender::BuildPLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
|
RTCPSender::BuildPLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
|
||||||
{
|
{
|
||||||
@@ -1567,7 +1635,6 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
|
|||||||
WebRtc_UWord32 pos = 0;
|
WebRtc_UWord32 pos = 0;
|
||||||
WebRtc_UWord8 rtcpbuffer[IP_PACKET_SIZE];
|
WebRtc_UWord8 rtcpbuffer[IP_PACKET_SIZE];
|
||||||
|
|
||||||
|
|
||||||
do // only to be able to use break :) (and the critsect must be inside its own scope)
|
do // only to be able to use break :) (and the critsect must be inside its own scope)
|
||||||
{
|
{
|
||||||
// collect the received information
|
// collect the received information
|
||||||
@@ -1576,6 +1643,7 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
|
|||||||
WebRtc_UWord32 NTPsec = 0;
|
WebRtc_UWord32 NTPsec = 0;
|
||||||
WebRtc_UWord32 NTPfrac = 0;
|
WebRtc_UWord32 NTPfrac = 0;
|
||||||
bool rtcpCompound = false;
|
bool rtcpCompound = false;
|
||||||
|
WebRtc_UWord32 jitterTransmissionOffset = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
CriticalSectionScoped lock(_criticalSectionRTCPSender);
|
CriticalSectionScoped lock(_criticalSectionRTCPSender);
|
||||||
@@ -1597,7 +1665,8 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
|
|||||||
if(_rtpRtcp.ReportBlockStatistics(&received.fractionLost,
|
if(_rtpRtcp.ReportBlockStatistics(&received.fractionLost,
|
||||||
&received.cumulativeLost,
|
&received.cumulativeLost,
|
||||||
&received.extendedHighSeqNum,
|
&received.extendedHighSeqNum,
|
||||||
&received.jitter) == 0)
|
&received.jitter,
|
||||||
|
&jitterTransmissionOffset) == 0)
|
||||||
{
|
{
|
||||||
hasReceived = true;
|
hasReceived = true;
|
||||||
|
|
||||||
@@ -1673,6 +1742,10 @@ RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
|
|||||||
{
|
{
|
||||||
rtcpPacketTypeFlags |= kRtcpRr;
|
rtcpPacketTypeFlags |= kRtcpRr;
|
||||||
}
|
}
|
||||||
|
if (_IJ && hasReceived)
|
||||||
|
{
|
||||||
|
rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
|
||||||
|
}
|
||||||
} else if(_method == kRtcpNonCompound)
|
} else if(_method == kRtcpNonCompound)
|
||||||
{
|
{
|
||||||
if(rtcpPacketTypeFlags & kRtcpReport)
|
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)
|
if(rtcpPacketTypeFlags & kRtcpPli)
|
||||||
{
|
{
|
||||||
buildVal = BuildPLI(rtcpbuffer, pos);
|
buildVal = BuildPLI(rtcpbuffer, pos);
|
||||||
|
|||||||
@@ -97,6 +97,13 @@ public:
|
|||||||
WebRtc_Word32 RequestTMMBR(const WebRtc_UWord32 estimatedBW,
|
WebRtc_Word32 RequestTMMBR(const WebRtc_UWord32 estimatedBW,
|
||||||
const WebRtc_UWord32 packetOH);
|
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 WebRtc_UWord32 NTPfrac,
|
||||||
const RTCPReportBlock* received = NULL);
|
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 BuildSDEC(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos);
|
||||||
WebRtc_Word32 BuildPLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos);
|
WebRtc_Word32 BuildPLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos);
|
||||||
WebRtc_Word32 BuildREMB(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos);
|
WebRtc_Word32 BuildREMB(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos);
|
||||||
@@ -188,6 +200,7 @@ private:
|
|||||||
bool _REMB;
|
bool _REMB;
|
||||||
bool _sendREMB;
|
bool _sendREMB;
|
||||||
bool _TMMBR;
|
bool _TMMBR;
|
||||||
|
bool _IJ;
|
||||||
|
|
||||||
WebRtc_UWord32 _nextTimeToSendRTCP;
|
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:
|
case State_BYEItem:
|
||||||
IterateBYEItem();
|
IterateBYEItem();
|
||||||
break;
|
break;
|
||||||
|
case State_ExtendedJitterItem:
|
||||||
|
IterateExtendedJitterItem();
|
||||||
|
break;
|
||||||
case State_RTPFB_NACKItem:
|
case State_RTPFB_NACKItem:
|
||||||
IterateNACKItem();
|
IterateNACKItem();
|
||||||
break;
|
break;
|
||||||
@@ -196,6 +199,13 @@ RTCPUtility::RTCPParserV2::IterateTopLevel()
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case PT_IJ:
|
||||||
|
{
|
||||||
|
// number of Report blocks
|
||||||
|
_numberOfBlocks = header.IC;
|
||||||
|
ParseIJ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
case PT_RTPFB: // Fall through!
|
case PT_RTPFB: // Fall through!
|
||||||
case PT_PSFB:
|
case PT_PSFB:
|
||||||
{
|
{
|
||||||
@@ -266,6 +276,16 @@ RTCPUtility::RTCPParserV2::IterateBYEItem()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RTCPUtility::RTCPParserV2::IterateExtendedJitterItem()
|
||||||
|
{
|
||||||
|
const bool success = ParseIJItem();
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
Iterate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RTCPUtility::RTCPParserV2::IterateNACKItem()
|
RTCPUtility::RTCPParserV2::IterateNACKItem()
|
||||||
{
|
{
|
||||||
@@ -587,6 +607,62 @@ RTCPUtility::RTCPParserV2::ParseReportBlockItem()
|
|||||||
return true;
|
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
|
bool
|
||||||
RTCPUtility::RTCPParserV2::ParseSDES()
|
RTCPUtility::RTCPParserV2::ParseSDES()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,6 +67,12 @@ namespace RTCPUtility {
|
|||||||
WebRtc_UWord8 CNameLength;
|
WebRtc_UWord8 CNameLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RTCPPacketExtendedJitterReportItem
|
||||||
|
{
|
||||||
|
// RFC 5450
|
||||||
|
WebRtc_UWord32 Jitter;
|
||||||
|
};
|
||||||
|
|
||||||
struct RTCPPacketBYE
|
struct RTCPPacketBYE
|
||||||
{
|
{
|
||||||
WebRtc_UWord32 SenderSSRC;
|
WebRtc_UWord32 SenderSSRC;
|
||||||
@@ -203,6 +209,8 @@ namespace RTCPUtility {
|
|||||||
RTCPPacketSDESCName CName;
|
RTCPPacketSDESCName CName;
|
||||||
RTCPPacketBYE BYE;
|
RTCPPacketBYE BYE;
|
||||||
|
|
||||||
|
RTCPPacketExtendedJitterReportItem ExtendedJitterReportItem;
|
||||||
|
|
||||||
RTCPPacketRTPFBNACK NACK;
|
RTCPPacketRTPFBNACK NACK;
|
||||||
RTCPPacketRTPFBNACKItem NACKItem;
|
RTCPPacketRTPFBNACKItem NACKItem;
|
||||||
|
|
||||||
@@ -238,6 +246,10 @@ namespace RTCPUtility {
|
|||||||
kRtcpSdesChunkCode,
|
kRtcpSdesChunkCode,
|
||||||
kRtcpByeCode,
|
kRtcpByeCode,
|
||||||
|
|
||||||
|
// RFC5450
|
||||||
|
kRtcpExtendedIjCode,
|
||||||
|
kRtcpExtendedIjItemCode,
|
||||||
|
|
||||||
// RFC4585
|
// RFC4585
|
||||||
kRtcpRtpfbNackCode,
|
kRtcpRtpfbNackCode,
|
||||||
kRtcpRtpfbNackItemCode,
|
kRtcpRtpfbNackItemCode,
|
||||||
@@ -290,6 +302,7 @@ namespace RTCPUtility {
|
|||||||
|
|
||||||
enum RTCPPT
|
enum RTCPPT
|
||||||
{
|
{
|
||||||
|
PT_IJ = 195,
|
||||||
PT_SR = 200,
|
PT_SR = 200,
|
||||||
PT_RR = 201,
|
PT_RR = 201,
|
||||||
PT_SDES = 202,
|
PT_SDES = 202,
|
||||||
@@ -329,6 +342,7 @@ namespace RTCPUtility {
|
|||||||
State_ReportBlockItem, // SR/RR report block
|
State_ReportBlockItem, // SR/RR report block
|
||||||
State_SDESChunk, // SDES chunk
|
State_SDESChunk, // SDES chunk
|
||||||
State_BYEItem, // BYE item
|
State_BYEItem, // BYE item
|
||||||
|
State_ExtendedJitterItem, // Extended jitter report item
|
||||||
State_RTPFB_NACKItem, // NACK FCI item
|
State_RTPFB_NACKItem, // NACK FCI item
|
||||||
State_RTPFB_TMMBRItem, // TMMBR FCI item
|
State_RTPFB_TMMBRItem, // TMMBR FCI item
|
||||||
State_RTPFB_TMMBNItem, // TMMBN FCI item
|
State_RTPFB_TMMBNItem, // TMMBN FCI item
|
||||||
@@ -346,6 +360,7 @@ namespace RTCPUtility {
|
|||||||
void IterateReportBlockItem();
|
void IterateReportBlockItem();
|
||||||
void IterateSDESChunk();
|
void IterateSDESChunk();
|
||||||
void IterateBYEItem();
|
void IterateBYEItem();
|
||||||
|
void IterateExtendedJitterItem();
|
||||||
void IterateNACKItem();
|
void IterateNACKItem();
|
||||||
void IterateTMMBRItem();
|
void IterateTMMBRItem();
|
||||||
void IterateTMMBNItem();
|
void IterateTMMBNItem();
|
||||||
@@ -370,6 +385,9 @@ namespace RTCPUtility {
|
|||||||
bool ParseBYE();
|
bool ParseBYE();
|
||||||
bool ParseBYEItem();
|
bool ParseBYEItem();
|
||||||
|
|
||||||
|
bool ParseIJ();
|
||||||
|
bool ParseIJItem();
|
||||||
|
|
||||||
bool ParseXR();
|
bool ParseXR();
|
||||||
bool ParseXRItem();
|
bool ParseXRItem();
|
||||||
bool ParseXRVOIPMetricItem();
|
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),
|
_redPayloadType(-1),
|
||||||
_payloadTypeMap(),
|
_payloadTypeMap(),
|
||||||
|
_rtpHeaderExtensionMap(),
|
||||||
_SSRC(0),
|
_SSRC(0),
|
||||||
_numCSRCs(0),
|
_numCSRCs(0),
|
||||||
_currentRemoteCSRC(),
|
_currentRemoteCSRC(),
|
||||||
@@ -59,9 +60,11 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id,
|
|||||||
_jitterQ4(0),
|
_jitterQ4(0),
|
||||||
_jitterMaxQ4(0),
|
_jitterMaxQ4(0),
|
||||||
_cumulativeLoss(0),
|
_cumulativeLoss(0),
|
||||||
|
_jitterQ4TransmissionTimeOffset(0),
|
||||||
_localTimeLastReceivedTimestamp(0),
|
_localTimeLastReceivedTimestamp(0),
|
||||||
_lastReceivedTimestamp(0),
|
_lastReceivedTimestamp(0),
|
||||||
_lastReceivedSequenceNumber(0),
|
_lastReceivedSequenceNumber(0),
|
||||||
|
_lastReceivedTransmissionTimeOffset(0),
|
||||||
|
|
||||||
_receivedSeqFirst(0),
|
_receivedSeqFirst(0),
|
||||||
_receivedSeqMax(0),
|
_receivedSeqMax(0),
|
||||||
@@ -79,6 +82,7 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id,
|
|||||||
_lastReportCumulativeLost(0),
|
_lastReportCumulativeLost(0),
|
||||||
_lastReportExtendedHighSeqNum(0),
|
_lastReportExtendedHighSeqNum(0),
|
||||||
_lastReportJitter(0),
|
_lastReportJitter(0),
|
||||||
|
_lastReportJitterTransmissionTimeOffset(0),
|
||||||
|
|
||||||
_nackMethod(kNackOff)
|
_nackMethod(kNackOff)
|
||||||
{
|
{
|
||||||
@@ -150,12 +154,14 @@ RTPReceiver::Init()
|
|||||||
_jitterQ4 = 0;
|
_jitterQ4 = 0;
|
||||||
_jitterMaxQ4 = 0;
|
_jitterMaxQ4 = 0;
|
||||||
_cumulativeLoss = 0;
|
_cumulativeLoss = 0;
|
||||||
|
_jitterQ4TransmissionTimeOffset = 0;
|
||||||
_useSSRCFilter = false;
|
_useSSRCFilter = false;
|
||||||
_SSRCFilter = 0;
|
_SSRCFilter = 0;
|
||||||
|
|
||||||
_localTimeLastReceivedTimestamp = 0;
|
_localTimeLastReceivedTimestamp = 0;
|
||||||
_lastReceivedTimestamp = 0;
|
_lastReceivedTimestamp = 0;
|
||||||
_lastReceivedSequenceNumber = 0;
|
_lastReceivedSequenceNumber = 0;
|
||||||
|
_lastReceivedTransmissionTimeOffset = 0;
|
||||||
|
|
||||||
_receivedSeqFirst = 0;
|
_receivedSeqFirst = 0;
|
||||||
_receivedSeqMax = 0;
|
_receivedSeqMax = 0;
|
||||||
@@ -173,6 +179,9 @@ RTPReceiver::Init()
|
|||||||
_lastReportCumulativeLost = 0;
|
_lastReportCumulativeLost = 0;
|
||||||
_lastReportExtendedHighSeqNum = 0;
|
_lastReportExtendedHighSeqNum = 0;
|
||||||
_lastReportJitter = 0;
|
_lastReportJitter = 0;
|
||||||
|
_lastReportJitterTransmissionTimeOffset = 0;
|
||||||
|
|
||||||
|
_rtpHeaderExtensionMap.Erase();
|
||||||
|
|
||||||
// clear db
|
// clear db
|
||||||
bool loop = true;
|
bool loop = true;
|
||||||
@@ -683,6 +692,27 @@ RTPReceiver::RemotePayload(WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
|||||||
return -1;
|
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
|
NACKMethod
|
||||||
RTPReceiver::NACK() const
|
RTPReceiver::NACK() const
|
||||||
{
|
{
|
||||||
@@ -852,6 +882,8 @@ RTPReceiver::IncomingRTPPacket(WebRtcRTPHeader* rtpHeader,
|
|||||||
_lastReceivedTimestamp = rtpHeader->header.timestamp;
|
_lastReceivedTimestamp = rtpHeader->header.timestamp;
|
||||||
}
|
}
|
||||||
_lastReceivedSequenceNumber = rtpHeader->header.sequenceNumber;
|
_lastReceivedSequenceNumber = rtpHeader->header.sequenceNumber;
|
||||||
|
_lastReceivedTransmissionTimeOffset =
|
||||||
|
rtpHeader->extension.transmissionTimeOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
@@ -931,6 +963,26 @@ RTPReceiver::UpdateStatistics(const WebRtcRTPHeader* rtpHeader,
|
|||||||
WebRtc_Word32 jitterDiffQ4 = (timeDiffSamples << 4) - _jitterQ4;
|
WebRtc_Word32 jitterDiffQ4 = (timeDiffSamples << 4) - _jitterQ4;
|
||||||
_jitterQ4 += ((jitterDiffQ4 + 8) >> 4);
|
_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;
|
_localTimeLastReceivedTimestamp = RTPtime;
|
||||||
} else
|
} else
|
||||||
@@ -1130,6 +1182,7 @@ RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtpHeader)
|
|||||||
|
|
||||||
_lastReceivedTimestamp = 0;
|
_lastReceivedTimestamp = 0;
|
||||||
_lastReceivedSequenceNumber = 0;
|
_lastReceivedSequenceNumber = 0;
|
||||||
|
_lastReceivedTransmissionTimeOffset = 0;
|
||||||
|
|
||||||
if (_SSRC) // do we have a SSRC? then the stream is restarted
|
if (_SSRC) // do we have a SSRC? then the stream is restarted
|
||||||
{
|
{
|
||||||
@@ -1461,9 +1514,11 @@ RTPReceiver::ResetStatistics()
|
|||||||
_lastReportCumulativeLost = 0;
|
_lastReportCumulativeLost = 0;
|
||||||
_lastReportExtendedHighSeqNum = 0;
|
_lastReportExtendedHighSeqNum = 0;
|
||||||
_lastReportJitter = 0;
|
_lastReportJitter = 0;
|
||||||
|
_lastReportJitterTransmissionTimeOffset = 0;
|
||||||
_jitterQ4 = 0;
|
_jitterQ4 = 0;
|
||||||
_jitterMaxQ4 = 0;
|
_jitterMaxQ4 = 0;
|
||||||
_cumulativeLoss = 0;
|
_cumulativeLoss = 0;
|
||||||
|
_jitterQ4TransmissionTimeOffset = 0;
|
||||||
_receivedSeqWraps = 0;
|
_receivedSeqWraps = 0;
|
||||||
_receivedSeqMax = 0;
|
_receivedSeqMax = 0;
|
||||||
_receivedSeqFirst = 0;
|
_receivedSeqFirst = 0;
|
||||||
@@ -1492,6 +1547,7 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
|
|||||||
WebRtc_UWord32 *ext_max,
|
WebRtc_UWord32 *ext_max,
|
||||||
WebRtc_UWord32 *jitter,
|
WebRtc_UWord32 *jitter,
|
||||||
WebRtc_UWord32 *max_jitter,
|
WebRtc_UWord32 *max_jitter,
|
||||||
|
WebRtc_UWord32 *jitter_transmission_time_offset,
|
||||||
bool reset) const
|
bool reset) const
|
||||||
{
|
{
|
||||||
WebRtc_Word32 missing;
|
WebRtc_Word32 missing;
|
||||||
@@ -1500,6 +1556,7 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
|
|||||||
ext_max,
|
ext_max,
|
||||||
jitter,
|
jitter,
|
||||||
max_jitter,
|
max_jitter,
|
||||||
|
jitter_transmission_time_offset,
|
||||||
&missing,
|
&missing,
|
||||||
reset);
|
reset);
|
||||||
}
|
}
|
||||||
@@ -1510,6 +1567,7 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
|
|||||||
WebRtc_UWord32 *ext_max,
|
WebRtc_UWord32 *ext_max,
|
||||||
WebRtc_UWord32 *jitter,
|
WebRtc_UWord32 *jitter,
|
||||||
WebRtc_UWord32 *max_jitter,
|
WebRtc_UWord32 *max_jitter,
|
||||||
|
WebRtc_UWord32 *jitter_transmission_time_offset,
|
||||||
WebRtc_Word32 *missing,
|
WebRtc_Word32 *missing,
|
||||||
bool reset) const
|
bool reset) const
|
||||||
{
|
{
|
||||||
@@ -1555,6 +1613,11 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
|
|||||||
// and needs to be scaled by 1/16
|
// and needs to be scaled by 1/16
|
||||||
*max_jitter = (_jitterMaxQ4 >> 4);
|
*max_jitter = (_jitterMaxQ4 >> 4);
|
||||||
}
|
}
|
||||||
|
if(jitter_transmission_time_offset)
|
||||||
|
{
|
||||||
|
*jitter_transmission_time_offset =
|
||||||
|
_lastReportJitterTransmissionTimeOffset;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1636,6 +1699,13 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
|
|||||||
// and needs to be scaled by 1/16
|
// and needs to be scaled by 1/16
|
||||||
*max_jitter = (_jitterMaxQ4 >> 4);
|
*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)
|
if(reset)
|
||||||
{
|
{
|
||||||
// store this report
|
// store this report
|
||||||
@@ -1643,6 +1713,8 @@ RTPReceiver::Statistics(WebRtc_UWord8 *fraction_lost,
|
|||||||
_lastReportCumulativeLost = _cumulativeLoss; // 24 bits valid
|
_lastReportCumulativeLost = _cumulativeLoss; // 24 bits valid
|
||||||
_lastReportExtendedHighSeqNum = (_receivedSeqWraps<<16) + _receivedSeqMax;
|
_lastReportExtendedHighSeqNum = (_receivedSeqWraps<<16) + _receivedSeqMax;
|
||||||
_lastReportJitter = (_jitterQ4 >> 4);
|
_lastReportJitter = (_jitterQ4 >> 4);
|
||||||
|
_lastReportJitterTransmissionTimeOffset =
|
||||||
|
(_jitterQ4TransmissionTimeOffset >> 4);
|
||||||
|
|
||||||
// only for report blocks in RTCP SR and RR
|
// only for report blocks in RTCP SR and RR
|
||||||
_lastReportInorderPackets = _receivedInorderPacketCount;
|
_lastReportInorderPackets = _receivedInorderPacketCount;
|
||||||
|
|||||||
@@ -14,7 +14,9 @@
|
|||||||
#include "typedefs.h"
|
#include "typedefs.h"
|
||||||
#include "rtp_utility.h"
|
#include "rtp_utility.h"
|
||||||
|
|
||||||
|
#include "rtp_header_extension.h"
|
||||||
#include "rtp_rtcp.h"
|
#include "rtp_rtcp.h"
|
||||||
|
#include "rtp_rtcp_defines.h"
|
||||||
#include "rtp_receiver_audio.h"
|
#include "rtp_receiver_audio.h"
|
||||||
#include "rtp_receiver_video.h"
|
#include "rtp_receiver_video.h"
|
||||||
#include "rtcp_receiver_help.h"
|
#include "rtcp_receiver_help.h"
|
||||||
@@ -111,6 +113,7 @@ public:
|
|||||||
WebRtc_UWord32 *ext_max,
|
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 *max_jitter,
|
||||||
|
WebRtc_UWord32 *jitter_transmission_time_offset,
|
||||||
bool reset = false) const;
|
bool reset = false) const;
|
||||||
|
|
||||||
WebRtc_Word32 Statistics(WebRtc_UWord8 *fraction_lost,
|
WebRtc_Word32 Statistics(WebRtc_UWord8 *fraction_lost,
|
||||||
@@ -118,6 +121,7 @@ public:
|
|||||||
WebRtc_UWord32 *ext_max,
|
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 *max_jitter,
|
||||||
|
WebRtc_UWord32 *jitter_transmission_time_offset,
|
||||||
WebRtc_Word32 *missing,
|
WebRtc_Word32 *missing,
|
||||||
bool reset = false) const;
|
bool reset = false) const;
|
||||||
|
|
||||||
@@ -134,6 +138,13 @@ public:
|
|||||||
|
|
||||||
WebRtc_UWord32 ByteCountReceived() const;
|
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,
|
virtual WebRtc_UWord32 PayloadTypeToPayload(const WebRtc_UWord8 payloadType,
|
||||||
ModuleRTPUtility::Payload*& payload) const;
|
ModuleRTPUtility::Payload*& payload) const;
|
||||||
|
|
||||||
@@ -193,6 +204,7 @@ private:
|
|||||||
|
|
||||||
//
|
//
|
||||||
MapWrapper _payloadTypeMap;
|
MapWrapper _payloadTypeMap;
|
||||||
|
RtpHeaderExtensionMap _rtpHeaderExtensionMap;
|
||||||
|
|
||||||
// SSRCs
|
// SSRCs
|
||||||
WebRtc_UWord32 _SSRC;
|
WebRtc_UWord32 _SSRC;
|
||||||
@@ -208,10 +220,12 @@ private:
|
|||||||
WebRtc_UWord32 _jitterQ4;
|
WebRtc_UWord32 _jitterQ4;
|
||||||
mutable WebRtc_UWord32 _jitterMaxQ4;
|
mutable WebRtc_UWord32 _jitterMaxQ4;
|
||||||
mutable WebRtc_UWord32 _cumulativeLoss;
|
mutable WebRtc_UWord32 _cumulativeLoss;
|
||||||
|
WebRtc_UWord32 _jitterQ4TransmissionTimeOffset;
|
||||||
|
|
||||||
WebRtc_UWord32 _localTimeLastReceivedTimestamp;
|
WebRtc_UWord32 _localTimeLastReceivedTimestamp;
|
||||||
WebRtc_UWord32 _lastReceivedTimestamp;
|
WebRtc_UWord32 _lastReceivedTimestamp;
|
||||||
WebRtc_UWord16 _lastReceivedSequenceNumber;
|
WebRtc_UWord16 _lastReceivedSequenceNumber;
|
||||||
|
WebRtc_Word32 _lastReceivedTransmissionTimeOffset;
|
||||||
WebRtc_UWord16 _receivedSeqFirst;
|
WebRtc_UWord16 _receivedSeqFirst;
|
||||||
WebRtc_UWord16 _receivedSeqMax;
|
WebRtc_UWord16 _receivedSeqMax;
|
||||||
WebRtc_UWord16 _receivedSeqWraps;
|
WebRtc_UWord16 _receivedSeqWraps;
|
||||||
@@ -230,6 +244,7 @@ private:
|
|||||||
mutable WebRtc_UWord32 _lastReportCumulativeLost; // 24 bits valid
|
mutable WebRtc_UWord32 _lastReportCumulativeLost; // 24 bits valid
|
||||||
mutable WebRtc_UWord32 _lastReportExtendedHighSeqNum;
|
mutable WebRtc_UWord32 _lastReportExtendedHighSeqNum;
|
||||||
mutable WebRtc_UWord32 _lastReportJitter;
|
mutable WebRtc_UWord32 _lastReportJitter;
|
||||||
|
mutable WebRtc_UWord32 _lastReportJitterTransmissionTimeOffset;
|
||||||
|
|
||||||
// NACK
|
// NACK
|
||||||
NACKMethod _nackMethod;
|
NACKMethod _nackMethod;
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
'rtcp_sender.h',
|
'rtcp_sender.h',
|
||||||
'rtcp_utility.cc',
|
'rtcp_utility.cc',
|
||||||
'rtcp_utility.h',
|
'rtcp_utility.h',
|
||||||
|
'rtp_header_extension.cc',
|
||||||
|
'rtp_header_extension.h',
|
||||||
'rtp_receiver.cc',
|
'rtp_receiver.cc',
|
||||||
'rtp_receiver.h',
|
'rtp_receiver.h',
|
||||||
'rtp_sender.cc',
|
'rtp_sender.cc',
|
||||||
|
|||||||
@@ -790,7 +790,10 @@ ModuleRtpRtcpImpl::IncomingPacket(const WebRtc_UWord8* incomingPacket,
|
|||||||
WebRtcRTPHeader rtpHeader;
|
WebRtcRTPHeader rtpHeader;
|
||||||
memset(&rtpHeader, 0, sizeof(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)
|
if(!validRTPHeader)
|
||||||
{
|
{
|
||||||
WEBRTC_TRACE(kTraceDebug,
|
WEBRTC_TRACE(kTraceDebug,
|
||||||
@@ -1668,7 +1671,11 @@ ModuleRtpRtcpImpl::StatisticsRTP(WebRtc_UWord8 *fraction_lost,
|
|||||||
{
|
{
|
||||||
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "StatisticsRTP()");
|
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)
|
if(retVal == -1)
|
||||||
{
|
{
|
||||||
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "StatisticsRTP() no statisitics availble");
|
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "StatisticsRTP() no statisitics availble");
|
||||||
@@ -1696,17 +1703,21 @@ ModuleRtpRtcpImpl::DataCountersRTP(WebRtc_UWord32 *bytesSent,
|
|||||||
}
|
}
|
||||||
|
|
||||||
WebRtc_Word32
|
WebRtc_Word32
|
||||||
ModuleRtpRtcpImpl::ReportBlockStatistics(WebRtc_UWord8 *fraction_lost,
|
ModuleRtpRtcpImpl::ReportBlockStatistics(
|
||||||
|
WebRtc_UWord8 *fraction_lost,
|
||||||
WebRtc_UWord32 *cum_lost,
|
WebRtc_UWord32 *cum_lost,
|
||||||
WebRtc_UWord32 *ext_max,
|
WebRtc_UWord32 *ext_max,
|
||||||
WebRtc_UWord32 *jitter)
|
WebRtc_UWord32 *jitter,
|
||||||
|
WebRtc_UWord32 *jitter_transmission_time_offset)
|
||||||
{
|
{
|
||||||
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ReportBlockStatistics()");
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "ReportBlockStatistics()");
|
||||||
WebRtc_Word32 missing = 0;
|
WebRtc_Word32 missing = 0;
|
||||||
WebRtc_Word32 ret = _rtpReceiver.Statistics(fraction_lost,
|
WebRtc_Word32 ret = _rtpReceiver.Statistics(fraction_lost,
|
||||||
cum_lost,ext_max,
|
cum_lost,
|
||||||
|
ext_max,
|
||||||
jitter,
|
jitter,
|
||||||
NULL,
|
NULL,
|
||||||
|
jitter_transmission_time_offset,
|
||||||
&missing,
|
&missing,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
@@ -1793,6 +1804,52 @@ WebRtc_Word32 ModuleRtpRtcpImpl::SetREMBData(const WebRtc_UWord32 bitrate,
|
|||||||
return _rtcpSender.SetREMBData(bitrate, numberOfSSRC, SSRC);
|
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
|
* (TMMBR) Temporary Max Media Bit Rate
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -97,6 +97,14 @@ public:
|
|||||||
virtual WebRtc_Word32 DeRegisterReceivePayload(
|
virtual WebRtc_Word32 DeRegisterReceivePayload(
|
||||||
const WebRtc_Word8 payloadType);
|
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
|
// get the currently configured SSRC filter
|
||||||
virtual WebRtc_Word32 SSRCFilter(WebRtc_UWord32& allowedSSRC) const;
|
virtual WebRtc_Word32 SSRCFilter(WebRtc_UWord32& allowedSSRC) const;
|
||||||
|
|
||||||
@@ -166,6 +174,14 @@ public:
|
|||||||
|
|
||||||
virtual WebRtc_Word8 SendPayloadType() const;
|
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
|
// get start timestamp
|
||||||
virtual WebRtc_UWord32 StartTimestamp() const;
|
virtual WebRtc_UWord32 StartTimestamp() const;
|
||||||
|
|
||||||
@@ -289,10 +305,12 @@ public:
|
|||||||
WebRtc_UWord32 *bytesReceived,
|
WebRtc_UWord32 *bytesReceived,
|
||||||
WebRtc_UWord32 *packetsReceived) const;
|
WebRtc_UWord32 *packetsReceived) const;
|
||||||
|
|
||||||
virtual WebRtc_Word32 ReportBlockStatistics(WebRtc_UWord8 *fraction_lost,
|
virtual WebRtc_Word32 ReportBlockStatistics(
|
||||||
|
WebRtc_UWord8 *fraction_lost,
|
||||||
WebRtc_UWord32 *cum_lost,
|
WebRtc_UWord32 *cum_lost,
|
||||||
WebRtc_UWord32 *ext_max,
|
WebRtc_UWord32 *ext_max,
|
||||||
WebRtc_UWord32 *jitter);
|
WebRtc_UWord32 *jitter,
|
||||||
|
WebRtc_UWord32 *jitter_transmission_time_offset);
|
||||||
|
|
||||||
// Get received RTCP report, sender info
|
// Get received RTCP report, sender info
|
||||||
virtual WebRtc_Word32 RemoteRTCPStat( RTCPSenderInfo* senderInfo);
|
virtual WebRtc_Word32 RemoteRTCPStat( RTCPSenderInfo* senderInfo);
|
||||||
@@ -317,6 +335,14 @@ public:
|
|||||||
virtual WebRtc_Word32 SetREMBData(const WebRtc_UWord32 bitrate,
|
virtual WebRtc_Word32 SetREMBData(const WebRtc_UWord32 bitrate,
|
||||||
const WebRtc_UWord8 numberOfSSRC,
|
const WebRtc_UWord8 numberOfSSRC,
|
||||||
const WebRtc_UWord32* SSRC);
|
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
|
* (TMMBR) Temporary Max Media Bit Rate
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
'rtp_format_vp8_unittest.cc',
|
'rtp_format_vp8_unittest.cc',
|
||||||
'rtcp_format_remb_unittest.cc',
|
'rtcp_format_remb_unittest.cc',
|
||||||
'rtp_utility_test.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),
|
_payloadType(-1),
|
||||||
_payloadTypeMap(),
|
_payloadTypeMap(),
|
||||||
|
|
||||||
|
_rtpHeaderExtensionMap(),
|
||||||
|
_transmissionTimeOffset(0),
|
||||||
|
|
||||||
_keepAliveIsActive(false),
|
_keepAliveIsActive(false),
|
||||||
_keepAlivePayloadType(-1),
|
_keepAlivePayloadType(-1),
|
||||||
_keepAliveLastSent(0),
|
_keepAliveLastSent(0),
|
||||||
@@ -176,6 +179,8 @@ RTPSender::Init(const WebRtc_UWord32 remoteSSRC)
|
|||||||
|
|
||||||
_keepAlivePayloadType = -1;
|
_keepAlivePayloadType = -1;
|
||||||
|
|
||||||
|
_rtpHeaderExtensionMap.Erase();
|
||||||
|
|
||||||
bool loop = true;
|
bool loop = true;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -264,6 +269,42 @@ RTPSender::NackOverheadRate() const {
|
|||||||
return _nackBitrate.BitrateLast();
|
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
|
//can be called multiple times
|
||||||
WebRtc_Word32
|
WebRtc_Word32
|
||||||
RTPSender::RegisterPayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
RTPSender::RegisterPayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
||||||
@@ -1114,6 +1155,8 @@ RTPSender::RTPHeaderLength() const
|
|||||||
{
|
{
|
||||||
rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
|
rtpHeaderLength += sizeof(WebRtc_UWord32)*_CSRCs;
|
||||||
}
|
}
|
||||||
|
rtpHeaderLength += RtpHeaderExtensionTotalLength();
|
||||||
|
|
||||||
return rtpHeaderLength;
|
return rtpHeaderLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1209,9 +1252,108 @@ RTPSender::BuildRTPheader(WebRtc_UWord8* dataBuffer,
|
|||||||
_sequenceNumber++; // prepare for next packet
|
_sequenceNumber++; // prepare for next packet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebRtc_UWord16 len = BuildRTPHeaderExtension(dataBuffer + rtpHeaderLength);
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
dataBuffer[0] |= 0x10; // set eXtension bit
|
||||||
|
rtpHeaderLength += len;
|
||||||
|
}
|
||||||
|
|
||||||
return rtpHeaderLength;
|
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
|
WebRtc_Word32
|
||||||
RTPSender::RegisterSendTransport(Transport* transport)
|
RTPSender::RegisterSendTransport(Transport* transport)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,11 +12,13 @@
|
|||||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
|
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
|
||||||
|
|
||||||
#include "rtp_rtcp_config.h" // misc. defines (e.g. MAX_PACKET_LENGTH)
|
#include "rtp_rtcp_config.h" // misc. defines (e.g. MAX_PACKET_LENGTH)
|
||||||
|
#include "rtp_rtcp_defines.h"
|
||||||
#include "common_types.h" // Encryption
|
#include "common_types.h" // Encryption
|
||||||
#include "ssrc_database.h"
|
#include "ssrc_database.h"
|
||||||
#include "list_wrapper.h"
|
#include "list_wrapper.h"
|
||||||
#include "map_wrapper.h"
|
#include "map_wrapper.h"
|
||||||
#include "Bitrate.h"
|
#include "Bitrate.h"
|
||||||
|
#include "rtp_header_extension.h"
|
||||||
#include "video_codec_information.h"
|
#include "video_codec_information.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -139,6 +141,24 @@ public:
|
|||||||
VideoCodecInformation* codecInfo = NULL,
|
VideoCodecInformation* codecInfo = NULL,
|
||||||
const RTPVideoTypeHeader* rtpTypeHdr = 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
|
* NACK
|
||||||
*/
|
*/
|
||||||
@@ -281,6 +301,9 @@ private:
|
|||||||
WebRtc_Word8 _payloadType;
|
WebRtc_Word8 _payloadType;
|
||||||
MapWrapper _payloadTypeMap;
|
MapWrapper _payloadTypeMap;
|
||||||
|
|
||||||
|
RtpHeaderExtensionMap _rtpHeaderExtensionMap;
|
||||||
|
WebRtc_Word32 _transmissionTimeOffset;
|
||||||
|
|
||||||
bool _keepAliveIsActive;
|
bool _keepAliveIsActive;
|
||||||
WebRtc_Word8 _keepAlivePayloadType;
|
WebRtc_Word8 _keepAlivePayloadType;
|
||||||
WebRtc_UWord32 _keepAliveLastSent;
|
WebRtc_UWord32 _keepAliveLastSent;
|
||||||
|
|||||||
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;
|
RTCP = true;
|
||||||
break;
|
break;
|
||||||
case 193:
|
case 193:
|
||||||
case 195:
|
|
||||||
// not supported
|
// not supported
|
||||||
// pass through and check for a potential RTP packet
|
// pass through and check for a potential RTP packet
|
||||||
break;
|
break;
|
||||||
|
case 195:
|
||||||
case 200:
|
case 200:
|
||||||
case 201:
|
case 201:
|
||||||
case 202:
|
case 202:
|
||||||
@@ -526,7 +526,8 @@ ModuleRTPUtility::RTPHeaderParser::RTCP() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const
|
ModuleRTPUtility::RTPHeaderParser::Parse(
|
||||||
|
WebRtcRTPHeader& parsedPacket, RtpHeaderExtensionMap* ptrExtensionMap) const
|
||||||
{
|
{
|
||||||
const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
|
const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
|
||||||
|
|
||||||
@@ -588,8 +589,22 @@ ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const
|
|||||||
parsedPacket.type.Audio.numEnergy = parsedPacket.header.numCSRCs;
|
parsedPacket.type.Audio.numEnergy = parsedPacket.header.numCSRCs;
|
||||||
|
|
||||||
parsedPacket.header.headerLength = 12 + CSRCocts;
|
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)
|
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;
|
const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
|
||||||
if (remain < 4)
|
if (remain < 4)
|
||||||
{
|
{
|
||||||
@@ -609,27 +624,13 @@ ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(definedByProfile == RTP_AUDIO_LEVEL_UNIQUE_ID && XLen == 4)
|
if (definedByProfile == RTP_ONE_BYTE_HEADER_EXTENSION)
|
||||||
{
|
{
|
||||||
// --- Only used for debugging ---
|
const WebRtc_UWord8* ptrRTPDataExtensionEnd = ptr + XLen;
|
||||||
|
ParseOneByteExtensionHeader(parsedPacket,
|
||||||
/*
|
ptrExtensionMap,
|
||||||
0 1 2 3
|
ptrRTPDataExtensionEnd,
|
||||||
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
|
ptr);
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
||||||
| 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);
|
|
||||||
}
|
}
|
||||||
parsedPacket.header.headerLength += XLen;
|
parsedPacket.header.headerLength += XLen;
|
||||||
}
|
}
|
||||||
@@ -637,6 +638,107 @@ ModuleRTPUtility::RTPHeaderParser::Parse(WebRtcRTPHeader& parsedPacket) const
|
|||||||
return true;
|
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
|
// RTP payload parser
|
||||||
ModuleRTPUtility::RTPPayloadParser::RTPPayloadParser(
|
ModuleRTPUtility::RTPPayloadParser::RTPPayloadParser(
|
||||||
const RtpVideoCodecTypes videoType,
|
const RtpVideoCodecTypes videoType,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <cstddef> // size_t, ptrdiff_t
|
#include <cstddef> // size_t, ptrdiff_t
|
||||||
|
|
||||||
#include "typedefs.h"
|
#include "typedefs.h"
|
||||||
|
#include "rtp_header_extension.h"
|
||||||
#include "rtp_rtcp_config.h"
|
#include "rtp_rtcp_config.h"
|
||||||
#include "rtp_rtcp_defines.h"
|
#include "rtp_rtcp_defines.h"
|
||||||
|
|
||||||
@@ -119,9 +120,20 @@ namespace ModuleRTPUtility
|
|||||||
~RTPHeaderParser();
|
~RTPHeaderParser();
|
||||||
|
|
||||||
bool RTCP() const;
|
bool RTCP() const;
|
||||||
bool Parse( WebRtcRTPHeader& parsedPacket) const;
|
bool Parse(WebRtcRTPHeader& parsedPacket,
|
||||||
|
RtpHeaderExtensionMap* ptrExtensionMap = NULL) const;
|
||||||
|
|
||||||
private:
|
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 _ptrRTPDataBegin;
|
||||||
const WebRtc_UWord8* const _ptrRTPDataEnd;
|
const WebRtc_UWord8* const _ptrRTPDataEnd;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user