From 1a65d6c36b6a25f9f734176c697c684c3b43ac4b Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Wed, 21 Aug 2013 16:22:21 +0000 Subject: [PATCH] Reverts a second set of reverts caused by a bug in a dependency. Revert "Revert r4328" Revert "Revert r4322 "Support sending multiple report blocks and keeping track of statistics on" BUG=1811 R=henrika@webrtc.org, pbos@webrtc.org, tina.legrand@webrtc.org Review URL: https://webrtc-codereview.appspot.com/2072004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4582 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/modules/modules.gyp | 1 + .../rtp_rtcp/interface/receive_statistics.h | 56 +- .../rtp_rtcp/interface/rtp_rtcp_defines.h | 8 +- .../rtp_rtcp/source/nack_rtx_unittest.cc | 4 +- .../source/receive_statistics_impl.cc | 212 ++-- .../rtp_rtcp/source/receive_statistics_impl.h | 65 +- .../source/receive_statistics_unittest.cc | 135 +++ .../source/rtcp_format_remb_unittest.cc | 11 +- webrtc/modules/rtp_rtcp/source/rtcp_sender.cc | 971 +++++++++--------- webrtc/modules/rtp_rtcp/source/rtcp_sender.h | 82 +- .../rtp_rtcp/source/rtcp_sender_unittest.cc | 26 +- .../rtp_rtcp/source/rtp_receiver_impl.cc | 4 +- .../modules/rtp_rtcp/source/rtp_rtcp_impl.cc | 68 +- .../modules/rtp_rtcp/source/rtp_rtcp_impl.h | 2 - webrtc/modules/rtp_rtcp/source/rtp_utility.cc | 5 + webrtc/modules/rtp_rtcp/source/rtp_utility.h | 2 + .../rtp_rtcp/test/testAPI/test_api_rtcp.cc | 10 +- webrtc/video_engine/vie_channel.cc | 34 +- webrtc/video_engine/vie_channel.h | 4 +- webrtc/video_engine/vie_receiver.cc | 6 +- webrtc/voice_engine/channel.cc | 41 +- webrtc/voice_engine/channel.h | 4 +- 22 files changed, 994 insertions(+), 757 deletions(-) create mode 100644 webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 75bf7bf2b..34930da0b 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -171,6 +171,7 @@ 'rtp_rtcp/source/nack_rtx_unittest.cc', 'rtp_rtcp/source/producer_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_sender_unittest.cc', 'rtp_rtcp/source/rtcp_receiver_unittest.cc', diff --git a/webrtc/modules/rtp_rtcp/interface/receive_statistics.h b/webrtc/modules/rtp_rtcp/interface/receive_statistics.h index fc47bf893..2ea155f9f 100644 --- a/webrtc/modules/rtp_rtcp/interface/receive_statistics.h +++ b/webrtc/modules/rtp_rtcp/interface/receive_statistics.h @@ -11,6 +11,8 @@ #ifndef WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_ #define WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_ +#include + #include "webrtc/modules/interface/module.h" #include "webrtc/modules/interface/module_common_types.h" #include "webrtc/typedefs.h" @@ -19,9 +21,16 @@ namespace webrtc { class Clock; -class ReceiveStatistics : public Module { +class StreamStatistician { 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; uint32_t cumulative_lost; uint32_t extended_max_sequence_number; @@ -29,26 +38,45 @@ class ReceiveStatistics : public Module { 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 StatisticianMap; + +class ReceiveStatistics : public Module { + public: virtual ~ReceiveStatistics() {} static ReceiveStatistics* Create(Clock* clock); + // Updates the receive statistics with this packet. virtual void IncomingPacket(const RTPHeader& rtp_header, size_t bytes, 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, - bool reset) = 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; + // Returns a pointer to the statistician of an ssrc. + virtual StreamStatistician* GetStatistician(uint32_t ssrc) const = 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 #endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RECEIVE_STATISTICS_H_ diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h index 31b38aba8..c56b71ffd 100644 --- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h +++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h @@ -205,13 +205,13 @@ public: const uint32_t rate) = 0; virtual void OnIncomingSSRCChanged( const int32_t id, - const uint32_t SSRC) = 0; + const uint32_t ssrc) = 0; virtual void OnIncomingCSRCChanged( const int32_t id, const uint32_t CSRC, const bool added) = 0; - virtual void ResetStatistics() = 0; + virtual void ResetStatistics(uint32_t ssrc) = 0; protected: virtual ~RtpFeedback() {} @@ -281,13 +281,13 @@ class NullRtpFeedback : public RtpFeedback { } virtual void OnIncomingSSRCChanged(const int32_t id, - const uint32_t SSRC) OVERRIDE {} + const uint32_t ssrc) OVERRIDE {} virtual void OnIncomingCSRCChanged(const int32_t id, const uint32_t CSRC, const bool added) OVERRIDE {} - virtual void ResetStatistics() OVERRIDE {} + virtual void ResetStatistics(uint32_t ssrc) OVERRIDE {} }; // Null object version of RtpData. diff --git a/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc b/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc index ecf4a07c1..56b49cc5b 100644 --- a/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc @@ -56,8 +56,8 @@ class TestRtpFeedback : public NullRtpFeedback { virtual ~TestRtpFeedback() {} virtual void OnIncomingSSRCChanged(const int32_t id, - const uint32_t SSRC) { - rtp_rtcp_->SetRemoteSSRC(SSRC); + const uint32_t ssrc) { + rtp_rtcp_->SetRemoteSSRC(ssrc); } private: diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc index 2189cce5e..c82693872 100644 --- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc @@ -17,41 +17,39 @@ namespace webrtc { -enum { kRateUpdateIntervalMs = 1000 }; +const int64_t kStatisticsTimeoutMs = 8000; +const int kStatisticsProcessIntervalMs = 1000; -ReceiveStatistics* ReceiveStatistics::Create(Clock* clock) { - return new ReceiveStatisticsImpl(clock); -} +StreamStatistician::~StreamStatistician() {} -ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock) - : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), - clock_(clock), +StreamStatisticianImpl::StreamStatisticianImpl(Clock* clock) + : clock_(clock), + crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), incoming_bitrate_(clock), ssrc_(0), jitter_q4_(0), jitter_max_q4_(0), cumulative_loss_(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_transmission_time_offset_(0), - received_seq_first_(0), received_seq_max_(0), received_seq_wraps_(0), - + first_packet_(true), received_packet_overhead_(12), received_byte_count_(0), received_retransmitted_packets_(0), received_inorder_packet_count_(0), - last_report_inorder_packets_(0), last_report_old_packets_(0), last_report_seq_max_(0), last_reported_statistics_() {} -void ReceiveStatisticsImpl::ResetStatistics() { - CriticalSectionScoped lock(crit_sect_.get()); +void StreamStatisticianImpl::ResetStatistics() { + CriticalSectionScoped cs(crit_sect_.get()); last_report_inorder_packets_ = 0; last_report_old_packets_ = 0; last_report_seq_max_ = 0; @@ -66,33 +64,25 @@ void ReceiveStatisticsImpl::ResetStatistics() { received_byte_count_ = 0; received_retransmitted_packets_ = 0; received_inorder_packet_count_ = 0; + first_packet_ = true; } -void ReceiveStatisticsImpl::ResetDataCounters() { - 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, - bool retransmitted, - bool in_order) { +void StreamStatisticianImpl::IncomingPacket(const RTPHeader& header, + size_t bytes, + bool retransmitted, + bool in_order) { + CriticalSectionScoped cs(crit_sect_.get()); ssrc_ = header.ssrc; incoming_bitrate_.Update(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. received_seq_first_ = header.sequenceNumber; received_seq_max_ = header.sequenceNumber; received_inorder_packet_count_ = 1; - // Current time in samples. - local_time_last_received_timestamp_ = - ModuleRTPUtility::GetCurrentRTP(clock_, header.payload_type_frequency); + clock_->CurrentNtp(last_receive_time_secs_, last_receive_time_frac_); return; } @@ -100,8 +90,9 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header, // are received, 4 will be ignored. if (in_order) { // Current time in samples. - const uint32_t RTPtime = - ModuleRTPUtility::GetCurrentRTP(clock_, header.payload_type_frequency); + uint32_t receive_time_secs; + uint32_t receive_time_frac; + clock_->CurrentNtp(receive_time_secs, receive_time_frac); received_inorder_packet_count_++; // Wrong if we use RetransmitOfOldPacket. @@ -116,8 +107,12 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header, if (header.timestamp != last_received_timestamp_ && received_inorder_packet_count_ > 1) { - int32_t time_diff_samples = - (RTPtime - local_time_last_received_timestamp_) - + uint32_t receive_time_rtp = ModuleRTPUtility::ConvertNTPTimeToRTP( + 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_); time_diff_samples = abs(time_diff_samples); @@ -134,7 +129,7 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header, // Extended jitter report, RFC 5450. // Actual network jitter, excluding the source-introduced jitter. int32_t time_diff_samples_ext = - (RTPtime - local_time_last_received_timestamp_) - + (receive_time_rtp - last_receive_time_rtp) - ((header.timestamp + header.extension.transmissionTimeOffset) - (last_received_timestamp_ + @@ -150,7 +145,8 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header, } } 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 { if (retransmitted) { received_retransmitted_packets_++; @@ -166,18 +162,8 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header, received_packet_overhead_ = (15 * received_packet_overhead_ + packet_oh) >> 4; } -bool ReceiveStatisticsImpl::Statistics(RtpReceiveStatistics* statistics, - bool reset) { - 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); - +bool StreamStatisticianImpl::GetStatistics(Statistics* statistics, bool reset) { + CriticalSectionScoped cs(crit_sect_.get()); if (received_seq_first_ == 0 && received_byte_count_ == 0) { // We have not received anything. return false; @@ -224,20 +210,20 @@ bool ReceiveStatisticsImpl::Statistics(RtpReceiveStatistics* statistics, received_retransmitted_packets_ - last_report_old_packets_; rec_since_last += retransmitted_packets; - *missing = 0; + int32_t missing = 0; 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; if (exp_since_last) { // Scale 0 to 255, where 255 is 100% loss. local_fraction_lost = - static_cast((255 * (*missing)) / exp_since_last); + static_cast(255 * missing / exp_since_last); } statistics->fraction_lost = local_fraction_lost; // We need a counter for cumulative loss too. - cumulative_loss_ += *missing; + cumulative_loss_ += missing; if (jitter_q4_ > jitter_max_q4_) { jitter_max_q4_ = jitter_q4_; @@ -260,10 +246,9 @@ bool ReceiveStatisticsImpl::Statistics(RtpReceiveStatistics* statistics, return true; } -void ReceiveStatisticsImpl::GetDataCounters( +void StreamStatisticianImpl::GetDataCounters( uint32_t* bytes_received, uint32_t* packets_received) const { - CriticalSectionScoped lock(crit_sect_.get()); - + CriticalSectionScoped cs(crit_sect_.get()); if (bytes_received) { *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(); } -int32_t ReceiveStatisticsImpl::TimeUntilNextProcess() { - int time_since_last_update = clock_->TimeInMilliseconds() - - incoming_bitrate_.time_last_rate_update(); - return std::max(kRateUpdateIntervalMs - time_since_last_update, 0); +void StreamStatisticianImpl::ProcessBitrate() { + CriticalSectionScoped cs(crit_sect_.get()); + incoming_bitrate_.Process(); +} + +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 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() { - 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; } +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 diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h index 03a394833..f96312336 100644 --- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h +++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h @@ -23,43 +23,43 @@ namespace webrtc { class CriticalSectionWrapper; -class ReceiveStatisticsImpl : public ReceiveStatistics { +class StreamStatisticianImpl : public StreamStatistician { public: - explicit ReceiveStatisticsImpl(Clock* clock); + explicit StreamStatisticianImpl(Clock* clock); - // Implements ReceiveStatistics. - 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(); + virtual ~StreamStatisticianImpl() {} - // Implements Module. - int32_t TimeUntilNextProcess(); - int32_t Process(); + virtual bool GetStatistics(Statistics* statistics, bool reset) OVERRIDE; + virtual void GetDataCounters(uint32_t* bytes_received, + 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: - scoped_ptr crit_sect_; Clock* clock_; + scoped_ptr crit_sect_; Bitrate incoming_bitrate_; uint32_t ssrc_; + // Stats on received RTP packets. uint32_t jitter_q4_; uint32_t jitter_max_q4_; uint32_t cumulative_loss_; 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_; int32_t last_received_transmission_time_offset_; uint16_t received_seq_first_; uint16_t received_seq_max_; uint16_t received_seq_wraps_; + bool first_packet_; // Current counter values. uint16_t received_packet_overhead_; @@ -71,7 +71,34 @@ class ReceiveStatisticsImpl : public ReceiveStatistics { uint32_t last_report_inorder_packets_; uint32_t last_report_old_packets_; 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 StatisticianImplMap; + + Clock* clock_; + scoped_ptr crit_sect_; + int64_t last_rate_update_ms_; + StatisticianImplMap statisticians_; }; } // namespace webrtc #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_ diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc new file mode 100644 index 000000000..a69e408e8 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc @@ -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 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 diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc index e7c7bcbf3..2a7902fad 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc @@ -61,6 +61,7 @@ class RtcpFormatRembTest : public ::testing::Test { RtcpFormatRembTest() : over_use_detector_options_(), system_clock_(Clock::GetRealTimeClock()), + receive_statistics_(ReceiveStatistics::Create(system_clock_)), remote_bitrate_observer_(), remote_bitrate_estimator_( RemoteBitrateEstimatorFactory().Create( @@ -72,6 +73,7 @@ class RtcpFormatRembTest : public ::testing::Test { OverUseDetectorOptions over_use_detector_options_; Clock* system_clock_; ModuleRtpRtcpImpl* dummy_rtp_rtcp_impl_; + scoped_ptr receive_statistics_; RTCPSender* rtcp_sender_; RTCPReceiver* rtcp_receiver_; TestTransport* test_transport_; @@ -86,7 +88,8 @@ void RtcpFormatRembTest::SetUp() { configuration.clock = system_clock_; configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get(); 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_); test_transport_ = new TestTransport(rtcp_receiver_); @@ -115,15 +118,13 @@ TEST_F(RtcpFormatRembTest, TestNonCompund) { uint32_t SSRC = 456789; EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpNonCompound)); 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) { uint32_t SSRCs[2] = {456789, 98765}; EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound)); EXPECT_EQ(0, rtcp_sender_->SetREMBData(1234, 2, SSRCs)); - ReceiveStatistics::RtpReceiveStatistics receive_stats; - memset(&receive_stats, 0, sizeof(receive_stats)); - EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRemb, &receive_stats)); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRemb)); } } // namespace diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc index a7c7dbc5e..551e1c559 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc @@ -68,7 +68,8 @@ std::string NACKStringBuilder::GetResult() RTCPSender::RTCPSender(const int32_t id, const bool audio, Clock* clock, - ModuleRtpRtcpImpl* owner) : + ModuleRtpRtcpImpl* owner, + ReceiveStatistics* receive_statistics) : _id(id), _audio(audio), _clock(clock), @@ -92,7 +93,9 @@ RTCPSender::RTCPSender(const int32_t id, _SSRC(0), _remoteSSRC(0), _CNAME(), - _reportBlocks(), + receive_statistics_(receive_statistics), + internal_report_blocks_(), + external_report_blocks_(), _csrcCNAMEs(), _cameraDelayMS(0), @@ -137,11 +140,15 @@ RTCPSender::~RTCPSender() { delete [] _rembSSRC; 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::iterator it = - _reportBlocks.begin(); + external_report_blocks_.begin(); delete it->second; - _reportBlocks.erase(it); + external_report_blocks_.erase(it); } while (!_csrcCNAMEs.empty()) { std::map::iterator it = @@ -271,7 +278,7 @@ RTCPSender::SetSendingStatus(const bool sending) } if(sendRTCPBye) { - return SendRTCP(kRtcpBye, NULL); + return SendRTCP(kRtcpBye); } return 0; } @@ -559,52 +566,59 @@ RTCPSender::SendTimeOfSendReport(const uint32_t sendReport) return 0; } -int32_t RTCPSender::AddReportBlock(const uint32_t SSRC, - const RTCPReportBlock* reportBlock) { +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* report_blocks, + const RTCPReportBlock* reportBlock) { if (reportBlock == NULL) { WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__); 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, "%s invalid argument", __FUNCTION__); return -1; } std::map::iterator it = - _reportBlocks.find(SSRC); - if (it != _reportBlocks.end()) { + report_blocks->find(SSRC); + if (it != report_blocks->end()) { delete it->second; - _reportBlocks.erase(it); + report_blocks->erase(it); } RTCPReportBlock* copyReportBlock = new RTCPReportBlock(); memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock)); - _reportBlocks[SSRC] = copyReportBlock; + (*report_blocks)[SSRC] = copyReportBlock; return 0; } -int32_t RTCPSender::RemoveReportBlock(const uint32_t SSRC) { +int32_t RTCPSender::RemoveExternalReportBlock(uint32_t SSRC) { CriticalSectionScoped lock(_criticalSectionRTCPSender); std::map::iterator it = - _reportBlocks.find(SSRC); + external_report_blocks_.find(SSRC); - if (it == _reportBlocks.end()) { + if (it == external_report_blocks_.end()) { return -1; } delete it->second; - _reportBlocks.erase(it); + external_report_blocks_.erase(it); return 0; } int32_t RTCPSender::BuildSR(uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const uint32_t NTPsec, - const uint32_t NTPfrac, - const RTCPReportBlock* received) + const uint32_t NTPfrac) { // sanity if(pos + 52 >= IP_PACKET_SIZE) @@ -672,12 +686,15 @@ RTCPSender::BuildSR(uint8_t* rtcpbuffer, pos += 4; 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) { // return retVal ; } + pos = retVal; rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks; uint16_t len = uint16_t((pos/4) -1); @@ -686,8 +703,7 @@ RTCPSender::BuildSR(uint8_t* rtcpbuffer, } -int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, - uint32_t& pos) { +int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, int& pos) { size_t lengthCname = strlen(_CNAME); assert(lengthCname < RTCP_CNAME_SIZE); @@ -782,10 +798,9 @@ int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, int32_t RTCPSender::BuildRR(uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const uint32_t NTPsec, - const uint32_t NTPfrac, - const RTCPReportBlock* received) + const uint32_t NTPfrac) { // sanity one block if(pos + 32 >= IP_PACKET_SIZE) @@ -806,11 +821,14 @@ RTCPSender::BuildRR(uint8_t* rtcpbuffer, pos += 4; 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) { - return retVal; + return pos; } + pos = retVal; rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks; uint16_t len = uint16_t((pos)/4 -1); @@ -839,10 +857,10 @@ RTCPSender::BuildRR(uint8_t* rtcpbuffer, int32_t RTCPSender::BuildExtendedJitterReport( uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const uint32_t jitterTransmissionTimeOffset) { - if (_reportBlocks.size() > 0) + if (external_report_blocks_.size() > 0) { WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Not implemented."); return 0; @@ -870,7 +888,7 @@ RTCPSender::BuildExtendedJitterReport( } int32_t -RTCPSender::BuildPLI(uint8_t* rtcpbuffer, uint32_t& pos) +RTCPSender::BuildPLI(uint8_t* rtcpbuffer, int& pos) { // sanity 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, - uint32_t& pos, + int& pos, bool repeat) { // sanity if(pos + 20 >= IP_PACKET_SIZE) { @@ -946,7 +964,7 @@ int32_t RTCPSender::BuildFIR(uint8_t* rtcpbuffer, +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 if(pos + 16 >= IP_PACKET_SIZE) @@ -993,7 +1011,7 @@ RTCPSender::BuildSLI(uint8_t* rtcpbuffer, uint32_t& pos, const uint8_t pictureID */ int32_t RTCPSender::BuildRPSI(uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const uint64_t pictureID, const uint8_t payloadType) { @@ -1069,7 +1087,7 @@ RTCPSender::BuildRPSI(uint8_t* rtcpbuffer, } int32_t -RTCPSender::BuildREMB(uint8_t* rtcpbuffer, uint32_t& pos) +RTCPSender::BuildREMB(uint8_t* rtcpbuffer, int& pos) { // sanity if(pos + 20 + 4 * _lengthRembSSRC >= IP_PACKET_SIZE) @@ -1130,7 +1148,7 @@ RTCPSender::SetTargetBitrate(unsigned int target_bitrate) } 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 // 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 -RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, uint32_t& pos) +RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, int& pos) { TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend(); if(boundingSet == NULL) @@ -1308,7 +1326,7 @@ RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, uint32_t& pos) } int32_t -RTCPSender::BuildAPP(uint8_t* rtcpbuffer, uint32_t& pos) +RTCPSender::BuildAPP(uint8_t* rtcpbuffer, int& pos) { // sanity if(_appData == NULL) @@ -1346,7 +1364,7 @@ RTCPSender::BuildAPP(uint8_t* rtcpbuffer, uint32_t& pos) int32_t RTCPSender::BuildNACK(uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const int32_t nackSize, const uint16_t* nackList, std::string* nackString) @@ -1416,7 +1434,7 @@ RTCPSender::BuildNACK(uint8_t* rtcpbuffer, } int32_t -RTCPSender::BuildBYE(uint8_t* rtcpbuffer, uint32_t& pos) +RTCPSender::BuildBYE(uint8_t* rtcpbuffer, int& pos) { // sanity if(pos + 8 >= IP_PACKET_SIZE) @@ -1461,7 +1479,7 @@ RTCPSender::BuildBYE(uint8_t* rtcpbuffer, uint32_t& pos) } int32_t -RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, uint32_t& pos) +RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos) { // sanity if(pos + 44 >= IP_PACKET_SIZE) @@ -1536,414 +1554,378 @@ RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, uint32_t& pos) int32_t RTCPSender::SendRTCP( uint32_t packetTypeFlags, - const ReceiveStatistics::RtpReceiveStatistics* receive_stats, int32_t nackSize, const uint16_t* nackList, bool repeat, 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); - if(_method == kRtcpOff) - { - WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, - "%s invalid state", __FUNCTION__); - return -1; - } - rtcpCompound = (_method == kRtcpCompound) ? true : false; - } - - if (rtcpCompound || - rtcpPacketTypeFlags & kRtcpReport || - rtcpPacketTypeFlags & kRtcpSr || - rtcpPacketTypeFlags & kRtcpRr) - { - // 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; - received.lastSR = remoteSR; - } else - { - // we need to send our NTP even if we dont have received any reports - _clock->CurrentNtp(NTPsec, NTPfrac); - } - } - - CriticalSectionScoped lock(_criticalSectionRTCPSender); - - if(_TMMBR ) // attach TMMBR to send and receive reports - { - rtcpPacketTypeFlags |= kRtcpTmmbr; - } - if(_appSend) - { - rtcpPacketTypeFlags |= kRtcpApp; - _appSend = false; - } - if(_REMB && _sendREMB) - { - // Always attach REMB to SR if that is configured. Note that REMB is - // only sent on one of the RTP modules in the REMB group. - rtcpPacketTypeFlags |= kRtcpRemb; - } - if(_xrSendVoIPMetric) - { - rtcpPacketTypeFlags |= kRtcpXrVoipMetric; - _xrSendVoIPMetric = false; - } - if(_sendTMMBN) // set when having received a TMMBR - { - rtcpPacketTypeFlags |= kRtcpTmmbn; - _sendTMMBN = false; - } - - if(_method == kRtcpCompound) - { - if(_sending) - { - rtcpPacketTypeFlags |= kRtcpSr; - } else - { - rtcpPacketTypeFlags |= kRtcpRr; - } - if (_IJ && hasReceived) - { - rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset; - } - } else if(_method == kRtcpNonCompound) - { - if(rtcpPacketTypeFlags & kRtcpReport) - { - if(_sending) - { - rtcpPacketTypeFlags |= kRtcpSr; - } else - { - rtcpPacketTypeFlags |= kRtcpRr; - } - } - } - if( rtcpPacketTypeFlags & kRtcpRr || - rtcpPacketTypeFlags & kRtcpSr) - { - // generate next time to send a RTCP report - // seeded from RTP constructor - int32_t random = rand() % 1000; - int32_t timeToNext = RTCP_INTERVAL_AUDIO_MS; - - if(_audio) - { - timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) + (RTCP_INTERVAL_AUDIO_MS*random/1000); - }else - { - uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS; - if(_sending) - { - // calc bw for video 360/sendBW in kbit/s - uint32_t sendBitrateKbit = 0; - uint32_t videoRate = 0; - uint32_t fecRate = 0; - uint32_t nackRate = 0; - _rtpRtcp.BitrateSent(&sendBitrateKbit, - &videoRate, - &fecRate, - &nackRate); - sendBitrateKbit /= 1000; - if(sendBitrateKbit != 0) - { - minIntervalMs = 360000/sendBitrateKbit; - } - } - if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS) - { - minIntervalMs = RTCP_INTERVAL_VIDEO_MS; - } - timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000); - } - _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext; - } - - // if the data does not fitt in the packet we fill it as much as possible - int32_t buildVal = 0; - - if(rtcpPacketTypeFlags & kRtcpSr) - { - if(hasReceived) - { - buildVal = BuildSR(rtcpbuffer, pos, NTPsec, NTPfrac, &received); - } else - { - buildVal = BuildSR(rtcpbuffer, pos, NTPsec, NTPfrac); - } - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - 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) - { - if(hasReceived) - { - buildVal = BuildRR(rtcpbuffer, pos, NTPsec, NTPfrac,&received); - }else - { - buildVal = BuildRR(rtcpbuffer, pos, NTPsec, NTPfrac); - } - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - // only of set - if(_CNAME[0] != 0) - { - buildVal = BuildSDEC(rtcpbuffer, pos); - if(buildVal == -1) - { - return -1; // error - } - } - } - if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset) - { - // If present, this RTCP packet must be placed after a - // receiver report. - buildVal = BuildExtendedJitterReport(rtcpbuffer, - pos, - jitterTransmissionOffset); - if(buildVal == -1) - { - return -1; // error - } - else if(buildVal == -2) - { - break; // out of buffer - } - } - if(rtcpPacketTypeFlags & kRtcpPli) - { - buildVal = BuildPLI(rtcpbuffer, pos); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI"); - _pliCount++; - TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_PLICount", _SSRC, _pliCount); - } - if(rtcpPacketTypeFlags & kRtcpFir) - { - buildVal = BuildFIR(rtcpbuffer, pos, repeat); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR"); - _fullIntraRequestCount++; - TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_FIRCount", _SSRC, - _fullIntraRequestCount); - } - if(rtcpPacketTypeFlags & kRtcpSli) - { - buildVal = BuildSLI(rtcpbuffer, pos, (uint8_t)pictureID); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - } - if(rtcpPacketTypeFlags & kRtcpRpsi) - { - const int8_t payloadType = _rtpRtcp.SendPayloadType(); - if(payloadType == -1) - { - return -1; - } - buildVal = BuildRPSI(rtcpbuffer, pos, pictureID, (uint8_t)payloadType); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - } - if(rtcpPacketTypeFlags & kRtcpRemb) - { - buildVal = BuildREMB(rtcpbuffer, pos); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::REMB"); - } - if(rtcpPacketTypeFlags & kRtcpBye) - { - buildVal = BuildBYE(rtcpbuffer, pos); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - } - if(rtcpPacketTypeFlags & kRtcpApp) - { - buildVal = BuildAPP(rtcpbuffer, pos); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - } - if(rtcpPacketTypeFlags & kRtcpTmmbr) - { - buildVal = BuildTMMBR(rtcpbuffer, pos); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - } - if(rtcpPacketTypeFlags & kRtcpTmmbn) - { - buildVal = BuildTMMBN(rtcpbuffer, pos); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - } - if(rtcpPacketTypeFlags & kRtcpNack) - { - std::string nackString; - buildVal = BuildNACK(rtcpbuffer, pos, nackSize, nackList, - &nackString); - if(buildVal == -1) - { - return -1; // error - - }else if(buildVal == -2) - { - break; // out of buffer - } - TRACE_EVENT_INSTANT1("webrtc_rtp", "RTCPSender::NACK", - "nacks", TRACE_STR_COPY(nackString.c_str())); - _nackCount++; - TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_NACKCount", _SSRC, _nackCount); - } - if(rtcpPacketTypeFlags & kRtcpXrVoipMetric) - { - buildVal = BuildVoIPMetric(rtcpbuffer, pos); - 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) + { + CriticalSectionScoped lock(_criticalSectionRTCPSender); + if(_method == kRtcpOff) { + WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, + "%s invalid state", __FUNCTION__); return -1; } - return SendToNetwork(rtcpbuffer, (uint16_t)pos); + } + uint8_t rtcp_buffer[IP_PACKET_SIZE]; + int rtcp_length = PrepareRTCP(packetTypeFlags, nackSize, nackList, repeat, + pictureID, rtcp_buffer, IP_PACKET_SIZE); + if (rtcp_length < 0) { + return -1; + } + // Sanity don't send empty packets. + if (rtcp_length == 0) + { + return -1; + } + return SendToNetwork(rtcp_buffer, static_cast(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); + + if(_TMMBR ) // Attach TMMBR to send and receive reports. + { + rtcpPacketTypeFlags |= kRtcpTmmbr; + } + if(_appSend) + { + rtcpPacketTypeFlags |= kRtcpApp; + _appSend = false; + } + if(_REMB && _sendREMB) + { + // Always attach REMB to SR if that is configured. Note that REMB is + // only sent on one of the RTP modules in the REMB group. + rtcpPacketTypeFlags |= kRtcpRemb; + } + if(_xrSendVoIPMetric) + { + rtcpPacketTypeFlags |= kRtcpXrVoipMetric; + _xrSendVoIPMetric = false; + } + if(_sendTMMBN) // Set when having received a TMMBR. + { + rtcpPacketTypeFlags |= kRtcpTmmbn; + _sendTMMBN = false; + } + + if(_method == kRtcpCompound) + { + if(_sending) + { + rtcpPacketTypeFlags |= kRtcpSr; + } else + { + rtcpPacketTypeFlags |= kRtcpRr; + } + } else if(_method == kRtcpNonCompound) + { + if(rtcpPacketTypeFlags & kRtcpReport) + { + if(_sending) + { + rtcpPacketTypeFlags |= kRtcpSr; + } else + { + rtcpPacketTypeFlags |= kRtcpRr; + } + } + } + if( rtcpPacketTypeFlags & kRtcpRr || + rtcpPacketTypeFlags & kRtcpSr) + { + // generate next time to send a RTCP report + // seeded from RTP constructor + int32_t random = rand() % 1000; + int32_t timeToNext = RTCP_INTERVAL_AUDIO_MS; + + if(_audio) + { + timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) + + (RTCP_INTERVAL_AUDIO_MS*random/1000); + }else + { + uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS; + if(_sending) + { + // Calculate bandwidth for video; 360 / send bandwidth in kbit/s. + uint32_t sendBitrateKbit = 0; + uint32_t videoRate = 0; + uint32_t fecRate = 0; + uint32_t nackRate = 0; + _rtpRtcp.BitrateSent(&sendBitrateKbit, + &videoRate, + &fecRate, + &nackRate); + sendBitrateKbit /= 1000; + if(sendBitrateKbit != 0) + { + minIntervalMs = 360000/sendBitrateKbit; + } + } + if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS) + { + minIntervalMs = RTCP_INTERVAL_VIDEO_MS; + } + timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000); + } + _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext; + } + + // If the data does not fit in the packet we fill it as much as possible. + 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) + { + buildVal = BuildSR(rtcp_buffer, position, NTPsec, NTPfrac); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + buildVal = BuildSDEC(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + }else if(rtcpPacketTypeFlags & kRtcpRr) + { + buildVal = BuildRR(rtcp_buffer, position, NTPsec, NTPfrac); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + // only of set + if(_CNAME[0] != 0) + { + buildVal = BuildSDEC(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } + } + } + if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset) + { + // If present, this RTCP packet must be placed after a + // receiver report. + buildVal = BuildExtendedJitterReport(rtcp_buffer, + position, + jitterTransmissionOffset); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + } + if(rtcpPacketTypeFlags & kRtcpPli) + { + buildVal = BuildPLI(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI"); + _pliCount++; + TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_PLICount", _SSRC, _pliCount); + } + if(rtcpPacketTypeFlags & kRtcpFir) + { + buildVal = BuildFIR(rtcp_buffer, position, repeat); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR"); + _fullIntraRequestCount++; + TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_FIRCount", _SSRC, + _fullIntraRequestCount); + } + if(rtcpPacketTypeFlags & kRtcpSli) + { + buildVal = BuildSLI(rtcp_buffer, position, (uint8_t)pictureID); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + } + if(rtcpPacketTypeFlags & kRtcpRpsi) + { + const int8_t payloadType = _rtpRtcp.SendPayloadType(); + if (payloadType == -1) { + return -1; + } + buildVal = BuildRPSI(rtcp_buffer, position, pictureID, + (uint8_t)payloadType); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + } + if(rtcpPacketTypeFlags & kRtcpRemb) + { + buildVal = BuildREMB(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::REMB"); + } + if(rtcpPacketTypeFlags & kRtcpBye) + { + buildVal = BuildBYE(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + } + if(rtcpPacketTypeFlags & kRtcpApp) + { + buildVal = BuildAPP(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + } + if(rtcpPacketTypeFlags & kRtcpTmmbr) + { + buildVal = BuildTMMBR(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + } + if(rtcpPacketTypeFlags & kRtcpTmmbn) + { + buildVal = BuildTMMBN(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + } + if(rtcpPacketTypeFlags & kRtcpNack) + { + std::string nackString; + buildVal = BuildNACK(rtcp_buffer, position, nackSize, nackList, + &nackString); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + TRACE_EVENT_INSTANT1("webrtc_rtp", "RTCPSender::NACK", + "nacks", TRACE_STR_COPY(nackString.c_str())); + _nackCount++; + TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_NACKCount", _SSRC, _nackCount); + } + if(rtcpPacketTypeFlags & kRtcpXrVoipMetric) + { + buildVal = BuildVoIPMetric(rtcp_buffer, position); + if (buildVal == -1) { + return -1; + } else if (buildVal == -2) { + return position; + } + } + 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 @@ -2027,103 +2009,76 @@ RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) } // called under critsect _criticalSectionRTCPSender -int32_t RTCPSender::AddReportBlocks(uint8_t* rtcpbuffer, - uint32_t& pos, - uint8_t& numberOfReportBlocks, - const RTCPReportBlock* received, - const uint32_t NTPsec, - const uint32_t NTPfrac) { +int32_t RTCPSender::WriteAllReportBlocksToBuffer( + uint8_t* rtcpbuffer, + int pos, + uint8_t& numberOfReportBlocks, + const uint32_t NTPsec, + const uint32_t NTPfrac) { // sanity one block if(pos + 24 >= IP_PACKET_SIZE) { WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__); return -1; } - numberOfReportBlocks = _reportBlocks.size(); - if (received) { - // add our multiple RR to numberOfReportBlocks - 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) { + numberOfReportBlocks = external_report_blocks_.size(); + numberOfReportBlocks += internal_report_blocks_.size(); + if ((pos + numberOfReportBlocks * 24) >= IP_PACKET_SIZE) { WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__); return -1; } - std::map::iterator it = - _reportBlocks.begin(); + pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, internal_report_blocks_); + 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++) { - // we can have multiple report block in a conference +int32_t RTCPSender::WriteReportBlocksToBuffer( + uint8_t* rtcpbuffer, + int32_t position, + const std::map& report_blocks) { + std::map::const_iterator it = + report_blocks.begin(); + for (; it != report_blocks.end(); it++) { uint32_t remoteSSRC = it->first; RTCPReportBlock* reportBlock = it->second; if (reportBlock) { // Remote SSRC - ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, remoteSSRC); - pos += 4; + ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position, remoteSSRC); + position += 4; // fraction lost - rtcpbuffer[pos++] = reportBlock->fractionLost; + rtcpbuffer[position++] = reportBlock->fractionLost; // cumulative loss - ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+pos, + ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+position, reportBlock->cumulativeLost); - pos += 3; + position += 3; // extended highest seq_no, contain the highest sequence number received - ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, + ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position, reportBlock->extendedHighSeqNum); - pos += 4; + position += 4; - //Jitter - ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, + // Jitter + ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position, reportBlock->jitter); - pos += 4; + position += 4; - ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, + ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position, reportBlock->lastSR); - pos += 4; + position += 4; - ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, + ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position, reportBlock->delaySinceLastSR); - pos += 4; + position += 4; } } - return pos; + return position; } // no callbacks allowed inside this function diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h index 3b6797780..06c14ce0e 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h @@ -49,7 +49,8 @@ class RTCPSender { public: RTCPSender(const int32_t id, const bool audio, - Clock* clock, ModuleRtpRtcpImpl* owner); + Clock* clock, ModuleRtpRtcpImpl* owner, + ReceiveStatistics* receive_statistics); virtual ~RTCPSender(); void ChangeUniqueId(const int32_t id); @@ -93,16 +94,16 @@ public: int32_t SendRTCP( uint32_t rtcpPacketTypeFlags, - const ReceiveStatistics::RtpReceiveStatistics* receive_stats, int32_t nackSize = 0, const uint16_t* nackList = 0, bool repeat = false, uint64_t pictureID = 0); - int32_t AddReportBlock(const uint32_t SSRC, - const RTCPReportBlock* receiveBlock); + int32_t AddExternalReportBlock( + uint32_t SSRC, + const RTCPReportBlock* receiveBlock); - int32_t RemoveReportBlock(const uint32_t SSRC); + int32_t RemoveExternalReportBlock(uint32_t SSRC); /* * REMB @@ -155,49 +156,71 @@ private: void UpdatePacketRate(); - int32_t AddReportBlocks(uint8_t* rtcpbuffer, - uint32_t& pos, + int32_t WriteAllReportBlocksToBuffer(uint8_t* rtcpbuffer, + int pos, uint8_t& numberOfReportBlocks, - const RTCPReportBlock* received, const uint32_t NTPsec, const uint32_t NTPfrac); + int32_t WriteReportBlocksToBuffer( + uint8_t* rtcpbuffer, + int32_t position, + const std::map& report_blocks); + + int32_t AddReportBlock( + uint32_t SSRC, + std::map* 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, - uint32_t& pos, + int& pos, const uint32_t NTPsec, - const uint32_t NTPfrac, - const RTCPReportBlock* received = NULL); + const uint32_t NTPfrac); int32_t BuildRR(uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const uint32_t NTPsec, - const uint32_t NTPfrac, - const RTCPReportBlock* received = NULL); + const uint32_t NTPfrac); + + 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( uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const uint32_t jitterTransmissionTimeOffset); - int32_t BuildSDEC(uint8_t* rtcpbuffer, uint32_t& pos); - int32_t BuildPLI(uint8_t* rtcpbuffer, uint32_t& pos); - int32_t BuildREMB(uint8_t* rtcpbuffer, uint32_t& pos); - int32_t BuildTMMBR(uint8_t* rtcpbuffer, uint32_t& pos); - int32_t BuildTMMBN(uint8_t* rtcpbuffer, uint32_t& pos); - int32_t BuildAPP(uint8_t* rtcpbuffer, uint32_t& pos); - int32_t BuildVoIPMetric(uint8_t* rtcpbuffer, uint32_t& pos); - int32_t BuildBYE(uint8_t* rtcpbuffer, uint32_t& pos); - int32_t BuildFIR(uint8_t* rtcpbuffer, uint32_t& pos, bool repeat); + int32_t BuildSDEC(uint8_t* rtcpbuffer, int& pos); + int32_t BuildPLI(uint8_t* rtcpbuffer, int& pos); + int32_t BuildREMB(uint8_t* rtcpbuffer, int& pos); + int32_t BuildTMMBR(uint8_t* rtcpbuffer, int& pos); + int32_t BuildTMMBN(uint8_t* rtcpbuffer, int& pos); + int32_t BuildAPP(uint8_t* rtcpbuffer, int& pos); + int32_t BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos); + int32_t BuildBYE(uint8_t* rtcpbuffer, int& pos); + int32_t BuildFIR(uint8_t* rtcpbuffer, int& pos, bool repeat); int32_t BuildSLI(uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const uint8_t pictureID); int32_t BuildRPSI(uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const uint64_t pictureID, const uint8_t payloadType); int32_t BuildNACK(uint8_t* rtcpbuffer, - uint32_t& pos, + int& pos, const int32_t nackSize, const uint16_t* nackList, std::string* nackString); @@ -231,7 +254,10 @@ private: uint32_t _remoteSSRC; // SSRC that we receive on our RTP channel char _CNAME[RTCP_CNAME_SIZE]; - std::map _reportBlocks; + + ReceiveStatistics* receive_statistics_; + std::map internal_report_blocks_; + std::map external_report_blocks_; std::map _csrcCNAMEs; int32_t _cameraDelayMS; diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc index 855f418cc..6e05fd125 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc @@ -285,7 +285,8 @@ class RtcpSenderTest : public ::testing::Test { remote_bitrate_estimator_( RemoteBitrateEstimatorFactory().Create( &remote_bitrate_observer_, - system_clock_)) { + system_clock_)), + receive_statistics_(ReceiveStatistics::Create(system_clock_)) { test_transport_ = new TestTransport(); RtpRtcp::Configuration configuration; @@ -298,7 +299,8 @@ class RtcpSenderTest : public ::testing::Test { rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration); rtp_receiver_.reset(RtpReceiver::CreateVideoReceiver( 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_); test_transport_->SetRTCPReceiver(rtcp_receiver_); // Initialize @@ -328,6 +330,7 @@ class RtcpSenderTest : public ::testing::Test { TestTransport* test_transport_; MockRemoteBitrateObserver remote_bitrate_observer_; scoped_ptr remote_bitrate_estimator_; + scoped_ptr receive_statistics_; enum {kMaxPacketLength = 1500}; uint8_t packet_[kMaxPacketLength]; @@ -335,7 +338,7 @@ class RtcpSenderTest : public ::testing::Test { TEST_F(RtcpSenderTest, RtcpOff) { 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) { @@ -372,14 +375,13 @@ TEST_F(RtcpSenderTest, TestCompound) { PayloadUnion payload_specific; EXPECT_TRUE(rtp_payload_registry_->GetPayloadSpecifics(header.payloadType, &payload_specific)); + receive_statistics_->IncomingPacket(header, packet_length, false, true); EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(&header, packet_, packet_length, payload_specific, true)); EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true)); EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound)); - ReceiveStatistics::RtpReceiveStatistics receive_stats; - memset(&receive_stats, 0, sizeof(receive_stats)); - EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr, &receive_stats)); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr)); // Transmission time offset packet should be received. ASSERT_TRUE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags & @@ -389,9 +391,7 @@ TEST_F(RtcpSenderTest, TestCompound) { TEST_F(RtcpSenderTest, TestCompound_NoRtpReceived) { EXPECT_EQ(0, rtcp_sender_->SetIJStatus(true)); EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound)); - // |receive_stats| is NULL since no data has been received. - ReceiveStatistics::RtpReceiveStatistics* receive_stats = NULL; - EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr, receive_stats)); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpRr)); // Transmission time offset packet should not be received. ASSERT_FALSE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags & @@ -409,9 +409,7 @@ TEST_F(RtcpSenderTest, SendsTmmbnIfSetAndEmpty) { TMMBRSet bounding_set; EXPECT_EQ(0, rtcp_sender_->SetTMMBN(&bounding_set, 3)); ASSERT_EQ(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags); - ReceiveStatistics::RtpReceiveStatistics receive_stats; - memset(&receive_stats, 0, sizeof(receive_stats)); - EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpSr, &receive_stats)); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpSr)); // We now expect the packet to show up in the rtcp_packet_info_ of // test_transport_. 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)); ASSERT_EQ(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags); - ReceiveStatistics::RtpReceiveStatistics receive_stats; - memset(&receive_stats, 0, sizeof(receive_stats)); - EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpSr, &receive_stats)); + EXPECT_EQ(0, rtcp_sender_->SendRTCP(kRtcpSr)); // We now expect the packet to show up in the rtcp_packet_info_ of // test_transport_. ASSERT_NE(0U, test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc index b50b348a9..c3d1039fa 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc @@ -283,7 +283,7 @@ bool RtpReceiverImpl::IncomingRtpPacket( } if (should_reset_statistics) { - cb_rtp_feedback_->ResetStatistics(); + cb_rtp_feedback_->ResetStatistics(ssrc_); } 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. new_ssrc = true; - cb_rtp_feedback_->ResetStatistics(); + cb_rtp_feedback_->ResetStatistics(ssrc_); last_received_timestamp_ = 0; last_received_sequence_number_ = 0; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 145c89b6e..1dd7cd057 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -41,7 +41,7 @@ RtpRtcp::Configuration::Configuration() audio(false), clock(NULL), default_module(NULL), - receive_statistics(NULL), + receive_statistics(NullObjectReceiveStatistics()), outgoing_transport(NULL), rtcp_feedback(NULL), intra_frame_callback(NULL), @@ -74,10 +74,9 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) configuration.audio_messages, configuration.paced_sender), rtcp_sender_(configuration.id, configuration.audio, configuration.clock, - this), + this, configuration.receive_statistics), rtcp_receiver_(configuration.id, configuration.clock, this), clock_(configuration.clock), - receive_statistics_(configuration.receive_statistics), id_(configuration.id), audio_(configuration.audio), collision_detected_(false), @@ -242,13 +241,7 @@ int32_t ModuleRtpRtcpImpl::Process() { } } if (rtcp_sender_.TimeToSendRTCPReport()) { - ReceiveStatistics::RtpReceiveStatistics receive_stats; - if (receive_statistics_ && - receive_statistics_->Statistics(&receive_stats, true)) { - rtcp_sender_.SendRTCP(kRtcpReport, &receive_stats); - } else { - rtcp_sender_.SendRTCP(kRtcpReport, NULL); - } + rtcp_sender_.SendRTCP(kRtcpReport); } } @@ -577,13 +570,7 @@ int32_t ModuleRtpRtcpImpl::SendOutgoingData( if (!have_child_modules) { // Don't send RTCP from default module. if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) { - ReceiveStatistics::RtpReceiveStatistics receive_stats; - if (receive_statistics_ && - receive_statistics_->Statistics(&receive_stats, true)) { - rtcp_sender_.SendRTCP(kRtcpReport, &receive_stats); - } else { - rtcp_sender_.SendRTCP(kRtcpReport, NULL); - } + rtcp_sender_.SendRTCP(kRtcpReport); } return rtp_sender_.SendOutgoingData(frame_type, payload_type, @@ -925,19 +912,7 @@ int32_t ModuleRtpRtcpImpl::ResetSendDataCountersRTP() { int32_t ModuleRtpRtcpImpl::SendRTCP(uint32_t rtcp_packet_type) { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SendRTCP(0x%x)", rtcp_packet_type); - ReceiveStatistics::RtpReceiveStatistics receive_stats; - 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); + return rtcp_sender_.SendRTCP(kRtcpReport); } int32_t ModuleRtpRtcpImpl::SetRTCPApplicationSpecificData( @@ -993,14 +968,14 @@ int32_t ModuleRtpRtcpImpl::AddRTCPReportBlock( const RTCPReportBlock* report_block) { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "AddRTCPReportBlock()"); - return rtcp_sender_.AddReportBlock(ssrc, report_block); + return rtcp_sender_.AddExternalReportBlock(ssrc, report_block); } int32_t ModuleRtpRtcpImpl::RemoveRTCPReportBlock( const uint32_t ssrc) { WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoveRTCPReportBlock()"); - return rtcp_sender_.RemoveReportBlock(ssrc); + return rtcp_sender_.RemoveExternalReportBlock(ssrc); } // (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]; - ReceiveStatistics::RtpReceiveStatistics receive_stats; - 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]); - } + return rtcp_sender_.SendRTCP(kRtcpNack, nackLength, &nack_list[start_id]); } // Store the sent packets, needed to answer to a Negative acknowledgment @@ -1357,14 +1324,8 @@ int32_t ModuleRtpRtcpImpl::SendRTCPSliceLossIndication( id_, "SendRTCPSliceLossIndication (picture_id:%d)", picture_id); - ReceiveStatistics::RtpReceiveStatistics receive_stats; - if (rtcp_sender_.Status() == kRtcpCompound && receive_statistics_ && - 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); - } + + return rtcp_sender_.SendRTCP(kRtcpSli, 0, 0, false, picture_id); } int32_t ModuleRtpRtcpImpl::SetCameraDelay(const int32_t delay_ms) { @@ -1562,14 +1523,7 @@ void ModuleRtpRtcpImpl::OnRequestSendReport() { int32_t ModuleRtpRtcpImpl::SendRTCPReferencePictureSelection( const uint64_t picture_id) { - ReceiveStatistics::RtpReceiveStatistics receive_stats; - 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); - } + return rtcp_sender_.SendRTCP(kRtcpRpsi, 0, 0, false, picture_id); } uint32_t ModuleRtpRtcpImpl::SendTimeOfSendReport( diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h index 76862884a..11340c264 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -377,8 +377,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp { private: int64_t RtcpReportInterval(); - ReceiveStatistics* receive_statistics_; - int32_t id_; const bool audio_; bool collision_detected_; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_utility.cc b/webrtc/modules/rtp_rtcp/source/rtp_utility.cc index dd6260445..409a1773d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_utility.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_utility.cc @@ -61,6 +61,11 @@ RtpAudioFeedback* NullObjectRtpAudioFeedback() { return &null_rtp_audio_feedback; } +ReceiveStatistics* NullObjectReceiveStatistics() { + static NullReceiveStatistics null_receive_statistics; + return &null_receive_statistics; +} + namespace ModuleRTPUtility { enum { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_utility.h b/webrtc/modules/rtp_rtcp/source/rtp_utility.h index e2706f2fe..72bbfa0e5 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_utility.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_utility.h @@ -14,6 +14,7 @@ #include // size_t, ptrdiff_t #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_rtcp_config.h" #include "webrtc/typedefs.h" @@ -25,6 +26,7 @@ const uint8_t kRtpMarkerBitMask = 0x80; RtpData* NullObjectRtpData(); RtpFeedback* NullObjectRtpFeedback(); RtpAudioFeedback* NullObjectRtpAudioFeedback(); +ReceiveStatistics* NullObjectReceiveStatistics(); namespace ModuleRTPUtility { diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc index 66026b05c..3df06a210 100644 --- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc +++ b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc @@ -76,8 +76,8 @@ class TestRtpFeedback : public NullRtpFeedback { virtual ~TestRtpFeedback() {} virtual void OnIncomingSSRCChanged(const int32_t id, - const uint32_t SSRC) { - rtp_rtcp_->SetRemoteSSRC(SSRC); + const uint32_t ssrc) { + rtp_rtcp_->SetRemoteSSRC(ssrc); } private: @@ -334,8 +334,10 @@ TEST_F(RtpRtcpRtcpTest, RTCP) { EXPECT_EQ(static_cast(0), reportBlockReceived.cumulativeLost); - ReceiveStatistics::RtpReceiveStatistics stats; - EXPECT_TRUE(receive_statistics2_->Statistics(&stats, true)); + StreamStatistician *statistician = + receive_statistics2_->GetStatistician(reportBlockReceived.sourceSSRC); + StreamStatistician::Statistics stats; + EXPECT_TRUE(statistician->GetStatistics(&stats, true)); EXPECT_EQ(0, stats.fraction_lost); EXPECT_EQ((uint32_t)0, stats.cumulative_lost); EXPECT_EQ(test_sequence_number, stats.extended_max_sequence_number); diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index 851d1c054..2a00c210c 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -324,6 +324,7 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_), "%s: RTP::SetRTCPStatus failure", __FUNCTION__); } + if (rtp_rtcp_->StorePackets()) { rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_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_), "%s", __FUNCTION__); + uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc(); uint8_t frac_lost = 0; - ReceiveStatistics* receive_statistics = vie_receiver_.GetReceiveStatistics(); - ReceiveStatistics::RtpReceiveStatistics receive_stats; - if (!receive_statistics || !receive_statistics->Statistics( + StreamStatistician* statistician = + vie_receiver_.GetReceiveStatistics()->GetStatistician(remote_ssrc); + StreamStatistician::Statistics receive_stats; + if (!statistician || !statistician->GetStatistics( &receive_stats, rtp_rtcp_->RTCP() == kRtcpOff)) { WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), "%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; *fraction_lost = frac_lost; - uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc(); uint16_t dummy = 0; uint16_t rtt = 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", __FUNCTION__); - ReceiveStatistics* receive_statistics = vie_receiver_.GetReceiveStatistics(); - receive_statistics->GetDataCounters(bytes_received, packets_received); + StreamStatistician* statistician = vie_receiver_.GetReceiveStatistics()-> + 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) { WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), "%s: Could not get counters", __FUNCTION__); @@ -1888,8 +1894,7 @@ int32_t ViEChannel::OnInitializeDecoder( return 0; } -void ViEChannel::OnIncomingSSRCChanged(const int32_t id, - const uint32_t SSRC) { +void ViEChannel::OnIncomingSSRCChanged(const int32_t id, const uint32_t ssrc) { if (channel_id_ != ChannelId(id)) { assert(false); 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_), - "%s: %u", __FUNCTION__, SSRC); + "%s: %u", __FUNCTION__, ssrc); - rtp_rtcp_->SetRemoteSSRC(SSRC); + rtp_rtcp_->SetRemoteSSRC(ssrc); CriticalSectionScoped cs(callback_cs_.get()); { 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() { - vie_receiver_.GetReceiveStatistics()->ResetStatistics(); +void ViEChannel::ResetStatistics(uint32_t ssrc) { + StreamStatistician* statistician = + vie_receiver_.GetReceiveStatistics()->GetStatistician(ssrc); + if (statistician) + statistician->ResetStatistics(); } } // namespace webrtc diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h index 0d2e64b42..322ec9521 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -212,11 +212,11 @@ class ViEChannel const uint8_t channels, const uint32_t rate); virtual void OnIncomingSSRCChanged(const int32_t id, - const uint32_t SSRC); + const uint32_t ssrc); virtual void OnIncomingCSRCChanged(const int32_t id, const uint32_t CSRC, const bool added); - virtual void ResetStatistics(); + virtual void ResetStatistics(uint32_t); int32_t SetLocalReceiver(const uint16_t rtp_port, const uint16_t rtcp_port, diff --git a/webrtc/video_engine/vie_receiver.cc b/webrtc/video_engine/vie_receiver.cc index 2edf68b76..cc50b9ac7 100644 --- a/webrtc/video_engine/vie_receiver.cc +++ b/webrtc/video_engine/vie_receiver.cc @@ -404,8 +404,10 @@ bool ViEReceiver::IsPacketRetransmitted(const RTPHeader& header) const { rtp_receiver_->RTXStatus(&rtx_enabled, &rtx_ssrc, &rtx_payload_type); if (!rtx_enabled) { // Check if this is a retransmission. - ReceiveStatistics::RtpReceiveStatistics stats; - if (rtp_receive_statistics_->Statistics(&stats, false)) { + StreamStatistician::Statistics stats; + StreamStatistician* statistician = + rtp_receive_statistics_->GetStatistician(header.ssrc); + if (statistician && statistician->GetStatistics(&stats, false)) { uint16_t min_rtt = 0; rtp_rtcp_->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL); return rtp_receiver_->RetransmitOfOldPacket(header, stats.jitter, diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc index f8f8bd2c3..4671b6fd1 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -360,20 +360,15 @@ Channel::OnPlayTelephoneEvent(int32_t id, } void -Channel::OnIncomingSSRCChanged(int32_t id, - uint32_t SSRC) +Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc) { WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId), "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)", - id, SSRC); + id, ssrc); int32_t channel = VoEChannelId(id); 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) { CriticalSectionScoped cs(&_callbackCritSect); @@ -381,7 +376,7 @@ Channel::OnIncomingSSRCChanged(int32_t id, if (_rtpObserverPtr) { // 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() { - rtp_receive_statistics_->ResetStatistics(); +void Channel::ResetStatistics(uint32_t ssrc) { + StreamStatistician* statistician = + rtp_receive_statistics_->GetStatistician(ssrc); + if (statistician) { + statistician->ResetStatistics(); + } } void @@ -2231,8 +2230,10 @@ bool Channel::IsPacketRetransmitted(const RTPHeader& header) const { rtp_receiver_->RTXStatus(&rtx_enabled, &rtx_ssrc, &rtx_payload_type); if (!rtx_enabled) { // Check if this is a retransmission. - ReceiveStatistics::RtpReceiveStatistics stats; - if (rtp_receive_statistics_->Statistics(&stats, false)) { + StreamStatistician::Statistics stats; + StreamStatistician* statistician = + rtp_receive_statistics_->GetStatistician(header.ssrc); + if (statistician && statistician->GetStatistics(&stats, false)) { uint16_t min_rtt = 0; _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL); 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 // based on received packets. - ReceiveStatistics::RtpReceiveStatistics statistics; - if (!rtp_receive_statistics_->Statistics( + StreamStatistician::Statistics statistics; + StreamStatistician* statistician = + rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC()); + if (!statistician || !statistician->GetStatistics( &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) { _engineStatisticsPtr->SetLastError( 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 // based on received packets. - ReceiveStatistics::RtpReceiveStatistics statistics; - if (!rtp_receive_statistics_->Statistics( + StreamStatistician::Statistics statistics; + StreamStatistician* statistician = + rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC()); + if (!statistician || !statistician->GetStatistics( &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) { _engineStatisticsPtr->SetLastError( VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning, @@ -4087,7 +4092,9 @@ Channel::GetRTPStatistics(CallStatistics& stats) uint32_t bytesReceived(0); uint32_t packetsReceived(0); - rtp_receive_statistics_->GetDataCounters(&bytesReceived, &packetsReceived); + if (statistician) { + statistician->GetDataCounters(&bytesReceived, &packetsReceived); + } if (_rtpRtcpModule->DataCountersRTP(&bytesSent, &packetsSent) != 0) diff --git a/webrtc/voice_engine/channel.h b/webrtc/voice_engine/channel.h index f88dca477..34013069f 100644 --- a/webrtc/voice_engine/channel.h +++ b/webrtc/voice_engine/channel.h @@ -329,12 +329,12 @@ public: RTPAliveType alive); void OnIncomingSSRCChanged(int32_t id, - uint32_t SSRC); + uint32_t ssrc); void OnIncomingCSRCChanged(int32_t id, uint32_t CSRC, bool added); - void ResetStatistics(); + void ResetStatistics(uint32_t ssrc); public: // From RtcpFeedback in the RTP/RTCP module