Make it possible to inject a custom NetEqFactory from the java interface.

Bug: webrtc:11005
Change-Id: I18b17847a6e066335f96ca1b718af2388805f8fb
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/160183
Commit-Queue: Ivo Creusen <ivoc@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29900}
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index 1e49597..8d2e183 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -285,6 +285,7 @@
       "api/org/webrtc/MediaStreamTrack.java",
       "api/org/webrtc/NativeLibraryLoader.java",
       "api/org/webrtc/NativePeerConnectionFactory.java",
+      "api/org/webrtc/NetEqFactoryFactory.java",
       "api/org/webrtc/NetworkMonitor.java",  # TODO(sakal): Break dependencies and move to base_java.
       "api/org/webrtc/NetworkMonitorAutoDetect.java",  # TODO(sakal): Break dependencies and move to base_java.
       "api/org/webrtc/PeerConnection.java",
diff --git a/sdk/android/api/org/webrtc/NetEqFactoryFactory.java b/sdk/android/api/org/webrtc/NetEqFactoryFactory.java
new file mode 100644
index 0000000..8464324
--- /dev/null
+++ b/sdk/android/api/org/webrtc/NetEqFactoryFactory.java
@@ -0,0 +1,21 @@
+/*
+ *  Copyright 2019 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;
+
+/**
+ * Implementations of this interface can create a native {@code webrtc::NetEqFactory}.
+ */
+public interface NetEqFactoryFactory {
+  /**
+   * Returns a pointer to a {@code webrtc::NetEqFactory}. The caller takes ownership.
+   */
+  long createNativeNetEqFactory();
+}
diff --git a/sdk/android/api/org/webrtc/PeerConnectionFactory.java b/sdk/android/api/org/webrtc/PeerConnectionFactory.java
index d48ef55..a2acfdd 100644
--- a/sdk/android/api/org/webrtc/PeerConnectionFactory.java
+++ b/sdk/android/api/org/webrtc/PeerConnectionFactory.java
@@ -167,6 +167,7 @@
     @Nullable private AudioDeviceModule audioDeviceModule;
     private AudioEncoderFactoryFactory audioEncoderFactoryFactory =
         new BuiltinAudioEncoderFactoryFactory();
+    @Nullable
     private AudioDecoderFactoryFactory audioDecoderFactoryFactory =
         new BuiltinAudioDecoderFactoryFactory();
     @Nullable private VideoEncoderFactory videoEncoderFactory;
@@ -176,6 +177,7 @@
     @Nullable private NetworkControllerFactoryFactory networkControllerFactoryFactory;
     @Nullable private NetworkStatePredictorFactoryFactory networkStatePredictorFactoryFactory;
     @Nullable private MediaTransportFactoryFactory mediaTransportFactoryFactory;
+    @Nullable private NetEqFactoryFactory neteqFactoryFactory;
 
     private Builder() {}
 
@@ -199,6 +201,7 @@
       return this;
     }
 
+    @Deprecated
     public Builder setAudioDecoderFactoryFactory(
         AudioDecoderFactoryFactory audioDecoderFactoryFactory) {
       if (audioDecoderFactoryFactory == null) {
@@ -253,17 +256,36 @@
       return this;
     }
 
+    /**
+     * Sets a NetEqFactoryFactory for the PeerConnectionFactory. When using a
+     * custom NetEqFactoryFactory, the AudioDecoderFactoryFactory will be set
+     * to null. The AudioDecoderFactoryFactory should be wrapped in the
+     * NetEqFactoryFactory.
+     */
+    public Builder setNetEqFactoryFactory(NetEqFactoryFactory neteqFactoryFactory) {
+      this.audioDecoderFactoryFactory = null;
+      this.neteqFactoryFactory = neteqFactoryFactory;
+      return this;
+    }
+
     public PeerConnectionFactory createPeerConnectionFactory() {
       checkInitializeHasBeenCalled();
       if (audioDeviceModule == null) {
         audioDeviceModule = JavaAudioDeviceModule.builder(ContextUtils.getApplicationContext())
                                 .createAudioDeviceModule();
       }
+      if (neteqFactoryFactory == null && audioDecoderFactoryFactory == null) {
+        throw new IllegalStateException(
+            "Setting both audioDecoderFactoryFactory and neteqFactoryFactory "
+            + "to null is not allowed.");
+      }
       return nativeCreatePeerConnectionFactory(ContextUtils.getApplicationContext(), options,
           audioDeviceModule.getNativeAudioDeviceModulePointer(),
           audioEncoderFactoryFactory.createNativeAudioEncoderFactory(),
-          audioDecoderFactoryFactory.createNativeAudioDecoderFactory(), videoEncoderFactory,
-          videoDecoderFactory,
+          audioDecoderFactoryFactory == null
+              ? 0
+              : audioDecoderFactoryFactory.createNativeAudioDecoderFactory(),
+          videoEncoderFactory, videoDecoderFactory,
           audioProcessingFactory == null ? 0 : audioProcessingFactory.createNative(),
           fecControllerFactoryFactory == null ? 0 : fecControllerFactoryFactory.createNative(),
           networkControllerFactoryFactory == null
@@ -274,7 +296,8 @@
               : networkStatePredictorFactoryFactory.createNativeNetworkStatePredictorFactory(),
           mediaTransportFactoryFactory == null
               ? 0
-              : mediaTransportFactoryFactory.createNativeMediaTransportFactory());
+              : mediaTransportFactoryFactory.createNativeMediaTransportFactory(),
+          neteqFactoryFactory == null ? 0 : neteqFactoryFactory.createNativeNetEqFactory());
     }
   }
 
