Skip to content

Splintercom/ClientiOS

Repository files navigation

Splintercom ClientiOS

Native iOS device client for the Splintercom video splintercom system — plays the same device role as ClientPython (OAuth2 device flow + WebRTC camera streaming), so an iPhone/iPad can be repurposed as a CCTV or doorbell camera instead of needing a Raspberry Pi.

Tech Stack

  • Swift 6 (strict concurrency), SwiftUI (iOS 15+)
  • stasel/WebRTC — prebuilt Google libwebrtc via Swift Package Manager
  • Built via xtool, not Xcode — works from Linux/Windows, not just macOS
  • Keychain (OAuth tokens), UserDefaults (server settings + device preferences)

Development

# One-time setup (installs the Darwin Swift SDK, handles Apple auth)
xtool setup

# Build
xtool dev build

# Pure-logic tests (no WebRTC/UIKit dependency) — runs on plain Linux Swift
swift test

# Install + launch on a connected device
xtool install xtool/ClientiOS.app
xtool launch com.intercom.clientios   # or launch manually from the home screen

If you're on a Mac with Xcode, xtool dev generate-xcode-project can produce an .xcodeproj for a more familiar editing experience — Package.swift/xtool.yml remain the source of truth either way.

Setup (first run)

  1. Build and install the app on a device (see above).
  2. Tap "Scan QR Code" in Settings and scan the QR code on the Frontend's "Add Device" page (/devices/add → iOS section) — fills in the server URLs + OAuth client ID in one go (manual entry is available as a fallback).
  3. Tap "Start Pairing", then approve the device from the Splintercom web dashboard using the displayed user code.
  4. Once paired, the app streams its camera to any viewer who opens that device in the Frontend.

Key Features

  • Foreground-only by design — iOS suspends camera capture within seconds of backgrounding, so there's no attempt to fight that with VoIP/PiP background modes. The app disables the idle timer while active and shows a "streaming paused" banner if backgrounded. Mount the device somewhere it can stay plugged in and awake.
  • Front/back camera choice (Settings → Camera) — useful for a doorbell-style mount using the front/selfie camera, screen facing the visitor.
  • On-screen display message — set locally (Settings) or remotely from the Frontend's device view page, e.g. "We're not home right now" — shown on the device's own screen without affecting the video feed to viewers. Anonymous share-link viewers can't set it, only signed-in owners.
  • Full-screen "kiosk" mode — hides connection diagnostics/viewer count, showing just the camera preview or message full-screen; available once the camera is set to front.
  • Two-way audio — the device streams mic audio alongside video and plays incoming viewer audio through the speaker (not the earpiece), so it works as a real splintercom once the viewer enables audio from the Frontend. No mute control on the device side by design — mute, if wanted, is a viewer-side concern (see Frontend's ViewDevice.tsx).

See CLAUDE.md for architecture details (DeviceClient orchestration, WebRTC/signaling internals, xtool-specific gotchas).

Real-device verification status

Most of this project was built and verified from a Linux dev machine with no physical iPhone or macOS host available, using xtool dev build/swift test plus live-backend wire-protocol checks. Two things couldn't be verified from Linux and needed a real device:

  1. URLSessionWebSocketTask at runtime. It compiles fine on Linux, but crashes there at runtime ("WebSockets not supported by libcurl") — a gap in swift-corelibs-foundation's Linux networking backend, not a bug in this code. Confirmed working on a real iPhone (iOS 15.8.3, installed via xtool install) — Apple's native, non-libcurl URLSession WebSocket implementation handles the signaling connection correctly.
  2. A single RTCVideoTrack added to multiple concurrent RTCPeerConnections. Standard behavior in libwebrtc's C++ core, and the reason CameraController doesn't need to port ClientPython's manual SharedCameraSource frame-queue fan-out. Confirmed working: paired the physical device, connected as a viewer from the Frontend dashboard, and saw live camera video.

Deployment note: the app was installed via xtool install under a free/personal Apple Developer account, which required revoking an existing "iOS Development" certificate first (Apple limits personal accounts to one active dev cert) — do this deliberately, since it invalidates any other app currently signed with that cert until rebuilt. xtool launch's automatic launch (which attaches a debugserver) failed with DebugserverClient.Error.unknown on iOS 15.8.3, likely a Developer Disk Image mismatch for this older OS version — launching the app manually from the home screen works fine and is unaffected.

Still untested: multiple simultaneous viewers on the same device (only one viewer has been tried so far).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages