[alsa-devel] Segmentation fault during snd_pcm_prepare()
Shane Loretz
a10.shane at gmail.com
Wed May 15 06:47:57 CEST 2013
I'm interested in writing an application using alsa. I've chosen to
explore the library by writing a program to echo sound data from a
microphone back to my speakers.
I'm only interested in mono sound.
When running this program, the first call to snd_pcm_readi() fails,
and a segmentation fault occurs inside of the snd_pcm_prepare()
function according to a backtrace from gdb. I suspect I'm not
allocating enough space for the pointer capdata, but I don't know how
to determine how much space I need.
Here is the code
// Test out the alsa library
//
#include <alsa/asoundlib.h>
#include <cstdio>
#include <unistd.h>
bool getMonoDevice(snd_pcm_t *pcm_handle, snd_pcm_stream_t stream,
unsigned int rate, int periods, snd_pcm_uframes_t periodsize);
int main()
{
snd_pcm_t *pcm_handle_read;
snd_pcm_t *pcm_handle_write;
snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
unsigned int rate = 44100;
int periods = 2;
snd_pcm_uframes_t periodsize = 8192;
if (!getMonoDevice(pcm_handle_write,
SND_PCM_STREAM_PLAYBACK,rate,periods,periodsize))
{
fprintf(stderr, "Error couldn't open speakers\n");
return -1;
}
if (!getMonoDevice(pcm_handle_read,
SND_PCM_STREAM_CAPTURE,rate,periods,periodsize))
{
fprintf(stderr, "Error couldn't open microphone\n");
return -1;
}
//read frames from device
//and echo them out
unsigned char *capdata;
int pcmreturn;
int num_frames;
int error;
capdata = (unsigned char *)malloc(periodsize);
num_frames = periodsize * 2;
while (true)
{
while ((pcmreturn = snd_pcm_readi(pcm_handle_read, capdata,
num_frames)) < 0)
{
usleep(10);
error = snd_pcm_prepare(pcm_handle_read);
if (error < 0)
{
fprintf(stderr, "Unrecoverable mic error
%s\n",snd_strerror(error));
return error;
}
}
while ((pcmreturn = snd_pcm_writei(pcm_handle_write, capdata,
num_frames)) < 0)
{
usleep(10);
error = snd_pcm_prepare(pcm_handle_write);
if (error < 0)
{
fprintf(stderr, "Unrecoverable speaker error
%s\n",snd_strerror(error));
return error;
}
}
}
//stop pcm device and drop pending frames
snd_pcm_drop(pcm_handle_read);
snd_pcm_drain(pcm_handle_read);
snd_pcm_drop(pcm_handle_write);
snd_pcm_drain(pcm_handle_write);
}
bool getMonoDevice(snd_pcm_t *pcm_handle, snd_pcm_stream_t stream,
unsigned int rate, int periods, snd_pcm_uframes_t periodsize)
{
snd_pcm_hw_params_t *hwparams;
char *pcm_name;
pcm_name = strdup("plughw:0,0");
snd_pcm_hw_params_alloca(&hwparams);
if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0) < 0)
{
fprintf(stderr, "Error opening PCM device %s\n", pcm_name);
return false;
}
if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0 )
{
fprintf(stderr, "Can not configure this PCM device.\n");
return false;
}
unsigned int exact_rate;
int dir;
if (snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
{
fprintf(stderr, "Error setting access.\n");
return false;
}
if (snd_pcm_hw_params_set_format(pcm_handle, hwparams,
SND_PCM_FORMAT_S16_LE) < 0)
{
fprintf(stderr, "Error setting format.\n");
return false;
}
exact_rate = rate;
if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
&exact_rate, 0) < 0)
{
fprintf(stderr, "Error setting rate.\n");
return false;
}
if (rate != exact_rate)
{
fprintf(stderr, "The rate %d is not supported by your
hardware.\n Using %d Hz instead.\n", rate, exact_rate);
}
//Configure mono sound
if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 1) < 0)
{
fprintf(stderr, "Error setting channels.\n");
return false;
}
if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0)
{
fprintf(stderr, "Error setting periods.\n");
return false;
}
if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams,
(periodsize * periods) >> 2) < 0 )
{
fprintf(stderr, "Error setting buffersize.\n");
return false;
}
if (snd_pcm_hw_params(pcm_handle, hwparams) < 0)
{
fprintf(stderr, "Error setting HW params.\n");
return false;
}
//device is finally configured
return true;
}
More information about the Alsa-devel
mailing list