From bfacda60be5f816a04bd278d4aa4cd3d8fd01e9f Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Wed, 27 Mar 2013 16:36:01 +0000 Subject: [PATCH] Add interface to signal a network down event. - In real-time mode encoding will be paused until the network is back up. - In buffering mode the encoder will keep encoding, and packets will be buffered at the sender. When the buffer grows above the target delay encoding will be paused. - Fixes a couple of issues related to pacing which was found with the new test. - Introduces different max bitrates for pacing and for encoding. This allows the pacer to faster get rid of the queue after a network down event. (Work based on issue 1237004) BUG=1524 TESTS=trybots,vie_auto_test Review URL: https://webrtc-codereview.appspot.com/1258004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3730 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/modules/pacing/include/paced_sender.h | 12 ++- webrtc/modules/pacing/paced_sender.cc | 25 ++++++ .../modules/pacing/paced_sender_unittest.cc | 11 ++- .../modules/rtp_rtcp/source/rtp_rtcp_impl.cc | 14 +++- webrtc/modules/rtp_rtcp/source/rtp_sender.cc | 2 +- .../rtp_rtcp/source/rtp_sender_video.cc | 2 +- .../main/source/media_optimization.cc | 6 ++ .../main/source/video_coding_impl.cc | 79 +++++++++---------- webrtc/video_engine/include/vie_network.h | 7 +- .../auto_test/source/vie_autotest_rtp_rtcp.cc | 75 ++++++++++++++++++ webrtc/video_engine/vie_encoder.cc | 55 ++++++++++--- webrtc/video_engine/vie_encoder.h | 8 +- webrtc/video_engine/vie_network_impl.cc | 26 ++++++ webrtc/video_engine/vie_network_impl.h | 2 + 14 files changed, 263 insertions(+), 61 deletions(-) diff --git a/webrtc/modules/pacing/include/paced_sender.h b/webrtc/modules/pacing/include/paced_sender.h index 26aefe5244..58c4b36e17 100644 --- a/webrtc/modules/pacing/include/paced_sender.h +++ b/webrtc/modules/pacing/include/paced_sender.h @@ -64,6 +64,9 @@ class PacedSender : public Module { bool SendPacket(Priority priority, uint32_t ssrc, uint16_t sequence_number, int64_t capture_time_ms, int bytes); + // Returns the time since the oldest queued packet was captured. + int QueueInMs() const; + // Returns the number of milliseconds until the module want a worker thread // to call Process. virtual int32_t TimeUntilNextProcess(); @@ -85,6 +88,9 @@ class PacedSender : public Module { int64_t capture_time_ms_; int bytes_; }; + + typedef std::list PacketList; + // Checks if next packet in line can be transmitted. Returns true on success. bool GetNextPacket(uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms); @@ -109,9 +115,9 @@ class PacedSender : public Module { TickTime time_last_update_; TickTime time_last_send_; - std::list high_priority_packets_; - std::list normal_priority_packets_; - std::list low_priority_packets_; + PacketList high_priority_packets_; + PacketList normal_priority_packets_; + PacketList low_priority_packets_; }; } // namespace webrtc #endif // WEBRTC_MODULES_PACED_SENDER_H_ diff --git a/webrtc/modules/pacing/paced_sender.cc b/webrtc/modules/pacing/paced_sender.cc index 1001b33a90..4f3fbd3ad2 100644 --- a/webrtc/modules/pacing/paced_sender.cc +++ b/webrtc/modules/pacing/paced_sender.cc @@ -82,6 +82,9 @@ bool PacedSender::SendPacket(Priority priority, uint32_t ssrc, UpdateState(bytes); return true; // We can send now. } + if (capture_time_ms < 0) { + capture_time_ms = TickTime::MillisecondTimestamp(); + } if (paused_) { // Queue all packets when we are paused. switch (priority) { @@ -135,6 +138,28 @@ bool PacedSender::SendPacket(Priority priority, uint32_t ssrc, return false; } +int PacedSender::QueueInMs() const { + CriticalSectionScoped cs(critsect_.get()); + int64_t now_ms = TickTime::MillisecondTimestamp(); + int64_t oldest_packet_capture_time = now_ms; + if (!high_priority_packets_.empty()) { + oldest_packet_capture_time = std::min( + oldest_packet_capture_time, + high_priority_packets_.front().capture_time_ms_); + } + if (!normal_priority_packets_.empty()) { + oldest_packet_capture_time = std::min( + oldest_packet_capture_time, + normal_priority_packets_.front().capture_time_ms_); + } + if (!low_priority_packets_.empty()) { + oldest_packet_capture_time = std::min( + oldest_packet_capture_time, + low_priority_packets_.front().capture_time_ms_); + } + return now_ms - oldest_packet_capture_time; +} + int32_t PacedSender::TimeUntilNextProcess() { CriticalSectionScoped cs(critsect_.get()); int64_t elapsed_time_ms = diff --git a/webrtc/modules/pacing/paced_sender_unittest.cc b/webrtc/modules/pacing/paced_sender_unittest.cc index da6e673278..943c3c81f2 100644 --- a/webrtc/modules/pacing/paced_sender_unittest.cc +++ b/webrtc/modules/pacing/paced_sender_unittest.cc @@ -185,8 +185,11 @@ TEST_F(PacedSenderTest, Pause) { uint32_t ssrc_low_priority = 12345; uint32_t ssrc = 12346; uint16_t sequence_number = 1234; - int64_t capture_time_ms = 56789; - int64_t second_capture_time_ms = 67890; + int64_t capture_time_ms = TickTime::MillisecondTimestamp(); + TickTime::AdvanceFakeClock(10000); + int64_t second_capture_time_ms = TickTime::MillisecondTimestamp(); + + EXPECT_EQ(0, send_bucket_->QueueInMs()); // Due to the multiplicative factor we can send 3 packets not 2 packets. EXPECT_TRUE(send_bucket_->SendPacket(PacedSender::kLowPriority, @@ -208,6 +211,9 @@ TEST_F(PacedSenderTest, Pause) { EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kHighPriority, ssrc, sequence_number++, capture_time_ms, 250)); + EXPECT_EQ(TickTime::MillisecondTimestamp() - capture_time_ms, + send_bucket_->QueueInMs()); + // Expect no packet to come out while paused. EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0); EXPECT_CALL(callback_, TimeToSendPacket(_, _, _)).Times(0); @@ -235,6 +241,7 @@ TEST_F(PacedSenderTest, Pause) { TickTime::AdvanceFakeClock(5); EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); EXPECT_EQ(0, send_bucket_->Process()); + EXPECT_EQ(0, send_bucket_->QueueInMs()); } } // namespace test diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 8626512a49..2d90074592 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -987,15 +987,25 @@ void ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc, (*it)->rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms); return; } - it++; + ++it; } } else { - bool have_child_modules(child_modules_.empty() ? false : true); + bool have_child_modules = !child_modules_.empty(); if (!have_child_modules) { // Don't send from default module. if (SendingMedia() && ssrc == rtp_sender_.SSRC()) { rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms); } + } else { + CriticalSectionScoped lock(critical_section_module_ptrs_.get()); + std::list::iterator it = child_modules_.begin(); + while (it != child_modules_.end()) { + if ((*it)->SendingMedia() && ssrc == (*it)->rtp_sender_.SSRC()) { + (*it)->rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms); + return; + } + ++it; + } } } } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index 50cf9f9bc5..c84373c4f2 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -673,7 +673,7 @@ WebRtc_Word32 RTPSender::SendToNetwork( } } - if (paced_sender_) { + if (paced_sender_ && storage != kDontStore) { if (!paced_sender_->SendPacket( PacedSender::kNormalPriority, rtp_header.header.ssrc, rtp_header.header.sequenceNumber, capture_time_ms, diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc index b99d1ac539..204f4e6d47 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -205,7 +205,7 @@ RTPSenderVideo::SendRTPIntraRequest() ModuleRTPUtility::AssignUWord32ToBuffer(data+4, _rtpSender.SSRC()); - return _rtpSender.SendToNetwork(data, 0, length, -1, kAllowRetransmission); + return _rtpSender.SendToNetwork(data, 0, length, -1, kDontStore); } WebRtc_Word32 diff --git a/webrtc/modules/video_coding/main/source/media_optimization.cc b/webrtc/modules/video_coding/main/source/media_optimization.cc index daa53583b8..fbed51cfec 100644 --- a/webrtc/modules/video_coding/main/source/media_optimization.cc +++ b/webrtc/modules/video_coding/main/source/media_optimization.cc @@ -94,6 +94,12 @@ VCMMediaOptimization::SetTargetRates(WebRtc_UWord32 target_bitrate, WebRtc_UWord8 &fractionLost, WebRtc_UWord32 roundTripTimeMs) { + // TODO(holmer): Consider putting this threshold only on the video bitrate, + // and not on protection. + if (_maxBitRate > 0 && + target_bitrate > static_cast(_maxBitRate)) { + target_bitrate = _maxBitRate; + } VCMProtectionMethod *selectedMethod = _lossProtLogic->SelectedMethod(); float target_bitrate_kbps = static_cast(target_bitrate) / 1000.0f; _lossProtLogic->UpdateBitRate(target_bitrate_kbps); diff --git a/webrtc/modules/video_coding/main/source/video_coding_impl.cc b/webrtc/modules/video_coding/main/source/video_coding_impl.cc index 242961bd2c..b1e46a8d77 100644 --- a/webrtc/modules/video_coding/main/source/video_coding_impl.cc +++ b/webrtc/modules/video_coding/main/source/video_coding_impl.cc @@ -47,50 +47,47 @@ VideoCodingModuleImpl::VideoCodingModuleImpl(const WebRtc_Word32 id, Clock* clock, EventFactory* event_factory, bool owns_event_factory) -: -_id(id), -clock_(clock), -_receiveCritSect(CriticalSectionWrapper::CreateCriticalSection()), -_receiverInited(false), -_timing(clock_, id, 1), -_dualTiming(clock_, id, 2, &_timing), -_receiver(&_timing, clock_, event_factory, id, 1, true), -_dualReceiver(&_dualTiming, clock_, event_factory, id, 2, false), -_decodedFrameCallback(_timing, clock_), -_dualDecodedFrameCallback(_dualTiming, clock_), -_frameTypeCallback(NULL), -_frameStorageCallback(NULL), -_receiveStatsCallback(NULL), -_packetRequestCallback(NULL), -_decoder(NULL), -_dualDecoder(NULL), + : _id(id), + clock_(clock), + _receiveCritSect(CriticalSectionWrapper::CreateCriticalSection()), + _receiverInited(false), + _timing(clock_, id, 1), + _dualTiming(clock_, id, 2, &_timing), + _receiver(&_timing, clock_, event_factory, id, 1, true), + _dualReceiver(&_dualTiming, clock_, event_factory, id, 2, false), + _decodedFrameCallback(_timing, clock_), + _dualDecodedFrameCallback(_dualTiming, clock_), + _frameTypeCallback(NULL), + _frameStorageCallback(NULL), + _receiveStatsCallback(NULL), + _packetRequestCallback(NULL), + _decoder(NULL), + _dualDecoder(NULL), #ifdef DEBUG_DECODER_BIT_STREAM -_bitStreamBeforeDecoder(NULL), + _bitStreamBeforeDecoder(NULL), #endif -_frameFromFile(), -_keyRequestMode(kKeyOnError), -_scheduleKeyRequest(false), -max_nack_list_size_(0), - -_sendCritSect(CriticalSectionWrapper::CreateCriticalSection()), -_encoder(), -_encodedFrameCallback(), -_nextFrameTypes(1, kVideoFrameDelta), -_mediaOpt(id, clock_), -_sendCodecType(kVideoCodecUnknown), -_sendStatsCallback(NULL), -_encoderInputFile(NULL), -_codecDataBase(id), -_receiveStatsTimer(1000, clock_), -_sendStatsTimer(1000, clock_), -_retransmissionTimer(10, clock_), -_keyRequestTimer(500, clock_), -event_factory_(event_factory), -owns_event_factory_(owns_event_factory) -{ - assert(clock_); + _frameFromFile(), + _keyRequestMode(kKeyOnError), + _scheduleKeyRequest(false), + max_nack_list_size_(0), + _sendCritSect(CriticalSectionWrapper::CreateCriticalSection()), + _encoder(), + _encodedFrameCallback(), + _nextFrameTypes(1, kVideoFrameDelta), + _mediaOpt(id, clock_), + _sendCodecType(kVideoCodecUnknown), + _sendStatsCallback(NULL), + _encoderInputFile(NULL), + _codecDataBase(id), + _receiveStatsTimer(1000, clock_), + _sendStatsTimer(1000, clock_), + _retransmissionTimer(10, clock_), + _keyRequestTimer(500, clock_), + event_factory_(event_factory), + owns_event_factory_(owns_event_factory) { + assert(clock_); #ifdef DEBUG_DECODER_BIT_STREAM - _bitStreamBeforeDecoder = fopen("decoderBitStream.bit", "wb"); + _bitStreamBeforeDecoder = fopen("decoderBitStream.bit", "wb"); #endif } diff --git a/webrtc/video_engine/include/vie_network.h b/webrtc/video_engine/include/vie_network.h index 9752008d93..4d2b7b81f8 100644 --- a/webrtc/video_engine/include/vie_network.h +++ b/webrtc/video_engine/include/vie_network.h @@ -19,7 +19,7 @@ // - Packet timeout notification. // - Dead‐or‐Alive connection observations. -#include "common_types.h" +#include "webrtc/common_types.h" namespace webrtc { @@ -65,6 +65,11 @@ class WEBRTC_DLLEXPORT ViENetwork { // for all sub-API:s before the VideoEngine object can be safely deleted. virtual int Release() = 0; + // Inform the engine about if the network adapter is currently transmitting + // packets or not. + virtual void SetNetworkTransmissionState(const int video_channel, + const bool is_transmitting) = 0; + // Specifies the ports to receive RTP packets on. It is also possible to set // port for RTCP and local IP address. virtual int SetLocalReceiver(const int video_channel, 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 8aa99eecf1..aadd874c0a 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 @@ -365,6 +365,81 @@ void ViEAutoTest::ViERtpRtcpStandardTest() // short above? // EXPECT_LT(inEndPos, outEndPos + 100); + EXPECT_EQ(0, ViE.base->StopReceive(tbChannel.videoChannel)); + + ViETest::Log("Testing Network Down...\n"); + + EXPECT_EQ(0, ViE.rtp_rtcp->SetNACKStatus(tbChannel.videoChannel, true)); + EXPECT_EQ(0, ViE.rtp_rtcp->SetTransmissionSmoothingStatus( + tbChannel.videoChannel, true)); + EXPECT_EQ(0, ViE.base->StartReceive(tbChannel.videoChannel)); + EXPECT_EQ(0, ViE.base->StartSend(tbChannel.videoChannel)); + + // Real-time mode. + AutoTestSleep(kAutoTestSleepTimeMs); + EXPECT_EQ(0, ViE.rtp_rtcp->GetBandwidthUsage( + tbChannel.videoChannel, sentTotalBitrate, sentVideoBitrate, + sentFecBitrate, sentNackBitrate)); + EXPECT_GT(sentTotalBitrate, 0u); + // Simulate lost reception and verify that nothing is sent during that time. + ViE.network->SetNetworkTransmissionState(tbChannel.videoChannel, false); + ViETest::Log("Network Down...\n"); + AutoTestSleep(kAutoTestSleepTimeMs); + EXPECT_EQ(0, ViE.rtp_rtcp->GetBandwidthUsage( + tbChannel.videoChannel, sentTotalBitrate, sentVideoBitrate, + sentFecBitrate, sentNackBitrate)); + EXPECT_EQ(sentTotalBitrate, 0u); + + // Network reception back. Video should now be sent. + ViE.network->SetNetworkTransmissionState(tbChannel.videoChannel, true); + ViETest::Log("Network Up...\n"); + AutoTestSleep(kAutoTestSleepTimeMs); + EXPECT_EQ(0, ViE.rtp_rtcp->GetBandwidthUsage( + tbChannel.videoChannel, sentTotalBitrate, sentVideoBitrate, + sentFecBitrate, sentNackBitrate)); + EXPECT_GT(sentTotalBitrate, 0u); + + // Buffering mode. + EXPECT_EQ(0, ViE.base->StopSend(tbChannel.videoChannel)); + EXPECT_EQ(0, ViE.base->StopReceive(tbChannel.videoChannel)); + ViE.rtp_rtcp->SetSenderBufferingMode(tbChannel.videoChannel, + kAutoTestSleepTimeMs / 2); + // Add extra delay to the receiver to make sure it doesn't flush due to + // too old packets being received (as the down-time introduced is longer + // than what we buffer at the sender). + ViE.rtp_rtcp->SetReceiverBufferingMode(tbChannel.videoChannel, + 3 * kAutoTestSleepTimeMs / 2); + EXPECT_EQ(0, ViE.base->StartReceive(tbChannel.videoChannel)); + EXPECT_EQ(0, ViE.base->StartSend(tbChannel.videoChannel)); + AutoTestSleep(kAutoTestSleepTimeMs); + EXPECT_EQ(0, ViE.rtp_rtcp->GetBandwidthUsage( + tbChannel.videoChannel, sentTotalBitrate, sentVideoBitrate, + sentFecBitrate, sentNackBitrate)); + EXPECT_GT(sentTotalBitrate, 0u); + // Simulate lost reception and verify that nothing is sent during that time. + ViETest::Log("Network Down...\n"); + ViE.network->SetNetworkTransmissionState(tbChannel.videoChannel, false); + AutoTestSleep(kAutoTestSleepTimeMs); + EXPECT_EQ(0, ViE.rtp_rtcp->GetBandwidthUsage( + tbChannel.videoChannel, sentTotalBitrate, sentVideoBitrate, + sentFecBitrate, sentNackBitrate)); + EXPECT_EQ(sentTotalBitrate, 0u); + // Network reception back. Video should now be sent. + ViETest::Log("Network Up...\n"); + ViE.network->SetNetworkTransmissionState(tbChannel.videoChannel, true); + AutoTestSleep(kAutoTestSleepTimeMs); + EXPECT_EQ(0, ViE.rtp_rtcp->GetBandwidthUsage( + tbChannel.videoChannel, sentTotalBitrate, sentVideoBitrate, + sentFecBitrate, sentNackBitrate)); + EXPECT_GT(sentTotalBitrate, 0u); + // TODO(holmer): Verify that the decoded framerate doesn't decrease on an + // outage when in buffering mode. This isn't currently possible because we + // don't have an API to get decoded framerate. + + EXPECT_EQ(0, ViE.base->StopSend(tbChannel.videoChannel)); + EXPECT_EQ(0, ViE.base->StopReceive(tbChannel.videoChannel)); + + // Deregister external transport EXPECT_EQ(0, ViE.network->DeregisterSendTransport(tbChannel.videoChannel)); diff --git a/webrtc/video_engine/vie_encoder.cc b/webrtc/video_engine/vie_encoder.cc index 01a7672569..034370b7c0 100644 --- a/webrtc/video_engine/vie_encoder.cc +++ b/webrtc/video_engine/vie_encoder.cc @@ -30,7 +30,12 @@ namespace webrtc { // Pace in kbits/s until we receive first estimate. -const int kInitialPace = 2000; +static const int kInitialPace = 2000; +// Allow packets to be transmitted in up to 2 times max video bitrate if the +// bandwidth estimate allows it. +// TODO(holmer): Expose transmission start, min and max bitrates in the +// VideoEngine API and remove the kTransmissionMaxBitrateMultiplier. +static const int kTransmissionMaxBitrateMultiplier = 2; class QMVideoSettingsCallback : public VCMQMSettingsCallback { public: @@ -93,7 +98,9 @@ ViEEncoder::ViEEncoder(WebRtc_Word32 engine_id, callback_cs_(CriticalSectionWrapper::CreateCriticalSection()), data_cs_(CriticalSectionWrapper::CreateCriticalSection()), bitrate_controller_(bitrate_controller), - paused_(false), + target_delay_ms_(0), + network_is_transmitting_(true), + encoder_paused_(false), channels_dropping_delta_frames_(0), drop_next_frame_(false), fec_enabled_(false), @@ -227,12 +234,28 @@ int ViEEncoder::Owner() const { return channel_id_; } +void ViEEncoder::SetNetworkTransmissionState(bool is_transmitting) { + WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, + ViEId(engine_id_, channel_id_), + "%s(%s)", __FUNCTION__, + is_transmitting ? "transmitting" : "not transmitting"); + { + CriticalSectionScoped cs(data_cs_.get()); + network_is_transmitting_ = is_transmitting; + } + if (is_transmitting) { + paced_sender_->Resume(); + } else { + paced_sender_->Pause(); + } +} + void ViEEncoder::Pause() { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(engine_id_, channel_id_), "%s", __FUNCTION__); CriticalSectionScoped cs(data_cs_.get()); - paused_ = true; + encoder_paused_ = true; } void ViEEncoder::Restart() { @@ -240,7 +263,7 @@ void ViEEncoder::Restart() { ViEId(engine_id_, channel_id_), "%s", __FUNCTION__); CriticalSectionScoped cs(data_cs_.get()); - paused_ = false; + encoder_paused_ = false; } WebRtc_Word32 ViEEncoder::DropDeltaAfterKey(bool enable) { @@ -386,6 +409,7 @@ WebRtc_Word32 ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) { bitrate_controller_->SetBitrateObserver(bitrate_observer_.get(), video_codec.startBitrate * 1000, video_codec.minBitrate * 1000, + kTransmissionMaxBitrateMultiplier * video_codec.maxBitrate * 1000); return 0; @@ -446,6 +470,15 @@ void ViEEncoder::TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number, default_rtp_rtcp_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms); } +bool ViEEncoder::EncoderPaused() const { + // Pause video if paused by caller or as long as the network is down and the + // pacer queue has grown too large. + const bool max_send_buffer_reached = + paced_sender_->QueueInMs() >= target_delay_ms_; + return encoder_paused_ || + (!network_is_transmitting_ && max_send_buffer_reached); +} + RtpRtcp* ViEEncoder::SendRtpRtcpModule() { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(engine_id_, channel_id_), "%s", __FUNCTION__); @@ -464,7 +497,7 @@ void ViEEncoder::DeliverFrame(int id, video_frame->timestamp()); { CriticalSectionScoped cs(data_cs_.get()); - if (paused_ || default_rtp_rtcp_->SendingMedia() == false) { + if (EncoderPaused() || default_rtp_rtcp_->SendingMedia() == false) { // We've paused or we have no channels attached, don't encode. return; } @@ -708,10 +741,14 @@ WebRtc_Word32 ViEEncoder::UpdateProtectionMethod() { } void ViEEncoder::SetSenderBufferingMode(int target_delay_ms) { + { + CriticalSectionScoped cs(data_cs_.get()); + target_delay_ms_ = target_delay_ms; + } if (target_delay_ms > 0) { - // Disable external frame-droppers. - vcm_.EnableFrameDropper(false); - vpm_.EnableTemporalDecimation(false); + // Disable external frame-droppers. + vcm_.EnableFrameDropper(false); + vpm_.EnableTemporalDecimation(false); } else { // Real-time mode - enable frame droppers. vpm_.EnableTemporalDecimation(true); @@ -730,7 +767,7 @@ WebRtc_Word32 ViEEncoder::SendData( const RTPVideoHeader* rtp_video_hdr) { { CriticalSectionScoped cs(data_cs_.get()); - if (paused_) { + if (EncoderPaused()) { // Paused, don't send this packet. return 0; } diff --git a/webrtc/video_engine/vie_encoder.h b/webrtc/video_engine/vie_encoder.h index 08295a7a79..8e03518921 100644 --- a/webrtc/video_engine/vie_encoder.h +++ b/webrtc/video_engine/vie_encoder.h @@ -57,6 +57,8 @@ class ViEEncoder bool Init(); + void SetNetworkTransmissionState(bool is_transmitting); + // Returns the id of the owning channel. int Owner() const; @@ -173,6 +175,8 @@ class ViEEncoder int64_t capture_time_ms); private: + bool EncoderPaused() const; + WebRtc_Word32 engine_id_; const int channel_id_; const WebRtc_UWord32 number_of_cores_; @@ -188,7 +192,9 @@ class ViEEncoder BitrateController* bitrate_controller_; - bool paused_; + int target_delay_ms_; + bool network_is_transmitting_; + bool encoder_paused_; std::map time_last_intra_request_ms_; WebRtc_Word32 channels_dropping_delta_frames_; bool drop_next_frame_; diff --git a/webrtc/video_engine/vie_network_impl.cc b/webrtc/video_engine/vie_network_impl.cc index 378d08f316..5be15e5e61 100644 --- a/webrtc/video_engine/vie_network_impl.cc +++ b/webrtc/video_engine/vie_network_impl.cc @@ -60,6 +60,32 @@ int ViENetworkImpl::Release() { return ref_count; } +void ViENetworkImpl::SetNetworkTransmissionState(const int video_channel, + const bool is_transmitting) { + WEBRTC_TRACE(kTraceApiCall, kTraceVideo, + ViEId(shared_data_->instance_id(), video_channel), + "%s(event: Network %s)", __FUNCTION__, + is_transmitting ? "transmitting" : "not transmitting"); + if (!shared_data_->Initialized()) { + shared_data_->SetLastError(kViENotInitialized); + WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(shared_data_->instance_id()), + "%s - ViE instance %d not initialized", __FUNCTION__, + shared_data_->instance_id()); + return; + } + + ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); + ViEEncoder* vie_encoder = cs.Encoder(video_channel); + if (!vie_encoder) { + WEBRTC_TRACE(kTraceError, kTraceVideo, + ViEId(shared_data_->instance_id(), video_channel), + "An encoder doesn't exist for this channel"); + shared_data_->SetLastError(kViENetworkInvalidChannelId); + return; + } + vie_encoder->SetNetworkTransmissionState(is_transmitting); +} + ViENetworkImpl::ViENetworkImpl(ViESharedData* shared_data) : shared_data_(shared_data) { WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_->instance_id(), diff --git a/webrtc/video_engine/vie_network_impl.h b/webrtc/video_engine/vie_network_impl.h index 56832df089..0a233e79d2 100644 --- a/webrtc/video_engine/vie_network_impl.h +++ b/webrtc/video_engine/vie_network_impl.h @@ -25,6 +25,8 @@ class ViENetworkImpl public: // Implements ViENetwork. virtual int Release(); + virtual void SetNetworkTransmissionState(const int video_channel, + const bool is_transmitting); virtual int SetLocalReceiver(const int video_channel, const uint16_t rtp_port, const uint16_t rtcp_port,