How to Observe Torchlevel in Swift

iOS check if torch is on

While this doesn't technically solve the problem this is KVO code for determining a state change in the torch. Maybe this could help. I am trying to solve the same problem but am unable to access any information about the torch that is turned on from the control center. It seems there should be some other way using KVO or something else to know if the torch is currently active or not.

static void * const torchActiveObservationContext = (void*)&torchActiveObservationContext;

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == torchActiveObservationContext) {
AVCaptureDevice *thisDevice = (AVCaptureDevice*)object;
NSLog( @"Current torch level: %f", thisDevice.torchActive);
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

-(id) init {
if (self = [super init]) {
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

[videoDevice addObserver:self forKeyPath:@"torchActive" options:NSKeyValueObservingOptionNew context:torchActiveObservationContext];

// whatever other initialization code ...
}
return self;
}

I also tried using torchLevel and torchMode to no avail. This is a real issue because I want to leave the torch on if it is on already when taking over control of the AVCaptureDevice.

torchLevel KVO - iOS

It took a while for me to figure out how to do this but I believe this KVO code will work for you. I haven't tested this code out thoroughly but I did get it basically working in an app:

static void * const torchLevelObservationContext = (void*)&torchLevelObservationContext;

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == torchLevelObservationContext) {
AVCaptureDevice *thisDevice = (AVCaptureDevice*)object;
NSLog( @"Current torch level: %f", thisDevice.torchLevel);
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

-(id) init {
if (self = [super init]) {
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

[videoDevice addObserver:self forKeyPath:@"torchLevel" options:NSKeyValueObservingOptionNew context:torchLevelObservationContext];

// whatever other initialization code ...
}
return self;
}

Caveat: the main reason I was trying to use this code is to determine the current state of the torch that is turned on via the control center so I could leave it on when using the AVCaptureDevice and the torch is turned off for some reason once the capture starts. But no matter what I tried (torchActive, torchMode, torchLevel), I was unable to determine the state. This code only seems to work after it has taken control of the AVCaptureDevice and is using it an AVCaptureSession. If anyone knows how to get the current state of the flashlight or torch that is turned on from the control center, that is what I am trying to do.

iOS: Torch level on iPhone 11 Pro

I remembered that back in the iOS 3.x days we didn't have simple LED API. We had to start a full video capture session. Well it turns out that with the iPhone 11 this seems to be the only solution. I'd love to hear about others which don't require this.

This is my tested workaround. I am using Objective C here, not Swift because that's what I used in this old app from 2009! You can easily find Swift code to start video capture (and ignore the output, it should work the same.

AVCaptureSession* session = [[AVCaptureSession alloc] init];

AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];
if ([session canAddInput:deviceInput]) {
[session addInput:deviceInput];
}

AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

CALayer *rootLayer = self.view.layer;
[rootLayer setMasksToBounds:YES];

CGRect frame = self.view.frame;
[previewLayer setFrame:frame];
[rootLayer insertSublayer:previewLayer atIndex:0];

//This is where you'd save the video with AVCaptureVideoDataOutput but of course we don't.

[session startRunning];

And after this you just start the LED as usual:

NSError *error = nil;

if ([inputDevice isTorchModeSupported:AVCaptureTorchModeOn])
[inputDevice setTorchModeOnWithLevel:1.0 error:&error];

This gets maximum brightness on my iPhone 11 Pro. I am now looking for the same solution without having to use the video capture (which obviously uses battery AND requires a permission, which users may not like. It needs to be explained well).

setTorchModeOnWithLevel from string

You need to cast torchLevel to Float.

Or make it float explicitly like so :

var torchLevel : Float = 0.0

How to turn flashlight ON and OFF in swift?

Update #1: (torchActive isn't returning the expected value; perhaps because it's been modified)

Update #2: For Swift 2.0

To toggle the flash from on to off (not just "on" as in mad pig's answer), you can use the following method:

func toggleFlash() {
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
if (device.hasTorch) {
do {
try device.lockForConfiguration()
if (device.torchMode == AVCaptureTorchMode.On) {
device.torchMode = AVCaptureTorchMode.Off
} else {
do {
try device.setTorchModeOnWithLevel(1.0)
} catch {
print(error)
}
}
device.unlockForConfiguration()
} catch {
print(error)
}
}
}

I used nested do-catch blocks to implement Awesomeness's suggestion from the comments. This way, even if try device.setTorchModeOnWithLevel(1.0) fails, the device is properly unlocked for configuration.

Update #3: For Swift 4:

(I edited the code a bit to my personal taste)

func toggleFlash() {
guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return }
guard device.hasTorch else { return }

do {
try device.lockForConfiguration()

if (device.torchMode == AVCaptureDevice.TorchMode.on) {
device.torchMode = AVCaptureDevice.TorchMode.off
} else {
do {
try device.setTorchModeOn(level: 1.0)
} catch {
print(error)
}
}

device.unlockForConfiguration()
} catch {
print(error)
}
}

Original answer:

To toggle the flash from on to off (not just "on" as in mad pig's answer), you can use the following method:

func toggleFlash() {
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
if (device.hasTorch) {
device.lockForConfiguration(nil)
let torchOn = !device.torchActive
device.setTorchModeOnWithLevel(1.0, error: nil)
device.torchMode = torchOn ? AVCaptureTorchMode.On : AVCaptureTorchMode.Off
device.unlockForConfiguration()
}
}

Turn on torch/flash on iPhone

the lockforConfiguration is set in your code, where you declare your AVCaptureDevice is a property.

[videoCaptureDevice lockForConfiguration:nil];


Related Topics



Leave a reply



Submit