Make PeerConnectionClient non-singleton.

Ownership of EglBase is moved to PeerConnectionClient.

BUG=webrtc:8135

Review-Url: https://codereview.webrtc.org/3007893002
Cr-Commit-Position: refs/heads/master@{#19634}
diff --git a/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java b/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java
index de9ecd0..9c3347b 100644
--- a/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java
+++ b/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java
@@ -45,7 +45,6 @@
 import org.webrtc.Camera1Enumerator;
 import org.webrtc.Camera2Enumerator;
 import org.webrtc.CameraEnumerator;
-import org.webrtc.EglBase;
 import org.webrtc.FileVideoCapturer;
 import org.webrtc.IceCandidate;
 import org.webrtc.Logging;
@@ -162,7 +161,6 @@
   private AppRTCClient appRtcClient;
   private SignalingParameters signalingParameters;
   private AppRTCAudioManager audioManager = null;
-  private EglBase rootEglBase;
   private SurfaceViewRenderer pipRenderer;
   private SurfaceViewRenderer fullscreenRenderer;
   private VideoFileRenderer videoFileRenderer;
@@ -234,9 +232,11 @@
 
     final Intent intent = getIntent();
 
+    // Create peer connection client.
+    peerConnectionClient = new PeerConnectionClient();
+
     // Create video renderers.
-    rootEglBase = EglBase.create();
-    pipRenderer.init(rootEglBase.getEglBaseContext(), null);
+    pipRenderer.init(peerConnectionClient.getRenderContext(), null);
     pipRenderer.setScalingType(ScalingType.SCALE_ASPECT_FIT);
     String saveRemoteVideoToFile = intent.getStringExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE);
 
@@ -245,15 +245,15 @@
       int videoOutWidth = intent.getIntExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH, 0);
       int videoOutHeight = intent.getIntExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT, 0);
       try {
-        videoFileRenderer = new VideoFileRenderer(
-            saveRemoteVideoToFile, videoOutWidth, videoOutHeight, rootEglBase.getEglBaseContext());
+        videoFileRenderer = new VideoFileRenderer(saveRemoteVideoToFile, videoOutWidth,
+            videoOutHeight, peerConnectionClient.getRenderContext());
         remoteRenderers.add(videoFileRenderer);
       } catch (IOException e) {
         throw new RuntimeException(
             "Failed to open video file for output: " + saveRemoteVideoToFile, e);
       }
     }
-    fullscreenRenderer.init(rootEglBase.getEglBaseContext(), null);
+    fullscreenRenderer.init(peerConnectionClient.getRenderContext(), null);
     fullscreenRenderer.setScalingType(ScalingType.SCALE_ASPECT_FILL);
 
     pipRenderer.setZOrderMediaOverlay(true);
@@ -368,7 +368,6 @@
       }, runTimeMs);
     }
 
-    peerConnectionClient = PeerConnectionClient.getInstance();
     if (loopback) {
       PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
       options.networkIgnoreMask = 0;
@@ -507,7 +506,6 @@
       logToast.cancel();
     }
     activityRunning = false;
-    rootEglBase.release();
     super.onDestroy();
   }
 
@@ -623,10 +621,6 @@
       appRtcClient.disconnectFromRoom();
       appRtcClient = null;
     }
-    if (peerConnectionClient != null) {
-      peerConnectionClient.close();
-      peerConnectionClient = null;
-    }
     if (pipRenderer != null) {
       pipRenderer.release();
       pipRenderer = null;
@@ -639,6 +633,10 @@
       fullscreenRenderer.release();
       fullscreenRenderer = null;
     }
+    if (peerConnectionClient != null) {
+      peerConnectionClient.close();
+      peerConnectionClient = null;
+    }
     if (audioManager != null) {
       audioManager.stop();
       audioManager = null;
@@ -747,8 +745,8 @@
     if (peerConnectionParameters.videoCallEnabled) {
       videoCapturer = createVideoCapturer();
     }
-    peerConnectionClient.createPeerConnection(rootEglBase.getEglBaseContext(), localProxyRenderer,
-        remoteRenderers, videoCapturer, signalingParameters);
+    peerConnectionClient.createPeerConnection(
+        localProxyRenderer, remoteRenderers, videoCapturer, signalingParameters);
 
     if (signalingParameters.initiator) {
       logAndToast("Creating OFFER...");
diff --git a/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java b/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java
index 28e7c7a..c9c9a51 100644
--- a/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java
+++ b/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java
@@ -103,11 +103,15 @@
   private static final int HD_VIDEO_HEIGHT = 720;
   private static final int BPS_IN_KBPS = 1000;
 
-  private static final PeerConnectionClient instance = new PeerConnectionClient();
+  // Executor thread is started once in private ctor and is used for all
+  // peer connection API calls to ensure new peer connection factory is
+  // created on the same thread as previously destroyed factory.
+  private static final ExecutorService executor = Executors.newSingleThreadExecutor();
+
   private final PCObserver pcObserver = new PCObserver();
   private final SDPObserver sdpObserver = new SDPObserver();
-  private final ExecutorService executor;
 
+  private final EglBase rootEglBase;
   private PeerConnectionFactory factory;
   private PeerConnection peerConnection;
   PeerConnectionFactory.Options options = null;
@@ -288,15 +292,8 @@
     void onPeerConnectionError(final String description);
   }
 
-  private PeerConnectionClient() {
-    // Executor thread is started once in private ctor and is used for all
-    // peer connection API calls to ensure new peer connection factory is
-    // created on the same thread as previously destroyed factory.
-    executor = Executors.newSingleThreadExecutor();
-  }
-
-  public static PeerConnectionClient getInstance() {
-    return instance;
+  public PeerConnectionClient() {
+    rootEglBase = EglBase.create();
   }
 
   public void setPeerConnectionFactoryOptions(PeerConnectionFactory.Options options) {
@@ -335,15 +332,15 @@
     });
   }
 
