Skip to content
Merged
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
49 changes: 48 additions & 1 deletion apps/simple-camera/__tests__/visioncamera.session.harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import {
it,
waitUntil,
} from 'react-native-harness'
import type { CameraDeviceFactory } from 'react-native-vision-camera'
import type {
CameraDeviceFactory,
TargetCameraPosition,
} from 'react-native-vision-camera'
import { CommonResolutions, VisionCamera } from 'react-native-vision-camera'
import { provider as workletsProvider } from 'react-native-vision-camera-worklets'
import { scheduleOnRN } from 'react-native-worklets'
Expand Down Expand Up @@ -71,6 +74,50 @@ describe('VisionCamera - Session', () => {
}
})

it('configures a session directly from each target camera position', async () => {
const positions: TargetCameraPosition[] = ['back', 'front', 'external']
const session = await VisionCamera.createCameraSession(false)
const previewOutput = VisionCamera.createPreviewOutput()
const photoOutput = VisionCamera.createPhotoOutput({
containerFormat: 'native',
quality: 1,
qualityPrioritization: 'balanced',
targetResolution: CommonResolutions.HD_4_3,
})

try {
for (const position of positions) {
const hasDeviceAtPosition = factory.cameraDevices.some(
(device) => device.position === position,
)
const configurePromise = session.configure([
{
input: position,
outputs: [
{
output: previewOutput,
mirrorMode: position === 'front' ? 'on' : 'auto',
},
{ output: photoOutput, mirrorMode: 'auto' },
],
constraints: [],
},
])

if (!hasDeviceAtPosition) {
await expect(configurePromise).rejects.toThrow()
continue
}

const controllers = await configurePromise
expect(controllers).toHaveLength(1)
expect(controllers[0]?.device.position).toBe(position)
}
} finally {
await session.stop()
}
})

