Home | History | Annotate | Download | only in sound
      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