"ViE GetSentRTCPStatistics fails on a sending channel if it don't receive rtp video packets.

BUG=222
TEST= tested in loopback. No new test added yet.

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1387 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
perkj@webrtc.org 2012-01-11 13:00:08 +00:00
parent 01530a2ac2
commit ce5990cb0b
10 changed files with 319 additions and 274 deletions

View File

@ -11,6 +11,8 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_H_ #ifndef WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_H_
#define WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_H_ #define WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_H_
#include <vector>
#include "module.h" #include "module.h"
#include "rtp_rtcp_defines.h" #include "rtp_rtcp_defines.h"
@ -740,22 +742,23 @@ public:
* *
* return -1 on failure else 0 * return -1 on failure else 0
*/ */
virtual WebRtc_Word32 RemoteRTCPStat( RTCPSenderInfo* senderInfo) = 0; virtual WebRtc_Word32 RemoteRTCPStat(RTCPSenderInfo* senderInfo) = 0;
/* /*
* Get received RTCP report block * Get received RTCP report block
* *
* return -1 on failure else 0 * return -1 on failure else 0
*/ */
virtual WebRtc_Word32 RemoteRTCPStat( const WebRtc_UWord32 remoteSSRC, virtual WebRtc_Word32 RemoteRTCPStat(
RTCPReportBlock* receiveBlock) = 0; std::vector<RTCPReportBlock>* receiveBlocks) const = 0;
/* /*
* Set received RTCP report block * Set received RTCP report block
* *
* return -1 on failure else 0 * return -1 on failure else 0
*/ */
virtual WebRtc_Word32 AddRTCPReportBlock(const WebRtc_UWord32 SSRC, virtual WebRtc_Word32 AddRTCPReportBlock(
const RTCPReportBlock* receiveBlock) = 0; const WebRtc_UWord32 SSRC,
const RTCPReportBlock* receiveBlock) = 0;
/* /*
* RemoveRTCPReportBlock * RemoveRTCPReportBlock

View File

@ -109,6 +109,9 @@ struct RTCPSenderInfo
struct RTCPReportBlock struct RTCPReportBlock
{ {
// Fields as described by RFC 3550 6.4.2.
WebRtc_UWord32 remoteSSRC; // SSRC of sender of this report.
WebRtc_UWord32 sourceSSRC; // SSRC of the RTP packet sender.
WebRtc_UWord8 fractionLost; WebRtc_UWord8 fractionLost;
WebRtc_UWord32 cumulativeLost; // 24 bits valid WebRtc_UWord32 cumulativeLost; // 24 bits valid
WebRtc_UWord32 extendedHighSeqNum; WebRtc_UWord32 extendedHighSeqNum;

View File

@ -170,8 +170,8 @@ class MockRtpRtcp : public RtpRtcp {
WebRtc_Word32(WebRtc_UWord32 *bytesSent, WebRtc_UWord32 *packetsSent, WebRtc_UWord32 *bytesReceived, WebRtc_UWord32 *packetsReceived)); WebRtc_Word32(WebRtc_UWord32 *bytesSent, WebRtc_UWord32 *packetsSent, WebRtc_UWord32 *bytesReceived, WebRtc_UWord32 *packetsReceived));
MOCK_METHOD1(RemoteRTCPStat, MOCK_METHOD1(RemoteRTCPStat,
WebRtc_Word32(RTCPSenderInfo* senderInfo)); WebRtc_Word32(RTCPSenderInfo* senderInfo));
MOCK_METHOD2(RemoteRTCPStat, MOCK_CONST_METHOD1(RemoteRTCPStat,
WebRtc_Word32(const WebRtc_UWord32 remoteSSRC, RTCPReportBlock* receiveBlock)); WebRtc_Word32(std::vector<RTCPReportBlock>* receiveBlocks));
MOCK_METHOD2(AddRTCPReportBlock, MOCK_METHOD2(AddRTCPReportBlock,
WebRtc_Word32(const WebRtc_UWord32 SSRC, const RTCPReportBlock* receiveBlock)); WebRtc_Word32(const WebRtc_UWord32 SSRC, const RTCPReportBlock* receiveBlock));
MOCK_METHOD1(RemoveRTCPReportBlock, MOCK_METHOD1(RemoveRTCPReportBlock,

View File

@ -179,56 +179,52 @@ RTCPReceiver::SetSSRC( const WebRtc_UWord32 ssrc)
_SSRC = ssrc; _SSRC = ssrc;
} }
WebRtc_Word32 WebRtc_Word32 RTCPReceiver::ResetRTT(const WebRtc_UWord32 remoteSSRC) {
RTCPReceiver::ResetRTT(const WebRtc_UWord32 remoteSSRC) CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
{ RTCPReportBlockInformation* reportBlock =
CriticalSectionScoped lock(_criticalSectionRTCPReceiver); GetReportBlockInformation(remoteSSRC);
RTCPReportBlockInformation* reportBlock = GetReportBlockInformation(remoteSSRC); if (reportBlock == NULL) {
if(reportBlock == NULL) WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
{ "\tfailed to GetReportBlockInformation(%u)", remoteSSRC);
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "\tfailed to GetReportBlockInformation(%d)", remoteSSRC); return -1;
return -1; }
} reportBlock->RTT = 0;
reportBlock->RTT = 0; reportBlock->avgRTT = 0;
reportBlock->avgRTT = 0; reportBlock->minRTT = 0;
reportBlock->minRTT = 0; reportBlock->maxRTT = 0;
reportBlock->maxRTT = 0;
return 0; return 0;
} }
WebRtc_Word32 WebRtc_Word32 RTCPReceiver::RTT(const WebRtc_UWord32 remoteSSRC,
RTCPReceiver::RTT(const WebRtc_UWord32 remoteSSRC, WebRtc_UWord16* RTT,
WebRtc_UWord16* RTT, WebRtc_UWord16* avgRTT,
WebRtc_UWord16* avgRTT, WebRtc_UWord16* minRTT,
WebRtc_UWord16* minRTT, WebRtc_UWord16* maxRTT) const {
WebRtc_UWord16* maxRTT) const CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
{ RTCPReportBlockInformation* reportBlock =
CriticalSectionScoped lock(_criticalSectionRTCPReceiver); GetReportBlockInformation(remoteSSRC);
RTCPReportBlockInformation* reportBlock = GetReportBlockInformation(remoteSSRC);
if(reportBlock == NULL) if (reportBlock == NULL) {
{ WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "\tfailed to GetReportBlockInformation(%d)", remoteSSRC); "\tfailed to GetReportBlockInformation(%u)",
return -1; remoteSSRC);
} return -1;
if(RTT) }
{ if (RTT) {
*RTT = reportBlock->RTT; *RTT = reportBlock->RTT;
} }
if(avgRTT) if (avgRTT) {
{ *avgRTT = reportBlock->avgRTT;
*avgRTT = reportBlock->avgRTT; }
} if (minRTT) {
if(minRTT) *minRTT = reportBlock->minRTT;
{ }
*minRTT = reportBlock->minRTT; if (maxRTT) {
} *maxRTT = reportBlock->maxRTT;
if(maxRTT) }
{ return 0;
*maxRTT = reportBlock->maxRTT;
}
return 0;
} }
void void
@ -287,24 +283,25 @@ RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const
// statistics // statistics
// we can get multiple receive reports when we receive the report from a CE // we can get multiple receive reports when we receive the report from a CE
WebRtc_Word32 WebRtc_Word32 RTCPReceiver::StatisticsReceived(
RTCPReceiver::StatisticsReceived(const WebRtc_UWord32 remoteSSRC, std::vector<RTCPReportBlock>* receiveBlocks) const {
RTCPReportBlock* receiveBlock) const if (receiveBlocks == NULL) {
{ WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument",
if(receiveBlock == NULL) __FUNCTION__);
{ return -1;
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__); }
return -1; CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
}
CriticalSectionScoped lock(_criticalSectionRTCPReceiver); MapItem* ptrReportBlockInfoItem = _receivedReportBlockMap.First();
RTCPReportBlockInformation* reportBlockInfo = GetReportBlockInformation(remoteSSRC); while (ptrReportBlockInfoItem != NULL) {
if(reportBlockInfo == NULL) RTCPReportBlockInformation* item =
{ static_cast<RTCPReportBlockInformation*> (
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "\tfailed to GetReportBlockInformation(%d)", remoteSSRC); ptrReportBlockInfoItem->GetItem());
return -1; receiveBlocks->push_back(item->remoteReceiveBlock);
} ptrReportBlockInfoItem =
memcpy(receiveBlock, &(reportBlockInfo->remoteReceiveBlock), sizeof(RTCPReportBlock)); _receivedReportBlockMap.Next(ptrReportBlockInfoItem);
return 0; }
return 0;
} }
WebRtc_Word32 WebRtc_Word32
@ -459,135 +456,113 @@ void
RTCPReceiver::HandleReportBlock(const RTCPUtility::RTCPPacket& rtcpPacket, RTCPReceiver::HandleReportBlock(const RTCPUtility::RTCPPacket& rtcpPacket,
RTCPPacketInformation& rtcpPacketInformation, RTCPPacketInformation& rtcpPacketInformation,
const WebRtc_UWord32 remoteSSRC, const WebRtc_UWord32 remoteSSRC,
const WebRtc_UWord8 numberOfReportBlocks) const WebRtc_UWord8 numberOfReportBlocks) {
{ // This will be called once per report block in the RTCP packet.
// this will be called once per report block in the RTCP packet // We filter out all report blocks that are not for us.
// we store all incoming reports // Each packet has max 31 RR blocks.
// each packet has max 31 RR blocks //
// // We can calc RTT if we send a send report and get a report block back.
// we can calc RTT if we send a send report and get a report block back
/* // |rtcpPacket.ReportBlockItem.SSRC| is the SSRC identifier of the source to
rtcpPacket.ReportBlockItem.SSRC // which the information in this reception report block pertains.
The SSRC identifier of the source to which the information in this
reception report block pertains.
*/
// if we receive a RTCP packet with multiple reportBlocks only store the ones to us // Filter out all report blocks that are not for us.
if( _SSRC && if (rtcpPacket.ReportBlockItem.SSRC != _SSRC) {
numberOfReportBlocks > 1) // This block is not for us ignore it.
{ return;
// we have more than one reportBlock in the RTCP packet }
if(rtcpPacket.ReportBlockItem.SSRC != _SSRC)
{ // To avoid problem with acquiring _criticalSectionRTCPSender while holding
// this block is not for us ignore it // _criticalSectionRTCPReceiver.
return; _criticalSectionRTCPReceiver->Leave();
} WebRtc_UWord32 sendTimeMS =
_rtpRtcp.SendTimeOfSendReport(rtcpPacket.ReportBlockItem.LastSR);
_criticalSectionRTCPReceiver->Enter();
RTCPReportBlockInformation* reportBlock =
CreateReportBlockInformation(remoteSSRC);
if (reportBlock == NULL) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"\tfailed to CreateReportBlockInformation(%u)", remoteSSRC);
return;
}
const RTCPPacketReportBlockItem& rb = rtcpPacket.ReportBlockItem;
reportBlock->remoteReceiveBlock.remoteSSRC = remoteSSRC;
reportBlock->remoteReceiveBlock.sourceSSRC = rb.SSRC;
reportBlock->remoteReceiveBlock.fractionLost = rb.FractionLost;
reportBlock->remoteReceiveBlock.cumulativeLost =
rb.CumulativeNumOfPacketsLost;
reportBlock->remoteReceiveBlock.extendedHighSeqNum =
rb.ExtendedHighestSequenceNumber;
reportBlock->remoteReceiveBlock.jitter = rb.Jitter;
reportBlock->remoteReceiveBlock.delaySinceLastSR = rb.DelayLastSR;
reportBlock->remoteReceiveBlock.lastSR = rb.LastSR;
if (rtcpPacket.ReportBlockItem.Jitter > reportBlock->remoteMaxJitter) {
reportBlock->remoteMaxJitter = rtcpPacket.ReportBlockItem.Jitter;
}
WebRtc_UWord32 delaySinceLastSendReport =
rtcpPacket.ReportBlockItem.DelayLastSR;
// local NTP time when we received this
WebRtc_UWord32 lastReceivedRRNTPsecs = 0;
WebRtc_UWord32 lastReceivedRRNTPfrac = 0;
_clock.CurrentNTP(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
// time when we received this in MS
WebRtc_UWord32 receiveTimeMS = ModuleRTPUtility::ConvertNTPTimeToMS(
lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
// Estimate RTT
WebRtc_UWord32 d = (delaySinceLastSendReport & 0x0000ffff) * 1000;
d /= 65536;
d += ((delaySinceLastSendReport & 0xffff0000) >> 16) * 1000;
WebRtc_Word32 RTT = 0;
if (sendTimeMS > 0) {
RTT = receiveTimeMS - d - sendTimeMS;
if (RTT <= 0) {
RTT = 1;
} }
if (RTT > reportBlock->maxRTT) {
_criticalSectionRTCPReceiver->Leave(); // store max RTT
// to avoid problem with accuireing _criticalSectionRTCPSender while holding _criticalSectionRTCPReceiver reportBlock->maxRTT = (WebRtc_UWord16) RTT;
WebRtc_UWord32 sendTimeMS =
_rtpRtcp.SendTimeOfSendReport(rtcpPacket.ReportBlockItem.LastSR);
_criticalSectionRTCPReceiver->Enter();
// ReportBlockItem.SSRC is who it's to
// we store all incoming reports, used in conference relay
RTCPReportBlockInformation* reportBlock = CreateReportBlockInformation(remoteSSRC);
if(reportBlock == NULL)
{
return;
} }
if (reportBlock->minRTT == 0) {
reportBlock->remoteReceiveBlock.fractionLost = rtcpPacket.ReportBlockItem.FractionLost; // first RTT
reportBlock->remoteReceiveBlock.cumulativeLost = rtcpPacket.ReportBlockItem.CumulativeNumOfPacketsLost; reportBlock->minRTT = (WebRtc_UWord16) RTT;
reportBlock->remoteReceiveBlock.extendedHighSeqNum= rtcpPacket.ReportBlockItem.ExtendedHighestSequenceNumber; } else if (RTT < reportBlock->minRTT) {
reportBlock->remoteReceiveBlock.jitter = rtcpPacket.ReportBlockItem.Jitter; // Store min RTT
reportBlock->remoteReceiveBlock.delaySinceLastSR = rtcpPacket.ReportBlockItem.DelayLastSR; reportBlock->minRTT = (WebRtc_UWord16) RTT;
reportBlock->remoteReceiveBlock.lastSR = rtcpPacket.ReportBlockItem.LastSR;
if(rtcpPacket.ReportBlockItem.Jitter > reportBlock->remoteMaxJitter)
{
reportBlock->remoteMaxJitter = rtcpPacket.ReportBlockItem.Jitter;
} }
// store last RTT
reportBlock->RTT = (WebRtc_UWord16) RTT;
WebRtc_UWord32 delaySinceLastSendReport = rtcpPacket.ReportBlockItem.DelayLastSR; // store average RTT
if (reportBlock->numAverageCalcs != 0) {
// do we have a local SSRC float ac = static_cast<float> (reportBlock->numAverageCalcs);
// keep track of our relayed SSRC too float newAverage = ((ac / (ac + 1)) * reportBlock->avgRTT)
if(_SSRC) + ((1 / (ac + 1)) * RTT);
{ reportBlock->avgRTT = static_cast<int> (newAverage + 0.5f);
// we filter rtcpPacket.ReportBlockItem.SSRC to our SSRC } else {
// hence only reports to us // first RTT
if( rtcpPacket.ReportBlockItem.SSRC == _SSRC) reportBlock->avgRTT = (WebRtc_UWord16) RTT;
{
// local NTP time when we received this
WebRtc_UWord32 lastReceivedRRNTPsecs = 0;
WebRtc_UWord32 lastReceivedRRNTPfrac = 0;
_clock.CurrentNTP(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
// time when we received this in MS
WebRtc_UWord32 receiveTimeMS = ModuleRTPUtility::ConvertNTPTimeToMS(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
// Estimate RTT
WebRtc_UWord32 d =(delaySinceLastSendReport&0x0000ffff)*1000;
d /= 65536;
d+=((delaySinceLastSendReport&0xffff0000)>>16)*1000;
WebRtc_Word32 RTT = 0;
if(sendTimeMS > 0)
{
RTT = receiveTimeMS - d - sendTimeMS;
if( RTT <= 0)
{
RTT = 1;
}
if (RTT > reportBlock->maxRTT)
{
// store max RTT
reportBlock->maxRTT = (WebRtc_UWord16)RTT;
}
if(reportBlock->minRTT == 0)
{
// first RTT
reportBlock->minRTT = (WebRtc_UWord16)RTT;
}else if (RTT < reportBlock->minRTT)
{
// Store min RTT
reportBlock->minRTT = (WebRtc_UWord16)RTT;
}
// store last RTT
reportBlock->RTT = (WebRtc_UWord16)RTT;
// store average RTT
if(reportBlock->numAverageCalcs != 0)
{
float ac = static_cast<float>(reportBlock->numAverageCalcs);
float newAverage = ((ac / (ac + 1)) * reportBlock->avgRTT) + ((1 / (ac + 1)) * RTT);
reportBlock->avgRTT = static_cast<int>(newAverage + 0.5f);
}else
{
// first RTT
reportBlock->avgRTT = (WebRtc_UWord16)RTT;
}
reportBlock->numAverageCalcs++;
}
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id,
" -> Received report block(%d), from SSRC:0x%x, RTT:%d, loss:%d", _id, remoteSSRC, RTT, rtcpPacket.ReportBlockItem.FractionLost);
// rtcpPacketInformation
rtcpPacketInformation.AddReportInfo(reportBlock->remoteReceiveBlock.fractionLost,
(WebRtc_UWord16)RTT,
reportBlock->remoteReceiveBlock.extendedHighSeqNum,
reportBlock->remoteReceiveBlock.jitter);
}
} }
reportBlock->numAverageCalcs++;
}
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, _id,
" -> Received report block(%d), from SSRC:0x%x, RTT:%d, loss:%d",
_id, remoteSSRC, RTT, rtcpPacket.ReportBlockItem.FractionLost);
// rtcpPacketInformation
rtcpPacketInformation.AddReportInfo(
reportBlock->remoteReceiveBlock.fractionLost, (WebRtc_UWord16) RTT,
reportBlock->remoteReceiveBlock.extendedHighSeqNum,
reportBlock->remoteReceiveBlock.jitter);
} }
RTCPReportBlockInformation* RTCPReportBlockInformation*

