Adding API to get sent total bitrate, FEC bitrate and NACK bitrate.
Also adding tests for this in vie_auto_test.
BUG=
TEST=
Review URL: http://webrtc-codereview.appspot.com/199001
git-svn-id: http://webrtc.googlecode.com/svn/trunk@749 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp.h b/src/modules/rtp_rtcp/interface/rtp_rtcp.h
index 12fdda1..7339438 100644
--- a/src/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/src/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -495,7 +495,9 @@
/*
* get sent bitrate in Kbit/s
*/
- virtual WebRtc_UWord32 BitrateSent() const = 0;
+ virtual void BitrateSent(WebRtc_UWord32* totalRate,
+ WebRtc_UWord32* fecRate,
+ WebRtc_UWord32* nackRate) const = 0;
/*
* Used by the codec module to deliver a video or audio frame for packetization
diff --git a/src/modules/rtp_rtcp/source/rtcp_sender.cc b/src/modules/rtp_rtcp/source/rtcp_sender.cc
index 5d2dc67..cb80b98 100644
--- a/src/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/src/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -1693,7 +1693,13 @@
if(_sending)
{
// calc bw for video 360/sendBW in kbit/s
- WebRtc_Word32 sendBitrateKbit = _rtpRtcp.BitrateSent()/1000;
+ WebRtc_UWord32 sendBitrateKbit = 0;
+ WebRtc_UWord32 fecRate = 0;
+ WebRtc_UWord32 nackRate = 0;
+ _rtpRtcp.BitrateSent(&sendBitrateKbit,
+ &fecRate,
+ &nackRate);
+ sendBitrateKbit /= 1000;
if(sendBitrateKbit != 0)
{
minIntervalMs = 360000/sendBitrateKbit;
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index eb07420..6667d83 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -2339,26 +2339,42 @@
return _rtpReceiver.BitrateNow();
}
-WebRtc_UWord32 ModuleRtpRtcpImpl::BitrateSent() const {
+void ModuleRtpRtcpImpl::BitrateSent(WebRtc_UWord32* totalRate,
+ WebRtc_UWord32* fecRate,
+ WebRtc_UWord32* nackRate) const {
const bool defaultInstance(_childModules.empty() ? false : true);
if (defaultInstance) {
// for default we need to update the send bitrate
CriticalSectionScoped lock(_criticalSectionModulePtrsFeedback);
- WebRtc_UWord32 bitrate = 0;
std::list<ModuleRtpRtcpImpl*>::const_iterator it =
_childModules.begin();
while (it != _childModules.end()) {
RtpRtcp* module = *it;
if (module) {
- bitrate = std::max(module->BitrateSent(), bitrate);
+ WebRtc_UWord32 childTotalRate = 0;
+ WebRtc_UWord32 childFecRate = 0;
+ WebRtc_UWord32 childNackRate = 0;
+ module->BitrateSent(&childTotalRate,
+ &childFecRate,
+ &childNackRate);
+ if (totalRate != NULL && childTotalRate > *totalRate)
+ *totalRate = childTotalRate;
+ if (fecRate != NULL && childFecRate > *fecRate)
+ *fecRate = childFecRate;
+ if (nackRate != NULL && childNackRate > *nackRate)
+ *nackRate = childNackRate;
}
it++;
}
- return bitrate;
}
- return _rtpSender.BitrateLast();
+ if (totalRate != NULL)
+ *totalRate = _rtpSender.BitrateLast();
+ if (fecRate != NULL)
+ *fecRate = _rtpSender.FecOverheadRate();
+ if (nackRate != NULL)
+ *nackRate = _rtpSender.NackOverheadRate();
}
// for lip sync
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index bfb1ed4..642f302 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -459,7 +459,9 @@
virtual WebRtc_Word32 BoundingSet(bool &tmmbrOwner,
TMMBRSet*& boundingSetRec);
- virtual WebRtc_UWord32 BitrateSent() const;
+ virtual void BitrateSent(WebRtc_UWord32* totalRate,
+ WebRtc_UWord32* fecRate,
+ WebRtc_UWord32* nackRate) const;
virtual void SetRemoteSSRC(const WebRtc_UWord32 SSRC);
diff --git a/src/modules/rtp_rtcp/source/rtp_sender.cc b/src/modules/rtp_rtcp/source/rtp_sender.cc
index a93ecf7..4a2311d 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/src/modules/rtp_rtcp/source/rtp_sender.cc
@@ -56,6 +56,7 @@
// NACK
_nackByteCountTimes(),
_nackByteCount(),
+ _nackBitrate(),
// statistics
_packetsSent(0),
@@ -192,6 +193,7 @@
memset(_nackByteCount, 0, sizeof(_nackByteCount));
memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
+ _nackBitrate.Init();
SetStorePacketsStatus(false, 0);
@@ -232,12 +234,23 @@
{
return _targetSendBitrate;
}
+
WebRtc_UWord16
RTPSender::ActualSendBitrateKbit() const
{
return (WebRtc_UWord16) (Bitrate::BitrateNow()/1000);
}
+WebRtc_UWord32
+RTPSender::FecOverheadRate() const {
+ return _video->FecOverheadRate();
+}
+
+WebRtc_UWord32
+RTPSender::NackOverheadRate() const {
+ return _nackBitrate.BitrateLast();
+}
+
//can be called multiple times
WebRtc_Word32
RTPSender::RegisterPayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
@@ -903,6 +916,7 @@
if (bytesReSent > 0)
{
UpdateNACKBitRate(bytesReSent,now); // Update the nack bit rate
+ _nackBitrate.Update(bytesReSent);
}
}else
{
@@ -918,7 +932,7 @@
{
WebRtc_UWord32 num = 0;
WebRtc_Word32 byteCount = 0;
- const WebRtc_UWord32 avgIntervall=1000;
+ const WebRtc_UWord32 avgInterval=1000;
CriticalSectionScoped cs(_sendCritsect);
@@ -929,24 +943,27 @@
for(num = 0; num < NACK_BYTECOUNT_SIZE; num++)
{
- if((now - _nackByteCountTimes[num]) > avgIntervall) // don't use data older than 1sec
+ if((now - _nackByteCountTimes[num]) > avgInterval)
{
+ // don't use data older than 1sec
break;
} else
{
byteCount += _nackByteCount[num];
}
}
- WebRtc_Word32 timeIntervall=avgIntervall;
- if (num == NACK_BYTECOUNT_SIZE ) // More than NACK_BYTECOUNT_SIZE nack messages has been received during the last msgIntervall
+ WebRtc_Word32 timeInterval = avgInterval;
+ if (num == NACK_BYTECOUNT_SIZE)
{
- timeIntervall= now - _nackByteCountTimes[num-1];
- if(timeIntervall <0)
+ // More than NACK_BYTECOUNT_SIZE nack messages has been received
+ // during the last msgInterval
+ timeInterval = now - _nackByteCountTimes[num-1];
+ if(timeInterval < 0)
{
- timeIntervall=avgIntervall;
+ timeInterval = avgInterval;
}
}
- return (byteCount*8)<(_targetSendBitrate*timeIntervall);
+ return (byteCount*8) < (_targetSendBitrate * timeInterval);
}
void
@@ -1056,6 +1073,8 @@
CriticalSectionScoped cs(_sendCritsect);
Bitrate::Process();
+ _nackBitrate.Process();
+ _video->ProcessBitrate();
}
WebRtc_UWord16
diff --git a/src/modules/rtp_rtcp/source/rtp_sender.h b/src/modules/rtp_rtcp/source/rtp_sender.h
index ebdd14c..3d05427 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender.h
+++ b/src/modules/rtp_rtcp/source/rtp_sender.h
@@ -73,6 +73,9 @@
WebRtc_UWord16 TargetSendBitrateKbit() const;
WebRtc_UWord16 ActualSendBitrateKbit() const;
+ WebRtc_UWord32 FecOverheadRate() const;
+ WebRtc_UWord32 NackOverheadRate() const;
+
WebRtc_Word32 SetTargetSendBitrate(const WebRtc_UWord32 bits);
WebRtc_UWord16 MaxDataPayloadLength() const; // with RTP and FEC headers
@@ -293,6 +296,7 @@
// NACK
WebRtc_UWord32 _nackByteCountTimes[NACK_BYTECOUNT_SIZE];
WebRtc_Word32 _nackByteCount[NACK_BYTECOUNT_SIZE];
+ Bitrate _nackBitrate;
// statistics
WebRtc_UWord32 _packetsSent;
diff --git a/src/modules/rtp_rtcp/source/rtp_sender_video.cc b/src/modules/rtp_rtcp/source/rtp_sender_video.cc
index a6ef3f4..5bb2951 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/src/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -47,6 +47,7 @@
_fecProtectionFactor(0),
_fecUseUepProtection(false),
_numberFirstPartition(0),
+ _fecOverheadRate(),
// H263
_savedByte(0),
@@ -78,6 +79,7 @@
_fecProtectionFactor = 0;
_fecUseUepProtection = false;
_numberFirstPartition = 0;
+ _fecOverheadRate.Init();
return 0;
}
@@ -155,6 +157,7 @@
const WebRtc_UWord16 payloadLength,
const WebRtc_UWord16 rtpHeaderLength)
{
+ int fecOverheadSent = 0;
if(_fecEnabled)
{
WebRtc_Word32 retVal = 0;
@@ -296,8 +299,15 @@
newDataBuffer,
packetToSend->length + REDForFECHeaderLength,
lastMediaRtpHeader.length);
+
+ if (retVal == 0)
+ {
+ fecOverheadSent += packetToSend->length +
+ REDForFECHeaderLength;
+ }
}
}
+ _fecOverheadRate.Update(fecOverheadSent);
return retVal;
}
return _rtpSender.SendToNetwork(dataBuffer,
@@ -1261,7 +1271,6 @@
// Set marker bit true if this is the last packet in frame.
_rtpSender.BuildRTPheader(dataBuffer, payloadType, last,
captureTimeStamp);
-
if (-1 == SendVideoPacket(frameType, dataBuffer, payloadBytesInPacket,
rtpHeaderLength))
{
@@ -1272,4 +1281,13 @@
}
return 0;
}
+
+void RTPSenderVideo::ProcessBitrate() {
+ _fecOverheadRate.Process();
+}
+
+WebRtc_UWord32 RTPSenderVideo::FecOverheadRate() const {
+ return _fecOverheadRate.BitrateLast();
+}
+
} // namespace webrtc
diff --git a/src/modules/rtp_rtcp/source/rtp_sender_video.h b/src/modules/rtp_rtcp/source/rtp_sender_video.h
index 46ea282..5a3781d 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender_video.h
+++ b/src/modules/rtp_rtcp/source/rtp_sender_video.h
@@ -85,6 +85,10 @@
WebRtc_Word32 SetFECUepProtection(const bool keyUseUepProtection,
const bool deltaUseUepProtection);
+ void ProcessBitrate();
+
+ WebRtc_UWord32 FecOverheadRate() const;
+
protected:
virtual WebRtc_Word32 SendVideoPacket(const FrameType frameType,
const WebRtc_UWord8* dataBuffer,
@@ -163,6 +167,7 @@
int _numberFirstPartition;
ListWrapper _mediaPacketListFec;
ListWrapper _rtpPacketListFec;
+ Bitrate _fecOverheadRate;
// H263
WebRtc_UWord8 _savedByte;
diff --git a/src/video_engine/main/interface/vie_rtp_rtcp.h b/src/video_engine/main/interface/vie_rtp_rtcp.h
index c31031b..9a37147 100644
--- a/src/video_engine/main/interface/vie_rtp_rtcp.h
+++ b/src/video_engine/main/interface/vie_rtp_rtcp.h
@@ -241,6 +241,13 @@
unsigned int& bytesReceived,
unsigned int& packetsReceived) const = 0;
+ // The function gets bandwidth usage statistics from the sent RTP streams in
+ // bits/s.
+ virtual int GetBandwidthUsage(const int videoChannel,
+ unsigned int& totalBitrateSent,
+ unsigned int& fecBitrateSent,
+ unsigned int& nackBitrateSent) const = 0;
+
// This function enables or disables an RTP keep-alive mechanism which can
// be used to maintain an existing Network Address Translator (NAT) mapping
// while regular RTP is no longer transmitted.
diff --git a/src/video_engine/main/source/vie_channel.cc b/src/video_engine/main/source/vie_channel.cc
index 84378f6..893519f 100644
--- a/src/video_engine/main/source/vie_channel.cc
+++ b/src/video_engine/main/source/vie_channel.cc
@@ -1449,6 +1449,29 @@
return 0;
}
+void ViEChannel::GetBandwidthUsage(WebRtc_UWord32& totalBitrateSent,
+ WebRtc_UWord32& fecBitrateSent,
+ WebRtc_UWord32& nackBitrateSent) const {
+ WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo,
+ ViEId(_engineId, _channelId),
+ "%s", __FUNCTION__);
+
+ _rtpRtcp.BitrateSent(&totalBitrateSent,
+ &fecBitrateSent,
+ &nackBitrateSent);
+ for (std::list<RtpRtcp*>::const_iterator it = _simulcastRtpRtcp.begin();
+ it != _simulcastRtpRtcp.end(); it++) {
+ WebRtc_UWord32 streamRate = 0;
+ WebRtc_UWord32 fecRate = 0;
+ WebRtc_UWord32 nackRate = 0;
+ RtpRtcp* rtpRtcp = *it;
+ rtpRtcp->BitrateSent(&streamRate, &fecRate, &nackRate);
+ totalBitrateSent += streamRate;
+ fecBitrateSent += fecRate;
+ nackBitrateSent += nackRate;
+ }
+}
+
// ----------------------------------------------------------------------------
// SetKeepAliveStatus
//
diff --git a/src/video_engine/main/source/vie_channel.h b/src/video_engine/main/source/vie_channel.h
index 131fd33..a68e85e 100644
--- a/src/video_engine/main/source/vie_channel.h
+++ b/src/video_engine/main/source/vie_channel.h
@@ -171,6 +171,10 @@
WebRtc_UWord32& bytesReceived,
WebRtc_UWord32& packetsReceived) const;
+ void GetBandwidthUsage(WebRtc_UWord32& totalBitrateSent,
+ WebRtc_UWord32& fecBitrateSent,
+ WebRtc_UWord32& nackBitrateSent) const;
+
WebRtc_Word32 SetKeepAliveStatus(const bool enable,
const WebRtc_Word8 unknownPayloadType,
const WebRtc_UWord16 deltaTransmitTimeMS);
diff --git a/src/video_engine/main/source/vie_rtp_rtcp_impl.cc b/src/video_engine/main/source/vie_rtp_rtcp_impl.cc
index 1a5a8bb..157a5a0 100644
--- a/src/video_engine/main/source/vie_rtp_rtcp_impl.cc
+++ b/src/video_engine/main/source/vie_rtp_rtcp_impl.cc
@@ -969,6 +969,34 @@
return 0;
}
+// The function gets bandwidth usage statistics from the sent RTP streams.
+int ViERTP_RTCPImpl::GetBandwidthUsage(const int videoChannel,
+ unsigned int& totalBitrateSent,
+ unsigned int& fecBitrateSent,
+ unsigned int& nackBitrateSent) const {
+ WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
+ ViEId(_instanceId, videoChannel), "%s(channel: %d)",
+ __FUNCTION__, videoChannel);
+
+ ViEChannelManagerScoped cs(_channelManager);
+ ViEChannel* ptrViEChannel = cs.Channel(videoChannel);
+ if (ptrViEChannel == NULL) {
+ // The channel doesn't exists
+ WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
+ ViEId(_instanceId, videoChannel),
+ "%s: Channel %d doesn't exist", __FUNCTION__,
+ videoChannel);
+ SetLastError(kViERtpRtcpInvalidChannelId);
+ return -1;
+ }
+
+ ptrViEChannel->GetBandwidthUsage(
+ static_cast<WebRtc_UWord32&>(totalBitrateSent),
+ static_cast<WebRtc_UWord32&>(fecBitrateSent),
+ static_cast<WebRtc_UWord32&>(nackBitrateSent));
+ return 0;
+}
+
// ============================================================================
// Keep alive
// ============================================================================
diff --git a/src/video_engine/main/source/vie_rtp_rtcp_impl.h b/src/video_engine/main/source/vie_rtp_rtcp_impl.h
index 763128e..62f959b 100644
--- a/src/video_engine/main/source/vie_rtp_rtcp_impl.h
+++ b/src/video_engine/main/source/vie_rtp_rtcp_impl.h
@@ -110,6 +110,11 @@
unsigned int& bytesReceived,
unsigned int& packetsReceived) const;
+ virtual int GetBandwidthUsage(const int videoChannel,
+ unsigned int& totalBitrateSent,
+ unsigned int& fecBitrateSent,
+ unsigned int& nackBitrateSent) const;
+
// Keep alive
virtual int SetRTPKeepAliveStatus(
const int videoChannel, bool enable, const char unknownPayloadType,
diff --git a/src/video_engine/main/test/AutoTest/source/vie_autotest_rtp_rtcp.cc b/src/video_engine/main/test/AutoTest/source/vie_autotest_rtp_rtcp.cc
index 58a976d..d6ab12f 100644
--- a/src/video_engine/main/test/AutoTest/source/vie_autotest_rtp_rtcp.cc
+++ b/src/video_engine/main/test/AutoTest/source/vie_autotest_rtp_rtcp.cc
@@ -232,6 +232,23 @@
unsigned int recJitter = 0;
int recRttMs = 0;
+ unsigned int sentTotalBitrate = 0;
+ unsigned int sentFecBitrate = 0;
+ unsigned int sentNackBitrate = 0;
+
+ error = ViE.ptrViERtpRtcp->GetBandwidthUsage(tbChannel.videoChannel,
+ sentTotalBitrate,
+ sentFecBitrate,
+ sentNackBitrate);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ numberOfErrors += ViETest::TestError(sentTotalBitrate > 0 &&
+ sentFecBitrate == 0 &&
+ sentNackBitrate == 0,
+ "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
error = ViE.ptrViEBase->StopReceive(tbChannel.videoChannel);
numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
__FUNCTION__, __LINE__);
@@ -267,6 +284,82 @@
"ERROR: %s at line %d", __FUNCTION__,
__LINE__);
+ error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ //
+ // Test bandwidth statistics with NACK and FEC separately
+ //
+
+ myTransport.ClearStats();
+ myTransport.SetPacketLoss(rate);
+
+ error = ViE.ptrViERtpRtcp->SetFECStatus(tbChannel.videoChannel,
+ true, 96, 97);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ error = ViE.ptrViEBase->StartReceive(tbChannel.videoChannel);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+ error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ AutoTestSleep(KAutoTestSleepTimeMs);
+
+ error = ViE.ptrViERtpRtcp->GetBandwidthUsage(tbChannel.videoChannel,
+ sentTotalBitrate,
+ sentFecBitrate,
+ sentNackBitrate);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ numberOfErrors += ViETest::TestError(sentTotalBitrate > 0 &&
+ sentFecBitrate > 0 &&
+ sentNackBitrate == 0,
+ "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ error = ViE.ptrViEBase->StopSend(tbChannel.videoChannel);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ error = ViE.ptrViERtpRtcp->SetFECStatus(tbChannel.videoChannel,
+ false, 96, 97);
+ error = ViE.ptrViERtpRtcp->SetNACKStatus(tbChannel.videoChannel, true);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ error = ViE.ptrViEBase->StartSend(tbChannel.videoChannel);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ AutoTestSleep(KAutoTestSleepTimeMs);
+
+ error = ViE.ptrViERtpRtcp->GetBandwidthUsage(tbChannel.videoChannel,
+ sentTotalBitrate,
+ sentFecBitrate,
+ sentNackBitrate);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ numberOfErrors += ViETest::TestError(sentTotalBitrate > 0 &&
+ sentFecBitrate == 0 &&
+ sentNackBitrate > 0,
+ "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+
+ error = ViE.ptrViEBase->StopReceive(tbChannel.videoChannel);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
+ error = ViE.ptrViERtpRtcp->SetNACKStatus(tbChannel.videoChannel, false);
+ numberOfErrors += ViETest::TestError(error == 0, "ERROR: %s at line %d",
+ __FUNCTION__, __LINE__);
+
//
// Keepalive
//