Add a mutex free implementation of webrtc::ReceiveStatistics
The mutex is removed from the old existing implementation and instead a wrapper is implemented that ensure thread-safety. Both the thread-safe and unsafe version share the same implementation of the logic. There are two ways of construction: webrtc::ReceiveStatistics::Create - thread-safe version. webrtc::ReceiveStatistics::CreateUnLocked -thread-unsafe Bug: none Change-Id: Ica375919fda70180335c8f9ea666497811daf866 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/211240 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33419}
This commit is contained in:
parent
bb22066e60
commit
ee8cd20ec5
@ -55,7 +55,12 @@ class ReceiveStatistics : public ReceiveStatisticsProvider,
|
||||
public:
|
||||
~ReceiveStatistics() override = default;
|
||||
|
||||
// Returns a thread-safe instance of ReceiveStatistics.
|
||||
// https://chromium.googlesource.com/chromium/src/+/lkgr/docs/threading_and_tasks.md#threading-lexicon
|
||||
static std::unique_ptr<ReceiveStatistics> Create(Clock* clock);
|
||||
// Returns a thread-compatible instance of ReceiveStatistics.
|
||||
static std::unique_ptr<ReceiveStatistics> CreateThreadCompatible(
|
||||
Clock* clock);
|
||||
|
||||
// Returns a pointer to the statistician of an ssrc.
|
||||
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const = 0;
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
||||
@ -100,7 +101,6 @@ bool StreamStatisticianImpl::UpdateOutOfOrder(const RtpPacketReceived& packet,
|
||||
}
|
||||
|
||||
void StreamStatisticianImpl::UpdateCounters(const RtpPacketReceived& packet) {
|
||||
MutexLock lock(&stream_lock_);
|
||||
RTC_DCHECK_EQ(ssrc_, packet.Ssrc());
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
|
||||
@ -159,17 +159,14 @@ void StreamStatisticianImpl::UpdateJitter(const RtpPacketReceived& packet,
|
||||
|
||||
void StreamStatisticianImpl::SetMaxReorderingThreshold(
|
||||
int max_reordering_threshold) {
|
||||
MutexLock lock(&stream_lock_);
|
||||
max_reordering_threshold_ = max_reordering_threshold;
|
||||
}
|
||||
|
||||
void StreamStatisticianImpl::EnableRetransmitDetection(bool enable) {
|
||||
MutexLock lock(&stream_lock_);
|
||||
enable_retransmit_detection_ = enable;
|
||||
}
|
||||
|
||||
RtpReceiveStats StreamStatisticianImpl::GetStats() const {
|
||||
MutexLock lock(&stream_lock_);
|
||||
RtpReceiveStats stats;
|
||||
stats.packets_lost = cumulative_loss_;
|
||||
// TODO(nisse): Can we return a float instead?
|
||||
@ -183,7 +180,6 @@ RtpReceiveStats StreamStatisticianImpl::GetStats() const {
|
||||
|
||||
bool StreamStatisticianImpl::GetActiveStatisticsAndReset(
|
||||
RtcpStatistics* statistics) {
|
||||
MutexLock lock(&stream_lock_);
|
||||
if (clock_->TimeInMilliseconds() - last_receive_time_ms_ >=
|
||||
kStatisticsTimeoutMs) {
|
||||
// Not active.
|
||||
@ -192,9 +188,7 @@ bool StreamStatisticianImpl::GetActiveStatisticsAndReset(
|
||||
if (!ReceivedRtpPacket()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*statistics = CalculateRtcpStatistics();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -241,7 +235,6 @@ RtcpStatistics StreamStatisticianImpl::CalculateRtcpStatistics() {
|
||||
}
|
||||
|
||||
absl::optional<int> StreamStatisticianImpl::GetFractionLostInPercent() const {
|
||||
MutexLock lock(&stream_lock_);
|
||||
if (!ReceivedRtpPacket()) {
|
||||
return absl::nullopt;
|
||||
}
|
||||
@ -257,12 +250,10 @@ absl::optional<int> StreamStatisticianImpl::GetFractionLostInPercent() const {
|
||||
|
||||
StreamDataCounters StreamStatisticianImpl::GetReceiveStreamDataCounters()
|
||||
const {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return receive_counters_;
|
||||
}
|
||||
|
||||
uint32_t StreamStatisticianImpl::BitrateReceived() const {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return incoming_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
|
||||
}
|
||||
|
||||
@ -295,21 +286,33 @@ bool StreamStatisticianImpl::IsRetransmitOfOldPacket(
|
||||
}
|
||||
|
||||
std::unique_ptr<ReceiveStatistics> ReceiveStatistics::Create(Clock* clock) {
|
||||
return std::make_unique<ReceiveStatisticsImpl>(clock);
|
||||
return std::make_unique<ReceiveStatisticsLocked>(
|
||||
clock, [](uint32_t ssrc, Clock* clock, int max_reordering_threshold) {
|
||||
return std::make_unique<StreamStatisticianLocked>(
|
||||
ssrc, clock, max_reordering_threshold);
|
||||
});
|
||||
}
|
||||
|
||||
ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock)
|
||||
std::unique_ptr<ReceiveStatistics> ReceiveStatistics::CreateThreadCompatible(
|
||||
Clock* clock) {
|
||||
return std::make_unique<ReceiveStatisticsImpl>(
|
||||
clock, [](uint32_t ssrc, Clock* clock, int max_reordering_threshold) {
|
||||
return std::make_unique<StreamStatisticianImpl>(
|
||||
ssrc, clock, max_reordering_threshold);
|
||||
});
|
||||
}
|
||||
|
||||
ReceiveStatisticsImpl::ReceiveStatisticsImpl(
|
||||
Clock* clock,
|
||||
std::function<std::unique_ptr<StreamStatisticianImplInterface>(
|
||||
uint32_t ssrc,
|
||||
Clock* clock,
|
||||
int max_reordering_threshold)> stream_statistician_factory)
|
||||
: clock_(clock),
|
||||
stream_statistician_factory_(std::move(stream_statistician_factory)),
|
||||
last_returned_ssrc_(0),
|
||||
max_reordering_threshold_(kDefaultMaxReorderingThreshold) {}
|
||||
|
||||
ReceiveStatisticsImpl::~ReceiveStatisticsImpl() {
|
||||
while (!statisticians_.empty()) {
|
||||
delete statisticians_.begin()->second;
|
||||
statisticians_.erase(statisticians_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiveStatisticsImpl::OnRtpPacket(const RtpPacketReceived& packet) {
|
||||
// StreamStatisticianImpl instance is created once and only destroyed when
|
||||
// this whole ReceiveStatisticsImpl is destroyed. StreamStatisticianImpl has
|
||||
@ -318,34 +321,28 @@ void ReceiveStatisticsImpl::OnRtpPacket(const RtpPacketReceived& packet) {
|
||||
GetOrCreateStatistician(packet.Ssrc())->UpdateCounters(packet);
|
||||
}
|
||||
|
||||
StreamStatisticianImpl* ReceiveStatisticsImpl::GetStatistician(
|
||||
StreamStatistician* ReceiveStatisticsImpl::GetStatistician(
|
||||
uint32_t ssrc) const {
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
const auto& it = statisticians_.find(ssrc);
|
||||
if (it == statisticians_.end())
|
||||
return NULL;
|
||||
return it->second;
|
||||
return nullptr;
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
StreamStatisticianImpl* ReceiveStatisticsImpl::GetOrCreateStatistician(
|
||||
StreamStatisticianImplInterface* ReceiveStatisticsImpl::GetOrCreateStatistician(
|
||||
uint32_t ssrc) {
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
StreamStatisticianImpl*& impl = statisticians_[ssrc];
|
||||
std::unique_ptr<StreamStatisticianImplInterface>& impl = statisticians_[ssrc];
|
||||
if (impl == nullptr) { // new element
|
||||
impl = new StreamStatisticianImpl(ssrc, clock_, max_reordering_threshold_);
|
||||
impl =
|
||||
stream_statistician_factory_(ssrc, clock_, max_reordering_threshold_);
|
||||
}
|
||||
return impl;
|
||||
return impl.get();
|
||||
}
|
||||
|
||||
void ReceiveStatisticsImpl::SetMaxReorderingThreshold(
|
||||
int max_reordering_threshold) {
|
||||
std::map<uint32_t, StreamStatisticianImpl*> statisticians;
|
||||
{
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
max_reordering_threshold_ = max_reordering_threshold;
|
||||
statisticians = statisticians_;
|
||||
}
|
||||
for (auto& statistician : statisticians) {
|
||||
max_reordering_threshold_ = max_reordering_threshold;
|
||||
for (auto& statistician : statisticians_) {
|
||||
statistician.second->SetMaxReorderingThreshold(max_reordering_threshold);
|
||||
}
|
||||
}
|
||||
@ -364,15 +361,11 @@ void ReceiveStatisticsImpl::EnableRetransmitDetection(uint32_t ssrc,
|
||||
|
||||
std::vector<rtcp::ReportBlock> ReceiveStatisticsImpl::RtcpReportBlocks(
|
||||
size_t max_blocks) {
|
||||
std::map<uint32_t, StreamStatisticianImpl*> statisticians;
|
||||
{
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
statisticians = statisticians_;
|
||||
}
|
||||
std::vector<rtcp::ReportBlock> result;
|
||||
result.reserve(std::min(max_blocks, statisticians.size()));
|
||||
auto add_report_block = [&result](uint32_t media_ssrc,
|
||||
StreamStatisticianImpl* statistician) {
|
||||
result.reserve(std::min(max_blocks, statisticians_.size()));
|
||||
auto add_report_block = [&result](
|
||||
uint32_t media_ssrc,
|
||||
StreamStatisticianImplInterface* statistician) {
|
||||
// Do we have receive statistics to send?
|
||||
RtcpStatistics stats;
|
||||
if (!statistician->GetActiveStatisticsAndReset(&stats))
|
||||
@ -390,13 +383,13 @@ std::vector<rtcp::ReportBlock> ReceiveStatisticsImpl::RtcpReportBlocks(
|
||||
block.SetJitter(stats.jitter);
|
||||
};
|
||||
|
||||
const auto start_it = statisticians.upper_bound(last_returned_ssrc_);
|
||||
const auto start_it = statisticians_.upper_bound(last_returned_ssrc_);
|
||||
for (auto it = start_it;
|
||||
result.size() < max_blocks && it != statisticians.end(); ++it)
|
||||
add_report_block(it->first, it->second);
|
||||
for (auto it = statisticians.begin();
|
||||
result.size() < max_blocks && it != statisticians_.end(); ++it)
|
||||
add_report_block(it->first, it->second.get());
|
||||
for (auto it = statisticians_.begin();
|
||||
result.size() < max_blocks && it != start_it; ++it)
|
||||
add_report_block(it->first, it->second);
|
||||
add_report_block(it->first, it->second.get());
|
||||
|
||||
if (!result.empty())
|
||||
last_returned_ssrc_ = result.back().source_ssrc();
|
||||
|
||||
@ -12,7 +12,10 @@
|
||||
#define MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
@ -24,86 +27,141 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class StreamStatisticianImpl : public StreamStatistician {
|
||||
// Extends StreamStatistician with methods needed by the implementation.
|
||||
class StreamStatisticianImplInterface : public StreamStatistician {
|
||||
public:
|
||||
virtual ~StreamStatisticianImplInterface() = default;
|
||||
virtual bool GetActiveStatisticsAndReset(RtcpStatistics* statistics) = 0;
|
||||
virtual void SetMaxReorderingThreshold(int max_reordering_threshold) = 0;
|
||||
virtual void EnableRetransmitDetection(bool enable) = 0;
|
||||
virtual void UpdateCounters(const RtpPacketReceived& packet) = 0;
|
||||
};
|
||||
|
||||
// Thread-compatible implementation of StreamStatisticianImplInterface.
|
||||
class StreamStatisticianImpl : public StreamStatisticianImplInterface {
|
||||
public:
|
||||
StreamStatisticianImpl(uint32_t ssrc,
|
||||
Clock* clock,
|
||||
int max_reordering_threshold);
|
||||
~StreamStatisticianImpl() override;
|
||||
|
||||
// Implements StreamStatistician
|
||||
RtpReceiveStats GetStats() const override;
|
||||
|
||||
bool GetActiveStatisticsAndReset(RtcpStatistics* statistics);
|
||||
absl::optional<int> GetFractionLostInPercent() const override;
|
||||
StreamDataCounters GetReceiveStreamDataCounters() const override;
|
||||
uint32_t BitrateReceived() const override;
|
||||
|
||||
void SetMaxReorderingThreshold(int max_reordering_threshold);
|
||||
void EnableRetransmitDetection(bool enable);
|
||||
|
||||
// Implements StreamStatisticianImplInterface
|
||||
bool GetActiveStatisticsAndReset(RtcpStatistics* statistics) override;
|
||||
void SetMaxReorderingThreshold(int max_reordering_threshold) override;
|
||||
void EnableRetransmitDetection(bool enable) override;
|
||||
// Updates StreamStatistician for incoming packets.
|
||||
void UpdateCounters(const RtpPacketReceived& packet);
|
||||
void UpdateCounters(const RtpPacketReceived& packet) override;
|
||||
|
||||
private:
|
||||
bool IsRetransmitOfOldPacket(const RtpPacketReceived& packet,
|
||||
int64_t now_ms) const
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_);
|
||||
RtcpStatistics CalculateRtcpStatistics()
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_);
|
||||
void UpdateJitter(const RtpPacketReceived& packet, int64_t receive_time_ms)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_);
|
||||
int64_t now_ms) const;
|
||||
RtcpStatistics CalculateRtcpStatistics();
|
||||
void UpdateJitter(const RtpPacketReceived& packet, int64_t receive_time_ms);
|
||||
// Updates StreamStatistician for out of order packets.
|
||||
// Returns true if packet considered to be out of order.
|
||||
bool UpdateOutOfOrder(const RtpPacketReceived& packet,
|
||||
int64_t sequence_number,
|
||||
int64_t now_ms)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_);
|
||||
int64_t now_ms);
|
||||
// Checks if this StreamStatistician received any rtp packets.
|
||||
bool ReceivedRtpPacket() const RTC_EXCLUSIVE_LOCKS_REQUIRED(stream_lock_) {
|
||||
return received_seq_first_ >= 0;
|
||||
}
|
||||
bool ReceivedRtpPacket() const { return received_seq_first_ >= 0; }
|
||||
|
||||
const uint32_t ssrc_;
|
||||
Clock* const clock_;
|
||||
mutable Mutex stream_lock_;
|
||||
RateStatistics incoming_bitrate_ RTC_GUARDED_BY(&stream_lock_);
|
||||
RateStatistics incoming_bitrate_;
|
||||
// In number of packets or sequence numbers.
|
||||
int max_reordering_threshold_ RTC_GUARDED_BY(&stream_lock_);
|
||||
bool enable_retransmit_detection_ RTC_GUARDED_BY(&stream_lock_);
|
||||
int max_reordering_threshold_;
|
||||
bool enable_retransmit_detection_;
|
||||
|
||||
// Stats on received RTP packets.
|
||||
uint32_t jitter_q4_ RTC_GUARDED_BY(&stream_lock_);
|
||||
uint32_t jitter_q4_;
|
||||
// Cumulative loss according to RFC 3550, which may be negative (and often is,
|
||||
// if packets are reordered and there are non-RTX retransmissions).
|
||||
int32_t cumulative_loss_ RTC_GUARDED_BY(&stream_lock_);
|
||||
int32_t cumulative_loss_;
|
||||
// Offset added to outgoing rtcp reports, to make ensure that the reported
|
||||
// cumulative loss is non-negative. Reports with negative values confuse some
|
||||
// senders, in particular, our own loss-based bandwidth estimator.
|
||||
int32_t cumulative_loss_rtcp_offset_ RTC_GUARDED_BY(&stream_lock_);
|
||||
int32_t cumulative_loss_rtcp_offset_;
|
||||
|
||||
int64_t last_receive_time_ms_ RTC_GUARDED_BY(&stream_lock_);
|
||||
uint32_t last_received_timestamp_ RTC_GUARDED_BY(&stream_lock_);
|
||||
SequenceNumberUnwrapper seq_unwrapper_ RTC_GUARDED_BY(&stream_lock_);
|
||||
int64_t received_seq_first_ RTC_GUARDED_BY(&stream_lock_);
|
||||
int64_t received_seq_max_ RTC_GUARDED_BY(&stream_lock_);
|
||||
int64_t last_receive_time_ms_;
|
||||
uint32_t last_received_timestamp_;
|
||||
SequenceNumberUnwrapper seq_unwrapper_;
|
||||
int64_t received_seq_first_;
|
||||
int64_t received_seq_max_;
|
||||
// Assume that the other side restarted when there are two sequential packets
|
||||
// with large jump from received_seq_max_.
|
||||
absl::optional<uint16_t> received_seq_out_of_order_
|
||||
RTC_GUARDED_BY(&stream_lock_);
|
||||
absl::optional<uint16_t> received_seq_out_of_order_;
|
||||
|
||||
// Current counter values.
|
||||
StreamDataCounters receive_counters_ RTC_GUARDED_BY(&stream_lock_);
|
||||
StreamDataCounters receive_counters_;
|
||||
|
||||
// Counter values when we sent the last report.
|
||||
int32_t last_report_cumulative_loss_ RTC_GUARDED_BY(&stream_lock_);
|
||||
int64_t last_report_seq_max_ RTC_GUARDED_BY(&stream_lock_);
|
||||
int32_t last_report_cumulative_loss_;
|
||||
int64_t last_report_seq_max_;
|
||||
};
|
||||
|
||||
// Thread-safe implementation of StreamStatisticianImplInterface.
|
||||
class StreamStatisticianLocked : public StreamStatisticianImplInterface {
|
||||
public:
|
||||
StreamStatisticianLocked(uint32_t ssrc,
|
||||
Clock* clock,
|
||||
int max_reordering_threshold)
|
||||
: impl_(ssrc, clock, max_reordering_threshold) {}
|
||||
~StreamStatisticianLocked() override = default;
|
||||
|
||||
RtpReceiveStats GetStats() const override {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return impl_.GetStats();
|
||||
}
|
||||
absl::optional<int> GetFractionLostInPercent() const override {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return impl_.GetFractionLostInPercent();
|
||||
}
|
||||
StreamDataCounters GetReceiveStreamDataCounters() const override {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return impl_.GetReceiveStreamDataCounters();
|
||||
}
|
||||
uint32_t BitrateReceived() const override {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return impl_.BitrateReceived();
|
||||
}
|
||||
bool GetActiveStatisticsAndReset(RtcpStatistics* statistics) override {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return impl_.GetActiveStatisticsAndReset(statistics);
|
||||
}
|
||||
void SetMaxReorderingThreshold(int max_reordering_threshold) override {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return impl_.SetMaxReorderingThreshold(max_reordering_threshold);
|
||||
}
|
||||
void EnableRetransmitDetection(bool enable) override {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return impl_.EnableRetransmitDetection(enable);
|
||||
}
|
||||
void UpdateCounters(const RtpPacketReceived& packet) override {
|
||||
MutexLock lock(&stream_lock_);
|
||||
return impl_.UpdateCounters(packet);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable Mutex stream_lock_;
|
||||
StreamStatisticianImpl impl_ RTC_GUARDED_BY(&stream_lock_);
|
||||
};
|
||||
|
||||
// Thread-compatible implementation.
|
||||
class ReceiveStatisticsImpl : public ReceiveStatistics {
|
||||
public:
|
||||
explicit ReceiveStatisticsImpl(Clock* clock);
|
||||
|
||||
~ReceiveStatisticsImpl() override;
|
||||
ReceiveStatisticsImpl(
|
||||
Clock* clock,
|
||||
std::function<std::unique_ptr<StreamStatisticianImplInterface>(
|
||||
uint32_t ssrc,
|
||||
Clock* clock,
|
||||
int max_reordering_threshold)> stream_statistician_factory);
|
||||
~ReceiveStatisticsImpl() override = default;
|
||||
|
||||
// Implements ReceiveStatisticsProvider.
|
||||
std::vector<rtcp::ReportBlock> RtcpReportBlocks(size_t max_blocks) override;
|
||||
@ -112,22 +170,69 @@ class ReceiveStatisticsImpl : public ReceiveStatistics {
|
||||
void OnRtpPacket(const RtpPacketReceived& packet) override;
|
||||
|
||||
// Implements ReceiveStatistics.
|
||||
// Note: More specific return type for use in the implementation.
|
||||
StreamStatisticianImpl* GetStatistician(uint32_t ssrc) const override;
|
||||
StreamStatistician* GetStatistician(uint32_t ssrc) const override;
|
||||
void SetMaxReorderingThreshold(int max_reordering_threshold) override;
|
||||
void SetMaxReorderingThreshold(uint32_t ssrc,
|
||||
int max_reordering_threshold) override;
|
||||
void EnableRetransmitDetection(uint32_t ssrc, bool enable) override;
|
||||
|
||||
private:
|
||||
StreamStatisticianImpl* GetOrCreateStatistician(uint32_t ssrc);
|
||||
StreamStatisticianImplInterface* GetOrCreateStatistician(uint32_t ssrc);
|
||||
|
||||
Clock* const clock_;
|
||||
mutable Mutex receive_statistics_lock_;
|
||||
std::function<std::unique_ptr<StreamStatisticianImplInterface>(
|
||||
uint32_t ssrc,
|
||||
Clock* clock,
|
||||
int max_reordering_threshold)>
|
||||
stream_statistician_factory_;
|
||||
uint32_t last_returned_ssrc_;
|
||||
int max_reordering_threshold_ RTC_GUARDED_BY(receive_statistics_lock_);
|
||||
std::map<uint32_t, StreamStatisticianImpl*> statisticians_
|
||||
RTC_GUARDED_BY(receive_statistics_lock_);
|
||||
int max_reordering_threshold_;
|
||||
std::map<uint32_t, std::unique_ptr<StreamStatisticianImplInterface>>
|
||||
statisticians_;
|
||||
};
|
||||
|
||||
// Thread-safe implementation wrapping access to ReceiveStatisticsImpl with a
|
||||
// mutex.
|
||||
class ReceiveStatisticsLocked : public ReceiveStatistics {
|
||||
public:
|
||||
explicit ReceiveStatisticsLocked(
|
||||
Clock* clock,
|
||||
std::function<std::unique_ptr<StreamStatisticianImplInterface>(
|
||||
uint32_t ssrc,
|
||||
Clock* clock,
|
||||
int max_reordering_threshold)> stream_statitician_factory)
|
||||
: impl_(clock, std::move(stream_statitician_factory)) {}
|
||||
~ReceiveStatisticsLocked() override = default;
|
||||
std::vector<rtcp::ReportBlock> RtcpReportBlocks(size_t max_blocks) override {
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
return impl_.RtcpReportBlocks(max_blocks);
|
||||
}
|
||||
void OnRtpPacket(const RtpPacketReceived& packet) override {
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
return impl_.OnRtpPacket(packet);
|
||||
}
|
||||
StreamStatistician* GetStatistician(uint32_t ssrc) const override {
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
return impl_.GetStatistician(ssrc);
|
||||
}
|
||||
void SetMaxReorderingThreshold(int max_reordering_threshold) override {
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
return impl_.SetMaxReorderingThreshold(max_reordering_threshold);
|
||||
}
|
||||
void SetMaxReorderingThreshold(uint32_t ssrc,
|
||||
int max_reordering_threshold) override {
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
return impl_.SetMaxReorderingThreshold(ssrc, max_reordering_threshold);
|
||||
}
|
||||
void EnableRetransmitDetection(uint32_t ssrc, bool enable) override {
|
||||
MutexLock lock(&receive_statistics_lock_);
|
||||
return impl_.EnableRetransmitDetection(ssrc, enable);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable Mutex receive_statistics_lock_;
|
||||
ReceiveStatisticsImpl impl_ RTC_GUARDED_BY(&receive_statistics_lock_);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // MODULES_RTP_RTCP_SOURCE_RECEIVE_STATISTICS_IMPL_H_
|
||||
|
||||
@ -65,10 +65,13 @@ void IncrementSequenceNumber(RtpPacketReceived* packet) {
|
||||
IncrementSequenceNumber(packet, 1);
|
||||
}
|
||||
|
||||
class ReceiveStatisticsTest : public ::testing::Test {
|
||||
class ReceiveStatisticsTest : public ::testing::TestWithParam<bool> {
|
||||
public:
|
||||
ReceiveStatisticsTest()
|
||||
: clock_(0), receive_statistics_(ReceiveStatistics::Create(&clock_)) {
|
||||
: clock_(0),
|
||||
receive_statistics_(
|
||||
GetParam() ? ReceiveStatistics::Create(&clock_)
|
||||
: ReceiveStatistics::CreateThreadCompatible(&clock_)) {
|
||||
packet1_ = CreateRtpPacket(kSsrc1, kPacketSize1);
|
||||
packet2_ = CreateRtpPacket(kSsrc2, kPacketSize2);
|
||||
}
|
||||
@ -80,7 +83,14 @@ class ReceiveStatisticsTest : public ::testing::Test {
|
||||
RtpPacketReceived packet2_;
|
||||
};
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, TwoIncomingSsrcs) {
|
||||
INSTANTIATE_TEST_SUITE_P(All,
|
||||
ReceiveStatisticsTest,
|
||||
::testing::Bool(),
|
||||
[](::testing::TestParamInfo<bool> info) {
|
||||
return info.param ? "WithMutex" : "WithoutMutex";
|
||||
});
|
||||
|
||||
TEST_P(ReceiveStatisticsTest, TwoIncomingSsrcs) {
|
||||
receive_statistics_->OnRtpPacket(packet1_);
|
||||
IncrementSequenceNumber(&packet1_);
|
||||
receive_statistics_->OnRtpPacket(packet2_);
|
||||
@ -133,7 +143,7 @@ TEST_F(ReceiveStatisticsTest, TwoIncomingSsrcs) {
|
||||
EXPECT_EQ(3u, counters.transmitted.packets);
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest,
|
||||
TEST_P(ReceiveStatisticsTest,
|
||||
RtcpReportBlocksReturnsMaxBlocksWhenThereAreMoreStatisticians) {
|
||||
RtpPacketReceived packet1 = CreateRtpPacket(kSsrc1, kPacketSize1);
|
||||
RtpPacketReceived packet2 = CreateRtpPacket(kSsrc2, kPacketSize1);
|
||||
@ -147,7 +157,7 @@ TEST_F(ReceiveStatisticsTest,
|
||||
EXPECT_THAT(receive_statistics_->RtcpReportBlocks(2), SizeIs(2));
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest,
|
||||
TEST_P(ReceiveStatisticsTest,
|
||||
RtcpReportBlocksReturnsAllObservedSsrcsWithMultipleCalls) {
|
||||
RtpPacketReceived packet1 = CreateRtpPacket(kSsrc1, kPacketSize1);
|
||||
RtpPacketReceived packet2 = CreateRtpPacket(kSsrc2, kPacketSize1);
|
||||
@ -174,7 +184,7 @@ TEST_F(ReceiveStatisticsTest,
|
||||
UnorderedElementsAre(kSsrc1, kSsrc2, kSsrc3, kSsrc4));
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, ActiveStatisticians) {
|
||||
TEST_P(ReceiveStatisticsTest, ActiveStatisticians) {
|
||||
receive_statistics_->OnRtpPacket(packet1_);
|
||||
IncrementSequenceNumber(&packet1_);
|
||||
clock_.AdvanceTimeMilliseconds(1000);
|
||||
@ -206,7 +216,7 @@ TEST_F(ReceiveStatisticsTest, ActiveStatisticians) {
|
||||
EXPECT_EQ(2u, counters.transmitted.packets);
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest,
|
||||
TEST_P(ReceiveStatisticsTest,
|
||||
DoesntCreateRtcpReportBlockUntilFirstReceivedPacketForSsrc) {
|
||||
// Creates a statistician object for the ssrc.
|
||||
receive_statistics_->EnableRetransmitDetection(kSsrc1, true);
|
||||
@ -217,7 +227,7 @@ TEST_F(ReceiveStatisticsTest,
|
||||
EXPECT_EQ(1u, receive_statistics_->RtcpReportBlocks(3).size());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, GetReceiveStreamDataCounters) {
|
||||
TEST_P(ReceiveStatisticsTest, GetReceiveStreamDataCounters) {
|
||||
receive_statistics_->OnRtpPacket(packet1_);
|
||||
StreamStatistician* statistician =
|
||||
receive_statistics_->GetStatistician(kSsrc1);
|
||||
@ -233,7 +243,7 @@ TEST_F(ReceiveStatisticsTest, GetReceiveStreamDataCounters) {
|
||||
EXPECT_EQ(2u, counters.transmitted.packets);
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, SimpleLossComputation) {
|
||||
TEST_P(ReceiveStatisticsTest, SimpleLossComputation) {
|
||||
packet1_.SetSequenceNumber(1);
|
||||
receive_statistics_->OnRtpPacket(packet1_);
|
||||
packet1_.SetSequenceNumber(3);
|
||||
@ -256,7 +266,7 @@ TEST_F(ReceiveStatisticsTest, SimpleLossComputation) {
|
||||
EXPECT_EQ(20, statistician->GetFractionLostInPercent());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, LossComputationWithReordering) {
|
||||
TEST_P(ReceiveStatisticsTest, LossComputationWithReordering) {
|
||||
packet1_.SetSequenceNumber(1);
|
||||
receive_statistics_->OnRtpPacket(packet1_);
|
||||
packet1_.SetSequenceNumber(3);
|
||||
@ -279,7 +289,7 @@ TEST_F(ReceiveStatisticsTest, LossComputationWithReordering) {
|
||||
EXPECT_EQ(20, statistician->GetFractionLostInPercent());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, LossComputationWithDuplicates) {
|
||||
TEST_P(ReceiveStatisticsTest, LossComputationWithDuplicates) {
|
||||
// Lose 2 packets, but also receive 1 duplicate. Should actually count as
|
||||
// only 1 packet being lost.
|
||||
packet1_.SetSequenceNumber(1);
|
||||
@ -304,7 +314,7 @@ TEST_F(ReceiveStatisticsTest, LossComputationWithDuplicates) {
|
||||
EXPECT_EQ(20, statistician->GetFractionLostInPercent());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, LossComputationWithSequenceNumberWrapping) {
|
||||
TEST_P(ReceiveStatisticsTest, LossComputationWithSequenceNumberWrapping) {
|
||||
// First, test loss computation over a period that included a sequence number
|
||||
// rollover.
|
||||
packet1_.SetSequenceNumber(0xfffd);
|
||||
@ -344,7 +354,7 @@ TEST_F(ReceiveStatisticsTest, LossComputationWithSequenceNumberWrapping) {
|
||||
EXPECT_EQ(28, statistician->GetFractionLostInPercent());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, StreamRestartDoesntCountAsLoss) {
|
||||
TEST_P(ReceiveStatisticsTest, StreamRestartDoesntCountAsLoss) {
|
||||
receive_statistics_->SetMaxReorderingThreshold(kSsrc1, 200);
|
||||
|
||||
packet1_.SetSequenceNumber(0);
|
||||
@ -377,7 +387,7 @@ TEST_F(ReceiveStatisticsTest, StreamRestartDoesntCountAsLoss) {
|
||||
EXPECT_EQ(0, statistician->GetFractionLostInPercent());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, CountsLossAfterStreamRestart) {
|
||||
TEST_P(ReceiveStatisticsTest, CountsLossAfterStreamRestart) {
|
||||
receive_statistics_->SetMaxReorderingThreshold(kSsrc1, 200);
|
||||
|
||||
packet1_.SetSequenceNumber(0);
|
||||
@ -405,7 +415,7 @@ TEST_F(ReceiveStatisticsTest, CountsLossAfterStreamRestart) {
|
||||
EXPECT_EQ(0, statistician->GetFractionLostInPercent());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, StreamCanRestartAtSequenceNumberWrapAround) {
|
||||
TEST_P(ReceiveStatisticsTest, StreamCanRestartAtSequenceNumberWrapAround) {
|
||||
receive_statistics_->SetMaxReorderingThreshold(kSsrc1, 200);
|
||||
|
||||
packet1_.SetSequenceNumber(0xffff - 401);
|
||||
@ -428,7 +438,7 @@ TEST_F(ReceiveStatisticsTest, StreamCanRestartAtSequenceNumberWrapAround) {
|
||||
EXPECT_EQ(1, report_blocks[0].cumulative_lost_signed());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, StreamRestartNeedsTwoConsecutivePackets) {
|
||||
TEST_P(ReceiveStatisticsTest, StreamRestartNeedsTwoConsecutivePackets) {
|
||||
receive_statistics_->SetMaxReorderingThreshold(kSsrc1, 200);
|
||||
|
||||
packet1_.SetSequenceNumber(400);
|
||||
@ -458,7 +468,7 @@ TEST_F(ReceiveStatisticsTest, StreamRestartNeedsTwoConsecutivePackets) {
|
||||
EXPECT_EQ(4u, report_blocks[0].extended_high_seq_num());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, WrapsAroundExtendedHighestSequenceNumber) {
|
||||
TEST_P(ReceiveStatisticsTest, WrapsAroundExtendedHighestSequenceNumber) {
|
||||
packet1_.SetSequenceNumber(0xffff);
|
||||
receive_statistics_->OnRtpPacket(packet1_);
|
||||
|
||||
@ -503,8 +513,7 @@ TEST_F(ReceiveStatisticsTest, WrapsAroundExtendedHighestSequenceNumber) {
|
||||
EXPECT_EQ(0x20001u, report_blocks[0].extended_high_seq_num());
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, StreamDataCounters) {
|
||||
receive_statistics_ = ReceiveStatistics::Create(&clock_);
|
||||
TEST_P(ReceiveStatisticsTest, StreamDataCounters) {
|
||||
receive_statistics_->EnableRetransmitDetection(kSsrc1, true);
|
||||
|
||||
const size_t kHeaderLength = 20;
|
||||
@ -554,9 +563,7 @@ TEST_F(ReceiveStatisticsTest, StreamDataCounters) {
|
||||
EXPECT_EQ(counters.retransmitted.packets, 1u);
|
||||
}
|
||||
|
||||
TEST_F(ReceiveStatisticsTest, LastPacketReceivedTimestamp) {
|
||||
receive_statistics_ = ReceiveStatistics::Create(&clock_);
|
||||
|
||||
TEST_P(ReceiveStatisticsTest, LastPacketReceivedTimestamp) {
|
||||
clock_.AdvanceTimeMilliseconds(42);
|
||||
receive_statistics_->OnRtpPacket(packet1_);
|
||||
StreamDataCounters counters = receive_statistics_->GetStatistician(kSsrc1)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user