Skip to content

Commit 886a3bb

Browse files
committed
Fixes for Camera1 and Camera2 shutter sound.
Shutter sound should now be consistent with the `playSoundOnCapture` prop. Additionally, it should happen on successful capture as opposed to camera capture start (consistent with iOS and any camera app) Lastly, added missing props to the docs.
1 parent fb2105c commit 886a3bb

File tree

7 files changed

+79
-15
lines changed

7 files changed

+79
-15
lines changed

android/src/main/java/com/google/android/cameraview/Camera1.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class Camera1 extends CameraViewImpl implements MediaRecorder.OnInfoListener,
123123

124124
private boolean mIsScanning;
125125

126+
private Boolean mPlaySoundOnCapture = false;
127+
126128
private boolean mustUpdateSurface;
127129
private boolean surfaceWasDestroyed;
128130

@@ -1048,6 +1050,8 @@ void adjustCameraParameters() {
10481050
setZoomInternal(mZoom);
10491051
setWhiteBalanceInternal(mWhiteBalance);
10501052
setScanningInternal(mIsScanning);
1053+
setPlaySoundInternal(mPlaySoundOnCapture);
1054+
10511055
try{
10521056
mCamera.setParameters(mCameraParameters);
10531057
}
@@ -1426,6 +1430,31 @@ private void setScanningInternal(boolean isScanning) {
14261430
}
14271431
}
14281432

