/*
 *  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 "absl/functional/any_invocable.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/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/sframe/sframe_encrypter_interface.h"
#include "api/sframe/sframe_types.h"
#include "api/task_queue/task_queue_base.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/scoped_operations_batcher.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"  // IWYU pragma: keep
#include "rtc_base/thread.h"
#include "rtc_base/unique_id_generator.h"
#include "test/create_test_environment.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/run_loop.h"
#include "test/wait_until.h"

namespace webrtc {

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 RtpSenderBase::SetStreamsObserver {
 public:
  MOCK_METHOD(void, OnSetStreams, (), (override));
};

}  // namespace


using ::testing::ContainerEq;
using RidList = std::vector<std::string>;

class MockVideoMediaSendChannel : public FakeVideoMediaSendChannel {
 public:
  MockVideoMediaSendChannel(const VideoOptions& options,
                            TaskQueueBase* network_thread)
      : FakeVideoMediaSendChannel(options, network_thread) {}

  void SetFrameEncryptor(
      uint32_t ssrc,
      scoped_refptr<FrameEncryptorInterface> frame_encryptor) override {
    last_set_frame_encryptor_ = frame_encryptor;
  }

  scoped_refptr<FrameEncryptorInterface> last_set_frame_encryptor_;
};

class RtpSenderReceiverTest
    : public ::testing::Test,
      public ::testing::WithParamInterface<std::pair<RidList, RidList>> {
 public:
  RtpSenderReceiverTest()
      : network_thread_(Thread::Create()),
        worker_thread_(Thread::Create()),
        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_.get(), network_thread_.get()),
        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(
        env_, &fake_call_, MediaConfig(), AudioOptions(), CryptoOptions());
    video_media_send_channel_ = media_engine_->video().CreateSendChannel(
        env_, &fake_call_, MediaConfig(), VideoOptions(), CryptoOptions(),
        video_bitrate_allocator_factory_.get(), nullptr, nullptr);
    voice_media_receive_channel_ = media_engine_->voice().CreateReceiveChannel(
        env_, &fake_call_, MediaConfig(), AudioOptions(), CryptoOptions());
    video_media_receive_channel_ = media_engine_->video().CreateReceiveChannel(
        env_, &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));

    network_thread_->Start();
    worker_thread_->Start();
  }

  ~RtpSenderReceiverTest() override {
    DestroyAudioRtpSender();
    DestroyVideoRtpSender();
    DestroyAudioRtpReceiver();
    DestroyVideoRtpReceiver();
    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>();
    worker_thread_->BlockingCall([&]() {
      audio_rtp_sender_ = AudioRtpSender::Create(
          CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
          audio_track_->id(), nullptr, set_streams_observer.get(),
          /*enable_sframe_at_owner=*/nullptr, voice_media_send_channel_.get());
    });
    ASSERT_TRUE(audio_rtp_sender_->SetTrack(audio_track_.get()));
    EXPECT_CALL(*set_streams_observer, OnSetStreams());
    audio_rtp_sender_->SetStreams({local_stream_->id()});
    SetSsrc(kAudioSsrc, *audio_rtp_sender_);
    VerifyVoiceChannelInput();
  }

  void CreateAudioRtpSenderWithNoTrack() {
    worker_thread_->BlockingCall([&]() {
      audio_rtp_sender_ = AudioRtpSender::Create(
          CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
          /*id=*/"", nullptr, nullptr,
          /*enable_sframe_at_owner=*/nullptr, voice_media_send_channel_.get());
    });
  }

  void CreateVideoRtpSender(uint32_t ssrc) {
    CreateVideoRtpSender(false, ssrc);
  }

  void CreateVideoRtpSender() {
    CreateVideoRtpSender(/*is_screencast=*/false, kVideoSsrc);
  }

  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) {
    AddVideoTrack(is_screencast);
    std::unique_ptr<MockSetStreamsObserver> set_streams_observer =
        std::make_unique<MockSetStreamsObserver>();
    worker_thread_->BlockingCall([&]() {
      video_rtp_sender_ = VideoRtpSender::Create(
          CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
          video_track_->id(), set_streams_observer.get(),
          /*enable_sframe_at_owner=*/nullptr, video_media_send_channel(),
          /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
          /*initial_simulcast_layers=*/{});
    });
    ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get()));
    EXPECT_CALL(*set_streams_observer, OnSetStreams());
    video_rtp_sender_->SetStreams({local_stream_->id()});
    SetSsrc(ssrc, *video_rtp_sender_);
    VerifyVideoChannelInput(ssrc);
  }
  void CreateVideoRtpSenderWithNoTrack() {
    worker_thread_->BlockingCall([&]() {
      video_rtp_sender_ = VideoRtpSender::Create(
          CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
          /*id=*/"", nullptr,
          /*enable_sframe_at_owner=*/nullptr, video_media_send_channel(),
          /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
          /*initial_simulcast_layers=*/{});
    });
  }

  void DestroyAudioRtpSender() {
    if (!audio_rtp_sender_)
      return;
    audio_rtp_sender_->Stop();
    audio_rtp_sender_ = nullptr;
    VerifyVoiceChannelNoInput();
  }

  void DestroyVideoRtpSender() {
    if (!video_rtp_sender_)
      return;
    video_rtp_sender_->Stop();
    video_rtp_sender_ = nullptr;
    VerifyVideoChannelNoInput();
  }

  void CreateAudioRtpReceiver(
      std::vector<scoped_refptr<MediaStreamInterface>> streams = {}) {
    audio_rtp_receiver_ = make_ref_counted<AudioRtpReceiver>(
        worker_thread_.get(), kAudioTrackId, streams);
    worker_thread_->BlockingCall([this] {
      audio_rtp_receiver_->SetMediaChannel(voice_media_receive_channel());
    });
    auto setup_task = audio_rtp_receiver_->GetSetupForMediaChannel(kAudioSsrc);
    worker_thread_->BlockingCall(
        [task = std::move(setup_task)]() mutable { std::move(task)(); });
    audio_track_ = audio_rtp_receiver_->audio_track();
    VerifyVoiceChannelOutput();
  }

  void CreateVideoRtpReceiver(
      std::vector<scoped_refptr<MediaStreamInterface>> streams = {}) {
    video_rtp_receiver_ = make_ref_counted<VideoRtpReceiver>(
        worker_thread_.get(), kVideoTrackId, streams,
        /*enable_sframe_at_owner=*/nullptr);
    worker_thread_->BlockingCall([this] {
      video_rtp_receiver_->SetMediaChannel(video_media_receive_channel());
    });
    auto setup_task = video_rtp_receiver_->GetSetupForMediaChannel(kVideoSsrc);
    worker_thread_->BlockingCall(
        [task = std::move(setup_task)]() mutable { std::move(task)(); });
    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>(
        worker_thread_.get(), kVideoTrackId, streams,
        /*enable_sframe_at_owner=*/nullptr);
    worker_thread_->BlockingCall([this] {
      video_rtp_receiver_->SetMediaChannel(video_media_receive_channel());
    });
    auto setup_task =
        video_rtp_receiver_->GetSetupForMediaChannel(primary_ssrc);
    worker_thread_->BlockingCall(
        [task = std::move(setup_task)]() mutable { std::move(task)(); });
    video_track_ = video_rtp_receiver_->video_track();
  }

  void DestroyAudioRtpReceiver() {
    if (!audio_rtp_receiver_)
      return;
    worker_thread_->BlockingCall(
        [this] { audio_rtp_receiver_->SetMediaChannel(nullptr); });
    audio_rtp_receiver_ = nullptr;
    VerifyVoiceChannelNoOutput();
  }

  void DestroyVideoRtpReceiver() {
    if (!video_rtp_receiver_)
      return;
    video_rtp_receiver_->Stop();
    worker_thread_->BlockingCall(
        [this] { video_rtp_receiver_->SetMediaChannel(nullptr); });
    video_rtp_receiver_ = nullptr;
    VerifyVideoChannelNoOutput();
  }

  void FlushWorker() {
    RTC_DCHECK_EQ(TaskQueueBase::Current(), run_loop_.task_queue());
    worker_thread_->PostTask([this, signaling_thread = run_loop_.task_queue()] {
      signaling_thread->PostTask([this] { run_loop_.Quit(); });
    });
    run_loop_.Run();
  }

  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(
        CreateTestEnvironment(), signaling_thread_, worker_thread_.get(), "1",
        nullptr, /*enable_sframe_at_owner=*/nullptr, nullptr,
        /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
        /*initial_simulcast_layers=*/{});
    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) {
    worker_thread_->BlockingCall(
        [&] { 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());
  }

  void SetSsrc(uint32_t ssrc, RtpSenderInternal& sender) {
    ScopedOperationsBatcher worker_tasks(worker_thread_.get());
    worker_tasks.AddWithFinalizer(sender.SetSsrcTask(ssrc));
  }

  test::RunLoop run_loop_;
  // Initialize `signaling_thread_` to point to the current thread.
  // This is the internal thread owned by `run_loop_`.
  Thread* const signaling_thread_ = Thread::Current();
  const std::unique_ptr<Thread> network_thread_;
  const std::unique_ptr<Thread> worker_thread_;
  const Environment env_ = CreateTestEnvironment();
  // 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);
  FlushWorker();  // Wait for volume change.

  EXPECT_TRUE(
      voice_media_receive_channel()->GetOutputVolume(kAudioSsrc, &volume));
  EXPECT_EQ(0, volume);

  audio_track_->set_enabled(true);
  FlushWorker();  // Wait for volume change.

  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);
  // Wait for the worker thread to apply the volume change.
  FlushWorker();

  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);
  audio_track_->GetSource()->SetVolume(0.8);
  FlushWorker();  // Wait for the the volume change.
  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);
  FlushWorker();  // The volume is applied asynchronously.

  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);
  FlushWorker();

  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));
  SetSsrc(kAudioSsrc, *audio_rtp_sender_);
  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));
  SetSsrc(kVideoSsrc, *video_rtp_sender_);
  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);
  SetSsrc(kAudioSsrc, *audio_rtp_sender_);
  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());
  SetSsrc(kAudioSsrc, *audio_rtp_sender_);
  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();
  SetSsrc(kVideoSsrc, *video_rtp_sender_);
  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());
  SetSsrc(kVideoSsrc, *video_rtp_sender_);
  VerifyVideoChannelInput();

  DestroyVideoRtpSender();
}

