# Camera scanning with SocketCam

Implement camera-based barcode scanning with SocketCam in CaptureSDK. Covers enabling SocketCam, handling SocketCam device presence events, and three camera presentation modes: fullscreen overlay, embedded subview within your UI, and popover. Also covers configuring continuous scanning mode, customizing the close button appearance, and triggering scans programmatically. SocketCam uses the same Capture Helper delegate events as physical scanners. Includes code samples for each mode.

## Device presence

On some platforms, SocketCam is enabled by default so the **Capture Helper device arrival event** is triggered automatically. If it's not, refer to the section [Enabling SocketCam](#enabling-socketcam)

## Swift

```swift
var socketCamDevice: CaptureHelperDevice?

extension MyViewController: CaptureHelperDevicePresenceDelegate {

  func didNotifyArrivalForDevice(_ device: CaptureHelperDevice, withResult result: SKTResult) {
      print("didNotifyArrivalForDevice: \(device.deviceInfo.name ?? "") - Result: \(result.rawValue)")
      if device.deviceInfo.deviceType = .socketCamC820 || device.deviceInfo.deviceType = .socketCamC860 {
          // handle SocketCam device arrival - Retains it to later trigger the camera scanning
          socketCamDevice = device
      }
  }

  func didNotifyRemovalForDevice(_ device: CaptureHelperDevice, withResult result: SKTResult) {
      print("didNotifyRemovalForDevice: \(device.deviceInfo.name ?? "") - Result: \(result.rawValue)")
      if device.deviceInfo.deviceType = .socketCamC820 || device.deviceInfo.deviceType = .socketCamC860 {
          // handle SocketCam device removal - Destroying the object
          socketCamDevice = nil
      }
  }

}
```

## Using SocketCam

Now the application is ready to use the camera as a barcode scanner. Usually an application shows a "Scan trigger" button somewhere in the UI to start scanning for a barcode.

> **Note**
>
> Applications can use physical buttons such as the volume up or down button to act as a trigger button.

The way to start the scanning operation is by sending the **setTrigger property**.

- The view closes once a barcode is scanned.
- The decoded data are sent in a **decoded data event** as it does for any other physical scanner.
- [Trigger continuous](#triggering-socketcam-in-continuous-mode) mode will launch the SocketCam view and continue to scan barcodes until the view is dismissed by the user. You can store the scanned barcodes into an array for instance.

## Triggering SocketCam

With CaptureSDK, you will be able to present SocketCam as you wish in a custom view, a popover and still in full screen. Now you decide where and when triggering and removing SocketCam view in your application's flow. 

> **Warning**
>
> This is your responsibility to handle the presentation and the dismissal of the view.
>
> Also, there's a minimal size of 250px x 250px to observe in order to display all SocketCam's UI elements as a subview or a popover.

## Sample code for SocketCam presented in Full screen

## Swift

```swift
var socketCamDevice: CaptureHelperDevice?
var mySocketCamViewController: UIViewController?

// The signature of the method to trigger SocketCam has now an extra return parameter: propertyObject. 
// It contains a dictionary that contains the SocketCam view controller that you can use as you wish in full screen, as a subview or a popover.

socketCamDevice.setTrigger(.start, withCompletionHandler: { result, propertyObject in
    DispatchQueue.main.async {
        if let anObject = propertyObject?.object,
           let dic = anObject as? [String: Any],
           let objectType = dic["SKTObjectType"] as? String, objectType == "SKTSocketCamViewControllerType",
           let socketCamViewController = dic["SKTSocketCamViewController"] as? UIViewController {
                socketCamViewController.modalPresentationStyle = .fullScreen
                self.present(socketCamViewController, animated: true)
                // retain the socketcam view controller for the dismissal later
                self.mySocketCamViewController = socketCamViewController
        }
    }
})

extension MyViewController: CaptureHelperDeviceDecodedDataDelegate {
    // This delegate is called each time a decoded data is read from a scanner or SocketCam
    func didReceiveDecodedData(_ decodedData: SKTCaptureDecodedData?, fromDevice device: CaptureHelperDevice, withResult result:SKTResult) {
        print("--->>> didReceiveDecodedData for device: \(device.deviceInfo.deviceType)")
        if result == .E_NOERROR {
            let str = decodedData!.stringFromDecodedData()
            print("Decoded Data \(String(describing: str))")
        }
        DispatchQueue.main.async {
            // Dismiss and reset your socketCamViewController
            self.mySocketCamViewController?.dismiss(animated: true, completion: {
                self.mySocketCamViewController = nil
            })
        }
    }
}
```

## Sample code for SocketCam presented as a subview

## Swift

```swift
var socketCamDevice: CaptureHelperDevice?
var mySocketCamViewController: UIViewController?
var mySocketCamView: UIView? // can be also an @IBOutlet

// The signature of the method to trigger SocketCam has now an extra return parameter: propertyObject. 
// It contains a dictionary that contains the SocketCam view controller that you can use as you wish in full screen, as a subview or a popover.

socketCamDevice.setTrigger(.start, withCompletionHandler: { result, propertyObject in
    DispatchQueue.main.async {
        if let anObject = propertyObject?.object,
           let dic = anObject as? [String: Any],
           let objectType = dic["SKTObjectType"] as? String, objectType == "SKTSocketCamViewControllerType",
           let socketCamViewController = dic["SKTSocketCamViewController"] as? UIViewController {
                self.mySocketCamViewController.view.frame = self.mySocketCamView.bounds
                self.mySocketCamView?.addSubview(socketCamViewController.view)
                // retain the socketcam view controller for the dismiss later
                self.mySocketCamViewController = socketCamViewController
        }
    }
})

extension MyViewController: CaptureHelperDeviceDecodedDataDelegate {
    // This delegate is called each time a decoded data is read from a scanner or SocketCam
    func didReceiveDecodedData(_ decodedData: SKTCaptureDecodedData?, fromDevice device: CaptureHelperDevice, withResult result:SKTResult) {
        print("--->>> didReceiveDecodedData for device: \(device.deviceInfo.deviceType)")
        if result == .E_NOERROR {
            let str = decodedData!.stringFromDecodedData()
            print("Decoded Data \(String(describing: str))")
        }
        DispatchQueue.main.async {
            // Remove your socketCamViewController view from the parent and reset it
            self.mySocketCamViewController?.view.removeFromSuperview()
            self.mySocketCamViewController = nil
        }
    }
}
```

## Sample code for SocketCam presented as a popover

## Swift

```swift
var socketCamDevice: CaptureHelperDevice?
var mySocketCamViewController: UIViewController?

// The signature of the method to trigger SocketCam has now an extra return parameter: propertyObject. 
// It contains a dictionary that contains the SocketCam view controller that you can use as you wish in full screen, as a subview or a popover.

socketCamDevice.setTrigger(.start, withCompletionHandler: { result, propertyObject in
    DispatchQueue.main.async {
        if let anObject = propertyObject?.object,
           let dic = anObject as? [String: Any],
           let objectType = dic["SKTObjectType"] as? String, objectType == "SKTSocketCamViewControllerType",
           let socketCamViewController = dic["SKTSocketCamViewController"] as? UIViewController {
                let popOverVC = socketCamViewController.popoverPresentationController
                popOverVC?.delegate = self
                popOverVC?.sourceView = // a view of your chosing
                socketCamViewController.preferredContentSize = CGSize(width: myWidth, height: myHeight)
                socketCamViewController.modalPresentationStyle = .popover
                self.present(socketCamViewController, animated: true)
                // retain the socketcam view controller for the dismiss later
                self.mySocketCamViewController = socketCamViewController
        }
    }
})

extension MyViewController: CaptureHelperDeviceDecodedDataDelegate {
    // This delegate is called each time a decoded data is read from a scanner or SocketCam
    func didReceiveDecodedData(_ decodedData: SKTCaptureDecodedData?, fromDevice device: CaptureHelperDevice, withResult result:SKTResult) {
        print("--->>> didReceiveDecodedData for device: \(device.deviceInfo.deviceType)")
        if result == .E_NOERROR {
            let str = decodedData!.stringFromDecodedData()
            print("Decoded Data \(String(describing: str))")
        }
        DispatchQueue.main.async {
            // Dismiss and reset your socketCamViewController
            self.mySocketCamViewController?.dismiss(animated: true, completion: {
                self.mySocketCamViewController = nil
            })
        }
    }
}
```

## Configuring SocketCam close button

Depending on how you want to display SocketCam in your application, it may require to show or hide the close button of the SocketCam view controller. Ideally, you can execute this at the device arrival of a SocketCam device, whether it is C820 or C860. In order to do so, add a specific configuration as follow. By default, the button is shown.

## Swift

```swift
var socketCamDevice: CaptureHelperDevice?

extension MyViewController: CaptureHelperDevicePresenceDelegate {

  func didNotifyArrivalForDevice(_ device: CaptureHelperDevice, withResult result: SKTResult) {
      print("didNotifyArrivalForDevice: \(device.deviceInfo.name ?? "") - Result: \(result.rawValue)")
      if device.deviceInfo.deviceType = .socketCamC820 || device.deviceInfo.deviceType = .socketCamC860 {
          // handle SocketCam device arrival - Retains it to later trigger the camera scanning
          socketCamDevice = device

          let prop = SKTCaptureProperty()
          prop.id = SKTCapturePropertyID.configuration
          prop.type = .string
          prop.stringValue = "SocketCamCloseButton=enabled" /// to show the close button
          // OR
          prop.stringValue = "SocketCamCloseButton=disabled" /// to hide the close button
          self.captureHelper.setProperty(prop) { result, complete in
              print("SocketCam button result: \(result.rawValue)")
          }
      }
  }

}
```

## Triggering SocketCam in Continuous mode

The only difference between starting SocketCam as a single scan and a continous scan is the parameter of the **setTrigger** helper method: "Start" or "ContinuousScan".

Then you can store the decoded data results into an array that you can use after closing the SocketCam view.

## Swift

```swift
var socketCamDevice: CaptureHelperDevice?
var mySocketCamViewController: UIViewController?
var results: [String] = []

// The signature of the method to trigger SocketCam has now an extra return parameter: propertyObject. 
// It contains a dictionary that contains the SocketCam view controller that you can use as you wish in full screen, as a subview or a popover.

socketCamDevice.setTrigger(.continuousScan, withCompletionHandler: { result, propertyObject in
    DispatchQueue.main.async {
        if let anObject = propertyObject?.object,
           let dic = anObject as? [String: Any],
           let objectType = dic["SKTObjectType"] as? String, objectType == "SKTSocketCamViewControllerType",
           let socketCamViewController = dic["SKTSocketCamViewController"] as? UIViewController {
                socketCamViewController.modalPresentationStyle = .fullScreen
                self.present(socketCamViewController, animated: true)
                // retain the socketcam view controller for the dismissal later
                self.mySocketCamViewController = socketCamViewController
        }
    }
})

extension MyViewController: CaptureHelperDeviceDecodedDataDelegate {
    // This delegate is called each time a decoded data is read from a scanner or SocketCam
    func didReceiveDecodedData(_ decodedData: SKTCaptureDecodedData?, fromDevice device: CaptureHelperDevice, withResult result:SKTResult) {
        print("--->>> didReceiveDecodedData for device: \(device.deviceInfo.deviceType)")
        if result == .E_NOERROR {
            let str = decodedData!.stringFromDecodedData()
            print("Decoded Data \(String(describing: str))")

            // Add the decoded data result into your results array
            results.append(str)
        }
        DispatchQueue.main.async {
            // Dismiss and reset your socketCamViewController
            self.mySocketCamViewController?.dismiss(animated: true, completion: {
                self.mySocketCamViewController = nil
            })
        }
    }
}
```

## Enabling SocketCam

On certain platforms, SocketCam needs to be enabled in order to be used.

## Swift

```swift
let captureHelper = CaptureHelper.sharedInstance

// retrieve the current status of SocketCam
captureHelper.getSocketCamStatusWithCompletionHandler( {(getResult, socketCamStatus) in
    if getResult == SKTCaptureErrors.E_NOERROR {
        if socketCamStatus == .disable {
            // set the status of SocketCam to enable
            self.captureHelper.setSocketCamStatus(.enable, withCompletionHandler: { (setResult) in
                if setResult == SKTCaptureErrors.E_NOERROR {
                    print("SocketCam enabled returned \(setResult.rawValue)")
                }
            })
        }
    }
})

// set the status of SocketCam to disable
captureHelper.setSocketCamStatus(.disable, withCompletionHandler: { (setResult) in
    if setResult == SKTCaptureErrors.E_NOERROR {
        print("SocketCam disabled returned \(setResult.rawValue)")
    }
})
```