Added logging for audio send/receive stream configs.

BUG=webrtc:4741,webrtc:6399

Review-Url: https://codereview.webrtc.org/2353543003
Cr-Commit-Position: refs/heads/master@{#14585}
diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc
index 5d6bbab..9515ac1 100644
--- a/webrtc/call/call.cc
+++ b/webrtc/call/call.cc
@@ -370,6 +370,7 @@
     const webrtc::AudioSendStream::Config& config) {
   TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream");
   RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
+  event_log_->LogAudioSendStreamConfig(config);
   AudioSendStream* send_stream = new AudioSendStream(
       config, config_.audio_state, &worker_queue_, congestion_controller_.get(),
       bitrate_allocator_.get(), event_log_);
@@ -407,6 +408,7 @@
     const webrtc::AudioReceiveStream::Config& config) {
   TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream");
   RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
+  event_log_->LogAudioReceiveStreamConfig(config);
   AudioReceiveStream* receive_stream = new AudioReceiveStream(
       congestion_controller_.get(), config, config_.audio_state, event_log_);
   {
diff --git a/webrtc/call/mock/mock_rtc_event_log.h b/webrtc/call/mock/mock_rtc_event_log.h
index 2762386..637389f 100644
--- a/webrtc/call/mock/mock_rtc_event_log.h
+++ b/webrtc/call/mock/mock_rtc_event_log.h
@@ -34,6 +34,12 @@
   MOCK_METHOD1(LogVideoSendStreamConfig,
                void(const webrtc::VideoSendStream::Config& config));
 
+  MOCK_METHOD1(LogAudioReceiveStreamConfig,
+               void(const webrtc::AudioReceiveStream::Config& config));
+
+  MOCK_METHOD1(LogAudioSendStreamConfig,
+               void(const webrtc::AudioSendStream::Config& config));
+
   MOCK_METHOD4(LogRtpHeader,
                void(PacketDirection direction,
                     MediaType media_type,
diff --git a/webrtc/logging/rtc_event_log/rtc_event_log.cc b/webrtc/logging/rtc_event_log/rtc_event_log.cc
index 00314e6..976ff23 100644
--- a/webrtc/logging/rtc_event_log/rtc_event_log.cc
+++ b/webrtc/logging/rtc_event_log/rtc_event_log.cc
@@ -62,6 +62,9 @@
   void LogVideoReceiveStreamConfig(
       const VideoReceiveStream::Config& config) override;
   void LogVideoSendStreamConfig(const VideoSendStream::Config& config) override;
+  void LogAudioReceiveStreamConfig(
+      const AudioReceiveStream::Config& config) override;
+  void LogAudioSendStreamConfig(const AudioSendStream::Config& config) override;
   void LogRtpHeader(PacketDirection direction,
                     MediaType media_type,
                     const uint8_t* header,
@@ -292,6 +295,46 @@
   StoreEvent(&event);
 }
 
+void RtcEventLogImpl::LogAudioReceiveStreamConfig(
+    const AudioReceiveStream::Config& config) {
+  std::unique_ptr<rtclog::Event> event(new rtclog::Event());
+  event->set_timestamp_us(clock_->TimeInMicroseconds());
+  event->set_type(rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT);
+
+  rtclog::AudioReceiveConfig* receiver_config =
+      event->mutable_audio_receiver_config();
+  receiver_config->set_remote_ssrc(config.rtp.remote_ssrc);
+  receiver_config->set_local_ssrc(config.rtp.local_ssrc);
+
+  for (const auto& e : config.rtp.extensions) {
+    rtclog::RtpHeaderExtension* extension =
+        receiver_config->add_header_extensions();
+    extension->set_name(e.uri);
+    extension->set_id(e.id);
+  }
+  StoreEvent(&event);
+}
+
+void RtcEventLogImpl::LogAudioSendStreamConfig(
+    const AudioSendStream::Config& config) {
+  std::unique_ptr<rtclog::Event> event(new rtclog::Event());
+  event->set_timestamp_us(clock_->TimeInMicroseconds());
+  event->set_type(rtclog::Event::AUDIO_SENDER_CONFIG_EVENT);
+
+  rtclog::AudioSendConfig* sender_config = event->mutable_audio_sender_config();
+
+  sender_config->set_ssrc(config.rtp.ssrc);
+
+  for (const auto& e : config.rtp.extensions) {
+    rtclog::RtpHeaderExtension* extension =
+        sender_config->add_header_extensions();
+    extension->set_name(e.uri);
+    extension->set_id(e.id);
+  }
+
+  StoreEvent(&event);
+}
+
 void RtcEventLogImpl::LogRtpHeader(PacketDirection direction,
                                    MediaType media_type,
                                    const uint8_t* header,
diff --git a/webrtc/logging/rtc_event_log/rtc_event_log.h b/webrtc/logging/rtc_event_log/rtc_event_log.h
index 910e9a6..ec57b8b 100644
--- a/webrtc/logging/rtc_event_log/rtc_event_log.h
+++ b/webrtc/logging/rtc_event_log/rtc_event_log.h
@@ -14,6 +14,8 @@
 #include <memory>
 #include <string>
 
+#include "webrtc/api/call/audio_receive_stream.h"
+#include "webrtc/api/call/audio_send_stream.h"
 #include "webrtc/base/platform_file.h"
 #include "webrtc/video_receive_stream.h"
 #include "webrtc/video_send_stream.h"
@@ -77,6 +79,14 @@
   virtual void LogVideoSendStreamConfig(
       const webrtc::VideoSendStream::Config& config) = 0;
 
+  // Logs configuration information for webrtc::AudioReceiveStream.
+  virtual void LogAudioReceiveStreamConfig(
+      const webrtc::AudioReceiveStream::Config& config) = 0;
+
+  // Logs configuration information for webrtc::AudioSendStream.
+  virtual void LogAudioSendStreamConfig(
+      const webrtc::AudioSendStream::Config& config) = 0;
+
   // Logs the header of an incoming or outgoing RTP packet. packet_length
   // is the total length of the packet, including both header and payload.
   virtual void LogRtpHeader(PacketDirection direction,
@@ -123,6 +133,10 @@
       const VideoReceiveStream::Config& config) override {}
   void LogVideoSendStreamConfig(
       const VideoSendStream::Config& config) override {}
+  void LogAudioReceiveStreamConfig(
+      const AudioReceiveStream::Config& config) override {}
+  void LogAudioSendStreamConfig(
+      const AudioSendStream::Config& config) override {}
   void LogRtpHeader(PacketDirection direction,
                     MediaType media_type,
                     const uint8_t* header,
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 362d79e..8f1b89d 100644
--- a/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc
+++ b/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc
@@ -104,6 +104,20 @@
   return std::make_pair(varint, false);
 }
 
+void GetHeaderExtensions(
+    std::vector<RtpExtension>* header_extensions,
+    const google::protobuf::RepeatedPtrField<rtclog::RtpHeaderExtension>&
+        proto_header_extensions) {
+  header_extensions->clear();
+  for (auto& p : proto_header_extensions) {
+    RTC_CHECK(p.has_name());
+    RTC_CHECK(p.has_id());
+    const std::string& name = p.name();
+    int id = p.id();
+    header_extensions->push_back(RtpExtension(name, id));
+  }
+}
+
 }  // namespace
 
 bool ParsedRtcEventLog::ParseFile(const std::string& filename) {
@@ -311,14 +325,8 @@
     config->rtp.rtx.insert(std::make_pair(map.payload_type(), rtx_pair));
   }
   // Get header extensions.
-  config->rtp.extensions.clear();
-  for (int i = 0; i < receiver_config.header_extensions_size(); i++) {
-    RTC_CHECK(receiver_config.header_extensions(i).has_name());
-    RTC_CHECK(receiver_config.header_extensions(i).has_id());
-    const std::string& name = receiver_config.header_extensions(i).name();
-    int id = receiver_config.header_extensions(i).id();
-    config->rtp.extensions.push_back(RtpExtension(name, id));
-  }
+  GetHeaderExtensions(&config->rtp.extensions,
+                      receiver_config.header_extensions());
   // Get decoders.
   config->decoders.clear();
   for (int i = 0; i < receiver_config.decoders_size(); i++) {
@@ -347,14 +355,8 @@
     config->rtp.ssrcs.push_back(sender_config.ssrcs(i));
   }
   // Get header extensions.
-  config->rtp.extensions.clear();
-  for (int i = 0; i < sender_config.header_extensions_size(); i++) {
-    RTC_CHECK(sender_config.header_extensions(i).has_name());
-    RTC_CHECK(sender_config.header_extensions(i).has_id());
-    const std::string& name = sender_config.header_extensions(i).name();
-    int id = sender_config.header_extensions(i).id();
-    config->rtp.extensions.push_back(RtpExtension(name, id));
-  }
+  GetHeaderExtensions(&config->rtp.extensions,
+                      sender_config.header_extensions());
   // Get RTX settings.
   config->rtp.rtx.ssrcs.clear();
   for (int i = 0; i < sender_config.rtx_ssrcs_size(); i++) {
@@ -376,6 +378,45 @@
       sender_config.encoder().payload_type();
 }
 
+void ParsedRtcEventLog::GetAudioReceiveConfig(
+    size_t index,
+    AudioReceiveStream::Config* config) const {
+  RTC_CHECK_LT(index, GetNumberOfEvents());
+  const rtclog::Event& event = events_[index];
+  RTC_CHECK(config != nullptr);
+  RTC_CHECK(event.has_type());
+  RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT);
+  RTC_CHECK(event.has_audio_receiver_config());
+  const rtclog::AudioReceiveConfig& receiver_config =
+      event.audio_receiver_config();
+  // Get SSRCs.
+  RTC_CHECK(receiver_config.has_remote_ssrc());
+  config->rtp.remote_ssrc = receiver_config.remote_ssrc();
+  RTC_CHECK(receiver_config.has_local_ssrc());
+  config->rtp.local_ssrc = receiver_config.local_ssrc();
+  // Get header extensions.
+  GetHeaderExtensions(&config->rtp.extensions,
+                      receiver_config.header_extensions());
+}
+
+void ParsedRtcEventLog::GetAudioSendConfig(
+    size_t index,
+    AudioSendStream::Config* config) const {
+  RTC_CHECK_LT(index, GetNumberOfEvents());
+  const rtclog::Event& event = events_[index];
+  RTC_CHECK(config != nullptr);
+  RTC_CHECK(event.has_type());
+  RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_SENDER_CONFIG_EVENT);
+  RTC_CHECK(event.has_audio_sender_config());
+  const rtclog::AudioSendConfig& sender_config = event.audio_sender_config();
+  // Get SSRCs.
+  RTC_CHECK(sender_config.has_ssrc());
+  config->rtp.ssrc = sender_config.ssrc();
+  // Get header extensions.
+  GetHeaderExtensions(&config->rtp.extensions,
+                      sender_config.header_extensions());
+}
+
 void ParsedRtcEventLog::GetAudioPlayout(size_t index, uint32_t* ssrc) const {
   RTC_CHECK_LT(index, GetNumberOfEvents());
   const rtclog::Event& event = events_[index];
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 6a684cb..2d66b90 100644
--- a/webrtc/logging/rtc_event_log/rtc_event_log_parser.h
+++ b/webrtc/logging/rtc_event_log/rtc_event_log_parser.h
@@ -99,6 +99,15 @@
   // Only the fields that are stored in the protobuf will be written.
   void GetVideoSendConfig(size_t index, VideoSendStream::Config* config) const;
 
+  // Reads a config event to a (non-NULL) AudioReceiveStream::Config struct.
+  // Only the fields that are stored in the protobuf will be written.
+  void GetAudioReceiveConfig(size_t index,
+                             AudioReceiveStream::Config* config) const;
+
+  // Reads a config event to a (non-NULL) AudioSendStream::Config struct.
+  // Only the fields that are stored in the protobuf will be written.
+  void GetAudioSendConfig(size_t index, AudioSendStream::Config* config) const;
+
   // Reads the SSRC from the audio playout event at |index|. The SSRC is stored
   // in the output parameter ssrc. The output parameter can be set to nullptr
   // and in that case the function only asserts that the event is well formed.
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 d6af3e9..5ca885c 100644
--- a/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc
+++ b/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc
@@ -200,6 +200,35 @@
   }
 }
 
+void GenerateAudioReceiveConfig(uint32_t extensions_bitvector,
+                                AudioReceiveStream::Config* config,
+                                Random* prng) {
+  // Add SSRCs for the stream.
+  config->rtp.remote_ssrc = prng->Rand<uint32_t>();
+  config->rtp.local_ssrc = prng->Rand<uint32_t>();
+  // Add header extensions.
+  for (unsigned i = 0; i < kNumExtensions; i++) {
+    if (extensions_bitvector & (1u << i)) {
+      config->rtp.extensions.push_back(
+          RtpExtension(kExtensionNames[i], prng->Rand<int>()));
+    }
+  }
+}
+
+void GenerateAudioSendConfig(uint32_t extensions_bitvector,
+                             AudioSendStream::Config* config,
+                             Random* prng) {
+  // Add SSRC to the stream.
+  config->rtp.ssrc = prng->Rand<uint32_t>();
+  // Add header extensions.
+  for (unsigned i = 0; i < kNumExtensions; i++) {
+    if (extensions_bitvector & (1u << i)) {
+      config->rtp.extensions.push_back(
+          RtpExtension(kExtensionNames[i], prng->Rand<int>()));
+    }
+  }
+}
+
 // 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,
@@ -324,9 +353,10 @@
     PrintExpectedEvents(rtp_count, rtcp_count, playout_count, bwe_loss_count);
   }
   RtcEventLogTestHelper::VerifyLogStartEvent(parsed_log, 0);
