tinycap.c revision dd88f13d9b398c132e3358c62137ff2e23f321ab
17153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson/* tinycap.c
27153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**
37153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** Copyright 2011, The Android Open Source Project
47153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**
57153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** Redistribution and use in source and binary forms, with or without
67153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** modification, are permitted provided that the following conditions are met:
77153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**     * Redistributions of source code must retain the above copyright
87153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**       notice, this list of conditions and the following disclaimer.
97153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**     * Redistributions in binary form must reproduce the above copyright
107153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**       notice, this list of conditions and the following disclaimer in the
117153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**       documentation and/or other materials provided with the distribution.
127153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**     * Neither the name of The Android Open Source Project nor the names of
137153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**       its contributors may be used to endorse or promote products derived
147153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**       from this software without specific prior written permission.
157153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson**
167153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
177153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
207153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
227153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
237153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
267153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson** DAMAGE.
277153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson*/
287153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
297153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <tinyalsa/asoundlib.h>
307153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <stdio.h>
317153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <stdlib.h>
327153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <stdint.h>
337153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#include <signal.h>
347153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
357153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define ID_RIFF 0x46464952
367153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define ID_WAVE 0x45564157
377153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define ID_FMT  0x20746d66
387153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define ID_DATA 0x61746164
397153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
407153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson#define FORMAT_PCM 1
417153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
427153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonstruct wav_header {
437153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t riff_id;
447153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t riff_sz;
457153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t riff_fmt;
467153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t fmt_id;
477153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t fmt_sz;
487153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint16_t audio_format;
497153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint16_t num_channels;
507153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t sample_rate;
517153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t byte_rate;
527153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint16_t block_align;
537153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint16_t bits_per_sample;
547153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t data_id;
557153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    uint32_t data_sz;
567153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson};
577153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
587153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonint capturing = 1;
597153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
607153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonunsigned int capture_sample(FILE *file, unsigned int device,
617153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson                            unsigned int channels, unsigned int rate,
627153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson                            unsigned int bits);
637153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
647153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonvoid sigint_handler(int sig)
657153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson{
667153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    capturing = 0;
677153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson}
687153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
697153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonint main(int argc, char **argv)
707153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson{
717153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    FILE *file;
727153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    struct wav_header header;
737153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    unsigned int device = 0;
747153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    unsigned int channels = 2;
757153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    unsigned int rate = 44100;
767153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    unsigned int bits = 16;
777153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    unsigned int frames;
787153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
797153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    if (argc < 2) {
807153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        fprintf(stderr, "Usage: %s file.wav [-d device] [-c channels] "
817153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson                "[-r rate] [-b bits]\n", argv[0]);
827153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        return 1;
837153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    }
847153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
857153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    file = fopen(argv[1], "wb");
867153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    if (!file) {
877153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        fprintf(stderr, "Unable to create file '%s'\n", argv[1]);
887153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        return 1;
897153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    }
907153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
917153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    /* parse command line arguments */
927153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    argv += 2;
937153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    while (*argv) {
94dd88f13d9b398c132e3358c62137ff2e23f321abSimon Wilson        if (strcmp(*argv, "-d") == 0) {
957153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            argv++;
967153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            device = atoi(*argv);
97dd88f13d9b398c132e3358c62137ff2e23f321abSimon Wilson        } else if (strcmp(*argv, "-c") == 0) {
987153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            argv++;
997153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            channels = atoi(*argv);
100dd88f13d9b398c132e3358c62137ff2e23f321abSimon Wilson        } else if (strcmp(*argv, "-r") == 0) {
1017153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            argv++;
1027153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            rate = atoi(*argv);
103dd88f13d9b398c132e3358c62137ff2e23f321abSimon Wilson        } else if (strcmp(*argv, "-b") == 0) {
1047153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            argv++;
1057153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            bits = atoi(*argv);
1067153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        }
1077153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        argv++;
1087153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    }
1097153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1107153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.riff_id = ID_RIFF;
1117153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.riff_sz = 0;
1127153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.riff_fmt = ID_WAVE;
1137153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.fmt_id = ID_FMT;
1147153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.fmt_sz = 16;
1157153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.audio_format = FORMAT_PCM;
1167153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.num_channels = channels;
1177153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.sample_rate = rate;
1187153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.byte_rate = (header.bits_per_sample / 8) * channels * rate;
1197153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.block_align = channels * (header.bits_per_sample / 8);
1207153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.bits_per_sample = bits;
1217153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.data_id = ID_DATA;
1227153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1237153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    /* leave enough room for header */
1247153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    fseek(file, sizeof(struct wav_header), SEEK_SET);
1257153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1267153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    /* install signal handler and begin capturing */
1277153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    signal(SIGINT, sigint_handler);
1287153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    frames = capture_sample(file, device, header.num_channels,
1297153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson                            header.sample_rate, header.bits_per_sample);
1307153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    printf("Captured %d frames\n", frames);
1317153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1327153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    /* write header now all information is known */
1337153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    header.data_sz = frames * header.block_align;
1347153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    fseek(file, 0, SEEK_SET);
1357153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    fwrite(&header, sizeof(struct wav_header), 1, file);
1367153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1377153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    fclose(file);
1387153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1397153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    return 0;
1407153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson}
1417153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1427153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilsonunsigned int capture_sample(FILE *file, unsigned int device,
1437153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson                            unsigned int channels, unsigned int rate,
1447153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson                            unsigned int bits)
1457153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson{
1467153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    struct pcm_config config;
1477153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    struct pcm *pcm;
1487153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    char *buffer;
1497153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    unsigned int size;
1507153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    unsigned int bytes_read = 0;
1517153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1527153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    config.channels = channels;
1537153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    config.rate = rate;
1547153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    config.period_size = 1024;
1557153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    config.period_count = 4;
1567153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    if (bits == 32)
1577153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        config.format = PCM_FORMAT_S32_LE;
1587153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    else if (bits == 16)
1597153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        config.format = PCM_FORMAT_S16_LE;
1607153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1617153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    pcm = pcm_open(0, device, PCM_IN, &config);
1627153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    if (!pcm || !pcm_is_ready(pcm)) {
1637153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        fprintf(stderr, "Unable to open PCM device (%s)\n",
1647153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson                pcm_get_error(pcm));
1657153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        return 0;
1667153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    }
1677153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1687153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    size = pcm_get_buffer_size(pcm);
1697153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    buffer = malloc(size);
1707153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    if (!buffer) {
1717153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        fprintf(stderr, "Unable to allocate %d bytes\n", size);
1727153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        free(buffer);
1737153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        pcm_close(pcm);
1747153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        return 0;
1757153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    }
1767153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1777153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);
1787153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1797153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    while (capturing && !pcm_read(pcm, buffer, size)) {
1807153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        if (fwrite(buffer, 1, size, file) != size) {
1817153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            fprintf(stderr,"Error capturing sample\n");
1827153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson            break;
1837153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        }
1847153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson        bytes_read += size;
1857153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    }
1867153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
1877153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    free(buffer);
1887153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    pcm_close(pcm);
1897153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson    return bytes_read / ((bits / 8) * channels);
1907153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson}
1917153bffb805359a82f7857889e82bdcc5ff0afd8Simon Wilson
192