@@ -596,7 +619,7 @@
       long audioDecoderFactory, VideoEncoderFactory encoderFactory,
       VideoDecoderFactory decoderFactory, long nativeAudioProcessor,
       long nativeFecControllerFactory, long nativeNetworkControllerFactory,
-      long nativeNetworkStatePredictorFactory, long mediaTransportFactory);
+      long nativeNetworkStatePredictorFactory, long mediaTransportFactory, long neteqFactory);
 
   private static native long nativeCreatePeerConnection(long factory,
       PeerConnection.RTCConfiguration rtcConfig, MediaConstraints constraints, long nativeObserver,
diff --git a/sdk/android/src/jni/pc/peer_connection_factory.cc b/sdk/android/src/jni/pc/peer_connection_factory.cc
index 4ae6faf..2a7569b 100644
--- a/sdk/android/src/jni/pc/peer_connection_factory.cc
+++ b/sdk/android/src/jni/pc/peer_connection_factory.cc
@@ -247,7 +247,7 @@
 // Following parameters are optional:
 // |audio_device_module|, |jencoder_factory|, |jdecoder_factory|,
 // |audio_processor|, |media_transport_factory|, |fec_controller_factory|,
-// |network_state_predictor_factory|.
+// |network_state_predictor_factory|, |neteq_factory|.
 ScopedJavaLocalRef<jobject> CreatePeerConnectionFactoryForJava(
     JNIEnv* jni,
     const JavaParamRef<jobject>& jcontext,
@@ -263,7 +263,8 @@
         network_controller_factory,
     std::unique_ptr<NetworkStatePredictorFactoryInterface>
         network_state_predictor_factory,
-    std::unique_ptr<MediaTransportFactory> media_transport_factory) {
+    std::unique_ptr<MediaTransportFactory> media_transport_factory,
+    std::unique_ptr<NetEqFactory> neteq_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
@@ -310,6 +311,7 @@
   dependencies.network_state_predictor_factory =
       std::move(network_state_predictor_factory);
   dependencies.media_transport_factory = std::move(media_transport_factory);
+  dependencies.neteq_factory = std::move(neteq_factory);
 
   cricket::MediaEngineDependencies media_dependencies;
   media_dependencies.task_queue_factory = dependencies.task_queue_factory.get();
@@ -353,7 +355,8 @@
     jlong native_fec_controller_factory,
     jlong native_network_controller_factory,
     jlong native_network_state_predictor_factory,
-    jlong native_media_transport_factory) {
+    jlong native_media_transport_factory,
+    jlong native_neteq_factory) {
   rtc::scoped_refptr<AudioProcessing> audio_processor =
       reinterpret_cast<AudioProcessing*>(native_audio_processor);
   return CreatePeerConnectionFactoryForJava(
@@ -370,7 +373,8 @@
       TakeOwnershipOfUniquePtr<NetworkStatePredictorFactoryInterface>(
           native_network_state_predictor_factory),
       TakeOwnershipOfUniquePtr<MediaTransportFactory>(
-          native_media_transport_factory));
+          native_media_transport_factory),
+      TakeOwnershipOfUniquePtr<NetEqFactory>(native_neteq_factory));
 }
 
 static void JNI_PeerConnectionFactory_FreeFactory(JNIEnv*,