-  RtcEventLogTestHelper::VerifyReceiveStreamConfig(parsed_log, 1,
-                                                   receiver_config);
-  RtcEventLogTestHelper::VerifySendStreamConfig(parsed_log, 2, sender_config);
+  RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig(parsed_log, 1,
+                                                        receiver_config);
+  RtcEventLogTestHelper::VerifyVideoSendStreamConfig(parsed_log, 2,
+                                                     sender_config);
   size_t event_index = config_count + 1;
   size_t rtcp_index = 1;
   size_t playout_index = 1;
@@ -457,4 +487,138 @@
   remove(temp_filename.c_str());
 }
 
+class ConfigReadWriteTest {
+ public:
+  ConfigReadWriteTest() : prng(987654321) {}
+  virtual ~ConfigReadWriteTest() {}
+  virtual void GenerateConfig(uint32_t extensions_bitvector) = 0;
+  virtual void VerifyConfig(const ParsedRtcEventLog& parsed_log,
+                            size_t index) = 0;
+  virtual void LogConfig(RtcEventLog* event_log) = 0;
+
+  void DoTest() {
+    // Find the name of the current test, in order to use it as a temporary
+    // filename.
+    auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
+    const std::string temp_filename =
+        test::OutputPath() + test_info->test_case_name() + test_info->name();
+
+    // Use all extensions.
+    uint32_t extensions_bitvector = (1u << kNumExtensions) - 1;
+    GenerateConfig(extensions_bitvector);
+
+    // Log a single config event and stop logging.
+    SimulatedClock fake_clock(prng.Rand<uint32_t>());
+    std::unique_ptr<RtcEventLog> log_dumper(RtcEventLog::Create(&fake_clock));
+
+    log_dumper->StartLogging(temp_filename, 10000000);
+    LogConfig(log_dumper.get());
+    log_dumper->StopLogging();
+
+    // Read the generated file from disk.
+    ParsedRtcEventLog parsed_log;
+    ASSERT_TRUE(parsed_log.ParseFile(temp_filename));
+
+    // Check the generated number of events.
+    EXPECT_EQ(3u, parsed_log.GetNumberOfEvents());
+
+    RtcEventLogTestHelper::VerifyLogStartEvent(parsed_log, 0);
+
+    // Verify that the parsed config struct matches the one that was logged.
+    VerifyConfig(parsed_log, 1);
+
+    RtcEventLogTestHelper::VerifyLogEndEvent(parsed_log, 2);
+
+    // Clean up temporary file - can be pretty slow.
+    remove(temp_filename.c_str());
+  }
+  Random prng;
+};
+
+class AudioReceiveConfigReadWriteTest : public ConfigReadWriteTest {
+ public:
+  void GenerateConfig(uint32_t extensions_bitvector) override {
+    GenerateAudioReceiveConfig(extensions_bitvector, &config, &prng);
+  }
+  void LogConfig(RtcEventLog* event_log) override {
+    event_log->LogAudioReceiveStreamConfig(config);
+  }
+  void VerifyConfig(const ParsedRtcEventLog& parsed_log,
+                    size_t index) override {
+    RtcEventLogTestHelper::VerifyAudioReceiveStreamConfig(parsed_log, index,
+                                                          config);
+  }
+  AudioReceiveStream::Config config;
+};
+
+class AudioSendConfigReadWriteTest : public ConfigReadWriteTest {
+ public:
+  AudioSendConfigReadWriteTest() : config(nullptr) {}
+  void GenerateConfig(uint32_t extensions_bitvector) override {
+    GenerateAudioSendConfig(extensions_bitvector, &config, &prng);
+  }
+  void LogConfig(RtcEventLog* event_log) override {
+    event_log->LogAudioSendStreamConfig(config);
+  }
+  void VerifyConfig(const ParsedRtcEventLog& parsed_log,
+                    size_t index) override {
+    RtcEventLogTestHelper::VerifyAudioSendStreamConfig(parsed_log, index,
+                                                       config);
+  }
+  AudioSendStream::Config config;
+};
+
+class VideoReceiveConfigReadWriteTest : public ConfigReadWriteTest {
+ public:
+  VideoReceiveConfigReadWriteTest() : config(nullptr) {}
+  void GenerateConfig(uint32_t extensions_bitvector) override {
+    GenerateVideoReceiveConfig(extensions_bitvector, &config, &prng);
+  }
+  void LogConfig(RtcEventLog* event_log) override {
+    event_log->LogVideoReceiveStreamConfig(config);
+  }
+  void VerifyConfig(const ParsedRtcEventLog& parsed_log,
+                    size_t index) override {
+    RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig(parsed_log, index,
+                                                          config);
+  }
+  VideoReceiveStream::Config config;
+};
+
+class VideoSendConfigReadWriteTest : public ConfigReadWriteTest {
+ public:
+  VideoSendConfigReadWriteTest() : config(nullptr) {}
+  void GenerateConfig(uint32_t extensions_bitvector) override {
+    GenerateVideoSendConfig(extensions_bitvector, &config, &prng);
+  }
+  void LogConfig(RtcEventLog* event_log) override {
+    event_log->LogVideoSendStreamConfig(config);
+  }
+  void VerifyConfig(const ParsedRtcEventLog& parsed_log,
+                    size_t index) override {
+    RtcEventLogTestHelper::VerifyVideoSendStreamConfig(parsed_log, index,
+                                                       config);
+  }
+  VideoSendStream::Config config;
+};
+
+TEST(RtcEventLogTest, LogAudioReceiveConfig) {
+  AudioReceiveConfigReadWriteTest test;
+  test.DoTest();
+}
+
+TEST(RtcEventLogTest, LogAudioSendConfig) {
+  AudioSendConfigReadWriteTest test;
+  test.DoTest();
+}
+
+TEST(RtcEventLogTest, LogVideoReceiveConfig) {
+  VideoReceiveConfigReadWriteTest test;
+  test.DoTest();
+}
+
+TEST(RtcEventLogTest, LogVideoSendConfig) {
+  VideoSendConfigReadWriteTest 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 b640301..88bc9ba 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
@@ -102,7 +102,7 @@
   return ::testing::AssertionSuccess();
 }
 
-void RtcEventLogTestHelper::VerifyReceiveStreamConfig(
+void RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig(
     const ParsedRtcEventLog& parsed_log,
     size_t index,
     const VideoReceiveStream::Config& config) {
@@ -198,7 +198,7 @@
   }
 }
 
-void RtcEventLogTestHelper::VerifySendStreamConfig(
+void RtcEventLogTestHelper::VerifyVideoSendStreamConfig(
     const ParsedRtcEventLog& parsed_log,
     size_t index,
     const VideoSendStream::Config& config) {
@@ -270,6 +270,82 @@
             parsed_config.encoder_settings.payload_type);
 }
 
+void RtcEventLogTestHelper::VerifyAudioReceiveStreamConfig(
+    const ParsedRtcEventLog& parsed_log,
+    size_t index,
+    const AudioReceiveStream::Config& config) {
+  const rtclog::Event& event = parsed_log.events_[index];
+  ASSERT_TRUE(IsValidBasicEvent(event));
+  ASSERT_EQ(rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT, event.type());
+  const rtclog::AudioReceiveConfig& receiver_config =
+      event.audio_receiver_config();
+  // Check SSRCs.
+  ASSERT_TRUE(receiver_config.has_remote_ssrc());
+  EXPECT_EQ(config.rtp.remote_ssrc, receiver_config.remote_ssrc());
+  ASSERT_TRUE(receiver_config.has_local_ssrc());
+  EXPECT_EQ(config.rtp.local_ssrc, receiver_config.local_ssrc());
+  // Check header extensions.
+  ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
+            receiver_config.header_extensions_size());
+  for (int i = 0; i < receiver_config.header_extensions_size(); i++) {
+    ASSERT_TRUE(receiver_config.header_extensions(i).has_name());
+    ASSERT_TRUE(receiver_config.header_extensions(i).has_id());
+    const std::string& name = receiver_config.header_extensions(i).name();
+    int id = receiver_config.header_extensions(i).id();
+    EXPECT_EQ(config.rtp.extensions[i].id, id);
+    EXPECT_EQ(config.rtp.extensions[i].uri, name);
+  }
+
+  // Check consistency of the parser.
+  AudioReceiveStream::Config parsed_config;
+  parsed_log.GetAudioReceiveConfig(index, &parsed_config);
+  EXPECT_EQ(config.rtp.remote_ssrc, parsed_config.rtp.remote_ssrc);
+  EXPECT_EQ(config.rtp.local_ssrc, parsed_config.rtp.local_ssrc);
+  // Check header extensions.
+  EXPECT_EQ(config.rtp.extensions.size(), parsed_config.rtp.extensions.size());
+  for (size_t i = 0; i < parsed_config.rtp.extensions.size(); i++) {
+    EXPECT_EQ(config.rtp.extensions[i].uri,
+              parsed_config.rtp.extensions[i].uri);
+    EXPECT_EQ(config.rtp.extensions[i].id, parsed_config.rtp.extensions[i].id);
+  }
+}
+
+void RtcEventLogTestHelper::VerifyAudioSendStreamConfig(
+    const ParsedRtcEventLog& parsed_log,
+    size_t index,
+    const AudioSendStream::Config& config) {
+  const rtclog::Event& event = parsed_log.events_[index];
+  ASSERT_TRUE(IsValidBasicEvent(event));
+  ASSERT_EQ(rtclog::Event::AUDIO_SENDER_CONFIG_EVENT, event.type());
+  const rtclog::AudioSendConfig& sender_config = event.audio_sender_config();
+  // Check SSRCs.
+  EXPECT_EQ(config.rtp.ssrc, sender_config.ssrc());
+  // Check header extensions.
+  ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
+            sender_config.header_extensions_size());
+  for (int i = 0; i < sender_config.header_extensions_size(); i++) {
+    ASSERT_TRUE(sender_config.header_extensions(i).has_name());
+    ASSERT_TRUE(sender_config.header_extensions(i).has_id());
+    const std::string& name = sender_config.header_extensions(i).name();
+    int id = sender_config.header_extensions(i).id();
+    EXPECT_EQ(config.rtp.extensions[i].id, id);
+    EXPECT_EQ(config.rtp.extensions[i].uri, name);
+  }
+
+  // Check consistency of the parser.
+  AudioSendStream::Config parsed_config(nullptr);
+  parsed_log.GetAudioSendConfig(index, &parsed_config);
+  // Check SSRCs
+  EXPECT_EQ(config.rtp.ssrc, parsed_config.rtp.ssrc);
+  // Check header extensions.
+  EXPECT_EQ(config.rtp.extensions.size(), parsed_config.rtp.extensions.size());
+  for (size_t i = 0; i < parsed_config.rtp.extensions.size(); i++) {
+    EXPECT_EQ(config.rtp.extensions[i].uri,
+              parsed_config.rtp.extensions[i].uri);
+    EXPECT_EQ(config.rtp.extensions[i].id, parsed_config.rtp.extensions[i].id);
+  }
+}
+
 void RtcEventLogTestHelper::VerifyRtpEvent(const ParsedRtcEventLog& parsed_log,
                                            size_t index,
                                            PacketDirection direction,
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 5ffb6f4..01ade07 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
@@ -18,13 +18,22 @@
 
 class RtcEventLogTestHelper {
  public:
-  static void VerifyReceiveStreamConfig(
+  static void VerifyVideoReceiveStreamConfig(
       const ParsedRtcEventLog& parsed_log,
       size_t index,
       const VideoReceiveStream::Config& config);
-  static void VerifySendStreamConfig(const ParsedRtcEventLog& parsed_log,
-                                     size_t index,
-                                     const VideoSendStream::Config& config);
+  static void VerifyVideoSendStreamConfig(
+      const ParsedRtcEventLog& parsed_log,
+      size_t index,
+      const VideoSendStream::Config& config);
+  static void VerifyAudioReceiveStreamConfig(
+      const ParsedRtcEventLog& parsed_log,
+      size_t index,
+      const AudioReceiveStream::Config& config);
+  static void VerifyAudioSendStreamConfig(
+      const ParsedRtcEventLog& parsed_log,
+      size_t index,
+      const AudioSendStream::Config& config);
   static void VerifyRtpEvent(const ParsedRtcEventLog& parsed_log,
                              size_t index,
                              PacketDirection direction,
diff --git a/webrtc/tools/event_log_visualizer/analyzer.cc b/webrtc/tools/event_log_visualizer/analyzer.cc
index 4ec1a29..cc6425f 100644
--- a/webrtc/tools/event_log_visualizer/analyzer.cc
+++ b/webrtc/tools/event_log_visualizer/analyzer.cc
@@ -353,12 +353,20 @@
       }
       case ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT: {
         AudioReceiveStream::Config config;
-        // TODO(terelius): Parse the audio configs once we have them.
+        parsed_log_.GetAudioReceiveConfig(i, &config);
+        StreamId stream(config.rtp.remote_ssrc, kIncomingPacket);
+        RegisterHeaderExtensions(config.rtp.extensions,
+                                 &extension_maps[stream]);
+        audio_ssrcs_.insert(stream);
         break;
       }
       case ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT: {
         AudioSendStream::Config config(nullptr);
-        // TODO(terelius): Parse the audio configs once we have them.
+        parsed_log_.GetAudioSendConfig(i, &config);
+        StreamId stream(config.rtp.ssrc, kOutgoingPacket);
+        RegisterHeaderExtensions(config.rtp.extensions,
+                                 &extension_maps[stream]);
+        audio_ssrcs_.insert(stream);
         break;
       }
       case ParsedRtcEventLog::RTP_EVENT: {
diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc
index ce9770e..8f196c6 100644
--- a/webrtc/voice_engine/channel.cc
+++ b/webrtc/voice_engine/channel.cc
@@ -94,6 +94,22 @@
     }
   }
 
+  void LogAudioReceiveStreamConfig(
+      const webrtc::AudioReceiveStream::Config& config) override {
+    rtc::CritScope lock(&crit_);
+    if (event_log_) {
+      event_log_->LogAudioReceiveStreamConfig(config);
+    }
+  }
+
+  void LogAudioSendStreamConfig(
+      const webrtc::AudioSendStream::Config& config) override {
+    rtc::CritScope lock(&crit_);
+    if (event_log_) {
+      event_log_->LogAudioSendStreamConfig(config);
+    }
+  }
+
   void LogRtpHeader(webrtc::PacketDirection direction,
                     webrtc::MediaType media_type,
                     const uint8_t* header,