Skip to content

Commit 7186153

Browse files
authored
Merge pull request #46 from GetStream/fix/fix-camera-facing
fix for camera facing
2 parents bbc798e + 5797a55 commit 7186153

File tree

5 files changed

+94
-35
lines changed

5 files changed

+94
-35
lines changed

android/src/main/java/io/getstream/webrtc/flutter/GetUserMediaImpl.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -792,12 +792,12 @@ private ConstraintsMap getUserVideo(ConstraintsMap constraints, MediaStream medi
792792
deviceId = result.first;
793793
VideoCapturer videoCapturer = result.second;
794794

795-
if (facingMode == null && cameraEnumerator.isFrontFacing(deviceId)) {
795+
if (cameraEnumerator.isFrontFacing(deviceId)) {
796796
facingMode = "user";
797-
} else if (facingMode == null && cameraEnumerator.isBackFacing(deviceId)) {
797+
} else if (cameraEnumerator.isBackFacing(deviceId)) {
798798
facingMode = "environment";
799799
}
800-
// else, leave facingMode as it was
800+
// else, leave facingMode as it was (for non-standard cameras)
801801

802802
PeerConnectionFactory pcFactory = stateProvider.getPeerConnectionFactory();
803803
VideoSource videoSource = pcFactory.createVideoSource(false);
@@ -841,6 +841,7 @@ private ConstraintsMap getUserVideo(ConstraintsMap constraints, MediaStream medi
841841
info.fps = targetFps;
842842
info.capturer = videoCapturer;
843843
info.cameraName = deviceId;
844+
info.isFrontFacing = cameraEnumerator.isFrontFacing(deviceId);
844845

845846
// Find actual capture format.
846847
Size actualSize = null;
@@ -992,12 +993,15 @@ private void requestPermissions(
992993
}
993994

994995
void switchCamera(String id, Result result) {
995-
VideoCapturer videoCapturer = mVideoCapturers.get(id).capturer;
996-
if (videoCapturer == null) {
996+
VideoCapturerInfoEx info = mVideoCapturers.get(id);
997+
if (info == null || info.capturer == null) {
997998
resultError("switchCamera", "Video capturer not found for id: " + id, result);
998999
return;
9991000
}
10001001

1002+
VideoCapturer videoCapturer = info.capturer;
1003+
boolean currentIsFrontFacing = info.isFrontFacing;
1004+
10011005
CameraEnumerator cameraEnumerator;
10021006

10031007
if (Camera2Enumerator.isSupported(applicationContext)) {
@@ -1010,21 +1014,24 @@ void switchCamera(String id, Result result) {
10101014
// if sourceId given, use specified sourceId first
10111015
final String[] deviceNames = cameraEnumerator.getDeviceNames();
10121016
for (String name : deviceNames) {
1013-
if (cameraEnumerator.isFrontFacing(name) == !isFacing) {
1017+
if (cameraEnumerator.isFrontFacing(name) == !currentIsFrontFacing) {
1018+
final String targetCameraName = name;
1019+
final boolean newIsFrontFacing = !currentIsFrontFacing;
10141020
CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) videoCapturer;
10151021
cameraVideoCapturer.switchCamera(
10161022
new CameraVideoCapturer.CameraSwitchHandler() {
10171023
@Override
10181024
public void onCameraSwitchDone(boolean b) {
1019-
isFacing = !isFacing;
1020-
result.success(b);
1025+
info.isFrontFacing = newIsFrontFacing;
1026+
info.cameraName = targetCameraName;
1027+
result.success(info.isFrontFacing);
10211028
}
10221029

10231030
@Override
10241031
public void onCameraSwitchError(String s) {
10251032
resultError("switchCamera", "Switching camera failed: " + id, result);
10261033
}
1027-
}, name);
1034+
}, targetCameraName);
10281035
return;
10291036
}
10301037
}
@@ -1066,8 +1073,6 @@ void stopRecording(Integer id, String albumName, Runnable onFinished) {
10661073
}
10671074
}
10681075

1069-
1070-
10711076
public void reStartCamera(IsCameraEnabled getCameraId) {
10721077
for (Map.Entry<String, VideoCapturerInfoEx> item : mVideoCapturers.entrySet()) {
10731078
if (!item.getValue().isScreenCapture && getCameraId.isEnabled(item.getKey())) {
@@ -1084,8 +1089,9 @@ public interface IsCameraEnabled {
10841089
boolean isEnabled(String id);
10851090
}
10861091

1087-
public static class VideoCapturerInfoEx extends VideoCapturerInfo {
1092+
public static class VideoCapturerInfoEx extends VideoCapturerInfo {
10881093
public CameraEventsHandler cameraEventsHandler;
1094+
public boolean isFrontFacing;
10891095
}
10901096

10911097
public VideoCapturerInfoEx getCapturerInfo(String trackId) {

common/darwin/Classes/CameraUtils.m

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -272,33 +272,66 @@ - (void)mediaStreamTrackSetExposurePoint:(nonnull RTCMediaStreamTrack*)track
272272
}
273273

274274
- (void)mediaStreamTrackSwitchCamera:(RTCMediaStreamTrack*)track result:(FlutterResult)result {
275+
NSString* trackId = track.trackId;
276+
NSMutableDictionary* captureState = self.videoCaptureState[trackId];
277+
275278
if (!self.videoCapturer) {
276-
NSLog(@"Video capturer is null. Can't switch camera");
277-
return;
279+
NSLog(@"Video capturer is null. Can't switch camera");
280+
result([FlutterError errorWithCode:@"Error while switching camera"
281+
message:@"Video capturer not found"
282+
details:nil]);
283+
return;
278284
}
285+
279286
#if TARGET_OS_IPHONE
280287
[self.videoCapturer stopCapture];
281288
#endif
282-
self._usingFrontCamera = !self._usingFrontCamera;
289+
290+
BOOL usingFrontCamera;
291+
NSInteger targetWidth;
292+
NSInteger targetHeight;
293+
NSInteger targetFps;
294+
295+
if (captureState) {
296+
// Use per-track state
297+
usingFrontCamera = [captureState[@"usingFrontCamera"] boolValue];
298+
targetWidth = [captureState[@"targetWidth"] integerValue];
299+
targetHeight = [captureState[@"targetHeight"] integerValue];
300+
targetFps = [captureState[@"targetFps"] integerValue];
301+
} else {
302+
// Use global state for backward compatibility
303+
usingFrontCamera = self._usingFrontCamera;
304+
targetWidth = self._lastTargetWidth;
305+
targetHeight = self._lastTargetHeight;
306+
targetFps = self._lastTargetFps;
307+
}
308+
309+
usingFrontCamera = !usingFrontCamera;
283310
AVCaptureDevicePosition position =
284-
self._usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
311+
usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
285312
AVCaptureDevice* videoDevice = [self findDeviceForPosition:position];
286313
AVCaptureDeviceFormat* selectedFormat = [self selectFormatForDevice:videoDevice
287-
targetWidth:self._lastTargetWidth
288-
targetHeight:self._lastTargetHeight];
314+
targetWidth:targetWidth
315+
targetHeight:targetHeight];
289316
[self.videoCapturer startCaptureWithDevice:videoDevice
290-
format:selectedFormat
291-
fps:[self selectFpsForFormat:selectedFormat
292-
targetFps:self._lastTargetFps]
293-
completionHandler:^(NSError* error) {
294-
if (error != nil) {
295-
result([FlutterError errorWithCode:@"Error while switching camera"
296-
message:@"Error while switching camera"
297-
details:error]);
298-
} else {
299-
result([NSNumber numberWithBool:self._usingFrontCamera]);
300-
}
301-
}];
317+
format:selectedFormat
318+
fps:[self selectFpsForFormat:selectedFormat
319+
targetFps:targetFps]
320+
completionHandler:^(NSError* error) {
321+
if (error != nil) {
322+
result([FlutterError errorWithCode:@"Error while switching camera"
323+
message:@"Error while switching camera"
324+
details:error]);
325+
} else {
326+
// Update per-track state
327+
if (captureState) {
328+
captureState[@"usingFrontCamera"] = @(usingFrontCamera);
329+
}
330+
// Update global state for backward compatibility
331+
self._usingFrontCamera = usingFrontCamera;
332+
result([NSNumber numberWithBool:usingFrontCamera]);
333+
}
334+
}];
302335
}
303336

304337

common/darwin/Classes/FlutterRTCMediaStream.m

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ - (void)getUserVideo:(NSDictionary*)constraints
413413
AVCaptureDevice* videoDevice;
414414
NSString* videoDeviceId = nil;
415415
NSString* facingMode = nil;
416+
AVCaptureDevicePosition position = AVCaptureDevicePositionUnspecified;
416417
NSArray<AVCaptureDevice*>* captureDevices = [self captureDevices];
417418

418419
if ([videoConstraints isKindOfClass:[NSDictionary class]]) {
@@ -456,7 +457,6 @@ - (void)getUserVideo:(NSDictionary*)constraints
456457
// https://www.w3.org/TR/mediacapture-streams/#def-constraint-facingMode
457458
facingMode = videoConstraints[@"facingMode"];
458459
if (facingMode && [facingMode isKindOfClass:[NSString class]]) {
459-
AVCaptureDevicePosition position;
460460
if ([facingMode isEqualToString:@"environment"]) {
461461
self._usingFrontCamera = NO;
462462
position = AVCaptureDevicePositionBack;
@@ -486,6 +486,10 @@ - (void)getUserVideo:(NSDictionary*)constraints
486486
videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
487487
}
488488

489+
if (videoDevice && position == AVCaptureDevicePositionUnspecified) {
490+
position = videoDevice.position;
491+
}
492+
489493
int possibleWidth = [self getConstrainInt:videoConstraints forKey:@"width"];
490494
if (possibleWidth != 0) {
491495
targetWidth = possibleWidth;
@@ -551,10 +555,6 @@ - (void)getUserVideo:(NSDictionary*)constraints
551555
NSInteger selectedWidth = (NSInteger) selectedDimension.width;
552556
NSInteger selectedHeight = (NSInteger) selectedDimension.height;
553557
NSInteger selectedFps = [self selectFpsForFormat:selectedFormat targetFps:targetFps];
554-
555-
self._lastTargetFps = selectedFps;
556-
self._lastTargetWidth = targetWidth;
557-
self._lastTargetHeight = targetHeight;
558558

559559
NSLog(@"target format %ldx%ld, targetFps: %ld, selected format: %ldx%ld, selected fps %ld", targetWidth, targetHeight, targetFps, selectedWidth, selectedHeight, selectedFps);
560560

@@ -583,6 +583,21 @@ - (void)getUserVideo:(NSDictionary*)constraints
583583
LocalVideoTrack *localVideoTrack = [[LocalVideoTrack alloc] initWithTrack:videoTrack videoProcessing:videoProcessingAdapter];
584584

585585
__weak RTCCameraVideoCapturer* capturer = self.videoCapturer;
586+
587+
// Store camera state per track
588+
NSMutableDictionary* captureState = [NSMutableDictionary new];
589+
captureState[@"usingFrontCamera"] = @(position == AVCaptureDevicePositionFront);
590+
captureState[@"targetWidth"] = @(targetWidth);
591+
captureState[@"targetHeight"] = @(targetHeight);
592+
captureState[@"targetFps"] = @(selectedFps);
593+
self.videoCaptureState[videoTrack.trackId] = captureState;
594+
595+
// Update global state for backward compatibility
596+
self._usingFrontCamera = (position == AVCaptureDevicePositionFront);
597+
self._lastTargetFps = selectedFps;
598+
self._lastTargetWidth = targetWidth;
599+
self._lastTargetHeight = targetHeight;
600+
586601
self.videoCapturerStopHandlers[videoTrack.trackId] = ^(CompletionHandler handler) {
587602
NSLog(@"Stop video capturer, trackID %@", videoTrack.trackId);
588603
[capturer stopCaptureWithCompletionHandler:handler];

common/darwin/Classes/FlutterWebRTCPlugin.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ typedef void (^CapturerStopHandler)(CompletionHandler _Nonnull handler);
4747
NSMutableDictionary<NSNumber*, FlutterRTCMediaRecorder*>* _Nonnull recorders;
4848
@property(nonatomic, strong)
4949
NSMutableDictionary<NSString*, CapturerStopHandler>* _Nullable videoCapturerStopHandlers;
50+
@property(nonatomic, strong)
51+
NSMutableDictionary<NSString*, NSMutableDictionary*>* _Nullable videoCaptureState;
5052

5153
@property(nonatomic, strong)
5254
NSMutableDictionary<NSString*, RTCFrameCryptor*>* _Nullable frameCryptors;

common/darwin/Classes/FlutterWebRTCPlugin.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ - (instancetype)initWithChannel:(FlutterMethodChannel*)channel
211211
self.dataCryptors = [NSMutableDictionary new];
212212
self.keyProviders = [NSMutableDictionary new];
213213
self.videoCapturerStopHandlers = [NSMutableDictionary new];
214+
self.videoCaptureState = [NSMutableDictionary new];
214215
self.recorders = [NSMutableDictionary new];
215216
#if TARGET_OS_IPHONE
216217
self.focusMode = @"locked";
@@ -696,6 +697,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
696697
result(nil);
697698
});
698699
[self.videoCapturerStopHandlers removeObjectForKey:videoTrack.trackId];
700+
[self.videoCaptureState removeObjectForKey:videoTrack.trackId];
699701
}
700702
}
701703
for (RTCAudioTrack* track in stream.audioTracks) {
@@ -793,6 +795,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
793795
NSLog(@"video capturer stopped, trackID = %@", track.trackId);
794796
});
795797
[self.videoCapturerStopHandlers removeObjectForKey:track.trackId];
798+
[self.videoCaptureState removeObjectForKey:track.trackId];
796799
}
797800
}
798801
}

0 commit comments

Comments
 (0)