diff options
Diffstat (limited to 'alsa-record-sound/record.c')
-rw-r--r-- | alsa-record-sound/record.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/alsa-record-sound/record.c b/alsa-record-sound/record.c new file mode 100644 index 0000000..ed9c2e1 --- /dev/null +++ b/alsa-record-sound/record.c @@ -0,0 +1,266 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include <alsa/asoundlib.h> + +#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; +}
\ No newline at end of file |