Add histogram stats for average send delay of sent packets for a sent video stream. The delay is measured from a packet is sent to the transport until leaving the socket.
- "WebRTC.Video.SendDelayInMs" Change so that PacketOption packet id is always set in RtpSender (if having a TransportSequenceNumberAllocator). Add SendDelayStats class for computing delays. Add SendPacketObserver to RtpRtcp config and register SendDelayStats as observer. Wire up OnSentPacket to SendDelayStats. BUG=webrtc:5215 Review-Url: https://codereview.webrtc.org/1478253002 Cr-Commit-Position: refs/heads/master@{#12600}
This commit is contained in:
parent
5a2463796e
commit
35151f35ec
@ -40,6 +40,7 @@
|
||||
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/video/call_stats.h"
|
||||
#include "webrtc/video/send_delay_stats.h"
|
||||
#include "webrtc/video/video_receive_stream.h"
|
||||
#include "webrtc/video/video_send_stream.h"
|
||||
#include "webrtc/video/vie_remb.h"
|
||||
@ -177,6 +178,7 @@ class Call : public webrtc::Call, public PacketReceiver,
|
||||
|
||||
VieRemb remb_;
|
||||
const std::unique_ptr<CongestionController> congestion_controller_;
|
||||
const std::unique_ptr<SendDelayStats> video_send_delay_stats_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Call);
|
||||
};
|
||||
@ -210,7 +212,8 @@ Call::Call(const Call::Config& config)
|
||||
pacer_bitrate_sum_kbits_(0),
|
||||
num_bitrate_updates_(0),
|
||||
remb_(clock_),
|
||||
congestion_controller_(new CongestionController(clock_, this, &remb_)) {
|
||||
congestion_controller_(new CongestionController(clock_, this, &remb_)),
|
||||
video_send_delay_stats_(new SendDelayStats(clock_)) {
|
||||
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK_GE(config.bitrate_config.min_bitrate_bps, 0);
|
||||
RTC_DCHECK_GE(config.bitrate_config.start_bitrate_bps,
|
||||
@ -403,12 +406,14 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream(
|
||||
TRACE_EVENT0("webrtc", "Call::CreateVideoSendStream");
|
||||
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
|
||||
|
||||
video_send_delay_stats_->AddSsrcs(config);
|
||||
// TODO(mflodman): Base the start bitrate on a current bandwidth estimate, if
|
||||
// the call has already started.
|
||||
VideoSendStream* send_stream = new VideoSendStream(
|
||||
num_cpu_cores_, module_process_thread_.get(), call_stats_.get(),
|
||||
congestion_controller_.get(), bitrate_allocator_.get(), &remb_, config,
|
||||
encoder_config, suspended_video_send_ssrcs_);
|
||||
congestion_controller_.get(), bitrate_allocator_.get(),
|
||||
video_send_delay_stats_.get(), &remb_, config, encoder_config,
|
||||
suspended_video_send_ssrcs_);
|
||||
{
|
||||
WriteLockScoped write_lock(*send_crit_);
|
||||
for (uint32_t ssrc : config.rtp.ssrcs) {
|
||||
@ -661,6 +666,8 @@ void Call::UpdateAggregateNetworkState() {
|
||||
void Call::OnSentPacket(const rtc::SentPacket& sent_packet) {
|
||||
if (first_packet_sent_ms_ == -1)
|
||||
first_packet_sent_ms_ = clock_->TimeInMilliseconds();
|
||||
video_send_delay_stats_->OnSentPacket(sent_packet.packet_id,
|
||||
clock_->TimeInMilliseconds());
|
||||
congestion_controller_->OnSentPacket(sent_packet);
|
||||
}
|
||||
|
||||
|
||||
@ -319,7 +319,8 @@ size_t GenerateRtpPacket(uint32_t extensions_bitvector,
|
||||
nullptr, // BitrateStatisticsObserver*
|
||||
nullptr, // FrameCountObserver*
|
||||
nullptr, // SendSideDelayObserver*
|
||||
nullptr); // RtcEventLog*
|
||||
nullptr, // RtcEventLog*
|
||||
nullptr); // SendPacketObserver*
|
||||
|
||||
std::vector<uint32_t> csrcs;
|
||||
for (unsigned i = 0; i < csrcs_count; i++) {
|
||||
|
||||
@ -296,6 +296,18 @@ class SendSideDelayObserver {
|
||||
uint32_t ssrc) = 0;
|
||||
};
|
||||
|
||||
// Callback, used to notify an observer whenever a packet is sent to the
|
||||
// transport.
|
||||
// TODO(asapersson): This class will remove the need for SendSideDelayObserver.
|
||||
// Remove SendSideDelayObserver once possible.
|
||||
class SendPacketObserver {
|
||||
public:
|
||||
virtual ~SendPacketObserver() {}
|
||||
virtual void OnSendPacket(uint16_t packet_id,
|
||||
int64_t capture_time_ms,
|
||||
uint32_t ssrc) = 0;
|
||||
};
|
||||
|
||||
// ==================================================================
|
||||
// Voice specific types
|
||||
// ==================================================================
|
||||
|
||||
@ -78,7 +78,7 @@ class RtpRtcp : public Module {
|
||||
FrameCountObserver* send_frame_count_observer;
|
||||
SendSideDelayObserver* send_side_delay_observer;
|
||||
RtcEventLog* event_log;
|
||||
|
||||
SendPacketObserver* send_packet_observer;
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Configuration);
|
||||
};
|
||||
|
||||
|
||||
@ -60,7 +60,8 @@ RtpRtcp::Configuration::Configuration()
|
||||
send_bitrate_observer(nullptr),
|
||||
send_frame_count_observer(nullptr),
|
||||
send_side_delay_observer(nullptr),
|
||||
event_log(nullptr) {}
|
||||
event_log(nullptr),
|
||||
send_packet_observer(nullptr) {}
|
||||
|
||||
RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) {
|
||||
if (configuration.clock) {
|
||||
@ -85,7 +86,8 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
|
||||
configuration.send_bitrate_observer,
|
||||
configuration.send_frame_count_observer,
|
||||
configuration.send_side_delay_observer,
|
||||
configuration.event_log),
|
||||
configuration.event_log,
|
||||
configuration.send_packet_observer),
|
||||
rtcp_sender_(configuration.audio,
|
||||
configuration.clock,
|
||||
configuration.receive_statistics,
|
||||
@ -105,7 +107,7 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
|
||||
last_process_time_(configuration.clock->TimeInMilliseconds()),
|
||||
last_bitrate_process_time_(configuration.clock->TimeInMilliseconds()),
|
||||
last_rtt_process_time_(configuration.clock->TimeInMilliseconds()),
|
||||
packet_overhead_(28), // IPV4 UDP.
|
||||
packet_overhead_(28), // IPV4 UDP.
|
||||
nack_last_time_sent_full_(0),
|
||||
nack_last_time_sent_full_prev_(0),
|
||||
nack_last_seq_number_sent_(0),
|
||||
|
||||
@ -113,7 +113,8 @@ RTPSender::RTPSender(
|
||||
BitrateStatisticsObserver* bitrate_callback,
|
||||
FrameCountObserver* frame_count_observer,
|
||||
SendSideDelayObserver* send_side_delay_observer,
|
||||
RtcEventLog* event_log)
|
||||
RtcEventLog* event_log,
|
||||
SendPacketObserver* send_packet_observer)
|
||||
: clock_(clock),
|
||||
// TODO(holmer): Remove this conversion when we remove the use of
|
||||
// TickTime.
|
||||
@ -150,6 +151,7 @@ RTPSender::RTPSender(
|
||||
frame_count_observer_(frame_count_observer),
|
||||
send_side_delay_observer_(send_side_delay_observer),
|
||||
event_log_(event_log),
|
||||
send_packet_observer_(send_packet_observer),
|
||||
// RTP variables
|
||||
start_timestamp_forced_(false),
|
||||
start_timestamp_(0),
|
||||
@ -672,13 +674,13 @@ size_t RTPSender::SendPadData(size_t bytes,
|
||||
UpdateAbsoluteSendTime(padding_packet, length, rtp_header, now_ms);
|
||||
|
||||
PacketOptions options;
|
||||
if (using_transport_seq) {
|
||||
options.packet_id =
|
||||
UpdateTransportSequenceNumber(padding_packet, length, rtp_header);
|
||||
}
|
||||
|
||||
if (using_transport_seq && transport_feedback_observer_) {
|
||||
transport_feedback_observer_->AddPacket(options.packet_id, length, true);
|
||||
if (AllocateTransportSequenceNumber(&options.packet_id)) {
|
||||
if (UpdateTransportSequenceNumber(options.packet_id, padding_packet,
|
||||
length, rtp_header)) {
|
||||
if (transport_feedback_observer_)
|
||||
transport_feedback_observer_->AddPacket(options.packet_id, length,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!SendPacketToNetwork(padding_packet, length, options))
|
||||
@ -883,9 +885,7 @@ bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
|
||||
// Packet cannot be found. Allow sending to continue.
|
||||
return true;
|
||||
}
|
||||
if (!retransmission && capture_time_ms > 0) {
|
||||
UpdateDelayStatistics(capture_time_ms, clock_->TimeInMilliseconds());
|
||||
}
|
||||
|
||||
int rtx;
|
||||
{
|
||||
rtc::CritScope lock(&send_critsect_);
|
||||
@ -929,19 +929,19 @@ bool RTPSender::PrepareAndSendPacket(uint8_t* buffer,
|
||||
diff_ms);
|
||||
UpdateAbsoluteSendTime(buffer_to_send_ptr, length, rtp_header, now_ms);
|
||||
|
||||
// TODO(sprang): Potentially too much overhead in IsRegistered()?
|
||||
bool using_transport_seq = rtp_header_extension_map_.IsRegistered(
|
||||
kRtpExtensionTransportSequenceNumber) &&
|
||||
transport_sequence_number_allocator_;
|
||||
|
||||
PacketOptions options;
|
||||
if (using_transport_seq) {
|
||||
options.packet_id =
|
||||
UpdateTransportSequenceNumber(buffer_to_send_ptr, length, rtp_header);
|
||||
if (AllocateTransportSequenceNumber(&options.packet_id)) {
|
||||
if (UpdateTransportSequenceNumber(options.packet_id, buffer_to_send_ptr,
|
||||
length, rtp_header)) {
|
||||
if (transport_feedback_observer_)
|
||||
transport_feedback_observer_->AddPacket(options.packet_id, length,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
if (using_transport_seq && transport_feedback_observer_) {
|
||||
transport_feedback_observer_->AddPacket(options.packet_id, length, true);
|
||||
if (!is_retransmit && !send_over_rtx) {
|
||||
UpdateDelayStatistics(capture_time_ms, now_ms);
|
||||
UpdateOnSendPacket(options.packet_id, capture_time_ms, rtp_header.ssrc);
|
||||
}
|
||||
|
||||
bool ret = SendPacketToNetwork(buffer_to_send_ptr, length, options);
|
||||
@ -1058,23 +1058,18 @@ int32_t RTPSender::SendToNetwork(uint8_t* buffer,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (capture_time_ms > 0) {
|
||||
UpdateDelayStatistics(capture_time_ms, now_ms);
|
||||
}
|
||||
|
||||
// TODO(sprang): Potentially too much overhead in IsRegistered()?
|
||||
bool using_transport_seq = rtp_header_extension_map_.IsRegistered(
|
||||
kRtpExtensionTransportSequenceNumber) &&
|
||||
transport_sequence_number_allocator_;
|
||||
|
||||
PacketOptions options;
|
||||
if (using_transport_seq) {
|
||||
options.packet_id =
|
||||
UpdateTransportSequenceNumber(buffer, length, rtp_header);
|
||||
if (transport_feedback_observer_) {
|
||||
transport_feedback_observer_->AddPacket(options.packet_id, length, true);
|
||||
if (AllocateTransportSequenceNumber(&options.packet_id)) {
|
||||
if (UpdateTransportSequenceNumber(options.packet_id, buffer, length,
|
||||
rtp_header)) {
|
||||
if (transport_feedback_observer_)
|
||||
transport_feedback_observer_->AddPacket(options.packet_id, length,
|
||||
true);
|
||||
}
|
||||
}
|
||||
UpdateDelayStatistics(capture_time_ms, now_ms);
|
||||
UpdateOnSendPacket(options.packet_id, capture_time_ms, rtp_header.ssrc);
|
||||
|
||||
bool sent = SendPacketToNetwork(buffer, length, options);
|
||||
|
||||
@ -1095,7 +1090,7 @@ int32_t RTPSender::SendToNetwork(uint8_t* buffer,
|
||||
}
|
||||
|
||||
void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
|
||||
if (!send_side_delay_observer_)
|
||||
if (!send_side_delay_observer_ || capture_time_ms <= 0)
|
||||
return;
|
||||
|
||||
uint32_t ssrc;
|
||||
@ -1127,6 +1122,15 @@ void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
|
||||
ssrc);
|
||||
}
|
||||
|
||||
void RTPSender::UpdateOnSendPacket(int packet_id,
|
||||
int64_t capture_time_ms,
|
||||
uint32_t ssrc) {
|
||||
if (!send_packet_observer_ || capture_time_ms <= 0 || packet_id == -1)
|
||||
return;
|
||||
|
||||
send_packet_observer_->OnSendPacket(packet_id, capture_time_ms, ssrc);
|
||||
}
|
||||
|
||||
void RTPSender::ProcessBitrate() {
|
||||
rtc::CritScope lock(&send_critsect_);
|
||||
total_bitrate_sent_.Process();
|
||||
@ -1610,7 +1614,8 @@ void RTPSender::UpdateAbsoluteSendTime(uint8_t* rtp_packet,
|
||||
ConvertMsTo24Bits(now_ms));
|
||||
}
|
||||
|
||||
uint16_t RTPSender::UpdateTransportSequenceNumber(
|
||||
bool RTPSender::UpdateTransportSequenceNumber(
|
||||
uint16_t sequence_number,
|
||||
uint8_t* rtp_packet,
|
||||
size_t rtp_packet_length,
|
||||
const RTPHeader& rtp_header) const {
|
||||
@ -1621,19 +1626,26 @@ uint16_t RTPSender::UpdateTransportSequenceNumber(
|
||||
rtp_packet_length, rtp_header,
|
||||
kTransportSequenceNumberLength, &offset)) {
|
||||
case ExtensionStatus::kNotRegistered:
|
||||
return 0;
|
||||
return false;
|
||||
case ExtensionStatus::kError:
|
||||
LOG(LS_WARNING) << "Failed to update transport sequence number";
|
||||
return 0;
|
||||
return false;
|
||||
case ExtensionStatus::kOk:
|
||||
break;
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
|
||||
uint16_t seq = transport_sequence_number_allocator_->AllocateSequenceNumber();
|
||||
BuildTransportSequenceNumberExtension(rtp_packet + offset, seq);
|
||||
return seq;
|
||||
BuildTransportSequenceNumberExtension(rtp_packet + offset, sequence_number);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTPSender::AllocateTransportSequenceNumber(int* packet_id) const {
|
||||
if (!transport_sequence_number_allocator_)
|
||||
return false;
|
||||
|
||||
*packet_id = transport_sequence_number_allocator_->AllocateSequenceNumber();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTPSender::SetSendingStatus(bool enabled) {
|
||||
|
||||
@ -97,7 +97,9 @@ class RTPSender : public RTPSenderInterface {
|
||||
BitrateStatisticsObserver* bitrate_callback,
|
||||
FrameCountObserver* frame_count_observer,
|
||||
SendSideDelayObserver* send_side_delay_observer,
|
||||
RtcEventLog* event_log);
|
||||
RtcEventLog* event_log,
|
||||
SendPacketObserver* send_packet_observer);
|
||||
|
||||
virtual ~RTPSender();
|
||||
|
||||
void ProcessBitrate();
|
||||
@ -353,6 +355,9 @@ class RTPSender : public RTPSenderInterface {
|
||||
const PacketOptions& options);
|
||||
|
||||
void UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms);
|
||||
void UpdateOnSendPacket(int packet_id,
|
||||
int64_t capture_time_ms,
|
||||
uint32_t ssrc);
|
||||
|
||||
// Find the byte position of the RTP extension as indicated by |type| in
|
||||
// |rtp_packet|. Return false if such extension doesn't exist.
|
||||
@ -370,12 +375,13 @@ class RTPSender : public RTPSenderInterface {
|
||||
size_t rtp_packet_length,
|
||||
const RTPHeader& rtp_header,
|
||||
int64_t now_ms) const;
|
||||
// Update the transport sequence number of the packet using a new sequence
|
||||
// number allocated by SequenceNumberAllocator. Returns the assigned sequence
|
||||
// number, or 0 if extension could not be updated.
|
||||
uint16_t UpdateTransportSequenceNumber(uint8_t* rtp_packet,
|
||||
size_t rtp_packet_length,
|
||||
const RTPHeader& rtp_header) const;
|
||||
|
||||
bool UpdateTransportSequenceNumber(uint16_t sequence_number,
|
||||
uint8_t* rtp_packet,
|
||||
size_t rtp_packet_length,
|
||||
const RTPHeader& rtp_header) const;
|
||||
|
||||
bool AllocateTransportSequenceNumber(int* packet_id) const;
|
||||
|
||||
void UpdateRtpStats(const uint8_t* buffer,
|
||||
size_t packet_length,
|
||||
@ -465,6 +471,7 @@ class RTPSender : public RTPSenderInterface {
|
||||
FrameCountObserver* const frame_count_observer_;
|
||||
SendSideDelayObserver* const send_side_delay_observer_;
|
||||
RtcEventLog* const event_log_;
|
||||
SendPacketObserver* const send_packet_observer_;
|
||||
|
||||
// RTP variables
|
||||
bool start_timestamp_forced_ GUARDED_BY(send_critsect_);
|
||||
|
||||
@ -122,6 +122,11 @@ class MockTransportSequenceNumberAllocator
|
||||
MOCK_METHOD0(AllocateSequenceNumber, uint16_t());
|
||||
};
|
||||
|
||||
class MockSendPacketObserver : public SendPacketObserver {
|
||||
public:
|
||||
MOCK_METHOD3(OnSendPacket, void(uint16_t, int64_t, uint32_t));
|
||||
};
|
||||
|
||||
class RtpSenderTest : public ::testing::Test {
|
||||
protected:
|
||||
RtpSenderTest()
|
||||
@ -137,10 +142,10 @@ class RtpSenderTest : public ::testing::Test {
|
||||
void SetUp() override { SetUpRtpSender(true); }
|
||||
|
||||
void SetUpRtpSender(bool pacer) {
|
||||
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_));
|
||||
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_));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
}
|
||||
|
||||
@ -148,6 +153,7 @@ class RtpSenderTest : public ::testing::Test {
|
||||
MockRtcEventLog mock_rtc_event_log_;
|
||||
MockRtpPacketSender mock_paced_sender_;
|
||||
MockTransportSequenceNumberAllocator seq_num_allocator_;
|
||||
MockSendPacketObserver send_packet_observer_;
|
||||
std::unique_ptr<RTPSender> rtp_sender_;
|
||||
int payload_;
|
||||
LoopbackTransportTest transport_;
|
||||
@ -185,6 +191,20 @@ class RtpSenderTest : public ::testing::Test {
|
||||
packet_, payload_length, rtp_length, capture_time_ms,
|
||||
kAllowRetransmission, RtpPacketSender::kNormalPriority));
|
||||
}
|
||||
|
||||
void SendGenericPayload() {
|
||||
const uint8_t kPayload[] = {47, 11, 32, 93, 89};
|
||||
const uint32_t kTimestamp = 1234;
|
||||
const uint8_t kPayloadType = 127;
|
||||
const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
|
||||
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterPayload(payload_name, kPayloadType, 90000,
|
||||
0, 1500));
|
||||
|
||||
EXPECT_EQ(0, rtp_sender_->SendOutgoingData(
|
||||
kVideoFrameKey, kPayloadType, kTimestamp, kCaptureTimeMs,
|
||||
kPayload, sizeof(kPayload), nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(pbos): Move tests over from WithoutPacer to RtpSenderTest as this is our
|
||||
@ -479,21 +499,13 @@ TEST_F(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) {
|
||||
kRtpExtensionTransportSequenceNumber,
|
||||
kTransportSequenceNumberExtensionId));
|
||||
|
||||
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
|
||||
const uint8_t payload_type = 127;
|
||||
ASSERT_EQ(0, rtp_sender_->RegisterPayload(payload_name, payload_type, 90000,
|
||||
0, 1500));
|
||||
// Create a dummy payload of 5 bytes.
|
||||
uint8_t payload[] = {47, 11, 32, 93, 89};
|
||||
|
||||
const uint16_t kTransportSequenceNumber = 17;
|
||||
EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
|
||||
.WillOnce(testing::Return(kTransportSequenceNumber));
|
||||
const uint32_t kTimestamp = 1234;
|
||||
const int64_t kCaptureTimeMs = 4321;
|
||||
ASSERT_EQ(0, rtp_sender_->SendOutgoingData(
|
||||
kVideoFrameKey, payload_type, kTimestamp, kCaptureTimeMs,
|
||||
payload, sizeof(payload), nullptr));
|
||||
EXPECT_CALL(send_packet_observer_,
|
||||
OnSendPacket(kTransportSequenceNumber, _, _))
|
||||
.Times(1);
|
||||
|
||||
SendGenericPayload();
|
||||
|
||||
RtpUtility::RtpHeaderParser rtp_parser(transport_.last_sent_packet_,
|
||||
transport_.last_sent_packet_len_);
|
||||
@ -509,6 +521,19 @@ TEST_F(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) {
|
||||
rtp_header.extension.transportSequenceNumber);
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderTestWithoutPacer, OnSendPacketUpdated) {
|
||||
EXPECT_CALL(mock_rtc_event_log_, // Ignore rtc event calls.
|
||||
LogRtpHeader(PacketDirection::kOutgoingPacket, _, _, _));
|
||||
|
||||
EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
|
||||
.WillOnce(testing::Return(kTransportSequenceNumber));
|
||||
EXPECT_CALL(send_packet_observer_,
|
||||
OnSendPacket(kTransportSequenceNumber, _, _))
|
||||
.Times(1);
|
||||
|
||||
SendGenericPayload();
|
||||
}
|
||||
|
||||
// Test CVO header extension is only set when marker bit is true.
|
||||
TEST_F(RtpSenderTestWithoutPacer, BuildRTPPacketWithVideoRotation_MarkerBit) {
|
||||
rtp_sender_->SetVideoRotation(kRotation);
|
||||
@ -947,11 +972,66 @@ TEST_F(RtpSenderTest, SendPadding) {
|
||||
EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime);
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderTest, OnSendPacketUpdated) {
|
||||
EXPECT_CALL(mock_rtc_event_log_, // Ignore rtc event calls.
|
||||
LogRtpHeader(PacketDirection::kOutgoingPacket, _, _, _));
|
||||
rtp_sender_->SetStorePacketsStatus(true, 10);
|
||||
|
||||
EXPECT_CALL(send_packet_observer_,
|
||||
OnSendPacket(kTransportSequenceNumber, _, _))
|
||||
.Times(1);
|
||||
EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
|
||||
.WillOnce(testing::Return(kTransportSequenceNumber));
|
||||
EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, _)).Times(1);
|
||||
|
||||
SendGenericPayload(); // Packet passed to pacer.
|
||||
const bool kIsRetransmit = false;
|
||||
rtp_sender_->TimeToSendPacket(kSeqNum, fake_clock_.TimeInMilliseconds(),
|
||||
kIsRetransmit);
|
||||
EXPECT_EQ(1, transport_.packets_sent_);
|
||||
}
|
||||
|
||||
TEST_F(RtpSenderTest, OnSendPacketNotUpdatedForRetransmits) {
|
||||
EXPECT_CALL(mock_rtc_event_log_, // Ignore rtc event calls.
|
||||
LogRtpHeader(PacketDirection::kOutgoingPacket, _, _, _));
|
||||
rtp_sender_->SetStorePacketsStatus(true, 10);
|
||||
|
||||
EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0);
|
||||
EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
|
||||
.WillOnce(testing::Return(kTransportSequenceNumber));
|
||||
EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, _)).Times(1);
|
||||
|
||||
SendGenericPayload(); // Packet passed to pacer.
|
||||
const bool kIsRetransmit = true;
|
||||
rtp_sender_->TimeToSendPacket(kSeqNum, fake_clock_.TimeInMilliseconds(),
|
||||
kIsRetransmit);
|
||||
EXPECT_EQ(1, transport_.packets_sent_);
|
||||
}
|
||||
|
||||
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_));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetStorePacketsStatus(true, 10);
|
||||
|
||||
EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0);
|
||||
EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, _)).Times(1);
|
||||
|
||||
SendGenericPayload(); // Packet passed to pacer.
|
||||
const bool kIsRetransmit = false;
|
||||
rtp_sender_->TimeToSendPacket(kSeqNum, fake_clock_.TimeInMilliseconds(),
|
||||
kIsRetransmit);
|
||||
EXPECT_EQ(1, transport_.packets_sent_);
|
||||
}
|
||||
|
||||
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_));
|
||||
false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr));
|
||||
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
|
||||
|
||||
@ -1092,9 +1172,9 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) {
|
||||
FrameCounts frame_counts_;
|
||||
} callback;
|
||||
|
||||
rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_,
|
||||
&mock_paced_sender_, nullptr, nullptr,
|
||||
nullptr, &callback, nullptr, nullptr));
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, nullptr,
|
||||
nullptr, &callback, nullptr, nullptr, nullptr));
|
||||
|
||||
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
|
||||
const uint8_t payload_type = 127;
|
||||
@ -1148,8 +1228,8 @@ TEST_F(RtpSenderTest, BitrateCallbacks) {
|
||||
BitrateStatistics total_stats_;
|
||||
BitrateStatistics retransmit_stats_;
|
||||
} callback;
|
||||
rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_,
|
||||
nullptr, nullptr, nullptr, &callback, nullptr,
|
||||
rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr,
|
||||
nullptr, nullptr, &callback, nullptr, nullptr,
|
||||
nullptr, nullptr));
|
||||
|
||||
// Simulate kNumPackets sent with kPacketInterval ms intervals.
|
||||
@ -1201,7 +1281,7 @@ class RtpSenderAudioTest : public RtpSenderTest {
|
||||
|
||||
void SetUp() override {
|
||||
payload_ = kAudioPayload;
|
||||
rtp_sender_.reset(new RTPSender(true, &fake_clock_, &transport_,
|
||||
rtp_sender_.reset(new RTPSender(true, &fake_clock_, &transport_, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
|
||||
@ -26,6 +26,8 @@ source_set("video") {
|
||||
"report_block_stats.h",
|
||||
"rtp_stream_receiver.cc",
|
||||
"rtp_stream_receiver.h",
|
||||
"send_delay_stats.cc",
|
||||
"send_delay_stats.h",
|
||||
"send_statistics_proxy.cc",
|
||||
"send_statistics_proxy.h",
|
||||
"stream_synchronization.cc",
|
||||
|
||||
@ -2176,6 +2176,7 @@ void EndToEndTest::VerifyHistogramStats(bool use_rtx,
|
||||
EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + "SendSideDelayInMs"));
|
||||
EXPECT_EQ(1,
|
||||
test::NumHistogramSamples(video_prefix + "SendSideDelayMaxInMs"));
|
||||
EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.SendDelayInMs"));
|
||||
|
||||
int num_rtx_samples = use_rtx ? 1 : 0;
|
||||
EXPECT_EQ(num_rtx_samples, test::NumHistogramSamples(
|
||||
|
||||
@ -53,6 +53,7 @@ std::unique_ptr<RtpRtcp> CreateRtpRtcpModule(
|
||||
configuration.send_bitrate_observer = nullptr;
|
||||
configuration.send_frame_count_observer = nullptr;
|
||||
configuration.send_side_delay_observer = nullptr;
|
||||
configuration.send_packet_observer = nullptr;
|
||||
configuration.bandwidth_callback = nullptr;
|
||||
configuration.transport_feedback_callback = nullptr;
|
||||
|
||||
|
||||
118
webrtc/video/send_delay_stats.cc
Normal file
118
webrtc/video/send_delay_stats.cc
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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/video/send_delay_stats.h"
|
||||
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/system_wrappers/include/metrics.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
// Packet with a larger delay are removed and excluded from the delay stats.
|
||||
// Set to larger than max histogram delay which is 10000.
|
||||
const int64_t kMaxSentPacketDelayMs = 11000;
|
||||
const size_t kMaxPacketMapSize = 2000;
|
||||
|
||||
// Limit for the maximum number of streams to calculate stats for.
|
||||
const size_t kMaxSsrcMapSize = 50;
|
||||
const int kMinRequiredSamples = 200;
|
||||
} // namespace
|
||||
|
||||
SendDelayStats::SendDelayStats(Clock* clock)
|
||||
: clock_(clock), num_old_packets_(0), num_skipped_packets_(0) {}
|
||||
|
||||
SendDelayStats::~SendDelayStats() {
|
||||
if (num_old_packets_ > 0 || num_skipped_packets_ > 0) {
|
||||
LOG(LS_WARNING) << "Delay stats: number of old packets " << num_old_packets_
|
||||
<< ", skipped packets " << num_skipped_packets_
|
||||
<< ". Number of streams " << send_delay_counters_.size();
|
||||
}
|
||||
UpdateHistograms();
|
||||
}
|
||||
|
||||
void SendDelayStats::UpdateHistograms() {
|
||||
rtc::CritScope lock(&crit_);
|
||||
for (const auto& it : send_delay_counters_) {
|
||||
int send_delay_ms = it.second.Avg(kMinRequiredSamples);
|
||||
if (send_delay_ms != -1) {
|
||||
RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.SendDelayInMs",
|
||||
send_delay_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendDelayStats::AddSsrcs(const VideoSendStream::Config& config) {
|
||||
rtc::CritScope lock(&crit_);
|
||||
if (ssrcs_.size() > kMaxSsrcMapSize)
|
||||
return;
|
||||
for (const auto& ssrc : config.rtp.ssrcs)
|
||||
ssrcs_.insert(ssrc);
|
||||
}
|
||||
|
||||
void SendDelayStats::OnSendPacket(uint16_t packet_id,
|
||||
int64_t capture_time_ms,
|
||||
uint32_t ssrc) {
|
||||
// Packet sent to transport.
|
||||
rtc::CritScope lock(&crit_);
|
||||
if (ssrcs_.find(ssrc) == ssrcs_.end())
|
||||
return;
|
||||
|
||||
int64_t now = clock_->TimeInMilliseconds();
|
||||
RemoveOld(now, &packets_);
|
||||
|
||||
if (packets_.size() > kMaxPacketMapSize) {
|
||||
++num_skipped_packets_;
|
||||
return;
|
||||
}
|
||||
packets_.insert(
|
||||
std::make_pair(packet_id, Packet(ssrc, capture_time_ms, now)));
|
||||
}
|
||||
|
||||
bool SendDelayStats::OnSentPacket(int packet_id, int64_t time_ms) {
|
||||
// Packet leaving socket.
|
||||
if (packet_id == -1)
|
||||
return false;
|
||||
|
||||
rtc::CritScope lock(&crit_);
|
||||
auto it = packets_.find(packet_id);
|
||||
if (it == packets_.end())
|
||||
return false;
|
||||
|
||||
// TODO(asapersson): Remove SendSideDelayUpdated(), use capture -> sent.
|
||||
// Elapsed time from send (to transport) -> sent (leaving socket).
|
||||
int diff_ms = time_ms - it->second.send_time_ms;
|
||||
send_delay_counters_[it->second.ssrc].Add(diff_ms);
|
||||
packets_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SendDelayStats::RemoveOld(int64_t now, PacketMap* packets) {
|
||||
while (!packets->empty()) {
|
||||
auto it = packets->begin();
|
||||
if (now - it->second.capture_time_ms < kMaxSentPacketDelayMs)
|
||||
break;
|
||||
|
||||
packets->erase(it);
|
||||
++num_old_packets_;
|
||||
}
|
||||
}
|
||||
|
||||
void SendDelayStats::SampleCounter::Add(int sample) {
|
||||
sum += sample;
|
||||
++num_samples;
|
||||
}
|
||||
|
||||
int SendDelayStats::SampleCounter::Avg(int min_required_samples) const {
|
||||
if (num_samples < min_required_samples || num_samples == 0)
|
||||
return -1;
|
||||
return (sum + (num_samples / 2)) / num_samples;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
93
webrtc/video/send_delay_stats.h
Normal file
93
webrtc/video/send_delay_stats.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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_VIDEO_SEND_DELAY_STATS_H_
|
||||
#define WEBRTC_VIDEO_SEND_DELAY_STATS_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/base/thread_annotations.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/system_wrappers/include/clock.h"
|
||||
#include "webrtc/video_send_stream.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class SendDelayStats : public SendPacketObserver {
|
||||
public:
|
||||
explicit SendDelayStats(Clock* clock);
|
||||
virtual ~SendDelayStats();
|
||||
|
||||
// Adds the configured ssrcs for the rtp streams.
|
||||
// Stats will be calculated for these streams.
|
||||
void AddSsrcs(const VideoSendStream::Config& config);
|
||||
|
||||
// Called when a packet is sent (leaving socket).
|
||||
bool OnSentPacket(int packet_id, int64_t time_ms);
|
||||
|
||||
protected:
|
||||
// From SendPacketObserver.
|
||||
// Called when a packet is sent to the transport.
|
||||
void OnSendPacket(uint16_t packet_id,
|
||||
int64_t capture_time_ms,
|
||||
uint32_t ssrc) override;
|
||||
|
||||
private:
|
||||
// Map holding sent packets (mapped by sequence number).
|
||||
struct SequenceNumberOlderThan {
|
||||
bool operator()(uint16_t seq1, uint16_t seq2) const {
|
||||
return IsNewerSequenceNumber(seq2, seq1);
|
||||
}
|
||||
};
|
||||
struct Packet {
|
||||
Packet(uint32_t ssrc, int64_t capture_time_ms, int64_t send_time_ms)
|
||||
: ssrc(ssrc),
|
||||
capture_time_ms(capture_time_ms),
|
||||
send_time_ms(send_time_ms) {}
|
||||
uint32_t ssrc;
|
||||
int64_t capture_time_ms;
|
||||
int64_t send_time_ms;
|
||||
};
|
||||
typedef std::map<uint16_t, Packet, SequenceNumberOlderThan> PacketMap;
|
||||
|
||||
class SampleCounter {
|
||||
public:
|
||||
SampleCounter() : sum(0), num_samples(0) {}
|
||||
~SampleCounter() {}
|
||||
void Add(int sample);
|
||||
int Avg(int min_required_samples) const;
|
||||
|
||||
private:
|
||||
int sum;
|
||||
int num_samples;
|
||||
};
|
||||
|
||||
void UpdateHistograms();
|
||||
void RemoveOld(int64_t now, PacketMap* packets)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
Clock* const clock_;
|
||||
rtc::CriticalSection crit_;
|
||||
|
||||
PacketMap packets_ GUARDED_BY(crit_);
|
||||
size_t num_old_packets_ GUARDED_BY(crit_);
|
||||
size_t num_skipped_packets_ GUARDED_BY(crit_);
|
||||
|
||||
std::set<uint32_t> ssrcs_ GUARDED_BY(crit_);
|
||||
std::map<uint32_t, SampleCounter> send_delay_counters_
|
||||
GUARDED_BY(crit_); // Mapped by SSRC.
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_VIDEO_SEND_DELAY_STATS_H_
|
||||
122
webrtc/video/send_delay_stats_unittest.cc
Normal file
122
webrtc/video/send_delay_stats_unittest.cc
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2016 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/video/send_delay_stats.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/system_wrappers/include/metrics.h"
|
||||
#include "webrtc/test/histogram.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
const uint32_t kSsrc1 = 17;
|
||||
const uint32_t kSsrc2 = 42;
|
||||
const uint32_t kRtxSsrc1 = 18;
|
||||
const uint32_t kRtxSsrc2 = 43;
|
||||
const uint16_t kPacketId = 2345;
|
||||
const int64_t kMaxPacketDelayMs = 11000;
|
||||
const int kMinRequiredSamples = 200;
|
||||
} // namespace
|
||||
|
||||
class SendDelayStatsTest : public ::testing::Test {
|
||||
public:
|
||||
SendDelayStatsTest() : clock_(1234), config_(CreateConfig()) {}
|
||||
virtual ~SendDelayStatsTest() {}
|
||||
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
stats_.reset(new SendDelayStats(&clock_));
|
||||
stats_->AddSsrcs(config_);
|
||||
}
|
||||
|
||||
VideoSendStream::Config CreateConfig() {
|
||||
VideoSendStream::Config config(nullptr);
|
||||
config.rtp.ssrcs.push_back(kSsrc1);
|
||||
config.rtp.ssrcs.push_back(kSsrc2);
|
||||
config.rtp.rtx.ssrcs.push_back(kRtxSsrc1);
|
||||
config.rtp.rtx.ssrcs.push_back(kRtxSsrc2);
|
||||
return config;
|
||||
}
|
||||
|
||||
void OnSendPacket(uint16_t id, uint32_t ssrc) {
|
||||
OnSendPacket(id, ssrc, clock_.TimeInMilliseconds());
|
||||
}
|
||||
|
||||
void OnSendPacket(uint16_t id, uint32_t ssrc, int64_t capture_ms) {
|
||||
SendPacketObserver* observer = stats_.get();
|
||||
observer->OnSendPacket(id, capture_ms, ssrc);
|
||||
}
|
||||
|
||||
bool OnSentPacket(uint16_t id) {
|
||||
return stats_->OnSentPacket(id, clock_.TimeInMilliseconds());
|
||||
}
|
||||
|
||||
SimulatedClock clock_;
|
||||
VideoSendStream::Config config_;
|
||||
std::unique_ptr<SendDelayStats> stats_;
|
||||
};
|
||||
|
||||
TEST_F(SendDelayStatsTest, SentPacketFound) {
|
||||
EXPECT_FALSE(OnSentPacket(kPacketId));
|
||||
OnSendPacket(kPacketId, kSsrc1);
|
||||
EXPECT_TRUE(OnSentPacket(kPacketId)); // Packet found.
|
||||
EXPECT_FALSE(OnSentPacket(kPacketId)); // Packet removed when found.
|
||||
}
|
||||
|
||||
TEST_F(SendDelayStatsTest, SentPacketNotFoundForNonRegisteredSsrc) {
|
||||
OnSendPacket(kPacketId, kSsrc1);
|
||||
EXPECT_TRUE(OnSentPacket(kPacketId));
|
||||
OnSendPacket(kPacketId + 1, kSsrc2);
|
||||
EXPECT_TRUE(OnSentPacket(kPacketId + 1));
|
||||
OnSendPacket(kPacketId + 2, kRtxSsrc1); // RTX SSRC not registered.
|
||||
EXPECT_FALSE(OnSentPacket(kPacketId + 2));
|
||||
}
|
||||
|
||||
TEST_F(SendDelayStatsTest, SentPacketFoundWithMaxSendDelay) {
|
||||
OnSendPacket(kPacketId, kSsrc1);
|
||||
clock_.AdvanceTimeMilliseconds(kMaxPacketDelayMs - 1);
|
||||
OnSendPacket(kPacketId + 1, kSsrc1); // kPacketId -> not old/removed.
|
||||
EXPECT_TRUE(OnSentPacket(kPacketId)); // Packet found.
|
||||
EXPECT_TRUE(OnSentPacket(kPacketId + 1)); // Packet found.
|
||||
}
|
||||
|
||||
TEST_F(SendDelayStatsTest, OldPacketsRemoved) {
|
||||
const int64_t kCaptureTimeMs = clock_.TimeInMilliseconds();
|
||||
OnSendPacket(0xffffu, kSsrc1, kCaptureTimeMs);
|
||||
OnSendPacket(0u, kSsrc1, kCaptureTimeMs);
|
||||
OnSendPacket(1u, kSsrc1, kCaptureTimeMs + 1);
|
||||
clock_.AdvanceTimeMilliseconds(kMaxPacketDelayMs); // 0xffff, 0 -> old.
|
||||
OnSendPacket(2u, kSsrc1, kCaptureTimeMs + 2);
|
||||
|
||||
EXPECT_FALSE(OnSentPacket(0xffffu)); // Old removed.
|
||||
EXPECT_FALSE(OnSentPacket(0u)); // Old removed.
|
||||
EXPECT_TRUE(OnSentPacket(1u));
|
||||
EXPECT_TRUE(OnSentPacket(2u));
|
||||
}
|
||||
|
||||
TEST_F(SendDelayStatsTest, HistogramsAreUpdated) {
|
||||
test::ClearHistograms();
|
||||
const int64_t kDelayMs1 = 5;
|
||||
const int64_t kDelayMs2 = 10;
|
||||
uint16_t id = 0;
|
||||
for (int i = 0; i < kMinRequiredSamples; ++i) {
|
||||
OnSendPacket(++id, kSsrc1);
|
||||
clock_.AdvanceTimeMilliseconds(kDelayMs1);
|
||||
EXPECT_TRUE(OnSentPacket(id));
|
||||
OnSendPacket(++id, kSsrc2);
|
||||
clock_.AdvanceTimeMilliseconds(kDelayMs2);
|
||||
EXPECT_TRUE(OnSentPacket(id));
|
||||
}
|
||||
stats_.reset();
|
||||
EXPECT_EQ(2, test::NumHistogramSamples("WebRTC.Video.SendDelayInMs"));
|
||||
EXPECT_EQ(kDelayMs2, test::LastHistogramSample("WebRTC.Video.SendDelayInMs"));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -110,10 +110,7 @@ class SendStatisticsProxyTest : public ::testing::Test {
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
|
||||
RtcpStatisticsCallback* callback = statistics_proxy_.get();
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
|
||||
it != config_.rtp.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.ssrcs) {
|
||||
VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
|
||||
|
||||
// Add statistics with some arbitrary, but unique, numbers.
|
||||
@ -124,10 +121,7 @@ TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
|
||||
ssrc_stats.rtcp_stats.jitter = offset + 3;
|
||||
callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc);
|
||||
}
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
|
||||
it != config_.rtp.rtx.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
|
||||
VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
|
||||
|
||||
// Add statistics with some arbitrary, but unique, numbers.
|
||||
@ -170,10 +164,7 @@ TEST_F(SendStatisticsProxyTest, Suspended) {
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, FrameCounts) {
|
||||
FrameCountObserver* observer = statistics_proxy_.get();
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
|
||||
it != config_.rtp.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.ssrcs) {
|
||||
// Add statistics with some arbitrary, but unique, numbers.
|
||||
VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
|
||||
uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
|
||||
@ -183,10 +174,7 @@ TEST_F(SendStatisticsProxyTest, FrameCounts) {
|
||||
stats.frame_counts = frame_counts;
|
||||
observer->FrameCountUpdated(frame_counts, ssrc);
|
||||
}
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
|
||||
it != config_.rtp.rtx.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
|
||||
// Add statistics with some arbitrary, but unique, numbers.
|
||||
VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
|
||||
uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
|
||||
@ -203,10 +191,7 @@ TEST_F(SendStatisticsProxyTest, FrameCounts) {
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, DataCounters) {
|
||||
StreamDataCountersCallback* callback = statistics_proxy_.get();
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
|
||||
it != config_.rtp.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.ssrcs) {
|
||||
StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
|
||||
// Add statistics with some arbitrary, but unique, numbers.
|
||||
size_t offset = ssrc * sizeof(StreamDataCounters);
|
||||
@ -219,10 +204,7 @@ TEST_F(SendStatisticsProxyTest, DataCounters) {
|
||||
counters.transmitted.packets = offset_uint32 + 5;
|
||||
callback->DataCountersUpdated(counters, ssrc);
|
||||
}
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
|
||||
it != config_.rtp.rtx.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
|
||||
StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
|
||||
// Add statistics with some arbitrary, but unique, numbers.
|
||||
size_t offset = ssrc * sizeof(StreamDataCounters);
|
||||
@ -242,10 +224,7 @@ TEST_F(SendStatisticsProxyTest, DataCounters) {
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, Bitrate) {
|
||||
BitrateStatisticsObserver* observer = statistics_proxy_.get();
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
|
||||
it != config_.rtp.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.ssrcs) {
|
||||
BitrateStatistics total;
|
||||
BitrateStatistics retransmit;
|
||||
// Use ssrc as bitrate_bps to get a unique value for each stream.
|
||||
@ -255,10 +234,7 @@ TEST_F(SendStatisticsProxyTest, Bitrate) {
|
||||
expected_.substreams[ssrc].total_bitrate_bps = total.bitrate_bps;
|
||||
expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit.bitrate_bps;
|
||||
}
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
|
||||
it != config_.rtp.rtx.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
|
||||
BitrateStatistics total;
|
||||
BitrateStatistics retransmit;
|
||||
// Use ssrc as bitrate_bps to get a unique value for each stream.
|
||||
@ -275,10 +251,7 @@ TEST_F(SendStatisticsProxyTest, Bitrate) {
|
||||
|
||||
TEST_F(SendStatisticsProxyTest, SendSideDelay) {
|
||||
SendSideDelayObserver* observer = statistics_proxy_.get();
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
|
||||
it != config_.rtp.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.ssrcs) {
|
||||
// Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
|
||||
// stream.
|
||||
int avg_delay_ms = ssrc;
|
||||
@ -287,10 +260,7 @@ TEST_F(SendStatisticsProxyTest, SendSideDelay) {
|
||||
expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
|
||||
expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
|
||||
}
|
||||
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
|
||||
it != config_.rtp.rtx.ssrcs.end();
|
||||
++it) {
|
||||
const uint32_t ssrc = *it;
|
||||
for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
|
||||
// Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
|
||||
// stream.
|
||||
int avg_delay_ms = ssrc;
|
||||
|
||||
@ -47,6 +47,7 @@ std::vector<RtpRtcp*> CreateRtpRtcpModules(
|
||||
RtpPacketSender* paced_sender,
|
||||
TransportSequenceNumberAllocator* transport_sequence_number_allocator,
|
||||
SendStatisticsProxy* stats_proxy,
|
||||
SendDelayStats* send_delay_stats,
|
||||
size_t num_modules) {
|
||||
RTC_DCHECK_GT(num_modules, 0u);
|
||||
RtpRtcp::Configuration configuration;
|
||||
@ -64,6 +65,7 @@ std::vector<RtpRtcp*> CreateRtpRtcpModules(
|
||||
configuration.send_bitrate_observer = stats_proxy;
|
||||
configuration.send_frame_count_observer = stats_proxy;
|
||||
configuration.send_side_delay_observer = stats_proxy;
|
||||
configuration.send_packet_observer = send_delay_stats;
|
||||
configuration.bandwidth_callback = bandwidth_callback;
|
||||
configuration.transport_feedback_callback = transport_feedback_callback;
|
||||
|
||||
@ -348,6 +350,7 @@ VideoSendStream::VideoSendStream(
|
||||
CallStats* call_stats,
|
||||
CongestionController* congestion_controller,
|
||||
BitrateAllocator* bitrate_allocator,
|
||||
SendDelayStats* send_delay_stats,
|
||||
VieRemb* remb,
|
||||
const VideoSendStream::Config& config,
|
||||
const VideoEncoderConfig& encoder_config,
|
||||
@ -391,6 +394,7 @@ VideoSendStream::VideoSendStream(
|
||||
congestion_controller_->pacer(),
|
||||
congestion_controller_->packet_router(),
|
||||
&stats_proxy_,
|
||||
send_delay_stats,
|
||||
config_.rtp.ssrcs.size())),
|
||||
payload_router_(rtp_rtcp_modules_, config.encoder_settings.payload_type),
|
||||
input_(&encoder_wakeup_event_,
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "webrtc/video/encoded_frame_callback_adapter.h"
|
||||
#include "webrtc/video/encoder_state_feedback.h"
|
||||
#include "webrtc/video/payload_router.h"
|
||||
#include "webrtc/video/send_delay_stats.h"
|
||||
#include "webrtc/video/send_statistics_proxy.h"
|
||||
#include "webrtc/video/video_capture_input.h"
|
||||
#include "webrtc/video/vie_channel.h"
|
||||
@ -57,6 +58,7 @@ class VideoSendStream : public webrtc::VideoSendStream,
|
||||
CallStats* call_stats,
|
||||
CongestionController* congestion_controller,
|
||||
BitrateAllocator* bitrate_allocator,
|
||||
SendDelayStats* send_delay_stats,
|
||||
VieRemb* remb,
|
||||
const VideoSendStream::Config& config,
|
||||
const VideoEncoderConfig& encoder_config,
|
||||
|
||||
@ -40,6 +40,8 @@
|
||||
'video/report_block_stats.h',
|
||||
'video/rtp_stream_receiver.cc',
|
||||
'video/rtp_stream_receiver.h',
|
||||
'video/send_delay_stats.cc',
|
||||
'video/send_delay_stats.h',
|
||||
'video/send_statistics_proxy.cc',
|
||||
'video/send_statistics_proxy.h',
|
||||
'video/stream_synchronization.cc',
|
||||
|
||||
@ -168,6 +168,7 @@
|
||||
'video/overuse_frame_detector_unittest.cc',
|
||||
'video/payload_router_unittest.cc',
|
||||
'video/report_block_stats_unittest.cc',
|
||||
'video/send_delay_stats_unittest.cc',
|
||||
'video/send_statistics_proxy_unittest.cc',
|
||||
'video/stream_synchronization_unittest.cc',
|
||||
'video/video_capture_input_unittest.cc',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user