Enables PeerConnectionFactory using external fec controller

Bug: webrtc:8799
Change-Id: Ieb2cf6163b9a83844ab9ed4822b4a7f1db4c24b8
Reviewed-on: https://webrtc-review.googlesource.com/43961
Commit-Queue: Ying Wang <yinwa@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22038}
diff --git a/api/BUILD.gn b/api/BUILD.gn
index d55fd46..91f707d 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -103,6 +103,7 @@
     ":audio_mixer_api",
     ":audio_options_api",
     ":callfactory_api",
+    ":fec_controller_api",
     ":libjingle_logging_api",
     ":optional",
     ":rtc_stats_api",
@@ -263,8 +264,8 @@
   ]
 
   deps = [
-    "../common_video:common_video",
-    "../modules:module_api",
+    "..:webrtc_common",
+    "../modules:module_fec_api",
   ]
 }
 
diff --git a/api/fec_controller.h b/api/fec_controller.h
index aad2316..59e86cc 100644
--- a/api/fec_controller.h
+++ b/api/fec_controller.h
@@ -11,10 +11,11 @@
 #ifndef API_FEC_CONTROLLER_H_
 #define API_FEC_CONTROLLER_H_
 
+#include <memory>
 #include <vector>
 
-#include "common_video/include/video_frame.h"
-#include "modules/include/module_common_types.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/include/module_fec_types.h"
 
 namespace webrtc {
 // TODO(yinwa): work in progress. API in class FecController should not be
@@ -73,11 +74,18 @@
                                   int64_t round_trip_time_ms) = 0;
 
   // Informs of encoded output.
-  virtual void UpdateWithEncodedData(const EncodedImage& encoded_image) = 0;
+  virtual void UpdateWithEncodedData(size_t encoded_image_length,
+                                     FrameType encoded_image_frametype) = 0;
 
   // Returns whether this FEC Controller needs Loss Vector Mask as input.
   virtual bool UseLossVectorMask() = 0;
 };
 
+class FecControllerFactoryInterface {
+ public:
+  virtual std::unique_ptr<FecController> CreateFecController() = 0;
+  virtual ~FecControllerFactoryInterface() = default;
+};
+
 }  // namespace webrtc
 #endif  // API_FEC_CONTROLLER_H_
diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h
index 8b4db9a..80794a8 100644
--- a/api/peerconnectioninterface.h
+++ b/api/peerconnectioninterface.h
@@ -83,6 +83,7 @@
 #include "api/call/callfactoryinterface.h"
 #include "api/datachannelinterface.h"
 #include "api/dtmfsenderinterface.h"
+#include "api/fec_controller.h"
 #include "api/jsep.h"
 #include "api/mediastreaminterface.h"
 #include "api/rtcerror.h"
@@ -1283,6 +1284,27 @@
     rtc::scoped_refptr<AudioMixer> audio_mixer,
     rtc::scoped_refptr<AudioProcessing> audio_processing);
 
+// Create a new instance of PeerConnectionFactoryInterface with optional
+// external audio mixer, audio processing, and fec controller modules.
+//
+// If |audio_mixer| is null, an internal audio mixer will be created and used.
+// If |audio_processing| is null, an internal audio processing module will be
+// created and used.
+// If |fec_controller_factory| is null, an internal fec controller module will
+// be created and used.
+rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
+    rtc::Thread* network_thread,
+    rtc::Thread* worker_thread,
+    rtc::Thread* signaling_thread,
+    AudioDeviceModule* default_adm,
+    rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
+    rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
+    cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
+    cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
+    rtc::scoped_refptr<AudioMixer> audio_mixer,
+    rtc::scoped_refptr<AudioProcessing> audio_processing,
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory);
+
 // Create a new instance of PeerConnectionFactoryInterface with optional video
 // codec factories. These video factories represents all video codecs, i.e. no
 // extra internal video codecs will be added.
@@ -1372,6 +1394,16 @@
     std::unique_ptr<CallFactoryInterface> call_factory,
     std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory);
 
+rtc::scoped_refptr<PeerConnectionFactoryInterface>
+CreateModularPeerConnectionFactory(
+    rtc::Thread* network_thread,
+    rtc::Thread* worker_thread,
+    rtc::Thread* signaling_thread,
+    std::unique_ptr<cricket::MediaEngineInterface> media_engine,
+    std::unique_ptr<CallFactoryInterface> call_factory,
+    std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory,
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory);
+
 }  // namespace webrtc
 
 #endif  // API_PEERCONNECTIONINTERFACE_H_
