"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_
#define WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_H_
#include <vector>
#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<RTCPReportBlock>* 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

View File

@ -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;

View File

@ -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<RTCPReportBlock>* receiveBlocks));
MOCK_METHOD2(AddRTCPReportBlock,
WebRtc_Word32(const WebRtc_UWord32 SSRC, const RTCPReportBlock* receiveBlock));
MOCK_METHOD1(RemoveRTCPReportBlock,

View File

@ -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<RTCPReportBlock>* 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<RTCPReportBlockInformation*> (
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<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);
}
// 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);
}
RTCPReportBlockInformation*

View File

@ -11,6 +11,8 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
#include <vector>
#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<RTCPReportBlock>* receiveBlocks) const;
// Get TMMBR
WebRtc_Word32 TMMBRReceived(const WebRtc_UWord32 size,
const WebRtc_UWord32 accNumCandidates,

View File

@ -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<RTCPReportBlock>* receiveBlocks) const {
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "RemoteRTCPStat()");
return _rtcpReceiver.StatisticsReceived(remoteSSRC, receiveBlock);
return _rtcpReceiver.StatisticsReceived(receiveBlocks);
}
WebRtc_Word32

View File

@ -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<RTCPReportBlock>* receiveBlocks) const;
// Set received RTCP report block
virtual WebRtc_Word32 AddRTCPReportBlock(const WebRtc_UWord32 SSRC,

View File

@ -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<RTCPReportBlock> 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<float>(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<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 <algorithm>
#include <vector>
#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<RTCPReportBlock> 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<RTCPReportBlock>::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;

View File

@ -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<RTCPReportBlock> 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<RTCPReportBlock>::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;
}