import type { HybridObject } from 'react-native-nitro-modules'; import type { CameraController } from '../CameraController.nitro'; import type { ListenerSubscription } from '../common-types/ListenerSubscription'; import type { CameraSessionConfiguration } from './CameraSessionConfiguration'; import type { CameraSessionConnection } from './CameraSessionConnection'; export type InterruptionReason = 'video-device-not-available-in-background' | 'audio-device-in-use-by-another-client' | 'video-device-in-use-by-another-client' | 'video-device-not-available-with-multiple-foreground-apps' | 'video-device-not-available-due-to-system-pressure' | 'sensitive-content-mitigation-activated' | 'unknown'; /** * Represents a Camera Session. * * A Camera Session can have {@linkcode CameraSessionConnection}s * to stream from an input device ({@linkcode CameraDevice}) * to an output ({@linkcode CameraOutput}). * * It is recommended to configure the {@linkcode CameraSession} * properly before starting it ({@linkcode start | start()}) to * avoid reconfiguration hiccups. * * You can create and use a Camera Session via the * {@linkcode useCamera | useCamera(...)} hook, or by * using the imperative APIs directly, which gives you * more control over individual properties like * {@linkcode CameraOutputConfiguration.mirrorMode | mirrorMode} * per output, or multi-cam {@linkcode CameraSession}s. * * @example * Create a Camera Session using the hooks: * ```ts * const device = ... * const photoOutput = ... * const camera = useCamera({ * isActive: true, * input: device, * outputs: [photoOutput] * }) * ``` * @example * Create a single Camera Session using the imperative API: * ```ts * const session = await VisionCamera.createCameraSession(false) * const [controller] = await session.configure([ * { * input: device, * outputs: [ * { output: previewOutput, mirrorMode: 'auto' }, * { output: photoOutput, mirrorMode: 'auto' }, * ], * constraints: [] * } * ]) * await session.start() * ``` * @example * Create a multi-cam Camera Session to stream from both the front-, * and back-Camera using the imperative API: * ```ts * if (VisionCamera.supportsMultiCamSessions) { * const deviceFactory = await VisionCamera.createDeviceFactory() * const deviceCombinations = deviceFactory.supportedMultiCamDeviceCombinations * // ... get `frontDevice` and `backDevice` from one of * // the combinations in `deviceCombinations`. * const session = await VisionCamera.createCameraSession(true) * const [frontController, backController] = await session.configure([ * // Front Camera * { * input: frontDevice, * outputs: [ * { output: frontPreviewOutput, mirrorMode: 'on' }, * { output: frontPhotoOutput, mirrorMode: 'off' }, * ], * constraints: [] * }, * // Back Camera * { * input: backDevice, * outputs: [ * { output: backPreviewOutput, mirrorMode: 'off' }, * { output: backPhotoOutput, mirrorMode: 'off' }, * ], * constraints: [] * } * ]) * await session.start() * } * ``` */ export interface CameraSession extends HybridObject<{ ios: 'swift'; android: 'kotlin'; }> { /** * Gets whether this {@linkcode CameraSession} is currently * running, or not. */ readonly isRunning: boolean; /** * Configures the {@linkcode CameraSession} with the given * {@linkcode connections}, and returns one {@linkcode CameraController} * per {@linkcode CameraSessionConnection}. * * One {@linkcode CameraSessionConnection} defines a connection * from one {@linkcode CameraDevice} (the _input_) to multiple * {@linkcode CameraOutput}s (the _outputs_). * * @note In a Multi-Cam Camera Session, the given {@linkcode connections}' input devices * must be supported to be used together in a Multi-Cam Camera Session, as not every * {@linkcode CameraDevice} can be used with every other {@linkcode CameraDevice} * simultaneously. See {@linkcode CameraDeviceFactory.supportedMultiCamDeviceCombinations} * for a full list of supported combinations. * * @note Some supported combinations can contain a single virtual * {@linkcode CameraDevice}, such as an iOS Dual- or Triple-Camera. Pass the * returned devices directly to {@linkcode configure | configure(...)} instead * of expanding virtual devices via {@linkcode CameraDevice.physicalDevices}. * * @param connections The list of connections from one _input_ to * multiple _outputs_. If this {@linkcode CameraSession} was created * as a multi-cam session (see {@linkcode CameraFactory.createCameraSession | createCameraSession(enableMultiCam)}), * you can add multiple {@linkcode CameraSessionConnection}s. * @param config Configures session-wide configuration, * such as {@linkcode CameraSessionConfiguration.allowBackgroundAudioPlayback}. * * @returns One {@linkcode CameraController} per {@linkcode CameraSessionConnection}. * * @throws If Camera Permission has not been granted - see {@linkcode CameraFactory.cameraPermissionStatus} * @throws If multiple {@linkcode connections} are added, but the * {@linkcode CameraSession} was not created as a multi-cam session. * @throws If hardware resources are being exhausted by too large connection graphs. * @throws If this is a Multi-Cam session, but the connection inputs are not supported to * be used together - see {@linkcode CameraDeviceFactory.supportedMultiCamDeviceCombinations} * * @example * Creating a simple Preview + Photo connection: * ```ts * const session = ... * const device = ... * const [controller] = await session.configure([ * { * input: device, * outputs: [ * { output: previewOutput, mirrorMode: 'auto' }, * { output: photoOutput, mirrorMode: 'auto' }, * ], * constraints: [] * } * ]) * ``` * @example * Configuring constraints (e.g. 60 FPS): * ```ts * const session = ... * const device = ... * const [controller] = await session.configure([ * { * input: device, * outputs: [ * { output: previewOutput, mirrorMode: 'auto' }, * { output: photoOutput, mirrorMode: 'auto' }, * ], * constraints: [ * { fps: 60 } * ] * } * ]) * await session.start() * ``` * @example * Creating a multi-cam session with front- and back Camera: * ```ts * if (VisionCamera.supportsMultiCamSessions) { * const deviceFactory = await VisionCamera.createDeviceFactory() * const deviceCombinations = deviceFactory.supportedMultiCamDeviceCombinations * // ... get `frontDevice` and `backDevice` from one of * // the combinations in `deviceCombinations`. * const session = await VisionCamera.createCameraSession(true) * const [frontController, backController] = await session.configure([ * // Front Camera * { * input: frontDevice, * outputs: [ * { output: frontPreviewOutput, mirrorMode: 'on' }, * { output: frontPhotoOutput, mirrorMode: 'off' }, * ], * constraints: [] * }, * // Back Camera * { * input: backDevice, * outputs: [ * { output: backPreviewOutput, mirrorMode: 'off' }, * { output: backPhotoOutput, mirrorMode: 'off' }, * ], * constraints: [] * } * ]) * await session.start() * } * ``` */ configure(connections: CameraSessionConnection[], config?: CameraSessionConfiguration): Promise; /** * Starts the {@linkcode CameraSession}. * * To avoid any runtime hiccups, it's good practice * to configure everything via {@linkcode configure | configure(...)} * before starting the {@linkcode CameraSession}. */ start(): Promise; /** * Stops the {@linkcode CameraSession}. */ stop(): Promise; /** * Adds a listener to when the {@linkcode CameraSession} * started running. */ addOnStartedListener(onStarted: () => void): ListenerSubscription; /** * Adds a listener to when the {@linkcode CameraSession} * stopped running. */ addOnStoppedListener(onStopped: () => void): ListenerSubscription; /** * Adds a listener to when the {@linkcode CameraSession} * encountered an error. */ addOnErrorListener(onError: (error: Error) => void): ListenerSubscription; /** * Adds a listener to when the {@linkcode CameraSession} * was interrupted, for example when the phone overheated, * or the user received a FaceTime call. */ addOnInterruptionStartedListener(onInterruptionStarted: (reason: InterruptionReason) => void): ListenerSubscription; /** * Adds a listener to when a {@linkcode CameraSession} * interruption has ended and the Camera continues * to run again. */ addOnInterruptionEndedListener(onInterruptionEnded: () => void): ListenerSubscription; }