View File

@ -11,6 +11,8 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_ #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
#include <vector>
#include "typedefs.h" #include "typedefs.h"
#include "map_wrapper.h" #include "map_wrapper.h"
#include "rtp_utility.h" #include "rtp_utility.h"
@ -81,8 +83,9 @@ public:
const WebRtc_UWord64 pitureID) const; const WebRtc_UWord64 pitureID) const;
// get statistics // get statistics
WebRtc_Word32 StatisticsReceived(const WebRtc_UWord32 remoteSSRC, WebRtc_Word32 StatisticsReceived(
RTCPReportBlock* receiveBlock) const; std::vector<RTCPReportBlock>* receiveBlocks) const;
// Get TMMBR // Get TMMBR
WebRtc_Word32 TMMBRReceived(const WebRtc_UWord32 size, WebRtc_Word32 TMMBRReceived(const WebRtc_UWord32 size,
const WebRtc_UWord32 accNumCandidates, const WebRtc_UWord32 accNumCandidates,

View File

@ -1738,13 +1738,11 @@ WebRtc_Word32 ModuleRtpRtcpImpl::RemoteRTCPStat( RTCPSenderInfo* senderInfo)
} }
// received RTCP report // received RTCP report
WebRtc_Word32 WebRtc_Word32 ModuleRtpRtcpImpl::RemoteRTCPStat(
ModuleRtpRtcpImpl::RemoteRTCPStat(const WebRtc_UWord32 remoteSSRC, std::vector<RTCPReportBlock>* receiveBlocks) const {
RTCPReportBlock* receiveBlock) WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteRTCPStat()");
{
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteRTCPStat()");
return _rtcpReceiver.StatisticsReceived(remoteSSRC, receiveBlock); return _rtcpReceiver.StatisticsReceived(receiveBlocks);
} }
WebRtc_Word32 WebRtc_Word32

