From sio_open(3):

     If the device is exposed by the sndiod(8) server, which is the default
     configuration, a transparent emulation layer will automatically be set
     up, and in this case any combination of rate, encoding and numbers of
     channels is supported.

Apparently the emulation layer (which I don't know anything about)
is downmixing badly the channels (the sound downmixed by xine
forcing stereo is perfect). Anyway I think it is a good idea
to add the audio.output.speaker_arrangement option to the driver,
so I'm going to contact the xine devs.

I would prefer to hear first if not from the maintainer, at least
from some other dev, so I'll try again: any thoughts?


On Sun, 25 Sep 2022, adr wrote:

Date: Sun, 25 Sep 2022 16:17:06 +0000 (UTC)
From: adr <a...@sdf.org>
To: m...@openbsd.org
Cc: ports@openbsd.org
Subject: Re: xine's ffmpegaudio doesn't downmix,
    sio_getpar() reports 6 channels instead of 2

On Thu, 22 Sep 2022, adr wrote:
Hi,

first of all, I've never contributed to the xine project, and
I don't have any experience with sndio, so bear with me...

Frustrated with the bad sound playing a 6 channels aac audio I decided to
take a look.  The device is a usb one:

$ dmesg | grep -i audio
uaudio0 at uhub2 port 3 configuration 1 interface 1 "GeneralPlus USB Audio Device" rev 1.10/1.00 addr 6
uaudio0: class v1, full-speed, sync, channels: 2 play, 1 rec, 8 ctls
audio0 at uaudio0
uhidev2 at uhub2 port 3 configuration 1 interface 3 "GeneralPlus USB Audio Device" rev 1.10/1.00 addr 6

It has only 2 channels for playback.

The file has 5.1 aac audio:
$ ffprobe file.mp4
[...]
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 224 kb/s (default)
[...]

Xine's ffmpegaudio plugin is supposed to do downmix (please, correct
me if I'm wrong), but:

$ xine --verbose=2 file.mp4
[...]
audio_out: ao_open (0x585415540)
audio_sndio_out: ao_sndio_open bits=16 rate=48000, mode=128
audio_sndio_out: ao_sndio_open 6 channels output
[...]

The code in xine-lib-1.2.12/src/audio_out/audio_sndio_out.c by Brad
Smith is following the recommendations at sio_open(3), there is no
problem there.

sio_getpar() is returning 6 channels as valid, so the sound ends
messed up. The right speaker gets mostly ambient sound and the
voices are almost only audible through the left speaker.

mplayer and mpv have means to force downmix, but xine is the only
media player which can play 1080p h264 video with a decent performance
(if the bitrate is not too high) on an rpi4 (no hardware acceleration,
cpu at 2.2Gz)

One workaround for this particular case could be adding the
configuration setting "audio.output.speaker_arrangement" to
audio_sndio_out.c.

This patch does that, following the alsa and oss drivers.
I CC'd it to ports@

============================================
Index: src/audio_out/audio_sndio_out.c
--- src/audio_out/audio_sndio_out.c.orig
+++ src/audio_out/audio_sndio_out.c
@@ -37,6 +37,8 @@
#include <xine/audio_out.h>
#include "bswap.h"

+#include "speakers.h"
+
#define GAP_TOLERANCE        AO_MAX_GAP
#define PCT_TO_MIDI(p)       (((p) * SIO_MAXVOL + 50) / 100)

@@ -248,11 +250,15 @@ static void ao_sndio_exit(ao_driver_t *this_gen)
{
  sndio_driver_t *this = (sndio_driver_t *) this_gen;

+ this->xine->config->unregister_callbacks (this->xine->config, "audio.output.speaker_arrangement", NULL, this, sizeof (*this));
+
  xprintf (this->xine, XINE_VERBOSITY_DEBUG,
           "audio_sndio_out: ao_sndio_exit called\n");

  if (this->hdl != NULL)
    sio_close(this->hdl);
+
+  free (this);
}

static int ao_sndio_get_property (ao_driver_t *this_gen, int property)
@@ -316,13 +322,27 @@ static int ao_sndio_ctrl(ao_driver_t *this_gen, int cm
  return 0;
}

+static void sndio_speaker_arrangement_cb (void *user_data,
+                                  xine_cfg_entry_t *entry);
+
static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data)
{
  sndio_class_t   *class = (sndio_class_t *) class_gen;
+  config_values_t *config = class->xine->config;
  sndio_driver_t  *this;

  lprintf ("audio_sndio_out: open_plugin called\n");

+  AUDIO_DEVICE_SPEAKER_ARRANGEMENT_TYPES;
+  int speakers;
+
+  speakers = config->register_enum (config,
+      "audio.output.speaker_arrangement",
+      STEREO,
+      (char **)speaker_arrangement,
+      AUDIO_DEVICE_SPEAKER_ARRANGEMENT_HELP,
+      0, sndio_speaker_arrangement_cb, this);
+
  this = calloc(1, sizeof (sndio_driver_t));
  if (!this)
    return NULL;
@@ -333,10 +353,16 @@ static ao_driver_t *open_plugin (audio_driver_class_t
   * Set capabilities
   */
  this->capabilities = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO |
-    AO_CAP_MODE_4CHANNEL | AO_CAP_MODE_4_1CHANNEL |
-    AO_CAP_MODE_5CHANNEL | AO_CAP_MODE_5_1CHANNEL |
    AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL | AO_CAP_8BITS |
    AO_CAP_16BITS;
+  if (speakers == SURROUND4)
+    this->capabilities |= AO_CAP_MODE_4CHANNEL;
+  if (speakers == SURROUND41)
+    this->capabilities |= AO_CAP_MODE_4_1CHANNEL;
+  if (speakers == SURROUND5)
+    this->capabilities |= AO_CAP_MODE_5CHANNEL;
+  if (speakers == SURROUND51)
+    this->capabilities |= AO_CAP_MODE_5_1CHANNEL;

  this->ao_driver.get_capabilities  = ao_sndio_get_capabilities;
  this->ao_driver.get_property      = ao_sndio_get_property;
@@ -352,6 +378,32 @@ static ao_driver_t *open_plugin (audio_driver_class_t
  this->ao_driver.control           = ao_sndio_ctrl;

  return &this->ao_driver;
+}
+
+static void sndio_speaker_arrangement_cb (void *user_data,
+                                  xine_cfg_entry_t *entry) {
+  sndio_driver_t *this = (sndio_driver_t *) user_data;
+  int32_t value = entry->num_value;
+  if (value == SURROUND4) {
+    this->capabilities |= AO_CAP_MODE_4CHANNEL;
+  } else {
+    this->capabilities &= ~AO_CAP_MODE_4CHANNEL;
+  }
+  if (value == SURROUND41) {
+    this->capabilities |= AO_CAP_MODE_4_1CHANNEL;
+  } else {
+    this->capabilities &= ~AO_CAP_MODE_4_1CHANNEL;
+  }
+  if (value == SURROUND5) {
+    this->capabilities |= AO_CAP_MODE_5CHANNEL;
+  } else {
+    this->capabilities &= ~AO_CAP_MODE_5CHANNEL;
+  }
+  if (value >= SURROUND51) {
+    this->capabilities |= AO_CAP_MODE_5_1CHANNEL;
+  } else {
+    this->capabilities &= ~AO_CAP_MODE_5_1CHANNEL;
+  }
}

/*

Reply via email to