55

Before iOS 10 came out I was using the following code to get the video and audio capture for my video recorder:

 for device in AVCaptureDevice.devices()
 {
     if (device as AnyObject).hasMediaType( AVMediaTypeAudio )
     {
         self.audioCapture = device as? AVCaptureDevice
     }
     else if (device as AnyObject).hasMediaType( AVMediaTypeVideo )
     {
         if (device as AnyObject).position == AVCaptureDevicePosition.back
         {
             self.backCameraVideoCapture = device as? AVCaptureDevice
         }
         else
         {
             self.frontCameraVideoCapture = device as? AVCaptureDevice
         }
     }
 }

When iOS 10 finally came out, I received the following warning when I was running my code. Note that my video recorder was still working smoothly for about 2 weeks.

'devices()' was deprecated in iOS 10.0: Use AVCaptureDeviceDiscoverySession instead.

As I was running my code this morning, my video recorder stopped working. xCode8 does not give me any errors but the previewLayer for the camera capture is completely white. When I then start recording I receive the following error:

Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x17554440 {Error Domain=NSOSStatusErrorDomain Code=-12780 "(null)"}, NSLocalizedFailureReason=An unknown error occurred (-12780)}

I believe that has something to do with the fact that I am using the deprecated approach AVCaptureDevice.devices(). Hence, I was wondering how to use AVCaptureDeviceDiscoverySession instead?

Thank you for your help in advance!

Andi
  • 8,154
  • 3
  • 30
  • 34

12 Answers12

111

You can get the front camera with the following:

AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .front)

The back camera:

AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)

And the microphone:

AVCaptureDevice.default(.builtInMicrophone, for: AVMediaType.audio, position: .unspecified)
Justin Vallely
  • 5,932
  • 3
  • 30
  • 44
ivan_yorgov
  • 1,281
  • 1
  • 9
  • 7
  • Turned out that my camera on my iPhone was broken, hence the white color showing in the preview layer. Thank you for your answer though, at least I could get rid of my warning xcode8 was constantly giving me. – Andi Oct 06 '16 at 17:43
  • 1
    Do you know how to do the same thing using the back camera with Objective-C instead? – fi12 Nov 14 '16 at 00:40
  • 1
    It seems all answers are using `.builtInWideAngleCamera` as device type. Can you explain why you use this type and not one of the many others? For example there is also `.builtInDualWideCamera`. Will a dual wide camera still be returned with your code? – ndreisg Oct 21 '20 at 17:21
  • 1
    @ndreisg you can find the answer in Apples documentation https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/choosing_a_capture_device – Ali Amin Feb 01 '22 at 08:09
  • @AliAmin this link has the best approach to getting the best camera available. ps: you should add the option for triple camera before the dual one for the best results as that link seems a bit old – Mostafa ElShazly Jun 27 '22 at 09:17
14

Here's my code (Swift 3) to get camera position :

// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found
func cameraWithPosition(_ position: AVCaptureDevicePosition) -> AVCaptureDevice?
{
    if let deviceDescoverySession = AVCaptureDeviceDiscoverySession.init(deviceTypes: [AVCaptureDeviceType.builtInWideAngleCamera],
                                                          mediaType: AVMediaTypeVideo,
                                                          position: AVCaptureDevicePosition.unspecified) {

        for device in deviceDescoverySession.devices {
            if device.position == position {
                return device
            }
        }
    }

    return nil
}

If you want, you can also get the new devicesTypes from iPhone 7+ (dual camera) by changing the deviceTypes array.

Here's a good read : https://forums.developer.apple.com/thread/63347

hefgi
  • 484
  • 5
  • 14
13

Swift 4, iOS 10+ and Xcode 10.1 replaces

if let cameraID = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)?.localizedName {
       //cameraID = "Front Camera"
}

with AVCaptureDevice.DiscoverySession implementation

if let cameraID = AVCaptureDevice.DiscoverySession.init(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: .video, position: .front).devices.first?.localizedName{
        //cameraID = "Front Camera"
} 

Need to wrap it with #available(iOS 10,*) check.

Rafat touqir Rafsun
  • 2,777
  • 28
  • 24
  • 1
    Code for the discovery session should now be: `if let cameraID = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.front).devices.first?.localizedName{ //cameraID = "Front Camera" }` `AVCaptureDeviceType` was replaced by `AVCaptureDevice.DeviceType` and `AVCaptureDevicePosition` was replaced by `AVCaptureDevice.Position` (XCode 9.2 / Swift 4) – esco_ Apr 01 '18 at 21:59
  • The devices array is empty, do you know why? – Ricardo Ruiz Romero Sep 27 '18 at 18:29
9

It works on Xcode 9.2 and Swift 4

AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)

https://developer.apple.com/documentation/avfoundation/avcapturedevice/2361508-default

atereshkov
  • 4,311
  • 1
  • 38
  • 49
3

Swift 3

