/*
 *  Copyright (c) 2020 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 "api/stats/rtc_stats_collector_callback.h"
#include "api/stats/rtcstats_objects.h"
#include "pc/test/mock_peer_connection_observers.h"
#include "test/field_trial.h"
#include "test/gtest.h"
#include "test/peer_scenario/peer_scenario.h"
#include "test/peer_scenario/peer_scenario_client.h"

namespace webrtc {
namespace test {

// TODO(terelius): Use fake encoder and enable on Android once
// https://bugs.chromium.org/p/webrtc/issues/detail?id=11408 is fixed.
#if defined(WEBRTC_ANDROID)
#define MAYBE_NoBweChangeFromVideoUnmute DISABLED_NoBweChangeFromVideoUnmute
#else
#define MAYBE_NoBweChangeFromVideoUnmute NoBweChangeFromVideoUnmute
#endif
TEST(GoogCcPeerScenarioTest, MAYBE_NoBweChangeFromVideoUnmute) {
  // If transport wide sequence numbers are used for audio, and the call
  // switches from audio only to video only, there will be a sharp change in
  // packets sizes. This will create a change in propagation time which might be
  // detected as an overuse. Using separate overuse detectors for audio and
  // video avoids the issue.
  std::string audio_twcc_trials("WebRTC-Audio-AlrProbing/Disabled/");
  std::string separate_audio_video(
      "WebRTC-Bwe-SeparateAudioPackets/"
      "enabled:true,packet_threshold:15,time_threshold:1000ms/");
  ScopedFieldTrials field_trial(audio_twcc_trials + separate_audio_video);
  PeerScenario s(*test_info_);
  auto* caller = s.CreateClient(PeerScenarioClient::Config());
  auto* callee = s.CreateClient(PeerScenarioClient::Config());

  BuiltInNetworkBehaviorConfig net_conf;
  net_conf.link_capacity_kbps = 350;
  net_conf.queue_delay_ms = 50;
  auto send_node = s.net()->CreateEmulatedNode(net_conf);
  auto ret_node = s.net()->CreateEmulatedNode(net_conf);

  PeerScenarioClient::VideoSendTrackConfig video_conf;
  video_conf.generator.squares_video->framerate = 15;
  auto video = caller->CreateVideo("VIDEO", video_conf);
  auto audio = caller->CreateAudio("AUDIO", cricket::AudioOptions());

  // Start ICE and exchange SDP.
  s.SimpleConnection(caller, callee, {send_node}, {ret_node});

  // Limit the encoder bitrate to ensure that there are no actual BWE overuses.
  ASSERT_EQ(caller->pc()->GetSenders().size(), 2u);  // 2 senders.
  int num_video_streams = 0;
  for (auto& rtp_sender : caller->pc()->GetSenders()) {
    auto parameters = rtp_sender->GetParameters();
    ASSERT_EQ(parameters.encodings.size(), 1u);  // 1 stream per sender.
    for (auto& encoding_parameters : parameters.encodings) {
      if (encoding_parameters.ssrc == video.sender->ssrc()) {
        num_video_streams++;
        encoding_parameters.max_bitrate_bps = 220000;
        encoding_parameters.max_framerate = 15;
      }
    }
    rtp_sender->SetParameters(parameters);
  }
  ASSERT_EQ(num_video_streams, 1);  // Exactly 1 video stream.

  auto get_bwe = [&] {
    auto callback =
        rtc::make_ref_counted<webrtc::MockRTCStatsCollectorCallback>();
    caller->pc()->GetStats(callback.get());
    s.net()->time_controller()->Wait([&] { return callback->called(); });
    auto stats =
        callback->report()->GetStatsOfType<RTCIceCandidatePairStats>()[0];
    return DataRate::BitsPerSec(*stats->available_outgoing_bitrate);
  };

  s.ProcessMessages(TimeDelta::Seconds(15));
  const DataRate initial_bwe = get_bwe();
  EXPECT_GE(initial_bwe, DataRate::KilobitsPerSec(300));

  // 10 seconds audio only. Bandwidth should not drop.
  video.capturer->Stop();
  s.ProcessMessages(TimeDelta::Seconds(10));
  EXPECT_GE(get_bwe(), initial_bwe);

  // Resume video but stop audio. Bandwidth should not drop.
  video.capturer->Start();
  RTCError status = caller->pc()->RemoveTrackOrError(audio.sender);
  ASSERT_TRUE(status.ok());
  audio.track->set_enabled(false);
  for (int i = 0; i < 10; i++) {
    s.ProcessMessages(TimeDelta::Seconds(1));
    EXPECT_GE(get_bwe(), initial_bwe);
  }

  caller->pc()->Close();
  callee->pc()->Close();
}

}  // namespace test
}  // namespace webrtc
