diff --git a/webrtc/logging/BUILD.gn b/webrtc/logging/BUILD.gn index a15945513d..fd0caca037 100644 --- a/webrtc/logging/BUILD.gn +++ b/webrtc/logging/BUILD.gn @@ -42,6 +42,7 @@ rtc_static_library("rtc_event_log_impl") { ":rtc_event_log_api", "..:webrtc_common", "../call:call_interfaces", + "../modules/audio_coding:audio_network_adaptor", "../modules/rtp_rtcp", ] diff --git a/webrtc/logging/rtc_event_log/DEPS b/webrtc/logging/rtc_event_log/DEPS index 39d2020bee..e340150be7 100644 --- a/webrtc/logging/rtc_event_log/DEPS +++ b/webrtc/logging/rtc_event_log/DEPS @@ -1,6 +1,7 @@ include_rules = [ "+webrtc/base", "+webrtc/call", + "+webrtc/modules/audio_coding/audio_network_adaptor", "+webrtc/modules/rtp_rtcp", "+webrtc/system_wrappers", ] diff --git a/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h b/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h index 315967b8c0..4db33a13ec 100644 --- a/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h +++ b/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h @@ -58,6 +58,8 @@ class MockRtcEventLog : public RtcEventLog { void(int32_t bitrate, uint8_t fraction_loss, int32_t total_packets)); + MOCK_METHOD1(LogAudioNetworkAdaptation, + void(const AudioNetworkAdaptor::EncoderRuntimeConfig& config)); }; } // namespace webrtc diff --git a/webrtc/logging/rtc_event_log/rtc_event_log.cc b/webrtc/logging/rtc_event_log/rtc_event_log.cc index 21ca5e127d..65ee7d8881 100644 --- a/webrtc/logging/rtc_event_log/rtc_event_log.cc +++ b/webrtc/logging/rtc_event_log/rtc_event_log.cc @@ -77,6 +77,8 @@ class RtcEventLogImpl final : public RtcEventLog { void LogBwePacketLossEvent(int32_t bitrate, uint8_t fraction_loss, int32_t total_packets) override; + void LogAudioNetworkAdaptation( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) override; private: void StoreEvent(std::unique_ptr* event); @@ -434,6 +436,29 @@ void RtcEventLogImpl::LogBwePacketLossEvent(int32_t bitrate, StoreEvent(&event); } +void RtcEventLogImpl::LogAudioNetworkAdaptation( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) { + std::unique_ptr event(new rtclog::Event()); + event->set_timestamp_us(rtc::TimeMicros()); + event->set_type(rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT); + auto audio_network_adaptation = event->mutable_audio_network_adaptation(); + if (config.bitrate_bps) + audio_network_adaptation->set_bitrate_bps(*config.bitrate_bps); + if (config.frame_length_ms) + audio_network_adaptation->set_frame_length_ms(*config.frame_length_ms); + if (config.uplink_packet_loss_fraction) { + audio_network_adaptation->set_uplink_packet_loss_fraction( + *config.uplink_packet_loss_fraction); + } + if (config.enable_fec) + audio_network_adaptation->set_enable_fec(*config.enable_fec); + if (config.enable_dtx) + audio_network_adaptation->set_enable_dtx(*config.enable_dtx); + if (config.num_channels) + audio_network_adaptation->set_num_channels(*config.num_channels); + StoreEvent(&event); +} + void RtcEventLogImpl::StoreEvent(std::unique_ptr* event) { if (!event_queue_.Insert(event)) { LOG(LS_ERROR) << "WebRTC event log queue full. Dropping event."; diff --git a/webrtc/logging/rtc_event_log/rtc_event_log.h b/webrtc/logging/rtc_event_log/rtc_event_log.h index ccf60944e2..5d221d4ef8 100644 --- a/webrtc/logging/rtc_event_log/rtc_event_log.h +++ b/webrtc/logging/rtc_event_log/rtc_event_log.h @@ -17,6 +17,7 @@ #include "webrtc/base/platform_file.h" #include "webrtc/call/audio_receive_stream.h" #include "webrtc/call/audio_send_stream.h" +#include "webrtc/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" #include "webrtc/video_receive_stream.h" #include "webrtc/video_send_stream.h" @@ -114,6 +115,10 @@ class RtcEventLog { uint8_t fraction_loss, int32_t total_packets) = 0; + // Logs audio encoder re-configuration driven by audio network adaptor. + virtual void LogAudioNetworkAdaptation( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) = 0; + // Reads an RtcEventLog file and returns true when reading was successful. // The result is stored in the given EventStream object. // The order of the events in the EventStream is implementation defined. @@ -155,6 +160,8 @@ class RtcEventLogNullImpl final : public RtcEventLog { void LogBwePacketLossEvent(int32_t bitrate, uint8_t fraction_loss, int32_t total_packets) override {} + void LogAudioNetworkAdaptation( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) override{}; }; } // namespace webrtc diff --git a/webrtc/logging/rtc_event_log/rtc_event_log.proto b/webrtc/logging/rtc_event_log/rtc_event_log.proto index a6d1695796..e807722979 100644 --- a/webrtc/logging/rtc_event_log/rtc_event_log.proto +++ b/webrtc/logging/rtc_event_log/rtc_event_log.proto @@ -37,6 +37,7 @@ message Event { VIDEO_SENDER_CONFIG_EVENT = 9; AUDIO_RECEIVER_CONFIG_EVENT = 10; AUDIO_SENDER_CONFIG_EVENT = 11; + AUDIO_NETWORK_ADAPTATION_EVENT = 16; } // required - Indicates the type of this event @@ -65,6 +66,9 @@ message Event { // optional - but required if type == AUDIO_SENDER_CONFIG_EVENT optional AudioSendConfig audio_sender_config = 11; + + // optional - but required if type == AUDIO_NETWORK_ADAPTATION_EVENT + optional AudioNetworkAdaptation audio_network_adaptation = 16; } message RtpPacket { @@ -227,3 +231,24 @@ message AudioSendConfig { // RTP header extensions used for the outgoing audio stream. repeated RtpHeaderExtension header_extensions = 2; } + +message AudioNetworkAdaptation { + // Bit rate that the audio encoder is operating at. + optional int32 bitrate_bps = 1; + + // Frame length that each encoded audio packet consists of. + optional int32 frame_length_ms = 2; + + // Packet loss fraction that the encoder's forward error correction (FEC) is + // optimized for. + optional float uplink_packet_loss_fraction = 3; + + // Whether forward error correction (FEC) is turned on or off. + optional bool enable_fec = 4; + + // Whether discontinuous transmission (DTX) is turned on or off. + optional bool enable_dtx = 5; + + // Number of audio channels that each encoded packet consists of. + optional uint32 num_channels = 6; +} \ No newline at end of file diff --git a/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc b/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc index ce55a4fb39..3b808b2e43 100644 --- a/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc +++ b/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc @@ -79,6 +79,8 @@ ParsedRtcEventLog::EventType GetRuntimeEventType( return ParsedRtcEventLog::EventType::AUDIO_RECEIVER_CONFIG_EVENT; case rtclog::Event::AUDIO_SENDER_CONFIG_EVENT: return ParsedRtcEventLog::EventType::AUDIO_SENDER_CONFIG_EVENT; + case rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT: + return ParsedRtcEventLog::EventType::AUDIO_NETWORK_ADAPTATION_EVENT; } RTC_NOTREACHED(); return ParsedRtcEventLog::EventType::UNKNOWN_EVENT; @@ -454,4 +456,29 @@ void ParsedRtcEventLog::GetBwePacketLossEvent(size_t index, } } +void ParsedRtcEventLog::GetAudioNetworkAdaptation( + size_t index, + AudioNetworkAdaptor::EncoderRuntimeConfig* config) const { + RTC_CHECK_LT(index, GetNumberOfEvents()); + const rtclog::Event& event = events_[index]; + RTC_CHECK(event.has_type()); + RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT); + RTC_CHECK(event.has_audio_network_adaptation()); + const rtclog::AudioNetworkAdaptation& ana_event = + event.audio_network_adaptation(); + if (ana_event.has_bitrate_bps()) + config->bitrate_bps = rtc::Optional(ana_event.bitrate_bps()); + if (ana_event.has_enable_fec()) + config->enable_fec = rtc::Optional(ana_event.enable_fec()); + if (ana_event.has_enable_dtx()) + config->enable_dtx = rtc::Optional(ana_event.enable_dtx()); + if (ana_event.has_frame_length_ms()) + config->frame_length_ms = rtc::Optional(ana_event.frame_length_ms()); + if (ana_event.has_num_channels()) + config->num_channels = rtc::Optional(ana_event.num_channels()); + if (ana_event.has_uplink_packet_loss_fraction()) + config->uplink_packet_loss_fraction = + rtc::Optional(ana_event.uplink_packet_loss_fraction()); +} + } // namespace webrtc diff --git a/webrtc/logging/rtc_event_log/rtc_event_log_parser.h b/webrtc/logging/rtc_event_log/rtc_event_log_parser.h index 2d66b9054b..8472668d75 100644 --- a/webrtc/logging/rtc_event_log/rtc_event_log_parser.h +++ b/webrtc/logging/rtc_event_log/rtc_event_log_parser.h @@ -47,7 +47,8 @@ class ParsedRtcEventLog { VIDEO_RECEIVER_CONFIG_EVENT = 8, VIDEO_SENDER_CONFIG_EVENT = 9, AUDIO_RECEIVER_CONFIG_EVENT = 10, - AUDIO_SENDER_CONFIG_EVENT = 11 + AUDIO_SENDER_CONFIG_EVENT = 11, + AUDIO_NETWORK_ADAPTATION_EVENT = 16 }; // Reads an RtcEventLog file and returns true if parsing was successful. @@ -123,6 +124,13 @@ class ParsedRtcEventLog { uint8_t* fraction_loss, int32_t* total_packets) const; + // Reads a audio network adaptation event to a (non-NULL) + // AudioNetworkAdaptor::EncoderRuntimeConfig struct. Only the fields that are + // stored in the protobuf will be written. + void GetAudioNetworkAdaptation( + size_t index, + AudioNetworkAdaptor::EncoderRuntimeConfig* config) const; + private: std::vector events_; }; diff --git a/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc b/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc index 1540466785..f0ee973a13 100644 --- a/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc +++ b/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc @@ -228,6 +228,19 @@ void GenerateAudioSendConfig(uint32_t extensions_bitvector, } } +void GenerateAudioNetworkAdaptation( + uint32_t extensions_bitvector, + AudioNetworkAdaptor::EncoderRuntimeConfig* config, + Random* prng) { + config->bitrate_bps = rtc::Optional(prng->Rand(0, 3000000)); + config->enable_fec = rtc::Optional(prng->Rand()); + config->enable_dtx = rtc::Optional(prng->Rand()); + config->frame_length_ms = rtc::Optional(prng->Rand(10, 120)); + config->num_channels = rtc::Optional(prng->Rand(1, 2)); + config->uplink_packet_loss_fraction = + rtc::Optional(prng->Rand()); +} + // Test for the RtcEventLog class. Dumps some RTP packets and other events // to disk, then reads them back to see if they match. void LogSessionAndReadBack(size_t rtp_count, @@ -604,6 +617,22 @@ class VideoSendConfigReadWriteTest : public ConfigReadWriteTest { VideoSendStream::Config config; }; +class AudioNetworkAdaptationReadWriteTest : public ConfigReadWriteTest { + public: + void GenerateConfig(uint32_t extensions_bitvector) override { + GenerateAudioNetworkAdaptation(extensions_bitvector, &config, &prng); + } + void LogConfig(RtcEventLog* event_log) override { + event_log->LogAudioNetworkAdaptation(config); + } + void VerifyConfig(const ParsedRtcEventLog& parsed_log, + size_t index) override { + RtcEventLogTestHelper::VerifyAudioNetworkAdaptation(parsed_log, index, + config); + } + AudioNetworkAdaptor::EncoderRuntimeConfig config; +}; + TEST(RtcEventLogTest, LogAudioReceiveConfig) { AudioReceiveConfigReadWriteTest test; test.DoTest(); @@ -623,4 +652,10 @@ TEST(RtcEventLogTest, LogVideoSendConfig) { VideoSendConfigReadWriteTest test; test.DoTest(); } + +TEST(RtcEventLogTest, LogAudioNetworkAdaptation) { + AudioNetworkAdaptationReadWriteTest test; + test.DoTest(); +} + } // namespace webrtc diff --git a/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc index fb60dbcc05..19ca8aa15c 100644 --- a/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc +++ b/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc @@ -461,6 +461,21 @@ void RtcEventLogTestHelper::VerifyBweLossEvent( EXPECT_EQ(total_packets, parsed_total_packets); } +void RtcEventLogTestHelper::VerifyAudioNetworkAdaptation( + const ParsedRtcEventLog& parsed_log, + size_t index, + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) { + AudioNetworkAdaptor::EncoderRuntimeConfig parsed_config; + parsed_log.GetAudioNetworkAdaptation(index, &parsed_config); + EXPECT_EQ(config.bitrate_bps, parsed_config.bitrate_bps); + EXPECT_EQ(config.enable_dtx, parsed_config.enable_dtx); + EXPECT_EQ(config.enable_fec, parsed_config.enable_fec); + EXPECT_EQ(config.frame_length_ms, parsed_config.frame_length_ms); + EXPECT_EQ(config.num_channels, parsed_config.num_channels); + EXPECT_EQ(config.uplink_packet_loss_fraction, + parsed_config.uplink_packet_loss_fraction); +} + void RtcEventLogTestHelper::VerifyLogStartEvent( const ParsedRtcEventLog& parsed_log, size_t index) { diff --git a/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h index 3f89e304b2..2f4e17703b 100644 --- a/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h +++ b/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h @@ -56,6 +56,11 @@ class RtcEventLogTestHelper { uint8_t fraction_loss, int32_t total_packets); + static void VerifyAudioNetworkAdaptation( + const ParsedRtcEventLog& parsed_log, + size_t index, + const AudioNetworkAdaptor::EncoderRuntimeConfig& config); + static void VerifyLogStartEvent(const ParsedRtcEventLog& parsed_log, size_t index); static void VerifyLogEndEvent(const ParsedRtcEventLog& parsed_log, diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index 9c285c9650..404637357d 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -914,6 +914,8 @@ rtc_static_library("audio_network_adaptor") { "audio_network_adaptor/debug_dump_writer.h", "audio_network_adaptor/dtx_controller.cc", "audio_network_adaptor/dtx_controller.h", + "audio_network_adaptor/event_log_writer.cc", + "audio_network_adaptor/event_log_writer.h", "audio_network_adaptor/fec_controller.cc", "audio_network_adaptor/fec_controller.h", "audio_network_adaptor/frame_length_controller.cc", @@ -925,6 +927,7 @@ rtc_static_library("audio_network_adaptor") { "../..:webrtc_common", "../../base:rtc_base_approved", "../../common_audio", + "../../logging:rtc_event_log_api", "../../system_wrappers", ] @@ -935,6 +938,11 @@ rtc_static_library("audio_network_adaptor") { ] defines = [ "WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP" ] } + + if (!build_with_chromium && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } } rtc_static_library("neteq") { @@ -1935,6 +1943,7 @@ if (rtc_include_tests) { "audio_network_adaptor/channel_controller_unittest.cc", "audio_network_adaptor/controller_manager_unittest.cc", "audio_network_adaptor/dtx_controller_unittest.cc", + "audio_network_adaptor/event_log_writer_unittest.cc", "audio_network_adaptor/fec_controller_unittest.cc", "audio_network_adaptor/frame_length_controller_unittest.cc", "audio_network_adaptor/mock/mock_controller.h", diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc index 3b767d9b59..6ec92b00fc 100644 --- a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc +++ b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.cc @@ -12,8 +12,16 @@ #include +#include "webrtc/base/logging.h" + namespace webrtc { +namespace { +constexpr int kEventLogMinBitrateChangeBps = 5000; +constexpr float kEventLogMinBitrateChangeFraction = 0.25; +constexpr float kEventLogMinPacketLossChangeFraction = 0.5; +} // namespace + AudioNetworkAdaptorImpl::Config::Config() : event_log(nullptr), clock(nullptr){}; @@ -25,7 +33,14 @@ AudioNetworkAdaptorImpl::AudioNetworkAdaptorImpl( std::unique_ptr debug_dump_writer) : config_(config), controller_manager_(std::move(controller_manager)), - debug_dump_writer_(std::move(debug_dump_writer)) { + debug_dump_writer_(std::move(debug_dump_writer)), + event_log_writer_( + config.event_log + ? new EventLogWriter(config.event_log, + kEventLogMinBitrateChangeBps, + kEventLogMinBitrateChangeFraction, + kEventLogMinPacketLossChangeFraction) + : nullptr) { RTC_DCHECK(controller_manager_); } @@ -68,11 +83,13 @@ AudioNetworkAdaptorImpl::GetEncoderRuntimeConfig() { controller_manager_->GetSortedControllers(last_metrics_)) controller->MakeDecision(last_metrics_, &config); - // TODO(minyue): Add debug dumping. if (debug_dump_writer_) debug_dump_writer_->DumpEncoderRuntimeConfig( config, config_.clock->TimeInMilliseconds()); + if (event_log_writer_) + event_log_writer_->MaybeLogEncoderConfig(config); + return config; } diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h index 801a9ccc59..9c47125da4 100644 --- a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h +++ b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h @@ -17,6 +17,7 @@ #include "webrtc/modules/audio_coding/audio_network_adaptor/controller.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/debug_dump_writer.h" +#include "webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" #include "webrtc/system_wrappers/include/clock.h" @@ -65,6 +66,8 @@ class AudioNetworkAdaptorImpl final : public AudioNetworkAdaptor { std::unique_ptr debug_dump_writer_; + const std::unique_ptr event_log_writer_; + Controller::NetworkMetrics last_metrics_; RTC_DISALLOW_COPY_AND_ASSIGN(AudioNetworkAdaptorImpl); diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc index b26d2f5db8..9b608dce47 100644 --- a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc +++ b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl_unittest.cc @@ -11,6 +11,7 @@ #include #include +#include "webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_controller.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_controller_manager.h" @@ -52,6 +53,7 @@ struct AudioNetworkAdaptorStates { std::unique_ptr audio_network_adaptor; std::vector> mock_controllers; std::unique_ptr simulated_clock; + std::unique_ptr event_log; MockDebugDumpWriter* mock_debug_dump_writer; }; @@ -76,6 +78,7 @@ AudioNetworkAdaptorStates CreateAudioNetworkAdaptor() { .WillRepeatedly(Return(controllers)); states.simulated_clock.reset(new SimulatedClock(kClockInitialTimeMs * 1000)); + states.event_log.reset(new NiceMock()); auto debug_dump_writer = std::unique_ptr(new NiceMock()); @@ -84,6 +87,7 @@ AudioNetworkAdaptorStates CreateAudioNetworkAdaptor() { AudioNetworkAdaptorImpl::Config config; config.clock = states.simulated_clock.get(); + config.event_log = states.event_log.get(); // AudioNetworkAdaptorImpl governs the lifetime of controller manager. states.audio_network_adaptor.reset(new AudioNetworkAdaptorImpl( config, @@ -205,4 +209,20 @@ TEST(AudioNetworkAdaptorImplTest, states.audio_network_adaptor->SetOverhead(kOverhead); } +TEST(AudioNetworkAdaptorImplTest, LogRuntimeConfigOnGetEncoderRuntimeConfig) { + auto states = CreateAudioNetworkAdaptor(); + + AudioNetworkAdaptor::EncoderRuntimeConfig config; + config.bitrate_bps = rtc::Optional(32000); + config.enable_fec = rtc::Optional(true); + + EXPECT_CALL(*states.mock_controllers[0], MakeDecision(_, _)) + .WillOnce(SetArgPointee<1>(config)); + + EXPECT_CALL(*states.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(config))) + .Times(1); + states.audio_network_adaptor->GetEncoderRuntimeConfig(); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.cc b/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.cc new file mode 100644 index 0000000000..619a2473d9 --- /dev/null +++ b/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.cc @@ -0,0 +1,68 @@ +/* + * 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 +#include + +#include "webrtc/logging/rtc_event_log/rtc_event_log.h" +#include "webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.h" + +namespace webrtc { + +EventLogWriter::EventLogWriter(RtcEventLog* event_log, + int min_bitrate_change_bps, + float min_bitrate_change_fraction, + float min_packet_loss_change_fraction) + : event_log_(event_log), + min_bitrate_change_bps_(min_bitrate_change_bps), + min_bitrate_change_fraction_(min_bitrate_change_fraction), + min_packet_loss_change_fraction_(min_packet_loss_change_fraction) { + RTC_DCHECK(event_log_); +} + +EventLogWriter::~EventLogWriter() = default; + +void EventLogWriter::MaybeLogEncoderConfig( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) { + if (last_logged_config_.num_channels != config.num_channels) + return LogEncoderConfig(config); + if (last_logged_config_.enable_dtx != config.enable_dtx) + return LogEncoderConfig(config); + if (last_logged_config_.enable_fec != config.enable_fec) + return LogEncoderConfig(config); + if (last_logged_config_.frame_length_ms != config.frame_length_ms) + return LogEncoderConfig(config); + if ((!last_logged_config_.bitrate_bps && config.bitrate_bps) || + (last_logged_config_.bitrate_bps && config.bitrate_bps && + std::abs(*last_logged_config_.bitrate_bps - *config.bitrate_bps) >= + std::min(static_cast(*last_logged_config_.bitrate_bps * + min_bitrate_change_fraction_), + min_bitrate_change_bps_))) { + return LogEncoderConfig(config); + } + if ((!last_logged_config_.uplink_packet_loss_fraction && + config.uplink_packet_loss_fraction) || + (last_logged_config_.uplink_packet_loss_fraction && + config.uplink_packet_loss_fraction && + fabs(*last_logged_config_.uplink_packet_loss_fraction - + *config.uplink_packet_loss_fraction) >= + min_packet_loss_change_fraction_ * + *last_logged_config_.uplink_packet_loss_fraction)) { + return LogEncoderConfig(config); + } +} + +void EventLogWriter::LogEncoderConfig( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) { + event_log_->LogAudioNetworkAdaptation(config); + last_logged_config_ = config; +} + +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.h b/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.h new file mode 100644 index 0000000000..740da8c31a --- /dev/null +++ b/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_EVENT_LOG_WRITER_H_ +#define WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_EVENT_LOG_WRITER_H_ + +#include "webrtc/base/constructormagic.h" +#include "webrtc/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" + +namespace webrtc { +class RtcEventLog; + +class EventLogWriter final { + public: + EventLogWriter(RtcEventLog* event_log, + int min_bitrate_change_bps, + float min_bitrate_change_fraction, + float min_packet_loss_change_fraction); + ~EventLogWriter(); + void MaybeLogEncoderConfig( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config); + + private: + void LogEncoderConfig( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config); + + RtcEventLog* const event_log_; + const int min_bitrate_change_bps_; + const float min_bitrate_change_fraction_; + const float min_packet_loss_change_fraction_; + AudioNetworkAdaptor::EncoderRuntimeConfig last_logged_config_; + RTC_DISALLOW_COPY_AND_ASSIGN(EventLogWriter); +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_EVENT_LOG_WRITER_H_ diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc new file mode 100644 index 0000000000..289b8e2c7a --- /dev/null +++ b/webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer_unittest.cc @@ -0,0 +1,265 @@ +/* + * 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 + +#include "webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h" +#include "webrtc/modules/audio_coding/audio_network_adaptor/event_log_writer.h" +#include "webrtc/test/gtest.h" + +namespace webrtc { + +namespace { + +constexpr int kMinBitrateChangeBps = 5000; +constexpr float kMinPacketLossChangeFraction = 0.5; +constexpr float kMinBitrateChangeFraction = 0.25; + +constexpr int kHighBitrateBps = 70000; +constexpr int kLowBitrateBps = 10000; +constexpr int kFrameLengthMs = 60; +constexpr bool kEnableFec = true; +constexpr bool kEnableDtx = true; +constexpr float kPacketLossFraction = 0.05f; +constexpr size_t kNumChannels = 1; + +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 EventLogWriterStates { + std::unique_ptr event_log_writer; + std::unique_ptr> event_log; + AudioNetworkAdaptor::EncoderRuntimeConfig runtime_config; +}; + +EventLogWriterStates CreateEventLogWriter() { + EventLogWriterStates state; + state.event_log.reset(new testing::StrictMock()); + state.event_log_writer.reset(new EventLogWriter( + state.event_log.get(), kMinBitrateChangeBps, kMinBitrateChangeFraction, + kMinPacketLossChangeFraction)); + state.runtime_config.bitrate_bps = rtc::Optional(kHighBitrateBps); + state.runtime_config.frame_length_ms = rtc::Optional(kFrameLengthMs); + state.runtime_config.uplink_packet_loss_fraction = + rtc::Optional(kPacketLossFraction); + state.runtime_config.enable_fec = rtc::Optional(kEnableFec); + state.runtime_config.enable_dtx = rtc::Optional(kEnableDtx); + state.runtime_config.num_channels = rtc::Optional(kNumChannels); + return state; +} +} // namespace + +TEST(EventLogWriterTest, FirstConfigIsLogged) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, SameConfigIsNotLogged) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogFecStateChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + + state.runtime_config.enable_fec = rtc::Optional(!kEnableFec); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogDtxStateChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + + state.runtime_config.enable_dtx = rtc::Optional(!kEnableDtx); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogChannelChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + + state.runtime_config.num_channels = rtc::Optional(kNumChannels + 1); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogFrameLengthChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + + state.runtime_config.frame_length_ms = rtc::Optional(20); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, DoNotLogSmallBitrateChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + state.runtime_config.bitrate_bps = + rtc::Optional(kHighBitrateBps + kMinBitrateChangeBps - 1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogLargeBitrateChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + // At high bitrate, the min fraction rule requires a larger change than the + // min change rule. We make sure that the min change rule applies. + RTC_DCHECK_GT(kHighBitrateBps * kMinBitrateChangeFraction, + kMinBitrateChangeBps); + state.runtime_config.bitrate_bps = + rtc::Optional(kHighBitrateBps + kMinBitrateChangeBps); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogMinBitrateChangeFractionOnLowBitrateChange) { + auto state = CreateEventLogWriter(); + state.runtime_config.bitrate_bps = rtc::Optional(kLowBitrateBps); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + // At high bitrate, the min change rule requires a larger change than the min + // fraction rule. We make sure that the min fraction rule applies. + state.runtime_config.bitrate_bps = rtc::Optional( + kLowBitrateBps + kLowBitrateBps * kMinBitrateChangeFraction); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, DoNotLogSmallPacketLossFractionChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + state.runtime_config.uplink_packet_loss_fraction = rtc::Optional( + kPacketLossFraction + kMinPacketLossChangeFraction * kPacketLossFraction - + 0.001f); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogLargePacketLossFractionChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + state.runtime_config.uplink_packet_loss_fraction = rtc::Optional( + kPacketLossFraction + kMinPacketLossChangeFraction * kPacketLossFraction); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogJustOnceOnMultipleChanges) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + state.runtime_config.uplink_packet_loss_fraction = rtc::Optional( + kPacketLossFraction + kMinPacketLossChangeFraction * kPacketLossFraction); + state.runtime_config.frame_length_ms = rtc::Optional(20); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); +} + +TEST(EventLogWriterTest, LogAfterGradualChange) { + auto state = CreateEventLogWriter(); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + state.runtime_config.bitrate_bps = + rtc::Optional(kHighBitrateBps + kMinBitrateChangeBps); + EXPECT_CALL( + *state.event_log, + LogAudioNetworkAdaptation(EncoderRuntimeConfigIs(state.runtime_config))) + .Times(1); + for (int bitrate_bps = kHighBitrateBps; + bitrate_bps <= kHighBitrateBps + kMinBitrateChangeBps; bitrate_bps++) { + state.runtime_config.bitrate_bps = rtc::Optional(bitrate_bps); + state.event_log_writer->MaybeLogEncoderConfig(state.runtime_config); + } +} +} // namespace webrtc diff --git a/webrtc/tools/BUILD.gn b/webrtc/tools/BUILD.gn index d2992a4ccc..46a0ede844 100644 --- a/webrtc/tools/BUILD.gn +++ b/webrtc/tools/BUILD.gn @@ -205,6 +205,7 @@ if (rtc_enable_protobuf) { "../call:call_interfaces", "../logging:rtc_event_log_impl", "../logging:rtc_event_log_parser", + "../modules/audio_coding:ana_debug_dump_proto", # TODO(kwiberg): Remove this dependency. "../modules/audio_coding:audio_format", diff --git a/webrtc/tools/event_log_visualizer/analyzer.cc b/webrtc/tools/event_log_visualizer/analyzer.cc index 89e516a950..3fd2c25fe8 100644 --- a/webrtc/tools/event_log_visualizer/analyzer.cc +++ b/webrtc/tools/event_log_visualizer/analyzer.cc @@ -423,6 +423,9 @@ EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log) bwe_loss_updates_.push_back(bwe_update); break; } + case ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: { + break; + } case ParsedRtcEventLog::BWE_PACKET_DELAY_EVENT: { break; } diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc index 5231691b55..2791f7f8b4 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -140,6 +140,14 @@ class RtcEventLogProxy final : public webrtc::RtcEventLog { } } + void LogAudioNetworkAdaptation( + const AudioNetworkAdaptor::EncoderRuntimeConfig& config) override { + rtc::CritScope lock(&crit_); + if (event_log_) { + event_log_->LogAudioNetworkAdaptation(config); + } + } + void SetEventLog(RtcEventLog* event_log) { rtc::CritScope lock(&crit_); event_log_ = event_log;