Revert 4585 "Revert "Revert 4582 "Reverts a second set of reverts caused by a bug in ..."""

...and fixes the RTCP bug.

BUG=2277
TBR=pbos@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4588 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2013-08-21 20:58:21 +00:00
parent dbf6a81cb5
commit 286fe0b04d
22 changed files with 994 additions and 757 deletions

View File

@ -171,6 +171,7 @@
'rtp_rtcp/source/nack_rtx_unittest.cc', 'rtp_rtcp/source/nack_rtx_unittest.cc',
'rtp_rtcp/source/producer_fec_unittest.cc', 'rtp_rtcp/source/producer_fec_unittest.cc',
'rtp_rtcp/source/receiver_fec_unittest.cc', 'rtp_rtcp/source/receiver_fec_unittest.cc',
'rtp_rtcp/source/receive_statistics_unittest.cc',
'rtp_rtcp/source/rtcp_format_remb_unittest.cc', 'rtp_rtcp/source/rtcp_format_remb_unittest.cc',
'rtp_rtcp/source/rtcp_sender_unittest.cc', 'rtp_rtcp/source/rtcp_sender_unittest.cc',
'rtp_rtcp/source/rtcp_receiver_unittest.cc', 'rtp_rtcp/source/rtcp_receiver_unittest.cc',

View File

@ -11,6 +11,8 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_ #ifndef WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_
#define WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_ #define WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_
#include <map>
#include "webrtc/modules/interface/module.h" #include "webrtc/modules/interface/module.h"
#include "webrtc/modules/interface/module_common_types.h" #include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/typedefs.h" #include "webrtc/typedefs.h"
@ -19,9 +21,16 @@ namespace webrtc {
class Clock; class Clock;
class ReceiveStatistics : public Module { class StreamStatistician {
public: public:
struct RtpReceiveStatistics { struct Statistics {
Statistics()
: fraction_lost(0),
cumulative_lost(0),
extended_max_sequence_number(0),
jitter(0),
max_jitter(0) {}
uint8_t fraction_lost; uint8_t fraction_lost;
uint32_t cumulative_lost; uint32_t cumulative_lost;
uint32_t extended_max_sequence_number; uint32_t extended_max_sequence_number;
@ -29,26 +38,45 @@ class ReceiveStatistics : public Module {
uint32_t max_jitter; uint32_t max_jitter;
}; };
virtual ~StreamStatistician();
virtual bool GetStatistics(Statistics* statistics, bool reset) = 0;
virtual void GetDataCounters(uint32_t* bytes_received,
uint32_t* packets_received) const = 0;
virtual uint32_t BitrateReceived() const = 0;
// Resets all statistics.
virtual void ResetStatistics() = 0;
};
typedef std::map<uint32_t, StreamStatistician*> StatisticianMap;
class ReceiveStatistics : public Module {
public:
virtual ~ReceiveStatistics() {} virtual ~ReceiveStatistics() {}
static ReceiveStatistics* Create(Clock* clock); static ReceiveStatistics* Create(Clock* clock);
// Updates the receive statistics with this packet.
virtual void IncomingPacket(const RTPHeader& rtp_header, size_t bytes, virtual void IncomingPacket(const RTPHeader& rtp_header, size_t bytes,
bool retransmitted, bool in_order) = 0; bool retransmitted, bool in_order) = 0;
virtual bool Statistics(RtpReceiveStatistics* statistics, bool reset) = 0; // Returns a map of all statisticians which have seen an incoming packet
// during the last two seconds.
virtual StatisticianMap GetActiveStatisticians() const = 0;
virtual bool Statistics(RtpReceiveStatistics* statistics, int32_t* missing, // Returns a pointer to the statistician of an ssrc.
bool reset) = 0; virtual StreamStatistician* GetStatistician(uint32_t ssrc) const = 0;
virtual void GetDataCounters(uint32_t* bytes_received,
uint32_t* packets_received) const = 0;
virtual uint32_t BitrateReceived() = 0;
virtual void ResetStatistics() = 0;
virtual void ResetDataCounters() = 0;
}; };
class NullReceiveStatistics : public ReceiveStatistics {
public:
virtual void IncomingPacket(const RTPHeader& rtp_header, size_t bytes,
bool retransmitted, bool in_order) OVERRIDE;
virtual StatisticianMap GetActiveStatisticians() const OVERRIDE;
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
virtual int32_t TimeUntilNextProcess() OVERRIDE;
virtual int32_t Process() OVERRIDE;
};
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_ #endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_

View File

@ -205,13 +205,13 @@ public:
const uint32_t rate) = 0; const uint32_t rate) = 0;
virtual void OnIncomingSSRCChanged( const int32_t id, virtual void OnIncomingSSRCChanged( const int32_t id,
const uint32_t SSRC) = 0; const uint32_t ssrc) = 0;
virtual void OnIncomingCSRCChanged( const int32_t id, virtual void OnIncomingCSRCChanged( const int32_t id,
const uint32_t CSRC, const uint32_t CSRC,
const bool added) = 0; const bool added) = 0;
virtual void ResetStatistics() = 0; virtual void ResetStatistics(uint32_t ssrc) = 0;
protected: protected:
virtual ~RtpFeedback() {} virtual ~RtpFeedback() {}
@ -281,13 +281,13 @@ class NullRtpFeedback : public RtpFeedback {
} }
virtual void OnIncomingSSRCChanged(const int32_t id, virtual void OnIncomingSSRCChanged(const int32_t id,
const uint32_t SSRC) OVERRIDE {} const uint32_t ssrc) OVERRIDE {}
virtual void OnIncomingCSRCChanged(const int32_t id, virtual void OnIncomingCSRCChanged(const int32_t id,
const uint32_t CSRC, const uint32_t CSRC,
const bool added) OVERRIDE {} const bool added) OVERRIDE {}
virtual void ResetStatistics() OVERRIDE {} virtual void ResetStatistics(uint32_t ssrc) OVERRIDE {}
}; };
// Null object version of RtpData. // Null object version of RtpData.

View File

