Skip to content

Add MixingAudioDeviceModule and loopback mixing transport#26

Closed
paterkleomenis wants to merge 1 commit intodesktop-app:masterfrom
paterkleomenis:mixing-audio-loopback
Closed

Add MixingAudioDeviceModule and loopback mixing transport#26
paterkleomenis wants to merge 1 commit intodesktop-app:masterfrom
paterkleomenis:mixing-audio-loopback

Conversation

@paterkleomenis
Copy link
Contributor

@paterkleomenis paterkleomenis commented Feb 22, 2026

Summary

Introduces infrastructure to mix system-audio loopback into the outgoing microphone stream during a call, on both Linux and Windows.

This PR does not include mic muting or playback volume control — those are in the follow-up PR.

Depends on: #22 (Linux loopback ADM)

Changes

All changes are in webrtc/webrtc_create_adm.cpp and webrtc/webrtc_create_adm.h.

New internal types (anonymous namespace)

LoopbackCollector
Thread-safe mono ring buffer (max 2 s at 48 kHz). Loopback capture threads call pushSamples(); MixingAudioTransport calls readAndMix() to saturating-add loopback audio into each mic frame. Stereo input is downmixed to mono on push.

DirectLoopbackCapture (Linux only, guarded by WEBRTC_LINUX)
Background std::thread that opens the PulseAudio monitor source via alcCaptureOpenDevice (stereo preferred, mono fallback), feeds decoded frames into LoopbackCollector, and stops cleanly on destruction. findMonitorDevice() prefers the monitor that matches the current default playback sink.

MixingAudioTransport
webrtc::AudioTransport decorator. When mixing is enabled it copies the mic buffer, calls LoopbackCollector::readAndMix, then forwards the blended frame to the inner transport. The disabled path is zero-overhead (no copy, no lock).

New internal class (details namespace)

MixingAudioDeviceModule
webrtc::AudioDeviceModule wrapper. Installs MixingAudioTransport in RegisterAudioCallback(), starts/stops DirectLoopbackCapture on Linux (or a dedicated loopback ADM + LoopbackAdmTransport on Windows) when setLoopbackEnabled() is toggled via MixingAudioControl.

New public API

MixingAudioControl
Shared handle that survives ADM recreation. setLoopbackEnabled() / loopbackEnabled() let callers toggle mixing at any time; the control re-applies pending state whenever a new MixingAudioDeviceModule attaches.

MixingAudioDeviceModuleCreator(innerCreator, control)
Returns a creator lambda that wraps any ADM (e.g. the OpenAL ADM) inside a MixingAudioDeviceModule.

Platform

Linux and Windows. macOS is unaffected.

Follow-up PR

@ilya-fedin
Copy link
Contributor

This PR now conflicts with #22 creating the same files

@paterkleomenis paterkleomenis force-pushed the mixing-audio-loopback branch 2 times, most recently from ecbbebe to 24b74d0 Compare February 22, 2026 23:22
@paterkleomenis
Copy link
Contributor Author

This PR now conflicts with #22 creating the same files

Unfortunately, it appears that introducing the changes in PR 24 without also including the commit from PR 26 is impossible, so if/when PR 26 is merged, I will rebase 24 for it to work correctly. In the meantime, if you want to test all of them, you can just include PR 24 which also contains the changes in 26 (or, since the changes are so dependent on each other, would you be okay with merging them in one PR?)

@ilya-fedin
Copy link
Contributor

The PR has conflicts

@paterkleomenis paterkleomenis force-pushed the mixing-audio-loopback branch from 24b74d0 to a6e12de Compare March 5, 2026 11:41
…back volume control

Introduces MixingAudioDeviceModule and MixingAudioControl to mix
system-audio loopback into the outgoing microphone stream, plus two
runtime controls for mic-only muting and per-call playback volume.

MixingAudioDeviceModule (ADM wrapper):
  Installs MixingAudioTransport in RegisterAudioCallback(),
  starts/stops DirectLoopbackCapture (Linux) or a dedicated loopback
  ADM + LoopbackAdmTransport (Windows) when setLoopbackEnabled() is
  toggled via MixingAudioControl.

MixingAudioTransport:
  setMicrophoneMuted(bool) -- zeroes mic samples before forwarding
    to WebRTC while keeping the channel open so loopback audio
    continues to flow through unchanged.
  setPlaybackVolume(float) -- scales decoded playback samples by the
    given factor (0.0-1.0), providing per-call software volume
    control independent of the system mixer.

MixingAudioControl (public API):
  Shared handle that survives ADM recreation. setLoopbackEnabled(),
  setMicrophoneMuted() and setPlaybackVolume() let callers control
  mixing at any time; state is re-applied whenever a new
  MixingAudioDeviceModule attaches.

MixingAudioDeviceModuleCreator(innerCreator, control):
  Returns a creator lambda that wraps any ADM inside a
  MixingAudioDeviceModule.

Platform: Linux and Windows. macOS is unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants