# How Vorssaint-utils Handles Per-App Volume Mixing on macOS

> Discover how Vorssaint-utils expertly manages per-app volume mixing on macOS. Learn about its mixer subsystem, System Audio Recording permission, and efficient audio stream control for personalized sound.

- Repository: [vorssaint/vorssaint-utils](https://github.com/vorssaint/vorssaint-utils)
- Tags: internals
- Published: 2026-09-12

---

**Vorssaint-utils implements per-app volume mixing through a dedicated mixer subsystem that reads and controls individual app audio streams using macOS's System Audio Recording permission, applying volume transformations only when needed and routing output to user-selected devices.**

Per-app volume mixing allows users to set different volume levels for individual applications rather than relying on a single system volume. In the `vorssaint/vorssaint-utils` repository, this feature is implemented through a sophisticated mixer subsystem that integrates with macOS audio APIs while keeping all processing local. The solution balances performance with functionality by remaining idle for apps using default volume levels and activating only when custom levels are detected.

## Mixer Subsystem Architecture

The core logic resides in **`MixerRoutingSupport`**, a helper class utilized throughout the UI and test suites. This component manages the entire lifecycle of per-app audio handling, from parsing user input to persisting settings and controlling audio engine activation.

### Key Responsibilities

The helper handles several critical functions:

- **Volume Parsing**: Converts user-entered percentages into normalized floats via `volumeFraction(fromPercentageText:)` (tested in [`Tests/MetricsTests.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Tests/MetricsTests.swift) at line 7423)
- **Persistence**: Stores per-app volumes safely using `Defaults.sanitizedAppVolume(_:)` with clamping logic (line 7419)
- **Engine Management**: Determines when an audio engine is required through `requiresEngine(volume:)` (line 7613)
- **Device Routing**: Updates mappings when users switch output devices via `preferencesAfterUniversalOutputSwitch` (line 7512)
- **UI State**: Controls row interactivity with `rowMayBeTapped(savedVolume:)` (line 7663) and restores volumes after device changes using `shouldRestoreOutputVolume(appliedVolume:currentVolume:)`

## Volume Parsing and Validation

Before any audio processing occurs, user input must be normalized. The `volumeFraction(fromPercentageText:)` method handles string conversion:

```swift
// Convert user input like "40%" or "-10%" to normalized Float
let fraction = MixerRoutingSupport.volumeFraction(fromPercentageText: "75%") // → 0.75

```

Once parsed, volumes are sanitized through `Defaults.sanitizedAppVolume(_:)`. This method clamps out-of-range values—negative inputs become 0, values greater than 2 are capped at 2, then normalized to 1 after boost processing.

## Engine Activation and Performance Optimization

A key optimization in Vorssaint-utils is **conditional engine activation**. The `requiresEngine(volume:)` method returns `true` only for volumes deviating from the default 1.0:

```swift
// Check if audio engine is needed for this volume
if MixerRoutingSupport.requiresEngine(volume: safeVolume) {
    MixerEngine.shared.start()
}

```

This design ensures the mixer stays idle for apps using system defaults, conserving CPU resources. The engine spins up exclusively when an app's volume differs from unity level, applying gain transformations and routing streams to the selected output device.

## Device Routing and Persistence

When users change output hardware or toggle "Universal Output", `preferencesAfterUniversalOutputSwitch` recalculates per-app volume mappings and device selections. The system maintains these settings through `shouldRestoreOutputVolume(appliedVolume:currentVolume:)`, ensuring custom volumes reapply automatically after audio device switches.

All preferences are stored locally via the `Defaults` API, with bundle identifiers or display names serving as unique keys for each running application.

## UI Integration in MixerSection.swift

The user interface layer lives in **[`Sources/Vorssaint/UI/MenuPanel/MixerSection.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/UI/MenuPanel/MixerSection.swift)**. This component binds mixer state to the interface, exposing per-app volume sliders and device selectors. It uses `MixerRoutingSupport.systemDefaultSelectionID` as the "auto" option and updates dynamically when users adjust sliders.

Row interactivity is controlled by `rowMayBeTapped(savedVolume:)`, which determines whether an app's row should be interactive based on existing custom volume settings.

## Complete Workflow Example

The following Swift code demonstrates the full per-app volume mixing workflow:

```swift
// 1. Parse a user-entered percentage string
let fraction = MixerRoutingSupport.volumeFraction(fromPercentageText: "75%") // → 0.75

// 2. Clamp and store a custom per-app volume
let safeVolume = Defaults.sanitizedAppVolume(fraction) // → 0.75 (or 1.0 if out-of-range)
Defaults.setAppVolume(appID: "com.example.Player", volume: safeVolume)

// 3. Conditionally start the audio engine
if MixerRoutingSupport.requiresEngine(volume: safeVolume) {
    MixerEngine.shared.start()
}

// 4. Handle output device changes
let newPrefs = MixerRoutingSupport.preferencesAfterUniversalOutputSwitch(
    oldPrefs: oldPrefs,
    selectedDeviceUID: "AirPods Pro"
)

```

## Required Permissions and Privacy

Per-app volume mixing requires **System Audio Recording** permission on macOS, documented in the repository's [`PERMISSIONS.md`](https://github.com/vorssaint/vorssaint-utils/blob/main/PERMISSIONS.md) and [`TROUBLESHOOTING.md`](https://github.com/vorssaint/vorssaint-utils/blob/main/TROUBLESHOOTING.md) files. According to [`PRIVACY.md`](https://github.com/vorssaint/vorssaint-utils/blob/main/PRIVACY.md), all audio processing occurs locally; no audio data is transmitted off-machine.

## Summary

- **MixerRoutingSupport** provides the core helper methods for parsing, clamping, and managing per-app volumes in `vorssaint/vorssaint-utils`
- **Conditional activation** via `requiresEngine(volume:)` ensures the mixer only runs when necessary, optimizing performance
- **Input validation** uses `volumeFraction(fromPercentageText:)` and `sanitizedAppVolume(_:)` to safely handle user percentages
- **Device routing** automatically updates through `preferencesAfterUniversalOutputSwitch` when hardware changes occur
- **UI binding** occurs in [`MixerSection.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/MixerSection.swift), displaying interactive sliders for each detected application
- **Privacy-first architecture** keeps all audio processing local, requiring only macOS System Audio Recording permission

## Frequently Asked Questions

### What permission is required for per-app volume mixing in Vorssaint-utils?

Vorssaint-utils requires the **System Audio Recording** permission on macOS to read and control individual app audio streams. Without this permission, the mixer cannot access per-app audio data, though the application will still function for other features. This permission is requested through the standard macOS security dialog and can be managed in System Settings.

### How does Vorssaint-utils handle invalid volume inputs?

Invalid entries are processed through `Defaults.sanitizedAppVolume(_:)`, which clamps negative values to 0 and values greater than 2 to 2 (subsequently normalized to 1 after boost calculation). The `volumeFraction(fromPercentageText:)` method handles string parsing, converting formats like "40%" or "-10%" into normalized Float values between 0 and 1 before sanitization occurs.

### Does the audio mixer run constantly in the background?

No, the mixer uses **conditional activation** to conserve resources. The `requiresEngine(volume:)` method returns `false` for apps using the default volume of 1.0, keeping the engine idle. The audio engine only activates when an app's stored volume differs from unity level, applying gain transformations and routing only when necessary.

### Where are per-app volume settings stored?

Per-app volumes are persisted through the `Defaults` API using bundle identifiers or display names as keys. Settings are stored locally on the device and automatically restored when switching output devices via `shouldRestoreOutputVolume(appliedVolume:currentVolume:)`. `preferencesAfterUniversalOutputSwitch` manages these transitions when users toggle "Universal Output" or change audio hardware.