1/* tinycap.c 2** 3** Copyright 2011, The Android Open Source Project 4** 5** Redistribution and use in source and binary forms, with or without 6** modification, are permitted provided that the following conditions are met: 7** * Redistributions of source code must retain the above copyright 8** notice, this list of conditions and the following disclaimer. 9** * Redistributions in binary form must reproduce the above copyright 10** notice, this list of conditions and the following disclaimer in the 11** documentation and/or other materials provided with the distribution. 12** * Neither the name of The Android Open Source Project nor the names of 13** its contributors may be used to endorse or promote products derived 14** from this software without specific prior written permission. 15** 16** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND 17** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE 20** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 26** DAMAGE. 27*/ 28 29#include <tinyalsa/asoundlib.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <stdint.h> 33#include <signal.h> 34 35#define ID_RIFF 0x46464952 36#define ID_WAVE 0x45564157 37#define ID_FMT 0x20746d66 38#define ID_DATA 0x61746164 39 40#define FORMAT_PCM 1 41 42struct wav_header { 43 uint32_t riff_id; 44 uint32_t riff_sz; 45 uint32_t riff_fmt; 46 uint32_t fmt_id; 47 uint32_t fmt_sz; 48 uint16_t audio_format; 49 uint16_t num_channels; 50 uint32_t sample_rate; 51 uint32_t byte_rate; 52 uint16_t block_align; 53 uint16_t bits_per_sample; 54 uint32_t data_id; 55 uint32_t data_sz; 56}; 57 58int capturing = 1; 59 60unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device, 61 unsigned int channels, unsigned int rate, 62 unsigned int bits, unsigned int period_size, 63 unsigned int period_count); 64 65void sigint_handler(int sig) 66{ 67 capturing = 0; 68} 69 70int main(int argc, char **argv) 71{ 72 FILE *file; 73 struct wav_header header; 74 unsigned int card = 0; 75 unsigned int device = 0; 76 unsigned int channels = 2; 77 unsigned int rate = 44100; 78 unsigned int bits = 16; 79 unsigned int frames; 80 unsigned int period_size = 1024; 81 unsigned int period_count = 4; 82 83 if (argc < 2) { 84 fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] [-c channels] " 85 "[-r rate] [-b bits] [-p period_size] [-n n_periods]\n", argv[0]); 86 return 1; 87 } 88 89 file = fopen(argv[1], "wb"); 90 if (!file) { 91 fprintf(stderr, "Unable to create file '%s'\n", argv[1]); 92 return 1; 93 } 94 95 /* parse command line arguments */ 96 argv += 2; 97 while (*argv) { 98 if (strcmp(*argv, "-d") == 0) { 99 argv++; 100 if (*argv) 101 device = atoi(*argv); 102 } else if (strcmp(*argv, "-c") == 0) { 103 argv++; 104 if (*argv) 105 channels = atoi(*argv); 106 } else if (strcmp(*argv, "-r") == 0) { 107 argv++; 108 if (*argv) 109 rate = atoi(*argv); 110 } else if (strcmp(*argv, "-b") == 0) { 111 argv++; 112 if (*argv) 113 bits = atoi(*argv); 114 } else if (strcmp(*argv, "-D") == 0) { 115 argv++; 116 if (*argv) 117 card = atoi(*argv); 118 } else if (strcmp(*argv, "-p") == 0) { 119 argv++; 120 if (*argv) 121 period_size = atoi(*argv); 122 } else if (strcmp(*argv, "-n") == 0) { 123 argv++; 124 if (*argv) 125 period_count = atoi(*argv); 126 } 127 if (*argv) 128 argv++; 129 } 130 131 header.riff_id = ID_RIFF; 132 header.riff_sz = 0; 133 header.riff_fmt = ID_WAVE; 134 header.fmt_id = ID_FMT; 135 header.fmt_sz = 16; 136 header.audio_format = FORMAT_PCM; 137 header.num_channels = channels; 138 header.sample_rate = rate; 139 header.bits_per_sample = bits; 140 header.byte_rate = (header.bits_per_sample / 8) * channels * rate; 141 header.block_align = channels * (header.bits_per_sample / 8); 142 header.data_id = ID_DATA; 143 144 /* leave enough room for header */ 145 fseek(file, sizeof(struct wav_header), SEEK_SET); 146 147 /* install signal handler and begin capturing */ 148 signal(SIGINT, sigint_handler); 149 frames = capture_sample(file, card, device, header.num_channels, 150 header.sample_rate, header.bits_per_sample, 151 period_size, period_count); 152 printf("Captured %d frames\n", frames); 153 154 /* write header now all information is known */ 155 header.data_sz = frames * header.block_align; 156 fseek(file, 0, SEEK_SET); 157 fwrite(&header, sizeof(struct wav_header), 1, file); 158 159 fclose(file); 160 161 return 0; 162} 163 164unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device, 165 unsigned int channels, unsigned int rate, 166 unsigned int bits, unsigned int period_size, 167 unsigned int period_count) 168{ 169 struct pcm_config config; 170 struct pcm *pcm; 171 char *buffer; 172 unsigned int size; 173 unsigned int bytes_read = 0; 174 175 config.channels = channels; 176 config.rate = rate; 177 config.period_size = period_size; 178 config.period_count = period_count; 179 if (bits == 32) 180 config.format = PCM_FORMAT_S32_LE; 181 else if (bits == 16) 182 config.format = PCM_FORMAT_S16_LE; 183 config.start_threshold = 0; 184 config.stop_threshold = 0; 185 config.silence_threshold = 0; 186 187 pcm = pcm_open(card, device, PCM_IN, &config); 188 if (!pcm || !pcm_is_ready(pcm)) { 189 fprintf(stderr, "Unable to open PCM device (%s)\n", 190 pcm_get_error(pcm)); 191 return 0; 192 } 193 194 size = pcm_get_buffer_size(pcm); 195 buffer = malloc(size); 196 if (!buffer) { 197 fprintf(stderr, "Unable to allocate %d bytes\n", size); 198 free(buffer); 199 pcm_close(pcm); 200 return 0; 201 } 202 203 printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); 204 205 while (capturing && !pcm_read(pcm, buffer, size)) { 206 if (fwrite(buffer, 1, size, file) != size) { 207 fprintf(stderr,"Error capturing sample\n"); 208 break; 209 } 210 bytes_read += size; 211 } 212 213 free(buffer); 214 pcm_close(pcm); 215 return bytes_read / ((bits / 8) * channels); 216} 217 218