SkillAgentSearch skills...

Rocc

A Swift framework for remote control of digital Cameras

Install / Use

/learn @simonmitchell/Rocc
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<p align="center"> <img width="376" height="182" alt="ROCC" src="https://github.com/simonmitchell/rocc/blob/master/assets/rocc.png"> </p> <p align="center"> <a href="https://travis-ci.org/simonmitchell/rocc"> <img alt="Build Status" src="https://travis-ci.org/simonmitchell/rocc.svg"> </a> <a href="https://github.com/Carthage/Carthage"> <img alt="Carthage Compatible" src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat"> </a> <a href="https://swift.org/package-manager/"> <img alt="Swift Package Manager Compatible" src="https://img.shields.io/badge/SPM-compatible-4BC51D.svg?style=flat"> </a> <a href="https://swift.org/blog/swift-5-3-released/"> <img alt="Swift 5.3" src="http://img.shields.io/badge/swift-5.3-brightgreen.svg"> </a> <a href="https://github.com/simonmitchell/rocc/blob/master/README.md"> <img alt="MIT" src="https://img.shields.io/badge/license-MIT-brightgreen.svg"> </a> </p>

Rocc (Remote Camera Control) is a Swift framework for interacting with Digital Cameras which support function control or Image/Video transfer via a WiFi connection. It currently only supports control/transfer from Sony's line-up of cameras but will be expanding in the future to support as many manufacturers as possible!

The Sony implementation is a tried and tested codebase which is used by the app Camrote to provide the connectivity with the camera.

Rocc is designed to be as generic as possible, both from a coding point of view and also from an API point of view, meaning support for other manufacturers should be a seamless integration with any existing codebase which is using the framework.

Installation

Swift Package Manager

Swift package manager is swift's de-facto distribution mechanism for code distribution.

Once you have your swift project/package setup, add Rocc as a dependency in your Package.swift file:

dependencies: [
    .package(url: "https://github.com/simonmitchell/rocc.git", .upToNextMajor(from: "2.0.0"))
]

Carthage

Carthage is a dependency manager which builds frameworks for you or downloads pre-built binaries from a specific tag on GitHub

  1. If you haven't already, setup Carthage as outlined here.
  2. Add Rocc as a dependency in your Cartfile: github "simonmitchell/rocc" == 2.0.0.
  3. Drag the Rocc.framework into your project's Frameworks, Libraries and Embedded Content section.
  4. Make sure that Rocc is included in your carthage copy files build phase.

Manual

Manual installation is a bit more involved, and not the suggested approach.

  1. Clone, download or add the repo as a submodule to your repo.
  2. Drag the Rocc project file into your main app's project.
  3. Add Rocc (Or the platform appropriate equivalent) to the Frameworks, Libraries and Embedded Content section of your app's target in the General panel of your project. Making sure you set it to Embed & Sign.
  4. Import Rocc and you're ready to go!

Examples

Discovering Cameras

To discover cameras you will use the class CameraDiscoverer. You must keep a strong reference to this in order to keep it in memory. It will start all the various tasks necessary for device discovery as well as keeping track of WiFi network changes and re-starting the search e.t.c. in these cases.

It will not start and re-start when your application enters the background and foreground however so you may want to implement this yourself!

init () {
    cameraDiscoverer = CameraDiscoverer()
    cameraDiscoverer.delegate = self
    cameraDiscoverer.start()
}


func cameraDiscoverer(_ discoverer: CameraDiscoverer, didError error: Error) {
    // Called with errors, these do happen a lot so you will want to check the error code and type here before displaying!        
}
    
func cameraDiscoverer(_ discoverer: CameraDiscoverer, discovered device: Camera) {
    // Connect to the device!
   connect(to: device)
}

CameraDiscoverer also maintains a dictionary of devices that have been discovered keyed by the SSID they were discovered on for your convenience, and the current SSID can be accessed using the Reachability class:

let cameras = discoverer.camerasBySSID[Reachability.currentWiFiSSID] ?? []

Connecting to a Camera


Once you have discovered to a camera, you will need to connect to it. Not all, but most Sony cameras require an API call to be made to enable remote functionality, but for the sake of genericness this should be called on all Camera objects.

func connect(to camera: Camera) {
    camera.connect { (error, isInTransferMode) in
        // isInTransferMode reflects whether the camera was already connected
        // to and has been re-connected to whilst in "Contents Transfer" mode.
    }
}