it('fires onStarted/onStopped exactly once per lifecycle', async () => {
const device = factory.getDefaultCamera('back')
expect(device).toBeDefined()
Expand Down
8 changes: 5 additions & 3 deletions docs/content/docs/camera-extensions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Some [`CameraDevice`](/api/react-native-vision-camera/hybrid-objects/CameraDevic

### Getting available Extensions

To get all available [`CameraExtension`](/api/react-native-vision-camera/hybrid-objects/CameraExtension)s, use [`getSupportedExtensions(...)`](/api/react-native-vision-camera/functions/getSupportedExtensions):
To get all available [`CameraExtension`](/api/react-native-vision-camera/hybrid-objects/CameraExtension)s, use [`useCameraDeviceExtensions(...)`](/api/react-native-vision-camera/functions/useCameraDeviceExtensions) or [`CameraDeviceFactory.getSupportedExtensions(...)`](/api/react-native-vision-camera/hybrid-objects/CameraDeviceFactory#getsupportedextensions):

<Tabs items={["Hooks", "Imperative"]} groupId="hooks-or-imperative" persist>
<Tab value="Hooks">
Expand All @@ -22,7 +22,8 @@ const extensions = useCameraDeviceExtensions(device)
<Tab value="Imperative">
```ts
const device = ...
const extensions = await getSupportedExtensions(device)
const deviceFactory = await VisionCamera.createDeviceFactory()
const extensions = await deviceFactory.getSupportedExtensions(device)
```
</Tab>
</Tabs>
Expand Down Expand Up @@ -71,7 +72,8 @@ function App() {
```tsx
const device = ...
const session = ...
const extensions = await getSupportedExtensions(device)
const deviceFactory = await VisionCamera.createDeviceFactory()
const extensions = await deviceFactory.getSupportedExtensions(device)
const extension = extensions.find((e) => e.type === 'night')

const controllers = await session.configure([
Expand Down
6 changes: 2 additions & 4 deletions docs/content/docs/camera-outputs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,12 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
const photoOutput = ...
const videoOutput = ...

await session.configure([
{
input: device,
input: 'back',
// [!code ++]
outputs: [
{ output: photoOutput, mirrorMode: 'auto' },
Expand Down Expand Up @@ -154,12 +153,11 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
const output = ...

await session.configure([
{
input: device,
input: 'back',
outputs: [
{ output: output, mirrorMode: 'auto' }
],
Expand Down
9 changes: 3 additions & 6 deletions docs/content/docs/constraints.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,10 @@ const session = await VisionCamera.createCameraSession(false)
const videoOutput = createVideoOutput({
targetResolution: CommonResolutions.UHD_16_9
})
const device = await getDefaultCameraDevice('back')

await session.configure([
{
input: device,
input: 'back',
outputs: [videoOutput],
// [!code ++:4]
constraints: [
Expand Down Expand Up @@ -136,11 +135,10 @@ const session = await VisionCamera.createCameraSession(false)
const videoOutput = createVideoOutput({
targetResolution: CommonResolutions.UHD_16_9
})
const device = await getDefaultCameraDevice('back')

await session.configure([
{
input: device,
input: 'back',
outputs: [videoOutput],
// [!code ++:4]
constraints: [
Expand Down Expand Up @@ -217,11 +215,10 @@ const session = await VisionCamera.createCameraSession(false)
const videoOutput = createVideoOutput({
targetResolution: CommonResolutions.UHD_16_9
})
const device = await getDefaultCameraDevice('back')

await session.configure([
{
input: device,
input: 'back',
outputs: [videoOutput],
// [!code ++:3]
constraints: [
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/depth-output.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
// [!code ++:9]
const depthOutput = VisionCamera.createDepthFrameOutput({ /* options */ })
const workletRuntime = createWorkletRuntimeForThread(depthOutput.thread)
Expand All @@ -76,7 +75,7 @@ scheduleOnRuntime(workletRuntime, () => {

await session.configure([
{
input: device,
input: 'back',
outputs: [
// [!code ++]
{ output: depthOutput, mirrorMode: 'auto' }
Expand Down
24 changes: 13 additions & 11 deletions docs/content/docs/devices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const device = useCameraDevice("back")
</Tab>
<Tab value="Imperative">
```ts
const device = await getDefaultCameraDevice("back")
const deviceFactory = await VisionCamera.createDeviceFactory()
const device = deviceFactory.getDefaultCamera("back")
```
</Tab>
</Tabs>
Expand Down Expand Up @@ -79,8 +80,8 @@ const device = useCameraDevice("back", {
</Tab>
<Tab value="Imperative">
```ts
const devices = getAllCameraDevices()
const device = getCameraDevice(devices, "back", {
const deviceFactory = await VisionCamera.createDeviceFactory()
const device = getCameraDevice(deviceFactory, "back", {
physicalDevices: ['ultra-wide-angle', 'wide-angle', 'telephoto']
})
```
Expand Down Expand Up @@ -111,8 +112,9 @@ const devices = useCameraDevices()
</Tab>
<Tab value="Imperative">
```ts
let devices = getAllCameraDevices()
addOnCameraDevicesChangedListener((d) => {
const deviceFactory = await VisionCamera.createDeviceFactory()
let devices = deviceFactory.cameraDevices
deviceFactory.addOnCameraDevicesChangedListener((d) => {
devices = d
})
```
Expand All @@ -134,14 +136,14 @@ As an external Camera is plugged in or plugged out from the device, the [`useCam
</Tab>
<Tab value="Imperative">
```ts
const devices = getAllCameraDevices()
let device = getCameraDevice(devices, "external")
addOnCameraDevicesChangedListener((d) => {
device = getCameraDevice(d, "external")
const deviceFactory = await VisionCamera.createDeviceFactory()
let device = getCameraDevice(deviceFactory, "external")
deviceFactory.addOnCameraDevicesChangedListener(() => {
device = getCameraDevice(deviceFactory, "external")
})
```

As an external Camera is plugged in or plugged out from the device, the [`addOnCameraDevicesChangedListener(...)`](/api/react-native-vision-camera/functions/addOnCameraDevicesChangedListener) listener fires and you can call [`getCameraDevice(...)`](/api/react-native-vision-camera/functions/getCameraDevice) again to possibly detect new devices, or avoid using removed devices.
As an external Camera is plugged in or plugged out from the device, the [`CameraDeviceFactory.addOnCameraDevicesChangedListener(...)`](/api/react-native-vision-camera/hybrid-objects/CameraDeviceFactory#addoncameradeviceschangedlistener) listener fires and you can call [`getCameraDevice(...)`](/api/react-native-vision-camera/functions/getCameraDevice) again to possibly detect new devices, or avoid using removed devices.
</Tab>
</Tabs>

Expand Down Expand Up @@ -182,7 +184,7 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
const device = ...
await session.configure([
{
// [!code ++]
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/fps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,9 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
await session.configure([
{
input: device,
input: 'back',
constraints: [
// [!code ++]
{ fps: 60 }
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/frame-output.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
// [!code ++:9]
const frameOutput = VisionCamera.createFrameOutput({ /* options */ })
const workletRuntime = createWorkletRuntimeForThread(frameOutput.thread)
Expand All @@ -79,7 +78,7 @@ scheduleOnRuntime(workletRuntime, () => {

await session.configure([
{
input: device,
input: 'back',
outputs: [
// [!code ++]
{ output: frameOutput, mirrorMode: 'auto' }
Expand Down
3 changes: 2 additions & 1 deletion docs/content/docs/low-light-boost.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ function App() {
```tsx
const device = ...
const session = ...
const extensions = await getSupportedExtensions(device)
const deviceFactory = await VisionCamera.createDeviceFactory()
const extensions = await deviceFactory.getSupportedExtensions(device)
const extension = extensions.find((e) => e.type === 'night')

const controllers = await session.configure([
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/object-output.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
// [!code ++:6]
const objectOutput = VisionCamera.createObjectOutput({
enabledObjectTypes: ['qr']
Expand All @@ -70,7 +69,7 @@ objectOutput.setOnObjectsScannedCallback((objects) => {

await session.configure([
{
input: device,
input: 'back',
outputs: [
// [!code ++]
{ output: objectOutput, mirrorMode: 'auto' }
Expand Down
6 changes: 3 additions & 3 deletions docs/content/docs/performance.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ const slowerDevice = useCameraDevice('back', {
<Tab value="Imperative API">

```ts
const devices = getAllCameraDevices()
const fasterDevice = getCameraDevice(devices, 'back', {
const deviceFactory = await VisionCamera.createDeviceFactory()
const fasterDevice = getCameraDevice(deviceFactory, 'back', {
physicalDevices: ['wide-angle-camera'],
})
const slowerDevice = getCameraDevice(devices, 'back', {
const slowerDevice = getCameraDevice(deviceFactory, 'back', {
physicalDevices: ['ultra-wide-angle-camera', 'wide-angle-camera', 'telephoto-camera'],
})
```
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/photo-output.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
// [!code ++]
const photoOutput = VisionCamera.createPhotoOutput({ /* options */ })

await session.configure([
{
input: device,
input: 'back',
outputs: [
// [!code ++]
{ output: photoOutput, mirrorMode: 'auto' }
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/preview-output.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
// [!code ++]
const previewOutput = VisionCamera.createPreviewOutput()

await session.configure([
{
input: device,
input: 'back',
outputs: [
// [!code ++]
{ output: previewOutput, mirrorMode: 'auto' }
Expand Down
3 changes: 1 addition & 2 deletions docs/content/docs/video-output.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@ function App() {
<Tab value="CameraSession (imperative)">
```tsx
const session = await VisionCamera.createCameraSession(false)
const device = await getDefaultCameraDevice('back')
// [!code ++]
const videoOutput = VisionCamera.createVideoOutput({ /* options */ })

await session.configure([
{
input: device,
input: 'back',
outputs: [
// [!code ++]
{ output: videoOutput, mirrorMode: 'auto' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ final class HybridBarcodeScannerOutput: HybridCameraOutputSpec, NativeCameraOutp
}
}

func configure(config: CameraOutputConfiguration) {
func configure(config: OutputConfiguration) {
guard let connection = self.output.connection(with: .video) else {
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import VisionCamera
final class HybridLocationManager: HybridLocationManagerSpec {
private let manager = CLLocationManager()
private let delegate = LocationDelegate()
private var permissionPromises: [Promise<Bool>] = []
var lastKnownLocation: (any HybridLocationSpec)? {
guard let location = manager.location else {
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.edit
import com.facebook.react.bridge.ReactApplicationContext
import com.margelo.nitro.NitroModules
import com.margelo.nitro.camera.extensions.getDefaultCamera
import com.margelo.nitro.camera.extensions.mapToArray
import com.margelo.nitro.camera.hybrids.inputs.HybridCameraDevice
import com.margelo.nitro.camera.hybrids.inputs.HybridCameraExtension
Expand Down Expand Up @@ -112,18 +113,8 @@ class HybridCameraDeviceFactory(

@OptIn(ExperimentalLensFacing::class)
override fun getDefaultCamera(position: TargetCameraPosition): HybridCameraDeviceSpec? {
val selector =
when (position) {
TargetCameraPosition.FRONT -> CameraSelector.DEFAULT_FRONT_CAMERA
TargetCameraPosition.BACK -> CameraSelector.DEFAULT_BACK_CAMERA
TargetCameraPosition.EXTERNAL ->
CameraSelector
.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_EXTERNAL)
.build()
}
try {
val defaultCamera = cameraProvider.getCameraInfo(selector)
val defaultCamera = cameraProvider.getDefaultCamera(position)
return HybridCameraDevice(defaultCamera)
} catch (e: Throwable) {
Log.e(TAG, "No default ${position.name} Camera found!", e)
Expand Down
Loading
Loading