From 85d7650ab6a84477e807d458ea835154cf5138da Mon Sep 17 00:00:00 2001 From: sakal Date: Thu, 31 Aug 2017 08:03:46 -0700 Subject: [PATCH] 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} --- .../src/org/appspot/apprtc/CallActivity.java | 28 ++++---- .../appspot/apprtc/PeerConnectionClient.java | 48 +++++++------ .../apprtc/test/PeerConnectionClientTest.java | 72 +++---------------- 3 files changed, 46 insertions(+), 102 deletions(-) diff --git a/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java b/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java index de9ecd019f..9c3347bbcf 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.appspot.apprtc.PeerConnectionClient.PeerConnectionParameters; 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 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven 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 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven 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 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven 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 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven }, runTimeMs); } - peerConnectionClient = PeerConnectionClient.getInstance(); if (loopback) { PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); options.networkIgnoreMask = 0; @@ -507,7 +506,6 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven logToast.cancel(); } activityRunning = false; - rootEglBase.release(); super.onDestroy(); } @@ -623,10 +621,6 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven appRtcClient.disconnectFromRoom(); appRtcClient = null; } - if (peerConnectionClient != null) { - peerConnectionClient.close(); - peerConnectionClient = null; - } if (pipRenderer != null) { pipRenderer.release(); pipRenderer = null; @@ -639,6 +633,10 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven fullscreenRenderer.release(); fullscreenRenderer = null; } + if (peerConnectionClient != null) { + peerConnectionClient.close(); + peerConnectionClient = null; + } if (audioManager != null) { audioManager.stop(); audioManager = null; @@ -747,8 +745,8 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven 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 28e7c7a8d0..c9c9a51011 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 @@ public class PeerConnectionClient { 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 @@ public class PeerConnectionClient { 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 class PeerConnectionClient { }); } - 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 remoteRenders, - final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) { + public void createPeerConnection(final VideoRenderer.Callbacks localRender, + final List 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 class PeerConnectionClient { 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 @@ public class PeerConnectionClient { } } - 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 @@ public class PeerConnectionClient { queuedRemoteCandidates = new LinkedList(); if (videoCallEnabled) { - Log.d(TAG, "EGLContext: " + renderEGLContext); - factory.setVideoHwAccelerationOptions(renderEGLContext, renderEGLContext); + factory.setVideoHwAccelerationOptions( + rootEglBase.getEglBaseContext(), rootEglBase.getEglBaseContext()); } PeerConnection.RTCConfiguration rtcConfig = @@ -698,6 +695,7 @@ public class PeerConnectionClient { factory = null; } options = null; + rootEglBase.release(); Log.d(TAG, "Closing peer connection done."); events.onPeerConnectionClosed(); PeerConnectionFactory.stopInternalTracingCapture(); @@ -713,6 +711,10 @@ public class PeerConnectionClient { 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 e93ce74928..08c024283c 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.junit.runner.RunWith; 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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { 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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { PeerConnectionClient createPeerConnectionClient(MockRenderer localRenderer, MockRenderer remoteRenderer, PeerConnectionParameters peerConnectionParameters, - VideoCapturer videoCapturer, EglBase.Context eglContext) { + VideoCapturer videoCapturer) { List iceServers = new LinkedList(); 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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { @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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { 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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { } 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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { 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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { 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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { 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 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { 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));