AI FaceTime

When someone FaceTimes the Mac mini, it auto-answers and sends back an AI avatar instead of a real camera feed.

3 min

What it is

Two independent tricks bolted together. Outgoing video is a solved problem — a virtual camera presents AI-generated frames as if they were a webcam, and FaceTime sends whatever camera you select. Auto-answer is the real work: macOS has no native unattended answer, so a small helper has to detect the incoming call and accept it.

How it works

Answering the call and faking the video are two separate pipelines that meet inside FaceTime.

1 · ANSWER THE CALL Caller (any Apple device) IDS + callservicesd Auto-answer helper FaceTime auto-accepts invite event answer() 2 · FAKE THE VIDEO AI video pipeline Virtual camera (CMIO extension) FaceTime cam = virtual Caller sees AI avatar frames selected video out An orchestrator (launchd) starts both pipelines on boot and keeps the virtual camera warm.

Components

ComponentJobApproachBuild
Virtual camera Present AI frames as a webcamsystem-wide, visible to FaceTime OBS Virtual Camera, or a custom CMIO camera extension off-the-shelf
AI video source Generate the talking headthe actual "face" Looped clip → real-time lip-sync avatar (HeyGen/D-ID, or local wav2lip/SadTalker) assemble
Camera selection Point FaceTime at the fake cam FaceTime → Video menu (one-time) off-the-shelf
Auto-answer Accept incoming call unattendedthe hard part Accessibility click or TelephonyUtilities build
Orchestrator Wire it up, start on boot launchd agent + small daemon build

Auto-answer options

The call log DB (~/Library/Application Support/CallHistoryDB/) is written after the fact — useless for live answering. The live source of truth is a daemon. Two ways to act on it:

START HERE

Accessibility click recommended

An AXObserver watches for the incoming-call window and presses Accept (AX or cliclick).

  • No SIP-off, no entitlements — just Accessibility permission
  • Survives most OS updates
  • Brittle if the call UI layout changes
  • Feels hacky; depends on a visible window
THE CLEAN ROUTE

Private framework

Use TUCallCenter / TUCall from the private TelephonyUtilities.framework — observe call state, call answer().

  • Event-driven, the real source of truth
  • No fragile UI dependency
  • Answering needs private entitlements or SIP/AMFI off + dylib injection
  • Signatures drift — class-dump per OS version

Risks & gotchas

Open questions