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
pcm_play(unsigned rate,unsigned channels,int (* fill)(void * buf,unsigned sz,void * cookie),void * cookie)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
fill_buffer(void * buf,unsigned sz,void * cookie)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
play_file(unsigned rate,unsigned channels,int fd,unsigned count)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
wav_play(const char * fn)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
wav_rec(const char * fn,unsigned channels,unsigned rate)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
mp3_play(const char * fn)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
main(int argc,char ** argv)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 }
378