You should then progress to performing the functionality you wish to with the connected Camera. You should first check the core capabilities of the camera however as Sony supports two (Really 3) connection modes:

switch camera.connectionMode {
case .contentsTransfer(let preselected): 
    if preselected {
        camera.loadFilesToTransfer(callback: { (fileUrls) in
            // Download Files Somehow!
            camera.finishTransfer(callback: { (_) in
                
            })
        })
    } else {
        // Show UI for transferring files
    }
case .remoteControl:
// Show remote control UI
}

Staying Connected!


Rocc provides a simple delegate based class that will alert you when a Camera has become disconnected.

init(camera: Camera) {
    connectivityNotifier = DeviceConnectivityNotifier(camera: camera, delegate: self)
}

func connectivityNotifier(_ notifier: DeviceConnectivityNotifier, didDisconnectFrom device: Camera) {
    // If it is appropriate to show some kind of UI to let 
    //  the user know the camera has disconnected!    
}

func connectivityNotifier(_ notifier: DeviceConnectivityNotifier, didReconnectTo device: Camera) {
    // Let the user carry on as they were!
}

Streaming the Live View


Streaming the live view is as simple as using a LiveViewStream class.

init(camera: Camera) {
    liveViewStream = LiveViewStream(camera: camera, delegate: self)
    liveViewStream.start()
}

func liveViewStream(_ stream: LiveViewStream, didReceive image: UIImage) {
    OperationQueue.main.addOperation {
        // Show the next image
    }
}
    
func liveViewStream(_ stream: LiveViewStream, didReceive frames: [FrameInfo]) {
    OperationQueue.main.addOperation {
        // Show frame information (Focus info)
    }
}
    
func liveViewStreamDidStop(_ stream: LiveViewStream) {
    // Live view stopped!
}
    
func liveViewStream(_ stream: LiveViewStream, didError error: Error) {
    // Stream errored, you can try and restart it in this method if
    // you want, but be careful not to recurse too much!
}

Receiving Camera "Events"


Because your camera settings can still be adjusted manually on the camera whilst shooting, and some settings may affect others (Changing aperture whilst in aperture priority mode may change shutter speed/ISO e.t.c) it is important that the camera can communicate these changes over WiFi. To get changes you should subscribe to them using CameraEventNotifier:

init(camera: Camera) {
    eventNotifier = CameraEventNotifier(camera: camera, delegate: self)
    eventNotifier.startNotifying()
}

func eventNotifier(_ notifier: CameraEventNotifier, didError error: Error) {
    // If it's important to, show the user an Error        
}
    
func eventNotifier(_ notifier: CameraEventNotifier, receivedEvent event: CameraEvent) {
    // Handle the event and update UI! CameraEvent includes all exposure
    // info as well as changes to shooting mode, camera status, e.t.c.
}

It is important to note that the information provided by CameraEventNotifier will vary by manufacturer, and even by model of camera for the same manufacturer, so you may not always be able to rely on it solely!

IMPORTANT: The CameraEvent object may have nil values for properties that haven't changed with a given event occuring. For example if only the aperture has changed things like cameraStatus could be nil, which doesn't mean the camera is now idle. This depends on whether the camera is API driven (e.g. a7ii) or PTP/IP model (e.g. a9ii). This behaviour will be bought in line across all models in a future release of ROCC.

Performing Camera Functions


Camera functions are written generically, so there are only 4 methods you need to call on Camera rather than an individual set of methods for each piece of functionality on the camera.

Function Support

Before showing the UI for a function, you should make sure it is supported on your camera. To do this you call a method on your Camera object:

camera.supportsFunction(Focus.Mode.set, callback: { (isSupported, error, supportedValues) in
    // Disable/enable features using the returned value
})

The type type of supportedValues is defined on the declaration of Focus.Mode by it's associatedtype SendType

Function Availability

Once you have deemed if a function is supported on your camera, you can then check manually for function availability:

camera.isFunctionAvailable(Focus.Mode.set, callback: { (isAvailable, error, availableValues) in
    // Update UI to enable/disable control and show available values
})

Important: Function availability is also provided by the eventing mechanism, which is often a friendlier way to check for function availability and should be used for disabling/enabling controls when things like shutter speed setting become temporarily unavailable as the user takes a picture or changes to "Auto" mode on their camera.

You can also attempt to make a

View on GitHub
GitHub Stars145
CategoryDevelopment
Updated1mo ago
Forks17

Languages

Swift

Security Score

100/100

Audited on Feb 9, 2026

No findings