tinycap.c revision dd88f13d9b398c132e3358c62137ff2e23f321ab
17153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson/* tinycap.c 27153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** 37153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** Copyright 2011, The Android Open Source Project 47153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** 57153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** Redistribution and use in source and binary forms, with or without 67153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** modification, are permitted provided that the following conditions are met: 77153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** * Redistributions of source code must retain the above copyright 87153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** notice, this list of conditions and the following disclaimer. 97153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** * Redistributions in binary form must reproduce the above copyright 107153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** notice, this list of conditions and the following disclaimer in the 117153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** documentation and/or other materials provided with the distribution. 127153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** * Neither the name of The Android Open Source Project nor the names of 137153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** its contributors may be used to endorse or promote products derived 147153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** from this software without specific prior written permission. 157153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** 167153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND 177153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 187153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 197153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE 207153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 217153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 227153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 237153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 247153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 257153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 267153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** DAMAGE. 277153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson*/ 287153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 297153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <tinyalsa/asoundlib.h> 307153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <stdio.h> 317153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <stdlib.h> 327153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <stdint.h> 337153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <signal.h> 347153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 357153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define ID_RIFF 0x46464952 367153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define ID_WAVE 0x45564157 377153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define ID_FMT 0x20746d66 387153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define ID_DATA 0x61746164 397153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 407153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define FORMAT_PCM 1 417153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 427153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonstruct wav_header { 437153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t riff_id; 447153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t riff_sz; 457153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t riff_fmt; 467153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t fmt_id; 477153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t fmt_sz; 487153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint16_t audio_format; 497153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint16_t num_channels; 507153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t sample_rate; 517153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t byte_rate; 527153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint16_t block_align; 537153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint16_t bits_per_sample; 547153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t data_id; 557153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson uint32_t data_sz; 567153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson}; 577153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 587153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonint capturing = 1; 597153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 607153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonunsigned int capture_sample(FILE *file, unsigned int device, 617153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int channels, unsigned int rate, 627153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int bits); 637153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 647153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonvoid sigint_handler(int sig) 657153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson{ 667153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson capturing = 0; 677153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson} 687153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 697153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonint main(int argc, char **argv) 707153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson{ 717153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson FILE *file; 727153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson struct wav_header header; 737153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int device = 0; 747153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int channels = 2; 757153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int rate = 44100; 767153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int bits = 16; 777153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int frames; 787153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 797153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson if (argc < 2) { 807153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fprintf(stderr, "Usage: %s file.wav [-d device] [-c channels] " 817153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson "[-r rate] [-b bits]\n", argv[0]); 827153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson return 1; 837153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson } 847153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 857153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson file = fopen(argv[1], "wb"); 867153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson if (!file) { 877153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fprintf(stderr, "Unable to create file '%s'\n", argv[1]); 887153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson return 1; 897153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson } 907153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 917153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson /* parse command line arguments */ 927153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson argv += 2; 937153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson while (*argv) { 94dd88f13d9b398c132e3358c62137ff2e23f321abSimon Wilson if (strcmp(*argv, "-d") == 0) { 957153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson argv++; 967153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson device = atoi(*argv); 97dd88f13d9b398c132e3358c62137ff2e23f321abSimon Wilson } else if (strcmp(*argv, "-c") == 0) { 987153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson argv++; 997153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson channels = atoi(*argv); 100dd88f13d9b398c132e3358c62137ff2e23f321abSimon Wilson } else if (strcmp(*argv, "-r") == 0) { 1017153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson argv++; 1027153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson rate = atoi(*argv); 103dd88f13d9b398c132e3358c62137ff2e23f321abSimon Wilson } else if (strcmp(*argv, "-b") == 0) { 1047153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson argv++; 1057153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson bits = atoi(*argv); 1067153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson } 1077153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson argv++; 1087153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson } 1097153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1107153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.riff_id = ID_RIFF; 1117153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.riff_sz = 0; 1127153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.riff_fmt = ID_WAVE; 1137153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.fmt_id = ID_FMT; 1147153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.fmt_sz = 16; 1157153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.audio_format = FORMAT_PCM; 1167153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.num_channels = channels; 1177153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.sample_rate = rate; 1187153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.byte_rate = (header.bits_per_sample / 8) * channels * rate; 1197153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.block_align = channels * (header.bits_per_sample / 8); 1207153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.bits_per_sample = bits; 1217153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.data_id = ID_DATA; 1227153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1237153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson /* leave enough room for header */ 1247153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fseek(file, sizeof(struct wav_header), SEEK_SET); 1257153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1267153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson /* install signal handler and begin capturing */ 1277153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson signal(SIGINT, sigint_handler); 1287153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson frames = capture_sample(file, device, header.num_channels, 1297153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.sample_rate, header.bits_per_sample); 1307153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson printf("Captured %d frames\n", frames); 1317153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1327153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson /* write header now all information is known */ 1337153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson header.data_sz = frames * header.block_align; 1347153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fseek(file, 0, SEEK_SET); 1357153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fwrite(&header, sizeof(struct wav_header), 1, file); 1367153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1377153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fclose(file); 1387153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1397153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson return 0; 1407153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson} 1417153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1427153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonunsigned int capture_sample(FILE *file, unsigned int device, 1437153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int channels, unsigned int rate, 1447153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int bits) 1457153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson{ 1467153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson struct pcm_config config; 1477153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson struct pcm *pcm; 1487153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson char *buffer; 1497153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int size; 1507153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson unsigned int bytes_read = 0; 1517153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1527153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson config.channels = channels; 1537153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson config.rate = rate; 1547153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson config.period_size = 1024; 1557153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson config.period_count = 4; 1567153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson if (bits == 32) 1577153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson config.format = PCM_FORMAT_S32_LE; 1587153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson else if (bits == 16) 1597153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson config.format = PCM_FORMAT_S16_LE; 1607153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1617153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson pcm = pcm_open(0, device, PCM_IN, &config); 1627153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson if (!pcm || !pcm_is_ready(pcm)) { 1637153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fprintf(stderr, "Unable to open PCM device (%s)\n", 1647153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson pcm_get_error(pcm)); 1657153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson return 0; 1667153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson } 1677153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1687153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson size = pcm_get_buffer_size(pcm); 1697153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson buffer = malloc(size); 1707153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson if (!buffer) { 1717153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fprintf(stderr, "Unable to allocate %d bytes\n", size); 1727153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson free(buffer); 1737153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson pcm_close(pcm); 1747153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson return 0; 1757153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson } 1767153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1777153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); 1787153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1797153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson while (capturing && !pcm_read(pcm, buffer, size)) { 1807153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson if (fwrite(buffer, 1, size, file) != size) { 1817153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson fprintf(stderr,"Error capturing sample\n"); 1827153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson break; 1837153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson } 1847153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson bytes_read += size; 1857153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson } 1867153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 1877153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson free(buffer); 1887153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson pcm_close(pcm); 1897153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson return bytes_read / ((bits / 8) * channels); 1907153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson} 1917153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson 192