Ticket #133 (closed defect: fixed)

Opened 3 years ago

Last modified 2 years ago

ALSA's SND_PCM_FORMAT_U16_BE (and LE) not supported, Allegro fails to initialize sound

Reported by: izm Owned by: lennart
Milestone: Component: module-alsa-*
Keywords: allegro alsa format snd_pcm_format Cc: steven.w.j.brown@…

Description

Not sure which project this is a bug of, but I figured I'd let you guys know and sort it out, since you'd be much more capable than me. :)

I'm using Pulseaudio o.9.5, Advanced Linux Sound Architecture Driver Version 1.0.14rc1, and Allegro 4.2. When Allegro (it's a cross-platform game development library, similar to SDL) attempts to initialize sound using ALSA, it fails with this message:

ALSA: snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) : Invalid argument

If I kill the pulseaudio daemon, it works (not going through pulseaudio, I guess). I'm unfamiliar with all this, but I looked at the allegro sources, and it looks like they're supporting alsa version 0.9 (and 0.5)... which is backwards compatible with ALSA but not Pulseaudio?

I've attached a simple program that performs a few tests and will generate the error on my system. I'm sorry if this is the wrong place to post this bug, but I wasn't sure where to put it. Suggestions?

Thanks.

Here's the output from the sample program when pulseaudio is running:

detect_digi_driver() attempts:_____________

DIGI_AUTODETECT: num channels: 65535
DIGI_NONE: num channels: 65535
DIGI_OSS: not detected 
DIGI_ESD: num channels: 64
DIGI_ARTS: num channels: 65535
DIGI_ALSA: num channels: 64
DIGI_JACK: num channels: 65535

install_sound attempts:_____________

install_sound ()
        using: DIGI/MIDI_AUTODETECT and DIGI/MIDI_AUTODETECT
ALSA lib rawmidi_hw.c:233:(snd_rawmidi_hw_open) open /dev/snd/midiC0D0 failed: No such file or directory
        Failed
        ALSA: snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) : Invalid argument
install_sound ()
        using: DIGI/MIDI_AUTODETECT and DIGI/MIDI_NONE
        Failed
        ALSA: snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) : Invalid argument
install_sound ()
        using: DIGI_OSS and DIGI/MIDI_NONE
        Failed
        /dev/dsp: Device or resource busy
install_sound ()
        using: DIGI_ESD and DIGI/MIDI_NONE
        Succeeded
install_sound ()
        using: DIGI_ARTS and DIGI/MIDI_NONE
        Failed
        ALSA: snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) : Invalid argument
install_sound ()
        using: DIGI_ALSA and DIGI/MIDI_NONE
        Failed
        ALSA: snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) : Invalid argument
install_sound ()
        using: DIGI_JACK and DIGI/MIDI_NONE
        Failed
        ALSA: snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) : Invalid argument

After I kill pulseaudio, I get this output:

detect_digi_driver() attempts:_____________

DIGI_AUTODETECT: num channels: 65535
DIGI_NONE: num channels: 65535
DIGI_OSS: num channels: 64
DIGI_ESD: not detected 
DIGI_ARTS: num channels: 65535
*** PULSEAUDIO: Unable to connect: Connection refused
DIGI_ALSA: not detected 
DIGI_JACK: num channels: 65535

install_sound attempts:_____________

install_sound ()
        using: DIGI/MIDI_AUTODETECT and DIGI/MIDI_AUTODETECT
*** PULSEAUDIO: Unable to connect: Connection refused
ALSA lib rawmidi_hw.c:233:(snd_rawmidi_hw_open) open /dev/snd/midiC0D0 failed: No such file or directory
        Failed
        No supported synth type found
install_sound ()
        using: DIGI/MIDI_AUTODETECT and DIGI/MIDI_NONE
*** PULSEAUDIO: Unable to connect: Connection refused
        Succeeded
install_sound ()
        using: DIGI_OSS and DIGI/MIDI_NONE
        Succeeded
install_sound ()
        using: DIGI_ESD and DIGI/MIDI_NONE
        Failed
        No server: can not open
install_sound ()
        using: DIGI_ARTS and DIGI/MIDI_NONE
*** PULSEAUDIO: Unable to connect: Connection refused
        Succeeded
install_sound ()
        using: DIGI_ALSA and DIGI/MIDI_NONE
*** PULSEAUDIO: Unable to connect: Connection refused
        Failed
        Can not open card/pcm device
install_sound ()
        using: DIGI_JACK and DIGI/MIDI_NONE
*** PULSEAUDIO: Unable to connect: Connection refused
        Succeeded

