diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc index 3d636c2a67..1a5f28ef04 100644 --- a/webrtc/audio/audio_send_stream.cc +++ b/webrtc/audio/audio_send_stream.cc @@ -28,7 +28,6 @@ #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" #include "webrtc/modules/congestion_controller/include/send_side_congestion_controller.h" #include "webrtc/modules/pacing/paced_sender.h" -#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" #include "webrtc/voice_engine/channel_proxy.h" #include "webrtc/voice_engine/include/voe_base.h" #include "webrtc/voice_engine/transmit_mixer.h" @@ -59,7 +58,8 @@ AudioSendStream::AudioSendStream( RtpTransportControllerSendInterface* transport, BitrateAllocator* bitrate_allocator, RtcEventLog* event_log, - RtcpRttStats* rtcp_rtt_stats) + RtcpRttStats* rtcp_rtt_stats, + const rtc::Optional& suspended_rtp_state) : worker_queue_(worker_queue), config_(Config(nullptr)), audio_state_(audio_state), @@ -68,7 +68,9 @@ AudioSendStream::AudioSendStream( transport_(transport), packet_loss_tracker_(kPacketLossTrackerMaxWindowSizeMs, kPacketLossRateMinNumAckedPackets, - kRecoverablePacketLossRateMinNumAckedPairs) { + kRecoverablePacketLossRateMinNumAckedPairs), + rtp_rtcp_module_(nullptr), + suspended_rtp_state_(suspended_rtp_state) { LOG(LS_INFO) << "AudioSendStream: " << config.ToString(); RTC_DCHECK_NE(config.voe_channel_id, -1); RTC_DCHECK(audio_state_.get()); @@ -81,6 +83,9 @@ AudioSendStream::AudioSendStream( channel_proxy_->SetRtcpRttStats(rtcp_rtt_stats); channel_proxy_->SetRTCPStatus(true); transport_->send_side_cc()->RegisterPacketFeedbackObserver(this); + RtpReceiver* rtpReceiver = nullptr; // Unused, but required for call. + channel_proxy_->GetRtpRtcp(&rtp_rtcp_module_, &rtpReceiver); + RTC_DCHECK(rtp_rtcp_module_); ConfigureStream(this, config, true); @@ -112,6 +117,9 @@ void AudioSendStream::ConfigureStream( if (first_time || old_config.rtp.ssrc != new_config.rtp.ssrc) { channel_proxy->SetLocalSSRC(new_config.rtp.ssrc); + if (stream->suspended_rtp_state_) { + stream->rtp_rtcp_module_->SetRtpState(*stream->suspended_rtp_state_); + } } if (first_time || old_config.rtp.c_name != new_config.rtp.c_name) { channel_proxy->SetRTCP_CNAME(new_config.rtp.c_name); @@ -375,6 +383,10 @@ void AudioSendStream::SetTransportOverhead(int transport_overhead_per_packet) { channel_proxy_->SetTransportOverhead(transport_overhead_per_packet); } +RtpState AudioSendStream::GetRtpState() const { + return rtp_rtcp_module_->GetRtpState(); +} + VoiceEngine* AudioSendStream::voice_engine() const { internal::AudioState* audio_state = static_cast(audio_state_.get()); @@ -588,13 +600,10 @@ void AudioSendStream::RemoveBitrateObserver() { void AudioSendStream::RegisterCngPayloadType(int payload_type, int clockrate_hz) { - RtpRtcp* rtpRtcpModule = nullptr; - RtpReceiver* rtpReceiver = nullptr; // Unused, but required for call. - channel_proxy_->GetRtpRtcp(&rtpRtcpModule, &rtpReceiver); const CodecInst codec = {payload_type, "CN", clockrate_hz, 0, 1, 0}; - if (rtpRtcpModule->RegisterSendPayload(codec) != 0) { - rtpRtcpModule->DeRegisterSendPayload(codec.pltype); - if (rtpRtcpModule->RegisterSendPayload(codec) != 0) { + if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) { + rtp_rtcp_module_->DeRegisterSendPayload(codec.pltype); + if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) { LOG(LS_ERROR) << "RegisterCngPayloadType() failed to register CN to " "RTP/RTCP module"; } diff --git a/webrtc/audio/audio_send_stream.h b/webrtc/audio/audio_send_stream.h index 065fee7894..881c68ed4d 100644 --- a/webrtc/audio/audio_send_stream.h +++ b/webrtc/audio/audio_send_stream.h @@ -19,7 +19,7 @@ #include "webrtc/call/audio_send_stream.h" #include "webrtc/call/audio_state.h" #include "webrtc/call/bitrate_allocator.h" -#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" #include "webrtc/voice_engine/transport_feedback_packet_loss_tracker.h" namespace webrtc { @@ -44,7 +44,8 @@ class AudioSendStream final : public webrtc::AudioSendStream, RtpTransportControllerSendInterface* transport, BitrateAllocator* bitrate_allocator, RtcEventLog* event_log, - RtcpRttStats* rtcp_rtt_stats); + RtcpRttStats* rtcp_rtt_stats, + const rtc::Optional& suspended_rtp_state); ~AudioSendStream() override; // webrtc::AudioSendStream implementation. @@ -74,6 +75,8 @@ class AudioSendStream final : public webrtc::AudioSendStream, const webrtc::AudioSendStream::Config& config() const; void SetTransportOverhead(int transport_overhead_per_packet); + RtpState GetRtpState() const; + private: VoiceEngine* voice_engine() const; @@ -111,6 +114,9 @@ class AudioSendStream final : public webrtc::AudioSendStream, TransportFeedbackPacketLossTracker packet_loss_tracker_ GUARDED_BY(&packet_loss_tracker_cs_); + RtpRtcp* rtp_rtcp_module_; + rtc::Optional const suspended_rtp_state_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream); }; } // namespace internal diff --git a/webrtc/audio/audio_send_stream_unittest.cc b/webrtc/audio/audio_send_stream_unittest.cc index 69ac2e4cfa..e6acf92efb 100644 --- a/webrtc/audio/audio_send_stream_unittest.cc +++ b/webrtc/audio/audio_send_stream_unittest.cc @@ -354,7 +354,7 @@ TEST(AudioSendStreamTest, ConstructDestruct) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); } TEST(AudioSendStreamTest, SendTelephoneEvent) { @@ -362,7 +362,7 @@ TEST(AudioSendStreamTest, SendTelephoneEvent) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); helper.SetupMockForSendTelephoneEvent(); EXPECT_TRUE(send_stream.SendTelephoneEvent(kTelephoneEventPayloadType, kTelephoneEventPayloadFrequency, kTelephoneEventCode, @@ -374,7 +374,7 @@ TEST(AudioSendStreamTest, SetMuted) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); EXPECT_CALL(*helper.channel_proxy(), SetInputMute(true)); send_stream.SetMuted(true); } @@ -384,7 +384,7 @@ TEST(AudioSendStreamTest, AudioBweCorrectObjectsOnChannelProxy) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); } TEST(AudioSendStreamTest, NoAudioBweCorrectObjectsOnChannelProxy) { @@ -392,7 +392,7 @@ TEST(AudioSendStreamTest, NoAudioBweCorrectObjectsOnChannelProxy) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); } TEST(AudioSendStreamTest, GetStats) { @@ -400,7 +400,7 @@ TEST(AudioSendStreamTest, GetStats) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); helper.SetupMockForGetStats(); AudioSendStream::Stats stats = send_stream.GetStats(); EXPECT_EQ(kSsrc, stats.local_ssrc); @@ -431,7 +431,7 @@ TEST(AudioSendStreamTest, GetStatsTypingNoiseDetected) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); helper.SetupMockForGetStats(); EXPECT_FALSE(send_stream.GetStats().typing_noise_detected); @@ -465,7 +465,7 @@ TEST(AudioSendStreamTest, SendCodecAppliesNetworkAdaptor) { internal::AudioSendStream send_stream( stream_config, helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); } // VAD is applied when codec is mono and the CNG frequency matches the codec @@ -489,7 +489,7 @@ TEST(AudioSendStreamTest, SendCodecCanApplyVad) { internal::AudioSendStream send_stream( stream_config, helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); // We cannot truly determine if the encoder created is an AudioEncoderCng. It // is the only reasonable implementation that will return something from @@ -503,7 +503,7 @@ TEST(AudioSendStreamTest, DoesNotPassHigherBitrateThanMaxBitrate) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); EXPECT_CALL(*helper.channel_proxy(), SetBitrate(helper.config().max_bitrate_bps, _)); send_stream.OnBitrateUpdated(helper.config().max_bitrate_bps + 5000, 0.0, 50, @@ -515,7 +515,7 @@ TEST(AudioSendStreamTest, ProbingIntervalOnBitrateUpdated) { internal::AudioSendStream send_stream( helper.config(), helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); EXPECT_CALL(*helper.channel_proxy(), SetBitrate(_, 5000)); send_stream.OnBitrateUpdated(50000, 0.0, 50, 5000); } @@ -538,7 +538,7 @@ TEST(AudioSendStreamTest, DontRecreateEncoder) { internal::AudioSendStream send_stream( stream_config, helper.audio_state(), helper.worker_queue(), helper.transport(), helper.bitrate_allocator(), helper.event_log(), - helper.rtcp_rtt_stats()); + helper.rtcp_rtt_stats(), rtc::Optional()); send_stream.Reconfigure(stream_config); } diff --git a/webrtc/call/BUILD.gn b/webrtc/call/BUILD.gn index 7728104cd1..a6afe30240 100644 --- a/webrtc/call/BUILD.gn +++ b/webrtc/call/BUILD.gn @@ -93,6 +93,7 @@ if (rtc_include_tests) { ] deps = [ ":call", + "../api:mock_audio_mixer", "../base:rtc_base_approved", "../logging:rtc_event_log_api", "../modules/audio_device:mock_audio_device", diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc index 87e41b0b41..a1aa1de5f7 100644 --- a/webrtc/call/call.cc +++ b/webrtc/call/call.cc @@ -305,7 +305,12 @@ class Call : public webrtc::Call, std::map video_send_ssrcs_ GUARDED_BY(send_crit_); std::set video_send_streams_ GUARDED_BY(send_crit_); - VideoSendStream::RtpStateMap suspended_video_send_ssrcs_; + using RtpStateMap = std::map; + RtpStateMap suspended_audio_send_ssrcs_ + GUARDED_BY(configuration_thread_checker_); + RtpStateMap suspended_video_send_ssrcs_ + GUARDED_BY(configuration_thread_checker_); + webrtc::RtcEventLog* event_log_; // The following members are only accessed (exclusively) from one thread and @@ -392,7 +397,7 @@ Call::Call(const Call::Config& config, video_send_delay_stats_(new SendDelayStats(clock_)), start_ms_(clock_->TimeInMilliseconds()), worker_queue_("call_worker_queue") { - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); RTC_DCHECK(config.event_log != nullptr); RTC_DCHECK_GE(config.bitrate_config.min_bitrate_bps, 0); RTC_DCHECK_GE(config.bitrate_config.start_bitrate_bps, @@ -426,7 +431,7 @@ Call::Call(const Call::Config& config, } Call::~Call() { - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); RTC_CHECK(audio_send_ssrcs_.empty()); RTC_CHECK(video_send_ssrcs_.empty()); @@ -553,18 +558,28 @@ void Call::UpdateReceiveHistograms() { PacketReceiver* Call::Receiver() { // TODO(solenberg): Some test cases in EndToEndTest use this from a different // thread. Re-enable once that is fixed. - // RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + // RTC_DCHECK_RUN_ON(&configuration_thread_checker_); return this; } webrtc::AudioSendStream* Call::CreateAudioSendStream( const webrtc::AudioSendStream::Config& config) { TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); event_log_->LogAudioSendStreamConfig(CreateRtcLogStreamConfig(config)); + + rtc::Optional suspended_rtp_state; + { + const auto& iter = suspended_audio_send_ssrcs_.find(config.rtp.ssrc); + if (iter != suspended_audio_send_ssrcs_.end()) { + suspended_rtp_state.emplace(iter->second); + } + } + AudioSendStream* send_stream = new AudioSendStream( config, config_.audio_state, &worker_queue_, transport_send_.get(), - bitrate_allocator_.get(), event_log_, call_stats_->rtcp_rtt_stats()); + bitrate_allocator_.get(), event_log_, call_stats_->rtcp_rtt_stats(), + suspended_rtp_state); { WriteLockScoped write_lock(*send_crit_); RTC_DCHECK(audio_send_ssrcs_.find(config.rtp.ssrc) == @@ -586,14 +601,15 @@ webrtc::AudioSendStream* Call::CreateAudioSendStream( void Call::DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) { TRACE_EVENT0("webrtc", "Call::DestroyAudioSendStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); RTC_DCHECK(send_stream != nullptr); send_stream->Stop(); webrtc::internal::AudioSendStream* audio_send_stream = static_cast(send_stream); - uint32_t ssrc = audio_send_stream->config().rtp.ssrc; + const uint32_t ssrc = audio_send_stream->config().rtp.ssrc; + suspended_audio_send_ssrcs_[ssrc] = audio_send_stream->GetRtpState(); { WriteLockScoped write_lock(*send_crit_); size_t num_deleted = audio_send_ssrcs_.erase(ssrc); @@ -614,7 +630,7 @@ void Call::DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) { webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream( const webrtc::AudioReceiveStream::Config& config) { TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); event_log_->LogAudioReceiveStreamConfig(CreateRtcLogStreamConfig(config)); AudioReceiveStream* receive_stream = new AudioReceiveStream(transport_send_->packet_router(), config, @@ -643,7 +659,7 @@ webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream( void Call::DestroyAudioReceiveStream( webrtc::AudioReceiveStream* receive_stream) { TRACE_EVENT0("webrtc", "Call::DestroyAudioReceiveStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); RTC_DCHECK(receive_stream != nullptr); webrtc::internal::AudioReceiveStream* audio_receive_stream = static_cast(receive_stream); @@ -673,7 +689,7 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream( webrtc::VideoSendStream::Config config, VideoEncoderConfig encoder_config) { TRACE_EVENT0("webrtc", "Call::CreateVideoSendStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); video_send_delay_stats_->AddSsrcs(config); for (size_t ssrc_index = 0; ssrc_index < config.rtp.ssrcs.size(); @@ -709,7 +725,7 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream( void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) { TRACE_EVENT0("webrtc", "Call::DestroyVideoSendStream"); RTC_DCHECK(send_stream != nullptr); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); send_stream->Stop(); @@ -744,7 +760,7 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) { webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream( webrtc::VideoReceiveStream::Config configuration) { TRACE_EVENT0("webrtc", "Call::CreateVideoReceiveStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); VideoReceiveStream* receive_stream = new VideoReceiveStream(num_cpu_cores_, transport_send_->packet_router(), @@ -778,7 +794,7 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream( void Call::DestroyVideoReceiveStream( webrtc::VideoReceiveStream* receive_stream) { TRACE_EVENT0("webrtc", "Call::DestroyVideoReceiveStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); RTC_DCHECK(receive_stream != nullptr); VideoReceiveStream* receive_stream_impl = static_cast(receive_stream); @@ -807,7 +823,7 @@ void Call::DestroyVideoReceiveStream( FlexfecReceiveStream* Call::CreateFlexfecReceiveStream( const FlexfecReceiveStream::Config& config) { TRACE_EVENT0("webrtc", "Call::CreateFlexfecReceiveStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); RecoveredPacketReceiver* recovered_packet_receiver = this; FlexfecReceiveStreamImpl* receive_stream = new FlexfecReceiveStreamImpl( @@ -834,7 +850,7 @@ FlexfecReceiveStream* Call::CreateFlexfecReceiveStream( void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) { TRACE_EVENT0("webrtc", "Call::DestroyFlexfecReceiveStream"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); RTC_DCHECK(receive_stream != nullptr); // There exist no other derived classes of FlexfecReceiveStream, @@ -862,7 +878,7 @@ void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) { Call::Stats Call::GetStats() const { // TODO(solenberg): Some test cases in EndToEndTest use this from a different // thread. Re-enable once that is fixed. - // RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + // RTC_DCHECK_RUN_ON(&configuration_thread_checker_); Stats stats; // Fetch available send/receive bitrates. uint32_t send_bandwidth = 0; @@ -887,7 +903,7 @@ Call::Stats Call::GetStats() const { void Call::SetBitrateConfig( const webrtc::Call::Config::BitrateConfig& bitrate_config) { TRACE_EVENT0("webrtc", "Call::SetBitrateConfig"); - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); RTC_DCHECK_GE(bitrate_config.min_bitrate_bps, 0); if (bitrate_config.max_bitrate_bps != -1) RTC_DCHECK_GT(bitrate_config.max_bitrate_bps, 0); @@ -914,7 +930,7 @@ void Call::SetBitrateConfig( } void Call::SignalChannelNetworkState(MediaType media, NetworkState state) { - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); switch (media) { case MediaType::AUDIO: audio_network_state_ = state; @@ -976,7 +992,7 @@ void Call::OnTransportOverheadChanged(MediaType media, // TODO(honghaiz): Add tests for this method. void Call::OnNetworkRouteChanged(const std::string& transport_name, const rtc::NetworkRoute& network_route) { - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); // Check if the network route is connected. if (!network_route.connected) { LOG(LS_INFO) << "Transport " << transport_name << " is disconnected"; @@ -1013,7 +1029,7 @@ void Call::OnNetworkRouteChanged(const std::string& transport_name, } void Call::UpdateAggregateNetworkState() { - RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread()); + RTC_DCHECK_RUN_ON(&configuration_thread_checker_); bool have_audio = false; bool have_video = false; diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc index 9576beb2ee..06ee2005b1 100644 --- a/webrtc/call/call_unittest.cc +++ b/webrtc/call/call_unittest.cc @@ -13,13 +13,16 @@ #include #include +#include "webrtc/api/test/mock_audio_mixer.h" #include "webrtc/base/ptr_util.h" #include "webrtc/call/audio_state.h" #include "webrtc/call/call.h" #include "webrtc/call/fake_rtp_transport_controller_send.h" #include "webrtc/logging/rtc_event_log/rtc_event_log.h" +#include "webrtc/modules/audio_device/include/mock_audio_device.h" #include "webrtc/modules/audio_mixer/audio_mixer_impl.h" #include "webrtc/modules/congestion_controller/include/mock/mock_send_side_congestion_controller.h" +#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" #include "webrtc/test/gtest.h" #include "webrtc/test/mock_audio_decoder_factory.h" #include "webrtc/test/mock_transport.h" @@ -134,6 +137,7 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_RecvFirst) { rtc::scoped_refptr decoder_factory( new rtc::RefCountedObject); CallHelper call(decoder_factory); + ::testing::NiceMock mock_rtp_rtcp; constexpr int kRecvChannelId = 101; @@ -151,6 +155,8 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_RecvFirst) { [](const std::map& codecs) { EXPECT_THAT(codecs, testing::IsEmpty()); })); + EXPECT_CALL(*channel_proxy, GetRtpRtcp(testing::_, testing::_)) + .WillRepeatedly(testing::SetArgPointee<0>(&mock_rtp_rtcp)); // If being called for the send channel, save a pointer to the channel // proxy for later. if (channel_id == kRecvChannelId) { @@ -186,6 +192,7 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_SendFirst) { rtc::scoped_refptr decoder_factory( new rtc::RefCountedObject); CallHelper call(decoder_factory); + ::testing::NiceMock mock_rtp_rtcp; constexpr int kRecvChannelId = 101; @@ -203,6 +210,8 @@ TEST(CallTest, CreateDestroy_AssociateAudioSendReceiveStreams_SendFirst) { [](const std::map& codecs) { EXPECT_THAT(codecs, testing::IsEmpty()); })); + EXPECT_CALL(*channel_proxy, GetRtpRtcp(testing::_, testing::_)) + .WillRepeatedly(testing::SetArgPointee<0>(&mock_rtp_rtcp)); // If being called for the send channel, save a pointer to the channel // proxy for later. if (channel_id == kRecvChannelId) { @@ -416,4 +425,69 @@ TEST(CallBitrateTest, call->SetBitrateConfig(bitrate_config); } +TEST(CallTest, RecreatingAudioStreamWithSameSsrcReusesRtpState) { + constexpr uint32_t kSSRC = 12345; + testing::NiceMock mock_adm; + // Reply with a 10ms timer every time TimeUntilNextProcess is called to + // avoid entering a tight loop on the process thread. + EXPECT_CALL(mock_adm, TimeUntilNextProcess()) + .WillRepeatedly(testing::Return(10)); + rtc::scoped_refptr mock_mixer( + new rtc::RefCountedObject); + + // There's similar functionality in cricket::VoEWrapper but it's not reachable + // from here. Since we're working on removing VoE interfaces, I doubt it's + // worth making VoEWrapper more easily available. + struct ScopedVoiceEngine { + ScopedVoiceEngine() + : voe(VoiceEngine::Create()), + base(VoEBase::GetInterface(voe)) {} + ~ScopedVoiceEngine() { + base->Release(); + EXPECT_TRUE(VoiceEngine::Delete(voe)); + } + + VoiceEngine* voe; + VoEBase* base; + }; + ScopedVoiceEngine voice_engine; + + voice_engine.base->Init(&mock_adm); + AudioState::Config audio_state_config; + audio_state_config.voice_engine = voice_engine.voe; + audio_state_config.audio_mixer = mock_mixer; + auto audio_state = AudioState::Create(audio_state_config); + RtcEventLogNullImpl event_log; + Call::Config call_config(&event_log); + call_config.audio_state = audio_state; + std::unique_ptr call(Call::Create(call_config)); + + auto create_stream_and_get_rtp_state = [&](uint32_t ssrc) { + AudioSendStream::Config config(nullptr); + config.rtp.ssrc = ssrc; + config.voe_channel_id = voice_engine.base->CreateChannel(); + AudioSendStream* stream = call->CreateAudioSendStream(config); + VoiceEngineImpl* voe_impl = static_cast(voice_engine.voe); + auto channel_proxy = voe_impl->GetChannelProxy(config.voe_channel_id); + RtpRtcp* rtp_rtcp = nullptr; + RtpReceiver* rtp_receiver = nullptr; // Unused but required for call. + channel_proxy->GetRtpRtcp(&rtp_rtcp, &rtp_receiver); + const RtpState rtp_state = rtp_rtcp->GetRtpState(); + call->DestroyAudioSendStream(stream); + voice_engine.base->DeleteChannel(config.voe_channel_id); + return rtp_state; + }; + + const RtpState rtp_state1 = create_stream_and_get_rtp_state(kSSRC); + const RtpState rtp_state2 = create_stream_and_get_rtp_state(kSSRC); + + EXPECT_EQ(rtp_state1.sequence_number, rtp_state2.sequence_number); + EXPECT_EQ(rtp_state1.start_timestamp, rtp_state2.start_timestamp); + EXPECT_EQ(rtp_state1.timestamp, rtp_state2.timestamp); + EXPECT_EQ(rtp_state1.capture_time_ms, rtp_state2.capture_time_ms); + EXPECT_EQ(rtp_state1.last_timestamp_time_ms, + rtp_state2.last_timestamp_time_ms); + EXPECT_EQ(rtp_state1.media_has_been_sent, rtp_state2.media_has_been_sent); +} + } // namespace webrtc diff --git a/webrtc/test/mock_voice_engine.h b/webrtc/test/mock_voice_engine.h index 6b1f9cf31f..7655d3b844 100644 --- a/webrtc/test/mock_voice_engine.h +++ b/webrtc/test/mock_voice_engine.h @@ -16,6 +16,7 @@ #include "webrtc/modules/audio_device/include/mock_audio_device.h" #include "webrtc/modules/audio_device/include/mock_audio_transport.h" #include "webrtc/modules/audio_processing/include/mock_audio_processing.h" +#include "webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" #include "webrtc/test/gmock.h" #include "webrtc/test/mock_voe_channel_proxy.h" #include "webrtc/voice_engine/voice_engine_impl.h" @@ -57,6 +58,9 @@ class MockVoiceEngine : public VoiceEngineImpl { [](const std::map& codecs) { EXPECT_THAT(codecs, testing::IsEmpty()); })); + EXPECT_CALL(*proxy, GetRtpRtcp(testing::_, testing::_)) + .WillRepeatedly( + testing::SetArgPointee<0>(GetMockRtpRtcp(channel_id))); return proxy; })); @@ -74,6 +78,15 @@ class MockVoiceEngine : public VoiceEngineImpl { // trigger an assertion. --_ref_count; } + + // These need to be the same each call to channel_id and must not leak. + MockRtpRtcp* GetMockRtpRtcp(int channel_id) { + if (mock_rtp_rtcps_.find(channel_id) == mock_rtp_rtcps_.end()) { + mock_rtp_rtcps_[channel_id].reset(new ::testing::NiceMock); + } + return mock_rtp_rtcps_[channel_id].get(); + } + // Allows injecting a ChannelProxy factory. MOCK_METHOD1(ChannelProxyFactory, voe::ChannelProxy*(int channel_id)); @@ -241,6 +254,8 @@ class MockVoiceEngine : public VoiceEngineImpl { // voe::Channel does. rtc::scoped_refptr decoder_factory_; + std::map> mock_rtp_rtcps_; + MockAudioDeviceModule mock_audio_device_; MockAudioProcessing mock_audio_processing_; MockAudioTransport mock_audio_transport_;