Added RTX to ViE.

Review URL: http://webrtc-codereview.appspot.com/336001

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1373 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pwestin@webrtc.org 2012-01-10 14:09:18 +00:00
parent ac4eb046e3
commit 8281e7dd4a
19 changed files with 1968 additions and 444 deletions

View File

@ -49,6 +49,7 @@
'rtp_rtcp/source/rtp_rtcp_tests.gypi',
'rtp_rtcp/test/test_bwe/test_bwe.gypi',
'rtp_rtcp/test/testFec/test_fec.gypi',
'rtp_rtcp/test/testAPI/test_api.gypi',
'video_coding/main/source/video_coding_test.gypi',
'video_coding/codecs/test/video_codecs_test_framework.gypi',
'video_coding/codecs/tools/video_codecs_tools.gypi',

View File

@ -261,7 +261,20 @@ public:
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 SetSSRCFilter(const bool enable, const WebRtc_UWord32 allowedSSRC) = 0;
virtual WebRtc_Word32 SetSSRCFilter(const bool enable,
const WebRtc_UWord32 allowedSSRC) = 0;
/*
* Turn on/off receiving RTX (RFC 4588) on a specific SSRC.
*/
virtual WebRtc_Word32 SetRTXReceiveStatus(const bool enable,
const WebRtc_UWord32 SSRC) = 0;
/*
* Get status of receiving RTX (RFC 4588) on a specific SSRC.
*/
virtual WebRtc_Word32 RTXReceiveStatus(bool* enable,
WebRtc_UWord32* SSRC) const = 0;
/*
* called by the network module when we receive a packet
@ -360,9 +373,10 @@ public:
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 SetRTPKeepaliveStatus(const bool enable,
const WebRtc_Word8 unknownPayloadType,
const WebRtc_UWord16 deltaTransmitTimeMS) = 0;
virtual WebRtc_Word32 SetRTPKeepaliveStatus(
const bool enable,
const WebRtc_Word8 unknownPayloadType,
const WebRtc_UWord16 deltaTransmitTimeMS) = 0;
/*
* Get RTPKeepaliveStatus
@ -406,7 +420,8 @@ public:
*
* return -1 on failure else 0
*/
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.
@ -432,7 +447,8 @@ public:
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 SetStartTimestamp(const WebRtc_UWord32 timestamp) = 0;
virtual WebRtc_Word32 SetStartTimestamp(
const WebRtc_UWord32 timestamp) = 0;
/*
* Get SequenceNumber
@ -465,7 +481,8 @@ public:
*
* return -1 on failure else number of valid entries in the array
*/
virtual WebRtc_Word32 CSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const = 0;
virtual WebRtc_Word32 CSRCs(
WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const = 0;
/*
* Set CSRC
@ -475,8 +492,9 @@ public:
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 SetCSRCs( const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
const WebRtc_UWord8 arrLength) = 0;
virtual WebRtc_Word32 SetCSRCs(
const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
const WebRtc_UWord8 arrLength) = 0;
/*
* includes CSRCs in RTP header if enabled
@ -489,6 +507,20 @@ public:
*/
virtual WebRtc_Word32 SetCSRCStatus(const bool include) = 0;
/*
* Turn on/off sending RTX (RFC 4588) on a specific SSRC.
*/
virtual WebRtc_Word32 SetRTXSendStatus(const bool enable,
const bool setSSRC,
const WebRtc_UWord32 SSRC) = 0;
/*
* Get status of sending RTX (RFC 4588) on a specific SSRC.
*/
virtual WebRtc_Word32 RTXSendStatus(bool* enable,
WebRtc_UWord32* SSRC) const = 0;
/*
* sends kRtcpByeCode when going from true to false
*
@ -537,14 +569,14 @@ public:
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32
SendOutgoingData(const FrameType frameType,
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 timeStamp,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader* fragmentation = NULL,
const RTPVideoHeader* rtpVideoHdr = NULL) = 0;
virtual WebRtc_Word32 SendOutgoingData(
const FrameType frameType,
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 timeStamp,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader* fragmentation = NULL,
const RTPVideoHeader* rtpVideoHdr = NULL) = 0;
/**************************************************************************
*
@ -594,26 +626,29 @@ public:
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 RemoteCNAME(const WebRtc_UWord32 remoteSSRC,
WebRtc_Word8 cName[RTCP_CNAME_SIZE]) const = 0;
virtual WebRtc_Word32 RemoteCNAME(
const WebRtc_UWord32 remoteSSRC,
WebRtc_Word8 cName[RTCP_CNAME_SIZE]) const = 0;
/*
* Get remote NTP
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 RemoteNTP(WebRtc_UWord32 *ReceivedNTPsecs,
WebRtc_UWord32 *ReceivedNTPfrac,
WebRtc_UWord32 *RTCPArrivalTimeSecs,
WebRtc_UWord32 *RTCPArrivalTimeFrac) const = 0;
virtual WebRtc_Word32 RemoteNTP(
WebRtc_UWord32 *ReceivedNTPsecs,
WebRtc_UWord32 *ReceivedNTPfrac,
WebRtc_UWord32 *RTCPArrivalTimeSecs,
WebRtc_UWord32 *RTCPArrivalTimeFrac) const = 0;
/*
* AddMixedCNAME
*
* return -1 on failure else 0
*/
virtual WebRtc_Word32 AddMixedCNAME(const WebRtc_UWord32 SSRC,
const WebRtc_Word8 cName[RTCP_CNAME_SIZE]) = 0;
virtual WebRtc_Word32 AddMixedCNAME(
const WebRtc_UWord32 SSRC,
const WebRtc_Word8 cName[RTCP_CNAME_SIZE]) = 0;
/*
* RemoveMixedCNAME
@ -628,10 +663,10 @@ public:
* return -1 on failure else 0
*/
virtual WebRtc_Word32 RTT(const WebRtc_UWord32 remoteSSRC,
WebRtc_UWord16* RTT,
WebRtc_UWord16* avgRTT,
WebRtc_UWord16* minRTT,
WebRtc_UWord16* maxRTT) const = 0 ;
WebRtc_UWord16* RTT,
WebRtc_UWord16* avgRTT,
WebRtc_UWord16* minRTT,
WebRtc_UWord16* maxRTT) const = 0 ;
/*
* Reset RoundTripTime statistics

View File

@ -60,6 +60,10 @@ class MockRtpRtcp : public RtpRtcp {
WebRtc_Word32(WebRtc_UWord32& allowedSSRC));
MOCK_METHOD2(SetSSRCFilter,
WebRtc_Word32(const bool enable, const WebRtc_UWord32 allowedSSRC));
MOCK_METHOD2(SetRTXReceiveStatus,
WebRtc_Word32(const bool enable, const WebRtc_UWord32 SSRC));
MOCK_CONST_METHOD2(RTXReceiveStatus,
WebRtc_Word32(bool* enable, WebRtc_UWord32* SSRC));
MOCK_METHOD2(IncomingPacket,
WebRtc_Word32(const WebRtc_UWord8* incomingPacket, const WebRtc_UWord16 packetLength));
MOCK_METHOD4(IncomingAudioNTP,
@ -110,6 +114,10 @@ class MockRtpRtcp : public RtpRtcp {
WebRtc_Word32(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize], const WebRtc_UWord8 arrLength));
MOCK_METHOD1(SetCSRCStatus,
WebRtc_Word32(const bool include));
MOCK_METHOD3(SetRTXSendStatus,
WebRtc_Word32(const bool enable, const bool setSSRC, const WebRtc_UWord32 SSRC));
MOCK_CONST_METHOD2(RTXSendStatus,
WebRtc_Word32(bool* enable, WebRtc_UWord32* SSRC));
MOCK_METHOD1(SetSendingStatus,
WebRtc_Word32(const bool sending));
MOCK_CONST_METHOD0(Sending,

View File

@ -84,17 +84,18 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id,
_lastReportJitter(0),
_lastReportJitterTransmissionTimeOffset(0),
_nackMethod(kNackOff)
{
memset(_currentRemoteCSRC, 0, sizeof(_currentRemoteCSRC));
memset(_currentRemoteEnergy, 0, sizeof(_currentRemoteEnergy));
memset(&_lastReceivedAudioSpecific, 0, sizeof(_lastReceivedAudioSpecific));
_nackMethod(kNackOff),
_RTX(false),
_ssrcRTX(0) {
memset(_currentRemoteCSRC, 0, sizeof(_currentRemoteCSRC));
memset(_currentRemoteEnergy, 0, sizeof(_currentRemoteEnergy));
memset(&_lastReceivedAudioSpecific, 0, sizeof(_lastReceivedAudioSpecific));
_lastReceivedAudioSpecific.channels = 1;
_lastReceivedVideoSpecific.maxRate = 0;
_lastReceivedVideoSpecific.videoCodecType = kRtpNoVideo;
_lastReceivedAudioSpecific.channels = 1;
_lastReceivedVideoSpecific.maxRate = 0;
_lastReceivedVideoSpecific.videoCodecType = kRtpNoVideo;
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
}
RTPReceiver::~RTPReceiver()
@ -729,6 +730,19 @@ RTPReceiver::SetNACKStatus(const NACKMethod method)
return 0;
}
void RTPReceiver::SetRTXStatus(const bool enable,
const WebRtc_UWord32 SSRC) {
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
_RTX = enable;
_ssrcRTX = SSRC;
}
void RTPReceiver::RTXStatus(bool* enable, WebRtc_UWord32* SSRC) const {
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
*enable = _RTX;
*SSRC = _ssrcRTX;
}
WebRtc_UWord32
RTPReceiver::SSRC() const
{
@ -765,136 +779,143 @@ RTPReceiver::Energy( WebRtc_UWord8 arrOfEnergy[kRtpCsrcSize]) const
return _numEnergy;
}
WebRtc_Word32
RTPReceiver::IncomingRTPPacket(WebRtcRTPHeader* rtpHeader,
const WebRtc_UWord8* incomingRtpPacket,
const WebRtc_UWord16 incomingRtpPacketLength)
{
// rtpHeader now contains the parsed RTP header.
// Adjust packet length w r t RTP padding.
WebRtc_Word32 length = incomingRtpPacketLength - rtpHeader->header.paddingLength;
WebRtc_Word32 RTPReceiver::IncomingRTPPacket(
WebRtcRTPHeader* rtp_header,
const WebRtc_UWord8* packet,
const WebRtc_UWord16 packet_length) {
// rtp_header contains the parsed RTP header.
// Adjust packet length w r t RTP padding.
int length = packet_length - rtp_header->header.paddingLength;
// length sanity
if((length - rtpHeader->header.headerLength) < 0)
{
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
return -1;
}
if(_useSSRCFilter)
{
if(rtpHeader->header.ssrc != _SSRCFilter)
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s drop packet due to SSRC filter", __FUNCTION__);
return -1;
}
}
if(_lastReceiveTime == 0)
{
// trigger only once
CriticalSectionScoped lock(_criticalSectionCbs);
if(_cbRtpFeedback)
{
if(length - rtpHeader->header.headerLength == 0)
{
// keepalive packet
_cbRtpFeedback->OnReceivedPacket(_id, kPacketKeepAlive);
}else
{
_cbRtpFeedback->OnReceivedPacket(_id, kPacketRtp);
}
}
}
WebRtc_Word8 firstPayloadByte = 0;
if(length > 0)
{
firstPayloadByte = incomingRtpPacket[rtpHeader->header.headerLength];
}
// trigger our callbacks
CheckSSRCChanged(rtpHeader);
bool isRED = false;
ModuleRTPUtility::VideoPayload videoSpecific;
videoSpecific.maxRate = 0;
videoSpecific.videoCodecType = kRtpNoVideo;
ModuleRTPUtility::AudioPayload audioSpecific;
audioSpecific.bitsPerSample = 0;
audioSpecific.channels = 0;
audioSpecific.frequency = 0;
if (CheckPayloadChanged(rtpHeader,
firstPayloadByte,
isRED,
audioSpecific,
videoSpecific) == -1)
{
if (length - rtpHeader->header.headerLength == 0)
{
// ok keepalive packet
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"%s received keepalive",
// length sanity
if ((length - rtp_header->header.headerLength) < 0) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"%s invalid argument",
__FUNCTION__);
return 0;
}
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
"%s received invalid payloadtype",
__FUNCTION__);
return -1;
}
if (_RTX) {
if (_ssrcRTX == rtp_header->header.ssrc) {
// Sanity check.
if (rtp_header->header.headerLength + 2 > packet_length) {
return -1;
}
rtp_header->header.ssrc = _SSRC;
rtp_header->header.sequenceNumber =
(packet[rtp_header->header.headerLength] << 8) +
packet[1 + rtp_header->header.headerLength];
// Count the RTX header as part of the RTP header.
rtp_header->header.headerLength += 2;
}
CheckCSRC(rtpHeader);
WebRtc_Word32 retVal = 0;
const WebRtc_UWord8* payloadData = incomingRtpPacket + rtpHeader->header.headerLength;
const WebRtc_UWord16 payloadDataLength = (WebRtc_UWord16)(length - rtpHeader->header.headerLength);
if(_audio)
{
retVal = ParseAudioCodecSpecific(rtpHeader,
payloadData,
payloadDataLength,
audioSpecific,
isRED);
} else
{
retVal = ParseVideoCodecSpecific(rtpHeader,
payloadData,
payloadDataLength,
videoSpecific.videoCodecType,
isRED,
incomingRtpPacket,
incomingRtpPacketLength,
_clock.GetTimeInMS());
}
if (_useSSRCFilter) {
if (rtp_header->header.ssrc != _SSRCFilter) {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
"%s drop packet due to SSRC filter",
__FUNCTION__);
return -1;
}
if(retVal != -1)
{
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
// this compare to _receivedSeqMax
// we store the last received after we have done the callback
const bool oldPacket = RetransmitOfOldPacket(rtpHeader->header.sequenceNumber,
rtpHeader->header.timestamp);
// this updates _receivedSeqMax and other members
UpdateStatistics(rtpHeader, payloadDataLength, oldPacket);
// need to be updated after RetransmitOfOldPacket &
// RetransmitOfOldPacketUpdateStatistics
_lastReceiveTime = _clock.GetTimeInMS();
_lastReceivedPayloadLength = payloadDataLength;
if(retVal >= 0 && !oldPacket)
{
if(_lastReceivedTimestamp != rtpHeader->header.timestamp)
{
_lastReceivedTimestamp = rtpHeader->header.timestamp;
}
_lastReceivedSequenceNumber = rtpHeader->header.sequenceNumber;
_lastReceivedTransmissionTimeOffset =
rtpHeader->extension.transmissionTimeOffset;
}
}
if (_lastReceiveTime == 0) {
// trigger only once
CriticalSectionScoped lock(_criticalSectionCbs);
if (_cbRtpFeedback) {
if (length - rtp_header->header.headerLength == 0) {
// keepalive packet
_cbRtpFeedback->OnReceivedPacket(_id, kPacketKeepAlive);
} else {
_cbRtpFeedback->OnReceivedPacket(_id, kPacketRtp);
}
}
}
WebRtc_Word8 first_payload_byte = 0;
if (length > 0) {
first_payload_byte = packet[rtp_header->header.headerLength];
}
// trigger our callbacks
CheckSSRCChanged(rtp_header);
bool is_red = false;
ModuleRTPUtility::VideoPayload video_specific;
video_specific.maxRate = 0;
video_specific.videoCodecType = kRtpNoVideo;
ModuleRTPUtility::AudioPayload audio_specific;
audio_specific.bitsPerSample = 0;
audio_specific.channels = 0;
audio_specific.frequency = 0;
if (CheckPayloadChanged(rtp_header,
first_payload_byte,
is_red,
audio_specific,
video_specific) == -1) {
if (length - rtp_header->header.headerLength == 0)
{
// ok keepalive packet
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"%s received keepalive",
__FUNCTION__);
return 0;
}
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
"%s received invalid payloadtype",
__FUNCTION__);
return -1;
}
CheckCSRC(rtp_header);
const WebRtc_UWord8* payload_data =
packet + rtp_header->header.headerLength;
WebRtc_UWord16 payload_data_length =
static_cast<WebRtc_UWord16>(length - rtp_header->header.headerLength);
WebRtc_Word32 retVal = 0;
if(_audio) {
retVal = ParseAudioCodecSpecific(rtp_header,
payload_data,
payload_data_length,
audio_specific,
is_red);
} else {
retVal = ParseVideoCodecSpecific(rtp_header,
payload_data,
payload_data_length,
video_specific.videoCodecType,
is_red,
packet,
packet_length,
_clock.GetTimeInMS());
}
if(retVal < 0) {
return retVal;
}
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
// this compare to _receivedSeqMax
// we store the last received after we have done the callback
bool old_packet = RetransmitOfOldPacket(rtp_header->header.sequenceNumber,
rtp_header->header.timestamp);
// this updates _receivedSeqMax and other members
UpdateStatistics(rtp_header, payload_data_length, old_packet);
// Need to be updated after RetransmitOfOldPacket &
// RetransmitOfOldPacketUpdateStatistics
_lastReceiveTime = _clock.GetTimeInMS();
_lastReceivedPayloadLength = payload_data_length;
if (!old_packet) {
if (_lastReceivedTimestamp != rtp_header->header.timestamp) {
_lastReceivedTimestamp = rtp_header->header.timestamp;
}
_lastReceivedSequenceNumber = rtp_header->header.sequenceNumber;
_lastReceivedTransmissionTimeOffset =
rtp_header->extension.transmissionTimeOffset;
}
return retVal;
}
// must not have critsect when called

View File

@ -147,6 +147,12 @@ public:
virtual WebRtc_UWord32 PayloadTypeToPayload(const WebRtc_UWord8 payloadType,
ModuleRTPUtility::Payload*& payload) const;
/*
* RTX
*/
void SetRTXStatus(const bool enable, const WebRtc_UWord32 SSRC);
void RTXStatus(bool* enable, WebRtc_UWord32* SSRC) const;
protected:
virtual WebRtc_Word32 CallbackOfReceivedPayloadData(const WebRtc_UWord8* payloadData,
@ -246,8 +252,10 @@ private:
mutable WebRtc_UWord32 _lastReportJitter;
mutable WebRtc_UWord32 _lastReportJitterTransmissionTimeOffset;
// NACK
NACKMethod _nackMethod;
NACKMethod _nackMethod;
bool _RTX;
WebRtc_UWord32 _ssrcRTX;
};
} // namespace webrtc

