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