All of lore.kernel.org
 help / color / mirror / Atom feed
* Segmentation fault during snd_pcm_prepare()
@ 2013-05-15  4:47 Shane Loretz
  2013-05-15  5:14 ` David Henningsson
  0 siblings, 1 reply; 2+ messages in thread
From: Shane Loretz @ 2013-05-15  4:47 UTC (permalink / raw)
  To: alsa-devel

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;
    }

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Segmentation fault during snd_pcm_prepare()
  2013-05-15  4:47 Segmentation fault during snd_pcm_prepare() Shane Loretz
@ 2013-05-15  5:14 ` David Henningsson
  0 siblings, 0 replies; 2+ messages in thread
From: David Henningsson @ 2013-05-15  5:14 UTC (permalink / raw)
  To: Shane Loretz; +Cc: alsa-devel

On 05/15/2013 06:47 AM, Shane Loretz wrote:
> 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.

S16_LE = 16 bits = 2 bytes per frame.

So if you're trying to read num_frames frames, the amount allocated must 
be at least num_frames * 2. (Also multiplied with the number of 
channels, which is 1 in this case.)

Also snd_pcm_recover is recommended to use to recover from error (rather 
than snd_pcm_prepare).

>
> 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;
>      }
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>



-- 
David Henningsson, Canonical Ltd.
https://launchpad.net/~diwic

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2013-05-15  5:13 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-15  4:47 Segmentation fault during snd_pcm_prepare() Shane Loretz
2013-05-15  5:14 ` David Henningsson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.