View File

@ -690,6 +690,33 @@ ModuleRtpRtcpImpl::RemoteCSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const
return _rtpReceiver.CSRCs(arrOfCSRC);
}
WebRtc_Word32 ModuleRtpRtcpImpl::SetRTXSendStatus(
const bool enable,
const bool setSSRC,
const WebRtc_UWord32 SSRC) {
_rtpSender.SetRTXStatus(enable, setSSRC, SSRC);
return 0;
}
WebRtc_Word32 ModuleRtpRtcpImpl::RTXSendStatus(bool* enable,
WebRtc_UWord32* SSRC) const {
_rtpSender.RTXStatus(enable, SSRC);
return 0;
}
WebRtc_Word32 ModuleRtpRtcpImpl::SetRTXReceiveStatus(
const bool enable,
const WebRtc_UWord32 SSRC) {
_rtpReceiver.SetRTXStatus(enable, SSRC);
return 0;
}
WebRtc_Word32 ModuleRtpRtcpImpl::RTXReceiveStatus(bool* enable,
WebRtc_UWord32* SSRC) const {
_rtpReceiver.RTXStatus(enable, SSRC);
return 0;
}
// called by the network module when we receive a packet
WebRtc_Word32
ModuleRtpRtcpImpl::IncomingPacket(const WebRtc_UWord8* incomingPacket,

View File

@ -112,12 +112,16 @@ public:
// Get the current estimated remote timestamp
virtual WebRtc_Word32 EstimatedRemoteTimeStamp(WebRtc_UWord32& timestamp) const;
// Get incoming SSRC
virtual WebRtc_UWord32 RemoteSSRC() const;
// Get remote CSRC
virtual WebRtc_Word32 RemoteCSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const ;
virtual WebRtc_Word32 SetRTXReceiveStatus(const bool enable,
const WebRtc_UWord32 SSRC);
virtual WebRtc_Word32 RTXReceiveStatus(bool* enable,
WebRtc_UWord32* SSRC) const;
// called by the network module when we receive a packet
virtual WebRtc_Word32 IncomingPacket( const WebRtc_UWord8* incomingPacket,
const WebRtc_UWord16 packetLength);
@ -183,22 +187,18 @@ public:
// configure start timestamp, default is a random number
virtual WebRtc_Word32 SetStartTimestamp(const WebRtc_UWord32 timestamp);
// Get SequenceNumber
virtual WebRtc_UWord16 SequenceNumber() const;
// Set SequenceNumber, default is a random number
virtual WebRtc_Word32 SetSequenceNumber(const WebRtc_UWord16 seq);
// Get SSRC
virtual WebRtc_UWord32 SSRC() const;
// configure SSRC, default is a random number
virtual WebRtc_Word32 SetSSRC(const WebRtc_UWord32 ssrc);
// Get CSRC
virtual WebRtc_Word32 CSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const ;
// Set CSRC
virtual WebRtc_Word32 SetCSRCs( const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
const WebRtc_UWord8 arrLength);
@ -210,30 +210,35 @@ public:
virtual WebRtc_UWord32 ByteCountSent() const;
virtual WebRtc_Word32 SetRTXSendStatus(const bool enable,
const bool setSSRC,
const WebRtc_UWord32 SSRC);
virtual WebRtc_Word32 RTXSendStatus(bool* enable,
WebRtc_UWord32* SSRC) const;
// sends kRtcpByeCode when going from true to false
virtual WebRtc_Word32 SetSendingStatus(const bool sending);
// get send status
virtual bool Sending() const;
// Drops or relays media packets
virtual WebRtc_Word32 SetSendingMediaStatus(const bool sending);
// Send media status
virtual bool SendingMedia() const;
// Used by the module to send RTP and RTCP packet to the network module
virtual WebRtc_Word32 RegisterSendTransport(Transport* outgoingTransport);
// Used by the codec module to deliver a video or audio frame for packetization
virtual WebRtc_Word32
SendOutgoingData(const FrameType frameType,
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 timeStamp,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader* fragmentation = NULL,
const RTPVideoHeader* rtpVideoHdr = NULL);
virtual WebRtc_Word32 SendOutgoingData(
const FrameType frameType,
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 timeStamp,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader* fragmentation = NULL,
const RTPVideoHeader* rtpVideoHdr = NULL);
/*
* RTCP

View File

@ -74,12 +74,15 @@ RTPSender::RTPSender(const WebRtc_Word32 id,
_remoteSSRC(0),
_sequenceNumberForced(false),
_sequenceNumber(0),
_sequenceNumberRTX(0),
_ssrcForced(false),
_ssrc(0),
_timeStamp(0),
_CSRCs(0),
_CSRC(),
_includeCSRCs(true)
_includeCSRCs(true),
_RTX(false),
_ssrcRTX(0)
{
memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
memset(_nackByteCount, 0, sizeof(_nackByteCount));
@ -173,6 +176,7 @@ RTPSender::Init(const WebRtc_UWord32 remoteSSRC)
_ssrcDB.RegisterSSRC(remoteSSRC);
}
_sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
_sequenceNumberRTX = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
_packetsSent = 0;
_payloadBytesSent = 0;
_packetOverHead = 28;
@ -592,16 +596,14 @@ RTPSender::SetMaxPayloadLength(const WebRtc_UWord16 maxPayloadLength, const WebR
return 0;
}
WebRtc_UWord16
RTPSender::MaxDataPayloadLength() const
{
if(_audioConfigured)
{
return _maxPayloadLength - RTPHeaderLength();
} else
{
return _maxPayloadLength - RTPHeaderLength() - _video->FECPacketOverhead(); // Include the FEC/ULP/RED overhead.
}
WebRtc_UWord16 RTPSender::MaxDataPayloadLength() const {
if(_audioConfigured) {
return _maxPayloadLength - RTPHeaderLength();
} else {
return _maxPayloadLength - RTPHeaderLength() -
_video->FECPacketOverhead() - ((_RTX) ? 2 : 0);
// Include the FEC/ULP/RED overhead.
}
}
WebRtc_UWord16
@ -616,6 +618,27 @@ RTPSender::PacketOverHead() const
return _packetOverHead;
}
void RTPSender::SetRTXStatus(const bool enable,
const bool setSSRC,
const WebRtc_UWord32 SSRC) {
CriticalSectionScoped cs(_sendCritsect);
_RTX = enable;
if (enable) {
if (setSSRC) {
_ssrcRTX = SSRC;
} else {
_ssrcRTX = _ssrcDB.CreateSSRC(); // can't be 0
}
}
}
void RTPSender::RTXStatus(bool* enable,
WebRtc_UWord32* SSRC) const {
CriticalSectionScoped cs(_sendCritsect);
*enable = _RTX;
*SSRC = _ssrcRTX;
}
WebRtc_Word32
RTPSender::CheckPayloadType(const WebRtc_Word8 payloadType,
RtpVideoCodecTypes& videoType)
@ -876,127 +899,159 @@ RTPSender::SetStorePacketsStatus(const bool enable, const WebRtc_UWord16 numberT
return 0;
}
bool
RTPSender::StorePackets() const
{
return _storeSentPackets;
bool RTPSender::StorePackets() const {
return _storeSentPackets;
}
WebRtc_Word32
RTPSender::ReSendToNetwork(WebRtc_UWord16 packetID,
WebRtc_UWord32 minResendTime)
{
#ifdef DEBUG_RTP_SEQUENCE_NUMBER
char str[256];
sprintf(str,"Re-Send sequenceNumber %d\n", packetID) ;
OutputDebugString(str);
#endif
WebRtc_Word32 RTPSender::ReSendPacket(WebRtc_UWord16 packetID,
WebRtc_UWord32 minResendTime) {
WebRtc_Word32 length = 0;
WebRtc_Word32 index = 0;
WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE];
{
CriticalSectionScoped lock(_prevSentPacketsCritsect);
WebRtc_Word32 i = -1;
WebRtc_Word32 length = 0;
WebRtc_Word32 index =0;
WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE];
{
CriticalSectionScoped lock(_prevSentPacketsCritsect);
WebRtc_UWord16 seqNum = 0;
if(_storeSentPackets)
{
if(_prevSentPacketsIndex)
{
seqNum = _prevSentPacketsSeqNum[_prevSentPacketsIndex-1];
}else
{
seqNum = _prevSentPacketsSeqNum[_storeSentPacketsNumber-1];
}
index = (_prevSentPacketsIndex-1) - (seqNum - packetID);
if (index >= 0 && index < _storeSentPacketsNumber)
{
seqNum = _prevSentPacketsSeqNum[index];
}
if(seqNum != packetID)
{
//we did not found a match, search all
for (WebRtc_Word32 m = 0; m < _storeSentPacketsNumber ;m++)
{
if(_prevSentPacketsSeqNum[m] == packetID)
{
index = m;
seqNum = _prevSentPacketsSeqNum[index];
break;
}
}
}
if(seqNum == packetID)
{
WebRtc_UWord32 timeNow= _clock.GetTimeInMS();
if(minResendTime>0 && (timeNow-_prevSentPacketsResendTime[index]<minResendTime))
{
// No point in sending the packet again yet. Get out of here
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "Skipping to resend RTP packet %d because it was just resent", seqNum);
return 0;
}
length = _prevSentPacketsLength[index];
if(length > _maxPayloadLength || _ptrPrevSentPackets[index] == 0)
{
WEBRTC_TRACE(
kTraceWarning, kTraceRtpRtcp, _id,
"Failed to resend seqNum %u: length = %d index = %d",
seqNum, length, index);
return -1;
}
} else
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
"No match for resending seqNum %u and packetId %u",
seqNum, packetID);
return -1;
}
}
if (length == 0)
{
// This is a valid case since packets which we decide not to
// retransmit are stored but with length zero.
return 0;
}
// copy to local buffer for callback
memcpy(dataBuffer, _ptrPrevSentPackets[index], length);
WebRtc_UWord16 seqNum = 0;
if (!_storeSentPackets) {
WEBRTC_TRACE(kTraceWarning,
kTraceRtpRtcp,
_id,
"Ignoring request to ReSendPacket:%u we're not storing.",
seqNum);
return -1;
}
{
CriticalSectionScoped lock(_transportCritsect);
if(_transport)
{
i = _transport->SendPacket(_id, dataBuffer, length);
if (_prevSentPacketsIndex) {
seqNum = _prevSentPacketsSeqNum[_prevSentPacketsIndex-1];
} else {
seqNum = _prevSentPacketsSeqNum[_storeSentPacketsNumber-1];
}
index = (_prevSentPacketsIndex-1) - (seqNum - packetID);
if (index >= 0 && index < _storeSentPacketsNumber) {
seqNum = _prevSentPacketsSeqNum[index];
}
if (seqNum != packetID) {
// we did not found a match, search all
for (WebRtc_Word32 m = 0; m < _storeSentPacketsNumber; m++) {
if(_prevSentPacketsSeqNum[m] == packetID) {
index = m;
seqNum = _prevSentPacketsSeqNum[index];
break;
}
}
}
if(i > 0)
{
CriticalSectionScoped cs(_sendCritsect);
Bitrate::Update(i);
_packetsSent++;
// we on purpose don't add to _payloadBytesSent since this is a re-transmit and not new payload data
if (seqNum != packetID) {
WEBRTC_TRACE(kTraceWarning,
kTraceRtpRtcp,
_id,
"No match for resending seqNum %u and packetId %u",
seqNum, packetID);
return -1;
}
if(_storeSentPackets && i > 0)
{
CriticalSectionScoped lock(_prevSentPacketsCritsect);
if(_prevSentPacketsSeqNum[index] == packetID) // Make sure the packet is still in the array
{
// Store the time when the frame was last resent.
_prevSentPacketsResendTime[index]= _clock.GetTimeInMS();
}
return i; //bytes sent over network
WebRtc_UWord32 timeNow = _clock.GetTimeInMS();
if (minResendTime > 0 &&
(timeNow-_prevSentPacketsResendTime[index] < minResendTime)) {
// No point in sending the packet again yet. Get out of here
WEBRTC_TRACE(kTraceStream,
kTraceRtpRtcp,
_id,
"Skipping to resend RTP packet %d, it was just resent",
seqNum);
return 0;
}
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
"Transport failed to resend packetID %u", packetID);
return -1;
length = _prevSentPacketsLength[index];
if (length > _maxPayloadLength || _ptrPrevSentPackets[index] == 0) {
WEBRTC_TRACE(kTraceWarning,
kTraceRtpRtcp,
_id,
"Failed to resend seqNum %u: length = %d index = %d",
seqNum, length, index);
return -1;
}
if (length == 0) {
WEBRTC_TRACE(kTraceWarning,
kTraceRtpRtcp,
_id,
"Resend packet length == 0 for seqNum %u",
seqNum);
return -1;
}
if (_RTX) {
CriticalSectionScoped cs(_sendCritsect);
// Copy to local buffer for callback and add RTX header.
ModuleRTPUtility::RTPHeaderParser rtpParser(
reinterpret_cast<const WebRtc_UWord8*>(_ptrPrevSentPackets[index]),
length);
WebRtcRTPHeader rtp_header;
rtpParser.Parse(rtp_header);
// Add original RTP header.
memcpy(dataBuffer, _ptrPrevSentPackets[index],
rtp_header.header.headerLength);
// Replace sequence number.
WebRtc_UWord8* ptr = dataBuffer + 2;
ModuleRTPUtility::AssignUWord16ToBuffer(ptr, _sequenceNumberRTX++);
// Replace SSRC.
ptr += 6;
ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _ssrcRTX);
// Add OSN (original sequence number).
ptr = dataBuffer + rtp_header.header.headerLength;
ModuleRTPUtility::AssignUWord16ToBuffer(
ptr, rtp_header.header.sequenceNumber);
ptr += 2;
// Add original payload data.
memcpy(ptr,
_ptrPrevSentPackets[index] + rtp_header.header.headerLength,
length - rtp_header.header.headerLength);
length += 2;
} else {
// copy to local buffer for callback
memcpy(dataBuffer, _ptrPrevSentPackets[index], length);
}
} // End of scope lock(_prevSentPacketsCritsect).
WebRtc_Word32 i = ReSendToNetwork(dataBuffer, length);
if (_storeSentPackets && i > 0) {
CriticalSectionScoped lock(_prevSentPacketsCritsect);
// Make sure the packet is still in the array
if(_prevSentPacketsSeqNum[index] == packetID) {
// Store the time when the frame was last resent.
_prevSentPacketsResendTime[index]= _clock.GetTimeInMS();
}
return i; //bytes sent over network
}
WEBRTC_TRACE(kTraceWarning,
kTraceRtpRtcp,
_id,
"Transport failed to resend packetID %u",
packetID);
return -1;
}
WebRtc_Word32 RTPSender::ReSendToNetwork(const WebRtc_UWord8* packet,
const WebRtc_UWord32 size) {
WebRtc_Word32 i = -1;
{
CriticalSectionScoped lock(_transportCritsect);
if(_transport) {
i = _transport->SendPacket(_id, packet, size);
}
}
if(i > 0) {
CriticalSectionScoped cs(_sendCritsect);
Bitrate::Update(i);
_packetsSent++;
// We on purpose don't add to _payloadBytesSent since this is a re-transmit
// and not new payload data
}
return i;
}
int RTPSender::SelectiveRetransmissions() const {
@ -1012,124 +1067,111 @@ int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
void
RTPSender::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
const WebRtc_UWord16* nackSequenceNumbers,
const WebRtc_UWord16 avgRTT)
{
const WebRtc_UWord16 avgRTT) {
const WebRtc_UWord32 now = _clock.GetTimeInMS();
WebRtc_UWord32 bytesReSent = 0;
// Enough bandwith to send NACK?
if(ProcessNACKBitRate(now))
{
for (WebRtc_UWord16 i = 0; i < nackSequenceNumbersLength; ++i)
{
const WebRtc_Word32 bytesSent = ReSendToNetwork(nackSequenceNumbers[i],
5+avgRTT);
if (bytesSent > 0)
{
bytesReSent += bytesSent;
// Enough bandwith to send NACK?
if (!ProcessNACKBitRate(now)) {
WEBRTC_TRACE(kTraceStream,
kTraceRtpRtcp,
_id,
"NACK bitrate reached. Skipp sending NACK response. Target %d",
TargetSendBitrateKbit());
return;
}
} else if(bytesSent==0)
{
continue; // The packet has previously been resent. Try resending next packet in the list.
} else if(bytesSent<0) // Failed to send one Sequence number. Give up the rest in this nack.
{
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Failed resending RTP packet %d, Discard rest of NACK RTP packets", nackSequenceNumbers[i]);
break;
}
// delay bandwidth estimate (RTT * BW)
if(TargetSendBitrateKbit() != 0 && avgRTT)
{
if(bytesReSent > (WebRtc_UWord32)(TargetSendBitrateKbit() * avgRTT)>>3 ) // kbits/s * ms= bits/8 = bytes
{
break; // ignore the rest of the packets in the list
}
}
}
if (bytesReSent > 0)
{
UpdateNACKBitRate(bytesReSent,now); // Update the nack bit rate
_nackBitrate.Update(bytesReSent);
}
}else
{
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "NACK bitrate reached. Skipp sending NACK response. Target %d",TargetSendBitrateKbit());
for (WebRtc_UWord16 i = 0; i < nackSequenceNumbersLength; ++i) {
const WebRtc_Word32 bytesSent = ReSendPacket(nackSequenceNumbers[i],
5+avgRTT);
if (bytesSent > 0) {
bytesReSent += bytesSent;
} else if (bytesSent == 0) {
// The packet has previously been resent.
// Try resending next packet in the list.
continue;
} else if (bytesSent < 0) {
// Failed to send one Sequence number. Give up the rest in this nack.
WEBRTC_TRACE(kTraceWarning,
kTraceRtpRtcp,
_id,
"Failed resending RTP packet %d, Discard rest of packets",
nackSequenceNumbers[i]);
break;
}
// delay bandwidth estimate (RTT * BW)
if (TargetSendBitrateKbit() != 0 && avgRTT) {
// kbits/s * ms = bits => bits/8 = bytes
WebRtc_UWord32 targetBytes =
(static_cast<WebRtc_UWord32>(TargetSendBitrateKbit()) * avgRTT) >> 3;
if (bytesReSent > targetBytes) {
break; // ignore the rest of the packets in the list
}
}
}
if (bytesReSent > 0) {
// TODO(pwestin) consolidate these two methods.
UpdateNACKBitRate(bytesReSent, now);
_nackBitrate.Update(bytesReSent);
}
}
/**
* @return true if the nack bitrate is lower than the requested max bitrate
*/
bool
RTPSender::ProcessNACKBitRate(const WebRtc_UWord32 now)
{
WebRtc_UWord32 num = 0;
WebRtc_Word32 byteCount = 0;
const WebRtc_UWord32 avgInterval=1000;
bool RTPSender::ProcessNACKBitRate(const WebRtc_UWord32 now) {
WebRtc_UWord32 num = 0;
WebRtc_Word32 byteCount = 0;
const WebRtc_UWord32 avgInterval=1000;
CriticalSectionScoped cs(_sendCritsect);
CriticalSectionScoped cs(_sendCritsect);
if(_targetSendBitrate == 0)
{
return true;
if (_targetSendBitrate == 0) {
return true;
}
for (num = 0; num < NACK_BYTECOUNT_SIZE; num++) {
if ((now - _nackByteCountTimes[num]) > avgInterval) {
// don't use data older than 1sec
break;
} else {
byteCount += _nackByteCount[num];
}
for(num = 0; num < NACK_BYTECOUNT_SIZE; num++)
{
if((now - _nackByteCountTimes[num]) > avgInterval)
{
// don't use data older than 1sec
break;
} else
{
byteCount += _nackByteCount[num];
}
}
WebRtc_Word32 timeInterval = avgInterval;
if (num == NACK_BYTECOUNT_SIZE) {
// More than NACK_BYTECOUNT_SIZE nack messages has been received
// during the last msgInterval
timeInterval = now - _nackByteCountTimes[num-1];
if(timeInterval < 0) {
timeInterval = avgInterval;
}
WebRtc_Word32 timeInterval = avgInterval;
if (num == NACK_BYTECOUNT_SIZE)
{
// More than NACK_BYTECOUNT_SIZE nack messages has been received
// during the last msgInterval
timeInterval = now - _nackByteCountTimes[num-1];
if(timeInterval < 0)
{
timeInterval = avgInterval;
}
}
return (byteCount*8) < (_targetSendBitrate * timeInterval);
}
return (byteCount*8) < (_targetSendBitrate * timeInterval);
}
void
RTPSender::UpdateNACKBitRate(const WebRtc_UWord32 bytes,
const WebRtc_UWord32 now)
{
CriticalSectionScoped cs(_sendCritsect);
void RTPSender::UpdateNACKBitRate(const WebRtc_UWord32 bytes,
const WebRtc_UWord32 now) {
CriticalSectionScoped cs(_sendCritsect);
// save bitrate statistics
if(bytes > 0)
{
if(now == 0)
{
// add padding length
_nackByteCount[0] += bytes;
} else
{
if(_nackByteCountTimes[0] == 0)
{
// first no shift
} else
{
// shift
for(int i = (NACK_BYTECOUNT_SIZE-2); i >= 0 ; i--)
{
_nackByteCount[i+1] = _nackByteCount[i];
_nackByteCountTimes[i+1] = _nackByteCountTimes[i];
}
}
_nackByteCount[0] = bytes;
_nackByteCountTimes[0] = now;
// save bitrate statistics
if(bytes > 0) {
if(now == 0) {
// add padding length
_nackByteCount[0] += bytes;
} else {
if(_nackByteCountTimes[0] == 0) {
// first no shift
} else {
// shift
for(int i = (NACK_BYTECOUNT_SIZE-2); i >= 0 ; i--) {
_nackByteCount[i+1] = _nackByteCount[i];
_nackByteCountTimes[i+1] = _nackByteCountTimes[i];
}
}
_nackByteCount[0] = bytes;
_nackByteCountTimes[0] = now;
}
}
}
WebRtc_Word32

View File

@ -93,11 +93,12 @@ public:
// callback
WebRtc_Word32 RegisterSendTransport(Transport* outgoingTransport);
WebRtc_Word32 RegisterPayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 frequency,
const WebRtc_UWord8 channels,
const WebRtc_UWord32 rate);
WebRtc_Word32 RegisterPayload(
const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 frequency,
const WebRtc_UWord8 channels,
const WebRtc_UWord32 rate);
WebRtc_Word32 DeRegisterSendPayload(const WebRtc_Word8 payloadType);
@ -119,7 +120,8 @@ public:
WebRtc_Word32 ResetDataCounters();
WebRtc_UWord32 StartTimestamp() const;
WebRtc_Word32 SetStartTimestamp( const WebRtc_UWord32 timestamp, const bool force = false);
WebRtc_Word32 SetStartTimestamp(const WebRtc_UWord32 timestamp,
const bool force = false);
WebRtc_UWord32 GenerateNewSSRC();
WebRtc_Word32 SetSSRC( const WebRtc_UWord32 ssrc);
@ -132,20 +134,19 @@ public:
WebRtc_Word32 SetCSRCStatus(const bool include);
WebRtc_Word32 SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
const WebRtc_UWord8 arrLength);
const WebRtc_UWord8 arrLength);
WebRtc_Word32 SetMaxPayloadLength(const WebRtc_UWord16 length,
const WebRtc_UWord16 packetOverHead);
const WebRtc_UWord16 packetOverHead);
WebRtc_Word32
SendOutgoingData(const FrameType frameType,
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 timeStamp,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader* fragmentation,
VideoCodecInformation* codecInfo = NULL,
const RTPVideoTypeHeader* rtpTypeHdr = NULL);
WebRtc_Word32 SendOutgoingData(const FrameType frameType,
const WebRtc_Word8 payloadType,
const WebRtc_UWord32 timeStamp,
const WebRtc_UWord8* payloadData,
const WebRtc_UWord32 payloadSize,
const RTPFragmentationHeader* fragmentation,
VideoCodecInformation* codecInfo = NULL,
const RTPVideoTypeHeader* rtpTypeHdr = NULL);
WebRtc_Word32 SendPadData(WebRtc_Word8 payload_type,
WebRtc_UWord32 capture_timestamp,
@ -177,18 +178,19 @@ public:
const WebRtc_UWord16* nackSequenceNumbers,
const WebRtc_UWord16 avgRTT);
WebRtc_Word32 SetStorePacketsStatus(const bool enable, const WebRtc_UWord16 numberToStore);
WebRtc_Word32 SetStorePacketsStatus(const bool enable,
const WebRtc_UWord16 numberToStore);
bool StorePackets() const;
WebRtc_Word32 ReSendToNetwork(WebRtc_UWord16 packetID,
WebRtc_UWord32 minResendTime=0);
WebRtc_Word32 ReSendPacket(WebRtc_UWord16 packetID,
WebRtc_UWord32 minResendTime=0);
WebRtc_Word32 ReSendToNetwork(const WebRtc_UWord8* packet,
const WebRtc_UWord32 size);
bool ProcessNACKBitRate(const WebRtc_UWord32 now);
void UpdateNACKBitRate( const WebRtc_UWord32 bytes,
const WebRtc_UWord32 now);
/*
* Keep alive
*/
@ -207,6 +209,15 @@ public:
WebRtc_Word32 SendRTPKeepalivePacket();
/*
* RTX
*/
void SetRTXStatus(const bool enable,
const bool setSSRC,
const WebRtc_UWord32 SSRC);
void RTXStatus(bool* enable, WebRtc_UWord32* SSRC) const;
/*
* Functions wrapping RTPSenderInterface
*/
@ -237,9 +248,9 @@ public:
WebRtc_Word32 RegisterAudioCallback(RtpAudioFeedback* messagesCallback);
// Send a DTMF tone using RFC 2833 (4733)
WebRtc_Word32 SendTelephoneEvent(const WebRtc_UWord8 key,
const WebRtc_UWord16 time_ms,
const WebRtc_UWord8 level);
WebRtc_Word32 SendTelephoneEvent(const WebRtc_UWord8 key,
const WebRtc_UWord16 time_ms,
const WebRtc_UWord8 level);
bool SendTelephoneEventActive(WebRtc_Word8& telephoneEvent) const;
@ -293,6 +304,9 @@ protected:
WebRtc_Word32 CheckPayloadType(const WebRtc_Word8 payloadType, RtpVideoCodecTypes& videoType);
private:
void UpdateNACKBitRate(const WebRtc_UWord32 bytes,
const WebRtc_UWord32 now);
void StorePacket(const uint8_t* buffer, uint16_t length,
uint16_t sequence_number);
@ -326,6 +340,7 @@ private:
bool _storeSentPackets;
WebRtc_UWord16 _storeSentPacketsNumber;
CriticalSectionWrapper* _prevSentPacketsCritsect;
WebRtc_Word32 _prevSentPacketsIndex;
WebRtc_Word8** _ptrPrevSentPackets;
WebRtc_UWord16* _prevSentPacketsSeqNum;
@ -348,12 +363,15 @@ private:
WebRtc_UWord32 _remoteSSRC;
bool _sequenceNumberForced;
WebRtc_UWord16 _sequenceNumber;
WebRtc_UWord16 _sequenceNumberRTX;
bool _ssrcForced;
WebRtc_UWord32 _ssrc;
WebRtc_UWord32 _timeStamp;
WebRtc_UWord8 _CSRCs;
WebRtc_UWord32 _CSRC[kRtpCsrcSize];
bool _includeCSRCs;
bool _RTX;
WebRtc_UWord32 _ssrcRTX;
};
} // namespace webrtc

View File

@ -0,0 +1,114 @@
/*
* 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 <algorithm>
#include <vector>
#include <gtest/gtest.h>
#include "test_api.h"
#include "common_types.h"
#include "rtp_rtcp.h"
#include "rtp_rtcp_defines.h"
using namespace webrtc;
class RtpRtcpAPITest : public ::testing::Test {
protected:
RtpRtcpAPITest() {
test_CSRC[0] = 1234;
test_CSRC[2] = 2345;
test_id = 123;
test_ssrc = 3456;
test_timestamp = 4567;
test_sequence_number = 2345;
}
~RtpRtcpAPITest() {}
virtual void SetUp() {
module = RtpRtcp::CreateRtpRtcp(test_id, true, &fake_clock);
EXPECT_EQ(0, module->InitReceiver());
EXPECT_EQ(0, module->InitSender());
}
virtual void TearDown() {
RtpRtcp::DestroyRtpRtcp(module);
}
int test_id;
RtpRtcp* module;
WebRtc_UWord32 test_ssrc;
WebRtc_UWord32 test_timestamp;
WebRtc_UWord16 test_sequence_number;
WebRtc_UWord32 test_CSRC[webrtc::kRtpCsrcSize];
FakeRtpRtcpClock fake_clock;
};
TEST_F(RtpRtcpAPITest, Basic) {
EXPECT_EQ(0, module->SetSequenceNumber(test_sequence_number));
EXPECT_EQ(test_sequence_number, module->SequenceNumber());
EXPECT_EQ(0, module->SetStartTimestamp(test_timestamp));
EXPECT_EQ(test_timestamp, module->StartTimestamp());
EXPECT_EQ(false, module->Sending());
EXPECT_EQ(0, module->SetSendingStatus(true));
EXPECT_EQ(true, module->Sending());
}
TEST_F(RtpRtcpAPITest, MTU) {
EXPECT_EQ(-1, module->SetMaxTransferUnit(10));
EXPECT_EQ(-1, module->SetMaxTransferUnit(IP_PACKET_SIZE + 1));
EXPECT_EQ(0, module->SetMaxTransferUnit(1234));
EXPECT_EQ(1234-20-8, module->MaxPayloadLength());
EXPECT_EQ(0, module->SetTransportOverhead(true, true, 12));
EXPECT_EQ(1234 - 20- 20 -20 - 12, module->MaxPayloadLength());
EXPECT_EQ(0, module->SetTransportOverhead(false, false, 0));
EXPECT_EQ(1234 - 20 - 8, module->MaxPayloadLength());
}
TEST_F(RtpRtcpAPITest, SSRC) {
EXPECT_EQ(0, module->SetSSRC(test_ssrc));
EXPECT_EQ(test_ssrc, module->SSRC());
}
TEST_F(RtpRtcpAPITest, CSRC) {
EXPECT_EQ(0, module->SetCSRCs(test_CSRC, 2));
WebRtc_UWord32 testOfCSRC[webrtc::kRtpCsrcSize];
EXPECT_EQ(2, module->CSRCs(testOfCSRC));
EXPECT_EQ(test_CSRC[0], testOfCSRC[0]);
EXPECT_EQ(test_CSRC[1], testOfCSRC[1]);
}
TEST_F(RtpRtcpAPITest, RTCP) {
EXPECT_EQ(kRtcpOff, module->RTCP());
EXPECT_EQ(0, module->SetRTCPStatus(kRtcpCompound));
EXPECT_EQ(kRtcpCompound, module->RTCP());
EXPECT_EQ(0, module->SetCNAME("john.doe@test.test"));
EXPECT_EQ(-1, module->SetCNAME(NULL));
WebRtc_Word8 cName[RTCP_CNAME_SIZE];
EXPECT_EQ(0, module->CNAME(cName));
EXPECT_STRCASEEQ(cName, "john.doe@test.test");
EXPECT_EQ(-1, module->CNAME(NULL));
EXPECT_EQ(false, module->TMMBR());
EXPECT_EQ(0, module->SetTMMBRStatus(true));
EXPECT_EQ(true, module->TMMBR());
EXPECT_EQ(0, module->SetTMMBRStatus(false));
EXPECT_EQ(false, module->TMMBR());
EXPECT_EQ(kNackOff, module->NACK());
EXPECT_EQ(0, module->SetNACKStatus(kNackRtcp));
EXPECT_EQ(kNackRtcp, module->NACK());
}

View File

@ -0,0 +1,42 @@
# 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.
{
'targets': [
{
'target_name': 'test_rtp_rtcp_api',
'type': 'executable',
'dependencies': [
'rtp_rtcp',
'<(webrtc_root)/../test/test.gyp:test_support_main',
'<(webrtc_root)/../testing/gtest.gyp:gtest',
],
'include_dirs': [
'../../interface',
'../../source',
'../../../../system_wrappers/interface',
],
'sources': [
'test_api.cc',
'test_api_audio.cc',
'test_api_nack.cc',
'test_api_rtcp.cc',
'test_api_video.cc',
],
},
],
}
# Local Variables:
# tab-width:2
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=2 shiftwidth=2:

View File

@ -0,0 +1,85 @@
/*
* 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 "common_types.h"
#include "rtp_rtcp.h"
#include "rtp_rtcp_defines.h"
using namespace webrtc;
class FakeRtpRtcpClock : public RtpRtcpClock {
public:
FakeRtpRtcpClock() {
time_in_ms_ = 123456;
}
// Return a timestamp in milliseconds relative to some arbitrary
// source; the source is fixed for this clock.
virtual WebRtc_UWord32 GetTimeInMS() {
return time_in_ms_;
}
// Retrieve an NTP absolute timestamp.
virtual void CurrentNTP(WebRtc_UWord32& secs, WebRtc_UWord32& frac) {
secs = time_in_ms_ / 1000;
frac = (time_in_ms_ % 1000) * 4294967;
}
void IncrementTime(WebRtc_UWord32 time_increment_ms) {
time_in_ms_ += time_increment_ms;
}
private:
WebRtc_UWord32 time_in_ms_;
};
// This class sends all its packet straight to the provided RtpRtcp module.
// with optional packet loss.
class LoopBackTransport : public webrtc::Transport {
public:
LoopBackTransport(RtpRtcp* rtpRtcpModule)
: _count(0),
_packetLoss(0),
_rtpRtcpModule(rtpRtcpModule) {
}
void DropEveryNthPacket(int n) {
_packetLoss = n;
}
virtual int SendPacket(int channel, const void *data, int len) {
_count++;
if (_packetLoss > 0) {
if ((_count % _packetLoss) == 0) {
return len;
}
}
if (_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) {
return len;
}
return -1;
}
virtual int SendRTCPPacket(int channel, const void *data, int len) {
if (_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) {
return len;
}
return -1;
}
private:
int _count;
int _packetLoss;
RtpRtcp* _rtpRtcpModule;
};
class RtpReceiver : public RtpData {
public:
virtual WebRtc_Word32 OnReceivedPayloadData(
const WebRtc_UWord8* payloadData,
const WebRtc_UWord16 payloadSize,
const webrtc::WebRtcRTPHeader* rtpHeader) {
return 0;
}
};

View File

@ -0,0 +1,446 @@
/*
* 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 <algorithm>
#include <vector>
#include <gtest/gtest.h>
#include "test_api.h"
#include "common_types.h"
#include "rtp_rtcp.h"
#include "rtp_rtcp_defines.h"
using namespace webrtc;
#define test_rate 64000u
class VerifyingAudioReceiver : public RtpData {
public:
VerifyingAudioReceiver(RtpRtcp* rtpRtcpModule) {}
virtual WebRtc_Word32 OnReceivedPayloadData(
const WebRtc_UWord8* payloadData,
const WebRtc_UWord16 payloadSize,
const webrtc::WebRtcRTPHeader* rtpHeader) {
if (rtpHeader->header.payloadType == 98 ||
rtpHeader->header.payloadType == 99) {
EXPECT_EQ(4, payloadSize);
char str[5];
memcpy(str, payloadData, payloadSize);
str[4] = 0;
// All our test vectors for payload type 96 and 97 even the stereo is on
// a per channel base equal to the 4 chars "test".
// Note there is no null termination so we add that to use the
// test EXPECT_STRCASEEQ.
EXPECT_STRCASEEQ("test", str);
return 0;
}
if (rtpHeader->header.payloadType == 100 ||
rtpHeader->header.payloadType == 101 ||
rtpHeader->header.payloadType == 102) {
if (rtpHeader->type.Audio.channel == 1) {
if (payloadData[0] == 0xff) {
// All our test vectors for payload type 100, 101 and 102 have the
// first channel data being equal to 0xff.
return 0;
}
} else if (rtpHeader->type.Audio.channel == 2) {
if (payloadData[0] == 0x0) {
// All our test vectors for payload type 100, 101 and 102 have the
// second channel data being equal to 0x00.
return 0;
}
} else if (rtpHeader->type.Audio.channel == 3) {
// All our test vectors for payload type 100, 101 and 102 have the
// third channel data being equal to 0xaa.
if (payloadData[0] == 0xaa) {
return 0;
}
}
EXPECT_EQ(false, true) << "This code path should never happen.";
return -1;
}
return 0;
}
};
class RTPCallback : public RtpFeedback {
public:
virtual WebRtc_Word32 OnInitializeDecoder(
const WebRtc_Word32 id,
const WebRtc_Word8 payloadType,
const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
const int frequency,
const WebRtc_UWord8 channels,
const WebRtc_UWord32 rate) {
if (payloadType == 96) {
EXPECT_EQ(test_rate, rate) <<
"The rate should be 64K for this payloadType";
}
return 0;
}
virtual void OnPacketTimeout(const WebRtc_Word32 id) {
}
virtual void OnReceivedPacket(const WebRtc_Word32 id,
const RtpRtcpPacketType packetType) {
}
virtual void OnPeriodicDeadOrAlive(const WebRtc_Word32 id,
const RTPAliveType alive) {
}
virtual void OnIncomingSSRCChanged(const WebRtc_Word32 id,
const WebRtc_UWord32 SSRC) {
}
virtual void OnIncomingCSRCChanged(const WebRtc_Word32 id,
const WebRtc_UWord32 CSRC,
const bool added) {
}
};
class AudioFeedback : public RtpAudioFeedback {
virtual void OnReceivedTelephoneEvent(const WebRtc_Word32 id,
const WebRtc_UWord8 event,
const bool end) {
static WebRtc_UWord8 expectedEvent = 0;
if (end) {
WebRtc_UWord8 oldEvent = expectedEvent-1;
if (expectedEvent == 32) {
oldEvent = 15;
}
EXPECT_EQ(oldEvent, event);
} else {
EXPECT_EQ(expectedEvent, event);
expectedEvent++;
}
if (expectedEvent == 16) {
expectedEvent = 32;
}
}
virtual void OnPlayTelephoneEvent(const WebRtc_Word32 id,
const WebRtc_UWord8 event,
const WebRtc_UWord16 lengthMs,
const WebRtc_UWord8 volume) {
};
};
class RtpRtcpAudioTest : public ::testing::Test {
protected:
RtpRtcpAudioTest() {
test_CSRC[0] = 1234;
test_CSRC[2] = 2345;
test_id = 123;
test_ssrc = 3456;
test_timestamp = 4567;
test_sequence_number = 2345;
}
~RtpRtcpAudioTest() {}
virtual void SetUp() {
module1 = RtpRtcp::CreateRtpRtcp(test_id, true, &fake_clock);
module2 = RtpRtcp::CreateRtpRtcp(test_id+1, true, &fake_clock);
EXPECT_EQ(0, module1->InitReceiver());
EXPECT_EQ(0, module1->InitSender());
EXPECT_EQ(0, module2->InitReceiver());
EXPECT_EQ(0, module2->InitSender());
data_receiver1 = new VerifyingAudioReceiver(module1);
EXPECT_EQ(0, module1->RegisterIncomingDataCallback(data_receiver1));
data_receiver2 = new VerifyingAudioReceiver(module2);
EXPECT_EQ(0, module2->RegisterIncomingDataCallback(data_receiver2));
transport1 = new LoopBackTransport(module2);
EXPECT_EQ(0, module1->RegisterSendTransport(transport1));
transport2 = new LoopBackTransport(module1);
EXPECT_EQ(0, module2->RegisterSendTransport(transport2));
rtp_callback = new RTPCallback();
EXPECT_EQ(0, module2->RegisterIncomingRTPCallback(rtp_callback));
}
virtual void TearDown() {
RtpRtcp::DestroyRtpRtcp(module1);
RtpRtcp::DestroyRtpRtcp(module2);
delete transport1;
delete transport2;
delete data_receiver1;
delete data_receiver2;
delete rtp_callback;
}
int test_id;
RtpRtcp* module1;
RtpRtcp* module2;
VerifyingAudioReceiver* data_receiver1;
VerifyingAudioReceiver* data_receiver2;
LoopBackTransport* transport1;
LoopBackTransport* transport2;
RTPCallback* rtp_callback;
WebRtc_UWord32 test_ssrc;
WebRtc_UWord32 test_timestamp;
WebRtc_UWord16 test_sequence_number;
WebRtc_UWord32 test_CSRC[webrtc::kRtpCsrcSize];
FakeRtpRtcpClock fake_clock;
};
TEST_F(RtpRtcpAudioTest, Basic) {
EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
EXPECT_EQ(false, module1->TelephoneEvent());
// Test detection at the end of a DTMF tone.
EXPECT_EQ(0, module2->SetTelephoneEventStatus(true, true, true));
EXPECT_EQ(true, module2->TelephoneEvent());
EXPECT_EQ(0, module1->SetSendingStatus(true));
// Start basic RTP test.
// Send an empty RTP packet.
// Should fail since we have not registerd the payload type.
EXPECT_EQ(-1, module1->SendOutgoingData(webrtc::kAudioFrameSpeech,
96, 0, NULL, 0));
CodecInst voiceCodec;
voiceCodec.pltype = 96;
voiceCodec.plfreq = 8000;
memcpy(voiceCodec.plname, "PCMU", 5);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
voiceCodec.rate = test_rate;
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
printf("4\n");
const WebRtc_UWord8 test[5] = "test";
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96,
0, test, 4));
EXPECT_EQ(test_ssrc, module2->RemoteSSRC());
EXPECT_EQ(test_timestamp, module2->RemoteTimestamp());
}
TEST_F(RtpRtcpAudioTest, RED) {
CodecInst voiceCodec;
voiceCodec.pltype = 96;
voiceCodec.plfreq = 8000;
memcpy(voiceCodec.plname, "PCMU", 5);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
voiceCodec.rate = test_rate;
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
EXPECT_EQ(0, module1->SetSendingStatus(true));
voiceCodec.pltype = 127;
voiceCodec.plfreq = 8000;
memcpy(voiceCodec.plname, "RED", 4);
EXPECT_EQ(0, module1->SetSendREDPayloadType(voiceCodec.pltype));
WebRtc_Word8 red = 0;
EXPECT_EQ(0, module1->SendREDPayloadType(red));
EXPECT_EQ(voiceCodec.pltype, red);
EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
RTPFragmentationHeader fragmentation;
fragmentation.fragmentationVectorSize = 2;
fragmentation.fragmentationLength = new WebRtc_UWord32[2];
fragmentation.fragmentationLength[0] = 4;
fragmentation.fragmentationLength[1] = 4;
fragmentation.fragmentationOffset = new WebRtc_UWord32[2];
fragmentation.fragmentationOffset[0] = 0;
fragmentation.fragmentationOffset[1] = 4;
fragmentation.fragmentationTimeDiff = new WebRtc_UWord16[2];
fragmentation.fragmentationTimeDiff[0] = 0;
fragmentation.fragmentationTimeDiff[1] = 0;
fragmentation.fragmentationPlType = new WebRtc_UWord8[2];
fragmentation.fragmentationPlType[0] = 96;
fragmentation.fragmentationPlType[1] = 96;
const WebRtc_UWord8 test[5] = "test";
// Send a RTP packet.
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech,
96, 160, test, 4,
&fragmentation));
EXPECT_EQ(0, module1->SetSendREDPayloadType(-1));
EXPECT_EQ(-1, module1->SendREDPayloadType(red));
}
TEST_F(RtpRtcpAudioTest, DTMF) {
CodecInst voiceCodec;
voiceCodec.pltype = 96;
voiceCodec.plfreq = 8000;
memcpy(voiceCodec.plname, "PCMU", 5);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
voiceCodec.rate = test_rate;
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
EXPECT_EQ(0, module1->SetSendingStatus(true));
AudioFeedback* audioFeedback = new AudioFeedback();
EXPECT_EQ(0, module2->RegisterAudioCallback(audioFeedback));
// Prepare for DTMF.
voiceCodec.pltype = 97;
voiceCodec.plfreq = 8000;
memcpy(voiceCodec.plname, "telephone-event", 16);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
// Start DTMF test.
WebRtc_UWord32 timeStamp = 160;
// Send a DTMF tone using RFC 2833 (4733).
for (int i = 0; i < 16; i++) {
EXPECT_EQ(0, module1->SendTelephoneEventOutband(i, timeStamp, 10));
}
timeStamp += 160; // Prepare for next packet.
const WebRtc_UWord8 test[9] = "test";
// Send RTP packets for 16 tones a 160 ms 100ms
// pause between = 2560ms + 1600ms = 4160ms
for (;timeStamp <= 250 * 160; timeStamp += 160) {
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96,
timeStamp, test, 4));
fake_clock.IncrementTime(20);
module1->Process();
}
EXPECT_EQ(0, module1->SendTelephoneEventOutband(32, 9000, 10));
for (;timeStamp <= 740 * 160; timeStamp += 160) {
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96,
timeStamp, test, 4));
fake_clock.IncrementTime(20);
module1->Process();
}
delete audioFeedback;
}
TEST_F(RtpRtcpAudioTest, Stereo) {
CodecInst voiceCodec;
voiceCodec.pltype = 96;
voiceCodec.plfreq = 8000;
memcpy(voiceCodec.plname, "PCMU", 5);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
voiceCodec.rate = test_rate;
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
EXPECT_EQ(0, module1->SetSendingStatus(true));
// Prepare for 3 channel audio 8 bits per sample.
voiceCodec.pltype = 98;
voiceCodec.channels = 3;
memcpy(voiceCodec.plname, "PCMA", 5);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
// Prepare for 3 channel audio 16 bits per sample.
voiceCodec.pltype = 99;
memcpy(voiceCodec.plname, "L16", 4);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
// Prepare for 3 channel audio 5 bits per sample.
voiceCodec.pltype = 100;
memcpy(voiceCodec.plname, "G726-40",8);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
// Prepare for 3 channel audio 3 bits per sample.
voiceCodec.pltype = 101;
memcpy(voiceCodec.plname, "G726-24",8);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
// Prepare for 3 channel audio 2 bits per sample.
voiceCodec.pltype = 102;
memcpy(voiceCodec.plname, "G726-16",8);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
// Test sample based multi channel codec, 3 channels 8 bits.
WebRtc_UWord8 test3channels[13] = "ttteeesssttt";
WebRtc_UWord32 timeStamp = 160;
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 98,
timeStamp, test3channels, 12));
fake_clock.IncrementTime(20);
module1->Process();
timeStamp += 160; // Prepare for next packet.
// Test sample based multi channel codec, 3 channels 16 bits.
const WebRtc_UWord8 test3channels16[13] = "teteteststst";
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 99,
timeStamp, test3channels16, 12));
fake_clock.IncrementTime(20);
module1->Process();
timeStamp += 160; // Prepare for next packet.
// Test sample based multi channel codec, 3 channels 5 bits.
test3channels[0] = 0xf8; // 5 ones 3 zeros.
test3channels[1] = 0x2b; // 2 zeros 5 10 1 one.
test3channels[2] = 0xf0; // 4 ones 4 zeros.
test3channels[3] = 0x2b; // 1 zero 5 01 2 ones.
test3channels[4] = 0xe0; // 3 ones 5 zeros.
test3channels[5] = 0x0;
test3channels[6] = 0x0;
test3channels[7] = 0x0;
test3channels[8] = 0x0;
test3channels[9] = 0x0;
test3channels[10] = 0x0;
test3channels[11] = 0x0;
test3channels[12] = 0x0;
test3channels[13] = 0x0;
test3channels[14] = 0x0;
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 100,
timeStamp, test3channels, 15));
fake_clock.IncrementTime(20);
module1->Process();
timeStamp += 160; // Prepare for next packet.
// Test sample based multi channel codec, 3 channels 3 bits.
test3channels[0] = 0xe2; // 3 ones 3 zeros 2 10
test3channels[1] = 0xf0; // 1 1 3 ones 3 zeros 1 0
test3channels[2] = 0xb8; // 2 10 3 ones 3 zeros
test3channels[3] = 0xa0; // 3 101 5 zeros
test3channels[4] = 0x0;
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 101,
timeStamp, test3channels, 15));
fake_clock.IncrementTime(20);
module1->Process();
timeStamp += 160; // Prepare for next packet.
// Test sample based multi channel codec, 3 channels 2 bits.
test3channels[0] = 0xcb; // 2 ones 2 zeros 2 10 2 ones
test3channels[1] = 0x2c; // 2 zeros 2 10 2 ones 2 zeros
test3channels[2] = 0xb2; // 2 10 2 ones 2 zeros 2 10
test3channels[3] = 0xcb; // 2 ones 2 zeros 2 10 2 ones
test3channels[4] = 0x2c; // 2 zeros 2 10 2 ones 2 zeros
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 102,
timeStamp, test3channels, 15));
}

View File

@ -0,0 +1,249 @@
/*
* 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 <algorithm>
#include <vector>
#include <gtest/gtest.h>
#include "test_api.h"
#include "common_types.h"
#include "rtp_rtcp.h"
#include "rtp_rtcp_defines.h"
using namespace webrtc;
const int kVideoNackListSize = 10;
const int kTestId = 123;
const WebRtc_UWord32 kTestSsrc = 3456;
const WebRtc_UWord16 kTestSequenceNumber = 2345;
const WebRtc_UWord32 kTestNumberOfPackets = 450;
const int kTestNumberOfRtxPackets = 49;
class VerifyingNackReceiver : public RtpData
{
public:
VerifyingNackReceiver() {}
virtual WebRtc_Word32 OnReceivedPayloadData(
const WebRtc_UWord8* data,
const WebRtc_UWord16 size,
const webrtc::WebRtcRTPHeader* rtp_header) {
EXPECT_EQ(kTestSsrc, rtp_header->header.ssrc);
EXPECT_EQ(find(sequence_numbers_.begin(),
sequence_numbers_.end(),
rtp_header->header.sequenceNumber),
sequence_numbers_.end());
sequence_numbers_.push_back(rtp_header->header.sequenceNumber);
return 0;
}
std::vector<WebRtc_UWord16 > sequence_numbers_;
};
class NackLoopBackTransport : public webrtc::Transport {
public:
NackLoopBackTransport(RtpRtcp* rtp_rtcp_module, uint32_t rtx_ssrc)
: count_(0),
packet_loss_(0),
rtx_ssrc_(rtx_ssrc),
count_rtx_ssrc_(0),
module_(rtp_rtcp_module) {
}
void DropEveryNthPacket(int n) {
packet_loss_ = n;
}
virtual int SendPacket(int channel, const void *data, int len) {
count_++;
const unsigned char* ptr = static_cast<const unsigned char*>(data);
uint32_t ssrc = (ptr[8] << 24) + (ptr[9] << 16) + (ptr[10] << 8) + ptr[11];
if (ssrc == rtx_ssrc_) count_rtx_ssrc_++;
if (packet_loss_ > 0) {
if ((count_ % packet_loss_) == 0) {
return len;
}
}
if (module_->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) {
return len;
}
return -1;
}
virtual int SendRTCPPacket(int channel, const void *data, int len) {
if (module_->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) {
return len;
}
return -1;
}
int count_;
int packet_loss_;
uint32_t rtx_ssrc_;
int count_rtx_ssrc_;
RtpRtcp* module_;
};
class RtpRtcpNackTest : public ::testing::Test {
protected:
RtpRtcpNackTest() {}
~RtpRtcpNackTest() {}
virtual void SetUp() {
video_module_ = RtpRtcp::CreateRtpRtcp(kTestId, false, &fake_clock);
EXPECT_EQ(0, video_module_->InitReceiver());
EXPECT_EQ(0, video_module_->InitSender());
EXPECT_EQ(0, video_module_->SetRTCPStatus(kRtcpCompound));
EXPECT_EQ(0, video_module_->SetSSRC(kTestSsrc));
EXPECT_EQ(0, video_module_->SetNACKStatus(kNackRtcp));
EXPECT_EQ(0, video_module_->SetStorePacketsStatus(true));
EXPECT_EQ(0, video_module_->SetSendingStatus(true));
EXPECT_EQ(0, video_module_->SetSequenceNumber(kTestSequenceNumber));
EXPECT_EQ(0, video_module_->SetStartTimestamp(111111));
transport_ = new NackLoopBackTransport(video_module_, kTestSsrc + 1);
EXPECT_EQ(0, video_module_->RegisterSendTransport(transport_));
nack_receiver_ = new VerifyingNackReceiver();
EXPECT_EQ(0, video_module_->RegisterIncomingDataCallback(nack_receiver_));
VideoCodec video_codec;
memset(&video_codec, 0, sizeof(video_codec));
video_codec.plType = 123;
memcpy(video_codec.plName, "I420", 5);
EXPECT_EQ(0, video_module_->RegisterSendPayload(video_codec));
EXPECT_EQ(0, video_module_->RegisterReceivePayload(video_codec));
payload_data_length = sizeof(payload_data);
for (int n = 0; n < payload_data_length; n++) {
payload_data[n] = n % 10;
}
}
virtual void TearDown() {
RtpRtcp::DestroyRtpRtcp(video_module_);
delete transport_;
delete nack_receiver_;
}
RtpRtcp* video_module_;
NackLoopBackTransport* transport_;
VerifyingNackReceiver* nack_receiver_;
WebRtc_UWord8 payload_data[65000];
int payload_data_length;
FakeRtpRtcpClock fake_clock;
};
TEST_F(RtpRtcpNackTest, RTCP) {
WebRtc_UWord32 timestamp = 3000;
WebRtc_UWord16 nack_list[kVideoNackListSize];
transport_->DropEveryNthPacket(10);
for (int frame = 0; frame < 10; ++frame) {
EXPECT_EQ(0, video_module_->SendOutgoingData(webrtc::kVideoFrameDelta, 123,
timestamp,
payload_data,
payload_data_length));
std::sort(nack_receiver_->sequence_numbers_.begin(),
nack_receiver_->sequence_numbers_.end());
std::vector<WebRtc_UWord16> missing_sequence_numbers;
std::vector<WebRtc_UWord16>::iterator it =
nack_receiver_->sequence_numbers_.begin();
while (it != nack_receiver_->sequence_numbers_.end()) {
WebRtc_UWord16 sequence_number_1 = *it;
++it;
if (it != nack_receiver_->sequence_numbers_.end()) {
WebRtc_UWord16 sequence_number_2 = *it;
// Add all missing sequence numbers to list
for (WebRtc_UWord16 i = sequence_number_1 + 1; i < sequence_number_2;
++i) {
missing_sequence_numbers.push_back(i);
}
}
}
int n = 0;
for (it = missing_sequence_numbers.begin();
it != missing_sequence_numbers.end(); ++it) {
nack_list[n++] = (*it);
}
video_module_->SendNACK(nack_list, n);
fake_clock.IncrementTime(33);
video_module_->Process();
// Prepare next frame.
timestamp += 3000;
}
std::sort(nack_receiver_->sequence_numbers_.begin(),
nack_receiver_->sequence_numbers_.end());
EXPECT_EQ(kTestSequenceNumber, *(nack_receiver_->sequence_numbers_.begin()));
EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
*(nack_receiver_->sequence_numbers_.rbegin()));
EXPECT_EQ(kTestNumberOfPackets, nack_receiver_->sequence_numbers_.size());
EXPECT_EQ(0, transport_->count_rtx_ssrc_);
}
TEST_F(RtpRtcpNackTest, RTX) {
EXPECT_EQ(0, video_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
EXPECT_EQ(0, video_module_->SetRTXSendStatus(true, true, kTestSsrc + 1));
transport_->DropEveryNthPacket(10);
WebRtc_UWord32 timestamp = 3000;
WebRtc_UWord16 nack_list[kVideoNackListSize];
for (int frame = 0; frame < 10; ++frame) {
EXPECT_EQ(0, video_module_->SendOutgoingData(webrtc::kVideoFrameDelta, 123,
timestamp,
payload_data,
payload_data_length));
std::sort(nack_receiver_->sequence_numbers_.begin(),
nack_receiver_->sequence_numbers_.end());
std::vector<WebRtc_UWord16> missing_sequence_numbers;
std::vector<WebRtc_UWord16>::iterator it =
nack_receiver_->sequence_numbers_.begin();
while (it != nack_receiver_->sequence_numbers_.end()) {
int sequence_number_1 = *it;
++it;
if (it != nack_receiver_->sequence_numbers_.end()) {
int sequence_number_2 = *it;
// Add all missing sequence numbers to list.
for (int i = sequence_number_1 + 1; i < sequence_number_2; ++i) {
missing_sequence_numbers.push_back(i);
}
}
}
int n = 0;
for (it = missing_sequence_numbers.begin();
it != missing_sequence_numbers.end(); ++it) {
nack_list[n++] = (*it);
}
video_module_->SendNACK(nack_list, n);
fake_clock.IncrementTime(33);
video_module_->Process();
// Prepare next frame.
timestamp += 3000;
}
std::sort(nack_receiver_->sequence_numbers_.begin(),
nack_receiver_->sequence_numbers_.end());
EXPECT_EQ(kTestSequenceNumber, *(nack_receiver_->sequence_numbers_.begin()));
EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
*(nack_receiver_->sequence_numbers_.rbegin()));
EXPECT_EQ(kTestNumberOfPackets, nack_receiver_->sequence_numbers_.size());
EXPECT_EQ(kTestNumberOfRtxPackets, transport_->count_rtx_ssrc_);
}

View File

@ -0,0 +1,297 @@
/*
* 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 <algorithm>
#include <vector>
#include <gtest/gtest.h>
#include "test_api.h"
#include "common_types.h"
#include "rtp_rtcp.h"
#include "rtp_rtcp_defines.h"
using namespace webrtc;
const WebRtc_UWord64 kTestPictureId = 12345678;
class RtcpCallback : public RtcpFeedback {
public:
RtcpCallback(RtpRtcp* module) {
_rtpRtcpModule = module;
};
virtual void OnRTCPPacketTimeout(const WebRtc_Word32 id) {
}
virtual void OnLipSyncUpdate(const WebRtc_Word32 id,
const WebRtc_Word32 audioVideoOffset) {
};
virtual void OnTMMBRReceived(const WebRtc_Word32 id,
const WebRtc_UWord16 bwEstimateKbit) {
};
virtual void OnXRVoIPMetricReceived(
const WebRtc_Word32 id,
const RTCPVoIPMetric* metric,
const WebRtc_Word8 VoIPmetricBuffer[28]) {
};
virtual void OnSLIReceived(const WebRtc_Word32 id,
const WebRtc_UWord8 pictureId) {
EXPECT_EQ(28, pictureId);
};
virtual void OnRPSIReceived(const WebRtc_Word32 id,
const WebRtc_UWord64 pictureId) {
EXPECT_EQ(kTestPictureId, pictureId);
};
virtual void OnApplicationDataReceived(const WebRtc_Word32 id,
const WebRtc_UWord8 subType,
const WebRtc_UWord32 name,
const WebRtc_UWord16 length,
const WebRtc_UWord8* data) {
char print_name[5];
print_name[0] = static_cast<char>(name >> 24);
print_name[1] = static_cast<char>(name >> 16);
print_name[2] = static_cast<char>(name >> 8);
print_name[3] = static_cast<char>(name);
print_name[4] = 0;
EXPECT_STRCASEEQ("test", print_name);
};
virtual void OnSendReportReceived(const WebRtc_Word32 id,
const WebRtc_UWord32 senderSSRC) {
RTCPSenderInfo senderInfo;
EXPECT_EQ(0, _rtpRtcpModule->RemoteRTCPStat(&senderInfo));
};
virtual void OnReceiveReportReceived(const WebRtc_Word32 id,
const WebRtc_UWord32 senderSSRC) {
};
private:
RtpRtcp* _rtpRtcpModule;
};
class RtpRtcpRtcpTest : public ::testing::Test {
protected:
RtpRtcpRtcpTest() {
test_CSRC[0] = 1234;
test_CSRC[2] = 2345;
test_id = 123;
test_ssrc = 3456;
test_timestamp = 4567;
test_sequence_number = 2345;
}
~RtpRtcpRtcpTest() {}
virtual void SetUp() {
module1 = RtpRtcp::CreateRtpRtcp(test_id, true, &fake_clock);
module2 = RtpRtcp::CreateRtpRtcp(test_id+1, true, &fake_clock);
EXPECT_EQ(0, module1->InitReceiver());
EXPECT_EQ(0, module1->InitSender());
EXPECT_EQ(0, module2->InitReceiver());
EXPECT_EQ(0, module2->InitSender());
receiver = new RtpReceiver();
EXPECT_EQ(0, module2->RegisterIncomingDataCallback(receiver));
transport1 = new LoopBackTransport(module2);
EXPECT_EQ(0, module1->RegisterSendTransport(transport1));
transport2 = new LoopBackTransport(module1);
EXPECT_EQ(0, module2->RegisterSendTransport(transport2));
}
virtual void TearDown() {
RtpRtcp::DestroyRtpRtcp(module1);
RtpRtcp::DestroyRtpRtcp(module2);
delete transport1;
delete transport2;
delete receiver;
}
int test_id;
RtpRtcp* module1;
RtpRtcp* module2;
RtpReceiver* receiver;
LoopBackTransport* transport1;
LoopBackTransport* transport2;
WebRtc_UWord32 test_ssrc;
WebRtc_UWord32 test_timestamp;
WebRtc_UWord16 test_sequence_number;
WebRtc_UWord32 test_CSRC[webrtc::kRtpCsrcSize];
FakeRtpRtcpClock fake_clock;
};
TEST_F(RtpRtcpRtcpTest, RTCP) {
RtcpCallback* myRTCPFeedback1 = new RtcpCallback(module1);
RtcpCallback* myRTCPFeedback2 = new RtcpCallback(module2);
EXPECT_EQ(0, module1->RegisterIncomingRTCPCallback(myRTCPFeedback1));
EXPECT_EQ(0, module2->RegisterIncomingRTCPCallback(myRTCPFeedback2));
EXPECT_EQ(0, module1->SetRTCPStatus(kRtcpCompound));
EXPECT_EQ(0, module2->SetRTCPStatus(kRtcpCompound));
EXPECT_EQ(0, module2->SetSSRC(test_ssrc + 1));
EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
EXPECT_EQ(0, module1->SetSequenceNumber(test_sequence_number));
EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
EXPECT_EQ(0, module1->SetCSRCs(test_CSRC, 2));
EXPECT_EQ(0, module1->SetCNAME("john.doe@test.test"));
EXPECT_EQ(0, module1->SetSendingStatus(true));
CodecInst voiceCodec;
voiceCodec.pltype = 96;
voiceCodec.plfreq = 8000;
voiceCodec.rate = 64000;
memcpy(voiceCodec.plname, "PCMU", 5);
EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
// We need to send one RTP packet to get the RTCP packet to be accepted by
// the receiving module.
// send RTP packet with the data "testtest"
const WebRtc_UWord8 test[9] = "testtest";
EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96,
0, test, 8));
EXPECT_EQ(0, module1->SendRTCPReferencePictureSelection(kTestPictureId));
EXPECT_EQ(0, module1->SendRTCPSliceLossIndication(156));
WebRtc_UWord32 testOfCSRC[webrtc::kRtpCsrcSize];
EXPECT_EQ(2, module2->RemoteCSRCs(testOfCSRC));
EXPECT_EQ(test_CSRC[0], testOfCSRC[0]);
EXPECT_EQ(test_CSRC[1], testOfCSRC[1]);
// Set cname of mixed.
EXPECT_EQ(0, module1->AddMixedCNAME(test_CSRC[0], "john@192.168.0.1"));
EXPECT_EQ(0, module1->AddMixedCNAME(test_CSRC[1], "jane@192.168.0.2"));
EXPECT_EQ(-1, module1->AddMixedCNAME(test_CSRC[0], NULL));
EXPECT_EQ(-1, module1->RemoveMixedCNAME(test_CSRC[0] + 1));
EXPECT_EQ(0, module1->RemoveMixedCNAME(test_CSRC[1]));
EXPECT_EQ(0, module1->AddMixedCNAME(test_CSRC[1], "jane@192.168.0.2"));
RTCPReportBlock reportBlock;
reportBlock.cumulativeLost = 1;
reportBlock.delaySinceLastSR = 2;
reportBlock.extendedHighSeqNum = 3;
reportBlock.fractionLost= 4;
reportBlock.jitter = 5;
reportBlock.lastSR = 6;
// Set report blocks.
EXPECT_EQ(-1, module1->AddRTCPReportBlock(test_CSRC[0], NULL));
EXPECT_EQ(0, module1->AddRTCPReportBlock(test_CSRC[0], &reportBlock));
reportBlock.lastSR= 7;
EXPECT_EQ(0, module1->AddRTCPReportBlock(test_CSRC[1], &reportBlock));
WebRtc_UWord32 name = 't' << 24;
name += 'e' << 16;
name += 's' << 8;
name += 't';
EXPECT_EQ(0, module1->SetRTCPApplicationSpecificData(
3,
name,
(const WebRtc_UWord8 *)"test test test test test test test test test"\
" test test test test test test test test test test test test test"\
" test test test test test test test test test test test test test"\
" test test test test test test test test test test test test test"\
" test test test test test test test test test test test test ",
300));
// send RTCP packet, triggered by timer
fake_clock.IncrementTime(7500);
module1->Process();
fake_clock.IncrementTime(100);
module2->Process();
WebRtc_UWord32 receivedNTPsecs = 0;
WebRtc_UWord32 receivedNTPfrac = 0;
WebRtc_UWord32 RTCPArrivalTimeSecs = 0;
WebRtc_UWord32 RTCPArrivalTimeFrac = 0;
WebRtc_Word8 cName[RTCP_CNAME_SIZE];
EXPECT_EQ(0, module2->RemoteNTP(&receivedNTPsecs, &receivedNTPfrac,
&RTCPArrivalTimeSecs, &RTCPArrivalTimeFrac));
EXPECT_EQ(-1, module2->RemoteCNAME(module2->RemoteSSRC() + 1, cName));
EXPECT_EQ(-1, module2->RemoteCNAME(module2->RemoteSSRC(), NULL));
// Check multiple CNAME.
EXPECT_EQ(0, module2->RemoteCNAME(module2->RemoteSSRC(), cName));
EXPECT_EQ(0, strncmp(cName, "john.doe@test.test", RTCP_CNAME_SIZE));
EXPECT_EQ(0, module2->RemoteCNAME(test_CSRC[0], cName));
EXPECT_EQ(0, strncmp(cName, "john@192.168.0.1", RTCP_CNAME_SIZE));
EXPECT_EQ(0, module2->RemoteCNAME(test_CSRC[1], cName));
EXPECT_EQ(0, strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE));
// get all report blocks
RTCPReportBlock reportBlockReceived;
EXPECT_EQ(-1, module1->RemoteRTCPStat(test_ssrc, &reportBlockReceived));
EXPECT_EQ(-1, module1->RemoteRTCPStat(test_ssrc + 1, NULL));
EXPECT_EQ(0, module1->RemoteRTCPStat(test_ssrc + 1, &reportBlockReceived));
float secSinceLastReport =
static_cast<float>(reportBlockReceived.delaySinceLastSR) / 65536.0f;
EXPECT_GE(0.101f, secSinceLastReport);
EXPECT_LE(0.100f, secSinceLastReport);
EXPECT_EQ(test_sequence_number, reportBlockReceived.extendedHighSeqNum);
EXPECT_EQ(0, reportBlockReceived.fractionLost);
EXPECT_EQ(static_cast<WebRtc_UWord32>(0),
reportBlockReceived.cumulativeLost);
WebRtc_UWord8 fraction_lost = 0; // scale 0 to 255
WebRtc_UWord32 cum_lost = 0; // number of lost packets
WebRtc_UWord32 ext_max = 0; // highest sequence number received
WebRtc_UWord32 jitter = 0;
WebRtc_UWord32 max_jitter = 0;
EXPECT_EQ(0, module2->StatisticsRTP(&fraction_lost,
&cum_lost,
&ext_max,
&jitter,
&max_jitter));
EXPECT_EQ(0, fraction_lost);
EXPECT_EQ((WebRtc_UWord32)0, cum_lost);
EXPECT_EQ(test_sequence_number, ext_max);
EXPECT_EQ(reportBlockReceived.jitter, jitter);
WebRtc_UWord16 RTT;
WebRtc_UWord16 avgRTT;
WebRtc_UWord16 minRTT;
WebRtc_UWord16 maxRTT;
// Get RoundTripTime.
EXPECT_EQ(0, module1->RTT(test_ssrc + 1, &RTT, &avgRTT, &minRTT, &maxRTT));
EXPECT_GE(10, RTT);
EXPECT_GE(10, avgRTT);
EXPECT_GE(10, minRTT);
EXPECT_GE(10, maxRTT);
// Set report blocks.
EXPECT_EQ(0, module1->AddRTCPReportBlock(test_CSRC[0], &reportBlock));
// Test receive report.
EXPECT_EQ(0, module1->SetSendingStatus(false));
// Test that BYE clears the CNAME
EXPECT_EQ(-1, module2->RemoteCNAME(module2->RemoteSSRC(), cName));
// Send RTCP packet, triggered by timer.
fake_clock.IncrementTime(5000);
module1->Process();
module2->Process();
delete myRTCPFeedback1;
delete myRTCPFeedback2;
}

View File

@ -0,0 +1,90 @@
/*
* 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 <algorithm>
#include <vector>
#include <gtest/gtest.h>
#include "test_api.h"
#include "common_types.h"
#include "rtp_rtcp.h"
#include "rtp_rtcp_defines.h"
using namespace webrtc;
class RtpRtcpVideoTest : public ::testing::Test {
protected:
RtpRtcpVideoTest() {
test_id = 123;
test_ssrc = 3456;
test_timestamp = 4567;
test_sequence_number = 2345;
}
~RtpRtcpVideoTest() {}
virtual void SetUp() {
video_module = RtpRtcp::CreateRtpRtcp(test_id, false, &fake_clock);
EXPECT_EQ(0, video_module->InitReceiver());
EXPECT_EQ(0, video_module->InitSender());
EXPECT_EQ(0, video_module->SetRTCPStatus(kRtcpCompound));
EXPECT_EQ(0, video_module->SetSSRC(test_ssrc));
EXPECT_EQ(0, video_module->SetNACKStatus(kNackRtcp));
EXPECT_EQ(0, video_module->SetStorePacketsStatus(true));
EXPECT_EQ(0, video_module->SetSendingStatus(true));
transport = new LoopBackTransport(video_module);
EXPECT_EQ(0, video_module->RegisterSendTransport(transport));
receiver = new RtpReceiver();
EXPECT_EQ(0, video_module->RegisterIncomingDataCallback(receiver));
VideoCodec video_codec;
memset(&video_codec, 0, sizeof(video_codec));
video_codec.plType = 123;
memcpy(video_codec.plName, "I420", 5);
EXPECT_EQ(0, video_module->RegisterSendPayload(video_codec));
EXPECT_EQ(0, video_module->RegisterReceivePayload(video_codec));
payload_data_length = sizeof(payload_data);
for (int n = 0; n < payload_data_length; n++) {
payload_data[n] = n%10;
}
}
virtual void TearDown() {
RtpRtcp::DestroyRtpRtcp(video_module);
delete transport;
delete receiver;
}
int test_id;
RtpRtcp* video_module;
LoopBackTransport* transport;
RtpReceiver* receiver;
WebRtc_UWord32 test_ssrc;
WebRtc_UWord32 test_timestamp;
WebRtc_UWord16 test_sequence_number;
WebRtc_UWord8 payload_data[65000];
int payload_data_length;
FakeRtpRtcpClock fake_clock;
};
TEST_F(RtpRtcpVideoTest, BasicVideo) {
WebRtc_UWord32 timestamp = 3000;
EXPECT_EQ(0, video_module->SendOutgoingData(webrtc::kVideoFrameDelta, 123,
timestamp,
payload_data,
payload_data_length));
}

View File

@ -731,26 +731,40 @@ WebRtc_Word32 ViEChannel::EnableKeyFrameRequestCallback(const bool enable) {
}
WebRtc_Word32 ViEChannel::SetSSRC(const WebRtc_UWord32 SSRC,
const StreamType /*usage*/,
const unsigned char simulcast_idx) {
// TODO(pwestin) add support for stream_type when we add RTX.
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
"%s(SSRC: %u, idx:%u)", __FUNCTION__, SSRC, simulcast_idx);
const StreamType usage,
const uint8_t simulcast_idx) {
WEBRTC_TRACE(webrtc::kTraceInfo,
webrtc::kTraceVideo,
ViEId(engine_id_, channel_id_),
"%s(usage:%d, SSRC: 0x%x, idx:%u)",
__FUNCTION__, usage, SSRC, simulcast_idx);
if (simulcast_idx == 0) {
return rtp_rtcp_.SetSSRC(SSRC);
}
std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
for (int i = 1; i < simulcast_idx; i++) {
it++;
if (it == simulcast_rtp_rtcp_.end()) {
for (int i = 1; i < simulcast_idx; ++i, ++it) {
if (it == simulcast_rtp_rtcp_.end()) {
return -1;
}
}
RtpRtcp* rtp_rtcp = *it;
if (usage == kViEStreamTypeRtx) {
return rtp_rtcp->SetRTXSendStatus(true, true, SSRC);
}
return rtp_rtcp->SetSSRC(SSRC);
}
WebRtc_Word32 ViEChannel::SetRemoteSSRCType(const StreamType usage,
const uint32_t SSRC) const {
WEBRTC_TRACE(webrtc::kTraceInfo,
webrtc::kTraceVideo,
ViEId(engine_id_, channel_id_),
"%s(usage:%d, SSRC: 0x%x)",
__FUNCTION__, usage, SSRC);
return rtp_rtcp_.SetRTXReceiveStatus(true, SSRC);
}
WebRtc_Word32 ViEChannel::GetLocalSSRC(WebRtc_UWord32& SSRC) {
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
"%s", __FUNCTION__);

View File

@ -221,6 +221,8 @@ class ViEChannel
WebRtc_Word8* ip_address,
WebRtc_UWord32 ip_address_length);
WebRtc_Word32 SetRemoteSSRCType(const StreamType usage,
const uint32_t SSRC) const;
WebRtc_Word32 StartSend();
WebRtc_Word32 StopSend();

View File

@ -144,6 +144,33 @@ int ViERTP_RTCPImpl::SetLocalSSRC(const int video_channel,
return 0;
}
int ViERTP_RTCPImpl::SetRemoteSSRCType(const int videoChannel,
const StreamType usage,
const unsigned int SSRC) const {
WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
ViEId(instance_id_, videoChannel),
"%s(channel: %d, usage:%d SSRC: 0x%x)",
__FUNCTION__, usage, videoChannel, SSRC);
// Get the channel
ViEChannelManagerScoped cs(channel_manager_);
ViEChannel* ptrViEChannel = cs.Channel(videoChannel);
if (ptrViEChannel == NULL) {
// The channel doesn't exists
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
ViEId(instance_id_, videoChannel),
"%s: Channel %d doesn't exist",
__FUNCTION__, videoChannel);
SetLastError(kViERtpRtcpInvalidChannelId);
return -1;
}
if (ptrViEChannel->SetRemoteSSRCType(usage, SSRC) != 0) {
SetLastError(kViERtpRtcpUnknownError);
return -1;
}
return 0;
}
int ViERTP_RTCPImpl::GetLocalSSRC(const int video_channel,
unsigned int& SSRC) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_, video_channel),
@ -163,13 +190,6 @@ int ViERTP_RTCPImpl::GetLocalSSRC(const int video_channel,
return 0;
}
int ViERTP_RTCPImpl::SetRemoteSSRCType(const int video_channel,
const StreamType usage,
const unsigned int SSRC) const {
// TODO(pwestin) add support for RTX.
return -1;
}
int ViERTP_RTCPImpl::GetRemoteSSRC(const int video_channel,
unsigned int& SSRC) const {
WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_, video_channel),