-  public void createPeerConnection(final EglBase.Context renderEGLContext,
-      final VideoRenderer.Callbacks localRender, final VideoRenderer.Callbacks remoteRender,
-      final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) {
-    createPeerConnection(renderEGLContext, localRender, Collections.singletonList(remoteRender),
-        videoCapturer, signalingParameters);
+  public void createPeerConnection(final VideoRenderer.Callbacks localRender,
+      final VideoRenderer.Callbacks remoteRender, final VideoCapturer videoCapturer,
+      final SignalingParameters signalingParameters) {
+    createPeerConnection(
+        localRender, Collections.singletonList(remoteRender), videoCapturer, signalingParameters);
   }
-  public void createPeerConnection(final EglBase.Context renderEGLContext,
-      final VideoRenderer.Callbacks localRender, final List<VideoRenderer.Callbacks> remoteRenders,
-      final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) {
+  public void createPeerConnection(final VideoRenderer.Callbacks localRender,
+      final List<VideoRenderer.Callbacks> remoteRenders, final VideoCapturer videoCapturer,
+      final SignalingParameters signalingParameters) {
     if (peerConnectionParameters == null) {
       Log.e(TAG, "Creating peer connection without initializing factory.");
       return;
@@ -357,7 +354,7 @@
       public void run() {
         try {
           createMediaConstraintsInternal();
-          createPeerConnectionInternal(renderEGLContext);
+          createPeerConnectionInternal();
         } catch (Exception e) {
           reportError("Failed to create peer connection: " + e.getMessage());
           throw e;
@@ -583,7 +580,7 @@
     }
   }
 
-  private void createPeerConnectionInternal(EglBase.Context renderEGLContext) {
+  private void createPeerConnectionInternal() {
     if (factory == null || isError) {
       Log.e(TAG, "Peerconnection factory is not created");
       return;
@@ -594,8 +591,8 @@
     queuedRemoteCandidates = new LinkedList<IceCandidate>();
 
     if (videoCallEnabled) {
-      Log.d(TAG, "EGLContext: " + renderEGLContext);
-      factory.setVideoHwAccelerationOptions(renderEGLContext, renderEGLContext);
+      factory.setVideoHwAccelerationOptions(
+          rootEglBase.getEglBaseContext(), rootEglBase.getEglBaseContext());
     }
 
     PeerConnection.RTCConfiguration rtcConfig =
@@ -698,6 +695,7 @@
       factory = null;
     }
     options = null;
+    rootEglBase.release();
     Log.d(TAG, "Closing peer connection done.");
     events.onPeerConnectionClosed();
     PeerConnectionFactory.stopInternalTracingCapture();
@@ -713,6 +711,10 @@
     return videoWidth * videoHeight >= 1280 * 720;
   }
 
+  public EglBase.Context getRenderContext() {
+    return rootEglBase.getEglBaseContext();
+  }
+
   private void getStats() {
     if (peerConnection == null || isError) {
       return;
diff --git a/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java b/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java
index e93ce74..08c0242 100644
--- a/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java
+++ b/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java
@@ -35,7 +35,6 @@
 import org.webrtc.Camera1Enumerator;
 import org.webrtc.Camera2Enumerator;
 import org.webrtc.CameraEnumerator;
-import org.webrtc.EglBase;
 import org.webrtc.IceCandidate;
 import org.webrtc.MediaCodecVideoEncoder;
 import org.webrtc.PeerConnection;
@@ -73,9 +72,6 @@
   private volatile PeerConnectionClient pcClient;
   private volatile boolean loopback;
 
-  // EGL context that can be used by hardware video decoders to decode to a texture.
-  private EglBase eglBase;
-
   // These are protected by their respective event objects.
   private ExecutorService signalingExecutor;
   private boolean isClosed;
@@ -242,22 +238,21 @@
 
   PeerConnectionClient createPeerConnectionClient(MockRenderer localRenderer,
       MockRenderer remoteRenderer, PeerConnectionParameters peerConnectionParameters,
-      VideoCapturer videoCapturer, EglBase.Context eglContext) {
+      VideoCapturer videoCapturer) {
     List<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>();
     SignalingParameters signalingParameters =
         new SignalingParameters(iceServers, true, // iceServers, initiator.
             null, null, null, // clientId, wssUrl, wssPostUrl.
             null, null); // offerSdp, iceCandidates.
 
-    PeerConnectionClient client = PeerConnectionClient.getInstance();
+    PeerConnectionClient client = new PeerConnectionClient();
     PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
     options.networkIgnoreMask = 0;
     options.disableNetworkMonitor = true;
     client.setPeerConnectionFactoryOptions(options);
     client.createPeerConnectionFactory(
         InstrumentationRegistry.getTargetContext(), peerConnectionParameters, this);
-    client.createPeerConnection(
-        eglContext, localRenderer, remoteRenderer, videoCapturer, signalingParameters);
+    client.createPeerConnection(localRenderer, remoteRenderer, videoCapturer, signalingParameters);
     client.createOffer();
     return client;
   }
@@ -327,17 +322,11 @@
   @Before
   public void setUp() {
     signalingExecutor = Executors.newSingleThreadExecutor();
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
-      eglBase = EglBase.create();
-    }
   }
 
   @After
   public void tearDown() {
     signalingExecutor.shutdown();
-    if (eglBase != null) {
-      eglBase.release();
-    }
   }
 
   @Test
@@ -347,7 +336,7 @@
     MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME);
     pcClient = createPeerConnectionClient(localRenderer, new MockRenderer(0, null),
         createParametersForVideoCall(VIDEO_CODEC_VP8),
-        createCameraCapturer(false /* captureToTexture */), null);
+        createCameraCapturer(false /* captureToTexture */));
 
     // Wait for local SDP and ice candidates set events.
     assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
@@ -375,8 +364,7 @@
     } else {
       Log.d(TAG, "testLoopback for audio.");
     }
-    pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, parameters, videoCapturer,
-        decodeToTexture ? eglBase.getEglBaseContext() : null);
+    pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, parameters, videoCapturer);
 
     // Wait for local SDP, rename it to answer and set as remote SDP.
     assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
@@ -481,50 +469,6 @@
         createCameraCapturer(true /* captureToTexture */), true /* decodeToTexture */);
   }
 
