From 8b6b56c20342aea92ff6b389d2174fc9ebf9c21e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 26 Apr 2009 22:42:19 +0200 Subject: Implement basic measurement logic --- dbmeasure.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 24 deletions(-) diff --git a/dbmeasure.c b/dbmeasure.c index c6d2c1d..f9140c8 100644 --- a/dbmeasure.c +++ b/dbmeasure.c @@ -30,10 +30,12 @@ static snd_pcm_t *open_device(const char *name, snd_pcm_stream_t stream, unsigne snd_pcm_t *d; int r; snd_pcm_hw_params_t *hw; + snd_pcm_uframes_t t; + snd_output_t *output = NULL; snd_pcm_hw_params_alloca(&hw); - if ((r = snd_pcm_open(&d, name, stream, 0)) < 0) { + if ((r = snd_pcm_open(&d, name, stream, SND_PCM_NONBLOCK)) < 0) { fprintf(stderr, "Cannot open audio device %s: %s\n", name, snd_strerror(r)); goto finish; } @@ -44,36 +46,58 @@ static snd_pcm_t *open_device(const char *name, snd_pcm_stream_t stream, unsigne } if ((r = snd_pcm_hw_params_set_access(d, hw, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { - fprintf(stderr, "Cannot set access type (%s)\n", snd_strerror(r)); + fprintf(stderr, "Cannot set access type: %s\n", snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params_set_format(d, hw, SND_PCM_FORMAT_FLOAT_LE)) < 0) { - fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(r)); + fprintf(stderr, "Cannot set sample format: %s\n", snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params_set_rate(d, hw, rate, 0)) < 0) { - fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(r)); + fprintf(stderr, "Cannot set sample rate: %s\n", snd_strerror(r)); goto finish; } - if ((r = snd_pcm_hw_params_set_channels(d, hw, 2)) < 0) { - fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(r)); + if ((r = snd_pcm_hw_params_set_channels(d, hw, 1)) < 0) { + fprintf(stderr, "Cannot set channel count: %s\n", snd_strerror(r)); + goto finish; + } + + t = rate; + if ((r = snd_pcm_hw_params_set_buffer_size_near(d, hw, &t)) < 0) { + fprintf(stderr, "Cannot set buffer size: %s\n", snd_strerror(r)); goto finish; } if ((r = snd_pcm_hw_params(d, hw)) < 0) { - fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(r)); + fprintf(stderr, "Cannot set parameters: %s\n", snd_strerror(r)); + goto finish; + } + + if ((r = snd_output_stdio_attach(&output, stderr, 0)) < 0) { + fprintf(stderr, "Cannot attach to stderr: %s\n", snd_strerror(r)); + goto finish; + } + + if ((r = snd_pcm_dump(d, output)) < 0) { + fprintf(stderr, "Cannot dump status: %s\n", snd_strerror(r)); goto finish; } + snd_output_close(output); + return d; finish: if (d) snd_pcm_close(d); + if (output) + snd_output_close(output); + + return NULL; } @@ -93,13 +117,15 @@ static double compute_level(const float *buffer, float *sum, unsigned n_samples, int main(int argc, char *argv[]) { int ret = 1; - snd_pcm_sframes_t n; float *signal = NULL, *silence = NULL, *buffer = NULL, *sum = NULL; snd_pcm_t *input = NULL, *output = NULL; unsigned rate = 44100; - unsigned skip_input = 0, skip_output = 0; + unsigned rindex = 0, windex = 0; double frequency = 440.0, amplitude = 0.5; - unsigned iteration; + unsigned iteration = 0; + int icount, ocount; + struct pollfd *pollfd; + int e; if (argc < 2) { fprintf(stderr, "Need to specify device.\n"); @@ -132,30 +158,91 @@ int main(int argc, char *argv[]) { goto finish; } - for (iteration = 1;; iteration ++) { - if ((n = snd_pcm_writei(output, silence + skip_input, rate - skip_input)) < 0) { - fprintf(stderr, "Cannot write samples: %s\n", snd_strerror(n)); + if ((icount = snd_pcm_poll_descriptors_count(input)) <= 0 || + (ocount = snd_pcm_poll_descriptors_count(output)) <= 0) { + fprintf(stderr, "Failed to determine number of pollfd descriptors.\n"); + goto finish; + } + + if (!(pollfd = calloc(icount + ocount, sizeof(struct pollfd)))) { + fprintf(stderr, "Failed to allocate pollfd array.\n"); + goto finish; + } + + if ((e = snd_pcm_prepare(input)) < 0 || + (e = snd_pcm_prepare(output)) < 0) { + fprintf(stderr, "snd_pcm_prepare() failed: %s\n", snd_strerror(e)); + goto finish; + } + + if ((e = snd_pcm_start(input)) < 0) { + fprintf(stderr, "snd_pcm_start() failed: %s\n", snd_strerror(e)); + goto finish; + } + + for (;;) { + snd_pcm_sframes_t n; + unsigned short irevents, orevents; + + if (snd_pcm_poll_descriptors(input, pollfd, icount) != icount || + snd_pcm_poll_descriptors(output, pollfd+icount, ocount) != ocount) { + fprintf(stderr, "ALSA changed its mind about number of file descriptors."); goto finish; } - skip_input += n; - if (skip_input == rate) - skip_input = 0; + if (poll(pollfd, icount+ocount, -1) < 0) { + fprintf(stderr, "poll() failed: %s\n", strerror(errno)); + goto finish; + } - if ((n = snd_pcm_readi(output, buffer + skip_output, rate - skip_output)) < 0) { - fprintf(stderr, "Cannot read samples: %s\n", snd_strerror(n)); + if ((e = snd_pcm_poll_descriptors_revents(input, pollfd, icount, &irevents)) < 0 || + (e = snd_pcm_poll_descriptors_revents(output, pollfd+icount, ocount, &orevents)) < 0) { + fprintf(stderr, "Cannot get revents: %s\n", snd_strerror(e)); goto finish; } - skip_output += n; - if (skip_output == rate) { - double level; + if (orevents) { + if ((n = snd_pcm_writei(output, signal + windex, rate - windex)) < 0) { + + if (snd_pcm_recover(output, n, 0) < 0) { + fprintf(stderr, "Cannot write samples: %s\n", snd_strerror(n)); + goto finish; + } else + continue; + } + + windex += n; + if (windex == rate) + windex = 0; + } + + + if (irevents) { + if ((n = snd_pcm_readi(input, buffer + rindex, rate - rindex)) < 0) { + + if (snd_pcm_recover(input, n, 0) < 0) { + fprintf(stderr, "Cannot read samples: %s\n", snd_strerror(n)); + goto finish; + } + + if ((e = snd_pcm_start(input)) < 0) { + fprintf(stderr, "snd_pcm_start() failed: %s\n", snd_strerror(e)); + goto finish; + } + + continue; + } - skip_output = 0; + rindex += n; + if (rindex == rate) { + double level; - level = compute_level(buffer, sum, rate, iteration); + rindex = 0; - fprintf(stderr, "Iteration %u, level is %g.\n", iteration, level); + iteration++; + level = compute_level(buffer, sum, rate, iteration); + fprintf(stderr, "Iteration %u, level is %g.\n", iteration, level); + } } } -- cgit