Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions apps/simple-camera/__tests__/visioncamera.controller.harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,6 @@ describe('VisionCamera - Controller', () => {
await session.start()

try {
// TODO: Add setTorchMode('on', STRENGTH) test when we expose something like
// CameraDevice.supportsTorchStrength - currently this might throw on
// some phones without a way to check upfront if it supports setting strength!
await controller.setTorchMode('on')
expect(controller.torchMode).toBe('on')

Expand All @@ -146,6 +143,46 @@ describe('VisionCamera - Controller', () => {
}
})

it('sets torchMode with a specific strength when the device supports it', async () => {
if (backDevice.maxTorchStrength === 0) {
console.log(
'[SKIP] torchStrength: device only supports binary torch (maxTorchStrength === 0)',
)
return
}
const session = await VisionCamera.createCameraSession(false)
const photoOutput = VisionCamera.createPhotoOutput({
targetResolution: CommonResolutions.HD_4_3,
containerFormat: 'jpeg',
quality: 0.8,
qualityPrioritization: 'balanced',
})
const [controller] = await session.configure([
{
input: backDevice,
outputs: [{ output: photoOutput, mirrorMode: 'auto' }],
constraints: [],
},
])
if (controller == null) throw new Error('no controller')
await session.start()

try {
const target = backDevice.maxTorchStrength / 2
await controller.setTorchMode('on', target)
expect(controller.torchMode).toBe('on')
expect(controller.torchStrength).toBeGreaterThan(0)
expect(controller.torchStrength).toBeLessThanOrEqual(
backDevice.maxTorchStrength,
)

await controller.setTorchMode('off')
expect(controller.torchMode).toBe('off')
} finally {
await session.stop()
}
})

it('sets exposure bias to min/max when the device supports it', async () => {
if (!backDevice.supportsExposureBias) {
console.log('[SKIP] exposureBias: not supported on this device')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,14 @@ class HybridCameraDevice(

override val hasTorch: Boolean
get() = cameraInfo.hasFlashUnit()
override val maxTorchStrength: Double
// CameraX reports `maxTorchStrengthLevel == 1` for devices that only
// support binary torch (on/off) and `> 1` for devices that accept a
// strength level. Our public `setTorchMode(mode, strength?)` API
// normalizes the incoming strength to 0..1 before multiplying by
// `maxTorchStrengthLevel`, so the public maximum is always `1.0`
// when strength is configurable, and `0.0` otherwise.
get() = if (cameraInfo.maxTorchStrengthLevel > 1) 1.0 else 0.0

override val supportsLowLightBoost: Boolean
get() = cameraInfo.isLowLightBoostSupported
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class HybridPhysicalCameraDevice(
override val maxWhiteBalanceGain: Double = 0.0
override val hasFlash: Boolean = false
override val hasTorch: Boolean = false
override val maxTorchStrength: Double = 0.0
override val supportsLowLightBoost: Boolean = false
override val minZoom: Double = 0.0
override val maxZoom: Double = 0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
return device.hasTorch
}

var maxTorchStrength: Double {
// AVCaptureDevice.maxAvailableTorchLevel is a platform constant (1.0).
// When the device has a torch, torch strength is always configurable via
// setTorchModeOn(level:) in the 0...1 range.
return device.hasTorch ? Double(AVCaptureDevice.maxAvailableTorchLevel) : 0.0
}

var supportsLowLightBoost: Bool {
return device.isLowLightBoostSupported
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,21 @@ export interface CameraDevice
* @see {@linkcode CameraController.setTorchMode | setTorchMode(...)}
*/
readonly hasTorch: boolean
/**
* The maximum `strength` value accepted by
* {@linkcode CameraController.setTorchMode | setTorchMode('on', strength)}.
*
* - `0` — Configurable torch strength is **not supported** on this device.
* You may still call {@linkcode CameraController.setTorchMode | setTorchMode('on')}
* / `setTorchMode('off')` to toggle the torch, but passing a specific
* {@linkcode CameraController.setTorchMode | strength} value is not supported
* and will throw.
* - `> 0` — Strength is configurable in the normalized range
* from `0` (off) to `maxTorchStrength` (brightest).
*
* @see {@linkcode CameraController.setTorchMode | setTorchMode(...)}
*/
readonly maxTorchStrength: number

// pragma MARK: Low Light Boost
/**
Expand Down
Loading