-  // Test that a call can be setup even if the EGL context used during initialization is
-  // released before the Video codecs are created. The HW encoder and decoder is setup to use
-  // textures.
-  @Test
-  @SmallTest
-  public void testLoopbackEglContextReleasedAfterCreatingPc() throws InterruptedException {
-    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
-      Log.i(TAG, "Decode to textures is not supported. Requires SDK version 19");
-      return;
-    }
-
-    loopback = true;
-    PeerConnectionParameters parameters = createParametersForVideoCall(VIDEO_CODEC_VP8);
-    MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME);
-    MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME);
-    pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, parameters,
-        createCameraCapturer(true /* captureToTexture */), eglBase.getEglBaseContext());
-
-    // Wait for local SDP, rename it to answer and set as remote SDP.
-    assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
-
-    // Release the EGL context used for creating the PeerConnectionClient.
-    // Since createPeerConnectionClient is asynchronous, we must wait for the local
-    // SessionDescription.
-    eglBase.release();
-    eglBase = null;
-
-    SessionDescription remoteSdp = new SessionDescription(
-        SessionDescription.Type.fromCanonicalForm("answer"), localSdp.description);
-    pcClient.setRemoteDescription(remoteSdp);
-
-    // Wait for ICE connection.
-    assertTrue("ICE connection failure.", waitForIceConnected(ICE_CONNECTION_WAIT_TIMEOUT));
-    // Check that local and remote video frames were rendered.
-    assertTrue(
-        "Local video frames were not rendered.", localRenderer.waitForFramesRendered(WAIT_TIMEOUT));
-    assertTrue("Remote video frames were not rendered.",
-        remoteRenderer.waitForFramesRendered(WAIT_TIMEOUT));
-
-    pcClient.close();
-    assertTrue(waitForPeerConnectionClosed(WAIT_TIMEOUT));
-    Log.d(TAG, "testLoopback done.");
-  }
-
   @Test
   @SmallTest
   public void testLoopbackH264CaptureToTexture() throws InterruptedException {
@@ -555,7 +499,7 @@
 
     pcClient = createPeerConnectionClient(localRenderer, remoteRenderer,
         createParametersForVideoCall(VIDEO_CODEC_VP8),
-        createCameraCapturer(false /* captureToTexture */), null);
+        createCameraCapturer(false /* captureToTexture */));
 
     // Wait for local SDP, rename it to answer and set as remote SDP.
     assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
@@ -603,7 +547,7 @@
 
     pcClient = createPeerConnectionClient(localRenderer, remoteRenderer,
         createParametersForVideoCall(VIDEO_CODEC_VP8),
-        createCameraCapturer(false /* captureToTexture */), null);
+        createCameraCapturer(false /* captureToTexture */));
 
     // Wait for local SDP, rename it to answer and set as remote SDP.
     assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
@@ -652,7 +596,7 @@
 
     pcClient = createPeerConnectionClient(localRenderer, remoteRenderer,
         createParametersForVideoCall(VIDEO_CODEC_VP8),
-        createCameraCapturer(false /* captureToTexture */), null);
+        createCameraCapturer(false /* captureToTexture */));
 
     // Wait for local SDP, rename it to answer and set as remote SDP.
     assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));