The officially official Devuan Forum!

You are not logged in.

#1 Yesterday 18:47:37

igorzwx
Member
Registered: 2024-05-06
Posts: 421  

Chasing the Fox (Caccia alla volpe)

So after the fox, after the fox
Off to the hunt with chains and locks
So after the fox, after the fox
Someone is always chasing after the fox

After the Fox (1966) _https://www.youtube.com/watch?v=MrQl0VsQYtw

📖 Manual: "We Can’t Yet Prove Firefox Is Resampling… But We’ll Keep Trying"

For the truly dedicated — those who believe their audio deserves better.

🔧 Step 0: Lock It Down
Before we begin, disable the PulseAudio backend - yes, even the rusty one:

  1. Open Firefox and type about:config  in the address bar

  2. Search: media.cubeb.backend

  3. Click +, set type to string, value to alsa

Now Firefox talks directly to ALSA - no middlemen.

✅ You’ve just sidestepped a surveillance-level audio framework.

🕵️ Step 1: The Smoking Gun
Firefox uses Speex Resampler under the hood - yes, that Speex.
It’s in the code: AudioConverter.cpp includes <speex/speex_resampler.h>.

_https://searchfox.org/firefox-main/source/dom/media/AudioConverter.cpp

#include "AudioConverter.h"

#include <speex/speex_resampler.h> 

But here’s the twist:

  • On macOS, cubeb logs:
    Input and output sample-rate match, target rate of 48000Hz

  • On Linux? Silence.
    Nothing. Nada. Zilch.

🚨 Suspicious?
Or is Mozilla simply not telling Linux users what it’s up to?

macOS Firefox logs:

