AVFoundation, how to turn off the shutter sound when captureStillImageAsynchronouslyFromConnection? AVFoundation, how to turn off the shutter sound when captureStillImageAsynchronouslyFromConnection? objective-c objective-c

AVFoundation, how to turn off the shutter sound when captureStillImageAsynchronouslyFromConnection?


I used this code once to capture iOS default shutter sound (here is list of sound file names https://github.com/TUNER88/iOSSystemSoundsLibrary):

NSString *path = @"/System/Library/Audio/UISounds/photoShutter.caf";NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];NSData *data = [NSData dataWithContentsOfFile:path];[data writeToFile:[docs stringByAppendingPathComponent:@"photoShutter.caf"] atomically:YES];

Then I used third-party app to extract photoShutter.caf from Documents directory (DiskAid for Mac). Next step I opened photoShutter.caf in Audacity audio editor and applied inversion effect, it looks like this on high zoom:

enter image description here

Then I saved this sound as photoShutter2.caf and tried to play this sound right before captureStillImageAsynchronouslyFromConnection:

static SystemSoundID soundID = 0;if (soundID == 0) {    NSString *path = [[NSBundle mainBundle] pathForResource:@"photoShutter2" ofType:@"caf"];    NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];    AudioServicesCreateSystemSoundID((__bridge CFURLRef)filePath, &soundID);}AudioServicesPlaySystemSound(soundID);[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:...

And this really works! I runs test several times, every time I hear no shutter sound :)

You can get already inverted sound, captured on iPhone 5S iOS 7.1.1 from this link: https://www.dropbox.com/s/1echsi6ivbb85bv/photoShutter2.caf


My Solution in Swift

When you call AVCapturePhotoOutput.capturePhoto method to capture an image like the below code.

photoOutput.capturePhoto(with: self.capturePhotoSettings, delegate: self)

AVCapturePhotoCaptureDelegate methods will be invoked.And the system tries to play shutter sound after willCapturePhotoFor invoked.So you can dispose of system sound in willCapturePhotoFor method.

enter image description here

extension PhotoCaptureService: AVCapturePhotoCaptureDelegate {    func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {        // dispose system shutter sound        AudioServicesDisposeSystemSoundID(1108)    }}

See also


Method 1: Not sure if this will work, but try playing a blank audio file right before you send the capture event.

To play a clip, add the Audio Toolbox framework, #include <AudioToolbox/AudioToolbox.h>and play the audio file like this immediately before you take the picture:

 NSString *path = [[NSBundle mainBundle] pathForResource:@"blank" ofType:@"wav"]; SystemSoundID soundID; NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO]; AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID); AudioServicesPlaySystemSound(soundID);

Here is a blank audio file if you need it. https://d1sz9tkli0lfjq.cloudfront.net/items/0Y3Z0A1j1H2r1c0z3n3t/blank.wav

________________________________________________________________________________________________________________________________________

Method 2: There's also an alternative if this doesn't work. As long as you don't need to have a good resolution, you can grab a frame from the video stream, thus avoiding the picture sound altogether.

________________________________________________________________________________________________________________________________________

Method 3: Another way to do this would be to take a "screenshot" of your application. Do it this way:

UIGraphicsBeginImageContext(self.window.bounds.size);[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];UIImage *image = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();NSData * data = UIImagePNGRepresentation(image);[data writeToFile:@"foo.png" atomically:YES];

If you're wanting this to fill the whole screen with a preview of the video stream so that your screenshot looks good:

AVCaptureSession *captureSession = yourcapturesession;AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];UIView *aView = theViewYouWantTheLayerIn;previewLayer.frame = aView.bounds; // Assume you want the preview layer to fill the view.[aView.layer addSublayer:previewLayer];