1 /* Copyright (C) 2008 The Android Open Source Project
2 */
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <fcntl.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <sys/mman.h>
10 #include <sys/ioctl.h>
11 #include <unistd.h>
12
13 #include <linux/ioctl.h>
14
15 #define AUDIO_IOCTL_MAGIC 'a'
16
17 #define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned)
18 #define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
19 #define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
20 #define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
21 #define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
22 #define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned)
23
24 struct msm_audio_config {
25 uint32_t buffer_size;
26 uint32_t buffer_count;
27 uint32_t channel_count;
28 uint32_t sample_rate;
29 uint32_t codec_type;
30 uint32_t unused[3];
31 };
32
33 struct msm_audio_stats {
34 uint32_t out_bytes;
35 uint32_t unused[3];
36 };
37
pcm_play(unsigned rate,unsigned channels,int (* fill)(void * buf,unsigned sz,void * cookie),void * cookie)38 int pcm_play(unsigned rate, unsigned channels,
39 int (*fill)(void *buf, unsigned sz, void *cookie),
40 void *cookie)
41 {
42 struct msm_audio_config config;
43 struct msm_audio_stats stats;
44 unsigned sz, n;
45 char buf[8192];
46 int afd;
47
48 afd = open("/dev/msm_pcm_out", O_RDWR);
49 if (afd < 0) {
50 perror("pcm_play: cannot open audio device");
51 return -1;
52 }
53
54 if(ioctl(afd, AUDIO_GET_CONFIG, &config)) {
55 perror("could not get config");
56 return -1;
57 }
58
59 config.channel_count = channels;
60 config.sample_rate = rate;
61 if (ioctl(afd, AUDIO_SET_CONFIG, &config)) {
62 perror("could not set config");
63 return -1;
64 }
65 sz = config.buffer_size;
66 if (sz > sizeof(buf)) {
67 fprintf(stderr,"too big\n");
68 return -1;
69 }
70
71 fprintf(stderr,"prefill\n");
72 for (n = 0; n < config.buffer_count; n++) {
73 if (fill(buf, sz, cookie))
74 break;
75 if (write(afd, buf, sz) != sz)
76 break;
77 }
78
79 fprintf(stderr,"start\n");
80 ioctl(afd, AUDIO_START, 0);
81
82 for (;;) {
83 #if 0
84 if (ioctl(afd, AUDIO_GET_STATS, &stats) == 0)
85 fprintf(stderr,"%10d\n", stats.out_bytes);
86 #endif
87 if (fill(buf, sz, cookie))
88 break;
89 if (write(afd, buf, sz) != sz)
90 break;
91 }
92
93 done:
94 close(afd);
95 return 0;
96 }
97
98 /* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
99
100 #define ID_RIFF 0x46464952
101 #define ID_WAVE 0x45564157
102 #define ID_FMT 0x20746d66
103 #define ID_DATA 0x61746164
104
105 #define FORMAT_PCM 1
106
107 struct wav_header {
108 uint32_t riff_id;
109 uint32_t riff_sz;
110 uint32_t riff_fmt;
111 uint32_t fmt_id;
112 uint32_t fmt_sz;
113 uint16_t audio_format;
114 uint16_t num_channels;
115 uint32_t sample_rate;
116 uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
117 uint16_t block_align; /* num_channels * bps / 8 */
118 uint16_t bits_per_sample;
119 uint32_t data_id;
120 uint32_t data_sz;
121 };
122
123
124 static char *next;
125 static unsigned avail;
126
fill_buffer(void * buf,unsigned sz,void * cookie)127 int fill_buffer(void *buf, unsigned sz, void *cookie)
128 {
129 if (sz > avail)
130 return -1;
131 memcpy(buf, next, sz);
132 next += sz;
133 avail -= sz;
134 return 0;
135 }
136
play_file(unsigned rate,unsigned channels,int fd,unsigned count)137 void play_file(unsigned rate, unsigned channels,
138 int fd, unsigned count)
139 {
140 next = malloc(count);
141 if (!next) {
142 fprintf(stderr,"could not allocate %d bytes\n", count);
143 return;
144 }
145 if (read(fd, next, count) != count) {
146 fprintf(stderr,"could not read %d bytes\n", count);
147 return;
148 }
149 avail = count;
150 pcm_play(rate, channels, fill_buffer, 0);
151 }
152
wav_play(const char * fn)153 int wav_play(const char *fn)
154 {
155 struct wav_header hdr;
156 unsigned rate, channels;
157 int fd;
158 fd = open(fn, O_RDONLY);
159 if (fd < 0) {
160 fprintf(stderr, "playwav: cannot open '%s'\n", fn);
161 return -1;
162 }
163 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
164 fprintf(stderr, "playwav: cannot read header\n");
165 return -1;
166 }
167 fprintf(stderr,"playwav: %d ch, %d hz, %d bit, %s\n",
168 hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
169 hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
170
171 if ((hdr.riff_id != ID_RIFF) ||
172 (hdr.riff_fmt != ID_WAVE) ||
173 (hdr.fmt_id != ID_FMT)) {
174 fprintf(stderr, "playwav: '%s' is not a riff/wave file\n", fn);
175 return -1;
176 }
177 if ((hdr.audio_format != FORMAT_PCM) ||
178 (hdr.fmt_sz != 16)) {
179 fprintf(stderr, "playwav: '%s' is not pcm format\n", fn);
180 return -1;
181 }
182 if (hdr.bits_per_sample != 16) {
183 fprintf(stderr, "playwav: '%s' is not 16bit per sample\n", fn);
184 return -1;
185 }
186
187 play_file(hdr.sample_rate, hdr.num_channels,
188 fd, hdr.data_sz);
189
190 return 0;
191 }
192
wav_rec(const char * fn,unsigned channels,unsigned rate)193 int wav_rec(const char *fn, unsigned channels, unsigned rate)
194 {
195 struct wav_header hdr;
196 unsigned char buf[8192];
197 struct msm_audio_config cfg;
198 unsigned sz, n;
199 int fd, afd;
200 unsigned total = 0;
201 unsigned char tmp;
202
203 hdr.riff_id = ID_RIFF;
204 hdr.riff_sz = 0;
205 hdr.riff_fmt = ID_WAVE;
206 hdr.fmt_id = ID_FMT;
207 hdr.fmt_sz = 16;
208 hdr.audio_format = FORMAT_PCM;
209 hdr.num_channels = channels;
210 hdr.sample_rate = rate;
211 hdr.byte_rate = hdr.sample_rate * hdr.num_channels * 2;
212 hdr.block_align = hdr.num_channels * 2;
213 hdr.bits_per_sample = 16;
214 hdr.data_id = ID_DATA;
215 hdr.data_sz = 0;
216
217 fd = open(fn, O_CREAT | O_RDWR, 0666);
218 if (fd < 0) {
219 perror("cannot open output file");
220 return -1;
221 }
222 write(fd, &hdr, sizeof(hdr));
223
224 afd = open("/dev/msm_pcm_in", O_RDWR);
225 if (afd < 0) {
226 perror("cannot open msm_pcm_in");
227 close(fd);
228 return -1;
229 }
230
231 /* config change should be a read-modify-write operation */
232 if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
233 perror("cannot read audio config");
234 goto fail;
235 }
236
237 cfg.channel_count = hdr.num_channels;
238 cfg.sample_rate = hdr.sample_rate;
239 if (ioctl(afd, AUDIO_SET_CONFIG, &cfg)) {
240 perror("cannot write audio config");
241 goto fail;
242 }
243
244 if (ioctl(afd, AUDIO_GET_CONFIG, &cfg)) {
245 perror("cannot read audio config");
246 goto fail;
247 }
248
249 sz = cfg.buffer_size;
250 fprintf(stderr,"buffer size %d x %d\n", sz, cfg.buffer_count);
251 if (sz > sizeof(buf)) {
252 fprintf(stderr,"buffer size %d too large\n", sz);
253 goto fail;
254 }
255
256 if (ioctl(afd, AUDIO_START, 0)) {
257 perror("cannot start audio");
258 goto fail;
259 }
260
261 fcntl(0, F_SETFL, O_NONBLOCK);
262 fprintf(stderr,"\n*** RECORDING * HIT ENTER TO STOP ***\n");
263
264 for (;;) {
265 while (read(0, &tmp, 1) == 1) {
266 if ((tmp == 13) || (tmp == 10)) goto done;
267 }
268 if (read(afd, buf, sz) != sz) {
269 perror("cannot read buffer");
270 goto fail;
271 }
272 if (write(fd, buf, sz) != sz) {
273 perror("cannot write buffer");
274 goto fail;
275 }
276 total += sz;
277
278 }
279 done:
280 close(afd);
281
282 /* update lengths in header */
283 hdr.data_sz = total;
284 hdr.riff_sz = total + 8 + 16 + 8;
285 lseek(fd, 0, SEEK_SET);
286 write(fd, &hdr, sizeof(hdr));
287 close(fd);
288 return 0;
289
290 fail:
291 close(afd);
292 close(fd);
293 unlink(fn);
294 return -1;
295 }
296
mp3_play(const char * fn)297 int mp3_play(const char *fn)
298 {
299 char buf[64*1024];
300 int r;
301 int fd, afd;
302
303 fd = open(fn, O_RDONLY);
304 if (fd < 0) {
305 perror("cannot open mp3 file");
306 return -1;
307 }
308
309 afd = open("/dev/msm_mp3", O_RDWR);
310 if (afd < 0) {
311 close(fd);
312 perror("cannot open mp3 output device");
313 return -1;
314 }
315
316 fprintf(stderr,"MP3 PLAY\n");
317 ioctl(afd, AUDIO_START, 0);
318
319 for (;;) {
320 r = read(fd, buf, 64*1024);
321 if (r <= 0) break;
322 r = write(afd, buf, r);
323 if (r < 0) break;
324 }
325
326 close(fd);
327 close(afd);
328 return 0;
329 }
330
main(int argc,char ** argv)331 int main(int argc, char **argv)
332 {
333 const char *fn = 0;
334 int play = 1;
335 unsigned channels = 1;
336 unsigned rate = 44100;
337
338 argc--;
339 argv++;
340 while (argc > 0) {
341 if (!strcmp(argv[0],"-rec")) {
342 play = 0;
343 } else if (!strcmp(argv[0],"-play")) {
344 play = 1;
345 } else if (!strcmp(argv[0],"-stereo")) {
346 channels = 2;
347 } else if (!strcmp(argv[0],"-mono")) {
348 channels = 1;
349 } else if (!strcmp(argv[0],"-rate")) {
350 argc--;
351 argv++;
352 if (argc == 0) {
353 fprintf(stderr,"playwav: -rate requires a parameter\n");
354 return -1;
355 }
356 rate = atoi(argv[0]);
357 } else {
358 fn = argv[0];
359 }
360 argc--;
361 argv++;
362 }
363
364 if (fn == 0) {
365 fn = play ? "/data/out.wav" : "/data/rec.wav";
366 }
367
368 if (play) {
369 const char *dot = strrchr(fn, '.');
370 if (dot && !strcmp(dot,".mp3")) {
371 return mp3_play(fn);
372 } else {
373 return wav_play(fn);
374 }
375 } else {
376 return wav_rec(fn, channels, rate);
377 }
378 return 0;
379 }
380