[alsa-devel] Audio passthrough on Pandaboard using ALSA API
Hello
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);
}?
Best
Your application does not handle overruns and underruns (EPIPE indicates that either of these is happening). It also doesn't have any drift correction, so overruns/underruns are to be expected (the sample rate of the capture and playback stream is not guaranteed to be exactly matched).
By the way, there is a tool called 'alsaloop' (from alsa-utils) which does exactly the same thing, but with drift correction and more options ...
Maarten Baert
On 28/02/14 09:47, Vadim Izmalkov wrote:
Hello
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?
participants (2)
-
Maarten Baert
-
Vadim Izmalkov