feat: automatically equalize participant audio levels - #1689
Prateek007rai wants to merge 1 commit into
Conversation
Closes suitenumerique#1345 - New hook useAudioLevelEqualization: samples remote participant audio levels every 500ms, smooths via EMA, and gradually adjusts each participant's HTML audio element volume toward a shared target level. Gain clamped to [0.2, 3.0]. Resets to 1.0 when disabled. - Store: adds audioLevelEqualizationEnabled (default off) to userChoicesStore - Settings: toggle in Audio tab under a new 'Audio level equalization' section - i18n: EN, FR, DE, NL translations added
|
PR Summary by QodoAdd automatic participant audio level equalization
AI Description
Diagram
High-Level Assessment
Files changed (8)
|
Code Review by Qodo
1. Quiet speakers halt audio leveling
|
| state.currentGain = Math.min(MAX_GAIN, Math.max(MIN_GAIN, state.currentGain)) | ||
|
|
||
| const audioElement = getAudioElement(participant) | ||
| if (audioElement) audioElement.volume = state.currentGain |
There was a problem hiding this comment.
1. Quiet speakers halt audio leveling 📎 Requirement gap ≡ Correctness
tick clamps state.currentGain at 3.0 and writes it directly to HTMLMediaElement.volume, whose valid range ends at 1.0. Whenever a participant’s sampled level is below the 0.12 target, the calculated ratio can exceed one—for example, a level of 0.02 yields 1.25 on the first update—so the assignment throws, prevents that quiet speaker from being boosted, and aborts the interval callback before later participants are adjusted.
Agent Prompt
## Issue description
The equalizer writes gain values as high as `3.0` to `HTMLMediaElement.volume`, which only accepts values from `0` through `1`. This causes a range error instead of amplifying quiet participants and can stop the current interval callback before remaining participants are processed.
## Issue Context
The algorithm intentionally supports gains through `3.0`, so amplification requires an audio path that accepts gain above unity, such as a Web Audio `GainNode`. Tie the graph lifecycle and cleanup to each remote track, and ensure one participant’s gain failure cannot prevent processing the remaining participants. Do not merely clamp the value at `1.0`, because that would still fail the quiet-speaker use case.
## Fix Focus Areas
- src/frontend/src/features/rooms/livekit/hooks/useAudioLevelEqualization.ts[7-10]
- src/frontend/src/features/rooms/livekit/hooks/useAudioLevelEqualization.ts[58-67]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| {t('audio.audioLevelEqualization.label')} | ||
| </Switch> | ||
| <div /> |
There was a problem hiding this comment.
2. Users miss the setting explanation 📎 Requirement gap ≡ Correctness
AudioTab renders an empty <div /> beside the switch instead of the translated audio.audioLevelEqualization.description value. Whenever users evaluate this beta setting, they see its label but not the available explanation of its continuous per-participant behavior.
Agent Prompt
## Issue description
The audio-leveling control omits the required one-line explanation even though translated description text was added.
## Issue Context
Render the description alongside the toggle using the settings tab's established text styling and translation function.
## Fix Focus Areas
- src/frontend/src/features/settings/components/tabs/AudioTab.tsx[140-155]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| return document.querySelector<HTMLAudioElement>( | ||
| `audio[data-lk-sid="${micPub.trackSid}"]` | ||
| ) |
There was a problem hiding this comment.
3. Equalization never reaches remote audio 🐞 Bug ≡ Correctness
getAudioElement searches for an audio[data-lk-sid] node, but remote playback is delegated to RoomAudioRenderer and no repository-owned renderer creates an audio element with that attribute. Every tick therefore receives null and skips the only volume assignment, so enabling the setting has no effect for remote participants.
Agent Prompt
## Issue description
Audio equalization searches for a `data-lk-sid` audio element that the current remote-audio rendering path does not expose, leaving the feature ineffective.
## Issue Context
Remote audio is rendered through LiveKit's `RoomAudioRenderer`. Integrate equalization with the actual rendered track or element rather than relying on an unsupported DOM attribute.
## Fix Focus Areas
- src/frontend/src/features/rooms/livekit/hooks/useAudioLevelEqualization.ts[83-92]
- src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx[143-155]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| state.smoothedLevel * (1 - ADAPTATION_RATE) + audioLevel * ADAPTATION_RATE | ||
|
|
||
| // Only adjust gain when participant is speaking, not on silence/noise floor | ||
| if (state.smoothedLevel > 0.01) { |
There was a problem hiding this comment.
4. Pauses make the next words too loud 🐞 Bug ≡ Correctness
smoothedLevel continues incorporating zero samples, while the speaking guard tests that slowly decaying average rather than the current sample. After someone stops speaking the state remains above 0.01 for many 500 ms ticks and keeps increasing the gain, so their next utterance starts over-amplified.
Agent Prompt
## Issue description
Silence is folded into the level average, but the previous average is then treated as evidence that the participant is still speaking. This drives gain upward during ordinary pauses.
## Issue Context
Gate adaptation using a current speaking signal or current raw level, and retain or initialize the speaking-level estimate separately so silence does not lower the reference used to calculate gain.
## Fix Focus Areas
- src/frontend/src/features/rooms/livekit/hooks/useAudioLevelEqualization.ts[42-62]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Closes #1345