diff --git a/call/call.cc b/call/call.cc
index e19051d..a14cc0d 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -407,6 +407,9 @@
   return new internal::Call(config, std::move(transport_send));
 }
 
+// This method here to avoid subclasses has to implement this method.
+// Call perf test will use Internal::Call::CreateVideoSendStream() to inject
+// FecController.
 VideoSendStream* Call::CreateVideoSendStream(
     VideoSendStream::Config config,
     VideoEncoderConfig encoder_config,
@@ -723,14 +726,7 @@
   delete audio_receive_stream;
 }
 
-webrtc::VideoSendStream* Call::CreateVideoSendStream(
-    webrtc::VideoSendStream::Config config,
-    VideoEncoderConfig encoder_config) {
-  return CreateVideoSendStream(
-      std::move(config), std::move(encoder_config),
-      rtc::MakeUnique<FecControllerDefault>(Clock::GetRealTimeClock()));
-}
-
+// This method can be used for Call tests with external fec controller factory.
 webrtc::VideoSendStream* Call::CreateVideoSendStream(
     webrtc::VideoSendStream::Config config,
     VideoEncoderConfig encoder_config,
@@ -749,6 +745,7 @@
   // the call has already started.
   // Copy ssrcs from |config| since |config| is moved.
   std::vector<uint32_t> ssrcs = config.rtp.ssrcs;
+
   VideoSendStream* send_stream = new VideoSendStream(
       num_cpu_cores_, module_process_thread_.get(), &worker_queue_,
       call_stats_.get(), transport_send_.get(), bitrate_allocator_.get(),
@@ -770,6 +767,17 @@
   return send_stream;
 }
 
+webrtc::VideoSendStream* Call::CreateVideoSendStream(
+    webrtc::VideoSendStream::Config config,
+    VideoEncoderConfig encoder_config) {
+  std::unique_ptr<FecController> fec_controller =
+      config_.fec_controller_factory
+          ? config_.fec_controller_factory->CreateFecController()
+          : rtc::MakeUnique<FecControllerDefault>(Clock::GetRealTimeClock());
+  return CreateVideoSendStream(std::move(config), std::move(encoder_config),
+                               std::move(fec_controller));
+}
+
 void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
   TRACE_EVENT0("webrtc", "Call::DestroyVideoSendStream");
   RTC_DCHECK(send_stream != nullptr);
diff --git a/call/call.h b/call/call.h
index 884a21b..1155aaf 100644
--- a/call/call.h
+++ b/call/call.h
@@ -109,6 +109,9 @@
   // RtcEventLog to use for this call. Required.
   // Use webrtc::RtcEventLog::CreateNull() for a null implementation.
   RtcEventLog* event_log = nullptr;
+
+  // FecController to use for this call.
+  FecControllerFactoryInterface* fec_controller_factory = nullptr;
 };
 
 // A Call instance can contain several send and/or receive streams. All streams
diff --git a/modules/BUILD.gn b/modules/BUILD.gn
index a45fd348..067710c 100644
--- a/modules/BUILD.gn
+++ b/modules/BUILD.gn
@@ -49,6 +49,7 @@
   ]
   deps = [
     ":module_api_public",
+    ":module_fec_api",
     "..:webrtc_common",
     "../:typedefs",
     "../api:audio_frame_api",
@@ -62,6 +63,13 @@
   ]
 }
 
