PortAudio / portaudio

PortAudio is a cross-platform, open-source C language library for real-time audio input and output.
Other
1.5k stars 308 forks source link

PA/ALSA doesn't support SND_PCM_FORMAT_S24_3BE input format (Native Instruments Audio4DJ soundcard) #211

Open PortAudio-admin opened 12 years ago

PortAudio-admin commented 12 years ago

Issue created by @RossBencina

Owen Williams reports:

The Native Instruments Audio4DJ soundcard requires a very specific format when recording audio -- SND_PCM_FORMAT_S24_3BE.

This is not supported in PortAudio prior to r1815.

Dmitry committed fixes for this in r1815 and r1822 however they are being rolled back for now pending review.

The most recent code from Dmitry is attached to this ticket.

Proposed fixes to this issue were comitted to trunk but have now been moved to a branch. the original commits were: http://www.assembla.com/code/portaudio/subversion/changesets/1815 http://www.assembla.com/code/portaudio/subversion/changesets/1822

The new branch is here: https://subversion.assembla.com/svn/portaudio/portaudio/branches/alsa_hw_endian_subdevice

PortAudio-admin commented 12 years ago

Comment by @RossBencina

pa_linux_alsa.c.txt

PortAudio-admin commented 12 years ago

Comment by gineera on Assembla

My reading of this issue is as follows:

Portaudio formats are endian-ambiguous, and effectively adopt the endianess of the host platform. In the pa_linux_alsa code these are translated into Alsa formats based on the platform/cpu endianess, and these are used in setting the stream format. When using the 'hw' devices Alsa is prevented from making format conversions, so if this does not correspond to the sound card native format, an error will occur when attempting to set the stream format.

Mostly this is fine since the majority of desktop systems are x86 (LE) and from looking at the Alsa-driver source code, all PCI cards support LE (some also allow BE) and nearly all USB devices are LE.

However, the Audio4 DJ unit unusually operates in BE data format and this is set in the Alsa driver snd-usb-caiaq. When Portaudio, hosted on x86, attempts to set the format of the 'hw' device it requests SND_PCM_FORMAT_S24_3LE and this will fail. But note a simlar problem would happen with LE cards on BE PowerPC platforms etc The problem will occur whenever the native soundcard endianess does not correspond to to the host endianess, and the raw 'hw' device is used. (Network audio would presumably also be BE?)

One straightforward solution should be to use the 'plughw' device, which will convert the format; the simplest way to do that with Portaudio at present is to set the environment variable 'PA_ALSA_PLUGHW' non-zero ( a value of 1 will do). I would be interested to know if that is effective in this case.

Alan

PortAudio-admin commented 12 years ago

Comment by @RossBencina

Alan wrote:

Portaudio formats are endian-ambiguous

By definition all PortAudio formats are in native (host) byte order.

Can you confirm: ALSA formats always explicitly specified BE or LE?

Yes, as a step along the way we need to hear from Owen and RJ whether using plughw solves the problem.

PortAudio-admin commented 12 years ago

Comment by gineera on Assembla

Alsa has both cpu-endian and explicit BE/LE format specifiers (except the 24-bit ones are explicit only). They are correctly used in pa_linux_alsa to request host-platform endianess. But that format is not available from Audio4DJ without Alsa converting the endianess. There is no mechanism in Portaudio-alsa to fall-back to whatever format is available, and pass-on the data for the app to sort out (which would probably be no use anyway).

Using the 'hw' device Alsa always passes the stream on raw and so it carries the endianess of the soundcard even if that differs from the host.

PortAudio-admin commented 12 years ago

Comment by @RossBencina

There is no mechanism in Portaudio-alsa to fall-back to whatever format is available,

So if I understand correctly, hardware that does not support one of the PortAudio host-endian sample formats is not compatible with PortAudio/ALSA using the hw device?

and pass-on the data for the app to sort out (which would probably be no use anyway).

The PortAudio API only supports passing data to PA clients in host byte order. Whether it would be of use isn't relevant here since, there is no plan to change the PA public API to support non-host byte order streams..

PortAudio-admin commented 12 years ago

Comment by gineera on Assembla

Even careful terminology can be ambiguous, I am realising! I may have given the wrong impression.

Alsa only uses explicit-endian formats at the hardware/driver level. Each driver will report it's capabilities, which may be single or multiple, and could include both BE and LE variants of the same format. For most common formats, additional endian-ambiguous definitions are provided that are defined from the endian-specific ones at build-time in a header file, depending upon the host endianess.

So, in the case of the Audio4DJ unit, unless Portaudio expressly uses SND_PCM_FORMAT_S24_3BE when setting the pcm format for the 'hw' device on a LE platform, that params set will fail. Using 'plughw' all the host formats, (including floats, alaw etc) should be acceptable, with Alsa doing whatever is necessary. The 'hw' device works on the basis that 'you get what the hardware can give', in every respect of the data stream - channels, formats (+ endianess), rates.

Note also that this is an unusual 24-bit format, 24 bits in 3 bytes. The much more common SND_PCM_FORMAT_S24_LE (or BE) uses 24 bits in 4 bytes. Most 24 bit PCI cards use the latter, as far as I am aware. The Portaudio code does seem to ignore that distinction.