diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.cc b/modules/rtp_rtcp/source/rtcp_transceiver.cc index a937131e41..f8f7750ffb 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver.cc +++ b/modules/rtp_rtcp/source/rtcp_transceiver.cc @@ -73,6 +73,14 @@ void RtcpTransceiver::RemoveMediaReceiverRtcpObserver( task_queue_->PostTaskAndReply(std::move(remove), std::move(on_removed)); } +void RtcpTransceiver::SetReadyToSend(bool ready) { + rtc::WeakPtr ptr = ptr_; + task_queue_->PostTask([ptr, ready] { + if (ptr) + ptr->SetReadyToSend(ready); + }); +} + void RtcpTransceiver::ReceivePacket(rtc::CopyOnWriteBuffer packet) { rtc::WeakPtr ptr = ptr_; int64_t now_us = rtc::TimeMicros(); diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.h b/modules/rtp_rtcp/source/rtcp_transceiver.h index 9df56d14e6..9125781ea5 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver.h +++ b/modules/rtp_rtcp/source/rtcp_transceiver.h @@ -43,6 +43,11 @@ class RtcpTransceiver : public RtcpFeedbackSenderInterface { MediaReceiverRtcpObserver* observer, std::unique_ptr on_removed); + // Enables/disables sending rtcp packets eventually. + // Packets may be sent after the SetReadyToSend(false) returns, but no new + // packets will be scheduled. + void SetReadyToSend(bool ready); + // Handles incoming rtcp packets. void ReceivePacket(rtc::CopyOnWriteBuffer packet); diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_config.h b/modules/rtp_rtcp/source/rtcp_transceiver_config.h index 264b8b30b4..75c007da18 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver_config.h +++ b/modules/rtp_rtcp/source/rtcp_transceiver_config.h @@ -80,6 +80,8 @@ struct RtcpTransceiverConfig { // // Tuning parameters. // + // Initial state if |outgoing_transport| ready to accept packets. + bool initial_ready_to_send = true; // Delay before 1st periodic compound packet. int initial_report_delay_ms = 500; diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc index 99977ff8fd..925cc03410 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc +++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc @@ -86,9 +86,11 @@ class RtcpTransceiverImpl::PacketSender { }; RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config) - : config_(config), ptr_factory_(this) { + : config_(config), + ready_to_send_(config.initial_ready_to_send), + ptr_factory_(this) { RTC_CHECK(config_.Validate()); - if (config_.schedule_periodic_compound_packets) + if (ready_to_send_ && config_.schedule_periodic_compound_packets) SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms); } @@ -115,6 +117,17 @@ void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver( stored.erase(it); } +void RtcpTransceiverImpl::SetReadyToSend(bool ready) { + if (config_.schedule_periodic_compound_packets) { + if (ready_to_send_ && !ready) // Stop existent send task. + ptr_factory_.InvalidateWeakPtrs(); + + if (!ready_to_send_ && ready) // Restart periodic sending. + SchedulePeriodicCompoundPackets(config_.report_period_ms / 2); + } + ready_to_send_ = ready; +} + void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView packet, int64_t now_us) { while (!packet.empty()) { @@ -130,6 +143,8 @@ void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView packet, } void RtcpTransceiverImpl::SendCompoundPacket() { + if (!ready_to_send_) + return; SendPeriodicCompoundPacket(); ReschedulePeriodicCompoundPackets(); } @@ -150,6 +165,8 @@ void RtcpTransceiverImpl::UnsetRemb() { } void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView packet) { + if (!ready_to_send_) + return; // Unlike other senders, this functions just tries to send packet away and // disregard rtcp_mode, max_packet_size or anything else. // TODO(bugs.webrtc.org/8239): respect config_ by creating the @@ -160,6 +177,8 @@ void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView packet) { void RtcpTransceiverImpl::SendNack(uint32_t ssrc, std::vector sequence_numbers) { RTC_DCHECK(!sequence_numbers.empty()); + if (!ready_to_send_) + return; rtcp::Nack nack; nack.SetSenderSsrc(config_.feedback_ssrc); nack.SetMediaSsrc(ssrc); @@ -168,6 +187,8 @@ void RtcpTransceiverImpl::SendNack(uint32_t ssrc, } void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) { + if (!ready_to_send_) + return; rtcp::Pli pli; pli.SetSenderSsrc(config_.feedback_ssrc); pli.SetMediaSsrc(ssrc); @@ -177,6 +198,8 @@ void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) { void RtcpTransceiverImpl::SendFullIntraRequest( rtc::ArrayView ssrcs) { RTC_DCHECK(!ssrcs.empty()); + if (!ready_to_send_) + return; rtcp::Fir fir; fir.SetSenderSsrc(config_.feedback_ssrc); for (uint32_t media_ssrc : ssrcs) diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h index abbc40fe03..05c74f27ee 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h +++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h @@ -43,6 +43,8 @@ class RtcpTransceiverImpl { void RemoveMediaReceiverRtcpObserver(uint32_t remote_ssrc, MediaReceiverRtcpObserver* observer); + void SetReadyToSend(bool ready); + void ReceivePacket(rtc::ArrayView packet, int64_t now_us); void SendCompoundPacket(); @@ -88,6 +90,7 @@ class RtcpTransceiverImpl { const RtcpTransceiverConfig config_; + bool ready_to_send_; rtc::Optional remb_; // TODO(danilchap): Remove entries from remote_senders_ that are no longer // needed. diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc index 5ab6858a88..0c1119d352 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc @@ -130,6 +130,8 @@ RtcpTransceiverConfig DefaultTestConfig() { RtcpTransceiverConfig config; config.outgoing_transport = &null_transport; config.schedule_periodic_compound_packets = false; + config.initial_report_delay_ms = 10; + config.report_period_ms = kReportPeriodMs; return config; } @@ -235,6 +237,71 @@ TEST(RtcpTransceiverImplTest, SendCompoundPacketDelaysPeriodicSendPackets) { ASSERT_TRUE(done.Wait(kAlmostForeverMs)); } +TEST(RtcpTransceiverImplTest, SendsNoRtcpWhenNetworkStateIsDown) { + MockTransport mock_transport; + RtcpTransceiverConfig config = DefaultTestConfig(); + config.initial_ready_to_send = false; + config.outgoing_transport = &mock_transport; + RtcpTransceiverImpl rtcp_transceiver(config); + + + EXPECT_CALL(mock_transport, SendRtcp(_, _)).Times(0); + + const uint8_t raw[] = {1, 2, 3, 4}; + const std::vector sequence_numbers = {45, 57}; + const uint32_t ssrcs[] = {123}; + rtcp_transceiver.SendCompoundPacket(); + rtcp_transceiver.SendRawPacket(raw); + rtcp_transceiver.SendNack(ssrcs[0], sequence_numbers); + rtcp_transceiver.SendPictureLossIndication(ssrcs[0]); + rtcp_transceiver.SendFullIntraRequest(ssrcs); +} + +TEST(RtcpTransceiverImplTest, SendsRtcpWhenNetworkStateIsUp) { + MockTransport mock_transport; + RtcpTransceiverConfig config = DefaultTestConfig(); + config.initial_ready_to_send = false; + config.outgoing_transport = &mock_transport; + RtcpTransceiverImpl rtcp_transceiver(config); + + rtcp_transceiver.SetReadyToSend(true); + + EXPECT_CALL(mock_transport, SendRtcp(_, _)).Times(5); + + const uint8_t raw[] = {1, 2, 3, 4}; + const std::vector sequence_numbers = {45, 57}; + const uint32_t ssrcs[] = {123}; + rtcp_transceiver.SendCompoundPacket(); + rtcp_transceiver.SendRawPacket(raw); + rtcp_transceiver.SendNack(ssrcs[0], sequence_numbers); + rtcp_transceiver.SendPictureLossIndication(ssrcs[0]); + rtcp_transceiver.SendFullIntraRequest(ssrcs); +} + +TEST(RtcpTransceiverImplTest, SendsPeriodicRtcpWhenNetworkStateIsUp) { + rtc::TaskQueue queue("rtcp"); + FakeRtcpTransport transport; + RtcpTransceiverConfig config = DefaultTestConfig(); + config.schedule_periodic_compound_packets = true; + config.initial_ready_to_send = false; + config.outgoing_transport = &transport; + config.task_queue = &queue; + rtc::Optional rtcp_transceiver; + rtcp_transceiver.emplace(config); + + rtcp_transceiver->SetReadyToSend(true); + + EXPECT_TRUE(transport.WaitPacket()); + + // Cleanup. + rtc::Event done(false, false); + queue.PostTask([&] { + rtcp_transceiver.reset(); + done.Set(); + }); + ASSERT_TRUE(done.Wait(kAlmostForeverMs)); +} + TEST(RtcpTransceiverImplTest, SendsMinimalCompoundPacket) { const uint32_t kSenderSsrc = 12345; RtcpTransceiverConfig config;