alsa-project / alsa-lib

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

snd_pcm_readn hangs at record & playback on same device #368

Closed nodemand closed 7 months ago

nodemand commented 7 months ago

I'm on a RPi5 4GB running Raspberry Pi OS 64bit Bookworm and my application hangs on snd_pcm_readn when I try to read and write to the same device. This occurs on an IQAudio Codec Zero sound card and on a HifiBerry DAC+ADC Pro as well. When I select a USB sound card as the output and one of the others described for input everything works like it should.

Here is my code:

#include <alsa/asoundlib.h>
#include <alsa/control.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <algorithm>
#include <iterator>

typedef   signed short  drwav_int16;
typedef   signed int    drwav_int32;

#define PCM_DEVICE_IN "plughw:Zero,0"
#define PCM_DEVICE_OUT "plughw:Zero,0" //"plughw:Device,0"

int err, result, loops, n, t;
unsigned int rate, pcm, tmp;

snd_pcm_t           *play;
snd_pcm_t           *record;
snd_pcm_hw_params_t *playparams;
snd_pcm_hw_params_t *recordparams;
snd_pcm_uframes_t   frames;
snd_pcm_sframes_t   recresult;
snd_pcm_format_t    format = SND_PCM_FORMAT_S16_LE;
int                 block = 0;//SND_PCM_NONBLOCK;

int buffer_frames           =   1024;
int bits_per_frame          =   16;
const int bits_per_byte     =   8;
int channels                =   2;

int bytesize_per_channel    =   buffer_frames 
                                * bits_per_frame 
                                / bits_per_byte;

