Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ De-couple use-cases (Allow photo-only capture without microphone permission, ..) #78

Closed
McFly78 opened this issue Mar 17, 2021 · 14 comments · Fixed by #168
Closed
Assignees
Labels
✨ feature Proposes a new feature or enhancement

Comments

@McFly78
Copy link

McFly78 commented Mar 17, 2021

Hello,

I would like to know if there is a way that microphone permission is not requested to the user when we just want to take photo and not any movie.

I have tried to use the following camera props but the microphone access is still requesting to the users:
preset= "photo"

Many thanks for your help

@McFly78 McFly78 added the 💭 question Further information is requested label Mar 17, 2021
@McFly78 McFly78 changed the title ❓ Possible to not request Microphone Permission to the user in photo mode usage ? ❓ Is it possible to not request Microphone Permission to the user in photo mode usage ? Mar 17, 2021
@McFly78 McFly78 changed the title ❓ Is it possible to not request Microphone Permission to the user in photo mode usage ? ❓ Is it possible to not request Microphone Permission dialog box to the user in photo mode usage ? Mar 17, 2021
@mrousavy
Copy link
Owner

Hi!

Sorry, that is currently not supported. The Camera is designed to be used with both Photo and Video capture always being ready.

I will convert this to a feature request and pick this up in the future.

@mrousavy mrousavy changed the title ❓ Is it possible to not request Microphone Permission dialog box to the user in photo mode usage ? ✨ De-couple use-cases (Allow photo-only capture without microphone permission, ..) Mar 17, 2021
@mrousavy mrousavy added ✨ feature Proposes a new feature or enhancement and removed 💭 question Further information is requested labels Mar 17, 2021
@filipef101
Copy link

It should be possible to capture video without audio permission, so this could be for example a prop like audio={false} like react native camera does

@mrousavy
Copy link
Owner

mrousavy commented Apr 12, 2021

It should be possible to capture video without audio permission

Interesting to see demand for this.

a prop like audio={false} like react native camera does

I'm not going to do it this way, since that's going to be a bit ugly when there are multiple props (no video, video without audio, no photo, no frame processors, etc).

return <Camera audio={true} photo={true} video={true} frameProcessor={true} />

See how that gets ugly quickly? Also it's not really meaningful and pretty hard to read. Also, I like to avoid props that are true by default, or are named disableX (inverted logic). That's just extra confusion, and when I follow this rule the user has to write ={true} for every default use case.

Instead I'm thinking about creating a config;

return <Camera useCases={['photo', 'video-with-audio', 'frame-processor']} />

Only thing annoying me is memoization in this case. It's ugly to use useMemo here, and it's ugly to prevent those rerenders by unwrapping the array in the Camera component.

I'll try to think of something fancy & easy to use soon.

@mrousavy mrousavy self-assigned this Apr 12, 2021
@filipef101
Copy link

I mean that prop defaulting to true, so what could happen is

return <Camera audio={false} photo={false} video={false} frameProcessor={false} />

@mrousavy
Copy link
Owner

I mean that prop defaulting to true

Exactly, that's something I don't really like. Props that default to true are added confusion, especially in this case since those are booleans and don't have a enable, allow or is prefix.

@filipef101
Copy link

Ah okay, yeah I agree makes more sense to be a prop useCases, array or an object, also might be useful to have video without audio?

@G0retZ
Copy link
Contributor

G0retZ commented Jun 3, 2021

I'm also interested in this.
Want to build QR code scanner and it should not ask user for microphone permissions.
What should I patch to make this work until the feature will arrive? 😁

@mrousavy
Copy link
Owner

mrousavy commented Jun 3, 2021

With the newest version (2.1.0) you can just remove the activateAudioSession and deactivateAudioSession calls. I will implement an option to disable audio very soon though (waiting for CameraX to support it)

@G0retZ
Copy link
Contributor

G0retZ commented Jun 3, 2021

Just in case if anyone needs this here is a patch to turn off the audio related errors and stuff

diff --git a/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/CameraView.kt b/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/CameraView.kt
index 4c26b34..bfe99a5 100644
--- a/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/CameraView.kt
+++ b/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/CameraView.kt
@@ -218,9 +218,6 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
       val startTime = System.currentTimeMillis()
       Log.i(TAG, "Configuring session...")
       if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
