@@ -134,13 +134,23 @@ - (UIImageOrientation)getImageRotation {
134
134
}
135
135
@end
136
136
137
- static AVCaptureFlashMode getFlashModeForString (NSString *mode) {
137
+ // Mirrors FlashMode in flash_mode.dart
138
+ typedef enum {
139
+ FlashModeOff,
140
+ FlashModeAuto,
141
+ FlashModeAlways,
142
+ FlashModeTorch,
143
+ } FlashMode;
144
+
145
+ static FlashMode getFlashModeForString (NSString *mode) {
138
146
if ([mode isEqualToString: @" off" ]) {
139
- return AVCaptureFlashModeOff ;
147
+ return FlashModeOff ;
140
148
} else if ([mode isEqualToString: @" auto" ]) {
141
- return AVCaptureFlashModeAuto ;
149
+ return FlashModeAuto ;
142
150
} else if ([mode isEqualToString: @" always" ]) {
143
- return AVCaptureFlashModeOn;
151
+ return FlashModeAlways;
152
+ } else if ([mode isEqualToString: @" torch" ]) {
153
+ return FlashModeTorch;
144
154
} else {
145
155
NSError *error = [NSError errorWithDomain: NSCocoaErrorDomain
146
156
code: NSURLErrorUnknown
@@ -152,6 +162,20 @@ static AVCaptureFlashMode getFlashModeForString(NSString *mode) {
152
162
}
153
163
}
154
164
165
+ static AVCaptureFlashMode getAVCaptureFlashModeForFlashMode (FlashMode mode) {
166
+ switch (mode) {
167
+ case FlashModeOff:
168
+ return AVCaptureFlashModeOff;
169
+ case FlashModeAuto:
170
+ return AVCaptureFlashModeAuto;
171
+ case FlashModeAlways:
172
+ return AVCaptureFlashModeOn;
173
+ case FlashModeTorch:
174
+ default :
175
+ return -1 ;
176
+ }
177
+ }
178
+
155
179
// Mirrors ResolutionPreset in camera.dart
156
180
typedef enum {
157
181
veryLow,
@@ -219,7 +243,7 @@ @interface FLTCam : NSObject <FlutterTexture,
219
243
@property (assign , nonatomic ) BOOL isAudioSetup;
220
244
@property (assign , nonatomic ) BOOL isStreamingImages;
221
245
@property (assign , nonatomic ) ResolutionPreset resolutionPreset;
222
- @property (assign , nonatomic ) AVCaptureFlashMode flashMode;
246
+ @property (assign , nonatomic ) FlashMode flashMode;
223
247
@property (assign , nonatomic ) CMTime lastVideoSampleTime;
224
248
@property (assign , nonatomic ) CMTime lastAudioSampleTime;
225
249
@property (assign , nonatomic ) CMTime videoTimeOffset;
@@ -250,7 +274,7 @@ - (instancetype)initWithCameraName:(NSString *)cameraName
250
274
_enableAudio = enableAudio;
251
275
_dispatchQueue = dispatchQueue;
252
276
_captureSession = [[AVCaptureSession alloc ] init ];
253
- _flashMode = AVCaptureFlashModeAuto ;
277
+ _flashMode = FlashModeAuto ;
254
278
255
279
_captureDevice = [AVCaptureDevice deviceWithUniqueID: cameraName];
256
280
NSError *localError = nil ;
@@ -303,7 +327,10 @@ - (void)captureToFile:(FlutterResult)result API_AVAILABLE(ios(10)) {
303
327
if (_resolutionPreset == max) {
304
328
[settings setHighResolutionPhotoEnabled: YES ];
305
329
}
306
- [settings setFlashMode: _flashMode];
330
+ AVCaptureFlashMode avFlashMode = getAVCaptureFlashModeForFlashMode (_flashMode);
331
+ if (avFlashMode != -1 ) {
332
+ [settings setFlashMode: avFlashMode];
333
+ }
307
334
NSError *error;
308
335
NSString *path = [self getTemporaryFilePathWithExtension: @" jpg"
309
336
subfolder: @" pictures"
@@ -694,25 +721,51 @@ - (void)resumeVideoRecordingWithResult:(FlutterResult)result {
694
721
}
695
722
696
723
- (void )setFlashModeWithResult : (FlutterResult)result mode : (NSString *)modeStr {
697
- AVCaptureFlashMode mode;
724
+ FlashMode mode;
698
725
@try {
699
726
mode = getFlashModeForString (modeStr);
700
727
} @catch (NSError *e) {
701
728
result (getFlutterError (e));
702
729
return ;
703
730
}
704
- if (!_captureDevice.hasFlash ) {
705
- result ([FlutterError errorWithCode: @" setFlashModeFailed"
706
- message: @" Device does not have flash capabilities"
707
- details: nil ]);
708
- return ;
709
- }
710
- if (![_capturePhotoOutput.supportedFlashModes
711
- containsObject: [NSNumber numberWithInt: ((int )mode)]]) {
712
- result ([FlutterError errorWithCode: @" setFlashModeFailed"
713
- message: @" Device does not support this specific flash mode"
714
- details: nil ]);
715
- return ;
731
+ if (mode == FlashModeTorch) {
732
+ if (!_captureDevice.hasTorch ) {
733
+ result ([FlutterError errorWithCode: @" setFlashModeFailed"
734
+ message: @" Device does not support torch mode"
735
+ details: nil ]);
736
+ return ;
737
+ }
738
+ if (!_captureDevice.isTorchAvailable ) {
739
+ result ([FlutterError errorWithCode: @" setFlashModeFailed"
740
+ message: @" Torch mode is currently not available"
741
+ details: nil ]);
742
+ return ;
743
+ }
744
+ if (_captureDevice.torchMode != AVCaptureTorchModeOn) {
745
+ [_captureDevice lockForConfiguration: nil ];
746
+ [_captureDevice setTorchMode: AVCaptureTorchModeOn];
747
+ [_captureDevice unlockForConfiguration ];
748
+ }
749
+ } else {
750
+ if (!_captureDevice.hasFlash ) {
751
+ result ([FlutterError errorWithCode: @" setFlashModeFailed"
752
+ message: @" Device does not have flash capabilities"
753
+ details: nil ]);
754
+ return ;
755
+ }
756
+ AVCaptureFlashMode avFlashMode = getAVCaptureFlashModeForFlashMode (mode);
757
+ if (![_capturePhotoOutput.supportedFlashModes
758
+ containsObject: [NSNumber numberWithInt: ((int )avFlashMode)]]) {
759
+ result ([FlutterError errorWithCode: @" setFlashModeFailed"
760
+ message: @" Device does not support this specific flash mode"
761
+ details: nil ]);
762
+ return ;
763
+ }
764
+ if (_captureDevice.torchMode != AVCaptureTorchModeOff) {
765
+ [_captureDevice lockForConfiguration: nil ];
766
+ [_captureDevice setTorchMode: AVCaptureTorchModeOff];
767
+ [_captureDevice unlockForConfiguration ];
768
+ }
716
769
}
717
770
_flashMode = mode;
718
771
result (nil );
@@ -854,6 +907,12 @@ - (BOOL)setupWriterForPath:(NSString *)path {
854
907
[_audioOutput setSampleBufferDelegate: self queue: _dispatchQueue];
855
908
}
856
909
910
+ if (_flashMode == FlashModeTorch) {
911
+ [self .captureDevice lockForConfiguration: nil ];
912
+ [self .captureDevice setTorchMode: AVCaptureTorchModeOn];
913
+ [self .captureDevice unlockForConfiguration ];
914
+ }
915
+
857
916
[_videoWriter addInput: _videoWriterInput];
858
917
[_captureVideoOutput setSampleBufferDelegate: self queue: _dispatchQueue];
859
918
0 commit comments