Files
linux-voice-assistant/linux_voice_assistant/webrtc.py
aryanhasgithub 4ee7bb04bc Add support for WebRTC Auto Gain and Noise Suppression (#250)
## WebRTC Auto Gain & Noise Suppression
 
This PR adds support for WebRTC Auto Gain and Noise Suppression as previously implemented in the Wyoming Satellite project.
 
### What's New
 
Two new entities have been created a number slider for gain and another one for noise suppression. The processing happens inside of the `webrtc.py` file and is implemented in the `__main__.py` file's `process_audio` function. The slider for gain has a limit of 0-31 and noise suppression has a limit of 0-4.
 
The Auto Gain and Noise Suppression persist through restarts and are saved as preferences. The values are dynamically chnged without needing a restart.
 
CLI flags called `--mic-auto-gain` and `--mic-noise-suppression` have also been added.
 
>  When both values are 0, WebRTC processing is bypassed entirely with no performance overhead.

Closes #25 
 
### Testing
 
When saving the audio recorded by LVA there is a noticeable increase. The following two files have been recorded with similar audio being played through them with these results (Gain-31 and NS-4):
 
| Metric | With AGC+NS | Without |
|---|---|---|
| Max amplitude | 0.329 | 0.054 |
| RMS amplitude | 0.008905 | 0.002862 |
| Volume adjustment needed | 3.034x | 13.479x |
| Rough frequency | 916 Hz | 705 Hz |
2026-04-09 00:43:11 +02:00

42 lines
1.5 KiB
Python

import logging
_LOGGER = logging.getLogger(__name__)
class WebRTCProcessor:
def __init__(self, agc_level: int = 0, ns_level: int = 0):
from webrtc_noise_gain import AudioProcessor # type: ignore[import-untyped]
self.apm = AudioProcessor(agc_level, ns_level)
self.agc_level = agc_level
self.ns_level = ns_level
self._buffer = bytearray()
self.FRAME_SIZE_BYTES = 320 # 160 samples * 2 bytes (16-bit PCM)
def update_settings(self, agc_level: int, ns_level: int):
"""Re-initialize processor if settings changed."""
if self.agc_level != agc_level or self.ns_level != ns_level:
from webrtc_noise_gain import AudioProcessor
_LOGGER.debug("Updating WebRTC settings: Gain=%s, NS=%s", agc_level, ns_level)
self.apm = AudioProcessor(agc_level, ns_level)
self.agc_level = agc_level
self.ns_level = ns_level
def process(self, raw_bytes: bytes) -> bytes:
"""
Buffer and process audio.
Returns processed bytes (may be shorter than input if buffering).
"""
self._buffer.extend(raw_bytes)
processed_chunks: list[bytes] = []
while len(self._buffer) >= self.FRAME_SIZE_BYTES:
frame = bytes(self._buffer[: self.FRAME_SIZE_BYTES])
del self._buffer[: self.FRAME_SIZE_BYTES] # drain in-place
result = self.apm.Process10ms(frame)
processed_chunks.append(result.audio)
return b"".join(processed_chunks)