feat: Add onStarted
and onStopped
events (#2273)
* feat: Add `onStarted` and `onStopped` events * Implement `onStart` for Android * Update CameraSession.kt * Update CameraSessionDelegate.swift
This commit is contained in:
parent
9ef4a9a210
commit
4ee52d6211
@ -19,6 +19,20 @@ fun CameraView.invokeOnInitialized() {
|
||||
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, "cameraInitialized", null)
|
||||
}
|
||||
|
||||
fun CameraView.invokeOnStarted() {
|
||||
Log.i(CameraView.TAG, "invokeOnStarted()")
|
||||
|
||||
val reactContext = context as ReactContext
|
||||
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, "cameraStarted", null)
|
||||
}
|
||||
|
||||
fun CameraView.invokeOnStopped() {
|
||||
Log.i(CameraView.TAG, "invokeOnStopped()")
|
||||
|
||||
val reactContext = context as ReactContext
|
||||
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, "cameraStopped", null)
|
||||
}
|
||||
|
||||
fun CameraView.invokeOnError(error: Throwable) {
|
||||
Log.e(CameraView.TAG, "invokeOnError(...):")
|
||||
error.printStackTrace()
|
||||
|
@ -239,6 +239,14 @@ class CameraView(context: Context) :
|
||||
invokeOnInitialized()
|
||||
}
|
||||
|
||||
override fun onStarted() {
|
||||
invokeOnStarted()
|
||||
}
|
||||
|
||||
override fun onStopped() {
|
||||
invokeOnStopped()
|
||||
}
|
||||
|
||||
override fun onCodeScanned(codes: List<Barcode>, scannerFrame: CodeScannerFrame) {
|
||||
invokeOnCodeScanned(codes, scannerFrame)
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ class CameraViewManager : ViewGroupManager<CameraView>() {
|
||||
MapBuilder.builder<String, Any>()
|
||||
.put("cameraViewReady", MapBuilder.of("registrationName", "onViewReady"))
|
||||
.put("cameraInitialized", MapBuilder.of("registrationName", "onInitialized"))
|
||||
.put("cameraStarted", MapBuilder.of("registrationName", "onStarted"))
|
||||
.put("cameraStopped", MapBuilder.of("registrationName", "onStopped"))
|
||||
.put("cameraError", MapBuilder.of("registrationName", "onError"))
|
||||
.put("cameraCodeScanned", MapBuilder.of("registrationName", "onCodeScanned"))
|
||||
.build()
|
||||
|
@ -76,7 +76,9 @@ data class CameraConfiguration(
|
||||
// Outputs & Session (Photo, Video, CodeScanner, HDR, Format)
|
||||
val outputsChanged: Boolean,
|
||||
// Side-Props for CaptureRequest (fps, low-light-boost, torch, zoom, videoStabilization)
|
||||
val sidePropsChanged: Boolean
|
||||
val sidePropsChanged: Boolean,
|
||||
// (isActive) changed
|
||||
val isActiveChanged: Boolean
|
||||
) {
|
||||
val hasAnyDifference: Boolean
|
||||
get() = sidePropsChanged || outputsChanged || deviceChanged
|
||||
@ -98,10 +100,13 @@ data class CameraConfiguration(
|
||||
left.zoom != right.zoom || left.videoStabilizationMode != right.videoStabilizationMode || left.isActive != right.isActive ||
|
||||
left.exposure != right.exposure
|
||||
|
||||
val isActiveChanged = left?.isActive != right.isActive
|
||||
|
||||
return Difference(
|
||||
deviceChanged,
|
||||
outputsChanged,
|
||||
sidePropsChanged
|
||||
sidePropsChanged,
|
||||
isActiveChanged
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -146,6 +146,16 @@ class CameraSession(private val context: Context, private val cameraManager: Cam
|
||||
if (diff.deviceChanged) {
|
||||
callback.onInitialized()
|
||||
}
|
||||
|
||||
// Notify about Camera start/stop
|
||||
if (diff.isActiveChanged) {
|
||||
// TODO: Move that into the CaptureRequest callback to get actual first-frame arrive time?
|
||||
if (config.isActive) {
|
||||
callback.onStarted()
|
||||
} else {
|
||||
callback.onStopped()
|
||||
}
|
||||
}
|
||||
} catch (error: Throwable) {
|
||||
Log.e(TAG, "Failed to configure CameraSession! Error: ${error.message}, Config-Diff: $diff", error)
|
||||
callback.onError(error)
|
||||
@ -367,6 +377,7 @@ class CameraSession(private val context: Context, private val cameraManager: Cam
|
||||
// TODO: Do we want to do stopRepeating() or entirely destroy the session?
|
||||
// If the Camera is not active, we don't do anything.
|
||||
captureSession?.stopRepeating()
|
||||
isRunning = false
|
||||
return
|
||||
}
|
||||
|
||||
@ -621,6 +632,8 @@ class CameraSession(private val context: Context, private val cameraManager: Cam
|
||||
interface CameraSessionCallback {
|
||||
fun onError(error: Throwable)
|
||||
fun onInitialized()
|
||||
fun onStarted()
|
||||
fun onStopped()
|
||||
fun onCodeScanned(codes: List<Barcode>, scannerFrame: CodeScannerFrame)
|
||||
}
|
||||
}
|
||||
|
@ -27,9 +27,9 @@ PODS:
|
||||
- libwebp/sharpyuv (1.3.2)
|
||||
- libwebp/webp (1.3.2):
|
||||
- libwebp/sharpyuv
|
||||
- MMKV (1.3.1):
|
||||
- MMKVCore (~> 1.3.1)
|
||||
- MMKVCore (1.3.1)
|
||||
- MMKV (1.3.2):
|
||||
- MMKVCore (~> 1.3.2)
|
||||
- MMKVCore (1.3.2)
|
||||
- RCT-Folly (2021.07.22.00):
|
||||
- boost
|
||||
- DoubleConversion
|
||||
@ -507,7 +507,7 @@ PODS:
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.10)
|
||||
- SocketRocket (0.6.1)
|
||||
- VisionCamera (3.6.11):
|
||||
- VisionCamera (3.6.14):
|
||||
- React
|
||||
- React-callinvoker
|
||||
- React-Core
|
||||
@ -698,8 +698,8 @@ SPEC CHECKSUMS:
|
||||
hermes-engine: 10fbd3f62405c41ea07e71973ea61e1878d07322
|
||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
|
||||
MMKV: 5a07930c70c70b86cd87761a42c8f3836fb681d7
|
||||
MMKVCore: e50135dbd33235b6ab390635991bab437ab873c0
|
||||
MMKV: f21593c0af4b3f2a0ceb8f820f28bb639ea22bb7
|
||||
MMKVCore: 31b4cb83f8266467eef20a35b6d78e409a11060d
|
||||
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
|
||||
RCTRequired: a2faf4bad4e438ca37b2040cb8f7799baa065c18
|
||||
RCTTypeSafety: cb09f3e4747b6d18331a15eb05271de7441ca0b3
|
||||
@ -747,7 +747,7 @@ SPEC CHECKSUMS:
|
||||
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
|
||||
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
|
||||
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
|
||||
VisionCamera: b35fc51a521ce0a9b9da41d8b13127e3d414d195
|
||||
VisionCamera: 3cf177fa91fa9fe04622071415032c5af618a5ac
|
||||
Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce
|
||||
|
||||
PODFILE CHECKSUM: 27f53791141a3303d814e09b55770336416ff4eb
|
||||
|
@ -59,6 +59,8 @@ public final class CameraView: UIView, CameraSessionDelegate {
|
||||
// events
|
||||
@objc var onInitialized: RCTDirectEventBlock?
|
||||
@objc var onError: RCTDirectEventBlock?
|
||||
@objc var onStarted: RCTDirectEventBlock?
|
||||
@objc var onStopped: RCTDirectEventBlock?
|
||||
@objc var onViewReady: RCTDirectEventBlock?
|
||||
@objc var onCodeScanned: RCTDirectEventBlock?
|
||||
// zoom
|
||||
@ -283,7 +285,23 @@ public final class CameraView: UIView, CameraSessionDelegate {
|
||||
guard let onInitialized = onInitialized else {
|
||||
return
|
||||
}
|
||||
onInitialized([String: Any]())
|
||||
onInitialized([:])
|
||||
}
|
||||
|
||||
func onCameraStarted() {
|
||||
ReactLogger.log(level: .info, message: "Camera started!")
|
||||
guard let onStarted = onStarted else {
|
||||
return
|
||||
}
|
||||
onStarted([:])
|
||||
}
|
||||
|
||||
func onCameraStopped() {
|
||||
ReactLogger.log(level: .info, message: "Camera stopped!")
|
||||
guard let onStopped = onStopped else {
|
||||
return
|
||||
}
|
||||
onStopped([:])
|
||||
}
|
||||
|
||||
func onFrame(sampleBuffer: CMSampleBuffer) {
|
||||
|
@ -52,6 +52,8 @@ RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
|
||||
// Camera View Events
|
||||
RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock);
|
||||
RCT_EXPORT_VIEW_PROPERTY(onInitialized, RCTDirectEventBlock);
|
||||
RCT_EXPORT_VIEW_PROPERTY(onStarted, RCTDirectEventBlock);
|
||||
RCT_EXPORT_VIEW_PROPERTY(onStopped, RCTDirectEventBlock);
|
||||
RCT_EXPORT_VIEW_PROPERTY(onViewReady, RCTDirectEventBlock);
|
||||
// Code Scanner
|
||||
RCT_EXPORT_VIEW_PROPERTY(codeScannerOptions, NSDictionary);
|
||||
|
@ -249,8 +249,10 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC
|
||||
// Start/Stop session
|
||||
if configuration.isActive {
|
||||
captureSession.startRunning()
|
||||
delegate?.onCameraStarted()
|
||||
} else {
|
||||
captureSession.stopRunning()
|
||||
delegate?.onCameraStopped()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,14 @@ protocol CameraSessionDelegate: AnyObject {
|
||||
Called when the [CameraSession] successfully initializes
|
||||
*/
|
||||
func onSessionInitialized()
|
||||
/**
|
||||
Called when the [CameraSession] starts streaming frames. (isActive=true)
|
||||
*/
|
||||
func onCameraStarted()
|
||||
/**
|
||||
Called when the [CameraSession] stopped streaming frames. (isActive=false)
|
||||
*/
|
||||
func onCameraStopped()
|
||||
/**
|
||||
Called for every frame (if video or frameProcessor is enabled)
|
||||
*/
|
||||
|
@ -33,6 +33,8 @@ type NativeCameraViewProps = Omit<CameraProps, 'device' | 'onInitialized' | 'onE
|
||||
onInitialized?: (event: NativeSyntheticEvent<void>) => void
|
||||
onError?: (event: NativeSyntheticEvent<OnErrorEvent>) => void
|
||||
onCodeScanned?: (event: NativeSyntheticEvent<OnCodeScannedEvent>) => void
|
||||
onStarted?: (event: NativeSyntheticEvent<void>) => void
|
||||
onStopped?: (event: NativeSyntheticEvent<void>) => void
|
||||
onViewReady: () => void
|
||||
}
|
||||
type NativeRecordVideoOptions = Omit<RecordVideoOptions, 'onRecordingError' | 'onRecordingFinished' | 'videoBitRate'> & {
|
||||
@ -89,6 +91,8 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
||||
super(props)
|
||||
this.onViewReady = this.onViewReady.bind(this)
|
||||
this.onInitialized = this.onInitialized.bind(this)
|
||||
this.onStarted = this.onStarted.bind(this)
|
||||
this.onStopped = this.onStopped.bind(this)
|
||||
this.onError = this.onError.bind(this)
|
||||
this.onCodeScanned = this.onCodeScanned.bind(this)
|
||||
this.ref = React.createRef<RefType>()
|
||||
@ -416,6 +420,14 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
||||
private onInitialized(): void {
|
||||
this.props.onInitialized?.()
|
||||
}
|
||||
|
||||
private onStarted(): void {
|
||||
this.props.onStarted?.()
|
||||
}
|
||||
|
||||
private onStopped(): void {
|
||||
this.props.onStopped?.()
|
||||
}
|
||||
//#endregion
|
||||
|
||||
private onCodeScanned(event: NativeSyntheticEvent<OnCodeScannedEvent>): void {
|
||||
@ -481,6 +493,8 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
|
||||
onViewReady={this.onViewReady}
|
||||
onInitialized={this.onInitialized}
|
||||
onCodeScanned={this.onCodeScanned}
|
||||
onStarted={this.onStarted}
|
||||
onStopped={this.onStopped}
|
||||
onError={this.onError}
|
||||
codeScannerOptions={codeScanner}
|
||||
enableFrameProcessor={frameProcessor != null}
|
||||
|
@ -246,9 +246,17 @@ export interface CameraProps extends ViewProps {
|
||||
*/
|
||||
onError?: (error: CameraRuntimeError) => void
|
||||
/**
|
||||
* Called when the camera was successfully initialized.
|
||||
* Called when the camera session was successfully initialized. This will get called everytime a new device is set.
|
||||
*/
|
||||
onInitialized?: () => void
|
||||
/**
|
||||
* Called when the camera started the session (`isActive={true}`)
|
||||
*/
|
||||
onStarted?: () => void
|
||||
/**
|
||||
* Called when the camera stopped the session (`isActive={false}`)
|
||||
*/
|
||||
onStopped?: () => void
|
||||
/**
|
||||
* A worklet which will be called for every frame the Camera "sees".
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user