diff --git a/android/src/main/java/com/mrousavy/camera/CameraView+RecordVideo.kt b/android/src/main/java/com/mrousavy/camera/CameraView+RecordVideo.kt index e84231d..14ee747 100644 --- a/android/src/main/java/com/mrousavy/camera/CameraView+RecordVideo.kt +++ b/android/src/main/java/com/mrousavy/camera/CameraView+RecordVideo.kt @@ -82,6 +82,30 @@ fun CameraView.startRecording(options: ReadableMap, onRecordCallback: Callback) }) } +@SuppressLint("RestrictedApi") +fun CameraView.pauseRecording() { + if (videoCapture == null) { + throw CameraNotReadyError() + } + if (activeVideoRecording == null) { + throw NoRecordingInProgressError() + } + + activeVideoRecording!!.pause() +} + +@SuppressLint("RestrictedApi") +fun CameraView.resumeRecording() { + if (videoCapture == null) { + throw CameraNotReadyError() + } + if (activeVideoRecording == null) { + throw NoRecordingInProgressError() + } + + activeVideoRecording!!.resume() +} + @SuppressLint("RestrictedApi") fun CameraView.stopRecording() { if (videoCapture == null) { diff --git a/android/src/main/java/com/mrousavy/camera/CameraViewModule.kt b/android/src/main/java/com/mrousavy/camera/CameraViewModule.kt index 92dcc93..5f1477b 100644 --- a/android/src/main/java/com/mrousavy/camera/CameraViewModule.kt +++ b/android/src/main/java/com/mrousavy/camera/CameraViewModule.kt @@ -115,6 +115,24 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase } } + @ReactMethod + fun pauseRecording(viewTag: Int, promise: Promise) { + withPromise(promise) { + val view = findCameraView(viewTag) + view.pauseRecording() + return@withPromise null + } + } + + @ReactMethod + fun resumeRecording(viewTag: Int, promise: Promise) { + withPromise(promise) { + val view = findCameraView(viewTag) + view.resumeRecording() + return@withPromise null + } + } + @ReactMethod fun stopRecording(viewTag: Int, promise: Promise) { withPromise(promise) { diff --git a/ios/CameraView+RecordVideo.swift b/ios/CameraView+RecordVideo.swift index 4cca687..a398737 100644 --- a/ios/CameraView+RecordVideo.swift +++ b/ios/CameraView+RecordVideo.swift @@ -161,30 +161,28 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud } } - // TODO: Implement for JS func pauseRecording(promise: Promise) { cameraQueue.async { withPromise(promise) { - if self.isRecording { - self.isRecording = false - return nil - } else { + guard self.recordingSession != nil else { + // there's no active recording! throw CameraError.capture(.noRecordingInProgress) } + self.isRecording = false + return nil } } } - // TODO: Implement for JS func resumeRecording(promise: Promise) { cameraQueue.async { withPromise(promise) { - if !self.isRecording { - self.isRecording = true - return nil - } else { + guard self.recordingSession != nil else { + // there's no active recording! throw CameraError.capture(.noRecordingInProgress) } + self.isRecording = true + return nil } } } diff --git a/ios/CameraViewManager.m b/ios/CameraViewManager.m index 960ad1e..6c9df17 100644 --- a/ios/CameraViewManager.m +++ b/ios/CameraViewManager.m @@ -54,6 +54,8 @@ RCT_EXPORT_VIEW_PROPERTY(onViewReady, RCTDirectEventBlock); // Camera View Functions RCT_EXTERN_METHOD(startRecording:(nonnull NSNumber *)node options:(NSDictionary *)options onRecordCallback:(RCTResponseSenderBlock)onRecordCallback); +RCT_EXTERN_METHOD(pauseRecording:(nonnull NSNumber *)node resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); +RCT_EXTERN_METHOD(resumeRecording:(nonnull NSNumber *)node resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); RCT_EXTERN_METHOD(stopRecording:(nonnull NSNumber *)node resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); RCT_EXTERN_METHOD(takePhoto:(nonnull NSNumber *)node options:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); RCT_EXTERN_METHOD(focus:(nonnull NSNumber *)node point:(NSDictionary *)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject); diff --git a/ios/CameraViewManager.swift b/ios/CameraViewManager.swift index ed45691..74df8cb 100644 --- a/ios/CameraViewManager.swift +++ b/ios/CameraViewManager.swift @@ -49,6 +49,18 @@ final class CameraViewManager: RCTViewManager { component.startRecording(options: options, callback: onRecordCallback) } + @objc + final func pauseRecording(_ node: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + let component = getCameraView(withTag: node) + component.pauseRecording(promise: Promise(resolver: resolve, rejecter: reject)) + } + + @objc + final func resumeRecording(_ node: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + let component = getCameraView(withTag: node) + component.resumeRecording(promise: Promise(resolver: resolve, rejecter: reject)) + } + @objc final func stopRecording(_ node: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { let component = getCameraView(withTag: node) diff --git a/src/Camera.tsx b/src/Camera.tsx index 6150022..68417ac 100644 --- a/src/Camera.tsx +++ b/src/Camera.tsx @@ -190,6 +190,63 @@ export class Camera extends React.PureComponent { throw tryParseNativeCameraError(e); } } + + /** + * Pauses the current video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while pausing the video recording. Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * // Start + * await camera.current.startRecording() + * await timeout(1000) + * // Pause + * await camera.current.pauseRecording() + * await timeout(500) + * // Resume + * await camera.current.resumeRecording() + * await timeout(2000) + * // Stop + * const video = await camera.current.stopRecording() + * ``` + */ + public async pauseRecording(): Promise { + try { + return await CameraModule.pauseRecording(this.handle); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + /** + * Resumes a currently paused video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while resuming the video recording. Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * // Start + * await camera.current.startRecording() + * await timeout(1000) + * // Pause + * await camera.current.pauseRecording() + * await timeout(500) + * // Resume + * await camera.current.resumeRecording() + * await timeout(2000) + * // Stop + * const video = await camera.current.stopRecording() + * ``` + */ + public async resumeRecording(): Promise { + try { + return await CameraModule.resumeRecording(this.handle); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + /** * Stop the current video recording. *