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 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 #if 0 44 struct msm_audio_stats stats; 45 #endif 46 unsigned sz, n; 47 char buf[8192]; 48 int afd; 49 50 afd = open("/dev/msm_pcm_out", O_RDWR); 51 if (afd < 0) { 52 perror("pcm_play: cannot open audio device"); 53 return -1; 54 } 55 56 if(ioctl(afd, AUDIO_GET_CONFIG, &config)) { 57 perror("could not get config"); 58 return -1; 59 } 60 61 config.channel_count = channels; 62 config.sample_rate = rate; 63 if (ioctl(afd, AUDIO_SET_CONFIG, &config)) { 64 perror("could not set config"); 65 return -1; 66 } 67 sz = config.buffer_size; 68 if (sz > sizeof(buf)) { 69 fprintf(stderr,"too big\n"); 70 return -1; 71 } 72 73 fprintf(stderr,"prefill\n"); 74 for (n = 0; n < config.buffer_count; n++) { 75 if (fill(buf, sz, cookie)) 76 break; 77 if (write(afd, buf, sz) != (ssize_t) sz) 78 break; 79 } 80 81 fprintf(stderr,"start\n"); 82 ioctl(afd, AUDIO_START, 0); 83 84 for (;;) { 85 #if 0 86 if (ioctl(afd, AUDIO_GET_STATS, &stats) == 0) 87 fprintf(stderr,"%10d\n", stats.out_bytes); 88 #endif 89 if (fill(buf, sz, cookie)) 90 break; 91 if (write(afd, buf, sz) != (ssize_t) sz) 92 break; 93 } 94 95 close(afd); 96 return 0; 97 } 98 99 /* http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */ 100 101 #define ID_RIFF 0x46464952 102 #define ID_WAVE 0x45564157 103 #define ID_FMT 0x20746d66 104 #define ID_DATA 0x61746164 105 106 #define FORMAT_PCM 1 107 108 struct wav_header { 109 uint32_t riff_id; 110 uint32_t riff_sz; 111 uint32_t riff_fmt; 112 uint32_t fmt_id; 113 uint32_t fmt_sz; 114 uint16_t audio_format; 115 uint16_t num_channels; 116 uint32_t sample_rate; 117 uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */ 118 uint16_t block_align; /* num_channels * bps / 8 */ 119 uint16_t bits_per_sample; 120 uint32_t data_id; 121 uint32_t data_sz; 122 }; 123 124 125 static char *next; 126 static unsigned avail; 127 128 int fill_buffer(void *buf, unsigned sz, void *cookie) 129 { 130 if (sz > avail) 131 return -1; 132 memcpy(buf, next, sz); 133 next += sz; 134 avail -= sz; 135 return 0; 136 } 137 138 void play_file(unsigned rate, unsigned channels, 139 int fd, unsigned count) 140 { 141 next = malloc(count); 142 if (!next) { 143 fprintf(stderr,"could not allocate %d bytes\n", count); 144 return; 145 } 146 if (read(fd, next, count) != (ssize_t) count) { 147 fprintf(stderr,"could not read %d bytes\n", count); 148 return; 149 } 150 avail = count; 151 pcm_play(rate, channels, fill_buffer, 0); 152 } 153 154 int wav_play(const char *fn) 155 { 156 struct wav_header hdr; 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 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; 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) != (ssize_t) sz) { 269 perror("cannot read buffer"); 270 goto fail; 271 } 272 if (write(fd, buf, sz) != (ssize_t) 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 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 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