Thursday, September 29, 2022

Re: xine's ffmpegaudio doesn't downmix, sio_getpar() reports 6 channels instead of 2

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 <adr@SDF.ORG>
> To: misc@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;
> + }
> }
>
> /*

No comments:

Post a Comment