Submix notes

What Submix Installs on Your Mac, What It Asks Permission For, and How It Gives Your Audio Back

Submix installs no audio driver, kernel extension, or system extension. It asks for one macOS permission, and this is what happens if giving your audio back does not go as planned.

On this page

Submix does not install an audio driver, a kernel extension, or a system extension. It never asks for an administrator password, because none of its audio engine runs outside the app process itself. The only thing it asks for is the macOS Audio Recording permission, the same plumbing behind Core Audio's process tap APIs. Submix needs Apple silicon and macOS 14.2 or later, because that is the first system carrying the tap API the app is built on.

I build Submix. Nothing here is a benchmark: this post contains no measurements, and every fact about the app traces to its own source or its build script, checked on 23 July 2026. Product behaviour describes Submix's current shipped build. This post names no other app.

What never touches disk

Open the built app bundle and there is very little to find. It is Submix.app, a Sparkle framework for updates, and nothing else. No .kext, no system extension bundle, no separate HAL plug in sitting in /Library/Audio/Plug-Ins. Every audio operation Submix performs, creating a tap, building an aggregate device, reading a volume property, is a HAL call made directly from the running app process, and nothing privileged does the work on its behalf.

That matters because the usual alternative in this category has a real installer step. A virtual audio device has to register itself with the system, typically through a package that needs your password, and it stays registered after you quit the app that put it there. Submix has nothing to register and nothing left behind. Quit it and the devices it built during that session are gone, because they were never anything more than a description held in memory while the app ran.

Why the driver had to go

I did not want to ship something that needs an admin password to remove a slider. That was the decision, not a workaround forced on me afterward. A kernel extension or a HAL plug in survives a crash, a force quit, an update gone wrong, sitting on the system as infrastructure someone has to go find and delete by hand later. A process tap does not linger that way. On a normal quit, Submix tears every tap down itself before the process exits; if the process disappears abruptly instead, Core Audio releases whatever taps and aggregates it still held. Either way, there is nothing installed to clean up afterward.

There is a real cost to that choice, and it is worth naming rather than hiding it. Core Audio has no public API for a persistent per app volume control that survives a reboot without the app running. Every tap and aggregate device Submix builds exists only while the app is open. That is the trade for not touching disk.

The one permission it does ask for

Submix cannot see inside any app's audio without the macOS Audio Recording grant, the permission macOS tracks internally as kTCCServiceAudioCapture. There is no public API to check that permission ahead of time, so the app reaches into /System/Library/PrivateFrameworks/TCC.framework/TCC with dlopen, resolves TCCAccessPreflight and TCCAccessRequest by symbol name, and reads the result back as granted, denied, or undetermined. If those symbols cannot be resolved on some future system, Submix falls back to a short, unmuted probe tap on whatever app happens to be playing audio. It runs for 600 milliseconds and calls the permission granted only if that probe actually saw sound moving through it.

The prompt macOS shows you is not generic boilerplate borrowed from a template. The exact string, set by NSAudioCaptureUsageDescription and written into the app's Info.plist at build time, reads: "Submix reads app audio so you can set each app's volume independently. Nothing is recorded, saved, or sent." I wrote that sentence to say exactly what the tap does and exactly what it does not do. The permission dialog is the only moment most people will read anything about this before they click.

The purple dot in the menu bar

Once that permission is granted and a tap is live, macOS turns on its own recording indicator for as long as capture continues, independent of anything Submix draws in its own interface. That indicator belongs to the operating system, not to the app. Preen's camera light works on the identical principle: the indicator tracks whether a capture session is running, not whether a particular window is visible. It stays lit the whole time a channel is active. It does not go away when you close the mixer panel, because the tap behind it is still running even with the window shut.

I would rather explain that indicator than avoid the permission that triggers it. A driver based approach sidesteps the audio capture prompt entirely, at the cost of the admin password and the leftover system component, a tradeoff covered across four different approaches to per app volume on a Mac.

Moving a slider without moving a driver

The mixing itself is smaller than the plumbing around it. Each controlled app gets a private process tap, wrapped in a private aggregate device whose real output is your chosen destination, with an IOProc doing the actual work. That IOProc reads a lock free gain value and, for every sample in the buffer, sets the output sample to the input sample multiplied by that gain. The same pass through the buffer also tracks the loudest sample it has seen, which feeds the live meter. Metering costs nothing extra.

Mute does not tear anything down. It sets the effective gain to zero and lets the same multiply run, which is why a muted app comes back instantly when you unmute it rather than needing its tap rebuilt. Boost works the same way in the other direction, capped at exactly 2.0, a 200 percent ceiling, with no limiter or soft knee sitting on top of that multiply. Push a channel that is already close to full scale past that ceiling and it will clip, because the only thing standing between your ears and clipping is the cap on the gain number, not anything watching the resulting samples.

The exact order everything comes down in

Every teardown, whether triggered by you closing a channel, quitting the app, or something going wrong, runs through the same four calls, always in this sequence: stop the device, destroy the IOProc, destroy the aggregate device, then destroy the process tap. If any one of those four returns a failure, Submix stops right there rather than pressing on and hoping the rest works anyway, and it keeps the handles from that failed step rather than discarding them.

Keeping the handles is what makes a retry possible: throw them away and the app loses its only reference to the thing it is trying to tear down.

A safety class that outranks your license

Restoring your audio to normal is not treated as a feature you can be sold or upsold on. In the code it is declared with an access class called safety, and the resolver that decides whether any feature is allowed checks that class before it checks configuration freshness, before it checks your license, before it checks the minimum required version. The view model that drives the interface goes one step further. It hard codes the restore audio feature to enabled, bypassing the general feature check entirely for that one path.

That ordering shows up whenever product access changes. If your license lapses or a request to the licensing service comes back as unauthorized, Submix un-routes every channel back to system output and brings any boosted channel down to 100 percent before it tears the taps down and locks the paid features. That order beats locking you out first and leaving your audio wherever it happened to be. A separate monitor task checks the Audio Recording permission every 5 seconds on its own schedule, independent of the visible mixer panel, so revoking the permission while the panel is closed still triggers the same full restore.

When a teardown step fails

I want to be specific about where the guarantee actually ends, because a vague promise here would be worse than an honest limit. If one of those four Core Audio calls returns a nonzero status partway through, the muted tap can still own that app's path to the hardware, and Submix has no second mechanism for that case. It retries the entire teardown sequence every 2 seconds, indefinitely, until every channel reports itself restored. It also surfaces which step is failing, along with the status code Core Audio returned for it.

Retrying is the whole plan, because there is no lower level fallback once the documented sequence has already failed. An abrupt termination, the kind where the process is gone before any of its own code runs, sits outside that plan entirely. Core Audio releases a dead process's taps and aggregates on its own in that case, a property of the operating system rather than something Submix arranges. I built the retry loop for every failure I could catch. I cannot build one for a process that no longer exists to run it.

Three things Submix will not pretend to do

Submix does not have a working equalizer. As of 23 July 2026 the catalog still lists submix.per-app-eq as a real, sellable feature, and the code contains a full ten band EQ model with a tested passthrough shortcut. None of that reaches your speakers. The only per sample operation anywhere in the audio path is the gain multiply described above, and there is no EQ control anywhere in the app's interface. Selling access to a data model that never touches the signal would be dishonest, so until there is actual filtering sitting inside that callback, this post is not going to describe one.

The second limit is the restore guarantee itself. Submix retries every failed teardown on a fixed schedule and tells you exactly which step is stuck, but a retry loop is not a guarantee, and I would rather say that plainly than let the word restore imply more certainty than the code actually delivers.

One more limit: per app volumes live in memory for as long as the app is open and nowhere else. Quit Submix and every level you set resets, because the settings dictionary is explicitly built to hold nothing after the process exits, and the only preference the app writes to disk across launches is whether you have completed onboarding. Per app routing destinations reset the same way, for the identical reason.

Questions people ask

Does Submix need a kernel extension or a driver to work?

No. It runs entirely inside the app process using Core Audio process taps and private aggregate devices, and neither requires a driver, a kernel extension, or a system extension.

Why does Submix need an admin password to install?

It does not. Installing the app itself is a drag to the Applications folder. The macOS Audio Recording permission it asks for afterward is a per app grant, not an administrator action. It is handled the same way a microphone or camera permission would be.

What does the purple recording indicator actually mean?

It means at least one process tap is currently live somewhere on your Mac. macOS controls that indicator directly, and it stays on for as long as the tap exists, whether or not the mixer window is open.

Will Submix remember the volumes I set the next time I open it?

Not yet. Every level resets when you quit, because per app settings are held only in memory for the current session and nothing is written to disk for them.

Does Submix have an equalizer?

Not a working one. The catalog lists a per app EQ feature and the underlying data model exists, but the audio path itself performs no filtering, so there is nothing to switch on.

What happens to my audio if Submix crashes?

On a normal quit, Submix runs that same teardown sequence before it actually exits, retrying every 2 seconds if any step fails until every channel reports itself restored. If the process is killed outright before any of its own code runs, cleanup falls to Core Audio, which releases a dead process's taps and aggregates on its own.

See the permission prompt and the indicator for yourself before you decide.

Submix asks for that one permission and nothing else; the basic mixer covers volume, mute and live meters before you need any of this, with more on how it works on the Submix blog.

Back to Submix