➤ MOZ_LOG="MediaDecoder:4,cubeb:5" stdbuf -oL /Applications/Firefox\ Developer\ Edition.app/Contents/MacOS/firefox 2>&1 https://youtu.be/uO6jfQ5tQHM | ggrep  --line-buffered -E "MetadataLoaded.*rate=|FirstFrameLoaded.*rate=|CubebStreamInit output stream rate|target rate|Output hardware" | ggrep -v "hasVideo=0"
[Child 4501: Main Thread]: D/MediaDecoder MediaDecoder[11631e700] MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
[Child 4501: Main Thread]: D/MediaDecoder MediaDecoder[116f37300] MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
[Child 4501: Main Thread]: D/MediaDecoder MediaDecoder[116f37300] FirstFrameLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1 mPlayState=PLAY_STATE_LOADING transportSeekable=1
[Child 4501: MediaDecoderStateMachine #1]: I/cubeb CubebStreamInit output stream rate 48000
[Parent 4486: AudioIPC Server RPC]: E/cubeb mod.rs:3995: (0x183e31c00) Output hardware description: AudioStreamBasicDescription { mSampleRate: 96000.0, mFormatID: 1819304813, mFormatFlags: 9, mBytesPerPacket: 8, mFramesPerPacket: 1, mBytesPerFrame: 8, mChannelsPerFrame: 2, mBitsPerChannel: 32, mReserved: 0 }
[Parent 4486: AudioIPC Server RPC]: E/cubeb cubeb_resampler_internal.h:553:Input and output sample-rate match, target rate of 48000Hz

On macOS, Firefox appears to feign transparency and user-friendliness. But macOS isn’t quite Linux: applications ought to behave in a civilised manner.

Right. So Firefox has its own resampler, and cubeb has its own as well - meaning the audio could be quietly upsampled and downsampled like some sort of secret internal game of pass-the-parcel, and we’d never even see it in the logs.

Typical, really. Everything’s transparent and user-friendly - just not actually.

What's Actually Happening

  1. Resampling: Cubeb uses its Speex-based resampler (cubeb_resampler_internal.h:199–207).

  2. Stream initialisation: Once the target rate is determined, Cubeb sets up the stream at 48kHz (cubeb_resampler_internal.h:561–577).

  3. Passthrough mode: When input and output rates match, Cubeb uses a passthrough resampler that simply forwards buffers without conversion (cubeb_resampler_internal.h:548–556).

The resampler selection logic in cubeb_resampler_create_internal() confirms this:

// Check if rates match - if so, use passthrough  
if (((input_params && input_params->rate == target_rate) &&  
     (output_params && output_params->rate == target_rate)) ||  
    (input_params && !output_params && (input_params->rate == target_rate)) ||  
    (output_params && !input_params &&  
     (output_params->rate == target_rate))) {  
  LOG("Input and output sample-rate match, target rate of %dHz", target_rate);  
  return new passthrough_resampler<T>(...);  
}

When rates don’t match, it creates a cubeb_resampler_speex_one_way for conversion (cubeb_resampler_internal.h:187–203).

🔍 Step 2: The Bit Depth Conspiracy
Firefox converts everything to 32-bit float - internally.

But let’s be honest:

  • 20 years ago, fftrate used 64-bit float.

  • Today, serious audio tools use 128-bit float or more.

And what does Firefox do?

sample spec: float32le 2ch 48000Hz

🧠 32-bit float - the Stone Age of precision.
It works, but is it good enough?

This isn’t about whether it functions — it’s whether it respects the medium. Firefox settles for the lowest common denominator, even when the hardware and OS are ready to do better.

🧩 Step 3: Who’s Really Resampling?
You’ve set:

media.resampling.enabled   false

So Firefox should not resample.

Logs show:

MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
FirstFrameLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1 
CubebStreamInit output stream rate 48000

🛠️ Final Command: Firefox logging together with fftrate logging

➤ MOZ_LOG="MediaDecoder:4,cubeb:5" stdbuf -oL firefox 2>&1 https://youtu.be/uO6jfQ5tQHM | grep  --line-buffered -E "MetadataLoaded.*rate=|FirstFrameLoaded.*rate=|CubebStreamInit output stream rate|target rate|Output hardware|Input|Output|Rates" | grep -v "hasVideo=0"
[Child 13197: Main Thread]: D/MediaDecoder MediaDecoder[7f6c62c17900] MetadataLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1
Input:  44100 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1764
Output: 48000 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 1920
Rates:  44100 --> 48000 (J: 0.00%, T: FFT, W: Vorbis)
[Child 13197: Main Thread]: D/MediaDecoder MediaDecoder[7f6c62c17900] FirstFrameLoaded, channels=2 rate=48000 hasAudio=1 hasVideo=1 mPlayState=PLAY_STATE_LOADING transportSeekable=1
[Child 13197: MediaDecoderStateMachine #1]: I/cubeb CubebStreamInit output stream rate 48000
Input:  48000 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1920
Output: 48000 Hz, 2 ch, 's16_le' (0x2): dummy = 0, period = 1920
Rates:  48000 --> 48000 (J: 0.00%, T: None, W: Planar)

This reflects only the observable behaviour. The full pipeline? Still hidden. As usual.

The Mystery Audio Stream

Input:  44100 Hz, 2 ch, 's32_le' (0xa): dummy = 0, period = 1764

The Short and Curious Tale
Right then, here's what's happening: Firefox, being a proper gentleman, politely taps your audio system on the shoulder to ask, "I say, what sample rate do you prefer?" This happens through Cubeb's alsa_get_preferred_sample_rate() function.

Firefox tries 44.1kHz first (a rather common rate, don't you know), but your dmix plugin, being a bit of a stickler for rules, insists on 48kHz. So ALSA’s resampler steps in like a proper butler, converting the stream—even though Firefox requested SND_PCM_NO_AUTO_RESAMPLE.

The "dummy = 0" in your logs? That's just ALSA's way of saying "This is a real device, gov'nor, not some test dummy."

Why This Isn't Your YouTube Video
This probing happens before any actual playback — it's merely Firefox checking what your audio system can handle. The actual YouTube stream will use whatever rate this probe determines (likely 48kHz in your case).

The Bottom Line
Perfectly normal behaviour, old chap! Just Firefox being thorough and your dmix plugin being particular. The resampling you see is ALSA doing its thing, completely separate from Cubeb's internal workings. Your hardware supporting 44.1kHz doesn't stop dmix from having its own ideas about proper audio rates.

Notes

  • This probe stream mechanism is used across all Cubeb backends for capability detection.

  • The format 's32_le' is 32-bit signed integer.

  • The "T: FFT" indicates ALSA's FFT-based resampling algorithm.

  • "J: 0.00%" shows minimal jitter — the conversion is working rather well indeed.

🧙♂️ Conclusion
We cannot prove Firefox is resampling — because it doesn’t log it.

But we know:

  • It uses Speex resampler.

  • It hides resampling logs on Linux.

So is it resampling?

🔎 We may never know.
But we’ll keep watching.

Citations

File: src/cubeb_alsa.c (L1228-1272)

static int
alsa_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
{
  (void)ctx;
  int r, dir;
  snd_pcm_t * pcm;
  snd_pcm_hw_params_t * hw_params;

  snd_pcm_hw_params_alloca(&hw_params);

  /* get a pcm, disabling resampling, so we get a rate the
   * hardware/dmix/pulse/etc. supports. */
  r = WRAP(snd_pcm_open)(&pcm, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK,
                         SND_PCM_NO_AUTO_RESAMPLE);
  if (r < 0) {
    return CUBEB_ERROR;
  }

  r = WRAP(snd_pcm_hw_params_any)(pcm, hw_params);
  if (r < 0) {
    WRAP(snd_pcm_close)(pcm);
    return CUBEB_ERROR;
  }

  r = WRAP(snd_pcm_hw_params_get_rate)(hw_params, rate, &dir);
  if (r >= 0) {
    /* There is a default rate: use it. */
    WRAP(snd_pcm_close)(pcm);
    return CUBEB_OK;
  }

  /* Use a common rate, alsa may adjust it based on hw/etc. capabilities. */
  *rate = 44100;

  r = WRAP(snd_pcm_hw_params_set_rate_near)(pcm, hw_params, rate, NULL);
  if (r < 0) {
    WRAP(snd_pcm_close)(pcm);
    return CUBEB_ERROR;
  }

  WRAP(snd_pcm_close)(pcm);

  return CUBEB_OK;
}

Offline

Board footer