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 #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