diff --git a/webrtc/common_types.h b/webrtc/common_types.h index bf7566c3cc..c3752f5b62 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -912,6 +912,17 @@ enum NetworkState { kNetworkDown, }; +struct RtpKeepAliveConfig { + // If no packet has been sent for |timeout_interval_ms|, send a keep-alive + // packet. The keep-alive packet is an empty (no payload) RTP packet with a + // payload type of 20 as long as the other end has not negotiated the use of + // this value. If this value has already been negotiated, then some other + // unused static payload type from table 5 of RFC 3551 shall be used and set + // in |payload_type|. + int64_t timeout_interval_ms = -1; + uint8_t payload_type = 20; +}; + } // namespace webrtc #endif // WEBRTC_COMMON_TYPES_H_ diff --git a/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h index 6fc6b862b8..a5d1b0b0d7 100644 --- a/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/include/rtp_rtcp.h @@ -19,6 +19,7 @@ #include "webrtc/base/constructormagic.h" #include "webrtc/base/deprecation.h" #include "webrtc/base/optional.h" +#include "webrtc/common_types.h" #include "webrtc/modules/include/module.h" #include "webrtc/modules/rtp_rtcp/include/flexfec_sender.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" @@ -92,6 +93,7 @@ class RtpRtcp : public Module { SendPacketObserver* send_packet_observer = nullptr; RateLimiter* retransmission_rate_limiter = nullptr; OverheadObserver* overhead_observer = nullptr; + RtpKeepAliveConfig keepalive_config; private: 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 d79e6899e1..446022bafd 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -12,6 +12,7 @@ #include +#include #include #include @@ -26,6 +27,11 @@ #endif namespace webrtc { +namespace { +const int64_t kRtpRtcpMaxIdleTimeProcessMs = 5; +const int64_t kRtpRtcpRttProcessTimeMs = 1000; +const int64_t kRtpRtcpBitrateProcessTimeMs = 10; +} // namespace RTPExtensionType StringToRtpExtensionType(const std::string& extension) { if (extension == RtpExtension::kTimestampOffsetUri) @@ -89,9 +95,12 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) this), clock_(configuration.clock), audio_(configuration.audio), - last_process_time_(configuration.clock->TimeInMilliseconds()), - last_bitrate_process_time_(configuration.clock->TimeInMilliseconds()), - last_rtt_process_time_(configuration.clock->TimeInMilliseconds()), + keepalive_config_(configuration.keepalive_config), + last_bitrate_process_time_(clock_->TimeInMilliseconds()), + last_rtt_process_time_(clock_->TimeInMilliseconds()), + next_process_time_(clock_->TimeInMilliseconds() + + kRtpRtcpMaxIdleTimeProcessMs), + next_keepalive_time_(-1), packet_overhead_(28), // IPV4 UDP. nack_last_time_sent_full_(0), nack_last_time_sent_full_prev_(0), @@ -118,6 +127,11 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) configuration.overhead_observer)); // Make sure rtcp sender use same timestamp offset as rtp sender. rtcp_sender_.SetTimestampOffset(rtp_sender_->TimestampOffset()); + + if (keepalive_config_.timeout_interval_ms != -1) { + next_keepalive_time_ = + clock_->TimeInMilliseconds() + keepalive_config_.timeout_interval_ms; + } } // Set default packet size limit. @@ -130,24 +144,38 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) // Returns the number of milliseconds until the module want a worker thread // to call Process. int64_t ModuleRtpRtcpImpl::TimeUntilNextProcess() { - const int64_t now = clock_->TimeInMilliseconds(); - const int64_t kRtpRtcpMaxIdleTimeProcessMs = 5; - return kRtpRtcpMaxIdleTimeProcessMs - (now - last_process_time_); + return std::max(0, + next_process_time_ - clock_->TimeInMilliseconds()); } // Process any pending tasks such as timeouts (non time critical events). void ModuleRtpRtcpImpl::Process() { const int64_t now = clock_->TimeInMilliseconds(); - last_process_time_ = now; + next_process_time_ = now + kRtpRtcpMaxIdleTimeProcessMs; if (rtp_sender_) { - const int64_t kRtpRtcpBitrateProcessTimeMs = 10; if (now >= last_bitrate_process_time_ + kRtpRtcpBitrateProcessTimeMs) { rtp_sender_->ProcessBitrate(); last_bitrate_process_time_ = now; + next_process_time_ = + std::min(next_process_time_, now + kRtpRtcpBitrateProcessTimeMs); + } + if (keepalive_config_.timeout_interval_ms > 0 && + now >= next_keepalive_time_) { + int64_t last_send_time_ms = rtp_sender_->LastTimestampTimeMs(); + // If no packet has been sent, |last_send_time_ms| will be 0, and so the + // keep-alive will be triggered as expected. + if (now >= last_send_time_ms + keepalive_config_.timeout_interval_ms) { + rtp_sender_->SendKeepAlive(keepalive_config_.payload_type); + next_keepalive_time_ = now + keepalive_config_.timeout_interval_ms; + } else { + next_keepalive_time_ = + last_send_time_ms + keepalive_config_.timeout_interval_ms; + } + next_process_time_ = std::min(next_process_time_, next_keepalive_time_); } } - const int64_t kRtpRtcpRttProcessTimeMs = 1000; + bool process_rtt = now >= last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs; if (rtcp_sender_.Sending()) { // Process RTT if we have received a receiver report and we haven't @@ -201,6 +229,8 @@ void ModuleRtpRtcpImpl::Process() { // Get processed rtt. if (process_rtt) { last_rtt_process_time_ = now; + next_process_time_ = std::min( + next_process_time_, last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs); if (rtt_stats_) { // Make sure we have a valid RTT before setting. int64_t last_rtt = rtt_stats_->LastProcessedRtt(); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h index 0c46e40e1e..edec70a60a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -335,9 +335,12 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp { const Clock* const clock_; const bool audio_; - int64_t last_process_time_; + + const RtpKeepAliveConfig keepalive_config_; int64_t last_bitrate_process_time_; int64_t last_rtt_process_time_; + int64_t next_process_time_; + int64_t next_keepalive_time_; uint16_t packet_overhead_; // Send side diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc index 73bdd7a5ab..0c84719295 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc @@ -53,11 +53,12 @@ class SendTransport : public Transport, public RtpData { public: SendTransport() - : receiver_(NULL), - clock_(NULL), + : receiver_(nullptr), + clock_(nullptr), delay_ms_(0), - rtp_packets_sent_(0) { - } + rtp_packets_sent_(0), + keepalive_payload_type_(0), + num_keepalive_sent_(0) {} void SetRtpRtcpModule(ModuleRtpRtcpImpl* receiver) { receiver_ = receiver; @@ -73,6 +74,8 @@ class SendTransport : public Transport, std::unique_ptr parser(RtpHeaderParser::Create()); EXPECT_TRUE(parser->Parse(static_cast(data), len, &header)); ++rtp_packets_sent_; + if (header.payloadType == keepalive_payload_type_) + ++num_keepalive_sent_; last_rtp_header_ = header; return true; } @@ -93,12 +96,18 @@ class SendTransport : public Transport, const WebRtcRTPHeader* rtp_header) override { return 0; } + void SetKeepalivePayloadType(uint8_t payload_type) { + keepalive_payload_type_ = payload_type; + } + size_t NumKeepaliveSent() { return num_keepalive_sent_; } ModuleRtpRtcpImpl* receiver_; SimulatedClock* clock_; int64_t delay_ms_; int rtp_packets_sent_; RTPHeader last_rtp_header_; std::vector last_nack_list_; + uint8_t keepalive_payload_type_; + size_t num_keepalive_sent_; }; class RtpRtcpModule : public RtcpPacketTypeCounterObserver { @@ -106,19 +115,9 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver { explicit RtpRtcpModule(SimulatedClock* clock) : receive_statistics_(ReceiveStatistics::Create(clock)), remote_ssrc_(0), - retransmission_rate_limiter_(clock, kMaxRttMs) { - RtpRtcp::Configuration config; - config.audio = false; - config.clock = clock; - config.outgoing_transport = &transport_; - config.receive_statistics = receive_statistics_.get(); - config.rtcp_packet_type_counter_observer = this; - config.rtt_stats = &rtt_stats_; - config.retransmission_rate_limiter = &retransmission_rate_limiter_; - - impl_.reset(new ModuleRtpRtcpImpl(config)); - impl_->SetRTCPStatus(RtcpMode::kCompound); - + retransmission_rate_limiter_(clock, kMaxRttMs), + clock_(clock) { + CreateModuleImpl(); transport_.SimulateNetworkDelay(kOneWayNetworkDelayMs, clock); } @@ -130,6 +129,7 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver { std::unique_ptr impl_; uint32_t remote_ssrc_; RateLimiter retransmission_rate_limiter_; + RtpKeepAliveConfig keepalive_config_; void SetRemoteSsrc(uint32_t ssrc) { remote_ssrc_ = ssrc; @@ -160,8 +160,30 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver { std::vector LastNackListSent() { return transport_.last_nack_list_; } + void SetKeepaliveConfigAndReset(const RtpKeepAliveConfig& config) { + keepalive_config_ = config; + // Need to create a new module impl, since it's configured at creation. + CreateModuleImpl(); + transport_.SetKeepalivePayloadType(config.payload_type); + } private: + void CreateModuleImpl() { + RtpRtcp::Configuration config; + config.audio = false; + config.clock = clock_; + config.outgoing_transport = &transport_; + config.receive_statistics = receive_statistics_.get(); + config.rtcp_packet_type_counter_observer = this; + config.rtt_stats = &rtt_stats_; + config.retransmission_rate_limiter = &retransmission_rate_limiter_; + config.keepalive_config = keepalive_config_; + + impl_.reset(new ModuleRtpRtcpImpl(config)); + impl_->SetRTCPStatus(RtcpMode::kCompound); + } + + SimulatedClock* const clock_; std::map counter_map_; }; } // namespace @@ -169,9 +191,9 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver { class RtpRtcpImplTest : public ::testing::Test { protected: RtpRtcpImplTest() - : clock_(133590000000000), - sender_(&clock_), - receiver_(&clock_) { + : clock_(133590000000000), sender_(&clock_), receiver_(&clock_) {} + + void SetUp() override { // Send module. sender_.impl_->SetSSRC(kSenderSsrc); EXPECT_EQ(0, sender_.impl_->SetSendingStatus(true)); @@ -196,6 +218,7 @@ class RtpRtcpImplTest : public ::testing::Test { sender_.transport_.SetRtpRtcpModule(receiver_.impl_.get()); receiver_.transport_.SetRtpRtcpModule(sender_.impl_.get()); } + SimulatedClock clock_; RtpRtcpModule sender_; RtpRtcpModule receiver_; @@ -567,4 +590,58 @@ TEST_F(RtpRtcpImplTest, UniqueNackRequests) { EXPECT_EQ(6U, sender_.RtcpReceived().unique_nack_requests); EXPECT_EQ(75, sender_.RtcpReceived().UniqueNackRequestsInPercent()); } + +TEST_F(RtpRtcpImplTest, SendsKeepaliveAfterTimout) { + const int kTimeoutMs = 1500; + + RtpKeepAliveConfig config; + config.timeout_interval_ms = kTimeoutMs; + + // Recreate sender impl with new configuration, and redo setup. + sender_.SetKeepaliveConfigAndReset(config); + SetUp(); + + // Initial process call. + sender_.impl_->Process(); + EXPECT_EQ(0U, sender_.transport_.NumKeepaliveSent()); + + // After one time, a single keep-alive packet should be sent. + clock_.AdvanceTimeMilliseconds(kTimeoutMs); + sender_.impl_->Process(); + EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent()); + + // Process for the same timestamp again, no new packet should be sent. + sender_.impl_->Process(); + EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent()); + + // Move ahead to the last ms before a keep-alive is expected, no action. + clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1); + sender_.impl_->Process(); + EXPECT_EQ(1U, sender_.transport_.NumKeepaliveSent()); + + // Move the final ms, timeout relative last KA. Should create new keep-alive. + clock_.AdvanceTimeMilliseconds(1); + sender_.impl_->Process(); + EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent()); + + // Move ahead to the last ms before Christmas. + clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1); + sender_.impl_->Process(); + EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent()); + + // Send actual payload data, no keep-alive expected. + SendFrame(&sender_, 0); + sender_.impl_->Process(); + EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent()); + + // Move ahead as far as possible again, timeout now relative payload. No KA. + clock_.AdvanceTimeMilliseconds(kTimeoutMs - 1); + sender_.impl_->Process(); + EXPECT_EQ(2U, sender_.transport_.NumKeepaliveSent()); + + // Timeout relative payload, send new keep-alive. + clock_.AdvanceTimeMilliseconds(1); + sender_.impl_->Process(); + EXPECT_EQ(3U, sender_.transport_.NumKeepaliveSent()); +} } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index 759bc9c980..06c2ea905a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -1289,4 +1289,24 @@ void RTPSender::UpdateRtpOverhead(const RtpPacketToSend& packet) { overhead_observer_->OnOverheadChanged(overhead_bytes_per_packet); } +int64_t RTPSender::LastTimestampTimeMs() const { + rtc::CritScope lock(&send_critsect_); + return last_timestamp_time_ms_; +} + +void RTPSender::SendKeepAlive(uint8_t payload_type) { + std::unique_ptr packet = AllocatePacket(); + packet->SetPayloadType(payload_type); + // Set marker bit and timestamps in the same manner as plain padding packets. + packet->SetMarker(false); + { + rtc::CritScope lock(&send_critsect_); + packet->SetTimestamp(last_rtp_timestamp_); + packet->set_capture_time_ms(capture_time_ms_); + } + AssignSequenceNumber(packet.get()); + SendToNetwork(std::move(packet), StorageType::kDontRetransmit, + RtpPacketSender::Priority::kLowPriority); +} + } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index 83bdc64c8f..56739ae4fa 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -205,6 +205,9 @@ class RTPSender { void SetRtxRtpState(const RtpState& rtp_state); RtpState GetRtxRtpState() const; + int64_t LastTimestampTimeMs() const; + void SendKeepAlive(uint8_t payload_type); + protected: int32_t CheckPayloadType(int8_t payload_type, RtpVideoCodecTypes* video_type); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index 89c1d1de56..f786c5d120 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -57,6 +57,7 @@ const uint8_t kPayloadData[] = {47, 11, 32, 93, 89}; using ::testing::_; using ::testing::ElementsAreArray; +using ::testing::Invoke; uint64_t ConvertMsToAbsSendTime(int64_t time_ms) { return (((time_ms << 18) + 500) / 1000) & 0x00ffffff; @@ -1711,6 +1712,40 @@ TEST_P(RtpSenderTest, SendAudioPadding) { rtp_sender_->TimeToSendPadding(kMinPaddingSize - 5, PacedPacketInfo())); } +TEST_P(RtpSenderTest, SendsKeepAlive) { + MockTransport transport; + rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &mock_rtc_event_log_, nullptr, + &retransmission_rate_limiter_, nullptr)); + rtp_sender_->SetSendPayloadType(kPayload); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetTimestampOffset(0); + rtp_sender_->SetSSRC(kSsrc); + + const uint8_t kKeepalivePayloadType = 20; + RTC_CHECK_NE(kKeepalivePayloadType, kPayload); + + EXPECT_CALL(transport, SendRtp(_, _, _)) + .WillOnce( + Invoke([&kKeepalivePayloadType](const uint8_t* packet, size_t len, + const PacketOptions& options) { + webrtc::RTPHeader rtp_header; + RtpUtility::RtpHeaderParser parser(packet, len); + EXPECT_TRUE(parser.Parse(&rtp_header, nullptr)); + EXPECT_FALSE(rtp_header.markerBit); + EXPECT_EQ(0U, rtp_header.paddingLength); + EXPECT_EQ(kKeepalivePayloadType, rtp_header.payloadType); + EXPECT_EQ(kSeqNum, rtp_header.sequenceNumber); + EXPECT_EQ(kSsrc, rtp_header.ssrc); + EXPECT_EQ(0u, len - rtp_header.headerLength); + return true; + })); + + rtp_sender_->SendKeepAlive(kKeepalivePayloadType); + EXPECT_EQ(kSeqNum + 1, rtp_sender_->SequenceNumber()); +} + INSTANTIATE_TEST_CASE_P(WithAndWithoutOverhead, RtpSenderTest, ::testing::Bool()); diff --git a/webrtc/video/replay.cc b/webrtc/video/replay.cc index 6f4ce678f0..25c71c42ef 100644 --- a/webrtc/video/replay.cc +++ b/webrtc/video/replay.cc @@ -302,8 +302,8 @@ void RtpReplay() { std::unique_ptr parser(RtpHeaderParser::Create()); parser->Parse(packet.data, packet.length, &header); fprintf(stderr, "Packet len=%zu pt=%u seq=%u ts=%u ssrc=0x%8x\n", - packet.length, header.payloadType, header.sequenceNumber, - header.timestamp, header.ssrc); + packet.length, header.payloadType, header.sequenceNumber, + header.timestamp, header.ssrc); break; } } diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index f4c82f49c1..fba3315a3b 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -58,7 +58,8 @@ std::vector CreateRtpRtcpModules( RtcEventLog* event_log, RateLimiter* retransmission_rate_limiter, OverheadObserver* overhead_observer, - size_t num_modules) { + size_t num_modules, + RtpKeepAliveConfig keepalive_config) { RTC_DCHECK_GT(num_modules, 0); RtpRtcp::Configuration configuration; ReceiveStatistics* null_receive_statistics = configuration.receive_statistics; @@ -83,6 +84,7 @@ std::vector CreateRtpRtcpModules( configuration.event_log = event_log; configuration.retransmission_rate_limiter = retransmission_rate_limiter; configuration.overhead_observer = overhead_observer; + configuration.keepalive_config = keepalive_config; std::vector modules; for (size_t i = 0; i < num_modules; ++i) { RtpRtcp* rtp_rtcp = RtpRtcp::CreateRtpRtcp(configuration); @@ -802,7 +804,8 @@ VideoSendStreamImpl::VideoSendStreamImpl( event_log, transport->send_side_cc()->GetRetransmissionRateLimiter(), this, - config_->rtp.ssrcs.size())), + config_->rtp.ssrcs.size(), + config_->rtp.keep_alive)), payload_router_(rtp_rtcp_modules_, config_->encoder_settings.payload_type), weak_ptr_factory_(this), diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc index 37a0249e37..7fa12e1c50 100644 --- a/webrtc/video/video_send_stream_tests.cc +++ b/webrtc/video/video_send_stream_tests.cc @@ -32,13 +32,14 @@ #include "webrtc/test/call_test.h" #include "webrtc/test/configurable_frame_size_encoder.h" #include "webrtc/test/fake_texture_frame.h" +#include "webrtc/test/field_trial.h" #include "webrtc/test/frame_generator.h" +#include "webrtc/test/frame_generator_capturer.h" #include "webrtc/test/frame_utils.h" #include "webrtc/test/gtest.h" #include "webrtc/test/null_transport.h" #include "webrtc/test/rtcp_packet_parser.h" #include "webrtc/test/testsupport/perf_test.h" -#include "webrtc/test/field_trial.h" #include "webrtc/video/send_statistics_proxy.h" #include "webrtc/video/transport_adapter.h" @@ -3407,4 +3408,51 @@ TEST_F(VideoSendStreamTest, RemoveOverheadFromBandwidth) { RunBaseTest(&test); } +TEST_F(VideoSendStreamTest, SendsKeepAlive) { + const int kTimeoutMs = 50; // Really short timeout for testing. + const int kPayloadType = 20; + + class KeepaliveObserver : public test::SendTest { + public: + KeepaliveObserver() : SendTest(kDefaultTimeoutMs) {} + + private: + Action OnSendRtp(const uint8_t* packet, size_t length) override { + RTPHeader header; + EXPECT_TRUE(parser_->Parse(packet, length, &header)); + + if (header.payloadType != kPayloadType) { + // The video stream has started. Stop it now. + if (capturer_) + capturer_->Stop(); + } else { + observation_complete_.Set(); + } + + return SEND_PACKET; + } + + void ModifyVideoConfigs( + VideoSendStream::Config* send_config, + std::vector* receive_configs, + VideoEncoderConfig* encoder_config) override { + send_config->rtp.keep_alive.timeout_interval_ms = kTimeoutMs; + send_config->rtp.keep_alive.payload_type = kPayloadType; + } + + void PerformTest() override { + EXPECT_TRUE(Wait()) << "Timed out while waiting for keep-alive packet."; + } + + void OnFrameGeneratorCapturerCreated( + test::FrameGeneratorCapturer* frame_generator_capturer) override { + capturer_ = frame_generator_capturer; + } + + test::FrameGeneratorCapturer* capturer_ = nullptr; + } test; + + RunBaseTest(&test); +} + } // namespace webrtc diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h index 266112e587..53be83f2aa 100644 --- a/webrtc/video_send_stream.h +++ b/webrtc/video_send_stream.h @@ -168,6 +168,8 @@ class VideoSendStream { int payload_type = -1; } rtx; + RtpKeepAliveConfig keep_alive; + // RTCP CNAME, see RFC 3550. std::string c_name; } rtp;