FEAT(windows client): Add support for the Universal Mute button#7136
FEAT(windows client): Add support for the Universal Mute button#7136citelao wants to merge 2 commits intomumble-voip:masterfrom
Conversation
WalkthroughThis pull request introduces Windows-specific WinRT universal mute functionality and updates build documentation. A new Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can use Trivy to scan for security misconfigurations and secrets in Infrastructure as Code files.Add a .trivyignore file to your project to customize which findings Trivy reports. |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/mumble/MainWindow.cpp (1)
2748-2780:⚠️ Potential issue | 🟠 MajorUniversal mute only stays in sync for one mute code path.
Lines 2774-2779 mirror the state only when the change flows through
MainWindow::on_qaAudioMute_triggered().MainWindow::on_qaAudioDeaf_triggered()still setsGlobal::get().s.bMutedirectly at Lines 2811-2815, andsrc/mumble/AudioWizard.cppdoes the same at Lines 174-176, 319-337, and 433-435. After self-deafen or audio-wizard transitions, the Windows coordinator keeps the old mute state. Please move the coordinator update into a shared helper and call it from everybMutewrite.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/mumble/MainWindow.cpp` around lines 2748 - 2780, The universal mute coordinator update is only applied in MainWindow::on_qaAudioMute_triggered; extract the m_universalMuter setMuted()/setUnmuted() logic behind a new shared helper (e.g., updateUniversalMuteState(bool muted) as a static/global helper or a member on a suitable central class) and call it whenever Global::get().s.bMute is written. Update MainWindow::on_qaAudioMute_triggered to call the helper instead of directly touching m_universalMuter, and modify MainWindow::on_qaAudioDeaf_triggered and the bMute assignments in AudioWizard.cpp (the blocks around the lines noted) to invoke this helper after changing Global::get().s.bMute so the Windows coordinator (m_universalMuter under USE_WIN_UNIVERSAL_MUTE) stays in sync across all code paths.
🧹 Nitpick comments (1)
docs/dev/build-instructions/build_windows.md (1)
9-9: Consider using a more flexible Python version.The command hardcodes Python 3.13, which may not be available on all systems or may become outdated. Consider using
Python.Python.3to install the latest Python 3.x version, or provide guidance for users to choose an appropriate version.📝 Suggested alternative
-You'll also need Python (`winget install --id=Python.Python.3.13 -e`). +You'll also need Python (`winget install --id=Python.Python.3 -e` for the latest 3.x version).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/dev/build-instructions/build_windows.md` at line 9, Replace the hardcoded Python installer reference "winget install --id=Python.Python.3.13 -e" with a more flexible instruction: either recommend using the generic package id "Python.Python.3" to install the latest Python 3.x, or instruct users to select an appropriate installed Python 3.x version (e.g., via winget search or manual download). Update the line containing the exact command string in build_windows.md to present the alternative command and a brief note advising users to pick a suitable Python 3.x if 3.13 is unavailable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/dev/build-instructions/build_static.md`:
- Around line 69-71: The fenced code block containing the cmake invocation
("cmake -G Ninja \"-DVCPKG_TARGET_TRIPLET=...\" \"-DCMAKE_BUILD_TYPE=Release\"
..") is labeled with "bash" but uses Windows backslash paths; change the code
block language identifier from "bash" to a Windows-appropriate one such as
"powershell" (or "cmd") so the snippet for the cmake command displays correct
syntax highlighting.
In `@docs/dev/build-instructions/build_windows.md`:
- Line 21: The vcvars64.bat path in the cmd invocation uses an invalid Visual
Studio version "18"; update the path string referencing "vcvars64.bat" to point
to a valid VS install (e.g., use "17" or "2022") or replace the hardcoded path
with the documented vswhere-based lookup used earlier in the file so the command
dynamically locates the correct "VC\Auxiliary\Build\vcvars64.bat" before calling
it.
In `@src/mumble/CMakeLists.txt`:
- Around line 662-671: The MSVC-specific link and delay-load settings for WinRT
are being applied unconditionally; wrap the calls that add runtimeobject.lib and
the LINK_FLAGS delay-load (the target_link_libraries(mumble_client_object_lib
PUBLIC runtimeobject.lib) and set_property(... "/DELAYLOAD:runtimeobject.dll")
lines) in an if(MSVC) ... endif block so they only apply when using MSVC,
leaving the rest of the win-universal-mute handling (target_sources and
target_compile_definitions for mumble_client_object_lib /
USE_WIN_UNIVERSAL_MUTE) unchanged.
In `@src/mumble/UniversalMute.cpp`:
- Around line 76-91: The callback registered in handler currently calls
impl->coordinator->NotifyMuted()/NotifyUnmuted() immediately after queuing the
state-change validation, which can notify Windows before the queued
MainWindow::on_qaAudioMute_triggered() slot validates or rejects the change;
remove these immediate Notify* calls from the lambda and instead ensure
NotifyMuted()/NotifyUnmuted() is invoked only after the queued validation and
state update succeed (for example, from the success path inside
MainWindow::on_qaAudioMute_triggered() or after setMuted()/setUnmuted()
complete), so that weakImpl, handler, MainWindow::on_qaAudioMute_triggered, and
setMuted/setUnmuted are the loci of the state-change and notification
sequencing.
- Around line 38-56: The call to RoGetActivationFactory in
tryCreateCallCoordinator requires the Windows Runtime to be initialized on the
calling thread; initialize WinRT before that call (either ensure the main thread
calls RoInitializeEx/Windows::Foundation::Initialize at startup or call
RoInitializeEx(RO_INIT_MULTITHREADED) at the start of tryCreateCallCoordinator),
check the HRESULT and proceed only on success, and if you initialize inside
tryCreateCallCoordinator ensure you call RoUninitialize on error or when done;
update the function to perform this initialization check/cleanup before invoking
RoGetActivationFactory.
---
Outside diff comments:
In `@src/mumble/MainWindow.cpp`:
- Around line 2748-2780: The universal mute coordinator update is only applied
in MainWindow::on_qaAudioMute_triggered; extract the m_universalMuter
setMuted()/setUnmuted() logic behind a new shared helper (e.g.,
updateUniversalMuteState(bool muted) as a static/global helper or a member on a
suitable central class) and call it whenever Global::get().s.bMute is written.
Update MainWindow::on_qaAudioMute_triggered to call the helper instead of
directly touching m_universalMuter, and modify
MainWindow::on_qaAudioDeaf_triggered and the bMute assignments in
AudioWizard.cpp (the blocks around the lines noted) to invoke this helper after
changing Global::get().s.bMute so the Windows coordinator (m_universalMuter
under USE_WIN_UNIVERSAL_MUTE) stays in sync across all code paths.
---
Nitpick comments:
In `@docs/dev/build-instructions/build_windows.md`:
- Line 9: Replace the hardcoded Python installer reference "winget install
--id=Python.Python.3.13 -e" with a more flexible instruction: either recommend
using the generic package id "Python.Python.3" to install the latest Python 3.x,
or instruct users to select an appropriate installed Python 3.x version (e.g.,
via winget search or manual download). Update the line containing the exact
command string in build_windows.md to present the alternative command and a
brief note advising users to pick a suitable Python 3.x if 3.13 is unavailable.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 33f64653-2433-42c1-87ec-51ba512c3e44
📒 Files selected for processing (10)
docs/dev/build-instructions/build_static.mddocs/dev/build-instructions/build_windows.mddocs/dev/build-instructions/common_build_errors.mddocs/dev/build-instructions/faq.mdsrc/mumble/CMakeLists.txtsrc/mumble/MainWindow.cppsrc/mumble/MainWindow.hsrc/mumble/Messages.cppsrc/mumble/UniversalMute.cppsrc/mumble/UniversalMute.h
8ea7308 to
82fe67e
Compare
| ## Prerequisites | ||
|
|
||
| First, [install Visual Studio](setup_visual_studio.md) in order to be able to compile the necessary code. | ||
|
|
||
| You'll also need Python (`winget install --id=Python.Python.3.13 -e`). | ||
|
|
||
| ## Inner loop | ||
|
|
||
| You'll need to set up a window with Visual Studio's variables. You can open a Visual Studio CMD window, but you can set up an existing PowerShell window: | ||
|
|
||
| ```pwsh | ||
| # Load vcvars64.bat into your PowerShell window. | ||
| # You can find this path with the `vswhere.exe` tool (C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe) | ||
| # that ships with Visual Studio: | ||
| # | ||
| # vswhere -latest -products * -find "VC\Auxiliary\Build\vcvars64.bat" | ||
| cmd /c "`"C:\Program Files (x86)\Microsoft Visual Studio\18\BuildTools\VC\Auxiliary\Build\vcvars64.bat`" && set" | | ||
| ForEach-Object { | ||
| if ($_ -match "^([^=]+)=(.*)$") { [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2]) } | ||
| } | ||
| ``` | ||
|
|
||
| Then, in the `mumble/` directory, set up CMake. For example: | ||
|
|
||
| ```pwsh | ||
| # Set this to wherever you set up vcpkg. | ||
| $env_root = "C:\Users\me\Projects\mumble-env\mumble_env.x64-windows-static-md.b1fe4a4257" | ||
|
|
||
| # Configure cmake, e.g. | ||
| cmake -G Ninja ` | ||
| -S "C:\Users\me\Projects\mumble" ` | ||
| -B "C:\Users\me\Projects\mumble\build" ` | ||
| -DVCPKG_TARGET_TRIPLET=x64-windows-static-md ` | ||
| -Dstatic=ON ` | ||
| "-DCMAKE_TOOLCHAIN_FILE=$env_root\scripts\buildsystems\vcpkg.cmake" ` | ||
| "-DIce_HOME=$env_root\installed\x64-windows-static-md" ` | ||
| -DCMAKE_BUILD_TYPE=Release | ||
| ``` | ||
|
|
||
| Then build: | ||
|
|
||
| ```pwsh | ||
| cmake --build "C:\Users\me\Projects\mumble\build" --parallel | ||
| ``` | ||
|
|
||
| For full guidance, see [static builds](build_static.md). No newline at end of file |
There was a problem hiding this comment.
Is this divergence from build_static.md intentional? This seems to introduce a separate set of Windows-specific instructions that could drift over time (e.g. different or missing CMake flags like the bundled-cli11/spdlog ones). It’s also no longer system-agnostic due to hardcoded paths that most users won’t have.
Additionally, stating we only support static builds at the top and then having a separate guide here feels a bit inconsistent. Should we condense this somehow?
There was a problem hiding this comment.
Any divergence is unintentional, but I honestly found the full build_static.md guidance confusing. I hoped to summarize the most important information in this build_windows.md file, similar to the Mac & Linux guidance. It really took me a long time to understand what actually amounts to ~3 commands.
I'm happy to try a different approach, or at least reduce/clarify the user-specific directories and minimize any divergence.
There was a problem hiding this comment.
I would indeed prefer to not duplicate information. Linux and MacOS have dedicated instructions because they support non-static builds. Windows doesn't.
However, I am definitely open to changing/improving the instructions for static builds. Do you recall what it was that you struggled with specifically?
There was a problem hiding this comment.
I took another pass at the revision; hopefully this should make static building & Windows building easier for new folks to understand. Most importantly:
- Included an example at the beginning of the guidance, to show it's not too tough.
- Emphasized pre-built vcpkg.
- Extracted Windows-specific stuff to Visual Studio page, since it makes more sense there.
- Clarified/emphasized the CMake generator commands by adding newlines.
- Added a "build" step, just to make end-to-end clear.
Thoughts?
There was a problem hiding this comment.
I'm also happy to move these docs changes into a separate PR.
maxer137
left a comment
There was a problem hiding this comment.
I think it could be helpful to split this PR into separate commits or even separate PRs, as you suggested, for clarity.
- Mute-button support
- Language updates (the automated one)
- Windows build documentation
I don’t use Windows myself, so I’m unable to test the universal mute button 😅, but I didn't see anything that looked extremely out of the ordinary. The only thing that made me look up was "muting your mic in Mumble also mutes the mic globally in Windows," but it seems that is intended from watching the global mute button in action.
For the docs, I appreciate the expansion on setup_visual_studio. I remember trying to compile it on Windows in the past and running into some struggles with the compilers, so this should help future contributors a lot. Splitting it from the Windows caveats is a worthy change.
|
|
||
| This will typically take 3 steps: |
There was a problem hiding this comment.
Since the steps are explained in more detail later in the document, this summary feels a bit redundant.
Perhaps it could be shortened to a one-line overview or removed entirely to avoid repeating information, so readers aren’t presented with the same instructions twice.
| > [!NOTE] | ||
| > The `-Dbundled-cli11=OFF -Dbundled-spdlog=OFF` flags are required when using pre-built environments from after 2026-02. Without these flags, linker errors for unresolved CLI11/spdlog/fmt symbols will occur. See [common build errors](common_build_errors.md) for details. |
There was a problem hiding this comment.
Just to clarify. Are these flags required for all OSes or only for Windows?
There was a problem hiding this comment.
I believe they are required for all OSes? They are present in set_environment_variables.sh. Honestly, I think they may be required for all builds now, but I haven't built on other OSes.
|
|
||
| MSVC (Microsoft Visual C++) is Microsoft’s C++ compiler toolchain. It can be installed from Visual Studio Build Tools, or Visual Studio Community. | ||
| Either can be downloaded [here](https://visualstudio.microsoft.com/downloads) (Any somewhat recent version should work). | ||
| MSVC (Microsoft Visual C++) is Microsoft’s C++ compiler toolchain. It can be installed for free via the **Visual Studio Build Tools** or **Visual Studio Community**. |
There was a problem hiding this comment.
This change, to me, reads a bit like a promotional note. I’m not sure if that was the intention, but my initial impression when reading it was that it stood out from the otherwise neutral tone of the documentation. 😬
There was a problem hiding this comment.
Given that I no longer work at Microsoft, I hope it's not a promotional note :).
I added the for free bit because historically Visual Studio has required payment (the tools are still not libre use). I'll simply remove that phrase though.
| ### Using pre-built environments | ||
|
|
||
| For common configurations, you can also use the [pre-built vcpkg environments](https://github.com/mumble-voip/vcpkg/releases) mentioned above instead of using the script. | ||
|
|
||
| 1. Download & unzip the appropriate environment from [the releases page](https://github.com/mumble-voip/vcpkg/releases). | ||
| 2. When using the `cmake` commands below, use the unzipped folder as `<vcpkg dir>` in the `-DCMAKE_TOOLCHAIN_FILE` and `-DIce_HOME` arguments. Use | ||
| the corresponding triplet for `-DVCPKG_TARGET_TRIPLET`. | ||
|
|
||
| For example, on Windows, after extracting `mumble_env.x64-windows-static-md.<hash>.7z` to `C:\mumble-env\`: | ||
|
|
||
| ```powershell | ||
| cmake -G Ninja ` | ||
| "-DVCPKG_TARGET_TRIPLET=x64-windows-static-md" ` | ||
| "-Dstatic=ON" ` | ||
| "-DCMAKE_TOOLCHAIN_FILE=C:\mumble-env\mumble_env.x64-windows-static-md.<hash>\scripts\buildsystems\vcpkg.cmake" ` | ||
| "-DIce_HOME=C:\mumble-env\mumble_env.x64-windows-static-md.<hash>\installed\x64-windows-static-md" ` | ||
| "-DCMAKE_BUILD_TYPE=Release" ` | ||
| -Dbundled-cli11=OFF ` | ||
| -Dbundled-spdlog=OFF ` | ||
| .. | ||
| ``` | ||
|
|
||
| (Replace `<hash>` with the commit hash in the filename, e.g. `b1fe4a4257`.) |
There was a problem hiding this comment.
I think this section could be streamlined. Currently it repeats most of the full build instructions (and uses ninja in the example again). The main difference for pre-built environments seems to be fetching the environments and the CMake flags; perhaps this section could focus only on those points rather than duplicating all the steps. This would reduce redundancy and make it easier for readers to see what’s different, especially since additional dependencies are discussed later.
|
@maxer137, I'll separate the PRs. Good suggestion. |
21e7256 to
3ef2e9c
Compare
|
@maxer137, pushed a new, scoped PR. I'll handle adding translatable strings & doc updates in separate PRs.
I appreciate it! I can send you a video, but indeed the universal mute button & Mumble's button stay in sync. The Universal Mute button doesn't actually change any global system state; it simply reflects the state of a "VOIP call" on the system, initiated & managed by an application. Notice that OBS is still using the microphone, even though Mumble is muted:
Apps like Teams (and now Mumble) call this WinRT API to signal that they have started a VOIP call, then hook up Clicking that button doesn't actually do anything directly: it sends a In fact, I wrote a demo that doesn't even use the microphone! See also https://stackoverflow.com/questions/74683703/how-do-i-support-call-mute-universal-mute-in-my-app-for-windows-11-22h2. (In case you're wondering, if there are multiple VOIP Calls at once, e.g. Teams + Mumble, the Universal Mute button behaves strangely & chooses the most recent one).
I hope so! It really was super simple to get development working, so I hope I can pay it forward for folks. |
maxer137
left a comment
There was a problem hiding this comment.
@maxer137, I'll separate the PRs. Good suggestion.
😅 I think the translation PR and the mute PR do need to be one and the same PR. The translation commit is just an automated script anyway. Just a split between docs and the mute feature should be sufficient.
Other than that, I think this looks good to me. Then again, I can't compile and test it because I don't have Windows.
|
@maxer137 done, I hope 😅! |
Today, Mumble does not support the Universal Mute button in Windows, which additionally means that physical mute buttons in newer laptops cannot mute Mumble. This change adds support for these button (and the Windows-wide shortcut Win+Alt+K) by using the Windows VOIP API. Tested by deploying locally on Windows 11. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
db9e001 to
c058e18
Compare
|
@maxer137, anything holding this back? |
I’m not a maintainer 😅. I just reviewed your PR because I saw some things that seemed odd to me. A maintainer of the mumble project has to review your work now and accept the changes. |
|
@maxer137 oh, well in that case, thanks for volunteering your time to review :) |

Today, Mumble does not support the Universal Mute button in Windows, which additionally means that physical mute buttons in newer laptops cannot mute Mumble. This change adds support for these button (and the Windows-wide shortcut
Win+Alt+K) by using the Windows VOIP API.What changed?
UniversalMuteron Windows builds that wraps the WinRTWindows.ApplicationModel.Calls.VoipCallCordinator' APIs.UniversalMuterto read/write mute state during calls.A bit of background: I've wanted to implement this for a while now. I wrote the most popular StackOverflow question about the Universal Mute API while I worked at Microsoft (I had no affiliation with writing the API), wrote a simple C# demo app for it, and I wrote a Rust plugin for Mumble that does the same thing.
I used Claude Code to help generate this work.
Checks
Deployed locally on Windows 11.
Happy to address any feedback!