@ -56,8 +56,8 @@ class TestRtpFeedback : public NullRtpFeedback {
virtual ~TestRtpFeedback() {} virtual ~TestRtpFeedback() {}
virtual void OnIncomingSSRCChanged(const int32_t id, virtual void OnIncomingSSRCChanged(const int32_t id,
const uint32_t SSRC) { const uint32_t ssrc) {
rtp_rtcp_->SetRemoteSSRC(SSRC); rtp_rtcp_->SetRemoteSSRC(ssrc);
} }
private: private:

View File

@ -17,41 +17,39 @@
namespace webrtc { namespace webrtc {
enum { kRateUpdateIntervalMs = 1000 }; const int64_t kStatisticsTimeoutMs = 8000;
const int kStatisticsProcessIntervalMs = 1000;
ReceiveStatistics* ReceiveStatistics::Create(Clock* clock) { StreamStatistician::~StreamStatistician() {}
return new ReceiveStatisticsImpl(clock);
}
ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock) StreamStatisticianImpl::StreamStatisticianImpl(Clock* clock)
: crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), : clock_(clock),
clock_(clock), crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
incoming_bitrate_(clock), incoming_bitrate_(clock),
ssrc_(0), ssrc_(0),
jitter_q4_(0), jitter_q4_(0),
jitter_max_q4_(0), jitter_max_q4_(0),
cumulative_loss_(0), cumulative_loss_(0),
jitter_q4_transmission_time_offset_(0), jitter_q4_transmission_time_offset_(0),
local_time_last_received_timestamp_(0), last_receive_time_secs_(0),
last_receive_time_frac_(0),
last_received_timestamp_(0), last_received_timestamp_(0),
last_received_transmission_time_offset_(0), last_received_transmission_time_offset_(0),
received_seq_first_(0), received_seq_first_(0),
received_seq_max_(0), received_seq_max_(0),
received_seq_wraps_(0), received_seq_wraps_(0),
first_packet_(true),
received_packet_overhead_(12), received_packet_overhead_(12),
received_byte_count_(0), received_byte_count_(0),
received_retransmitted_packets_(0), received_retransmitted_packets_(0),
received_inorder_packet_count_(0), received_inorder_packet_count_(0),
last_report_inorder_packets_(0), last_report_inorder_packets_(0),
last_report_old_packets_(0), last_report_old_packets_(0),
last_report_seq_max_(0), last_report_seq_max_(0),
last_reported_statistics_() {} last_reported_statistics_() {}
void ReceiveStatisticsImpl::ResetStatistics() { void StreamStatisticianImpl::ResetStatistics() {
CriticalSectionScoped lock(crit_sect_.get()); CriticalSectionScoped cs(crit_sect_.get());
last_report_inorder_packets_ = 0; last_report_inorder_packets_ = 0;
last_report_old_packets_ = 0; last_report_old_packets_ = 0;
last_report_seq_max_ = 0; last_report_seq_max_ = 0;
@ -66,33 +64,25 @@ void ReceiveStatisticsImpl::ResetStatistics() {
received_byte_count_ = 0; received_byte_count_ = 0;
received_retransmitted_packets_ = 0; received_retransmitted_packets_ = 0;
received_inorder_packet_count_ = 0; received_inorder_packet_count_ = 0;
first_packet_ = true;
} }
void ReceiveStatisticsImpl::ResetDataCounters() { void StreamStatisticianImpl::IncomingPacket(const RTPHeader& header,
CriticalSectionScoped lock(crit_sect_.get());
received_byte_count_ = 0;
received_retransmitted_packets_ = 0;
received_inorder_packet_count_ = 0;
last_report_inorder_packets_ = 0;
}
void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
size_t bytes, size_t bytes,
bool retransmitted, bool retransmitted,
bool in_order) { bool in_order) {
CriticalSectionScoped cs(crit_sect_.get());
ssrc_ = header.ssrc; ssrc_ = header.ssrc;
incoming_bitrate_.Update(bytes); incoming_bitrate_.Update(bytes);
received_byte_count_ += bytes; received_byte_count_ += bytes;
if (received_seq_max_ == 0 && received_seq_wraps_ == 0) { if (first_packet_) {
first_packet_ = false;
// This is the first received report. // This is the first received report.
received_seq_first_ = header.sequenceNumber; received_seq_first_ = header.sequenceNumber;
received_seq_max_ = header.sequenceNumber; received_seq_max_ = header.sequenceNumber;
received_inorder_packet_count_ = 1; received_inorder_packet_count_ = 1;
// Current time in samples. clock_->CurrentNtp(last_receive_time_secs_, last_receive_time_frac_);
local_time_last_received_timestamp_ =
ModuleRTPUtility::GetCurrentRTP(clock_, header.payload_type_frequency);
return; return;
} }
@ -100,8 +90,9 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
// are received, 4 will be ignored. // are received, 4 will be ignored.
if (in_order) { if (in_order) {
// Current time in samples. // Current time in samples.
const uint32_t RTPtime = uint32_t receive_time_secs;
ModuleRTPUtility::GetCurrentRTP(clock_, header.payload_type_frequency); uint32_t receive_time_frac;
clock_->CurrentNtp(receive_time_secs, receive_time_frac);
received_inorder_packet_count_++; received_inorder_packet_count_++;
// Wrong if we use RetransmitOfOldPacket. // Wrong if we use RetransmitOfOldPacket.
@ -116,8 +107,12 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
if (header.timestamp != last_received_timestamp_ && if (header.timestamp != last_received_timestamp_ &&
received_inorder_packet_count_ > 1) { received_inorder_packet_count_ > 1) {
int32_t time_diff_samples = uint32_t receive_time_rtp = ModuleRTPUtility::ConvertNTPTimeToRTP(
(RTPtime - local_time_last_received_timestamp_) - receive_time_secs, receive_time_frac, header.payload_type_frequency);
uint32_t last_receive_time_rtp = ModuleRTPUtility::ConvertNTPTimeToRTP(
last_receive_time_secs_, last_receive_time_frac_,
header.payload_type_frequency);
int32_t time_diff_samples = (receive_time_rtp - last_receive_time_rtp) -
(header.timestamp - last_received_timestamp_); (header.timestamp - last_received_timestamp_);
time_diff_samples = abs(time_diff_samples); time_diff_samples = abs(time_diff_samples);
@ -134,7 +129,7 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
// Extended jitter report, RFC 5450. // Extended jitter report, RFC 5450.
// Actual network jitter, excluding the source-introduced jitter. // Actual network jitter, excluding the source-introduced jitter.
int32_t time_diff_samples_ext = int32_t time_diff_samples_ext =
(RTPtime - local_time_last_received_timestamp_) - (receive_time_rtp - last_receive_time_rtp) -
((header.timestamp + ((header.timestamp +
header.extension.transmissionTimeOffset) - header.extension.transmissionTimeOffset) -
(last_received_timestamp_ + (last_received_timestamp_ +
@ -150,7 +145,8 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
} }
} }
last_received_timestamp_ = header.timestamp; last_received_timestamp_ = header.timestamp;
local_time_last_received_timestamp_ = RTPtime; last_receive_time_secs_ = receive_time_secs;
last_receive_time_frac_ = receive_time_frac;
} else { } else {
if (retransmitted) { if (retransmitted) {
received_retransmitted_packets_++; received_retransmitted_packets_++;
@ -166,18 +162,8 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
received_packet_overhead_ = (15 * received_packet_overhead_ + packet_oh) >> 4; received_packet_overhead_ = (15 * received_packet_overhead_ + packet_oh) >> 4;
} }
bool ReceiveStatisticsImpl::Statistics(RtpReceiveStatistics* statistics, bool StreamStatisticianImpl::GetStatistics(Statistics* statistics, bool reset) {
bool reset) { CriticalSectionScoped cs(crit_sect_.get());
int32_t missing;
return Statistics(statistics, &missing, reset);
}
bool ReceiveStatisticsImpl::Statistics(RtpReceiveStatistics* statistics,
int32_t* missing, bool reset) {
CriticalSectionScoped lock(crit_sect_.get());
assert(missing);
if (received_seq_first_ == 0 && received_byte_count_ == 0) { if (received_seq_first_ == 0 && received_byte_count_ == 0) {
// We have not received anything. // We have not received anything.
return false; return false;
@ -224,20 +210,20 @@ bool ReceiveStatisticsImpl::Statistics(RtpReceiveStatistics* statistics,
received_retransmitted_packets_ - last_report_old_packets_; received_retransmitted_packets_ - last_report_old_packets_;
rec_since_last += retransmitted_packets; rec_since_last += retransmitted_packets;
*missing = 0; int32_t missing = 0;
if (exp_since_last > rec_since_last) { if (exp_since_last > rec_since_last) {
*missing = (exp_since_last - rec_since_last); missing = (exp_since_last - rec_since_last);
} }
uint8_t local_fraction_lost = 0; uint8_t local_fraction_lost = 0;
if (exp_since_last) { if (exp_since_last) {
// Scale 0 to 255, where 255 is 100% loss. // Scale 0 to 255, where 255 is 100% loss.
local_fraction_lost = local_fraction_lost =
static_cast<uint8_t>((255 * (*missing)) / exp_since_last); static_cast<uint8_t>(255 * missing / exp_since_last);
} }
statistics->fraction_lost = local_fraction_lost; statistics->fraction_lost = local_fraction_lost;
// We need a counter for cumulative loss too. // We need a counter for cumulative loss too.
cumulative_loss_ += *missing; cumulative_loss_ += missing;
if (jitter_q4_ > jitter_max_q4_) { if (jitter_q4_ > jitter_max_q4_) {
jitter_max_q4_ = jitter_q4_; jitter_max_q4_ = jitter_q4_;
@ -260,10 +246,9 @@ bool ReceiveStatisticsImpl::Statistics(RtpReceiveStatistics* statistics,
return true; return true;
} }
void ReceiveStatisticsImpl::GetDataCounters( void StreamStatisticianImpl::GetDataCounters(
uint32_t* bytes_received, uint32_t* packets_received) const { uint32_t* bytes_received, uint32_t* packets_received) const {
CriticalSectionScoped lock(crit_sect_.get()); CriticalSectionScoped cs(crit_sect_.get());
if (bytes_received) { if (bytes_received) {
*bytes_received = received_byte_count_; *bytes_received = received_byte_count_;
} }
@ -273,19 +258,124 @@ void ReceiveStatisticsImpl::GetDataCounters(
} }
} }
uint32_t ReceiveStatisticsImpl::BitrateReceived() { uint32_t StreamStatisticianImpl::BitrateReceived() const {
CriticalSectionScoped cs(crit_sect_.get());
return incoming_bitrate_.BitrateNow(); return incoming_bitrate_.BitrateNow();
} }
int32_t ReceiveStatisticsImpl::TimeUntilNextProcess() { void StreamStatisticianImpl::ProcessBitrate() {
int time_since_last_update = clock_->TimeInMilliseconds() - CriticalSectionScoped cs(crit_sect_.get());
incoming_bitrate_.time_last_rate_update(); incoming_bitrate_.Process();
return std::max(kRateUpdateIntervalMs - time_since_last_update, 0); }
void StreamStatisticianImpl::LastReceiveTimeNtp(uint32_t* secs,
uint32_t* frac) const {
CriticalSectionScoped cs(crit_sect_.get());
*secs = last_receive_time_secs_;
*frac = last_receive_time_frac_;
}
ReceiveStatistics* ReceiveStatistics::Create(Clock* clock) {
return new ReceiveStatisticsImpl(clock);
}
ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock)
: clock_(clock),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
last_rate_update_ms_(0) {}
ReceiveStatisticsImpl::~ReceiveStatisticsImpl() {
while (!statisticians_.empty()) {
delete statisticians_.begin()->second;
statisticians_.erase(statisticians_.begin());
}
}
void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
size_t bytes, bool old_packet,
bool in_order) {
CriticalSectionScoped cs(crit_sect_.get());
StatisticianImplMap::iterator it = statisticians_.find(header.ssrc);
if (it == statisticians_.end()) {
std::pair<StatisticianImplMap::iterator, uint32_t> insert_result =
statisticians_.insert(std::make_pair(
header.ssrc, new StreamStatisticianImpl(clock_)));
it = insert_result.first;
}
statisticians_[header.ssrc]->IncomingPacket(header, bytes, old_packet,
in_order);
}
void ReceiveStatisticsImpl::ChangeSsrc(uint32_t from_ssrc, uint32_t to_ssrc) {
CriticalSectionScoped cs(crit_sect_.get());
StatisticianImplMap::iterator from_it = statisticians_.find(from_ssrc);
if (from_it == statisticians_.end())
return;
if (statisticians_.find(to_ssrc) != statisticians_.end())
return;
statisticians_[to_ssrc] = from_it->second;
statisticians_.erase(from_it);
}
StatisticianMap ReceiveStatisticsImpl::GetActiveStatisticians() const {
CriticalSectionScoped cs(crit_sect_.get());
StatisticianMap active_statisticians;
for (StatisticianImplMap::const_iterator it = statisticians_.begin();
it != statisticians_.end(); ++it) {
uint32_t secs;
uint32_t frac;
it->second->LastReceiveTimeNtp(&secs, &frac);
if (clock_->CurrentNtpInMilliseconds() -
Clock::NtpToMs(secs, frac) < kStatisticsTimeoutMs) {
active_statisticians[it->first] = it->second;
}
}
return active_statisticians;
}
StreamStatistician* ReceiveStatisticsImpl::GetStatistician(
uint32_t ssrc) const {
CriticalSectionScoped cs(crit_sect_.get());
StatisticianImplMap::const_iterator it = statisticians_.find(ssrc);
if (it == statisticians_.end())
return NULL;
return it->second;
} }
int32_t ReceiveStatisticsImpl::Process() { int32_t ReceiveStatisticsImpl::Process() {
incoming_bitrate_.Process(); CriticalSectionScoped cs(crit_sect_.get());
for (StatisticianImplMap::iterator it = statisticians_.begin();
it != statisticians_.end(); ++it) {
it->second->ProcessBitrate();
}
last_rate_update_ms_ = clock_->TimeInMilliseconds();
return 0; return 0;
} }
int32_t ReceiveStatisticsImpl::TimeUntilNextProcess() {
CriticalSectionScoped cs(crit_sect_.get());
int time_since_last_update = clock_->TimeInMilliseconds() -
last_rate_update_ms_;
return std::max(kStatisticsProcessIntervalMs - time_since_last_update, 0);
}
void NullReceiveStatistics::IncomingPacket(const RTPHeader& rtp_header,
size_t bytes,
bool retransmitted,
bool in_order) {}
StatisticianMap NullReceiveStatistics::GetActiveStatisticians() const {
return StatisticianMap();
}
StreamStatistician* NullReceiveStatistics::GetStatistician(
uint32_t ssrc) const {
return NULL;
}
int32_t NullReceiveStatistics::TimeUntilNextProcess() { return 0; }
int32_t NullReceiveStatistics::Process() { return 0; }
} // namespace webrtc } // namespace webrtc

View File

@ -23,43 +23,43 @@ namespace webrtc {
class CriticalSectionWrapper; class CriticalSectionWrapper;
class ReceiveStatisticsImpl : public ReceiveStatistics { class StreamStatisticianImpl : public StreamStatistician {
public: public:
explicit ReceiveStatisticsImpl(Clock* clock); explicit StreamStatisticianImpl(Clock* clock);
// Implements ReceiveStatistics. virtual ~StreamStatisticianImpl() {}
void IncomingPacket(const RTPHeader& header, size_t bytes,
bool old_packet, bool in_order);
bool Statistics(RtpReceiveStatistics* statistics, bool reset);
bool Statistics(RtpReceiveStatistics* statistics, int32_t* missing,
bool reset);
void GetDataCounters(uint32_t* bytes_received,
uint32_t* packets_received) const;
uint32_t BitrateReceived();
void ResetStatistics();
void ResetDataCounters();
// Implements Module. virtual bool GetStatistics(Statistics* statistics, bool reset) OVERRIDE;
int32_t TimeUntilNextProcess(); virtual void GetDataCounters(uint32_t* bytes_received,
int32_t Process(); uint32_t* packets_received) const OVERRIDE;
virtual uint32_t BitrateReceived() const OVERRIDE;
virtual void ResetStatistics() OVERRIDE;
void IncomingPacket(const RTPHeader& rtp_header, size_t bytes,
bool retransmitted, bool in_order);
void ProcessBitrate();
virtual void LastReceiveTimeNtp(uint32_t* secs, uint32_t* frac) const;
private: private:
scoped_ptr<CriticalSectionWrapper> crit_sect_;
Clock* clock_; Clock* clock_;
scoped_ptr<CriticalSectionWrapper> crit_sect_;
Bitrate incoming_bitrate_; Bitrate incoming_bitrate_;
uint32_t ssrc_; uint32_t ssrc_;
// Stats on received RTP packets. // Stats on received RTP packets.
uint32_t jitter_q4_; uint32_t jitter_q4_;
uint32_t jitter_max_q4_; uint32_t jitter_max_q4_;
uint32_t cumulative_loss_; uint32_t cumulative_loss_;
uint32_t jitter_q4_transmission_time_offset_; uint32_t jitter_q4_transmission_time_offset_;
uint32_t local_time_last_received_timestamp_; uint32_t last_receive_time_secs_;
uint32_t last_receive_time_frac_;
uint32_t last_received_timestamp_; uint32_t last_received_timestamp_;
int32_t last_received_transmission_time_offset_; int32_t last_received_transmission_time_offset_;
uint16_t received_seq_first_; uint16_t received_seq_first_;
uint16_t received_seq_max_; uint16_t received_seq_max_;
uint16_t received_seq_wraps_; uint16_t received_seq_wraps_;
bool first_packet_;
// Current counter values. // Current counter values.
uint16_t received_packet_overhead_; uint16_t received_packet_overhead_;
@ -71,7 +71,34 @@ class ReceiveStatisticsImpl : public ReceiveStatistics {
uint32_t last_report_inorder_packets_; uint32_t last_report_inorder_packets_;
uint32_t last_report_old_packets_; uint32_t last_report_old_packets_;
uint16_t last_report_seq_max_; uint16_t last_report_seq_max_;
RtpReceiveStatistics last_reported_statistics_; Statistics last_reported_statistics_;
};
class ReceiveStatisticsImpl : public ReceiveStatistics {
public:
explicit ReceiveStatisticsImpl(Clock* clock);
~ReceiveStatisticsImpl();
// Implement ReceiveStatistics.
virtual void IncomingPacket(const RTPHeader& header, size_t bytes,
bool old_packet, bool in_order) OVERRIDE;
virtual StatisticianMap GetActiveStatisticians() const OVERRIDE;
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
// Implement Module.
virtual int32_t Process() OVERRIDE;
virtual int32_t TimeUntilNextProcess() OVERRIDE;
void ChangeSsrc(uint32_t from_ssrc, uint32_t to_ssrc);
private:
typedef std::map<uint32_t, StreamStatisticianImpl*> StatisticianImplMap;
Clock* clock_;
scoped_ptr<CriticalSectionWrapper> crit_sect_;
int64_t last_rate_update_ms_;
StatisticianImplMap statisticians_;
}; };
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_ #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
namespace webrtc {
const int kPacketSize1 = 100;
const int kPacketSize2 = 300;
const uint32_t kSsrc1 = 1;
const uint32_t kSsrc2 = 2;
const uint32_t kSsrc3 = 3;
class ReceiveStatisticsTest : public ::testing::Test {
public:
ReceiveStatisticsTest() :
clock_(0),
receive_statistics_(ReceiveStatistics::Create(&clock_)) {
memset(&header1_, 0, sizeof(header1_));
header1_.ssrc = kSsrc1;
header1_.sequenceNumber = 0;
memset(&header2_, 0, sizeof(header2_));
header2_.ssrc = kSsrc2;
header2_.sequenceNumber = 0;
}
protected:
SimulatedClock clock_;
scoped_ptr<ReceiveStatistics> receive_statistics_;
RTPHeader header1_;
RTPHeader header2_;
};
TEST_F(ReceiveStatisticsTest, TwoIncomingSsrcs) {
receive_statistics_->IncomingPacket(header1_, kPacketSize1, false, true);
++header1_.sequenceNumber;
receive_statistics_->IncomingPacket(header2_, kPacketSize2, false, true);
++header2_.sequenceNumber;
clock_.AdvanceTimeMilliseconds(100);
receive_statistics_->IncomingPacket(header1_, kPacketSize1, false, true);
++header1_.sequenceNumber;
receive_statistics_->IncomingPacket(header2_, kPacketSize2, false, true);
++header2_.sequenceNumber;
StreamStatistician* statistician =
receive_statistics_->GetStatistician(kSsrc1);
ASSERT_TRUE(statistician != NULL);
EXPECT_GT(statistician->BitrateReceived(), 0u);
uint32_t bytes_received = 0;
uint32_t packets_received = 0;
statistician->GetDataCounters(&bytes_received, &packets_received);
EXPECT_EQ(200u, bytes_received);
EXPECT_EQ(2u, packets_received);
statistician =
receive_statistics_->GetStatistician(kSsrc2);
ASSERT_TRUE(statistician != NULL);
EXPECT_GT(statistician->BitrateReceived(), 0u);
statistician->GetDataCounters(&bytes_received, &packets_received);
EXPECT_EQ(600u, bytes_received);
EXPECT_EQ(2u, packets_received);
StatisticianMap statisticians = receive_statistics_->GetActiveStatisticians();
EXPECT_EQ(2u, statisticians.size());
// Add more incoming packets and verify that they are registered in both
// access methods.
receive_statistics_->IncomingPacket(header1_, kPacketSize1, false, true);
++header1_.sequenceNumber;
receive_statistics_->IncomingPacket(header2_, kPacketSize2, false, true);
++header2_.sequenceNumber;
statisticians[kSsrc1]->GetDataCounters(&bytes_received, &packets_received);
EXPECT_EQ(300u, bytes_received);
EXPECT_EQ(3u, packets_received);
statisticians[kSsrc2]->GetDataCounters(&bytes_received, &packets_received);
EXPECT_EQ(900u, bytes_received);
EXPECT_EQ(3u, packets_received);
receive_statistics_->GetStatistician(kSsrc1)->GetDataCounters(
&bytes_received, &packets_received);
EXPECT_EQ(300u, bytes_received);
EXPECT_EQ(3u, packets_received);
receive_statistics_->GetStatistician(kSsrc2)->GetDataCounters(
&bytes_received, &packets_received);
EXPECT_EQ(900u, bytes_received);
EXPECT_EQ(3u, packets_received);
}
TEST_F(ReceiveStatisticsTest, ActiveStatisticians) {
receive_statistics_->IncomingPacket(header1_, kPacketSize1, false, true);
++header1_.sequenceNumber;
clock_.AdvanceTimeMilliseconds(1000);
receive_statistics_->IncomingPacket(header2_, kPacketSize2, false, true);
++header2_.sequenceNumber;
StatisticianMap statisticians = receive_statistics_->GetActiveStatisticians();
// Nothing should time out since only 1000 ms has passed since the first
// packet came in.
EXPECT_EQ(2u, statisticians.size());
clock_.AdvanceTimeMilliseconds(7000);
// kSsrc1 should have timed out.
statisticians = receive_statistics_->GetActiveStatisticians();
EXPECT_EQ(1u, statisticians.size());
clock_.AdvanceTimeMilliseconds(1000);
// kSsrc2 should have timed out.
statisticians = receive_statistics_->GetActiveStatisticians();
EXPECT_EQ(0u, statisticians.size());
receive_statistics_->IncomingPacket(header1_, kPacketSize1, false, true);
++header1_.sequenceNumber;
// kSsrc1 should be active again and the data counters should have survived.
statisticians = receive_statistics_->GetActiveStatisticians();
EXPECT_EQ(1u, statisticians.size());
StreamStatistician* statistician =
receive_statistics_->GetStatistician(kSsrc1);
ASSERT_TRUE(statistician != NULL);
uint32_t bytes_received = 0;
uint32_t packets_received = 0;
statistician->GetDataCounters(&bytes_received, &packets_received);
EXPECT_EQ(200u, bytes_received);
EXPECT_EQ(2u, packets_received);
}
} // namespace webrtc

View File

@ -61,6 +61,7 @@ class RtcpFormatRembTest : public ::testing::Test {
RtcpFormatRembTest() RtcpFormatRembTest()
: over_use_detector_options_(), : over_use_detector_options_(),
system_clock_(Clock::GetRealTimeClock()), system_clock_(Clock::GetRealTimeClock()),
receive_statistics_(ReceiveStatistics::Create(system_clock_)),
remote_bitrate_observer_(), remote_bitrate_observer_(),
remote_bitrate_estimator_( remote_bitrate_estimator_(
RemoteBitrateEstimatorFactory().Create( RemoteBitrateEstimatorFactory().Create(
@ -72,6 +73,7 @@ class RtcpFormatRembTest : public ::testing::Test {
OverUseDetectorOptions over_use_detector_options_; OverUseDetectorOptions over_use_detector_options_;
Clock* system_clock_; Clock* system_clock_;
ModuleRtpRtcpImpl* dummy_rtp_rtcp_impl_; ModuleRtpRtcpImpl* dummy_rtp_rtcp_impl_;
scoped_ptr<ReceiveStatistics> receive_statistics_;
RTCPSender* rtcp_sender_; RTCPSender* rtcp_sender_;
RTCPReceiver* rtcp_receiver_; RTCPReceiver* rtcp_receiver_;
TestTransport* test_transport_; TestTransport* test_transport_;
@ -86,7 +88,8 @@ void RtcpFormatRembTest::SetUp() {
configuration.clock = system_clock_; configuration.clock = system_clock_;
configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get(); configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get();
dummy_rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration); dummy_rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration);
rtcp_sender_ = new RTCPSender(0, false, system_clock_, dummy_rtp_rtcp_impl_); rtcp_sender_ = new RTCPSender(0, false, system_clock_, dummy_rtp_rtcp_impl_,
receive_statistics_.get());
rtcp_receiver_ = new RTCPReceiver(0, system_clock_, dummy_rtp_rtcp_impl_); rtcp_receiver_ = new RTCPReceiver(0, system_clock_, dummy_rtp_rtcp_impl_);
test_transport_ = new TestTransport(rtcp_receiver_); test_transport_ = new TestTransport(rtcp_receiver_);
@ -115,15 +118,13 @@ TEST_F(RtcpFormatRembTest, TestNonCompund) {
uint32_t SSRC = 456789; uint32_t SSRC = 456789;
EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpNonCompound)); EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpNonCompound));
EXPECT_EQ(0, rtcp_sender_->SetREMBData(1234, 1, &SSRC)); EXPECT_EQ(0, rtcp_sender_->SetREMBData(1234, 1, &SSRC));
EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRemb, NULL)); EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRemb));
} }
TEST_F(RtcpFormatRembTest, TestCompund) { TEST_F(RtcpFormatRembTest, TestCompund) {
uint32_t SSRCs[2] = {456789, 98765}; uint32_t SSRCs[2] = {456789, 98765};
EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound)); EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
EXPECT_EQ(0, rtcp_sender_->SetREMBData(1234, 2, SSRCs)); EXPECT_EQ(0, rtcp_sender_->SetREMBData(1234, 2, SSRCs));
ReceiveStatistics::RtpReceiveStatistics receive_stats; EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRemb));
memset(&receive_stats, 0, sizeof(receive_stats));
EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRemb, &receive_stats));
} }
} // namespace } // namespace