View File

@ -316,8 +316,8 @@ public:
virtual WebRtc_Word32 RemoteRTCPStat( RTCPSenderInfo* senderInfo); virtual WebRtc_Word32 RemoteRTCPStat( RTCPSenderInfo* senderInfo);
// Get received RTCP report, report block // Get received RTCP report, report block
virtual WebRtc_Word32 RemoteRTCPStat( const WebRtc_UWord32 remoteSSRC, virtual WebRtc_Word32 RemoteRTCPStat(
RTCPReportBlock* receiveBlock); std::vector<RTCPReportBlock>* receiveBlocks) const;
// Set received RTCP report block // Set received RTCP report block
virtual WebRtc_Word32 AddRTCPReportBlock(const WebRtc_UWord32 SSRC, virtual WebRtc_Word32 AddRTCPReportBlock(const WebRtc_UWord32 SSRC,

View File

@ -113,6 +113,41 @@ class RtpRtcpRtcpTest : public ::testing::Test {
delete receiver; delete receiver;
} }
void SetUpCallFromModule1(RtcpCallback* feedback1, RtcpCallback* feedback2 ) {
EXPECT_EQ(0, module1->RegisterIncomingRTCPCallback(feedback1));
EXPECT_EQ(0, module2->RegisterIncomingRTCPCallback(feedback2));
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));
}
int test_id; int test_id;
RtpRtcp* module1; RtpRtcp* module1;
RtpRtcp* module2; RtpRtcp* module2;
@ -129,38 +164,8 @@ class RtpRtcpRtcpTest : public ::testing::Test {
TEST_F(RtpRtcpRtcpTest, RTCP) { TEST_F(RtpRtcpRtcpTest, RTCP) {
RtcpCallback* myRTCPFeedback1 = new RtcpCallback(module1); RtcpCallback* myRTCPFeedback1 = new RtcpCallback(module1);
RtcpCallback* myRTCPFeedback2 = new RtcpCallback(module2); RtcpCallback* myRTCPFeedback2 = new RtcpCallback(module2);
EXPECT_EQ(0, module1->RegisterIncomingRTCPCallback(myRTCPFeedback1));
EXPECT_EQ(0, module2->RegisterIncomingRTCPCallback(myRTCPFeedback2));
EXPECT_EQ(0, module1->SetRTCPStatus(kRtcpCompound)); SetUpCallFromModule1(myRTCPFeedback1, myRTCPFeedback2);
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->SendRTCPReferencePictureSelection(kTestPictureId));
EXPECT_EQ(0, module1->SendRTCPSliceLossIndication(156)); EXPECT_EQ(0, module1->SendRTCPSliceLossIndication(156));
@ -237,10 +242,12 @@ TEST_F(RtpRtcpRtcpTest, RTCP) {
EXPECT_EQ(0, strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE)); EXPECT_EQ(0, strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE));
// get all report blocks // get all report blocks
RTCPReportBlock reportBlockReceived; std::vector<RTCPReportBlock> report_blocks;
EXPECT_EQ(-1, module1->RemoteRTCPStat(test_ssrc, &reportBlockReceived)); EXPECT_EQ(-1, module1->RemoteRTCPStat(NULL));
EXPECT_EQ(-1, module1->RemoteRTCPStat(test_ssrc + 1, NULL)); EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks));
EXPECT_EQ(0, module1->RemoteRTCPStat(test_ssrc + 1, &reportBlockReceived)); EXPECT_EQ(1u, report_blocks.size());
const RTCPReportBlock& reportBlockReceived = report_blocks[0];
float secSinceLastReport = float secSinceLastReport =
static_cast<float>(reportBlockReceived.delaySinceLastSR) / 65536.0f; static_cast<float>(reportBlockReceived.delaySinceLastSR) / 65536.0f;
EXPECT_GE(0.101f, secSinceLastReport); EXPECT_GE(0.101f, secSinceLastReport);
@ -295,3 +302,32 @@ TEST_F(RtpRtcpRtcpTest, RTCP) {
delete myRTCPFeedback1; delete myRTCPFeedback1;
delete myRTCPFeedback2; delete myRTCPFeedback2;
} }
TEST_F(RtpRtcpRtcpTest, RemoteRTCPStatRemote) {
std::vector<RTCPReportBlock> report_blocks;
RtcpCallback feedback1(module1);
RtcpCallback feedback2(module2);
SetUpCallFromModule1(&feedback1, &feedback2);
EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks));
EXPECT_EQ(0u, report_blocks.size());
// send RTCP packet, triggered by timer
fake_clock.IncrementTime(7500);
module1->Process();
fake_clock.IncrementTime(100);
module2->Process();
EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks));
ASSERT_EQ(1u, report_blocks.size());
// |test_ssrc+1| is the SSRC of module2 that send the report.
EXPECT_EQ(test_ssrc+1, report_blocks[0].remoteSSRC);
EXPECT_EQ(test_ssrc, report_blocks[0].sourceSSRC);
EXPECT_EQ(0u, report_blocks[0].cumulativeLost);
EXPECT_LT(0u, report_blocks[0].delaySinceLastSR);
EXPECT_EQ(test_sequence_number, report_blocks[0].extendedHighSeqNum);
EXPECT_EQ(0u, report_blocks[0].fractionLost);
}

