Add RTCP packet type counter (for getting statistics such as sent/received NACK and FIR).

Add counter to RTCP sender and RTCP receiver.
Add video api GetRtcpPacketTypes().

BUG=2638
R=mflodman@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/8179004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5575 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
asapersson@webrtc.org 2014-02-19 11:59:02 +00:00
parent b7a91fa95a
commit 8098e07478
15 changed files with 167 additions and 19 deletions

View File

@ -192,6 +192,24 @@ class RtcpStatisticsCallback {
uint32_t ssrc) = 0; uint32_t ssrc) = 0;
}; };
// Statistics for RTCP packet types.
struct RtcpPacketTypeCounter {
RtcpPacketTypeCounter()
: nack_packets(0),
fir_packets(0),
pli_packets(0) {}
void Add(const RtcpPacketTypeCounter& other) {
nack_packets += other.nack_packets;
fir_packets += other.fir_packets;
pli_packets += other.pli_packets;
}
uint32_t nack_packets;
uint32_t fir_packets;
uint32_t pli_packets;
};
// Data usage statistics for a (rtp) stream // Data usage statistics for a (rtp) stream
struct StreamDataCounters { struct StreamDataCounters {
StreamDataCounters() StreamDataCounters()

View File

@ -507,6 +507,13 @@ class RtpRtcp : public Module {
*/ */
virtual int32_t RemoveRTCPReportBlock(const uint32_t SSRC) = 0; virtual int32_t RemoveRTCPReportBlock(const uint32_t SSRC) = 0;
/*
* Get number of sent and received RTCP packet types.
*/
virtual void GetRtcpPacketTypeCounters(
RtcpPacketTypeCounter* packets_sent,
RtcpPacketTypeCounter* packets_received) const = 0;
/* /*
* (APP) Application specific data * (APP) Application specific data
* *

View File

@ -168,6 +168,8 @@ class MockRtpRtcp : public RtpRtcp {
int32_t(const uint32_t SSRC, const RTCPReportBlock* receiveBlock)); int32_t(const uint32_t SSRC, const RTCPReportBlock* receiveBlock));
MOCK_METHOD1(RemoveRTCPReportBlock, MOCK_METHOD1(RemoveRTCPReportBlock,
int32_t(const uint32_t SSRC)); int32_t(const uint32_t SSRC));
MOCK_CONST_METHOD2(GetRtcpPacketTypeCounters,
void(RtcpPacketTypeCounter*, RtcpPacketTypeCounter*));
MOCK_METHOD4(SetRTCPApplicationSpecificData, MOCK_METHOD4(SetRTCPApplicationSpecificData,
int32_t(const uint8_t subType, const uint32_t name, const uint8_t* data, const uint16_t length)); int32_t(const uint8_t subType, const uint32_t name, const uint8_t* data, const uint16_t length));
MOCK_METHOD1(SetRTCPVoIPMetrics, MOCK_METHOD1(SetRTCPVoIPMetrics,

View File

@ -317,6 +317,12 @@ int32_t RTCPReceiver::StatisticsReceived(
return 0; return 0;
} }
void RTCPReceiver::GetPacketTypeCounter(
RtcpPacketTypeCounter* packet_counter) const {
CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
*packet_counter = packet_type_counter_;
}
int32_t int32_t
RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation, RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation,
RTCPUtility::RTCPParserV2* rtcpParser) RTCPUtility::RTCPParserV2* rtcpParser)
@ -839,6 +845,10 @@ RTCPReceiver::HandleNACK(RTCPUtility::RTCPParserV2& rtcpParser,
HandleNACKItem(rtcpPacket, rtcpPacketInformation); HandleNACKItem(rtcpPacket, rtcpPacketInformation);
pktType = rtcpParser.Iterate(); pktType = rtcpParser.Iterate();
} }
if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack) {
++packet_type_counter_.nack_packets;
}
} }
// no need for critsect we have _criticalSectionRTCPReceiver // no need for critsect we have _criticalSectionRTCPReceiver
@ -1028,6 +1038,7 @@ void RTCPReceiver::HandlePLI(RTCPUtility::RTCPParserV2& rtcpParser,
if (main_ssrc_ == rtcpPacket.PLI.MediaSSRC) { if (main_ssrc_ == rtcpPacket.PLI.MediaSSRC) {
TRACE_EVENT_INSTANT0("webrtc_rtp", "PLI"); TRACE_EVENT_INSTANT0("webrtc_rtp", "PLI");
++packet_type_counter_.pli_packets;
// Received a signal that we need to send a new key frame. // Received a signal that we need to send a new key frame.
rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpPli; rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpPli;
} }
@ -1270,6 +1281,9 @@ void RTCPReceiver::HandleFIRItem(RTCPReceiveInformation* receiveInfo,
if (main_ssrc_ != rtcpPacket.FIRItem.SSRC) { if (main_ssrc_ != rtcpPacket.FIRItem.SSRC) {
return; return;
} }
++packet_type_counter_.fir_packets;
// rtcpPacket.FIR.MediaSSRC SHOULD be 0 but we ignore to check it // rtcpPacket.FIR.MediaSSRC SHOULD be 0 but we ignore to check it
// we don't know who this originate from // we don't know who this originate from
if (receiveInfo) { if (receiveInfo) {

View File

@ -88,6 +88,8 @@ public:
int32_t StatisticsReceived( int32_t StatisticsReceived(
std::vector<RTCPReportBlock>* receiveBlocks) const; std::vector<RTCPReportBlock>* receiveBlocks) const;
void GetPacketTypeCounter(RtcpPacketTypeCounter* packet_counter) const;
// Returns true if we haven't received an RTCP RR for several RTCP // Returns true if we haven't received an RTCP RR for several RTCP
// intervals, but only triggers true once. // intervals, but only triggers true once.
bool RtcpRrTimeout(int64_t rtcp_interval_ms); bool RtcpRrTimeout(int64_t rtcp_interval_ms);
@ -266,6 +268,8 @@ protected:
int64_t _lastIncreasedSequenceNumberMs; int64_t _lastIncreasedSequenceNumberMs;
RtcpStatisticsCallback* stats_callback_; RtcpStatisticsCallback* stats_callback_;
RtcpPacketTypeCounter packet_type_counter_;
}; };
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_ #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_

View File

@ -156,10 +156,7 @@ RTCPSender::RTCPSender(const int32_t id,
xrSendReceiverReferenceTimeEnabled_(false), xrSendReceiverReferenceTimeEnabled_(false),
_xrSendVoIPMetric(false), _xrSendVoIPMetric(false),
_xrVoIPMetric(), _xrVoIPMetric()
_nackCount(0),
_pliCount(0),
_fullIntraRequestCount(0)
{ {
memset(_CNAME, 0, sizeof(_CNAME)); memset(_CNAME, 0, sizeof(_CNAME));
memset(_lastSendReport, 0, sizeof(_lastSendReport)); memset(_lastSendReport, 0, sizeof(_lastSendReport));
@ -239,10 +236,7 @@ RTCPSender::Init()
memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime)); memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
last_xr_rr_.clear(); last_xr_rr_.clear();
_nackCount = 0; memset(&packet_type_counter_, 0, sizeof(packet_type_counter_));
_pliCount = 0;
_fullIntraRequestCount = 0;
return 0; return 0;
} }
@ -616,6 +610,12 @@ bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
return true; return true;
} }
void RTCPSender::GetPacketTypeCounter(
RtcpPacketTypeCounter* packet_counter) const {
CriticalSectionScoped lock(_criticalSectionRTCPSender);
*packet_counter = packet_type_counter_;
}
int32_t RTCPSender::AddExternalReportBlock( int32_t RTCPSender::AddExternalReportBlock(
uint32_t SSRC, uint32_t SSRC,
const RTCPReportBlock* reportBlock) { const RTCPReportBlock* reportBlock) {
@ -1919,8 +1919,9 @@ int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
return position; return position;
} }
TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI"); TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI");
_pliCount++; ++packet_type_counter_.pli_packets;
TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_PLICount", _SSRC, _pliCount); TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_PLICount", _SSRC,
packet_type_counter_.pli_packets);
} }
if(rtcpPacketTypeFlags & kRtcpFir) if(rtcpPacketTypeFlags & kRtcpFir)
{ {
@ -1931,9 +1932,9 @@ int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
return position; return position;
} }
TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR"); TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR");
_fullIntraRequestCount++; ++packet_type_counter_.fir_packets;
TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_FIRCount", _SSRC, TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_FIRCount", _SSRC,
_fullIntraRequestCount); packet_type_counter_.fir_packets);
} }
if(rtcpPacketTypeFlags & kRtcpSli) if(rtcpPacketTypeFlags & kRtcpSli)
{ {
@ -2016,8 +2017,9 @@ int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
} }
TRACE_EVENT_INSTANT1("webrtc_rtp", "RTCPSender::NACK", TRACE_EVENT_INSTANT1("webrtc_rtp", "RTCPSender::NACK",
"nacks", TRACE_STR_COPY(nackString.c_str())); "nacks", TRACE_STR_COPY(nackString.c_str()));
_nackCount++; ++packet_type_counter_.nack_packets;
TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_NACKCount", _SSRC, _nackCount); TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_NACKCount", _SSRC,
packet_type_counter_.nack_packets);
} }
if(rtcpPacketTypeFlags & kRtcpXrVoipMetric) if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
{ {

View File

@ -180,6 +180,8 @@ public:
void SetTargetBitrate(unsigned int target_bitrate); void SetTargetBitrate(unsigned int target_bitrate);
void GetPacketTypeCounter(RtcpPacketTypeCounter* packet_counter) const;
private: private:
int32_t SendToNetwork(const uint8_t* dataBuffer, const uint16_t length); int32_t SendToNetwork(const uint8_t* dataBuffer, const uint16_t length);
@ -342,10 +344,7 @@ private:
bool _xrSendVoIPMetric; bool _xrSendVoIPMetric;
RTCPVoIPMetric _xrVoIPMetric; RTCPVoIPMetric _xrVoIPMetric;
// Counters RtcpPacketTypeCounter packet_type_counter_;
uint32_t _nackCount;
uint32_t _pliCount;
uint32_t _fullIntraRequestCount;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -983,6 +983,13 @@ int32_t ModuleRtpRtcpImpl::RemoveRTCPReportBlock(
return rtcp_sender_.RemoveExternalReportBlock(ssrc); return rtcp_sender_.RemoveExternalReportBlock(ssrc);
} }
void ModuleRtpRtcpImpl::GetRtcpPacketTypeCounters(
RtcpPacketTypeCounter* packets_sent,
RtcpPacketTypeCounter* packets_received) const {
rtcp_sender_.GetPacketTypeCounter(packets_sent);
rtcp_receiver_.GetPacketTypeCounter(packets_received);
}
// (REMB) Receiver Estimated Max Bitrate. // (REMB) Receiver Estimated Max Bitrate.
bool ModuleRtpRtcpImpl::REMB() const { bool ModuleRtpRtcpImpl::REMB() const {
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "REMB()"); WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "REMB()");

View File

@ -197,10 +197,14 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
// Set received RTCP report block. // Set received RTCP report block.
virtual int32_t AddRTCPReportBlock( virtual int32_t AddRTCPReportBlock(
const uint32_t ssrc, const RTCPReportBlock* receive_block) OVERRIDE; const uint32_t ssrc, const RTCPReportBlock* receive_block) OVERRIDE;
virtual int32_t RemoveRTCPReportBlock(const uint32_t ssrc) OVERRIDE; virtual int32_t RemoveRTCPReportBlock(const uint32_t ssrc) OVERRIDE;
virtual void GetRtcpPacketTypeCounters(
RtcpPacketTypeCounter* packets_sent,
RtcpPacketTypeCounter* packets_received) const OVERRIDE;
// (REMB) Receiver Estimated Max Bitrate. // (REMB) Receiver Estimated Max Bitrate.
virtual bool REMB() const OVERRIDE; virtual bool REMB() const OVERRIDE;

View File

@ -80,10 +80,22 @@ class RtpRtcpModule {
transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock); transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock);
} }
RtcpPacketTypeCounter packets_sent_;
RtcpPacketTypeCounter packets_received_;
scoped_ptr<ReceiveStatistics> receive_statistics_; scoped_ptr<ReceiveStatistics> receive_statistics_;
SendTransport transport_; SendTransport transport_;
RtcpRttStatsTestImpl rtt_stats_; RtcpRttStatsTestImpl rtt_stats_;
scoped_ptr<ModuleRtpRtcpImpl> impl_; scoped_ptr<ModuleRtpRtcpImpl> impl_;
RtcpPacketTypeCounter RtcpSent() {
impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_);
return packets_sent_;
}
RtcpPacketTypeCounter RtcpReceived() {
impl_->GetRtcpPacketTypeCounters(&packets_sent_, &packets_received_);
return packets_received_;
}
}; };
} // namespace } // namespace
@ -172,4 +184,35 @@ TEST_F(RtpRtcpImplTest, RttForReceiverOnly) {
EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.rtt_stats_.LastProcessedRtt()); EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.rtt_stats_.LastProcessedRtt());
EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.impl_->rtt_ms()); EXPECT_EQ(2 * kOneWayNetworkDelayMs, receiver_.impl_->rtt_ms());
} }
TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_Nack) {
EXPECT_EQ(0U, sender_.RtcpReceived().nack_packets);
EXPECT_EQ(0U, receiver_.RtcpSent().nack_packets);
// Receive module sends a NACK.
const uint16_t kNackLength = 1;
uint16_t nack_list[kNackLength] = {123};
EXPECT_EQ(0, receiver_.impl_->SendNACK(nack_list, kNackLength));
EXPECT_EQ(1U, receiver_.RtcpSent().nack_packets);
// Send module receives the NACK.
EXPECT_EQ(1U, sender_.RtcpReceived().nack_packets);
}
TEST_F(RtpRtcpImplTest, RtcpPacketTypeCounter_FirAndPli) {
EXPECT_EQ(0U, sender_.RtcpReceived().fir_packets);
EXPECT_EQ(0U, receiver_.RtcpSent().fir_packets);
// Receive module sends a FIR.
EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir));
EXPECT_EQ(1U, receiver_.RtcpSent().fir_packets);
// Send module receives the FIR.
EXPECT_EQ(1U, sender_.RtcpReceived().fir_packets);
// Receive module sends a FIR and PLI.
EXPECT_EQ(0, receiver_.impl_->SendRTCP(kRtcpFir | kRtcpPli));
EXPECT_EQ(2U, receiver_.RtcpSent().fir_packets);
EXPECT_EQ(1U, receiver_.RtcpSent().pli_packets);
// Send module receives the FIR and PLI.
EXPECT_EQ(2U, sender_.RtcpReceived().fir_packets);
EXPECT_EQ(1U, sender_.RtcpReceived().pli_packets);
}
} // namespace webrtc } // namespace webrtc

View File

@ -360,6 +360,14 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP {
virtual int DeregisterReceiveChannelRtpStatisticsCallback( virtual int DeregisterReceiveChannelRtpStatisticsCallback(
int video_channel, StreamDataCountersCallback* callback) = 0; int video_channel, StreamDataCountersCallback* callback) = 0;
// Gets sent and received RTCP packet types.
// TODO(asapersson): Remove default implementation.
virtual int GetRtcpPacketTypeCounters(
int video_channel,
RtcpPacketTypeCounter* packets_sent,
RtcpPacketTypeCounter* packets_received) const { return -1; }
// The function gets bandwidth usage statistics from the sent RTP streams in // The function gets bandwidth usage statistics from the sent RTP streams in
// bits/s. // bits/s.
virtual int GetBandwidthUsage(const int video_channel, virtual int GetBandwidthUsage(const int video_channel,

View File

@ -1381,6 +1381,22 @@ void ViEChannel::RegisterReceiveChannelRtpStatisticsCallback(
vie_receiver_.GetReceiveStatistics()->RegisterRtpStatisticsCallback(callback); vie_receiver_.GetReceiveStatistics()->RegisterRtpStatisticsCallback(callback);
} }
void ViEChannel::GetRtcpPacketTypeCounters(
RtcpPacketTypeCounter* packets_sent,
RtcpPacketTypeCounter* packets_received) const {
rtp_rtcp_->GetRtcpPacketTypeCounters(packets_sent, packets_received);
CriticalSectionScoped cs(rtp_rtcp_cs_.get());
for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
it != simulcast_rtp_rtcp_.end(); ++it) {
RtcpPacketTypeCounter sent;
RtcpPacketTypeCounter received;
(*it)->GetRtcpPacketTypeCounters(&sent, &received);
packets_sent->Add(sent);
packets_received->Add(received);
}
}
void ViEChannel::GetBandwidthUsage(uint32_t* total_bitrate_sent, void ViEChannel::GetBandwidthUsage(uint32_t* total_bitrate_sent,
uint32_t* video_bitrate_sent, uint32_t* video_bitrate_sent,
uint32_t* fec_bitrate_sent, uint32_t* fec_bitrate_sent,

View File

@ -202,6 +202,9 @@ class ViEChannel
void RegisterReceiveChannelRtpStatisticsCallback( void RegisterReceiveChannelRtpStatisticsCallback(
StreamDataCountersCallback* callback); StreamDataCountersCallback* callback);
void GetRtcpPacketTypeCounters(RtcpPacketTypeCounter* packets_sent,
RtcpPacketTypeCounter* packets_received) const;
void GetBandwidthUsage(uint32_t* total_bitrate_sent, void GetBandwidthUsage(uint32_t* total_bitrate_sent,
uint32_t* video_bitrate_sent, uint32_t* video_bitrate_sent,
uint32_t* fec_bitrate_sent, uint32_t* fec_bitrate_sent,

View File

@ -938,6 +938,23 @@ int ViERTP_RTCPImpl::GetRtpStatistics(const int video_channel,
return 0; return 0;
} }
int ViERTP_RTCPImpl::GetRtcpPacketTypeCounters(
int video_channel,
RtcpPacketTypeCounter* packets_sent,
RtcpPacketTypeCounter* packets_received) const {
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
ViEChannel* vie_channel = cs.Channel(video_channel);
if (!vie_channel) {
WEBRTC_TRACE(kTraceError, kTraceVideo,
ViEId(shared_data_->instance_id(), video_channel),
"%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
return -1;
}
vie_channel->GetRtcpPacketTypeCounters(packets_sent, packets_received);
return 0;
}
int ViERTP_RTCPImpl::GetBandwidthUsage(const int video_channel, int ViERTP_RTCPImpl::GetBandwidthUsage(const int video_channel,
unsigned int& total_bitrate_sent, unsigned int& total_bitrate_sent,
unsigned int& video_bitrate_sent, unsigned int& video_bitrate_sent,

View File

@ -99,6 +99,10 @@ class ViERTP_RTCPImpl
virtual int GetRtpStatistics(const int video_channel, virtual int GetRtpStatistics(const int video_channel,
StreamDataCounters& sent, StreamDataCounters& sent,
StreamDataCounters& received) const; StreamDataCounters& received) const;
virtual int GetRtcpPacketTypeCounters(
int video_channel,
RtcpPacketTypeCounter* packets_sent,
RtcpPacketTypeCounter* packets_received) const;
virtual int GetBandwidthUsage(const int video_channel, virtual int GetBandwidthUsage(const int video_channel,
unsigned int& total_bitrate_sent, unsigned int& total_bitrate_sent,
unsigned int& video_bitrate_sent, unsigned int& video_bitrate_sent,