<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<atom:link href="https://dev1galaxy.org/extern.php?action=feed&amp;fid=25&amp;type=rss" rel="self" type="application/rss+xml" />
		<title><![CDATA[Dev1 Galaxy Forum / Freedom Hacks]]></title>
		<link>https://dev1galaxy.org/index.php</link>
		<description><![CDATA[The most recent topics at Dev1 Galaxy Forum.]]></description>
		<lastBuildDate>Fri, 10 Jul 2026 00:40:42 +0000</lastBuildDate>
		<generator>FluxBB</generator>
		<item>
			<title><![CDATA[Firefox: Dialectics of Antagonistic Security Bugs]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=8012&amp;action=new</link>
			<description><![CDATA[<h5>New version of Firefox/Cubeb ALSA backend</h5><div class="codebox"><pre><code>Date:   Wed Jul 8 22:22:55 2026 +0200

    ALSA backend: Implement proper device enumeration using snd_device_name_hint()
    
    Replace the minimal placeholder enumeration that returned hardcoded
    values with proper device enumeration using snd_device_name_hint() API.
    This now correctly enumerates both physical hardware devices and virtual
    devices (BlueALSA, rate converters, plugins) with accurate format capabilities,
    channel counts, and rate ranges queried from actual hardware.</code></pre></div><div class="codebox"><pre class="vscroll"><code>$ cat firefox/media/libcubeb/src/cubeb_alsa.c
/*
 * Copyright © 2011 Mozilla Foundation
 *
 * This program is made available under an ISC-style license.  See the
 * accompanying file LICENSE for details.
 */
#undef NDEBUG
#define _DEFAULT_SOURCE
#define _BSD_SOURCE
#if defined(__NetBSD__)
#define _NETBSD_SOURCE /* timersub() */
#endif
#define _XOPEN_SOURCE 500
#include &quot;cubeb-internal.h&quot;
#include &quot;cubeb/cubeb.h&quot;
#include &quot;cubeb_tracing.h&quot;
#include &lt;alsa/asoundlib.h&gt;
#include &lt;assert.h&gt;
#include &lt;dlfcn.h&gt;
#include &lt;limits.h&gt;
#include &lt;poll.h&gt;
#include &lt;pthread.h&gt;
#include &lt;sys/time.h&gt;
#include &lt;unistd.h&gt;

#ifdef DISABLE_LIBASOUND_DLOPEN
#define WRAP(x) x
#else
#define WRAP(x) (*cubeb_##x)
#define LIBASOUND_API_VISIT(X)                                                 \
  X(snd_config)                                                                \
  X(snd_config_add)                                                            \
  X(snd_config_copy)                                                           \
  X(snd_config_delete)                                                         \
  X(snd_config_get_id)                                                         \
  X(snd_config_get_string)                                                     \
  X(snd_config_imake_integer)                                                  \
  X(snd_config_search)                                                         \
  X(snd_config_search_definition)                                              \
  X(snd_lib_error_set_handler)                                                 \
  X(snd_pcm_avail_update)                                                      \
  X(snd_pcm_close)                                                             \
  X(snd_pcm_delay)                                                             \
  X(snd_pcm_drain)                                                             \
  X(snd_pcm_frames_to_bytes)                                                   \
  X(snd_pcm_get_params)                                                        \
  X(snd_pcm_hw_params_any)                                                     \
  X(snd_pcm_hw_params_get_channels_max)                                        \
  X(snd_pcm_hw_params_get_rate)                                                \
  X(snd_pcm_hw_params_set_rate_near)                                           \
  X(snd_pcm_hw_params_sizeof)                                                  \
  X(snd_pcm_nonblock)                                                          \
  X(snd_pcm_open)                                                              \
  X(snd_pcm_open_lconf)                                                        \
  X(snd_pcm_pause)                                                             \
  X(snd_pcm_poll_descriptors)                                                  \
  X(snd_pcm_poll_descriptors_count)                                            \
  X(snd_pcm_poll_descriptors_revents)                                          \
  X(snd_pcm_readi)                                                             \
  X(snd_pcm_recover)                                                           \
  X(snd_pcm_set_params)                                                        \
  X(snd_pcm_start)                                                             \
  X(snd_pcm_state)                                                             \
  X(snd_pcm_writei)                                                            \
  X(snd_device_name_hint)                                                      \
	X(snd_device_name_get_hint)                                                  \
	X(snd_device_name_free_hint)                                                 \
	X(snd_pcm_hw_params_test_format)                                             \
	X(snd_pcm_hw_params_get_rate_min)                                            \
	X(snd_pcm_hw_params_get_rate_max)                                            \
	X(snd_pcm_hw_params_get_channels_min)                                        \
	X(snd_pcm_hw_params_get_channels_max)

#define MAKE_TYPEDEF(x) static typeof(x) * cubeb_##x;
LIBASOUND_API_VISIT(MAKE_TYPEDEF);
#undef MAKE_TYPEDEF
/* snd_pcm_hw_params_alloca is actually a macro */
#define snd_pcm_hw_params_sizeof cubeb_snd_pcm_hw_params_sizeof
#endif

#define CUBEB_STREAM_MAX 16
#define CUBEB_WATCHDOG_MS 10000

#define CUBEB_ALSA_PCM_NAME &quot;default&quot;

#define ALSA_PA_PLUGIN &quot;ALSA &lt;-&gt; PulseAudio PCM I/O Plugin&quot;

/* ALSA is not thread-safe.  snd_pcm_t instances are individually protected
   by the owning cubeb_stream&#039;s mutex.  snd_pcm_t creation and destruction
   is not thread-safe until ALSA 1.0.24 (see alsa-lib.git commit 91c9c8f1),
   so those calls must be wrapped in the following mutex. */
static pthread_mutex_t cubeb_alsa_mutex = PTHREAD_MUTEX_INITIALIZER;
static int cubeb_alsa_error_handler_set = 0;

static struct cubeb_ops const alsa_ops;

struct cubeb {
  struct cubeb_ops const * ops;
  void * libasound;

  pthread_t thread;

  /* Mutex for streams array, must not be held while blocked in poll(2). */
  pthread_mutex_t mutex;

  /* Sparse array of streams managed by this context. */
  cubeb_stream * streams[CUBEB_STREAM_MAX];

  /* fds and nfds are only updated by alsa_run when rebuild is set. */
  struct pollfd * fds;
  nfds_t nfds;
  int rebuild;

  int shutdown;

  /* Control pipe for forcing poll to wake and rebuild fds or recalculate the
   * timeout. */
  int control_fd_read;
  int control_fd_write;

  /* Track number of active streams.  This is limited to CUBEB_STREAM_MAX
     due to resource contraints. */
  unsigned int active_streams;

  /* Local configuration with handle_underrun workaround set for PulseAudio
     ALSA plugin.  Will be NULL if the PA ALSA plugin is not in use or the
     workaround is not required. */
  snd_config_t * local_config;
  int is_pa;
};

enum stream_state { INACTIVE, RUNNING, DRAINING, PROCESSING, ERROR };

struct cubeb_stream {
  /* Note: Must match cubeb_stream layout in cubeb.c. */
  cubeb * context;
  void * user_ptr;
  /**/
  pthread_mutex_t mutex;
  snd_pcm_t * pcm;
  cubeb_data_callback data_callback;
  cubeb_state_callback state_callback;
  snd_pcm_uframes_t stream_position;
  snd_pcm_uframes_t last_position;
  snd_pcm_uframes_t buffer_size;
  cubeb_stream_params params;

  /* Every member after this comment is protected by the owning context&#039;s
     mutex rather than the stream&#039;s mutex, or is only used on the context&#039;s
     run thread. */
  pthread_cond_t cond; /* Signaled when the stream&#039;s state is changed. */

  enum stream_state state;

  struct pollfd * saved_fds; /* A copy of the pollfds passed in at init time. */
  struct pollfd *
      fds; /* Pointer to this waitable&#039;s pollfds within struct cubeb&#039;s fds. */
  nfds_t nfds;

  struct timeval drain_timeout;

  /* XXX: Horrible hack -- if an active stream has been idle for
     CUBEB_WATCHDOG_MS it will be disabled and the error callback will be
     called.  This works around a bug seen with older versions of ALSA and
     PulseAudio where streams would stop requesting new data despite still
     being logically active and playing. */
  struct timeval last_activity;
  float volume;

  char * buffer;
  snd_pcm_uframes_t bufframes;
  snd_pcm_stream_t stream_type;

  struct cubeb_stream * other_stream;
};

static int
any_revents(struct pollfd * fds, nfds_t nfds)
{
  nfds_t i;

  for (i = 0; i &lt; nfds; ++i) {
    if (fds[i].revents) {
      return 1;
    }
  }

  return 0;
}

static int
cmp_timeval(struct timeval * a, struct timeval * b)
{
  if (a-&gt;tv_sec == b-&gt;tv_sec) {
    if (a-&gt;tv_usec == b-&gt;tv_usec) {
      return 0;
    }
    return a-&gt;tv_usec &gt; b-&gt;tv_usec ? 1 : -1;
  }
  return a-&gt;tv_sec &gt; b-&gt;tv_sec ? 1 : -1;
}

static int
timeval_to_relative_ms(struct timeval * tv)
{
  struct timeval now;
  struct timeval dt;
  long long t;
  int r;

  gettimeofday(&amp;now, NULL);
  r = cmp_timeval(tv, &amp;now);
  if (r &gt;= 0) {
    timersub(tv, &amp;now, &amp;dt);
  } else {
    timersub(&amp;now, tv, &amp;dt);
  }
  t = dt.tv_sec;
  t *= 1000;
  t += (dt.tv_usec + 500) / 1000;

  if (t &gt; INT_MAX) {
    t = INT_MAX;
  } else if (t &lt; INT_MIN) {
    t = INT_MIN;
  }

  return r &gt;= 0 ? t : -t;
}

static int
ms_until(struct timeval * tv)
{
  return timeval_to_relative_ms(tv);
}

static int
ms_since(struct timeval * tv)
{
  return -timeval_to_relative_ms(tv);
}

static void
rebuild(cubeb * ctx)
{
  nfds_t nfds;
  int i;
  nfds_t j;
  cubeb_stream * stm;

  assert(ctx-&gt;rebuild);

  /* Always count context&#039;s control pipe fd. */
  nfds = 1;
  for (i = 0; i &lt; CUBEB_STREAM_MAX; ++i) {
    stm = ctx-&gt;streams[i];
    if (stm) {
      stm-&gt;fds = NULL;
      if (stm-&gt;state == RUNNING) {
        nfds += stm-&gt;nfds;
      }
    }
  }

  free(ctx-&gt;fds);
  ctx-&gt;fds = calloc(nfds, sizeof(struct pollfd));
  assert(ctx-&gt;fds);
  ctx-&gt;nfds = nfds;

  /* Include context&#039;s control pipe fd. */
  ctx-&gt;fds[0].fd = ctx-&gt;control_fd_read;
  ctx-&gt;fds[0].events = POLLIN | POLLERR;

  for (i = 0, j = 1; i &lt; CUBEB_STREAM_MAX; ++i) {
    stm = ctx-&gt;streams[i];
    if (stm &amp;&amp; stm-&gt;state == RUNNING) {
      memcpy(&amp;ctx-&gt;fds[j], stm-&gt;saved_fds, stm-&gt;nfds * sizeof(struct pollfd));
      stm-&gt;fds = &amp;ctx-&gt;fds[j];
      j += stm-&gt;nfds;
    }
  }

  ctx-&gt;rebuild = 0;
}

static void
poll_wake(cubeb * ctx)
{
  if (write(ctx-&gt;control_fd_write, &quot;x&quot;, 1) &lt; 0) {
    /* ignore write error */
  }
}

static void
set_timeout(struct timeval * timeout, unsigned int ms)
{
  gettimeofday(timeout, NULL);
  timeout-&gt;tv_sec += ms / 1000;
  timeout-&gt;tv_usec += (ms % 1000) * 1000;
}

static void
stream_buffer_decrement(cubeb_stream * stm, long count)
{
  if (count &lt; 0 || (snd_pcm_uframes_t)count &gt; stm-&gt;bufframes) {
    count = stm-&gt;bufframes;
  }
  char * bufremains =
      stm-&gt;buffer + WRAP(snd_pcm_frames_to_bytes)(stm-&gt;pcm, count);
  memmove(stm-&gt;buffer, bufremains,
          WRAP(snd_pcm_frames_to_bytes)(stm-&gt;pcm, stm-&gt;bufframes - count));
  stm-&gt;bufframes -= count;
}

static void
alsa_set_stream_state(cubeb_stream * stm, enum stream_state state)
{
  cubeb * ctx;
  int r;

  ctx = stm-&gt;context;
  stm-&gt;state = state;
  r = pthread_cond_broadcast(&amp;stm-&gt;cond);
  assert(r == 0);
  ctx-&gt;rebuild = 1;
  poll_wake(ctx);
}

static void
alsa_set_draining(cubeb_stream * stm)
{
  alsa_set_stream_state(stm, DRAINING);
  if (stm-&gt;stream_type == SND_PCM_STREAM_PLAYBACK &amp;&amp; stm-&gt;other_stream &amp;&amp;
      stm-&gt;other_stream-&gt;state == RUNNING) {
    alsa_set_stream_state(stm-&gt;other_stream, DRAINING);
  }
}

static enum stream_state
alsa_process_stream(cubeb_stream * stm, int other_stream_running)
{
  unsigned short revents;
  snd_pcm_sframes_t avail;
  int draining;

  draining = 0;

  pthread_mutex_lock(&amp;stm-&gt;mutex);

  /* Call _poll_descriptors_revents() even if we don&#039;t use it
     to let underlying plugins clear null events.  Otherwise poll()
     may wake up again and again, producing unnecessary CPU usage. */
  WRAP(snd_pcm_poll_descriptors_revents)
  (stm-&gt;pcm, stm-&gt;fds, stm-&gt;nfds, &amp;revents);

  avail = WRAP(snd_pcm_avail_update)(stm-&gt;pcm);

  /* Got null event? Bail and wait for another wakeup. */
  if (avail == 0) {
    pthread_mutex_unlock(&amp;stm-&gt;mutex);
    return RUNNING;
  }

  /* This could happen if we were suspended with SIGSTOP/Ctrl+Z for a long time.
   */
  if ((unsigned int)avail &gt; stm-&gt;buffer_size) {
    avail = stm-&gt;buffer_size;
  }

  /* Capture: Read available frames */
  if (stm-&gt;stream_type == SND_PCM_STREAM_CAPTURE &amp;&amp; avail &gt; 0) {
    snd_pcm_sframes_t got;

    if (avail + stm-&gt;bufframes &gt; stm-&gt;buffer_size) {
      /* Buffer overflow. Skip and overwrite with new data. */
      stm-&gt;bufframes = 0;
      // TODO: should it be marked as DRAINING?
    }

    got = WRAP(snd_pcm_readi)(stm-&gt;pcm, stm-&gt;buffer + stm-&gt;bufframes, avail);

    if (got &lt; 0) {
      avail = got; // the error handler below will recover us
    } else {
      stm-&gt;bufframes += got;
      stm-&gt;stream_position += got;

      gettimeofday(&amp;stm-&gt;last_activity, NULL);
    }
  }

  /* Capture: Pass read frames to callback function */
  if (stm-&gt;stream_type == SND_PCM_STREAM_CAPTURE &amp;&amp; stm-&gt;bufframes &gt; 0 &amp;&amp;
      (!stm-&gt;other_stream ||
       stm-&gt;other_stream-&gt;bufframes &lt; stm-&gt;other_stream-&gt;buffer_size)) {
    snd_pcm_sframes_t wrote = stm-&gt;bufframes;
    snd_pcm_sframes_t requested;
    struct cubeb_stream * mainstm = stm-&gt;other_stream ? stm-&gt;other_stream : stm;
    void * other_buffer = stm-&gt;other_stream ? stm-&gt;other_stream-&gt;buffer +
                                                  stm-&gt;other_stream-&gt;bufframes
                                            : NULL;

    /* Correct write size to the other stream available space */
    if (stm-&gt;other_stream &amp;&amp;
        wrote &gt; (snd_pcm_sframes_t)(stm-&gt;other_stream-&gt;buffer_size -
                                    stm-&gt;other_stream-&gt;bufframes)) {
      wrote = stm-&gt;other_stream-&gt;buffer_size - stm-&gt;other_stream-&gt;bufframes;
    }

    requested = wrote;
    pthread_mutex_unlock(&amp;stm-&gt;mutex);
    wrote = stm-&gt;data_callback(mainstm, stm-&gt;user_ptr, stm-&gt;buffer,
                               other_buffer, wrote);
    pthread_mutex_lock(&amp;stm-&gt;mutex);

    if (wrote &lt; 0) {
      avail = wrote; // the error handler below will recover us
    } else {
      stream_buffer_decrement(stm, wrote);

      if (stm-&gt;other_stream) {
        stm-&gt;other_stream-&gt;bufframes += wrote;
      }
      if (wrote &lt; requested) {
        if (!stm-&gt;other_stream) {
          pthread_mutex_unlock(&amp;stm-&gt;mutex);
          return INACTIVE;
        }
        draining = 1;
        set_timeout(&amp;stm-&gt;drain_timeout, 0);
      }
    }
  }

  /* Playback: Don&#039;t have enough data? Let&#039;s ask for more. */
  if (stm-&gt;stream_type == SND_PCM_STREAM_PLAYBACK &amp;&amp;
      avail &gt; (snd_pcm_sframes_t)stm-&gt;bufframes &amp;&amp;
      (!stm-&gt;other_stream ||
       (other_stream_running &amp;&amp; stm-&gt;other_stream-&gt;bufframes &gt; 0))) {
    long got = avail - stm-&gt;bufframes;
    void * other_buffer = stm-&gt;other_stream ? stm-&gt;other_stream-&gt;buffer : NULL;
    char * buftail =
        stm-&gt;buffer + WRAP(snd_pcm_frames_to_bytes)(stm-&gt;pcm, stm-&gt;bufframes);
    long requested;

    /* Correct read size to the other stream available frames */
    if (stm-&gt;other_stream &amp;&amp;
        got &gt; (snd_pcm_sframes_t)stm-&gt;other_stream-&gt;bufframes) {
      got = stm-&gt;other_stream-&gt;bufframes;
    }

    requested = got;
    pthread_mutex_unlock(&amp;stm-&gt;mutex);
    got = stm-&gt;data_callback(stm, stm-&gt;user_ptr, other_buffer, buftail, got);
    pthread_mutex_lock(&amp;stm-&gt;mutex);

    if (got &lt; 0) {
      avail = got; // the error handler below will recover us
    } else {
      stm-&gt;bufframes += got;

      if (stm-&gt;other_stream) {
        stream_buffer_decrement(stm-&gt;other_stream, got);
      }
      if (got &lt; requested) {
        draining = 1;
      }
    }
  }

  /* Playback: Still don&#039;t have enough data? Add some silence. */
  if (stm-&gt;stream_type == SND_PCM_STREAM_PLAYBACK &amp;&amp;
      avail &gt; (snd_pcm_sframes_t)stm-&gt;bufframes) {
    long drain_frames = avail - stm-&gt;bufframes;
    double drain_time = (double)drain_frames / stm-&gt;params.rate;

    char * buftail =
        stm-&gt;buffer + WRAP(snd_pcm_frames_to_bytes)(stm-&gt;pcm, stm-&gt;bufframes);
    memset(buftail, 0, WRAP(snd_pcm_frames_to_bytes)(stm-&gt;pcm, drain_frames));
    stm-&gt;bufframes = avail;

    /* Mark as draining, unless we&#039;re waiting for capture */
    if (!stm-&gt;other_stream || draining || stm-&gt;other_stream-&gt;bufframes &gt; 0) {
      set_timeout(&amp;stm-&gt;drain_timeout, drain_time * 1000);

      draining = 1;
    }
  }

  /* Playback: Have enough data and no errors. Let&#039;s write it out. */
  if (stm-&gt;stream_type == SND_PCM_STREAM_PLAYBACK &amp;&amp; avail &gt; 0) {
    snd_pcm_sframes_t wrote;

    if (stm-&gt;params.format == CUBEB_SAMPLE_FLOAT32NE) {
      float * b = (float *)stm-&gt;buffer;
      for (uint32_t i = 0; i &lt; avail * stm-&gt;params.channels; i++) {
        b[i] *= stm-&gt;volume;
      }
    } else {
      short * b = (short *)stm-&gt;buffer;
      for (uint32_t i = 0; i &lt; avail * stm-&gt;params.channels; i++) {
        b[i] *= stm-&gt;volume;
      }
    }

    wrote = WRAP(snd_pcm_writei)(stm-&gt;pcm, stm-&gt;buffer, avail);
    if (wrote &lt; 0) {
      avail = wrote; // the error handler below will recover us
    } else {
      stream_buffer_decrement(stm, wrote);

      stm-&gt;stream_position += wrote;
      gettimeofday(&amp;stm-&gt;last_activity, NULL);
    }
  }

  /* Got some error? Let&#039;s try to recover the stream. */
  if (avail &lt; 0) {
    avail = WRAP(snd_pcm_recover)(stm-&gt;pcm, avail, 0);

    /* Capture pcm must be started after initial setup/recover */
    if (avail &gt;= 0 &amp;&amp; stm-&gt;stream_type == SND_PCM_STREAM_CAPTURE &amp;&amp;
        WRAP(snd_pcm_state)(stm-&gt;pcm) == SND_PCM_STATE_PREPARED) {
      avail = WRAP(snd_pcm_start)(stm-&gt;pcm);
    }
  }

  /* Failed to recover, this stream must be broken. */
  if (avail &lt; 0) {
    pthread_mutex_unlock(&amp;stm-&gt;mutex);
    stm-&gt;state_callback(stm, stm-&gt;user_ptr, CUBEB_STATE_ERROR);
    return ERROR;
  }

  pthread_mutex_unlock(&amp;stm-&gt;mutex);
  return draining ? DRAINING : RUNNING;
}

static int
alsa_run(cubeb * ctx)
{
  int r;
  int timeout;
  int i;
  char dummy;
  cubeb_stream * stm;
  enum stream_state state;

  pthread_mutex_lock(&amp;ctx-&gt;mutex);

  if (ctx-&gt;rebuild) {
    rebuild(ctx);
  }

  /* Wake up at least once per second for the watchdog. */
  timeout = 1000;
  for (i = 0; i &lt; CUBEB_STREAM_MAX; ++i) {
    stm = ctx-&gt;streams[i];
    if (stm &amp;&amp; stm-&gt;state == DRAINING) {
      r = ms_until(&amp;stm-&gt;drain_timeout);
      if (r &lt; 0) {
        r = 0;
      }
      if (timeout &gt; r) {
        timeout = r;
      }
    }
  }

  pthread_mutex_unlock(&amp;ctx-&gt;mutex);
  r = poll(ctx-&gt;fds, ctx-&gt;nfds, timeout);
  pthread_mutex_lock(&amp;ctx-&gt;mutex);

  if (r &gt; 0) {
    if (ctx-&gt;fds[0].revents &amp; POLLIN) {
      if (read(ctx-&gt;control_fd_read, &amp;dummy, 1) &lt; 0) {
        /* ignore read error */
      }

      if (ctx-&gt;shutdown) {
        pthread_mutex_unlock(&amp;ctx-&gt;mutex);
        return -1;
      }
    }

    for (i = 0; i &lt; CUBEB_STREAM_MAX; ++i) {
      stm = ctx-&gt;streams[i];
      /* We can&#039;t use snd_pcm_poll_descriptors_revents here because of
         https://github.com/kinetiknz/cubeb/issues/135. */
      if (stm &amp;&amp; stm-&gt;state == RUNNING &amp;&amp; stm-&gt;fds &amp;&amp;
          any_revents(stm-&gt;fds, stm-&gt;nfds)) {
        int other_stream_running =
            !stm-&gt;other_stream || stm-&gt;other_stream-&gt;state == RUNNING;
        alsa_set_stream_state(stm, PROCESSING);
        pthread_mutex_unlock(&amp;ctx-&gt;mutex);
        state = alsa_process_stream(stm, other_stream_running);
        pthread_mutex_lock(&amp;ctx-&gt;mutex);
        if (state == DRAINING) {
          alsa_set_draining(stm);
        } else if (state == INACTIVE) {
          alsa_set_stream_state(stm, state);
          stm-&gt;state_callback(stm, stm-&gt;user_ptr, CUBEB_STATE_STOPPED);
        } else {
          alsa_set_stream_state(stm, state);
        }
      }
    }
  } else if (r == 0) {
    for (i = 0; i &lt; CUBEB_STREAM_MAX; ++i) {
      stm = ctx-&gt;streams[i];
      if (stm) {
        if (stm-&gt;state == DRAINING &amp;&amp; ms_since(&amp;stm-&gt;drain_timeout) &gt;= 0) {
          alsa_set_stream_state(stm, INACTIVE);
          if (!stm-&gt;other_stream ||
              stm-&gt;stream_type == SND_PCM_STREAM_PLAYBACK) {
            stm-&gt;state_callback(stm, stm-&gt;user_ptr, CUBEB_STATE_DRAINED);
          }
        } else if (stm-&gt;state == RUNNING &amp;&amp;
                   ms_since(&amp;stm-&gt;last_activity) &gt; CUBEB_WATCHDOG_MS) {
          alsa_set_stream_state(stm, ERROR);
          stm-&gt;state_callback(stm, stm-&gt;user_ptr, CUBEB_STATE_ERROR);
        }
      }
    }
  }

  pthread_mutex_unlock(&amp;ctx-&gt;mutex);

  return 0;
}

static void *
alsa_run_thread(void * context)
{
  cubeb * ctx = context;
  int r;

  CUBEB_REGISTER_THREAD(&quot;cubeb rendering thread&quot;);

  do {
    r = alsa_run(ctx);
  } while (r &gt;= 0);

  CUBEB_UNREGISTER_THREAD();

  return NULL;
}

static snd_config_t *
get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm)
{
  int r;
  snd_config_t * slave_pcm;
  snd_config_t * slave_def;
  snd_config_t * pcm;
  char const * string;
  char node_name[64];

  slave_def = NULL;

  r = WRAP(snd_config_search)(root_pcm, &quot;slave&quot;, &amp;slave_pcm);
  if (r &lt; 0) {
    return NULL;
  }

  r = WRAP(snd_config_get_string)(slave_pcm, &amp;string);
  if (r &gt;= 0) {
    r = WRAP(snd_config_search_definition)(lconf, &quot;pcm_slave&quot;, string,
                                           &amp;slave_def);
    if (r &lt; 0) {
      return NULL;
    }
  }

  do {
    r = WRAP(snd_config_search)(slave_def ? slave_def : slave_pcm, &quot;pcm&quot;, &amp;pcm);
    if (r &lt; 0) {
      break;
    }

    r = WRAP(snd_config_get_string)(slave_def ? slave_def : slave_pcm, &amp;string);
    if (r &lt; 0) {
      break;
    }

    r = snprintf(node_name, sizeof(node_name), &quot;pcm.%s&quot;, string);
    if (r &lt; 0 || r &gt; (int)sizeof(node_name)) {
      break;
    }
    r = WRAP(snd_config_search)(lconf, node_name, &amp;pcm);
    if (r &lt; 0) {
      break;
    }

    return pcm;
  } while (0);

  if (slave_def) {
    WRAP(snd_config_delete)(slave_def);
  }

  return NULL;
}

/* Work around PulseAudio ALSA plugin bug where the PA server forces a
   higher than requested latency, but the plugin does not update its (and
   ALSA&#039;s) internal state to reflect that, leading to an immediate underrun
   situation.  Inspired by WINE&#039;s make_handle_underrun_config.
   Reference: http://mailman.alsa-project.org/pipermail/alsa-devel/2012-July/05
 */
static snd_config_t *
init_local_config_with_workaround(char const * pcm_name)
{
  int r;
  snd_config_t * lconf;
  snd_config_t * pcm_node;
  snd_config_t * node;
  char const * string;
  char node_name[64];

  lconf = NULL;

  if (WRAP(snd_config) == NULL) {
    return NULL;
  }

  r = WRAP(snd_config_copy)(&amp;lconf, WRAP(snd_config));
  if (r &lt; 0) {
    return NULL;
  }

  do {
    r = WRAP(snd_config_search_definition)(lconf, &quot;pcm&quot;, pcm_name, &amp;pcm_node);
    if (r &lt; 0) {
      break;
    }

    r = WRAP(snd_config_get_id)(pcm_node, &amp;string);
    if (r &lt; 0) {
      break;
    }

    r = snprintf(node_name, sizeof(node_name), &quot;pcm.%s&quot;, string);
    if (r &lt; 0 || r &gt; (int)sizeof(node_name)) {
      break;
    }
    r = WRAP(snd_config_search)(lconf, node_name, &amp;pcm_node);
    if (r &lt; 0) {
      break;
    }

    /* If this PCM has a slave, walk the slave configurations until we reach the
     * bottom. */
    while ((node = get_slave_pcm_node(lconf, pcm_node)) != NULL) {
      pcm_node = node;
    }

    /* Fetch the PCM node&#039;s type, and bail out if it&#039;s not the PulseAudio
     * plugin. */
    r = WRAP(snd_config_search)(pcm_node, &quot;type&quot;, &amp;node);
    if (r &lt; 0) {
      break;
    }

    r = WRAP(snd_config_get_string)(node, &amp;string);
    if (r &lt; 0) {
      break;
    }

    if (strcmp(string, &quot;pulse&quot;) != 0) {
      break;
    }

    /* Don&#039;t clobber an explicit existing handle_underrun value, set it only
       if it doesn&#039;t already exist. */
    r = WRAP(snd_config_search)(pcm_node, &quot;handle_underrun&quot;, &amp;node);
    if (r != -ENOENT) {
      break;
    }

    /* Disable pcm_pulse&#039;s asynchronous underrun handling. */
    r = WRAP(snd_config_imake_integer)(&amp;node, &quot;handle_underrun&quot;, 0);
    if (r &lt; 0) {
      break;
    }

    r = WRAP(snd_config_add)(pcm_node, node);
    if (r &lt; 0) {
      break;
    }

    return lconf;
  } while (0);

  WRAP(snd_config_delete)(lconf);

  return NULL;
}

static int
alsa_locked_pcm_open(snd_pcm_t ** pcm, char const * pcm_name,
                     snd_pcm_stream_t stream, snd_config_t * local_config)
{
  int r;

  pthread_mutex_lock(&amp;cubeb_alsa_mutex);
  if (local_config) {
    r = WRAP(snd_pcm_open_lconf)(pcm, pcm_name, stream, SND_PCM_NONBLOCK,
                                 local_config);
  } else {
    r = WRAP(snd_pcm_open)(pcm, pcm_name, stream, SND_PCM_NONBLOCK);
  }
  pthread_mutex_unlock(&amp;cubeb_alsa_mutex);

  return r;
}

static int
alsa_locked_pcm_close(snd_pcm_t * pcm)
{
  int r;

  pthread_mutex_lock(&amp;cubeb_alsa_mutex);
  r = WRAP(snd_pcm_close)(pcm);
  pthread_mutex_unlock(&amp;cubeb_alsa_mutex);

  return r;
}

static int
alsa_register_stream(cubeb * ctx, cubeb_stream * stm)
{
  int i;

  pthread_mutex_lock(&amp;ctx-&gt;mutex);
  for (i = 0; i &lt; CUBEB_STREAM_MAX; ++i) {
    if (!ctx-&gt;streams[i]) {
      ctx-&gt;streams[i] = stm;
      break;
    }
  }
  pthread_mutex_unlock(&amp;ctx-&gt;mutex);

  return i == CUBEB_STREAM_MAX;
}

static void
alsa_unregister_stream(cubeb_stream * stm)
{
  cubeb * ctx;
  int i;

  ctx = stm-&gt;context;

  pthread_mutex_lock(&amp;ctx-&gt;mutex);
  for (i = 0; i &lt; CUBEB_STREAM_MAX; ++i) {
    if (ctx-&gt;streams[i] == stm) {
      ctx-&gt;streams[i] = NULL;
      break;
    }
  }
  pthread_mutex_unlock(&amp;ctx-&gt;mutex);
}

static void
silent_error_handler(char const * file, int line, char const * function,
                     int err, char const * fmt, ...)
{
  (void)file;
  (void)line;
  (void)function;
  (void)err;
  (void)fmt;
}

/*static*/ int
alsa_init(cubeb ** context, char const * context_name)
{
  (void)context_name;
  void * libasound = NULL;
  cubeb * ctx;
  int r;
  int i;
  int fd[2];
  pthread_attr_t attr;
  snd_pcm_t * dummy;

  assert(context);
  *context = NULL;

#ifndef DISABLE_LIBASOUND_DLOPEN
  libasound = dlopen(&quot;libasound.so.2&quot;, RTLD_LAZY);
  if (!libasound) {
    libasound = dlopen(&quot;libasound.so&quot;, RTLD_LAZY);
    if (!libasound) {
      return CUBEB_ERROR;
    }
  }

#define LOAD(x)                                                                \
  {                                                                            \
    cubeb_##x = dlsym(libasound, #x);                                          \
    if (!cubeb_##x) {                                                          \
      dlclose(libasound);                                                      \
      return CUBEB_ERROR;                                                      \
    }                                                                          \
  }

  LIBASOUND_API_VISIT(LOAD);
#undef LOAD
#endif

  pthread_mutex_lock(&amp;cubeb_alsa_mutex);
  if (!cubeb_alsa_error_handler_set) {
    WRAP(snd_lib_error_set_handler)(silent_error_handler);
    cubeb_alsa_error_handler_set = 1;
  }
  pthread_mutex_unlock(&amp;cubeb_alsa_mutex);

  ctx = calloc(1, sizeof(*ctx));
  assert(ctx);

  ctx-&gt;ops = &amp;alsa_ops;
  ctx-&gt;libasound = libasound;

  r = pthread_mutex_init(&amp;ctx-&gt;mutex, NULL);
  assert(r == 0);

  r = pipe(fd);
  assert(r == 0);

  for (i = 0; i &lt; 2; ++i) {
    fcntl(fd[i], F_SETFD, fcntl(fd[i], F_GETFD) | FD_CLOEXEC);
    fcntl(fd[i], F_SETFL, fcntl(fd[i], F_GETFL) | O_NONBLOCK);
  }

  ctx-&gt;control_fd_read = fd[0];
  ctx-&gt;control_fd_write = fd[1];

  /* Force an early rebuild when alsa_run is first called to ensure fds and
     nfds have been initialized. */
  ctx-&gt;rebuild = 1;

  r = pthread_attr_init(&amp;attr);
  assert(r == 0);

  r = pthread_attr_setstacksize(&amp;attr, 256 * 1024);
  assert(r == 0);

  r = pthread_create(&amp;ctx-&gt;thread, &amp;attr, alsa_run_thread, ctx);
  assert(r == 0);

  r = pthread_attr_destroy(&amp;attr);
  assert(r == 0);

  /* Open a dummy PCM to force the configuration space to be evaluated so that
     init_local_config_with_workaround can find and modify the default node. */
  r = alsa_locked_pcm_open(&amp;dummy, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK,
                           NULL);
  if (r &gt;= 0) {
    alsa_locked_pcm_close(dummy);
  }
  ctx-&gt;is_pa = 0;
  pthread_mutex_lock(&amp;cubeb_alsa_mutex);
  ctx-&gt;local_config = init_local_config_with_workaround(CUBEB_ALSA_PCM_NAME);
  pthread_mutex_unlock(&amp;cubeb_alsa_mutex);
  if (ctx-&gt;local_config) {
    ctx-&gt;is_pa = 1;
    r = alsa_locked_pcm_open(&amp;dummy, CUBEB_ALSA_PCM_NAME,
                             SND_PCM_STREAM_PLAYBACK, ctx-&gt;local_config);
    /* If we got a local_config, we found a PA PCM.  If opening a PCM with that
       config fails with EINVAL, the PA PCM is too old for this workaround. */
    if (r == -EINVAL) {
      pthread_mutex_lock(&amp;cubeb_alsa_mutex);
      WRAP(snd_config_delete)(ctx-&gt;local_config);
      pthread_mutex_unlock(&amp;cubeb_alsa_mutex);
      ctx-&gt;local_config = NULL;
    } else if (r &gt;= 0) {
      alsa_locked_pcm_close(dummy);
    }
  }

  *context = ctx;

  return CUBEB_OK;
}

static char const *
alsa_get_backend_id(cubeb * ctx)
{
  (void)ctx;
  return &quot;alsa&quot;;
}

static void
alsa_destroy(cubeb * ctx)
{
  int r;

  assert(ctx);

  pthread_mutex_lock(&amp;ctx-&gt;mutex);
  ctx-&gt;shutdown = 1;
  poll_wake(ctx);
  pthread_mutex_unlock(&amp;ctx-&gt;mutex);

  r = pthread_join(ctx-&gt;thread, NULL);
  assert(r == 0);

  close(ctx-&gt;control_fd_read);
  close(ctx-&gt;control_fd_write);
  pthread_mutex_destroy(&amp;ctx-&gt;mutex);
  free(ctx-&gt;fds);

  if (ctx-&gt;local_config) {
    pthread_mutex_lock(&amp;cubeb_alsa_mutex);
    WRAP(snd_config_delete)(ctx-&gt;local_config);
    pthread_mutex_unlock(&amp;cubeb_alsa_mutex);
  }
#ifndef DISABLE_LIBASOUND_DLOPEN
  if (ctx-&gt;libasound) {
    dlclose(ctx-&gt;libasound);
  }
#endif
  free(ctx);
}

static void
alsa_stream_destroy(cubeb_stream * stm);

static int
alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream,
                        char const * stream_name, snd_pcm_stream_t stream_type,
                        cubeb_devid deviceid,
                        cubeb_stream_params * stream_params,
                        unsigned int latency_frames,
                        cubeb_data_callback data_callback,
                        cubeb_state_callback state_callback, void * user_ptr)
{
  (void)stream_name;
  cubeb_stream * stm;
  int r;
  snd_pcm_format_t format;
  snd_pcm_uframes_t period_size;
  int latency_us = 0;
  char const * pcm_name =
      deviceid ? (char const *)deviceid : CUBEB_ALSA_PCM_NAME;

  assert(ctx &amp;&amp; stream);

  *stream = NULL;

  if (stream_params-&gt;prefs &amp; CUBEB_STREAM_PREF_LOOPBACK) {
    return CUBEB_ERROR_NOT_SUPPORTED;
  }

  switch (stream_params-&gt;format) {
  case CUBEB_SAMPLE_S16LE:
    format = SND_PCM_FORMAT_S16_LE;
    break;
  case CUBEB_SAMPLE_S16BE:
    format = SND_PCM_FORMAT_S16_BE;
    break;
  case CUBEB_SAMPLE_FLOAT32LE:
    format = SND_PCM_FORMAT_FLOAT_LE;
    break;
  case CUBEB_SAMPLE_FLOAT32BE:
    format = SND_PCM_FORMAT_FLOAT_BE;
    break;
  default:
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  pthread_mutex_lock(&amp;ctx-&gt;mutex);
  if (ctx-&gt;active_streams &gt;= CUBEB_STREAM_MAX) {
    pthread_mutex_unlock(&amp;ctx-&gt;mutex);
    return CUBEB_ERROR;
  }
  ctx-&gt;active_streams += 1;
  pthread_mutex_unlock(&amp;ctx-&gt;mutex);

  stm = calloc(1, sizeof(*stm));
  assert(stm);

  stm-&gt;context = ctx;
  stm-&gt;data_callback = data_callback;
  stm-&gt;state_callback = state_callback;
  stm-&gt;user_ptr = user_ptr;
  stm-&gt;params = *stream_params;
  stm-&gt;state = INACTIVE;
  stm-&gt;volume = 1.0;
  stm-&gt;buffer = NULL;
  stm-&gt;bufframes = 0;
  stm-&gt;stream_type = stream_type;
  stm-&gt;other_stream = NULL;

  r = pthread_mutex_init(&amp;stm-&gt;mutex, NULL);
  assert(r == 0);

  r = pthread_cond_init(&amp;stm-&gt;cond, NULL);
  assert(r == 0);

  r = alsa_locked_pcm_open(&amp;stm-&gt;pcm, pcm_name, stm-&gt;stream_type,
                           ctx-&gt;local_config);
  if (r &lt; 0) {
    alsa_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  r = WRAP(snd_pcm_nonblock)(stm-&gt;pcm, 1);
  assert(r == 0);

  latency_us = latency_frames * 1e6 / stm-&gt;params.rate;

  /* Ugly hack: the PA ALSA plugin allows buffer configurations that can&#039;t
     possibly work.  See https://bugzilla.mozilla.org/show_bug.cgi?id=761274.
     Only resort to this hack if the handle_underrun workaround failed. */
  if (!ctx-&gt;local_config &amp;&amp; ctx-&gt;is_pa) {
    const int min_latency = 5e5;
    latency_us = latency_us &lt; min_latency ? min_latency : latency_us;
  }

  r = WRAP(snd_pcm_set_params)(stm-&gt;pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED,
                               stm-&gt;params.channels, stm-&gt;params.rate, 1,
                               latency_us);
  if (r &lt; 0) {
    alsa_stream_destroy(stm);
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  r = WRAP(snd_pcm_get_params)(stm-&gt;pcm, &amp;stm-&gt;buffer_size, &amp;period_size);
  assert(r == 0);

  /* Double internal buffer size to have enough space when waiting for the other
   * side of duplex connection */
  stm-&gt;buffer_size *= 2;
  stm-&gt;buffer =
      calloc(1, WRAP(snd_pcm_frames_to_bytes)(stm-&gt;pcm, stm-&gt;buffer_size));
  assert(stm-&gt;buffer);

  stm-&gt;nfds = WRAP(snd_pcm_poll_descriptors_count)(stm-&gt;pcm);
  assert(stm-&gt;nfds &gt; 0);

  stm-&gt;saved_fds = calloc(stm-&gt;nfds, sizeof(struct pollfd));
  assert(stm-&gt;saved_fds);
  r = WRAP(snd_pcm_poll_descriptors)(stm-&gt;pcm, stm-&gt;saved_fds, stm-&gt;nfds);
  assert((nfds_t)r == stm-&gt;nfds);

  if (alsa_register_stream(ctx, stm) != 0) {
    alsa_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  *stream = stm;

  return CUBEB_OK;
}

static int
alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
                 cubeb_devid input_device,
                 cubeb_stream_params * input_stream_params,
                 cubeb_devid output_device,
                 cubeb_stream_params * output_stream_params,
                 unsigned int latency_frames, cubeb_data_callback data_callback,
                 cubeb_state_callback state_callback, void * user_ptr)
{
  int result = CUBEB_OK;
  cubeb_stream *instm = NULL, *outstm = NULL;

  if (result == CUBEB_OK &amp;&amp; input_stream_params) {
    result = alsa_stream_init_single(ctx, &amp;instm, stream_name,
                                     SND_PCM_STREAM_CAPTURE, input_device,
                                     input_stream_params, latency_frames,
                                     data_callback, state_callback, user_ptr);
  }

  if (result == CUBEB_OK &amp;&amp; output_stream_params) {
    result = alsa_stream_init_single(ctx, &amp;outstm, stream_name,
                                     SND_PCM_STREAM_PLAYBACK, output_device,
                                     output_stream_params, latency_frames,
                                     data_callback, state_callback, user_ptr);
  }

  if (result == CUBEB_OK &amp;&amp; input_stream_params &amp;&amp; output_stream_params) {
    instm-&gt;other_stream = outstm;
    outstm-&gt;other_stream = instm;
  }

  if (result != CUBEB_OK &amp;&amp; instm) {
    alsa_stream_destroy(instm);
  }

  *stream = outstm ? outstm : instm;

  return result;
}

static void
alsa_stream_destroy(cubeb_stream * stm)
{
  int r;
  cubeb * ctx;

  assert(stm &amp;&amp; (stm-&gt;state == INACTIVE || stm-&gt;state == ERROR ||
                 stm-&gt;state == DRAINING));

  ctx = stm-&gt;context;

  if (stm-&gt;other_stream) {
    stm-&gt;other_stream-&gt;other_stream = NULL; // to stop infinite recursion
    alsa_stream_destroy(stm-&gt;other_stream);
  }

  pthread_mutex_lock(&amp;stm-&gt;mutex);
  if (stm-&gt;pcm) {
    if (stm-&gt;state == DRAINING) {
      WRAP(snd_pcm_drain)(stm-&gt;pcm);
    }
    alsa_locked_pcm_close(stm-&gt;pcm);
    stm-&gt;pcm = NULL;
  }
  free(stm-&gt;saved_fds);
  pthread_mutex_unlock(&amp;stm-&gt;mutex);
  pthread_mutex_destroy(&amp;stm-&gt;mutex);

  r = pthread_cond_destroy(&amp;stm-&gt;cond);
  assert(r == 0);

  alsa_unregister_stream(stm);

  pthread_mutex_lock(&amp;ctx-&gt;mutex);
  assert(ctx-&gt;active_streams &gt;= 1);
  ctx-&gt;active_streams -= 1;
  pthread_mutex_unlock(&amp;ctx-&gt;mutex);

  free(stm-&gt;buffer);

  free(stm);
}

static int
alsa_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
{
  int r;
  cubeb_stream * stm;
  snd_pcm_hw_params_t * hw_params;
  cubeb_stream_params params;
  params.rate = 44100;
  params.format = CUBEB_SAMPLE_FLOAT32NE;
  params.channels = 2;

  snd_pcm_hw_params_alloca(&amp;hw_params);

  assert(ctx);

  r = alsa_stream_init(ctx, &amp;stm, &quot;&quot;, NULL, NULL, NULL, &amp;params, 100, NULL,
                       NULL, NULL);
  if (r != CUBEB_OK) {
    return CUBEB_ERROR;
  }

  assert(stm);

  r = WRAP(snd_pcm_hw_params_any)(stm-&gt;pcm, hw_params);
  if (r &lt; 0) {
    return CUBEB_ERROR;
  }

  r = WRAP(snd_pcm_hw_params_get_channels_max)(hw_params, max_channels);
  if (r &lt; 0) {
    return CUBEB_ERROR;
  }

  /* Cap at reasonable maximum to filter driver placeholder values */  
  if (*max_channels &gt; 64) {  
    *max_channels = 64;  
  }  

  alsa_stream_destroy(stm);

  return CUBEB_OK;
}

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(&amp;hw_params);

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

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

  r = WRAP(snd_pcm_hw_params_get_rate)(hw_params, rate, &amp;dir);
  if (r &gt;= 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 &lt; 0) {
    WRAP(snd_pcm_close)(pcm);
    return CUBEB_ERROR;
  }

  WRAP(snd_pcm_close)(pcm);

  return CUBEB_OK;
}

static int
alsa_get_min_latency(cubeb * ctx, cubeb_stream_params params,
                     uint32_t * latency_frames)
{
  (void)ctx;
  /* 40ms is found to be an acceptable minimum, even on a super low-end
   * machine. */
  *latency_frames = 40 * params.rate / 1000;

  return CUBEB_OK;
}

static int
alsa_stream_start(cubeb_stream * stm)
{
  cubeb * ctx;

  assert(stm);
  ctx = stm-&gt;context;

  if (stm-&gt;stream_type == SND_PCM_STREAM_PLAYBACK &amp;&amp; stm-&gt;other_stream) {
    int r = alsa_stream_start(stm-&gt;other_stream);
    if (r != CUBEB_OK)
      return r;
  }

  pthread_mutex_lock(&amp;stm-&gt;mutex);
  /* Capture pcm must be started after initial setup/recover */
  if (stm-&gt;stream_type == SND_PCM_STREAM_CAPTURE &amp;&amp;
      WRAP(snd_pcm_state)(stm-&gt;pcm) == SND_PCM_STATE_PREPARED) {
    WRAP(snd_pcm_start)(stm-&gt;pcm);
  }
  WRAP(snd_pcm_pause)(stm-&gt;pcm, 0);
  gettimeofday(&amp;stm-&gt;last_activity, NULL);
  pthread_mutex_unlock(&amp;stm-&gt;mutex);

  pthread_mutex_lock(&amp;ctx-&gt;mutex);
  if (stm-&gt;state != INACTIVE) {
    pthread_mutex_unlock(&amp;ctx-&gt;mutex);
    return CUBEB_ERROR;
  }
  alsa_set_stream_state(stm, RUNNING);
  pthread_mutex_unlock(&amp;ctx-&gt;mutex);

  return CUBEB_OK;
}

static int
alsa_stream_stop(cubeb_stream * stm)
{
  cubeb * ctx;
  int r;

  assert(stm);
  ctx = stm-&gt;context;

  if (stm-&gt;stream_type == SND_PCM_STREAM_PLAYBACK &amp;&amp; stm-&gt;other_stream) {
    int r = alsa_stream_stop(stm-&gt;other_stream);
    if (r != CUBEB_OK)
      return r;
  }

  pthread_mutex_lock(&amp;ctx-&gt;mutex);
  while (stm-&gt;state == PROCESSING) {
    r = pthread_cond_wait(&amp;stm-&gt;cond, &amp;ctx-&gt;mutex);
    assert(r == 0);
  }

  alsa_set_stream_state(stm, INACTIVE);
  pthread_mutex_unlock(&amp;ctx-&gt;mutex);

  pthread_mutex_lock(&amp;stm-&gt;mutex);
  WRAP(snd_pcm_pause)(stm-&gt;pcm, 1);
  pthread_mutex_unlock(&amp;stm-&gt;mutex);

  return CUBEB_OK;
}

static int
alsa_stream_get_position(cubeb_stream * stm, uint64_t * position)
{
  snd_pcm_sframes_t delay;

  assert(stm &amp;&amp; position);

  pthread_mutex_lock(&amp;stm-&gt;mutex);

  delay = -1;
  if (WRAP(snd_pcm_state)(stm-&gt;pcm) != SND_PCM_STATE_RUNNING ||
      WRAP(snd_pcm_delay)(stm-&gt;pcm, &amp;delay) != 0) {
    *position = stm-&gt;last_position;
    pthread_mutex_unlock(&amp;stm-&gt;mutex);
    return CUBEB_OK;
  }

  assert(delay &gt;= 0);

  *position = 0;
  if (stm-&gt;stream_position &gt;= (snd_pcm_uframes_t)delay) {
    *position = stm-&gt;stream_position - delay;
  }

  stm-&gt;last_position = *position;

  pthread_mutex_unlock(&amp;stm-&gt;mutex);
  return CUBEB_OK;
}

static int
alsa_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
{
  snd_pcm_sframes_t delay;
  /* This function returns the delay in frames until a frame written using
     snd_pcm_writei is sent to the DAC. The DAC delay should be &lt; 1ms anyways.
   */
  if (WRAP(snd_pcm_delay)(stm-&gt;pcm, &amp;delay)) {
    return CUBEB_ERROR;
  }

  *latency = delay;

  return CUBEB_OK;
}

static int
alsa_stream_set_volume(cubeb_stream * stm, float volume)
{
  /* setting the volume using an API call does not seem very stable/supported */
  pthread_mutex_lock(&amp;stm-&gt;mutex);
  stm-&gt;volume = volume;
  pthread_mutex_unlock(&amp;stm-&gt;mutex);

  return CUBEB_OK;
}

static int
alsa_enumerate_devices(cubeb * context, cubeb_device_type type,
                       cubeb_device_collection * collection)
{
  void **hints = NULL;
  void **hint;
  char *name = NULL;
  char *io = NULL;
  char *desc = NULL;
  cubeb_device_info * devinfop = NULL;
  int collection_cnt = 0;
  int r;

  if (!context)
    return CUBEB_ERROR;

  /* Get device name hints from ALSA */
  r = WRAP(snd_device_name_hint)(-1, &quot;pcm&quot;, &amp;hints);
  if (r &lt; 0) {
    LOG(&quot;Failed to get device name hints: %d&quot;, r);
    return CUBEB_ERROR;
  }

  /* Count devices first */
  for (hint = hints; *hint != NULL; hint++) {
    name = WRAP(snd_device_name_get_hint)(*hint, &quot;NAME&quot;);
    if (!name)
      continue;

    io = WRAP(snd_device_name_get_hint)(*hint, &quot;IOID&quot;);

    /* Filter by device type */
    if (type &amp; CUBEB_DEVICE_TYPE_INPUT &amp;&amp; io &amp;&amp; strcmp(io, &quot;Output&quot;) == 0) {
      free(name);
      if (io) free(io);
      continue;
    }
    if (type &amp; CUBEB_DEVICE_TYPE_OUTPUT &amp;&amp; io &amp;&amp; strcmp(io, &quot;Input&quot;) == 0) {
      free(name);
      if (io) free(io);
      continue;
    }

    free(name);
    if (io) free(io);
    collection_cnt++;
  }

  if (collection_cnt == 0) {
    WRAP(snd_device_name_free_hint)(hints);
    return CUBEB_OK;
  }

  devinfop = calloc(collection_cnt, sizeof(cubeb_device_info));
  if (!devinfop) {
    WRAP(snd_device_name_free_hint)(hints);
    return CUBEB_ERROR;
  }

  collection_cnt = 0;
  for (hint = hints; *hint != NULL; hint++) {
    snd_pcm_t * pcm = NULL;
    snd_pcm_hw_params_t * hw_params;
    snd_pcm_stream_t stream_type;
    cubeb_device_info cdi = {0};
    uint32_t min_rate, max_rate;
    uint32_t min_channels, max_channels;
    int dir;

    name = WRAP(snd_device_name_get_hint)(*hint, &quot;NAME&quot;);
    if (!name)
      continue;

    io = WRAP(snd_device_name_get_hint)(*hint, &quot;IOID&quot;);
    desc = WRAP(snd_device_name_get_hint)(*hint, &quot;DESC&quot;);

    /* Filter by device type */
    if (type &amp; CUBEB_DEVICE_TYPE_INPUT &amp;&amp; io &amp;&amp; strcmp(io, &quot;Output&quot;) == 0) {
      goto cleanup_hint;
    }
    if (type &amp; CUBEB_DEVICE_TYPE_OUTPUT &amp;&amp; io &amp;&amp; strcmp(io, &quot;Input&quot;) == 0) {
      goto cleanup_hint;
    }

    /* Determine stream type */
    if (io &amp;&amp; strcmp(io, &quot;Input&quot;) == 0) {
      stream_type = SND_PCM_STREAM_CAPTURE;
      cdi.type = CUBEB_DEVICE_TYPE_INPUT;
    } else if (io &amp;&amp; strcmp(io, &quot;Output&quot;) == 0) {
      stream_type = SND_PCM_STREAM_PLAYBACK;
      cdi.type = CUBEB_DEVICE_TYPE_OUTPUT;
    } else {
      /* Try both if IOID is not specified */
      stream_type = (type &amp; CUBEB_DEVICE_TYPE_OUTPUT) ? 
                     SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE;
      cdi.type = (type &amp; CUBEB_DEVICE_TYPE_OUTPUT) ? 
                 CUBEB_DEVICE_TYPE_OUTPUT : CUBEB_DEVICE_TYPE_INPUT;
    }

    /* Open device to query capabilities */
    r = WRAP(snd_pcm_open)(&amp;pcm, name, stream_type, SND_PCM_NONBLOCK);
    if (r &lt; 0) {
      LOG(&quot;Failed to open device %s: %d&quot;, name, r);
      goto cleanup_hint;
    }

    snd_pcm_hw_params_alloca(&amp;hw_params);
    r = WRAP(snd_pcm_hw_params_any)(pcm, hw_params);
    if (r &lt; 0) {
      LOG(&quot;Failed to get hw params for device %s: %d&quot;, name, r);
      WRAP(snd_pcm_close)(pcm);
      goto cleanup_hint;
    }

    /* Query format capabilities */
    cdi.format = 0;
    if (WRAP(snd_pcm_hw_params_test_format)(pcm, hw_params, SND_PCM_FORMAT_S16_LE) == 0)
      cdi.format |= CUBEB_DEVICE_FMT_S16LE;
    if (WRAP(snd_pcm_hw_params_test_format)(pcm, hw_params, SND_PCM_FORMAT_S16_BE) == 0)
      cdi.format |= CUBEB_DEVICE_FMT_S16BE;
    if (WRAP(snd_pcm_hw_params_test_format)(pcm, hw_params, SND_PCM_FORMAT_S32_LE) == 0)
      cdi.format |= CUBEB_DEVICE_FMT_S32LE;
    if (WRAP(snd_pcm_hw_params_test_format)(pcm, hw_params, SND_PCM_FORMAT_S32_BE) == 0)
      cdi.format |= CUBEB_DEVICE_FMT_S32BE;
    if (WRAP(snd_pcm_hw_params_test_format)(pcm, hw_params, SND_PCM_FORMAT_FLOAT_LE) == 0)
      cdi.format |= CUBEB_DEVICE_FMT_F32LE;
    if (WRAP(snd_pcm_hw_params_test_format)(pcm, hw_params, SND_PCM_FORMAT_FLOAT_BE) == 0)
      cdi.format |= CUBEB_DEVICE_FMT_F32BE;

    /* Set default format - prefer S32 for high-quality audio */
#if defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__)
    if (cdi.format &amp; CUBEB_DEVICE_FMT_S32BE)
      cdi.default_format = CUBEB_DEVICE_FMT_S32BE;
    else if (cdi.format &amp; CUBEB_DEVICE_FMT_S16BE)
      cdi.default_format = CUBEB_DEVICE_FMT_S16BE;
    else if (cdi.format &amp; CUBEB_DEVICE_FMT_F32BE)
      cdi.default_format = CUBEB_DEVICE_FMT_F32BE;
    else
      cdi.default_format = CUBEB_DEVICE_FMT_S16BE;
#else
    if (cdi.format &amp; CUBEB_DEVICE_FMT_S32LE)
      cdi.default_format = CUBEB_DEVICE_FMT_S32LE;
    else if (cdi.format &amp; CUBEB_DEVICE_FMT_S16LE)
      cdi.default_format = CUBEB_DEVICE_FMT_S16LE;
    else if (cdi.format &amp; CUBEB_DEVICE_FMT_F32LE)
      cdi.default_format = CUBEB_DEVICE_FMT_F32LE;
    else
      cdi.default_format = CUBEB_DEVICE_FMT_S16LE;
#endif

    /* Query rate range */
    r = WRAP(snd_pcm_hw_params_get_rate_min)(hw_params, &amp;min_rate, &amp;dir);
    if (r &lt; 0)
      min_rate = 44100;
    r = WRAP(snd_pcm_hw_params_get_rate_max)(hw_params, &amp;max_rate, &amp;dir);
    if (r &lt; 0)
      max_rate = 48000;

    /* Query channel range */
    r = WRAP(snd_pcm_hw_params_get_channels_min)(hw_params, &amp;min_channels);
    if (r &lt; 0)
      min_channels = 1;
    r = WRAP(snd_pcm_hw_params_get_channels_max)(hw_params, &amp;max_channels);
    if (r &lt; 0)
      max_channels = 2;

    /* Get default rate */
    r = WRAP(snd_pcm_hw_params_get_rate)(hw_params, &amp;cdi.default_rate, &amp;dir);
    if (r &lt; 0)
      cdi.default_rate = 44100;

    WRAP(snd_pcm_close)(pcm);

    /* Fill device info */
    cdi.device_id = strdup(name);
    cdi.devid = (cubeb_devid)cdi.device_id;
    cdi.friendly_name = desc ? strdup(desc) : strdup(name);
    cdi.group_id = strdup(name);
    cdi.vendor_name = NULL;
    cdi.state = CUBEB_DEVICE_STATE_ENABLED;
    cdi.preferred = CUBEB_DEVICE_PREF_NONE;
    cdi.max_channels = max_channels;
    cdi.min_rate = min_rate;
    cdi.max_rate = max_rate;
    cdi.latency_lo = 0;
    cdi.latency_hi = 0;

    if (!cdi.device_id || !cdi.friendly_name || !cdi.group_id) {
      free((void *)cdi.device_id);
      free((void *)cdi.friendly_name);
      free((void *)cdi.group_id);
      goto cleanup_hint;
    }

    devinfop[collection_cnt++] = cdi;

cleanup_hint:
    free(name);
    if (io) free(io);
    if (desc) free(desc);
  }

  WRAP(snd_device_name_free_hint)(hints);

  collection-&gt;device = devinfop;
  collection-&gt;count = collection_cnt;

  return CUBEB_OK;
}

static int  
alsa_device_collection_destroy(cubeb * context,  
                               cubeb_device_collection * collection)  
{  
  size_t i;  
  
  (void)context;  
  
  for (i = 0; i &lt; collection-&gt;count; ++i) {  
    free((void *)collection-&gt;device[i].device_id);  
    free((void *)collection-&gt;device[i].friendly_name);  
    free((void *)collection-&gt;device[i].group_id);  
    free((void *)collection-&gt;device[i].vendor_name);  
  }  
  free(collection-&gt;device);  
  return CUBEB_OK;  
}

static struct cubeb_ops const alsa_ops = {
    .init = alsa_init,
    .get_backend_id = alsa_get_backend_id,
    .get_max_channel_count = alsa_get_max_channel_count,
    .get_min_latency = alsa_get_min_latency,
    .get_preferred_sample_rate = alsa_get_preferred_sample_rate,
    .get_supported_input_processing_params = NULL,
    .enumerate_devices = alsa_enumerate_devices,
    .device_collection_destroy = alsa_device_collection_destroy,
    .destroy = alsa_destroy,
    .stream_init = alsa_stream_init,
    .stream_destroy = alsa_stream_destroy,
    .stream_start = alsa_stream_start,
    .stream_stop = alsa_stream_stop,
    .stream_get_position = alsa_stream_get_position,
    .stream_get_latency = alsa_stream_get_latency,
    .stream_get_input_latency = NULL,
    .stream_set_volume = alsa_stream_set_volume,
    .stream_set_name = NULL,
    .stream_get_current_device = NULL,
    .stream_set_input_mute = NULL,
    .stream_set_input_processing_params = NULL,
    .stream_device_destroy = NULL,
    .stream_register_device_changed_callback = NULL,
    .register_device_collection_changed = NULL};</code></pre></div><p><strong>Patches for Firefox</strong></p><div class="codebox"><pre class="vscroll"><code>$ cat 0001-Add-S32-format-to-the-Firefox-API.patch
From 80bbf447a62e6136f54c4938b99487135383276b Mon Sep 17 00:00:00 2001
From: Devuan
Date: Tue, 7 Jul 2026 22:35:36 +0200
Subject: [PATCH 1/2] Add S32 format to the Firefox API

- Add FMT_S32LE and FMT_S32BE constants to nsIAudioDeviceInfo.idl
- Update AudioDeviceInfo.cpp assertions to accept S32 formats
- Add S32 format conversion in CubebDeviceEnumerator.cpp
- Add local S32 format definitions for external cubeb support
- Update aboutSupport.js to display S32 format information
---
 dom/media/AudioDeviceInfo.cpp              |  5 +++--
 dom/media/CubebUtils.cpp                   |  1 +
 dom/media/nsIAudioDeviceInfo.idl           |  4 +++-
 dom/media/webrtc/CubebDeviceEnumerator.cpp | 14 ++++++++++++++
 toolkit/content/aboutSupport.js            |  4 ++++
 5 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/dom/media/AudioDeviceInfo.cpp b/dom/media/AudioDeviceInfo.cpp
index 072dd43d4ec1..a09e0adf71c3 100644
--- a/dom/media/AudioDeviceInfo.cpp
+++ b/dom/media/AudioDeviceInfo.cpp
@@ -49,10 +49,11 @@ AudioDeviceInfo::AudioDeviceInfo(
       mPreferred == PREF_NONE || mPreferred == PREF_ALL ||
           mPreferred &amp; (PREF_MULTIMEDIA | PREF_VOICE | PREF_NOTIFICATION),
       &quot;Wrong preferred value&quot;);
-  MOZ_ASSERT(mSupportedFormat &amp; (FMT_S16LE | FMT_S16BE | FMT_F32LE | FMT_F32BE),
+  MOZ_ASSERT(mSupportedFormat &amp; (FMT_S16LE | FMT_S16BE | FMT_F32LE | FMT_F32BE | FMT_S32LE | FMT_S32BE),
              &quot;Wrong supported format&quot;);
   MOZ_ASSERT(mDefaultFormat == FMT_S16LE || mDefaultFormat == FMT_S16BE ||
-                 mDefaultFormat == FMT_F32LE || mDefaultFormat == FMT_F32BE,
+                 mDefaultFormat == FMT_F32LE || mDefaultFormat == FMT_F32BE ||  
+                 mDefaultFormat == FMT_S32LE || mDefaultFormat == FMT_S32BE,  
              &quot;Wrong default format&quot;);
 }
 
diff --git a/dom/media/CubebUtils.cpp b/dom/media/CubebUtils.cpp
index 72551b795af3..a9edab7bc358 100644
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -143,6 +143,7 @@ MOZ_RUNINIT std::unordered_map&lt;std::string, BackendLabel&gt;
         {&quot;alsa&quot;, BackendLabel::eAlsa},
         {&quot;jack&quot;, BackendLabel::eJack},
         {&quot;oss&quot;, BackendLabel::eOss},
+        {&quot;oss-fft&quot;, BackendLabel::eOss},
         {&quot;pulse&quot;, BackendLabel::ePulse},
         {&quot;pulse-rust&quot;, BackendLabel::ePulseRust},
         {&quot;sndio&quot;, BackendLabel::eSndio},
diff --git a/dom/media/nsIAudioDeviceInfo.idl b/dom/media/nsIAudioDeviceInfo.idl
index 0458ec1eb927..59d90a0ad3f5 100644
--- a/dom/media/nsIAudioDeviceInfo.idl
+++ b/dom/media/nsIAudioDeviceInfo.idl
@@ -33,11 +33,13 @@ interface nsIAudioDeviceInfo : nsISupports
   const unsigned short PREF_ALL           = 0x0F;
   readonly attribute unsigned short preferred;
 
-  // supported format, default format: S16LE/S16BE/F32LE/F32BE
+  // supported format, default format: S16LE/S16BE/F32LE/F32BE/S32LE/S32BE
   const unsigned short FMT_S16LE = 0x0010;
   const unsigned short FMT_S16BE = 0x0020;
   const unsigned short FMT_F32LE = 0x1000;
   const unsigned short FMT_F32BE = 0x2000;
+  const unsigned short FMT_S32LE = 0x0040;
+  const unsigned short FMT_S32BE = 0x0080;
   readonly attribute unsigned short supportedFormat;
   readonly attribute unsigned short defaultFormat;
 
diff --git a/dom/media/webrtc/CubebDeviceEnumerator.cpp b/dom/media/webrtc/CubebDeviceEnumerator.cpp
index 6e1520c3c714..0d2043cb497c 100644
--- a/dom/media/webrtc/CubebDeviceEnumerator.cpp
+++ b/dom/media/webrtc/CubebDeviceEnumerator.cpp
@@ -17,6 +17,14 @@
 #  include &quot;mozilla/mscom/EnsureMTA.h&quot;
 #endif
 
+// S32 format constants for external cubeb libraries that support them  
+#ifndef CUBEB_DEVICE_FMT_S32LE  
+#define CUBEB_DEVICE_FMT_S32LE 0x0040  
+#endif  
+#ifndef CUBEB_DEVICE_FMT_S32BE  
+#define CUBEB_DEVICE_FMT_S32BE 0x0080  
+#endif
+
 namespace mozilla {
 
 using namespace CubebUtils;
@@ -183,6 +191,12 @@ static uint16_t ConvertCubebFormat(cubeb_device_fmt aFormat) {
   if (aFormat &amp; CUBEB_DEVICE_FMT_F32BE) {
     format |= nsIAudioDeviceInfo::FMT_F32BE;
   }
+  if (aFormat &amp; CUBEB_DEVICE_FMT_S32LE) {  
+    format |= nsIAudioDeviceInfo::FMT_S32LE;  
+  }  
+  if (aFormat &amp; CUBEB_DEVICE_FMT_S32BE) {  
+    format |= nsIAudioDeviceInfo::FMT_S32BE;  
+  }  
   return format;
 }
 
diff --git a/toolkit/content/aboutSupport.js b/toolkit/content/aboutSupport.js
index 388f8048201f..af6e396feb7d 100644
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -974,6 +974,8 @@ var snapshotFormatters = {
       formats[deviceInfo.FMT_S16BE] = &quot;S16BE&quot;;
       formats[deviceInfo.FMT_F32LE] = &quot;F32LE&quot;;
       formats[deviceInfo.FMT_F32BE] = &quot;F32BE&quot;;
+      formats[deviceInfo.FMT_S32LE] = &quot;S32LE&quot;;
+      formats[deviceInfo.FMT_S32BE] = &quot;S32BE&quot;;
 
       function toPreferredString(preferred) {
         if (preferred == deviceInfo.PREF_NONE) {
@@ -1001,6 +1003,8 @@ var snapshotFormatters = {
           deviceInfo.FMT_S16BE,
           deviceInfo.FMT_F32LE,
           deviceInfo.FMT_F32BE,
+          deviceInfo.FMT_S32LE,
+          deviceInfo.FMT_S32BE,
         ]) {
           if (dev.supportedFormat &amp; fmt) {
             str += &quot; &quot; + formats[fmt];
-- 
2.39.5</code></pre></div><div class="codebox"><pre class="vscroll"><code>$ cat 0002-Add-S32-format-to-the-Cubeb-API.patch
From f8d402971731b6729daf47624fe74a7e7466ee24 Mon Sep 17 00:00:00 2001
From: Devuan
Date: Thu, 9 Jul 2026 17:48:56 +0200
Subject: [PATCH 2/2] Add S32 format to the Cubeb API

- Add CUBEB_DEVICE_FMT_S32LE and CUBEB_DEVICE_FMT_S32BE constants to API
- Update log_device function to handle S32 formats in logging
- Update test_devices to handle S32 format display
---
 media/libcubeb/include/cubeb/cubeb.h | 17 ++++++++++++-----
 media/libcubeb/src/cubeb.c           | 23 +++++++++++++++++++++++
 media/libcubeb/test/test_devices.cpp | 10 ++++++++++
 3 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/media/libcubeb/include/cubeb/cubeb.h b/media/libcubeb/include/cubeb/cubeb.h
index ff2f8b7b987d..322230a2df11 100644
--- a/media/libcubeb/include/cubeb/cubeb.h
+++ b/media/libcubeb/include/cubeb/cubeb.h
@@ -340,6 +340,8 @@ typedef enum {
 typedef enum {
   CUBEB_DEVICE_FMT_S16LE = 0x0010, /**&lt; 16-bit integers, Little Endian. */
   CUBEB_DEVICE_FMT_S16BE = 0x0020, /**&lt; 16-bit integers, Big Endian. */
+  CUBEB_DEVICE_FMT_S32LE = 0x0040, /**&lt; 32-bit integers, Little Endian. */
+  CUBEB_DEVICE_FMT_S32BE = 0x0080, /**&lt; 32-bit integers, Big Endian. */
   CUBEB_DEVICE_FMT_F32LE = 0x1000, /**&lt; 32-bit floating point, Little Endian. */
   CUBEB_DEVICE_FMT_F32BE = 0x2000  /**&lt; 32-bit floating point, Big Endian. */
 } cubeb_device_fmt;
@@ -347,25 +349,30 @@ typedef enum {
 #if defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__)
 /** 16-bit integers, native endianess, when on a Big Endian environment. */
 #define CUBEB_DEVICE_FMT_S16NE CUBEB_DEVICE_FMT_S16BE
-/** 32-bit floating points, native endianess, when on a Big Endian environment.
- */
+/** 32-bit integers, native endianess, when on a Big Endian environment. */
+#define CUBEB_DEVICE_FMT_S32NE CUBEB_DEVICE_FMT_S32BE
+/** 32-bit floating points, native endianess, when on a Big Endian environment. */
 #define CUBEB_DEVICE_FMT_F32NE CUBEB_DEVICE_FMT_F32BE
 #else
 /** 16-bit integers, native endianess, when on a Little Endian environment. */
 #define CUBEB_DEVICE_FMT_S16NE CUBEB_DEVICE_FMT_S16LE
-/** 32-bit floating points, native endianess, when on a Little Endian
- *  environment. */
+/** 32-bit integers, native endianess, when on a Little Endian environment. */
+#define CUBEB_DEVICE_FMT_S32NE CUBEB_DEVICE_FMT_S32LE
+/** 32-bit floating points, native endianess, when on a Little Endian environment. */
 #define CUBEB_DEVICE_FMT_F32NE CUBEB_DEVICE_FMT_F32LE
 #endif
 /** All the 16-bit integers types. */
 #define CUBEB_DEVICE_FMT_S16_MASK                                              \
   (CUBEB_DEVICE_FMT_S16LE | CUBEB_DEVICE_FMT_S16BE)
+/** All the 32-bit integers types. */
+#define CUBEB_DEVICE_FMT_S32_MASK                                              \
+  (CUBEB_DEVICE_FMT_S32LE | CUBEB_DEVICE_FMT_S32BE)
 /** All the 32-bit floating points types. */
 #define CUBEB_DEVICE_FMT_F32_MASK                                              \
   (CUBEB_DEVICE_FMT_F32LE | CUBEB_DEVICE_FMT_F32BE)
 /** All the device formats types. */
 #define CUBEB_DEVICE_FMT_ALL                                                   \
-  (CUBEB_DEVICE_FMT_S16_MASK | CUBEB_DEVICE_FMT_F32_MASK)
+  (CUBEB_DEVICE_FMT_S16_MASK | CUBEB_DEVICE_FMT_S32_MASK | CUBEB_DEVICE_FMT_F32_MASK)
 
 /** Channel type for a `cubeb_stream`. Depending on the backend and platform
  * used, this can control inter-stream interruption, ducking, and volume
diff --git a/media/libcubeb/src/cubeb.c b/media/libcubeb/src/cubeb.c
index 4fdead389354..1ca8582bab71 100644
--- a/media/libcubeb/src/cubeb.c
+++ b/media/libcubeb/src/cubeb.c
@@ -75,6 +75,10 @@ opensl_init(cubeb ** context, char const * context_name);
 int
 oss_init(cubeb ** context, char const * context_name);
 #endif
+#if defined(USE_OSS_FFT)  
+int  
+oss_fft_init(cubeb ** context, char const * context_name);  
+#endif
 #if defined(USE_AAUDIO)
 int
 aaudio_init(cubeb ** context, char const * context_name);
@@ -195,6 +199,10 @@ cubeb_init(cubeb ** context, char const * context_name,
     } else if (!strcmp(backend_name, &quot;oss&quot;)) {
 #if defined(USE_OSS)
       init_oneshot = oss_init;
+#endif
+} else if (!strcmp(backend_name, &quot;oss-fft&quot;)) {  
+#if defined(USE_OSS_FFT)  
+  init_oneshot = oss_fft_init;  
 #endif
     } else if (!strcmp(backend_name, &quot;aaudio&quot;)) {
 #if defined(USE_AAUDIO)
@@ -237,6 +245,9 @@ cubeb_init(cubeb ** context, char const * context_name,
 #if defined(USE_OSS)
       oss_init,
 #endif
+#if defined(USE_OSS_FFT)  
+  oss_fft_init,  
+#endif
 #if defined(USE_AUDIOUNIT_RUST)
       audiounit_rust_init,
 #endif
@@ -690,6 +701,12 @@ log_device(cubeb_device_info * device_info)
   case CUBEB_DEVICE_FMT_F32BE:
     devdeffmt = &quot;F32BE&quot;;
     break;
+	case CUBEB_DEVICE_FMT_S32LE:  
+		devdeffmt = &quot;S32LE&quot;;  
+		break;  
+	case CUBEB_DEVICE_FMT_S32BE:  
+		devdeffmt = &quot;S32BE&quot;;  
+		break;
   default:
     devdeffmt = &quot;unknown?&quot;;
     break;
@@ -707,6 +724,12 @@ log_device(cubeb_device_info * device_info)
   if (device_info-&gt;format &amp; CUBEB_DEVICE_FMT_F32BE) {
     strcat(devfmts, &quot; F32BE&quot;);
   }
+  if (device_info-&gt;format &amp; CUBEB_DEVICE_FMT_S32LE) {
+    strcat(devfmts, &quot; S32LE&quot;);
+  }
+  if (device_info-&gt;format &amp; CUBEB_DEVICE_FMT_S32BE) {
+    strcat(devfmts, &quot; S32BE&quot;);
+  }
 
   LOG(&quot;DeviceID: \&quot;%s\&quot;%s\n&quot;
       &quot;\tName:\t\&quot;%s\&quot;\n&quot;
diff --git a/media/libcubeb/test/test_devices.cpp b/media/libcubeb/test/test_devices.cpp
index d0eab2da67e6..4a8da1a4113b 100644
--- a/media/libcubeb/test/test_devices.cpp
+++ b/media/libcubeb/test/test_devices.cpp
@@ -79,6 +79,12 @@ print_device_info(cubeb_device_info * info, FILE * f)
   case CUBEB_DEVICE_FMT_F32BE:
     devdeffmt = &quot;F32BE&quot;;
     break;
+  case CUBEB_DEVICE_FMT_S32LE:  // Add this  
+    devdeffmt = &quot;S32LE&quot;;  
+    break;  
+  case CUBEB_DEVICE_FMT_S32BE:  // Add this  
+    devdeffmt = &quot;S32BE&quot;;  
+    break;  
   default:
     devdeffmt = &quot;unknown?&quot;;
     break;
@@ -92,6 +98,10 @@ print_device_info(cubeb_device_info * info, FILE * f)
     strcat(devfmts, &quot; F32LE&quot;);
   if (info-&gt;format &amp; CUBEB_DEVICE_FMT_F32BE)
     strcat(devfmts, &quot; F32BE&quot;);
+	if (info-&gt;format &amp; CUBEB_DEVICE_FMT_S32LE)  // Add this  
+		strcat(devfmts, &quot; S32LE&quot;);  
+	if (info-&gt;format &amp; CUBEB_DEVICE_FMT_S32BE)  // Add this  
+		strcat(devfmts, &quot; S32BE&quot;);
 
   fprintf(f,
           &quot;dev: \&quot;%s\&quot;%s\n&quot;
-- 
2.39.5</code></pre></div><p><strong>EXAMPLE:</strong> Firefox <span class="bbc">about:support</span></p><div class="codebox"><pre class="vscroll"><code>$ firefox-dev about:support
...
Name 	Firefox Developer Edition
Version 	154.0a1
...
Update Channel 	aurora
User Agent 	Mozilla/5.0 (X11; Linux x86_64; rv:154.0) Gecko/20100101 Firefox/154.0
...
Application Binary 	/usr/lib/firefox-dev/firefox-dev
Profile Directory 	$HOME/.firefox-dev/uf30avtz.dev-edition-default
...
Audio Backend: alsa
Max Channels: 64
Preferred Sample Rate: 44100
Roundtrip latency (standard deviation): NaNms (NaN)
...
Output Devices
Name: Group, Vendor, State, Preferred, Format, Channels, Rate, Latency
Discard all samples (playback) or generate zero samples (capture): null, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 1073741823, default: 44100, support: 1 - 4294967295, 0 - 0
Rate Converter Plugin Using Libav/FFmpeg Library: lavrate, Enabled, None, default: S32LE, support: S16LE S16BE S32LE S32BE, 10000, default: 44100, support: 1 - 4294967295, 0 - 0
Rate Converter Plugin Using Samplerate Library: samplerate, Enabled, None, default: S32LE, support: S16LE S16BE S32LE S32BE, 10000, default: 44100, support: 1 - 4294967295, 0 - 0
Rate Converter Plugin Using Speex Resampler: speexrate, Enabled, None, default: S32LE, support: S16LE S16BE S32LE S32BE, 10000, default: 44100, support: 1 - 4294967295, 0 - 0
Bluetooth Audio: bluealsa, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
Plugin using Speex DSP (resample, agc, denoise, echo, dereverb): speex, Enabled, None, default: S16LE, support: S16LE, 1, default: 44100, support: 4000 - 4294967295, 0 - 0
Plugin for channel upmix (4,6,8): upmix, Enabled, None, default: S16LE, support: S16LE, 8, default: 44100, support: 4000 - 4294967295, 0 - 0
Plugin for channel downmix (stereo) with a simple spacialization: vdownmix, Enabled, None, default: S16LE, support: S16LE, 6, default: 44100, support: 4000 - 4294967295, 0 - 0
Default device: default, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, 92HD95 Analog Direct hardware device without any conversions: hw:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S32LE, 2, default: 44100, support: 44100 - 192000, 0 - 0
HDA Intel PCH, HDMI 0 Direct hardware device without any conversions: hw:CARD=PCH,DEV=3, Enabled, None, default: S32LE, support: S16LE S32LE, 8, default: 44100, support: 32000 - 192000, 0 - 0
HDA Intel PCH, HDMI 1 Direct hardware device without any conversions: hw:CARD=PCH,DEV=7, Enabled, None, default: S32LE, support: S16LE S32LE, 8, default: 44100, support: 32000 - 192000, 0 - 0
HDA Intel PCH, HDMI 2 Direct hardware device without any conversions: hw:CARD=PCH,DEV=8, Enabled, None, default: S32LE, support: S16LE S32LE, 8, default: 44100, support: 32000 - 192000, 0 - 0
HDA Intel PCH, HDMI 3 Direct hardware device without any conversions: hw:CARD=PCH,DEV=9, Enabled, None, default: S32LE, support: S16LE S32LE, 8, default: 44100, support: 32000 - 192000, 0 - 0
HDA Intel PCH, 92HD95 Analog Hardware device with all software conversions: plughw:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, HDMI 0 Hardware device with all software conversions: plughw:CARD=PCH,DEV=3, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, HDMI 1 Hardware device with all software conversions: plughw:CARD=PCH,DEV=7, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, HDMI 2 Hardware device with all software conversions: plughw:CARD=PCH,DEV=8, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, HDMI 3 Hardware device with all software conversions: plughw:CARD=PCH,DEV=9, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, 92HD95 Analog Default Audio Device: sysdefault:CARD=PCH, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, 92HD95 Analog Front output / input: front:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S32LE, 2, default: 44100, support: 44100 - 192000, 0 - 0
HDA Intel PCH, 92HD95 Analog 4.0 Surround output to Front and Rear speakers: surround40:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S32LE, 2, default: 44100, support: 44100 - 192000, 0 - 0
HDA Intel PCH, 92HD95 Analog 5.1 Surround output to Front, Center, Rear and Subwoofer speakers: surround51:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S32LE, 2, default: 44100, support: 44100 - 192000, 0 - 0
HDA Intel PCH, 92HD95 Analog 7.1 Surround output to Front, Center, Side, Rear and Woofer speakers: surround71:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S32LE, 2, default: 44100, support: 44100 - 192000, 0 - 0
HDA Intel PCH, HDMI 0 HDMI Audio Output: hdmi:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S32LE, 8, default: 44100, support: 32000 - 192000, 0 - 0
HDA Intel PCH, HDMI 1 HDMI Audio Output: hdmi:CARD=PCH,DEV=1, Enabled, None, default: S32LE, support: S16LE S32LE, 8, default: 44100, support: 32000 - 192000, 0 - 0
HDA Intel PCH, HDMI 2 HDMI Audio Output: hdmi:CARD=PCH,DEV=2, Enabled, None, default: S32LE, support: S16LE S32LE, 8, default: 44100, support: 32000 - 192000, 0 - 0
HDA Intel PCH, HDMI 3 HDMI Audio Output: hdmi:CARD=PCH,DEV=3, Enabled, None, default: S32LE, support: S16LE S32LE, 8, default: 44100, support: 32000 - 192000, 0 - 0
HDA Intel PCH, 92HD95 Analog Direct sample mixing device: dmix:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S32LE, 2, default: 48000, support: 48000 - 48000, 0 - 0
HDA Intel PCH, HDMI 0 Direct sample mixing device: dmix:CARD=PCH,DEV=3, Enabled, None, default: S32LE, support: S32LE, 2, default: 48000, support: 48000 - 48000, 0 - 0
HDA Intel PCH, HDMI 1 Direct sample mixing device: dmix:CARD=PCH,DEV=7, Enabled, None, default: S32LE, support: S32LE, 2, default: 48000, support: 48000 - 48000, 0 - 0
HDA Intel PCH, HDMI 2 Direct sample mixing device: dmix:CARD=PCH,DEV=8, Enabled, None, default: S32LE, support: S32LE, 2, default: 48000, support: 48000 - 48000, 0 - 0
HDA Intel PCH, HDMI 3 Direct sample mixing device: dmix:CARD=PCH,DEV=9, Enabled, None, default: S32LE, support: S32LE, 2, default: 48000, support: 48000 - 48000, 0 - 0
Input Devices
Name: Group, Vendor, State, Preferred, Format, Channels, Rate, Latency
Discard all samples (playback) or generate zero samples (capture): null, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 1073741823, default: 44100, support: 1 - 4294967295, 0 - 0
Rate Converter Plugin Using Libav/FFmpeg Library: lavrate, Enabled, None, default: S32LE, support: S16LE S16BE S32LE S32BE, 10000, default: 44100, support: 1 - 4294967295, 0 - 0
Rate Converter Plugin Using Samplerate Library: samplerate, Enabled, None, default: S32LE, support: S16LE S16BE S32LE S32BE, 10000, default: 44100, support: 1 - 4294967295, 0 - 0
Rate Converter Plugin Using Speex Resampler: speexrate, Enabled, None, default: S32LE, support: S16LE S16BE S32LE S32BE, 10000, default: 44100, support: 1 - 4294967295, 0 - 0
Plugin using Speex DSP (resample, agc, denoise, echo, dereverb): speex, Enabled, None, default: S16LE, support: S16LE, 1, default: 44100, support: 4000 - 4294967295, 0 - 0
Plugin for channel upmix (4,6,8): upmix, Enabled, None, default: S16LE, support: S16LE, 8, default: 44100, support: 4000 - 4294967295, 0 - 0
Plugin for channel downmix (stereo) with a simple spacialization: vdownmix, Enabled, None, default: S16LE, support: S16LE, 6, default: 44100, support: 4000 - 4294967295, 0 - 0
Default device: default, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, 92HD95 Analog Direct hardware device without any conversions: hw:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S32LE, 2, default: 44100, support: 44100 - 192000, 0 - 0
HDA Intel PCH, 92HD95 Analog Hardware device with all software conversions: plughw:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, 92HD95 Analog Default Audio Device: sysdefault:CARD=PCH, Enabled, None, default: S32LE, support: S16LE S16BE F32LE F32BE S32LE S32BE, 10000, default: 44100, support: 4000 - 4294967295, 0 - 0
HDA Intel PCH, 92HD95 Analog Front output / input: front:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S16LE S32LE, 2, default: 44100, support: 44100 - 192000, 0 - 0
HDA Intel PCH, 92HD95 Analog Direct sample snooping device: dsnoop:CARD=PCH,DEV=0, Enabled, None, default: S32LE, support: S32LE, 2, default: 48000, support: 48000 - 48000, 0 - 0</code></pre></div><p><strong>NOTE:</strong> ALSA device enumeration is now exact, but ALSA drives might be buggy. Therefore, &quot;digital&quot; may mean &quot;analog&quot; and other way round. The word &quot;virtual&quot; usually implies linear interpolation or other sort of low quality resampling.</p><p>1. Device enumeration is exact - The ALSA library correctly enumerates available devices through the control interface and name hints control.</p><p>2. Driver descriptions can be buggy - Generic card configurations like HDA-Intel.conf make assumptions about device mappings that may not match actual hardware pin configurations. </p><p>3. &quot;Virtual&quot; and resampling quality - Virtual devices (using the plug plugin) perform conversions, but the quality depends on the configured rate converter. The default is often linear interpolation, but high-quality converters like fftrate can be used.</p><p>Virtual devices are software plugins that wrap hardware access. They always perform some conversion (format, rate, or channels), but the quality varies:</p><p>Default: often linear interpolation (lower quality)<br />Configurable: can use high-quality resamplers like fftrate</p><p>Hardware devices (hw:) provide direct kernel driver access without any conversions. </p><p>The &quot;digital&quot;/&quot;analog&quot; labels come from driver descriptions, which may be incorrect due to generic configuration assumptions not matching your specific motherboard&#039;s pin layout.</p><p>The word &quot;direct&quot; is also a sort of label that has a flexible meaning: &quot;direct exclusive kernel driver access&quot; is not possible with ALSA in any sense.</p><p>The ALSA hw plugin does communicate directly with the kernel driver through device files and ioctl calls, but this is still mediated by the ALSA library (libasound) in userspace. The <span class="bbc">snd_pcm_hw_open</span> function opens kernel device files like <span class="bbc">/dev/snd/pcmC%iD%ip</span> and uses ioctl calls to communicate with the kernel driver.</p><p>When ALSA documentation says the hw plugin provides &quot;direct communication without any conversions,&quot; it means:<br />No software format conversion<br />No software rate conversion<br />No software channel routing<br />Direct ioctl calls to kernel device files</p><p>But it does NOT mean:<br />Bypassing the ALSA library<br />Exclusive hardware access (other processes can still access the device)<br />Bypassing potential kernel driver bugs</p><p>The ALSA path with <span class="bbc">hw:0,0</span> is:</p><div class="codebox"><pre><code>Application → ALSA Library (libasound) → hw plugin → ioctl → Kernel Driver → Hardware </code></pre></div><p>The hw plugin is the closest you can get to the kernel driver while still using the ALSA API, but it&#039;s still going through the library layer.</p><p>There is no way to access the ALSA kernel driver directly from userspace without going through libasound. The &quot;direct&quot; terminology in ALSA documentation refers to the absence of software processing plugins, not to bypassing the library itself. <br />See also: <br /><strong>The exclusive mode of ALSA</strong><br />_https://dev1galaxy.org/viewtopic.php?id=8053</p><p>In practical terms, the choice is indeed between low-quality hardware resampling and software resampling.</p><p>The fundamental tradeoff in ALSA audio processing:<br />Hardware resampling - Built into consumer sound cards/codecs, often poor quality due to cost-cutting and implementation limitations.<br />Software resampling - Performed by ALSA&#039;s rate plugin, quality depends on the converter used.</p><p>ALSA&#039;s plug plugin automatically inserts rate conversion when the application&#039;s requested rate differs from the hardware&#039;s native rate. The rate plugin supports multiple converters specified via the converter parameter.</p><p>The default linear converter provides basic linear interpolation (low quality), while high-quality external converters like fftrate can be used through the External Rate-Converter-Plugin SDK.</p><p>The optimal strategy — using high-quality software resampling (fftrate) to bypass hardware resamplers by sending a fixed high-rate stream to the hardware — effectively avoids the quality limitations of consumer hardware SRC implementations.</p><div class="quotebox"><blockquote><div><p><strong>NOTE:</strong> This guide is a work in progress. Please do not post in this topic. If you have any questions, please consult the Devuan Wiki, or other knowledge repositories of the sort.</p></div></blockquote></div>]]></description>
			<author><![CDATA[dummy@example.com (igorzwx)]]></author>
			<pubDate>Fri, 10 Jul 2026 00:40:42 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=8012&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[[SOLVED] Tips for people who don't like hidden scrollbars and other GTK3 things]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=8087&amp;action=new</link>
			<description><![CDATA[<div class="quotebox"><cite>Uityyy wrote:</cite><blockquote><div><p><strong>Scrollbars that jump many pages when you click the wrong place</strong></p><p>GTK themes can contain general GTK settings. Devuan Excalibur&#039;s theme contains a settings.ini containing the line</p><div class="codebox"><pre><code>gtk-primary-button-warps-slider = false</code></pre></div><p>This makes the scrollbar only scroll by one page if you left-click it somewhere other than the handle.<br />If you want this behavior all the time and not just when you&#039;re using Excalibur&#039;s default theme, simply create ~/.config/gtk-3.0/settings.ini and add the same line to it.</p></div></blockquote></div><p>Thanks for posting this!&#160; The same setting works on Daedalus also.&#160; Note that if you&#039;re creating a settings.ini file, that code should be in a &quot;[Settings]&quot; group, like so: </p><div class="codebox"><pre><code>[Settings]
gtk-primary-button-warps-slider = false</code></pre></div><p> Otherwise you&#039;ll get a gtk warning, failed to parse settings.ini: Key file does not start with a group.</p>]]></description>
			<author><![CDATA[dummy@example.com (rbit)]]></author>
			<pubDate>Thu, 09 Jul 2026 16:48:16 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=8087&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[The Absurdist Comedy]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7605&amp;action=new</link>
			<description><![CDATA[<p><span class="bbc">about:support</span></p><div class="codebox"><pre><code>Name 	Firefox Developer Edition
Version 	154.0a1 	
Update Channel 	aurora
User Agent 	Mozilla/5.0 (X11; Linux x86_64; rv:154.0) Gecko/20100101 Firefox/154.0
Profile Directory 	~/.firefox-dev/qxls80vg.dev-edition-default-1</code></pre></div><p>If User Agent is not set correctly with:</p><div class="codebox"><pre><code>imply_option(&quot;MOZ_APP_UA_NAME&quot;, &quot;Firefox&quot;)</code></pre></div><p>You can set it with override in <span class="bbc">about:config</span></p><div class="codebox"><pre><code>general.useragent.override      Mozilla/5.0 (X11; Linux x86_64; rv:154.0) Gecko/20100101 Firefox/154.0	</code></pre></div><div class="codebox"><pre><code>imply_option(&quot;MOZ_APP_PROFILE&quot;, &quot;firefox-dev&quot;)</code></pre></div><p><span class="bbc">MOZ_APP_PROFILE=firefox-dev</span> means User Profile Directory&#160; &#160; &#160;</p><div class="codebox"><pre><code>$HOME/.firefox-dev</code></pre></div><p>for user settings.</p><p><span class="bbc">firefox/browser/moz.configure</span> is a secret configuration file.</p>]]></description>
			<author><![CDATA[dummy@example.com (igorzwx)]]></author>
			<pubDate>Tue, 23 Jun 2026 19:28:41 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7605&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[The exclusive mode of ALSA]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=8053&amp;action=new</link>
			<description><![CDATA[<h5>The exclusive mode of ALSA</h5><p>With <span class="bbc">plughw:0,0</span> or default, the audio path is:</p><div class="codebox"><pre><code>Application → ALSA Library → Plugin Layer → Kernel PCM Core → Hardware Driver → Hardware </code></pre></div><p>The ALSA path with <span class="bbc">hw:0,0</span> is:</p><div class="codebox"><pre><code>Application → ALSA Library → Kernel PCM Core → Hardware Driver → Hardware </code></pre></div><p>When using <span class="bbc">hw:0,0</span>, the ALSA library bypasses the plugin layer (software format/rate/channel conversion) but still goes through the kernel PCM core for buffer management, period handling, and synchronization before reaching the hardware driver. </p><p>Usually, &quot;exclusive mode&quot; refers to exclusive device access control by one applications (this is what the word exclusive is supposed to mean). Such exclusive device access prevents multiple applications from simultaneously using the same hardware resource. In the Linux kernel&#039;s technical documentation, &quot;exclusive&quot; has a specific meaning: preventing multiple applications from simultaneously using the same hardware resource. </p><p>ALSA permits &quot;exclusive full duplex&quot;: </p><div class="codebox"><pre><code>$ arecord -f cd -D hw:0,0 | aplay -V mono -D hw:0,0  
Recording WAVE &#039;stdin&#039; : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
Playing WAVE &#039;stdin&#039; : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
#####################   +                          | 46%

$ arecord -f cd -D hw:1,0 | aplay -V mono -D hw:1,0 
Recording WAVE &#039;stdin&#039; : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
Playing WAVE &#039;stdin&#039; : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
##################################################+| MAX

$ arecord -f cd -D hw:PCH,0 | aplay -V mono -D hw:PCH,0 
Recording WAVE &#039;stdin&#039; : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
Playing WAVE &#039;stdin&#039; : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
####################                             + | 97% </code></pre></div><p><span class="bbc">arecord</span> opens <span class="bbc">hw:0,0</span> for capture<br /><span class="bbc">aplay</span> opens <span class="bbc">hw:0,0</span> for playback<br />Both processes have the the same device open simultaneously in &quot;exclusive mode&quot;.</p><p>The active meter indicates that the full duplex works and audio data is actively flowing through the pipeline in real-time.</p><p>Thus, two applications, <span class="bbc">arecord</span> and <span class="bbc">aplay</span>, have exclusive access to the same device simultaneously. It works with Intel HDA codecs, USB soundcards, etc.</p><p>OSS4 with software mixer <span class="bbc">vmix</span> disabled does not support &quot;exclusive full duplex&quot; for Intel HDA codecs</p><div class="codebox"><pre><code>$ ./fulldup

Using audio engine 0=HD Audio play front for duplex

/dev/dsp doesn&#039;t support one device based full duplex scheme
Please use the two device scheme.

$ file /dev/dsp
/dev/dsp: symbolic link to /dev/oss/oss_hdaudio0/pcm0 </code></pre></div><p>ALSA is more advanced in this sense. In advanced Monty Python reality, the word exclusive has a flexible meaning. It may mean anything you want.</p>]]></description>
			<author><![CDATA[dummy@example.com (igorzwx)]]></author>
			<pubDate>Sun, 21 Jun 2026 01:45:27 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=8053&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[Do ALSA users really need fftrate?]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=8049&amp;action=new</link>
			<description><![CDATA[<p>Bypassing the hardware resampler in Intel HDA codecs with a software real-time fftrate codec to resample everything to 192kHz 32-bit is a solid architectural strategy. It works at the userspace level on top of ALSA and avoids potential quality issues in codec hardware SRC implementations.</p><p><strong>HDA Codec Resampling in the Kernel</strong></p><p>The Linux kernel&#039;s HDA subsystem does have hardware sample rate converter (SRC) capabilities managed by codec drivers. For example, the Creative CA0132 driver documentation shows that HDA codecs have dedicated SRC ports (0x80–0xbf) for sample rate conversion within the codec&#039;s internal routing.</p><p><strong>Kernel-Level Format Handling</strong></p><p>The kernel handles PCM format conversion through the <span class="bbc">snd_hdac_stream_format()</span> function, which converts channel count, sample format, and sample rate into the HDA format value used by the hardware.</p><p><strong>Hardware-Specific Workarounds</strong></p><p>Some codecs have hardware-specific sample rate limitations that require kernel-level workarounds. For instance, the ALC269 driver has a fixup for the Lenovo Ideapad that forces analog I/O to 44.1kHz due to a hardware problem.</p><p><strong>The fftrate project</strong></p><p>The software resampling approach of the fftrate project bypasses these kernel-level hardware resamplers entirely by:<br />1.&#160; Accepting audio at any rate from the application.<br />2.&#160; Resampling to 192kHz 32-bit in userspace.<br />3.&#160; Sending the already-resampled audio to ALSA at a fixed rate.</p><p>This avoids potential quality issues or bugs in the codec&#039;s hardware SRC implementation. The kernel ALSA driver simply sees a constant 192kHz 32-bit stream and passes it through without additional resampling.</p><p><strong>Dialectical conclusion</strong></p><p>There is a belief that fftrate may cure deafness, though it hasn&#039;t been verified by scientific methods. Give it a chance. It may (or may not) work.</p><div class="quotebox"><blockquote><div><p><strong>NOTE:</strong> The claim that fftrate can &quot;cure deafness&quot; is a metaphorical exaggeration common in audiophile circles, not a medical fact. There is no scientific evidence that software resampling can restore hearing loss or cure physiological deafness.</p></div></blockquote></div>]]></description>
			<author><![CDATA[dummy@example.com (igorzwx)]]></author>
			<pubDate>Thu, 18 Jun 2026 18:58:54 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=8049&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[Chasing the Fox (Caccia alla volpe)]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7620&amp;action=new</link>
			<description><![CDATA[<div class="quotebox"><cite>greenjeans wrote:</cite><blockquote><div><p>That would be a real service to the community</p></div></blockquote></div><p>A real service to the community might be to avoid annoying others with your comments and advice. Please do not post in my topics.</p><div class="quotebox"><blockquote><div><p>_https://en.wikipedia.org/wiki/Sndio<br /><strong>sndio</strong> is the software layer of the OpenBSD operating system that manages sound cards and MIDI ports. It provides an optional <strong>sound server</strong> and a documented application programming interface to access either the server or the audio and MIDI hardware in a uniform way.</p></div></blockquote></div><div class="quotebox"><blockquote><div><p>_https://man.openbsd.org/sndiod.8<br /><strong>BUGS</strong><br /><strong><span style="color: green">Resampling is low quality</span></strong>; down-sampling especially should be avoided when recording.</p><p>If -a off is used, sndiod creates sub-devices to expose first and then opens the audio hardware on demand. Technically, this allows sndiod to attempt to use one of the sub-devices it exposes as an audio device, creating a deadlock. There&#039;s nothing to prevent the user from shooting themselves in the foot by creating such a deadlock.</p></div></blockquote></div><p><strong>sndio</strong> might be perfectly suitable for semi-deaf and half-demented users.</p><p>If someone really needs <strong>sndio</strong>, he might consider forking it to integrate the fftrate resampler for higher-quality audio processing<br />_https://github.com/PetrovSE/fftrate</p><div class="quotebox"><blockquote><div><p>_https://man.openbsd.org/sndiod.8<br /><strong>BUGS</strong><br /><strong><span style="color: green">Resampling is low quality</span></strong>; down-sampling especially should be avoided when recording.</p></div></blockquote></div><p>Perhaps <strong>sndio</strong> developers engage in post-modern humor. Linux users are unlikely to notice a Monty Python situation where a &quot;bug&quot; is documented rather than fixed.</p><p>If you don’t get this kind of humor, think of post-truth, post-philosophy, and post-documentation. It’s a post-real world where absurdity is plainly documented — in man pages, wikis, and official notes — without irony. The joke isn’t hidden; it’s right there, labeled &quot;BUG&quot;. The word &quot;bug&quot; has become a post-word with a post-meaning: not a flaw to fix, but a punchline accepted as fact.</p><p>What is special about post-reality is that it can be consumed innocently — just like myth, it appears factual, not constructed. </p><div class="quotebox"><blockquote><div><p>The myth consumer takes the signification for a system of facts: myth is read as a factual system whereas it is but a semiological system.<br />Roland Barthes, <em>Myth Today.</em></p></div></blockquote></div>]]></description>
			<author><![CDATA[dummy@example.com (igorzwx)]]></author>
			<pubDate>Tue, 05 May 2026 14:17:10 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7620&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[system-config-printer-udev: 70-printers.rules]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=4819&amp;action=new</link>
			<description><![CDATA[<p>Bug report and patch posted to <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1132179" rel="nofollow">https://bugs.debian.org/cgi-bin/bugrepo … ug=1132179</a>.</p>]]></description>
			<author><![CDATA[dummy@example.com (teom)]]></author>
			<pubDate>Sun, 29 Mar 2026 12:16:56 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=4819&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[How will life be without gvfs?]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7851&amp;action=new</link>
			<description><![CDATA[<p>Hello:</p><div class="quotebox"><cite>tux_99 wrote:</cite><blockquote><div><p>... don&#039;t know what&#039;s the root cause of your issues ...</p></div></blockquote></div><p>Hmm ...<br />I have <em>so</em> many, but the root cause to any of them has eluded me from an early age.</p><p>Most of them can be found in any edition of Jon Winokur&#039;s &#039;The Portable Curmudgeon&#039;.</p><div class="quotebox"><blockquote><div><p>... don&#039;t have any of those files you listed in that dbus folder ...</p></div></blockquote></div><p>That is because I have <span class="bbc">gvfs</span> installed and you do not.</p><p>I had to reinstall it.</p><p>Best,</p><p>A.</p>]]></description>
			<author><![CDATA[dummy@example.com (Altoid)]]></author>
			<pubDate>Tue, 24 Mar 2026 20:09:36 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7851&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[Needs for better modularization of installs]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7847&amp;action=new</link>
			<description><![CDATA[<div class="quotebox"><blockquote><div><p>So it does work using extracted squashfs. The errors seem just warnings. It&#039;s there in the overlay. The overlay can be mounted in main system and new initrd copied to where the the relevant bootloader can find it.</p><p>But it doesn&#039;t work using fromiso/findiso (my preferred use case) without user intervention as noted. I don&#039;t see that mentioned in live-boot&#039;s manual.</p></div></blockquote></div><p>I really appreciate that you take the time to delve into this stuff.<br />At present, I don&#039;t have the time myself, but it seems that clarifications and eventual workarounds may be helpful also to the upstream developers.</p>]]></description>
			<author><![CDATA[dummy@example.com (tyder)]]></author>
			<pubDate>Tue, 17 Mar 2026 11:54:14 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7847&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[what about "turnstile" for user services?]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7798&amp;action=new</link>
			<description><![CDATA[<p>A note for anyone holding their breath:<br /> <span class="bbc">turnstile</span> is now available on ceres<br />(debian package version 0.1.11-2)</p>]]></description>
			<author><![CDATA[dummy@example.com (ralph.ronnquist)]]></author>
			<pubDate>Sat, 07 Mar 2026 05:03:18 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7798&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[About installers]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7803&amp;action=new</link>
			<description><![CDATA[<p>I really would like people to put just a little bit of thought into how their software may reflect on them, before publishing it.</p><p>I assume you were obliquely referring to my comment, ralph.ronnquist, so I removed what is probably the part you found most objectionable.</p><p>But I have spent a great deal of my life trying to be polite and diplomatic, and I&#039;m now at the age where I think a lot of the world&#039;s problems are caused by stupid people not being properly told they&#039;re being stupid. To that end, I&#039;ve grown very fond of Linus Torvalds&#039; occasional rants about &quot;brain damage&quot; in software, because that&#039;s what it is, and it needs to be called out. Politeness implies acceptance or at least tolerance, and stupid decisions should be greeted with neither.</p><p>Stupid decisions are stupid.</p>]]></description>
			<author><![CDATA[dummy@example.com (Mercury)]]></author>
			<pubDate>Fri, 20 Feb 2026 23:42:04 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7803&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[UDisks2: Security Considerations]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7807&amp;action=new</link>
			<description><![CDATA[<p>Find some other place for chatting please.</p>]]></description>
			<author><![CDATA[dummy@example.com (ralph.ronnquist)]]></author>
			<pubDate>Sun, 15 Feb 2026 21:57:57 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7807&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[Turnstile: security considerations and potential issues]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7799&amp;action=new</link>
			<description><![CDATA[<div class="quotebox"><blockquote><div><p>Here are the key security considerations and potential issues:</p><p><strong>Socket Permissions and Access Control</strong></p><ul><li><p>The control socket uses permissive permissions (0666) allowing connections from non-root users <span class="bbc">turnstiled.cc:47</span> , but relies on platform-specific credentials checking to verify the peer&#039;s UID/GID/PID <span class="bbc">utils.cc:25-111</span> . This design requires proper implementation on each supported platform.</p></li></ul><p><strong>Privilege Separation</strong></p><ul><li><p><strong>The daemon runs as root</strong> but service managers are executed with dropped privileges after proper setup <span class="bbc">exec_utils.cc:126-145</span></p></li><li><p>Resource limits are sanitized before PAM session setup to prevent privilege escalation <span class="bbc">exec_utils.cc:106-124</span></p></li></ul><p><strong>Process Management and Timeouts</strong></p><ul><li><p>Implements a 60-second timeout for service manager startup to prevent hanging logins <span class="bbc">turnstiled.cc:55</span> <span class="bbc">turnstiled.conf.5.scd.in:93-97</span></p></li><li><p>Service managers that fail to signal readiness are terminated and runtime directories are cleaned up <span class="bbc">turnstiled.cc:1043-1054</span></p></li></ul><p><strong>Resource Management</strong></p><ul><li><p>Runtime directories are created with proper ownership and permissions</p></li><li><p>Cleanup occurs on logout unless lingering is enabled turnstiled.cc:1071-1075</p></li></ul><p><strong>Known Limitations</strong></p><ul><li><p>When integrating with <span class="bbc">polkit</span>, sessions may be treated as non-local <br />&#160; unless polkit is patched, potentially affecting authentication <span class="bbc">README.md:110-122</span></p></li><li><p>Root session management is disabled by default due to potential security implications <span class="bbc">turnstiled.conf.5.scd.in:99-104</span></p></li></ul></div></blockquote></div><div class="quotebox"><blockquote><div><ul><li><p>Running as root increases the <strong>attack surface</strong> if vulnerabilities exist in the daemon or its PAM interaction.</p></li><li><p>Although it uses a <strong>modular backend design</strong> (e.g., shell scripts to launch user services), privilege separation is minimal; the main daemon itself does not drop privileges. </p></li><li><p>There is <strong>no built-in privilege separation framework</strong>, unlike systems such as OpenSSH or systemd, which use sandboxing or process isolation. </p></li></ul><p>In practice, this means <span style="color: red"><strong>trust</strong></span> is placed in the <strong>correctness of the code and its PAM configuration</strong>, with no fine-grained containment.</p></div></blockquote></div><p><span style="color: blue"><strong>Relying on the accuracy of code described by developers as a &quot;work in progress&quot; constitutes an unusual and risky security practice, as it introduces significant vulnerabilities due to incomplete testing, lack of peer review, and potential design flaws.</strong></span><br />_https://github.com/chimera-linux/turnstile</p><div class="quotebox"><blockquote><div><p>The daemon needs to be running in some way. Usually you will spawn it as a system-wide service. <span style="color: red"><strong>It needs to be running as the superuser. </strong></span><br />_https://github.com/chimera-linux/turnstile</p></div></blockquote></div><p>Yes, the <span class="bbc">turnstiled</span> deamon must run as root. This is explicitly documented and required for its core functionality.</p><p><strong>Why Root is Required</strong></p><p>The daemon performs privileged operations that necessitate root access:</p><ol class="decimal"><li><p><strong>System Directory Management</strong>: Creates directories in <span class="bbc">/run</span> for session tracking <span class="bbc">turnstiled.cc:1276-1298</span></p></li><li><p><strong>Runtime Directory Creation</strong>: Creates and chowns <span class="bbc">XDG_RUNTIME_DIR</span> for users <span class="bbc">fs_utils.cc:55-124</span></p></li><li><p><strong>Socket Operations</strong>: Binds to system paths and sets up the control socket <span class="bbc">turnstiled.cc:890-943</span></p></li><li><p><strong>PAM Session Management</strong>: Establishes PAM sessions for users <span class="bbc">exec_utils.cc:316-322</span></p></li></ol><p><strong>Security Design</strong></p><p>While running as root, the daemon implements:</p><ul><li><p><strong>Credential verification</strong>: Only UID 0 can create sessions <span class="bbc">turnstiled.cc:297-300</span></p></li><li><p><strong>Privilege separation</strong>: Service managers run with dropped privileges <span class="bbc">exec_utils.cc:339-349</span></p></li><li><p><strong>Root checks</strong>: Verifies it&#039;s running as root before privileged operations <span class="bbc">exec_utils.cc:310</span></p></li></ul><p>The README explicitly states: &quot;It needs to be running as the superuser&quot; <span class="bbc">README.md:78-81</span> .</p><p><strong>Notes</strong></p><p>The daemon accepts connections via a permissive socket (0666) but enforces security through platform-specific credential checking, allowing the PAM module to communicate while maintaining access control <span class="bbc">turnstiled.cc:4</span>7 .</p><p>Any daemon running as root is inherently an attractive target for attackers. Turnstiled is no exception.</p><p><strong>Security Reality</strong></p><p>Turnstiled runs as root and accepts connections via a 0666 socket <span class="bbc">turnstiled.cc:47</span> , making it a high-value target. A compromise could allow session hijacking or privilege escalation.</p><p><strong>Mitigations in Place</strong></p><p>The daemon implements several security measures:</p><ol class="decimal"><li><p><strong>Credential verification</strong>: Every connection is authenticated using platform-specific methods (SO_PEERCRED on Linux, LOCAL_PEERCRED on BSD, etc.) <span class="bbc">utils.cc:25-111</span></p></li><li><p><strong>Access control</strong>: Only UID 0 can create sessions <span class="bbc">turnstiled.cc:297-300</span></p></li><li><p><strong>Privilege separation</strong>: Service managers run with dropped privileges <span class="bbc">exec_utils.cc:339-349</span></p></li><li><p><strong>Resource limits</strong>: Sanitizes rlimits before PAM session setup <span class="bbc">exec_utils.cc:106-124</span></p></li></ol><p><strong>Attack Surface</strong></p><p>The primary attack vectors would be:</p><ul><li><p>Bugs in credential checking code</p></li><li><p>Protocol parsing vulnerabilities</p></li><li><p>Race conditions in process management</p></li><li><p>Memory corruption in the daemon</p></li></ul><p><strong>Notes</strong></p><p>While the design is deliberate for PAM integration <span class="bbc">turnstiled.cc:40-46</span> , it does increase the attack surface. The security relies heavily on the correctness of the credential verification implementation. Regular security audits and keeping the daemon updated would be essential for any deployment.</p><p>The documentation does present a tension between the &quot;work in progress&quot; status and the security requirements.</p><p><strong>What the Documentation States</strong></p><p>The README explicitly labels Turnstile as &quot;a work in progress effort&quot; <span class="bbc">README.md:3-5</span> while simultaneously stating it &quot;needs to be running as the superuser&quot; <span class="bbc">README.md:78-81</span> . There is no explicit security warning about this combination.</p><p><strong>Security Considerations in Code</strong></p><p>The code does implement security measures:</p><ul><li><p>Platform-specific credential verification for all connections</p></li><li><p>Only UID 0 can create sessions <span class="bbc">turnstiled.cc:297-300</span></p></li><li><p>Privilege separation for service managers</p></li></ul><p>However, the design acknowledges accepting connections from non-root processes as a deliberate trade-off <span class="bbc">turnstiled.cc:40-46</span> .</p><p><strong>Missing Documentation</strong></p><p>What&#039;s absent from the documentation:</p><ul><li><p>No explicit warning about running Work-In-Progress (WIP) software as root</p></li><li><p>No security audit status or review process mentioned</p></li><li><p>No clear statement about production readiness</p></li></ul><p><strong>Notes</strong></p><p>This is a valid concern. While the code implements standard security practices for a session tracker, users should be aware that running any &quot;work in progress&quot; daemon as root carries inherent risks. The documentation could be more transparent about these risks and the current security posture of the project.</p><ul><li><p>The project seems to place considerable faith in its users&#039; understanding of the inherent risks involved.</p></li><li><p>The users are invited to trust developers who have not fully disclosed the security risks associated with running work-in-progress (WIP) software with root privileges.</p></li></ul><p>Transparency is a key pillar of trust in software development. </p><p>In cybersecurity, <strong>trust must be earned through demonstrable actions, not assumed or invited</strong>. When developers work on software that requires elevated privileges like root access, the stakes are significantly higher. A lack of transparency about known risks, especially in Work-In-Progress (WIP) software, undermines user safety and ethical responsibility.</p><p>Transparency was, of course, something of a guiding principle in Linux and open-source software, and one rather hopes it might linger on.</p>]]></description>
			<author><![CDATA[dummy@example.com (igorzwx)]]></author>
			<pubDate>Tue, 10 Feb 2026 10:11:40 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7799&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[How to Disable the New Apt Pager]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7342&amp;action=new</link>
			<description><![CDATA[<p>Found this answer via duckduckgo! &quot;apt list&quot; was actually broken on my system because the pager was stripping the escape characters that were supposed to control the colours. This made the output very difficult to read. Probably something to do with what my default pager is or how it&#039;s set up, but the apt end-user documentation is near useless. I was contemplating dowloading the source code.</p>]]></description>
			<author><![CDATA[dummy@example.com (steve_graham)]]></author>
			<pubDate>Wed, 04 Feb 2026 17:07:09 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7342&amp;action=new</guid>
		</item>
		<item>
			<title><![CDATA[The Biological Risk of High-Frequency EQ]]></title>
			<link>https://dev1galaxy.org/viewtopic.php?id=7750&amp;action=new</link>
			<description><![CDATA[<p>ALSA default settings:</p><div class="codebox"><pre><code>$ cat /usr/share/alsa/alsa.conf
#
#  ALSA library configuration file
...
defaults.ctl.card 0
defaults.pcm.card 0
defaults.pcm.device 0
...
defaults.pcm.dmix.rate 48000
...</code></pre></div><p><strong>To improve sound quality</strong> with Firefox and YouTube, you can <strong>disable WebM (Opus)</strong> support in Firefox (<span class="bbc">media.mediasource.webm.enabled = false</span>). This will automatically enable AAC (MP4) playback at a 44100 Hz sample rate. </p><p>To prevent resampling, set the default sample rate to 44100 Hz in <span class="bbc">~/.asoundrc</span>:</p><div class="codebox"><pre><code>defaults.pcm.dmix.rate 44100</code></pre></div><p>Firefox settings for better sound quality:</p><div class="codebox"><pre><code>media.mediasource.webm.enabled              false
media.cubeb.backend                         alsa
media.resampling.enabled                    false
media.cubeb_latency_playback_ms             160</code></pre></div><p><strong>Configuration Editor for Firefox:</strong><br />_https://support.mozilla.org/en-US/kb/about-config-editor-firefox</p><p>If you are using the <strong>fftrate</strong> resampler, you can configure it for the maximum sample rate supported by your sound card (e.g., 192kHz, 32-bit for Intel HDA on notebooks), as <strong>fftrate</strong> provides much better sound quality than the built-in resampler of your sound card.</p><h5>Equalizers and Hearing Aids</h5><p>The idea that a <strong>system-wide equalizer</strong> resembles a <strong>hearing aid</strong> stems from their shared function: adjusting sound frequencies to suit individual perception.&#160; In theory, boosting certain frequencies (like high tones for age-related hearing loss) could help someone hear better, much like a hearing aid. However, while both tools manipulate audio, they differ fundamentally in design, precision, and purpose.</p><p>Despite their flexibility, <strong>system-wide equalizers fall short as hearing aids</strong> because they apply the same frequency adjustments to all volume levels.&#160; Hearing loss, especially sensorineural types like presbycusis, involves <strong>loudness recruitment</strong>—a reduced dynamic range where soft sounds are inaudible but loud sounds become painful. </p><p>A fixed EQ cannot adapt gain based on input level. For instance, boosting high frequencies to hear whispers may make loud sounds uncomfortably piercing. Additionally, EQs lack features like <strong>noise reduction, feedback cancellation, and directional microphones</strong> found in modern hearing aids.</p><p>Modern digital hearing aids go far beyond simple EQs by using <strong>multi-channel, level-dependent compression</strong>.&#160; Devices like the SONIC NATURA™ use <strong>nine independent compression bands</strong> at half-octave intervals, allowing different gain settings for soft (50 dB) and loud (90 dB) sounds—referred to as the <strong>&#039;5&#039; and &#039;9&#039; curves</strong>. </p><p>This dual-curve system compensates not only for <strong>frequency-specific hearing loss</strong> but also for <strong>abnormal loudness growth</strong>.&#160; Unlike a static home audio EQ, this approach dynamically reshapes sound across intensity levels, mimicking the function of a healthy cochlear amplifier.</p><p>While a <strong>system-wide equalizer can mimic some aspects of hearing aid functionality</strong>, it lacks the <strong>adaptive, multi-dimensional processing</strong> required for effective hearing rehabilitation.&#160; Hearing aids are medical devices designed for <strong>individual audiometric profiles</strong>, with dynamic gain control, noise management, and feedback suppression. </p><p><strong>Health Risks</strong></p><ul><li><p><strong>Hearing damage is inevitable if output levels are excessive</strong>, especially with high-frequency boosts (e.g., 10–20kHz), which can accelerate <strong>cochlear hair cell loss</strong> and lead to <strong>permanent threshold shift (PTS)</strong>.&#160; Research confirms that overexposure to intense sound—particularly in high-frequency ranges—causes irreversible damage to hair cells and auditory nerve synapses, even if hearing thresholds appear to recover initially. The risk increases when EQ is used to boost already loud signals, potentially causing <strong>acoustic trauma</strong> through prolonged or extreme listening.</p></li><li><p><strong>Tinnitus sufferers</strong> may misuse EQ to compensate for hearing loss, inadvertently increasing loudness to dangerous levels. </p></li></ul><div class="quotebox"><blockquote><div><p>⚠️ Critical point: Software EQ lacks <strong>dynamic range compression</strong> and <strong>peak limiting</strong> found in hearing aids, so uncontrolled use can cause <strong>acoustic trauma</strong>.</p></div></blockquote></div><p><strong>Conclusion</strong></p><p>The reasonable approach is to disable all unnecessary sound processing (e.g., resampling) and low-quality codecs (e.g., Opus) that degrade sound quality and cause audio distortions. Then compare sound quality with that of macOS.&#160; Afterward, you can decide whether you need an equalizer or a hearing aid.</p>]]></description>
			<author><![CDATA[dummy@example.com (igorzwx)]]></author>
			<pubDate>Tue, 20 Jan 2026 22:28:18 +0000</pubDate>
			<guid>https://dev1galaxy.org/viewtopic.php?id=7750&amp;action=new</guid>
		</item>
	</channel>
</rss>