View File

@ -11,6 +11,7 @@
#include "video_engine/vie_channel.h" #include "video_engine/vie_channel.h"
#include <algorithm> #include <algorithm>
#include <vector>
#include "modules/rtp_rtcp/interface/rtp_rtcp.h" #include "modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "modules/udp_transport/interface/udp_transport.h" #include "modules/udp_transport/interface/udp_transport.h"
@ -941,16 +942,36 @@ WebRtc_Word32 ViEChannel::GetSendRtcpStatistics(WebRtc_UWord16& fraction_lost,
// RtpRtcp* rtp_rtcp = *it; // RtpRtcp* rtp_rtcp = *it;
// } // }
WebRtc_UWord32 remoteSSRC = rtp_rtcp_.RemoteSSRC(); WebRtc_UWord32 remoteSSRC = rtp_rtcp_.RemoteSSRC();
RTCPReportBlock remote_stat;
if (rtp_rtcp_.RemoteRTCPStat(remoteSSRC, &remote_stat) != 0) { // Get all RTCP receiver report blocks that have been received on this
// channel. If we receive RTP packets from a remote source we know the
// remote SSRC and use the report block from him.
// Otherwise use the first report block.
std::vector<RTCPReportBlock> remote_stats;
if (rtp_rtcp_.RemoteRTCPStat(&remote_stats) != 0 || remote_stats.empty()) {
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_), WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
"%s: Could not get remote stats", __FUNCTION__); "%s: Could not get remote stats", __FUNCTION__);
return -1; return -1;
} }
fraction_lost = remote_stat.fractionLost; std::vector<RTCPReportBlock>::const_iterator statistics =
cumulative_lost = remote_stat.cumulativeLost; remote_stats.begin();
extended_max = remote_stat.extendedHighSeqNum; for (; statistics != remote_stats.end(); ++statistics) {
jitter_samples = remote_stat.jitter; if (statistics->remoteSSRC == remoteSSRC)
break;
}
if (statistics == remote_stats.end()) {
// If we have not received any RTCP packets from this SSRC it probably means
// we have not received any RTP packets.
// Use the first received report block instead.
statistics = remote_stats.begin();
remoteSSRC = statistics->remoteSSRC;
}
fraction_lost = statistics->fractionLost;
cumulative_lost = statistics->cumulativeLost;
extended_max = statistics->extendedHighSeqNum;
jitter_samples = statistics->jitter;
WebRtc_UWord16 dummy; WebRtc_UWord16 dummy;
WebRtc_UWord16 rtt = 0; WebRtc_UWord16 rtt = 0;

