Android AppRTCMobile: Transition local render to new VideoSink interface

BUG=None

Review-Url: https://codereview.webrtc.org/3016443002
Cr-Commit-Position: refs/heads/master@{#19820}
This commit is contained in:
magjed
2017-09-13 07:11:16 -07:00
committed by Commit Bot
parent c434e964e0
commit 4e15e67da8
3 changed files with 74 additions and 14 deletions

View File

@ -56,7 +56,9 @@ import org.webrtc.StatsReport;
import org.webrtc.SurfaceViewRenderer; import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer; import org.webrtc.VideoCapturer;
import org.webrtc.VideoFileRenderer; import org.webrtc.VideoFileRenderer;
import org.webrtc.VideoFrame;
import org.webrtc.VideoRenderer; import org.webrtc.VideoRenderer;
import org.webrtc.VideoSink;
/** /**
* Activity for peer connection call setup, call waiting * 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. // Peer connection statistics callback period in ms.
private static final int STAT_CALLBACK_PERIOD = 1000; private static final int STAT_CALLBACK_PERIOD = 1000;
private class ProxyRenderer implements VideoRenderer.Callbacks { private class ProxyRenderer<T extends VideoRenderer.Callbacks & VideoSink>
private VideoRenderer.Callbacks target; implements VideoRenderer.Callbacks, VideoSink {
private T target;
@Override
synchronized public void renderFrame(VideoRenderer.I420Frame frame) { synchronized public void renderFrame(VideoRenderer.I420Frame frame) {
if (target == null) { if (target == null) {
Logging.d(TAG, "Dropping frame in proxy because target is 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); 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; this.target = target;
} }
} }

View File

@ -52,6 +52,7 @@ import org.webrtc.StatsObserver;
import org.webrtc.StatsReport; import org.webrtc.StatsReport;
import org.webrtc.VideoCapturer; import org.webrtc.VideoCapturer;
import org.webrtc.VideoRenderer; import org.webrtc.VideoRenderer;
import org.webrtc.VideoSink;
import org.webrtc.VideoSource; import org.webrtc.VideoSource;
import org.webrtc.VideoTrack; import org.webrtc.VideoTrack;
import org.webrtc.voiceengine.WebRtcAudioManager; import org.webrtc.voiceengine.WebRtcAudioManager;
@ -123,7 +124,7 @@ public class PeerConnectionClient {
private boolean videoCapturerStopped; private boolean videoCapturerStopped;
private boolean isError; private boolean isError;
private Timer statsTimer; private Timer statsTimer;
private VideoRenderer.Callbacks localRender; private VideoSink localRender;
private List<VideoRenderer.Callbacks> remoteRenders; private List<VideoRenderer.Callbacks> remoteRenders;
private SignalingParameters signalingParameters; private SignalingParameters signalingParameters;
private MediaConstraints pcConstraints; 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 VideoRenderer.Callbacks remoteRender, final VideoCapturer videoCapturer,
final SignalingParameters signalingParameters) { final SignalingParameters signalingParameters) {
createPeerConnection( createPeerConnection(
localRender, Collections.singletonList(remoteRender), videoCapturer, signalingParameters); localRender, Collections.singletonList(remoteRender), videoCapturer, signalingParameters);
} }
public void createPeerConnection(final VideoRenderer.Callbacks localRender, public void createPeerConnection(final VideoSink localRender,
final List<VideoRenderer.Callbacks> remoteRenders, final VideoCapturer videoCapturer, final List<VideoRenderer.Callbacks> remoteRenders, final VideoCapturer videoCapturer,
final SignalingParameters signalingParameters) { final SignalingParameters signalingParameters) {
if (peerConnectionParameters == null) { if (peerConnectionParameters == null) {
@ -946,7 +947,7 @@ public class PeerConnectionClient {
localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource); localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
localVideoTrack.setEnabled(renderVideo); localVideoTrack.setEnabled(renderVideo);
localVideoTrack.addRenderer(new VideoRenderer(localRender)); localVideoTrack.addSink(localRender);
return localVideoTrack; return localVideoTrack;
} }

View File

@ -42,7 +42,9 @@ import org.webrtc.PeerConnectionFactory;
import org.webrtc.SessionDescription; import org.webrtc.SessionDescription;
import org.webrtc.StatsReport; import org.webrtc.StatsReport;
import org.webrtc.VideoCapturer; import org.webrtc.VideoCapturer;
import org.webrtc.VideoFrame;
import org.webrtc.VideoRenderer; import org.webrtc.VideoRenderer;
import org.webrtc.VideoSink;
@RunWith(BaseJUnit4ClassRunner.class) @RunWith(BaseJUnit4ClassRunner.class)
public class PeerConnectionClientTest implements PeerConnectionEvents { 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. // Peer connection events implementation.
@Override @Override
public void onLocalDescription(SessionDescription sdp) { 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, MockRenderer remoteRenderer, PeerConnectionParameters peerConnectionParameters,
VideoCapturer videoCapturer) { VideoCapturer videoCapturer) {
List<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>(); List<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>();
@ -333,7 +378,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents {
@SmallTest @SmallTest
public void testSetLocalOfferMakesVideoFlowLocally() throws InterruptedException { public void testSetLocalOfferMakesVideoFlowLocally() throws InterruptedException {
Log.d(TAG, "testSetLocalOfferMakesVideoFlowLocally"); 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), pcClient = createPeerConnectionClient(localRenderer, new MockRenderer(0, null),
createParametersForVideoCall(VIDEO_CODEC_VP8), createParametersForVideoCall(VIDEO_CODEC_VP8),
createCameraCapturer(false /* captureToTexture */)); createCameraCapturer(false /* captureToTexture */));
@ -355,11 +400,11 @@ public class PeerConnectionClientTest implements PeerConnectionEvents {
private void doLoopbackTest(PeerConnectionParameters parameters, VideoCapturer videoCapturer, private void doLoopbackTest(PeerConnectionParameters parameters, VideoCapturer videoCapturer,
boolean decodeToTexture) throws InterruptedException { boolean decodeToTexture) throws InterruptedException {
loopback = true; loopback = true;
MockRenderer localRenderer = null; MockSink localRenderer = null;
MockRenderer remoteRenderer = null; MockRenderer remoteRenderer = null;
if (parameters.videoCallEnabled) { if (parameters.videoCallEnabled) {
Log.d(TAG, "testLoopback for video " + parameters.videoCodec); 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); remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME);
} else { } else {
Log.d(TAG, "testLoopback for audio."); Log.d(TAG, "testLoopback for audio.");
@ -494,7 +539,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents {
Log.d(TAG, "testCameraSwitch"); Log.d(TAG, "testCameraSwitch");
loopback = true; 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); MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME);
pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, pcClient = createPeerConnectionClient(localRenderer, remoteRenderer,
@ -542,7 +587,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents {
Log.d(TAG, "testVideoSourceRestart"); Log.d(TAG, "testVideoSourceRestart");
loopback = true; 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); MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME);
pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, pcClient = createPeerConnectionClient(localRenderer, remoteRenderer,
@ -591,7 +636,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents {
Log.d(TAG, "testCaptureFormatChange"); Log.d(TAG, "testCaptureFormatChange");
loopback = true; 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); MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME);
pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, pcClient = createPeerConnectionClient(localRenderer, remoteRenderer,