+rtc_source_set("module_fec_api") {
+  visibility = [ "*" ]
+  sources = [
+    "include/module_fec_types.h",
+  ]
+}
+
 if (rtc_include_tests) {
   modules_tests_resources = [
     "../resources/audio_coding/testfile32kHz.pcm",
diff --git a/modules/include/module_common_types.h b/modules/include/module_common_types.h
index 0842370..1290075 100644
--- a/modules/include/module_common_types.h
+++ b/modules/include/module_common_types.h
@@ -25,6 +25,7 @@
 #include "api/video/video_rotation.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "modules/include/module_common_types_public.h"
+#include "modules/include/module_fec_types.h"
 #include "modules/video_coding/codecs/h264/include/h264_globals.h"
 #include "modules/video_coding/codecs/vp8/include/vp8_globals.h"
 #include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
@@ -265,22 +266,6 @@
   uint16_t JBabsMax;
 };
 
-// Types for the FEC packet masks. The type |kFecMaskRandom| is based on a
-// random loss model. The type |kFecMaskBursty| is based on a bursty/consecutive
-// loss model. The packet masks are defined in
-// modules/rtp_rtcp/fec_private_tables_random(bursty).h
-enum FecMaskType {
-  kFecMaskRandom,
-  kFecMaskBursty,
-};
-
-// Struct containing forward error correction settings.
-struct FecProtectionParams {
-  int fec_rate;
-  int max_fec_frames;
-  FecMaskType fec_mask_type;
-};
-
 // Interface used by the CallStats class to distribute call statistics.
 // Callbacks will be triggered as soon as the class has been registered to a
 // CallStats object using RegisterStatsObserver.
diff --git a/modules/include/module_fec_types.h b/modules/include/module_fec_types.h
new file mode 100644
index 0000000..25d6bc5
--- /dev/null
+++ b/modules/include/module_fec_types.h
@@ -0,0 +1,34 @@
+/*
+ *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_INCLUDE_MODULE_FEC_TYPES_H_
+#define MODULES_INCLUDE_MODULE_FEC_TYPES_H_
+
+namespace webrtc {
+
+// Types for the FEC packet masks. The type |kFecMaskRandom| is based on a
+// random loss model. The type |kFecMaskBursty| is based on a bursty/consecutive
+// loss model. The packet masks are defined in
+// modules/rtp_rtcp/fec_private_tables_random(bursty).h
+enum FecMaskType {
+  kFecMaskRandom,
+  kFecMaskBursty,
+};
+
+// Struct containing forward error correction settings.
+struct FecProtectionParams {
+  int fec_rate;
+  int max_fec_frames;
+  FecMaskType fec_mask_type;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_INCLUDE_MODULE_FEC_TYPES_H_
diff --git a/modules/video_coding/fec_controller_default.cc b/modules/video_coding/fec_controller_default.cc
index 9d26aac..84e8a7b 100644
--- a/modules/video_coding/fec_controller_default.cc
+++ b/modules/video_coding/fec_controller_default.cc
@@ -145,11 +145,12 @@
   loss_prot_logic_->SetMethod(method);
 }
 void FecControllerDefault::UpdateWithEncodedData(
-    const EncodedImage& encoded_image) {
-  const size_t encoded_length = encoded_image._length;
+    const size_t encoded_image_length,
+    const FrameType encoded_image_frametype) {
+  const size_t encoded_length = encoded_image_length;
   CritScope lock(&crit_sect_);
   if (encoded_length > 0) {
-    const bool delta_frame = encoded_image._frameType != kVideoFrameKey;
+    const bool delta_frame = encoded_image_frametype != kVideoFrameKey;
     if (max_payload_size_ > 0 && encoded_length > 0) {
       const float min_packets_per_frame =
           encoded_length / static_cast<float>(max_payload_size_);
diff --git a/modules/video_coding/fec_controller_default.h b/modules/video_coding/fec_controller_default.h
index a7f445f..776977a 100644
--- a/modules/video_coding/fec_controller_default.h
+++ b/modules/video_coding/fec_controller_default.h
@@ -39,7 +39,8 @@
                           uint8_t fraction_lost,
                           std::vector<bool> loss_mask_vector,
                           int64_t round_trip_time_ms) override;
-  void UpdateWithEncodedData(const EncodedImage& encoded_image) override;
+  void UpdateWithEncodedData(const size_t encoded_image_length,
+                             const FrameType encoded_image_frametype) override;
   bool UseLossVectorMask() override { return false; }
 
  private:
diff --git a/modules/video_coding/generic_encoder.cc b/modules/video_coding/generic_encoder.cc
index bb5f75e..d1816e0 100644
--- a/modules/video_coding/generic_encoder.cc
+++ b/modules/video_coding/generic_encoder.cc
@@ -412,7 +412,8 @@
     return result;
 
   if (media_opt_) {
-    media_opt_->UpdateWithEncodedData(image_copy);
+    media_opt_->UpdateWithEncodedData(image_copy._length,
+                                      image_copy._frameType);
     if (internal_source_) {
       // Signal to encoder to drop next frame.
       result.drop_next_frame = media_opt_->DropFrame();
diff --git a/modules/video_coding/media_optimization.cc b/modules/video_coding/media_optimization.cc
index 51c5bcb..ea70f3f 100644
--- a/modules/video_coding/media_optimization.cc
+++ b/modules/video_coding/media_optimization.cc
@@ -90,11 +90,12 @@
 }
 
 void MediaOptimization::UpdateWithEncodedData(
-    const EncodedImage& encoded_image) {
-  size_t encoded_length = encoded_image._length;
+    const size_t encoded_image_length,
+    const FrameType encoded_image_frametype) {
+  size_t encoded_length = encoded_image_length;
   rtc::CritScope lock(&crit_sect_);
   if (encoded_length > 0) {
-    const bool delta_frame = encoded_image._frameType != kVideoFrameKey;
+    const bool delta_frame = encoded_image_frametype != kVideoFrameKey;
     frame_dropper_->Fill(encoded_length, delta_frame);
   }
 }
diff --git a/modules/video_coding/media_optimization.h b/modules/video_coding/media_optimization.h
index 5fa0254..411f86c 100644
--- a/modules/video_coding/media_optimization.h
+++ b/modules/video_coding/media_optimization.h
@@ -51,7 +51,8 @@
   // Informs Media Optimization of encoded output.
   // TODO(perkj): Deprecate SetEncodingData once its not used for stats in
   // VideoStreamEncoder.
-  void UpdateWithEncodedData(const EncodedImage& encoded_image);
+  void UpdateWithEncodedData(const size_t encoded_image_length,
+                             const FrameType encoded_image_frametype);
 
   // InputFrameRate 0 = no frame rate estimate available.
   uint32_t InputFrameRate();
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index cf506bf..706fec0 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -180,6 +180,7 @@
     ":rtc_pc_base",
     "..:webrtc_common",
     "../api:call_api",
+    "../api:fec_controller_api",
     "../api:libjingle_peerconnection_api",
     "../api:optional",
     "../api:rtc_stats_api",
diff --git a/pc/createpeerconnectionfactory.cc b/pc/createpeerconnectionfactory.cc
index 197df8a..11650ec 100644
--- a/pc/createpeerconnectionfactory.cc
+++ b/pc/createpeerconnectionfactory.cc
@@ -73,6 +73,40 @@
     rtc::Thread* network_thread,
     rtc::Thread* worker_thread,
     rtc::Thread* signaling_thread,
+    AudioDeviceModule* default_adm,
+    rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
+    rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
+    cricket::WebRtcVideoEncoderFactory* video_encoder_factory,
+    cricket::WebRtcVideoDecoderFactory* video_decoder_factory,
+    rtc::scoped_refptr<AudioMixer> audio_mixer,
+    rtc::scoped_refptr<AudioProcessing> audio_processing,
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory) {
+  rtc::scoped_refptr<AudioProcessing> audio_processing_use = audio_processing;
+  if (!audio_processing_use) {
+    audio_processing_use = AudioProcessingBuilder().Create();
+  }
+
+  std::unique_ptr<cricket::MediaEngineInterface> media_engine(
+      cricket::WebRtcMediaEngineFactory::Create(
+          default_adm, audio_encoder_factory, audio_decoder_factory,
+          video_encoder_factory, video_decoder_factory, audio_mixer,
+          audio_processing_use));
+
+  std::unique_ptr<CallFactoryInterface> call_factory = CreateCallFactory();
+
+  std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory =
+      CreateRtcEventLogFactory();
+
+  return CreateModularPeerConnectionFactory(
+      network_thread, worker_thread, signaling_thread, std::move(media_engine),
+      std::move(call_factory), std::move(event_log_factory),
+      std::move(fec_controller_factory));
+}
+
+rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
+    rtc::Thread* network_thread,
+    rtc::Thread* worker_thread,
+    rtc::Thread* signaling_thread,
     rtc::scoped_refptr<AudioDeviceModule> default_adm,
     rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory,
     rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory,
diff --git a/pc/peerconnectionfactory.cc b/pc/peerconnectionfactory.cc
index af8f541..a6b889b 100644
--- a/pc/peerconnectionfactory.cc
+++ b/pc/peerconnectionfactory.cc
@@ -12,6 +12,7 @@
 
 #include <utility>
 
+#include "api/fec_controller.h"
 #include "api/mediaconstraintsinterface.h"
 #include "api/mediastreamproxy.h"
 #include "api/mediastreamtrackproxy.h"
@@ -52,11 +53,25 @@
     std::unique_ptr<cricket::MediaEngineInterface> media_engine,
     std::unique_ptr<CallFactoryInterface> call_factory,
     std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory) {
+  return CreateModularPeerConnectionFactory(
+      network_thread, worker_thread, signaling_thread, std::move(media_engine),
+      std::move(call_factory), std::move(event_log_factory), nullptr);
+}
+
+rtc::scoped_refptr<PeerConnectionFactoryInterface>
+CreateModularPeerConnectionFactory(
+    rtc::Thread* network_thread,
+    rtc::Thread* worker_thread,
+    rtc::Thread* signaling_thread,
+    std::unique_ptr<cricket::MediaEngineInterface> media_engine,
+    std::unique_ptr<CallFactoryInterface> call_factory,
+    std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory,
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory) {
   rtc::scoped_refptr<PeerConnectionFactory> pc_factory(
       new rtc::RefCountedObject<PeerConnectionFactory>(
           network_thread, worker_thread, signaling_thread,
           std::move(media_engine), std::move(call_factory),
-          std::move(event_log_factory)));
+          std::move(event_log_factory), std::move(fec_controller_factory)));
 
   // Call Initialize synchronously but make sure it is executed on
   // |signaling_thread|.
@@ -78,13 +93,30 @@
     std::unique_ptr<cricket::MediaEngineInterface> media_engine,
     std::unique_ptr<webrtc::CallFactoryInterface> call_factory,
     std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory)
+    : PeerConnectionFactory(network_thread,
+                            worker_thread,
+                            signaling_thread,
+                            std::move(media_engine),
+                            std::move(call_factory),
+                            std::move(event_log_factory),
+                            nullptr) {}
+
+PeerConnectionFactory::PeerConnectionFactory(
+    rtc::Thread* network_thread,
+    rtc::Thread* worker_thread,
+    rtc::Thread* signaling_thread,
+    std::unique_ptr<cricket::MediaEngineInterface> media_engine,
+    std::unique_ptr<webrtc::CallFactoryInterface> call_factory,
+    std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory,
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory)
     : wraps_current_thread_(false),
       network_thread_(network_thread),
       worker_thread_(worker_thread),
       signaling_thread_(signaling_thread),
       media_engine_(std::move(media_engine)),
       call_factory_(std::move(call_factory)),
-      event_log_factory_(std::move(event_log_factory)) {
+      event_log_factory_(std::move(event_log_factory)),
+      fec_controller_factory_(std::move(fec_controller_factory)) {
   if (!network_thread_) {
     owned_network_thread_ = rtc::Thread::CreateWithSocketServer();
     owned_network_thread_->SetName("pc_network_thread", nullptr);
@@ -355,6 +387,8 @@
   call_config.bitrate_config.start_bitrate_bps = kStartBandwidthBps;
   call_config.bitrate_config.max_bitrate_bps = kMaxBandwidthBps;
 
+  call_config.fec_controller_factory = fec_controller_factory_.get();
+
   return std::unique_ptr<Call>(call_factory_->CreateCall(call_config));
 }
 
diff --git a/pc/peerconnectionfactory.h b/pc/peerconnectionfactory.h
index 652f76a..60facec 100644
--- a/pc/peerconnectionfactory.h
+++ b/pc/peerconnectionfactory.h
@@ -109,6 +109,14 @@
       std::unique_ptr<cricket::MediaEngineInterface> media_engine,
       std::unique_ptr<webrtc::CallFactoryInterface> call_factory,
       std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory);
+  PeerConnectionFactory(
+      rtc::Thread* network_thread,
+      rtc::Thread* worker_thread,
+      rtc::Thread* signaling_thread,
+      std::unique_ptr<cricket::MediaEngineInterface> media_engine,
+      std::unique_ptr<webrtc::CallFactoryInterface> call_factory,
+      std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory,
+      std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory);
   virtual ~PeerConnectionFactory();
 
  private:
@@ -128,6 +136,7 @@
   std::unique_ptr<cricket::MediaEngineInterface> media_engine_;
   std::unique_ptr<webrtc::CallFactoryInterface> call_factory_;
   std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory_;
+  std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory_;
 };
 
 }  // namespace webrtc
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index 18d9987..935cd72 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -641,6 +641,7 @@
     "api/org/webrtc/EglBase.java",
     "api/org/webrtc/EglRenderer.java",
     "api/org/webrtc/EncodedImage.java",
+    "api/org/webrtc/FecControllerFactoryFactoryInterface.java",
     "api/org/webrtc/FileVideoCapturer.java",
     "api/org/webrtc/GlRectDrawer.java",
     "api/org/webrtc/GlShader.java",
diff --git a/sdk/android/api/org/webrtc/FecControllerFactoryFactoryInterface.java b/sdk/android/api/org/webrtc/FecControllerFactoryFactoryInterface.java
new file mode 100644
index 0000000..6d39390
--- /dev/null
+++ b/sdk/android/api/org/webrtc/FecControllerFactoryFactoryInterface.java
@@ -0,0 +1,22 @@
+/*
+ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+package org.webrtc;
+
+/**
+ * Factory for creating webrtc::FecControllerFactory instances.
+ */
+public interface FecControllerFactoryFactoryInterface {
+  /**
+   * Dynamically allocates a webrtc::FecControllerFactory instance and returns a pointer to it.
+   * The caller takes ownership of the object.
+   */
+  public long createNative();
+}
diff --git a/sdk/android/api/org/webrtc/PeerConnectionFactory.java b/sdk/android/api/org/webrtc/PeerConnectionFactory.java
index 79eca7e..b38a8fb 100644
--- a/sdk/android/api/org/webrtc/PeerConnectionFactory.java
+++ b/sdk/android/api/org/webrtc/PeerConnectionFactory.java
@@ -124,6 +124,55 @@
     }
   }
 
+  public static class Builder {
+    private Options options;
+    private VideoEncoderFactory encoderFactory;
+    private VideoDecoderFactory decoderFactory;
+    private AudioProcessingFactory audioProcessingFactory;
+    private FecControllerFactoryFactoryInterface fecControllerFactoryFactory;
+
+    private Builder() {}
+
+    public Builder setOptions(Options options) {
+      this.options = options;
+      return this;
+    }
+
+    public Builder setVideoEncoderFactory(VideoEncoderFactory encoderFactory) {
+      this.encoderFactory = encoderFactory;
+      return this;
+    }
+
+    public Builder setVideoDecoderFactory(VideoDecoderFactory decoderFactory) {
+      this.decoderFactory = decoderFactory;
+      return this;
+    }
+
+    public Builder setAudioProcessingFactory(AudioProcessingFactory audioProcessingFactory) {
+      if (audioProcessingFactory == null) {
+        throw new NullPointerException(
+            "PeerConnectionFactory builder does not accept a null AudioProcessingFactory.");
+      }
+      this.audioProcessingFactory = audioProcessingFactory;
+      return this;
+    }
+
+    public Builder setFecControllerFactoryFactoryInterface(
+        FecControllerFactoryFactoryInterface fecControllerFactoryFactory) {
+      this.fecControllerFactoryFactory = fecControllerFactoryFactory;
+      return this;
+    }
+
+    public PeerConnectionFactory createPeerConnectionFactory() {
+      return new PeerConnectionFactory(options, encoderFactory, decoderFactory,
+          audioProcessingFactory, fecControllerFactoryFactory);
+    }
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
   /**
    * Loads and initializes WebRTC. This must be called at least once before creating a
    * PeerConnectionFactory. Replaces all the old initialization methods. Must not be called while
@@ -191,28 +240,32 @@
 
   // Note: initializeAndroidGlobals must be called at least once before
   // constructing a PeerConnectionFactory.
+  @Deprecated
   public PeerConnectionFactory(Options options) {
     this(options, null /* encoderFactory */, null /* decoderFactory */);
   }
 
+  @Deprecated
   public PeerConnectionFactory(
       Options options, VideoEncoderFactory encoderFactory, VideoDecoderFactory decoderFactory) {
-    checkInitializeHasBeenCalled();
-    nativeFactory = nativeCreatePeerConnectionFactory(options, encoderFactory, decoderFactory);
-    if (nativeFactory == 0) {
-      throw new RuntimeException("Failed to initialize PeerConnectionFactory!");
-    }
+    this(options, encoderFactory, decoderFactory, null /* audioProcessingFactory */,
+        null /* fecControllerFactoryFactory */);
   }
 
+  @Deprecated
   public PeerConnectionFactory(Options options, VideoEncoderFactory encoderFactory,
       VideoDecoderFactory decoderFactory, AudioProcessingFactory audioProcessingFactory) {
+    this(options, encoderFactory, decoderFactory, audioProcessingFactory,
+        null /* fecControllerFactoryFactory */);
+  }
+
+  private PeerConnectionFactory(Options options, VideoEncoderFactory encoderFactory,
+      VideoDecoderFactory decoderFactory, AudioProcessingFactory audioProcessingFactory,
+      FecControllerFactoryFactoryInterface fecControllerFactoryFactory) {
     checkInitializeHasBeenCalled();
-    if (audioProcessingFactory == null) {
-      throw new NullPointerException(
-          "PeerConnectionFactory constructor does not accept a null AudioProcessingFactory.");
-    }
-    nativeFactory = nativeCreatePeerConnectionFactoryWithAudioProcessing(
-        options, encoderFactory, decoderFactory, audioProcessingFactory.createNative());
+    nativeFactory = nativeCreatePeerConnectionFactory(options, encoderFactory, decoderFactory,
+        audioProcessingFactory == null ? 0 : audioProcessingFactory.createNative(),
+        fecControllerFactoryFactory == null ? 0 : fecControllerFactoryFactory.createNative());
     if (nativeFactory == 0) {
       throw new RuntimeException("Failed to initialize PeerConnectionFactory!");
     }
@@ -405,11 +458,9 @@
   private static native void nativeShutdownInternalTracer();
   private static native boolean nativeStartInternalTracingCapture(String tracingFilename);
   private static native void nativeStopInternalTracingCapture();
-  private static native long nativeCreatePeerConnectionFactory(
-      Options options, VideoEncoderFactory encoderFactory, VideoDecoderFactory decoderFactory);
-  private static native long nativeCreatePeerConnectionFactoryWithAudioProcessing(Options options,
+  private static native long nativeCreatePeerConnectionFactory(Options options,
       VideoEncoderFactory encoderFactory, VideoDecoderFactory decoderFactory,
-      long nativeAudioProcessor);
+      long nativeAudioProcessor, long nativeFecControllerFactory);
   private static native long nativeCreatePeerConnection(long factory,
       PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, long nativeObserver);
   private static native long nativeCreateLocalMediaStream(long factory, String label);
diff --git a/sdk/android/src/jni/pc/peerconnectionfactory.cc b/sdk/android/src/jni/pc/peerconnectionfactory.cc
index 1a7008a..b251a17 100644
--- a/sdk/android/src/jni/pc/peerconnectionfactory.cc
+++ b/sdk/android/src/jni/pc/peerconnectionfactory.cc
@@ -172,7 +172,8 @@
     const JavaParamRef<jobject>& joptions,
     const JavaParamRef<jobject>& jencoder_factory,
     const JavaParamRef<jobject>& jdecoder_factory,
-    rtc::scoped_refptr<AudioProcessing> audio_processor) {
+    rtc::scoped_refptr<AudioProcessing> audio_processor,
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory) {
   // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
   // ThreadManager only WrapCurrentThread()s the thread where it is first
   // created.  Since the semantics around when auto-wrapping happens in
@@ -269,7 +270,7 @@
       CreateModularPeerConnectionFactory(
           network_thread.get(), worker_thread.get(), signaling_thread.get(),
           std::move(media_engine), std::move(call_factory),
-          std::move(rtc_event_log_factory)));
+          std::move(rtc_event_log_factory), std::move(fec_controller_factory)));
   RTC_CHECK(factory) << "Failed to create the peer connection factory; "
                      << "WebRTC/libjingle init likely failed on this device";
   // TODO(honghaiz): Maybe put the options as the argument of
