Hi, i got this code constructed from an example i found googling.
What i basically want is to initialise some settings and then i'd like to capture some PCM to a buffer. This should be repeatable, i want to initialise ONCE and call a capture function whenever i need some data. It is perfectly ok, if the data buffers that are captured are not consecutive. The code basically works, but whenever i try to capture the buffer a SECOND time, the whole program crashes. Has anybody got a hint for me on what could be wrong? Thanks for any hints, Torsten.
#define _GNU_SOURCE #include <stdio.h> #include <malloc.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <alsa/asoundlib.h> #include <sys/signal.h> #include "sound.h" #include "settings.h" #define QWE fprintf(stderr, "File %s, Line %i\n", __FILE__, __LINE__) snd_pcm_t *pcm_handle; snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE; snd_pcm_hw_params_t* hwparams; char *pcm_name = "default"; int rate = 44100; /* Sample rate */ int exact_rate; /* Sample rate returned by */ /* snd_pcm_hw_params_set_rate_near */ int dir; /* exact_rate == rate --> dir = 0 */ /* exact_rate < rate --> dir = -1 */ /* exact_rate > rate --> dir = 1 */ int periods = 2; /* Number of periods */ int periodsize = 4*SAMPLES; /* Periodsize (bytes) */ unsigned char *data; int pcmreturn, l1, l2; short s1, s2; int frames; snd_pcm_state_t sss; static void show(snd_pcm_state_t* s) { switch(*s) { case SND_PCM_STATE_OPEN: printf("open\n"); break; case SND_PCM_STATE_SETUP: printf("SETUP\n"); break; case SND_PCM_STATE_PREPARED: printf("PREPARED\n"); break; case SND_PCM_STATE_RUNNING: printf("RUNNING\n"); break; case SND_PCM_STATE_XRUN: printf("XRUN\n"); break; case SND_PCM_STATE_DRAINING: printf("DRAINING\n"); break; case SND_PCM_STATE_PAUSED: printf("PAUSED\n"); break; case SND_PCM_STATE_SUSPENDED: printf("SUSPENDED\n"); break; } } unsigned char* sound_get_data(void) { return data; } int sound_init(void) { 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(-1); } /* Init hwparams with full configuration space */ if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { fprintf(stderr, "Can not configure this PCM device.\n"); return(-1); } if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { fprintf(stderr, "Error setting access.\n"); return(-1); } /* Set sample format */ if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) { fprintf(stderr, "Error setting format.\n"); return(-1); } /* Set sample rate. If the exact rate is not supported */ /* by the hardware, use nearest possible rate. */ exact_rate = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, &dir); if (dir != 0) { fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n" "==> Using %d Hz instead.\n", rate, exact_rate); } /* Set number of channels */ if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) { fprintf(stderr, "Error setting channels.\n"); return(-1); } /* Set number of periods. Periods used to be called fragments. */ if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0) { fprintf(stderr, "Error setting periods.\n"); return(-1); } /* Set buffer size (in frames). The resulting latency is given by */ /* latency = periodsize * periods / (rate * bytes_per_frame) */ if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize * periods)>>2) < 0) { fprintf(stderr, "Error setting buffersize.\n"); return(-1); } /* Apply HW parameter settings to */ /* PCM device and prepare device */ if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) { fprintf(stderr, "Error setting HW params.\n"); return(-1); } data = (unsigned char *)calloc(periodsize*periods*4, 0); frames = periodsize >> 2; QWE; // snd_pcm_start(pcm_handle); sss = snd_pcm_state(pcm_handle); show(&sss); } void sound_capture(void) { QWE; show(&sss); QWE; while(pcmreturn = snd_pcm_readi(pcm_handle, data, frames), pcmreturn < 0) { snd_pcm_prepare(pcm_handle); QWE; } QWE; show(&sss); QWE; snd_pcm_drop(pcm_handle); QWE; show(&sss); QWE; printf("pcmreturn %i\nperiodsize %i\n", pcmreturn, periodsize); // */ QWE; show(&sss); }