View File

@ -5330,39 +5330,45 @@ Channel::GetRemoteRTCPData(
if (NULL != jitter || NULL != fractionLost) if (NULL != jitter || NULL != fractionLost)
{ {
WebRtc_Word32 ret(-1); // Get all RTCP receiver report blocks that have been received on this
RTCPReportBlock reportBlock; // channel. If we receive RTP packets from a remote source we know the
WebRtc_Word32 remoteSSRC = _rtpRtcpModule.RemoteSSRC(); // remote SSRC and use the report block from him.
if (remoteSSRC > 0) // Otherwise use the first report block.
{ std::vector<RTCPReportBlock> remote_stats;
// We must feed the module with remote SSRC to get the correct if (_rtpRtcpModule.RemoteRTCPStat(&remote_stats) != 0 ||
// report block. remote_stats.empty()) {
ret = _rtpRtcpModule.RemoteRTCPStat(remoteSSRC, &reportBlock); WEBRTC_TRACE(kTraceWarning, kTraceVoice,
VoEId(_instanceId, _channelId),
"GetRemoteRTCPData() failed to measure statistics due"
" to lack of received RTP and/or RTCP packets");
return -1;
} }
if ((remoteSSRC < 0) || (ret != 0))
{ WebRtc_UWord32 remoteSSRC = _rtpRtcpModule.RemoteSSRC();
reportBlock.jitter = 0; std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
reportBlock.fractionLost = 0; for (; it != remote_stats.end(); ++it) {
WEBRTC_TRACE(kTraceWarning, kTraceVoice, if (it->remoteSSRC == remoteSSRC)
VoEId(_instanceId, _channelId), break;
"GetRemoteRTCPData() failed to measure statistics due"
" to lack of received RTP and/or RTCP packets");
} }
if (NULL != jitter)
{ if (it == remote_stats.end()) {
*jitter = reportBlock.jitter; // If we have not received any RTCP packets from this SSRC it probably
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, // means that we have not received any RTP packets.
VoEId(_instanceId, _channelId), // Use the first received report block instead.
"GetRemoteRTCPData() => jitter = %lu", *jitter); it = remote_stats.begin();
} remoteSSRC = it->remoteSSRC;
if (NULL != fractionLost)
{
*fractionLost = reportBlock.fractionLost;
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_instanceId, _channelId),
"GetRemoteRTCPData() => fractionLost = %lu",
*fractionLost);
} }
*jitter = it->jitter;
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_instanceId, _channelId),
"GetRemoteRTCPData() => jitter = %lu", *jitter);
*fractionLost = it->fractionLost;
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
VoEId(_instanceId, _channelId),
"GetRemoteRTCPData() => fractionLost = %lu",
*fractionLost);
} }
return 0; return 0;
} }