@@ -290,25 +291,18 @@
     const JavaParamRef<jclass>&,
     const JavaParamRef<jobject>& joptions,
     const JavaParamRef<jobject>& jencoder_factory,
-    const JavaParamRef<jobject>& jdecoder_factory) {
-  return CreatePeerConnectionFactoryForJava(jni, joptions, jencoder_factory,
-                                            jdecoder_factory,
-                                            CreateAudioProcessing());
-}
-
-static jlong
-JNI_PeerConnectionFactory_CreatePeerConnectionFactoryWithAudioProcessing(
-    JNIEnv* jni,
-    const JavaParamRef<jclass>&,
-    const JavaParamRef<jobject>& joptions,
-    const JavaParamRef<jobject>& jencoder_factory,
     const JavaParamRef<jobject>& jdecoder_factory,
-    jlong native_audio_processor) {
+    jlong native_audio_processor,
+    jlong native_fec_controller_factory) {
   rtc::scoped_refptr<AudioProcessing> audio_processor =
       reinterpret_cast<AudioProcessing*>(native_audio_processor);
-  RTC_DCHECK(audio_processor);
-  return CreatePeerConnectionFactoryForJava(jni, joptions, jencoder_factory,
-                                            jdecoder_factory, audio_processor);
+  std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory(
+      reinterpret_cast<FecControllerFactoryInterface*>(
+          native_fec_controller_factory));
+  return CreatePeerConnectionFactoryForJava(
+      jni, joptions, jencoder_factory, jdecoder_factory,
+      audio_processor ? audio_processor : CreateAudioProcessing(),
+      std::move(fec_controller_factory));
 }
 
 static void JNI_PeerConnectionFactory_FreeFactory(JNIEnv*,
diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc
index ef853a5..f913402 100644
--- a/video/video_quality_test.cc
+++ b/video/video_quality_test.cc
@@ -1087,9 +1087,9 @@
 }
 
 VideoQualityTest::VideoQualityTest(
-    std::unique_ptr<FecController> fec_controller)
+    std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory)
     : VideoQualityTest() {
-  fec_controller_ = std::move(fec_controller);
+  fec_controller_factory_ = std::move(fec_controller_factory);
 }
 
 VideoQualityTest::Params::Params()
