alsa-project / alsa-lib

The Advanced Linux Sound Architecture (ALSA) - library
GNU Lesser General Public License v2.1
375 stars 177 forks source link

alsa cant initialize on raspberry pi 5 #386

Open sy-project opened 9 months ago

sy-project commented 9 months ago

I can use alsa command

# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: sndrpihifiberry [snd_rpi_hifiberry_dacplusadcpro], device 0: HiFiBerry DAC+ADC Pro HiFi multicodec-0 [HiFiBerry DAC+ADC Pro HiFi multicodec-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
# arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: sndrpihifiberry [snd_rpi_hifiberry_dacplusadcpro], device 0: HiFiBerry DAC+ADC Pro HiFi multicodec-0 [HiFiBerry DAC+ADC Pro HiFi multicodec-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

and I can aplay to use wav file.

# aplay -D hw:0,0 /root/C_Code/audiotest/test1.wav
Playing WAVE '/root/C_Code/audiotest/test1.wav' : Signed 32 bit Little Endian, Rate 48000 Hz, Stereo

but I cant initialize on c code. my code is here.

    printf("alsa start\n");
    int err;
    snd_pcm_t *capture_handle, *playback_handle;
    snd_pcm_hw_params_t *hw_params;
    unsigned char *buffer;
    int sample_rate = SAMPLE_RATE;
    int dir;
    snd_pcm_uframes_t frames = 32;
    snd_pcm_uframes_t bufferSize, periodSize;
    double x_prev = 0.0;
    double y_prev = 0.0;
    double b0 = 1.0;
    double b1 = -0.8;
    double a1 = 0.0;

    printf("alsa open capture handle\n");
    err = snd_pcm_open(&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 0);
    if(err < 0)
    {
        fprintf(stderr, "Capture open error: %s\n", snd_strerror(err));
        exit(1);
    }

    printf("alsa open playback handle\n");
    err = snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
    if(err < 0)
    {
        fprintf(stderr, "Playback open error: %s\n", snd_strerror(err));
        exit(1);
    }

    printf("alsa pcm hw param alloc\n");
    snd_pcm_hw_params_alloca(&hw_params);

    printf("alsa capture_handle set start\n");
    err = snd_pcm_hw_params_any(capture_handle, hw_params);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_any cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_access cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_format(capture_handle, hw_params, SND_PCM_FORMAT_S16_LE);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_format cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, NUM_CHANNELS);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_channels cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &sample_rate, &dir);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_rate_near cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_buffer_size_near(capture_handle, hw_params, &bufferSize);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_buffer_size_near cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params, &periodSize, &dir);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_period_size_near cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params(capture_handle, hw_params);
    if (err < 0) {
        fprintf(stderr, "alsa cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    snd_pcm_hw_params_get_buffer_size(hw_params, &bufferSize);
    snd_pcm_hw_params_get_period_size(hw_params, &periodSize, &dir);

    printf("Buffer size: %lu frames\n", bufferSize);
    printf("Period size: %lu frames\n", periodSize);

    printf("alsa playback_handle set start\n");
    snd_pcm_hw_params_any(playback_handle, hw_params);
    snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_channels(playback_handle, hw_params, NUM_CHANNELS);
    snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &sample_rate, 0);
    snd_pcm_hw_params(playback_handle, hw_params);
    printf("alsa playback_handle set success\n");

    printf("alsa buf malloc\n");
    buffer = (unsigned char*)malloc(BUFFER_SIZE*NUM_CHANNELS*2);

    while(1)
    {
        printf("main loop start\n");
        err = snd_pcm_readi(capture_handle, buffer, BUFFER_SIZE);
        if(err<0)
        {
            fprintf(stderr, "Capture read error[%d]: %s\n", err, snd_strerror(err));
            break;
        }

        for(int i = 0; i < BUFFER_SIZE * NUM_CHANNELS * 2; i += 2)
        {
            short sample = ((short)buffer[i + 1] << 8) | buffer[i];
            double x = (double)sample / 32768.0;

            double y = b0 * x + b1 * x_prev + a1 * y_prev;

            x_prev = x;
            y_prev = y;

            short filter_sample = (short)(y * 32768.0);
            buffer[i] = (unsigned char)(filter_sample & 0xFF);
            buffer[i+1] = (unsigned char)((filter_sample >> 8) & 0xFF);
        }

        err = snd_pcm_writei(playback_handle, buffer, BUFFER_SIZE);
        if(err < 0)
        {
            fprintf(stderr, "Playback write error: %s\n", snd_strerror(err));
            break;
        }
    }
    free(buffer);
    snd_pcm_close(capture_handle);
    snd_pcm_close(playback_handle);
    exit(0);

This code said

alsa start
alsa open capture handle
alsa open playback handle
alsa pcm hw param alloc
alsa capture_handle set start
snd_pcm_hw_params_set_buffer_size_near cant set hw params. [Invalid argument]

what should I do?

sy-project commented 9 months ago

and I use this code. but this code has error, too.

    printf("alsa start\n");
    int err;
    snd_pcm_t *capture_handle, *playback_handle;
    snd_pcm_hw_params_t *hw_params;
    unsigned char *buffer;
    int sample_rate = SAMPLE_RATE;
    double x_prev = 0.0;
    double y_prev = 0.0;
    double b0 = 1.0;
    double b1 = -0.8;
    double a1 = 0.0;

    printf("alsa open capture handle\n");
    err = snd_pcm_open(&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 0);
    if(err < 0)
    {
        fprintf(stderr, "Capture open error: %s\n", snd_strerror(err));
        exit(1);
    }

    printf("alsa open playback handle\n");
    err = snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
    if(err < 0)
    {
        fprintf(stderr, "Playback open error: %s\n", snd_strerror(err));
        exit(1);
    }

    printf("alsa pcm hw param alloc\n");
    snd_pcm_hw_params_alloca(&hw_params);

    printf("alsa capture_handle set start\n");
    err = snd_pcm_hw_params_any(capture_handle, hw_params);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_any cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_access cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_format(capture_handle, hw_params, SND_PCM_FORMAT_S16_LE);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_format cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, NUM_CHANNELS);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_channels cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &sample_rate, 0);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_rate_near cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params(capture_handle, hw_params);
    if (err < 0) {
        fprintf(stderr, "alsa cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }

    printf("alsa playback_handle set start\n");
    err = snd_pcm_hw_params_any(playback_handle, hw_params);
    if (err < 0) {
        fprintf(stderr, "playback_handle cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_access cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_S16_LE);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_format cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, NUM_CHANNELS);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_channels cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &sample_rate, 0);
    if (err < 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_rate_near cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    err = snd_pcm_hw_params(playback_handle, hw_params);
    if (err < 0) {
        fprintf(stderr, "alsa cant set hw params. [%s]\n", snd_strerror(err));
        exit(1);
    }
    printf("alsa playback_handle set success\n");

    printf("alsa buf malloc\n");
    buffer = (unsigned char*)malloc(BUFFER_SIZE*NUM_CHANNELS*2);

    while(1)
    {
        printf("main loop start\n");
        err = snd_pcm_readi(capture_handle, buffer, BUFFER_SIZE);
        if(err<0)
        {
            fprintf(stderr, "Capture read error[%d]: %s\n", err, snd_strerror(err));
            break;
        }

        for(int i = 0; i < BUFFER_SIZE * NUM_CHANNELS * 2; i += 2)
        {
            short sample = ((short)buffer[i + 1] << 8) | buffer[i];
            double x = (double)sample / 32768.0;

            double y = b0 * x + b1 * x_prev + a1 * y_prev;

            x_prev = x;
            y_prev = y;

            short filter_sample = (short)(y * 32768.0);
            buffer[i] = (unsigned char)(filter_sample & 0xFF);
            buffer[i+1] = (unsigned char)((filter_sample >> 8) & 0xFF);
        }

        err = snd_pcm_writei(playback_handle, buffer, BUFFER_SIZE);
        if(err < 0)
        {
            fprintf(stderr, "Playback write error: %s\n", snd_strerror(err));
            break;
        }
    }
    free(buffer);
    snd_pcm_close(capture_handle);
    snd_pcm_close(playback_handle);
    exit(0);

terminal

alsa start
alsa open capture handle
alsa open playback handle
alsa pcm hw param alloc
alsa capture_handle set start
alsa playback_handle set start
alsa playback_handle set success
alsa buf malloc
main loop start
Capture read error[-5]: Input/output error
z-s-e commented 9 months ago

I believe this bug tracker is not the right place to ask for code reviews. Alsa is clearly working on your raspi, as you verified that with aplay yourself, so there must be bugs in your own code. For the first error it seems you do not initialize bufferSize or periodSize with reasonable values, it even tells you that in the error.

Whenever your code is not working, I generally recommend comparing your code very carefully to working code or examples such as this one and try to find the problematic places yourself first before asking for help - that is also a good way to learn finding and fixing bugs by yourself.