View File

@ -68,7 +68,8 @@ std::string NACKStringBuilder::GetResult()
RTCPSender::RTCPSender(const int32_t id, RTCPSender::RTCPSender(const int32_t id,
const bool audio, const bool audio,
Clock* clock, Clock* clock,
ModuleRtpRtcpImpl* owner) : ModuleRtpRtcpImpl* owner,
ReceiveStatistics* receive_statistics) :
_id(id), _id(id),
_audio(audio), _audio(audio),
_clock(clock), _clock(clock),
@ -92,7 +93,9 @@ RTCPSender::RTCPSender(const int32_t id,
_SSRC(0), _SSRC(0),
_remoteSSRC(0), _remoteSSRC(0),
_CNAME(), _CNAME(),
_reportBlocks(), receive_statistics_(receive_statistics),
internal_report_blocks_(),
external_report_blocks_(),
_csrcCNAMEs(), _csrcCNAMEs(),
_cameraDelayMS(0), _cameraDelayMS(0),
@ -137,11 +140,15 @@ RTCPSender::~RTCPSender() {
delete [] _rembSSRC; delete [] _rembSSRC;
delete [] _appData; delete [] _appData;
while (!_reportBlocks.empty()) { while (!internal_report_blocks_.empty()) {
delete internal_report_blocks_.begin()->second;
internal_report_blocks_.erase(internal_report_blocks_.begin());
}
while (!external_report_blocks_.empty()) {
std::map<uint32_t, RTCPReportBlock*>::iterator it = std::map<uint32_t, RTCPReportBlock*>::iterator it =
_reportBlocks.begin(); external_report_blocks_.begin();
delete it->second; delete it->second;
_reportBlocks.erase(it); external_report_blocks_.erase(it);
} }
while (!_csrcCNAMEs.empty()) { while (!_csrcCNAMEs.empty()) {
std::map<uint32_t, RTCPCnameInformation*>::iterator it = std::map<uint32_t, RTCPCnameInformation*>::iterator it =
@ -271,7 +278,7 @@ RTCPSender::SetSendingStatus(const bool sending)
} }
if(sendRTCPBye) if(sendRTCPBye)
{ {
return SendRTCP(kRtcpBye, NULL); return SendRTCP(kRtcpBye);
} }
return 0; return 0;
} }
@ -559,52 +566,59 @@ RTCPSender::SendTimeOfSendReport(const uint32_t sendReport)
return 0; return 0;
} }
int32_t RTCPSender::AddReportBlock(const uint32_t SSRC, int32_t RTCPSender::AddExternalReportBlock(
uint32_t SSRC,
const RTCPReportBlock* reportBlock) {
CriticalSectionScoped lock(_criticalSectionRTCPSender);
return AddReportBlock(SSRC, &external_report_blocks_, reportBlock);
}
int32_t RTCPSender::AddReportBlock(
uint32_t SSRC,
std::map<uint32_t, RTCPReportBlock*>* report_blocks,
const RTCPReportBlock* reportBlock) { const RTCPReportBlock* reportBlock) {
if (reportBlock == NULL) { if (reportBlock == NULL) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"%s invalid argument", __FUNCTION__); "%s invalid argument", __FUNCTION__);
return -1; return -1;
} }
CriticalSectionScoped lock(_criticalSectionRTCPSender);
if (_reportBlocks.size() >= RTCP_MAX_REPORT_BLOCKS) { if (report_blocks->size() >= RTCP_MAX_REPORT_BLOCKS) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"%s invalid argument", __FUNCTION__); "%s invalid argument", __FUNCTION__);
return -1; return -1;
} }
std::map<uint32_t, RTCPReportBlock*>::iterator it = std::map<uint32_t, RTCPReportBlock*>::iterator it =
_reportBlocks.find(SSRC); report_blocks->find(SSRC);
if (it != _reportBlocks.end()) { if (it != report_blocks->end()) {
delete it->second; delete it->second;
_reportBlocks.erase(it); report_blocks->erase(it);
} }
RTCPReportBlock* copyReportBlock = new RTCPReportBlock(); RTCPReportBlock* copyReportBlock = new RTCPReportBlock();
memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock)); memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock));
_reportBlocks[SSRC] = copyReportBlock; (*report_blocks)[SSRC] = copyReportBlock;
return 0; return 0;
} }
int32_t RTCPSender::RemoveReportBlock(const uint32_t SSRC) { int32_t RTCPSender::RemoveExternalReportBlock(uint32_t SSRC) {
CriticalSectionScoped lock(_criticalSectionRTCPSender); CriticalSectionScoped lock(_criticalSectionRTCPSender);
std::map<uint32_t, RTCPReportBlock*>::iterator it = std::map<uint32_t, RTCPReportBlock*>::iterator it =
_reportBlocks.find(SSRC); external_report_blocks_.find(SSRC);
if (it == _reportBlocks.end()) { if (it == external_report_blocks_.end()) {
return -1; return -1;
} }
delete it->second; delete it->second;
_reportBlocks.erase(it); external_report_blocks_.erase(it);
return 0; return 0;
} }
int32_t int32_t
RTCPSender::BuildSR(uint8_t* rtcpbuffer, RTCPSender::BuildSR(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint32_t NTPsec, const uint32_t NTPsec,
const uint32_t NTPfrac, const uint32_t NTPfrac)
const RTCPReportBlock* received)
{ {
// sanity // sanity
if(pos + 52 >= IP_PACKET_SIZE) if(pos + 52 >= IP_PACKET_SIZE)
@ -672,12 +686,15 @@ RTCPSender::BuildSR(uint8_t* rtcpbuffer,
pos += 4; pos += 4;
uint8_t numberOfReportBlocks = 0; uint8_t numberOfReportBlocks = 0;
int32_t retVal = AddReportBlocks(rtcpbuffer, pos, numberOfReportBlocks, received, NTPsec, NTPfrac); int32_t retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
numberOfReportBlocks,
NTPsec, NTPfrac);
if(retVal < 0) if(retVal < 0)
{ {
// //
return retVal ; return retVal ;
} }
pos = retVal;
rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks; rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
uint16_t len = uint16_t((pos/4) -1); uint16_t len = uint16_t((pos/4) -1);
@ -686,8 +703,7 @@ RTCPSender::BuildSR(uint8_t* rtcpbuffer,
} }
int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, int& pos) {
uint32_t& pos) {
size_t lengthCname = strlen(_CNAME); size_t lengthCname = strlen(_CNAME);
assert(lengthCname < RTCP_CNAME_SIZE); assert(lengthCname < RTCP_CNAME_SIZE);
@ -782,10 +798,9 @@ int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer,
int32_t int32_t
RTCPSender::BuildRR(uint8_t* rtcpbuffer, RTCPSender::BuildRR(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint32_t NTPsec, const uint32_t NTPsec,
const uint32_t NTPfrac, const uint32_t NTPfrac)
const RTCPReportBlock* received)
{ {
// sanity one block // sanity one block
if(pos + 32 >= IP_PACKET_SIZE) if(pos + 32 >= IP_PACKET_SIZE)
@ -806,11 +821,14 @@ RTCPSender::BuildRR(uint8_t* rtcpbuffer,
pos += 4; pos += 4;
uint8_t numberOfReportBlocks = 0; uint8_t numberOfReportBlocks = 0;
int32_t retVal = AddReportBlocks(rtcpbuffer, pos, numberOfReportBlocks, received, NTPsec, NTPfrac); int retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
numberOfReportBlocks,
NTPsec, NTPfrac);
if(retVal < 0) if(retVal < 0)
{ {
return retVal; return pos;
} }
pos = retVal;
rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks; rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
uint16_t len = uint16_t((pos)/4 -1); uint16_t len = uint16_t((pos)/4 -1);
@ -839,10 +857,10 @@ RTCPSender::BuildRR(uint8_t* rtcpbuffer,
int32_t int32_t
RTCPSender::BuildExtendedJitterReport( RTCPSender::BuildExtendedJitterReport(
uint8_t* rtcpbuffer, uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint32_t jitterTransmissionTimeOffset) const uint32_t jitterTransmissionTimeOffset)
{ {
if (_reportBlocks.size() > 0) if (external_report_blocks_.size() > 0)
{ {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Not implemented."); WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Not implemented.");
return 0; return 0;
@ -870,7 +888,7 @@ RTCPSender::BuildExtendedJitterReport(
} }
int32_t int32_t
RTCPSender::BuildPLI(uint8_t* rtcpbuffer, uint32_t& pos) RTCPSender::BuildPLI(uint8_t* rtcpbuffer, int& pos)
{ {
// sanity // sanity
if(pos + 12 >= IP_PACKET_SIZE) if(pos + 12 >= IP_PACKET_SIZE)
@ -897,7 +915,7 @@ RTCPSender::BuildPLI(uint8_t* rtcpbuffer, uint32_t& pos)
} }
int32_t RTCPSender::BuildFIR(uint8_t* rtcpbuffer, int32_t RTCPSender::BuildFIR(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
bool repeat) { bool repeat) {
// sanity // sanity
if(pos + 20 >= IP_PACKET_SIZE) { if(pos + 20 >= IP_PACKET_SIZE) {
@ -946,7 +964,7 @@ int32_t RTCPSender::BuildFIR(uint8_t* rtcpbuffer,
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/ */
int32_t int32_t
RTCPSender::BuildSLI(uint8_t* rtcpbuffer, uint32_t& pos, const uint8_t pictureID) RTCPSender::BuildSLI(uint8_t* rtcpbuffer, int& pos, const uint8_t pictureID)
{ {
// sanity // sanity
if(pos + 16 >= IP_PACKET_SIZE) if(pos + 16 >= IP_PACKET_SIZE)
@ -993,7 +1011,7 @@ RTCPSender::BuildSLI(uint8_t* rtcpbuffer, uint32_t& pos, const uint8_t pictureID
*/ */
int32_t int32_t
RTCPSender::BuildRPSI(uint8_t* rtcpbuffer, RTCPSender::BuildRPSI(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint64_t pictureID, const uint64_t pictureID,
const uint8_t payloadType) const uint8_t payloadType)
{ {
@ -1069,7 +1087,7 @@ RTCPSender::BuildRPSI(uint8_t* rtcpbuffer,
} }
int32_t int32_t
RTCPSender::BuildREMB(uint8_t* rtcpbuffer, uint32_t& pos) RTCPSender::BuildREMB(uint8_t* rtcpbuffer, int& pos)
{ {
// sanity // sanity
if(pos + 20 + 4 * _lengthRembSSRC >= IP_PACKET_SIZE) if(pos + 20 + 4 * _lengthRembSSRC >= IP_PACKET_SIZE)
@ -1130,7 +1148,7 @@ RTCPSender::SetTargetBitrate(unsigned int target_bitrate)
} }
int32_t int32_t
RTCPSender::BuildTMMBR(uint8_t* rtcpbuffer, uint32_t& pos) RTCPSender::BuildTMMBR(uint8_t* rtcpbuffer, int& pos)
{ {
// Before sending the TMMBR check the received TMMBN, only an owner is allowed to raise the bitrate // Before sending the TMMBR check the received TMMBN, only an owner is allowed to raise the bitrate
// If the sender is an owner of the TMMBN -> send TMMBR // If the sender is an owner of the TMMBN -> send TMMBR
@ -1236,7 +1254,7 @@ RTCPSender::BuildTMMBR(uint8_t* rtcpbuffer, uint32_t& pos)
} }
int32_t int32_t
RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, uint32_t& pos) RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, int& pos)
{ {
TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend(); TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend();
if(boundingSet == NULL) if(boundingSet == NULL)
@ -1308,7 +1326,7 @@ RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, uint32_t& pos)
} }
int32_t int32_t
RTCPSender::BuildAPP(uint8_t* rtcpbuffer, uint32_t& pos) RTCPSender::BuildAPP(uint8_t* rtcpbuffer, int& pos)
{ {
// sanity // sanity
if(_appData == NULL) if(_appData == NULL)
@ -1346,7 +1364,7 @@ RTCPSender::BuildAPP(uint8_t* rtcpbuffer, uint32_t& pos)
int32_t int32_t
RTCPSender::BuildNACK(uint8_t* rtcpbuffer, RTCPSender::BuildNACK(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const int32_t nackSize, const int32_t nackSize,
const uint16_t* nackList, const uint16_t* nackList,
std::string* nackString) std::string* nackString)
@ -1416,7 +1434,7 @@ RTCPSender::BuildNACK(uint8_t* rtcpbuffer,
} }
int32_t int32_t
RTCPSender::BuildBYE(uint8_t* rtcpbuffer, uint32_t& pos) RTCPSender::BuildBYE(uint8_t* rtcpbuffer, int& pos)
{ {
// sanity // sanity
if(pos + 8 >= IP_PACKET_SIZE) if(pos + 8 >= IP_PACKET_SIZE)
@ -1461,7 +1479,7 @@ RTCPSender::BuildBYE(uint8_t* rtcpbuffer, uint32_t& pos)
} }
int32_t int32_t
RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, uint32_t& pos) RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos)
{ {
// sanity // sanity
if(pos + 44 >= IP_PACKET_SIZE) if(pos + 44 >= IP_PACKET_SIZE)
@ -1536,26 +1554,11 @@ RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, uint32_t& pos)
int32_t int32_t
RTCPSender::SendRTCP( RTCPSender::SendRTCP(
uint32_t packetTypeFlags, uint32_t packetTypeFlags,
const ReceiveStatistics::RtpReceiveStatistics* receive_stats,
int32_t nackSize, int32_t nackSize,
const uint16_t* nackList, const uint16_t* nackList,
bool repeat, bool repeat,
uint64_t pictureID) uint64_t pictureID)
{ {
uint32_t rtcpPacketTypeFlags = packetTypeFlags;
uint32_t pos = 0;
uint8_t rtcpbuffer[IP_PACKET_SIZE];
do // only to be able to use break :) (and the critsect must be inside its own scope)
{
// collect the received information
RTCPReportBlock received;
bool hasReceived = false;
uint32_t NTPsec = 0;
uint32_t NTPfrac = 0;
bool rtcpCompound = false;
uint32_t jitterTransmissionOffset = 0;
{ {
CriticalSectionScoped lock(_criticalSectionRTCPSender); CriticalSectionScoped lock(_criticalSectionRTCPSender);
if(_method == kRtcpOff) if(_method == kRtcpOff)
@ -1564,64 +1567,39 @@ RTCPSender::SendRTCP(
"%s invalid state", __FUNCTION__); "%s invalid state", __FUNCTION__);
return -1; return -1;
} }
rtcpCompound = (_method == kRtcpCompound) ? true : false;
} }
uint8_t rtcp_buffer[IP_PACKET_SIZE];
if (rtcpCompound || int rtcp_length = PrepareRTCP(packetTypeFlags, nackSize, nackList, repeat,
rtcpPacketTypeFlags & kRtcpReport || pictureID, rtcp_buffer, IP_PACKET_SIZE);
rtcpPacketTypeFlags & kRtcpSr || if (rtcp_length < 0) {
rtcpPacketTypeFlags & kRtcpRr) return -1;
{
// Do we have receive statistics to send?
if (receive_stats)
{
received.fractionLost = receive_stats->fraction_lost;
received.cumulativeLost = receive_stats->cumulative_lost;
received.extendedHighSeqNum =
receive_stats->extended_max_sequence_number;
received.jitter = receive_stats->jitter;
jitterTransmissionOffset = 0;
hasReceived = true;
uint32_t lastReceivedRRNTPsecs = 0;
uint32_t lastReceivedRRNTPfrac = 0;
uint32_t remoteSR = 0;
// ok even if we have not received a SR, we will send 0 in that case
_rtpRtcp.LastReceivedNTP(lastReceivedRRNTPsecs,
lastReceivedRRNTPfrac,
remoteSR);
// get our NTP as late as possible to avoid a race
_clock->CurrentNtp(NTPsec, NTPfrac);
// Delay since last received report
uint32_t delaySinceLastReceivedSR = 0;
if((lastReceivedRRNTPsecs !=0) || (lastReceivedRRNTPfrac !=0))
{
// get the 16 lowest bits of seconds and the 16 higest bits of fractions
uint32_t now=NTPsec&0x0000FFFF;
now <<=16;
now += (NTPfrac&0xffff0000)>>16;
uint32_t receiveTime = lastReceivedRRNTPsecs&0x0000FFFF;
receiveTime <<=16;
receiveTime += (lastReceivedRRNTPfrac&0xffff0000)>>16;
delaySinceLastReceivedSR = now-receiveTime;
} }
received.delaySinceLastSR = delaySinceLastReceivedSR; // Sanity don't send empty packets.
received.lastSR = remoteSR; if (rtcp_length == 0)
} else
{ {
// we need to send our NTP even if we dont have received any reports return -1;
_clock->CurrentNtp(NTPsec, NTPfrac);
}
} }
return SendToNetwork(rtcp_buffer, static_cast<uint16_t>(rtcp_length));
}
int RTCPSender::PrepareRTCP(
uint32_t packetTypeFlags,
int32_t nackSize,
const uint16_t* nackList,
bool repeat,
uint64_t pictureID,
uint8_t* rtcp_buffer,
int buffer_size) {
uint32_t rtcpPacketTypeFlags = packetTypeFlags;
// Collect the received information.
uint32_t NTPsec = 0;
uint32_t NTPfrac = 0;
uint32_t jitterTransmissionOffset = 0;
int position = 0;
CriticalSectionScoped lock(_criticalSectionRTCPSender); CriticalSectionScoped lock(_criticalSectionRTCPSender);
if(_TMMBR ) // attach TMMBR to send and receive reports if(_TMMBR ) // Attach TMMBR to send and receive reports.
{ {
rtcpPacketTypeFlags |= kRtcpTmmbr; rtcpPacketTypeFlags |= kRtcpTmmbr;
} }
@ -1641,7 +1619,7 @@ RTCPSender::SendRTCP(
rtcpPacketTypeFlags |= kRtcpXrVoipMetric; rtcpPacketTypeFlags |= kRtcpXrVoipMetric;
_xrSendVoIPMetric = false; _xrSendVoIPMetric = false;
} }
if(_sendTMMBN) // set when having received a TMMBR if(_sendTMMBN) // Set when having received a TMMBR.
{ {
rtcpPacketTypeFlags |= kRtcpTmmbn; rtcpPacketTypeFlags |= kRtcpTmmbn;
_sendTMMBN = false; _sendTMMBN = false;
@ -1656,10 +1634,6 @@ RTCPSender::SendRTCP(
{ {
rtcpPacketTypeFlags |= kRtcpRr; rtcpPacketTypeFlags |= kRtcpRr;
} }
if (_IJ && hasReceived)
{
rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
}
} else if(_method == kRtcpNonCompound) } else if(_method == kRtcpNonCompound)
{ {
if(rtcpPacketTypeFlags & kRtcpReport) if(rtcpPacketTypeFlags & kRtcpReport)
@ -1683,13 +1657,14 @@ RTCPSender::SendRTCP(
if(_audio) if(_audio)
{ {
timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) + (RTCP_INTERVAL_AUDIO_MS*random/1000); timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) +
(RTCP_INTERVAL_AUDIO_MS*random/1000);
}else }else
{ {
uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS; uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
if(_sending) if(_sending)
{ {
// calc bw for video 360/sendBW in kbit/s // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
uint32_t sendBitrateKbit = 0; uint32_t sendBitrateKbit = 0;
uint32_t videoRate = 0; uint32_t videoRate = 0;
uint32_t fecRate = 0; uint32_t fecRate = 0;
@ -1713,60 +1688,58 @@ RTCPSender::SendRTCP(
_nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext; _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext;
} }
// if the data does not fitt in the packet we fill it as much as possible // If the data does not fit in the packet we fill it as much as possible.
int32_t buildVal = 0; int32_t buildVal = 0;
// We need to send our NTP even if we haven't received any reports.
_clock->CurrentNtp(NTPsec, NTPfrac);
if (ShouldSendReportBlocks(rtcpPacketTypeFlags)) {
StatisticianMap statisticians =
receive_statistics_->GetActiveStatisticians();
if (!statisticians.empty()) {
StatisticianMap::const_iterator it;
int i;
for (it = statisticians.begin(), i = 0; it != statisticians.end();
++it, ++i) {
RTCPReportBlock report_block;
if (PrepareReport(it->second, &report_block, &NTPsec, &NTPfrac))
AddReportBlock(it->first, &internal_report_blocks_, &report_block);
}
if (_IJ && !statisticians.empty()) {
rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
}
_lastRTCPTime[0] = Clock::NtpToMs(NTPsec, NTPfrac);
}
}
if(rtcpPacketTypeFlags & kRtcpSr) if(rtcpPacketTypeFlags & kRtcpSr)
{ {
if(hasReceived) buildVal = BuildSR(rtcp_buffer, position, NTPsec, NTPfrac);
{ if (buildVal == -1) {
buildVal = BuildSR(rtcpbuffer, pos, NTPsec, NTPfrac, &received); return -1;
} else } else if (buildVal == -2) {
{ return position;
buildVal = BuildSR(rtcpbuffer, pos, NTPsec, NTPfrac);
} }
if(buildVal == -1) buildVal = BuildSDEC(rtcp_buffer, position);
{ if (buildVal == -1) {
return -1; // error return -1;
} else if (buildVal == -2) {
}else if(buildVal == -2) return position;
{
break; // out of buffer
} }
buildVal = BuildSDEC(rtcpbuffer, pos);
if(buildVal == -1)
{
return -1; // error
}else if(buildVal == -2)
{
break; // out of buffer
}
}else if(rtcpPacketTypeFlags & kRtcpRr) }else if(rtcpPacketTypeFlags & kRtcpRr)
{ {
if(hasReceived) buildVal = BuildRR(rtcp_buffer, position, NTPsec, NTPfrac);
{ if (buildVal == -1) {
buildVal = BuildRR(rtcpbuffer, pos, NTPsec, NTPfrac,&received); return -1;
}else } else if (buildVal == -2) {
{ return position;
buildVal = BuildRR(rtcpbuffer, pos, NTPsec, NTPfrac);
}
if(buildVal == -1)
{
return -1; // error
}else if(buildVal == -2)
{
break; // out of buffer
} }
// only of set // only of set
if(_CNAME[0] != 0) if(_CNAME[0] != 0)
{ {
buildVal = BuildSDEC(rtcpbuffer, pos); buildVal = BuildSDEC(rtcp_buffer, position);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error
} }
} }
} }
@ -1774,28 +1747,22 @@ RTCPSender::SendRTCP(
{ {
// If present, this RTCP packet must be placed after a // If present, this RTCP packet must be placed after a
// receiver report. // receiver report.
buildVal = BuildExtendedJitterReport(rtcpbuffer, buildVal = BuildExtendedJitterReport(rtcp_buffer,
pos, position,
jitterTransmissionOffset); jitterTransmissionOffset);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
} return position;
else if(buildVal == -2)
{
break; // out of buffer
} }
} }
if(rtcpPacketTypeFlags & kRtcpPli) if(rtcpPacketTypeFlags & kRtcpPli)
{ {
buildVal = BuildPLI(rtcpbuffer, pos); buildVal = BuildPLI(rtcp_buffer, position);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI"); TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI");
_pliCount++; _pliCount++;
@ -1803,14 +1770,11 @@ RTCPSender::SendRTCP(
} }
if(rtcpPacketTypeFlags & kRtcpFir) if(rtcpPacketTypeFlags & kRtcpFir)
{ {
buildVal = BuildFIR(rtcpbuffer, pos, repeat); buildVal = BuildFIR(rtcp_buffer, position, repeat);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR"); TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR");
_fullIntraRequestCount++; _fullIntraRequestCount++;
@ -1819,106 +1783,82 @@ RTCPSender::SendRTCP(
} }
if(rtcpPacketTypeFlags & kRtcpSli) if(rtcpPacketTypeFlags & kRtcpSli)
{ {
buildVal = BuildSLI(rtcpbuffer, pos, (uint8_t)pictureID); buildVal = BuildSLI(rtcp_buffer, position, (uint8_t)pictureID);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
} }
if(rtcpPacketTypeFlags & kRtcpRpsi) if(rtcpPacketTypeFlags & kRtcpRpsi)
{ {
const int8_t payloadType = _rtpRtcp.SendPayloadType(); const int8_t payloadType = _rtpRtcp.SendPayloadType();
if(payloadType == -1) if (payloadType == -1) {
{
return -1; return -1;
} }
buildVal = BuildRPSI(rtcpbuffer, pos, pictureID, (uint8_t)payloadType); buildVal = BuildRPSI(rtcp_buffer, position, pictureID,
if(buildVal == -1) (uint8_t)payloadType);
{ if (buildVal == -1) {
return -1; // error return -1;
} else if (buildVal == -2) {
}else if(buildVal == -2) return position;
{
break; // out of buffer
} }
} }
if(rtcpPacketTypeFlags & kRtcpRemb) if(rtcpPacketTypeFlags & kRtcpRemb)
{ {
buildVal = BuildREMB(rtcpbuffer, pos); buildVal = BuildREMB(rtcp_buffer, position);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::REMB"); TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::REMB");
} }
if(rtcpPacketTypeFlags & kRtcpBye) if(rtcpPacketTypeFlags & kRtcpBye)
{ {
buildVal = BuildBYE(rtcpbuffer, pos); buildVal = BuildBYE(rtcp_buffer, position);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
} }
if(rtcpPacketTypeFlags & kRtcpApp) if(rtcpPacketTypeFlags & kRtcpApp)
{ {
buildVal = BuildAPP(rtcpbuffer, pos); buildVal = BuildAPP(rtcp_buffer, position);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
} }
if(rtcpPacketTypeFlags & kRtcpTmmbr) if(rtcpPacketTypeFlags & kRtcpTmmbr)
{ {
buildVal = BuildTMMBR(rtcpbuffer, pos); buildVal = BuildTMMBR(rtcp_buffer, position);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
} }
if(rtcpPacketTypeFlags & kRtcpTmmbn) if(rtcpPacketTypeFlags & kRtcpTmmbn)
{ {
buildVal = BuildTMMBN(rtcpbuffer, pos); buildVal = BuildTMMBN(rtcp_buffer, position);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
} }
if(rtcpPacketTypeFlags & kRtcpNack) if(rtcpPacketTypeFlags & kRtcpNack)
{ {
std::string nackString; std::string nackString;
buildVal = BuildNACK(rtcpbuffer, pos, nackSize, nackList, buildVal = BuildNACK(rtcp_buffer, position, nackSize, nackList,
&nackString); &nackString);
if(buildVal == -1) if (buildVal == -1) {
{ return -1;
return -1; // error } else if (buildVal == -2) {
return position;
}else if(buildVal == -2)
{
break; // out of buffer
} }
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()));
@ -1927,23 +1867,65 @@ RTCPSender::SendRTCP(
} }
if(rtcpPacketTypeFlags & kRtcpXrVoipMetric) if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
{ {
buildVal = BuildVoIPMetric(rtcpbuffer, pos); buildVal = BuildVoIPMetric(rtcp_buffer, position);
if(buildVal == -1) if (buildVal == -1) {
{
return -1; // error
}else if(buildVal == -2)
{
break; // out of buffer
}
}
}while (false);
// Sanity don't send empty packets.
if (pos == 0)
{
return -1; return -1;
} else if (buildVal == -2) {
return position;
} }
return SendToNetwork(rtcpbuffer, (uint16_t)pos); }
return position;
}
bool RTCPSender::ShouldSendReportBlocks(uint32_t rtcp_packet_type) const {
return Status() == kRtcpCompound ||
(rtcp_packet_type & kRtcpReport) ||
(rtcp_packet_type & kRtcpSr) ||
(rtcp_packet_type & kRtcpRr);
}
bool RTCPSender::PrepareReport(StreamStatistician* statistician,
RTCPReportBlock* report_block,
uint32_t* ntp_secs, uint32_t* ntp_frac) {
// Do we have receive statistics to send?
StreamStatistician::Statistics stats;
if (!statistician->GetStatistics(&stats, true))
return false;
report_block->fractionLost = stats.fraction_lost;
report_block->cumulativeLost = stats.cumulative_lost;
report_block->extendedHighSeqNum =
stats.extended_max_sequence_number;
report_block->jitter = stats.jitter;
uint32_t lastReceivedRRNTPsecs = 0;
uint32_t lastReceivedRRNTPfrac = 0;
uint32_t remoteSR = 0;
// ok even if we have not received a SR, we will send 0 in that case
_rtpRtcp.LastReceivedNTP(lastReceivedRRNTPsecs,
lastReceivedRRNTPfrac,
remoteSR);
// get our NTP as late as possible to avoid a race
_clock->CurrentNtp(*ntp_secs, *ntp_frac);
// Delay since last received report
uint32_t delaySinceLastReceivedSR = 0;
if((lastReceivedRRNTPsecs !=0) || (lastReceivedRRNTPfrac !=0)) {
// get the 16 lowest bits of seconds and the 16 higest bits of fractions
uint32_t now=*ntp_secs&0x0000FFFF;
now <<=16;
now += (*ntp_frac&0xffff0000)>>16;
uint32_t receiveTime = lastReceivedRRNTPsecs&0x0000FFFF;
receiveTime <<=16;
receiveTime += (lastReceivedRRNTPfrac&0xffff0000)>>16;
delaySinceLastReceivedSR = now-receiveTime;
}
report_block->delaySinceLastSR = delaySinceLastReceivedSR;
report_block->lastSR = remoteSR;
return true;
} }
int32_t int32_t
@ -2027,10 +2009,10 @@ RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
} }
// called under critsect _criticalSectionRTCPSender // called under critsect _criticalSectionRTCPSender
int32_t RTCPSender::AddReportBlocks(uint8_t* rtcpbuffer, int32_t RTCPSender::WriteAllReportBlocksToBuffer(
uint32_t& pos, uint8_t* rtcpbuffer,
int pos,
uint8_t& numberOfReportBlocks, uint8_t& numberOfReportBlocks,
const RTCPReportBlock* received,
const uint32_t NTPsec, const uint32_t NTPsec,
const uint32_t NTPfrac) { const uint32_t NTPfrac) {
// sanity one block // sanity one block
@ -2039,91 +2021,64 @@ int32_t RTCPSender::AddReportBlocks(uint8_t* rtcpbuffer,
"%s invalid argument", __FUNCTION__); "%s invalid argument", __FUNCTION__);
return -1; return -1;
} }
numberOfReportBlocks = _reportBlocks.size(); numberOfReportBlocks = external_report_blocks_.size();
if (received) { numberOfReportBlocks += internal_report_blocks_.size();
// add our multiple RR to numberOfReportBlocks if ((pos + numberOfReportBlocks * 24) >= IP_PACKET_SIZE) {
numberOfReportBlocks++;
}
if (received) {
// answer to the one that sends to me
_lastRTCPTime[0] = Clock::NtpToMs(NTPsec, NTPfrac);
// Remote SSRC
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
pos += 4;
// fraction lost
rtcpbuffer[pos++]=received->fractionLost;
// cumulative loss
ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+pos,
received->cumulativeLost);
pos += 3;
// extended highest seq_no, contain the highest sequence number received
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
received->extendedHighSeqNum);
pos += 4;
//Jitter
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, received->jitter);
pos += 4;
// Last SR timestamp, our NTP time when we received the last report
// This is the value that we read from the send report packet not when we
// received it...
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, received->lastSR);
pos += 4;
// Delay since last received report,time since we received the report
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
received->delaySinceLastSR);
pos += 4;
}
if ((pos + _reportBlocks.size() * 24) >= IP_PACKET_SIZE) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"%s invalid argument", __FUNCTION__); "%s invalid argument", __FUNCTION__);
return -1; return -1;
} }
std::map<uint32_t, RTCPReportBlock*>::iterator it = pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, internal_report_blocks_);
_reportBlocks.begin(); while (!internal_report_blocks_.empty()) {
delete internal_report_blocks_.begin()->second;
internal_report_blocks_.erase(internal_report_blocks_.begin());
}
pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, external_report_blocks_);
return pos;
}
for (; it != _reportBlocks.end(); it++) { int32_t RTCPSender::WriteReportBlocksToBuffer(
// we can have multiple report block in a conference uint8_t* rtcpbuffer,
int32_t position,
const std::map<uint32_t, RTCPReportBlock*>& report_blocks) {
std::map<uint32_t, RTCPReportBlock*>::const_iterator it =
report_blocks.begin();
for (; it != report_blocks.end(); it++) {
uint32_t remoteSSRC = it->first; uint32_t remoteSSRC = it->first;
RTCPReportBlock* reportBlock = it->second; RTCPReportBlock* reportBlock = it->second;
if (reportBlock) { if (reportBlock) {
// Remote SSRC // Remote SSRC
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, remoteSSRC); ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position, remoteSSRC);
pos += 4; position += 4;
// fraction lost // fraction lost
rtcpbuffer[pos++] = reportBlock->fractionLost; rtcpbuffer[position++] = reportBlock->fractionLost;
// cumulative loss // cumulative loss
ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+pos, ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+position,
reportBlock->cumulativeLost); reportBlock->cumulativeLost);
pos += 3; position += 3;
// extended highest seq_no, contain the highest sequence number received // extended highest seq_no, contain the highest sequence number received
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position,
reportBlock->extendedHighSeqNum); reportBlock->extendedHighSeqNum);
pos += 4; position += 4;
//Jitter // Jitter
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position,
reportBlock->jitter); reportBlock->jitter);
pos += 4; position += 4;
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position,
reportBlock->lastSR); reportBlock->lastSR);
pos += 4; position += 4;
ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position,
reportBlock->delaySinceLastSR); reportBlock->delaySinceLastSR);
pos += 4; position += 4;
} }
} }
return pos; return position;
} }
// no callbacks allowed inside this function // no callbacks allowed inside this function