(not sure if that's useful... .)

Attachments

allegro-sound-test.tar.gz (6.2 kB) - added by izm 3 years ago.
small program to test detecting and setting up sound using allegro
.asoundrc (189 bytes) - added by izm 3 years ago.
~/.asoundrc
.asoundrc.asoundconf (305 bytes) - added by izm 3 years ago.
~/.asoundrc.asoundconf (generated by asoundconf)
asound.conf (157 bytes) - added by izm 3 years ago.
/etc/asound.conf
default.pa (3.5 kB) - added by izm 3 years ago.
/etc/pulse/default.pa (can't recall if I modified this...)

Change History

Changed 3 years ago by izm

small program to test detecting and setting up sound using allegro

Changed 3 years ago by izm

  • cc steven.w.j.brown@… added

Changed 3 years ago by izm

~/.asoundrc

Changed 3 years ago by izm

~/.asoundrc.asoundconf (generated by asoundconf)

Changed 3 years ago by izm

/etc/asound.conf

Changed 3 years ago by izm

/etc/pulse/default.pa (can't recall if I modified this...)

Changed 3 years ago by izm

I've informed the Allegro developers about this.

Maybe they have an idea. :)

Changed 3 years ago by izm

  • keywords format snd_pcm_format added
  • summary changed from Allegro fails to initialize sound to ALSA's SND_PCM_FORMAT_U16_BE (and LE) not supported, Allegro fails to initialize sound

After some (a lot of) poking, I've discovered that Allegro uses SND_PCM_FORMAT_U16_BE and SND_PCM_FORMAT_U16_LE to set the format, and these are NOT DEFINED in PA's alsa-util.c. alsa-util.c only defines translations for SND_PCM_FORMAT_S16_LE and SND_PCM_FORMAT_S16_BE, but not the unsigned equivalents, so Allegro's sound format gets assigned PA_SAMPLE_INVALID, which of course would make the "Invalid argument" message make sense.

Tanuk, in IRC, suggested that either more formats could be added to the alsa plugin which would perform the translation, or more formats could be supported in pulseaudio.

The ALSA driver for Allegro can be seen here: alsa9.c

Here's a snip of the code that handles the format, from the alsa_init() function:

format = ((alsa_bits == 16) ? SND_PCM_FORMAT_U16_NE : SND_PCM_FORMAT_U8);

   switch (format) {

      case SND_PCM_FORMAT_U8:
	 alsa_bits = 8;
	 break;

      case SND_PCM_FORMAT_U16_NE:
	 if (sizeof(short) != 2) {
	    ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
	    goto Error;
	 }
	 break;

      default:
	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
	 goto Error;
   }

   alsa_sample_size = (alsa_bits / 8) * (alsa_stereo ? 2 : 1);

   if (fragsize == 0) {
      unsigned int size = alsa_rate * ALSA_DEFAULT_BUFFER_MS / 1000 / numfrags;
      fragsize = 1;
      while (fragsize < size)
	 fragsize <<= 1;
   }

   snd_pcm_hw_params_malloc(&hwparams);
   snd_pcm_sw_params_malloc(&swparams);

   ALSA9_CHECK(snd_pcm_hw_params_any(pcm_handle, hwparams));
   ALSA9_CHECK(snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED));
   ALSA9_CHECK(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format));

where the macros of importance are:

#ifndef SND_PCM_FORMAT_S16_NE
   #ifdef ALLEGRO_BIG_ENDIAN
      #define SND_PCM_FORMAT_S16_NE SND_PCM_FORMAT_S16_BE
   #else
      #define SND_PCM_FORMAT_S16_NE SND_PCM_FORMAT_S16_LE
   #endif
#endif
#ifndef SND_PCM_FORMAT_U16_NE
   #ifdef ALLEGRO_BIG_ENDIAN
      #define SND_PCM_FORMAT_U16_NE SND_PCM_FORMAT_U16_BE
   #else
      #define SND_PCM_FORMAT_U16_NE SND_PCM_FORMAT_U16_LE
   #endif
#endif

#define ALSA9_CHECK(a) do { \
   int err = (a); \
   if (err<0) { \
      uszprintf(allegro_error, ALLEGRO_ERROR_SIZE, "ALSA: %s : %s", #a, get_config_text(snd_strerror(err))); \
      goto Error; \
   } \
} while(0)

Changed 3 years ago by lennart

  • status changed from new to assigned

Why oh why does allegro use U16 samples? This is so wrong. But yeah, I will fix this eventually.

Changed 3 years ago by elias

Actually, I was wrong on the Allegro mailing list - we do support signed as well as unsigned.

If in the above file, src/unix/alsa9.c, the line "alsa_signed = 0;" is changed to "alsa_signed = 1;", the alsa driver always uses signed instead of unsigned. Now we'd just need someone who knows how to query ALSA about what it supports, and we could fix Allegro's alsa driver.

Changed 3 years ago by lennart

Quite frankly, I know of not a single audio device that can deal with U16 samples natively. If Allegro always generates U16 samples than this is quite a waste of resources because they need to be converted to S16 all the time. Not a good thing.

Changed 3 years ago by elias

Well, the format is specified to be unsigned, and data are user accessible. And it's like that since almost 10 years, so there's no way we can change it now - whatever the reasons were back then to choose unsigned. (Likely, soundblaster 1.0 or whatever was current then used 8-bit unsigned, then when 16-bit support was first added, it was kept unsigned.)

Now, the above change does an XOR with 0x8000 on each 16-bit sample right before providing data to Alsa. So if that indeed is such a waste of resources (myself I'd hope you can hardly notice any performance penalty) - then I'll have a hard time arguing for applying the above change, as Alsa itself certainly can do a much better job converting the format.

What really is needed is a simple way when initializing Alsa to query if it can support unsigned 16-bit (it which case Allegro will keep providing that) or not (in which case we can convert ourselves).. but I wasn't able to learn from the Alsa docs how to do that, after a quick glance.

Changed 3 years ago by elias

  • status changed from assigned to closed
  • resolution set to fixed

I set it to fixed (well, trying, not sure I'm authorized), as someone provided us with a patch to fix it at the Allegro side: http://alleg.svn.sourceforge.net/viewvc/alleg?view=rev&revision=9936

Note: See TracTickets for help on using tickets.