diff options
author | Simon Wilson <simonwilson@google.com> | 2011-07-14 12:02:05 -0700 |
---|---|---|
committer | Simon Wilson <simonwilson@google.com> | 2011-07-14 12:06:23 -0700 |
commit | dd84573ac22e3ec11f8edbf79f82384c01355ec6 (patch) | |
tree | 1f2282b1c8a340c73623f8ada757c8e028a8cf32 | |
parent | d6458e6f62ea7d09a82f78f509df58c452358ae8 (diff) |
Add tinycap utility to capture PCM riff/wave files
This adds a utility to capture audio with a specified number of
parameters. Capturing continues until a signal is received
(ctrl-c).
Contains some contributions from Chris Kelly <c-kelly@ti.com>
-rw-r--r-- | Android.mk | 9 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | tinycap.c | 191 |
3 files changed, 206 insertions, 2 deletions
@@ -20,6 +20,15 @@ include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_C_INCLUDES:= external/tinyalsa/include +LOCAL_SRC_FILES:= tinycap.c +LOCAL_MODULE := tinycap +LOCAL_SHARED_LIBRARIES:= libcutils libutils libtinyalsa +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_C_INCLUDES:= external/tinyalsa/include LOCAL_SRC_FILES:= tinymix.c LOCAL_MODULE := tinymix LOCAL_SHARED_LIBRARIES:= libcutils libutils libtinyalsa @@ -3,11 +3,14 @@ INC = include OBJECTS = mixer.o pcm.o LIB = libtinyalsa.so -all: $(LIB) tinyplay tinymix +all: $(LIB) tinyplay tinycap tinymix tinyplay: $(LIB) tinyplay.o gcc tinyplay.o -L. -ltinyalsa -o tinyplay +tinycap: $(LIB) tinycap.o + gcc tinycap.o -L. -ltinyalsa -o tinycap + tinymix: $(LIB) tinymix.o gcc tinymix.o -L. -ltinyalsa -o tinymix @@ -18,4 +21,5 @@ $(LIB): $(OBJECTS) gcc $(CFLAGS) $< -I$(INC) clean: - rm $(LIB) $(OBJECTS) tinyplay.o tinyplay + rm $(LIB) $(OBJECTS) tinyplay.o tinyplay tinycap.o tinycap \ + tinymix.o tinymix diff --git a/tinycap.c b/tinycap.c new file mode 100644 index 0000000..c5ffd33 --- /dev/null +++ b/tinycap.c @@ -0,0 +1,191 @@ +/* tinycap.c +** +** Copyright 2011, The Android Open Source Project +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of The Android Open Source Project nor the names of +** its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +** DAMAGE. +*/ + +#include <tinyalsa/asoundlib.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <signal.h> + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; + uint16_t block_align; + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +int capturing = 1; + +unsigned int capture_sample(FILE *file, unsigned int device, + unsigned int channels, unsigned int rate, + unsigned int bits); + +void sigint_handler(int sig) +{ + capturing = 0; +} + +int main(int argc, char **argv) +{ + FILE *file; + struct wav_header header; + unsigned int device = 0; + unsigned int channels = 2; + unsigned int rate = 44100; + unsigned int bits = 16; + unsigned int frames; + + if (argc < 2) { + fprintf(stderr, "Usage: %s file.wav [-d device] [-c channels] " + "[-r rate] [-b bits]\n", argv[0]); + return 1; + } + + file = fopen(argv[1], "wb"); + if (!file) { + fprintf(stderr, "Unable to create file '%s'\n", argv[1]); + return 1; + } + + /* parse command line arguments */ + argv += 2; + while (*argv) { + if (strcmp(*argv, "-d", 2) == 0) { + argv++; + device = atoi(*argv); + } else if (strcmp(*argv, "-c", 2) == 0) { + argv++; + channels = atoi(*argv); + } else if (strcmp(*argv, "-r", 2) == 0) { + argv++; + rate = atoi(*argv); + } else if (strcmp(*argv, "-b", 2) == 0) { + argv++; + bits = atoi(*argv); + } + argv++; + } + + header.riff_id = ID_RIFF; + header.riff_sz = 0; + header.riff_fmt = ID_WAVE; + header.fmt_id = ID_FMT; + header.fmt_sz = 16; + header.audio_format = FORMAT_PCM; + header.num_channels = channels; + header.sample_rate = rate; + header.byte_rate = (header.bits_per_sample / 8) * channels * rate; + header.block_align = channels * (header.bits_per_sample / 8); + header.bits_per_sample = bits; + header.data_id = ID_DATA; + + /* leave enough room for header */ + fseek(file, sizeof(struct wav_header), SEEK_SET); + + /* install signal handler and begin capturing */ + signal(SIGINT, sigint_handler); + frames = capture_sample(file, device, header.num_channels, + header.sample_rate, header.bits_per_sample); + printf("Captured %d frames\n", frames); + + /* write header now all information is known */ + header.data_sz = frames * header.block_align; + fseek(file, 0, SEEK_SET); + fwrite(&header, sizeof(struct wav_header), 1, file); + + fclose(file); + + return 0; +} + +unsigned int capture_sample(FILE *file, unsigned int device, + unsigned int channels, unsigned int rate, + unsigned int bits) +{ + struct pcm_config config; + struct pcm *pcm; + char *buffer; + unsigned int size; + unsigned int bytes_read = 0; + + config.channels = channels; + config.rate = rate; + config.period_size = 1024; + config.period_count = 4; + if (bits == 32) + config.format = PCM_FORMAT_S32_LE; + else if (bits == 16) + config.format = PCM_FORMAT_S16_LE; + + pcm = pcm_open(0, device, PCM_IN, &config); + if (!pcm || !pcm_is_ready(pcm)) { + fprintf(stderr, "Unable to open PCM device (%s)\n", + pcm_get_error(pcm)); + return 0; + } + + size = pcm_get_buffer_size(pcm); + buffer = malloc(size); + if (!buffer) { + fprintf(stderr, "Unable to allocate %d bytes\n", size); + free(buffer); + pcm_close(pcm); + return 0; + } + + printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); + + while (capturing && !pcm_read(pcm, buffer, size)) { + if (fwrite(buffer, 1, size, file) != size) { + fprintf(stderr,"Error capturing sample\n"); + break; + } + bytes_read += size; + } + + free(buffer); + pcm_close(pcm); + return bytes_read / ((bits / 8) * channels); +} + |