blob: 72c5e8709873b2054ad82ae95e1c8d69a7f73bbf [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.camera.camera2.pipe
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.params.MeteringRectangle
import android.hardware.camera2.params.SessionConfiguration
import android.os.Build
import android.view.Surface
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.camera.camera2.pipe.CameraGraph.Constants3A.DEFAULT_FRAME_LIMIT
import androidx.camera.camera2.pipe.CameraGraph.Constants3A.DEFAULT_TIME_LIMIT_NS
import androidx.camera.camera2.pipe.CameraGraph.Flags.FinalizeSessionOnCloseBehavior.Companion.OFF
import androidx.camera.camera2.pipe.CameraGraph.OperatingMode.Companion.EXTENSION
import androidx.camera.camera2.pipe.CameraGraph.OperatingMode.Companion.HIGH_SPEED
import androidx.camera.camera2.pipe.CameraGraph.OperatingMode.Companion.NORMAL
import androidx.camera.camera2.pipe.GraphState.GraphStateStarting
import androidx.camera.camera2.pipe.GraphState.GraphStateStopped
import androidx.camera.camera2.pipe.GraphState.GraphStateStopping
import androidx.camera.camera2.pipe.core.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.flow.StateFlow
/** A [CameraGraph] represents the combined configuration and state of a camera. */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
interface CameraGraph : AutoCloseable {
val streams: StreamGraph
/**
* Returns the state flow of [GraphState], which emits the current state of the [CameraGraph],
* including when a [CameraGraph] is stopped, starting or started.
*/
val graphState: StateFlow<GraphState>
/**
* This is a hint an app can give to a camera graph to indicate whether the camera is being used
* in a foreground setting, for example whether the user could see the app itself. This would
* inform the underlying implementation to open cameras more actively (e.g., longer timeout).
*/
var isForeground: Boolean
/**
* This will cause the [CameraGraph] to start opening the [CameraDevice] and configuring a
* [CameraCaptureSession]. While the CameraGraph is alive it will attempt to keep the camera
* open, active, and in a configured running state.
*/
fun start()
/**
* This will cause the [CameraGraph] to stop executing requests and close the current Camera2
* [CameraCaptureSession] (if one is active). The most recent repeating request will be
* preserved, and any calls to submit a request to a session will be enqueued. To stop requests
* from being enqueued, close the [CameraGraph].
*/
fun stop()
/** Used exclusively interact with the camera via a [Session] from within an existing suspending
* function. This function will suspend until the internal mutex lock can be acquired and
* returned. When possible, prefer [useSession] when possible as it will guarantee that the
* session will be closed.
*
* The returned [Session] **must** be closed.
*/
suspend fun acquireSession(): Session
/**
* Immediately try to acquire access to the internal mutex lock, and return null if it is not
* currently available.
*
* The returned [Session] **must** be closed.
*/
fun acquireSessionOrNull(): Session?
/**
* Used exclusively interact with the camera via a [Session] from within an existing suspending
* function. This method will suspend until the internal mutex lock can be acquired. This is
* similar to [acquireSession] an [use] with the additional guarantee that all launch and async
* calls will complete before the lock is released (unless the [Session] is closed early). The
* [action] will always execute unless parent scope has been canceled.
*
* Example:
* ```
* suspend fun process(cameraGraph: CameraGraph, analysisStream: CameraStream) {
* cameraGraph.useSession { session ->
* val result = session.capture(
* Request(streams = listOf(jpegStream.id))
* )
* val frame = result.awaitFrame()
* val image = frame?.awaitImage(analysisStream.id)
* // process image if not null
* }
* }
* ```
*/
suspend fun <T> useSession(
action: suspend CoroutineScope.(Session) -> T
): T
/**
* Used to exclusively interact with the camera from a normal function with a [Session]
* by acquiring a lock to the internal mutex and running the [action] in the provided [scope].
* This is similar to [useSession] with the additional guarantee that multiple calls to
* [useSessionIn] will be executed in the same order they are invoked in, which is not the case
* for `scope.launch` or `scope.async`. When possible, prefer using this function when
* interacting with a [CameraGraph.Session] from non-suspending code. The [action] will always
* execute unless parent scope has been canceled.
*
* Example:
* ```
* fun capture(
* cameraGraph: CameraGraph, jpegStream: CameraStream, scope: CoroutineScope
* ) {
* cameraGraph.useSessionIn(scope) { session ->
* val result = session.capture(
* Request(streams = listOf(jpegStream.id))
* )
* val frame = result.awaitFrame()
* val jpeg = frame?.awaitImage(jpegStream.id)
* // Save jpeg
* }
* }
* ```
*/
fun <T> useSessionIn(
scope: CoroutineScope,
action: suspend CoroutineScope.(Session) -> T
): Deferred<T>
/**
* This configures the camera graph to use a specific Surface for the given stream.
*
* Changing a surface may cause the camera to stall and/or reconfigure.
*/
fun setSurface(stream: StreamId, surface: Surface?)
/**
* CameraPipe allows setting the global audio restriction through [CameraPipe] and audio
* restrictions on individual [CameraGraph]s. When multiple settings are present, the highest
* level of audio restriction across global and individual [CameraGraph]s is used as the
* device's audio restriction.
*
* Sets the audio restriction of CameraGraph.
*/
fun updateAudioRestrictionMode(mode: AudioRestrictionMode)
/**
* This defines the configuration, flags, and pre-defined structure of a [CameraGraph] instance.
* Note that for parameters, null is considered a valid value, and unset keys are ignored.
*
* @param camera The Camera2 [CameraId] that this [CameraGraph] represents.
* @param streams A list of [CameraStream]s to use when building the configuration.
* @param exclusiveStreamGroups A list of [CameraStream] groups where the [CameraStream]s in
* a group aren't expected to used simultaneously.
* @param input A list of input configurations to support Camera2 Reprocessing.
* @param sessionTemplate The template id to use when creating the [CaptureRequest] to supply
* the default parameters for a [SessionConfiguration] object.
* @param sessionParameters the extra parameters to apply to the [CaptureRequest] used to supply
* the default parameters for a [SessionConfiguration] object. These parameters are *only*
* used to create the [CaptureRequest] for session configuration. Use [defaultParameters] or
* [requiredParameters] to enforce that the key is set for every request.
* @param sessionMode defines the [OperatingMode] of the session. May be used to configure a
* [CameraConstrainedHighSpeedCaptureSession] for slow motion capture (If available)
* @param defaultTemplate The default template to be used if a [Request] does not specify one.
* @param defaultParameters The default parameters to be used for a [Request].
* @param defaultListeners A default set of listeners that will be added to every [Request].
* @param requiredParameters Will override any other configured parameter, and can be used to
* enforce that specific keys are always set to specific value for every [CaptureRequest].
* @param cameraBackendId If defined, this tells the [CameraGraph] to use a specific
* [CameraBackend] to open and operate the camera. The defined [camera] parameter must be a
* camera that can be opened by this [CameraBackend]. If this value is null it will use the
* default backend that has been configured by [CameraPipe].
* @param customCameraBackend If defined, this [customCameraBackend] will be created an used for
* _only_ this [CameraGraph]. This cannot be defined if [cameraBackendId] is defined.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class Config(
val camera: CameraId,
val streams: List<CameraStream.Config>,
val exclusiveStreamGroups: List<List<CameraStream.Config>> = listOf(),
val input: List<InputStream.Config>? = null,
val postviewStream: CameraStream.Config? = null,
val sessionTemplate: RequestTemplate = RequestTemplate(1),
val sessionParameters: Map<*, Any?> = emptyMap<Any, Any?>(),
val sessionMode: OperatingMode = NORMAL,
val defaultTemplate: RequestTemplate = RequestTemplate(1),
val defaultParameters: Map<*, Any?> = emptyMap<Any, Any?>(),
val defaultListeners: List<Request.Listener> = listOf(),
val requiredParameters: Map<*, Any?> = emptyMap<Any, Any?>(),
val cameraBackendId: CameraBackendId? = null,
val customCameraBackend: CameraBackendFactory? = null,
val metadataTransform: MetadataTransform = MetadataTransform(),
val flags: Flags = Flags(),
// TODO: Internal error handling. May be better at the CameraPipe level.
) {
internal var sharedCameraIds: List<CameraId> = emptyList()
init {
check(cameraBackendId == null || customCameraBackend == null) {
"Setting both cameraBackendId and customCameraBackend is not supported."
}
}
}
/**
* Flags define boolean values that are used to adjust the behavior and interactions with
* camera2. These flags should default to the ideal behavior and should be overridden on
* specific devices to be faster or to work around bad behavior.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
data class Flags(
val configureBlankSessionOnStop: Boolean = false,
/**
* When creating a new capture session, the camera framework waits for all the inflight
* capture requests from the prior session before creating the new session. Calling
* abortCaptures() triggers an explicit flush on the camera HAL side. Therefore, aborting
* the captures allows us to switch to a new capture session sooner (see the referenced bug
* for more info).
*
* However, there might be cases where we might not want to trigger the flush. For example,
* if we're recording a video, we may not want the video recording to be disrupted too
* early. Hence, this flag is provided so that we can override this behavior.
*
* Ideally we should be able to invoke abortCaptures() every time during close. However,
* improper flush implementations, which seem to occur largely on older devices, have shown
* to cause irregular behaviors, such as NPEs (b/139448807), capture session entering
* abnormal states (b/162314023), and (potentially) camera device close stalling based on
* testing, etc. Hence, we're enabling this behavior by default on API level >= R (30) for
* now.
*
* - Bug(s): b/287020251
* - API levels: R (30) and above
*/
val abortCapturesOnStop: Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R,
/**
* A quirk that waits for the last repeating capture request to start before stopping the
* current capture session. Please refer to the bugs linked here, or
* [androidx.camera.camera2.pipe.compat.Camera2Quirks.shouldWaitForRepeatingRequest] for
* more information.
*
* This flag provides the overrides for you to override the default behavior (CameraPipe
* would turn on/off the quirk automatically based on device information).
*
* - Bug(s): b/146773463, b/267557892
* - Device(s): Camera devices on hardware level LEGACY
* - API levels: All
*/
val quirkWaitForRepeatingRequestOnDisconnect: Boolean? = null,
/**
* A quirk that finalizes [androidx.camera.camera2.pipe.compat.CaptureSessionState] when
* the CameraGraph is stopped or closed. When a CameraGraph is started, the app might
* wait for the Surfaces to be released before setting the new Surfaces. This creates a
* potential deadlock, and this quirk is aimed to mitigate such behavior by releasing the
* Surfaces (finalizing the session) when the graph is stopped or closed.
*
* - Bug(s): b/277310425
* - Device(s): All (but behaviors might differ across devices)
* - API levels: All
*/
val quirkFinalizeSessionOnCloseBehavior: FinalizeSessionOnCloseBehavior = OFF,
/**
* A quirk that closes the camera capture session when the CameraGraph is stopped or closed.
* This is needed in cases where the app that do not wish to receive further frames, or
* in cases where not closing the capture session before closing the camera device might
* cause the camera close call itself to hang indefinitely.
*
* - Bug(s): b/277310425, b/277310425
* - Device(s): Depends on the situation and the use case.
* - API levels: All
*/
val quirkCloseCaptureSessionOnDisconnect: Boolean = false,
/**
* A quirk that closes the camera device when the CameraGraph is closed. This is needed on
* devices where not closing the camera device before creating a new capture session can
* lead to crashes.
*
* - Bug(s): b/282871038
* - Device(s): Exynos7870 platforms.
* - API levels: All
*/
val quirkCloseCameraDeviceOnClose: Boolean = false,
) {
@JvmInline
value class FinalizeSessionOnCloseBehavior private constructor(val value: Int) {
companion object {
/**
* OFF indicates that the CameraGraph only finalizes capture session under regular
* conditions, i.e., when the camera device is closed, or when a new capture
* session is created.
*/
val OFF = FinalizeSessionOnCloseBehavior(0)
/**
* IMMEDIATE indicates that the CameraGraph will finalize the current session
* immediately when the CameraGraph is stopped or closed. This should be the
* default behavior for devices that allows for immediate Surface reuse.
*/
val IMMEDIATE = FinalizeSessionOnCloseBehavior(1)
/**
* TIMEOUT indicates that the CameraGraph will finalize the current session on a 2s
* timeout when the CameraGraph is stopped or closed. This should only be enabled
* for devices that require waiting for Surfaces to be released.
*/
val TIMEOUT = FinalizeSessionOnCloseBehavior(2)
}
}
}
/**
* Operating mode defines the major categories of how a CameraGraph instance will operate when
* not operating a [NORMAL] camera graph.
*
* @property NORMAL represents standard camera operation and behavior.
* @property HIGH_SPEED represents a camera operating at high frame rate, usually used to
* produce slow motion videos.
* @property EXTENSION represents device-specific modes that may operate differently or have
* significant limitations in order to produce specific kinds of camera results.
*/
@JvmInline
value class OperatingMode private constructor(internal val mode: Int) {
companion object {
val NORMAL = OperatingMode(0)
val HIGH_SPEED = OperatingMode(1)
val EXTENSION = OperatingMode(2)
fun custom(mode: Int): OperatingMode {
require(mode != NORMAL.mode && mode != HIGH_SPEED.mode) {
Log.error { "Custom operating mode $mode conflicts with standard modes" }
}
return OperatingMode(mode)
}
}
}
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
object Constants3A {
// Constants related to controlling the time or frame budget a 3A operation should get.
const val DEFAULT_FRAME_LIMIT: Int = 60
const val DEFAULT_TIME_LIMIT_MS: Int = 3_000
const val DEFAULT_TIME_LIMIT_NS: Long = 3_000_000_000L
// Constants related to metering regions.
/** No metering region is specified. */
val METERING_REGIONS_EMPTY: Array<MeteringRectangle> = emptyArray()
/**
* No-op metering regions, this will tell camera device to pick the right metering region
* for us.
*/
val METERING_REGIONS_DEFAULT: Array<MeteringRectangle> =
arrayOf(MeteringRectangle(0, 0, 0, 0, 0))
/** Placeholder frame number for [Result3A] when a 3A method encounters an error. */
val FRAME_NUMBER_INVALID: FrameNumber = FrameNumber(-1L)
}
/**
* A [Session] is an interactive lock for [CameraGraph] and allows state to be changed.
*
* Holding this object prevents other systems from acquiring a [Session] until the currently
* held session is released. Because of its exclusive nature, [Session]s are intended for fast,
* short-lived state updates, or for interactive capture sequences that must not be altered.
* (Flash photo sequences, for example).
*
* While this object is thread-safe, it should not shared or held for long periods of time.
* Example: A [Session] should *not* be held during video recording.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
interface Session : AutoCloseable {
/**
* Causes the CameraGraph to start or update the current repeating request with the provided
* [Request] object. The [Request] object may be cached, and may be used for other
* interactions with the camera (such as updating 3A, or issuing 3A triggers).
*/
fun startRepeating(request: Request)
/** Stop the current repeating request. */
fun stopRepeating()
/**
* Submit the [Request] to the camera. Requests are issued to the Camera, in order, on a
* background queue. Each call to submit will issue the [Request] to the camera exactly
* once unless the request is invalid, or unless the requests are aborted via [abort].
* The same request can be submitted multiple times.
*/
fun submit(request: Request)
/**
* Submit the [Request]s to the camera. [Request]s are issued to the Camera, in order, on a
* background queue. Each call to submit will issue the List of [Request]s to the camera
* exactly once unless the one or more of the requests are invalid, or unless the requests
* are aborted via [abort]. The same list of [Request]s may be submitted multiple times.
*/
fun submit(requests: List<Request>)
/**
* Submit the [Request] to the camera, and aggregate the results into a [FrameCapture],
* which can be used to wait for the [Frame] to start using [FrameCapture.awaitFrame].
*
* The [FrameCapture] **must** be closed, or it will result in a memory leak.
*/
fun capture(request: Request): FrameCapture
/**
* Submit the [Request]s to the camera, and aggregate the results into a list of
* [FrameCapture]s, which can be used to wait for the associated [Frame]
* using [FrameCapture.awaitFrame].
*
* Each [FrameCapture] **must** be closed, or it will result in a memory leak.
*/
fun capture(requests: List<Request>): List<FrameCapture>
/**
* Abort in-flight requests. This will abort *all* requests in the current
* CameraCaptureSession as well as any requests that are enqueued, but that have not yet
* been submitted to the camera.
*/
fun abort()
/**
* Applies the given 3A parameters to the camera device.
*
* @return earliest FrameNumber at which the parameters were successfully applied.
*/
fun update3A(
aeMode: AeMode? = null,
afMode: AfMode? = null,
awbMode: AwbMode? = null,
aeRegions: List<MeteringRectangle>? = null,
afRegions: List<MeteringRectangle>? = null,
awbRegions: List<MeteringRectangle>? = null
): Deferred<Result3A>
/**
* Applies the given 3A parameters to the camera device but for only one frame.
*
* @return the FrameNumber for which these parameters were applied.
*/
suspend fun submit3A(
aeMode: AeMode? = null,
afMode: AfMode? = null,
awbMode: AwbMode? = null,
aeRegions: List<MeteringRectangle>? = null,
afRegions: List<MeteringRectangle>? = null,
awbRegions: List<MeteringRectangle>? = null
): Deferred<Result3A>
/**
* Turns the torch to ON or OFF.
*
* This method has a side effect on the currently set AE mode. Ref:
* https://developer.android.com/reference/android/hardware/camera2/CaptureRequest#FLASH_MODE
* To use the flash control, AE mode must be set to ON or OFF. So if the AE mode is already
* not either ON or OFF, we will need to update the AE mode to one of those states, here we
* will choose ON. It is the responsibility of the application layer above CameraPipe to
* restore the AE mode after the torch control has been used. The [update3A] method can be
* used to restore the AE state to a previous value.
*
* @return the FrameNumber at which the turn was fully turned on if switch was ON, or the
* FrameNumber at which it was completely turned off when the switch was OFF.
*/
fun setTorch(torchState: TorchState): Deferred<Result3A>
/**
* Locks the auto-exposure, auto-focus and auto-whitebalance as per the given desired
* behaviors. This given 3A parameters are applied before the lock is obtained. If 'null'
* value is passed for a parameter, that parameter is ignored, and the current value for
* that parameter continues to be applied.
*
* @param afTriggerStartAeMode the AeMode value that should override current AeMode for
* AF_TRIGGER_START request, this value should not be retained for following requests
* @param convergedCondition an optional function can be used to identify if the result
* frame with correct 3A converge state is received. Returns true to complete the 3A scan
* and going to lock the 3A state, otherwise it will continue to receive the frame results
* until the [frameLimit] or [timeLimitNs] is reached.
* @param lockedCondition an optional function can be used to identify if the result frame
* with correct 3A lock states are received. Returns true to complete lock 3A task,
* otherwise it will continue to receive the frame results until the [frameLimit]
* or [timeLimitNs] is reached.
* @param frameLimit the maximum number of frames to wait before we give up waiting for this
* operation to complete.
* @param timeLimitNs the maximum time limit in ms we wait before we give up waiting for
* this operation to complete.
* @return [Result3A], which will contain the latest frame number at which the locks were
* applied or the frame number at which the method returned early because either frame
* limit or time limit was reached.
*
* TODO(sushilnath@): Add support for specifying the AE, AF and AWB modes as well. The
* update of modes require special care if the desired lock behavior is immediate. In that
* case we have to submit a combination of repeating and single requests so that the AF
* skips the initial state of the new mode's state machine and stays locks in the new mode
* as well.
*/
suspend fun lock3A(
aeMode: AeMode? = null,
afMode: AfMode? = null,
awbMode: AwbMode? = null,
aeRegions: List<MeteringRectangle>? = null,
afRegions: List<MeteringRectangle>? = null,
awbRegions: List<MeteringRectangle>? = null,
aeLockBehavior: Lock3ABehavior? = null,
afLockBehavior: Lock3ABehavior? = null,
awbLockBehavior: Lock3ABehavior? = null,
afTriggerStartAeMode: AeMode? = null,
convergedCondition: ((FrameMetadata) -> Boolean)? = null,
lockedCondition: ((FrameMetadata) -> Boolean)? = null,
frameLimit: Int = DEFAULT_FRAME_LIMIT,
timeLimitNs: Long = DEFAULT_TIME_LIMIT_NS
): Deferred<Result3A>
/**
* Unlocks auto-exposure, auto-focus, auto-whitebalance. Once they are unlocked they get
* back to their initial state or resume their auto scan depending on the current mode they
* are operating in.
*
* Providing 'true' for a parameter in this method will unlock that component and if 'false'
* is provided or the parameter is not specified then it will have no effect on the lock of
* that component, i.e. if it was locked earlier it will stay locked and if it was already
* unlocked, it will stay unlocked.
*
* @param unlockedCondition an optional function can be used to identify if the result frame
* with correct ae, af and awb states are received. Returns true to complete the unlock
* 3A task, otherwise it will continue to receive the frame results until the [frameLimit]
* or [timeLimitNs] is reached.
* @param frameLimit the maximum number of frames to wait before we give up waiting for this
* operation to complete.
* @param timeLimitNs the maximum time limit in ms we wait before we give up waiting for
* this operation to complete.
*
* @return [Result3A], which will contain the latest frame number at which the auto-focus,
* auto-exposure, auto-white balance were unlocked as per the method arguments.
*/
suspend fun unlock3A(
ae: Boolean? = null,
af: Boolean? = null,
awb: Boolean? = null,
unlockedCondition: ((FrameMetadata) -> Boolean)? = null,
frameLimit: Int = DEFAULT_FRAME_LIMIT,
timeLimitNs: Long = DEFAULT_TIME_LIMIT_NS
): Deferred<Result3A>
/**
* This methods does pre-capture metering sequence and locks auto-focus. Once the operation
* completes, we can proceed to take high-quality pictures.
*
* Note: Flash will be used during pre-capture metering and during image capture if the AE
* mode was set to [AeMode.ON_AUTO_FLASH] or [AeMode.ON_ALWAYS_FLASH], thus firing it for
* low light captures or for every capture, respectively.
*
* @param lockedCondition an optional function can be used to identify if the result frame
* with correct lock states for ae, af and awb is received. Returns true to complete lock
* 3A task, otherwise it will continue to receive the frame results until the [frameLimit]
* or [timeLimitNs] is reached.
* @param frameLimit the maximum number of frames to wait before we give up waiting for this
* operation to complete.
* @param timeLimitNs the maximum time limit in ms we wait before we give up waiting for
* this operation to complete.
*
* @return [Result3A], which will contain the latest frame number at which the locks were
* applied or the frame number at which the method returned early because either frame
* limit or time limit was reached.
*/
suspend fun lock3AForCapture(
lockedCondition: ((FrameMetadata) -> Boolean)? = null,
frameLimit: Int = DEFAULT_FRAME_LIMIT,
timeLimitNs: Long = DEFAULT_TIME_LIMIT_NS,
): Deferred<Result3A>
/**
* This methods does pre-capture metering sequence and locks auto-focus. Once the operation
* completes, we can proceed to take high-quality pictures.
*
* Note: Flash will be used during pre-capture metering and during image capture if the AE
* mode was set to [AeMode.ON_AUTO_FLASH] or [AeMode.ON_ALWAYS_FLASH], thus firing it for
* low light captures or for every capture, respectively.
*
* @param triggerAf Whether to trigger AF, enabled by default.
* @param waitForAwb Whether to wait for AWB to converge/lock, disabled by default.
* @param frameLimit the maximum number of frames to wait before we give up waiting for this
* operation to complete.
* @param timeLimitNs the maximum time limit in ms we wait before we give up waiting for
* this operation to complete.
*
* @return [Result3A], which will contain the latest frame number at which the locks were
* applied or the frame number at which the method returned early because either frame
* limit or time limit was reached.
*/
suspend fun lock3AForCapture(
triggerAf: Boolean = true,
waitForAwb: Boolean = false,
frameLimit: Int = DEFAULT_FRAME_LIMIT,
timeLimitNs: Long = DEFAULT_TIME_LIMIT_NS,
): Deferred<Result3A>
/**
* After submitting pre-capture metering sequence needed by [lock3AForCapture] method, the
* camera system can internally lock the auto-exposure routine for subsequent still image
* capture, and if not image capture request is submitted the auto-exposure may not resume
* it's normal scan. This method brings focus and exposure back to normal after high quality
* image captures using [lock3AForCapture] method.
*
* @param cancelAf Whether to trigger AF cancel, enabled by default.
*/
suspend fun unlock3APostCapture(cancelAf: Boolean = true): Deferred<Result3A>
}
}
/**
* GraphState represents public the public facing state of a [CameraGraph] instance. When created,
* a [CameraGraph] starts in [GraphStateStopped]. Calling [CameraGraph.start] puts the graph into
* [GraphStateStarting], and [CameraGraph.stop] puts the graph into [GraphStateStopping]. Remaining
* states are produced by the underlying camera as a result of these start/stop calls.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
abstract class GraphState internal constructor() {
/**
* When the [CameraGraph] is starting. This means we're in the process of opening a (virtual)
* camera and creating a capture session.
*/
object GraphStateStarting : GraphState()
/**
* When the [CameraGraph] is started. This means a capture session has been successfully created
* for the [CameraGraph].
*/
object GraphStateStarted : GraphState()
/**
* When the [CameraGraph] is stopping. This means we're in the process of stopping the graph.
*/
object GraphStateStopping : GraphState()
/**
* When the [CameraGraph] hasn't been started, or stopped. This does not guarantee the closure
* of the capture session or the camera device itself.
*/
object GraphStateStopped : GraphState()
/**
* When the [CameraGraph] has encountered an error. If [willAttemptRetry] is true, CameraPipe
* will retry opening the camera (and creating a capture session).
*/
class GraphStateError(val cameraError: CameraError, val willAttemptRetry: Boolean) :
GraphState() {
override fun toString(): String =
super.toString() + "(cameraError=$cameraError, willAttemptRetry=$willAttemptRetry)"
}
}
/**
* @see [CameraDevice.AUDIO_RESTRICTION_NONE] and other constants.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@JvmInline
value class AudioRestrictionMode internal constructor(val value: Int) {
companion object {
val AUDIO_RESTRICTION_NONE = AudioRestrictionMode(0)
val AUDIO_RESTRICTION_VIBRATION = AudioRestrictionMode(1)
val AUDIO_RESTRICTION_VIBRATION_SOUND = AudioRestrictionMode(3)
}
}