For selecting the back camera:(also you can change .back as needed)

For selecting another deviceType simple add it inside the [ ] (i.e:

[deviceTypeCamera, AVCaptureDeviceType.builtInMicrophone]

(or create a private let... like I did in the code with the back camera)

 private let position = AVCaptureDevicePosition.back
 private let deviceTypeBackCamera = AVCaptureDeviceType.builtInWideAngleCamera

 private func selectCaptureDevice() -> AVCaptureDevice? {
    return AVCaptureDeviceDiscoverySession(deviceTypes: [deviceTypeBackCamera], mediaType: AVMediaTypeVideo, position: position).devices.first

 }
MLBDG
  • 1,357
  • 17
  • 23
  • Xcode 9 just asked to me use __deviceTypes: instead of deviceTypes:, apart from that, it works. – epx Aug 01 '17 at 22:01
3

example: iOS 11 Swift 4

override func viewDidLoad() {
    super.viewDidLoad()

    // Get the back-facing camera for capturing videos

    // AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)
    let deviceDiscoverySession = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)

   guard let captureDevice = deviceDiscoverySession else {
       print("Failed to get the camera device")
       return
   }

    do {
        // Get an instance of the AVCaptureDeviceInput class using the previous device object.
        let input = try AVCaptureDeviceInput(device: captureDevice)

        // Set the input device on the capture session.
        captureSession.addInput(input)

    } catch {
        // If any error occurs, simply print it out and don't continue any more.
        print(error)
        return
    }

    // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
    videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    videoPreviewLayer?.frame = view.layer.bounds
    view.layer.addSublayer(videoPreviewLayer!)

    // Start video capture.
    captureSession.startRunning()
Harry McGovern
  • 517
  • 5
  • 19
  • Anyone finding that this does not work with the latest beta 11.3 SDK on 10+ phones? This works on my phone but non of my testflight testers phone the video preview layer is not getting created. – justdan0227 Mar 26 '18 at 00:13
2

Try below code to get camera ID:

NSString *cameraID = nil;

NSArray *captureDeviceType = @[AVCaptureDeviceTypeBuiltInWideAngleCamera];
AVCaptureDeviceDiscoverySession *captureDevice = 
              [AVCaptureDeviceDiscoverySession 
                discoverySessionWithDeviceTypes:captureDeviceType 
                mediaType:AVMediaTypeVideo 
                position:AVCaptureDevicePositionUnspecified];

cameraID = [captureDevice.devices.lastObject localizedName];
pckill
  • 3,709
  • 36
  • 48
Adriel Artiza
  • 327
  • 4
  • 12
2

Swift 4 (xCode 10.1)

This is what worked for me in the latest version of Swift. I did not see this answer, and it took me a while to suss out so here is how to get the front facing camera.

 if let device = AVCaptureDevice.defaultDevice(withDeviceType: .builtInWideAngleCamera , mediaType: AVMediaTypeVideo, position: .front)  {
    //Do the camera thing here..
}
Dave Levy
  • 1,036
  • 13
  • 20
2

Simplified:

func getCamera(with position: AVCaptureDevice.Position) -> AVCaptureDevice? {
    let deviceDescoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera], mediaType: .video, position: .unspecified)
    return deviceDescoverySession.devices.first(where: { $0.position == position })
}

// and you can use like that:

guard let device = getCamera(with: .back) else { return }
Can Koç
  • 21
  • 2
1

For my video capture app I'm using the following code to get the mic, front and rear camera and I've tested this code from iOS 7 to 10.0.2.

        var frontCamera : AVCaptureDevice?
        var rearCamera : AVCaptureDevice?

        captureSession = AVCaptureSession()

        let devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)

        let audioDevices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeAudio)

        for mic in audioDevices {
            audioDevice = mic as? AVCaptureDevice
            audioCapturePossible = true
        }

        for device in devices {
            if device.position == AVCaptureDevicePosition.Front {
                frontCamera = device as? AVCaptureDevice
                hasFrontCamera = true
            }
            else if device.position == AVCaptureDevicePosition.Back {
                rearCamera = device as? AVCaptureDevice
                hasRearCamera = true
            }

        }
Hammadzafar
  • 480
  • 1
  • 7
  • 21
1

In Swift 5 it is more easy

AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .front)
Ulugbek
  • 127
  • 3
  • 15
-1

05/2019 :

 //video
        self.session = AVCaptureSession()
        guard
            let videoDeviceInput = try? AVCaptureDeviceInput(device: device!),
            self.session!.canAddInput(videoDeviceInput)
            else { return }
        self.session!.addInput(videoDeviceInput)

  //audio
        guard
            let audioDeviceInput = try? AVCaptureDeviceInput(device: mic!),
            self.session!.canAddInput(audioDeviceInput)
            else { return }
        self.session!.addInput(audioDeviceInput) 
BorisD
  • 1,611
  • 17
  • 22