Android: Expose underlying EGL context in API

This CL adds a way to extract the underlying android.opengl.EGLContext
and javax.microedition.khronos.egl.EGLContext for EglBase14 and
EglBase10 respectively. The reason is that clients can't be expected to
use only WebRTC's OpenGL code and might need to integrate with their
own GL code.

Bug: None
Change-Id: Ie00a564de45a090683542a52005da7e43c586ced
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/127888
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27205}
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index d8b1302..4111fcd 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -247,6 +247,8 @@
   rtc_android_library("video_java") {
     java_files = [
       "api/org/webrtc/EglBase.java",
+      "api/org/webrtc/EglBase10.java",
+      "api/org/webrtc/EglBase14.java",
       "api/org/webrtc/EglRenderer.java",
       "api/org/webrtc/GlRectDrawer.java",
       "api/org/webrtc/GlShader.java",
@@ -263,8 +265,8 @@
       "api/org/webrtc/YuvConverter.java",
       "api/org/webrtc/YuvHelper.java",
       "api/org/webrtc/TimestampAligner.java",
-      "src/java/org/webrtc/EglBase10.java",
-      "src/java/org/webrtc/EglBase14.java",
+      "src/java/org/webrtc/EglBase10Impl.java",
+      "src/java/org/webrtc/EglBase14Impl.java",
       "src/java/org/webrtc/GlGenericDrawer.java",
       "src/java/org/webrtc/H264Utils.java",
       "src/java/org/webrtc/NV21Buffer.java",
diff --git a/sdk/android/api/org/webrtc/EglBase.java b/sdk/android/api/org/webrtc/EglBase.java
index 43baee7..3d0238d 100644
--- a/sdk/android/api/org/webrtc/EglBase.java
+++ b/sdk/android/api/org/webrtc/EglBase.java
@@ -96,10 +96,15 @@
    * 1.4 context if possible, and an EGL 1.0 context otherwise.
    */
   public static EglBase create(@Nullable Context sharedContext, int[] configAttributes) {
-    return (EglBase14.isEGL14Supported()
-               && (sharedContext == null || sharedContext instanceof EglBase14.Context))
-        ? new EglBase14((EglBase14.Context) sharedContext, configAttributes)
-        : new EglBase10((EglBase10.Context) sharedContext, configAttributes);
+    if (sharedContext == null) {
+      return EglBase14Impl.isEGL14Supported() ? createEgl14(configAttributes)
+                                              : createEgl10(configAttributes);
+    } else if (sharedContext instanceof EglBase14.Context) {
+      return createEgl14((EglBase14.Context) sharedContext, configAttributes);
+    } else if (sharedContext instanceof EglBase10.Context) {
+      return createEgl10((EglBase10.Context) sharedContext, configAttributes);
+    }
+    throw new IllegalArgumentException("Unrecognized Context");
   }
 
   /**
@@ -118,36 +123,50 @@
     return create(sharedContext, CONFIG_PLAIN);
   }
 
+  /** Explicitly create a root EGl 1.0 context with the specified config attributes. */
+  public static EglBase10 createEgl10(int[] configAttributes) {
+    return new EglBase10Impl(/* sharedContext= */ null, configAttributes);
+  }
+
   /**
-   * Explicitly create a root EGl 1.0 context with the specified config attributes.
+   * Explicitly create a root EGl 1.0 context with the specified config attributes and shared
+   * context.
    */
-  public static EglBase createEgl10(int[] configAttributes) {
-    return new EglBase10(null /* shaderContext */, configAttributes);
+  public static EglBase10 createEgl10(EglBase10.Context sharedContext, int[] configAttributes) {
+    return new EglBase10Impl(
+        sharedContext == null ? null : sharedContext.getRawContext(), configAttributes);
   }
 
   /**
    * Explicitly create a root EGl 1.0 context with the specified config attributes
    * and shared context.
    */
-  public static EglBase createEgl10(
+  public static EglBase10 createEgl10(
       javax.microedition.khronos.egl.EGLContext sharedContext, int[] configAttributes) {
-    return new EglBase10(new EglBase10.Context(sharedContext), configAttributes);
+    return new EglBase10Impl(sharedContext, configAttributes);
+  }
+
+  /** Explicitly create a root EGl 1.4 context with the specified config attributes. */
+  public static EglBase14 createEgl14(int[] configAttributes) {
+    return new EglBase14Impl(/* sharedContext= */ null, configAttributes);
   }
 
   /**
-   * Explicitly create a root EGl 1.4 context with the specified config attributes.
+   * Explicitly create a root EGl 1.4 context with the specified config attributes and shared
+   * context.
    */
-  public static EglBase createEgl14(int[] configAttributes) {
-    return new EglBase14(null /* shaderContext */, configAttributes);
+  public static EglBase14 createEgl14(EglBase14.Context sharedContext, int[] configAttributes) {
+    return new EglBase14Impl(
+        sharedContext == null ? null : sharedContext.getRawContext(), configAttributes);
   }
 
   /**
    * Explicitly create a root EGl 1.4 context with the specified config attributes
    * and shared context.
    */
-  public static EglBase createEgl14(
+  public static EglBase14 createEgl14(
       android.opengl.EGLContext sharedContext, int[] configAttributes) {
-    return new EglBase14(new EglBase14.Context(sharedContext), configAttributes);
+    return new EglBase14Impl(sharedContext, configAttributes);
   }
 
   void createSurface(Surface surface);
diff --git a/sdk/android/api/org/webrtc/EglBase10.java b/sdk/android/api/org/webrtc/EglBase10.java
new file mode 100644
index 0000000..f8b0a3c
--- /dev/null
+++ b/sdk/android/api/org/webrtc/EglBase10.java
@@ -0,0 +1,20 @@
+/*
+ *  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;
+
+import javax.microedition.khronos.egl.EGLContext;
+
+/** EGL 1.0 implementation of EglBase. */
+public interface EglBase10 extends EglBase {
+  interface Context extends EglBase.Context {
+    EGLContext getRawContext();
+  }
+}
diff --git a/sdk/android/api/org/webrtc/EglBase14.java b/sdk/android/api/org/webrtc/EglBase14.java
new file mode 100644
index 0000000..69c89c4
--- /dev/null
+++ b/sdk/android/api/org/webrtc/EglBase14.java
@@ -0,0 +1,20 @@
+/*
+ *  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;
+
+import android.opengl.EGLContext;
+
+/** EGL 1.4 implementation of EglBase. */
+public interface EglBase14 extends EglBase {
+  interface Context extends EglBase.Context {
+    EGLContext getRawContext();
+  }
+}
diff --git a/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java b/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
index 8ffe1e2..773ed16 100644
--- a/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
+++ b/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
@@ -660,7 +660,8 @@
       mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
 
       if (useSurface) {
-        eglBase = new EglBase14((EglBase14.Context) getEglContext(), EglBase.CONFIG_RECORDABLE);
+        eglBase =
+            EglBase.createEgl14((EglBase14.Context) getEglContext(), EglBase.CONFIG_RECORDABLE);
         // Create an input surface and keep a reference since we must release the surface when done.
         inputSurface = mediaCodec.createInputSurface();
         eglBase.createSurface(inputSurface);
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/AndroidVideoDecoderInstrumentationTest.java b/sdk/android/instrumentationtests/src/org/webrtc/AndroidVideoDecoderInstrumentationTest.java
index f31d710..211b93a 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/AndroidVideoDecoderInstrumentationTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/AndroidVideoDecoderInstrumentationTest.java
@@ -162,7 +162,7 @@
 
     TEST_FRAMES = generateTestFrames();
 
-    eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN);
+    eglBase = EglBase.createEgl14(EglBase.CONFIG_PLAIN);
     eglBase.createDummyPbufferSurface();
     eglBase.makeCurrent();
 
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java b/sdk/android/instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java
index 5af9ea2..8c75878 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/HardwareVideoEncoderTest.java
@@ -356,7 +356,7 @@
   public void setUp() {
     NativeLibrary.initialize(new NativeLibrary.DefaultLoader(), TestConstants.NATIVE_LIBRARY);
 
-    eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN);
+    eglBase = EglBase.createEgl14(EglBase.CONFIG_PLAIN);
     eglBase.createDummyPbufferSurface();
     eglBase.makeCurrent();
     lastTimestampNs = System.nanoTime();
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/MediaCodecVideoEncoderTest.java b/sdk/android/instrumentationtests/src/org/webrtc/MediaCodecVideoEncoderTest.java
index a91f88e..ef402aa 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/MediaCodecVideoEncoderTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/MediaCodecVideoEncoderTest.java
@@ -52,7 +52,7 @@
       Log.i(TAG, "hardware does not support VP8 encoding, skipping testEncoderUsingTextures");
       return;
     }
-    EglBase14 eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN);
+    EglBase14 eglBase = EglBase.createEgl14(EglBase.CONFIG_PLAIN);
     MediaCodecVideoEncoder.setEglContext(eglBase.getEglBaseContext());
     MediaCodecVideoEncoder encoder = new MediaCodecVideoEncoder();
     assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile,
@@ -73,7 +73,7 @@
     assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile,
         640, 480, 300, 30, /* useSurface= */ false));
     encoder.release();
-    EglBase14 eglBase = new EglBase14(null, EglBase.CONFIG_PLAIN);
+    EglBase14 eglBase = EglBase.createEgl14(EglBase.CONFIG_PLAIN);
     MediaCodecVideoEncoder.setEglContext(eglBase.getEglBaseContext());
     assertTrue(encoder.initEncode(MediaCodecVideoEncoder.VideoCodecType.VIDEO_CODEC_VP8, profile,
         640, 480, 300, 30, /* useSurface= */ true));
diff --git a/sdk/android/src/java/org/webrtc/EglBase10.java b/sdk/android/src/java/org/webrtc/EglBase10Impl.java
similarity index 94%
rename from sdk/android/src/java/org/webrtc/EglBase10.java
rename to sdk/android/src/java/org/webrtc/EglBase10Impl.java
index c213ee7..08f6620 100644
--- a/sdk/android/src/java/org/webrtc/EglBase10.java
+++ b/sdk/android/src/java/org/webrtc/EglBase10Impl.java
@@ -26,7 +26,7 @@
  * Holds EGL state and utility methods for handling an egl 1.0 EGLContext, an EGLDisplay,
  * and an EGLSurface.
  */
-class EglBase10 implements EglBase {
+class EglBase10Impl implements EglBase10 {
   // This constant is taken from EGL14.EGL_CONTEXT_CLIENT_VERSION.
   private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
 
@@ -37,10 +37,15 @@
   private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE;
 
   // EGL wrapper for an actual EGLContext.
-  public static class Context implements EglBase.Context {
+  private static class Context implements EglBase10.Context {
     private final EGLContext eglContext;
 
     @Override
+    public EGLContext getRawContext() {
+      return eglContext;
+    }
+
+    @Override
     public long getNativeEglContext() {
       // TODO(magjed): Implement. There is no easy way of getting the native context for EGL 1.0. We
       // need to make sure to have an EglSurface, then make the context current using that surface,
@@ -55,7 +60,7 @@
   }
 
   // Create a new context with the specified config type, sharing data with sharedContext.
-  public EglBase10(Context sharedContext, int[] configAttributes) {
+  public EglBase10Impl(EGLContext sharedContext, int[] configAttributes) {
     this.egl = (EGL10) EGLContext.getEGL();
     eglDisplay = getEglDisplay();
     eglConfig = getEglConfig(eglDisplay, configAttributes);
@@ -178,7 +183,7 @@
 
   @Override
   public org.webrtc.EglBase.Context getEglBaseContext() {
-    return new EglBase10.Context(eglContext);
+    return new Context(eglContext);
   }
 
   @Override
@@ -305,13 +310,12 @@
 
   // Return an EGLConfig, or die trying.
   private EGLContext createEglContext(
-      @Nullable Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) {
-    if (sharedContext != null && sharedContext.eglContext == EGL10.EGL_NO_CONTEXT) {
+      @Nullable EGLContext sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+    if (sharedContext != null && sharedContext == EGL10.EGL_NO_CONTEXT) {
       throw new RuntimeException("Invalid sharedContext");
     }
     int[] contextAttributes = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
-    EGLContext rootContext =
-        sharedContext == null ? EGL10.EGL_NO_CONTEXT : sharedContext.eglContext;
+    EGLContext rootContext = sharedContext == null ? EGL10.EGL_NO_CONTEXT : sharedContext;
     final EGLContext eglContext;
     synchronized (EglBase.lock) {
       eglContext = egl.eglCreateContext(eglDisplay, eglConfig, rootContext, contextAttributes);
diff --git a/sdk/android/src/java/org/webrtc/EglBase14.java b/sdk/android/src/java/org/webrtc/EglBase14Impl.java
similarity index 92%
rename from sdk/android/src/java/org/webrtc/EglBase14.java
rename to sdk/android/src/java/org/webrtc/EglBase14Impl.java
index 547731c..07fbe46 100644
--- a/sdk/android/src/java/org/webrtc/EglBase14.java
+++ b/sdk/android/src/java/org/webrtc/EglBase14Impl.java
@@ -29,10 +29,10 @@
  */
 @SuppressWarnings("ReferenceEquality") // We want to compare to EGL14 constants.
 @TargetApi(18)
-class EglBase14 implements EglBase {
+class EglBase14Impl implements EglBase14 {
   private static final String TAG = "EglBase14";
-  private static final int EGLExt_SDK_VERSION = android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
-  private static final int CURRENT_SDK_VERSION = android.os.Build.VERSION.SDK_INT;
+  private static final int EGLExt_SDK_VERSION = Build.VERSION_CODES.JELLY_BEAN_MR2;
+  private static final int CURRENT_SDK_VERSION = Build.VERSION.SDK_INT;
   private EGLContext eglContext;
   @Nullable private EGLConfig eglConfig;
   private EGLDisplay eglDisplay;
@@ -47,8 +47,13 @@
     return (CURRENT_SDK_VERSION >= EGLExt_SDK_VERSION);
   }
 
-  public static class Context implements EglBase.Context {
-    private final android.opengl.EGLContext egl14Context;
+  public static class Context implements EglBase14.Context {
+    private final EGLContext egl14Context;
+
+    @Override
+    public EGLContext getRawContext() {
+      return egl14Context;
+    }
 
     @Override
     @SuppressWarnings("deprecation")
@@ -65,7 +70,7 @@
 
   // Create a new context with the specified config type, sharing data with sharedContext.
   // |sharedContext| may be null.
-  public EglBase14(EglBase14.Context sharedContext, int[] configAttributes) {
+  public EglBase14Impl(EGLContext sharedContext, int[] configAttributes) {
     eglDisplay = getEglDisplay();
     eglConfig = getEglConfig(eglDisplay, configAttributes);
     eglContext = createEglContext(sharedContext, eglDisplay, eglConfig);
@@ -121,7 +126,7 @@
 
   @Override
   public Context getEglBaseContext() {
-    return new EglBase14.Context(eglContext);
+    return new Context(eglContext);
   }
 
   @Override
@@ -258,13 +263,12 @@
 
   // Return an EGLConfig, or die trying.
   private static EGLContext createEglContext(
-      @Nullable EglBase14.Context sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) {
-    if (sharedContext != null && sharedContext.egl14Context == EGL14.EGL_NO_CONTEXT) {
+      @Nullable EGLContext sharedContext, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+    if (sharedContext != null && sharedContext == EGL14.EGL_NO_CONTEXT) {
       throw new RuntimeException("Invalid sharedContext");
     }
     int[] contextAttributes = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE};
-    EGLContext rootContext =
-        sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext.egl14Context;
+    EGLContext rootContext = sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext;
     final EGLContext eglContext;
     synchronized (EglBase.lock) {
       eglContext = EGL14.eglCreateContext(eglDisplay, eglConfig, rootContext, contextAttributes, 0);
diff --git a/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java b/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java
index e2c9035..4a84bfa 100644
--- a/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java
+++ b/sdk/android/src/java/org/webrtc/HardwareVideoEncoder.java
@@ -215,7 +215,7 @@
           format, null /* surface */, null /* crypto */, MediaCodec.CONFIGURE_FLAG_ENCODE);
 
       if (useSurfaceMode) {
-        textureEglBase = new EglBase14(sharedContext, EglBase.CONFIG_RECORDABLE);
+        textureEglBase = EglBase.createEgl14(sharedContext, EglBase.CONFIG_RECORDABLE);
         textureInputSurface = codec.createInputSurface();
         textureEglBase.createSurface(textureInputSurface);
         textureEglBase.makeCurrent();