View File

@ -49,7 +49,8 @@ class RTCPSender
{ {
public: public:
RTCPSender(const int32_t id, const bool audio, RTCPSender(const int32_t id, const bool audio,
Clock* clock, ModuleRtpRtcpImpl* owner); Clock* clock, ModuleRtpRtcpImpl* owner,
ReceiveStatistics* receive_statistics);
virtual ~RTCPSender(); virtual ~RTCPSender();
void ChangeUniqueId(const int32_t id); void ChangeUniqueId(const int32_t id);
@ -93,16 +94,16 @@ public:
int32_t SendRTCP( int32_t SendRTCP(
uint32_t rtcpPacketTypeFlags, uint32_t rtcpPacketTypeFlags,
const ReceiveStatistics::RtpReceiveStatistics* receive_stats,
int32_t nackSize = 0, int32_t nackSize = 0,
const uint16_t* nackList = 0, const uint16_t* nackList = 0,
bool repeat = false, bool repeat = false,
uint64_t pictureID = 0); uint64_t pictureID = 0);
int32_t AddReportBlock(const uint32_t SSRC, int32_t AddExternalReportBlock(
uint32_t SSRC,
const RTCPReportBlock* receiveBlock); const RTCPReportBlock* receiveBlock);
int32_t RemoveReportBlock(const uint32_t SSRC); int32_t RemoveExternalReportBlock(uint32_t SSRC);
/* /*
* REMB * REMB
@ -155,49 +156,71 @@ private:
void UpdatePacketRate(); void UpdatePacketRate();
int32_t AddReportBlocks(uint8_t* rtcpbuffer, int32_t WriteAllReportBlocksToBuffer(uint8_t* rtcpbuffer,
uint32_t& pos, int pos,
uint8_t& numberOfReportBlocks, uint8_t& numberOfReportBlocks,
const RTCPReportBlock* received,
const uint32_t NTPsec, const uint32_t NTPsec,
const uint32_t NTPfrac); const uint32_t NTPfrac);
int32_t WriteReportBlocksToBuffer(
uint8_t* rtcpbuffer,
int32_t position,
const std::map<uint32_t, RTCPReportBlock*>& report_blocks);
int32_t AddReportBlock(
uint32_t SSRC,
std::map<uint32_t, RTCPReportBlock*>* report_blocks,
const RTCPReportBlock* receiveBlock);
bool PrepareReport(StreamStatistician* statistician,
RTCPReportBlock* report_block,
uint32_t* ntp_secs, uint32_t* ntp_frac);
int32_t BuildSR(uint8_t* rtcpbuffer, int32_t BuildSR(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint32_t NTPsec, const uint32_t NTPsec,
const uint32_t NTPfrac, const uint32_t NTPfrac);
const RTCPReportBlock* received = NULL);
int32_t BuildRR(uint8_t* rtcpbuffer, int32_t BuildRR(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint32_t NTPsec, const uint32_t NTPsec,
const uint32_t NTPfrac, const uint32_t NTPfrac);
const RTCPReportBlock* received = NULL);
int PrepareRTCP(
uint32_t packetTypeFlags,
int32_t nackSize,
const uint16_t* nackList,
bool repeat,
uint64_t pictureID,
uint8_t* rtcp_buffer,
int buffer_size);
bool ShouldSendReportBlocks(uint32_t rtcp_packet_type) const;
int32_t BuildExtendedJitterReport( int32_t BuildExtendedJitterReport(
uint8_t* rtcpbuffer, uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint32_t jitterTransmissionTimeOffset); const uint32_t jitterTransmissionTimeOffset);
int32_t BuildSDEC(uint8_t* rtcpbuffer, uint32_t& pos); int32_t BuildSDEC(uint8_t* rtcpbuffer, int& pos);
int32_t BuildPLI(uint8_t* rtcpbuffer, uint32_t& pos); int32_t BuildPLI(uint8_t* rtcpbuffer, int& pos);
int32_t BuildREMB(uint8_t* rtcpbuffer, uint32_t& pos); int32_t BuildREMB(uint8_t* rtcpbuffer, int& pos);
int32_t BuildTMMBR(uint8_t* rtcpbuffer, uint32_t& pos); int32_t BuildTMMBR(uint8_t* rtcpbuffer, int& pos);
int32_t BuildTMMBN(uint8_t* rtcpbuffer, uint32_t& pos); int32_t BuildTMMBN(uint8_t* rtcpbuffer, int& pos);
int32_t BuildAPP(uint8_t* rtcpbuffer, uint32_t& pos); int32_t BuildAPP(uint8_t* rtcpbuffer, int& pos);
int32_t BuildVoIPMetric(uint8_t* rtcpbuffer, uint32_t& pos); int32_t BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos);
int32_t BuildBYE(uint8_t* rtcpbuffer, uint32_t& pos); int32_t BuildBYE(uint8_t* rtcpbuffer, int& pos);
int32_t BuildFIR(uint8_t* rtcpbuffer, uint32_t& pos, bool repeat); int32_t BuildFIR(uint8_t* rtcpbuffer, int& pos, bool repeat);
int32_t BuildSLI(uint8_t* rtcpbuffer, int32_t BuildSLI(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint8_t pictureID); const uint8_t pictureID);
int32_t BuildRPSI(uint8_t* rtcpbuffer, int32_t BuildRPSI(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const uint64_t pictureID, const uint64_t pictureID,
const uint8_t payloadType); const uint8_t payloadType);
int32_t BuildNACK(uint8_t* rtcpbuffer, int32_t BuildNACK(uint8_t* rtcpbuffer,
uint32_t& pos, int& pos,
const int32_t nackSize, const int32_t nackSize,
const uint16_t* nackList, const uint16_t* nackList,
std::string* nackString); std::string* nackString);
@ -231,7 +254,10 @@ private:
uint32_t _remoteSSRC; // SSRC that we receive on our RTP channel uint32_t _remoteSSRC; // SSRC that we receive on our RTP channel
char _CNAME[RTCP_CNAME_SIZE]; char _CNAME[RTCP_CNAME_SIZE];
std::map<uint32_t, RTCPReportBlock*> _reportBlocks;
ReceiveStatistics* receive_statistics_;
std::map<uint32_t, RTCPReportBlock*> internal_report_blocks_;
std::map<uint32_t, RTCPReportBlock*> external_report_blocks_;
std::map<uint32_t, RTCPUtility::RTCPCnameInformation*> _csrcCNAMEs; std::map<uint32_t, RTCPUtility::RTCPCnameInformation*> _csrcCNAMEs;
int32_t _cameraDelayMS; int32_t _cameraDelayMS;

View File

@ -285,7 +285,8 @@ class RtcpSenderTest : public ::testing::Test {
remote_bitrate_estimator_( remote_bitrate_estimator_(
RemoteBitrateEstimatorFactory().Create( RemoteBitrateEstimatorFactory().Create(
&remote_bitrate_observer_, &remote_bitrate_observer_,
system_clock_)) { system_clock_)),
receive_statistics_(ReceiveStatistics::Create(system_clock_)) {
test_transport_ = new TestTransport(); test_transport_ = new TestTransport();
RtpRtcp::Configuration configuration; RtpRtcp::Configuration configuration;
@ -298,7 +299,8 @@ class RtcpSenderTest : public ::testing::Test {
rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration); rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration);
rtp_receiver_.reset(RtpReceiver::CreateVideoReceiver( rtp_receiver_.reset(RtpReceiver::CreateVideoReceiver(
0, system_clock_, test_transport_, NULL, rtp_payload_registry_.get())); 0, system_clock_, test_transport_, NULL, rtp_payload_registry_.get()));
rtcp_sender_ = new RTCPSender(0, false, system_clock_, rtp_rtcp_impl_); rtcp_sender_ = new RTCPSender(0, false, system_clock_, rtp_rtcp_impl_,
receive_statistics_.get());
rtcp_receiver_ = new RTCPReceiver(0, system_clock_, rtp_rtcp_impl_); rtcp_receiver_ = new RTCPReceiver(0, system_clock_, rtp_rtcp_impl_);
test_transport_->SetRTCPReceiver(rtcp_receiver_); test_transport_->SetRTCPReceiver(rtcp_receiver_);
// Initialize // Initialize
@ -328,6 +330,7 @@ class RtcpSenderTest : public ::testing::Test {
TestTransport* test_transport_; TestTransport* test_transport_;
MockRemoteBitrateObserver remote_bitrate_observer_; MockRemoteBitrateObserver remote_bitrate_observer_;
scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_; scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_;
scoped_ptr<ReceiveStatistics> receive_statistics_;
enum {kMaxPacketLength = 1500}; enum {kMaxPacketLength = 1500};
uint8_t packet_[kMaxPacketLength]; uint8_t packet_[kMaxPacketLength];
@ -335,7 +338,7 @@ class RtcpSenderTest : public ::testing::Test {
TEST_F(RtcpSenderTest, RtcpOff) { TEST_F(RtcpSenderTest, RtcpOff) {
EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpOff)); EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpOff));
EXPECT_EQ(-1, rtcp_sender_->SendRTCP(kRtcpSr, NULL)); EXPECT_EQ(-1, rtcp_sender_->SendRTCP(kRtcpSr));
} }
TEST_F(RtcpSenderTest, IJStatus) { TEST_F(RtcpSenderTest, IJStatus) {
@ -372,14 +375,13 @@ TEST_F(RtcpSenderTest, TestCompound) {
PayloadUnion payload_specific; PayloadUnion payload_specific;
EXPECT_TRUE(rtp_payload_registry_->GetPayloadSpecifics(header.payloadType, EXPECT_TRUE(rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
&payload_specific)); &payload_specific));
receive_statistics_->IncomingPacket(header, packet_length, false, true);
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(&header, packet_, packet_length, EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(&header, packet_, packet_length,
payload_specific, true)); payload_specific, true));
EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true)); EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true));
EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound)); EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
ReceiveStatistics::RtpReceiveStatistics receive_stats; EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr));
memset(&receive_stats, 0, sizeof(receive_stats));
EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr, &receive_stats));
// Transmission time offset packet should be received. // Transmission time offset packet should be received.
ASSERT_TRUE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags & ASSERT_TRUE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags &
@ -389,9 +391,7 @@ TEST_F(RtcpSenderTest, TestCompound) {
TEST_F(RtcpSenderTest, TestCompound_NoRtpReceived) { TEST_F(RtcpSenderTest, TestCompound_NoRtpReceived) {
EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true)); EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true));
EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound)); EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
// |receive_stats| is NULL since no data has been received. EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr));
ReceiveStatistics::RtpReceiveStatistics* receive_stats = NULL;
EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr, receive_stats));
// Transmission time offset packet should not be received. // Transmission time offset packet should not be received.
ASSERT_FALSE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags & ASSERT_FALSE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags &
@ -409,9 +409,7 @@ TEST_F(RtcpSenderTest, SendsTmmbnIfSetAndEmpty) {
TMMBRSet bounding_set; TMMBRSet bounding_set;
EXPECT_EQ(0, rtcp_sender_->SetTMMBN(&bounding_set, 3)); EXPECT_EQ(0, rtcp_sender_->SetTMMBN(&bounding_set, 3));
ASSERT_EQ(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags); ASSERT_EQ(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags);
ReceiveStatistics::RtpReceiveStatistics receive_stats; EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpSr));
memset(&receive_stats, 0, sizeof(receive_stats));
EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpSr, &receive_stats));
// We now expect the packet to show up in the rtcp_packet_info_ of // We now expect the packet to show up in the rtcp_packet_info_ of
// test_transport_. // test_transport_.
ASSERT_NE(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags); ASSERT_NE(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags);
@ -433,9 +431,7 @@ TEST_F(RtcpSenderTest, SendsTmmbnIfSetAndValid) {
EXPECT_EQ(0, rtcp_sender_->SetTMMBN(&bounding_set, 3)); EXPECT_EQ(0, rtcp_sender_->SetTMMBN(&bounding_set, 3));
ASSERT_EQ(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags); ASSERT_EQ(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags);
ReceiveStatistics::RtpReceiveStatistics receive_stats; EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpSr));
memset(&receive_stats, 0, sizeof(receive_stats));
EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpSr, &receive_stats));
// We now expect the packet to show up in the rtcp_packet_info_ of // We now expect the packet to show up in the rtcp_packet_info_ of
// test_transport_. // test_transport_.
ASSERT_NE(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags); ASSERT_NE(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags);

View File

@ -283,7 +283,7 @@ bool RtpReceiverImpl::IncomingRtpPacket(
} }
if (should_reset_statistics) { if (should_reset_statistics) {
cb_rtp_feedback_->ResetStatistics(); cb_rtp_feedback_->ResetStatistics(ssrc_);
} }
WebRtcRTPHeader webrtc_rtp_header; WebRtcRTPHeader webrtc_rtp_header;
@ -418,7 +418,7 @@ void RtpReceiverImpl::CheckSSRCChanged(const RTPHeader* rtp_header) {
// We need the payload_type_ to make the call if the remote SSRC is 0. // We need the payload_type_ to make the call if the remote SSRC is 0.
new_ssrc = true; new_ssrc = true;
cb_rtp_feedback_->ResetStatistics(); cb_rtp_feedback_->ResetStatistics(ssrc_);
last_received_timestamp_ = 0; last_received_timestamp_ = 0;
last_received_sequence_number_ = 0; last_received_sequence_number_ = 0;

View File

@ -41,7 +41,7 @@ RtpRtcp::Configuration::Configuration()
audio(false), audio(false),
clock(NULL), clock(NULL),
default_module(NULL), default_module(NULL),
receive_statistics(NULL), receive_statistics(NullObjectReceiveStatistics()),
outgoing_transport(NULL), outgoing_transport(NULL),
rtcp_feedback(NULL), rtcp_feedback(NULL),
intra_frame_callback(NULL), intra_frame_callback(NULL),
@ -74,10 +74,9 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
configuration.audio_messages, configuration.audio_messages,
configuration.paced_sender), configuration.paced_sender),
rtcp_sender_(configuration.id, configuration.audio, configuration.clock, rtcp_sender_(configuration.id, configuration.audio, configuration.clock,
this), this, configuration.receive_statistics),
rtcp_receiver_(configuration.id, configuration.clock, this), rtcp_receiver_(configuration.id, configuration.clock, this),
clock_(configuration.clock), clock_(configuration.clock),
receive_statistics_(configuration.receive_statistics),
id_(configuration.id), id_(configuration.id),
audio_(configuration.audio), audio_(configuration.audio),
collision_detected_(false), collision_detected_(false),
@ -242,13 +241,7 @@ int32_t ModuleRtpRtcpImpl::Process() {
} }
} }
if (rtcp_sender_.TimeToSendRTCPReport()) { if (rtcp_sender_.TimeToSendRTCPReport()) {
ReceiveStatistics::RtpReceiveStatistics receive_stats; rtcp_sender_.SendRTCP(kRtcpReport);
if (receive_statistics_ &&
receive_statistics_->Statistics(&receive_stats, true)) {
rtcp_sender_.SendRTCP(kRtcpReport, &receive_stats);
} else {
rtcp_sender_.SendRTCP(kRtcpReport, NULL);
}
} }
} }
@ -577,13 +570,7 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData(
if (!have_child_modules) { if (!have_child_modules) {
// Don't send RTCP from default module. // Don't send RTCP from default module.
if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) { if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) {
ReceiveStatistics::RtpReceiveStatistics receive_stats; rtcp_sender_.SendRTCP(kRtcpReport);
if (receive_statistics_ &&
receive_statistics_->Statistics(&receive_stats, true)) {
rtcp_sender_.SendRTCP(kRtcpReport, &receive_stats);
} else {
rtcp_sender_.SendRTCP(kRtcpReport, NULL);
}
} }
return rtp_sender_.SendOutgoingData(frame_type, return rtp_sender_.SendOutgoingData(frame_type,
payload_type, payload_type,
@ -925,19 +912,7 @@ int32_t ModuleRtpRtcpImpl::ResetSendDataCountersRTP() {
int32_t ModuleRtpRtcpImpl::SendRTCP(uint32_t rtcp_packet_type) { int32_t ModuleRtpRtcpImpl::SendRTCP(uint32_t rtcp_packet_type) {
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SendRTCP(0x%x)", WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SendRTCP(0x%x)",
rtcp_packet_type); rtcp_packet_type);
ReceiveStatistics::RtpReceiveStatistics receive_stats; return rtcp_sender_.SendRTCP(rtcp_packet_type);
if (rtcp_sender_.Status() == kRtcpCompound ||
(rtcp_packet_type & kRtcpReport) ||
(rtcp_packet_type & kRtcpSr) ||
(rtcp_packet_type & kRtcpRr)) {
if (receive_statistics_ &&
receive_statistics_->Statistics(&receive_stats, true)) {
return rtcp_sender_.SendRTCP(rtcp_packet_type, &receive_stats);
} else {
return rtcp_sender_.SendRTCP(rtcp_packet_type, NULL);
}
}
return rtcp_sender_.SendRTCP(rtcp_packet_type, NULL);
} }
int32_t ModuleRtpRtcpImpl::SetRTCPApplicationSpecificData( int32_t ModuleRtpRtcpImpl::SetRTCPApplicationSpecificData(
@ -993,14 +968,14 @@ int32_t ModuleRtpRtcpImpl::AddRTCPReportBlock(
const RTCPReportBlock* report_block) { const RTCPReportBlock* report_block) {
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "AddRTCPReportBlock()"); WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "AddRTCPReportBlock()");
return rtcp_sender_.AddReportBlock(ssrc, report_block); return rtcp_sender_.AddExternalReportBlock(ssrc, report_block);
} }
int32_t ModuleRtpRtcpImpl::RemoveRTCPReportBlock( int32_t ModuleRtpRtcpImpl::RemoveRTCPReportBlock(
const uint32_t ssrc) { const uint32_t ssrc) {
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoveRTCPReportBlock()"); WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoveRTCPReportBlock()");
return rtcp_sender_.RemoveReportBlock(ssrc); return rtcp_sender_.RemoveExternalReportBlock(ssrc);
} }
// (REMB) Receiver Estimated Max Bitrate. // (REMB) Receiver Estimated Max Bitrate.
@ -1154,15 +1129,7 @@ int32_t ModuleRtpRtcpImpl::SendNACK(const uint16_t* nack_list,
} }
nack_last_seq_number_sent_ = nack_list[start_id + nackLength - 1]; nack_last_seq_number_sent_ = nack_list[start_id + nackLength - 1];
ReceiveStatistics::RtpReceiveStatistics receive_stats; return rtcp_sender_.SendRTCP(kRtcpNack, nackLength, &nack_list[start_id]);
if (rtcp_sender_.Status() == kRtcpCompound && receive_statistics_ &&
receive_statistics_->Statistics(&receive_stats, true)) {
return rtcp_sender_.SendRTCP(kRtcpNack, &receive_stats, nackLength,
&nack_list[start_id]);
} else {
return rtcp_sender_.SendRTCP(kRtcpNack, NULL, nackLength,
&nack_list[start_id]);
}
} }
// Store the sent packets, needed to answer to a Negative acknowledgment // Store the sent packets, needed to answer to a Negative acknowledgment
@ -1357,14 +1324,8 @@ int32_t ModuleRtpRtcpImpl::SendRTCPSliceLossIndication(
id_, id_,
"SendRTCPSliceLossIndication (picture_id:%d)", "SendRTCPSliceLossIndication (picture_id:%d)",
picture_id); picture_id);
ReceiveStatistics::RtpReceiveStatistics receive_stats;
if (rtcp_sender_.Status() == kRtcpCompound && receive_statistics_ && return rtcp_sender_.SendRTCP(kRtcpSli, 0, 0, false, picture_id);
receive_statistics_->Statistics(&receive_stats, true)) {
return rtcp_sender_.SendRTCP(kRtcpSli, &receive_stats, 0, 0, false,
picture_id);
} else {
return rtcp_sender_.SendRTCP(kRtcpSli, NULL, 0, 0, false, picture_id);
}
} }
int32_t ModuleRtpRtcpImpl::SetCameraDelay(const int32_t delay_ms) { int32_t ModuleRtpRtcpImpl::SetCameraDelay(const int32_t delay_ms) {
@ -1562,14 +1523,7 @@ void ModuleRtpRtcpImpl::OnRequestSendReport() {
int32_t ModuleRtpRtcpImpl::SendRTCPReferencePictureSelection( int32_t ModuleRtpRtcpImpl::SendRTCPReferencePictureSelection(
const uint64_t picture_id) { const uint64_t picture_id) {
ReceiveStatistics::RtpReceiveStatistics receive_stats; return rtcp_sender_.SendRTCP(kRtcpRpsi, 0, 0, false, picture_id);
if (rtcp_sender_.Status() == kRtcpCompound && receive_statistics_ &&
receive_statistics_->Statistics(&receive_stats, true)) {
return rtcp_sender_.SendRTCP(kRtcpRpsi, &receive_stats, 0, 0, false,
picture_id);
} else {
return rtcp_sender_.SendRTCP(kRtcpRpsi, NULL, 0, 0, false, picture_id);
}
} }
uint32_t ModuleRtpRtcpImpl::SendTimeOfSendReport( uint32_t ModuleRtpRtcpImpl::SendTimeOfSendReport(

View File

@ -377,8 +377,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
private: private:
int64_t RtcpReportInterval(); int64_t RtcpReportInterval();
ReceiveStatistics* receive_statistics_;
int32_t id_; int32_t id_;
const bool audio_; const bool audio_;
bool collision_detected_; bool collision_detected_;

View File

@ -61,6 +61,11 @@ RtpAudioFeedback* NullObjectRtpAudioFeedback() {
return &null_rtp_audio_feedback; return &null_rtp_audio_feedback;
} }
ReceiveStatistics* NullObjectReceiveStatistics() {
static NullReceiveStatistics null_receive_statistics;
return &null_receive_statistics;
}
namespace ModuleRTPUtility { namespace ModuleRTPUtility {
enum { enum {

View File

@ -14,6 +14,7 @@
#include <stddef.h> // size_t, ptrdiff_t #include <stddef.h> // size_t, ptrdiff_t
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h" #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
#include "webrtc/typedefs.h" #include "webrtc/typedefs.h"
@ -25,6 +26,7 @@ const uint8_t kRtpMarkerBitMask = 0x80;
RtpData* NullObjectRtpData(); RtpData* NullObjectRtpData();
RtpFeedback* NullObjectRtpFeedback(); RtpFeedback* NullObjectRtpFeedback();
RtpAudioFeedback* NullObjectRtpAudioFeedback(); RtpAudioFeedback* NullObjectRtpAudioFeedback();
ReceiveStatistics* NullObjectReceiveStatistics();
namespace ModuleRTPUtility namespace ModuleRTPUtility
{ {

View File

@ -76,8 +76,8 @@ class TestRtpFeedback : public NullRtpFeedback {
virtual ~TestRtpFeedback() {} virtual ~TestRtpFeedback() {}
virtual void OnIncomingSSRCChanged(const int32_t id, virtual void OnIncomingSSRCChanged(const int32_t id,
const uint32_t SSRC) { const uint32_t ssrc) {
rtp_rtcp_->SetRemoteSSRC(SSRC); rtp_rtcp_->SetRemoteSSRC(ssrc);
} }
private: private:
@ -334,8 +334,10 @@ TEST_F(RtpRtcpRtcpTest, RTCP) {
EXPECT_EQ(static_cast<uint32_t>(0), EXPECT_EQ(static_cast<uint32_t>(0),
reportBlockReceived.cumulativeLost); reportBlockReceived.cumulativeLost);
ReceiveStatistics::RtpReceiveStatistics stats; StreamStatistician *statistician =
EXPECT_TRUE(receive_statistics2_->Statistics(&stats, true)); receive_statistics2_->GetStatistician(reportBlockReceived.sourceSSRC);
StreamStatistician::Statistics stats;
EXPECT_TRUE(statistician->GetStatistics(&stats, true));
EXPECT_EQ(0, stats.fraction_lost); EXPECT_EQ(0, stats.fraction_lost);
EXPECT_EQ((uint32_t)0, stats.cumulative_lost); EXPECT_EQ((uint32_t)0, stats.cumulative_lost);
EXPECT_EQ(test_sequence_number, stats.extended_max_sequence_number); EXPECT_EQ(test_sequence_number, stats.extended_max_sequence_number);

View File

@ -324,6 +324,7 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_), WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
"%s: RTP::SetRTCPStatus failure", __FUNCTION__); "%s: RTP::SetRTCPStatus failure", __FUNCTION__);
} }
if (rtp_rtcp_->StorePackets()) { if (rtp_rtcp_->StorePackets()) {
rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_); rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_);
} else if (paced_sender_) { } else if (paced_sender_) {
@ -1272,10 +1273,12 @@ int32_t ViEChannel::GetReceivedRtcpStatistics(uint16_t* fraction_lost,
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
"%s", __FUNCTION__); "%s", __FUNCTION__);
uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc();
uint8_t frac_lost = 0; uint8_t frac_lost = 0;
ReceiveStatistics* receive_statistics = vie_receiver_.GetReceiveStatistics(); StreamStatistician* statistician =
ReceiveStatistics::RtpReceiveStatistics receive_stats; vie_receiver_.GetReceiveStatistics()->GetStatistician(remote_ssrc);
if (!receive_statistics || !receive_statistics->Statistics( StreamStatistician::Statistics receive_stats;
if (!statistician || !statistician->GetStatistics(
&receive_stats, rtp_rtcp_->RTCP() == kRtcpOff)) { &receive_stats, rtp_rtcp_->RTCP() == kRtcpOff)) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
"%s: Could not get received RTP statistics", __FUNCTION__); "%s: Could not get received RTP statistics", __FUNCTION__);
@ -1287,7 +1290,6 @@ int32_t ViEChannel::GetReceivedRtcpStatistics(uint16_t* fraction_lost,
*jitter_samples = receive_stats.jitter; *jitter_samples = receive_stats.jitter;
*fraction_lost = frac_lost; *fraction_lost = frac_lost;
uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc();
uint16_t dummy = 0; uint16_t dummy = 0;
uint16_t rtt = 0; uint16_t rtt = 0;
if (rtp_rtcp_->RTT(remote_ssrc, &rtt, &dummy, &dummy, &dummy) != 0) { if (rtp_rtcp_->RTT(remote_ssrc, &rtt, &dummy, &dummy, &dummy) != 0) {
@ -1305,8 +1307,12 @@ int32_t ViEChannel::GetRtpStatistics(uint32_t* bytes_sent,
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s", WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
__FUNCTION__); __FUNCTION__);
ReceiveStatistics* receive_statistics = vie_receiver_.GetReceiveStatistics(); StreamStatistician* statistician = vie_receiver_.GetReceiveStatistics()->
receive_statistics->GetDataCounters(bytes_received, packets_received); GetStatistician(vie_receiver_.GetRemoteSsrc());
*bytes_received = 0;
*packets_received = 0;
if (statistician)
statistician->GetDataCounters(bytes_received, packets_received);
if (rtp_rtcp_->DataCountersRTP(bytes_sent, packets_sent) != 0) { if (rtp_rtcp_->DataCountersRTP(bytes_sent, packets_sent) != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
"%s: Could not get counters", __FUNCTION__); "%s: Could not get counters", __FUNCTION__);
@ -1888,8 +1894,7 @@ int32_t ViEChannel::OnInitializeDecoder(
return 0; return 0;
} }
void ViEChannel::OnIncomingSSRCChanged(const int32_t id, void ViEChannel::OnIncomingSSRCChanged(const int32_t id, const uint32_t ssrc) {
const uint32_t SSRC) {
if (channel_id_ != ChannelId(id)) { if (channel_id_ != ChannelId(id)) {
assert(false); assert(false);
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
@ -1898,14 +1903,14 @@ void ViEChannel::OnIncomingSSRCChanged(const int32_t id,
} }
WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
"%s: %u", __FUNCTION__, SSRC); "%s: %u", __FUNCTION__, ssrc);
rtp_rtcp_->SetRemoteSSRC(SSRC); rtp_rtcp_->SetRemoteSSRC(ssrc);
CriticalSectionScoped cs(callback_cs_.get()); CriticalSectionScoped cs(callback_cs_.get());
{ {
if (rtp_observer_) { if (rtp_observer_) {
rtp_observer_->IncomingSSRCChanged(channel_id_, SSRC); rtp_observer_->IncomingSSRCChanged(channel_id_, ssrc);
} }
} }
} }
@ -1934,8 +1939,11 @@ void ViEChannel::OnIncomingCSRCChanged(const int32_t id,
} }
} }
void ViEChannel::ResetStatistics() { void ViEChannel::ResetStatistics(uint32_t ssrc) {
vie_receiver_.GetReceiveStatistics()->ResetStatistics(); StreamStatistician* statistician =
vie_receiver_.GetReceiveStatistics()->GetStatistician(ssrc);
if (statistician)
statistician->ResetStatistics();
} }
} // namespace webrtc } // namespace webrtc

View File

@ -212,11 +212,11 @@ class ViEChannel
const uint8_t channels, const uint8_t channels,
const uint32_t rate); const uint32_t rate);
virtual void OnIncomingSSRCChanged(const int32_t id, virtual void OnIncomingSSRCChanged(const int32_t id,
const uint32_t SSRC); const uint32_t ssrc);
virtual void OnIncomingCSRCChanged(const int32_t id, virtual void OnIncomingCSRCChanged(const int32_t id,
const uint32_t CSRC, const uint32_t CSRC,
const bool added); const bool added);
virtual void ResetStatistics(); virtual void ResetStatistics(uint32_t);
int32_t SetLocalReceiver(const uint16_t rtp_port, int32_t SetLocalReceiver(const uint16_t rtp_port,
const uint16_t rtcp_port, const uint16_t rtcp_port,

View File

@ -404,8 +404,10 @@ bool ViEReceiver::IsPacketRetransmitted(const RTPHeader& header) const {
rtp_receiver_->RTXStatus(&rtx_enabled, &rtx_ssrc, &rtx_payload_type); rtp_receiver_->RTXStatus(&rtx_enabled, &rtx_ssrc, &rtx_payload_type);
if (!rtx_enabled) { if (!rtx_enabled) {
// Check if this is a retransmission. // Check if this is a retransmission.
ReceiveStatistics::RtpReceiveStatistics stats; StreamStatistician::Statistics stats;
if (rtp_receive_statistics_->Statistics(&stats, false)) { StreamStatistician* statistician =
rtp_receive_statistics_->GetStatistician(header.ssrc);
if (statistician && statistician->GetStatistics(&stats, false)) {
uint16_t min_rtt = 0; uint16_t min_rtt = 0;
rtp_rtcp_->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL); rtp_rtcp_->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
return rtp_receiver_->RetransmitOfOldPacket(header, stats.jitter, return rtp_receiver_->RetransmitOfOldPacket(header, stats.jitter,

View File

@ -360,20 +360,15 @@ Channel::OnPlayTelephoneEvent(int32_t id,
} }
void void
Channel::OnIncomingSSRCChanged(int32_t id, Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
uint32_t SSRC)
{ {
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId), WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
"Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)", "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
id, SSRC); id, ssrc);
int32_t channel = VoEChannelId(id); int32_t channel = VoEChannelId(id);
assert(channel == _channelId); assert(channel == _channelId);
// Reset RTP-module counters since a new incoming RTP stream is detected
rtp_receive_statistics_->ResetDataCounters();
rtp_receive_statistics_->ResetStatistics();
if (_rtpObserver) if (_rtpObserver)
{ {
CriticalSectionScoped cs(&_callbackCritSect); CriticalSectionScoped cs(&_callbackCritSect);
@ -381,7 +376,7 @@ Channel::OnIncomingSSRCChanged(int32_t id,
if (_rtpObserverPtr) if (_rtpObserverPtr)
{ {
// Send new SSRC to registered observer using callback // Send new SSRC to registered observer using callback
_rtpObserverPtr->OnIncomingSSRCChanged(channel, SSRC); _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
} }
} }
} }
@ -408,8 +403,12 @@ void Channel::OnIncomingCSRCChanged(int32_t id,
} }
} }
void Channel::ResetStatistics() { void Channel::ResetStatistics(uint32_t ssrc) {
rtp_receive_statistics_->ResetStatistics(); StreamStatistician* statistician =
rtp_receive_statistics_->GetStatistician(ssrc);
if (statistician) {
statistician->ResetStatistics();
}
} }
void void
@ -2231,8 +2230,10 @@ bool Channel::IsPacketRetransmitted(const RTPHeader& header) const {
rtp_receiver_->RTXStatus(&rtx_enabled, &rtx_ssrc, &rtx_payload_type); rtp_receiver_->RTXStatus(&rtx_enabled, &rtx_ssrc, &rtx_payload_type);
if (!rtx_enabled) { if (!rtx_enabled) {
// Check if this is a retransmission. // Check if this is a retransmission.
ReceiveStatistics::RtpReceiveStatistics stats; StreamStatistician::Statistics stats;
if (rtp_receive_statistics_->Statistics(&stats, false)) { StreamStatistician* statistician =
rtp_receive_statistics_->GetStatistician(header.ssrc);
if (statistician && statistician->GetStatistics(&stats, false)) {
uint16_t min_rtt = 0; uint16_t min_rtt = 0;
_rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL); _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
return rtp_receiver_->RetransmitOfOldPacket(header, stats.jitter, return rtp_receiver_->RetransmitOfOldPacket(header, stats.jitter,
@ -3921,8 +3922,10 @@ Channel::GetRTPStatistics(
{ {
// The jitter statistics is updated for each received RTP packet and is // The jitter statistics is updated for each received RTP packet and is
// based on received packets. // based on received packets.
ReceiveStatistics::RtpReceiveStatistics statistics; StreamStatistician::Statistics statistics;
if (!rtp_receive_statistics_->Statistics( StreamStatistician* statistician =
rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
if (!statistician || !statistician->GetStatistics(
&statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) { &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
_engineStatisticsPtr->SetLastError( _engineStatisticsPtr->SetLastError(
VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning, VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
@ -4016,8 +4019,10 @@ Channel::GetRTPStatistics(CallStatistics& stats)
// The jitter statistics is updated for each received RTP packet and is // The jitter statistics is updated for each received RTP packet and is
// based on received packets. // based on received packets.
ReceiveStatistics::RtpReceiveStatistics statistics; StreamStatistician::Statistics statistics;
if (!rtp_receive_statistics_->Statistics( StreamStatistician* statistician =
rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
if (!statistician || !statistician->GetStatistics(
&statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) { &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
_engineStatisticsPtr->SetLastError( _engineStatisticsPtr->SetLastError(
VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning, VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
@ -4087,7 +4092,9 @@ Channel::GetRTPStatistics(CallStatistics& stats)
uint32_t bytesReceived(0); uint32_t bytesReceived(0);
uint32_t packetsReceived(0); uint32_t packetsReceived(0);
rtp_receive_statistics_->GetDataCounters(&bytesReceived, &packetsReceived); if (statistician) {
statistician->GetDataCounters(&bytesReceived, &packetsReceived);
}
if (_rtpRtcpModule->DataCountersRTP(&bytesSent, if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
&packetsSent) != 0) &packetsSent) != 0)

View File

@ -329,12 +329,12 @@ public:
RTPAliveType alive); RTPAliveType alive);
void OnIncomingSSRCChanged(int32_t id, void OnIncomingSSRCChanged(int32_t id,
uint32_t SSRC); uint32_t ssrc);
void OnIncomingCSRCChanged(int32_t id, void OnIncomingCSRCChanged(int32_t id,
uint32_t CSRC, bool added); uint32_t CSRC, bool added);
void ResetStatistics(); void ResetStatistics(uint32_t ssrc);
public: public:
// From RtcpFeedback in the RTP/RTCP module // From RtcpFeedback in the RTP/RTCP module