ApprtDemo Android: Switch between front and back camera.
This adds a UI icon for switching between the front and back camera. This cl adds the possibility to change between the front and back camera while in a call or before the other end have connected. BUG=3786 R=glaznev@webrtc.org Review URL: https://webrtc-codereview.appspot.com/23219004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7553 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
663fdd02fd
commit
7998089789
@ -18,6 +18,13 @@
|
||||
|
||||
<!-- TODO(kjellander): Add audio and video mute buttons. -->
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_switch_camera"
|
||||
android:background="@android:drawable/ic_menu_camera"
|
||||
android:contentDescription="@string/switch_camera"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_toggle_debug"
|
||||
android:background="@android:drawable/ic_menu_info_details"
|
||||
|
@ -16,6 +16,7 @@
|
||||
<string name="connecting_to">Connecting to: %1$s</string>
|
||||
<string name="missing_url">FATAL ERROR: Missing URL to connect to.</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="switch_camera">Switch front/back camera</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
|
||||
<!-- Settings strings. -->
|
||||
|
@ -139,6 +139,14 @@ public class AppRTCDemoActivity extends Activity
|
||||
}
|
||||
});
|
||||
|
||||
((ImageButton) findViewById(R.id.button_switch_camera)).setOnClickListener(
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
pc.switchCamera();
|
||||
}
|
||||
});
|
||||
|
||||
((ImageButton) findViewById(R.id.button_toggle_debug)).setOnClickListener(
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
|
@ -60,13 +60,17 @@ public class PeerConnectionClient {
|
||||
private boolean videoSourceStopped;
|
||||
private final PCObserver pcObserver = new PCObserver();
|
||||
private final SDPObserver sdpObserver = new SDPObserver();
|
||||
private final MediaConstraints videoConstraints;
|
||||
private final VideoRenderer.Callbacks localRender;
|
||||
private final VideoRenderer.Callbacks remoteRender;
|
||||
private LinkedList<IceCandidate> queuedRemoteCandidates =
|
||||
new LinkedList<IceCandidate>();
|
||||
private MediaConstraints sdpMediaConstraints;
|
||||
private PeerConnectionEvents events;
|
||||
private final MediaConstraints sdpMediaConstraints;
|
||||
private final PeerConnectionEvents events;
|
||||
private boolean isInitiator;
|
||||
private boolean useFrontFacingCamera = true;
|
||||
private SessionDescription localSdp = null; // either offer or answer SDP
|
||||
private MediaStream videoMediaStream = null;
|
||||
|
||||
public PeerConnectionClient(
|
||||
Activity activity,
|
||||
@ -75,6 +79,8 @@ public class PeerConnectionClient {
|
||||
AppRTCSignalingParameters appRtcParameters,
|
||||
PeerConnectionEvents events) {
|
||||
this.activity = activity;
|
||||
this.videoConstraints = appRtcParameters.videoConstraints;
|
||||
this.localRender = localRender;
|
||||
this.remoteRender = remoteRender;
|
||||
this.events = events;
|
||||
isInitiator = appRtcParameters.initiator;
|
||||
@ -101,23 +107,19 @@ public class PeerConnectionClient {
|
||||
// EnumSet.of(Logging.TraceLevel.TRACE_ALL),
|
||||
// Logging.Severity.LS_SENSITIVE);
|
||||
|
||||
Log.d(TAG, "Creating local video source");
|
||||
MediaStream lMS = factory.createLocalMediaStream("ARDAMS");
|
||||
if (appRtcParameters.videoConstraints != null) {
|
||||
VideoCapturer capturer = getVideoCapturer();
|
||||
videoSource = factory.createVideoSource(
|
||||
capturer, appRtcParameters.videoConstraints);
|
||||
VideoTrack videoTrack =
|
||||
factory.createVideoTrack("ARDAMSv0", videoSource);
|
||||
videoTrack.addRenderer(new VideoRenderer(localRender));
|
||||
lMS.addTrack(videoTrack);
|
||||
if (videoConstraints != null) {
|
||||
videoMediaStream = factory.createLocalMediaStream("ARDAMSVideo");
|
||||
videoMediaStream.addTrack(createVideoTrack(useFrontFacingCamera));
|
||||
pc.addStream(videoMediaStream, new MediaConstraints());
|
||||
}
|
||||
|
||||
if (appRtcParameters.audioConstraints != null) {
|
||||
MediaStream lMS = factory.createLocalMediaStream("ARDAMSAudio");
|
||||
lMS.addTrack(factory.createAudioTrack(
|
||||
"ARDAMSa0",
|
||||
factory.createAudioSource(appRtcParameters.audioConstraints)));
|
||||
pc.addStream(lMS, new MediaConstraints());
|
||||
}
|
||||
pc.addStream(lMS, new MediaConstraints());
|
||||
}
|
||||
|
||||
public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
|
||||
@ -202,11 +204,15 @@ public class PeerConnectionClient {
|
||||
|
||||
// Cycle through likely device names for the camera and return the first
|
||||
// capturer that works, or crash if none do.
|
||||
private VideoCapturer getVideoCapturer() {
|
||||
private VideoCapturer getVideoCapturer(boolean useFrontFacing) {
|
||||
String[] cameraFacing = { "front", "back" };
|
||||
int[] cameraIndex = { 0, 1 };
|
||||
int[] cameraOrientation = { 0, 90, 180, 270 };
|
||||
if (!useFrontFacing) {
|
||||
cameraFacing[0] = "back";
|
||||
cameraFacing[1] = "front";
|
||||
}
|
||||
for (String facing : cameraFacing) {
|
||||
int[] cameraIndex = { 0, 1 };
|
||||
int[] cameraOrientation = { 0, 90, 180, 270 };
|
||||
for (int index : cameraIndex) {
|
||||
for (int orientation : cameraOrientation) {
|
||||
String name = "Camera " + index + ", Facing " + facing +
|
||||
@ -222,6 +228,22 @@ public class PeerConnectionClient {
|
||||
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.
|
||||
private static void abortUnless(boolean condition, String msg) {
|
||||
if (!condition) {
|
||||
@ -285,6 +307,49 @@ public class PeerConnectionClient {
|
||||
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.
|
||||
private class PCObserver implements PeerConnection.Observer {
|
||||
@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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user