OSDN Git Service

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