Context :
- I’m working on Linux, x86_64, recent kernel (customized 6.1.68), but the code will be cross-compiled for Windows later (no problem with that)
- sdl2-config --version returns : 2.28.4
- inxi -F returns, for the audio part :
Audio: Device-1: Intel Tiger Lake-LP Smart Sound Audio driver: snd_hda_intel
Device-2: Logitech HD Pro Webcam C920 type: USB driver: snd-usb-audio,uvcvideo
Sound Server: ALSA v: k6.1.68-ericb
And I’m trying to record audio+video with a Logitech C920 webcam.
For obvious portability reasons, my choice is to use SDL2 (I’ll try the promising SDL3 asap).
As a summary, actually, recording audio+video works, but audio is suboptimal, and I’d like to fix the problem seriously.
Separately, there are NO problem at all :
- record video alone works since years, using OpenCV + OpenGL or OpenGLES (even Vulkan works well) ;
- record audio alone using alsa only works finely (see GitHub - ebachard/Linux_Alsa_Audio_Record: Very simple Linux audio recording using Alsa) ;
- record both audio+video works with ffmpeg in one command line, but that’s not my need.
and when using ALSA directly, the AUDIO_S16LSB format works as expected, in stereo mode, and the sound is perfect for my need.
(see https://github.com/ebachard/Linux_Alsa_Audio_Record/blob/master/src/alsa_record.cpp in the sources)
And I observed that, when recording, the SDL2 alsa audio driver, does not work as expected. More precisely, AUDIO_S16LSB format is NOT detected. So I tried to find what happens with SDL2.
Methodology: I compared SDL alsa driver intialisation to my own alsa driver initialisation.
I did first study how works alsa driver. Adding some verbosity, my webcam, in recording mode, is seen by SDL2 alsa audio driver as
INFO: Using audio driver: alsa
this->spec.format : 8 (should be AUDIO_S16LSB)
this->spec.format = SND_PCM_FORMAT_U24_LE. It means, it’s an unsigned 24 bit Little Endian
using low three bytes in 32-bit word (not handled by SDL …)
Investigating alsa sources, (for example enum snd_pcm_format_t — ALSA Library Documentation), I found :
SND_PCM_FORMAT_S24_BE,
/** Unsigned 24 bit Little Endian using low three bytes in 32-bit word */
SND_PCM_FORMAT_U24_LE,
/** Unsigned 24 bit Big Endian using low three bytes in 32-bit word */
That means SND_PCM_FORMAT_U24* formats are seen by alsa as 32-bit words (indeed, after some tries, looks like the -planar- bytes are grouped by 3, sort of LLL RRR planar)
This case is obviously internaly managed by alsa library (see https://github.com/alsa-project/alsa-lib/blob/master/src/pcm/pcm_misc.c for further information)
Note: full C920 detected features are provided at the end of my post.
Back to SDL2 source code, there is NO trace of SND_PCM_FORMAT_U24* at least in 2.28.4 version, and I wonder what I can do to find a clean solution.
My questions now :
Is SDL2 alsa audio driver missing some cases ?
Do you have a solution/workaround ? Of course if the solution is simply not implemented, and not too complicated, I can propose a patch or something close to help, but I need SDL audio experts answers before.
Any suggestion is welcome. Thanks in advance for any help
Complement: full C920 detected features
ALSA library version: 1.2.2
PCM stream types:
PLAYBACK
CAPTURE
PCM access types:
MMAP_INTERLEAVED
MMAP_NONINTERLEAVED
MMAP_COMPLEX
RW_INTERLEAVED
RW_NONINTERLEAVED
PCM formats:
S8 (Signed 8 bit)
U8 (Unsigned 8 bit)
S16_LE (Signed 16 bit Little Endian)
S16_BE (Signed 16 bit Big Endian)
U16_LE (Unsigned 16 bit Little Endian)
U16_BE (Unsigned 16 bit Big Endian)
S24_LE (Signed 24 bit Little Endian)
S24_BE (Signed 24 bit Big Endian)
U24_LE (Unsigned 24 bit Little Endian)
U24_BE (Unsigned 24 bit Big Endian)
S32_LE (Signed 32 bit Little Endian)
S32_BE (Signed 32 bit Big Endian)
U32_LE (Unsigned 32 bit Little Endian)
U32_BE (Unsigned 32 bit Big Endian)
FLOAT_LE (Float 32 bit Little Endian)
FLOAT_BE (Float 32 bit Big Endian)
FLOAT64_LE (Float 64 bit Little Endian)
FLOAT64_BE (Float 64 bit Big Endian)
IEC958_SUBFRAME_LE (IEC-958 Little Endian)
IEC958_SUBFRAME_BE (IEC-958 Big Endian)
MU_LAW (Mu-Law)
A_LAW (A-Law)
IMA_ADPCM (Ima-ADPCM)
MPEG (MPEG)
GSM (GSM)
S20_LE (Signed 20 bit Little Endian in 4 bytes, LSB justified)
S20_BE (Signed 20 bit Big Endian in 4 bytes, LSB justified)
U20_LE (Unsigned 20 bit Little Endian in 4 bytes, LSB justified)
U20_BE (Unsigned 20 bit Big Endian in 4 bytes, LSB justified)
SPECIAL (Special)
S24_3LE (Signed 24 bit Little Endian in 3bytes)
S24_3BE (Signed 24 bit Big Endian in 3bytes)
U24_3LE (Unsigned 24 bit Little Endian in 3bytes)
U24_3BE (Unsigned 24 bit Big Endian in 3bytes)
S20_3LE (Signed 20 bit Little Endian in 3bytes)
S20_3BE (Signed 20 bit Big Endian in 3bytes)
U20_3LE (Unsigned 20 bit Little Endian in 3bytes)
U20_3BE (Unsigned 20 bit Big Endian in 3bytes)
S18_3LE (Signed 18 bit Little Endian in 3bytes)
S18_3BE (Signed 18 bit Big Endian in 3bytes)
U18_3LE (Unsigned 18 bit Little Endian in 3bytes)
U18_3BE (Unsigned 18 bit Big Endian in 3bytes)
G723_24 (G.723 (ADPCM) 24 kbit/s, 8 samples in 3 bytes)
G723_24_1B (G.723 (ADPCM) 24 kbit/s, 1 sample in 1 byte)
G723_40 (G.723 (ADPCM) 40 kbit/s, 8 samples in 3 bytes)
G723_40_1B (G.723 (ADPCM) 40 kbit/s, 1 sample in 1 byte)
DSD_U8 (Direct Stream Digital, 1-byte (x8), oldest bit in MSB)
DSD_U16_LE (Direct Stream Digital, 2-byte (x16), little endian, oldest bits in MSB)
DSD_U32_LE (Direct Stream Digital, 4-byte (x32), little endian, oldest bits in MSB)
DSD_U16_BE (Direct Stream Digital, 2-byte (x16), big endian, oldest bits in MSB)
DSD_U32_BE (Direct Stream Digital, 4-byte (x32), big endian, oldest bits in MSB)
PCM subformats:
STD (Standard)
PCM states:
OPEN
SETUP
PREPARED
RUNNING
XRUN
DRAINING
PAUSED
SUSPENDED
DISCONNECTED