From ce5990cb0bbfbf5ee5306cf990e975a2faa090b7 Mon Sep 17 00:00:00 2001 From: "perkj@webrtc.org" Date: Wed, 11 Jan 2012 13:00:08 +0000 Subject: [PATCH] Fix defect http://code.google.com/p/webrtc/issues/detail?id=222 "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 --- src/modules/rtp_rtcp/interface/rtp_rtcp.h | 13 +- .../rtp_rtcp/interface/rtp_rtcp_defines.h | 3 + src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h | 4 +- src/modules/rtp_rtcp/source/rtcp_receiver.cc | 347 ++++++++---------- src/modules/rtp_rtcp/source/rtcp_receiver.h | 7 +- src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc | 10 +- src/modules/rtp_rtcp/source/rtp_rtcp_impl.h | 4 +- .../rtp_rtcp/test/testAPI/test_api_rtcp.cc | 106 ++++-- src/video_engine/vie_channel.cc | 33 +- src/voice_engine/main/source/channel.cc | 66 ++-- 10 files changed, 319 insertions(+), 274 deletions(-) diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp.h b/src/modules/rtp_rtcp/interface/rtp_rtcp.h index 646501d53..d3257be00 100644 --- a/src/modules/rtp_rtcp/interface/rtp_rtcp.h +++ b/src/modules/rtp_rtcp/interface/rtp_rtcp.h @@ -11,6 +11,8 @@ #ifndef WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_H_ #define WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_H_ +#include + #include "module.h" #include "rtp_rtcp_defines.h" @@ -740,22 +742,23 @@ public: * * 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 * * return -1 on failure else 0 */ - virtual WebRtc_Word32 RemoteRTCPStat( const WebRtc_UWord32 remoteSSRC, - RTCPReportBlock* receiveBlock) = 0; + virtual WebRtc_Word32 RemoteRTCPStat( + std::vector* receiveBlocks) const = 0; /* * Set received RTCP report block * * return -1 on failure else 0 */ - virtual WebRtc_Word32 AddRTCPReportBlock(const WebRtc_UWord32 SSRC, - const RTCPReportBlock* receiveBlock) = 0; + virtual WebRtc_Word32 AddRTCPReportBlock( + const WebRtc_UWord32 SSRC, + const RTCPReportBlock* receiveBlock) = 0; /* * RemoveRTCPReportBlock diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h index ddd994a37..be04b3906 100644 --- a/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h +++ b/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h @@ -109,6 +109,9 @@ struct RTCPSenderInfo 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_UWord32 cumulativeLost; // 24 bits valid WebRtc_UWord32 extendedHighSeqNum; diff --git a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h index 372131641..dea883867 100644 --- a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h +++ b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -170,8 +170,8 @@ class MockRtpRtcp : public RtpRtcp { WebRtc_Word32(WebRtc_UWord32 *bytesSent, WebRtc_UWord32 *packetsSent, WebRtc_UWord32 *bytesReceived, WebRtc_UWord32 *packetsReceived)); MOCK_METHOD1(RemoteRTCPStat, WebRtc_Word32(RTCPSenderInfo* senderInfo)); - MOCK_METHOD2(RemoteRTCPStat, - WebRtc_Word32(const WebRtc_UWord32 remoteSSRC, RTCPReportBlock* receiveBlock)); + MOCK_CONST_METHOD1(RemoteRTCPStat, + WebRtc_Word32(std::vector* receiveBlocks)); MOCK_METHOD2(AddRTCPReportBlock, WebRtc_Word32(const WebRtc_UWord32 SSRC, const RTCPReportBlock* receiveBlock)); MOCK_METHOD1(RemoveRTCPReportBlock, diff --git a/src/modules/rtp_rtcp/source/rtcp_receiver.cc b/src/modules/rtp_rtcp/source/rtcp_receiver.cc index 4b215b366..730656744 100644 --- a/src/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/src/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -179,56 +179,52 @@ RTCPReceiver::SetSSRC( const WebRtc_UWord32 ssrc) _SSRC = ssrc; } -WebRtc_Word32 -RTCPReceiver::ResetRTT(const WebRtc_UWord32 remoteSSRC) -{ - CriticalSectionScoped lock(_criticalSectionRTCPReceiver); - RTCPReportBlockInformation* reportBlock = GetReportBlockInformation(remoteSSRC); - if(reportBlock == NULL) - { - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "\tfailed to GetReportBlockInformation(%d)", remoteSSRC); - return -1; - } - reportBlock->RTT = 0; - reportBlock->avgRTT = 0; - reportBlock->minRTT = 0; - reportBlock->maxRTT = 0; +WebRtc_Word32 RTCPReceiver::ResetRTT(const WebRtc_UWord32 remoteSSRC) { + CriticalSectionScoped lock(_criticalSectionRTCPReceiver); + RTCPReportBlockInformation* reportBlock = + GetReportBlockInformation(remoteSSRC); + if (reportBlock == NULL) { + WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, + "\tfailed to GetReportBlockInformation(%u)", remoteSSRC); + return -1; + } + reportBlock->RTT = 0; + reportBlock->avgRTT = 0; + reportBlock->minRTT = 0; + reportBlock->maxRTT = 0; - return 0; + return 0; } -WebRtc_Word32 -RTCPReceiver::RTT(const WebRtc_UWord32 remoteSSRC, - WebRtc_UWord16* RTT, - WebRtc_UWord16* avgRTT, - WebRtc_UWord16* minRTT, - WebRtc_UWord16* maxRTT) const +WebRtc_Word32 RTCPReceiver::RTT(const WebRtc_UWord32 remoteSSRC, + WebRtc_UWord16* RTT, + WebRtc_UWord16* avgRTT, + WebRtc_UWord16* minRTT, + WebRtc_UWord16* maxRTT) const { + CriticalSectionScoped lock(_criticalSectionRTCPReceiver); -{ - CriticalSectionScoped lock(_criticalSectionRTCPReceiver); - RTCPReportBlockInformation* reportBlock = GetReportBlockInformation(remoteSSRC); - if(reportBlock == NULL) - { - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "\tfailed to GetReportBlockInformation(%d)", remoteSSRC); - return -1; - } - if(RTT) - { - *RTT = reportBlock->RTT; - } - if(avgRTT) - { - *avgRTT = reportBlock->avgRTT; - } - if(minRTT) - { - *minRTT = reportBlock->minRTT; - } - if(maxRTT) - { - *maxRTT = reportBlock->maxRTT; - } - return 0; + RTCPReportBlockInformation* reportBlock = + GetReportBlockInformation(remoteSSRC); + + if (reportBlock == NULL) { + WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, + "\tfailed to GetReportBlockInformation(%u)", + remoteSSRC); + return -1; + } + if (RTT) { + *RTT = reportBlock->RTT; + } + if (avgRTT) { + *avgRTT = reportBlock->avgRTT; + } + if (minRTT) { + *minRTT = reportBlock->minRTT; + } + if (maxRTT) { + *maxRTT = reportBlock->maxRTT; + } + return 0; } void @@ -287,24 +283,25 @@ RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const // statistics // we can get multiple receive reports when we receive the report from a CE -WebRtc_Word32 -RTCPReceiver::StatisticsReceived(const WebRtc_UWord32 remoteSSRC, - RTCPReportBlock* receiveBlock) const -{ - if(receiveBlock == NULL) - { - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__); - return -1; - } - CriticalSectionScoped lock(_criticalSectionRTCPReceiver); - RTCPReportBlockInformation* reportBlockInfo = GetReportBlockInformation(remoteSSRC); - if(reportBlockInfo == NULL) - { - WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "\tfailed to GetReportBlockInformation(%d)", remoteSSRC); - return -1; - } - memcpy(receiveBlock, &(reportBlockInfo->remoteReceiveBlock), sizeof(RTCPReportBlock)); - return 0; +WebRtc_Word32 RTCPReceiver::StatisticsReceived( + std::vector* receiveBlocks) const { + if (receiveBlocks == NULL) { + WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", + __FUNCTION__); + return -1; + } + CriticalSectionScoped lock(_criticalSectionRTCPReceiver); + + MapItem* ptrReportBlockInfoItem = _receivedReportBlockMap.First(); + while (ptrReportBlockInfoItem != NULL) { + RTCPReportBlockInformation* item = + static_cast ( + ptrReportBlockInfoItem->GetItem()); + receiveBlocks->push_back(item->remoteReceiveBlock); + ptrReportBlockInfoItem = + _receivedReportBlockMap.Next(ptrReportBlockInfoItem); + } + return 0; } WebRtc_Word32 @@ -459,135 +456,113 @@ void RTCPReceiver::HandleReportBlock(const RTCPUtility::RTCPPacket& rtcpPacket, RTCPPacketInformation& rtcpPacketInformation, const WebRtc_UWord32 remoteSSRC, - const WebRtc_UWord8 numberOfReportBlocks) -{ - // this will be called once per report block in the RTCP packet - // we store all incoming reports - // each packet has max 31 RR blocks - // - // we can calc RTT if we send a send report and get a report block back + const WebRtc_UWord8 numberOfReportBlocks) { + // This will be called once per report block in the RTCP packet. + // We filter out all report blocks that are not for us. + // Each packet has max 31 RR blocks. + // + // We can calc RTT if we send a send report and get a report block back. - /* - rtcpPacket.ReportBlockItem.SSRC - The SSRC identifier of the source to which the information in this - reception report block pertains. - */ + // |rtcpPacket.ReportBlockItem.SSRC| is 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 - if( _SSRC && - numberOfReportBlocks > 1) - { - // we have more than one reportBlock in the RTCP packet - if(rtcpPacket.ReportBlockItem.SSRC != _SSRC) - { - // this block is not for us ignore it - return; - } + // Filter out all report blocks that are not for us. + if (rtcpPacket.ReportBlockItem.SSRC != _SSRC) { + // This block is not for us ignore it. + return; + } + + // To avoid problem with acquiring _criticalSectionRTCPSender while holding + // _criticalSectionRTCPReceiver. + _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; } - - _criticalSectionRTCPReceiver->Leave(); - // to avoid problem with accuireing _criticalSectionRTCPSender while holding _criticalSectionRTCPReceiver - - 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 (RTT > reportBlock->maxRTT) { + // store max RTT + reportBlock->maxRTT = (WebRtc_UWord16) RTT; } - - reportBlock->remoteReceiveBlock.fractionLost = rtcpPacket.ReportBlockItem.FractionLost; - reportBlock->remoteReceiveBlock.cumulativeLost = rtcpPacket.ReportBlockItem.CumulativeNumOfPacketsLost; - reportBlock->remoteReceiveBlock.extendedHighSeqNum= rtcpPacket.ReportBlockItem.ExtendedHighestSequenceNumber; - reportBlock->remoteReceiveBlock.jitter = rtcpPacket.ReportBlockItem.Jitter; - reportBlock->remoteReceiveBlock.delaySinceLastSR = rtcpPacket.ReportBlockItem.DelayLastSR; - reportBlock->remoteReceiveBlock.lastSR = rtcpPacket.ReportBlockItem.LastSR; - - if(rtcpPacket.ReportBlockItem.Jitter > reportBlock->remoteMaxJitter) - { - reportBlock->remoteMaxJitter = rtcpPacket.ReportBlockItem.Jitter; + 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; - WebRtc_UWord32 delaySinceLastSendReport = rtcpPacket.ReportBlockItem.DelayLastSR; - - // do we have a local SSRC - // keep track of our relayed SSRC too - if(_SSRC) - { - // we filter rtcpPacket.ReportBlockItem.SSRC to our SSRC - // hence only reports to us - if( rtcpPacket.ReportBlockItem.SSRC == _SSRC) - { - // 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(reportBlock->numAverageCalcs); - float newAverage = ((ac / (ac + 1)) * reportBlock->avgRTT) + ((1 / (ac + 1)) * RTT); - reportBlock->avgRTT = static_cast(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); - } + // store average RTT + if (reportBlock->numAverageCalcs != 0) { + float ac = static_cast (reportBlock->numAverageCalcs); + float newAverage = ((ac / (ac + 1)) * reportBlock->avgRTT) + + ((1 / (ac + 1)) * RTT); + reportBlock->avgRTT = static_cast (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); } RTCPReportBlockInformation* diff --git a/src/modules/rtp_rtcp/source/rtcp_receiver.h b/src/modules/rtp_rtcp/source/rtcp_receiver.h index 8b0d6d5f7..8b856f00d 100644 --- a/src/modules/rtp_rtcp/source/rtcp_receiver.h +++ b/src/modules/rtp_rtcp/source/rtcp_receiver.h @@ -11,6 +11,8 @@ #ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_ #define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_ +#include + #include "typedefs.h" #include "map_wrapper.h" #include "rtp_utility.h" @@ -81,8 +83,9 @@ public: const WebRtc_UWord64 pitureID) const; // get statistics - WebRtc_Word32 StatisticsReceived(const WebRtc_UWord32 remoteSSRC, - RTCPReportBlock* receiveBlock) const; + WebRtc_Word32 StatisticsReceived( + std::vector* receiveBlocks) const; + // Get TMMBR WebRtc_Word32 TMMBRReceived(const WebRtc_UWord32 size, const WebRtc_UWord32 accNumCandidates, diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 378b07821..e0ec5778c 100644 --- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -1738,13 +1738,11 @@ WebRtc_Word32 ModuleRtpRtcpImpl::RemoteRTCPStat( RTCPSenderInfo* senderInfo) } // received RTCP report -WebRtc_Word32 -ModuleRtpRtcpImpl::RemoteRTCPStat(const WebRtc_UWord32 remoteSSRC, - RTCPReportBlock* receiveBlock) -{ - WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteRTCPStat()"); +WebRtc_Word32 ModuleRtpRtcpImpl::RemoteRTCPStat( + std::vector* receiveBlocks) const { + WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteRTCPStat()"); - return _rtcpReceiver.StatisticsReceived(remoteSSRC, receiveBlock); + return _rtcpReceiver.StatisticsReceived(receiveBlocks); } WebRtc_Word32 diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h index 8548bba79..717f12cd3 100644 --- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -316,8 +316,8 @@ public: virtual WebRtc_Word32 RemoteRTCPStat( RTCPSenderInfo* senderInfo); // Get received RTCP report, report block - virtual WebRtc_Word32 RemoteRTCPStat( const WebRtc_UWord32 remoteSSRC, - RTCPReportBlock* receiveBlock); + virtual WebRtc_Word32 RemoteRTCPStat( + std::vector* receiveBlocks) const; // Set received RTCP report block virtual WebRtc_Word32 AddRTCPReportBlock(const WebRtc_UWord32 SSRC, diff --git a/src/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc b/src/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc index 9766b451c..a9268533d 100644 --- a/src/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc +++ b/src/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc @@ -113,6 +113,41 @@ class RtpRtcpRtcpTest : public ::testing::Test { 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; RtpRtcp* module1; RtpRtcp* module2; @@ -129,38 +164,8 @@ class RtpRtcpRtcpTest : public ::testing::Test { 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)); + SetUpCallFromModule1(myRTCPFeedback1, myRTCPFeedback2); EXPECT_EQ(0, module1->SendRTCPReferencePictureSelection(kTestPictureId)); 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)); // 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)); + std::vector report_blocks; + EXPECT_EQ(-1, module1->RemoteRTCPStat(NULL)); + EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks)); + EXPECT_EQ(1u, report_blocks.size()); + const RTCPReportBlock& reportBlockReceived = report_blocks[0]; + float secSinceLastReport = static_cast(reportBlockReceived.delaySinceLastSR) / 65536.0f; EXPECT_GE(0.101f, secSinceLastReport); @@ -295,3 +302,32 @@ TEST_F(RtpRtcpRtcpTest, RTCP) { delete myRTCPFeedback1; delete myRTCPFeedback2; } + +TEST_F(RtpRtcpRtcpTest, RemoteRTCPStatRemote) { + std::vector 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); +} diff --git a/src/video_engine/vie_channel.cc b/src/video_engine/vie_channel.cc index 75271be92..d37b82891 100644 --- a/src/video_engine/vie_channel.cc +++ b/src/video_engine/vie_channel.cc @@ -11,6 +11,7 @@ #include "video_engine/vie_channel.h" #include +#include #include "modules/rtp_rtcp/interface/rtp_rtcp.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; // } 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 remote_stats; + if (rtp_rtcp_.RemoteRTCPStat(&remote_stats) != 0 || remote_stats.empty()) { WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_), "%s: Could not get remote stats", __FUNCTION__); return -1; } - fraction_lost = remote_stat.fractionLost; - cumulative_lost = remote_stat.cumulativeLost; - extended_max = remote_stat.extendedHighSeqNum; - jitter_samples = remote_stat.jitter; + std::vector::const_iterator statistics = + remote_stats.begin(); + for (; statistics != remote_stats.end(); ++statistics) { + 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 rtt = 0; diff --git a/src/voice_engine/main/source/channel.cc b/src/voice_engine/main/source/channel.cc index dc563b9c9..4d01b5b11 100644 --- a/src/voice_engine/main/source/channel.cc +++ b/src/voice_engine/main/source/channel.cc @@ -5330,39 +5330,45 @@ Channel::GetRemoteRTCPData( if (NULL != jitter || NULL != fractionLost) { - WebRtc_Word32 ret(-1); - RTCPReportBlock reportBlock; - WebRtc_Word32 remoteSSRC = _rtpRtcpModule.RemoteSSRC(); - if (remoteSSRC > 0) - { - // We must feed the module with remote SSRC to get the correct - // report block. - ret = _rtpRtcpModule.RemoteRTCPStat(remoteSSRC, &reportBlock); + // 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 remote_stats; + if (_rtpRtcpModule.RemoteRTCPStat(&remote_stats) != 0 || + remote_stats.empty()) { + 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)) - { - reportBlock.jitter = 0; - reportBlock.fractionLost = 0; - WEBRTC_TRACE(kTraceWarning, kTraceVoice, - VoEId(_instanceId, _channelId), - "GetRemoteRTCPData() failed to measure statistics due" - " to lack of received RTP and/or RTCP packets"); + + WebRtc_UWord32 remoteSSRC = _rtpRtcpModule.RemoteSSRC(); + std::vector::const_iterator it = remote_stats.begin(); + for (; it != remote_stats.end(); ++it) { + if (it->remoteSSRC == remoteSSRC) + break; } - if (NULL != jitter) - { - *jitter = reportBlock.jitter; - WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, - VoEId(_instanceId, _channelId), - "GetRemoteRTCPData() => jitter = %lu", *jitter); - } - if (NULL != fractionLost) - { - *fractionLost = reportBlock.fractionLost; - WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, - VoEId(_instanceId, _channelId), - "GetRemoteRTCPData() => fractionLost = %lu", - *fractionLost); + + if (it == remote_stats.end()) { + // If we have not received any RTCP packets from this SSRC it probably + // means that we have not received any RTP packets. + // Use the first received report block instead. + it = remote_stats.begin(); + remoteSSRC = it->remoteSSRC; } + + *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; }