• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 static char buffer[4096];
20 
21 struct 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 
init_wav_header(struct wav_header * hdr,uint32_t num_samples,uint16_t bits_per_sample,int channels,uint32_t sample_rate)39 static 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 
77 int
main(int argc,char * argv[])78 main(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