AVCaptureDevice isTorchActive does not work for React Native - ios

I've tried to write my own module to detect is torch turned on/off.
According to documentation I've tried to run KVC as below
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == torchActiveObservationContext) {
AVCaptureDevice *thisDevice = (AVCaptureDevice*)object;
[self sendEventWithName:#"TorchEvent" body:#{#"isTorchActive": thisDevice.isTorchActive ? #"ACTIVE" : #"INACTIVE"}];
NSLog( #"Current torch level: %f", thisDevice.torchLevel);
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
NSLog( #"ABCDEF");
}
}
-(id) init {
if (self = [super init]) {
NSLog( #"Start Initialization");
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
[videoDevice addObserver:self forKeyPath:#"isTorchActive" options:NSKeyValueObservingOptionNew context:torchActiveObservationContext];
NSLog( #"End Initialization");
// whatever other initialization code ...
}
return self;
}
But I noticed that any change is recorded if i try to turn on the torch in Control Panel. So i tried to do it much easier and check the current torch state manually. I created simple method:
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isTorchActive)
{
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCapturePhotoSettings *photosettings = [AVCapturePhotoSettings photoSettings];
NSLog( videoDevice.isTorchActive ? #"on" : #"off");
NSLog( #"Level : %f", videoDevice.torchLevel);
return videoDevice.isTorchActive ? #"on" : #"off";
}
But it returns "off" all the time, even if torch is initially flashed. Torch level is 0.0.
What am I doing wrong?

Replace videoDevice.isTorchActive with videoDevice.torchMode == AVCaptureTorchModeOn If torch was previously activated from Control Center, you can get AVCaptureTorchModeOff, when running this code first time.

Related

How to get notified when user allows the camera access alert in iOS?

I want to record a video after a count down 3 2 1. But on first time without allowing the camera the video has started recording without showing to camera . I want to call the recording code in the block which is called when the user allow to camera on camera access alert.
self.recordingManager.previewLayer.frame = CGRectMake(47, 2000, 280, 154);
// set code for count down
imageArr = [[NSArray alloc]initWithObjects:#"countdown_three",#"countdown_two",#"countdown_one", nil];
[_countImageView setImage:[UIImage imageNamed:[imageArr objectAtIndex:0]]];
[_countImageView setHidden:NO];
NSLog(#"%#",[imageArr objectAtIndex:0]);
count = 4;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(setCountDownDuration) userInfo:nil repeats:YES];
// customize progressbar
_captureProgress.hidden = NO;
_captureProgress.progress = 0.0;
_captureProgress.layer.borderWidth = 0.2;
_captureProgress.layer.borderColor = [UIColor colorWithRed:167.0f/255 green:188.0f/255 blue:219.0f/255 alpha:1].CGColor;
CGAffineTransform transform = CGAffineTransformMakeScale(1.6f, 8.0f);
_captureProgress.transform = transform;
count--;
if (count == 3) {
[self.progressStatusLbl setText:#"GET READY"];
[_countImageView setImage:[UIImage imageNamed:[imageArr objectAtIndex:0]]];
}
if (count == 2) {
[_countImageView setImage:[UIImage imageNamed:[imageArr objectAtIndex:1]]];
}
if (count == 1) {
[_countImageView setImage:[UIImage imageNamed:[imageArr objectAtIndex:2]]];
}
if (count == 0) {
[timer invalidate];
timer = nil;
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusAuthorized)
{
[self.progressStatusLbl setText:#"RECORDING"];
[self openCamera];
}
else if(authStatus == AVAuthorizationStatusNotDetermined)
{
NSLog(#"%#", #"Camera access not determined. Ask for permission.");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted)
{
if(granted)
{
NSLog(#"Granted access to %#", AVMediaTypeVideo);
[self.progressStatusLbl setText:#"RECORDING"];
[self openCamera];
}
else
{
NSLog(#"Not granted access to %#", AVMediaTypeVideo);
[self camDenied];
}
}];
}
else if (authStatus == AVAuthorizationStatusRestricted)
{
// My own Helper class is used here to pop a dialog in one simple line.
//[Helper popAlertMessageWithTitle:#"Error" alertText:#"You've been restricted from using the camera on this device. Without camera access this feature won't work. Please contact the device owner so they can give you access."];
[Utils showAlertMessageWithTitle:#"Error" msg:#"You've been restricted from using the camera on this device. Without camera access this feature won't work. Please contact the device owner so they can give you access." firstButtonTitle:#"Ok" secontButtonTitle:nil];
}
else
{
[self camDenied];
}
For AVAuthorizationStatusNotDetermined state, add observer for a key (boolean), and update this flag in completion of requestAccessForMediaType then start camera or call camDenied deoending on user's actions.
So you code should look like as below:
Add a new private property in your class
#property (nonatomic, strong) NSNumber *granted;
then add following methods
- (void)askForPermission {
NSLog(#"%#", #"Camera access not determined. Ask for permission.");
[self addObserver:self forKeyPath:#"granted" options:NSKeyValueObservingOptionNew context:nil];
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted)
{
self.granted = #(granted);
}];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"granted"]) {
BOOL granted = [object boolValue];
if(granted)
{
NSLog(#"Granted access to %#", AVMediaTypeVideo);
[self.progressStatusLbl setText:#"RECORDING"];
[self openCamera];
}
else
{
NSLog(#"Not granted access to %#", AVMediaTypeVideo);
[self camDenied];
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
call askForPermission in AVAuthorizationStatusNotDetermined case.

iOS - AVCaptureDevice - Autofocus & Exposure with camera capture

I have been implementing Custom Camera using AVCaptureDevice, which require AutoFocus & Exposure to work nicely. I am using the following code to do the camera initialisation
- (void) initializeCamera {
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(status == AVAuthorizationStatusAuthorized) { // authorized
[self.captureVideoPreviewLayer removeFromSuperlayer];
self.captureSession = [[AVCaptureSession alloc] init];
self.captureSession.sessionPreset = AVCaptureSessionPresetPhoto;
[self removeDeviceObserverForFocus];
self.captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
[self addDeviceObserverForFocus];
NSError *error = nil;
[self.captureDevice lockForConfiguration:nil]; //you must lock before setting torch mode
[self.captureDevice setSubjectAreaChangeMonitoringEnabled:YES];
[self.captureDevice unlockForConfiguration];
//Capture layer
self.captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
self.captureVideoPreviewLayer.bounds = CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), CGRectGetHeight([UIScreen mainScreen].bounds));
self.captureVideoPreviewLayer.position = CGPointMake(CGRectGetMidX(self.captureVideoPreviewLayer.bounds), CGRectGetMidY(self.captureVideoPreviewLayer.bounds));
[self.captureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
self.captureVideoPreviewLayer.connection.enabled = YES;
[self.viewCamera.layer insertSublayer:self.captureVideoPreviewLayer atIndex:0];
//Capture input
self.captureInput = [AVCaptureDeviceInput deviceInputWithDevice:self.captureDevice error:&error];
if (!self.captureInput) {
[self capturePhoto];
}
else {
if ([self.captureSession canAddInput:self.captureInput]) {
[self.captureSession addInput:self.captureInput];
}
}
self.captureOutput = [[AVCaptureStillImageOutput alloc] init];
[self.captureOutput setOutputSettings:#{AVVideoCodecKey : AVVideoCodecJPEG}];
[self.captureSession addOutput:self.captureOutput];
//THIS LINE
[self.captureSession setSessionPreset:AVCaptureSessionPresetPhoto];
// setup metadata capture
AVCaptureMetadataOutput *metadataOutput = [[AVCaptureMetadataOutput alloc] init];
CGRect visibleMetadataOutputRect = [self.captureVideoPreviewLayer metadataOutputRectOfInterestForRect:self.vwCamera.bounds];
metadataOutput.rectOfInterest = visibleMetadataOutputRect;
[self.captureSession addOutput:metadataOutput];
dispatch_async(dispatch_get_main_queue(), ^{
[self.captureSession startRunning];
});
}
else if(status == AVAuthorizationStatusNotDetermined){ // not determined
//Try for getting permission
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
[self performSelectorOnMainThread:#selector(initializeCamera) withObject:nil waitUntilDone:NO];
}];
}
}
- (void)removeDeviceObserverForFocus {
#try {
while ([self.captureDevice observationInfo] != nil) {
[self.captureDevice removeObserver:self forKeyPath:#"adjustingFocus"];
}
}
#catch (NSException *exception) {
NSLog(#"Exception");
}
#finally {
}
}
- (void)addDeviceObserverForFocus {
[self.captureDevice addObserver:self forKeyPath:#"adjustingFocus" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if( [keyPath isEqualToString:#"adjustingFocus"] ){
BOOL adjustingFocus = [ [change objectForKey:NSKeyValueChangeNewKey] isEqualToNumber:[NSNumber numberWithInt:1] ];
if (adjustingFocus) {
[self showFocusSquareAtPoint:self.viewCamera.center];
}
}
}
To monitor focus by movement of camera I am doing the following..
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(avCaptureDeviceSubjectAreaDidChangeNotification:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:nil];
#pragma mark - AVCaptureDeviceSubjectAreaDidChangeNotification
-(void)avCaptureDeviceSubjectAreaDidChangeNotification:(NSNotification *)notification{
CGPoint devicePoint = CGPointMake( 0.5, 0.5 );
[self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposeWithMode:AVCaptureExposureModeContinuousAutoExposure atDevicePoint:devicePoint monitorSubjectAreaChange:NO];
[self showFocusSquareAtPoint:self.vwCamera.center];
}
- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange
{
dispatch_async( dispatch_get_main_queue(), ^{
AVCaptureDevice *device = self.captureDevice;
NSError *error = nil;
if ( [device lockForConfiguration:&error] ) {
// Setting (focus/exposure)PointOfInterest alone does not initiate a (focus/exposure) operation.
// Call -set(Focus/Exposure)Mode: to apply the new point of interest.
if ( device.isFocusPointOfInterestSupported && [device isFocusModeSupported:focusMode] ) {
device.focusPointOfInterest = point;
device.focusMode = focusMode;
}
if ( device.isExposurePointOfInterestSupported && [device isExposureModeSupported:exposureMode] ) {
device.exposurePointOfInterest = point;
device.exposureMode = exposureMode;
}
device.subjectAreaChangeMonitoringEnabled = monitorSubjectAreaChange;
[device unlockForConfiguration];
}
else {
NSLog( #"Could not lock device for configuration: %#", error );
}
} );
}
Everything works as expected when I use this [self.captureSession setSessionPreset:AVCaptureSessionPresetPhoto];
If I change the camera preset to something else like AVCaptureSessionPresetHigh AutoFocus and Exposure doesn't work well as expected..
Anyone who has come across such situation?
Thank you for help.
Are you trying to take a picture or record video? Cause the High preset is for video and the exposure and focus work differently(I believe). Here is info on the different presets in the docs - AVCaptureSessionPresets

How to turn off Torch when leaving (segue) from view?

I have made an app that utilizes Torch. I have a button that turns torch on / off. However, if user turns torch on, then navigates away from view, torch stays on. User must navigate back to view to turn off. What I want is for the torch to turn off automatically when user navigates away from page.
Using Xcode 5.1.1; ios 7; this app primarily for iPhone
Here is the code I use for Torch:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize btnFlash;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btnFlashOnClicked:(id)sender
{
AVCaptureDevice *flashLight = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if ([flashLight isTorchAvailable] && [flashLight isTorchModeSupported:AVCaptureTorchModeOn])
{
BOOL success = [flashLight lockForConfiguration:nil];
if (success)
{
if ([flashLight isTorchActive])
{
[btnFlash setTitle:#"Light On" forState:UIControlStateNormal];
[flashLight setTorchMode:AVCaptureTorchModeOff];
}
else
{
[btnFlash setTitle:#"Light Off" forState:UIControlStateNormal];
[flashLight setTorchMode:AVCaptureTorchModeOn];
}
[flashLight unlockForConfiguration];
}
}
}
#end
OK, break down the functionality into methods that allow easy querying of the current light state and methods to turn it on or off:
- (AVCaptureDevice *)flashLight
{
AVCaptureDevice *flashLight = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if (![flashLight isTorchAvailable] ||
![flashLight isTorchModeSupported:AVCaptureTorchModeOn]) {
flashLight = nil;
}
return flashLight;
}
- (BOOL)isLightOn
{
BOOL isOn = NO;
AVCaptureDevice *flashLight = [self flashLight];
if ([flashLight lockForConfiguration:nil]) {
isOn = [flashLight isTorchActive];
[flashLight unlockForConfiguration];
}
return isOn;
}
- (void)turnLightOn:(BOOL)on
{
AVCaptureDevice *flashLight = [self flashLight];
if ([flashLight lockForConfiguration:nil]) {
[flashLight setTorchMode:on ? AVCaptureTorchModeOn : AVCaptureTorchModeOff];
[flashLight unlockForConfiguration];
}
}
as that will make it easier to simply call turnLightOn:NO regardless of the current state and easier to manipulate in your action method:
- (IBAction)btnFlashOnClicked:(id)sender
{
BOOL newState = ![self isTorchOn];
[self turnLightOn:newState];
[btnFlash setTitle:newState ? #"Light Off" : #"Light On"
forState:UIControlStateNormal];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self turnLightOn:NO];
}
You could turn the torch off inside the method:
- (void)viewDidDisappear:(BOOL)animated
simply paste the following in your view controller:
- (void)viewDidDisappear:(BOOL)animated{
[super viewDidAppear:animated];
// your code to turn the torch off goes here
}

AVCaptureDevice Low Light Boost Does Not work

The low light boost property of AVCaptureDevice is not enabling when it should. I am testing this on an iPhone 5 with iOS 6. Here's the code:
// finds a device that supports the video media type
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSArray *allDevices = [AVCaptureDevice devices];
for (AVCaptureDevice *currentDevice in allDevices) {
if (currentDevice.position == AVCaptureDevicePositionBack) {
device = currentDevice;
}
}
NSError *deviceError = nil;
if (device.isFlashAvailable){
[device lockForConfiguration:&deviceError];
device.flashMode = AVCaptureFlashModeAuto;
[device unlockForConfiguration];
}
if ([device respondsToSelector:#selector(isLowLightBoostSupported)]) {
if ([device lockForConfiguration:nil]) {
if (device.isLowLightBoostSupported)
device.automaticallyEnablesLowLightBoostWhenAvailable = YES;
[device unlockForConfiguration];
}
}
if ([device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
[device lockForConfiguration:&deviceError];
device.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
// CODE FOR device.exposurePointOfInterest determined from wherever the face is based off of the faceScan method
[device unlockForConfiguration];
}
AVCaptureDeviceInput *newVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&deviceError];
AVCaptureStillImageOutput *newStillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
AVVideoCodecJPEG, AVVideoCodecKey,
nil];
[newStillImageOutput setOutputSettings:outputSettings];
self.sess = [[AVCaptureSession alloc] init];
if ([self.sess canAddInput:newVideoInput]) {
[self.sess addInput:newVideoInput];
}
if ([self.sess canAddOutput:newStillImageOutput]) {
[self.sess addOutput:newStillImageOutput];
}
self.stillImageOutput = newStillImageOutput;
if (device.lowLightBoostEnabled) {
NSLog(#"ENABLED");
}
// register as an observer of changes to lowLightBoostEnabled
[device addObserver:self forKeyPath:#"automaticallyEnablesLowLightBoostWhenAvailable" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqual:#"lowLightBoostEnabled"]) {
NSLog(#"lowLightBoostEnabled changed");
NSNumber *boostIsActiveValue = [change objectForKey:NSKeyValueChangeNewKey];
BOOL boostIsActive = boostIsActiveValue.boolValue;
NSLog(#"is low light boost currently active: %d", boostIsActive);
}
}
Can anyone give me any help? I've looked online but haven't found very conclusive results. I'd appreciate all the help I can get.
You need to lockForConfiguration, according to the docs (well, the header file):
if ([[self backFacingCamera] respondsToSelector:#selector(isLowLightBoostSupported)]) {
if ([[self backFacingCamera] lockForConfiguration:nil]) {
if ([self backFacingCamera].isLowLightBoostSupported)
[self backFacingCamera].automaticallyEnablesLowLightBoostWhenAvailable = YES;
[[self backFacingCamera] unlockForConfiguration];
}
}
Also, isLowLightBoostEnabled tells you whether or not the low light is actually being boosted, not whether it can be. That's the isLowLightBoostSupported selector, as above (to which only iOS 6 devices respond).

Capture images in the background?

I'm trying to capture images in the background from the camera without loading a camera or preview interface.
In my app photos are taken in the background with no preview screen, just the normal app screen and then shown to the user later.
Can someone please point me in the right direction?
You have to use AVCaptureSession & AVCaptureDeviceInput.
This is part of code may help you:
#interface MyViewController : UIViewController
{
AVCaptureStillImageOutput *_output;
AVCaptureConnection *_videoConnection;
bool _isCaptureSessionStarted;
}
#property (retain, nonatomic) AVCaptureDevice *frontalCamera;
- (void)takePhoto;
Implementation:
#interface MyViewController ()
#end
#implementation MyViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_isCaptureSessionStarted = false;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Finding frontal camera
NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (int i = 0; i < cameras.count; i++) {
AVCaptureDevice *camera = [cameras objectAtIndex:i];
if (camera.position == AVCaptureDevicePositionFront) {
self.frontalCamera = camera;
[self.frontalCamera addObserver:self forKeyPath:#"adjustingExposure" options:NSKeyValueObservingOptionNew context:nil];
[self.frontalCamera addObserver:self forKeyPath:#"adjustingWhiteBalance" options:NSKeyValueObservingOptionNew context:nil];
}
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (!self.frontalCamera.adjustingExposure && !self.frontalCamera.adjustingWhiteBalance) {
if (_isCaptureSessionStarted) {
[self captureStillImage];
}
}
}
- (void)takePhoto
{
if (self.frontalCamera != nil) {
// Add camera to session
AVCaptureSession *session = [[AVCaptureSession alloc] init];
NSError *error;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:self.frontalCamera error:&error];
if (!error && [session canAddInput:input]) {
[session addInput:input];
// Capture still image
_output = [[AVCaptureStillImageOutput alloc] init];
// Captured image settings
[_output setOutputSettings:[[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil]];
if ([session canAddOutput:_output]) {
[session addOutput:_output];
_videoConnection = nil;
for (AVCaptureConnection *connection in _output.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
_videoConnection = connection;
break;
}
}
if (_videoConnection) {
break;
}
}
if (_videoConnection) {
[session startRunning];
NSLock *lock = [[[NSLock alloc] init] autorelease];
[lock lock];
_isCaptureSessionStarted = true;
[lock unlock];
}
}
} else {
NSLog(#"%#",[error localizedDescription]);
}
}
}
- (void) captureStillImage
{
[_output captureStillImageAsynchronouslyFromConnection:_videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
NSLock *lock = [[[NSLock alloc] init] autorelease];
[lock lock];
_isCaptureSessionStarted = false;
[lock unlock];
if (imageDataSampleBuffer != NULL) {
NSData *bitmap = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
// You can get image here via [[UIImage alloc] initWithData:bitmap]
}
}];
}
In a (game ) application on ones phone.. example android cell phone;
is it.. you push the camera button and the frontal power button at the same time.. volume up and or down button with the frontal power button or volume up / down side power button? To capture image of application (app) for like extra points? via that games contest rules.

Resources