int main(int argc, char **argv) {
    if (argc < 3) {
        printf("Usage: %s <sample_rate> <frames>\n", argv[0]);
        return -1;
    }

    rate            = atoi(argv[1]);
    buffer_frames   = atoi(argv[2]);

    bytesize_per_channel    =   buffer_frames 
                                * snd_pcm_format_width(format)  
                                / bits_per_byte;

    drwav_int16 *buffer_in[channels];

    /* Open the PCM device in record mode */
    if ((pcm = snd_pcm_open(&record, PCM_DEVICE_IN, SND_PCM_STREAM_CAPTURE, block)) < 0)
        printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE_IN, snd_strerror(pcm));

    /* Allocate parameters object and fill it with default values*/
    if ((pcm = snd_pcm_hw_params_malloc(&recordparams)) < 0)
        printf("ERROR: Can't allocate hardware parameter structure. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_any(record, recordparams)) < 0)
        printf("ERROR: Can't initialize hardware parameter structure. %s\n", snd_strerror(pcm));

    /* Set parameters */
    if ((pcm = snd_pcm_hw_params_set_access(record, recordparams, SND_PCM_ACCESS_RW_NONINTERLEAVED )) < 0) 
        printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_format(record, recordparams, format)) < 0)
        printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_channels(record, recordparams, channels)) < 0) 
        printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_rate_near(record, recordparams, &rate, 0)) < 0) 
        printf("ERROR: Can't set sample rate. %s\n", snd_strerror(pcm));

    /* Write parameters */
    if ((pcm = snd_pcm_hw_params(record, recordparams)) < 0)
        printf("ERROR: Can't set hardware parameters. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_prepare(record)) < 0)
        printf("ERROR: Can't prepare audio interface for use. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_start(record)) < 0)
        printf("ERROR: Can't start hardware soundcard. %s\n", snd_strerror(pcm));

    /* Resume information */
    printf("PCM name: '%s'\n", snd_pcm_name(record));

    printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(record)));

    snd_pcm_hw_params_get_channels(recordparams, &tmp);
    printf("channels: %i ", tmp);

    if (tmp == 1)
        printf("(mono)\n");
    else if (tmp == 2)
        printf("(stereo)\n");

    snd_pcm_hw_params_get_rate(recordparams, &tmp, 0);
    printf("sample rate: %d bps\n", tmp);

    /* Open the PCM device in playback mode */
    if ((pcm = snd_pcm_open(&play, PCM_DEVICE_OUT, SND_PCM_STREAM_PLAYBACK, block)) < 0)
        printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE_OUT, snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_malloc(&playparams)) < 0)
        printf("ERROR: Can't allocate hardware parameter structure. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_any(play, playparams)) < 0)
        printf("ERROR: Can't initialize hardware parameter structure. %s\n", snd_strerror(pcm));

    /* Set parameters */
    if ((pcm = snd_pcm_hw_params_set_access(play, playparams, SND_PCM_ACCESS_RW_NONINTERLEAVED )) < 0) 
        printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_format(play, playparams, format)) < 0)
        printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_channels(play, playparams, channels)) < 0) 
        printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_rate_near(play, playparams, &rate, 0)) < 0) 
        printf("ERROR: Can't set sample rate. %s\n", snd_strerror(pcm));

    /* Write parameters */
    if ((pcm = snd_pcm_hw_params(play, playparams)) < 0)
        printf("ERROR: Can't set hardware parameters. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_prepare(play)) < 0)
        printf("ERROR: Can't prepare audio interface for use. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_start(play)) < 0)
        printf("ERROR: Can't start hardware soundcard. %s\n", snd_strerror(pcm));

    /* Resume information */
    printf("PCM name: '%s'\n", snd_pcm_name(play));

    printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(play)));

    snd_pcm_hw_params_get_channels(playparams, &tmp);
    printf("channels: %i ", tmp);

    if (tmp == 1)
        printf("(mono)\n");
    else if (tmp == 2)
        printf("(stereo)\n");

    snd_pcm_hw_params_get_rate(playparams, &tmp, 0);
    printf("sample rate: %d bps\n", tmp);

    buffer_in[0]    = (drwav_int16*) malloc(bytesize_per_channel);
    buffer_in[1]    = (drwav_int16*) malloc(bytesize_per_channel);

    printf("buffers allocated: %d bytes per channel\n", bytesize_per_channel);

    for (loops = 0; loops < 25000; loops++)
    {

        if ((recresult = snd_pcm_readn(record, (void**) buffer_in, buffer_frames)) < 0) {
             printf ("ERROR. Read from audio interface failed. (%s)\n", snd_strerror(recresult));
            exit(1);
        }
        n = (int) recresult;
        printf("read %d done, %d frames\n", loops, n);

        if ((result = snd_pcm_writen(play, (void**) buffer_in, recresult)) == -EPIPE) {
            printf("XRUN.\n");
            snd_pcm_prepare(play);
        } else if (result < 0) {
            printf("ERROR. Can't write to playback device. %s\n", snd_strerror(result));
            exit(1);
        }
        printf("write %d done\n", loops);
    }

    snd_pcm_hw_params_free(playparams);
    snd_pcm_hw_params_free(recordparams);
    printf("params freed\n");

    snd_pcm_drain(play);
    snd_pcm_close(play);
    snd_pcm_drain(record);
    snd_pcm_close(record);
    printf("audio interface closed\n");

    free(buffer_in[0]);
    free(buffer_in[1]);
    printf("buffers freed\n");

    return 0;
}
aditpape commented 7 months ago

some remarks: a) unsigned int rate, pcm, tmp; --> 'pcm' should be signed as used to check return values <0 b) you configure and start capture device before even having opened the playback device. opening + configuring playback device can take quite long time and leading to capture device already going into overrun -> first configure both devices before starting capture device c) playback device gets started w/o having written data to it -> may immediately enter underrun d) I see no explicit configuration of buffer / period size. The read request 'buffer_frames' may be even bigger than overall buffer size e) use snd_pcm_dump() to check the finally accepted configuration

nodemand commented 7 months ago

Hi @aditpape, thanks for you feedback! I corrected most things: a) done b) done c) I'm not sure what you mean by this d) I reserve the correct amount of memory with malloc. is this not enough? e) I'm getting the following error: pcm.c:2378: snd_pcm_dump: Assertion `out' failed.

this is my new code:

#include <alsa/asoundlib.h>
#include <alsa/control.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <algorithm>
#include <iterator>

typedef   signed short  drwav_int16;
typedef   signed int    drwav_int32;

#define PCM_DEVICE_IN "plughw:Zero,0"
#define PCM_DEVICE_OUT "plughw:Zero,0" //"plughw:Device,0"

int pcm, err, result, loops, n, t;
unsigned int rate, tmp;

snd_pcm_t           *play;
snd_pcm_t           *record;
snd_pcm_hw_params_t *playparams;
snd_pcm_hw_params_t *recordparams;
snd_pcm_uframes_t   frames;
snd_pcm_sframes_t   recresult;
snd_pcm_format_t    format = SND_PCM_FORMAT_S16_LE;
static snd_output_t *info = NULL;
int                 block = 0;//SND_PCM_NONBLOCK;

int buffer_frames           =   1024;
int bits_per_frame          =   16;
const int bits_per_byte     =   8;
int channels                =   2;

int bytesize_per_channel    =   buffer_frames 
                                * bits_per_frame 
                                / bits_per_byte;

int main(int argc, char **argv) {
    if (argc < 3) {
        printf("Usage: %s <sample_rate> <frames>\n", argv[0]);
        return -1;
    }

    rate            = atoi(argv[1]);
    buffer_frames   = atoi(argv[2]);

    bytesize_per_channel    =   buffer_frames 
                                * snd_pcm_format_width(format)  
                                / bits_per_byte;

    drwav_int16 *buffer_in[channels];

    /* Open the PCM device in record mode */
    if ((pcm = snd_pcm_open(&record, PCM_DEVICE_IN, SND_PCM_STREAM_CAPTURE, block)) < 0)
        printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE_IN, snd_strerror(pcm));

    /* Allocate parameters object and fill it with default values*/
    if ((pcm = snd_pcm_hw_params_malloc(&recordparams)) < 0)
        printf("ERROR: Can't allocate hardware parameter structure. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_any(record, recordparams)) < 0)
        printf("ERROR: Can't initialize hardware parameter structure. %s\n", snd_strerror(pcm));

    /* Set parameters */
    if ((pcm = snd_pcm_hw_params_set_access(record, recordparams, SND_PCM_ACCESS_RW_NONINTERLEAVED )) < 0) 
        printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_format(record, recordparams, format)) < 0)
        printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_channels(record, recordparams, channels)) < 0) 
        printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_rate_near(record, recordparams, &rate, 0)) < 0) 
        printf("ERROR: Can't set sample rate. %s\n", snd_strerror(pcm));

    /* Write parameters */
    if ((pcm = snd_pcm_hw_params(record, recordparams)) < 0)
        printf("ERROR: Can't set hardware parameters. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_prepare(record)) < 0)
        printf("ERROR: Can't prepare audio interface for use. %s\n", snd_strerror(pcm));

    /* Resume information */
    printf("PCM name: '%s'\n", snd_pcm_name(record));

    printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(record)));

    snd_pcm_hw_params_get_channels(recordparams, &tmp);
    printf("channels: %i ", tmp);

    if (tmp == 1)
        printf("(mono)\n");
    else if (tmp == 2)
        printf("(stereo)\n");

    snd_pcm_hw_params_get_rate(recordparams, &tmp, 0);
    printf("sample rate: %d bps\n", tmp);

    /* Open the PCM device in playback mode */
    if ((pcm = snd_pcm_open(&play, PCM_DEVICE_OUT, SND_PCM_STREAM_PLAYBACK, block)) < 0)
        printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE_OUT, snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_malloc(&playparams)) < 0)
        printf("ERROR: Can't allocate hardware parameter structure. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_any(play, playparams)) < 0)
        printf("ERROR: Can't initialize hardware parameter structure. %s\n", snd_strerror(pcm));

    /* Set parameters */
    if ((pcm = snd_pcm_hw_params_set_access(play, playparams, SND_PCM_ACCESS_RW_NONINTERLEAVED )) < 0) 
        printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_format(play, playparams, format)) < 0)
        printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_channels(play, playparams, channels)) < 0) 
        printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_hw_params_set_rate_near(play, playparams, &rate, 0)) < 0) 
        printf("ERROR: Can't set sample rate. %s\n", snd_strerror(pcm));

    /* Write parameters */
    if ((pcm = snd_pcm_hw_params(play, playparams)) < 0)
        printf("ERROR: Can't set hardware parameters. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_prepare(play)) < 0)
        printf("ERROR: Can't prepare audio interface for use. %s\n", snd_strerror(pcm));

    /* Resume information */
    printf("PCM name: '%s'\n", snd_pcm_name(play));

    printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(play)));

    snd_pcm_hw_params_get_channels(playparams, &tmp);
    printf("channels: %i ", tmp);

    if (tmp == 1)
        printf("(mono)\n");
    else if (tmp == 2)
        printf("(stereo)\n");

    snd_pcm_hw_params_get_rate(playparams, &tmp, 0);
    printf("sample rate: %d bps\n", tmp);

    // allocate buffers
    buffer_in[0]    = (drwav_int16*) malloc(bytesize_per_channel);
    buffer_in[1]    = (drwav_int16*) malloc(bytesize_per_channel);

    printf("buffers allocated: %d bytes per channel\n", bytesize_per_channel);

    // check accepted configuration
    err = snd_pcm_dump(play, info);
    err = snd_pcm_dump(record, info);

    // start both devices
    if ((pcm = snd_pcm_start(play)) < 0)
        printf("ERROR: Can't start soundcard for playback. %s\n", snd_strerror(pcm));

    if ((pcm = snd_pcm_start(record)) < 0)
        printf("ERROR: Can't start soundcard for recording. %s\n", snd_strerror(pcm));

    for (loops = 0; loops < 25000; loops++)
    {

        if ((recresult = snd_pcm_readn(record, (void**) buffer_in, buffer_frames)) < 0) {
             printf ("ERROR. Read from audio interface failed. (%s)\n", snd_strerror(recresult));
            exit(1);
        }
        n = (int) recresult;
        printf("read %d done, %d frames\n", loops, n);

        if ((result = snd_pcm_writen(play, (void**) buffer_in, recresult)) == -EPIPE) {
            printf("XRUN.\n");
            snd_pcm_prepare(play);
        } else if (result < 0) {
            printf("ERROR. Can't write to playback device. %s\n", snd_strerror(result));
            exit(1);
        }
        printf("write %d done\n", loops);
    }

    snd_pcm_hw_params_free(playparams);
    snd_pcm_hw_params_free(recordparams);
    printf("params freed\n");

    snd_pcm_drain(play);
    snd_pcm_close(play);
    snd_pcm_drain(record);
    snd_pcm_close(record);
    printf("audio interface closed\n");

    free(buffer_in[0]);
    free(buffer_in[1]);
    printf("buffers freed\n");

    return 0;
}

output:

PCM name: 'plughw:Zero,0'
PCM state: PREPARED
channels: 2 (stereo)
sample rate: 48000 bps
PCM name: 'plughw:Zero,0'
PCM state: PREPARED
channels: 2 (stereo)
sample rate: 48000 bps
buffers allocated: 2048 bytes per channel
ps9: pcm.c:2378: snd_pcm_dump: Assertion `out' failed.
Aborted

