diff --git a/webrtc/modules/video_coding/main/source/video_coding_impl.h b/webrtc/modules/video_coding/main/source/video_coding_impl.h index bf0bc7905b..816552fe23 100644 --- a/webrtc/modules/video_coding/main/source/video_coding_impl.h +++ b/webrtc/modules/video_coding/main/source/video_coding_impl.h @@ -25,6 +25,7 @@ #include "webrtc/modules/video_coding/main/source/timing.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#include "webrtc/system_wrappers/interface/thread_annotations.h" namespace webrtc { @@ -199,21 +200,25 @@ class VideoReceiver { // in any frame }; - Clock* clock_; + Clock* const clock_; scoped_ptr process_crit_sect_; CriticalSectionWrapper* _receiveCritSect; - bool _receiverInited; + bool _receiverInited GUARDED_BY(_receiveCritSect); VCMTiming _timing; VCMTiming _dualTiming; VCMReceiver _receiver; VCMReceiver _dualReceiver; VCMDecodedFrameCallback _decodedFrameCallback; VCMDecodedFrameCallback _dualDecodedFrameCallback; - VCMFrameTypeCallback* _frameTypeCallback; - VCMReceiveStatisticsCallback* _receiveStatsCallback; - VCMDecoderTimingCallback* _decoderTimingCallback; - VCMPacketRequestCallback* _packetRequestCallback; - VCMRenderBufferSizeCallback* render_buffer_callback_; + VCMFrameTypeCallback* _frameTypeCallback GUARDED_BY(process_crit_sect_); + VCMReceiveStatisticsCallback* _receiveStatsCallback + GUARDED_BY(process_crit_sect_); + VCMDecoderTimingCallback* _decoderTimingCallback + GUARDED_BY(process_crit_sect_); + VCMPacketRequestCallback* _packetRequestCallback + GUARDED_BY(process_crit_sect_); + VCMRenderBufferSizeCallback* render_buffer_callback_ + GUARDED_BY(process_crit_sect_); VCMGenericDecoder* _decoder; VCMGenericDecoder* _dualDecoder; #ifdef DEBUG_DECODER_BIT_STREAM @@ -221,9 +226,9 @@ class VideoReceiver { #endif VCMFrameBuffer _frameFromFile; VCMKeyRequestMode _keyRequestMode; - bool _scheduleKeyRequest; - size_t max_nack_list_size_; - EncodedImageCallback* pre_decode_image_callback_; + bool _scheduleKeyRequest GUARDED_BY(process_crit_sect_); + size_t max_nack_list_size_ GUARDED_BY(process_crit_sect_); + EncodedImageCallback* pre_decode_image_callback_ GUARDED_BY(_receiveCritSect); VCMCodecDataBase _codecDataBase; VCMProcessTimer _receiveStatsTimer; diff --git a/webrtc/modules/video_coding/main/source/video_receiver.cc b/webrtc/modules/video_coding/main/source/video_receiver.cc index 5bc1c90f52..0b56124927 100644 --- a/webrtc/modules/video_coding/main/source/video_receiver.cc +++ b/webrtc/modules/video_coding/main/source/video_receiver.cc @@ -271,8 +271,6 @@ int32_t VideoReceiver::SetVideoProtection(VCMVideoProtection videoProtection, // Initialize receiver, resets codec database etc int32_t VideoReceiver::InitializeReceiver() { - CriticalSectionScoped receive_cs(_receiveCritSect); - CriticalSectionScoped process_cs(process_crit_sect_.get()); int32_t ret = _receiver.Initialize(); if (ret < 0) { return ret; @@ -285,15 +283,22 @@ int32_t VideoReceiver::InitializeReceiver() { _codecDataBase.ResetReceiver(); _timing.Reset(); - _decoder = NULL; - _decodedFrameCallback.SetUserReceiveCallback(NULL); - _receiverInited = true; - _frameTypeCallback = NULL; - _receiveStatsCallback = NULL; - _decoderTimingCallback = NULL; - _packetRequestCallback = NULL; - _keyRequestMode = kKeyOnError; - _scheduleKeyRequest = false; + { + CriticalSectionScoped receive_cs(_receiveCritSect); + _receiverInited = true; + } + + { + CriticalSectionScoped process_cs(process_crit_sect_.get()); + _decoder = NULL; + _decodedFrameCallback.SetUserReceiveCallback(NULL); + _frameTypeCallback = NULL; + _receiveStatsCallback = NULL; + _decoderTimingCallback = NULL; + _packetRequestCallback = NULL; + _keyRequestMode = kKeyOnError; + _scheduleKeyRequest = false; + } return VCM_OK; } @@ -781,7 +786,6 @@ void VideoReceiver::SetNackSettings(size_t max_nack_list_size, int max_packet_age_to_nack, int max_incomplete_time_ms) { if (max_nack_list_size != 0) { - CriticalSectionScoped receive_cs(_receiveCritSect); CriticalSectionScoped process_cs(process_crit_sect_.get()); max_nack_list_size_ = max_nack_list_size; } diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc index fa3d3cf449..39f1e6942d 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc @@ -1543,4 +1543,80 @@ TEST_F(EndToEndTest, CanSwitchToUseAllSsrcs) { TestSendsSetSsrcs(kNumSsrcs, true); } +TEST_F(EndToEndTest, RedundantPayloadsTransmittedOnAllSsrcs) { + // TODO(pbos): Use CallTest::kSendRtxSsrcs when they're an array (pending CL). + static const uint32_t kSendRtxSsrcs[kNumSsrcs] = { + 0xBADCAFD, 0xBADCAFE, 0xBADCAFF}; + class ObserveRedundantPayloads: public test::EndToEndTest { + public: + ObserveRedundantPayloads() + : EndToEndTest(kDefaultTimeoutMs), ssrcs_to_observe_(kNumSsrcs) { + for(size_t i = 0; i < kNumSsrcs; ++i) { + registered_rtx_ssrc_[kSendRtxSsrcs[i]] = true; + } + } + + private: + virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE { + RTPHeader header; + EXPECT_TRUE(parser_->Parse(packet, static_cast(length), &header)); + + if (!registered_rtx_ssrc_[header.ssrc]) + return SEND_PACKET; + + EXPECT_LE(static_cast(header.headerLength + header.paddingLength), + length); + const bool packet_is_redundant_payload = + static_cast(header.headerLength + header.paddingLength) < + length; + + if (!packet_is_redundant_payload) + return SEND_PACKET; + + if (!observed_redundant_retransmission_[header.ssrc]) { + observed_redundant_retransmission_[header.ssrc] = true; + if (--ssrcs_to_observe_ == 0) + observation_complete_->Set(); + } + + return SEND_PACKET; + } + + virtual size_t GetNumStreams() const OVERRIDE { return kNumSsrcs; } + + virtual void ModifyConfigs( + VideoSendStream::Config* send_config, + std::vector* receive_configs, + std::vector* video_streams) OVERRIDE { + // Set low simulcast bitrates to not have to wait for bandwidth ramp-up. + for (size_t i = 0; i < video_streams->size(); ++i) { + (*video_streams)[i].min_bitrate_bps = 10000; + (*video_streams)[i].target_bitrate_bps = 15000; + (*video_streams)[i].max_bitrate_bps = 20000; + } + // Significantly higher than max bitrates for all video streams -> forcing + // padding to trigger redundant padding on all RTX SSRCs. + send_config->rtp.min_transmit_bitrate_bps = 100000; + + send_config->rtp.rtx.payload_type = kSendRtxPayloadType; + send_config->rtp.rtx.pad_with_redundant_payloads = true; + + for (size_t i = 0; i < kNumSsrcs; ++i) + send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[i]); + } + + virtual void PerformTest() OVERRIDE { + EXPECT_EQ(kEventSignaled, Wait()) + << "Timed out while waiting for redundant payloads on all SSRCs."; + } + + private: + size_t ssrcs_to_observe_; + std::map observed_redundant_retransmission_; + std::map registered_rtx_ssrc_; + } test; + + RunBaseTest(&test); +} + } // namespace webrtc diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index 80d3065b85..3031376da1 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -278,6 +278,11 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, rtp_rtcp->SetSendingStatus(rtp_rtcp_->Sending()); rtp_rtcp->SetSendingMediaStatus(rtp_rtcp_->SendingMedia()); + int mode; + uint32_t ssrc; + int payload_type; + rtp_rtcp_->RTXSendStatus(&mode, &ssrc, &payload_type); + rtp_rtcp->SetRTXSendStatus(mode); simulcast_rtp_rtcp_.push_back(rtp_rtcp); // Silently ignore error.