Audio on a Mac has had a routing culture for twenty years. There are virtual devices, aggregates, matrices, and a shared vocabulary for talking about them. Video has had virtual cameras and a lot of hope.
Understanding why tells you which video routing problems are solvable and which ones you should stop trying to solve.
The three video APIs, and what each one is for
AVFoundation is what applications use. It enumerates capture devices, gives you frames, handles formats. If an app has a camera picker, it is almost certainly asking AVFoundation what exists.
CoreMediaIO is the layer below, where devices are defined. A physical camera appears here because its driver registers it. A virtual camera appears here because a plugin registers it. This is the extension point — the only supported way to make a device that does not physically exist.
Screen capture — ScreenCaptureKit on current macOS — is a separate path entirely. It is not a device, and it is not routing. It reads window and display content, and it is gated by the Screen Recording permission that breaks in its own specific ways.
The consequence that shapes everything: there is no video equivalent of an aggregate device. CoreAudio lets macOS itself combine and route devices. CoreMediaIO has no such construct. Every piece of video routing on a Mac is either a plugin registering a device, or an application-level transport like Syphon or NDI.
DAL plugins and Core Media extensions
If you have installed virtual camera software over the last few years you have lived through a transition.
DAL plugins (Device Abstraction Layer) were the old way: a bundle dropped into /Library/CoreMediaIO/Plug-Ins/DAL/, loaded into the address space of every app that enumerated cameras. That last part is the problem — a crash in the plugin took the host app with it, and a plugin loaded into a hardened app was a security concern. Apple deprecated them.
Core Media extensions (CMIO extensions) are the replacement: a system extension running out of process, delivered inside an app bundle, activated with user consent. Safer, crashes are contained, and Apple’s stated direction.
Practically, on a rig, this means:
- Some apps see only extensions. Hardened and sandboxed applications — particularly ones distributed through the App Store — will not load a DAL plugin. If your virtual camera appears in OBS and not in a conferencing app, this is usually why.
- An extension needs activating, once, with a user click. On a managed Mac, that click may be blocked by policy.
- Version drift is real. An old DAL plugin from software you no longer use can sit in that folder for years and cause camera enumeration to be slow or to fail. It is worth looking in that directory when video devices behave oddly.
Why an app cannot see your device
The most common video routing complaint, and it has a short list of causes:
- The app is hardened and the device is a DAL plugin. Nothing you can configure fixes this; the device needs to be an extension.
- The extension is not activated. Check System Settings → General → Login Items & Extensions.
- Camera permission not granted to the consuming app. Virtual cameras count as cameras for privacy purposes.
- The app caches its device list at launch. Very common. Restart the consuming app after starting the publisher, not before.
- The device only exists while its owning app runs. Many virtual cameras are only present when their host application is open.
Work down that list and the answer is nearly always in it.
The one-consumer problem
Here is the limitation that surprises people most: a camera can generally only be opened by one application at a time.
macOS has improved on this — multiple apps can share a camera in more cases than they used to — but it remains true often enough that you cannot plan around it. Certainly you cannot rely on a capture card being simultaneously available to a streaming app, a recorder and a switcher.
This is precisely the problem audio solved with routing and video did not. The answer is not a device-level fix; it is to stop treating the device as the distribution point:
- One application opens the device — the one doing the primary work.
- That application republishes the frames as Syphon for other apps on the same Mac, or NDI for other machines.
- Everything else subscribes to the published source, not to the device.
Syphon and NDI have no one-consumer restriction. Any number of receivers can take the same source. Once you see the shape, most “the card is busy” problems become routing decisions rather than limitations.
What routing video on a Mac actually looks like
Putting it together, the available moves are:
| Goal | Mechanism |
|---|---|
| Physical camera into one app | AVFoundation device, directly |
| One camera into several apps | One app opens it, republishes as Syphon |
| App content into a conferencing app | Virtual camera (CMIO extension) — the only route |
| App content into a creative app | Syphon — better quality, no device involved |
| Any window as a source | Screen capture, published as Syphon |
| Anything to another machine | NDI |
| Anything to hardware | SDI via a DeckLink |
Note where virtual cameras appear: exactly once, for the case where the destination will accept nothing else. That is the honest scope of them. They are a compatibility shim for conferencing apps, not a routing system — and they cost you the camera pipeline’s 8-bit subsampled colour to use, which is why sending a window to a creative app should never go through one.
Where this is heading for us
SpectraRoute treats audio and video devices in one matrix, because that is how a rig is described on paper: this input goes to those destinations. The audio half of that has a well-trodden path through CoreAudio. The video half is genuinely harder, for the structural reason this article is about — there is no system-level video routing to drive, so the honest implementation is a mixture of device enumeration, screen capture where it is appropriate, and republishing over Syphon and NDI rather than pretending macOS has a video patchbay it does not have.
The related audio problem, and why stacking virtual devices gets fragile, is in routing audio between Mac apps.
Useful commands
# what video devices exist right now
system_profiler SPCameraDataType
# old DAL plugins still installed
ls -la /Library/CoreMediaIO/Plug-Ins/DAL/
# active system extensions, including CMIO
systemextensionsctl listThree commands that answer most “why can’t it see the camera” questions faster than any amount of clicking.
Originally published on the SpectraRig blog.
