1

I'm writing an audio decoding program for ALSA, which among others detects audio capabilities. It uses the snd_pcm_hw_params_get_XXX() functions for that. This works well on my Ubuntu PC but on Raspberry Pi 3 these calls return no information. They return success but the min and max values are meaningless.

For instance the period:

int err;
snd_pcm_t *pcm;
snd_pcm_hw_params_t *hw_params;
const char* device_name = "hw:0,0";

// open audio device
err = snd_pcm_open(&pcm, device_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed to open audio device '%s': %s\n", device_name, snd_strerror(err));
    return false;
}

// initialize
snd_pcm_hw_params_alloca(&hw_params);
err = snd_pcm_hw_params_any(pcm, hw_params);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed to get hardware parameters: %s\n", snd_strerror(err));
    goto fail;
}

// query period size
snd_pcm_uframes_t period_min;
snd_pcm_uframes_t period_max;
unsigned period_min_us;
unsigned period_max_us;

err = snd_pcm_hw_params_get_period_size_min(hw_params, &period_min, NULL);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed to get minimum period time: %s\n", snd_strerror(err));
    goto fail;
}
err = snd_pcm_hw_params_get_period_size_max(hw_params, &period_max, NULL);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed to get maximum period time: %s\n", snd_strerror(err));
    goto fail;
}
err = snd_pcm_hw_params_get_period_time_min(hw_params, &period_min_us, NULL);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed to get minimum period time: %s\n", snd_strerror(err));
    goto fail;
}
err = snd_pcm_hw_params_get_period_time_max(hw_params, &period_max_us, NULL);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed to get maximum period time: %s\n", snd_strerror(err));
    goto fail;
}
LOG(LOG_DEBUG, LOG_OBJ "Supported period: %lu to %lu frames (%u to %u us)\n",
        (unsigned long)period_min, (unsigned long)period_max,
        period_min_us, period_max_us);

This prints:

Supported period: 0 to 0 frames (1 to 0 us)

Or the buffer size:

snd_pcm_uframes_t buffer_min;
snd_pcm_uframes_t buffer_max;
unsigned buffer_min_us;
unsigned buffer_max_us;
err = snd_pcm_hw_params_get_buffer_size_min(hw_params, &buffer_min);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed get minimum buffer time: %s\n", snd_strerror(err));
    goto fail;
}
err = snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_max);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed get maximum buffer time: %s\n", snd_strerror(err));
    goto fail;
}
err = snd_pcm_hw_params_get_buffer_time_min(hw_params, &buffer_min_us, NULL);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed get minimum buffer time: %s\n", snd_strerror(err));
    goto fail;
}
err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &buffer_max_us, NULL);
if (err < 0) {
    LOG(LOG_ERROR, LOG_OBJ "Failed get maximum buffer time: %s\n", snd_strerror(err));
    goto fail;
}
LOG(LOG_DEBUG, LOG_OBJ "Supported buffer size: %lu to %lu frames (%u to %u us)\n",
        (unsigned long)buffer_min, (unsigned long)buffer_max,
        buffer_min_us, buffer_max_us);

This prints:

Supported buffer size: 0 to 0 frames (1 to 0 us)

And so on. Same for the number of periods and channels. On the other hand the snd_pcm_hw_params_test_XXX() calls do work and that way I can detect the rates, formats, accesses.

Why do the get functions return no meaningful information? Am I doing something wrong? And more importantly, how can I get the buffering and channel information also on Raspberry Pi?

Brain
  • 311
  • 2
  • 12
  • If you run the [original program](https://www.spinics.net/linux/fedora/alsa-user/msg07230.html) unchanged, does it work? – CL. Sep 04 '17 at 13:24
  • That's a god observation. Indeed I have used the original program as the base. But also the original program unchanged just prints Device: hw:0,0 (type: HW) Access types: MMAP_INTERLEAVED RW_INTERLEAVED Formats: U8 S16_LE and then hangs. It does not even print "Channels:" any more, which is really odd... – Brain Sep 04 '17 at 15:11
  • I guess the `max` channels value is zero. – CL. Sep 04 '17 at 15:34
  • Did you ever recompile the kernel or alsa-lib, or did you install them from a non-standard source? – CL. Sep 04 '17 at 15:35
  • I have rebuilt the kernel using Buildroot and the custom repo https://github.com/raspberrypi/linux.git This should IMHO have no negative effect. The "Channels" string should be printed regardless the `max` channels value. If it doesn't print it means that either `snd_pcm_hw_params_get_channels_min()` or `snd_pcm_hw_params_get_channels_max` is hanging. – Brain Sep 04 '17 at 17:16
  • 1
    With some more debug using gdb it seems the Pi's `libasound 1.0.28` returns the min and max channels as **return value** instead in the provided pointer (the min call returns 1 and the max call returns 2). This is conflicting the alsa-lib doc, which says they should return 0. Is it to be expected in an older version of libasound (my PC has 1.1.0 installed)? – Brain Sep 04 '17 at 17:26
  • 1
    1.0.28 is three years old. Anyway, `libasound` also contains backwards-compatible functions for versions 0.9.x, and it appears you are calling those; apparently, something went wrong when compiling the library. – CL. Sep 04 '17 at 20:56
  • The library is the original from the Raspberry Pi's binary image. Apparently it is broken. I will try to compile the `libasound` from the recent sources. – Brain Sep 05 '17 at 08:20
  • How did you compile your program? Standard `-lasound`? No special `#define`s? – CL. Sep 05 '17 at 08:51
  • Just with the standard `-lasound`. – Brain Sep 05 '17 at 10:19

0 Answers0