|  | /* | 
|  | *  Copyright 2012 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  | #include <iterator> | 
|  | #include <memory> | 
|  | #include <optional> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/algorithm/container.h" | 
|  | #include "api/audio_codecs/audio_codec_pair_id.h" | 
|  | #include "api/audio_options.h" | 
|  | #include "api/crypto/crypto_options.h" | 
|  | #include "api/crypto/frame_decryptor_interface.h" | 
|  | #include "api/crypto/frame_encryptor_interface.h" | 
|  | #include "api/dtmf_sender_interface.h" | 
|  | #include "api/environment/environment.h" | 
|  | #include "api/environment/environment_factory.h" | 
|  | #include "api/make_ref_counted.h" | 
|  | #include "api/media_stream_interface.h" | 
|  | #include "api/rtc_error.h" | 
|  | #include "api/rtp_parameters.h" | 
|  | #include "api/rtp_receiver_interface.h" | 
|  | #include "api/scoped_refptr.h" | 
|  | #include "api/test/fake_frame_decryptor.h" | 
|  | #include "api/test/fake_frame_encryptor.h" | 
|  | #include "api/test/rtc_error_matchers.h" | 
|  | #include "api/video/builtin_video_bitrate_allocator_factory.h" | 
|  | #include "api/video/video_bitrate_allocator_factory.h" | 
|  | #include "api/video/video_codec_constants.h" | 
|  | #include "media/base/codec.h" | 
|  | #include "media/base/fake_media_engine.h" | 
|  | #include "media/base/media_channel.h" | 
|  | #include "media/base/media_config.h" | 
|  | #include "media/base/media_engine.h" | 
|  | #include "media/base/rid_description.h" | 
|  | #include "media/base/stream_params.h" | 
|  | #include "media/base/test_utils.h" | 
|  | #include "media/engine/fake_webrtc_call.h" | 
|  | #include "p2p/base/p2p_constants.h" | 
|  | #include "p2p/dtls/dtls_transport_internal.h" | 
|  | #include "p2p/dtls/fake_dtls_transport.h" | 
|  | #include "pc/audio_rtp_receiver.h" | 
|  | #include "pc/audio_track.h" | 
|  | #include "pc/dtls_srtp_transport.h" | 
|  | #include "pc/local_audio_source.h" | 
|  | #include "pc/media_stream.h" | 
|  | #include "pc/rtp_sender.h" | 
|  | #include "pc/rtp_transport_internal.h" | 
|  | #include "pc/test/fake_video_track_source.h" | 
|  | #include "pc/video_rtp_receiver.h" | 
|  | #include "pc/video_track.h" | 
|  | #include "rtc_base/checks.h" | 
|  | #include "rtc_base/thread.h" | 
|  | #include "rtc_base/unique_id_generator.h" | 
|  | #include "test/gmock.h" | 
|  | #include "test/gtest.h" | 
|  | #include "test/run_loop.h" | 
|  | #include "test/wait_until.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | constexpr char kStreamId1[] = "local_stream_1"; | 
|  | constexpr char kVideoTrackId[] = "video_1"; | 
|  | constexpr char kAudioTrackId[] = "audio_1"; | 
|  | constexpr uint32_t kVideoSsrc = 98; | 
|  | constexpr uint32_t kVideoSsrc2 = 100; | 
|  | constexpr uint32_t kAudioSsrc = 99; | 
|  | constexpr uint32_t kAudioSsrc2 = 101; | 
|  | constexpr uint32_t kVideoSsrcSimulcast = 102; | 
|  | constexpr uint32_t kVideoSimulcastLayerCount = 2; | 
|  |  | 
|  | class MockSetStreamsObserver | 
|  | : public webrtc::RtpSenderBase::SetStreamsObserver { | 
|  | public: | 
|  | MOCK_METHOD(void, OnSetStreams, (), (override)); | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | using ::testing::ContainerEq; | 
|  | using RidList = std::vector<std::string>; | 
|  |  | 
|  | class RtpSenderReceiverTest | 
|  | : public ::testing::Test, | 
|  | public ::testing::WithParamInterface<std::pair<RidList, RidList>> { | 
|  | public: | 
|  | RtpSenderReceiverTest() | 
|  | : network_thread_(Thread::Current()), | 
|  | worker_thread_(Thread::Current()), | 
|  | video_bitrate_allocator_factory_( | 
|  | CreateBuiltinVideoBitrateAllocatorFactory()), | 
|  | // Create fake media engine/etc. so we can create channels to use to | 
|  | // test RtpSenders/RtpReceivers. | 
|  | media_engine_(std::make_unique<FakeMediaEngine>()), | 
|  | fake_call_(env_, worker_thread_, network_thread_), | 
|  | local_stream_(MediaStream::Create(kStreamId1)) { | 
|  | rtp_dtls_transport_ = std::make_unique<FakeDtlsTransport>( | 
|  | "fake_dtls_transport", ICE_CANDIDATE_COMPONENT_RTP); | 
|  | rtp_transport_ = CreateDtlsSrtpTransport(); | 
|  |  | 
|  | // Create the channels, discard the result; we get them later. | 
|  | // Fake media channels are owned by the media engine. | 
|  | voice_media_send_channel_ = media_engine_->voice().CreateSendChannel( | 
|  | &fake_call_, MediaConfig(), AudioOptions(), CryptoOptions(), | 
|  | AudioCodecPairId::Create()); | 
|  | video_media_send_channel_ = media_engine_->video().CreateSendChannel( | 
|  | &fake_call_, MediaConfig(), VideoOptions(), CryptoOptions(), | 
|  | video_bitrate_allocator_factory_.get()); | 
|  | voice_media_receive_channel_ = media_engine_->voice().CreateReceiveChannel( | 
|  | &fake_call_, MediaConfig(), AudioOptions(), CryptoOptions(), | 
|  | AudioCodecPairId::Create()); | 
|  | video_media_receive_channel_ = media_engine_->video().CreateReceiveChannel( | 
|  | &fake_call_, MediaConfig(), VideoOptions(), CryptoOptions()); | 
|  |  | 
|  | // Create streams for predefined SSRCs. Streams need to exist in order | 
|  | // for the senders and receievers to apply parameters to them. | 
|  | // Normally these would be created by SetLocalDescription and | 
|  | // SetRemoteDescription. | 
|  | voice_media_send_channel_->AddSendStream( | 
|  | StreamParams::CreateLegacy(kAudioSsrc)); | 
|  | voice_media_receive_channel_->AddRecvStream( | 
|  | StreamParams::CreateLegacy(kAudioSsrc)); | 
|  | voice_media_send_channel_->AddSendStream( | 
|  | StreamParams::CreateLegacy(kAudioSsrc2)); | 
|  | voice_media_receive_channel_->AddRecvStream( | 
|  | StreamParams::CreateLegacy(kAudioSsrc2)); | 
|  | video_media_send_channel_->AddSendStream( | 
|  | StreamParams::CreateLegacy(kVideoSsrc)); | 
|  | video_media_receive_channel_->AddRecvStream( | 
|  | StreamParams::CreateLegacy(kVideoSsrc)); | 
|  | video_media_send_channel_->AddSendStream( | 
|  | StreamParams::CreateLegacy(kVideoSsrc2)); | 
|  | video_media_receive_channel_->AddRecvStream( | 
|  | StreamParams::CreateLegacy(kVideoSsrc2)); | 
|  | } | 
|  |  | 
|  | ~RtpSenderReceiverTest() override { | 
|  | audio_rtp_sender_ = nullptr; | 
|  | video_rtp_sender_ = nullptr; | 
|  | audio_rtp_receiver_ = nullptr; | 
|  | video_rtp_receiver_ = nullptr; | 
|  | local_stream_ = nullptr; | 
|  | video_track_ = nullptr; | 
|  | audio_track_ = nullptr; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<RtpTransportInternal> CreateDtlsSrtpTransport() { | 
|  | auto dtls_srtp_transport = std::make_unique<DtlsSrtpTransport>( | 
|  | /*rtcp_mux_required=*/true, env_.field_trials()); | 
|  | dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport_.get(), | 
|  | /*rtcp_dtls_transport=*/nullptr); | 
|  | return dtls_srtp_transport; | 
|  | } | 
|  |  | 
|  | // Needed to use DTMF sender. | 
|  | void AddDtmfCodec() { | 
|  | AudioSenderParameter params; | 
|  | const Codec kTelephoneEventCodec = | 
|  | CreateAudioCodec(106, "telephone-event", 8000, 1); | 
|  | params.codecs.push_back(kTelephoneEventCodec); | 
|  | voice_media_send_channel()->SetSenderParameters(params); | 
|  | } | 
|  |  | 
|  | void AddVideoTrack() { AddVideoTrack(false); } | 
|  |  | 
|  | void AddVideoTrack(bool is_screencast) { | 
|  | scoped_refptr<VideoTrackSourceInterface> source( | 
|  | FakeVideoTrackSource::Create(is_screencast)); | 
|  | video_track_ = VideoTrack::Create(kVideoTrackId, source, Thread::Current()); | 
|  | EXPECT_TRUE(local_stream_->AddTrack(video_track_)); | 
|  | } | 
|  |  | 
|  | void CreateAudioRtpSender() { CreateAudioRtpSender(nullptr); } | 
|  |  | 
|  | void CreateAudioRtpSender(const scoped_refptr<LocalAudioSource>& source) { | 
|  | audio_track_ = AudioTrack::Create(kAudioTrackId, source); | 
|  | EXPECT_TRUE(local_stream_->AddTrack(audio_track_)); | 
|  | std::unique_ptr<MockSetStreamsObserver> set_streams_observer = | 
|  | std::make_unique<MockSetStreamsObserver>(); | 
|  | audio_rtp_sender_ = AudioRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, audio_track_->id(), nullptr, | 
|  | set_streams_observer.get()); | 
|  | ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_.get())); | 
|  | EXPECT_CALL(*set_streams_observer, OnSetStreams()); | 
|  | audio_rtp_sender_->SetStreams({local_stream_->id()}); | 
|  | audio_rtp_sender_->SetMediaChannel(voice_media_send_channel_.get()); | 
|  | audio_rtp_sender_->SetSsrc(kAudioSsrc); | 
|  | VerifyVoiceChannelInput(); | 
|  | } | 
|  |  | 
|  | void CreateAudioRtpSenderWithNoTrack() { | 
|  | audio_rtp_sender_ = AudioRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, /*id=*/"", nullptr, nullptr); | 
|  | audio_rtp_sender_->SetMediaChannel(voice_media_send_channel_.get()); | 
|  | } | 
|  |  | 
|  | void CreateVideoRtpSender(uint32_t ssrc) { | 
|  | CreateVideoRtpSender(false, ssrc); | 
|  | } | 
|  |  | 
|  | void CreateVideoRtpSender() { CreateVideoRtpSender(false); } | 
|  |  | 
|  | StreamParams CreateSimulcastStreamParams(int num_layers) { | 
|  | std::vector<uint32_t> ssrcs; | 
|  | ssrcs.reserve(num_layers); | 
|  | for (int i = 0; i < num_layers; ++i) { | 
|  | ssrcs.push_back(kVideoSsrcSimulcast + i); | 
|  | } | 
|  | return CreateSimStreamParams("cname", ssrcs); | 
|  | } | 
|  |  | 
|  | uint32_t CreateVideoRtpSender(const StreamParams& stream_params) { | 
|  | video_media_send_channel_->AddSendStream(stream_params); | 
|  | uint32_t primary_ssrc = stream_params.first_ssrc(); | 
|  | CreateVideoRtpSender(primary_ssrc); | 
|  | return primary_ssrc; | 
|  | } | 
|  |  | 
|  | uint32_t CreateVideoRtpSenderWithSimulcast( | 
|  | int num_layers = kVideoSimulcastLayerCount) { | 
|  | return CreateVideoRtpSender(CreateSimulcastStreamParams(num_layers)); | 
|  | } | 
|  |  | 
|  | uint32_t CreateVideoRtpSenderWithSimulcast( | 
|  | const std::vector<std::string>& rids) { | 
|  | StreamParams stream_params = CreateSimulcastStreamParams(rids.size()); | 
|  | std::vector<RidDescription> rid_descriptions; | 
|  | absl::c_transform(rids, std::back_inserter(rid_descriptions), | 
|  | [](const std::string& rid) { | 
|  | return RidDescription(rid, RidDirection::kSend); | 
|  | }); | 
|  | stream_params.set_rids(rid_descriptions); | 
|  | return CreateVideoRtpSender(stream_params); | 
|  | } | 
|  |  | 
|  | void CreateVideoRtpSender(bool is_screencast, uint32_t ssrc = kVideoSsrc) { | 
|  | AddVideoTrack(is_screencast); | 
|  | std::unique_ptr<MockSetStreamsObserver> set_streams_observer = | 
|  | std::make_unique<MockSetStreamsObserver>(); | 
|  | video_rtp_sender_ = | 
|  | VideoRtpSender::Create(CreateEnvironment(), worker_thread_, | 
|  | video_track_->id(), set_streams_observer.get()); | 
|  | ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get())); | 
|  | EXPECT_CALL(*set_streams_observer, OnSetStreams()); | 
|  | video_rtp_sender_->SetStreams({local_stream_->id()}); | 
|  | video_rtp_sender_->SetMediaChannel(video_media_send_channel()); | 
|  | video_rtp_sender_->SetSsrc(ssrc); | 
|  | VerifyVideoChannelInput(ssrc); | 
|  | } | 
|  | void CreateVideoRtpSenderWithNoTrack() { | 
|  | video_rtp_sender_ = VideoRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, /*id=*/"", nullptr); | 
|  | video_rtp_sender_->SetMediaChannel(video_media_send_channel()); | 
|  | } | 
|  |  | 
|  | void DestroyAudioRtpSender() { | 
|  | audio_rtp_sender_ = nullptr; | 
|  | VerifyVoiceChannelNoInput(); | 
|  | } | 
|  |  | 
|  | void DestroyVideoRtpSender() { | 
|  | video_rtp_sender_ = nullptr; | 
|  | VerifyVideoChannelNoInput(); | 
|  | } | 
|  |  | 
|  | void CreateAudioRtpReceiver( | 
|  | std::vector<scoped_refptr<MediaStreamInterface>> streams = {}) { | 
|  | audio_rtp_receiver_ = make_ref_counted<AudioRtpReceiver>( | 
|  | Thread::Current(), kAudioTrackId, streams, | 
|  | /*is_unified_plan=*/true); | 
|  | audio_rtp_receiver_->SetMediaChannel(voice_media_receive_channel()); | 
|  | audio_rtp_receiver_->SetupMediaChannel(kAudioSsrc); | 
|  | audio_track_ = audio_rtp_receiver_->audio_track(); | 
|  | VerifyVoiceChannelOutput(); | 
|  | } | 
|  |  | 
|  | void CreateVideoRtpReceiver( | 
|  | std::vector<scoped_refptr<MediaStreamInterface>> streams = {}) { | 
|  | video_rtp_receiver_ = make_ref_counted<VideoRtpReceiver>( | 
|  | Thread::Current(), kVideoTrackId, streams); | 
|  | video_rtp_receiver_->SetMediaChannel(video_media_receive_channel()); | 
|  | video_rtp_receiver_->SetupMediaChannel(kVideoSsrc); | 
|  | video_track_ = video_rtp_receiver_->video_track(); | 
|  | VerifyVideoChannelOutput(); | 
|  | } | 
|  |  | 
|  | void CreateVideoRtpReceiverWithSimulcast( | 
|  | std::vector<scoped_refptr<MediaStreamInterface>> streams = {}, | 
|  | int num_layers = kVideoSimulcastLayerCount) { | 
|  | std::vector<uint32_t> ssrcs; | 
|  | ssrcs.reserve(num_layers); | 
|  | for (int i = 0; i < num_layers; ++i) | 
|  | ssrcs.push_back(kVideoSsrcSimulcast + i); | 
|  | StreamParams stream_params = CreateSimStreamParams("cname", ssrcs); | 
|  | video_media_receive_channel_->AddRecvStream(stream_params); | 
|  | uint32_t primary_ssrc = stream_params.first_ssrc(); | 
|  |  | 
|  | video_rtp_receiver_ = make_ref_counted<VideoRtpReceiver>( | 
|  | Thread::Current(), kVideoTrackId, streams); | 
|  | video_rtp_receiver_->SetMediaChannel(video_media_receive_channel()); | 
|  | video_rtp_receiver_->SetupMediaChannel(primary_ssrc); | 
|  | video_track_ = video_rtp_receiver_->video_track(); | 
|  | } | 
|  |  | 
|  | void DestroyAudioRtpReceiver() { | 
|  | if (!audio_rtp_receiver_) | 
|  | return; | 
|  | audio_rtp_receiver_->SetMediaChannel(nullptr); | 
|  | audio_rtp_receiver_ = nullptr; | 
|  | VerifyVoiceChannelNoOutput(); | 
|  | } | 
|  |  | 
|  | void DestroyVideoRtpReceiver() { | 
|  | if (!video_rtp_receiver_) | 
|  | return; | 
|  | video_rtp_receiver_->Stop(); | 
|  | video_rtp_receiver_->SetMediaChannel(nullptr); | 
|  | video_rtp_receiver_ = nullptr; | 
|  | VerifyVideoChannelNoOutput(); | 
|  | } | 
|  |  | 
|  | void VerifyVoiceChannelInput() { VerifyVoiceChannelInput(kAudioSsrc); } | 
|  |  | 
|  | void VerifyVoiceChannelInput(uint32_t ssrc) { | 
|  | // Verify that the media channel has an audio source, and the stream isn't | 
|  | // muted. | 
|  | EXPECT_TRUE(voice_media_send_channel()->HasSource(ssrc)); | 
|  | EXPECT_FALSE(voice_media_send_channel()->IsStreamMuted(ssrc)); | 
|  | } | 
|  |  | 
|  | void VerifyVideoChannelInput() { VerifyVideoChannelInput(kVideoSsrc); } | 
|  |  | 
|  | void VerifyVideoChannelInput(uint32_t ssrc) { | 
|  | // Verify that the media channel has a video source, | 
|  | EXPECT_TRUE(video_media_send_channel()->HasSource(ssrc)); | 
|  | } | 
|  |  | 
|  | void VerifyVoiceChannelNoInput() { VerifyVoiceChannelNoInput(kAudioSsrc); } | 
|  |  | 
|  | void VerifyVoiceChannelNoInput(uint32_t ssrc) { | 
|  | // Verify that the media channel's source is reset. | 
|  | EXPECT_FALSE(voice_media_receive_channel()->HasSource(ssrc)); | 
|  | } | 
|  |  | 
|  | void VerifyVideoChannelNoInput() { VerifyVideoChannelNoInput(kVideoSsrc); } | 
|  |  | 
|  | void VerifyVideoChannelNoInput(uint32_t ssrc) { | 
|  | // Verify that the media channel's source is reset. | 
|  | EXPECT_FALSE(video_media_receive_channel()->HasSource(ssrc)); | 
|  | } | 
|  |  | 
|  | void VerifyVoiceChannelOutput() { | 
|  | // Verify that the volume is initialized to 1. | 
|  | double volume; | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(1, volume); | 
|  | } | 
|  |  | 
|  | void VerifyVideoChannelOutput() { | 
|  | // Verify that the media channel has a sink. | 
|  | EXPECT_TRUE(video_media_receive_channel()->HasSink(kVideoSsrc)); | 
|  | } | 
|  |  | 
|  | void VerifyVoiceChannelNoOutput() { | 
|  | // Verify that the volume is reset to 0. | 
|  | double volume; | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(0, volume); | 
|  | } | 
|  |  | 
|  | void VerifyVideoChannelNoOutput() { | 
|  | // Verify that the media channel's sink is reset. | 
|  | EXPECT_FALSE(video_media_receive_channel()->HasSink(kVideoSsrc)); | 
|  | } | 
|  |  | 
|  | // Verifies that the encoding layers contain the specified RIDs. | 
|  | bool VerifyEncodingLayers(const VideoRtpSender& sender, | 
|  | const std::vector<std::string>& rids) { | 
|  | bool has_failure = HasFailure(); | 
|  | RtpParameters parameters = sender.GetParameters(); | 
|  | std::vector<std::string> encoding_rids; | 
|  | absl::c_transform( | 
|  | parameters.encodings, std::back_inserter(encoding_rids), | 
|  | [](const RtpEncodingParameters& encoding) { return encoding.rid; }); | 
|  | EXPECT_THAT(rids, ContainerEq(encoding_rids)); | 
|  | return has_failure || !HasFailure(); | 
|  | } | 
|  |  | 
|  | // Runs a test for disabling the encoding layers on the specified sender. | 
|  | void RunDisableEncodingLayersTest( | 
|  | const std::vector<std::string>& all_layers, | 
|  | const std::vector<std::string>& disabled_layers, | 
|  | VideoRtpSender* sender) { | 
|  | std::vector<std::string> expected; | 
|  | absl::c_copy_if(all_layers, std::back_inserter(expected), | 
|  | [&disabled_layers](const std::string& rid) { | 
|  | return !absl::c_linear_search(disabled_layers, rid); | 
|  | }); | 
|  |  | 
|  | EXPECT_TRUE(VerifyEncodingLayers(*sender, all_layers)); | 
|  | sender->DisableEncodingLayers(disabled_layers); | 
|  | EXPECT_TRUE(VerifyEncodingLayers(*sender, expected)); | 
|  | } | 
|  |  | 
|  | // Runs a test for setting an encoding layer as inactive. | 
|  | // This test assumes that some layers have already been disabled. | 
|  | void RunSetLastLayerAsInactiveTest(VideoRtpSender* sender) { | 
|  | auto parameters = sender->GetParameters(); | 
|  | if (parameters.encodings.empty()) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | RtpEncodingParameters& encoding = parameters.encodings.back(); | 
|  | auto rid = encoding.rid; | 
|  | EXPECT_TRUE(encoding.active); | 
|  | encoding.active = false; | 
|  | auto error = sender->SetParameters(parameters); | 
|  | ASSERT_TRUE(error.ok()); | 
|  | parameters = sender->GetParameters(); | 
|  | RtpEncodingParameters& result_encoding = parameters.encodings.back(); | 
|  | EXPECT_EQ(rid, result_encoding.rid); | 
|  | EXPECT_FALSE(result_encoding.active); | 
|  | } | 
|  |  | 
|  | // Runs a test for disabling the encoding layers on a sender without a media | 
|  | // channel. | 
|  | void RunDisableSimulcastLayersWithoutMediaEngineTest( | 
|  | const std::vector<std::string>& all_layers, | 
|  | const std::vector<std::string>& disabled_layers) { | 
|  | auto sender = VideoRtpSender::Create(CreateEnvironment(), Thread::Current(), | 
|  | "1", nullptr); | 
|  | RtpParameters parameters; | 
|  | parameters.encodings.resize(all_layers.size()); | 
|  | for (size_t i = 0; i < all_layers.size(); ++i) { | 
|  | parameters.encodings[i].rid = all_layers[i]; | 
|  | } | 
|  | sender->set_init_send_encodings(parameters.encodings); | 
|  | RunDisableEncodingLayersTest(all_layers, disabled_layers, sender.get()); | 
|  | RunSetLastLayerAsInactiveTest(sender.get()); | 
|  | } | 
|  |  | 
|  | // Runs a test for disabling the encoding layers on a sender with a media | 
|  | // channel. | 
|  | void RunDisableSimulcastLayersWithMediaEngineTest( | 
|  | const std::vector<std::string>& all_layers, | 
|  | const std::vector<std::string>& disabled_layers) { | 
|  | uint32_t ssrc = CreateVideoRtpSenderWithSimulcast(all_layers); | 
|  | RunDisableEncodingLayersTest(all_layers, disabled_layers, | 
|  | video_rtp_sender_.get()); | 
|  |  | 
|  | auto channel_parameters = | 
|  | video_media_send_channel_->GetRtpSendParameters(ssrc); | 
|  | ASSERT_EQ(channel_parameters.encodings.size(), all_layers.size()); | 
|  | for (size_t i = 0; i < all_layers.size(); ++i) { | 
|  | EXPECT_EQ(all_layers[i], channel_parameters.encodings[i].rid); | 
|  | bool is_active = !absl::c_linear_search(disabled_layers, all_layers[i]); | 
|  | EXPECT_EQ(is_active, channel_parameters.encodings[i].active); | 
|  | } | 
|  |  | 
|  | RunSetLastLayerAsInactiveTest(video_rtp_sender_.get()); | 
|  | } | 
|  |  | 
|  | // Check that minimum Jitter Buffer delay is propagated to the underlying | 
|  | // `media_channel`. | 
|  | void VerifyRtpReceiverDelayBehaviour( | 
|  | MediaReceiveChannelInterface* media_channel, | 
|  | RtpReceiverInterface* receiver, | 
|  | uint32_t ssrc) { | 
|  | receiver->SetJitterBufferMinimumDelay(/*delay_seconds=*/0.5); | 
|  | std::optional<int> delay_ms = | 
|  | media_channel->GetBaseMinimumPlayoutDelayMs(ssrc);  // In milliseconds. | 
|  | EXPECT_DOUBLE_EQ(0.5, delay_ms.value_or(0) / 1000.0); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | FakeVideoMediaSendChannel* video_media_send_channel() { | 
|  | return static_cast<FakeVideoMediaSendChannel*>( | 
|  | video_media_send_channel_.get()); | 
|  | } | 
|  | FakeVoiceMediaSendChannel* voice_media_send_channel() { | 
|  | return static_cast<FakeVoiceMediaSendChannel*>( | 
|  | voice_media_send_channel_.get()); | 
|  | } | 
|  | FakeVideoMediaReceiveChannel* video_media_receive_channel() { | 
|  | return static_cast<FakeVideoMediaReceiveChannel*>( | 
|  | video_media_receive_channel_.get()); | 
|  | } | 
|  | FakeVoiceMediaReceiveChannel* voice_media_receive_channel() { | 
|  | return static_cast<FakeVoiceMediaReceiveChannel*>( | 
|  | voice_media_receive_channel_.get()); | 
|  | } | 
|  |  | 
|  | test::RunLoop run_loop_; | 
|  | Thread* const network_thread_; | 
|  | Thread* const worker_thread_; | 
|  | const Environment env_ = CreateEnvironment(); | 
|  | // The `rtp_dtls_transport_` and `rtp_transport_` should be destroyed after | 
|  | // the `channel_manager`. | 
|  | std::unique_ptr<DtlsTransportInternal> rtp_dtls_transport_; | 
|  | std::unique_ptr<RtpTransportInternal> rtp_transport_; | 
|  | std::unique_ptr<VideoBitrateAllocatorFactory> | 
|  | video_bitrate_allocator_factory_; | 
|  | std::unique_ptr<FakeMediaEngine> media_engine_; | 
|  | UniqueRandomIdGenerator ssrc_generator_; | 
|  | FakeCall fake_call_; | 
|  | std::unique_ptr<VoiceMediaSendChannelInterface> voice_media_send_channel_; | 
|  | std::unique_ptr<VideoMediaSendChannelInterface> video_media_send_channel_; | 
|  | std::unique_ptr<VoiceMediaReceiveChannelInterface> | 
|  | voice_media_receive_channel_; | 
|  | std::unique_ptr<VideoMediaReceiveChannelInterface> | 
|  | video_media_receive_channel_; | 
|  | scoped_refptr<AudioRtpSender> audio_rtp_sender_; | 
|  | scoped_refptr<VideoRtpSender> video_rtp_sender_; | 
|  | scoped_refptr<AudioRtpReceiver> audio_rtp_receiver_; | 
|  | scoped_refptr<VideoRtpReceiver> video_rtp_receiver_; | 
|  | scoped_refptr<MediaStreamInterface> local_stream_; | 
|  | scoped_refptr<VideoTrackInterface> video_track_; | 
|  | scoped_refptr<AudioTrackInterface> audio_track_; | 
|  | }; | 
|  |  | 
|  | // Test that `voice_channel_` is updated when an audio track is associated | 
|  | // and disassociated with an AudioRtpSender. | 
|  | TEST_F(RtpSenderReceiverTest, AddAndDestroyAudioRtpSender) { | 
|  | CreateAudioRtpSender(); | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that `video_channel_` is updated when a video track is associated and | 
|  | // disassociated with a VideoRtpSender. | 
|  | TEST_F(RtpSenderReceiverTest, AddAndDestroyVideoRtpSender) { | 
|  | CreateVideoRtpSender(); | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that `voice_channel_` is updated when a remote audio track is | 
|  | // associated and disassociated with an AudioRtpReceiver. | 
|  | TEST_F(RtpSenderReceiverTest, AddAndDestroyAudioRtpReceiver) { | 
|  | CreateAudioRtpReceiver(); | 
|  | DestroyAudioRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Test that `video_channel_` is updated when a remote video track is | 
|  | // associated and disassociated with a VideoRtpReceiver. | 
|  | TEST_F(RtpSenderReceiverTest, AddAndDestroyVideoRtpReceiver) { | 
|  | CreateVideoRtpReceiver(); | 
|  | DestroyVideoRtpReceiver(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AddAndDestroyAudioRtpReceiverWithStreams) { | 
|  | CreateAudioRtpReceiver({local_stream_}); | 
|  | DestroyAudioRtpReceiver(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AddAndDestroyVideoRtpReceiverWithStreams) { | 
|  | CreateVideoRtpReceiver({local_stream_}); | 
|  | DestroyVideoRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Test that the AudioRtpSender applies options from the local audio source. | 
|  | TEST_F(RtpSenderReceiverTest, LocalAudioSourceOptionsApplied) { | 
|  | AudioOptions options; | 
|  | options.echo_cancellation = true; | 
|  | auto source = LocalAudioSource::Create(&options); | 
|  | CreateAudioRtpSender(source); | 
|  |  | 
|  | EXPECT_EQ(true, voice_media_send_channel()->options().echo_cancellation); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that the stream is muted when the track is disabled, and unmuted when | 
|  | // the track is enabled. | 
|  | TEST_F(RtpSenderReceiverTest, LocalAudioTrackDisable) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | audio_track_->set_enabled(false); | 
|  | EXPECT_TRUE(voice_media_send_channel()->IsStreamMuted(kAudioSsrc)); | 
|  |  | 
|  | audio_track_->set_enabled(true); | 
|  | EXPECT_FALSE(voice_media_send_channel()->IsStreamMuted(kAudioSsrc)); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that the volume is set to 0 when the track is disabled, and back to | 
|  | // 1 when the track is enabled. | 
|  | TEST_F(RtpSenderReceiverTest, RemoteAudioTrackDisable) { | 
|  | CreateAudioRtpReceiver(); | 
|  |  | 
|  | double volume; | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(1, volume); | 
|  |  | 
|  | // Handling of enable/disable is applied asynchronously. | 
|  | audio_track_->set_enabled(false); | 
|  | run_loop_.Flush(); | 
|  |  | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(0, volume); | 
|  |  | 
|  | audio_track_->set_enabled(true); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(1, volume); | 
|  |  | 
|  | DestroyAudioRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Currently no action is taken when a remote video track is disabled or | 
|  | // enabled, so there's nothing to test here, other than what is normally | 
|  | // verified in DestroyVideoRtpSender. | 
|  | TEST_F(RtpSenderReceiverTest, LocalVideoTrackDisable) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | video_track_->set_enabled(false); | 
|  | video_track_->set_enabled(true); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that the state of the video track created by the VideoRtpReceiver is | 
|  | // updated when the receiver is destroyed. | 
|  | TEST_F(RtpSenderReceiverTest, RemoteVideoTrackState) { | 
|  | CreateVideoRtpReceiver(); | 
|  |  | 
|  | EXPECT_EQ(MediaStreamTrackInterface::kLive, video_track_->state()); | 
|  | EXPECT_EQ(MediaSourceInterface::kLive, video_track_->GetSource()->state()); | 
|  |  | 
|  | DestroyVideoRtpReceiver(); | 
|  |  | 
|  | EXPECT_EQ(MediaStreamTrackInterface::kEnded, video_track_->state()); | 
|  | EXPECT_EQ(MediaSourceInterface::kEnded, video_track_->GetSource()->state()); | 
|  | DestroyVideoRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Currently no action is taken when a remote video track is disabled or | 
|  | // enabled, so there's nothing to test here, other than what is normally | 
|  | // verified in DestroyVideoRtpReceiver. | 
|  | TEST_F(RtpSenderReceiverTest, RemoteVideoTrackDisable) { | 
|  | CreateVideoRtpReceiver(); | 
|  |  | 
|  | video_track_->set_enabled(false); | 
|  | video_track_->set_enabled(true); | 
|  |  | 
|  | DestroyVideoRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Test that the AudioRtpReceiver applies volume changes from the track source | 
|  | // to the media channel. | 
|  | TEST_F(RtpSenderReceiverTest, RemoteAudioTrackSetVolume) { | 
|  | CreateAudioRtpReceiver(); | 
|  |  | 
|  | double volume; | 
|  | audio_track_->GetSource()->SetVolume(0.5); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(0.5, volume); | 
|  |  | 
|  | // Disable the audio track, this should prevent setting the volume. | 
|  | audio_track_->set_enabled(false); | 
|  | RTC_DCHECK_EQ(worker_thread_, run_loop_.task_queue()); | 
|  | run_loop_.Flush(); | 
|  | audio_track_->GetSource()->SetVolume(0.8); | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(0, volume); | 
|  |  | 
|  | // When the track is enabled, the previously set volume should take effect. | 
|  | audio_track_->set_enabled(true); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(0.8, volume); | 
|  |  | 
|  | // Try changing volume one more time. | 
|  | audio_track_->GetSource()->SetVolume(0.9); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE( | 
|  | voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume)); | 
|  | EXPECT_EQ(0.9, volume); | 
|  |  | 
|  | DestroyAudioRtpReceiver(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioRtpReceiverDelay) { | 
|  | CreateAudioRtpReceiver(); | 
|  | VerifyRtpReceiverDelayBehaviour( | 
|  | voice_media_receive_channel()->AsVoiceReceiveChannel(), | 
|  | audio_rtp_receiver_.get(), kAudioSsrc); | 
|  | DestroyAudioRtpReceiver(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoRtpReceiverDelay) { | 
|  | CreateVideoRtpReceiver(); | 
|  | VerifyRtpReceiverDelayBehaviour( | 
|  | video_media_receive_channel()->AsVideoReceiveChannel(), | 
|  | video_rtp_receiver_.get(), kVideoSsrc); | 
|  | DestroyVideoRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel isn't enabled for sending if the audio sender | 
|  | // doesn't have both a track and SSRC. | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderWithoutTrackAndSsrc) { | 
|  | CreateAudioRtpSenderWithNoTrack(); | 
|  | scoped_refptr<AudioTrackInterface> track = | 
|  | AudioTrack::Create(kAudioTrackId, nullptr); | 
|  |  | 
|  | // Track but no SSRC. | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetTrack(track.get())); | 
|  | VerifyVoiceChannelNoInput(); | 
|  |  | 
|  | // SSRC but no track. | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetTrack(nullptr)); | 
|  | audio_rtp_sender_->SetSsrc(kAudioSsrc); | 
|  | VerifyVoiceChannelNoInput(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel isn't enabled for sending if the video sender | 
|  | // doesn't have both a track and SSRC. | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderWithoutTrackAndSsrc) { | 
|  | CreateVideoRtpSenderWithNoTrack(); | 
|  |  | 
|  | // Track but no SSRC. | 
|  | EXPECT_TRUE(video_rtp_sender_->SetTrack(video_track_.get())); | 
|  | VerifyVideoChannelNoInput(); | 
|  |  | 
|  | // SSRC but no track. | 
|  | EXPECT_TRUE(video_rtp_sender_->SetTrack(nullptr)); | 
|  | video_rtp_sender_->SetSsrc(kVideoSsrc); | 
|  | VerifyVideoChannelNoInput(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel is enabled for sending when the audio sender | 
|  | // has a track and SSRC, when the SSRC is set first. | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderEarlyWarmupSsrcThenTrack) { | 
|  | CreateAudioRtpSenderWithNoTrack(); | 
|  | scoped_refptr<AudioTrackInterface> track = | 
|  | AudioTrack::Create(kAudioTrackId, nullptr); | 
|  | audio_rtp_sender_->SetSsrc(kAudioSsrc); | 
|  | audio_rtp_sender_->SetTrack(track.get()); | 
|  | VerifyVoiceChannelInput(); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel is enabled for sending when the audio sender | 
|  | // has a track and SSRC, when the SSRC is set last. | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderEarlyWarmupTrackThenSsrc) { | 
|  | CreateAudioRtpSenderWithNoTrack(); | 
|  | scoped_refptr<AudioTrackInterface> track = | 
|  | AudioTrack::Create(kAudioTrackId, nullptr); | 
|  | audio_rtp_sender_->SetTrack(track.get()); | 
|  | audio_rtp_sender_->SetSsrc(kAudioSsrc); | 
|  | VerifyVoiceChannelInput(); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel is enabled for sending when the video sender | 
|  | // has a track and SSRC, when the SSRC is set first. | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderEarlyWarmupSsrcThenTrack) { | 
|  | AddVideoTrack(); | 
|  | CreateVideoRtpSenderWithNoTrack(); | 
|  | video_rtp_sender_->SetSsrc(kVideoSsrc); | 
|  | video_rtp_sender_->SetTrack(video_track_.get()); | 
|  | VerifyVideoChannelInput(); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel is enabled for sending when the video sender | 
|  | // has a track and SSRC, when the SSRC is set last. | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderEarlyWarmupTrackThenSsrc) { | 
|  | AddVideoTrack(); | 
|  | CreateVideoRtpSenderWithNoTrack(); | 
|  | video_rtp_sender_->SetTrack(video_track_.get()); | 
|  | video_rtp_sender_->SetSsrc(kVideoSsrc); | 
|  | VerifyVideoChannelInput(); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel stops sending when the audio sender's SSRC is set | 
|  | // to 0. | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderSsrcSetToZero) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | audio_rtp_sender_->SetSsrc(0); | 
|  | VerifyVoiceChannelNoInput(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel stops sending when the video sender's SSRC is set | 
|  | // to 0. | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderSsrcSetToZero) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | audio_rtp_sender_->SetSsrc(0); | 
|  | VerifyVideoChannelNoInput(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel stops sending when the audio sender's track is | 
|  | // set to null. | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderTrackSetToNull) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetTrack(nullptr)); | 
|  | VerifyVoiceChannelNoInput(); | 
|  | } | 
|  |  | 
|  | // Test that the media channel stops sending when the video sender's track is | 
|  | // set to null. | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderTrackSetToNull) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | video_rtp_sender_->SetSsrc(0); | 
|  | VerifyVideoChannelNoInput(); | 
|  | } | 
|  |  | 
|  | // Test that when the audio sender's SSRC is changed, the media channel stops | 
|  | // sending with the old SSRC and starts sending with the new one. | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderSsrcChanged) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | audio_rtp_sender_->SetSsrc(kAudioSsrc2); | 
|  | VerifyVoiceChannelNoInput(kAudioSsrc); | 
|  | VerifyVoiceChannelInput(kAudioSsrc2); | 
|  |  | 
|  | audio_rtp_sender_ = nullptr; | 
|  | VerifyVoiceChannelNoInput(kAudioSsrc2); | 
|  | } | 
|  |  | 
|  | // Test that when the audio sender's SSRC is changed, the media channel stops | 
|  | // sending with the old SSRC and starts sending with the new one. | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderSsrcChanged) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | video_rtp_sender_->SetSsrc(kVideoSsrc2); | 
|  | VerifyVideoChannelNoInput(kVideoSsrc); | 
|  | VerifyVideoChannelInput(kVideoSsrc2); | 
|  |  | 
|  | video_rtp_sender_ = nullptr; | 
|  | VerifyVideoChannelNoInput(kVideoSsrc2); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParameters) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersAsync) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  | std::optional<RTCError> result; | 
|  | audio_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE(result->ok()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersBeforeNegotiation) { | 
|  | audio_rtp_sender_ = AudioRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, /*id=*/"", nullptr, nullptr); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(1u, params.encodings.size()); | 
|  | params.encodings[0].max_bitrate_bps = 90000; | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000); | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | AudioSenderCanSetParametersAsyncBeforeNegotiation) { | 
|  | audio_rtp_sender_ = AudioRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, /*id=*/"", nullptr, nullptr); | 
|  |  | 
|  | std::optional<RTCError> result; | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(1u, params.encodings.size()); | 
|  | params.encodings[0].max_bitrate_bps = 90000; | 
|  |  | 
|  | audio_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE(result->ok()); | 
|  |  | 
|  | params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000); | 
|  |  | 
|  | audio_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE(result->ok()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderInitParametersMovedAfterNegotiation) { | 
|  | audio_track_ = AudioTrack::Create(kAudioTrackId, nullptr); | 
|  | EXPECT_TRUE(local_stream_->AddTrack(audio_track_)); | 
|  |  | 
|  | std::unique_ptr<MockSetStreamsObserver> set_streams_observer = | 
|  | std::make_unique<MockSetStreamsObserver>(); | 
|  | audio_rtp_sender_ = AudioRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, audio_track_->id(), nullptr, | 
|  | set_streams_observer.get()); | 
|  | ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_.get())); | 
|  | EXPECT_CALL(*set_streams_observer, OnSetStreams()); | 
|  | audio_rtp_sender_->SetStreams({local_stream_->id()}); | 
|  |  | 
|  | std::vector<RtpEncodingParameters> init_encodings(1); | 
|  | init_encodings[0].max_bitrate_bps = 60000; | 
|  | audio_rtp_sender_->set_init_send_encodings(init_encodings); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(1u, params.encodings.size()); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000); | 
|  |  | 
|  | // Simulate the setLocalDescription call | 
|  | std::vector<uint32_t> ssrcs(1, 1); | 
|  | StreamParams stream_params = CreateSimStreamParams("cname", ssrcs); | 
|  | voice_media_send_channel()->AddSendStream(stream_params); | 
|  | audio_rtp_sender_->SetMediaChannel( | 
|  | voice_media_send_channel()->AsVoiceSendChannel()); | 
|  | audio_rtp_sender_->SetSsrc(1); | 
|  |  | 
|  | params = audio_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(1u, params.encodings.size()); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | AudioSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) { | 
|  | audio_rtp_sender_ = AudioRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, /*id=*/"", nullptr, nullptr); | 
|  |  | 
|  | RtpParameters params; | 
|  | RTCError result = audio_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type()); | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | AudioSenderMustCallGetParametersBeforeSetParameters) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params; | 
|  | RTCError result = audio_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | AudioSenderSetParametersInvalidatesTransactionId) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok()); | 
|  | RTCError result = audio_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | AudioSenderSetParametersAsyncInvalidatesTransactionId) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  | std::optional<RTCError> result; | 
|  | audio_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE(result->ok()); | 
|  | audio_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_STATE, result->type()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderDetectTransactionIdModification) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | params.transaction_id = ""; | 
|  | RTCError result = audio_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderCheckTransactionIdRefresh) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_NE(params.transaction_id.size(), 0U); | 
|  | auto saved_transaction_id = params.transaction_id; | 
|  | params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_NE(saved_transaction_id, params.transaction_id); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderSetParametersOldValueFail) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | RtpParameters second_params = audio_rtp_sender_->GetParameters(); | 
|  |  | 
|  | RTCError result = audio_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type()); | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderCantSetUnimplementedRtpParameters) { | 
|  | CreateAudioRtpSender(); | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  |  | 
|  | // Unimplemented RtpParameters: mid | 
|  | params.mid = "dummy_mid"; | 
|  | EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, | 
|  | audio_rtp_sender_->SetParameters(params).type()); | 
|  | params = audio_rtp_sender_->GetParameters(); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, SetAudioMaxSendBitrate) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | EXPECT_EQ(-1, voice_media_send_channel()->max_bps()); | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_FALSE(params.encodings[0].max_bitrate_bps); | 
|  | params.encodings[0].max_bitrate_bps = 1000; | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | // Read back the parameters and verify they have been changed. | 
|  | params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); | 
|  |  | 
|  | // Verify that the audio channel received the new parameters. | 
|  | params = voice_media_send_channel()->GetRtpSendParameters(kAudioSsrc); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); | 
|  |  | 
|  | // Verify that the global bitrate limit has not been changed. | 
|  | EXPECT_EQ(-1, voice_media_send_channel()->max_bps()); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, SetAudioBitratePriority) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | RtpParameters params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(kDefaultBitratePriority, params.encodings[0].bitrate_priority); | 
|  | double new_bitrate_priority = 2.0; | 
|  | params.encodings[0].bitrate_priority = new_bitrate_priority; | 
|  | EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | params = audio_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(new_bitrate_priority, params.encodings[0].bitrate_priority); | 
|  |  | 
|  | params = voice_media_send_channel()->GetRtpSendParameters(kAudioSsrc); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(new_bitrate_priority, params.encodings[0].bitrate_priority); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParameters) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersAsync) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  | std::optional<RTCError> result; | 
|  | video_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE(result->ok()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersBeforeNegotiation) { | 
|  | video_rtp_sender_ = VideoRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, /*id=*/"", nullptr); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(1u, params.encodings.size()); | 
|  | params.encodings[0].max_bitrate_bps = 90000; | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | VideoSenderCanSetParametersAsyncBeforeNegotiation) { | 
|  | video_rtp_sender_ = VideoRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, /*id=*/"", nullptr); | 
|  |  | 
|  | std::optional<RTCError> result; | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(1u, params.encodings.size()); | 
|  | params.encodings[0].max_bitrate_bps = 90000; | 
|  | video_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE(result->ok()); | 
|  |  | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000); | 
|  | video_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE(result->ok()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderInitParametersMovedAfterNegotiation) { | 
|  | AddVideoTrack(false); | 
|  |  | 
|  | std::unique_ptr<MockSetStreamsObserver> set_streams_observer = | 
|  | std::make_unique<MockSetStreamsObserver>(); | 
|  | video_rtp_sender_ = | 
|  | VideoRtpSender::Create(CreateEnvironment(), worker_thread_, | 
|  | video_track_->id(), set_streams_observer.get()); | 
|  | ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get())); | 
|  | EXPECT_CALL(*set_streams_observer, OnSetStreams()); | 
|  | video_rtp_sender_->SetStreams({local_stream_->id()}); | 
|  |  | 
|  | std::vector<RtpEncodingParameters> init_encodings(2); | 
|  | init_encodings[0].max_bitrate_bps = 60000; | 
|  | init_encodings[1].max_bitrate_bps = 900000; | 
|  | video_rtp_sender_->set_init_send_encodings(init_encodings); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(2u, params.encodings.size()); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000); | 
|  | EXPECT_EQ(params.encodings[1].max_bitrate_bps, 900000); | 
|  |  | 
|  | // Simulate the setLocalDescription call | 
|  | std::vector<uint32_t> ssrcs; | 
|  | ssrcs.reserve(2); | 
|  | for (int i = 0; i < 2; ++i) | 
|  | ssrcs.push_back(kVideoSsrcSimulcast + i); | 
|  | StreamParams stream_params = CreateSimStreamParams("cname", ssrcs); | 
|  | video_media_send_channel()->AddSendStream(stream_params); | 
|  | video_rtp_sender_->SetMediaChannel( | 
|  | video_media_send_channel()->AsVideoSendChannel()); | 
|  | video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast); | 
|  |  | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(2u, params.encodings.size()); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000); | 
|  | EXPECT_EQ(params.encodings[1].max_bitrate_bps, 900000); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | VideoSenderInitParametersMovedAfterManualSimulcastAndNegotiation) { | 
|  | AddVideoTrack(false); | 
|  |  | 
|  | std::unique_ptr<MockSetStreamsObserver> set_streams_observer = | 
|  | std::make_unique<MockSetStreamsObserver>(); | 
|  | video_rtp_sender_ = | 
|  | VideoRtpSender::Create(CreateEnvironment(), worker_thread_, | 
|  | video_track_->id(), set_streams_observer.get()); | 
|  | ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get())); | 
|  | EXPECT_CALL(*set_streams_observer, OnSetStreams()); | 
|  | video_rtp_sender_->SetStreams({local_stream_->id()}); | 
|  |  | 
|  | std::vector<RtpEncodingParameters> init_encodings(1); | 
|  | init_encodings[0].max_bitrate_bps = 60000; | 
|  | video_rtp_sender_->set_init_send_encodings(init_encodings); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(1u, params.encodings.size()); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000); | 
|  |  | 
|  | // Simulate the setLocalDescription call as if the user used SDP munging | 
|  | // to enable simulcast | 
|  | std::vector<uint32_t> ssrcs; | 
|  | ssrcs.reserve(2); | 
|  | for (int i = 0; i < 2; ++i) | 
|  | ssrcs.push_back(kVideoSsrcSimulcast + i); | 
|  | StreamParams stream_params = CreateSimStreamParams("cname", ssrcs); | 
|  | video_media_send_channel()->AddSendStream(stream_params); | 
|  | video_rtp_sender_->SetMediaChannel( | 
|  | video_media_send_channel()->AsVideoSendChannel()); | 
|  | video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast); | 
|  |  | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(2u, params.encodings.size()); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) | 
|  | using RtpSenderReceiverDeathTest = RtpSenderReceiverTest; | 
|  |  | 
|  | TEST_F(RtpSenderReceiverDeathTest, | 
|  | VideoSenderManualRemoveSimulcastFailsDeathTest) { | 
|  | AddVideoTrack(false); | 
|  |  | 
|  | std::unique_ptr<MockSetStreamsObserver> set_streams_observer = | 
|  | std::make_unique<MockSetStreamsObserver>(); | 
|  | video_rtp_sender_ = | 
|  | VideoRtpSender::Create(CreateEnvironment(), worker_thread_, | 
|  | video_track_->id(), set_streams_observer.get()); | 
|  | ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get())); | 
|  | EXPECT_CALL(*set_streams_observer, OnSetStreams()); | 
|  | video_rtp_sender_->SetStreams({local_stream_->id()}); | 
|  |  | 
|  | std::vector<RtpEncodingParameters> init_encodings(2); | 
|  | init_encodings[0].max_bitrate_bps = 60000; | 
|  | init_encodings[1].max_bitrate_bps = 120000; | 
|  | video_rtp_sender_->set_init_send_encodings(init_encodings); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | ASSERT_EQ(2u, params.encodings.size()); | 
|  | EXPECT_EQ(params.encodings[0].max_bitrate_bps, 60000); | 
|  |  | 
|  | // Simulate the setLocalDescription call as if the user used SDP munging | 
|  | // to disable simulcast. | 
|  | std::vector<uint32_t> ssrcs; | 
|  | ssrcs.reserve(2); | 
|  | for (int i = 0; i < 2; ++i) | 
|  | ssrcs.push_back(kVideoSsrcSimulcast + i); | 
|  | StreamParams stream_params = StreamParams::CreateLegacy(kVideoSsrc); | 
|  | video_media_send_channel()->AddSendStream(stream_params); | 
|  | video_rtp_sender_->SetMediaChannel( | 
|  | video_media_send_channel()->AsVideoSendChannel()); | 
|  | EXPECT_DEATH(video_rtp_sender_->SetSsrc(kVideoSsrcSimulcast), ""); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | VideoSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) { | 
|  | video_rtp_sender_ = VideoRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, /*id=*/"", nullptr); | 
|  |  | 
|  | RtpParameters params; | 
|  | RTCError result = video_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type()); | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | VideoSenderMustCallGetParametersBeforeSetParameters) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params; | 
|  | RTCError result = video_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | VideoSenderSetParametersInvalidatesTransactionId) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  | RTCError result = video_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_STATE, result.type()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | VideoSenderSetParametersAsyncInvalidatesTransactionId) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  | std::optional<RTCError> result; | 
|  | video_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_TRUE(result->ok()); | 
|  | video_rtp_sender_->SetParametersAsync( | 
|  | params, [&result](RTCError error) { result = error; }); | 
|  | run_loop_.Flush(); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_STATE, result->type()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderDetectTransactionIdModification) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | params.transaction_id = ""; | 
|  | RTCError result = video_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCheckTransactionIdRefresh) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_NE(params.transaction_id.size(), 0U); | 
|  | auto saved_transaction_id = params.transaction_id; | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_NE(saved_transaction_id, params.transaction_id); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderSetParametersOldValueFail) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | RtpParameters second_params = video_rtp_sender_->GetParameters(); | 
|  |  | 
|  | RTCError result = video_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, result.type()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCantSetUnimplementedRtpParameters) { | 
|  | CreateVideoRtpSender(); | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1u, params.encodings.size()); | 
|  |  | 
|  | // Unimplemented RtpParameters: mid | 
|  | params.mid = "dummy_mid"; | 
|  | EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, | 
|  | video_rtp_sender_->SetParameters(params).type()); | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCanSetScaleResolutionDownBy) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | params.encodings[0].scale_resolution_down_by = 2; | 
|  |  | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(2, params.encodings[0].scale_resolution_down_by); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderDetectInvalidScaleResolutionDownBy) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | params.encodings[0].scale_resolution_down_by = 0.5; | 
|  | RTCError result = video_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.type()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCanSetNumTemporalLayers) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | params.encodings[0].num_temporal_layers = 2; | 
|  |  | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(2, params.encodings[0].num_temporal_layers); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderDetectInvalidNumTemporalLayers) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | params.encodings[0].num_temporal_layers = kMaxTemporalStreams + 1; | 
|  | RTCError result = video_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.type()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCanSetMaxFramerate) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | params.encodings[0].max_framerate = 20; | 
|  |  | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(20., params.encodings[0].max_framerate); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCanSetMaxFramerateZero) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | params.encodings[0].max_framerate = 0.; | 
|  |  | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(0., params.encodings[0].max_framerate); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderDetectInvalidMaxFramerate) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | params.encodings[0].max_framerate = -5.; | 
|  | RTCError result = video_rtp_sender_->SetParameters(params); | 
|  | EXPECT_EQ(RTCErrorType::INVALID_RANGE, result.type()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | // A video sender can have multiple simulcast layers, in which case it will | 
|  | // contain multiple RtpEncodingParameters. This tests that if this is the case | 
|  | // (simulcast), then we can't set the bitrate_priority, or max_bitrate_bps | 
|  | // for any encodings besides at index 0, because these are both implemented | 
|  | // "per-sender." | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCantSetPerSenderEncodingParameters) { | 
|  | // Add a simulcast specific send stream that contains 2 encoding parameters. | 
|  | CreateVideoRtpSenderWithSimulcast(); | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size()); | 
|  |  | 
|  | params.encodings[1].bitrate_priority = 2.0; | 
|  | EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, | 
|  | video_rtp_sender_->SetParameters(params).type()); | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCantSetReadOnlyEncodingParameters) { | 
|  | // Add a simulcast specific send stream that contains 2 encoding parameters. | 
|  | CreateVideoRtpSenderWithSimulcast(); | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size()); | 
|  |  | 
|  | for (size_t i = 0; i < params.encodings.size(); i++) { | 
|  | params.encodings[i].ssrc = 1337; | 
|  | EXPECT_EQ(RTCErrorType::INVALID_MODIFICATION, | 
|  | video_rtp_sender_->SetParameters(params).type()); | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | } | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, SetVideoMinMaxSendBitrate) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | EXPECT_EQ(-1, video_media_send_channel()->max_bps()); | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_FALSE(params.encodings[0].min_bitrate_bps); | 
|  | EXPECT_FALSE(params.encodings[0].max_bitrate_bps); | 
|  | params.encodings[0].min_bitrate_bps = 100; | 
|  | params.encodings[0].max_bitrate_bps = 1000; | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | // Read back the parameters and verify they have been changed. | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(100, params.encodings[0].min_bitrate_bps); | 
|  | EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); | 
|  |  | 
|  | // Verify that the video channel received the new parameters. | 
|  | params = video_media_send_channel()->GetRtpSendParameters(kVideoSsrc); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(100, params.encodings[0].min_bitrate_bps); | 
|  | EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); | 
|  |  | 
|  | // Verify that the global bitrate limit has not been changed. | 
|  | EXPECT_EQ(-1, video_media_send_channel()->max_bps()); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, SetVideoMinMaxSendBitrateSimulcast) { | 
|  | // Add a simulcast specific send stream that contains 2 encoding parameters. | 
|  | CreateVideoRtpSenderWithSimulcast(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size()); | 
|  | params.encodings[0].min_bitrate_bps = 100; | 
|  | params.encodings[0].max_bitrate_bps = 1000; | 
|  | params.encodings[1].min_bitrate_bps = 200; | 
|  | params.encodings[1].max_bitrate_bps = 2000; | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | // Verify that the video channel received the new parameters. | 
|  | params = | 
|  | video_media_send_channel()->GetRtpSendParameters(kVideoSsrcSimulcast); | 
|  | EXPECT_EQ(kVideoSimulcastLayerCount, params.encodings.size()); | 
|  | EXPECT_EQ(100, params.encodings[0].min_bitrate_bps); | 
|  | EXPECT_EQ(1000, params.encodings[0].max_bitrate_bps); | 
|  | EXPECT_EQ(200, params.encodings[1].min_bitrate_bps); | 
|  | EXPECT_EQ(2000, params.encodings[1].max_bitrate_bps); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, SetVideoBitratePriority) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | RtpParameters params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(kDefaultBitratePriority, params.encodings[0].bitrate_priority); | 
|  | double new_bitrate_priority = 2.0; | 
|  | params.encodings[0].bitrate_priority = new_bitrate_priority; | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(params).ok()); | 
|  |  | 
|  | params = video_rtp_sender_->GetParameters(); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(new_bitrate_priority, params.encodings[0].bitrate_priority); | 
|  |  | 
|  | params = video_media_send_channel()->GetRtpSendParameters(kVideoSsrc); | 
|  | EXPECT_EQ(1U, params.encodings.size()); | 
|  | EXPECT_EQ(new_bitrate_priority, params.encodings[0].bitrate_priority); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoReceiverCanGetParametersWithSimulcast) { | 
|  | CreateVideoRtpReceiverWithSimulcast({}, 2); | 
|  |  | 
|  | RtpParameters params = video_rtp_receiver_->GetParameters(); | 
|  | EXPECT_EQ(2u, params.encodings.size()); | 
|  |  | 
|  | DestroyVideoRtpReceiver(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, GenerateKeyFrameWithAudio) { | 
|  | CreateAudioRtpSender(); | 
|  |  | 
|  | auto error = audio_rtp_sender_->GenerateKeyFrame({}); | 
|  | EXPECT_FALSE(error.ok()); | 
|  | EXPECT_EQ(error.type(), RTCErrorType::UNSUPPORTED_OPERATION); | 
|  |  | 
|  | DestroyAudioRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, GenerateKeyFrameWithVideo) { | 
|  | CreateVideoRtpSenderWithSimulcast({"1", "2", "3"}); | 
|  |  | 
|  | auto error = video_rtp_sender_->GenerateKeyFrame({}); | 
|  | EXPECT_TRUE(error.ok()); | 
|  |  | 
|  | error = video_rtp_sender_->GenerateKeyFrame({"1"}); | 
|  | EXPECT_TRUE(error.ok()); | 
|  |  | 
|  | error = video_rtp_sender_->GenerateKeyFrame({""}); | 
|  | EXPECT_FALSE(error.ok()); | 
|  | EXPECT_EQ(error.type(), RTCErrorType::INVALID_PARAMETER); | 
|  |  | 
|  | error = video_rtp_sender_->GenerateKeyFrame({"no-such-rid"}); | 
|  | EXPECT_FALSE(error.ok()); | 
|  | EXPECT_EQ(error.type(), RTCErrorType::INVALID_PARAMETER); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that makes sure that a video track content hint translates to the proper | 
|  | // value for sources that are not screencast. | 
|  | TEST_F(RtpSenderReceiverTest, PropagatesVideoTrackContentHint) { | 
|  | CreateVideoRtpSender(); | 
|  |  | 
|  | video_track_->set_enabled(true); | 
|  |  | 
|  | // `video_track_` is not screencast by default. | 
|  | EXPECT_EQ(false, video_media_send_channel()->options().is_screencast); | 
|  | // No content hint should be set by default. | 
|  | EXPECT_EQ(VideoTrackInterface::ContentHint::kNone, | 
|  | video_track_->content_hint()); | 
|  | // Setting detailed should turn a non-screencast source into screencast mode. | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kDetailed); | 
|  | EXPECT_EQ(true, video_media_send_channel()->options().is_screencast); | 
|  | // Removing the content hint should turn the track back into non-screencast | 
|  | // mode. | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kNone); | 
|  | EXPECT_EQ(false, video_media_send_channel()->options().is_screencast); | 
|  | // Setting fluid should remain in non-screencast mode (its default). | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kFluid); | 
|  | EXPECT_EQ(false, video_media_send_channel()->options().is_screencast); | 
|  | // Setting text should have the same effect as Detailed | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kText); | 
|  | EXPECT_EQ(true, video_media_send_channel()->options().is_screencast); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that makes sure that a video track content hint translates to the proper | 
|  | // value for screencast sources. | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | PropagatesVideoTrackContentHintForScreencastSource) { | 
|  | CreateVideoRtpSender(true); | 
|  |  | 
|  | video_track_->set_enabled(true); | 
|  |  | 
|  | // `video_track_` with a screencast source should be screencast by default. | 
|  | EXPECT_EQ(true, video_media_send_channel()->options().is_screencast); | 
|  | // No content hint should be set by default. | 
|  | EXPECT_EQ(VideoTrackInterface::ContentHint::kNone, | 
|  | video_track_->content_hint()); | 
|  | // Setting fluid should turn a screencast source into non-screencast mode. | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kFluid); | 
|  | EXPECT_EQ(false, video_media_send_channel()->options().is_screencast); | 
|  | // Removing the content hint should turn the track back into screencast mode. | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kNone); | 
|  | EXPECT_EQ(true, video_media_send_channel()->options().is_screencast); | 
|  | // Setting detailed should still remain in screencast mode (its default). | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kDetailed); | 
|  | EXPECT_EQ(true, video_media_send_channel()->options().is_screencast); | 
|  | // Setting text should have the same effect as Detailed | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kText); | 
|  | EXPECT_EQ(true, video_media_send_channel()->options().is_screencast); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | // Test that makes sure any content hints that are set on a track before | 
|  | // VideoRtpSender is ready to send are still applied when it gets ready to send. | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | PropagatesVideoTrackContentHintSetBeforeEnabling) { | 
|  | AddVideoTrack(); | 
|  | std::unique_ptr<MockSetStreamsObserver> set_streams_observer = | 
|  | std::make_unique<MockSetStreamsObserver>(); | 
|  | // Setting detailed overrides the default non-screencast mode. This should be | 
|  | // applied even if the track is set on construction. | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kDetailed); | 
|  | video_rtp_sender_ = | 
|  | VideoRtpSender::Create(CreateEnvironment(), worker_thread_, | 
|  | video_track_->id(), set_streams_observer.get()); | 
|  | ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get())); | 
|  | EXPECT_CALL(*set_streams_observer, OnSetStreams()); | 
|  | video_rtp_sender_->SetStreams({local_stream_->id()}); | 
|  | video_rtp_sender_->SetMediaChannel( | 
|  | video_media_send_channel()->AsVideoSendChannel()); | 
|  | video_track_->set_enabled(true); | 
|  |  | 
|  | // Sender is not ready to send (no SSRC) so no option should have been set. | 
|  | EXPECT_EQ(std::nullopt, video_media_send_channel()->options().is_screencast); | 
|  |  | 
|  | // Verify that the content hint is accounted for when video_rtp_sender_ does | 
|  | // get enabled. | 
|  | video_rtp_sender_->SetSsrc(kVideoSsrc); | 
|  | EXPECT_EQ(true, video_media_send_channel()->options().is_screencast); | 
|  |  | 
|  | // And removing the hint should go back to false (to verify that false was | 
|  | // default correctly). | 
|  | video_track_->set_content_hint(VideoTrackInterface::ContentHint::kNone); | 
|  | EXPECT_EQ(false, video_media_send_channel()->options().is_screencast); | 
|  |  | 
|  | DestroyVideoRtpSender(); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderHasDtmfSender) { | 
|  | CreateAudioRtpSender(); | 
|  | EXPECT_NE(nullptr, audio_rtp_sender_->GetDtmfSender()); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderDoesNotHaveDtmfSender) { | 
|  | CreateVideoRtpSender(); | 
|  | EXPECT_EQ(nullptr, video_rtp_sender_->GetDtmfSender()); | 
|  | } | 
|  |  | 
|  | // Test that the DTMF sender is really using `voice_channel_`, and thus returns | 
|  | // true/false from CanSendDtmf based on what `voice_channel_` returns. | 
|  | TEST_F(RtpSenderReceiverTest, CanInsertDtmf) { | 
|  | AddDtmfCodec(); | 
|  | CreateAudioRtpSender(); | 
|  | auto dtmf_sender = audio_rtp_sender_->GetDtmfSender(); | 
|  | ASSERT_NE(nullptr, dtmf_sender); | 
|  | EXPECT_TRUE(dtmf_sender->CanInsertDtmf()); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, CanNotInsertDtmf) { | 
|  | CreateAudioRtpSender(); | 
|  | auto dtmf_sender = audio_rtp_sender_->GetDtmfSender(); | 
|  | ASSERT_NE(nullptr, dtmf_sender); | 
|  | // DTMF codec has not been added, as it was in the above test. | 
|  | EXPECT_FALSE(dtmf_sender->CanInsertDtmf()); | 
|  | } | 
|  |  | 
|  | TEST_F(RtpSenderReceiverTest, InsertDtmf) { | 
|  | AddDtmfCodec(); | 
|  | CreateAudioRtpSender(); | 
|  | auto dtmf_sender = audio_rtp_sender_->GetDtmfSender(); | 
|  | ASSERT_NE(nullptr, dtmf_sender); | 
|  |  | 
|  | EXPECT_EQ(0U, voice_media_send_channel()->dtmf_info_queue().size()); | 
|  |  | 
|  | // Insert DTMF | 
|  | const int expected_duration = 90; | 
|  | dtmf_sender->InsertDtmf("012", expected_duration, 100); | 
|  |  | 
|  | // Verify | 
|  | ASSERT_THAT( | 
|  | WaitUntil( | 
|  | [&] { return voice_media_send_channel()->dtmf_info_queue().size(); }, | 
|  | ::testing::Eq(3U)), | 
|  | IsRtcOk()); | 
|  | const uint32_t send_ssrc = | 
|  | voice_media_send_channel()->send_streams()[0].first_ssrc(); | 
|  | EXPECT_TRUE(CompareDtmfInfo(voice_media_send_channel()->dtmf_info_queue()[0], | 
|  | send_ssrc, 0, expected_duration)); | 
|  | EXPECT_TRUE(CompareDtmfInfo(voice_media_send_channel()->dtmf_info_queue()[1], | 
|  | send_ssrc, 1, expected_duration)); | 
|  | EXPECT_TRUE(CompareDtmfInfo(voice_media_send_channel()->dtmf_info_queue()[2], | 
|  | send_ssrc, 2, expected_duration)); | 
|  | } | 
|  |  | 
|  | // Validate that the default FrameEncryptor setting is nullptr. | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderCanSetFrameEncryptor) { | 
|  | CreateAudioRtpSender(); | 
|  | scoped_refptr<FrameEncryptorInterface> fake_frame_encryptor( | 
|  | new FakeFrameEncryptor()); | 
|  | EXPECT_EQ(nullptr, audio_rtp_sender_->GetFrameEncryptor()); | 
|  | audio_rtp_sender_->SetFrameEncryptor(fake_frame_encryptor); | 
|  | EXPECT_EQ(fake_frame_encryptor.get(), | 
|  | audio_rtp_sender_->GetFrameEncryptor().get()); | 
|  | } | 
|  |  | 
|  | // Validate that setting a FrameEncryptor after the send stream is stopped does | 
|  | // nothing. | 
|  | TEST_F(RtpSenderReceiverTest, AudioSenderCannotSetFrameEncryptorAfterStop) { | 
|  | CreateAudioRtpSender(); | 
|  | scoped_refptr<FrameEncryptorInterface> fake_frame_encryptor( | 
|  | new FakeFrameEncryptor()); | 
|  | EXPECT_EQ(nullptr, audio_rtp_sender_->GetFrameEncryptor()); | 
|  | audio_rtp_sender_->Stop(); | 
|  | audio_rtp_sender_->SetFrameEncryptor(fake_frame_encryptor); | 
|  | // TODO(webrtc:9926) - Validate media channel not set once fakes updated. | 
|  | } | 
|  |  | 
|  | // Validate that the default FrameEncryptor setting is nullptr. | 
|  | TEST_F(RtpSenderReceiverTest, AudioReceiverCanSetFrameDecryptor) { | 
|  | CreateAudioRtpReceiver(); | 
|  | scoped_refptr<FrameDecryptorInterface> fake_frame_decryptor( | 
|  | make_ref_counted<FakeFrameDecryptor>()); | 
|  | EXPECT_EQ(nullptr, audio_rtp_receiver_->GetFrameDecryptor()); | 
|  | audio_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor); | 
|  | EXPECT_EQ(fake_frame_decryptor.get(), | 
|  | audio_rtp_receiver_->GetFrameDecryptor().get()); | 
|  | DestroyAudioRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Validate that the default FrameEncryptor setting is nullptr. | 
|  | TEST_F(RtpSenderReceiverTest, AudioReceiverCannotSetFrameDecryptorAfterStop) { | 
|  | CreateAudioRtpReceiver(); | 
|  | scoped_refptr<FrameDecryptorInterface> fake_frame_decryptor( | 
|  | make_ref_counted<FakeFrameDecryptor>()); | 
|  | EXPECT_EQ(nullptr, audio_rtp_receiver_->GetFrameDecryptor()); | 
|  | audio_rtp_receiver_->SetMediaChannel(nullptr); | 
|  | audio_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor); | 
|  | // TODO(webrtc:9926) - Validate media channel not set once fakes updated. | 
|  | DestroyAudioRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Validate that the default FrameEncryptor setting is nullptr. | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCanSetFrameEncryptor) { | 
|  | CreateVideoRtpSender(); | 
|  | scoped_refptr<FrameEncryptorInterface> fake_frame_encryptor( | 
|  | new FakeFrameEncryptor()); | 
|  | EXPECT_EQ(nullptr, video_rtp_sender_->GetFrameEncryptor()); | 
|  | video_rtp_sender_->SetFrameEncryptor(fake_frame_encryptor); | 
|  | EXPECT_EQ(fake_frame_encryptor.get(), | 
|  | video_rtp_sender_->GetFrameEncryptor().get()); | 
|  | } | 
|  |  | 
|  | // Validate that setting a FrameEncryptor after the send stream is stopped does | 
|  | // nothing. | 
|  | TEST_F(RtpSenderReceiverTest, VideoSenderCannotSetFrameEncryptorAfterStop) { | 
|  | CreateVideoRtpSender(); | 
|  | scoped_refptr<FrameEncryptorInterface> fake_frame_encryptor( | 
|  | new FakeFrameEncryptor()); | 
|  | EXPECT_EQ(nullptr, video_rtp_sender_->GetFrameEncryptor()); | 
|  | video_rtp_sender_->Stop(); | 
|  | video_rtp_sender_->SetFrameEncryptor(fake_frame_encryptor); | 
|  | // TODO(webrtc:9926) - Validate media channel not set once fakes updated. | 
|  | } | 
|  |  | 
|  | // Validate that the default FrameEncryptor setting is nullptr. | 
|  | TEST_F(RtpSenderReceiverTest, VideoReceiverCanSetFrameDecryptor) { | 
|  | CreateVideoRtpReceiver(); | 
|  | scoped_refptr<FrameDecryptorInterface> fake_frame_decryptor( | 
|  | make_ref_counted<FakeFrameDecryptor>()); | 
|  | EXPECT_EQ(nullptr, video_rtp_receiver_->GetFrameDecryptor()); | 
|  | video_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor); | 
|  | EXPECT_EQ(fake_frame_decryptor.get(), | 
|  | video_rtp_receiver_->GetFrameDecryptor().get()); | 
|  | DestroyVideoRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Validate that the default FrameEncryptor setting is nullptr. | 
|  | TEST_F(RtpSenderReceiverTest, VideoReceiverCannotSetFrameDecryptorAfterStop) { | 
|  | CreateVideoRtpReceiver(); | 
|  | scoped_refptr<FrameDecryptorInterface> fake_frame_decryptor( | 
|  | make_ref_counted<FakeFrameDecryptor>()); | 
|  | EXPECT_EQ(nullptr, video_rtp_receiver_->GetFrameDecryptor()); | 
|  | video_rtp_receiver_->SetMediaChannel(nullptr); | 
|  | video_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor); | 
|  | // TODO(webrtc:9926) - Validate media channel not set once fakes updated. | 
|  | DestroyVideoRtpReceiver(); | 
|  | } | 
|  |  | 
|  | // Checks that calling the internal methods for get/set parameters do not | 
|  | // invalidate any parameters retreived by clients. | 
|  | TEST_F(RtpSenderReceiverTest, | 
|  | InternalParameterMethodsDoNotInvalidateTransaction) { | 
|  | CreateVideoRtpSender(); | 
|  | RtpParameters parameters = video_rtp_sender_->GetParameters(); | 
|  | RtpParameters new_parameters = video_rtp_sender_->GetParametersInternal(); | 
|  | new_parameters.encodings[0].active = false; | 
|  | video_rtp_sender_->SetParametersInternal(new_parameters, nullptr, true); | 
|  | new_parameters.encodings[0].active = true; | 
|  | video_rtp_sender_->SetParametersInternal(new_parameters, nullptr, true); | 
|  | parameters.encodings[0].active = false; | 
|  | EXPECT_TRUE(video_rtp_sender_->SetParameters(parameters).ok()); | 
|  | } | 
|  |  | 
|  | // Checks that the senders SetStreams eliminates duplicate stream ids. | 
|  | TEST_F(RtpSenderReceiverTest, SenderSetStreamsEliminatesDuplicateIds) { | 
|  | AddVideoTrack(); | 
|  | video_rtp_sender_ = VideoRtpSender::Create( | 
|  | CreateEnvironment(), worker_thread_, video_track_->id(), nullptr); | 
|  | video_rtp_sender_->SetStreams({"1", "2", "1"}); | 
|  | EXPECT_EQ(video_rtp_sender_->stream_ids().size(), 2u); | 
|  | } | 
|  |  | 
|  | // Helper method for syntactic sugar for accepting a vector with '{}' notation. | 
|  | std::pair<RidList, RidList> CreatePairOfRidVectors( | 
|  | const std::vector<std::string>& first, | 
|  | const std::vector<std::string>& second) { | 
|  | return std::make_pair(first, second); | 
|  | } | 
|  |  | 
|  | // These parameters are used to test disabling simulcast layers. | 
|  | const std::pair<RidList, RidList> kDisableSimulcastLayersParameters[] = { | 
|  | // Tests removing the first layer. This is a special case because | 
|  | // the first layer's SSRC is also the 'primary' SSRC used to associate the | 
|  | // parameters to the media channel. | 
|  | CreatePairOfRidVectors({"1", "2", "3", "4"}, {"1"}), | 
|  | // Tests removing some layers. | 
|  | CreatePairOfRidVectors({"1", "2", "3", "4"}, {"2", "4"}), | 
|  | // Tests simulcast rejected scenario all layers except first are rejected. | 
|  | CreatePairOfRidVectors({"1", "2", "3", "4"}, {"2", "3", "4"}), | 
|  | // Tests removing all layers. | 
|  | CreatePairOfRidVectors({"1", "2", "3", "4"}, {"1", "2", "3", "4"}), | 
|  | }; | 
|  |  | 
|  | // Runs test for disabling layers on a sender without a media engine set. | 
|  | TEST_P(RtpSenderReceiverTest, DisableSimulcastLayersWithoutMediaEngine) { | 
|  | auto parameter = GetParam(); | 
|  | RunDisableSimulcastLayersWithoutMediaEngineTest(parameter.first, | 
|  | parameter.second); | 
|  | } | 
|  |  | 
|  | // Runs test for disabling layers on a sender with a media engine set. | 
|  | TEST_P(RtpSenderReceiverTest, DisableSimulcastLayersWithMediaEngine) { | 
|  | auto parameter = GetParam(); | 
|  | RunDisableSimulcastLayersWithMediaEngineTest(parameter.first, | 
|  | parameter.second); | 
|  | } | 
|  |  | 
|  | INSTANTIATE_TEST_SUITE_P( | 
|  | DisableSimulcastLayersInSender, | 
|  | RtpSenderReceiverTest, | 
|  | ::testing::ValuesIn(kDisableSimulcastLayersParameters)); | 
|  |  | 
|  | }  // namespace webrtc |