Reland of actor NACK bitrate allocation (patchset #1 id:1 of https://codereview.webrtc.org/2131913003/ )
Reason for revert:
Upstream fixes in place, should be OK now.
Original issue's description:
> Revert of Refactor NACK bitrate allocation (patchset #16 id:300001 of https://codereview.webrtc.org/2061423003/ )
>
> Reason for revert:
> Breaks upstream code.
>
> Original issue's description:
> > Refactor NACK bitrate allocation
> >
> > Nack bitrate allocation should not be done on a per-rtp-module basis,
> > but rather shared bitrate pool per call. This CL moves allocation to the
> > pacer and cleans up a bunch if bitrate stats handling.
> >
> > BUG=
> > R=danilchap@webrtc.org, stefan@webrtc.org, tommi@webrtc.org
> >
> > Committed: 5fc59e810b
>
> TBR=tommi@webrtc.org,danilchap@webrtc.org,stefan@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=
>
> Committed: https://crrev.com/e5dd44101eca485f5ad12e5f7ce6f6b0d204116b
> Cr-Commit-Position: refs/heads/master@{#13417}
TBR=tommi@webrtc.org,danilchap@webrtc.org,stefan@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=
Review-Url: https://codereview.webrtc.org/2146013002
Cr-Commit-Position: refs/heads/master@{#13465}
This commit is contained in:
@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 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 "webrtc/modules/rtp_rtcp/source/bitrate.h"
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
Bitrate::Bitrate(Clock* clock, Observer* observer)
|
||||
: clock_(clock),
|
||||
packet_rate_(0),
|
||||
bitrate_(0),
|
||||
bitrate_next_idx_(0),
|
||||
time_last_rate_update_(0),
|
||||
bytes_count_(0),
|
||||
packet_count_(0),
|
||||
observer_(observer) {
|
||||
memset(packet_rate_array_, 0, sizeof(packet_rate_array_));
|
||||
memset(bitrate_diff_ms_, 0, sizeof(bitrate_diff_ms_));
|
||||
memset(bitrate_array_, 0, sizeof(bitrate_array_));
|
||||
}
|
||||
|
||||
Bitrate::~Bitrate() {}
|
||||
|
||||
void Bitrate::Update(const size_t bytes) {
|
||||
rtc::CritScope cs(&crit_);
|
||||
bytes_count_ += bytes;
|
||||
packet_count_++;
|
||||
}
|
||||
|
||||
uint32_t Bitrate::PacketRate() const {
|
||||
rtc::CritScope cs(&crit_);
|
||||
return packet_rate_;
|
||||
}
|
||||
|
||||
uint32_t Bitrate::BitrateLast() const {
|
||||
rtc::CritScope cs(&crit_);
|
||||
return bitrate_;
|
||||
}
|
||||
|
||||
uint32_t Bitrate::BitrateNow() const {
|
||||
rtc::CritScope cs(&crit_);
|
||||
int64_t now = clock_->TimeInMilliseconds();
|
||||
int64_t diff_ms = now - time_last_rate_update_;
|
||||
|
||||
if (diff_ms > 10000) { // 10 seconds.
|
||||
// Too high difference, ignore.
|
||||
return bitrate_;
|
||||
}
|
||||
int64_t bits_since_last_rate_update = 8 * bytes_count_ * 1000;
|
||||
|
||||
// We have to consider the time when the measurement was done:
|
||||
// ((bits/sec * sec) + (bits)) / sec.
|
||||
int64_t bitrate = (static_cast<uint64_t>(bitrate_) * 1000 +
|
||||
bits_since_last_rate_update) / (1000 + diff_ms);
|
||||
return static_cast<uint32_t>(bitrate);
|
||||
}
|
||||
|
||||
int64_t Bitrate::time_last_rate_update() const {
|
||||
rtc::CritScope cs(&crit_);
|
||||
return time_last_rate_update_;
|
||||
}
|
||||
|
||||
// Triggered by timer.
|
||||
void Bitrate::Process() {
|
||||
BitrateStatistics stats;
|
||||
{
|
||||
rtc::CritScope cs(&crit_);
|
||||
int64_t now = clock_->CurrentNtpInMilliseconds();
|
||||
int64_t diff_ms = now - time_last_rate_update_;
|
||||
|
||||
if (diff_ms < 100) {
|
||||
// Not enough data, wait...
|
||||
return;
|
||||
}
|
||||
if (diff_ms > 10000) { // 10 seconds.
|
||||
// Too high difference, ignore.
|
||||
time_last_rate_update_ = now;
|
||||
bytes_count_ = 0;
|
||||
packet_count_ = 0;
|
||||
return;
|
||||
}
|
||||
packet_rate_array_[bitrate_next_idx_] = (packet_count_ * 1000) / diff_ms;
|
||||
bitrate_array_[bitrate_next_idx_] = 8 * ((bytes_count_ * 1000) / diff_ms);
|
||||
bitrate_diff_ms_[bitrate_next_idx_] = diff_ms;
|
||||
bitrate_next_idx_++;
|
||||
if (bitrate_next_idx_ >= 10) {
|
||||
bitrate_next_idx_ = 0;
|
||||
}
|
||||
int64_t sum_diffMS = 0;
|
||||
int64_t sum_bitrateMS = 0;
|
||||
int64_t sum_packetrateMS = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
sum_diffMS += bitrate_diff_ms_[i];
|
||||
sum_bitrateMS += bitrate_array_[i] * bitrate_diff_ms_[i];
|
||||
sum_packetrateMS += packet_rate_array_[i] * bitrate_diff_ms_[i];
|
||||
}
|
||||
time_last_rate_update_ = now;
|
||||
bytes_count_ = 0;
|
||||
packet_count_ = 0;
|
||||
packet_rate_ = static_cast<uint32_t>(sum_packetrateMS / sum_diffMS);
|
||||
bitrate_ = static_cast<uint32_t>(sum_bitrateMS / sum_diffMS);
|
||||
|
||||
stats.bitrate_bps = bitrate_;
|
||||
stats.packet_rate = packet_rate_;
|
||||
stats.timestamp_ms = now;
|
||||
}
|
||||
|
||||
if (observer_)
|
||||
observer_->BitrateUpdated(stats);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_BITRATE_H_
|
||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_BITRATE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class Clock;
|
||||
|
||||
class Bitrate {
|
||||
public:
|
||||
class Observer;
|
||||
Bitrate(Clock* clock, Observer* observer);
|
||||
virtual ~Bitrate();
|
||||
|
||||
// Calculates rates.
|
||||
void Process();
|
||||
|
||||
// Update with a packet.
|
||||
void Update(const size_t bytes);
|
||||
|
||||
// Packet rate last second, updated roughly every 100 ms.
|
||||
uint32_t PacketRate() const;
|
||||
|
||||
// Bitrate last second, updated roughly every 100 ms.
|
||||
uint32_t BitrateLast() const;
|
||||
|
||||
// Bitrate last second, updated now.
|
||||
uint32_t BitrateNow() const;
|
||||
|
||||
int64_t time_last_rate_update() const;
|
||||
|
||||
class Observer {
|
||||
public:
|
||||
Observer() {}
|
||||
virtual ~Observer() {}
|
||||
|
||||
virtual void BitrateUpdated(const BitrateStatistics& stats) = 0;
|
||||
};
|
||||
|
||||
protected:
|
||||
Clock* clock_;
|
||||
|
||||
private:
|
||||
rtc::CriticalSection crit_;
|
||||
uint32_t packet_rate_;
|
||||
uint32_t bitrate_;
|
||||
uint8_t bitrate_next_idx_;
|
||||
int64_t packet_rate_array_[10];
|
||||
int64_t bitrate_array_[10];
|
||||
int64_t bitrate_diff_ms_[10];
|
||||
int64_t time_last_rate_update_;
|
||||
size_t bytes_count_;
|
||||
uint32_t packet_count_;
|
||||
Observer* const observer_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_BITRATE_H_
|
||||
@ -15,6 +15,7 @@
|
||||
#include <set>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/rate_limiter.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
|
||||
@ -34,6 +35,7 @@ const int kTestNumberOfRtxPackets = 149;
|
||||
const int kNumFrames = 30;
|
||||
const int kPayloadType = 123;
|
||||
const int kRtxPayloadType = 98;
|
||||
const int64_t kMaxRttMs = 1000;
|
||||
|
||||
class VerifyingRtxReceiver : public NullRtpData {
|
||||
public:
|
||||
@ -168,11 +170,12 @@ class RtpRtcpRtxNackTest : public ::testing::Test {
|
||||
protected:
|
||||
RtpRtcpRtxNackTest()
|
||||
: rtp_payload_registry_(RTPPayloadStrategy::CreateStrategy(false)),
|
||||
rtp_rtcp_module_(NULL),
|
||||
rtp_rtcp_module_(nullptr),
|
||||
transport_(kTestSsrc + 1),
|
||||
receiver_(),
|
||||
payload_data_length(sizeof(payload_data)),
|
||||
fake_clock(123456) {}
|
||||
fake_clock(123456),
|
||||
retranmission_rate_limiter_(&fake_clock, kMaxRttMs) {}
|
||||
~RtpRtcpRtxNackTest() {}
|
||||
|
||||
void SetUp() override {
|
||||
@ -182,6 +185,7 @@ class RtpRtcpRtxNackTest : public ::testing::Test {
|
||||
receive_statistics_.reset(ReceiveStatistics::Create(&fake_clock));
|
||||
configuration.receive_statistics = receive_statistics_.get();
|
||||
configuration.outgoing_transport = &transport_;
|
||||
configuration.retransmission_rate_limiter = &retranmission_rate_limiter_;
|
||||
rtp_rtcp_module_ = RtpRtcp::CreateRtpRtcp(configuration);
|
||||
|
||||
rtp_feedback_.reset(new TestRtpFeedback(rtp_rtcp_module_));
|
||||
@ -288,6 +292,7 @@ class RtpRtcpRtxNackTest : public ::testing::Test {
|
||||
uint8_t payload_data[65000];
|
||||
size_t payload_data_length;
|
||||
SimulatedClock fake_clock;
|
||||
RateLimiter retranmission_rate_limiter_;
|
||||
};
|
||||
|
||||
TEST_F(RtpRtcpRtxNackTest, LongNackList) {
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "webrtc/modules/rtp_rtcp/source/bitrate.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/time_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -29,7 +29,8 @@ StreamStatisticianImpl::StreamStatisticianImpl(
|
||||
RtcpStatisticsCallback* rtcp_callback,
|
||||
StreamDataCountersCallback* rtp_callback)
|
||||
: clock_(clock),
|
||||
incoming_bitrate_(clock, NULL),
|
||||
incoming_bitrate_(kStatisticsProcessIntervalMs,
|
||||
RateStatistics::kBpsScale),
|
||||
ssrc_(0),
|
||||
max_reordering_threshold_(kDefaultMaxReorderingThreshold),
|
||||
jitter_q4_(0),
|
||||
@ -61,7 +62,7 @@ void StreamStatisticianImpl::UpdateCounters(const RTPHeader& header,
|
||||
rtc::CritScope cs(&stream_lock_);
|
||||
bool in_order = InOrderPacketInternal(header.sequenceNumber);
|
||||
ssrc_ = header.ssrc;
|
||||
incoming_bitrate_.Update(packet_length);
|
||||
incoming_bitrate_.Update(packet_length, clock_->TimeInMilliseconds());
|
||||
receive_counters_.transmitted.AddPacket(packet_length, header);
|
||||
if (!in_order && retransmitted) {
|
||||
receive_counters_.retransmitted.AddPacket(packet_length, header);
|
||||
@ -300,12 +301,7 @@ void StreamStatisticianImpl::GetReceiveStreamDataCounters(
|
||||
|
||||
uint32_t StreamStatisticianImpl::BitrateReceived() const {
|
||||
rtc::CritScope cs(&stream_lock_);
|
||||
return incoming_bitrate_.BitrateNow();
|
||||
}
|
||||
|
||||
void StreamStatisticianImpl::ProcessBitrate() {
|
||||
rtc::CritScope cs(&stream_lock_);
|
||||
incoming_bitrate_.Process();
|
||||
return incoming_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
|
||||
}
|
||||
|
||||
void StreamStatisticianImpl::LastReceiveTimeNtp(uint32_t* secs,
|
||||
@ -376,7 +372,6 @@ ReceiveStatistics* ReceiveStatistics::Create(Clock* clock) {
|
||||
|
||||
ReceiveStatisticsImpl::ReceiveStatisticsImpl(Clock* clock)
|
||||
: clock_(clock),
|
||||
last_rate_update_ms_(0),
|
||||
rtcp_stats_callback_(NULL),
|
||||
rtp_stats_callback_(NULL) {}
|
||||
|
||||
@ -452,23 +447,6 @@ void ReceiveStatisticsImpl::SetMaxReorderingThreshold(
|
||||
}
|
||||
}
|
||||
|
||||
void ReceiveStatisticsImpl::Process() {
|
||||
rtc::CritScope cs(&receive_statistics_lock_);
|
||||
for (StatisticianImplMap::iterator it = statisticians_.begin();
|
||||
it != statisticians_.end(); ++it) {
|
||||
it->second->ProcessBitrate();
|
||||
}
|
||||
last_rate_update_ms_ = clock_->TimeInMilliseconds();
|
||||
}
|
||||
|
||||
int64_t ReceiveStatisticsImpl::TimeUntilNextProcess() {
|
||||
rtc::CritScope cs(&receive_statistics_lock_);
|
||||
int64_t time_since_last_update = clock_->TimeInMilliseconds() -
|
||||
last_rate_update_ms_;
|
||||
return std::max<int64_t>(
|
||||
kStatisticsProcessIntervalMs - time_since_last_update, 0);
|
||||
}
|
||||
|
||||
void ReceiveStatisticsImpl::RegisterRtcpStatisticsCallback(
|
||||
RtcpStatisticsCallback* callback) {
|
||||
rtc::CritScope cs(&receive_statistics_lock_);
|
||||
@ -525,10 +503,6 @@ StreamStatistician* NullReceiveStatistics::GetStatistician(
|
||||
void NullReceiveStatistics::SetMaxReorderingThreshold(
|
||||
int max_reordering_threshold) {}
|
||||
|
||||
int64_t NullReceiveStatistics::TimeUntilNextProcess() { return 0; }
|
||||
|
||||
void NullReceiveStatistics::Process() {}
|
||||
|
||||
void NullReceiveStatistics::RegisterRtcpStatisticsCallback(
|
||||
RtcpStatisticsCallback* callback) {}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
#include <map>
|
||||
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/bitrate.h"
|
||||
#include "webrtc/base/rate_statistics.h"
|
||||
#include "webrtc/system_wrappers/include/ntp_time.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -44,7 +44,6 @@ class StreamStatisticianImpl : public StreamStatistician {
|
||||
bool retransmitted);
|
||||
void FecPacketReceived(const RTPHeader& header, size_t packet_length);
|
||||
void SetMaxReorderingThreshold(int max_reordering_threshold);
|
||||
void ProcessBitrate();
|
||||
virtual void LastReceiveTimeNtp(uint32_t* secs, uint32_t* frac) const;
|
||||
|
||||
private:
|
||||
@ -57,9 +56,9 @@ class StreamStatisticianImpl : public StreamStatistician {
|
||||
void NotifyRtpCallback() LOCKS_EXCLUDED(stream_lock_);
|
||||
void NotifyRtcpCallback() LOCKS_EXCLUDED(stream_lock_);
|
||||
|
||||
Clock* clock_;
|
||||
Clock* const clock_;
|
||||
rtc::CriticalSection stream_lock_;
|
||||
Bitrate incoming_bitrate_;
|
||||
RateStatistics incoming_bitrate_;
|
||||
uint32_t ssrc_;
|
||||
int max_reordering_threshold_; // In number of packets or sequence numbers.
|
||||
|
||||
@ -108,10 +107,6 @@ class ReceiveStatisticsImpl : public ReceiveStatistics,
|
||||
StreamStatistician* GetStatistician(uint32_t ssrc) const override;
|
||||
void SetMaxReorderingThreshold(int max_reordering_threshold) override;
|
||||
|
||||
// Implement Module.
|
||||
void Process() override;
|
||||
int64_t TimeUntilNextProcess() override;
|
||||
|
||||
void RegisterRtcpStatisticsCallback(
|
||||
RtcpStatisticsCallback* callback) override;
|
||||
|
||||
@ -127,9 +122,8 @@ class ReceiveStatisticsImpl : public ReceiveStatistics,
|
||||
|
||||
typedef std::map<uint32_t, StreamStatisticianImpl*> StatisticianImplMap;
|
||||
|
||||
Clock* clock_;
|
||||
Clock* const clock_;
|
||||
rtc::CriticalSection receive_statistics_lock_;
|
||||
int64_t last_rate_update_ms_;
|
||||
StatisticianImplMap statisticians_;
|
||||
|
||||
RtcpStatisticsCallback* rtcp_stats_callback_;
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
|
||||
#include "webrtc/base/onetimeevent.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/bitrate.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
@ -63,7 +63,8 @@ RtpRtcp::Configuration::Configuration()
|
||||
send_frame_count_observer(nullptr),
|
||||
send_side_delay_observer(nullptr),
|
||||
event_log(nullptr),
|
||||
send_packet_observer(nullptr) {}
|
||||
send_packet_observer(nullptr),
|
||||
retransmission_rate_limiter(nullptr) {}
|
||||
|
||||
RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) {
|
||||
if (configuration.clock) {
|
||||
@ -89,7 +90,8 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
|
||||
configuration.send_frame_count_observer,
|
||||
configuration.send_side_delay_observer,
|
||||
configuration.event_log,
|
||||
configuration.send_packet_observer),
|
||||
configuration.send_packet_observer,
|
||||
configuration.retransmission_rate_limiter),
|
||||
rtcp_sender_(configuration.audio,
|
||||
configuration.clock,
|
||||
configuration.receive_statistics,
|
||||
@ -820,10 +822,6 @@ int32_t ModuleRtpRtcpImpl::SendREDPayloadType(int8_t* payload_type) const {
|
||||
return rtp_sender_.RED(payload_type);
|
||||
}
|
||||
|
||||
void ModuleRtpRtcpImpl::SetTargetSendBitrate(uint32_t bitrate_bps) {
|
||||
rtp_sender_.SetTargetBitrate(bitrate_bps);
|
||||
}
|
||||
|
||||
int32_t ModuleRtpRtcpImpl::SetKeyFrameRequestMethod(
|
||||
const KeyFrameRequestMethod method) {
|
||||
key_frame_req_method_ = method;
|
||||
|
||||
@ -285,8 +285,6 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
|
||||
// Send a request for a keyframe.
|
||||
int32_t RequestKeyFrame() override;
|
||||
|
||||
void SetTargetSendBitrate(uint32_t bitrate_bps) override;
|
||||
|
||||
void SetGenericFECStatus(bool enable,
|
||||
uint8_t payload_type_red,
|
||||
uint8_t payload_type_fec) override;
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "webrtc/base/rate_limiter.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
@ -37,6 +38,7 @@ const int64_t kOneWayNetworkDelayMs = 100;
|
||||
const uint8_t kBaseLayerTid = 0;
|
||||
const uint8_t kHigherLayerTid = 1;
|
||||
const uint16_t kSequenceNumber = 100;
|
||||
const int64_t kMaxRttMs = 1000;
|
||||
|
||||
class RtcpRttStatsTestImpl : public RtcpRttStats {
|
||||
public:
|
||||
@ -99,7 +101,9 @@ class SendTransport : public Transport,
|
||||
class RtpRtcpModule : public RtcpPacketTypeCounterObserver {
|
||||
public:
|
||||
explicit RtpRtcpModule(SimulatedClock* clock)
|
||||
: receive_statistics_(ReceiveStatistics::Create(clock)) {
|
||||
: receive_statistics_(ReceiveStatistics::Create(clock)),
|
||||
remote_ssrc_(0),
|
||||
retransmission_rate_limiter_(clock, kMaxRttMs) {
|
||||
RtpRtcp::Configuration config;
|
||||
config.audio = false;
|
||||
config.clock = clock;
|
||||
@ -107,6 +111,7 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver {
|
||||
config.receive_statistics = receive_statistics_.get();
|
||||
config.rtcp_packet_type_counter_observer = this;
|
||||
config.rtt_stats = &rtt_stats_;
|
||||
config.retransmission_rate_limiter = &retransmission_rate_limiter_;
|
||||
|
||||
impl_.reset(new ModuleRtpRtcpImpl(config));
|
||||
impl_->SetRTCPStatus(RtcpMode::kCompound);
|
||||
@ -121,6 +126,7 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver {
|
||||
RtcpRttStatsTestImpl rtt_stats_;
|
||||
std::unique_ptr<ModuleRtpRtcpImpl> impl_;
|
||||
uint32_t remote_ssrc_;
|
||||
RateLimiter retransmission_rate_limiter_;
|
||||
|
||||
void SetRemoteSsrc(uint32_t ssrc) {
|
||||
remote_ssrc_ = ssrc;
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/rate_limiter.h"
|
||||
#include "webrtc/base/trace_event.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
#include "webrtc/call.h"
|
||||
@ -33,6 +34,7 @@ namespace webrtc {
|
||||
static const size_t kMaxPaddingLength = 224;
|
||||
static const int kSendSideDelayWindowMs = 1000;
|
||||
static const uint32_t kAbsSendTimeFraction = 18;
|
||||
static const int kBitrateStatisticsWindowMs = 1000;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -63,47 +65,6 @@ uint32_t ConvertMsTo24Bits(int64_t time_ms) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
RTPSender::BitrateAggregator::BitrateAggregator(
|
||||
BitrateStatisticsObserver* bitrate_callback)
|
||||
: callback_(bitrate_callback),
|
||||
total_bitrate_observer_(*this),
|
||||
retransmit_bitrate_observer_(*this),
|
||||
ssrc_(0) {}
|
||||
|
||||
void RTPSender::BitrateAggregator::OnStatsUpdated() const {
|
||||
if (callback_) {
|
||||
callback_->Notify(total_bitrate_observer_.statistics(),
|
||||
retransmit_bitrate_observer_.statistics(), ssrc_);
|
||||
}
|
||||
}
|
||||
|
||||
Bitrate::Observer* RTPSender::BitrateAggregator::total_bitrate_observer() {
|
||||
return &total_bitrate_observer_;
|
||||
}
|
||||
Bitrate::Observer* RTPSender::BitrateAggregator::retransmit_bitrate_observer() {
|
||||
return &retransmit_bitrate_observer_;
|
||||
}
|
||||
|
||||
void RTPSender::BitrateAggregator::set_ssrc(uint32_t ssrc) {
|
||||
ssrc_ = ssrc;
|
||||
}
|
||||
|
||||
RTPSender::BitrateAggregator::BitrateObserver::BitrateObserver(
|
||||
const BitrateAggregator& aggregator)
|
||||
: aggregator_(aggregator) {}
|
||||
|
||||
// Implements Bitrate::Observer.
|
||||
void RTPSender::BitrateAggregator::BitrateObserver::BitrateUpdated(
|
||||
const BitrateStatistics& stats) {
|
||||
statistics_ = stats;
|
||||
aggregator_.OnStatsUpdated();
|
||||
}
|
||||
|
||||
const BitrateStatistics&
|
||||
RTPSender::BitrateAggregator::BitrateObserver::statistics() const {
|
||||
return statistics_;
|
||||
}
|
||||
|
||||
RTPSender::RTPSender(
|
||||
bool audio,
|
||||
Clock* clock,
|
||||
@ -115,13 +76,12 @@ RTPSender::RTPSender(
|
||||
FrameCountObserver* frame_count_observer,
|
||||
SendSideDelayObserver* send_side_delay_observer,
|
||||
RtcEventLog* event_log,
|
||||
SendPacketObserver* send_packet_observer)
|
||||
SendPacketObserver* send_packet_observer,
|
||||
RateLimiter* retransmission_rate_limiter)
|
||||
: clock_(clock),
|
||||
// TODO(holmer): Remove this conversion?
|
||||
clock_delta_ms_(clock_->TimeInMilliseconds() - rtc::TimeMillis()),
|
||||
random_(clock_->TimeInMicroseconds()),
|
||||
bitrates_(bitrate_callback),
|
||||
total_bitrate_sent_(clock, bitrates_.total_bitrate_observer()),
|
||||
audio_configured_(audio),
|
||||
audio_(audio ? new RTPSenderAudio(clock, this) : nullptr),
|
||||
video_(audio ? nullptr : new RTPSenderVideo(clock, this)),
|
||||
@ -140,18 +100,18 @@ RTPSender::RTPSender(
|
||||
rotation_(kVideoRotation_0),
|
||||
video_rotation_active_(false),
|
||||
transport_sequence_number_(0),
|
||||
// NACK.
|
||||
nack_byte_count_times_(),
|
||||
nack_byte_count_(),
|
||||
nack_bitrate_(clock, bitrates_.retransmit_bitrate_observer()),
|
||||
playout_delay_active_(false),
|
||||
packet_history_(clock),
|
||||
// Statistics
|
||||
rtp_stats_callback_(NULL),
|
||||
rtp_stats_callback_(nullptr),
|
||||
total_bitrate_sent_(kBitrateStatisticsWindowMs,
|
||||
RateStatistics::kBpsScale),
|
||||
nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale),
|
||||
frame_count_observer_(frame_count_observer),
|
||||
send_side_delay_observer_(send_side_delay_observer),
|
||||
event_log_(event_log),
|
||||
send_packet_observer_(send_packet_observer),
|
||||
bitrate_callback_(bitrate_callback),
|
||||
// RTP variables
|
||||
start_timestamp_forced_(false),
|
||||
start_timestamp_(0),
|
||||
@ -166,9 +126,7 @@ RTPSender::RTPSender(
|
||||
last_packet_marker_bit_(false),
|
||||
csrcs_(),
|
||||
rtx_(kRtxOff),
|
||||
target_bitrate_(0) {
|
||||
memset(nack_byte_count_times_, 0, sizeof(nack_byte_count_times_));
|
||||
memset(nack_byte_count_, 0, sizeof(nack_byte_count_));
|
||||
retransmission_rate_limiter_(retransmission_rate_limiter) {
|
||||
// We need to seed the random generator for BuildPaddingPacket() below.
|
||||
// TODO(holmer,tommi): Note that TimeInMilliseconds might return 0 on Mac
|
||||
// early on in the process.
|
||||
@ -178,7 +136,6 @@ RTPSender::RTPSender(
|
||||
ssrc_rtx_ = ssrc_db_->CreateSSRC();
|
||||
RTC_DCHECK(ssrc_rtx_ != 0);
|
||||
|
||||
bitrates_.set_ssrc(ssrc_);
|
||||
// Random start, 16 bits. Can't be 0.
|
||||
sequence_number_rtx_ = random_.Rand(1, kMaxInitRtpSeqNumber);
|
||||
sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber);
|
||||
@ -208,18 +165,11 @@ RTPSender::~RTPSender() {
|
||||
}
|
||||
}
|
||||
|
||||
void RTPSender::SetTargetBitrate(uint32_t bitrate) {
|
||||
rtc::CritScope cs(&target_bitrate_critsect_);
|
||||
target_bitrate_ = bitrate;
|
||||
}
|
||||
|
||||
uint32_t RTPSender::GetTargetBitrate() {
|
||||
rtc::CritScope cs(&target_bitrate_critsect_);
|
||||
return target_bitrate_;
|
||||
}
|
||||
|
||||
uint16_t RTPSender::ActualSendBitrateKbit() const {
|
||||
return (uint16_t)(total_bitrate_sent_.BitrateNow() / 1000);
|
||||
rtc::CritScope cs(&statistics_crit_);
|
||||
return static_cast<uint16_t>(
|
||||
total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0) /
|
||||
1000);
|
||||
}
|
||||
|
||||
uint32_t RTPSender::VideoBitrateSent() const {
|
||||
@ -237,7 +187,8 @@ uint32_t RTPSender::FecOverheadRate() const {
|
||||
}
|
||||
|
||||
uint32_t RTPSender::NackOverheadRate() const {
|
||||
return nack_bitrate_.BitrateLast();
|
||||
rtc::CritScope cs(&statistics_crit_);
|
||||
return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
|
||||
}
|
||||
|
||||
int32_t RTPSender::SetTransmissionTimeOffset(int32_t transmission_time_offset) {
|
||||
@ -754,6 +705,12 @@ int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if we're overusing retransmission bitrate.
|
||||
// TODO(sprang): Add histograms for nack success or failure reasons.
|
||||
RTC_DCHECK(retransmission_rate_limiter_);
|
||||
if (!retransmission_rate_limiter_->TryUseRate(length))
|
||||
return -1;
|
||||
|
||||
if (paced_sender_) {
|
||||
RtpUtility::RtpHeaderParser rtp_parser(data_buffer, length);
|
||||
RTPHeader header;
|
||||
@ -824,44 +781,14 @@ void RTPSender::OnReceivedNACK(const std::list<uint16_t>& nack_sequence_numbers,
|
||||
TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
||||
"RTPSender::OnReceivedNACK", "num_seqnum",
|
||||
nack_sequence_numbers.size(), "avg_rtt", avg_rtt);
|
||||
const int64_t now = clock_->TimeInMilliseconds();
|
||||
uint32_t bytes_re_sent = 0;
|
||||
uint32_t target_bitrate = GetTargetBitrate();
|
||||
|
||||
// Enough bandwidth to send NACK?
|
||||
if (!ProcessNACKBitRate(now)) {
|
||||
LOG(LS_INFO) << "NACK bitrate reached. Skip sending NACK response. Target "
|
||||
<< target_bitrate;
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::list<uint16_t>::const_iterator it = nack_sequence_numbers.begin();
|
||||
it != nack_sequence_numbers.end(); ++it) {
|
||||
const int32_t bytes_sent = ReSendPacket(*it, 5 + avg_rtt);
|
||||
if (bytes_sent > 0) {
|
||||
bytes_re_sent += bytes_sent;
|
||||
} else if (bytes_sent == 0) {
|
||||
// The packet has previously been resent.
|
||||
// Try resending next packet in the list.
|
||||
continue;
|
||||
} else {
|
||||
for (uint16_t seq_no : nack_sequence_numbers) {
|
||||
const int32_t bytes_sent = ReSendPacket(seq_no, 5 + avg_rtt);
|
||||
if (bytes_sent < 0) {
|
||||
// Failed to send one Sequence number. Give up the rest in this nack.
|
||||
LOG(LS_WARNING) << "Failed resending RTP packet " << *it
|
||||
LOG(LS_WARNING) << "Failed resending RTP packet " << seq_no
|
||||
<< ", Discard rest of packets";
|
||||
break;
|
||||
}
|
||||
// Delay bandwidth estimate (RTT * BW).
|
||||
if (target_bitrate != 0 && avg_rtt) {
|
||||
// kbits/s * ms = bits => bits/8 = bytes
|
||||
size_t target_bytes =
|
||||
(static_cast<size_t>(target_bitrate / 1000) * avg_rtt) >> 3;
|
||||
if (bytes_re_sent > target_bytes) {
|
||||
break; // Ignore the rest of the packets in the list.
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bytes_re_sent > 0) {
|
||||
UpdateNACKBitRate(bytes_re_sent, now);
|
||||
}
|
||||
}
|
||||
|
||||
@ -870,51 +797,6 @@ void RTPSender::OnReceivedRtcpReportBlocks(
|
||||
playout_delay_oracle_.OnReceivedRtcpReportBlocks(report_blocks);
|
||||
}
|
||||
|
||||
bool RTPSender::ProcessNACKBitRate(uint32_t now) {
|
||||
uint32_t num = 0;
|
||||
size_t byte_count = 0;
|
||||
const uint32_t kAvgIntervalMs = 1000;
|
||||
uint32_t target_bitrate = GetTargetBitrate();
|
||||
|
||||
rtc::CritScope lock(&send_critsect_);
|
||||
|
||||
if (target_bitrate == 0) {
|
||||
return true;
|
||||
}
|
||||
for (num = 0; num < NACK_BYTECOUNT_SIZE; ++num) {
|
||||
if ((now - nack_byte_count_times_[num]) > kAvgIntervalMs) {
|
||||
// Don't use data older than 1sec.
|
||||
break;
|
||||
} else {
|
||||
byte_count += nack_byte_count_[num];
|
||||
}
|
||||
}
|
||||
uint32_t time_interval = kAvgIntervalMs;
|
||||
if (num == NACK_BYTECOUNT_SIZE) {
|
||||
// More than NACK_BYTECOUNT_SIZE nack messages has been received
|
||||
// during the last msg_interval.
|
||||
if (nack_byte_count_times_[num - 1] <= now) {
|
||||
time_interval = now - nack_byte_count_times_[num - 1];
|
||||
}
|
||||
}
|
||||
return (byte_count * 8) < (target_bitrate / 1000 * time_interval);
|
||||
}
|
||||
|
||||
void RTPSender::UpdateNACKBitRate(uint32_t bytes, int64_t now) {
|
||||
rtc::CritScope lock(&send_critsect_);
|
||||
if (bytes == 0)
|
||||
return;
|
||||
nack_bitrate_.Update(bytes);
|
||||
// Save bitrate statistics.
|
||||
// Shift all but first time.
|
||||
for (int i = NACK_BYTECOUNT_SIZE - 2; i >= 0; i--) {
|
||||
nack_byte_count_[i + 1] = nack_byte_count_[i];
|
||||
nack_byte_count_times_[i + 1] = nack_byte_count_times_[i];
|
||||
}
|
||||
nack_byte_count_[0] = bytes;
|
||||
nack_byte_count_times_[0] = now;
|
||||
}
|
||||
|
||||
// Called from pacer when we can send the packet.
|
||||
bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
|
||||
int64_t capture_time_ms,
|
||||
@ -1009,6 +891,7 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer,
|
||||
StreamDataCounters* counters;
|
||||
// Get ssrc before taking statistics_crit_ to avoid possible deadlock.
|
||||
uint32_t ssrc = is_rtx ? RtxSsrc() : SSRC();
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
|
||||
rtc::CritScope lock(&statistics_crit_);
|
||||
if (is_rtx) {
|
||||
@ -1017,22 +900,23 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer,
|
||||
counters = &rtp_stats_;
|
||||
}
|
||||
|
||||
total_bitrate_sent_.Update(packet_length);
|
||||
total_bitrate_sent_.Update(packet_length, now_ms);
|
||||
|
||||
if (counters->first_packet_time_ms == -1) {
|
||||
if (counters->first_packet_time_ms == -1)
|
||||
counters->first_packet_time_ms = clock_->TimeInMilliseconds();
|
||||
}
|
||||
if (IsFecPacket(buffer, header)) {
|
||||
|
||||
if (IsFecPacket(buffer, header))
|
||||
counters->fec.AddPacket(packet_length, header);
|
||||
}
|
||||
|
||||
if (is_retransmit) {
|
||||
counters->retransmitted.AddPacket(packet_length, header);
|
||||
nack_bitrate_sent_.Update(packet_length, now_ms);
|
||||
}
|
||||
|
||||
counters->transmitted.AddPacket(packet_length, header);
|
||||
|
||||
if (rtp_stats_callback_) {
|
||||
if (rtp_stats_callback_)
|
||||
rtp_stats_callback_->DataCountersUpdated(*counters, ssrc);
|
||||
}
|
||||
}
|
||||
|
||||
bool RTPSender::IsFecPacket(const uint8_t* buffer,
|
||||
@ -1180,13 +1064,18 @@ void RTPSender::UpdateOnSendPacket(int packet_id,
|
||||
}
|
||||
|
||||
void RTPSender::ProcessBitrate() {
|
||||
rtc::CritScope lock(&send_critsect_);
|
||||
total_bitrate_sent_.Process();
|
||||
nack_bitrate_.Process();
|
||||
if (audio_configured_) {
|
||||
if (!bitrate_callback_)
|
||||
return;
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
uint32_t ssrc;
|
||||
{
|
||||
rtc::CritScope lock(&send_critsect_);
|
||||
ssrc = ssrc_;
|
||||
}
|
||||
video_->ProcessBitrate();
|
||||
|
||||
rtc::CritScope lock(&statistics_crit_);
|
||||
bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0),
|
||||
nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc);
|
||||
}
|
||||
|
||||
size_t RTPSender::RtpHeaderLength() const {
|
||||
@ -1746,7 +1635,6 @@ void RTPSender::SetSendingStatus(bool enabled) {
|
||||
ssrc_db_->ReturnSSRC(ssrc_);
|
||||
ssrc_ = ssrc_db_->CreateSSRC();
|
||||
RTC_DCHECK(ssrc_ != 0);
|
||||
bitrates_.set_ssrc(ssrc_);
|
||||
}
|
||||
// Don't initialize seq number if SSRC passed externally.
|
||||
if (!sequence_number_forced_ && !ssrc_forced_) {
|
||||
@ -1797,7 +1685,6 @@ uint32_t RTPSender::GenerateNewSSRC() {
|
||||
}
|
||||
ssrc_ = ssrc_db_->CreateSSRC();
|
||||
RTC_DCHECK(ssrc_ != 0);
|
||||
bitrates_.set_ssrc(ssrc_);
|
||||
return ssrc_;
|
||||
}
|
||||
|
||||
@ -1812,7 +1699,6 @@ void RTPSender::SetSSRC(uint32_t ssrc) {
|
||||
ssrc_db_->ReturnSSRC(ssrc_);
|
||||
ssrc_db_->RegisterSSRC(ssrc);
|
||||
ssrc_ = ssrc;
|
||||
bitrates_.set_ssrc(ssrc_);
|
||||
if (!sequence_number_forced_) {
|
||||
sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber);
|
||||
}
|
||||
@ -1961,7 +1847,8 @@ StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const {
|
||||
}
|
||||
|
||||
uint32_t RTPSender::BitrateSent() const {
|
||||
return total_bitrate_sent_.BitrateLast();
|
||||
rtc::CritScope cs(&statistics_crit_);
|
||||
return total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
|
||||
}
|
||||
|
||||
void RTPSender::SetRtpState(const RtpState& rtp_state) {
|
||||
|
||||
@ -20,10 +20,10 @@
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/base/random.h"
|
||||
#include "webrtc/base/rate_statistics.h"
|
||||
#include "webrtc/base/thread_annotations.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/bitrate.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
|
||||
@ -34,6 +34,7 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RateLimiter;
|
||||
class RTPSenderAudio;
|
||||
class RTPSenderVideo;
|
||||
class RtcEventLog;
|
||||
@ -93,7 +94,8 @@ class RTPSender : public RTPSenderInterface {
|
||||
FrameCountObserver* frame_count_observer,
|
||||
SendSideDelayObserver* send_side_delay_observer,
|
||||
RtcEventLog* event_log,
|
||||
SendPacketObserver* send_packet_observer);
|
||||
SendPacketObserver* send_packet_observer,
|
||||
RateLimiter* nack_rate_limiter);
|
||||
|
||||
virtual ~RTPSender();
|
||||
|
||||
@ -105,9 +107,6 @@ class RTPSender : public RTPSenderInterface {
|
||||
uint32_t FecOverheadRate() const;
|
||||
uint32_t NackOverheadRate() const;
|
||||
|
||||
void SetTargetBitrate(uint32_t bitrate);
|
||||
uint32_t GetTargetBitrate();
|
||||
|
||||
// Includes size of RTP and FEC headers.
|
||||
size_t MaxDataPayloadLength() const override;
|
||||
|
||||
@ -227,8 +226,6 @@ class RTPSender : public RTPSenderInterface {
|
||||
|
||||
int32_t ReSendPacket(uint16_t packet_id, int64_t min_resend_time = 0);
|
||||
|
||||
bool ProcessNACKBitRate(uint32_t now);
|
||||
|
||||
// Feedback to decide when to stop sending playout delay.
|
||||
void OnReceivedRtcpReportBlocks(const ReportBlockList& report_blocks);
|
||||
|
||||
@ -340,8 +337,6 @@ class RTPSender : public RTPSenderInterface {
|
||||
uint16_t sequence_number,
|
||||
const std::vector<uint32_t>& csrcs) const;
|
||||
|
||||
void UpdateNACKBitRate(uint32_t bytes, int64_t now);
|
||||
|
||||
bool PrepareAndSendPacket(uint8_t* buffer,
|
||||
size_t length,
|
||||
int64_t capture_time_ms,
|
||||
@ -406,45 +401,10 @@ class RTPSender : public RTPSenderInterface {
|
||||
bool is_retransmit);
|
||||
bool IsFecPacket(const uint8_t* buffer, const RTPHeader& header) const;
|
||||
|
||||
class BitrateAggregator {
|
||||
public:
|
||||
explicit BitrateAggregator(BitrateStatisticsObserver* bitrate_callback);
|
||||
|
||||
void OnStatsUpdated() const;
|
||||
|
||||
Bitrate::Observer* total_bitrate_observer();
|
||||
Bitrate::Observer* retransmit_bitrate_observer();
|
||||
void set_ssrc(uint32_t ssrc);
|
||||
|
||||
private:
|
||||
// We assume that these observers are called on the same thread, which is
|
||||
// true for RtpSender as they are called on the Process thread.
|
||||
class BitrateObserver : public Bitrate::Observer {
|
||||
public:
|
||||
explicit BitrateObserver(const BitrateAggregator& aggregator);
|
||||
|
||||
// Implements Bitrate::Observer.
|
||||
void BitrateUpdated(const BitrateStatistics& stats) override;
|
||||
const BitrateStatistics& statistics() const;
|
||||
|
||||
private:
|
||||
BitrateStatistics statistics_;
|
||||
const BitrateAggregator& aggregator_;
|
||||
};
|
||||
|
||||
BitrateStatisticsObserver* const callback_;
|
||||
BitrateObserver total_bitrate_observer_;
|
||||
BitrateObserver retransmit_bitrate_observer_;
|
||||
uint32_t ssrc_;
|
||||
};
|
||||
|
||||
Clock* const clock_;
|
||||
const int64_t clock_delta_ms_;
|
||||
Random random_ GUARDED_BY(send_critsect_);
|
||||
|
||||
BitrateAggregator bitrates_;
|
||||
Bitrate total_bitrate_sent_;
|
||||
|
||||
const bool audio_configured_;
|
||||
const std::unique_ptr<RTPSenderAudio> audio_;
|
||||
const std::unique_ptr<RTPSenderVideo> video_;
|
||||
@ -470,11 +430,6 @@ class RTPSender : public RTPSenderInterface {
|
||||
bool video_rotation_active_;
|
||||
uint16_t transport_sequence_number_;
|
||||
|
||||
// NACK
|
||||
uint32_t nack_byte_count_times_[NACK_BYTECOUNT_SIZE];
|
||||
size_t nack_byte_count_[NACK_BYTECOUNT_SIZE];
|
||||
Bitrate nack_bitrate_;
|
||||
|
||||
// Tracks the current request for playout delay limits from application
|
||||
// and decides whether the current RTP frame should include the playout
|
||||
// delay extension on header.
|
||||
@ -490,10 +445,13 @@ class RTPSender : public RTPSenderInterface {
|
||||
StreamDataCounters rtp_stats_ GUARDED_BY(statistics_crit_);
|
||||
StreamDataCounters rtx_rtp_stats_ GUARDED_BY(statistics_crit_);
|
||||
StreamDataCountersCallback* rtp_stats_callback_ GUARDED_BY(statistics_crit_);
|
||||
RateStatistics total_bitrate_sent_ GUARDED_BY(statistics_crit_);
|
||||
RateStatistics nack_bitrate_sent_ GUARDED_BY(statistics_crit_);
|
||||
FrameCountObserver* const frame_count_observer_;
|
||||
SendSideDelayObserver* const send_side_delay_observer_;
|
||||
RtcEventLog* const event_log_;
|
||||
SendPacketObserver* const send_packet_observer_;
|
||||
BitrateStatisticsObserver* const bitrate_callback_;
|
||||
|
||||
// RTP variables
|
||||
bool start_timestamp_forced_ GUARDED_BY(send_critsect_);
|
||||
@ -516,12 +474,7 @@ class RTPSender : public RTPSenderInterface {
|
||||
// Mapping rtx_payload_type_map_[associated] = rtx.
|
||||
std::map<int8_t, int8_t> rtx_payload_type_map_ GUARDED_BY(send_critsect_);
|
||||
|
||||
// Note: Don't access this variable directly, always go through
|
||||
// SetTargetBitrateKbps or GetTargetBitrateKbps. Also remember
|
||||
// that by the time the function returns there is no guarantee
|
||||
// that the target bitrate is still valid.
|
||||
rtc::CriticalSection target_bitrate_critsect_;
|
||||
uint32_t target_bitrate_ GUARDED_BY(target_bitrate_critsect_);
|
||||
RateLimiter* const retransmission_rate_limiter_;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSender);
|
||||
};
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/buffer.h"
|
||||
#include "webrtc/base/rate_limiter.h"
|
||||
#include "webrtc/call/mock/mock_rtc_event_log.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
|
||||
@ -133,11 +134,11 @@ class RtpSenderTest : public ::testing::Test {
|
||||
: fake_clock_(kStartTime),
|
||||
mock_rtc_event_log_(),
|
||||
mock_paced_sender_(),
|
||||
retransmission_rate_limiter_(&fake_clock_, 1000),
|
||||
rtp_sender_(),
|
||||
payload_(kPayload),
|
||||
transport_(),
|
||||
kMarkerBit(true) {
|
||||
}
|
||||
kMarkerBit(true) {}
|
||||
|
||||
void SetUp() override { SetUpRtpSender(true); }
|
||||
|
||||
@ -145,7 +146,8 @@ class RtpSenderTest : public ::testing::Test {
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr,
|
||||
&seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
|
||||
&mock_rtc_event_log_, &send_packet_observer_));
|
||||
&mock_rtc_event_log_, &send_packet_observer_,
|
||||
&retransmission_rate_limiter_));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
}
|
||||
|
||||
@ -154,6 +156,7 @@ class RtpSenderTest : public ::testing::Test {
|
||||
MockRtpPacketSender mock_paced_sender_;
|
||||
MockTransportSequenceNumberAllocator seq_num_allocator_;
|
||||
MockSendPacketObserver send_packet_observer_;
|
||||
RateLimiter retransmission_rate_limiter_;
|
||||
std::unique_ptr<RTPSender> rtp_sender_;
|
||||
int payload_;
|
||||
LoopbackTransportTest transport_;
|
||||
@ -743,7 +746,6 @@ TEST_F(RtpSenderTest, TrafficSmoothingWithExtensions) {
|
||||
EXPECT_EQ(
|
||||
0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
|
||||
kAbsoluteSendTimeExtensionId));
|
||||
rtp_sender_->SetTargetBitrate(300000);
|
||||
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
||||
int rtp_length_int = rtp_sender_->BuildRTPheader(
|
||||
packet_, kPayload, kMarkerBit, kTimestamp, capture_time_ms);
|
||||
@ -797,7 +799,6 @@ TEST_F(RtpSenderTest, TrafficSmoothingRetransmits) {
|
||||
EXPECT_EQ(
|
||||
0, rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
|
||||
kAbsoluteSendTimeExtensionId));
|
||||
rtp_sender_->SetTargetBitrate(300000);
|
||||
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
||||
int rtp_length_int = rtp_sender_->BuildRTPheader(
|
||||
packet_, kPayload, kMarkerBit, kTimestamp, capture_time_ms);
|
||||
@ -879,7 +880,6 @@ TEST_F(RtpSenderTest, SendPadding) {
|
||||
kAbsoluteSendTimeExtensionId);
|
||||
webrtc::RTPHeader rtp_header;
|
||||
|
||||
rtp_sender_->SetTargetBitrate(300000);
|
||||
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
|
||||
int rtp_length_int = rtp_sender_->BuildRTPheader(
|
||||
packet_, kPayload, kMarkerBit, timestamp, capture_time_ms);
|
||||
@ -1011,7 +1011,7 @@ TEST_F(RtpSenderTest, OnSendPacketNotUpdatedWithoutSeqNumAllocator) {
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_,
|
||||
nullptr /* TransportSequenceNumberAllocator */, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &send_packet_observer_));
|
||||
nullptr, nullptr, &send_packet_observer_, nullptr));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetStorePacketsStatus(true, 10);
|
||||
|
||||
@ -1029,7 +1029,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) {
|
||||
MockTransport transport;
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr));
|
||||
nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr, nullptr));
|
||||
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
|
||||
@ -1054,7 +1054,6 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) {
|
||||
kTransmissionTimeOffsetExtensionId);
|
||||
rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
|
||||
kAbsoluteSendTimeExtensionId);
|
||||
rtp_sender_->SetTargetBitrate(300000);
|
||||
const size_t kNumPayloadSizes = 10;
|
||||
const size_t kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700,
|
||||
750, 800, 850, 900, 950};
|
||||
@ -1176,7 +1175,7 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) {
|
||||
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, nullptr,
|
||||
nullptr, &callback, nullptr, nullptr, nullptr));
|
||||
nullptr, &callback, nullptr, nullptr, nullptr, nullptr));
|
||||
|
||||
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
|
||||
const uint8_t payload_type = 127;
|
||||
@ -1213,30 +1212,39 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) {
|
||||
TEST_F(RtpSenderTest, BitrateCallbacks) {
|
||||
class TestCallback : public BitrateStatisticsObserver {
|
||||
public:
|
||||
TestCallback() : BitrateStatisticsObserver(), num_calls_(0), ssrc_(0) {}
|
||||
TestCallback()
|
||||
: BitrateStatisticsObserver(),
|
||||
num_calls_(0),
|
||||
ssrc_(0),
|
||||
total_bitrate_(0),
|
||||
retransmit_bitrate_(0) {}
|
||||
virtual ~TestCallback() {}
|
||||
|
||||
void Notify(const BitrateStatistics& total_stats,
|
||||
const BitrateStatistics& retransmit_stats,
|
||||
void Notify(uint32_t total_bitrate,
|
||||
uint32_t retransmit_bitrate,
|
||||
uint32_t ssrc) override {
|
||||
++num_calls_;
|
||||
ssrc_ = ssrc;
|
||||
total_stats_ = total_stats;
|
||||
retransmit_stats_ = retransmit_stats;
|
||||
total_bitrate_ = total_bitrate;
|
||||
retransmit_bitrate_ = retransmit_bitrate;
|
||||
}
|
||||
|
||||
uint32_t num_calls_;
|
||||
uint32_t ssrc_;
|
||||
BitrateStatistics total_stats_;
|
||||
BitrateStatistics retransmit_stats_;
|
||||
uint32_t total_bitrate_;
|
||||
uint32_t retransmit_bitrate_;
|
||||
} callback;
|
||||
rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr,
|
||||
nullptr, nullptr, &callback, nullptr, nullptr,
|
||||
nullptr, nullptr));
|
||||
nullptr, nullptr, nullptr));
|
||||
|
||||
// Simulate kNumPackets sent with kPacketInterval ms intervals.
|
||||
const uint32_t kNumPackets = 15;
|
||||
// Simulate kNumPackets sent with kPacketInterval ms intervals, with the
|
||||
// number of packets selected so that we fill (but don't overflow) the one
|
||||
// second averaging window.
|
||||
const uint32_t kWindowSizeMs = 1000;
|
||||
const uint32_t kPacketInterval = 20;
|
||||
const uint32_t kNumPackets =
|
||||
(kWindowSizeMs - kPacketInterval) / kPacketInterval;
|
||||
// Overhead = 12 bytes RTP header + 1 byte generic header.
|
||||
const uint32_t kPacketOverhead = 13;
|
||||
|
||||
@ -1250,7 +1258,6 @@ TEST_F(RtpSenderTest, BitrateCallbacks) {
|
||||
|
||||
// Initial process call so we get a new time window.
|
||||
rtp_sender_->ProcessBitrate();
|
||||
uint64_t start_time = fake_clock_.CurrentNtpInMilliseconds();
|
||||
|
||||
// Send a few frames.
|
||||
for (uint32_t i = 0; i < kNumPackets; ++i) {
|
||||
@ -1262,17 +1269,18 @@ TEST_F(RtpSenderTest, BitrateCallbacks) {
|
||||
|
||||
rtp_sender_->ProcessBitrate();
|
||||
|
||||
const uint32_t expected_packet_rate = 1000 / kPacketInterval;
|
||||
|
||||
// We get one call for every stats updated, thus two calls since both the
|
||||
// stream stats and the retransmit stats are updated once.
|
||||
EXPECT_EQ(2u, callback.num_calls_);
|
||||
EXPECT_EQ(ssrc, callback.ssrc_);
|
||||
EXPECT_EQ(start_time + (kNumPackets * kPacketInterval),
|
||||
callback.total_stats_.timestamp_ms);
|
||||
EXPECT_EQ(expected_packet_rate, callback.total_stats_.packet_rate);
|
||||
EXPECT_EQ((kPacketOverhead + sizeof(payload)) * 8 * expected_packet_rate,
|
||||
callback.total_stats_.bitrate_bps);
|
||||
const uint32_t kTotalPacketSize = kPacketOverhead + sizeof(payload);
|
||||
// Bitrate measured over delta between last and first timestamp, plus one.
|
||||
const uint32_t kExpectedWindowMs = kNumPackets * kPacketInterval + 1;
|
||||
const uint32_t kExpectedBitsAccumulated = kTotalPacketSize * kNumPackets * 8;
|
||||
const uint32_t kExpectedRateBps =
|
||||
(kExpectedBitsAccumulated * 1000 + (kExpectedWindowMs / 2)) /
|
||||
kExpectedWindowMs;
|
||||
EXPECT_EQ(kExpectedRateBps, callback.total_bitrate_);
|
||||
|
||||
rtp_sender_.reset();
|
||||
}
|
||||
@ -1285,7 +1293,7 @@ class RtpSenderAudioTest : public RtpSenderTest {
|
||||
payload_ = kAudioPayload;
|
||||
rtp_sender_.reset(new RTPSender(true, &fake_clock_, &transport_, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr));
|
||||
nullptr, nullptr, nullptr));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
}
|
||||
};
|
||||
@ -1553,9 +1561,9 @@ TEST_F(RtpSenderTestWithoutPacer, RespectsNackBitrateLimit) {
|
||||
const int32_t kPacketSize = 1400;
|
||||
const int32_t kNumPackets = 30;
|
||||
|
||||
retransmission_rate_limiter_.SetMaxRate(kPacketSize * kNumPackets * 8);
|
||||
|
||||
rtp_sender_->SetStorePacketsStatus(true, kNumPackets);
|
||||
// Set bitrate (in kbps) to fit kNumPackets á kPacketSize bytes in one second.
|
||||
rtp_sender_->SetTargetBitrate(kNumPackets * kPacketSize * 8);
|
||||
const uint16_t kStartSequenceNumber = rtp_sender_->SequenceNumber();
|
||||
std::list<uint16_t> sequence_numbers;
|
||||
for (int32_t i = 0; i < kNumPackets; ++i) {
|
||||
@ -1573,6 +1581,9 @@ TEST_F(RtpSenderTestWithoutPacer, RespectsNackBitrateLimit) {
|
||||
rtp_sender_->OnReceivedNACK(sequence_numbers, 0);
|
||||
EXPECT_EQ(kNumPackets * 2, transport_.packets_sent_);
|
||||
|
||||
// Must be at least 5ms in between retransmission attempts.
|
||||
fake_clock_.AdvanceTimeMilliseconds(5);
|
||||
|
||||
// Resending should not work, bandwidth exceeded.
|
||||
rtp_sender_->OnReceivedNACK(sequence_numbers, 0);
|
||||
EXPECT_EQ(kNumPackets * 2, transport_.packets_sent_);
|
||||
|
||||
@ -31,6 +31,7 @@ enum { REDForFECHeaderLength = 1 };
|
||||
|
||||
RTPSenderVideo::RTPSenderVideo(Clock* clock, RTPSenderInterface* rtpSender)
|
||||
: _rtpSender(*rtpSender),
|
||||
clock_(clock),
|
||||
_videoType(kRtpVideoGeneric),
|
||||
_retransmissionSettings(kRetransmitBaseLayer),
|
||||
// Generic FEC
|
||||
@ -41,8 +42,8 @@ RTPSenderVideo::RTPSenderVideo(Clock* clock, RTPSenderInterface* rtpSender)
|
||||
delta_fec_params_(),
|
||||
key_fec_params_(),
|
||||
producer_fec_(&fec_),
|
||||
_fecOverheadRate(clock, NULL),
|
||||
_videoBitrate(clock, NULL) {
|
||||
fec_bitrate_(1000, RateStatistics::kBpsScale),
|
||||
video_bitrate_(1000, RateStatistics::kBpsScale) {
|
||||
memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
|
||||
memset(&key_fec_params_, 0, sizeof(key_fec_params_));
|
||||
delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
|
||||
@ -95,7 +96,9 @@ void RTPSenderVideo::SendVideoPacket(uint8_t* data_buffer,
|
||||
if (_rtpSender.SendToNetwork(data_buffer, payload_length, rtp_header_length,
|
||||
capture_time_ms, storage,
|
||||
RtpPacketSender::kLowPriority) == 0) {
|
||||
_videoBitrate.Update(payload_length + rtp_header_length);
|
||||
rtc::CritScope cs(&stats_crit_);
|
||||
video_bitrate_.Update(payload_length + rtp_header_length,
|
||||
clock_->TimeInMilliseconds());
|
||||
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
||||
"Video::PacketNormal", "timestamp", capture_timestamp,
|
||||
"seqnum", seq_num);
|
||||
@ -141,7 +144,8 @@ void RTPSenderVideo::SendVideoPacketAsRed(uint8_t* data_buffer,
|
||||
red_packet->data(), red_packet->length() - rtp_header_length,
|
||||
rtp_header_length, capture_time_ms, media_packet_storage,
|
||||
RtpPacketSender::kLowPriority) == 0) {
|
||||
_videoBitrate.Update(red_packet->length());
|
||||
rtc::CritScope cs(&stats_crit_);
|
||||
video_bitrate_.Update(red_packet->length(), clock_->TimeInMilliseconds());
|
||||
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
||||
"Video::PacketRed", "timestamp", capture_timestamp,
|
||||
"seqnum", media_seq_num);
|
||||
@ -153,7 +157,8 @@ void RTPSenderVideo::SendVideoPacketAsRed(uint8_t* data_buffer,
|
||||
fec_packet->data(), fec_packet->length() - rtp_header_length,
|
||||
rtp_header_length, capture_time_ms, fec_storage,
|
||||
RtpPacketSender::kLowPriority) == 0) {
|
||||
_fecOverheadRate.Update(fec_packet->length());
|
||||
rtc::CritScope cs(&stats_crit_);
|
||||
fec_bitrate_.Update(fec_packet->length(), clock_->TimeInMilliseconds());
|
||||
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
||||
"Video::PacketFec", "timestamp", capture_timestamp,
|
||||
"seqnum", next_fec_sequence_number);
|
||||
@ -337,17 +342,14 @@ int32_t RTPSenderVideo::SendVideo(const RtpVideoCodecTypes videoType,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RTPSenderVideo::ProcessBitrate() {
|
||||
_videoBitrate.Process();
|
||||
_fecOverheadRate.Process();
|
||||
}
|
||||
|
||||
uint32_t RTPSenderVideo::VideoBitrateSent() const {
|
||||
return _videoBitrate.BitrateLast();
|
||||
rtc::CritScope cs(&stats_crit_);
|
||||
return video_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
|
||||
}
|
||||
|
||||
uint32_t RTPSenderVideo::FecOverheadRate() const {
|
||||
return _fecOverheadRate.BitrateLast();
|
||||
rtc::CritScope cs(&stats_crit_);
|
||||
return fec_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
|
||||
}
|
||||
|
||||
int RTPSenderVideo::SelectiveRetransmissions() const {
|
||||
|
||||
@ -15,10 +15,10 @@
|
||||
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/base/onetimeevent.h"
|
||||
#include "webrtc/base/rate_statistics.h"
|
||||
#include "webrtc/base/thread_annotations.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/bitrate.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/producer_fec.h"
|
||||
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
|
||||
@ -68,8 +68,6 @@ class RTPSenderVideo {
|
||||
void SetFecParameters(const FecProtectionParams* delta_params,
|
||||
const FecProtectionParams* key_params);
|
||||
|
||||
void ProcessBitrate();
|
||||
|
||||
uint32_t VideoBitrateSent() const;
|
||||
uint32_t FecOverheadRate() const;
|
||||
|
||||
@ -95,9 +93,10 @@ class RTPSenderVideo {
|
||||
bool protect);
|
||||
|
||||
RTPSenderInterface& _rtpSender;
|
||||
Clock* const clock_;
|
||||
|
||||
// Should never be held when calling out of this class.
|
||||
const rtc::CriticalSection crit_;
|
||||
rtc::CriticalSection crit_;
|
||||
|
||||
RtpVideoCodecTypes _videoType;
|
||||
int32_t _retransmissionSettings GUARDED_BY(crit_);
|
||||
@ -111,11 +110,12 @@ class RTPSenderVideo {
|
||||
FecProtectionParams key_fec_params_ GUARDED_BY(crit_);
|
||||
ProducerFec producer_fec_ GUARDED_BY(crit_);
|
||||
|
||||
rtc::CriticalSection stats_crit_;
|
||||
// Bitrate used for FEC payload, RED headers, RTP headers for FEC packets
|
||||
// and any padding overhead.
|
||||
Bitrate _fecOverheadRate;
|
||||
// Bitrate used for video payload and RTP headers
|
||||
Bitrate _videoBitrate;
|
||||
RateStatistics fec_bitrate_ GUARDED_BY(stats_crit_);
|
||||
// Bitrate used for video payload and RTP headers.
|
||||
RateStatistics video_bitrate_ GUARDED_BY(stats_crit_);
|
||||
OneTimeEvent first_frame_sent_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
Reference in New Issue
Block a user