Skip to content

Commit

Permalink
Merge pull request #10 from daily-co/expose-camera-facing-mode
Browse files Browse the repository at this point in the history
Expose camera facing mode
  • Loading branch information
kompfner authored Oct 28, 2020
2 parents c0a0cad + 2760ba7 commit 6987854
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 15 deletions.
16 changes: 15 additions & 1 deletion MediaStreamTrack.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,21 @@ class MediaStreamTrack extends EventTarget(MEDIA_STREAM_TRACK_EVENTS) {
if (this.kind !== 'video') {
throw new Error('Only implemented for video tracks');
}
WebRTCModule.mediaStreamTrackSwitchCamera(this.id);
return WebRTCModule.mediaStreamTrackSwitchCamera(this.id);
}

/**
* Private / custom API for retrieving the current camera facing mode.
* Returns "user" or "environment".
*/
_getCameraFacingMode() {
if (this.remote) {
throw new Error('Not implemented for remote tracks');
}
if (this.kind !== 'video') {
throw new Error('Only implemented for video tracks');
}
return WebRTCModule.mediaStreamTrackGetCameraFacingMode(this.id);
}

applyConstraints() {
Expand Down
17 changes: 15 additions & 2 deletions android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,23 @@ void disposeTrack(String id) {
}
}

