diff --git a/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java b/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java index 9c3347bbcf..45bc26b64d 100644 --- a/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java +++ b/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java @@ -56,7 +56,9 @@ import org.webrtc.StatsReport; import org.webrtc.SurfaceViewRenderer; import org.webrtc.VideoCapturer; import org.webrtc.VideoFileRenderer; +import org.webrtc.VideoFrame; import org.webrtc.VideoRenderer; +import org.webrtc.VideoSink; /** * Activity for peer connection call setup, call waiting @@ -137,9 +139,11 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven // Peer connection statistics callback period in ms. private static final int STAT_CALLBACK_PERIOD = 1000; - private class ProxyRenderer implements VideoRenderer.Callbacks { - private VideoRenderer.Callbacks target; + private class ProxyRenderer + implements VideoRenderer.Callbacks, VideoSink { + private T target; + @Override synchronized public void renderFrame(VideoRenderer.I420Frame frame) { if (target == null) { Logging.d(TAG, "Dropping frame in proxy because target is null."); @@ -150,7 +154,17 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven target.renderFrame(frame); } - synchronized public void setTarget(VideoRenderer.Callbacks target) { + @Override + synchronized public void onFrame(VideoFrame frame) { + if (target == null) { + Logging.d(TAG, "Dropping frame in proxy because target is null."); + return; + } + + target.onFrame(frame); + } + + synchronized public void setTarget(T target) { this.target = target; } } diff --git a/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java b/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java index c9c9a51011..e40a17cd14 100644 --- a/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java +++ b/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java @@ -52,6 +52,7 @@ import org.webrtc.StatsObserver; import org.webrtc.StatsReport; import org.webrtc.VideoCapturer; import org.webrtc.VideoRenderer; +import org.webrtc.VideoSink; import org.webrtc.VideoSource; import org.webrtc.VideoTrack; import org.webrtc.voiceengine.WebRtcAudioManager; @@ -123,7 +124,7 @@ public class PeerConnectionClient { private boolean videoCapturerStopped; private boolean isError; private Timer statsTimer; - private VideoRenderer.Callbacks localRender; + private VideoSink localRender; private List remoteRenders; private SignalingParameters signalingParameters; private MediaConstraints pcConstraints; @@ -332,13 +333,13 @@ public class PeerConnectionClient { }); } - public void createPeerConnection(final VideoRenderer.Callbacks localRender, + public void createPeerConnection(final VideoSink localRender, final VideoRenderer.Callbacks remoteRender, final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) { createPeerConnection( localRender, Collections.singletonList(remoteRender), videoCapturer, signalingParameters); } - public void createPeerConnection(final VideoRenderer.Callbacks localRender, + public void createPeerConnection(final VideoSink localRender, final List remoteRenders, final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) { if (peerConnectionParameters == null) { @@ -946,7 +947,7 @@ public class PeerConnectionClient { localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource); localVideoTrack.setEnabled(renderVideo); - localVideoTrack.addRenderer(new VideoRenderer(localRender)); + localVideoTrack.addSink(localRender); return localVideoTrack; } 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 08c024283c..dda16ad390 100644 --- a/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java +++ b/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java @@ -42,7 +42,9 @@ import org.webrtc.PeerConnectionFactory; import org.webrtc.SessionDescription; import org.webrtc.StatsReport; import org.webrtc.VideoCapturer; +import org.webrtc.VideoFrame; import org.webrtc.VideoRenderer; +import org.webrtc.VideoSink; @RunWith(BaseJUnit4ClassRunner.class) public class PeerConnectionClientTest implements PeerConnectionEvents { @@ -126,6 +128,49 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { } } + // Mock VideoSink implementation. + private static class MockSink implements VideoSink { + // These are protected by 'this' since we gets called from worker threads. + private String rendererName; + private boolean renderFrameCalled = false; + + // Thread-safe in itself. + private CountDownLatch doneRendering; + + public MockSink(int expectedFrames, String rendererName) { + this.rendererName = rendererName; + reset(expectedFrames); + } + + // Resets render to wait for new amount of video frames. + public synchronized void reset(int expectedFrames) { + renderFrameCalled = false; + doneRendering = new CountDownLatch(expectedFrames); + } + + @Override + public synchronized void onFrame(VideoFrame frame) { + if (!renderFrameCalled) { + if (rendererName != null) { + Log.d(TAG, + rendererName + " render frame: " + frame.getRotatedWidth() + " x " + + frame.getRotatedHeight()); + } else { + Log.d(TAG, "Render frame: " + frame.getRotatedWidth() + " x " + frame.getRotatedHeight()); + } + } + renderFrameCalled = true; + doneRendering.countDown(); + } + + // This method shouldn't hold any locks or touch member variables since it + // blocks. + public boolean waitForFramesRendered(int timeoutMs) throws InterruptedException { + doneRendering.await(timeoutMs, TimeUnit.MILLISECONDS); + return (doneRendering.getCount() <= 0); + } + } + // Peer connection events implementation. @Override public void onLocalDescription(SessionDescription sdp) { @@ -236,7 +281,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { } } - PeerConnectionClient createPeerConnectionClient(MockRenderer localRenderer, + PeerConnectionClient createPeerConnectionClient(MockSink localRenderer, MockRenderer remoteRenderer, PeerConnectionParameters peerConnectionParameters, VideoCapturer videoCapturer) { List iceServers = new LinkedList(); @@ -333,7 +378,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { @SmallTest public void testSetLocalOfferMakesVideoFlowLocally() throws InterruptedException { Log.d(TAG, "testSetLocalOfferMakesVideoFlowLocally"); - MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); + MockSink localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); pcClient = createPeerConnectionClient(localRenderer, new MockRenderer(0, null), createParametersForVideoCall(VIDEO_CODEC_VP8), createCameraCapturer(false /* captureToTexture */)); @@ -355,11 +400,11 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { private void doLoopbackTest(PeerConnectionParameters parameters, VideoCapturer videoCapturer, boolean decodeToTexture) throws InterruptedException { loopback = true; - MockRenderer localRenderer = null; + MockSink localRenderer = null; MockRenderer remoteRenderer = null; if (parameters.videoCallEnabled) { Log.d(TAG, "testLoopback for video " + parameters.videoCodec); - localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); + localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); } else { Log.d(TAG, "testLoopback for audio."); @@ -494,7 +539,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { Log.d(TAG, "testCameraSwitch"); loopback = true; - MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); + MockSink localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, @@ -542,7 +587,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { Log.d(TAG, "testVideoSourceRestart"); loopback = true; - MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); + MockSink localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, @@ -591,7 +636,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { Log.d(TAG, "testCaptureFormatChange"); loopback = true; - MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); + MockSink localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); pcClient = createPeerConnectionClient(localRenderer, remoteRenderer,