#include #include #include #include #include #include "debug.h" #define AERR(S) if (err<0) {printf("error line %d:"S" %s\n", __LINE__, snd_strerror(err));}; typedef struct audio_params { snd_pcm_format_t format; unsigned int channels; unsigned int rate; } audio_params; int main(int argc, char **argv) { /* variables */ int i; int err; size_t n; snd_pcm_uframes_t chunk_size; size_t chunk_bytes; snd_output_t *log; const snd_pcm_channel_area_t *areas; snd_pcm_uframes_t mmap_offset, mmap_size = chunk_size; long long max_file_size = 0; FILE *fout=NULL; /* audio params */ char audio_name[] = "hw:0"; int open_mode = 0; audio_params params; unsigned int rate; unsigned int buffer_time; unsigned int period_time; snd_pcm_uframes_t period_frames = 0; snd_pcm_uframes_t buffer_frames = 0; int monotonic = 0; int can_pause = 0; int avail_min = -1; int start_delay = 0; int stop_delay = 0; snd_pcm_uframes_t start_threshold, stop_threshold; size_t significant_bits_per_sample, bits_per_sample, bits_per_frame; u_char *audiobuf = NULL; uint64_t fdcount=0; /* audio variables */ snd_pcm_t *handle; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size; snd_pcm_access_mask_t *mask; /* set recording params */ params.channels = 2; params.rate = 44100; params.format = SND_PCM_FORMAT_S16_LE; /* set device */ err = snd_pcm_open(&handle, audio_name, SND_PCM_STREAM_CAPTURE, open_mode); AERR("Cant open"); /* alloc hw params */ err = snd_pcm_hw_params_malloc(&hwparams); AERR("hw params alloc"); err = snd_pcm_hw_params_any(handle, hwparams); AERR("hw params initialisation"); /* alooc sw params */ err = snd_pcm_sw_params_malloc(&swparams); AERR("sw params alloca"); /* mmaped buffer */ mask = alloca(snd_pcm_access_mask_sizeof()); snd_pcm_access_mask_none(mask); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX); err = snd_pcm_hw_params_set_access_mask(handle, hwparams, mask); AERR("Cannot set access mask"); /* set channels */ err = snd_pcm_hw_params_set_channels(handle, hwparams, params.channels ); AERR("Cannot set channels");PNL(); /* set and check rate */ rate = params.rate; err = snd_pcm_hw_params_set_rate_near(handle, hwparams, ¶ms.rate, 0); if ((float)rate*1.05 < params.rate || (float)rate*0.95>params.rate) { printf("Inaccurare rate setting\n"); } /*set buffer time and perioid max*/ rate = params.rate; if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0); AERR("Cannt get buffer time max"); if (buffer_time > 500000) buffer_time = 500000; } if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) { err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); } else { err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_frames, 0); } AERR("Cant set period");PNL(); if (buffer_time > 0) { err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); } else { err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_frames); } AERR("Cant set buffer time/size");PNL(); monotonic = snd_pcm_hw_params_is_monotonic(hwparams); can_pause = snd_pcm_hw_params_can_pause(hwparams); err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { printf("Unable to install hw params:\n"); snd_pcm_hw_params_dump(hwparams, log); exit(EXIT_FAILURE); } snd_pcm_hw_params_get_period_size(hwparams, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); if (chunk_size == buffer_size) { printf("Can't use period equal to buffer size (%lu == %lu)\n", chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); if (avail_min < 0) { n = chunk_size; } else { n = (double)rate * avail_min * 1000000; } err = snd_pcm_sw_params_set_avail_min(handle, swparams, n); AERR("Couldnt set avaliable min"); /* round up to closest transfer boundry */ n = buffer_size; if (start_delay <= 0) { start_threshold = n + (double) rate * start_delay / 1000000; } else start_threshold = (double) rate * start_delay / 1000000; if (start_threshold < 1) start_threshold = 1; if (start_threshold > n) start_threshold = n; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err >= 0); if (stop_delay <= 0) stop_threshold = buffer_size + (double) rate * stop_delay / 1000000; else stop_threshold = (double) rate * stop_delay / 1000000; err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); assert(err >= 0); err = snd_pcm_sw_params(handle, swparams); AERR("Unable to install sw params\n");PNL(); /*do we neet setup_chmap?*/ //snd_pcm_dump(handle, log);PNL(); bits_per_sample = snd_pcm_format_physical_width(params.format); printf("!bits_per_sample=%d\n",bits_per_sample); significant_bits_per_sample = snd_pcm_format_width(params.format); bits_per_frame = bits_per_sample * params.channels; chunk_bytes = chunk_size * bits_per_frame / 8; printf("INFO: audio buffer size %d bytes\n",chunk_bytes); audiobuf = realloc(audiobuf, chunk_bytes); if (audiobuf == NULL) { printf("not enough memory\n"); exit(EXIT_FAILURE); } // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size); /* show mmap buffer arragment */ err = snd_pcm_mmap_begin(handle, &areas, &mmap_offset, &mmap_size); if (err < 0) { printf("snd_pcm_mmap_begin problem: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } for (i = 0; i < params.channels; i++) fprintf(stderr, "mmap_area[%i] = %p,%u,%u (%u)\n", i, areas[i].addr, areas[i].first, areas[i].step, snd_pcm_format_physical_width(params.format)); /* not required, but for sure */ snd_pcm_mmap_commit(handle, mmap_offset, 0); buffer_frames = buffer_size; /* for position test */ /* get size of record for current config */ max_file_size = snd_pcm_format_size(params.format, params.rate*params.channels); printf("INFO: Date %d byters per record\n", max_file_size); /* open file where to record */ fout = fopen("foo_r2.wav","w"); if (fout==NULL) { printf("Couldnt open record file"); exit(0); } /* recording loop */ { size_t rest=0; size_t r=0; size_t idx=0; u_char *data = audiobuf; size_t c = chunk_bytes; size_t f = c * 8 / bits_per_frame; rest = f*100; idx = 0; //fdcount = 0; while (rest > 1) { r = snd_pcm_mmap_readi(handle,data, f); if ((r == -EAGAIN) || ((r >= 0) && (r < rest))) { //snd_pcm_wait(handle, 100); } else { printf("Buffer reading problem %d\n",r); //break; } rest -= r; err = fwrite(audiobuf,1,r*bits_per_frame/8,fout); if (err != r*bits_per_frame/8) printf("Not all data saved %d\n",err); } } fclose(fout); /* free audio resources */ snd_pcm_close(handle); free(audiobuf); //snd_output_close(log); snd_config_update_free_global(); return 0; }