Changelog
What changed
The repository ships three artefacts with one shared version number: the macOS app with the virtual camera (mac-app/, MIT), the iOS app (ios-app/, MIT) and the macOS OBS plugin (obs-plugin/, GPL-2.0-or-later). A tag vX.Y.Z releases them together.
0.4.0 — 2026-09-10
Added
- Mac app: the camera extension can be restarted from the menu. After an install or an update of the extension the app waits up to 10 seconds for the camera device. If macOS started no device — the known race on an in-place extension replacement, where the new job is rejected while the old one is still being torn down — the menu and the setup guide say so instead of showing a camera that does not exist, and offer “Restart camera extension”. The device is re-checked every time the menu opens. (#32)
- Mac app: update check. Once a day at launch the app asks GitHub whether a newer release exists; the menu then shows “Update available: x.y.z” with a link. Settings gain “Check for updates now” and a switch “Check for updates automatically”, the check is off in headless runs, and only
https://github.comrelease URLs are opened. The privacy policy names the request. (#27)
Changed
- Mac app: the menu is structured — status block, Setup guide, the submenus “Camera extension” and “Settings”, the version, Quit — instead of one flat list.
- The camera extension keeps its open authorization, on purpose. Measured with a Developer ID build that the client’s signing identity reads “unknown”, so a whitelist would lock every app out of the camera. The extension logs the reading app once per process instead. (#28)
- Website, README, install guide,
llms.txtand the App Store copy got a second messaging round: your iPhone, instead of a webcam — two apps, one cable. (#31, #30)
Fixed
- A receiver name longer than 63 bytes is now cut at a UTF-8 character boundary instead of in the middle of a character, so the phone never shows a mangled receiver name. (#25)
- Mac app: cancelling the macOS confirmation dialog for the camera extension is no longer reported as an error. (#25)
0.3.0 — 2026-09-10
Added
- Mac app: setup guide, app icon, DMG, login item. First launch (and any launch while the camera extension is not approved) opens a setup guide with four steps and live checkmarks: app in /Applications, extension approved (a button opens the System Settings pane), iPhone connected, camera picked. Its notes name the two limits (video only, one receiver at a time) and the fix for a camera missing in Zoom or Teams: quit the app with Cmd-Q and reopen it, and after an extension install or update restart the Mac. The app has an icon, the
.dmgopens with a drag-to-Applications layout, and the menu gains About with the version, Launch at Login and Remove camera extension. (#20) - Mac app: honest counters. The menu says “Camera ready, no app is reading it yet” instead of a rising drop count while nothing consumes the camera; scaler pool drops are counted; the extension logs state changes at notice level. (#16)
- Zoom and Microsoft Teams verified with a real iPhone 15 Pro Max on 2026-09-10: both list the camera “TetherCam” after a fresh start of the app. (#13)
- iOS: the app knows who is receiving. Protocol 1.2 adds
CLIENT_INFO(Mac → App): the Mac app and the OBS plugin name themselves, and the phone’s status line says “Connected to TetherCam for Mac” or “Connected to OBS” instead of always claiming OBS. The waiting line is now “Waiting for the Mac”, the first-run hint names both paths, and the settings footer links to both downloads. A second receiver turned away with BUSY now says so on the phone for five seconds, and a “Receiver” row in the diagnostics shows the receiver’s name and version. (#19) - CI for the Mac app:
swift testfor the Core package plus an unsigned Release build on every push. (#21)
Changed
- Positioning: the Mac app is the default path, OBS the pro path. Website, README, install guide,
llms.txtand the App Store listing present TetherCam as a wired Mac webcam for Zoom, Teams, Meet and FaceTime, with the OBS plugin for streaming, recording and audio. (#22, #23) - iOS: the microphone footnote follows the receiver. The Mac app carries no audio, so it points at the Mac’s own microphone or the OBS plugin instead of promising sound that cannot arrive.
Fixed
- iOS: “Auto rotation” and the manual angle survive a relaunch; both were in-memory only.
- iOS: the German microphone purpose string was missing, so the German system prompt asked in English.
- Mac app: the setup guide no longer jumps to the front on every extension state poll, and “Done” keeps it away until the next launch. (#25)
0.2.1 — 2026-09-09
Added
- macOS virtual camera (
mac-app/, MIT). A menu bar app embeds a CoreMediaIO camera extension and publishes the iPhone as the system camera “TetherCam” (1920x1080 NV12, 30 fps), so Zoom, Microsoft Teams, Google Meet, FaceTime, QuickTime Player, Photo Booth, Safari, Chrome and ffmpeg see it like any webcam, with no OBS running. The host receives over usbmux like the plugin, decodes with VideoToolbox and letterboxes every geometry into the one format. Ships as the Developer ID signed and notarizedTetherCam-mac.dmg, orbrew tap kanevry/tethercam && brew install --cask tethercam. Video only (a camera extension carries no audio), macOS 14 or newer, and the phone serves one receiver at a time, so the Mac app and the OBS plugin do not run together. Verified on 2026-09-09 with a real iPhone 15 Pro Max in QuickTime Player, Photo Booth, FaceTime, Google Meet in Chrome, Safari, Chrome and ffmpeg, portrait and landscape, including reconnect. (#12, #13, #14) tools/vcam-test.sh: an end-to-end check of the virtual camera without a phone (simulator, headless host app, ffmpeg capture, assertions on resolution, frame rate and motion; optional browsergetUserMedia). Green on 2026-09-09: 1920x1080, 30.3 fps, Chrome lists the camera.
Fixed
- Plugin: black source with the App Store app 0.1.0. Plugin 0.2.0 sent the audio wish in START to every phone; the shipped 1.0 app drops it as a decode error and never starts the camera, so OBS showed a black source with no error. The audio flag is now only sent when HELLO announces protocol 1.1 or later; against a 1.0 app the plugin logs “audio needs 1.1, starting video only” and streams video.
usbcam-recvgates the same way. - iOS: a message the parser frames but cannot decode is now logged (
[usbcam] dropped undecodable message) instead of vanishing silently. - iOS: switching the camera decides on the session queue, so a lens change during a take no longer races the capture session’s format selection. (#11)
0.2.0 — 2026-09-09
Added
- Audio from the phone. The app captures the microphone, encodes AAC-LC 48 kHz mono (96 kbps) and sends it on the same cable. The plugin decodes with AudioToolbox and hands the samples to OBS (
obs_source_output_audio), so the source shows up in the audio mixer like any other. Protocol 1.1 addsAUDIO_CONFIG(0x13),AUDIO(0x14), an audio flag in START,MIC_DENIED(error 6) and STATS bits for audio active and muted. 1.0 receivers keep working and simply get no audio. - Mute switch in the app’s settings sheet (frame gate, the pts chain stays monotone), a
mic.slashbadge in the status capsule while muted, and a microphone-denied state. - Plugin property “Audio from the phone” (default on). The status line reports the audio rate, mute and a denied microphone.
usbcam-simsends a 440 Hz AAC tone,usbcam-recvdecodes and counts it (audio_frames,audio_video_pts_skew_ms,--dump-audioas ADTS) andtools/integration.shasserts the audio path.- Double-tap the preview to switch the camera. The next lens in list order (wide, ultra wide, telephoto, front), a short capsule names it, a light haptic confirms it, and the choice persists like a pick in Settings. Works during a take: the server swaps the lens and OBS gets a fresh CONFIG. (#9, user request after the App Store launch)
- Homebrew tap:
brew tap kanevry/tethercam && brew install --cask tethercam-obscopies the plugin bundle into the user’s own OBS plugin folder, no admin rights.
Changed
- The plugin keeps the link on non-fatal peer errors (only BUSY and VERSION_UNSUPPORTED disconnect). Before, a denied microphone caused an endless reconnect loop without picture.
- iOS build number 3 for the next TestFlight upload (build 2 is the one on the App Store).
- The iOS app is on the App Store since 2026-09-09 (0.1.0 approved on the first submission). README and website point at the store, TestFlight stays the pre-release channel.
- Repository ships
.env.examplefor the App Store Connect API variables.
0.1.0 — 2026-09-05
Added
- Tools menu entry “TetherCam: Add iPhone camera to current scene” (obs-frontend-api, no Qt): creates the source in the current scene, names it
TetherCam iPhone, fits it to the canvas (OBS_BOUNDS_SCALE_INNER) and does nothing if the scene already has one. - First-run hint: if no scene in the collection contains a TetherCam source, the plugin logs the Tools-menu path once per scene collection at
FINISHED_LOADING. - Status line in the source properties: read-only first row saying whether a phone is attached, whether the app is in the foreground, and the live format plus measured frame rate while streaming. Plus a plain-text link to the setup guide.
- German plugin locale (
data/locale/de-DE.ini). - German and English app localisation (
ios-app/Sources/Resources/{de,en}.lproj), including the Info.plist purpose strings. - Homebrew cask draft (
packaging/homebrew/), unpublished. - Website https://tethercam.app as the user-facing entry point: quick start, the three-step setup and the download link.
- Public GitHub repository
Kanevry/tethercam: the mirror is now the release host, withSECURITY.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md, issue templates and a pull-request template. - IUCM wire protocol (
protocol/PROTOCOL.md) as the contract between both sides: framing, message types (CONFIG, VIDEO, PING/PONG), error codes. - Shared C core (
shared/, MIT): incremental frame parser and usbmux client, free of Apple frameworks so it builds and unit-tests on Linux. - iOS app (
ios-app/, SwiftUI): AVFoundation capture, hardware HEVC encoding via VideoToolbox, TCP listener on port 7878 reachable from the Mac through the usbmux tunnel. No Wi-Fi involved. - OBS source plugin “TetherCam (iPhone via USB)” (
obs-plugin/, C/ObjC++): connects over usbmuxd, decodes HEVC with VideoToolbox, delivers NV12 frames as an async source. Universal binary (arm64 + x86_64), Hardened Runtime, macOS 12.0+. - Auto-rotation: the app levels to the horizon via
AVCaptureDevice.RotationCoordinatorwith gravity-based hysteresis and a flat-device fallback; geometry changes rebuild the encoder session and emit a fresh CONFIG. - Developer tools (
tools/, Swift package):usbcam-sim(test-pattern sender),usbcam-recv(CLI receiver over TCP or the usbmux tunnel), andintegration.sh, an end-to-end acceptance run that needs no iPhone. - Release engineering: installer
.pkg, signed and notarized when the release is built with the Apple signing secrets, otherwise unsigned; one-line installer script, TestFlight upload workflow, GitHub Actions CI. - Product name TetherCam and an app icon.
- App Store submission of 0.1.0 (2) on 2026-09-05: listing in en-US and de-DE pushed with
scripts/asc-listing.py, five marketing screenshots designed intethercam.pen(AI-generated studio scene, no people), TestFlight external group “Public Beta” with the public link https://testflight.apple.com/join/wmT74Ry8, Beta App Review and App Review both submitted. - Local release tooling:
scripts/appstore-upload.sh(archive and upload with the App Store Connect API key),scripts/asc-api.sh(JWT helper),.claude/skills/distribute. - Website: demo video embedded with poster, gallery carousel of the App Store frames, TestFlight button, FAQ answers for the USB and Continuity Camera queries, VideoObject schema,
llms.txtdiscoverable.
Changed
- Camera names sent to OBS are English (
Back Wide,Back Ultra Wide,Back Telephoto,Front) instead of German. - iOS app reduced to one screen: full-screen preview with a single status line and a traffic-light dot. Camera choice, auto rotation, horizon levelling, manual angle and the diagnostics moved behind one gear icon.
- Camera permission is requested on first launch without an intermediate onboarding page; a denial shows a card with a button into Settings.
- ENABLE_FRONTEND_API defaults to ON in
obs-plugin/CMakeLists.txtand the CMake presets. - scripts/install.sh now points at the right repository (
OWNER=Kanevry). - TestFlight workflow no longer fails without secrets: a
check-secretsjob resolvesASC_KEY_P8presence and the upload job is skipped rather than failed. - The App Preview video was withdrawn from the listing (it showed the owner). 0.1.0 ships without an App Preview.
Verified
- 1080p30 over usbmuxd against a physical iPhone.
tools/integration.shend to end against the simulator: frame rate, keyframe cadence, first-frame latency, ping round-trip, and an ffmpeg decode of the dump.
Known limitations
- macOS only. The plugin depends on VideoToolbox and usbmuxd; the CMake configure step fails on other platforms by design.
- One iPhone at a time.
- The iOS app is distributed via the App Store, plus a TestFlight beta for pre-release builds. Apple offers no free public distribution channel outside those two.