/* * Copyright (c) 2016 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 "modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h" #include #include #include "api/rtc_event_log/rtc_event.h" #include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h" #include "logging/rtc_event_log/mock/mock_rtc_event_log.h" #include "modules/audio_coding/audio_network_adaptor/mock/mock_controller.h" #include "modules/audio_coding/audio_network_adaptor/mock/mock_controller_manager.h" #include "modules/audio_coding/audio_network_adaptor/mock/mock_debug_dump_writer.h" #include "rtc_base/fake_clock.h" #include "test/field_trial.h" #include "test/gtest.h" namespace webrtc { using ::testing::_; using ::testing::NiceMock; using ::testing::Return; using ::testing::SetArgPointee; namespace { constexpr size_t kNumControllers = 2; constexpr int64_t kClockInitialTimeMs = 12345678; MATCHER_P(NetworkMetricsIs, metric, "") { return arg.uplink_bandwidth_bps == metric.uplink_bandwidth_bps && arg.target_audio_bitrate_bps == metric.target_audio_bitrate_bps && arg.rtt_ms == metric.rtt_ms && arg.overhead_bytes_per_packet == metric.overhead_bytes_per_packet && arg.uplink_packet_loss_fraction == metric.uplink_packet_loss_fraction; } MATCHER_P(IsRtcEventAnaConfigEqualTo, config, "") { if (arg->GetType() != RtcEvent::Type::AudioNetworkAdaptation) { return false; } auto ana_event = static_cast(arg); return ana_event->config() == config; } MATCHER_P(EncoderRuntimeConfigIs, config, "") { return arg.bitrate_bps == config.bitrate_bps && arg.frame_length_ms == config.frame_length_ms && arg.uplink_packet_loss_fraction == config.uplink_packet_loss_fraction && arg.enable_fec == config.enable_fec && arg.enable_dtx == config.enable_dtx && arg.num_channels == config.num_channels; } struct AudioNetworkAdaptorStates { std::unique_ptr audio_network_adaptor; std::vector> mock_controllers; std::unique_ptr event_log; MockDebugDumpWriter* mock_debug_dump_writer; }; AudioNetworkAdaptorStates CreateAudioNetworkAdaptor() { AudioNetworkAdaptorStates states; std::vector controllers; for (size_t i = 0; i < kNumControllers; ++i) { auto controller = std::unique_ptr(new NiceMock()); EXPECT_CALL(*controller, Die()); controllers.push_back(controller.get()); states.mock_controllers.push_back(std::move(controller)); } auto controller_manager = std::unique_ptr( new NiceMock()); EXPECT_CALL(*controller_manager, Die()); EXPECT_CALL(*controller_manager, GetControllers()) .WillRepeatedly(Return(controllers)); EXPECT_CALL(*controller_manager, GetSortedControllers(_)) .WillRepeatedly(Return(controllers)); states.event_log.reset(new NiceMock()); auto debug_dump_writer = std::unique_ptr(new NiceMock()); EXPECT_CALL(*debug_dump_writer, Die()); states.mock_debug_dump_writer = debug_dump_writer.get(); AudioNetworkAdaptorImpl::Config config; config.event_log = states.event_log.get(); // AudioNetworkAdaptorImpl governs the lifetime of controller manager. states.audio_network_adaptor.reset(new AudioNetworkAdaptorImpl( config, std::move(controller_manager), std::move(debug_dump_writer))); return states; } void SetExpectCallToUpdateNetworkMetrics( const std::vector>& controllers, const Controller::NetworkMetrics& check) { for (auto& mock_controller : controllers) { EXPECT_CALL(*mock_controller, UpdateNetworkMetrics(NetworkMetricsIs(check))); } } } // namespace TEST(AudioNetworkAdaptorImplTest, UpdateNetworkMetricsIsCalledOnSetUplinkBandwidth) { auto states = CreateAudioNetworkAdaptor(); constexpr int kBandwidth = 16000; Controller::NetworkMetrics check; check.uplink_bandwidth_bps = kBandwidth; SetExpectCallToUpdateNetworkMetrics(states.mock_controllers, check); states.audio_network_adaptor->SetUplinkBandwidth(kBandwidth); } TEST(AudioNetworkAdaptorImplTest, UpdateNetworkMetricsIsCalledOnSetUplinkPacketLossFraction) { auto states = CreateAudioNetworkAdaptor(); constexpr float kPacketLoss = 0.7f; Controller::NetworkMetrics check; check.uplink_packet_loss_fraction = kPacketLoss; SetExpectCallToUpdateNetworkMetrics(states.mock_controllers, check); states.audio_network_adaptor->SetUplinkPacketLossFraction(kPacketLoss); } TEST(AudioNetworkAdaptorImplTest, UpdateNetworkMetricsIsCalledOnSetRtt) { auto states = CreateAudioNetworkAdaptor(); constexpr int kRtt = 100; Controller::NetworkMetrics check; check.rtt_ms = kRtt; SetExpectCallToUpdateNetworkMetrics(states.mock_controllers, check); states.audio_network_adaptor->SetRtt(kRtt); } TEST(AudioNetworkAdaptorImplTest, UpdateNetworkMetricsIsCalledOnSetTargetAudioBitrate) { auto states = CreateAudioNetworkAdaptor(); constexpr int kTargetAudioBitrate = 15000; Controller::NetworkMetrics check; check.target_audio_bitrate_bps = kTargetAudioBitrate; SetExpectCallToUpdateNetworkMetrics(states.mock_controllers, check); states.audio_network_adaptor->SetTargetAudioBitrate(kTargetAudioBitrate); } TEST(AudioNetworkAdaptorImplTest, UpdateNetworkMetricsIsCalledOnSetOverhead) { auto states = CreateAudioNetworkAdaptor(); constexpr size_t kOverhead = 64; Controller::NetworkMetrics check; check.overhead_bytes_per_packet = kOverhead; SetExpectCallToUpdateNetworkMetrics(states.mock_controllers, check); states.audio_network_adaptor->SetOverhead(kOverhead); } TEST(AudioNetworkAdaptorImplTest, MakeDecisionIsCalledOnGetEncoderRuntimeConfig) { auto states = CreateAudioNetworkAdaptor(); for (auto& mock_controller : states.mock_controllers) EXPECT_CALL(*mock_controller, MakeDecision(_)); states.audio_network_adaptor->GetEncoderRuntimeConfig(); } TEST(AudioNetworkAdaptorImplTest, DumpEncoderRuntimeConfigIsCalledOnGetEncoderRuntimeConfig) { test::ScopedFieldTrials override_field_trials( "WebRTC-Audio-FecAdaptation/Enabled/"); rtc::ScopedFakeClock fake_clock; fake_clock.AdvanceTime(TimeDelta::Millis(kClockInitialTimeMs)); auto states = CreateAudioNetworkAdaptor(); AudioEncoderRuntimeConfig config; config.bitrate_bps = 32000; config.enable_fec = true; EXPECT_CALL(*states.mock_controllers[0], MakeDecision(_)) .WillOnce(SetArgPointee<0>(config)); EXPECT_CALL(*states.mock_debug_dump_writer, DumpEncoderRuntimeConfig(EncoderRuntimeConfigIs(config), kClockInitialTimeMs)); states.audio_network_adaptor->GetEncoderRuntimeConfig(); } TEST(AudioNetworkAdaptorImplTest, DumpNetworkMetricsIsCalledOnSetNetworkMetrics) { rtc::ScopedFakeClock fake_clock; fake_clock.AdvanceTime(TimeDelta::Millis(kClockInitialTimeMs)); auto states = CreateAudioNetworkAdaptor(); constexpr int kBandwidth = 16000; constexpr float kPacketLoss = 0.7f; constexpr int kRtt = 100; constexpr int kTargetAudioBitrate = 15000; constexpr size_t kOverhead = 64; Controller::NetworkMetrics check; check.uplink_bandwidth_bps = kBandwidth; int64_t timestamp_check = kClockInitialTimeMs; EXPECT_CALL(*states.mock_debug_dump_writer, DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check)); states.audio_network_adaptor->SetUplinkBandwidth(kBandwidth); fake_clock.AdvanceTime(TimeDelta::Millis(100)); timestamp_check += 100; check.uplink_packet_loss_fraction = kPacketLoss; EXPECT_CALL(*states.mock_debug_dump_writer, DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check)); states.audio_network_adaptor->SetUplinkPacketLossFraction(kPacketLoss); fake_clock.AdvanceTime(TimeDelta::Millis(50)); timestamp_check += 50; fake_clock.AdvanceTime(TimeDelta::Millis(200)); timestamp_check += 200; check.rtt_ms = kRtt; EXPECT_CALL(*states.mock_debug_dump_writer, DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check)); states.audio_network_adaptor->SetRtt(kRtt); fake_clock.AdvanceTime(TimeDelta::Millis(150)); timestamp_check += 150; check.target_audio_bitrate_bps = kTargetAudioBitrate; EXPECT_CALL(*states.mock_debug_dump_writer, DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check)); states.audio_network_adaptor->SetTargetAudioBitrate(kTargetAudioBitrate); fake_clock.AdvanceTime(TimeDelta::Millis(50)); timestamp_check += 50; check.overhead_bytes_per_packet = kOverhead; EXPECT_CALL(*states.mock_debug_dump_writer, DumpNetworkMetrics(NetworkMetricsIs(check), timestamp_check)); states.audio_network_adaptor->SetOverhead(kOverhead); } TEST(AudioNetworkAdaptorImplTest, LogRuntimeConfigOnGetEncoderRuntimeConfig) { test::ScopedFieldTrials override_field_trials( "WebRTC-Audio-FecAdaptation/Enabled/"); auto states = CreateAudioNetworkAdaptor(); AudioEncoderRuntimeConfig config; config.bitrate_bps = 32000; config.enable_fec = true; EXPECT_CALL(*states.mock_controllers[0], MakeDecision(_)) .WillOnce(SetArgPointee<0>(config)); EXPECT_CALL(*states.event_log, LogProxy(IsRtcEventAnaConfigEqualTo(config))) .Times(1); states.audio_network_adaptor->GetEncoderRuntimeConfig(); } TEST(AudioNetworkAdaptorImplTest, TestANAStats) { auto states = CreateAudioNetworkAdaptor(); // Simulate some adaptation, otherwise the stats will not show anything. AudioEncoderRuntimeConfig config1, config2; config1.bitrate_bps = 32000; config1.num_channels = 2; config1.enable_fec = true; config1.enable_dtx = true; config1.frame_length_ms = 120; config1.uplink_packet_loss_fraction = 0.1f; config2.bitrate_bps = 16000; config2.num_channels = 1; config2.enable_fec = false; config2.enable_dtx = false; config2.frame_length_ms = 60; config1.uplink_packet_loss_fraction = 0.1f; EXPECT_CALL(*states.mock_controllers[0], MakeDecision(_)) .WillOnce(SetArgPointee<0>(config1)); states.audio_network_adaptor->GetEncoderRuntimeConfig(); EXPECT_CALL(*states.mock_controllers[0], MakeDecision(_)) .WillOnce(SetArgPointee<0>(config2)); states.audio_network_adaptor->GetEncoderRuntimeConfig(); EXPECT_CALL(*states.mock_controllers[0], MakeDecision(_)) .WillOnce(SetArgPointee<0>(config1)); states.audio_network_adaptor->GetEncoderRuntimeConfig(); auto ana_stats = states.audio_network_adaptor->GetStats(); EXPECT_EQ(ana_stats.bitrate_action_counter, 2u); EXPECT_EQ(ana_stats.channel_action_counter, 2u); EXPECT_EQ(ana_stats.dtx_action_counter, 2u); EXPECT_EQ(ana_stats.fec_action_counter, 2u); EXPECT_EQ(ana_stats.frame_length_increase_counter, 1u); EXPECT_EQ(ana_stats.frame_length_decrease_counter, 1u); EXPECT_EQ(ana_stats.uplink_packet_loss_fraction, 0.1f); } } // namespace webrtc