Asusio
Asusio

Reputation: 27

Alsa lib 32 bits

I've been trying to use the ALSA lib for a while and I don't understand how I should use it.

I took an example program and I've tried to modify it to use float (32bits) instead of unsigned char (8bits). But now when I'm running it, I have a segmentation fault in the second loop.

Here is my code :

#include <alsa/asoundlib.h>




snd_pcm_t *create_pcm(const char* name, snd_pcm_stream_t mode, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int nbChannel, unsigned int rate, int softSample, unsigned int latency)
{
    int err;
    snd_pcm_t *handle;

    if ((err = snd_pcm_open(&handle, name, mode, 0)) < 0) {
        printf("Playback open error: %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }

    if ((err = snd_pcm_set_params(handle,
                                  format,
                                  access,
                                  nbChannel,
                                  rate,
                                  softSample,
                                  latency)) < 0) {   /* 0.5sec */
        printf("Playback open error: %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }

    return handle;
}



int main(void)
{
    unsigned int i;
    snd_pcm_t *handle;
    snd_pcm_sframes_t frames;
    float buffer[16*1024];              /* some random data */


    handle = create_pcm("default", // name of the device used by the sound card
                        SND_PCM_STREAM_PLAYBACK, // to use the device in output
                        SND_PCM_FORMAT_FLOAT, // use the device with 32bit depth (float)
                        SND_PCM_ACCESS_RW_INTERLEAVED,
                        1, // use 1 channel
                        48000, // use 48000 Hz (dvd quality)
                        1, // soft resample ON
                        500000); // 0.5s of latency


    // building random data
    for(i = 0; i < sizeof(buffer); i++)
        buffer[i] = i % 255; // random();





    for (i = 0; i < 16; i++) {
        frames = snd_pcm_writei(handle, buffer, sizeof(buffer)); // segmentation fault
        if(frames < 0)
            frames = snd_pcm_recover(handle, frames, 0);
        if (frames < 0) {
            printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
            break;
        }
        if (frames > 0 && frames < (long)sizeof(buffer))
            printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames);
    }

    snd_pcm_close(handle);
    return 0;
}

How to use this lib with 32bits?

I've tried this format and others like little endian or big endian.. The only one that doesn't crash is SND_PCM_FORMAT_FLOAT but it's making the error :

ALSA lib pcm.c:8507:(snd_pcm_set_params) Sample format not available for PLAYBACK: Invalid argument
Playback open error: Invalid argument

Thanks in advance.

P.S.: Linux, Ubuntu 19.10 64bits

Upvotes: 0

Views: 754

Answers (2)

Asusio
Asusio

Reputation: 27

It was indeed a problem of condition in my loop and my snd_pcm_writei()

Here is the code without errors thanks to @Osiris :

#include <alsa/asoundlib.h>




snd_pcm_t *create_pcm(const char* name, snd_pcm_stream_t mode, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int nbChannel, unsigned int rate, int softSample, unsigned int latency)
{
    int err;
    snd_pcm_t *handle;

    if ((err = snd_pcm_open(&handle, name, mode, 0)) < 0) {
        printf("Playback open error: %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }

    if ((err = snd_pcm_set_params(handle,
                                  format,
                                  access,
                                  nbChannel,
                                  rate,
                                  softSample,
                                  latency)) < 0) {   /* 0.5sec */
        printf("Playback open error: %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }

    return handle;
}



int main(void)
{
    unsigned int i;
    snd_pcm_t *handle;
    snd_pcm_sframes_t frames;
    float buffer[16*1024];              /* some random data */


    handle = create_pcm("default", // name of the device used by the sound card
                        SND_PCM_STREAM_PLAYBACK, // to use the device in output
                        SND_PCM_FORMAT_FLOAT, // use the device with 32bit depth (float)
                        SND_PCM_ACCESS_RW_INTERLEAVED,
                        1, // use 1 channel
                        48000, // use 48000 Hz (dvd quality)
                        1, // soft resample ON
                        500000); // 0.5s of latency


    // building random data
    for(i = 0; i < sizeof(buffer) / sizeof(*buffer); i++)
        buffer[i] = i % 0xffffffff; // random();





    for (i = 0; i < 16; i++) {
        frames = snd_pcm_writei(handle, buffer, sizeof(buffer) / sizeof(*buffer)); // segmentation fault
        if(frames < 0)
            frames = snd_pcm_recover(handle, frames, 0);
        if (frames < 0) {
            printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
            break;
        }
        if (frames > 0 && frames < (long)(sizeof(buffer) / sizeof(*buffer)))
            printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames);
    }

    snd_pcm_close(handle);
    return 0;
}

Upvotes: 0

Osiris
Osiris

Reputation: 2823

The segmentation fault may already occur when you write into buffer:

for(i = 0; i < sizeof(buffer); i++)
    buffer[i] = i % 255; // random();

sizeof(buffer) will give you the size in bytes not the number of elements. They are only equal for char (and unsigned char) since sizeof(char) is 1. You most likely want to iterate over the elements:

for(i = 0; i < sizeof buffer/sizeof *buffer; i++)
    buffer[i] = i % 255; // random();

Upvotes: 1

Related Questions