Open Bug 2036218 Opened 4 months ago Updated 1 month ago

WebRTC getUserMedia audio is distorted when sent via PeerConnection on Linux (works in Chromium)

Categories

(Core :: WebRTC: Audio/Video, defect, P3)

Firefox 150
defect

Tracking

()

UNCONFIRMED

People

(Reporter: azomDev, Unassigned)

References

(Blocks 1 open bug, Regression)

Details

(Keywords: regression)

Steps to reproduce:

What did you do? (steps to reproduce)

  1. Set up a minimal WebRTC peer-to-peer audio call between two devices (signaling server + ICE/TURN)
  2. On the Firefox/Linux device, call navigator.mediaDevices.getUserMedia with audio constraints:
navigator.mediaDevices.getUserMedia({
    audio: {
        channelCount: { ideal: 2, min: 1 },
        sampleRate: { ideal: 48000 },
        sampleSize: { ideal: 24 },
        echoCancellation: false,
        noiseSuppression: false,
        autoGainControl: false,
        latency: { ideal: 0.01 },
    },
    video: false,
})
  1. Add the resulting track to an RTCPeerConnection
  2. Connect to a second peer (tested with Chromium on another device)
  3. Listen to the audio received on the other end

Note: The issue also reproduces with just { audio: true, video: false } -- no constraints needed to trigger it.

Actual results:

Audio sent from Firefox has persistent distortion/artifacts. It sounds like a mix of unwanted processing and slight clipping/warping. It is NOT static or pops -- it is a continuous quality degradation applied to the voice.

  • The distortion is on the sending side only (the Firefox device sends bad audio; receiving playback is fine)
  • Chromium/Ungoogled Chromium on the same machine, same OS, same mic sends perfect audio
  • Happens with audio: true (all defaults, all processing enabled)
  • Also happens with all processing disabled
  • Not caused by AudioContext/AnalyserNode tapping the stream (tested with meters disabled)
  • Not caused by SDP munging (tested with raw unmodified SDP)

Expected results:

Clean audio output matching the local microphone input, same as Chromium produces on the identical system with the identical microphone.

Hey azom, what os and device were you testing on? Can you provide your about:support text please? Thanks.

Flags: needinfo?(azomDev)
Flags: needinfo?(kinetik)

It'd be very useful to capture the logs when this is happening. If you could please:

  1. In a fresh Firefox window (ideally with no other tabs), open a new
    tab and navigate to about:logging.
  2. Under "Logging preset" select "WebRTC", then click "Start Logging".
  3. Reproduce the bug
  4. Switch back to the about:logging tab and click "Stop Logging".
  5. A new tab will open with the Firefox Profiler; in the top right
    click the upload button, make sure "Include hidden threads" is
    selected, and upload. Paste the resulting share URL here.

Short video walkthrough: https://paul.cx/public/about-logging-presentation.webm

Also if you're able to include the output from pactl info run in a terminal window on the same system, that'd be helpful. Thanks!

Flags: needinfo?(kinetik)

Redirect a needinfo that is pending on an inactive user to the triage owner.
:jib, since the bug has recent activity, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(azomDev) → needinfo?(jib)

Sorry for the delay on this one, and thanks for the detailed instructions, really appreciate the help figuring this out :)

I've confirmed that the issue is caused by privacy.resistFingerprinting. When enabled, WebRTC audio becomes audibly distorted. Flipping it off in about:config makes the problem go away completely.

One thing I observed is that RFP forces AudioContext.sampleRate from 48000 down to 44100, so maybe its part of the issue.

Tested on:

  • Firefox 151.0.2 on Arch Linux, kernel 7.0.10-2-cachyos
  • NVIDIA RTX 4070, Wayland/KDE
  • Audio backend: pulse-rust
  • Blue Yeti microphone over USB (default: 48000, support: 1 - 384000)

I put together a minimal test app at https://webrtc-bug-poc.azom.dev. You can reproduce by opening it on two devices (I wasn't able to make it work on the same device) and talking. With RFP on, distortion is obvious (I think). You need to refresh the test app for the new RFP setting to take effect.

Profiler capture (with RFP on): https://share.firefox.dev/438iiVP

Other things I noticed while debugging:

  • track.getSettings() always returns echoCancellation=true, noiseSuppression=true, autoGainControl=true with RFP on, even if you explicitly request { exact: false } for all of them
  • getSupportedConstraints() stops listing sampleRate and sampleSize entirely when RFP is active

Oh and here is the pactl info:

pactl info
Server String: /run/user/1000/pulse/native
Library Protocol Version: 35
Server Protocol Version: 35
Is Local: yes
Client Index: 1669
Tile Size: 65472
User Name: azom
Host Name: azom-desktop
Server Name: PulseAudio (on PipeWire 1.6.6)
Server Version: 15.0.0
Default Sample Specification: float32le 2ch 48000Hz
Default Channel Map: front-left,front-right
Default Sink: alsa_output.usb-Generic_Blue_Microphones_LT_2203231650249D03017E_111000-00.analog-stereo
Default Source: alsa_input.usb-Generic_Blue_Microphones_LT_2203231650249D03017E_111000-00.analog-stereo
Cookie: c30d:95bc

Instead of having a PoC that requires another computer, I made an even smaller PoC that just plays back the audio directly to you (use headphones since echo cancellation is disabled).

No idea if I should post the file here, but I'll be hosting it at https://azom.dev/webrtc-loopback-poc.html. You can obviously also download it if you want to look at the code easily and try it completely locally, but now everything happens in the browser anyways. Since this PoC is simpler, I'll be taking down https://webrtc-bug-poc.azom.dev.

See comment 4, something related to resistFingerprinting.

Flags: needinfo?(jib) → needinfo?(karlt)
Severity: -- → S3
Priority: -- → P3

Sounds like the audio is being gated, with words cutting off before they finish,
similar to AEC.
It improves quite a bit after some seconds.

The same occurs without resistFingerprinting if no processing constraints are applied, so that echo, noise, and agc processing are enabled.

https://bugzilla.mozilla.org/attachment.cgi?id=9496623 indicates that it is the interaction of output at the same time as input.
If audio received by the microphone is short in duration, then the delayed audio output sounds clean.
If the audio received by the microphone lasts longer than the delay then it interferes with the quality of the delayed audio output.

There is similar processing in Chrome. It's hard to compare the qualities because my experiments were not exactly the same. Even if they were, there is non-determinism in the processing.

The effect of the resistFingerprinting pref is to ignore all constraints passed to getUserMedia(), so this processing cannot be turned off.

Flags: needinfo?(karlt)
Keywords: regression
Regressed by: 1372073
Blocks: rfp-breakage
You need to log in before you can comment on or make changes to this bug.