[alsa-devel] capturing data from the microphone

Raymond Yau superquad.vortex2 at gmail.com
Thu Jan 7 00:59:28 CET 2010


2010/1/6 Riccardo Magliocchetti <riccardo.magliocchetti at gmail.com>

> Hi Pierre,
>
> pl bossart ha scritto:
> > You haven't specified the buffer/period size in the hw params. See
> > alsa-lib/test/pcm.c
> > - Pierre
>
> They fail when opening default device so I had to remove them, work fine
> when opening
> plughw:0,0 though.
>
> > On Mon, Jan 4, 2010 at 11:39 AM, Riccardo Magliocchetti
> > <riccardo.magliocchetti at gmail.com> wrote:
> >> [the same message is waiting in moderator queue, sorry if you receive it
> two times]
> >>
> >> Hello,
> >>
> >> i'm trying to capture audio data from the microphone, but i'm not able
> to
> >> read any frames.
> >> The frames are always 0 and delay is fixed to 2730. I've tried calling
> >> snd_pcm_avail_delay,  snd_pcm_avail_update but does not make a
> difference.
> >> The soundcard is driven by  snd_hda_intel. The code is more or less the
> >> same as Paul Davis' tutorial on using the alsa api.
> >>
> >> This is the code for init and the loop that tries to read the data:
> >>
> >> #define MIC_BUFSIZE 4096
> >>
> >> static gpointer snd_pcm_read(gpointer data)
> >> {
> >>   int error;
> >>   snd_pcm_sframes_t frames = MIC_BUFSIZE;
> >>
> >>   while (TRUE) {
> >>
> >>     if ((error = snd_pcm_wait (pcm_handle, 1000)) < 0) {
> >>         g_printerr("Failed to poll: %s\n", snd_strerror(error));
> >>         continue;
> >>     }
> >>
> >>     if ((error = snd_pcm_avail(pcm_handle)) < 0) {
> >>       if (error == -EPIPE) {
> >>         g_printerr("xrun! %s\n", snd_strerror(error));
> >>         continue;
> >>         //return GINT_TO_POINTER(FALSE);
> >>       } else {
> >>         g_printerr("alsa_pcm_avail_update error %s\n",
> snd_strerror(error));
> >>         continue;
> >>         //return GINT_TO_POINTER(FALSE);
> >>       }
> >>     }
> >>
> >>     frames = error;
> >>     if (frames == 0)
> >>       continue;
> >>
> >>     frames = frames > MIC_BUFSIZE ? MIC_BUFSIZE : frames;
> >>     g_printerr ("frames: %ld\n", frames);
> >>     g_static_mutex_lock(&mutex);
> >>     error = snd_pcm_readi(pcm_handle, Mic_Buffer[Mic_WriteBuf], frames);
> >>     g_static_mutex_unlock(&mutex);
> >>     if (error < 0)
> >>         error = snd_pcm_recover(pcm_handle, error, 0);
> >>     if (error < 0) {
> >>        LOG("snd_pcm_readi FAIL!: %s\n", snd_strerror(error));
> >>     }
> >>   }
> >>
> >>   return GINT_TO_POINTER(TRUE);
> >> }
> >>
> >> BOOL Mic_Init()
> >> {
> >>     snd_pcm_hw_params_t *hwparams;
> >>     snd_pcm_sw_params_t *swparams;
> >>     int err;
> >>
> >>     if (Mic_Inited)
> >>         return TRUE;
> >>
> >>     // Open the default sound card in capture
> >>     if ((err = snd_pcm_open(&pcm_handle, "default",
> SND_PCM_STREAM_CAPTURE,
> >> /*SND_PCM_NONBLOCK*/ 0)) < 0) {
> >>         g_printerr("Failed to open device: %s\n", snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     // Allocate the snd_pcm_hw_params_t structure and fill it.
> >>     snd_pcm_hw_params_alloca(&hwparams);
> >>     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
> >>         g_printerr("Failed to setup hw parameters: %s\n",
> snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     //Set the access
> >>     if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams,
> >> SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
> >>         g_printerr("Failed to set access: %s\n", snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     //dir 0 == exacte (Rate = 16K exacte)
> >>     if ((err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, 16000,
> 0)) < 0) {
> >>         g_printerr("Failed to set rate: %s\n", snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     /* Set sample format */
> >>     if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams,
> SND_PCM_FORMAT_S8)) < 0) {
> >>         g_printerr("Failed to set format: %s\n", snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     // Set one channel (mono)
> >>     if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 1))
> < 0) {
> >>         g_printerr("Failed to set channels: %s\n", snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     //Set the params
> >>     if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
> >>         g_printerr("Failed to set hw parameters: %s\n",
> snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     snd_pcm_sw_params_alloca(&swparams);
> >>     if ((err = snd_pcm_sw_params_current (pcm_handle, swparams)) < 0) {
> >>         g_printerr("Failed to set current sw parameters: %s\n",
> snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     if ((err = snd_pcm_sw_params_set_avail_min (pcm_handle, swparams,
> MIC_BUFSIZE)) < 0) {
> >>         g_printerr("Failed to set minimum available count: %s\n",
> snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     if ((err = snd_pcm_sw_params_set_start_threshold (pcm_handle,
> swparams, 0U)) < 0) {
> >>         g_printerr("Failed to set start mode: %s\n", snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     if ((err = snd_pcm_sw_params (pcm_handle, swparams)) < 0) {
> >>         g_printerr("Failed to set sw parameters: %s\n",
> snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     if ((err = snd_pcm_prepare (pcm_handle)) < 0) {
> >>         g_printerr("Failed to prepare audio interface to use: %s\n",
> snd_strerror(err));
> >>         return FALSE;
> >>     }
> >>
> >>     Mic_Inited = TRUE;
> >>     Mic_Reset();
> >>
> >>     mic_reader = g_thread_create(snd_pcm_read, NULL, TRUE, NULL);
> >>
> >>     return TRUE;
> >> }
> >>
> >>
> >> thanks,
> >> Riccardo
> >>
>

Even 4096 bytes is x86 DMA page size , seem to be a good choice for those
PCI sound cards, however you cannot assume all sound cards/plugins support
this buffer size

If you did not set period_size, buffer_size or periods (period_time,
buffer_time or periods)  , you should call
snd_pcm_hw_params_get_buffer_size() and snd_pcm_hw_params_get_period_size()
after snd_pcm_hw_params()


More information about the Alsa-devel mailing list