| /* | 
 |  *  Copyright (c) 2018 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 "call/rtp_bitrate_configurator.h" | 
 |  | 
 | #include <memory> | 
 | #include <optional> | 
 |  | 
 | #include "api/transport/bitrate_settings.h" | 
 | #include "test/gtest.h" | 
 |  | 
 | namespace webrtc { | 
 | using std::nullopt; | 
 |  | 
 | class RtpBitrateConfiguratorTest : public ::testing::Test { | 
 |  public: | 
 |   RtpBitrateConfiguratorTest() | 
 |       : configurator_(new RtpBitrateConfigurator(BitrateConstraints())) {} | 
 |   std::unique_ptr<RtpBitrateConfigurator> configurator_; | 
 |   void UpdateConfigMatches(BitrateConstraints bitrate_config, | 
 |                            std::optional<int> min_bitrate_bps, | 
 |                            std::optional<int> start_bitrate_bps, | 
 |                            std::optional<int> max_bitrate_bps) { | 
 |     std::optional<BitrateConstraints> result = | 
 |         configurator_->UpdateWithSdpParameters(bitrate_config); | 
 |     EXPECT_TRUE(result.has_value()); | 
 |     if (start_bitrate_bps.has_value()) | 
 |       EXPECT_EQ(result->start_bitrate_bps, start_bitrate_bps); | 
 |     if (min_bitrate_bps.has_value()) | 
 |       EXPECT_EQ(result->min_bitrate_bps, min_bitrate_bps); | 
 |     if (max_bitrate_bps.has_value()) | 
 |       EXPECT_EQ(result->max_bitrate_bps, max_bitrate_bps); | 
 |   } | 
 |  | 
 |   void UpdateMaskMatches(BitrateSettings bitrate_mask, | 
 |                          std::optional<int> min_bitrate_bps, | 
 |                          std::optional<int> start_bitrate_bps, | 
 |                          std::optional<int> max_bitrate_bps) { | 
 |     std::optional<BitrateConstraints> result = | 
 |         configurator_->UpdateWithClientPreferences(bitrate_mask); | 
 |     EXPECT_TRUE(result.has_value()); | 
 |     if (start_bitrate_bps.has_value()) | 
 |       EXPECT_EQ(result->start_bitrate_bps, start_bitrate_bps); | 
 |     if (min_bitrate_bps.has_value()) | 
 |       EXPECT_EQ(result->min_bitrate_bps, min_bitrate_bps); | 
 |     if (max_bitrate_bps.has_value()) | 
 |       EXPECT_EQ(result->max_bitrate_bps, max_bitrate_bps); | 
 |   } | 
 | }; | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, NewConfigWithValidConfigReturnsNewConfig) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.min_bitrate_bps = 1; | 
 |   bitrate_config.start_bitrate_bps = 2; | 
 |   bitrate_config.max_bitrate_bps = 3; | 
 |  | 
 |   UpdateConfigMatches(bitrate_config, 1, 2, 3); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, NewConfigWithDifferentMinReturnsNewConfig) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.min_bitrate_bps = 10; | 
 |   bitrate_config.start_bitrate_bps = 20; | 
 |   bitrate_config.max_bitrate_bps = 30; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   bitrate_config.min_bitrate_bps = 11; | 
 |   UpdateConfigMatches(bitrate_config, 11, -1, 30); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, | 
 |        NewConfigWithDifferentStartReturnsNewConfig) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.min_bitrate_bps = 10; | 
 |   bitrate_config.start_bitrate_bps = 20; | 
 |   bitrate_config.max_bitrate_bps = 30; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   bitrate_config.start_bitrate_bps = 21; | 
 |   UpdateConfigMatches(bitrate_config, 10, 21, 30); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, NewConfigWithDifferentMaxReturnsNewConfig) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.min_bitrate_bps = 10; | 
 |   bitrate_config.start_bitrate_bps = 20; | 
 |   bitrate_config.max_bitrate_bps = 30; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   bitrate_config.max_bitrate_bps = 31; | 
 |   UpdateConfigMatches(bitrate_config, 10, -1, 31); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, NewConfigWithSameConfigElidesSecondCall) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.min_bitrate_bps = 1; | 
 |   bitrate_config.start_bitrate_bps = 2; | 
 |   bitrate_config.max_bitrate_bps = 3; | 
 |  | 
 |   UpdateConfigMatches(bitrate_config, 1, 2, 3); | 
 |   EXPECT_FALSE( | 
 |       configurator_->UpdateWithSdpParameters(bitrate_config).has_value()); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, | 
 |        NewConfigWithSameMinMaxAndNegativeStartElidesSecondCall) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.min_bitrate_bps = 1; | 
 |   bitrate_config.start_bitrate_bps = 2; | 
 |   bitrate_config.max_bitrate_bps = 3; | 
 |  | 
 |   UpdateConfigMatches(bitrate_config, 1, 2, 3); | 
 |  | 
 |   bitrate_config.start_bitrate_bps = -1; | 
 |   EXPECT_FALSE( | 
 |       configurator_->UpdateWithSdpParameters(bitrate_config).has_value()); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, BiggerMaskMinUsed) { | 
 |   BitrateSettings mask; | 
 |   mask.min_bitrate_bps = 1234; | 
 |   UpdateMaskMatches(mask, *mask.min_bitrate_bps, nullopt, nullopt); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, BiggerConfigMinUsed) { | 
 |   BitrateSettings mask; | 
 |   mask.min_bitrate_bps = 1000; | 
 |   UpdateMaskMatches(mask, 1000, nullopt, nullopt); | 
 |  | 
 |   BitrateConstraints config; | 
 |   config.min_bitrate_bps = 1234; | 
 |   UpdateConfigMatches(config, 1234, nullopt, nullopt); | 
 | } | 
 |  | 
 | // The last call to set start should be used. | 
 | TEST_F(RtpBitrateConfiguratorTest, LatestStartMaskPreferred) { | 
 |   BitrateSettings mask; | 
 |   mask.start_bitrate_bps = 1300; | 
 |   UpdateMaskMatches(mask, nullopt, *mask.start_bitrate_bps, nullopt); | 
 |  | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.start_bitrate_bps = 1200; | 
 |  | 
 |   UpdateConfigMatches(bitrate_config, nullopt, bitrate_config.start_bitrate_bps, | 
 |                       nullopt); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, SmallerMaskMaxUsed) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.max_bitrate_bps = bitrate_config.start_bitrate_bps + 2000; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   BitrateSettings mask; | 
 |   mask.max_bitrate_bps = bitrate_config.start_bitrate_bps + 1000; | 
 |  | 
 |   UpdateMaskMatches(mask, nullopt, nullopt, *mask.max_bitrate_bps); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, SmallerConfigMaxUsed) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.max_bitrate_bps = bitrate_config.start_bitrate_bps + 1000; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   BitrateSettings mask; | 
 |   mask.max_bitrate_bps = bitrate_config.start_bitrate_bps + 2000; | 
 |  | 
 |   // Expect no return because nothing changes | 
 |   EXPECT_FALSE(configurator_->UpdateWithClientPreferences(mask).has_value()); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, MaskStartLessThanConfigMinClamped) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.min_bitrate_bps = 2000; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   BitrateSettings mask; | 
 |   mask.start_bitrate_bps = 1000; | 
 |   UpdateMaskMatches(mask, 2000, 2000, nullopt); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, MaskStartGreaterThanConfigMaxClamped) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.start_bitrate_bps = 2000; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   BitrateSettings mask; | 
 |   mask.max_bitrate_bps = 1000; | 
 |  | 
 |   UpdateMaskMatches(mask, nullopt, -1, 1000); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, MaskMinGreaterThanConfigMaxClamped) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.min_bitrate_bps = 2000; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   BitrateSettings mask; | 
 |   mask.max_bitrate_bps = 1000; | 
 |  | 
 |   UpdateMaskMatches(mask, 1000, nullopt, 1000); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, SettingMaskStartForcesUpdate) { | 
 |   BitrateSettings mask; | 
 |   mask.start_bitrate_bps = 1000; | 
 |  | 
 |   // Config should be returned twice with the same params since | 
 |   // start_bitrate_bps is set. | 
 |   UpdateMaskMatches(mask, nullopt, 1000, nullopt); | 
 |   UpdateMaskMatches(mask, nullopt, 1000, nullopt); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, NewConfigWithNoChangesDoesNotCallNewConfig) { | 
 |   BitrateConstraints config1; | 
 |   config1.min_bitrate_bps = 0; | 
 |   config1.start_bitrate_bps = 1000; | 
 |   config1.max_bitrate_bps = -1; | 
 |  | 
 |   BitrateConstraints config2; | 
 |   config2.min_bitrate_bps = 0; | 
 |   config2.start_bitrate_bps = -1; | 
 |   config2.max_bitrate_bps = -1; | 
 |  | 
 |   // The second call should not return anything because it doesn't | 
 |   // change any values. | 
 |   UpdateConfigMatches(config1, 0, 1000, -1); | 
 |   EXPECT_FALSE(configurator_->UpdateWithSdpParameters(config2).has_value()); | 
 | } | 
 |  | 
 | // If config changes the max, but not the effective max, | 
 | // new config shouldn't be returned, to avoid unnecessary encoder | 
 | // reconfigurations. | 
 | TEST_F(RtpBitrateConfiguratorTest, | 
 |        NewConfigNotReturnedWhenEffectiveMaxUnchanged) { | 
 |   BitrateConstraints config; | 
 |   config.min_bitrate_bps = 0; | 
 |   config.start_bitrate_bps = -1; | 
 |   config.max_bitrate_bps = 2000; | 
 |   UpdateConfigMatches(config, nullopt, nullopt, 2000); | 
 |  | 
 |   // Reduce effective max to 1000 with the mask. | 
 |   BitrateSettings mask; | 
 |   mask.max_bitrate_bps = 1000; | 
 |   UpdateMaskMatches(mask, nullopt, nullopt, 1000); | 
 |  | 
 |   // This leaves the effective max unchanged, so new config shouldn't be | 
 |   // returned again. | 
 |   config.max_bitrate_bps = 1000; | 
 |   EXPECT_FALSE(configurator_->UpdateWithSdpParameters(config).has_value()); | 
 | } | 
 |  | 
 | // When the "start bitrate" mask is removed, new config shouldn't be returned | 
 | // again, since nothing's changing. | 
 | TEST_F(RtpBitrateConfiguratorTest, NewConfigNotReturnedWhenStartMaskRemoved) { | 
 |   BitrateSettings mask; | 
 |   mask.start_bitrate_bps = 1000; | 
 |   UpdateMaskMatches(mask, 0, 1000, -1); | 
 |  | 
 |   mask.start_bitrate_bps.reset(); | 
 |   EXPECT_FALSE(configurator_->UpdateWithClientPreferences(mask).has_value()); | 
 | } | 
 |  | 
 | // Test that if a new config is returned after BitrateSettings applies a | 
 | // "start" value, the new config won't return that start value a | 
 | // second time. | 
 | TEST_F(RtpBitrateConfiguratorTest, NewConfigAfterBitrateConfigMaskWithStart) { | 
 |   BitrateSettings mask; | 
 |   mask.start_bitrate_bps = 1000; | 
 |   UpdateMaskMatches(mask, 0, 1000, -1); | 
 |  | 
 |   BitrateConstraints config; | 
 |   config.min_bitrate_bps = 0; | 
 |   config.start_bitrate_bps = -1; | 
 |   config.max_bitrate_bps = 5000; | 
 |   // The start value isn't changing, so new config should be returned with | 
 |   // -1. | 
 |   UpdateConfigMatches(config, 0, -1, 5000); | 
 | } | 
 |  | 
 | TEST_F(RtpBitrateConfiguratorTest, | 
 |        NewConfigNotReturnedWhenClampedMinUnchanged) { | 
 |   BitrateConstraints bitrate_config; | 
 |   bitrate_config.start_bitrate_bps = 500; | 
 |   bitrate_config.max_bitrate_bps = 1000; | 
 |   configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); | 
 |  | 
 |   // Set min to 2000; it is clamped to the max (1000). | 
 |   BitrateSettings mask; | 
 |   mask.min_bitrate_bps = 2000; | 
 |   UpdateMaskMatches(mask, 1000, -1, 1000); | 
 |  | 
 |   // Set min to 3000; the clamped value stays the same so nothing happens. | 
 |   mask.min_bitrate_bps = 3000; | 
 |   EXPECT_FALSE(configurator_->UpdateWithClientPreferences(mask).has_value()); | 
 | } | 
 | }  // namespace webrtc |