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 } 378