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}
This commit is contained in:
sakal
2017-08-31 08:03:46 -07:00
committed by Commit Bot
parent da194e79c4
commit 85d7650ab6
3 changed files with 46 additions and 102 deletions

View File

@ -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...");

View File

@ -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<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 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<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 @@ 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;

View File

@ -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<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 @@ 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));