The original pcm.c has 925 lines to send a sine wave with various transfer methods. Here is a simplified version only to support asynchronous notification, and instead of playing a waveform, the audio signal is captured from the device.
The source program is compiled, the audio signal from IC-7410 (hw:2,0) is captured and stored in a file, and the file is played back on a speaker (hw:1,3).
/* file name = pcm_capture3.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sched.h> #include <errno.h> #include <getopt.h> #include "asoundlib.h" #include <sys/time.h> #include <math.h> static char *device = "hw:2,0"; /* playback device is IC-7410*/ static unsigned int rate = 44100; /* stream rate */ static unsigned int channels = 2; /* count of channels */ static int byte_per_sample = 2; /* 16 bit format */ static unsigned int buffer_time = 500000; /* ring buffer length in us */ static unsigned int period_time = 100000; /* period time in us */ static int resample = 0; /* enable alsa-lib resampling */ static int period_event = 0; /* produce poll event after each period */ static snd_pcm_sframes_t buffer_size; static snd_pcm_sframes_t period_size; static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params) { unsigned int rrate; snd_pcm_uframes_t size; int err, dir; /* choose all parameters */ err = snd_pcm_hw_params_any(handle, params); if (err < 0) { fprintf(stderr,"Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); return err; } /* set hardware resampling */ err = snd_pcm_hw_params_set_rate_resample(handle, params, resample); if (err < 0) { fprintf(stderr,"Resampling setup failed for playback: %s\n", snd_strerror(err)); return err; } /* set the interleaved read/write format */ err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { fprintf(stderr,"Access type not available for playback: %s\n", snd_strerror(err)); return err; } /* set the sample format */ err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16); if (err < 0) { fprintf(stderr,"Sample format not available for playback: %s\n", snd_strerror(err)); return err; } /* set the count of channels */ err = snd_pcm_hw_params_set_channels(handle, params, channels); if (err < 0) { fprintf(stderr,"Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); return err; } /* set the stream rate */ rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); if (err < 0) { fprintf(stderr,"Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); return err; } if (rrate != rate) { fprintf(stderr,"Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); return -EINVAL; } /* set the buffer time */ err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir); if (err < 0) { fprintf(stderr,"Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)); return err; } err = snd_pcm_hw_params_get_buffer_size(params, &size); if (err < 0) { fprintf(stderr,"Unable to get buffer size for playback: %s\n", snd_strerror(err)); return err; } buffer_size = size; /* set the period time */ err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir); if (err < 0) { fprintf(stderr,"Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); return err; } err = snd_pcm_hw_params_get_period_size(params, &size, &dir); if (err < 0) { fprintf(stderr,"Unable to get period size for playback: %s\n", snd_strerror(err)); return err; } period_size = size; /* write the parameters to device */ err = snd_pcm_hw_params(handle, params); if (err < 0) { fprintf(stderr,"Unable to set hw params for playback: %s\n", snd_strerror(err)); return err; } return 0; } static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) { int err; /* get the current swparams */ err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { fprintf(stderr,"Unable to determine current swparams for playback: %s\n", snd_strerror(err)); return err; } /* start the transfer when the buffer is almost full: */ /* (buffer_size / avail_min) * avail_min */ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (buffer_size / period_size) * period_size); if (err < 0) { fprintf(stderr,"Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); return err; } /* allow the transfer when at least period_size samples can be processed */ /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */ err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size); if (err < 0) { fprintf(stderr,"Unable to set avail min for playback: %s\n", snd_strerror(err)); return err; } /* enable period events when requested */ if (period_event) { err = snd_pcm_sw_params_set_period_event(handle, swparams, 1); if (err < 0) { fprintf(stderr,"Unable to set period event: %s\n", snd_strerror(err)); return err; } } /* write the parameters to the playback device */ err = snd_pcm_sw_params(handle, swparams); if (err < 0) { fprintf(stderr,"Unable to set sw params for playback: %s\n", snd_strerror(err)); return err; } return 0; } static void async_callback(snd_async_handler_t *ahandler) { snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); signed short *samples = snd_async_handler_get_callback_private(ahandler); snd_pcm_sframes_t avail; int err, write_count, wc; avail = snd_pcm_avail_update(handle); while (avail >= period_size) { err = snd_pcm_readi (handle, samples, period_size); if (err < 0) { fprintf(stderr,"Write error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if (err != period_size) { fprintf(stderr,"Write error: written %i expected %li\n", err, period_size); exit(EXIT_FAILURE); } write_count = period_size * channels * byte_per_sample; wc = write(1, samples, write_count); if(wc != write_count) { fprintf(stderr,"file write error. \n"); } avail = snd_pcm_avail_update(handle); } } static int async_loop(snd_pcm_t *handle, signed short *samples) { snd_async_handler_t *ahandler; int err; err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, samples); if (err < 0) { fprintf(stderr,"Unable to register async handler\n"); exit(EXIT_FAILURE); } if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED) { err = snd_pcm_start(handle); if (err < 0) { fprintf(stderr,"Start error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } } while (1) { sleep(1); } } int main(int argc, char *argv[]) { snd_pcm_t *handle; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; signed short *samples; int err; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); fprintf(stderr,"capture device = %s, rate = %i Hz, %i channels\n", device, rate, channels); if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) { fprintf(stderr,"Capture open error: %s\n", snd_strerror(err)); return 0; } if ((err = set_hwparams(handle, hwparams)) < 0) { fprintf(stderr,"Setting of hwparams failed: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = set_swparams(handle, swparams)) < 0) { fprintf(stderr,"Setting of swparams failed: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } samples = malloc(period_size * channels * byte_per_sample); if (samples == NULL) { fprintf(stderr,"No enough memory\n"); exit(EXIT_FAILURE); } err = async_loop(handle, samples); if (err < 0) fprintf(stderr,"Transfer failed: %s\n", snd_strerror(err)); free(samples); snd_pcm_close(handle); return 0; }