diff --git a/webrtc/video_engine/include/vie_rtp_rtcp.h b/webrtc/video_engine/include/vie_rtp_rtcp.h index 73b444a1b..83b6f57b1 100644 --- a/webrtc/video_engine/include/vie_rtp_rtcp.h +++ b/webrtc/video_engine/include/vie_rtp_rtcp.h @@ -22,7 +22,7 @@ #ifndef WEBRTC_VIDEO_ENGINE_INCLUDE_VIE_RTP_RTCP_H_ #define WEBRTC_VIDEO_ENGINE_INCLUDE_VIE_RTP_RTCP_H_ -#include "common_types.h" +#include "webrtc/common_types.h" namespace webrtc { @@ -199,6 +199,12 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP { const unsigned char payload_typeRED, const unsigned char payload_typeFEC) = 0; + // Enables send side support for delayed video streaming (actual delay will + // be exhibited on the receiver side). + // Target delay should be set to zero for real-time mode. + virtual int EnableSenderStreamingMode(int video_channel, + int target_delay_ms) = 0; + // This function enables RTCP key frame requests. virtual int SetKeyFrameRequestMethod( const int video_channel, const ViEKeyFrameRequestMethod method) = 0; diff --git a/webrtc/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc b/webrtc/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc index d8bf8aa90..64d5c2dee 100644 --- a/webrtc/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc +++ b/webrtc/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc @@ -687,6 +687,21 @@ void ViEAutoTest::ViERtpRtcpAPITest() EXPECT_EQ(0, ViE.rtp_rtcp->SetTransmissionSmoothingStatus( tbChannel.videoChannel, false)); + // Streaming Mode. + EXPECT_EQ(-1, ViE.rtp_rtcp->EnableSenderStreamingMode( + invalid_channel_id, 0)); + int invalid_delay = -1; + EXPECT_EQ(-1, ViE.rtp_rtcp->EnableSenderStreamingMode( + tbChannel.videoChannel, invalid_delay)); + invalid_delay = 15000; + EXPECT_EQ(-1, ViE.rtp_rtcp->EnableSenderStreamingMode( + tbChannel.videoChannel, invalid_delay)); + EXPECT_EQ(0, ViE.rtp_rtcp->EnableSenderStreamingMode( + tbChannel.videoChannel, 5000)); + // Real-time mode. + EXPECT_EQ(0, ViE.rtp_rtcp->EnableSenderStreamingMode( + tbChannel.videoChannel, 0)); + //*************************************************************** // Testing finished. Tear down Video Engine //*************************************************************** diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index 0c137095a..b3e1b7eb2 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -35,6 +35,7 @@ namespace webrtc { const int kMaxDecodeWaitTimeMs = 50; const int kInvalidRtpExtensionId = 0; +static const int kMaxTargetDelayMs = 10000; // Helper class receiving statistics callbacks. class ChannelStatsObserver : public StatsObserver { @@ -102,7 +103,8 @@ ViEChannel::ViEChannel(WebRtc_Word32 channel_id, color_enhancement_(false), file_recorder_(channel_id), mtu_(0), - sender_(sender) { + sender_(sender), + nack_history_size_sender_(kSendSidePacketHistorySize) { WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id, channel_id), "ViEChannel::ViEChannel(channel_id: %d, engine_id: %d)", channel_id, engine_id); @@ -151,7 +153,7 @@ WebRtc_Word32 ViEChannel::Init() { "%s: RTP::SetRTCPStatus failure", __FUNCTION__); } if (paced_sender_) { - if (rtp_rtcp_->SetStorePacketsStatus(true, kSendSidePacketHistorySize) != + if (rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_) != 0) { WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_), "%s:SetStorePacketsStatus failure", __FUNCTION__); @@ -295,10 +297,10 @@ WebRtc_Word32 ViEChannel::SetSendCodec(const VideoCodec& video_codec, "%s: RTP::SetRTCPStatus failure", __FUNCTION__); } if (nack_method != kNackOff) { - rtp_rtcp->SetStorePacketsStatus(true, kSendSidePacketHistorySize); + rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_); rtp_rtcp->SetNACKStatus(nack_method, kMaxPacketAgeToNack); } else if (paced_sender_) { - rtp_rtcp->SetStorePacketsStatus(true, kSendSidePacketHistorySize); + rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_); } if (fec_enabled) { rtp_rtcp->SetGenericFECStatus(fec_enabled, payload_type_red, @@ -628,7 +630,7 @@ WebRtc_Word32 ViEChannel::ProcessNACKRequest(const bool enable) { } WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s: Using NACK method %d", __FUNCTION__, nackMethod); - rtp_rtcp_->SetStorePacketsStatus(true, kSendSidePacketHistorySize); + rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_); vcm_.RegisterPacketRequestCallback(this); @@ -639,7 +641,7 @@ WebRtc_Word32 ViEChannel::ProcessNACKRequest(const bool enable) { it++) { RtpRtcp* rtp_rtcp = *it; rtp_rtcp->SetNACKStatus(nackMethod, kMaxPacketAgeToNack); - rtp_rtcp->SetStorePacketsStatus(true, kSendSidePacketHistorySize); + rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_); } } else { CriticalSectionScoped cs(rtp_rtcp_cs_.get()); @@ -721,6 +723,45 @@ WebRtc_Word32 ViEChannel::SetHybridNACKFECStatus( return ProcessFECRequest(enable, payload_typeRED, payload_typeFEC); } +int ViEChannel::EnableSenderStreamingMode(int target_delay_ms) { + if ((target_delay_ms < 0) || (target_delay_ms > kMaxTargetDelayMs)) { + WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), + "%s: Target streaming delay out of bounds: %d", __FUNCTION__, + target_delay_ms); + return -1; + } + if (target_delay_ms == 0) { + // Real-time mode. + nack_history_size_sender_ = kSendSidePacketHistorySize; + vcm_.EnableFrameDropper(true); + } else { + // The max size of the nack list should be large enough to accommodate the + // the number of packets(frames) resulting from the increased delay. + // Roughly estimating for ~15 packets per frame @ 30fps. + nack_history_size_sender_ = target_delay_ms * 15 * 30 / 1000; + // Don't allow a number lower than the default value. + if (nack_history_size_sender_ < kSendSidePacketHistorySize) { + nack_history_size_sender_ = kSendSidePacketHistorySize; + } + // Disable external VCM frame-dropper. In streaming mode, we are more + // flexible with rate control constraints. + vcm_.EnableFrameDropper(false); + } + // Setting nack_history_size_. + // First disabling (forcing free) and then resetting to desired value. + if (rtp_rtcp_->SetStorePacketsStatus(false, 0) != 0) { + WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), + "%s:SetStorePacketsStatus failure", __FUNCTION__); + return -1; + } + if (rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_) != 0) { + WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_), + "%s:SetStorePacketsStatus failure", __FUNCTION__); + return -1; + } + return 0; +} + WebRtc_Word32 ViEChannel::SetKeyFrameRequestMethod( const KeyFrameRequestMethod method) { WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h index 4ff77f5a5..5eec802b1 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -116,6 +116,7 @@ class ViEChannel WebRtc_Word32 SetHybridNACKFECStatus(const bool enable, const unsigned char payload_typeRED, const unsigned char payload_typeFEC); + int EnableSenderStreamingMode(int target_delay_ms); WebRtc_Word32 SetKeyFrameRequestMethod(const KeyFrameRequestMethod method); bool EnableRemb(bool enable); int SetSendTimestampOffsetStatus(bool enable, int id); @@ -422,6 +423,8 @@ class ViEChannel // User set MTU, -1 if not set. uint16_t mtu_; const bool sender_; + + int nack_history_size_sender_; }; } // namespace webrtc diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc index 0c047d7ad..7bd6f6d2e 100644 --- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc +++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc @@ -553,6 +553,33 @@ int ViERTP_RTCPImpl::SetHybridNACKFECStatus( return 0; } +int ViERTP_RTCPImpl::EnableSenderStreamingMode(int video_channel, + int target_delay_ms) { + WEBRTC_TRACE(kTraceApiCall, kTraceVideo, + ViEId(shared_data_->instance_id(), video_channel), + "%s(channel: %d, target_delay: %d)", + __FUNCTION__, video_channel, target_delay_ms); + ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); + ViEChannel* vie_channel = cs.Channel(video_channel); + if (!vie_channel) { + WEBRTC_TRACE(kTraceError, kTraceVideo, + ViEId(shared_data_->instance_id(), video_channel), + "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); + shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + + // Update the channel's streaming mode settings. + if (vie_channel->EnableSenderStreamingMode(target_delay_ms) != 0) { + WEBRTC_TRACE(kTraceError, kTraceVideo, + ViEId(shared_data_->instance_id(), video_channel), + "%s: failed for channel %d", __FUNCTION__, video_channel); + shared_data_->SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + int ViERTP_RTCPImpl::SetKeyFrameRequestMethod( const int video_channel, const ViEKeyFrameRequestMethod method) { diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.h b/webrtc/video_engine/vie_rtp_rtcp_impl.h index 577e0853e..210afcf9b 100644 --- a/webrtc/video_engine/vie_rtp_rtcp_impl.h +++ b/webrtc/video_engine/vie_rtp_rtcp_impl.h @@ -64,6 +64,8 @@ class ViERTP_RTCPImpl virtual int SetHybridNACKFECStatus(const int video_channel, const bool enable, const unsigned char payload_typeRED, const unsigned char payload_typeFEC); + virtual int EnableSenderStreamingMode(int video_channel, + int target_delay_ms); virtual int SetKeyFrameRequestMethod(const int video_channel, const ViEKeyFrameRequestMethod method); virtual int SetTMMBRStatus(const int video_channel, const bool enable);