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:
Per Kjellander
2021-03-10 12:31:38 +01:00
committed by Commit Bot
parent bb22066e60
commit ee8cd20ec5
4 changed files with 225 additions and 115 deletions

View File

@ -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_