@@ -1829,14 +1829,14 @@
   RTC_DCHECK_EQ(video_send_configs_.size(), num_video_streams_);
   // We currently only support testing external fec controllers with a single
   // VideoSendStream.
-  if (fec_controller_.get()) {
+  if (fec_controller_factory_.get()) {
     RTC_DCHECK_LE(video_send_configs_.size(), 1);
   }
   for (size_t i = 0; i < video_send_configs_.size(); ++i) {
-    if (fec_controller_.get()) {
+    if (fec_controller_factory_.get()) {
       video_send_streams_.push_back(sender_call_->CreateVideoSendStream(
           video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy(),
-          std::move(fec_controller_)));
+          fec_controller_factory_->CreateFecController()));
     } else {
       video_send_streams_.push_back(sender_call_->CreateVideoSendStream(
           video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy()));
@@ -1850,24 +1850,6 @@
   AssociateFlexfecStreamsWithVideoStreams();
 }
 
-void VideoQualityTest::CreateVideoStreamsWithProtectionBitrateCalculator(
-    std::unique_ptr<FecController> fec_controller) {
-  RTC_DCHECK(video_send_streams_.empty());
-  RTC_DCHECK(video_receive_streams_.empty());
-  RTC_DCHECK_EQ(video_send_configs_.size(), num_video_streams_);
-  for (size_t i = 0; i < video_send_configs_.size(); ++i) {
-    video_send_streams_.push_back(sender_call_->CreateVideoSendStream(
-        video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy(),
-        std::move(fec_controller)));
-  }
-  for (size_t i = 0; i < video_receive_configs_.size(); ++i) {
-    video_receive_streams_.push_back(receiver_call_->CreateVideoReceiveStream(
-        video_receive_configs_[i].Copy()));
-  }
-
-  AssociateFlexfecStreamsWithVideoStreams();
-}
-
 void VideoQualityTest::DestroyStreams() {
   CallTest::DestroyStreams();
 
diff --git a/video/video_quality_test.h b/video/video_quality_test.h
index f1b44fe..da79894 100644
--- a/video/video_quality_test.h
+++ b/video/video_quality_test.h
@@ -96,7 +96,8 @@
   };
 
   VideoQualityTest();
-  explicit VideoQualityTest(std::unique_ptr<FecController> fec_controller);
+  explicit VideoQualityTest(
+      std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory);
   void RunWithAnalyzer(const Params& params);
   void RunWithRenderers(const Params& params);
 
@@ -112,7 +113,7 @@
 
  protected:
   std::map<uint8_t, webrtc::MediaType> payload_type_map_;
-  std::unique_ptr<FecController> fec_controller_;
+  std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory_;
 
   // No-op implementation to be able to instantiate this class from non-TEST_F
   // locations.
@@ -129,8 +130,6 @@
 
   // Helper methods for setting up the call.
   void CreateVideoStreams();
-  void CreateVideoStreamsWithProtectionBitrateCalculator(
-      std::unique_ptr<FecController> fec_controller);
   void DestroyStreams();
   void CreateCapturers();
   std::unique_ptr<test::FrameGenerator> CreateFrameGenerator(size_t video_idx);
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index 3d59bc2..d00e749 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -1120,7 +1120,8 @@
       check_encoder_activity_task_->UpdateEncoderActivity();
   }
 
-  fec_controller_->UpdateWithEncodedData(encoded_image);
+  fec_controller_->UpdateWithEncodedData(encoded_image._length,
+                                         encoded_image._frameType);
   EncodedImageCallback::Result result = payload_router_.OnEncodedImage(
       encoded_image, codec_specific_info, fragmentation);