-        throw MicrophonePermissionError()
-      }
-      if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
         throw CameraPermissionError()
       }
       if (cameraId == null) {
diff --git a/node_modules/react-native-vision-camera/ios/CameraView+AVAudioSession.swift b/node_modules/react-native-vision-camera/ios/CameraView+AVAudioSession.swift
index eff11ec..a5f09d4 100644
--- a/node_modules/react-native-vision-camera/ios/CameraView+AVAudioSession.swift
+++ b/node_modules/react-native-vision-camera/ios/CameraView+AVAudioSession.swift
@@ -59,38 +59,6 @@ extension CameraView {
     audioCaptureSession.addOutput(audioOutput!)
   }
 
-  /**
-   Configures the Audio session and activates it. If the session was active it will shortly be deactivated before configuration.
-
-   The Audio Session will be configured to allow background music, haptics (vibrations) and system sound playback while recording.
-   Background audio is allowed to play on speakers or bluetooth speakers.
-   */
-  final func activateAudioSession() {
-    ReactLogger.log(level: .info, message: "Activating Audio Session...")
-
-    do {
-      try AVAudioSession.sharedInstance().updateCategory(AVAudioSession.Category.playAndRecord,
-                                                         options: [.mixWithOthers,
-                                                                   .allowBluetoothA2DP,
-                                                                   .defaultToSpeaker,
-                                                                   .allowAirPlay])
-      audioCaptureSession.startRunning()
-    } catch let error as NSError {
-      switch error.code {
-      case 561_017_449:
-        self.invokeOnError(.session(.audioInUseByOtherApp), cause: error)
-      default:
-        self.invokeOnError(.session(.audioSessionFailedToActivate), cause: error)
-      }
-    }
-  }
-
-  final func deactivateAudioSession() {
-    ReactLogger.log(level: .info, message: "Deactivating Audio Session...")
-
-    audioCaptureSession.stopRunning()
-  }
-
   @objc
   func audioSessionInterrupted(notification: Notification) {
     ReactLogger.log(level: .error, message: "Audio Session Interruption Notification!")
@@ -112,8 +80,6 @@ extension CameraView {
         if isRecording {
           audioQueue.async {
             ReactLogger.log(level: .info, message: "Resuming interrupted Audio Session...", alsoLogToJS: true)
-            // restart audio session because interruption is over
-            self.activateAudioSession()
           }
         }
       } else {
diff --git a/node_modules/react-native-vision-camera/ios/CameraView+RecordVideo.swift b/node_modules/react-native-vision-camera/ios/CameraView+RecordVideo.swift
index 8a958d2..6c43d2a 100644
--- a/node_modules/react-native-vision-camera/ios/CameraView+RecordVideo.swift
+++ b/node_modules/react-native-vision-camera/ios/CameraView+RecordVideo.swift
@@ -45,9 +45,6 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
         let onFinish = { (status: AVAssetWriter.Status, error: Error?) -> Void in
           defer {
             self.recordingSession = nil
-            self.audioQueue.async {
-              self.deactivateAudioSession()
-            }
           }
           ReactLogger.log(level: .info, message: "RecordingSession finished with status \(status.descriptor).")
           if let error = error {
@@ -81,7 +78,6 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
         // Init Audio (optional, async)
         self.audioQueue.async {
           // Activate Audio Session (blocking)
-          self.activateAudioSession()
           guard let recordingSession = self.recordingSession else {
             // recording has already been cancelled
             return

@mrousavy
Copy link
Owner

mrousavy commented Jun 3, 2021

doesn't android crash when it doesn't have microphone permission in a video recording?

@G0retZ
Copy link
Contributor

G0retZ commented Jun 4, 2021

doesn't android crash when it doesn't have microphone permission in a video recording?

Sorry, I didn't test that.
It's a temporary workaround for those who don't need audio (and thus video) recording...

@dcangulo
Copy link
Contributor

dcangulo commented Jun 4, 2021

Just added difference highlighting. Thanks, @G0retZ for this.

Just in case if anyone needs this here is a patch to turn off the audio related errors and stuff

diff --git a/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/CameraView.kt b/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/CameraView.kt
index 4c26b34..bfe99a5 100644
--- a/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/CameraView.kt
+++ b/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/CameraView.kt
@@ -218,9 +218,6 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
       val startTime = System.currentTimeMillis()
       Log.i(TAG, "Configuring session...")
       if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
-        throw MicrophonePermissionError()
-      }
-      if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
         throw CameraPermissionError()
       }
       if (cameraId == null) {
diff --git a/node_modules/react-native-vision-camera/ios/CameraView+AVAudioSession.swift b/node_modules/react-native-vision-camera/ios/CameraView+AVAudioSession.swift
index eff11ec..a5f09d4 100644
--- a/node_modules/react-native-vision-camera/ios/CameraView+AVAudioSession.swift
+++ b/node_modules/react-native-vision-camera/ios/CameraView+AVAudioSession.swift
@@ -59,38 +59,6 @@ extension CameraView {
     audioCaptureSession.addOutput(audioOutput!)
   }
 
-  /**
-   Configures the Audio session and activates it. If the session was active it will shortly be deactivated before configuration.
-
-   The Audio Session will be configured to allow background music, haptics (vibrations) and system sound playback while recording.
-   Background audio is allowed to play on speakers or bluetooth speakers.
-   */
-  final func activateAudioSession() {
-    ReactLogger.log(level: .info, message: "Activating Audio Session...")
-
-    do {
-      try AVAudioSession.sharedInstance().updateCategory(AVAudioSession.Category.playAndRecord,
-                                                         options: [.mixWithOthers,
-                                                                   .allowBluetoothA2DP,
-                                                                   .defaultToSpeaker,
-                                                                   .allowAirPlay])
-      audioCaptureSession.startRunning()
-    } catch let error as NSError {
-      switch error.code {
-      case 561_017_449:
-        self.invokeOnError(.session(.audioInUseByOtherApp), cause: error)
-      default:
-        self.invokeOnError(.session(.audioSessionFailedToActivate), cause: error)
-      }
-    }
-  }
-
-  final func deactivateAudioSession() {
-    ReactLogger.log(level: .info, message: "Deactivating Audio Session...")
-
-    audioCaptureSession.stopRunning()
-  }
-
   @objc
   func audioSessionInterrupted(notification: Notification) {
     ReactLogger.log(level: .error, message: "Audio Session Interruption Notification!")
@@ -112,8 +80,6 @@ extension CameraView {
         if isRecording {
           audioQueue.async {
             ReactLogger.log(level: .info, message: "Resuming interrupted Audio Session...", alsoLogToJS: true)
-            // restart audio session because interruption is over
-            self.activateAudioSession()
           }
         }
       } else {
diff --git a/node_modules/react-native-vision-camera/ios/CameraView+RecordVideo.swift b/node_modules/react-native-vision-camera/ios/CameraView+RecordVideo.swift
index 8a958d2..6c43d2a 100644
--- a/node_modules/react-native-vision-camera/ios/CameraView+RecordVideo.swift
+++ b/node_modules/react-native-vision-camera/ios/CameraView+RecordVideo.swift
@@ -45,9 +45,6 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
         let onFinish = { (status: AVAssetWriter.Status, error: Error?) -> Void in
           defer {
             self.recordingSession = nil
-            self.audioQueue.async {
-              self.deactivateAudioSession()
-            }
           }
           ReactLogger.log(level: .info, message: "RecordingSession finished with status \(status.descriptor).")
           if let error = error {
@@ -81,7 +78,6 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
         // Init Audio (optional, async)
         self.audioQueue.async {
           // Activate Audio Session (blocking)
-          self.activateAudioSession()
           guard let recordingSession = self.recordingSession else {
             // recording has already been cancelled
             return

@mrousavy
Copy link
Owner

mrousavy commented Jun 7, 2021

I've implemented this in #168. Try upgrading to 2.2.0 and make sure to check out the docs for the supportsPhotoAndVideoCapture prop - let me know if it works for you!

@G0retZ
Copy link
Contributor

G0retZ commented Jun 7, 2021

Great! Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ feature Proposes a new feature or enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants