Attach TransportFeedbackPacketLossTracker to ANA (PLR only)

This CL is one in a series. To finish the work, the following CLs will be added:
1. CL for connecting RPLR as well
2. CL for RPLR-based FecController
3. CL for allowing experiment-driven configuration of the above (through both field-trials and protobuf)

BUG=webrtc:7058

Review-Url: https://codereview.webrtc.org/2638083002
Cr-Commit-Position: refs/heads/master@{#17365}
This commit is contained in:
elad.alon
2017-03-23 11:04:48 -07:00
committed by Commit bot
parent 7b3ce5b872
commit d12a8e1c8e
24 changed files with 285 additions and 55 deletions

View File

@ -19,6 +19,7 @@
#include "webrtc/base/event.h" #include "webrtc/base/event.h"
#include "webrtc/base/logging.h" #include "webrtc/base/logging.h"
#include "webrtc/base/task_queue.h" #include "webrtc/base/task_queue.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/congestion_controller/include/send_side_congestion_controller.h" #include "webrtc/modules/congestion_controller/include/send_side_congestion_controller.h"
#include "webrtc/modules/pacing/paced_sender.h" #include "webrtc/modules/pacing/paced_sender.h"
@ -40,6 +41,11 @@ bool IsCodec(const webrtc::CodecInst& codec, const char* ref_name) {
} // namespace } // namespace
namespace internal { namespace internal {
// TODO(elad.alon): Subsequent CL will make these values experiment-dependent.
constexpr size_t kPacketLossTrackerMaxWindowSizeMs = 15000;
constexpr size_t kPacketLossRateMinNumAckedPackets = 50;
constexpr size_t kRecoverablePacketLossRateMinNumAckedPairs = 40;
AudioSendStream::AudioSendStream( AudioSendStream::AudioSendStream(
const webrtc::AudioSendStream::Config& config, const webrtc::AudioSendStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state, const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
@ -53,7 +59,10 @@ AudioSendStream::AudioSendStream(
config_(config), config_(config),
audio_state_(audio_state), audio_state_(audio_state),
bitrate_allocator_(bitrate_allocator), bitrate_allocator_(bitrate_allocator),
send_side_cc_(send_side_cc) { send_side_cc_(send_side_cc),
packet_loss_tracker_(kPacketLossTrackerMaxWindowSizeMs,
kPacketLossRateMinNumAckedPackets,
kRecoverablePacketLossRateMinNumAckedPairs) {
LOG(LS_INFO) << "AudioSendStream: " << config_.ToString(); LOG(LS_INFO) << "AudioSendStream: " << config_.ToString();
RTC_DCHECK_NE(config_.voe_channel_id, -1); RTC_DCHECK_NE(config_.voe_channel_id, -1);
RTC_DCHECK(audio_state_.get()); RTC_DCHECK(audio_state_.get());
@ -72,6 +81,7 @@ AudioSendStream::AudioSendStream(
config_.rtp.nack.rtp_history_ms / 20); config_.rtp.nack.rtp_history_ms / 20);
channel_proxy_->RegisterExternalTransport(config.send_transport); channel_proxy_->RegisterExternalTransport(config.send_transport);
send_side_cc_->RegisterPacketFeedbackObserver(this);
for (const auto& extension : config.rtp.extensions) { for (const auto& extension : config.rtp.extensions) {
if (extension.uri == RtpExtension::kAudioLevelUri) { if (extension.uri == RtpExtension::kAudioLevelUri) {
@ -91,11 +101,14 @@ AudioSendStream::AudioSendStream(
if (!SetupSendCodec()) { if (!SetupSendCodec()) {
LOG(LS_ERROR) << "Failed to set up send codec state."; LOG(LS_ERROR) << "Failed to set up send codec state.";
} }
pacer_thread_checker_.DetachFromThread();
} }
AudioSendStream::~AudioSendStream() { AudioSendStream::~AudioSendStream() {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString(); LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString();
send_side_cc_->DeRegisterPacketFeedbackObserver(this);
channel_proxy_->DeRegisterExternalTransport(); channel_proxy_->DeRegisterExternalTransport();
channel_proxy_->ResetCongestionControlObjects(); channel_proxy_->ResetCongestionControlObjects();
channel_proxy_->SetRtcEventLog(nullptr); channel_proxy_->SetRtcEventLog(nullptr);
@ -103,7 +116,7 @@ AudioSendStream::~AudioSendStream() {
} }
void AudioSendStream::Start() { void AudioSendStream::Start() {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
if (config_.min_bitrate_bps != -1 && config_.max_bitrate_bps != -1) { if (config_.min_bitrate_bps != -1 && config_.max_bitrate_bps != -1) {
RTC_DCHECK_GE(config_.max_bitrate_bps, config_.min_bitrate_bps); RTC_DCHECK_GE(config_.max_bitrate_bps, config_.min_bitrate_bps);
rtc::Event thread_sync_event(false /* manual_reset */, false); rtc::Event thread_sync_event(false /* manual_reset */, false);
@ -123,7 +136,7 @@ void AudioSendStream::Start() {
} }
void AudioSendStream::Stop() { void AudioSendStream::Stop() {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
rtc::Event thread_sync_event(false /* manual_reset */, false); rtc::Event thread_sync_event(false /* manual_reset */, false);
worker_queue_->PostTask([this, &thread_sync_event] { worker_queue_->PostTask([this, &thread_sync_event] {
bitrate_allocator_->RemoveObserver(this); bitrate_allocator_->RemoveObserver(this);
@ -141,19 +154,19 @@ void AudioSendStream::Stop() {
bool AudioSendStream::SendTelephoneEvent(int payload_type, bool AudioSendStream::SendTelephoneEvent(int payload_type,
int payload_frequency, int event, int payload_frequency, int event,
int duration_ms) { int duration_ms) {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
return channel_proxy_->SetSendTelephoneEventPayloadType(payload_type, return channel_proxy_->SetSendTelephoneEventPayloadType(payload_type,
payload_frequency) && payload_frequency) &&
channel_proxy_->SendTelephoneEventOutband(event, duration_ms); channel_proxy_->SendTelephoneEventOutband(event, duration_ms);
} }
void AudioSendStream::SetMuted(bool muted) { void AudioSendStream::SetMuted(bool muted) {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
channel_proxy_->SetInputMute(muted); channel_proxy_->SetInputMute(muted);
} }
webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const { webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
webrtc::AudioSendStream::Stats stats; webrtc::AudioSendStream::Stats stats;
stats.local_ssrc = config_.rtp.ssrc; stats.local_ssrc = config_.rtp.ssrc;
@ -217,14 +230,14 @@ webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
} }
void AudioSendStream::SignalNetworkState(NetworkState state) { void AudioSendStream::SignalNetworkState(NetworkState state) {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
} }
bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
// TODO(solenberg): Tests call this function on a network thread, libjingle // TODO(solenberg): Tests call this function on a network thread, libjingle
// calls on the worker thread. We should move towards always using a network // calls on the worker thread. We should move towards always using a network
// thread. Then this check can be enabled. // thread. Then this check can be enabled.
// RTC_DCHECK(!thread_checker_.CalledOnValidThread()); // RTC_DCHECK(!worker_thread_checker_.CalledOnValidThread());
return channel_proxy_->ReceivedRTCPPacket(packet, length); return channel_proxy_->ReceivedRTCPPacket(packet, length);
} }
@ -247,13 +260,43 @@ uint32_t AudioSendStream::OnBitrateUpdated(uint32_t bitrate_bps,
return 0; return 0;
} }
void AudioSendStream::OnPacketAdded(uint32_t ssrc, uint16_t seq_num) {
RTC_DCHECK(pacer_thread_checker_.CalledOnValidThread());
// Only packets that belong to this stream are of interest.
if (ssrc == config_.rtp.ssrc) {
rtc::CritScope lock(&packet_loss_tracker_cs_);
// TODO(elad.alon): This function call could potentially reset the window,
// setting both PLR and RPLR to unknown. Consider (during upcoming
// refactoring) passing an indication of such an event.
packet_loss_tracker_.OnPacketAdded(seq_num, rtc::TimeMillis());
}
}
void AudioSendStream::OnPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector) {
// TODO(elad.alon): This fails in UT; fix and uncomment.
// RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
rtc::Optional<float> plr;
{
rtc::CritScope lock(&packet_loss_tracker_cs_);
packet_loss_tracker_.OnPacketFeedbackVector(packet_feedback_vector);
plr = packet_loss_tracker_.GetPacketLossRate();
}
// TODO(elad.alon): If PLR goes back to unknown, no indication is given that
// the previously sent value is no longer relevant. This will be taken care
// of with some refactoring which is now being done.
if (plr) {
channel_proxy_->OnTwccBasedUplinkPacketLossRate(*plr);
}
}
const webrtc::AudioSendStream::Config& AudioSendStream::config() const { const webrtc::AudioSendStream::Config& AudioSendStream::config() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
return config_; return config_;
} }
void AudioSendStream::SetTransportOverhead(int transport_overhead_per_packet) { void AudioSendStream::SetTransportOverhead(int transport_overhead_per_packet) {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
send_side_cc_->SetTransportOverhead(transport_overhead_per_packet); send_side_cc_->SetTransportOverhead(transport_overhead_per_packet);
channel_proxy_->SetTransportOverhead(transport_overhead_per_packet); channel_proxy_->SetTransportOverhead(transport_overhead_per_packet);
} }

View File

@ -12,12 +12,15 @@
#define WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_ #define WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
#include <memory> #include <memory>
#include <vector>
#include "webrtc/base/constructormagic.h" #include "webrtc/base/constructormagic.h"
#include "webrtc/base/thread_checker.h" #include "webrtc/base/thread_checker.h"
#include "webrtc/call/audio_send_stream.h" #include "webrtc/call/audio_send_stream.h"
#include "webrtc/call/audio_state.h" #include "webrtc/call/audio_state.h"
#include "webrtc/call/bitrate_allocator.h" #include "webrtc/call/bitrate_allocator.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/voice_engine/transport_feedback_packet_loss_tracker.h"
namespace webrtc { namespace webrtc {
class SendSideCongestionController; class SendSideCongestionController;
@ -33,7 +36,8 @@ class ChannelProxy;
namespace internal { namespace internal {
class AudioSendStream final : public webrtc::AudioSendStream, class AudioSendStream final : public webrtc::AudioSendStream,
public webrtc::BitrateAllocatorObserver { public webrtc::BitrateAllocatorObserver,
public webrtc::PacketFeedbackObserver {
public: public:
AudioSendStream(const webrtc::AudioSendStream::Config& config, AudioSendStream(const webrtc::AudioSendStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state, const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
@ -62,6 +66,11 @@ class AudioSendStream final : public webrtc::AudioSendStream,
int64_t rtt, int64_t rtt,
int64_t probing_interval_ms) override; int64_t probing_interval_ms) override;
// From PacketFeedbackObserver.
void OnPacketAdded(uint32_t ssrc, uint16_t seq_num) override;
void OnPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector) override;
const webrtc::AudioSendStream::Config& config() const; const webrtc::AudioSendStream::Config& config() const;
void SetTransportOverhead(int transport_overhead_per_packet); void SetTransportOverhead(int transport_overhead_per_packet);
@ -70,7 +79,8 @@ class AudioSendStream final : public webrtc::AudioSendStream,
bool SetupSendCodec(); bool SetupSendCodec();
rtc::ThreadChecker thread_checker_; rtc::ThreadChecker worker_thread_checker_;
rtc::ThreadChecker pacer_thread_checker_;
rtc::TaskQueue* worker_queue_; rtc::TaskQueue* worker_queue_;
const webrtc::AudioSendStream::Config config_; const webrtc::AudioSendStream::Config config_;
rtc::scoped_refptr<webrtc::AudioState> audio_state_; rtc::scoped_refptr<webrtc::AudioState> audio_state_;
@ -80,6 +90,10 @@ class AudioSendStream final : public webrtc::AudioSendStream,
SendSideCongestionController* const send_side_cc_; SendSideCongestionController* const send_side_cc_;
std::unique_ptr<RtcpBandwidthObserver> bandwidth_observer_; std::unique_ptr<RtcpBandwidthObserver> bandwidth_observer_;
rtc::CriticalSection packet_loss_tracker_cs_;
TransportFeedbackPacketLossTracker packet_loss_tracker_
GUARDED_BY(&packet_loss_tracker_cs_);
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream); RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream);
}; };
} // namespace internal } // namespace internal

View File

@ -106,10 +106,11 @@ void CongestionController::Process() {
receive_side_cc_.Process(); receive_side_cc_.Process();
} }
void CongestionController::AddPacket(uint16_t sequence_number, void CongestionController::AddPacket(uint32_t ssrc,
uint16_t sequence_number,
size_t length, size_t length,
const PacedPacketInfo& pacing_info) { const PacedPacketInfo& pacing_info) {
send_side_cc_.AddPacket(sequence_number, length, pacing_info); send_side_cc_.AddPacket(ssrc, sequence_number, length, pacing_info);
} }
void CongestionController::OnTransportFeedback( void CongestionController::OnTransportFeedback(

View File

@ -79,7 +79,8 @@ class CongestionControllerTest : public ::testing::Test {
} }
void OnSentPacket(const PacketFeedback& packet_feedback) { void OnSentPacket(const PacketFeedback& packet_feedback) {
controller_->AddPacket(packet_feedback.sequence_number, constexpr uint32_t ssrc = 0;
controller_->AddPacket(ssrc, packet_feedback.sequence_number,
packet_feedback.payload_size, packet_feedback.payload_size,
packet_feedback.pacing_info); packet_feedback.pacing_info);
controller_->OnSentPacket(rtc::SentPacket(packet_feedback.sequence_number, controller_->OnSentPacket(rtc::SentPacket(packet_feedback.sequence_number,

View File

@ -119,7 +119,8 @@ class CongestionController : public CallStatsObserver,
void Process() override; void Process() override;
// Implements TransportFeedbackObserver. // Implements TransportFeedbackObserver.
void AddPacket(uint16_t sequence_number, void AddPacket(uint32_t ssrc,
uint16_t sequence_number,
size_t length, size_t length,
const PacedPacketInfo& pacing_info) override; const PacedPacketInfo& pacing_info) override;
void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override; void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override;

View File

@ -67,6 +67,9 @@ class SendSideCongestionController : public CallStatsObserver,
std::unique_ptr<PacedSender> pacer); std::unique_ptr<PacedSender> pacer);
virtual ~SendSideCongestionController(); virtual ~SendSideCongestionController();
void RegisterPacketFeedbackObserver(PacketFeedbackObserver* observer);
void DeRegisterPacketFeedbackObserver(PacketFeedbackObserver* observer);
virtual void SetBweBitrates(int min_bitrate_bps, virtual void SetBweBitrates(int min_bitrate_bps,
int start_bitrate_bps, int start_bitrate_bps,
int max_bitrate_bps); int max_bitrate_bps);
@ -111,7 +114,8 @@ class SendSideCongestionController : public CallStatsObserver,
void Process() override; void Process() override;
// Implements TransportFeedbackObserver. // Implements TransportFeedbackObserver.
void AddPacket(uint16_t sequence_number, void AddPacket(uint32_t ssrc,
uint16_t sequence_number,
size_t length, size_t length,
const PacedPacketInfo& pacing_info) override; const PacedPacketInfo& pacing_info) override;
void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override; void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override;

View File

@ -83,6 +83,16 @@ SendSideCongestionController::SendSideCongestionController(
SendSideCongestionController::~SendSideCongestionController() {} SendSideCongestionController::~SendSideCongestionController() {}
void SendSideCongestionController::RegisterPacketFeedbackObserver(
PacketFeedbackObserver* observer) {
transport_feedback_adapter_.RegisterPacketFeedbackObserver(observer);
}
void SendSideCongestionController::DeRegisterPacketFeedbackObserver(
PacketFeedbackObserver* observer) {
transport_feedback_adapter_.DeRegisterPacketFeedbackObserver(observer);
}
void SendSideCongestionController::SetBweBitrates(int min_bitrate_bps, void SendSideCongestionController::SetBweBitrates(int min_bitrate_bps,
int start_bitrate_bps, int start_bitrate_bps,
int max_bitrate_bps) { int max_bitrate_bps) {
@ -203,10 +213,12 @@ void SendSideCongestionController::Process() {
} }
void SendSideCongestionController::AddPacket( void SendSideCongestionController::AddPacket(
uint32_t ssrc,
uint16_t sequence_number, uint16_t sequence_number,
size_t length, size_t length,
const PacedPacketInfo& pacing_info) { const PacedPacketInfo& pacing_info) {
transport_feedback_adapter_.AddPacket(sequence_number, length, pacing_info); transport_feedback_adapter_.AddPacket(ssrc, sequence_number, length,
pacing_info);
} }
void SendSideCongestionController::OnTransportFeedback( void SendSideCongestionController::OnTransportFeedback(

View File

@ -36,11 +36,33 @@ TransportFeedbackAdapter::TransportFeedbackAdapter(const Clock* clock)
local_net_id_(0), local_net_id_(0),
remote_net_id_(0) {} remote_net_id_(0) {}
TransportFeedbackAdapter::~TransportFeedbackAdapter() {} TransportFeedbackAdapter::~TransportFeedbackAdapter() {
RTC_DCHECK(observers_.empty());
}
void TransportFeedbackAdapter::AddPacket(uint16_t sequence_number, void TransportFeedbackAdapter::RegisterPacketFeedbackObserver(
PacketFeedbackObserver* observer) {
rtc::CritScope cs(&observers_lock_);
RTC_DCHECK(observer);
RTC_DCHECK(std::find(observers_.begin(), observers_.end(), observer) ==
observers_.end());
observers_.push_back(observer);
}
void TransportFeedbackAdapter::DeRegisterPacketFeedbackObserver(
PacketFeedbackObserver* observer) {
rtc::CritScope cs(&observers_lock_);
RTC_DCHECK(observer);
const auto it = std::find(observers_.begin(), observers_.end(), observer);
RTC_DCHECK(it != observers_.end());
observers_.erase(it);
}
void TransportFeedbackAdapter::AddPacket(uint32_t ssrc,
uint16_t sequence_number,
size_t length, size_t length,
const PacedPacketInfo& pacing_info) { const PacedPacketInfo& pacing_info) {
{
rtc::CritScope cs(&lock_); rtc::CritScope cs(&lock_);
if (send_side_bwe_with_overhead_) { if (send_side_bwe_with_overhead_) {
length += transport_overhead_bytes_per_packet_; length += transport_overhead_bytes_per_packet_;
@ -51,6 +73,14 @@ void TransportFeedbackAdapter::AddPacket(uint16_t sequence_number,
remote_net_id_, pacing_info)); remote_net_id_, pacing_info));
} }
{
rtc::CritScope cs(&observers_lock_);
for (auto observer : observers_) {
observer->OnPacketAdded(ssrc, sequence_number);
}
}
}
void TransportFeedbackAdapter::OnSentPacket(uint16_t sequence_number, void TransportFeedbackAdapter::OnSentPacket(uint16_t sequence_number,
int64_t send_time_ms) { int64_t send_time_ms) {
rtc::CritScope cs(&lock_); rtc::CritScope cs(&lock_);
@ -154,6 +184,12 @@ std::vector<PacketFeedback> TransportFeedbackAdapter::GetPacketFeedbackVector(
void TransportFeedbackAdapter::OnTransportFeedback( void TransportFeedbackAdapter::OnTransportFeedback(
const rtcp::TransportFeedback& feedback) { const rtcp::TransportFeedback& feedback) {
last_packet_feedback_vector_ = GetPacketFeedbackVector(feedback); last_packet_feedback_vector_ = GetPacketFeedbackVector(feedback);
{
rtc::CritScope cs(&observers_lock_);
for (auto observer : observers_) {
observer->OnPacketFeedbackVector(last_packet_feedback_vector_);
}
}
} }
std::vector<PacketFeedback> std::vector<PacketFeedback>

View File

@ -21,6 +21,8 @@
namespace webrtc { namespace webrtc {
class PacketFeedbackObserver;
namespace rtcp { namespace rtcp {
class TransportFeedback; class TransportFeedback;
} // namespace rtcp } // namespace rtcp
@ -30,7 +32,11 @@ class TransportFeedbackAdapter {
explicit TransportFeedbackAdapter(const Clock* clock); explicit TransportFeedbackAdapter(const Clock* clock);
virtual ~TransportFeedbackAdapter(); virtual ~TransportFeedbackAdapter();
void AddPacket(uint16_t sequence_number, void RegisterPacketFeedbackObserver(PacketFeedbackObserver* observer);
void DeRegisterPacketFeedbackObserver(PacketFeedbackObserver* observer);
void AddPacket(uint32_t ssrc,
uint16_t sequence_number,
size_t length, size_t length,
const PacedPacketInfo& pacing_info); const PacedPacketInfo& pacing_info);
void OnSentPacket(uint16_t sequence_number, int64_t send_time_ms); void OnSentPacket(uint16_t sequence_number, int64_t send_time_ms);
@ -57,8 +63,11 @@ class TransportFeedbackAdapter {
int64_t current_offset_ms_; int64_t current_offset_ms_;
int64_t last_timestamp_us_; int64_t last_timestamp_us_;
std::vector<PacketFeedback> last_packet_feedback_vector_; std::vector<PacketFeedback> last_packet_feedback_vector_;
uint16_t local_net_id_; uint16_t local_net_id_ GUARDED_BY(&lock_);
uint16_t remote_net_id_; uint16_t remote_net_id_ GUARDED_BY(&lock_);
rtc::CriticalSection observers_lock_;
std::vector<PacketFeedbackObserver*> observers_ GUARDED_BY(&observers_lock_);
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -38,6 +38,13 @@ const PacedPacketInfo kPacingInfo4(4, 22, 10000);
namespace test { namespace test {
class MockPacketFeedbackObserver : public webrtc::PacketFeedbackObserver {
public:
MOCK_METHOD2(OnPacketAdded, void(uint32_t ssrc, uint16_t seq_num));
MOCK_METHOD1(OnPacketFeedbackVector,
void(const std::vector<PacketFeedback>& packet_feedback_vector));
};
class TransportFeedbackAdapterTest : public ::testing::Test { class TransportFeedbackAdapterTest : public ::testing::Test {
public: public:
TransportFeedbackAdapterTest() : clock_(0) {} TransportFeedbackAdapterTest() : clock_(0) {}
@ -58,17 +65,75 @@ class TransportFeedbackAdapterTest : public ::testing::Test {
int64_t now_ms) {} int64_t now_ms) {}
void OnSentPacket(const PacketFeedback& packet_feedback) { void OnSentPacket(const PacketFeedback& packet_feedback) {
adapter_->AddPacket(packet_feedback.sequence_number, adapter_->AddPacket(kSsrc, packet_feedback.sequence_number,
packet_feedback.payload_size, packet_feedback.payload_size,
packet_feedback.pacing_info); packet_feedback.pacing_info);
adapter_->OnSentPacket(packet_feedback.sequence_number, adapter_->OnSentPacket(packet_feedback.sequence_number,
packet_feedback.send_time_ms); packet_feedback.send_time_ms);
} }
static constexpr uint32_t kSsrc = 8492;
SimulatedClock clock_; SimulatedClock clock_;
std::unique_ptr<TransportFeedbackAdapter> adapter_; std::unique_ptr<TransportFeedbackAdapter> adapter_;
}; };
TEST_F(TransportFeedbackAdapterTest, ObserverSanity) {
MockPacketFeedbackObserver mock;
adapter_->RegisterPacketFeedbackObserver(&mock);
const std::vector<PacketFeedback> packets = {
PacketFeedback(100, 200, 0, 1000, kPacingInfo0),
PacketFeedback(110, 210, 1, 2000, kPacingInfo0),
PacketFeedback(120, 220, 2, 3000, kPacingInfo0)
};
rtcp::TransportFeedback feedback;
feedback.SetBase(packets[0].sequence_number,
packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : packets) {
EXPECT_CALL(mock, OnPacketAdded(kSsrc, packet.sequence_number)).Times(1);
OnSentPacket(packet);
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
EXPECT_CALL(mock, OnPacketFeedbackVector(_)).Times(1);
adapter_->OnTransportFeedback(feedback);
adapter_->DeRegisterPacketFeedbackObserver(&mock);
// After deregistration, the observer no longers gets indications.
EXPECT_CALL(mock, OnPacketAdded(_, _)).Times(0);
const PacketFeedback new_packet(130, 230, 3, 4000, kPacingInfo0);
OnSentPacket(new_packet);
rtcp::TransportFeedback second_feedback;
second_feedback.SetBase(new_packet.sequence_number,
new_packet.arrival_time_ms * 1000);
EXPECT_TRUE(feedback.AddReceivedPacket(new_packet.sequence_number,
new_packet.arrival_time_ms * 1000));
EXPECT_CALL(mock, OnPacketFeedbackVector(_)).Times(0);
adapter_->OnTransportFeedback(second_feedback);
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(TransportFeedbackAdapterTest, ObserverDoubleRegistrationDeathTest) {
MockPacketFeedbackObserver mock;
adapter_->RegisterPacketFeedbackObserver(&mock);
EXPECT_DEATH(adapter_->RegisterPacketFeedbackObserver(&mock), "");
adapter_->DeRegisterPacketFeedbackObserver(&mock);
}
TEST_F(TransportFeedbackAdapterTest, ObserverMissingDeRegistrationDeathTest) {
MockPacketFeedbackObserver mock;
adapter_->RegisterPacketFeedbackObserver(&mock);
EXPECT_DEATH(adapter_.reset(), "");
adapter_->DeRegisterPacketFeedbackObserver(&mock);
}
#endif
TEST_F(TransportFeedbackAdapterTest, AdaptsFeedbackAndPopulatesSendTimes) { TEST_F(TransportFeedbackAdapterTest, AdaptsFeedbackAndPopulatesSendTimes) {
std::vector<PacketFeedback> packets; std::vector<PacketFeedback> packets;
packets.push_back(PacketFeedback(100, 200, 0, 1500, kPacingInfo0)); packets.push_back(PacketFeedback(100, 200, 0, 1500, kPacingInfo0));

View File

@ -342,7 +342,8 @@ class TransportFeedbackObserver {
virtual ~TransportFeedbackObserver() {} virtual ~TransportFeedbackObserver() {}
// Note: Transport-wide sequence number as sequence number. // Note: Transport-wide sequence number as sequence number.
virtual void AddPacket(uint16_t sequence_number, virtual void AddPacket(uint32_t ssrc,
uint16_t sequence_number,
size_t length, size_t length,
const PacedPacketInfo& pacing_info) = 0; const PacedPacketInfo& pacing_info) = 0;
@ -351,6 +352,15 @@ class TransportFeedbackObserver {
virtual std::vector<PacketFeedback> GetTransportFeedbackVector() const = 0; virtual std::vector<PacketFeedback> GetTransportFeedbackVector() const = 0;
}; };
class PacketFeedbackObserver {
public:
virtual ~PacketFeedbackObserver() = default;
virtual void OnPacketAdded(uint32_t ssrc, uint16_t seq_num) = 0;
virtual void OnPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector) = 0;
};
class RtcpRttStats { class RtcpRttStats {
public: public:
virtual void OnRttUpdate(int64_t rtt) = 0; virtual void OnRttUpdate(int64_t rtt) = 0;

View File

@ -73,8 +73,9 @@ class MockRtcpCallbackImpl : public RtcpStatisticsCallback {
class MockTransportFeedbackObserver : public TransportFeedbackObserver { class MockTransportFeedbackObserver : public TransportFeedbackObserver {
public: public:
MOCK_METHOD2(AddPacket, void(uint16_t, size_t)); MOCK_METHOD3(AddPacket, void(uint32_t, uint16_t, size_t));
MOCK_METHOD3(AddPacket, void(uint16_t, size_t, const PacedPacketInfo&)); MOCK_METHOD4(AddPacket,
void(uint32_t, uint16_t, size_t, const PacedPacketInfo&));
MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&)); MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&));
MOCK_CONST_METHOD0(GetTransportFeedbackVector, std::vector<PacketFeedback>()); MOCK_CONST_METHOD0(GetTransportFeedbackVector, std::vector<PacketFeedback>());
}; };

View File

@ -1256,7 +1256,7 @@ void RTPSender::AddPacketToTransportFeedback(
} }
if (transport_feedback_observer_) { if (transport_feedback_observer_) {
transport_feedback_observer_->AddPacket(packet_id, packet_size, transport_feedback_observer_->AddPacket(SSRC(), packet_id, packet_size,
pacing_info); pacing_info);
} }
} }

View File

@ -126,7 +126,8 @@ class MockSendPacketObserver : public SendPacketObserver {
class MockTransportFeedbackObserver : public TransportFeedbackObserver { class MockTransportFeedbackObserver : public TransportFeedbackObserver {
public: public:
MOCK_METHOD3(AddPacket, void(uint16_t, size_t, const PacedPacketInfo&)); MOCK_METHOD4(AddPacket,
void(uint32_t, uint16_t, size_t, const PacedPacketInfo&));
MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&)); MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&));
MOCK_CONST_METHOD0(GetTransportFeedbackVector, std::vector<PacketFeedback>()); MOCK_CONST_METHOD0(GetTransportFeedbackVector, std::vector<PacketFeedback>());
}; };
@ -355,7 +356,7 @@ TEST_F(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) {
.Times(1); .Times(1);
EXPECT_CALL( EXPECT_CALL(
feedback_observer_, feedback_observer_,
AddPacket(kTransportSequenceNumber, AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber,
sizeof(kPayloadData) + kGenericHeaderLength, PacedPacketInfo())) sizeof(kPayloadData) + kGenericHeaderLength, PacedPacketInfo()))
.Times(1); .Times(1);
@ -406,7 +407,7 @@ TEST_F(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) {
.Times(1); .Times(1);
EXPECT_CALL( EXPECT_CALL(
feedback_observer_, feedback_observer_,
AddPacket(kTransportSequenceNumber, AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber,
sizeof(kPayloadData) + kGenericHeaderLength, PacedPacketInfo())) sizeof(kPayloadData) + kGenericHeaderLength, PacedPacketInfo()))
.Times(1); .Times(1);
@ -1487,7 +1488,7 @@ TEST_F(RtpSenderTest, AddOverheadToTransportFeedbackObserver) {
EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber()) EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
.WillOnce(testing::Return(kTransportSequenceNumber)); .WillOnce(testing::Return(kTransportSequenceNumber));
EXPECT_CALL(feedback_observer_, EXPECT_CALL(feedback_observer_,
AddPacket(kTransportSequenceNumber, AddPacket(rtp_sender_->SSRC(), kTransportSequenceNumber,
sizeof(kPayloadData) + kGenericHeaderLength + sizeof(kPayloadData) + kGenericHeaderLength +
kRtpOverheadBytesPerPacket, kRtpOverheadBytesPerPacket,
PacedPacketInfo())) PacedPacketInfo()))

View File

@ -245,7 +245,7 @@ bool FuzzTransportFeedbackBlock(
if (!may_continue) { if (!may_continue) {
return false; return false;
} }
tracker->OnNewTransportFeedbackVector(feedback_vector); tracker->OnPacketFeedbackVector(feedback_vector);
tracker->Validate(); tracker->Validate();
} }

View File

@ -87,6 +87,7 @@ class MockVoEChannelProxy : public voe::ChannelProxy {
MOCK_METHOD1(SetSendCodec, bool(const CodecInst& codec_inst)); MOCK_METHOD1(SetSendCodec, bool(const CodecInst& codec_inst));
MOCK_METHOD2(SetSendCNPayloadType, MOCK_METHOD2(SetSendCNPayloadType,
bool(int type, PayloadFrequencies frequency)); bool(int type, PayloadFrequencies frequency));
MOCK_METHOD1(OnTwccBasedUplinkPacketLossRate, void(float packet_loss_rate));
}; };
} // namespace test } // namespace test
} // namespace webrtc } // namespace webrtc

View File

@ -1070,7 +1070,8 @@ void EventLogAnalyzer::CreateBweSimulationGraph(Plot* plot) {
const LoggedRtpPacket& rtp = *rtp_iterator->second; const LoggedRtpPacket& rtp = *rtp_iterator->second;
if (rtp.header.extension.hasTransportSequenceNumber) { if (rtp.header.extension.hasTransportSequenceNumber) {
RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber); RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber);
cc.AddPacket(rtp.header.extension.transportSequenceNumber, cc.AddPacket(rtp.header.ssrc,
rtp.header.extension.transportSequenceNumber,
rtp.total_length, PacedPacketInfo()); rtp.total_length, PacedPacketInfo());
rtc::SentPacket sent_packet( rtc::SentPacket sent_packet(
rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000); rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000);
@ -1169,7 +1170,8 @@ void EventLogAnalyzer::CreateNetworkDelayFeedbackGraph(Plot* plot) {
const LoggedRtpPacket& rtp = *rtp_iterator->second; const LoggedRtpPacket& rtp = *rtp_iterator->second;
if (rtp.header.extension.hasTransportSequenceNumber) { if (rtp.header.extension.hasTransportSequenceNumber) {
RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber); RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber);
feedback_adapter.AddPacket(rtp.header.extension.transportSequenceNumber, feedback_adapter.AddPacket(rtp.header.ssrc,
rtp.header.extension.transportSequenceNumber,
rtp.total_length, PacedPacketInfo()); rtp.total_length, PacedPacketInfo());
feedback_adapter.OnSentPacket( feedback_adapter.OnSentPacket(
rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000); rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000);

View File

@ -246,13 +246,14 @@ class TransportFeedbackProxy : public TransportFeedbackObserver {
} }
// Implements TransportFeedbackObserver. // Implements TransportFeedbackObserver.
void AddPacket(uint16_t sequence_number, void AddPacket(uint32_t ssrc,
uint16_t sequence_number,
size_t length, size_t length,
const PacedPacketInfo& pacing_info) override { const PacedPacketInfo& pacing_info) override {
RTC_DCHECK(pacer_thread_.CalledOnValidThread()); RTC_DCHECK(pacer_thread_.CalledOnValidThread());
rtc::CritScope lock(&crit_); rtc::CritScope lock(&crit_);
if (feedback_observer_) if (feedback_observer_)
feedback_observer_->AddPacket(sequence_number, length, pacing_info); feedback_observer_->AddPacket(ssrc, sequence_number, length, pacing_info);
} }
void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override { void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override {
@ -395,7 +396,7 @@ class VoERtcpObserver : public RtcpBandwidthObserver {
(fraction_lost_aggregate + total_number_of_packets / 2) / (fraction_lost_aggregate + total_number_of_packets / 2) /
total_number_of_packets; total_number_of_packets;
} }
owner_->OnIncomingFractionLoss(weighted_fraction_lost); owner_->OnUplinkPacketLossRate(weighted_fraction_lost / 255.0f);
} }
private: private:
@ -902,7 +903,9 @@ Channel::Channel(int32_t channelId,
rtp_packet_sender_proxy_(new RtpPacketSenderProxy()), rtp_packet_sender_proxy_(new RtpPacketSenderProxy()),
retransmission_rate_limiter_(new RateLimiter(Clock::GetRealTimeClock(), retransmission_rate_limiter_(new RateLimiter(Clock::GetRealTimeClock(),
kMaxRetransmissionWindowMs)), kMaxRetransmissionWindowMs)),
decoder_factory_(config.acm_config.decoder_factory) { decoder_factory_(config.acm_config.decoder_factory),
// TODO(elad.alon): Subsequent CL experiments with PLR source.
use_twcc_plr_for_ana_(false) {
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, _channelId), WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, _channelId),
"Channel::Channel() - ctor"); "Channel::Channel() - ctor");
AudioCodingModule::Config acm_config(config.acm_config); AudioCodingModule::Config acm_config(config.acm_config);
@ -1301,10 +1304,23 @@ void Channel::SetBitRate(int bitrate_bps, int64_t probing_interval_ms) {
retransmission_rate_limiter_->SetMaxRate(bitrate_bps); retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
} }
void Channel::OnIncomingFractionLoss(int fraction_lost) { void Channel::OnTwccBasedUplinkPacketLossRate(float packet_loss_rate) {
if (!use_twcc_plr_for_ana_)
return;
audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) { audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
if (*encoder) if (*encoder) {
(*encoder)->OnReceivedUplinkPacketLossFraction(fraction_lost / 255.0f); (*encoder)->OnReceivedUplinkPacketLossFraction(packet_loss_rate);
}
});
}
void Channel::OnUplinkPacketLossRate(float packet_loss_rate) {
if (use_twcc_plr_for_ana_)
return;
audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
if (*encoder) {
(*encoder)->OnReceivedUplinkPacketLossFraction(packet_loss_rate);
}
}); });
} }

View File

@ -378,10 +378,15 @@ class Channel
// From OverheadObserver in the RTP/RTCP module // From OverheadObserver in the RTP/RTCP module
void OnOverheadChanged(size_t overhead_bytes_per_packet) override; void OnOverheadChanged(size_t overhead_bytes_per_packet) override;
protected: // The existence of this function alongside OnUplinkPacketLossRate is
void OnIncomingFractionLoss(int fraction_lost); // a compromise. We want the encoder to be agnostic of the PLR source, but
// we also don't want it to receive conflicting information from TWCC and
// from RTCP-XR.
void OnTwccBasedUplinkPacketLossRate(float packet_loss_rate);
private: private:
void OnUplinkPacketLossRate(float packet_loss_rate);
bool InputMute() const; bool InputMute() const;
bool OnRtpPacketWithHeader(const uint8_t* received_packet, bool OnRtpPacketWithHeader(const uint8_t* received_packet,
size_t length, size_t length,
@ -508,6 +513,8 @@ class Channel
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_; rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
rtc::ThreadChecker construction_thread_; rtc::ThreadChecker construction_thread_;
const bool use_twcc_plr_for_ana_;
}; };
} // namespace voe } // namespace voe

View File

@ -367,6 +367,11 @@ bool ChannelProxy::SetSendCNPayloadType(int type,
return channel()->SetSendCNPayloadType(type, frequency) == 0; return channel()->SetSendCNPayloadType(type, frequency) == 0;
} }
void ChannelProxy::OnTwccBasedUplinkPacketLossRate(float packet_loss_rate) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
channel()->OnTwccBasedUplinkPacketLossRate(packet_loss_rate);
}
Channel* ChannelProxy::channel() const { Channel* ChannelProxy::channel() const {
RTC_DCHECK(channel_owner_.channel()); RTC_DCHECK(channel_owner_.channel());
return channel_owner_.channel(); return channel_owner_.channel();

View File

@ -116,6 +116,7 @@ class ChannelProxy {
virtual bool SetOpusMaxPlaybackRate(int frequency_hz); virtual bool SetOpusMaxPlaybackRate(int frequency_hz);
virtual bool SetSendCodec(const CodecInst& codec_inst); virtual bool SetSendCodec(const CodecInst& codec_inst);
virtual bool SetSendCNPayloadType(int type, PayloadFrequencies frequency); virtual bool SetSendCNPayloadType(int type, PayloadFrequencies frequency);
virtual void OnTwccBasedUplinkPacketLossRate(float packet_loss_rate);
private: private:
Channel* channel() const; Channel* channel() const;

View File

@ -98,7 +98,7 @@ void TransportFeedbackPacketLossTracker::OnPacketAdded(uint16_t seq_num,
} }
} }
void TransportFeedbackPacketLossTracker::OnNewTransportFeedbackVector( void TransportFeedbackPacketLossTracker::OnPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector) { const std::vector<PacketFeedback>& packet_feedback_vector) {
for (const PacketFeedback& packet : packet_feedback_vector) { for (const PacketFeedback& packet : packet_feedback_vector) {
const auto& it = packet_status_window_.find(packet.sequence_number); const auto& it = packet_status_window_.find(packet.sequence_number);

View File

@ -38,7 +38,7 @@ class TransportFeedbackPacketLossTracker final {
void OnPacketAdded(uint16_t seq_num, int64_t send_time_ms); void OnPacketAdded(uint16_t seq_num, int64_t send_time_ms);
void OnNewTransportFeedbackVector( void OnPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedbacks_vector); const std::vector<PacketFeedback>& packet_feedbacks_vector);
// Returns the packet loss rate, if the window has enough packet statuses to // Returns the packet loss rate, if the window has enough packet statuses to

View File

@ -86,7 +86,7 @@ class TransportFeedbackPacketLossTrackerTest
++seq_num; ++seq_num;
} }
tracker->OnNewTransportFeedbackVector(packet_feedback_vector); tracker->OnPacketFeedbackVector(packet_feedback_vector);
tracker->Validate(); tracker->Validate();
} }