feat: Add enableShutterSound
prop to takePhoto()
🔊 (#1702)
* feat: Add `enableShutterSound` prop to `takePhoto()` 🔊
* Swift lint
This commit is contained in:
parent
0a51980f26
commit
a46839a57b
@ -178,6 +178,7 @@ class CameraSession(private val context: Context,
|
|||||||
|
|
||||||
suspend fun takePhoto(qualityPrioritization: QualityPrioritization,
|
suspend fun takePhoto(qualityPrioritization: QualityPrioritization,
|
||||||
flashMode: Flash,
|
flashMode: Flash,
|
||||||
|
enableShutterSound: Boolean,
|
||||||
enableRedEyeReduction: Boolean,
|
enableRedEyeReduction: Boolean,
|
||||||
enableAutoStabilization: Boolean,
|
enableAutoStabilization: Boolean,
|
||||||
outputOrientation: Orientation): CapturedPhoto {
|
outputOrientation: Orientation): CapturedPhoto {
|
||||||
@ -197,7 +198,7 @@ class CameraSession(private val context: Context,
|
|||||||
enableAutoStabilization,
|
enableAutoStabilization,
|
||||||
orientation)
|
orientation)
|
||||||
Log.i(TAG, "Photo capture 0/2 - starting capture...")
|
Log.i(TAG, "Photo capture 0/2 - starting capture...")
|
||||||
val result = captureSession.capture(captureRequest)
|
val result = captureSession.capture(captureRequest, enableShutterSound)
|
||||||
val timestamp = result[CaptureResult.SENSOR_TIMESTAMP]!!
|
val timestamp = result[CaptureResult.SENSOR_TIMESTAMP]!!
|
||||||
Log.i(TAG, "Photo capture 1/2 complete - received metadata with timestamp $timestamp")
|
Log.i(TAG, "Photo capture 1/2 complete - received metadata with timestamp $timestamp")
|
||||||
try {
|
try {
|
||||||
|
@ -30,12 +30,14 @@ suspend fun CameraView.takePhoto(optionsMap: ReadableMap): WritableMap {
|
|||||||
val flash = options["flash"] as? String ?: "off"
|
val flash = options["flash"] as? String ?: "off"
|
||||||
val enableAutoRedEyeReduction = options["enableAutoRedEyeReduction"] == true
|
val enableAutoRedEyeReduction = options["enableAutoRedEyeReduction"] == true
|
||||||
val enableAutoStabilization = options["enableAutoStabilization"] == true
|
val enableAutoStabilization = options["enableAutoStabilization"] == true
|
||||||
|
val enableShutterSound = options["enableShutterSound"] as? Boolean ?: true
|
||||||
|
|
||||||
val flashMode = Flash.fromUnionValue(flash)
|
val flashMode = Flash.fromUnionValue(flash)
|
||||||
val qualityPrioritizationMode = QualityPrioritization.fromUnionValue(qualityPrioritization)
|
val qualityPrioritizationMode = QualityPrioritization.fromUnionValue(qualityPrioritization)
|
||||||
|
|
||||||
val photo = cameraSession.takePhoto(qualityPrioritizationMode,
|
val photo = cameraSession.takePhoto(qualityPrioritizationMode,
|
||||||
flashMode,
|
flashMode,
|
||||||
|
enableShutterSound,
|
||||||
enableAutoRedEyeReduction,
|
enableAutoRedEyeReduction,
|
||||||
enableAutoStabilization,
|
enableAutoStabilization,
|
||||||
outputOrientation)
|
outputOrientation)
|
||||||
|
@ -4,6 +4,7 @@ import android.hardware.camera2.CameraCaptureSession
|
|||||||
import android.hardware.camera2.CaptureFailure
|
import android.hardware.camera2.CaptureFailure
|
||||||
import android.hardware.camera2.CaptureRequest
|
import android.hardware.camera2.CaptureRequest
|
||||||
import android.hardware.camera2.TotalCaptureResult
|
import android.hardware.camera2.TotalCaptureResult
|
||||||
|
import android.media.MediaActionSound
|
||||||
import com.mrousavy.camera.CameraQueues
|
import com.mrousavy.camera.CameraQueues
|
||||||
import com.mrousavy.camera.CaptureAbortedError
|
import com.mrousavy.camera.CaptureAbortedError
|
||||||
import com.mrousavy.camera.UnknownCaptureError
|
import com.mrousavy.camera.UnknownCaptureError
|
||||||
@ -11,7 +12,7 @@ import kotlin.coroutines.resume
|
|||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
import kotlin.coroutines.suspendCoroutine
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
suspend fun CameraCaptureSession.capture(captureRequest: CaptureRequest): TotalCaptureResult {
|
suspend fun CameraCaptureSession.capture(captureRequest: CaptureRequest, enableShutterSound: Boolean): TotalCaptureResult {
|
||||||
return suspendCoroutine { continuation ->
|
return suspendCoroutine { continuation ->
|
||||||
this.capture(captureRequest, object: CameraCaptureSession.CaptureCallback() {
|
this.capture(captureRequest, object: CameraCaptureSession.CaptureCallback() {
|
||||||
override fun onCaptureCompleted(
|
override fun onCaptureCompleted(
|
||||||
@ -20,9 +21,19 @@ suspend fun CameraCaptureSession.capture(captureRequest: CaptureRequest): TotalC
|
|||||||
result: TotalCaptureResult
|
result: TotalCaptureResult
|
||||||
) {
|
) {
|
||||||
super.onCaptureCompleted(session, request, result)
|
super.onCaptureCompleted(session, request, result)
|
||||||
|
|
||||||
continuation.resume(result)
|
continuation.resume(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCaptureStarted(session: CameraCaptureSession, request: CaptureRequest, timestamp: Long, frameNumber: Long) {
|
||||||
|
super.onCaptureStarted(session, request, timestamp, frameNumber)
|
||||||
|
|
||||||
|
if (enableShutterSound) {
|
||||||
|
val mediaActionSound = MediaActionSound()
|
||||||
|
mediaActionSound.play(MediaActionSound.SHUTTER_CLICK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCaptureFailed(
|
override fun onCaptureFailed(
|
||||||
session: CameraCaptureSession,
|
session: CameraCaptureSession,
|
||||||
request: CaptureRequest,
|
request: CaptureRequest,
|
||||||
|
@ -64,6 +64,7 @@ const _CaptureButton: React.FC<Props> = ({
|
|||||||
qualityPrioritization: 'speed',
|
qualityPrioritization: 'speed',
|
||||||
flash: flash,
|
flash: flash,
|
||||||
quality: 90,
|
quality: 90,
|
||||||
|
enableShutterSound: false,
|
||||||
}),
|
}),
|
||||||
[flash],
|
[flash],
|
||||||
);
|
);
|
||||||
|
@ -45,6 +45,9 @@ extension CameraView {
|
|||||||
photoSettings.flashMode = flashMode
|
photoSettings.flashMode = flashMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shutter sound
|
||||||
|
let enableShutterSound = options["enableShutterSound"] as? Bool ?? true
|
||||||
|
|
||||||
// depth data
|
// depth data
|
||||||
photoSettings.isDepthDataDeliveryEnabled = photoOutput.isDepthDataDeliveryEnabled
|
photoSettings.isDepthDataDeliveryEnabled = photoOutput.isDepthDataDeliveryEnabled
|
||||||
if #available(iOS 12.0, *) {
|
if #available(iOS 12.0, *) {
|
||||||
@ -75,7 +78,7 @@ extension CameraView {
|
|||||||
photoSettings.isAutoContentAwareDistortionCorrectionEnabled = enableAutoDistortionCorrection
|
photoSettings.isAutoContentAwareDistortionCorrectionEnabled = enableAutoDistortionCorrection
|
||||||
}
|
}
|
||||||
|
|
||||||
photoOutput.capturePhoto(with: photoSettings, delegate: PhotoCaptureDelegate(promise: promise))
|
photoOutput.capturePhoto(with: photoSettings, delegate: PhotoCaptureDelegate(promise: promise, enableShutterSound: enableShutterSound))
|
||||||
|
|
||||||
// Assume that `takePhoto` is always called with the same parameters, so prepare the next call too.
|
// Assume that `takePhoto` is always called with the same parameters, so prepare the next call too.
|
||||||
photoOutput.setPreparedPhotoSettingsArray([photoSettings], completionHandler: nil)
|
photoOutput.setPreparedPhotoSettingsArray([photoSettings], completionHandler: nil)
|
||||||
|
@ -14,13 +14,22 @@ private var delegatesReferences: [NSObject] = []
|
|||||||
|
|
||||||
class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
|
class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
|
||||||
private let promise: Promise
|
private let promise: Promise
|
||||||
|
private let enableShutterSound: Bool
|
||||||
|
|
||||||
required init(promise: Promise) {
|
required init(promise: Promise, enableShutterSound: Bool) {
|
||||||
self.promise = promise
|
self.promise = promise
|
||||||
|
self.enableShutterSound = enableShutterSound
|
||||||
super.init()
|
super.init()
|
||||||
delegatesReferences.append(self)
|
delegatesReferences.append(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func photoOutput(_: AVCapturePhotoOutput, willCapturePhotoFor _: AVCaptureResolvedPhotoSettings) {
|
||||||
|
if !enableShutterSound {
|
||||||
|
// disable system shutter sound (see https://stackoverflow.com/a/55235949/5281431)
|
||||||
|
AudioServicesDisposeSystemSoundID(1108)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func photoOutput(_: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
|
func photoOutput(_: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
|
||||||
defer {
|
defer {
|
||||||
delegatesReferences.removeAll(where: { $0 == self })
|
delegatesReferences.removeAll(where: { $0 == self })
|
||||||
|
@ -38,6 +38,12 @@ export interface TakePhotoOptions {
|
|||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
enableAutoDistortionCorrection?: boolean;
|
enableAutoDistortionCorrection?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether to play the default shutter "click" sound when taking a picture or not.
|
||||||
|
*
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
enableShutterSound?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user