|
|
|
@@ -60,13 +60,17 @@ public class PeerConnectionClient {
|
|
|
|
private boolean videoSourceStopped;
|
|
|
|
private boolean videoSourceStopped;
|
|
|
|
private final PCObserver pcObserver = new PCObserver();
|
|
|
|
private final PCObserver pcObserver = new PCObserver();
|
|
|
|
private final SDPObserver sdpObserver = new SDPObserver();
|
|
|
|
private final SDPObserver sdpObserver = new SDPObserver();
|
|
|
|
|
|
|
|
private final MediaConstraints videoConstraints;
|
|
|
|
|
|
|
|
private final VideoRenderer.Callbacks localRender;
|
|
|
|
private final VideoRenderer.Callbacks remoteRender;
|
|
|
|
private final VideoRenderer.Callbacks remoteRender;
|
|
|
|
private LinkedList<IceCandidate> queuedRemoteCandidates =
|
|
|
|
private LinkedList<IceCandidate> queuedRemoteCandidates =
|
|
|
|
new LinkedList<IceCandidate>();
|
|
|
|
new LinkedList<IceCandidate>();
|
|
|
|
private MediaConstraints sdpMediaConstraints;
|
|
|
|
private final MediaConstraints sdpMediaConstraints;
|
|
|
|
private PeerConnectionEvents events;
|
|
|
|
private final PeerConnectionEvents events;
|
|
|
|
private boolean isInitiator;
|
|
|
|
private boolean isInitiator;
|
|
|
|
|
|
|
|
private boolean useFrontFacingCamera = true;
|
|
|
|
private SessionDescription localSdp = null; // either offer or answer SDP
|
|
|
|
private SessionDescription localSdp = null; // either offer or answer SDP
|
|
|
|
|
|
|
|
private MediaStream videoMediaStream = null;
|
|
|
|
|
|
|
|
|
|
|
|
public PeerConnectionClient(
|
|
|
|
public PeerConnectionClient(
|
|
|
|
Activity activity,
|
|
|
|
Activity activity,
|
|
|
|
@@ -75,6 +79,8 @@ public class PeerConnectionClient {
|
|
|
|
AppRTCSignalingParameters appRtcParameters,
|
|
|
|
AppRTCSignalingParameters appRtcParameters,
|
|
|
|
PeerConnectionEvents events) {
|
|
|
|
PeerConnectionEvents events) {
|
|
|
|
this.activity = activity;
|
|
|
|
this.activity = activity;
|
|
|
|
|
|
|
|
this.videoConstraints = appRtcParameters.videoConstraints;
|
|
|
|
|
|
|
|
this.localRender = localRender;
|
|
|
|
this.remoteRender = remoteRender;
|
|
|
|
this.remoteRender = remoteRender;
|
|
|
|
this.events = events;
|
|
|
|
this.events = events;
|
|
|
|
isInitiator = appRtcParameters.initiator;
|
|
|
|
isInitiator = appRtcParameters.initiator;
|
|
|
|
@@ -101,24 +107,20 @@ public class PeerConnectionClient {
|
|
|
|
// EnumSet.of(Logging.TraceLevel.TRACE_ALL),
|
|
|
|
// EnumSet.of(Logging.TraceLevel.TRACE_ALL),
|
|
|
|
// Logging.Severity.LS_SENSITIVE);
|
|
|
|
// Logging.Severity.LS_SENSITIVE);
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "Creating local video source");
|
|
|
|
if (videoConstraints != null) {
|
|
|
|
MediaStream lMS = factory.createLocalMediaStream("ARDAMS");
|
|
|
|
videoMediaStream = factory.createLocalMediaStream("ARDAMSVideo");
|
|
|
|
if (appRtcParameters.videoConstraints != null) {
|
|
|
|
videoMediaStream.addTrack(createVideoTrack(useFrontFacingCamera));
|
|
|
|
VideoCapturer capturer = getVideoCapturer();
|
|
|
|
pc.addStream(videoMediaStream, new MediaConstraints());
|
|
|
|
videoSource = factory.createVideoSource(
|
|
|
|
|
|
|
|
capturer, appRtcParameters.videoConstraints);
|
|
|
|
|
|
|
|
VideoTrack videoTrack =
|
|
|
|
|
|
|
|
factory.createVideoTrack("ARDAMSv0", videoSource);
|
|
|
|
|
|
|
|
videoTrack.addRenderer(new VideoRenderer(localRender));
|
|
|
|
|
|
|
|
lMS.addTrack(videoTrack);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (appRtcParameters.audioConstraints != null) {
|
|
|
|
if (appRtcParameters.audioConstraints != null) {
|
|
|
|
|
|
|
|
MediaStream lMS = factory.createLocalMediaStream("ARDAMSAudio");
|
|
|
|
lMS.addTrack(factory.createAudioTrack(
|
|
|
|
lMS.addTrack(factory.createAudioTrack(
|
|
|
|
"ARDAMSa0",
|
|
|
|
"ARDAMSa0",
|
|
|
|
factory.createAudioSource(appRtcParameters.audioConstraints)));
|
|
|
|
factory.createAudioSource(appRtcParameters.audioConstraints)));
|
|
|
|
}
|
|
|
|
|
|
|
|
pc.addStream(lMS, new MediaConstraints());
|
|
|
|
pc.addStream(lMS, new MediaConstraints());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
|
|
|
|
public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
|
|
|
|
return pc.getStats(observer, track);
|
|
|
|
return pc.getStats(observer, track);
|
|
|
|
@@ -202,11 +204,15 @@ public class PeerConnectionClient {
|
|
|
|
|
|
|
|
|
|
|
|
// Cycle through likely device names for the camera and return the first
|
|
|
|
// Cycle through likely device names for the camera and return the first
|
|
|
|
// capturer that works, or crash if none do.
|
|
|
|
// capturer that works, or crash if none do.
|
|
|
|
private VideoCapturer getVideoCapturer() {
|
|
|
|
private VideoCapturer getVideoCapturer(boolean useFrontFacing) {
|
|
|
|
String[] cameraFacing = { "front", "back" };
|
|
|
|
String[] cameraFacing = { "front", "back" };
|
|
|
|
|
|
|
|
if (!useFrontFacing) {
|
|
|
|
|
|
|
|
cameraFacing[0] = "back";
|
|
|
|
|
|
|
|
cameraFacing[1] = "front";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for (String facing : cameraFacing) {
|
|
|
|
int[] cameraIndex = { 0, 1 };
|
|
|
|
int[] cameraIndex = { 0, 1 };
|
|
|
|
int[] cameraOrientation = { 0, 90, 180, 270 };
|
|
|
|
int[] cameraOrientation = { 0, 90, 180, 270 };
|
|
|
|
for (String facing : cameraFacing) {
|
|
|
|
|
|
|
|
for (int index : cameraIndex) {
|
|
|
|
for (int index : cameraIndex) {
|
|
|
|
for (int orientation : cameraOrientation) {
|
|
|
|
for (int orientation : cameraOrientation) {
|
|
|
|
String name = "Camera " + index + ", Facing " + facing +
|
|
|
|
String name = "Camera " + index + ", Facing " + facing +
|
|
|
|
@@ -222,6 +228,22 @@ public class PeerConnectionClient {
|
|
|
|
throw new RuntimeException("Failed to open capturer");
|
|
|
|
throw new RuntimeException("Failed to open capturer");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private VideoTrack createVideoTrack(boolean frontFacing) {
|
|
|
|
|
|
|
|
VideoCapturer capturer = getVideoCapturer(frontFacing);
|
|
|
|
|
|
|
|
if (videoSource != null) {
|
|
|
|
|
|
|
|
videoSource.stop();
|
|
|
|
|
|
|
|
videoSource.dispose();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
videoSource = factory.createVideoSource(
|
|
|
|
|
|
|
|
capturer, videoConstraints);
|
|
|
|
|
|
|
|
String trackExtension = frontFacing ? "frontFacing" : "backFacing";
|
|
|
|
|
|
|
|
VideoTrack videoTrack =
|
|
|
|
|
|
|
|
factory.createVideoTrack("ARDAMSv0" + trackExtension, videoSource);
|
|
|
|
|
|
|
|
videoTrack.addRenderer(new VideoRenderer(localRender));
|
|
|
|
|
|
|
|
return videoTrack;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Poor-man's assert(): die with |msg| unless |condition| is true.
|
|
|
|
// Poor-man's assert(): die with |msg| unless |condition| is true.
|
|
|
|
private static void abortUnless(boolean condition, String msg) {
|
|
|
|
private static void abortUnless(boolean condition, String msg) {
|
|
|
|
if (!condition) {
|
|
|
|
if (!condition) {
|
|
|
|
@@ -285,6 +307,49 @@ public class PeerConnectionClient {
|
|
|
|
queuedRemoteCandidates = null;
|
|
|
|
queuedRemoteCandidates = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void switchCamera() {
|
|
|
|
|
|
|
|
if (videoConstraints == null)
|
|
|
|
|
|
|
|
return; // No video is sent.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pc.signalingState() != PeerConnection.SignalingState.STABLE) {
|
|
|
|
|
|
|
|
Log.e(TAG, "Switching camera during negotiation is not handled.");
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pc.removeStream(videoMediaStream);
|
|
|
|
|
|
|
|
VideoTrack currentTrack = videoMediaStream.videoTracks.get(0);
|
|
|
|
|
|
|
|
videoMediaStream.removeTrack(currentTrack);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String trackId = currentTrack.id();
|
|
|
|
|
|
|
|
// On Android, there can only be one camera open at the time and we
|
|
|
|
|
|
|
|
// need to release our implicit references to the videoSource before the
|
|
|
|
|
|
|
|
// PeerConnectionFactory is released. Since createVideoTrack creates a new
|
|
|
|
|
|
|
|
// videoSource and frees the old one, we need to release the track here.
|
|
|
|
|
|
|
|
currentTrack.dispose();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useFrontFacingCamera = !useFrontFacingCamera;
|
|
|
|
|
|
|
|
VideoTrack newTrack = createVideoTrack(useFrontFacingCamera);
|
|
|
|
|
|
|
|
videoMediaStream.addTrack(newTrack);
|
|
|
|
|
|
|
|
pc.addStream(videoMediaStream, new MediaConstraints());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SessionDescription remoteDesc = pc.getRemoteDescription();
|
|
|
|
|
|
|
|
if (localSdp == null || remoteDesc == null) {
|
|
|
|
|
|
|
|
Log.d(TAG, "Switching camera before the negotiation started.");
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
localSdp = new SessionDescription(localSdp.type,
|
|
|
|
|
|
|
|
localSdp.description.replaceAll(trackId, newTrack.id()));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isInitiator) {
|
|
|
|
|
|
|
|
pc.setLocalDescription(new SwitchCameraSdbObserver(), localSdp);
|
|
|
|
|
|
|
|
pc.setRemoteDescription(new SwitchCameraSdbObserver(), remoteDesc);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
pc.setRemoteDescription(new SwitchCameraSdbObserver(), remoteDesc);
|
|
|
|
|
|
|
|
pc.setLocalDescription(new SwitchCameraSdbObserver(), localSdp);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Implementation detail: observe ICE & stream changes and react accordingly.
|
|
|
|
// Implementation detail: observe ICE & stream changes and react accordingly.
|
|
|
|
private class PCObserver implements PeerConnection.Observer {
|
|
|
|
private class PCObserver implements PeerConnection.Observer {
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
@@ -442,4 +507,28 @@ public class PeerConnectionClient {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private class SwitchCameraSdbObserver implements SdpObserver {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void onCreateSuccess(SessionDescription sdp) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void onSetSuccess() {
|
|
|
|
|
|
|
|
Log.d(TAG, "Camera switch SDP set succesfully");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void onCreateFailure(final String error) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void onSetFailure(final String error) {
|
|
|
|
|
|
|
|
activity.runOnUiThread(new Runnable() {
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
|
|
|
|
throw new RuntimeException("setSDP error while switching camera: " + error);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|