// Test that the media channel stops sending when the audio sender's SSRC is set
// to 0.
TEST_F(RtpSenderReceiverTest, AudioSenderSsrcSetToZero) {
  CreateAudioRtpSender();

  SetSsrc(0, *audio_rtp_sender_);
  VerifyVoiceChannelNoInput();
}

// Test that the media channel stops sending when the video sender's SSRC is set
// to 0.
TEST_F(RtpSenderReceiverTest, VideoSenderSsrcSetToZero) {
  CreateAudioRtpSender();

  SetSsrc(0, *audio_rtp_sender_);
  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();

  SetSsrc(0, *video_rtp_sender_);
  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();

  SetSsrc(kAudioSsrc2, *audio_rtp_sender_);
  VerifyVoiceChannelNoInput(kAudioSsrc);
  VerifyVoiceChannelInput(kAudioSsrc2);

  DestroyAudioRtpSender();
  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();

  SetSsrc(kVideoSsrc2, *video_rtp_sender_);
  VerifyVideoChannelNoInput(kVideoSsrc);
  VerifyVideoChannelInput(kVideoSsrc2);

  DestroyVideoRtpSender();
  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, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  EXPECT_TRUE(result->ok());

  DestroyAudioRtpSender();
}

TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersBeforeNegotiation) {
  audio_rtp_sender_ = AudioRtpSender::Create(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      /*id=*/"", nullptr, nullptr,
      /*enable_sframe_at_owner=*/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(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      /*id=*/"", nullptr, nullptr,
      /*enable_sframe_at_owner=*/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, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  EXPECT_TRUE(result->ok());

  params = audio_rtp_sender_->GetParameters();
  EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000);

  audio_rtp_sender_->SetParametersAsync(params, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  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(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      audio_track_->id(), nullptr, set_streams_observer.get(),
      /*enable_sframe_at_owner=*/nullptr, nullptr);
  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);
  worker_thread_->BlockingCall([&] {
    audio_rtp_sender_->SetMediaChannel(
        voice_media_send_channel()->AsVoiceSendChannel());
  });
  SetSsrc(1, *audio_rtp_sender_);

  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(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      /*id=*/"", nullptr, nullptr,
      /*enable_sframe_at_owner=*/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, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  EXPECT_TRUE(result->ok());
  audio_rtp_sender_->SetParametersAsync(params, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  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, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  EXPECT_TRUE(result->ok());

  DestroyVideoRtpSender();
}

TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersBeforeNegotiation) {
  video_rtp_sender_ = VideoRtpSender::Create(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      /*id=*/"", nullptr, /*enable_sframe_at_owner=*/nullptr, nullptr,
      /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
      /*initial_simulcast_layers=*/{});

  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, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  EXPECT_TRUE(result->ok());

  params = video_rtp_sender_->GetParameters();
  EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000);
  video_rtp_sender_->SetParametersAsync(params, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  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(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      video_track_->id(), set_streams_observer.get(),
      /*enable_sframe_at_owner=*/nullptr, nullptr,
      /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
      /*initial_simulcast_layers=*/{});
  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);
  worker_thread_->BlockingCall([&] {
    video_rtp_sender_->SetMediaChannel(
        video_media_send_channel()->AsVideoSendChannel());
  });
  SetSsrc(kVideoSsrcSimulcast, *video_rtp_sender_);

  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(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      video_track_->id(), set_streams_observer.get(),
      /*enable_sframe_at_owner=*/nullptr, nullptr,
      /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
      /*initial_simulcast_layers=*/{});
  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);
  worker_thread_->BlockingCall([&] {
    video_rtp_sender_->SetMediaChannel(
        video_media_send_channel()->AsVideoSendChannel());
  });
  SetSsrc(kVideoSsrcSimulcast, *video_rtp_sender_);

  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)