1433+
private void setPlaySoundInternal(boolean playSoundOnCapture){
1434+
mPlaySoundOnCapture = playSoundOnCapture;
1435+
if(mCamera != null){
1436+
try{
1437+
mCamera.enableShutterSound(mPlaySoundOnCapture);
1438+
}
1439+
catch(Exception ex){
1440+
Log.e("CAMERA_1::", "setPlaySoundInternal failed", ex);
1441+
}
1442+
}
1443+
}
1444+
1445+
@Override
1446+
void setPlaySoundOnCapture(boolean playSoundOnCapture) {
1447+
if (playSoundOnCapture == mPlaySoundOnCapture) {
1448+
return;
1449+
}
1450+
setPlaySoundInternal(playSoundOnCapture);
1451+
}
1452+
1453+
@Override
1454+
public boolean getPlaySoundOnCapture(){
1455+
return mPlaySoundOnCapture;
1456+
}
1457+
14291458
@Override
14301459
public void onPreviewFrame(byte[] data, Camera camera) {
14311460
Camera.Size previewSize = mCameraParameters.getPreviewSize();

android/src/main/java/com/google/android/cameraview/Camera2.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import android.media.Image;
3838
import android.media.ImageReader;
3939
import android.media.MediaRecorder;
40+
import android.media.MediaActionSound;
4041
import androidx.annotation.NonNull;
4142
import android.util.Log;
4243
import android.util.SparseIntArray;
@@ -194,6 +195,10 @@ public void onImageAvailable(ImageReader reader) {
194195
if (image.getFormat() == ImageFormat.JPEG) {
195196
// @TODO: implement deviceOrientation
196197
mCallback.onPictureTaken(data, 0);
198+
if (mPlaySoundOnCapture) {
199+
MediaActionSound sound = new MediaActionSound();
200+
sound.play(MediaActionSound.SHUTTER_CLICK);
201+
}
197202
} else {
198203
mCallback.onFramePreview(data, image.getWidth(), image.getHeight(), mDisplayOrientation);
199204
}
@@ -262,6 +267,8 @@ public void onImageAvailable(ImageReader reader) {
262267

263268
private boolean mIsScanning;
264269

270+
private Boolean mPlaySoundOnCapture = false;
271+
265272
private Surface mPreviewSurface;
266273

267274
private Rect mInitialCropRegion;
@@ -675,6 +682,16 @@ public int getWhiteBalance() {
675682
return mWhiteBalance;
676683
}
677684

685+
@Override
686+
void setPlaySoundOnCapture(boolean playSoundOnCapture) {
687+
mPlaySoundOnCapture = playSoundOnCapture;
688+
}
689+
690+
@Override
691+
public boolean getPlaySoundOnCapture(){
692+
return mPlaySoundOnCapture;
693+
}
694+
678695
@Override
679696
void setScanning(boolean isScanning) {
680697
if (mIsScanning == isScanning) {
@@ -905,6 +922,7 @@ void startCaptureSession() {
905922
mCamera.createCaptureSession(Arrays.asList(surface, mStillImageReader.getSurface(),
906923
mScanImageReader.getSurface()), mSessionCallback, null);
907924
} catch (CameraAccessException e) {
925+
Log.e(TAG, "Failed to start capture session", e);
908926
mCallback.onMountError();
909927
}
910928
}

android/src/main/java/com/google/android/cameraview/CameraView.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ protected Parcelable onSaveInstanceState() {
256256
state.focusDepth = getFocusDepth();
257257
state.zoom = getZoom();
258258
state.whiteBalance = getWhiteBalance();
259+
state.playSoundOnCapture = getPlaySoundOnCapture();
259260
state.scanning = getScanning();
260261
state.pictureSize = getPictureSize();
261262
return state;
@@ -278,6 +279,7 @@ protected void onRestoreInstanceState(Parcelable state) {
278279
setFocusDepth(ss.focusDepth);
279280
setZoom(ss.zoom);
280281
setWhiteBalance(ss.whiteBalance);
282+
setPlaySoundOnCapture(ss.playSoundOnCapture);
281283
setScanning(ss.scanning);
282284
setPictureSize(ss.pictureSize);
283285
}
@@ -585,6 +587,14 @@ public int getWhiteBalance() {
585587
return mImpl.getWhiteBalance();
586588
}
587589

590+
public void setPlaySoundOnCapture(boolean playSoundOnCapture) {
591+
mImpl.setPlaySoundOnCapture(playSoundOnCapture);
592+
}
593+
594+
public boolean getPlaySoundOnCapture() {
595+
return mImpl.getPlaySoundOnCapture();
596+
}
597+
588598
public void setScanning(boolean isScanning) { mImpl.setScanning(isScanning);}
589599

590600
public boolean getScanning() { return mImpl.getScanning(); }
@@ -736,6 +746,8 @@ protected static class SavedState extends BaseSavedState {
736746

737747
int whiteBalance;
738748

749+
boolean playSoundOnCapture;
750+
739751
boolean scanning;
740752

741753
Size pictureSize;
@@ -752,6 +764,7 @@ public SavedState(Parcel source, ClassLoader loader) {
752764
focusDepth = source.readFloat();
753765
zoom = source.readFloat();
754766
whiteBalance = source.readInt();
767+
playSoundOnCapture = source.readByte() != 0;
755768
scanning = source.readByte() != 0;
756769
pictureSize = source.readParcelable(loader);
757770
}
@@ -772,6 +785,7 @@ public void writeToParcel(Parcel out, int flags) {
772785
out.writeFloat(focusDepth);
773786
out.writeFloat(zoom);
774787
out.writeInt(whiteBalance);
788+
out.writeByte((byte) (playSoundOnCapture ? 1 : 0));
775789
out.writeByte((byte) (scanning ? 1 : 0));
776790
out.writeParcelable(pictureSize, flags);
777791
}

android/src/main/java/com/google/android/cameraview/CameraViewImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ abstract boolean record(String path, int maxDuration, int maxFileSize,
124124

125125
abstract int getWhiteBalance();
126126

127+
abstract void setPlaySoundOnCapture(boolean playSoundOnCapture);
128+
129+
abstract boolean getPlaySoundOnCapture();
130+
127131
abstract void setScanning(boolean isScanning);
128132

129133
abstract boolean getScanning();

android/src/main/java/org/reactnative/camera/CameraViewManager.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ public void setPictureSize(RNCameraView view, String size) {
129129
view.setPictureSize(size.equals("None") ? null : Size.parse(size));
130130
}
131131

132+
@ReactProp(name = "playSoundOnCapture")
133+
public void setPlaySoundOnCapture(RNCameraView view, boolean playSoundOnCapture) {
134+
view.setPlaySoundOnCapture(playSoundOnCapture);
135+
}
136+
132137
@ReactProp(name = "barCodeTypes")
133138
public void setBarCodeTypes(RNCameraView view, ReadableArray barCodeTypes) {
134139
if (barCodeTypes == null) {
@@ -151,11 +156,6 @@ public void setUseCamera2Api(RNCameraView view, boolean useCamera2Api) {
151156
view.setUsingCamera2Api(useCamera2Api);
152157
}
153158

154-
@ReactProp(name = "playSoundOnCapture")
155-
public void setPlaySoundOnCapture(RNCameraView view, boolean playSoundOnCapture) {
156-
view.setPlaySoundOnCapture(playSoundOnCapture);
157-
}
158-
159159
@ReactProp(name = "faceDetectorEnabled")
160160
public void setFaceDetecting(RNCameraView view, boolean faceDetectorEnabled) {
161161
view.setShouldDetectFaces(faceDetectorEnabled);

android/src/main/java/org/reactnative/camera/RNCameraView.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import android.content.pm.PackageManager;
66
import android.graphics.Color;
77
import android.media.CamcorderProfile;
8-
import android.media.MediaActionSound;
98
import android.os.Build;
109
import androidx.core.content.ContextCompat;
1110
import android.view.View;
@@ -36,7 +35,6 @@ public class RNCameraView extends CameraView implements LifecycleEventListener,
3635
private Map<Promise, File> mPictureTakenDirectories = new ConcurrentHashMap<>();
3736
private Promise mVideoRecordedPromise;
3837
private List<String> mBarCodeTypes = null;
39-
private Boolean mPlaySoundOnCapture = false;
4038

4139
private boolean mIsPaused = false;
4240
private boolean mIsNew = true;
@@ -245,21 +243,14 @@ public void setBarCodeTypes(List<String> barCodeTypes) {
245243
initBarcodeReader();
246244
}
247245

248-
public void setPlaySoundOnCapture(Boolean playSoundOnCapture) {
249-
mPlaySoundOnCapture = playSoundOnCapture;
250-
}
251-
252246
public void takePicture(final ReadableMap options, final Promise promise, final File cacheDirectory) {
253247
mBgHandler.post(new Runnable() {
254248
@Override
255249
public void run() {
256250
mPictureTakenPromises.add(promise);
257251
mPictureTakenOptions.put(promise, options);
258252
mPictureTakenDirectories.put(promise, cacheDirectory);
259-
if (mPlaySoundOnCapture) {
260-
MediaActionSound sound = new MediaActionSound();
261-
sound.play(MediaActionSound.SHUTTER_CLICK);
262-
}
253+
263254
try {
264255
RNCameraView.super.takePicture(options);
265256
} catch (Exception e) {

docs/RNCamera.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ The idea is that you select the appropriate white balance setting for the type o
286286

287287
Use the `whiteBalance` property to specify which white balance setting the camera should use.
288288

289+
### `exposure`
290+
Value: float from `0` to `1.0`, or `-1` (default) for auto.
291+
292+
Sets the camera's exposure value.
293+
289294
### `zoom`
290295

291296
Value: float from `0` to `1.0`
@@ -334,6 +339,9 @@ Note: Must also provide cameraViewDimensions prop for Android device
334339

335340
An `{width:, height: }` object which defines the width and height of the cameraView. This prop is used to adjust the effect of Aspect Raio for rectOfInterest area on Android
336341

342+
### `Android` `playSoundOnCapture`
343+
Boolean to turn on or off the camera's shutter sound (default false). Note that in some countries, the shutter sound cannot be turned off.
344+
337345

338346
### `iOS` `videoStabilizationMode`
339347

0 commit comments

Comments
 (0)