diff options
author | Brad Midgley <bmidgley@xmission.com> | 2007-03-24 02:56:52 +0000 |
---|---|---|
committer | Brad Midgley <bmidgley@xmission.com> | 2007-03-24 02:56:52 +0000 |
commit | 1d6beece31584c71a7ce730133923f2e1d0d3b7d (patch) | |
tree | c5471990d4871a59f11096d8f8f9f8fc7178e9cd /sbc/sbcdec.c | |
parent | 4ce3d5461ad7640782cd032a547f3aec5a2265ad (diff) |
add Marcel's original, unmodified sbcdec/enc clients to sbc
Diffstat (limited to 'sbc/sbcdec.c')
-rw-r--r-- | sbc/sbcdec.c | 195 |
1 files changed, 194 insertions, 1 deletions
diff --git a/sbc/sbcdec.c b/sbc/sbcdec.c index 208cdfd8..0617fe04 100644 --- a/sbc/sbcdec.c +++ b/sbc/sbcdec.c @@ -1,6 +1,6 @@ /* * - * Bluetooth low-complexity, subband codec (SBC) library + * Bluetooth low-complexity, subband codec (SBC) decoder * * Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org> * @@ -25,9 +25,202 @@ #include <config.h> #endif +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/soundcard.h> + #include "sbc.h" +#define BUF_SIZE 8192 + +static void decode(char *filename, char *audiodevice, int tofile) +{ + unsigned char buf[BUF_SIZE], *stream; + struct stat st; + off_t filesize; + sbc_t sbc; + int fd, ad, pos, streamlen, framelen, count, format = AFMT_S16_BE; + + if (stat(filename, &st) < 0) { + fprintf(stderr, "Can't get size of file %s: %s\n", + filename, strerror(errno)); + return; + } + + filesize = st.st_size; + stream = malloc(st.st_size); + + if (!stream) { + fprintf(stderr, "Can't allocate memory for %s: %s\n", + filename, strerror(errno)); + return; + } + + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't open file %s: %s\n", + filename, strerror(errno)); + goto free; + } + + if (read(fd, stream, st.st_size) != st.st_size) { + fprintf(stderr, "Can't read content of %s: %s\n", + filename, strerror(errno)); + close(fd); + goto free; + } + + close(fd); + + pos = 0; + streamlen = st.st_size; + + ad = open(audiodevice, O_WRONLY | (tofile ? (O_CREAT | O_TRUNC) : 0), tofile ? 0644 : 0); + if (ad < 0) { + fprintf(stderr, "Can't open audio device %s: %s\n", + audiodevice, strerror(errno)); + goto free; + } + + sbc_init(&sbc, 0L); + + framelen = sbc_decode(&sbc, stream, streamlen); + printf("%d Hz, %d channels\n", sbc.rate, sbc.channels); + if (!tofile) { + if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) { + fprintf(stderr, "Can't set audio format on %s: %s\n", + audiodevice, strerror(errno)); + goto close; + } + if (ioctl(ad, SNDCTL_DSP_CHANNELS, &sbc.channels) < 0) { + fprintf(stderr, "Can't set number of channels on %s: %s\n", + audiodevice, strerror(errno)); + goto close; + } + + if (ioctl(ad, SNDCTL_DSP_SPEED, &sbc.rate) < 0) { + fprintf(stderr, "Can't set audio rate on %s: %s\n", + audiodevice, strerror(errno)); + goto close; + } + } + + count = 0; + while (framelen > 0) { + // we have completed an sbc_decode at this point + // sbc.len is the length of the frame we just decoded + // count is the number of decoded bytes yet to be written + + if (count + sbc.len > BUF_SIZE) { + // buffer is too full to stuff decoded audio in + // so it must be written to the device + write(ad, buf, count); + count = 0; + } + + // sanity check + if(count + sbc.len > BUF_SIZE) { + fprintf(stderr, "buffer size of %d is too small for decoded data (%d)\n", BUF_SIZE, sbc.len + count); + exit(1); + } + + // move the latest decoded data into buf and increase the count + memcpy(buf + count, sbc.data, sbc.len); + count += sbc.len; + + // push the pointer in the file forward to the next bit to be decoded + // tell the decoder to decode up to the remaining length of the file (!) + pos += framelen; + framelen = sbc_decode(&sbc, stream + pos, streamlen - pos); + } + + if (count > 0) + write(ad, buf, count); + +close: + sbc_finish(&sbc); + + close(ad); + +free: + free(stream); +} + +static void usage(void) +{ + printf("SBC decoder utility ver %s\n", VERSION); + printf("Copyright (c) 2004 Marcel Holtmann\n\n"); + + printf("Usage:\n" + "\tsbcdec [options] file(s)\n" + "\n"); + + printf("Options:\n" + "\t-h, --help Display help\n" + "\t-d, --device <dsp> Sound device\n" + "\t-v, --verbose Verbose mode\n" + "\t-f, --file Decode to a file\n" + "\n"); +} + +static struct option main_options[] = { + { "help", 0, 0, 'h' }, + { "device", 1, 0, 'd' }, + { "verbose", 0, 0, 'v' }, + { "file", 1, 0, 'f' }, + { 0, 0, 0, 0 } +}; + int main(int argc, char *argv[]) { + char *device = NULL; + char *file = NULL; + int i, opt, verbose = 0, tofile = 0; + + while ((opt = getopt_long(argc, argv, "+hd:vf:", main_options, NULL)) != -1) { + switch(opt) { + case 'h': + usage(); + exit(0); + + case 'd': + device = strdup(optarg); + break; + + case 'v': + verbose = 1; + break; + case 'f' : + file = strdup(optarg); + tofile = 1; + break; + + default: + exit(1); + } + } + + argc -= optind; + argv += optind; + optind = 0; + + if (argc < 1) { + usage(); + exit(1); + } + + for (i = 0; i < argc; i++) + decode(argv[i], device ? device : file ? file : "/dev/dsp", tofile); + + if (device) + free(device); + return 0; } |