TEST(RtpSenderReceiverDeathTest,
     VideoSenderManualRemoveSimulcastFailsDeathTest) {
  test::RunLoop run_loop;
  Environment env = CreateTestEnvironment();
  // This test uses a single thread for all of signaling, worker and network.
  Thread* thread = Thread::Current();

  auto media_engine = std::make_unique<FakeMediaEngine>();
  FakeCall fake_call(env, thread, thread);

  std::unique_ptr<VideoBitrateAllocatorFactory>
      video_bitrate_allocator_factory =
          CreateBuiltinVideoBitrateAllocatorFactory();
  auto video_media_send_channel = media_engine->video().CreateSendChannel(
      env, &fake_call, MediaConfig(), VideoOptions(), CryptoOptions(),
      video_bitrate_allocator_factory.get(), nullptr, nullptr);

  scoped_refptr<MediaStreamInterface> local_stream =
      MediaStream::Create(kStreamId1);
  scoped_refptr<VideoTrackInterface> video_track = VideoTrack::Create(
      kVideoTrackId, FakeVideoTrackSource::Create(/*is_screencast=*/false),
      thread);
  EXPECT_TRUE(local_stream->AddTrack(video_track));

  std::unique_ptr<MockSetStreamsObserver> set_streams_observer =
      std::make_unique<MockSetStreamsObserver>();
  auto video_rtp_sender = VideoRtpSender::Create(
      env, thread, thread, video_track->id(), set_streams_observer.get(),
      /*enable_sframe_at_owner=*/nullptr, nullptr,
      /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
      /*initial_simulcast_layers=*/{});

  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.
  StreamParams stream_params = StreamParams::CreateLegacy(kVideoSsrc);
  video_media_send_channel->AddSendStream(stream_params);

  video_rtp_sender->SetMediaChannel(
      video_media_send_channel->AsVideoSendChannel());
  EXPECT_DEATH(
      {
        ScopedOperationsBatcher worker_tasks(thread);
        worker_tasks.AddWithFinalizer(
            video_rtp_sender->SetSsrcTask(kVideoSsrcSimulcast));
      },
      "");
  video_rtp_sender->Stop();
}
#endif

