| /* |
| * Copyright (c) 2015 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 <array> |
| #include <memory> |
| |
| #include "webrtc/base/checks.h" |
| #include "webrtc/base/fakeclock.h" |
| #include "webrtc/common_audio/mocks/mock_smoothing_filter.h" |
| #include "webrtc/common_types.h" |
| #include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_audio_network_adaptor.h" |
| #include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" |
| #include "webrtc/test/field_trial.h" |
| #include "webrtc/test/gmock.h" |
| #include "webrtc/test/gtest.h" |
| #include "webrtc/system_wrappers/include/clock.h" |
| |
| namespace webrtc { |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| |
| namespace { |
| |
| const CodecInst kDefaultOpusSettings = {105, "opus", 48000, 960, 1, 32000}; |
| constexpr int64_t kInitialTimeUs = 12345678; |
| |
| AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) { |
| AudioEncoderOpus::Config config; |
| config.frame_size_ms = rtc::CheckedDivExact(codec_inst.pacsize, 48); |
| config.num_channels = codec_inst.channels; |
| config.bitrate_bps = rtc::Optional<int>(codec_inst.rate); |
| config.payload_type = codec_inst.pltype; |
| config.application = config.num_channels == 1 ? AudioEncoderOpus::kVoip |
| : AudioEncoderOpus::kAudio; |
| config.supported_frame_lengths_ms.push_back(config.frame_size_ms); |
| return config; |
| } |
| |
| struct AudioEncoderOpusStates { |
| std::shared_ptr<MockAudioNetworkAdaptor*> mock_audio_network_adaptor; |
| MockSmoothingFilter* mock_bitrate_smoother; |
| std::unique_ptr<AudioEncoderOpus> encoder; |
| std::unique_ptr<SimulatedClock> simulated_clock; |
| AudioEncoderOpus::Config config; |
| }; |
| |
| AudioEncoderOpusStates CreateCodec(size_t num_channels) { |
| AudioEncoderOpusStates states; |
| states.mock_audio_network_adaptor = |
| std::make_shared<MockAudioNetworkAdaptor*>(nullptr); |
| |
| std::weak_ptr<MockAudioNetworkAdaptor*> mock_ptr( |
| states.mock_audio_network_adaptor); |
| AudioEncoderOpus::AudioNetworkAdaptorCreator creator = [mock_ptr]( |
| const std::string&, RtcEventLog* event_log, const Clock*) { |
| std::unique_ptr<MockAudioNetworkAdaptor> adaptor( |
| new NiceMock<MockAudioNetworkAdaptor>()); |
| EXPECT_CALL(*adaptor, Die()); |
| if (auto sp = mock_ptr.lock()) { |
| *sp = adaptor.get(); |
| } else { |
| RTC_NOTREACHED(); |
| } |
| return adaptor; |
| }; |
| |
| CodecInst codec_inst = kDefaultOpusSettings; |
| codec_inst.channels = num_channels; |
| states.config = CreateConfig(codec_inst); |
| std::unique_ptr<MockSmoothingFilter> bitrate_smoother( |
| new MockSmoothingFilter()); |
| states.mock_bitrate_smoother = bitrate_smoother.get(); |
| states.simulated_clock.reset(new SimulatedClock(kInitialTimeUs)); |
| states.config.clock = states.simulated_clock.get(); |
| |
| states.encoder.reset(new AudioEncoderOpus(states.config, std::move(creator), |
| std::move(bitrate_smoother))); |
| return states; |
| } |
| |
| AudioNetworkAdaptor::EncoderRuntimeConfig CreateEncoderRuntimeConfig() { |
| constexpr int kBitrate = 40000; |
| constexpr int kFrameLength = 60; |
| constexpr bool kEnableFec = true; |
| constexpr bool kEnableDtx = false; |
| constexpr size_t kNumChannels = 1; |
| constexpr float kPacketLossFraction = 0.1f; |
| AudioNetworkAdaptor::EncoderRuntimeConfig config; |
| config.bitrate_bps = rtc::Optional<int>(kBitrate); |
| config.frame_length_ms = rtc::Optional<int>(kFrameLength); |
| config.enable_fec = rtc::Optional<bool>(kEnableFec); |
| config.enable_dtx = rtc::Optional<bool>(kEnableDtx); |
| config.num_channels = rtc::Optional<size_t>(kNumChannels); |
| config.uplink_packet_loss_fraction = |
| rtc::Optional<float>(kPacketLossFraction); |
| return config; |
| } |
| |
| void CheckEncoderRuntimeConfig( |
| const AudioEncoderOpus* encoder, |
| const AudioNetworkAdaptor::EncoderRuntimeConfig& config) { |
| EXPECT_EQ(*config.bitrate_bps, encoder->GetTargetBitrate()); |
| EXPECT_EQ(*config.frame_length_ms, encoder->next_frame_length_ms()); |
| EXPECT_EQ(*config.enable_fec, encoder->fec_enabled()); |
| EXPECT_EQ(*config.enable_dtx, encoder->GetDtx()); |
| EXPECT_EQ(*config.num_channels, encoder->num_channels_to_encode()); |
| } |
| |
| } // namespace |
| |
| TEST(AudioEncoderOpusTest, DefaultApplicationModeMono) { |
| auto states = CreateCodec(1); |
| EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); |
| } |
| |
| TEST(AudioEncoderOpusTest, DefaultApplicationModeStereo) { |
| auto states = CreateCodec(2); |
| EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application()); |
| } |
| |
| TEST(AudioEncoderOpusTest, ChangeApplicationMode) { |
| auto states = CreateCodec(2); |
| EXPECT_TRUE( |
| states.encoder->SetApplication(AudioEncoder::Application::kSpeech)); |
| EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); |
| } |
| |
| TEST(AudioEncoderOpusTest, ResetWontChangeApplicationMode) { |
| auto states = CreateCodec(2); |
| |
| // Trigger a reset. |
| states.encoder->Reset(); |
| // Verify that the mode is still kAudio. |
| EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application()); |
| |
| // Now change to kVoip. |
| EXPECT_TRUE( |
| states.encoder->SetApplication(AudioEncoder::Application::kSpeech)); |
| EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); |
| |
| // Trigger a reset again. |
| states.encoder->Reset(); |
| // Verify that the mode is still kVoip. |
| EXPECT_EQ(AudioEncoderOpus::kVoip, states.encoder->application()); |
| } |
| |
| TEST(AudioEncoderOpusTest, ToggleDtx) { |
| auto states = CreateCodec(2); |
| // Enable DTX |
| EXPECT_TRUE(states.encoder->SetDtx(true)); |
| // Verify that the mode is still kAudio. |
| EXPECT_EQ(AudioEncoderOpus::kAudio, states.encoder->application()); |
| // Turn off DTX. |
| EXPECT_TRUE(states.encoder->SetDtx(false)); |
| } |
| |
| TEST(AudioEncoderOpusTest, |
| OnReceivedUplinkBandwidthWithoutAudioNetworkAdaptor) { |
| auto states = CreateCodec(1); |
| // Constants are replicated from audio_states.encoderopus.cc. |
| const int kMinBitrateBps = 500; |
| const int kMaxBitrateBps = 512000; |
| // Set a too low bitrate. |
| states.encoder->OnReceivedUplinkBandwidth(kMinBitrateBps - 1, |
| rtc::Optional<int64_t>()); |
| EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate()); |
| // Set a too high bitrate. |
| states.encoder->OnReceivedUplinkBandwidth(kMaxBitrateBps + 1, |
| rtc::Optional<int64_t>()); |
| EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate()); |
| // Set the minimum rate. |
| states.encoder->OnReceivedUplinkBandwidth(kMinBitrateBps, |
| rtc::Optional<int64_t>()); |
| EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate()); |
| // Set the maximum rate. |
| states.encoder->OnReceivedUplinkBandwidth(kMaxBitrateBps, |
| rtc::Optional<int64_t>()); |
| EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate()); |
| // Set rates from 1000 up to 32000 bps. |
| for (int rate = 1000; rate <= 32000; rate += 1000) { |
| states.encoder->OnReceivedUplinkBandwidth(rate, rtc::Optional<int64_t>()); |
| EXPECT_EQ(rate, states.encoder->GetTargetBitrate()); |
| } |
| } |
| |
| namespace { |
| |
| // Returns a vector with the n evenly-spaced numbers a, a + (b - a)/(n - 1), |
| // ..., b. |
| std::vector<float> IntervalSteps(float a, float b, size_t n) { |
| RTC_DCHECK_GT(n, 1u); |
| const float step = (b - a) / (n - 1); |
| std::vector<float> points; |
| points.push_back(a); |
| for (size_t i = 1; i < n - 1; ++i) |
| points.push_back(a + i * step); |
| points.push_back(b); |
| return points; |
| } |
| |
| // Sets the packet loss rate to each number in the vector in turn, and verifies |
| // that the loss rate as reported by the encoder is |expected_return| for all |
| // of them. |
| void TestSetPacketLossRate(AudioEncoderOpusStates* states, |
| const std::vector<float>& losses, |
| float expected_return) { |
| // |kSampleIntervalMs| is chosen to ease the calculation since |
| // 0.9999 ^ 184198 = 1e-8. Which minimizes the effect of |
| // PacketLossFractionSmoother used in AudioEncoderOpus. |
| constexpr int64_t kSampleIntervalMs = 184198; |
| for (float loss : losses) { |
| states->encoder->OnReceivedUplinkPacketLossFraction(loss); |
| states->simulated_clock->AdvanceTimeMilliseconds(kSampleIntervalMs); |
| EXPECT_FLOAT_EQ(expected_return, states->encoder->packet_loss_rate()); |
| } |
| } |
| |
| } // namespace |
| |
| TEST(AudioEncoderOpusTest, PacketLossRateOptimized) { |
| auto states = CreateCodec(1); |
| auto I = [](float a, float b) { return IntervalSteps(a, b, 10); }; |
| constexpr float eps = 1e-8f; |
| |
| // Note that the order of the following calls is critical. |
| |
| // clang-format off |
| TestSetPacketLossRate(&states, I(0.00f , 0.01f - eps), 0.00f); |
| TestSetPacketLossRate(&states, I(0.01f + eps, 0.06f - eps), 0.01f); |
| TestSetPacketLossRate(&states, I(0.06f + eps, 0.11f - eps), 0.05f); |
| TestSetPacketLossRate(&states, I(0.11f + eps, 0.22f - eps), 0.10f); |
| TestSetPacketLossRate(&states, I(0.22f + eps, 1.00f ), 0.20f); |
| |
| TestSetPacketLossRate(&states, I(1.00f , 0.18f + eps), 0.20f); |
| TestSetPacketLossRate(&states, I(0.18f - eps, 0.09f + eps), 0.10f); |
| TestSetPacketLossRate(&states, I(0.09f - eps, 0.04f + eps), 0.05f); |
| TestSetPacketLossRate(&states, I(0.04f - eps, 0.01f + eps), 0.01f); |
| TestSetPacketLossRate(&states, I(0.01f - eps, 0.00f ), 0.00f); |
| // clang-format on |
| } |
| |
| TEST(AudioEncoderOpusTest, SetReceiverFrameLengthRange) { |
| auto states = CreateCodec(2); |
| // Before calling to |SetReceiverFrameLengthRange|, |
| // |supported_frame_lengths_ms| should contain only the frame length being |
| // used. |
| using ::testing::ElementsAre; |
| EXPECT_THAT(states.encoder->supported_frame_lengths_ms(), |
| ElementsAre(states.encoder->next_frame_length_ms())); |
| states.encoder->SetReceiverFrameLengthRange(0, 12345); |
| EXPECT_THAT(states.encoder->supported_frame_lengths_ms(), |
| ElementsAre(20, 60)); |
| states.encoder->SetReceiverFrameLengthRange(21, 60); |
| EXPECT_THAT(states.encoder->supported_frame_lengths_ms(), ElementsAre(60)); |
| states.encoder->SetReceiverFrameLengthRange(20, 59); |
| EXPECT_THAT(states.encoder->supported_frame_lengths_ms(), ElementsAre(20)); |
| } |
| |
| TEST(AudioEncoderOpusTest, |
| InvokeAudioNetworkAdaptorOnReceivedUplinkPacketLossFraction) { |
| auto states = CreateCodec(2); |
| states.encoder->EnableAudioNetworkAdaptor("", nullptr, nullptr); |
| |
| auto config = CreateEncoderRuntimeConfig(); |
| EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| .WillOnce(Return(config)); |
| |
| // Since using mock audio network adaptor, any packet loss fraction is fine. |
| constexpr float kUplinkPacketLoss = 0.1f; |
| EXPECT_CALL(**states.mock_audio_network_adaptor, |
| SetUplinkPacketLossFraction(kUplinkPacketLoss)); |
| states.encoder->OnReceivedUplinkPacketLossFraction(kUplinkPacketLoss); |
| |
| CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| } |
| |
| TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedUplinkBandwidth) { |
| auto states = CreateCodec(2); |
| states.encoder->EnableAudioNetworkAdaptor("", nullptr, nullptr); |
| |
| auto config = CreateEncoderRuntimeConfig(); |
| EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| .WillOnce(Return(config)); |
| |
| // Since using mock audio network adaptor, any target audio bitrate is fine. |
| constexpr int kTargetAudioBitrate = 30000; |
| constexpr int64_t kProbingIntervalMs = 3000; |
| EXPECT_CALL(**states.mock_audio_network_adaptor, |
| SetTargetAudioBitrate(kTargetAudioBitrate)); |
| EXPECT_CALL(*states.mock_bitrate_smoother, |
| SetTimeConstantMs(kProbingIntervalMs * 4)); |
| EXPECT_CALL(*states.mock_bitrate_smoother, AddSample(kTargetAudioBitrate)); |
| states.encoder->OnReceivedUplinkBandwidth( |
| kTargetAudioBitrate, rtc::Optional<int64_t>(kProbingIntervalMs)); |
| |
| CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| } |
| |
| TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedRtt) { |
| auto states = CreateCodec(2); |
| states.encoder->EnableAudioNetworkAdaptor("", nullptr, nullptr); |
| |
| auto config = CreateEncoderRuntimeConfig(); |
| EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| .WillOnce(Return(config)); |
| |
| // Since using mock audio network adaptor, any rtt is fine. |
| constexpr int kRtt = 30; |
| EXPECT_CALL(**states.mock_audio_network_adaptor, SetRtt(kRtt)); |
| states.encoder->OnReceivedRtt(kRtt); |
| |
| CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| } |
| |
| TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedOverhead) { |
| auto states = CreateCodec(2); |
| states.encoder->EnableAudioNetworkAdaptor("", nullptr, nullptr); |
| |
| auto config = CreateEncoderRuntimeConfig(); |
| EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| .WillOnce(Return(config)); |
| |
| // Since using mock audio network adaptor, any overhead is fine. |
| constexpr size_t kOverhead = 64; |
| EXPECT_CALL(**states.mock_audio_network_adaptor, SetOverhead(kOverhead)); |
| states.encoder->OnReceivedOverhead(kOverhead); |
| |
| CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| } |
| |
| TEST(AudioEncoderOpusTest, |
| PacketLossFractionSmoothedOnSetUplinkPacketLossFraction) { |
| auto states = CreateCodec(2); |
| |
| // The values are carefully chosen so that if no smoothing is made, the test |
| // will fail. |
| constexpr float kPacketLossFraction_1 = 0.02f; |
| constexpr float kPacketLossFraction_2 = 0.198f; |
| // |kSecondSampleTimeMs| is chosen to ease the calculation since |
| // 0.9999 ^ 6931 = 0.5. |
| constexpr int64_t kSecondSampleTimeMs = 6931; |
| |
| // First time, no filtering. |
| states.encoder->OnReceivedUplinkPacketLossFraction(kPacketLossFraction_1); |
| EXPECT_FLOAT_EQ(0.01f, states.encoder->packet_loss_rate()); |
| |
| states.simulated_clock->AdvanceTimeMilliseconds(kSecondSampleTimeMs); |
| states.encoder->OnReceivedUplinkPacketLossFraction(kPacketLossFraction_2); |
| |
| // Now the output of packet loss fraction smoother should be |
| // (0.02 + 0.198) / 2 = 0.109, which reach the threshold for the optimized |
| // packet loss rate to increase to 0.05. If no smoothing has been made, the |
| // optimized packet loss rate should have been increase to 0.1. |
| EXPECT_FLOAT_EQ(0.05f, states.encoder->packet_loss_rate()); |
| } |
| |
| TEST(AudioEncoderOpusTest, DoNotInvokeSetTargetBitrateIfOverheadUnknown) { |
| test::ScopedFieldTrials override_field_trials( |
| "WebRTC-SendSideBwe-WithOverhead/Enabled/"); |
| |
| auto states = CreateCodec(2); |
| |
| states.encoder->OnReceivedUplinkBandwidth(kDefaultOpusSettings.rate * 2, |
| rtc::Optional<int64_t>()); |
| |
| // Since |OnReceivedOverhead| has not been called, the codec bitrate should |
| // not change. |
| EXPECT_EQ(kDefaultOpusSettings.rate, states.encoder->GetTargetBitrate()); |
| } |
| |
| TEST(AudioEncoderOpusTest, OverheadRemovedFromTargetAudioBitrate) { |
| test::ScopedFieldTrials override_field_trials( |
| "WebRTC-SendSideBwe-WithOverhead/Enabled/"); |
| |
| auto states = CreateCodec(2); |
| |
| constexpr size_t kOverheadBytesPerPacket = 64; |
| states.encoder->OnReceivedOverhead(kOverheadBytesPerPacket); |
| |
| constexpr int kTargetBitrateBps = 40000; |
| states.encoder->OnReceivedUplinkBandwidth(kTargetBitrateBps, |
| rtc::Optional<int64_t>()); |
| |
| int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize); |
| EXPECT_EQ(kTargetBitrateBps - |
| 8 * static_cast<int>(kOverheadBytesPerPacket) * packet_rate, |
| states.encoder->GetTargetBitrate()); |
| } |
| |
| TEST(AudioEncoderOpusTest, BitrateBounded) { |
| test::ScopedFieldTrials override_field_trials( |
| "WebRTC-SendSideBwe-WithOverhead/Enabled/"); |
| |
| constexpr int kMinBitrateBps = 500; |
| constexpr int kMaxBitrateBps = 512000; |
| |
| auto states = CreateCodec(2); |
| |
| constexpr size_t kOverheadBytesPerPacket = 64; |
| states.encoder->OnReceivedOverhead(kOverheadBytesPerPacket); |
| |
| int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize); |
| |
| // Set a target rate that is smaller than |kMinBitrateBps| when overhead is |
| // subtracted. The eventual codec rate should be bounded by |kMinBitrateBps|. |
| int target_bitrate = |
| kOverheadBytesPerPacket * 8 * packet_rate + kMinBitrateBps - 1; |
| states.encoder->OnReceivedUplinkBandwidth(target_bitrate, |
| rtc::Optional<int64_t>()); |
| EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate()); |
| |
| // Set a target rate that is greater than |kMaxBitrateBps| when overhead is |
| // subtracted. The eventual codec rate should be bounded by |kMaxBitrateBps|. |
| target_bitrate = |
| kOverheadBytesPerPacket * 8 * packet_rate + kMaxBitrateBps + 1; |
| states.encoder->OnReceivedUplinkBandwidth(target_bitrate, |
| rtc::Optional<int64_t>()); |
| EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate()); |
| } |
| |
| // Verifies that the complexity adaptation in the config works as intended. |
| TEST(AudioEncoderOpusTest, ConfigComplexityAdaptation) { |
| AudioEncoderOpus::Config config; |
| config.low_rate_complexity = 8; |
| config.complexity = 6; |
| |
| // Bitrate within hysteresis window. Expect empty output. |
| config.bitrate_bps = rtc::Optional<int>(12500); |
| EXPECT_EQ(rtc::Optional<int>(), config.GetNewComplexity()); |
| |
| // Bitrate below hysteresis window. Expect higher complexity. |
| config.bitrate_bps = rtc::Optional<int>(10999); |
| EXPECT_EQ(rtc::Optional<int>(8), config.GetNewComplexity()); |
| |
| // Bitrate within hysteresis window. Expect empty output. |
| config.bitrate_bps = rtc::Optional<int>(12500); |
| EXPECT_EQ(rtc::Optional<int>(), config.GetNewComplexity()); |
| |
| // Bitrate above hysteresis window. Expect lower complexity. |
| config.bitrate_bps = rtc::Optional<int>(14001); |
| EXPECT_EQ(rtc::Optional<int>(6), config.GetNewComplexity()); |
| } |
| |
| TEST(AudioEncoderOpusTest, EmptyConfigDoesNotAffectEncoderSettings) { |
| auto states = CreateCodec(2); |
| states.encoder->EnableAudioNetworkAdaptor("", nullptr, nullptr); |
| |
| auto config = CreateEncoderRuntimeConfig(); |
| AudioNetworkAdaptor::EncoderRuntimeConfig empty_config; |
| |
| EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig()) |
| .WillOnce(Return(config)) |
| .WillOnce(Return(empty_config)); |
| |
| constexpr size_t kOverhead = 64; |
| EXPECT_CALL(**states.mock_audio_network_adaptor, SetOverhead(kOverhead)) |
| .Times(2); |
| states.encoder->OnReceivedOverhead(kOverhead); |
| states.encoder->OnReceivedOverhead(kOverhead); |
| |
| CheckEncoderRuntimeConfig(states.encoder.get(), config); |
| } |
| |
| TEST(AudioEncoderOpusTest, UpdateUplinkBandwidthInAudioNetworkAdaptor) { |
| rtc::ScopedFakeClock fake_clock; |
| auto states = CreateCodec(2); |
| states.encoder->EnableAudioNetworkAdaptor("", nullptr, nullptr); |
| std::array<int16_t, 480 * 2> audio; |
| audio.fill(0); |
| rtc::Buffer encoded; |
| EXPECT_CALL(*states.mock_bitrate_smoother, GetAverage()) |
| .WillOnce(Return(rtc::Optional<float>(50000))); |
| EXPECT_CALL(**states.mock_audio_network_adaptor, SetUplinkBandwidth(50000)); |
| states.encoder->Encode( |
| 0, rtc::ArrayView<const int16_t>(audio.data(), audio.size()), &encoded); |
| |
| // Repeat update uplink bandwidth tests. |
| for (int i = 0; i < 5; i++) { |
| // Don't update till it is time to update again. |
| fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds( |
| states.config.uplink_bandwidth_update_interval_ms - 1)); |
| states.encoder->Encode( |
| 0, rtc::ArrayView<const int16_t>(audio.data(), audio.size()), &encoded); |
| |
| // Update when it is time to update. |
| EXPECT_CALL(*states.mock_bitrate_smoother, GetAverage()) |
| .WillOnce(Return(rtc::Optional<float>(40000))); |
| EXPECT_CALL(**states.mock_audio_network_adaptor, SetUplinkBandwidth(40000)); |
| fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); |
| states.encoder->Encode( |
| 0, rtc::ArrayView<const int16_t>(audio.data(), audio.size()), &encoded); |
| } |
| } |
| |
| } // namespace webrtc |