Skip to content

Repository files navigation

SimulatorCamera

Plug a real camera, a video file, or your screen into the iOS Simulator. Finally.

Swift 5.9+PlatformsSwiftPMLicense: MITReleaseCISponsor

The iOS Simulator has never supported a real camera. AVCaptureDevice is empty. Every app that touches the camera — QR scanners, barcode readers, document capture, ML pipelines, AR prototypes — either stubs out the camera path, runs only on device, or ships a brittle "use a photo instead" fallback.

SimulatorCamera is a tiny two-piece developer tool that fixes it:

  • a macOS companion app that streams video frames over localhost:9876 using a compact binary protocol (SCMF — Simulator Camera Message Format), and
  • an iOS Swift Package with an AVCaptureSession-shaped API. On device it compiles to a no-op.

Frames show up in your app. Vision, VisionKit, Core ML, barcode detection, custom pipelines — the SDK is designed to drive them in the Simulator at 25–30 FPS over localhost, no device, no cables, no private APIs.


Why

Because Apple never added a way the camera from the Simulator. A must have for every developer. SimulatorCamera finally fill that gap.

Features

  • 🎥 Live video into the Simulator at 30 FPS via localhost TCP
  • 🧩 Drop-in SDK — FrameSource mirrors AVCaptureSession semantics (start(), stop(), delegate, CVPixelBuffer callbacks)
  • 🔌 Sources on the Mac: test pattern (built-in), webcam, video file, screen region (roadmap)
  • 📦 One-line install via Swift Package Manager
  • 🛡 No private APIs — Network.framework + CoreVideo + ImageIO
  • 📵 Zero overhead on device — #if targetEnvironment(simulator)-guarded
  • 🔐 Localhost-only by default
  • 🧪 Vision / Core ML ready — frames land as CVPixelBuffer

Installation

iOS SDK — Swift Package Manager

dependencies:[.package(url:"https://github.com/Akylas/SimulatorCamera.git", from:"1.0.0"),],targets:[.target(
name:"MyApp",
dependencies:[.product(name:"SimulatorCameraClient",package:"SimulatorCamera"),]),]

Or in Xcode: File → Add Package Dependencies… → paste the repo URL.

macOS companion app

Homebrew (recommended):

brew tap akylas/simulatorcamera https://github.com/Akylas/SimulatorCamera
brew install simulatorcamera
open -a SimulatorCameraServer

Or grab the signed & notarized .dmg from Releases. Or build from source:

git clone https://github.com/dautovri/SimulatorCamera.git
cd SimulatorCamera
brew install xcodegen
xcodegen generate --spec apps/MacServer/project.yml
open apps/MacServer/SimulatorCameraServer.xcodeproj

Usage

  1. Launch SimCameraServer.app on your Mac. Pick a source and click Start.
  2. In your iOS code:
import SimulatorCameraClient
finalclassCameraController:NSObject,FrameSourceDelegate{privateletsource:FrameSourceoverrideinit(){#if targetEnvironment(simulator)
source =SimulatorCameraSession(host:"127.0.0.1", port:9876)#else
source =AVCaptureFrameSource() // your existing AVCapture wrapper
#endif
super.init()
source.delegate =self
source.start()}func frameSource(_ source:FrameSource, didOutput pixelBuffer:CVPixelBuffer, at time:CMTime){
// Feed to Vision, Core ML, preview layer, whatever.
}}

Full AVCaptureSession drop-in

The shim now mirrors the whole AVCaptureSession → addInput → addOutput → startRunning dance. Your existing camera-setup code ports over by prefixing each type with Simulator:

import SimulatorCameraClient
SimulatorCamera.configure(host:"127.0.0.1", port:9876)letsession=SimulatorCaptureSession()
session.sessionPreset =.hd1280x720
guardlet device =SimulatorCaptureDevice.default(for:.video)else{return}letinput=trySimulatorCaptureDeviceInput(device: device)
session.addInput(input)letoutput=SimulatorCameraOutput() // AVCaptureVideoDataOutput-shaped
output.setSampleBufferDelegate(self, queue: frameQueue)
session.addOutput(output)
session.startRunning() // kicks off the network session

Your existing captureOutput(_:didOutput:from:) delegate fires with a valid CMSampleBuffer wrapping a CVPixelBuffer — same code path as the real device.

Zero-change AVFoundation path (recommended)

If you already have an AVCaptureVideoDataOutputSampleBufferDelegate, swap the output for SimulatorCameraOutput inside a simulator guard and keep your delegate code unchanged. The standard captureOutput(_:didOutput:from:) method fires with a real CMSampleBufferSimulatorCameraOutput is an AVCaptureVideoDataOutput subclass, so the first argument is a genuine AV output, not a stand-in:

#if targetEnvironment(simulator)letoutput=SimulatorCameraOutput()
output.setSampleBufferDelegate(self, queue: myQueue)SimulatorCamera.start()#elseletoutput=AVCaptureVideoDataOutput()
output.setSampleBufferDelegate(self, queue: myQueue)
session.addOutput(output)#endif

Or use the drop-in SwiftUI view:

import SwiftUI
import SimulatorCameraClient
structContentView:View{varbody:someView{SimulatorCameraPreviewView()}}

Protocol (SCMF)

+--------+---------------+------------------+--------+---------+----------+
| magic | payloadLength | timestamp | width | height | jpegData |
| 4 B | 4 B uint32 LE | 8 B Float64 LE | 4 B LE | 4 B LE | N bytes |
| "SCMF" | |
+--------+---------------+------------------+--------+---------+----------+

Full spec: docs/PROTOCOL.md · architecture: docs/ARCHITECTURE.md · roadmap: docs/ROADMAP.md.

Repo layout

SimulatorCamera/
├── Package.swift # SwiftPM manifest (exposes SimulatorCameraClient)
├── Sources/SimulatorCameraClient/ # the iOS SDK
├── Tests/SimulatorCameraClientTests/ # unit tests for the SCMF codec
├── apps/
│ ├── MacServer/ # SwiftUI macOS companion app
│ └── iOSDemo/ # sample iOS app using the SDK
├── docs/
│ ├── PROTOCOL.md # wire format
│ ├── ARCHITECTURE.md # threading, transport, failure modes
│ └── ROADMAP.md
├── Casks/simulatorcamera.rb # Homebrew cask formula
├── scripts/
│ ├── bootstrap.sh # swift build + test
│ └── build-release.sh # archive + codesign + notarize + .dmg/.zip
├── .github/
│ ├── FUNDING.yml # GitHub Sponsors / BMC
│ └── workflows/
│ ├── ci.yml # SwiftPM CI on macos-14
│ └── release.yml # tag-driven signed release
└── RELEASING.md # release runbook

Development

./scripts/bootstrap.sh # swift build && swift test
brew install xcodegen
xcodegen generate --spec apps/MacServer/project.yml
xcodegen generate --spec apps/iOSDemo/project.yml

Status

v0.2.0 — "Use my real camera." First stable release with a drop-in AVCaptureSession shim and live Mac webcam source. See CHANGELOG.md and docs/RELEASE_NOTES_v0.2.0.md.

Contributing

See CONTRIBUTING.md. Good first issues are labelled on the tracker. For release mechanics, see RELEASING.md.

Sponsor

SimulatorCamera is fully MIT-licensed and maintained on donations. If it saves you a device-build loop, consider sponsoring or buying a coffee. No paid tier, no license keys, no telemetry — just a tip jar.

License

MIT — see LICENSE.

About

Plug a real camera, a video file, or your screen into the iOS Simulator. Finally.

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages