Hello All.
I created simple application that makes audio pass-through (from analog input to analog output),
After 2-10 seconds get error like:
AlsaPassthrough: pcm.c:693: snd_pcm_close: Assertion `pcm' failed.
or
write to audio interface failed (Broken pipe)
Seems I have problem with buffer size/time or somethink like that.
Parameters used:
Buffer - 100 ms / 4800 frames / 19200 bytes
Period - 10 ms / 480 frames / 1920 bytes
Buffer length used 19200 bytes.
char buffer[19200];
Write/read function used as follow
snd_pcm_readi(pcm, buffer, frames); snd_pcm_writei(pcm, buffer, frames);
Have somebody any suggestion?
Segments of the code you can find bellow.
Alsamixer settings:
amixer cset name='Analog Left Capture Route' 'Headset Mic' amixer cset name='Analog Right Capture Route' 'Headset Mic' amixer cset name='MUX_UL00' 'AMic0' amixer cset name='MUX_UL01' 'AMic1' amixer cset name='Headset Left Playback' 'HS DAC' amixer cset name='Headset Right Playback' 'HS DAC' amixer cset name='Headset Playback Volume' 100 amixer cset name='DL1 Media' 120
Structure for the devices:
typedef struct { char *deviceName; snd_pcm_t *pcm; snd_pcm_hw_params_t *hwParams; snd_pcm_stream_t stream; snd_pcm_access_t access; snd_pcm_format_t format; snd_pcm_uframes_t frames; int mode; unsigned int sampleRate; unsigned int bufferTime; unsigned int periodTime; unsigned int channels; } pcmDevice_t;
Parameters for capture:
pcmDevice_t* initRecordDevice() { pcmDevice_t *device; device = malloc(sizeof(pcmDevice_t)); device->deviceName = strdup("plughw:0,0"); device->stream = SND_PCM_STREAM_CAPTURE; device->access = SND_PCM_ACCESS_RW_INTERLEAVED; device->format = SND_PCM_FORMAT_S16_LE; device->mode = 0; //SND_PCM_ASYNC; //SND_PCM_NONBLOCK; device->sampleRate = 48000; device->bufferTime = 100 * 1000; // 100 ms device->periodTime = 10 * 1000; // 20ms device->channels = 2; return device; }
Parameters for playback:
pcmDevice_t* initPlaybackDevice() { pcmDevice_t *device; device = malloc(sizeof(pcmDevice_t)); device->deviceName = strdup("plughw:0,0"); device->stream = SND_PCM_STREAM_PLAYBACK; device->access = SND_PCM_ACCESS_RW_INTERLEAVED; device->format = SND_PCM_FORMAT_S16_LE; device->mode = 0; //SND_PCM_ASYNC; //SND_PCM_NONBLOCK; device->sampleRate = 48000; device->bufferTime = 100 * 1000; // 100 ms device->periodTime = 10 * 1000; // 20ms device->channels = 2; return device; }
Setup devices:
int setupDevice(pcmDevice_t *device) { int err; /* Open PCM. The last parameter of this function is the mode. */ /* If this is set to 0, the standard mode is used. Possible */ /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */ /* If SND_PCM_NONBLOCK is used, read / write access to the */ /* PCM device will return immediately. If SND_PCM_ASYNC is */ /* specified, SIGIO will be emitted whenever a period has */ /* been completely processed by the soundcard. */ if ((err = snd_pcm_open(&device->pcm, device->deviceName, device->stream, device->mode)) < 0) { fprintf (stderr, "cannot open audio device %s (%s)\n", device->deviceName, snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_malloc (&device->hwParams)) < 0) { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_any (device->pcm, device->hwParams)) < 0) { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_access (device->pcm, device->hwParams, device->access)) < 0) { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_format (device->pcm, device->hwParams, device->format)) < 0) { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_buffer_time_near (device->pcm, device->hwParams, &device->bufferTime, NULL)) < 0) { fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)); exit (1); } else { /* Set buffer size (in frames). The resulting latency is given by */ /* latency = periodsize * periods / (rate * bytes_per_frame) */ snd_pcm_hw_params_get_buffer_size(device->hwParams, &device->frames); } if ((err = snd_pcm_hw_params_set_period_time_near (device->pcm, device->hwParams, &device->periodTime, NULL)) < 0) { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_rate_near (device->pcm, device->hwParams, &device->sampleRate, NULL)) < 0) { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)); exit (1); } if ((err = snd_pcm_hw_params_set_channels (device->pcm, device->hwParams, device->channels)) < 0) { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)); exit (1); } /* Apply HW parameter settings to */ /* PCM device and prepare device */ if ((err = snd_pcm_hw_params (device->pcm, device->hwParams)) < 0) { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)); exit (1); } snd_pcm_hw_params_free (device->hwParams); if ((err = snd_pcm_prepare (device->pcm)) < 0) { fprintf (stderr, "cannot prepare audio interface for use (%s)\n", snd_strerror (err)); exit (1); } return 0; }
Main:
main (int argc, char *argv[]) { int i; int err; char buf[4800*4]; snd_pcm_t *capture_handle; snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t frames; pcmDevice_t *pcmRecord; pcmDevice_t *pcmPlayback; pcmRecord = initRecordDevice(); pcmPlayback = initPlaybackDevice(); printf("\n----------- RECORD DEVICE -----------\n"); setupDevice(pcmRecord); showConfig(pcmRecord); printf("\n---------- PLAYBACK DEVICE ----------\n"); setupDevice(pcmPlayback); showConfig(pcmPlayback); for (i = 0; i < 100; ++i) { /* Read num_frames frames from the PCM device */ /* pointed to by pcm_handle to buffer capdata. */ /* Returns the number of frames actually read. */ //if((err = snd_pcm_readi (pcmRecord->pcm, buf, pcmRecord->frames)) != pcmRecord->frames) { if((err = snd_pcm_readi (pcmRecord->pcm, buf, 480)) != 480) { fprintf (stderr, "read from audio interface failed (%s)\n", snd_strerror (err)); exit (1); } /* Write num_frames frames from buffer data to */ /* the PCM device pointed to by pcm_handle. */ /* Returns the number of frames actually written. */ if((err = snd_pcm_writei (pcmPlayback->pcm, buf, pcmRecord->frames)) != pcmRecord->frames) { fprintf (stderr, "write to audio interface failed (%s)\n", snd_strerror (err)); exit (1); } } snd_pcm_close (capture_handle); exit (0); }