[PR #1929] Add opt-in software volume fallback for digital monitor audio #1339

Open
opened 2026-10-23 22:02:35 -06:00 by gitea-mirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/MonitorControl/MonitorControl/pull/1929
Author: @jodansi90
Created: 10/18/2026
Status: 🔄 Open

Base: main ← Head: software-volume-fallback


📝 Commits (2)

  • d0eaf59 Add opt-in software volume fallback for digital monitor audio
  • a4efde3 Preserve playback key routing with session volume tap

📊 Changes

24 files changed (+1509 additions, -3 deletions)

View changed files

📝 MonitorControl.xcodeproj/project.pbxproj (+40 -0)
📝 MonitorControl/Info.plist (+2 -0)
📝 MonitorControl/Model/OtherDisplay.swift (+12 -1)
➕ MonitorControl/SoftwareAudio/AudioBufferListUtilities.swift (+116 -0)
➕ MonitorControl/SoftwareAudio/AudioDevices.swift (+109 -0)
➕ MonitorControl/SoftwareAudio/AudioOutputDevice.swift (+18 -0)
➕ MonitorControl/SoftwareAudio/AudioProcessor.swift (+37 -0)
➕ MonitorControl/SoftwareAudio/CoreAudioTapError.swift (+27 -0)
➕ MonitorControl/SoftwareAudio/Licenses/CoreAudioTapKit-MIT.txt (+21 -0)
➕ MonitorControl/SoftwareAudio/Licenses/CoreAudioTapKit-commit.txt (+1 -0)
➕ MonitorControl/SoftwareAudio/MonitorSoftwareAudio.swift (+181 -0)
➕ MonitorControl/SoftwareAudio/SoftwareVolume.swift (+268 -0)
➕ MonitorControl/SoftwareAudio/SystemAudioDeviceLookup.swift (+113 -0)
➕ MonitorControl/SoftwareAudio/SystemAudioTapEngine.swift (+119 -0)
➕ MonitorControl/SoftwareAudio/SystemTapCapture.swift (+337 -0)
➕ MonitorControl/SoftwareAudio/TapKitIdentity.swift (+12 -0)
📝 MonitorControl/Support/AppDelegate.swift (+5 -0)
📝 MonitorControl/Support/MediaKeyTapManager.swift (+6 -0)
📝 MonitorControl/Support/MenuHandler.swift (+3 -2)
📝 MonitorControl/Support/SliderHandler.swift (+4 -0)

...and 4 more files

📄 Description

Digital monitor outputs such as the Samsung Smart M80F can expose no writable CoreAudio volume and ignore DDC volume commands: the OSD moves, but the sound stays unchanged. This adds an opt-in software-volume fallback for the selected monitor output on macOS 15+, using a device-scoped CoreAudio process tap and a private aggregate device. It attenuates the audio signal, not the monitor’s internal volume.

The existing slider and multimedia volume/mute keys share one state and the existing OSD. Duplicate press notifications observed 2–4 ms apart are coalesced within 20 ms, so mute does not immediately toggle back and volume does not advance twice. Volume repeat and fine adjustment are preserved. The backend pauses on another output, releases resources on quit/sleep, and uses an idle-aware progress watchdog with bounded recovery.

The change is disabled by default, explains audio capture before opt-in, and is availability-gated without raising the existing deployment target. Brightness, slider layout, signing, application version and updater behavior are retained. No Logitech-specific reader, key remapping, driver or companion app is added. Vendored CoreAudioTapKit is MIT-licensed; its attribution and pinned revision are included in source and app resources. See implementation and testing notes.

Validation

  • Release build on Apple Silicon; an Intel Release build also passed during preparation. Xcode 27 requires a deployment-target override of 12.0 for these builds; the project’s older deployment settings are unchanged.
  • bash Tests/run-software-audio-tests.sh: gain bounds/NaN, stereo ramp to silence, duplicate media events, mute repeat, output matching, watchdog idle/stall/recovery.
  • The local prototype with the same audio backend worked on Apple Silicon/macOS 27.2 beta + Samsung Smart M80F DisplayPort audio + MX Keys Mini/Bolt: brightness, volume, mute/unmute and a fresh sign-out/sign-in were physically confirmed. The cleaned upstream integration is compiled and unit-tested separately; its availability facade and opt-in menu still need additional runtime review. Sleep/wake, hotplug, output switching and wider format/device coverage are not claimed as tested.

Related discussion: #1077, particularly https://github.com/MonitorControl/MonitorControl/discussions/1077#discussioncomment-19010109 . This PR offers a concrete implementation for maintainer review; architecture and broader support can be refined together.

Playback-key compatibility update

The dedicated volume interceptor now uses cgSessionEventTap instead of cgAnnotatedSessionEventTap. In the local Samsung prototype, this restored Spotify previous/next/play-pause keys while retaining software volume and mute; the user confirmed playback keys and volume worked together. Playback events are passed through unchanged, without Spotify-specific handling or key remapping. The cleaned PR integration was rebuilt for Apple Silicon and the software-audio test suite passed; the physical confirmation applies to the local prototype. Existing OSD and brightness behavior in this PR remain unchanged.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/MonitorControl/MonitorControl/pull/1929 **Author:** [@jodansi90](https://github.com/jodansi90) **Created:** 10/18/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `software-volume-fallback` --- ### 📝 Commits (2) - [`d0eaf59`](https://github.com/MonitorControl/MonitorControl/commit/d0eaf59c3a17e68ee1621050ce74be0319a95692) Add opt-in software volume fallback for digital monitor audio - [`a4efde3`](https://github.com/MonitorControl/MonitorControl/commit/a4efde3b7f2cf7238216c145409b963a62d0ef0b) Preserve playback key routing with session volume tap ### 📊 Changes **24 files changed** (+1509 additions, -3 deletions) <details> <summary>View changed files</summary> 📝 `MonitorControl.xcodeproj/project.pbxproj` (+40 -0) 📝 `MonitorControl/Info.plist` (+2 -0) 📝 `MonitorControl/Model/OtherDisplay.swift` (+12 -1) ➕ `MonitorControl/SoftwareAudio/AudioBufferListUtilities.swift` (+116 -0) ➕ `MonitorControl/SoftwareAudio/AudioDevices.swift` (+109 -0) ➕ `MonitorControl/SoftwareAudio/AudioOutputDevice.swift` (+18 -0) ➕ `MonitorControl/SoftwareAudio/AudioProcessor.swift` (+37 -0) ➕ `MonitorControl/SoftwareAudio/CoreAudioTapError.swift` (+27 -0) ➕ `MonitorControl/SoftwareAudio/Licenses/CoreAudioTapKit-MIT.txt` (+21 -0) ➕ `MonitorControl/SoftwareAudio/Licenses/CoreAudioTapKit-commit.txt` (+1 -0) ➕ `MonitorControl/SoftwareAudio/MonitorSoftwareAudio.swift` (+181 -0) ➕ `MonitorControl/SoftwareAudio/SoftwareVolume.swift` (+268 -0) ➕ `MonitorControl/SoftwareAudio/SystemAudioDeviceLookup.swift` (+113 -0) ➕ `MonitorControl/SoftwareAudio/SystemAudioTapEngine.swift` (+119 -0) ➕ `MonitorControl/SoftwareAudio/SystemTapCapture.swift` (+337 -0) ➕ `MonitorControl/SoftwareAudio/TapKitIdentity.swift` (+12 -0) 📝 `MonitorControl/Support/AppDelegate.swift` (+5 -0) 📝 `MonitorControl/Support/MediaKeyTapManager.swift` (+6 -0) 📝 `MonitorControl/Support/MenuHandler.swift` (+3 -2) 📝 `MonitorControl/Support/SliderHandler.swift` (+4 -0) _...and 4 more files_ </details> ### 📄 Description Digital monitor outputs such as the Samsung Smart M80F can expose no writable CoreAudio volume and ignore DDC volume commands: the OSD moves, but the sound stays unchanged. This adds an **opt-in software-volume fallback** for the selected monitor output on macOS 15+, using a device-scoped CoreAudio process tap and a private aggregate device. It attenuates the audio signal, not the monitor’s internal volume. The existing slider and multimedia volume/mute keys share one state and the existing OSD. Duplicate press notifications observed 2–4 ms apart are coalesced within 20 ms, so mute does not immediately toggle back and volume does not advance twice. Volume repeat and fine adjustment are preserved. The backend pauses on another output, releases resources on quit/sleep, and uses an idle-aware progress watchdog with bounded recovery. The change is disabled by default, explains audio capture before opt-in, and is availability-gated without raising the existing deployment target. Brightness, slider layout, signing, application version and updater behavior are retained. No Logitech-specific reader, key remapping, driver or companion app is added. Vendored CoreAudioTapKit is MIT-licensed; its attribution and pinned revision are included in source and app resources. See [implementation and testing notes](https://github.com/jodansi90/MonitorControl/blob/software-volume-fallback/docs/software-volume.md). ### Validation - Release build on Apple Silicon; an Intel Release build also passed during preparation. Xcode 27 requires a deployment-target override of 12.0 for these builds; the project’s older deployment settings are unchanged. - `bash Tests/run-software-audio-tests.sh`: gain bounds/NaN, stereo ramp to silence, duplicate media events, mute repeat, output matching, watchdog idle/stall/recovery. - The local prototype with the same audio backend worked on Apple Silicon/macOS 27.2 beta + Samsung Smart M80F DisplayPort audio + MX Keys Mini/Bolt: brightness, volume, mute/unmute and a fresh sign-out/sign-in were physically confirmed. The cleaned upstream integration is compiled and unit-tested separately; its availability facade and opt-in menu still need additional runtime review. Sleep/wake, hotplug, output switching and wider format/device coverage are not claimed as tested. Related discussion: #1077, particularly https://github.com/MonitorControl/MonitorControl/discussions/1077#discussioncomment-19010109 . This PR offers a concrete implementation for maintainer review; architecture and broader support can be refined together. ### Playback-key compatibility update The dedicated volume interceptor now uses `cgSessionEventTap` instead of `cgAnnotatedSessionEventTap`. In the local Samsung prototype, this restored Spotify previous/next/play-pause keys while retaining software volume and mute; the user confirmed playback keys and volume worked together. Playback events are passed through unchanged, without Spotify-specific handling or key remapping. The cleaned PR integration was rebuilt for Apple Silicon and the software-audio test suite passed; the physical confirmation applies to the local prototype. Existing OSD and brightness behavior in this PR remain unchanged. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
github-starred/MonitorControl#1339
No description provided.