Home | History | Annotate | Download | only in taudio
      1 #include <unistd.h>
      2 #include <stdlib.h>
      3 #include <stdio.h>
      4 #include <fcntl.h>
      5 #include <errno.h>
      6 #include <stdint.h>
      7 #include <assert.h>
      8 #include <sys/types.h>
      9 #include <sys/stat.h>
     10 #include <sys/ioctl.h>
     11 #include <linux/cpcap_audio.h>
     12 #include <linux/tegra_audio.h>
     13 
     14 #define FAILIF(x, ...) do if (x) { \
     15     fprintf(stderr, __VA_ARGS__);  \
     16     exit(EXIT_FAILURE);            \
     17 } while (0)
     18 
     19 static char buffer[4096];
     20 
     21 struct wav_header {
     22     char  riff[4];
     23     uint32_t chunk_size;
     24     char  format[4];
     25 
     26     char  subchunk1_id[4];
     27     uint32_t subchunk1_size;
     28     uint16_t audio_format;
     29     uint16_t num_channels;
     30     uint32_t sample_rate;
     31     uint32_t byte_rate;
     32     uint16_t block_align;
     33     uint16_t bits_per_sample;
     34 
     35     char  subchunk2_id[4];
     36     uint32_t subchunk2_size;
     37 } __attribute__((packed));
     38 
     39 static void init_wav_header(struct wav_header *hdr,
     40                        uint32_t num_samples,
     41                        uint16_t bits_per_sample,
     42                        int   channels,
     43                        uint32_t sample_rate)
     44 {
     45     hdr->riff[0] = 'R';
     46     hdr->riff[1] = 'I';
     47     hdr->riff[2] = 'F';
     48     hdr->riff[3] = 'F';
     49 
     50     hdr->subchunk2_size = num_samples * channels * bits_per_sample / 8;
     51 
     52     hdr->chunk_size = 36 + hdr->subchunk2_size;
     53     hdr->format[0] = 'W';
     54     hdr->format[1] = 'A';
     55     hdr->format[2] = 'V';
     56     hdr->format[3] = 'E';
     57 
     58     hdr->subchunk1_id[0] = 'f';
     59     hdr->subchunk1_id[1] = 'm';
     60     hdr->subchunk1_id[2] = 't';
     61     hdr->subchunk1_id[3] = ' ';
     62 
     63     hdr->subchunk1_size = 16;
     64     hdr->audio_format = 1; /* PCM */
     65     hdr->num_channels = channels;
     66     hdr->sample_rate = sample_rate;
     67     hdr->byte_rate = sample_rate * channels * bits_per_sample / 8;
     68     hdr->block_align = channels * bits_per_sample / 8;
     69     hdr->bits_per_sample = bits_per_sample;
     70 
     71     hdr->subchunk2_id[0] = 'd';
     72     hdr->subchunk2_id[1] = 'a';
     73     hdr->subchunk2_id[2] = 't';
     74     hdr->subchunk2_id[3] = 'a';
     75 }
     76 
     77 int
     78 main(int argc, char *argv[])
     79 {
     80     int ifd, ifd_c, ofd, opt, cfd;
     81     const char *name;
     82     int nr, nw = 0, total = 0;
     83     int wave = 0;
     84     const int bits_per_sample = 16;
     85     int sampling_rate = -1;
     86     int num_channels = -1;
     87 
     88     struct tegra_audio_in_config cfg;
     89     struct wav_header hdr;
     90 
     91     while ((opt = getopt(argc, argv, "wc:s:")) != -1) {
     92         switch (opt) {
     93         case 'w':
     94             wave = 1;
     95             break;
     96         case 'c':
     97             num_channels = atoi(optarg);
     98             assert(num_channels == 1 || num_channels == 2);
     99             break;
    100         case 's':
    101             sampling_rate = atoi(optarg);
    102             break;
    103         default: /* '?' */
    104             fprintf(stderr,
    105                     "usage: %s [-w] [-s<rate>] [-c<chans>] <destfile>\n",
    106                     *argv);
    107             exit(EXIT_FAILURE);
    108         }
    109     }
    110 
    111     FAILIF(optind >= argc,
    112                     "usage: %s [-w] [-s<rate>] [-c<chans>] <destfile>\n",
    113                     *argv);
    114 
    115     name = argv[optind];
    116 
    117     printf("> recording into %s\n", name);
    118     printf("> sampling rate %d\n", sampling_rate);
    119     printf("> channels %d\n", num_channels);
    120 
    121     cfd = open("/dev/audio_ctl", O_RDWR);
    122     FAILIF(cfd < 0, "could not open control: %s\n", strerror(errno));
    123     if(sampling_rate > 0) {
    124         FAILIF(ioctl(cfd, CPCAP_AUDIO_IN_SET_RATE, sampling_rate),
    125             "Could not set input sampling rate: %s\n", strerror(errno));
    126     }
    127 
    128     ifd = open("/dev/audio1_in", O_RDWR);
    129     FAILIF(ifd < 0, "could not open input: %s\n", strerror(errno));
    130 
    131     ifd_c = open("/dev/audio1_in_ctl", O_RDWR);
    132     FAILIF(ifd < 0, "could not open input: %s\n", strerror(errno));
    133 
    134     printf("getting audio-input config\n");
    135     FAILIF(ioctl(ifd_c, TEGRA_AUDIO_IN_GET_CONFIG, &cfg) < 0,
    136            "could not get input config: %s\n", strerror(errno));
    137 
    138     if (num_channels >= 0 || sampling_rate >= 0) {
    139         if (num_channels >= 0)
    140             cfg.stereo = num_channels == 2;
    141 //        if (sampling_rate >= 0)
    142 //            cfg.rate = sampling_rate;
    143 //  No sample rate conversion in driver
    144         cfg.rate = 44100;
    145         printf("setting audio-input config (stereo %d, rate %d)\n",
    146                cfg.stereo, cfg.rate);
    147         FAILIF(ioctl(ifd_c, TEGRA_AUDIO_IN_SET_CONFIG, &cfg) < 0,
    148                "could not set input config: %s\n", strerror(errno));
    149     }
    150 
    151     if (num_channels < 0) {
    152         num_channels = cfg.stereo ? 2 : 1;
    153         printf("> channels %d (from config)\n", num_channels);
    154     }
    155 
    156     if (sampling_rate < 0) {
    157         sampling_rate = cfg.rate;
    158         printf("> sampling rate %d (from config)\n", sampling_rate);
    159     }
    160 
    161     ofd = open(name, O_WRONLY | O_TRUNC | O_CREAT, 0666);
    162     FAILIF(ofd < 0, "could not open %s: %s\n", name, strerror(errno));
    163 
    164     if (wave)
    165         FAILIF(lseek(ofd, sizeof(struct wav_header), SEEK_SET) < 0,
    166                "seek error: %s\n", strerror(errno));
    167 
    168     do {
    169         errno = 0;
    170         nr = read(ifd, buffer, sizeof(buffer));
    171         FAILIF(nr < 0, "input read error: %s\n", strerror(errno));
    172 
    173         if (!nr) {
    174             printf("done recording\n");
    175             break;
    176         }
    177 
    178         printf("in %d\n", nr);
    179 
    180         nw = write(ofd, buffer, nr);
    181         FAILIF(nw < 0, "Could not copy to output: %s\n", strerror(errno));
    182         FAILIF(nw != nr, "Mismatch nw = %d nr = %d\n", nw, nr);
    183         total += nw;
    184     } while (1);
    185 
    186     if (wave) {
    187         printf("writing WAV header\n");
    188         lseek(ofd, 0, SEEK_SET);
    189         init_wav_header(&hdr,
    190                         total * 8 / (num_channels * bits_per_sample),
    191                         bits_per_sample,
    192                         num_channels,
    193                         sampling_rate);
    194         FAILIF(write(ofd, &hdr, sizeof(hdr)) != sizeof(hdr),
    195                "Could not write WAV header: %s\n", strerror(errno));
    196     }
    197 
    198     printf("done\n");
    199     return 0;
    200 }
    201