void switchCamera(String trackId) {
void switchCamera(String trackId, VideoCaptureController.SwitchCameraHandler handler) throws Exception {
TrackPrivate track = tracks.get(trackId);
if (track != null && track.videoCaptureController != null) {
track.videoCaptureController.switchCamera();
track.videoCaptureController.switchCamera(handler);
}
else {
throw new Exception("Track not found when attempting to switch camera");
}
}

String getCameraFacingMode(String trackId) throws Exception {
TrackPrivate track = tracks.get(trackId);
if (track != null && track.videoCaptureController != null) {
return track.videoCaptureController.facingMode();
}
else {
throw new Exception("Track not found when attempting to get camera facing mode");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,20 @@ public boolean stopCapture() {
}
}

public void switchCamera() {
public interface SwitchCameraHandler {
// Called whether or not it succeeded
public void onSwitchCameraDone(String facingMode);
}

public void switchCamera(SwitchCameraHandler handler) {
if (videoCapturer instanceof CameraVideoCapturer) {
CameraVideoCapturer capturer = (CameraVideoCapturer) videoCapturer;
String[] deviceNames = cameraEnumerator.getDeviceNames();
int deviceCount = deviceNames.length;

// Nothing to switch to.
if (deviceCount < 2) {
return;
handler.onSwitchCameraDone(facingMode());
}

// The usual case.
Expand All @@ -104,29 +109,34 @@ public void switchCamera() {
@Override
public void onCameraSwitchDone(boolean b) {
isFrontFacing = b;
handler.onSwitchCameraDone(facingMode());
}

@Override
public void onCameraSwitchError(String s) {
Log.e(TAG, "Error switching camera: " + s);
handler.onSwitchCameraDone(facingMode());
}
});
return;
}

// If we are here the device has more than 2 cameras. Cycle through them
// and switch to the first one of the desired facing mode.
switchCamera(!isFrontFacing, deviceCount);
switchCamera(!isFrontFacing, deviceCount, handler);
}
}

public String facingMode() {
return isFrontFacing ? "user" : "environment";
}

/**
* Helper function which tries to switch cameras until the desired facing mode is found.
*
* @param desiredFrontFacing - The desired front facing value.
* @param tries - How many times to try switching.
*/
private void switchCamera(boolean desiredFrontFacing, int tries) {
private void switchCamera(boolean desiredFrontFacing, int tries, SwitchCameraHandler handler) {
CameraVideoCapturer capturer = (CameraVideoCapturer) videoCapturer;

capturer.switchCamera(new CameraVideoCapturer.CameraSwitchHandler() {
Expand All @@ -135,16 +145,18 @@ public void onCameraSwitchDone(boolean b) {
if (b != desiredFrontFacing) {
int newTries = tries-1;
if (newTries > 0) {
switchCamera(desiredFrontFacing, newTries);
switchCamera(desiredFrontFacing, newTries, handler);
}
} else {
isFrontFacing = desiredFrontFacing;
handler.onSwitchCameraDone(facingMode());
}
}

@Override
public void onCameraSwitchError(String s) {
Log.e(TAG, "Error switching camera: " + s);
handler.onSwitchCameraDone(facingMode());
}
});
}
Expand Down
38 changes: 36 additions & 2 deletions android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
Expand Down Expand Up @@ -634,11 +635,44 @@ private void mediaStreamTrackSetEnabledAsync(String id, boolean enabled) {
getUserMediaImpl.mediaStreamTrackSetEnabled(id, enabled);
}

private static final String SWITCH_CAMERA_ERROR = "SWITCH_CAMERA_ERROR";

@ReactMethod
public void mediaStreamTrackSwitchCamera(String id, Promise promise) {
MediaStreamTrack track = getLocalTrack(id);
if (track != null) {
try {
getUserMediaImpl.switchCamera(id, new VideoCaptureController.SwitchCameraHandler() {
@Override
public void onSwitchCameraDone(String facingMode) {
promise.resolve(facingMode);
}
});
}
catch (Exception e) {
promise.reject(SWITCH_CAMERA_ERROR, e);
}
}
else {
promise.reject(SWITCH_CAMERA_ERROR, "Local track not found when attempting to switch camera");
}
}

private static final String GET_CAMERA_FACING_MODE_ERROR = "GET_CAMERA_FACING_MODE_ERROR";

@ReactMethod
public void mediaStreamTrackSwitchCamera(String id) {
public void mediaStreamTrackGetCameraFacingMode(String id, Promise promise) {
MediaStreamTrack track = getLocalTrack(id);
if (track != null) {
getUserMediaImpl.switchCamera(id);
try {
promise.resolve(getUserMediaImpl.getCameraFacingMode(id));
}
catch (Exception e) {
promise.reject(GET_CAMERA_FACING_MODE_ERROR, e);
}
}
else {
promise.reject(GET_CAMERA_FACING_MODE_ERROR, "Local track not found when attempting to get camera facing mode");
}
}

Expand Down
3 changes: 2 additions & 1 deletion ios/RCTWebRTC/VideoCaptureController.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
andConstraints:(NSDictionary *)constraints;
-(void)startCapture;
-(void)stopCapture;
-(void)switchCamera;
-(NSString *)switchCamera;
-(NSString *)facingMode;

@end
7 changes: 6 additions & 1 deletion ios/RCTWebRTC/VideoCaptureController.m
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,15 @@ -(void)stopCapture {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

-(void)switchCamera {
-(NSString *)switchCamera {
_usingFrontCamera = !_usingFrontCamera;

[self startCapture];
return [self facingMode];
}

-(NSString *)facingMode {
return _usingFrontCamera ? @"user" : @"environment";
}

#pragma mark Private
Expand Down
26 changes: 24 additions & 2 deletions ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,35 @@ - (RTCVideoTrack *)createVideoTrack:(NSDictionary *)constraints {
}
}

RCT_EXPORT_METHOD(mediaStreamTrackSwitchCamera:(nonnull NSString *)trackID)
RCT_EXPORT_METHOD(mediaStreamTrackSwitchCamera:(nonnull NSString *)trackID
withResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
RTCMediaStreamTrack *track = self.localTracks[trackID];
if (track) {
RTCVideoTrack *videoTrack = (RTCVideoTrack *)track;
[videoTrack.videoCaptureController switchCamera];
NSString *newFacingMode = [videoTrack.videoCaptureController switchCamera];
resolve(newFacingMode);
return;
}
reject(@"switch_camera_error",
@"Local track not found when attempting to switch camera",
nil);
}

RCT_EXPORT_METHOD(mediaStreamTrackGetCameraFacingMode:(nonnull NSString *)trackID
withResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
RTCMediaStreamTrack *track = self.localTracks[trackID];
if (track) {
RTCVideoTrack *videoTrack = (RTCVideoTrack *)track;
resolve([videoTrack.videoCaptureController facingMode]);
return;
}
reject(@"get_camera_facing_mode_error",
@"Local track not found when attempting to get camera facing mode",
nil);
}

#pragma mark - Helpers
Expand Down

0 comments on commit 6987854

Please sign in to comment.