Also, I have the same issue when I switch to PortAudio. Then my application hangs on Pa_ReadStream. And I'm using one of their examples as the basis of my application.

aditpape commented 7 months ago

c) refer to 'start_threshold'. You should start the device once full or enough data got written to it. Also relates to d).. d) you implement a 'forwarding' which requires some alignment of chunk sized read from input and written to output. In ideal case you configure same period size on input and output and forward period by period.

e) needs initialization like e.g. snd_output_stdio_attach(&info, stderr, 0);

Also, I have the same issue when I switch to PortAudio.

Assume you refer to PulseAudio via pulse ALSA plugin? EDIT: PortAudio is right (ref: Pa_ReadStream), was not aware that same prefix PA is used at API than for PulseAudio

nodemand commented 7 months ago

ok, I have output!

PCM name: 'plughw:Zero,0'
PCM state: PREPARED
channels: 2 (stereo)
sample rate: 48000 bps
PCM name: 'plughw:Zero,0'
PCM state: PREPARED
channels: 2 (stereo)
sample rate: 48000 bps
buffers allocated: 2048 bytes per channel
Plug PCM: Copy conversion PCM
Its setup is:
  stream       : PLAYBACK
  access       : RW_NONINTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 131072
  period_size  : 256
  period_time  : 5333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 256
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 131072
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
Slave: Hardware PCM card 0 'RPi Codec Zero' device 0 subdevice 0
Its setup is:
  stream       : PLAYBACK
  access       : MMAP_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 131072
  period_size  : 256
  period_time  : 5333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 256
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 131072
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
  appl_ptr     : 0
  hw_ptr       : 0
Plug PCM: Copy conversion PCM
Its setup is:
  stream       : CAPTURE
  access       : RW_NONINTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 131072
  period_size  : 256
  period_time  : 5333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 256
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 131072
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
Slave: Hardware PCM card 0 'RPi Codec Zero' device 0 subdevice 0
Its setup is:
  stream       : CAPTURE
  access       : MMAP_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 131072
  period_size  : 256
  period_time  : 5333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 256
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 131072
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
  appl_ptr     : 0
  hw_ptr       : 0
ERROR: Can't start soundcard for playback. Broken pipe
nodemand commented 7 months ago

I switched to buffer_frames = 256 instead of 1024 and I wrote some data into the playback device before starting it. Now the broken pipe error disappeared but my app still hangs.

PCM name: 'plughw:Zero,0'
PCM state: PREPARED
channels: 2 (stereo)
sample rate: 48000 bps
PCM name: 'plughw:Zero,0'
PCM state: PREPARED
channels: 2 (stereo)
sample rate: 48000 bps
buffers allocated: 512 bytes per channel
Plug PCM: Copy conversion PCM
Its setup is:
  stream       : PLAYBACK
  access       : RW_NONINTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 131072
  period_size  : 256
  period_time  : 5333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 256
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 131072
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
Slave: Hardware PCM card 0 'RPi Codec Zero' device 0 subdevice 0
Its setup is:
  stream       : PLAYBACK
  access       : MMAP_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 131072
  period_size  : 256
  period_time  : 5333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 256
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 131072
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
  appl_ptr     : 0
  hw_ptr       : 0
Plug PCM: Copy conversion PCM
Its setup is:
  stream       : CAPTURE
  access       : RW_NONINTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 131072
  period_size  : 256
  period_time  : 5333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 256
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 131072
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
Slave: Hardware PCM card 0 'RPi Codec Zero' device 0 subdevice 0
Its setup is:
  stream       : CAPTURE
  access       : MMAP_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 131072
  period_size  : 256
  period_time  : 5333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 256
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 131072
  silence_threshold: 0
  silence_size : 0
  boundary     : 4611686018427387904
  appl_ptr     : 0
  hw_ptr       : 0

oh, and I just remembered, I also tried alsaloop and piping audio from arecord to aplay using some examples, but nowhere ever does there come audio out of the lineout of the same device I record from...

aditpape commented 7 months ago

propose to verify the underlaying devices separately with aplay/arecord..

aplay -vvv -Dplughw:Zero,0 -fdat /dev/urandom arecord -vvv -Dplughw:Zero,0 -fdat >/dev/null

once properly working separately you can form a forwarding via arecord | aplay

..and if that is working you can continue with your own app.

nodemand commented 7 months ago

both arecord and aplay work as they did before, but forwarding is where it goes wrong. I tried that already as I said ... output of aplay:

Playing raw data '/dev/urandom' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
Plug PCM: Hardware PCM card 0 'RPi Codec Zero' device 0 subdevice 0
Its setup is:
  stream       : PLAYBACK
  access       : RW_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 23552
  period_size  : 1024
  period_time  : 21333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 1024
  period_event : 0
  start_threshold  : 23552
  stop_threshold   : 23552
  silence_threshold: 0
  silence_size : 0
  boundary     : 6629298651489370112
  appl_ptr     : 0
  hw_ptr       : 0
Max peak (2048 samples): 0x00007fee #################### 99%
Max peak (2048 samples): 0x00007fdf #################### 99%
Max peak (2048 samples): 0x00007ffb #################### 99%
Max peak (2048 samples): 0x00007ff1 #################### 99%
Max peak (2048 samples): 0x00007fe3 #################### 99%
Max peak (2048 samples): 0x00007fed #################### 99%
Max peak (2048 samples): 0x00007ffb #################### 99%
Max peak (2048 samples): 0x00007ff9 #################### 99%
Max peak (2048 samples): 0x00007ff7 #################### 99%
Max peak (2048 samples): 0x00007fff #################### 99%
Max peak (2048 samples): 0x00007fe2 #################### 99%
Max peak (2048 samples): 0x00007ffb #################### 99%
Max peak (2048 samples): 0x00007ffc #################### 99%
Max peak (2048 samples): 0x00007fe8 #################### 99%
Max peak (2048 samples): 0x00007ffc #################### 99%
Max peak (2048 samples): 0x00007ff5 #################### 99%
Max peak (2048 samples): 0x00007fed #################### 99%
Max peak (2048 samples): 0x00007fee #################### 99%
Max peak (2048 samples): 0x00007fee #################### 99%
Max peak (2048 samples): 0x00007ff4 #################### 99%
Max peak (2048 samples): 0x00007fdf #################### 99%
Max peak (2048 samples): 0x00007ff3 #################### 99%
Max peak (2048 samples): 0x00007ffb #################### 99%
Max peak (2048 samples): 0x00007fed #################### 99%
Max peak (2048 samples): 0x00007ff9 #################### 99%
Max peak (2048 samples): 0x00007fe4 #################### 99%

output of arecord:

Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
Plug PCM: Hardware PCM card 0 'RPi Codec Zero' device 0 subdevice 0
Its setup is:
  stream       : CAPTURE
  access       : RW_INTERLEAVED
  format       : S16_LE
  subformat    : STD
  channels     : 2
  rate         : 48000
  exact rate   : 48000 (48000/1)
  msbits       : 16
  buffer_size  : 23552
  period_size  : 1024
  period_time  : 21333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 1024
  period_event : 0
  start_threshold  : 1
  stop_threshold   : 23552
  silence_threshold: 0
  silence_size : 0
  boundary     : 6629298651489370112
  appl_ptr     : 0
  hw_ptr       : 0
Max peak (2048 samples): 0x00000e9c ###                  11%
Max peak (2048 samples): 0x00001025 ###                  12%
Max peak (2048 samples): 0x00000d8e ###                  10%
Max peak (2048 samples): 0x00001039 ###                  12%
Max peak (2048 samples): 0x000011c4 ###                  13%
Max peak (2048 samples): 0x00000eac ###                  11%
Max peak (2048 samples): 0x000014ac ####                 16%
Max peak (2048 samples): 0x0000167f ####                 17%
Max peak (2048 samples): 0x000016d0 ####                 17%
Max peak (2048 samples): 0x00001545 ####                 16%
Max peak (2048 samples): 0x000011c1 ###                  13%
Max peak (2048 samples): 0x00001158 ###                  13%
Max peak (2048 samples): 0x00001233 ###                  14%
Max peak (2048 samples): 0x000017ca ####                 18%
Max peak (2048 samples): 0x0000125b ###                  14%
Max peak (2048 samples): 0x000010b1 ###                  13%
Max peak (2048 samples): 0x00000e5d ###                  11%
Max peak (2048 samples): 0x00001047 ###                  12%
Max peak (2048 samples): 0x00000fa8 ###                  12%
Max peak (2048 samples): 0x000008bc ##                   6%
Max peak (2048 samples): 0x00001eb2 #####                23%

EDIT:

arecord -f S16_LE -r48000 -c2 -D plughw:Zero,0 -F0 --period-size=256 -B0 --buffer-size=4096 | aplay -D plughw:Zero,0 -

Recording WAVE 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
Playing WAVE 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
arecord: pcm_read:2221: read error: Input/output error

so how do I get the forwarding to work?

aditpape commented 7 months ago

Seems devices do not accept duplex mode.. (using as playback and capture simultaneously) -you can verify by issuing arecord + aplay in separate shells...

nodemand commented 7 months ago

I opened two SSH connections to my RPi. One with: arecord -f S16_LE -r48000 -c2 -D plughw:Zero,0 -F0 --period-size=256 -B0 --buffer-size=4096 test.wav and one with: aplay test.wav -f S16_LE -r48000 -c2 -D plughw:Zero,0

And I do actually hear music! After awhile though I get "arecord: pcm_read:2221: read error: Input/output error", but that might be because of both shells reading and writing to the same file?

aditpape commented 7 months ago

After awhile though I get "arecord: pcm_read:2221: read error: Input/output error",

That error is returned from the snd_pcm_readX()-API, thus cannot be related to the concurrent access to file. -> any error seen in kernel log ? (dmesg) -> error seen after 5 or 10s of 'blocking'? (there are timeout value in kernel which are 5 or 10s..)

Also, for verification, access hardware as direct as possible.. (remove plugins) plughw -> hw

nodemand commented 7 months ago

I'm not sure if this is what we are looking for but there are errors:

[   10.533134] brcmfmac mmc1:0001:1: firmware: failed to load brcm/brcmfmac43455-sdio.raspberrypi,5-model-b.bin (-2)
[   10.533142] firmware_class: See https://wiki.debian.org/Firmware for information about missing firmware
[   10.533146] brcmfmac mmc1:0001:1: Direct firmware load for brcm/brcmfmac43455-sdio.raspberrypi,5-model-b.bin failed with error -2
[   10.542402] Registered IR keymap rc-cec
[   10.548627] brcmfmac mmc1:0001:1: firmware: direct-loading firmware brcm/brcmfmac43455-sdio.bin
[   10.548690] brcmfmac mmc1:0001:1: firmware: failed to load brcm/brcmfmac43455-sdio.raspberrypi,5-model-b.txt (-2)
[   10.550827] brcmfmac mmc1:0001:1: firmware: direct-loading firmware brcm/brcmfmac43455-sdio.txt
[   10.551426] brcmfmac mmc1:0001:1: firmware: failed to load brcm/brcmfmac43455-sdio.raspberrypi,5-model-b.clm_blob (-2)

Going from plughw to hw makes no difference. Same error...

aditpape commented 7 months ago

messages in kernel log are not audio related.. If EINVVAL is also seen when directly acting on hardware it is more pointing to issue in the kernel / sound driver. -You may try to avoid the 'termination' of aplay / arecord by using nonblocking access via -N option. -then monitor device status in procfs whether device's status is still 'running' and hw pointer is still moving. cat /proc/asound/card ...

nodemand commented 7 months ago

When I add the -N option to both commands the error does not show anymore, but playback with aplay stops prematurely. arecord just keeps on going without any errors...

status: RUNNING Nope. HW pointer is NOT moving

aditpape commented 7 months ago

'status' or 'info' should show the runtime.. doing cat multiple times should show hw_ptr moving -do on both input and output stream: pcm0c= capture, pcm0p = playback

aditpape commented 7 months ago

status: RUNNING Nope. HW pointer is NOT moving

hw doesn't give any more interrupts...

nodemand commented 7 months ago

btw this was on the record stream...

nodemand commented 7 months ago

doing cat multiple times should show hw_ptr moving

it does, but as soon as I start aplay in another shell, it stops moving

aditpape commented 7 months ago

Correct alsa state files 'loaded'? https://github.com/raspberrypi/Pi-Codec/tree/master

For duplex operation AUXIN HPOUT seems a dedicated state file needed. Codec_Zero_AUXIN_record_and_HP_playback.state

sudo alsactl restore -f

nodemand commented 7 months ago

ahhh yes, I ran into a little problem there. But not with the HifiBerry with which I have the same issue. Anyway, this is the output of sudo alsactl restore -f:

alsa-lib main.c:1541:(snd_use_case_mgr_open) error: failed to import hw:0 use case configuration -2
No state is present for card Device
Found hardware: "USB-Audio" "USB Mixer" "USB040d:340a" "" ""
Hardware is initialized using a generic method
No state is present for card Device
aditpape commented 7 months ago

command for your case should be: sudo alsactl restore -f Codec_Zero_AUXIN_record_and_HP_playback.state

Topic seems to turn into pure 'Raspi codec related', thus 'Rapi forum' may help further.

nodemand commented 7 months ago

I ran that command exactly. And no. Like I said it also happens with the HifiBerry!

aditpape commented 7 months ago

Not that familiar with the alsactrl + involvement of the UCM (use case manager) -as 'hw:0' and even 'USB' sound cards are mentioned in alsactrl output you could instruct alsactrl to only act on your Zero card. sudo alsactl restore Zero -f Codec_Zero_AUXIN_record_and_HP_playback.state

If that also does not help, I am 'out'

nodemand commented 7 months ago

Same error I'm afraid. Ok, well thank you very much for your input! I learned a lot! Thanx!

nodemand commented 7 months ago

I double checked EVERYTHING with only the HifiBerry installed and exactly the same symptoms as with the IQAudio Codec Zero! In the end the HW pointer stops moving as soon as I start aplay in a different shell and arecord exits with a 2221 input/output error. Help!

perexg commented 7 months ago

It looks like an issue with the BCM I2S kernel driver for RPi 5. You should consult your issue in the RPi forums.

nodemand commented 7 months ago

Ok! Thank you! Will investigate further in the RPi forums…

nodemand commented 7 months ago

It's fixed!