TEST_F(RtpSenderReceiverTest,
       VideoSenderMustCallGetParametersBeforeSetParametersBeforeNegotiation) {
  video_rtp_sender_ = VideoRtpSender::Create(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      /*id=*/"", nullptr, /*enable_sframe_at_owner=*/nullptr, nullptr,
      /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
      /*initial_simulcast_layers=*/{});

  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::string old_id = params.transaction_id;
  std::optional<RTCError> result;
  video_rtp_sender_->SetParametersAsync(params, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  EXPECT_TRUE(result->ok());

  params.transaction_id = old_id;
  result.reset();
  video_rtp_sender_->SetParametersAsync(params, [&](RTCError error) {
    result = error;
    run_loop_.Quit();
  });
  run_loop_.Run();
  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 = worker_thread_->BlockingCall(
      [&] { return 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, kVideoSsrc);

  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(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      video_track_->id(), set_streams_observer.get(),
      /*enable_sframe_at_owner=*/nullptr, nullptr,
      /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
      /*initial_simulcast_layers=*/{});
  ASSERT_TRUE(video_rtp_sender_->SetTrack(video_track_.get()));
  EXPECT_CALL(*set_streams_observer, OnSetStreams());
  video_rtp_sender_->SetStreams({local_stream_->id()});
  worker_thread_->BlockingCall([&] {
    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.
  SetSsrc(kVideoSsrc, *video_rtp_sender_);
  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>());
  worker_thread_->BlockingCall([&] {
    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>());
  worker_thread_->BlockingCall([&] {
    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>());
  worker_thread_->BlockingCall([&] {
    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>());
  worker_thread_->BlockingCall([&] {
    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;
  EXPECT_TRUE(
      video_rtp_sender_->SetParametersInternal(new_parameters, nullptr, true)
          .ok());
  new_parameters.encodings[0].active = true;
  EXPECT_TRUE(
      video_rtp_sender_->SetParametersInternal(new_parameters, nullptr, true)
          .ok());
  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(
      CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
      video_track_->id(), nullptr,
      /*enable_sframe_at_owner=*/nullptr, nullptr,
      /*init_send_encodings=*/{}, /*simulcast_rejected=*/false,
      /*initial_simulcast_layers=*/{});
  video_rtp_sender_->SetStreams({"1", "2", "1"});
  EXPECT_EQ(video_rtp_sender_->stream_ids().size(), 2u);
}

TEST_F(RtpSenderReceiverTest, SetSsrcPropagatesFrameEncryptorWithNoEncodings) {
  // Create mock channel with strict expectations.
  auto mock_channel = std::make_unique<MockVideoMediaSendChannel>(
      VideoOptions(), network_thread_.get());
  MockVideoMediaSendChannel* mock_channel_ptr = mock_channel.get();
  // RtpSenderReceiverTest takes ownership of the channel.
  video_media_send_channel_ = std::move(mock_channel);

  // Create sender with no track, which results in empty encodings.
  CreateVideoRtpSenderWithNoTrack();
  video_rtp_sender_->set_init_send_encodings({});

  auto frame_encryptor =
      scoped_refptr<FakeFrameEncryptor>(new FakeFrameEncryptor());
  video_rtp_sender_->SetFrameEncryptor(frame_encryptor);
  mock_channel_ptr->last_set_frame_encryptor_ = nullptr;

  // Expect propagation to media channel when SSRC is set.
  SetSsrc(kVideoSsrc, *video_rtp_sender_);
  EXPECT_EQ(mock_channel_ptr->last_set_frame_encryptor_, frame_encryptor);
}

// 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));

TEST_F(RtpSenderReceiverTest, AudioSenderCreateSframeEncrypterInvokesCallback) {
  bool callback_called = false;
  worker_thread_->BlockingCall([&]() {
    audio_rtp_sender_ = AudioRtpSender::Create(
        CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
        /*id=*/"", nullptr, nullptr,
        [&callback_called]() -> RTCError {
          callback_called = true;
          return RTCError::OK();
        },
        nullptr);
  });

  SframeEncrypterInit options{SframeMode::kPerFrame,
                              SframeCipherSuite::kAes128GcmSha256_128};
  audio_rtp_sender_->CreateSframeEncrypterOrError(options);
  EXPECT_TRUE(callback_called);
}

TEST_F(RtpSenderReceiverTest, VideoSenderCreateSframeEncrypterInvokesCallback) {
  bool callback_called = false;
  worker_thread_->BlockingCall([&]() {
    video_rtp_sender_ = VideoRtpSender::Create(
        CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
        /*id=*/"", nullptr,
        [&callback_called]() -> RTCError {
          callback_called = true;
          return RTCError::OK();
        },
        nullptr, /*init_send_encodings=*/{},
        /*simulcast_rejected=*/false, /*initial_simulcast_layers=*/{});
  });

  SframeEncrypterInit options{SframeMode::kPerFrame,
                              SframeCipherSuite::kAes128GcmSha256_128};
  video_rtp_sender_->CreateSframeEncrypterOrError(options);
  EXPECT_TRUE(callback_called);
}

TEST_F(RtpSenderReceiverTest,
       SenderCreateSframeEncrypterPropagatesCallbackError) {
  worker_thread_->BlockingCall([&]() {
    audio_rtp_sender_ = AudioRtpSender::Create(
        CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
        /*id=*/"", nullptr, nullptr,
        []() -> RTCError {
          return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
                          "Rejected for testing");
        },
        nullptr);
  });

  SframeEncrypterInit options{SframeMode::kPerFrame,
                              SframeCipherSuite::kAes128GcmSha256_128};
  auto result = audio_rtp_sender_->CreateSframeEncrypterOrError(options);
  EXPECT_FALSE(result.ok());
  EXPECT_EQ(result.error().type(), RTCErrorType::UNSUPPORTED_OPERATION);
  EXPECT_STREQ(result.error().message(), "Rejected for testing");
}

TEST_F(RtpSenderReceiverTest,
       SenderCreateSframeEncrypterFailsWithNullCallback) {
  worker_thread_->BlockingCall([&]() {
    audio_rtp_sender_ = AudioRtpSender::Create(
        CreateTestEnvironment(), signaling_thread_, worker_thread_.get(),
        /*id=*/"", nullptr, nullptr,
        /*enable_sframe_at_owner=*/nullptr, nullptr);
  });

  SframeEncrypterInit options{SframeMode::kPerFrame,
                              SframeCipherSuite::kAes128GcmSha256_128};
  auto result = audio_rtp_sender_->CreateSframeEncrypterOrError(options);
  EXPECT_FALSE(result.ok());
  EXPECT_EQ(result.error().type(), RTCErrorType::INTERNAL_ERROR);
}

TEST_F(RtpSenderReceiverTest,
       AudioReceiverCreateSframeDecrypterInvokesCallback) {
  bool callback_called = false;
  auto receiver = make_ref_counted<AudioRtpReceiver>(
      worker_thread_.get(), kAudioTrackId, std::vector<std::string>(),
      [&callback_called]() -> RTCError {
        callback_called = true;
        return RTCError::OK();
      });

  receiver->CreateSframeDecrypterOrError(
      SframeCipherSuite::kAes128GcmSha256_128);
  EXPECT_TRUE(callback_called);
}

TEST_F(RtpSenderReceiverTest,
       VideoReceiverCreateSframeDecrypterInvokesCallback) {
  bool callback_called = false;
  auto receiver = make_ref_counted<VideoRtpReceiver>(
      worker_thread_.get(), kVideoTrackId, std::vector<std::string>(),
      [&callback_called]() -> RTCError {
        callback_called = true;
        return RTCError::OK();
      });

  receiver->CreateSframeDecrypterOrError(
      SframeCipherSuite::kAes128GcmSha256_128);
  EXPECT_TRUE(callback_called);
}

TEST_F(RtpSenderReceiverTest,
       ReceiverCreateSframeDecrypterPropagatesCallbackError) {
  auto receiver = make_ref_counted<AudioRtpReceiver>(
      worker_thread_.get(), kAudioTrackId, std::vector<std::string>(),
      []() -> RTCError {
        return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
                        "Rejected for testing");
      });

  auto result = receiver->CreateSframeDecrypterOrError(
      SframeCipherSuite::kAes128GcmSha256_128);
  EXPECT_FALSE(result.ok());
  EXPECT_EQ(result.error().type(), RTCErrorType::UNSUPPORTED_OPERATION);
  EXPECT_STREQ(result.error().message(), "Rejected for testing");
}

TEST_F(RtpSenderReceiverTest,
       ReceiverCreateSframeDecrypterFailsWithNullCallback) {
  auto receiver = make_ref_counted<AudioRtpReceiver>(
      worker_thread_.get(), kAudioTrackId, std::vector<std::string>(),
      /*enable_sframe_at_owner=*/nullptr);

  auto result = receiver->CreateSframeDecrypterOrError(
      SframeCipherSuite::kAes128GcmSha256_128);
  EXPECT_FALSE(result.ok());
  EXPECT_EQ(result.error().type(), RTCErrorType::INTERNAL_ERROR);
}

}  // namespace webrtc
