1#include <unistd.h> 2#include <stdlib.h> 3#include <stdio.h> 4#include <fcntl.h> 5#include <errno.h> 6#include <stdint.h> 7#include <assert.h> 8#include <sys/types.h> 9#include <sys/stat.h> 10#include <sys/ioctl.h> 11#include <linux/cpcap_audio.h> 12#include <linux/tegra_audio.h> 13 14#define FAILIF(x, ...) do if (x) { \ 15 fprintf(stderr, __VA_ARGS__); \ 16 exit(EXIT_FAILURE); \ 17} while (0) 18 19static char buffer[4096]; 20 21struct wav_header { 22 char riff[4]; 23 uint32_t chunk_size; 24 char format[4]; 25 26 char subchunk1_id[4]; 27 uint32_t subchunk1_size; 28 uint16_t audio_format; 29 uint16_t num_channels; 30 uint32_t sample_rate; 31 uint32_t byte_rate; 32 uint16_t block_align; 33 uint16_t bits_per_sample; 34 35 char subchunk2_id[4]; 36 uint32_t subchunk2_size; 37} __attribute__((packed)); 38 39static void init_wav_header(struct wav_header *hdr, 40 uint32_t num_samples, 41 uint16_t bits_per_sample, 42 int channels, 43 uint32_t sample_rate) 44{ 45 hdr->riff[0] = 'R'; 46 hdr->riff[1] = 'I'; 47 hdr->riff[2] = 'F'; 48 hdr->riff[3] = 'F'; 49 50 hdr->subchunk2_size = num_samples * channels * bits_per_sample / 8; 51 52 hdr->chunk_size = 36 + hdr->subchunk2_size; 53 hdr->format[0] = 'W'; 54 hdr->format[1] = 'A'; 55 hdr->format[2] = 'V'; 56 hdr->format[3] = 'E'; 57 58 hdr->subchunk1_id[0] = 'f'; 59 hdr->subchunk1_id[1] = 'm'; 60 hdr->subchunk1_id[2] = 't'; 61 hdr->subchunk1_id[3] = ' '; 62 63 hdr->subchunk1_size = 16; 64 hdr->audio_format = 1; /* PCM */ 65 hdr->num_channels = channels; 66 hdr->sample_rate = sample_rate; 67 hdr->byte_rate = sample_rate * channels * bits_per_sample / 8; 68 hdr->block_align = channels * bits_per_sample / 8; 69 hdr->bits_per_sample = bits_per_sample; 70 71 hdr->subchunk2_id[0] = 'd'; 72 hdr->subchunk2_id[1] = 'a'; 73 hdr->subchunk2_id[2] = 't'; 74 hdr->subchunk2_id[3] = 'a'; 75} 76 77int 78main(int argc, char *argv[]) 79{ 80 int ifd, ifd_c, ofd, opt, cfd; 81 const char *name; 82 int nr, nw = 0, total = 0; 83 int wave = 0; 84 const int bits_per_sample = 16; 85 int sampling_rate = -1; 86 int num_channels = -1; 87 88 struct tegra_audio_in_config cfg; 89 struct wav_header hdr; 90 91 while ((opt = getopt(argc, argv, "wc:s:")) != -1) { 92 switch (opt) { 93 case 'w': 94 wave = 1; 95 break; 96 case 'c': 97 num_channels = atoi(optarg); 98 assert(num_channels == 1 || num_channels == 2); 99 break; 100 case 's': 101 sampling_rate = atoi(optarg); 102 break; 103 default: /* '?' */ 104 fprintf(stderr, 105 "usage: %s [-w] [-s<rate>] [-c<chans>] <destfile>\n", 106 *argv); 107 exit(EXIT_FAILURE); 108 } 109 } 110 111 FAILIF(optind >= argc, 112 "usage: %s [-w] [-s<rate>] [-c<chans>] <destfile>\n", 113 *argv); 114 115 name = argv[optind]; 116 117 printf("> recording into %s\n", name); 118 printf("> sampling rate %d\n", sampling_rate); 119 printf("> channels %d\n", num_channels); 120 121 cfd = open("/dev/audio_ctl", O_RDWR); 122 FAILIF(cfd < 0, "could not open control: %s\n", strerror(errno)); 123 if(sampling_rate > 0) { 124 FAILIF(ioctl(cfd, CPCAP_AUDIO_IN_SET_RATE, sampling_rate), 125 "Could not set input sampling rate: %s\n", strerror(errno)); 126 } 127 128 ifd = open("/dev/audio1_in", O_RDWR); 129 FAILIF(ifd < 0, "could not open input: %s\n", strerror(errno)); 130 131 ifd_c = open("/dev/audio1_in_ctl", O_RDWR); 132 FAILIF(ifd < 0, "could not open input: %s\n", strerror(errno)); 133 134 printf("getting audio-input config\n"); 135 FAILIF(ioctl(ifd_c, TEGRA_AUDIO_IN_GET_CONFIG, &cfg) < 0, 136 "could not get input config: %s\n", strerror(errno)); 137 138 if (num_channels >= 0 || sampling_rate >= 0) { 139 if (num_channels >= 0) 140 cfg.stereo = num_channels == 2; 141// if (sampling_rate >= 0) 142// cfg.rate = sampling_rate; 143// No sample rate conversion in driver 144 cfg.rate = 44100; 145 printf("setting audio-input config (stereo %d, rate %d)\n", 146 cfg.stereo, cfg.rate); 147 FAILIF(ioctl(ifd_c, TEGRA_AUDIO_IN_SET_CONFIG, &cfg) < 0, 148 "could not set input config: %s\n", strerror(errno)); 149 } 150 151 if (num_channels < 0) { 152 num_channels = cfg.stereo ? 2 : 1; 153 printf("> channels %d (from config)\n", num_channels); 154 } 155 156 if (sampling_rate < 0) { 157 sampling_rate = cfg.rate; 158 printf("> sampling rate %d (from config)\n", sampling_rate); 159 } 160 161 ofd = open(name, O_WRONLY | O_TRUNC | O_CREAT, 0666); 162 FAILIF(ofd < 0, "could not open %s: %s\n", name, strerror(errno)); 163 164 if (wave) 165 FAILIF(lseek(ofd, sizeof(struct wav_header), SEEK_SET) < 0, 166 "seek error: %s\n", strerror(errno)); 167 168 do { 169 errno = 0; 170 nr = read(ifd, buffer, sizeof(buffer)); 171 FAILIF(nr < 0, "input read error: %s\n", strerror(errno)); 172 173 if (!nr) { 174 printf("done recording\n"); 175 break; 176 } 177 178 printf("in %d\n", nr); 179 180 nw = write(ofd, buffer, nr); 181 FAILIF(nw < 0, "Could not copy to output: %s\n", strerror(errno)); 182 FAILIF(nw != nr, "Mismatch nw = %d nr = %d\n", nw, nr); 183 total += nw; 184 } while (1); 185 186 if (wave) { 187 printf("writing WAV header\n"); 188 lseek(ofd, 0, SEEK_SET); 189 init_wav_header(&hdr, 190 total * 8 / (num_channels * bits_per_sample), 191 bits_per_sample, 192 num_channels, 193 sampling_rate); 194 FAILIF(write(ofd, &hdr, sizeof(hdr)) != sizeof(hdr), 195 "Could not write WAV header: %s\n", strerror(errno)); 196 } 197 198 printf("done\n"); 199 return 0; 200} 201