diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc index 23173decc6..82ca630ad2 100644 --- a/webrtc/call/call.cc +++ b/webrtc/call/call.cc @@ -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 congestion_controller_; + const std::unique_ptr 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); } diff --git a/webrtc/call/rtc_event_log_unittest.cc b/webrtc/call/rtc_event_log_unittest.cc index 825718674d..0779f8e013 100644 --- a/webrtc/call/rtc_event_log_unittest.cc +++ b/webrtc/call/rtc_event_log_unittest.cc @@ -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 csrcs; for (unsigned i = 0; i < csrcs_count; i++) { diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 58aebdcdac..587b90d753 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -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 // ================================================================== diff --git a/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h index 3f496d4657..301cb84765 100644 --- a/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h @@ -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); }; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index ec767d8336..8a1e2fc36c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -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), diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index f7b72b875c..5b79fe385c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -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) { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index f9d5df6802..f501d27a72 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -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_); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index f350effc21..d04ff4d200 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -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 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); diff --git a/webrtc/video/BUILD.gn b/webrtc/video/BUILD.gn index 0bc5a12fef..74fad8489d 100644 --- a/webrtc/video/BUILD.gn +++ b/webrtc/video/BUILD.gn @@ -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", diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc index 0e02ff8b2e..f59044cf01 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.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( diff --git a/webrtc/video/rtp_stream_receiver.cc b/webrtc/video/rtp_stream_receiver.cc index 6421190e98..6def90f708 100644 --- a/webrtc/video/rtp_stream_receiver.cc +++ b/webrtc/video/rtp_stream_receiver.cc @@ -53,6 +53,7 @@ std::unique_ptr 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; diff --git a/webrtc/video/send_delay_stats.cc b/webrtc/video/send_delay_stats.cc new file mode 100644 index 0000000000..8701066519 --- /dev/null +++ b/webrtc/video/send_delay_stats.cc @@ -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 diff --git a/webrtc/video/send_delay_stats.h b/webrtc/video/send_delay_stats.h new file mode 100644 index 0000000000..20a97814c7 --- /dev/null +++ b/webrtc/video/send_delay_stats.h @@ -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 +#include +#include + +#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 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 ssrcs_ GUARDED_BY(crit_); + std::map send_delay_counters_ + GUARDED_BY(crit_); // Mapped by SSRC. +}; + +} // namespace webrtc +#endif // WEBRTC_VIDEO_SEND_DELAY_STATS_H_ diff --git a/webrtc/video/send_delay_stats_unittest.cc b/webrtc/video/send_delay_stats_unittest.cc new file mode 100644 index 0000000000..44c62c3a45 --- /dev/null +++ b/webrtc/video/send_delay_stats_unittest.cc @@ -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 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 diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc index d7f4a62d16..636b9dc40c 100644 --- a/webrtc/video/send_statistics_proxy_unittest.cc +++ b/webrtc/video/send_statistics_proxy_unittest.cc @@ -110,10 +110,7 @@ class SendStatisticsProxyTest : public ::testing::Test { TEST_F(SendStatisticsProxyTest, RtcpStatistics) { RtcpStatisticsCallback* callback = statistics_proxy_.get(); - for (std::vector::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::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::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::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::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::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::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::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::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::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; diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index c42c6d059a..f27a858a27 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -47,6 +47,7 @@ std::vector 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 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_, diff --git a/webrtc/video/video_send_stream.h b/webrtc/video/video_send_stream.h index ead1abfc70..bdb0e645b0 100644 --- a/webrtc/video/video_send_stream.h +++ b/webrtc/video/video_send_stream.h @@ -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, diff --git a/webrtc/video/webrtc_video.gypi b/webrtc/video/webrtc_video.gypi index 514b21dc1f..cb63a2e87d 100644 --- a/webrtc/video/webrtc_video.gypi +++ b/webrtc/video/webrtc_video.gypi @@ -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', diff --git a/webrtc/webrtc_tests.gypi b/webrtc/webrtc_tests.gypi index 75fc35a680..b194121850 100644 --- a/webrtc/webrtc_tests.gypi +++ b/webrtc/webrtc_tests.gypi @@ -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',