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