]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge commit 'meins/next'
authorAndre Noll <maan@systemlinux.org>
Mon, 1 Dec 2008 14:02:26 +0000 (15:02 +0100)
committerAndre Noll <maan@systemlinux.org>
Mon, 1 Dec 2008 14:02:26 +0000 (15:02 +0100)
22 files changed:
Makefile.in
aacdec.c [deleted file]
aacdec_filter.c [new file with mode: 0644]
aft.c
amp_filter.c
compress.c [deleted file]
compress_filter.c [new file with mode: 0644]
configure.ac
error.h
filter.c
filter.h
filter_chain.c [deleted file]
filter_common.c [new file with mode: 0644]
hash.h
mp3dec.c [deleted file]
mp3dec_filter.c [new file with mode: 0644]
oggdec.c [deleted file]
oggdec_filter.c [new file with mode: 0644]
osl_core.h
server.c
wav.c [deleted file]
wav_filter.c [new file with mode: 0644]

index 2f903d0c4038f09a225598dff59e9c42976a7a2d..9e60b0df1f399b94bc1c90c7915366bb083fa970 100644 (file)
@@ -161,15 +161,15 @@ ortp_recv.o: ortp_recv.c
 ortp_send.o: ortp_send.c
        $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @ortp_cppflags@ $<
 
-oggdec.o: oggdec.c
+oggdec_filter.o: oggdec_filter.c
        $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @oggvorbis_cppflags@ $<
 ogg_afh.o: ogg_afh.c
        $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @oggvorbis_cppflags@ $<
 
-mp3dec.o: mp3dec.c
+mp3dec_filter.o: mp3dec_filter.c
        $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @mad_cppflags@ $<
 
-aacdec.o: aacdec.c
+aacdec_filter.o: aacdec_filter.c
        $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @faad_cppflags@ $<
 
 aac_common.o: aac_common.c
diff --git a/aacdec.c b/aacdec.c
deleted file mode 100644 (file)
index 4c25694..0000000
--- a/aacdec.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2006-2008 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
-/*
- * based in parts on libfaad, Copyright (C) 2003-2005 M. Bakker,
- * Ahead Software AG
- */
-
-/** \file aacdec.c paraslash's aac (m4a) decoder */
-
-#include "para.h"
-
-#include "list.h"
-#include "sched.h"
-#include "filter.h"
-#include "error.h"
-#include "string.h"
-#include "aac.h"
-
-/** the output buffer size */
-#define AAC_OUTBUF_SIZE (32 * 1024)
-
-/** give up decoding after that many errors */
-#define MAX_ERRORS 20
-
-/**
- * data specific to the aacdec filter
- *
- * \sa filter, filter_node
- */
-struct private_aacdec_data {
-       /** the return value of aac_open */
-       NeAACDecHandle handle;
-       /** info about the currently decoded frame */
-       NeAACDecFrameInfo frame_info;
-       /** whether this instance of the aac decoder is already initialized */
-       int initialized;
-       /**
-        * return value of aac_find_esds(). Used to call the right aacdec
-        * init function
-        */
-       unsigned long decoder_length;
-       /** number of times the decoder returned an error */
-       unsigned error_count;
-       /** number of bytes already consumed from the imput stream */
-       size_t consumed_total;
-       /** return value of aac_find_entry_point */
-       size_t entry;
-};
-
-static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn)
-{
-       struct private_aacdec_data *padd = fn->private_data;
-       struct filter_chain *fc = fn->fc;
-       int i, ret;
-       unsigned char *p, *outbuffer;
-       unsigned char *inbuf = (unsigned char*)input_buffer;
-       size_t skip, consumed = 0;
-
-       if (fn->loaded > fn->bufsize * 3 / 5)
-               return 0;
-       if (len < 2048 && !*fc->input_error)
-               return 0;
-
-       if (!padd->initialized) {
-               unsigned long rate = 0;
-               unsigned char channels = 0;
-               ret = aac_find_esds(inbuf, len, &skip, &padd->decoder_length);
-               if (ret < 0) {
-                       PARA_INFO_LOG("%s\n", para_strerror(-ret));
-                       ret = NeAACDecInit(padd->handle, inbuf,
-                               len, &rate, &channels);
-                       PARA_INFO_LOG("decoder init: %d\n", ret);
-                       if (ret < 0) {
-                               ret = -E_AACDEC_INIT;
-                               goto out;
-                       }
-                       consumed = ret;
-               } else {
-                       PARA_INFO_LOG("decoder len: %lu\n",
-                               padd->decoder_length);
-                       consumed += skip;
-                       p = inbuf + consumed;
-                       ret = -E_AACDEC_INIT;
-                       if (NeAACDecInit2(padd->handle, p,
-                                       padd->decoder_length, &rate,
-                                       &channels) < 0)
-                               goto out;
-               }
-               fc->samplerate = rate;
-               fc->channels = channels;
-               PARA_INFO_LOG("rate: %u, channels: %d\n",
-                       fc->samplerate, fc->channels);
-               padd->initialized = 1;
-       }
-       if (padd->decoder_length > 0) {
-               consumed = 0;
-               if (!padd->entry) {
-                       ret = aac_find_entry_point(inbuf + consumed,
-                               len - consumed, &skip);
-                       if (ret < 0) {
-                               ret = len;
-                               goto out;
-                       }
-                       consumed += skip;
-                       padd->entry = ret;
-                       PARA_INFO_LOG("entry: %zu\n", padd->entry);
-               }
-               ret = len;
-               if (padd->consumed_total + len < padd->entry)
-                       goto out;
-               if (padd->consumed_total < padd->entry)
-                       consumed = padd->entry - padd->consumed_total;
-       }
-       for (; consumed < len; consumed++)
-               if ((inbuf[consumed] & 0xfe) == 0x20)
-                       break;
-       if (consumed >= len)
-               goto success;
-       p = inbuf + consumed;
-       outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p,
-               len - consumed);
-       if (padd->frame_info.error) {
-               ret = -E_AAC_DECODE;
-               if (padd->error_count++ > MAX_ERRORS)
-                       goto out;
-               PARA_ERROR_LOG("frame_error: %d, consumed: %zu + %zd + %lu\n",
-                       padd->frame_info.error, padd->consumed_total,
-                       consumed, padd->frame_info.bytesconsumed);
-               PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage(
-                       padd->frame_info.error));
-               consumed++; /* catch 21 */
-               goto success;
-       }
-       padd->error_count = 0;
-       consumed += padd->frame_info.bytesconsumed;
-       ret = consumed;
-       if (!padd->frame_info.samples)
-               goto out;
-       ret = -E_AAC_OVERRUN;
-       if (padd->frame_info.samples * 2 + fn->loaded > fn->bufsize)
-               goto out;
-       for (i = 0; i < padd->frame_info.samples; i++) {
-               short *s = (short *)outbuffer;
-               write_int16_host_endian(fn->buf + fn->loaded, s[i]);
-               fn->loaded += 2;
-       }
-success:
-       ret = consumed;
-out:
-       if (ret > 0)
-               padd->consumed_total += ret;
-       return ret;
-}
-
-static void aacdec_open(struct filter_node *fn)
-{
-       struct private_aacdec_data *padd = para_calloc(sizeof(*padd));
-
-       fn->private_data = padd;
-       fn->bufsize = AAC_OUTBUF_SIZE;
-       fn->buf = para_calloc(fn->bufsize);
-       padd->handle = aac_open();
-}
-
-static void aacdec_close(struct filter_node *fn)
-{
-       struct private_aacdec_data *padd = fn->private_data;
-
-       NeAACDecClose(padd->handle);
-       free(fn->buf);
-       fn->buf = NULL;
-       free(padd);
-       fn->private_data = NULL;
-}
-
-/**
- * the init function of the aacdec filter
- *
- * \param f pointer to the filter struct to initialize
- *
- * \sa filter::init
- */
-void aacdec_init(struct filter *f)
-{
-       f->open = aacdec_open;
-       f->convert = aacdec;
-       f->close = aacdec_close;
-}
diff --git a/aacdec_filter.c b/aacdec_filter.c
new file mode 100644 (file)
index 0000000..956f338
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2006-2008 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+/*
+ * based in parts on libfaad, Copyright (C) 2003-2005 M. Bakker,
+ * Ahead Software AG
+ */
+
+/** \file aacdec_filter.c paraslash's aac (m4a) decoder. */
+
+#include "para.h"
+
+#include "list.h"
+#include "sched.h"
+#include "filter.h"
+#include "error.h"
+#include "string.h"
+#include "aac.h"
+
+/** the output buffer size */
+#define AAC_OUTBUF_SIZE (32 * 1024)
+
+/** give up decoding after that many errors */
+#define MAX_ERRORS 20
+
+/**
+ * data specific to the aacdec filter
+ *
+ * \sa filter, filter_node
+ */
+struct private_aacdec_data {
+       /** the return value of aac_open */
+       NeAACDecHandle handle;
+       /** info about the currently decoded frame */
+       NeAACDecFrameInfo frame_info;
+       /** whether this instance of the aac decoder is already initialized */
+       int initialized;
+       /**
+        * return value of aac_find_esds(). Used to call the right aacdec
+        * init function
+        */
+       unsigned long decoder_length;
+       /** number of times the decoder returned an error */
+       unsigned error_count;
+       /** number of bytes already consumed from the imput stream */
+       size_t consumed_total;
+       /** return value of aac_find_entry_point */
+       size_t entry;
+};
+
+static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn)
+{
+       struct private_aacdec_data *padd = fn->private_data;
+       struct filter_chain *fc = fn->fc;
+       int i, ret;
+       unsigned char *p, *outbuffer;
+       unsigned char *inbuf = (unsigned char*)input_buffer;
+       size_t skip, consumed = 0;
+
+       if (fn->loaded > fn->bufsize * 3 / 5)
+               return 0;
+       if (len < 2048 && !*fc->input_error)
+               return 0;
+
+       if (!padd->initialized) {
+               unsigned long rate = 0;
+               unsigned char channels = 0;
+               ret = aac_find_esds(inbuf, len, &skip, &padd->decoder_length);
+               if (ret < 0) {
+                       PARA_INFO_LOG("%s\n", para_strerror(-ret));
+                       ret = NeAACDecInit(padd->handle, inbuf,
+                               len, &rate, &channels);
+                       PARA_INFO_LOG("decoder init: %d\n", ret);
+                       if (ret < 0) {
+                               ret = -E_AACDEC_INIT;
+                               goto out;
+                       }
+                       consumed = ret;
+               } else {
+                       PARA_INFO_LOG("decoder len: %lu\n",
+                               padd->decoder_length);
+                       consumed += skip;
+                       p = inbuf + consumed;
+                       ret = -E_AACDEC_INIT;
+                       if (NeAACDecInit2(padd->handle, p,
+                                       padd->decoder_length, &rate,
+                                       &channels) < 0)
+                               goto out;
+               }
+               fc->samplerate = rate;
+               fc->channels = channels;
+               PARA_INFO_LOG("rate: %u, channels: %d\n",
+                       fc->samplerate, fc->channels);
+               padd->initialized = 1;
+       }
+       if (padd->decoder_length > 0) {
+               consumed = 0;
+               if (!padd->entry) {
+                       ret = aac_find_entry_point(inbuf + consumed,
+                               len - consumed, &skip);
+                       if (ret < 0) {
+                               ret = len;
+                               goto out;
+                       }
+                       consumed += skip;
+                       padd->entry = ret;
+                       PARA_INFO_LOG("entry: %zu\n", padd->entry);
+               }
+               ret = len;
+               if (padd->consumed_total + len < padd->entry)
+                       goto out;
+               if (padd->consumed_total < padd->entry)
+                       consumed = padd->entry - padd->consumed_total;
+       }
+       for (; consumed < len; consumed++)
+               if ((inbuf[consumed] & 0xfe) == 0x20)
+                       break;
+       if (consumed >= len)
+               goto success;
+       p = inbuf + consumed;
+       outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p,
+               len - consumed);
+       if (padd->frame_info.error) {
+               ret = -E_AAC_DECODE;
+               if (padd->error_count++ > MAX_ERRORS)
+                       goto out;
+               PARA_ERROR_LOG("frame_error: %d, consumed: %zu + %zd + %lu\n",
+                       padd->frame_info.error, padd->consumed_total,
+                       consumed, padd->frame_info.bytesconsumed);
+               PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage(
+                       padd->frame_info.error));
+               consumed++; /* catch 21 */
+               goto success;
+       }
+       padd->error_count = 0;
+       consumed += padd->frame_info.bytesconsumed;
+       ret = consumed;
+       if (!padd->frame_info.samples)
+               goto out;
+       ret = -E_AAC_OVERRUN;
+       if (padd->frame_info.samples * 2 + fn->loaded > fn->bufsize)
+               goto out;
+       for (i = 0; i < padd->frame_info.samples; i++) {
+               short *s = (short *)outbuffer;
+               write_int16_host_endian(fn->buf + fn->loaded, s[i]);
+               fn->loaded += 2;
+       }
+success:
+       ret = consumed;
+out:
+       if (ret > 0)
+               padd->consumed_total += ret;
+       return ret;
+}
+
+static void aacdec_open(struct filter_node *fn)
+{
+       struct private_aacdec_data *padd = para_calloc(sizeof(*padd));
+
+       fn->private_data = padd;
+       fn->bufsize = AAC_OUTBUF_SIZE;
+       fn->buf = para_calloc(fn->bufsize);
+       padd->handle = aac_open();
+}
+
+static void aacdec_close(struct filter_node *fn)
+{
+       struct private_aacdec_data *padd = fn->private_data;
+
+       NeAACDecClose(padd->handle);
+       free(fn->buf);
+       fn->buf = NULL;
+       free(padd);
+       fn->private_data = NULL;
+}
+
+/**
+ * the init function of the aacdec filter
+ *
+ * \param f pointer to the filter struct to initialize
+ *
+ * \sa filter::init
+ */
+void aacdec_filter_init(struct filter *f)
+{
+       f->open = aacdec_open;
+       f->convert = aacdec;
+       f->close = aacdec_close;
+}
diff --git a/aft.c b/aft.c
index 90989284df90cac401a056b7af1d6d7c05c2a27f..5cca5b8d88f0e6de4e7f5770df63fc0785815049 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -20,6 +20,7 @@
 #include "vss.h"
 #include "fd.h"
 #include "ipc.h"
+#include "portable_io.h"
 
 static struct osl_table *audio_file_table;
 
index 750205ba69ea5ae747aa37290d57503005b0d49f..2f05260157de9e7103d1a717812981773489fd59 100644 (file)
@@ -50,20 +50,23 @@ static void amp_close(struct filter_node *fn)
        free(fn->buf);
 }
 
-static void *amp_parse_config(int argc, char **argv)
+static int amp_parse_config(int argc, char **argv, void **config)
 {
-       struct amp_filter_args_info *conf = para_calloc(sizeof(*conf));
+       struct amp_filter_args_info *amp_conf = para_calloc(sizeof(*amp_conf));
+       int ret = -E_AMP_SYNTAX;
 
-       if (amp_cmdline_parser(argc, argv, conf))
+       if (amp_cmdline_parser(argc, argv, amp_conf))
                goto err;
-       if (conf->amp_arg < 0)
+       ret = -ERRNO_TO_PARA_ERROR(EINVAL);
+       if (amp_conf->amp_arg < 0)
                goto err;
-       PARA_NOTICE_LOG("amplification: %u (scaling factor: %1.2f)\n", conf->amp_arg,
-               conf->amp_arg / 64.0 + 1.0);
-       return conf;
+       PARA_NOTICE_LOG("amplification: %u (scaling factor: %1.2f)\n",
+               amp_conf->amp_arg, amp_conf->amp_arg / 64.0 + 1.0);
+       *config = amp_conf;
+       return 1;
 err:
-       free(conf);
-       return NULL;
+       free(amp_conf);
+       return ret;
 }
 
 static void amp_open(struct filter_node *fn)
@@ -87,7 +90,7 @@ static void amp_open(struct filter_node *fn)
  *
  * \param f Pointer to the struct to initialize.
  */
-void amp_init(struct filter *f)
+void amp_filter_init(struct filter *f)
 {
        f->open = amp_open;
        f->close = amp_close;
diff --git a/compress.c b/compress.c
deleted file mode 100644 (file)
index c30c998..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
-
-/** \file compress.c Paraslash's dynamic audio range compressor. */
-
-/*
- * Uses ideas of AudioCompress, (C) 2002-2004  M. Hari Nezumi <magenta@trikuare.cx>
- */
-
-#include "para.h"
-#include "compress_filter.cmdline.h"
-#include "list.h"
-#include "sched.h"
-#include "filter.h"
-#include "string.h"
-
-/** The size of the output data buffer. */
-#define COMPRESS_CHUNK_SIZE 40960
-
-extern char *stat_item_values[NUM_STAT_ITEMS];
-
-/** Data specific to the compress filter. */
-struct private_compress_data {
-       /** The current multiplier. */
-       unsigned current_gain;
-       /** Points to the configuration data for this instance of the compress filter. */
-       struct compress_filter_args_info *conf;
-       /** Maximal admissible gain. */
-       unsigned max_gain;
-       /** Number of samples already seen. */
-       unsigned num_samples;
-       /** Absolute value of the maximal sample in the current block. */
-       unsigned peak;
-};
-
-static ssize_t compress(char *inbuf, size_t inbuf_len, struct filter_node *fn)
-{
-       size_t i, length = PARA_MIN((inbuf_len / 2) * 2,
-               (fn->bufsize - fn->loaded) / 2 * 2);
-       struct private_compress_data *pcd = fn->private_data;
-       int16_t *ip = (int16_t *)inbuf, *op = (int16_t *)(fn->buf + fn->loaded);
-       unsigned gain_shift = pcd->conf->inertia_arg + pcd->conf->damp_arg,
-               mask = (1 << pcd->conf->blocksize_arg) - 1;
-
-       if (!length)
-               return 0;
-       for (i = 0; i < length / 2; i++) {
-               /* be careful in that heat, my dear */
-               int sample = *ip++, adjusted_sample = (PARA_ABS(sample) *
-                       pcd->current_gain) >> gain_shift;
-               if (unlikely(adjusted_sample > 32767)) { /* clip */
-                       PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n",
-                               sample, adjusted_sample);
-                       adjusted_sample = 32767;
-                       pcd->current_gain = (3 * pcd->current_gain +
-                               (1 << pcd->conf->inertia_arg)) / 4;
-                       pcd->peak = 0;
-               } else
-                       pcd->peak = PARA_MAX(pcd->peak, adjusted_sample);
-               *op++ = sample >= 0? adjusted_sample : -adjusted_sample;
-               if (likely(++pcd->num_samples & mask))
-                       continue;
-//             PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
-//                     pcd->peak);
-               if (pcd->peak < pcd->conf->target_level_arg) {
-                       if (pcd->current_gain < pcd->max_gain)
-                               pcd->current_gain++;
-               } else
-                       pcd->current_gain = PARA_MAX(pcd->current_gain - 2,
-                               1 << pcd->conf->inertia_arg);
-               pcd->peak = 0;
-       }
-       fn->loaded += length;
-       return length;
-}
-
-static void close_compress(struct filter_node *fn)
-{
-       free(fn->private_data);
-       free(fn->buf);
-}
-
-static void *compress_parse_config(int argc, char **argv)
-{
-       struct compress_filter_args_info *ret = para_calloc(sizeof(struct compress_filter_args_info));
-       if (!compress_cmdline_parser(argc, argv, ret))
-               return ret;
-       free(ret);
-       return NULL;
-}
-
-static void open_compress(struct filter_node *fn)
-{
-       struct private_compress_data *pcd = para_calloc(
-               sizeof(struct private_compress_data));
-       pcd->conf = fn->conf;
-       fn->private_data = pcd;
-       fn->bufsize = COMPRESS_CHUNK_SIZE;
-       fn->buf = para_malloc(fn->bufsize);
-       pcd->current_gain = 1 << pcd->conf->inertia_arg;
-       pcd->max_gain = 1 << (pcd->conf->inertia_arg + pcd->conf->aggressiveness_arg);
-}
-
-/**
- * The init function of the compress filter.
- *
- * \param f Pointer to the struct to initialize.
- */
-void compress_init(struct filter *f)
-{
-       f->open = open_compress;
-       f->close = close_compress;
-       f->convert = compress;
-       f->print_help = compress_cmdline_parser_print_help;
-       f->parse_config = compress_parse_config;
-}
diff --git a/compress_filter.c b/compress_filter.c
new file mode 100644 (file)
index 0000000..6034ce7
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/** \file compress_filter.c Paraslash's dynamic audio range compressor. */
+
+/*
+ * Uses ideas of AudioCompress, (C) 2002-2004  M. Hari Nezumi <magenta@trikuare.cx>
+ */
+
+#include "para.h"
+#include "compress_filter.cmdline.h"
+#include "list.h"
+#include "sched.h"
+#include "filter.h"
+#include "string.h"
+#include "error.h"
+
+/** The size of the output data buffer. */
+#define COMPRESS_CHUNK_SIZE 40960
+
+extern char *stat_item_values[NUM_STAT_ITEMS];
+
+/** Data specific to the compress filter. */
+struct private_compress_data {
+       /** The current multiplier. */
+       unsigned current_gain;
+       /** Points to the configuration data for this instance of the compress filter. */
+       struct compress_filter_args_info *conf;
+       /** Maximal admissible gain. */
+       unsigned max_gain;
+       /** Number of samples already seen. */
+       unsigned num_samples;
+       /** Absolute value of the maximal sample in the current block. */
+       unsigned peak;
+};
+
+static ssize_t compress(char *inbuf, size_t inbuf_len, struct filter_node *fn)
+{
+       size_t i, length = PARA_MIN((inbuf_len / 2) * 2,
+               (fn->bufsize - fn->loaded) / 2 * 2);
+       struct private_compress_data *pcd = fn->private_data;
+       int16_t *ip = (int16_t *)inbuf, *op = (int16_t *)(fn->buf + fn->loaded);
+       unsigned gain_shift = pcd->conf->inertia_arg + pcd->conf->damp_arg,
+               mask = (1 << pcd->conf->blocksize_arg) - 1;
+
+       if (!length)
+               return 0;
+       for (i = 0; i < length / 2; i++) {
+               /* be careful in that heat, my dear */
+               int sample = *ip++, adjusted_sample = (PARA_ABS(sample) *
+                       pcd->current_gain) >> gain_shift;
+               if (unlikely(adjusted_sample > 32767)) { /* clip */
+                       PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n",
+                               sample, adjusted_sample);
+                       adjusted_sample = 32767;
+                       pcd->current_gain = (3 * pcd->current_gain +
+                               (1 << pcd->conf->inertia_arg)) / 4;
+                       pcd->peak = 0;
+               } else
+                       pcd->peak = PARA_MAX(pcd->peak, adjusted_sample);
+               *op++ = sample >= 0? adjusted_sample : -adjusted_sample;
+               if (likely(++pcd->num_samples & mask))
+                       continue;
+//             PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
+//                     pcd->peak);
+               if (pcd->peak < pcd->conf->target_level_arg) {
+                       if (pcd->current_gain < pcd->max_gain)
+                               pcd->current_gain++;
+               } else
+                       pcd->current_gain = PARA_MAX(pcd->current_gain - 2,
+                               1 << pcd->conf->inertia_arg);
+               pcd->peak = 0;
+       }
+       fn->loaded += length;
+       return length;
+}
+
+static void close_compress(struct filter_node *fn)
+{
+       free(fn->private_data);
+       free(fn->buf);
+}
+
+/** TODO: Add sanity checks */
+static int compress_parse_config(int argc, char **argv, void **config)
+{
+       int ret;
+       struct compress_filter_args_info *compress_conf
+               = para_calloc(sizeof(*compress_conf));
+
+       ret = -E_COMPRESS_SYNTAX;
+       if (compress_cmdline_parser(argc, argv, compress_conf))
+               goto err;
+       *config = compress_conf;
+       return 1;
+err:
+       free(compress_conf);
+       return  ret;
+}
+
+static void open_compress(struct filter_node *fn)
+{
+       struct private_compress_data *pcd = para_calloc(
+               sizeof(struct private_compress_data));
+       pcd->conf = fn->conf;
+       fn->private_data = pcd;
+       fn->bufsize = COMPRESS_CHUNK_SIZE;
+       fn->buf = para_malloc(fn->bufsize);
+       pcd->current_gain = 1 << pcd->conf->inertia_arg;
+       pcd->max_gain = 1 << (pcd->conf->inertia_arg + pcd->conf->aggressiveness_arg);
+}
+
+/**
+ * The init function of the compress filter.
+ *
+ * \param f Pointer to the struct to initialize.
+ */
+void compress_filter_init(struct filter *f)
+{
+       f->open = open_compress;
+       f->close = close_compress;
+       f->convert = compress;
+       f->print_help = compress_cmdline_parser_print_help;
+       f->parse_config = compress_parse_config;
+}
index 449246459f8619244e33e18d4eab5f20e0821071..c80b2610c19172e9348519aa6621598004e70d30 100644 (file)
@@ -81,7 +81,7 @@ AC_CHECK_FUNCS([atexit dup2 memchr memmove memset \
 all_errlist_objs="server mp3_afh afh_common vss command net string signal time
 daemon stat crypt http_send close_on_fork ipc acl afh fade amp_filter
 dccp_send fd user_list chunk_queue afs osl aft mood score attribute blob ringbuffer
-playlist sha1 rbtree sched audiod grab_client filter_chain wav compress
+playlist sha1 rbtree sched audiod grab_client filter_common wav_filter compress_filter
 http_recv dccp_recv recv_common write_common file_write audiod_command
 client_common recv stdout filter stdin audioc write client fsck exec send_common"
 
@@ -96,7 +96,7 @@ receivers=" http dccp"
 senders=" http dccp"
 
 filter_cmdline_objs="filter.cmdline compress_filter.cmdline amp_filter.cmdline"
-filter_errlist_objs="filter_chain wav compress filter string stdin stdout sched fd amp_filter"
+filter_errlist_objs="filter_common wav_filter compress_filter filter string stdin stdout sched fd amp_filter"
 filter_ldflags=""
 filters=" compress wav amp"
 
@@ -108,7 +108,7 @@ audiod_cmdline_objs="audiod.cmdline grab_client.cmdline compress_filter.cmdline
        http_recv.cmdline dccp_recv.cmdline file_write.cmdline client.cmdline
        audiod_command_list amp_filter.cmdline"
 audiod_errlist_objs="audiod signal string daemon stat net
-       time grab_client filter_chain wav compress amp_filter http_recv dccp_recv
+       time grab_client filter_common wav_filter compress_filter amp_filter http_recv dccp_recv
        recv_common fd sched write_common file_write audiod_command crypt
        client_common"
 audiod_ldflags=""
@@ -316,7 +316,7 @@ AC_CHECK_LIB([ogg], [ogg_stream_init], [], [ have_ogg="no" ])
 AC_CHECK_LIB([vorbis], [vorbis_info_init], [], [ have_ogg="no" ])
 AC_CHECK_HEADERS([ogg/ogg.h vorbis/codec.h], [], [ have_ogg="no" ])
 if test "$have_ogg" = "yes"; then
-       all_errlist_objs="$all_errlist_objs oggdec ogg_afh"
+       all_errlist_objs="$all_errlist_objs oggdec_filter ogg_afh"
        AC_DEFINE(HAVE_OGGVORBIS, 1, define to 1 to turn on ogg vorbis support)
        filters="$filters oggdec"
        if test "$OSTYPE" = "Darwin"; then
@@ -331,8 +331,8 @@ if test "$have_ogg" = "yes"; then
        audiod_cmdline_objs="$audiod_cmdline_objs oggdec_filter.cmdline"
 
        server_errlist_objs="$server_errlist_objs ogg_afh"
-       filter_errlist_objs="$filter_errlist_objs oggdec"
-       audiod_errlist_objs="$audiod_errlist_objs oggdec"
+       filter_errlist_objs="$filter_errlist_objs oggdec_filter"
+       audiod_errlist_objs="$audiod_errlist_objs oggdec_filter"
        afh_errlist_objs="$afh_errlist_objs ogg_afh"
 
        audiod_audio_formats="ogg"
@@ -366,10 +366,10 @@ AC_CHECK_HEADER(neaacdec.h, [], have_faad=no)
 AC_CHECK_LIB([faad], [NeAACDecOpen], [], have_faad=no)
 if test "$have_faad" = "yes"; then
        AC_DEFINE(HAVE_FAAD, 1, define to 1 if you want to build the aacdec filter)
-       all_errlist_objs="$all_errlist_objs aac_common aacdec aac_afh"
-       filter_errlist_objs="$filter_errlist_objs aacdec aac_common"
+       all_errlist_objs="$all_errlist_objs aac_common aacdec_filter aac_afh"
+       filter_errlist_objs="$filter_errlist_objs aacdec_filter aac_common"
        afh_errlist_objs="$afh_errlist_objs aac_common aac_afh"
-       audiod_errlist_objs="$audiod_errlist_objs aacdec aac_common"
+       audiod_errlist_objs="$audiod_errlist_objs aacdec_filter aac_common"
        server_errlist_objs="$server_errlist_objs aac_afh aac_common"
        server_ldflags="$server_ldflags $faad_libs -lfaad"
        filter_ldflags="$filter_ldflags $faad_libs -lfaad"
@@ -412,9 +412,9 @@ AC_CHECK_LIB([mad], [mad_stream_init], [], [
 ])
 if test "$have_mad" = "yes"; then
        AC_DEFINE(HAVE_MAD, 1, define to 1 if you want to build the mp3dec filter)
-       all_errlist_objs="$all_errlist_objs mp3dec"
-       filter_errlist_objs="$filter_errlist_objs mp3dec"
-       audiod_errlist_objs="$audiod_errlist_objs mp3dec"
+       all_errlist_objs="$all_errlist_objs mp3dec_filter"
+       filter_errlist_objs="$filter_errlist_objs mp3dec_filter"
+       audiod_errlist_objs="$audiod_errlist_objs mp3dec_filter"
        filter_ldflags="$filter_ldflags $mad_libs -lmad"
        audiod_ldflags="$audiod_ldflags $mad_libs -lmad"
        audiod_audio_formats="$audiod_audio_formats mp3"
@@ -705,6 +705,15 @@ AC_SUBST(fade_objs, add_dot_o($fade_objs))
 AC_DEFINE_UNQUOTED(INIT_FADE_ERRLISTS,
        objlist_to_errlist($fade_errlist_objs), errors used by para_fade)
 
+
+enum="$(for i in $filters; do printf "${i}_FILTER, " | tr '[a-z]' '[A-Z]'; done)"
+AC_DEFINE_UNQUOTED(FILTER_ENUM, $enum NUM_SUPPORTED_FILTERS,
+       enum of supported filters)
+inits="$(for i in $filters; do printf 'extern void '$i'_filter_init(struct filter *f); '; done)"
+AC_DEFINE_UNQUOTED(DECLARE_FILTER_INITS, $inits, init functions of the supported filters)
+array="$(for i in $filters; do printf '{.name = \"'$i'\", .init = '$i'_filter_init},'; done)"
+AC_DEFINE_UNQUOTED(FILTER_ARRAY, $array, array of supported filters)
+
 enum="$(for i in $writers; do printf "${i}_WRITE, " | tr '[a-z]' '[A-Z]'; done)"
 AC_DEFINE_UNQUOTED(WRITER_ENUM, $enum NUM_SUPPORTED_WRITERS,
        enum of supported writers)
@@ -715,6 +724,7 @@ inits="$(for i in $writers; do printf 'extern void '$i'_write_init(struct writer
 AC_DEFINE_UNQUOTED(DECLARE_WRITER_INITS, $inits, init functions of the supported writers)
 array="$(for i in $writers; do printf '{.init = '$i'_write_init},'; done)"
 AC_DEFINE_UNQUOTED(WRITER_ARRAY, $array, array of supported writers)
+
 enum="$(for i in $audiod_audio_formats; do printf "AUDIO_FORMAT_${i}, " | tr '[a-z]' '[A-Z]'; done)"
 AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMATS_ENUM, $enum NUM_AUDIO_FORMATS,
        enum of audio formats supported by audiod)
diff --git a/error.h b/error.h
index f0a2510da3c8425d4c514b3cbf2da977b7e877f6..7259a4cca22a748b029a1b45818e41af497ba206 100644 (file)
--- a/error.h
+++ b/error.h
@@ -13,8 +13,7 @@ DEFINE_ERRLIST_OBJECT_ENUM;
 
 /* these do not need error handling (yet) */
 #define SERVER_ERRORS
-#define WAV_ERRORS
-#define COMPRESS_ERRORS
+#define WAV_FILTER_ERRORS
 #define TIME_ERRORS
 #define CLOSE_ON_FORK_ERRORS
 #define DAEMON_ERRORS
@@ -27,13 +26,20 @@ DEFINE_ERRLIST_OBJECT_ENUM;
 #define RECV_ERRORS
 #define STDOUT_ERRORS
 #define IPC_ERRORS
-#define AMP_FILTER_ERRORS
 #define DCCP_SEND_ERRORS
 #define HTTP_SEND_ERRORS
 
 
 extern const char **para_errlist[];
 
+#define COMPRESS_FILTER_ERRORS \
+       PARA_ERROR(COMPRESS_SYNTAX, "syntax error in compress filter config"), \
+
+
+#define AMP_FILTER_ERRORS \
+       PARA_ERROR(AMP_SYNTAX, "syntax error in amp filter config"), \
+
+
 #define SEND_COMMON_ERRORS \
        PARA_ERROR(MAX_CLIENTS, "maximal number of clients exceeded"), \
 
@@ -234,7 +240,7 @@ extern const char **para_errlist[];
        PARA_ERROR(INVALID_AUDIOD_CMD, "invalid command"), \
 
 
-#define FILTER_CHAIN_ERRORS \
+#define FILTER_COMMON_ERRORS \
        PARA_ERROR(UNSUPPORTED_FILTER, "given filter not supported"), \
        PARA_ERROR(BAD_FILTER_OPTIONS, "invalid filter option given"), \
        PARA_ERROR(FC_EOF, "filter chain: eof"), \
@@ -245,13 +251,14 @@ extern const char **para_errlist[];
        PARA_ERROR(UNKNOWN_STAT_ITEM, "status item not recognized"), \
 
 
-#define OGGDEC_ERRORS \
+#define OGGDEC_FILTER_ERRORS \
        PARA_ERROR(OGGDEC_READ, "read from media returned an error"), \
        PARA_ERROR(OGGDEC_NOTVORBIS, "bitstream is not vorbis data"), \
        PARA_ERROR(OGGDEC_VERSION, "vorbis version mismatch"), \
        PARA_ERROR(OGGDEC_BADHEADER, "invalid vorbis bitstream header"), \
        PARA_ERROR(OGGDEC_FAULT, "bug or heap/stack corruption"), \
        PARA_ERROR(OGGDEC_BADLINK, "invalid stream section or requested link corrupt"), \
+       PARA_ERROR(OGGDEC_SYNTAX, "syntax error in oggdec config"), \
 
 
 #define GRAB_CLIENT_ERRORS \
@@ -264,7 +271,7 @@ extern const char **para_errlist[];
        PARA_ERROR(GC_VERSION_GIVEN, ""), /* not really an error */ \
 
 
-#define MP3DEC_ERRORS \
+#define MP3DEC_FILTER_ERRORS \
        PARA_ERROR(MAD_FRAME_DECODE, "mad frame decode error"), \
        PARA_ERROR(MP3DEC_OVERRUN, "mp3 output buffer overrun"), \
 
@@ -391,7 +398,7 @@ extern const char **para_errlist[];
        PARA_ERROR(WRITE_COMMON_SYNTAX, "syntax error in write option"), \
 
 
-#define AACDEC_ERRORS \
+#define AACDEC_FILTER_ERRORS \
        PARA_ERROR(AACDEC_INIT, "failed to init aac decoder"), \
        PARA_ERROR(AAC_DECODE, "aac decode error"), \
        PARA_ERROR(AAC_OVERRUN, "aac output buffer overrun"), \
index adfadea7733d01862d1a767504e298f7d601ffa8..b97bdaaa3cbc9de39d62573da476495c73cc3e6a 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -121,7 +121,7 @@ static int parse_config(int argc, char *argv[])
        if (!conf.list_filters_given)
                return 1;
        printf("available filters: ");
-       for (i = 0; filters[i].name; i++)
+       FOR_EACH_SUPPORTED_FILTER(i)
                printf("%s%s%s", i? " " : "", filters[i].name,
                        filters[i].parse_config? "*": "");
        printf("\nFilters marked with \"*\" have further command line options. Try\n"
index 8c1c9e0d431c26e20a01fff76a2f3edb5e57c054..39cec9ba03f4cbee46497b43fda7bdebc7b63dbb 100644 (file)
--- a/filter.h
+++ b/filter.h
@@ -4,8 +4,10 @@
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
 
-/** \file filter.h Filter-related structures and exported symbols from filter_chain.c. */
+/** \file filter.h Filter-related structures and exported symbols from filter_common.c. */
 
+/** The list of supported filters. */
+enum filter_enum {FILTER_ENUM};
 
 /**
  * Describes one running instance of a filter.
@@ -141,7 +143,7 @@ struct filter_callback {
  * Note: As several instances of the same filter may be running at the same
  * time, all these filter functions must be reentrant; no static non-constant
  * variables may be used.
- * \sa mp3dec.c, oggdec.c, wav.c, compress.c, filter_node
+ * \sa mp3dec_filter.c, oggdec_filter.c, wav_filter.c, compress_filter.c, filter_node
  */
 struct filter {
        /** The name of the filter. */
@@ -191,14 +193,16 @@ struct filter {
        /**
         * A pointer to the filter's command line parser.
         *
-        * If this optional function pointer is not NULL, any filter options are passed
-        * from the main program to this command line parser once at application
-        * startup. The command line parser should check its command line options given
-        * by \a argc and \a argv and abort on errors. On success, it should return a
-        * pointer to the filter-specific configuration data determined by \a argc and
-        * \a argv.
+        * If this optional function pointer is not NULL, any filter options
+        * are passed from the main program to this command line parser once at
+        * application startup. The command line parser should check its
+        * command line options given by \a argc and \a argv and abort on
+        * errors. Success must be indicated by a non-negative return value. In
+        * this case the function should return a pointer to the
+        * filter-specific configuration data determined by \a argc and \a
+        * argv. On failure, a negative paraslash error code must be returned.
         */
-       void *(*parse_config)(int argc, char **argv);
+       int (*parse_config)(int argc, char **argv, void **config);
 };
 
 void close_filters(struct filter_chain *fc);
@@ -218,55 +222,9 @@ static inline void write_int16_host_endian(char *buf, int val)
 #endif
 }
 
+DECLARE_FILTER_INITS
 
-/** \cond */
-extern struct filter filters[];
-#define DECLARE_EXTERN_FILTER_INIT(name) \
-       extern void name ## _init(struct filter *f)
-
-#define FILTER_INIT(filter) { \
-       .name = #filter, \
-       .init = filter ## _init, \
-       .parse_config = NULL, \
-       .print_help = NULL \
-},
-
-/* filters that are always present */
-DECLARE_EXTERN_FILTER_INIT(wav);
-DECLARE_EXTERN_FILTER_INIT(compress);
-DECLARE_EXTERN_FILTER_INIT(amp);
-
-/* next the optional filters */
-#ifdef HAVE_MAD
-DECLARE_EXTERN_FILTER_INIT(mp3dec);
-#define MP3DEC_FILTER FILTER_INIT(mp3dec)
-#else
-#define MP3DEC_FILTER
-#endif
-
-#ifdef HAVE_FAAD
-DECLARE_EXTERN_FILTER_INIT(aacdec);
-#define AACDEC_FILTER FILTER_INIT(aacdec)
-#else
-#define AACDEC_FILTER
-#endif
-
-#ifdef HAVE_OGGVORBIS
-DECLARE_EXTERN_FILTER_INIT(oggdec);
-#define OGGDEC_FILTER FILTER_INIT(oggdec)
-#else
-#define OGGDEC_FILTER
-#endif
-/** \endcond */
-
-/** define an array of all available filters */
-#define DEFINE_FILTER_ARRAY(filters) struct filter filters[] = { \
-       FILTER_INIT(wav) \
-       FILTER_INIT(compress) \
-       FILTER_INIT(amp) \
-       MP3DEC_FILTER \
-       AACDEC_FILTER \
-       OGGDEC_FILTER \
-       { .name = NULL } };
-
+#define FOR_EACH_SUPPORTED_FILTER(j)  for (j = 0; j < NUM_SUPPORTED_FILTERS; j++)
 
+/** The filter array, one structure for each supported filter. */
+extern struct filter filters[NUM_SUPPORTED_FILTERS];
diff --git a/filter_chain.c b/filter_chain.c
deleted file mode 100644 (file)
index fa8637e..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
-
-/** \file filter_chain.c Common helper functions for filter input/output. */
-
-#include <sys/types.h>
-#include <dirent.h>
-
-#include "para.h"
-#include "list.h"
-#include "sched.h"
-#include "fd.h"
-#include "filter.h"
-#include "error.h"
-#include "string.h"
-
-DEFINE_FILTER_ARRAY(filters);
-
-/**
- * Call the init function of each supported filter.
- *
- * \param all_filters the array of all supported filters.
- *
- * \sa filter::init
- */
-void filter_init(struct filter *all_filters)
-{
-       struct filter *f;
-
-       for (f = all_filters; f->name; f++)
-               f->init(f);
-}
-
-/**
- * Close and destroy a filter callback.
- *
- * \param fcb The filter callback to close.
- *
- * This removes \a fcb from the list of filter callbacks and calls
- * the close callback associated with \a fcb.
- */
-static void close_filter_callback(struct filter_callback *fcb)
-{
-       PARA_NOTICE_LOG("closing filter_callback %p, data: %p\n", fcb, fcb->data);
-       list_del(&fcb->node);
-       fcb->close(fcb);
-}
-
-/**
- * Close all callbacks of a filter node.
- *
- * \param fn The filter node which contains the filter callbacks to be closed.
- *
- * Call close_filter_callback() for each entry in the filter callback list
- * of \a fn.
- */
-static void close_callbacks(struct filter_node *fn)
-{
-       struct filter_callback *fcb, *tmp;
-
-       list_for_each_entry_safe(fcb, tmp, &fn->callbacks, node) {
-               PARA_INFO_LOG("closing %s filter callback\n",
-                       filters[fn->filter_num].name);
-               close_filter_callback(fcb);
-       }
-}
-
-static void call_callbacks(struct filter_node *fn, char *inbuf, size_t inlen,
-       char *outbuf, size_t outlen)
-{
-       struct filter_callback *fcb, *tmp;
-       list_for_each_entry_safe(fcb, tmp, &fn->callbacks, node) {
-               int ret;
-               if (inlen && fcb->input_cb) {
-                       ret = fcb->input_cb(inbuf, inlen, fcb);
-                       if (ret < 0) {
-                               close_filter_callback(fcb);
-                               continue;
-                       }
-               }
-               if (!outlen || !fcb->output_cb)
-                       continue;
-               ret = fcb->output_cb(outbuf, outlen, fcb);
-               if (ret < 0)
-                       close_filter_callback(fcb);
-       }
-}
-
-/**
- * Call the convert function of each filter.
- *
- * \param s Unused.
- * \param t The task identifying the filter chain.
- *
- * This is the core function of the filter subsystem. It loops over the list of
- * filter nodes determined by \a t and calls the filter's convert function if
- * there is input available for the filter node in question. If the convert
- * function consumed some or all of its input data, all registered input
- * callbacks are called.  Similarly, if a convert function produced output, all
- * registerd output callbacks get called.
- *
- * On errors a (negative) error code is stored in t->error.
- *
- * \sa filter_node, filter#convert, filter_callback.
- */
-void filter_pre_select(__a_unused struct sched *s, struct task *t)
-{
-       struct filter_chain *fc = container_of(t, struct filter_chain, task);
-       struct filter_node *fn;
-       char *ib;
-       size_t *loaded;
-       int i, conv, conv_total = 0;
-
-       if (fc->output_error && *fc->output_error < 0) {
-               t->error =  *fc->output_error;
-               return;
-       }
-again:
-       ib = fc->inbuf;
-       loaded = fc->in_loaded;
-       conv = 0;
-       FOR_EACH_FILTER_NODE(fn, fc, i) {
-               struct filter *f = filters + fn->filter_num;
-               if (fn->loaded < fn->bufsize) {
-                       size_t size, old_fn_loaded = fn->loaded;
-//                     PARA_DEBUG_LOG("fc %p loaded: %zd, calling %s convert\n",
-//                             fc, *loaded, fn->filter->name);
-                       t->error = f->convert(ib, *loaded, fn);
-                       if (t->error < 0)
-                               return;
-                       size = t->error;
-                       call_callbacks(fn, ib, size, fn->buf + old_fn_loaded,
-                               fn->loaded - old_fn_loaded);
-                       *loaded -= size;
-                       conv += size;
-                       if (*loaded && size) {
-//                             PARA_DEBUG_LOG("moving %zd bytes in input "
-//                                     "buffer for %s filter\n",
-//                                     *loaded,  fn->filter->name);
-                               memmove(ib, ib + size, *loaded);
-                       }
-               }
-               ib = fn->buf;
-               loaded = &fn->loaded;
-       }
-       conv_total += conv;
-//     PARA_DEBUG_LOG("eof (in/out/fc): %d/%d/%d out_loaded: %zd, "
-//             "conv: %d, conv_total: %d\n", *fc->input_eof,
-//             fc->output_eof? *fc->output_eof : -42,
-//             fc->eof, *fc->out_loaded, conv, conv_total);
-       if (conv)
-               goto again;
-       if (!*fc->input_error)
-               return;
-       if (*fc->out_loaded)
-               return;
-       if (*fc->in_loaded && conv_total)
-               return;
-       t->error = -E_FC_EOF;
-}
-
-/**
- * Close all filter nodes and their callbacks.
- *
- * \param fc The filter chain to close.
- *
- * For each filter node determined by \a fc, call the close function of each
- * registered filter callback as well as the close function of the
- * corresponding filter.  Free all resources and destroy all callback lists and
- * the filter node list.
- *
- * \sa filter::close, filter_callback::close
- */
-void close_filters(struct filter_chain *fc)
-{
-       struct filter_node *fn;
-       int i;
-
-       if (!fc)
-               return;
-       PARA_NOTICE_LOG("closing filter chain %p\n", fc);
-       FOR_EACH_FILTER_NODE(fn, fc, i) {
-               struct filter *f = filters + fn->filter_num;
-               close_callbacks(fn);
-               PARA_INFO_LOG("closing %s filter\n", f->name);
-               f->close(fn);
-       }
-       free(fc->filter_nodes);
-}
-
-/*
- * If the filter has a command line parser and options is not NULL, run it.
- * Returns filter_num on success, negative on errors
- */
-static int parse_filter_args(int filter_num, char *options, void **conf)
-{
-       struct filter *f = &filters[filter_num];
-       int i, argc = 2;
-       char **argv;
-
-//     PARA_DEBUG_LOG("%s, options: %s, parser: %p\n", f->name,
-//             options? options : "(none)", f->parse_config);
-       if (!f->parse_config)
-               return strlen(options)? -E_BAD_FILTER_OPTIONS : filter_num;
-//     PARA_DEBUG_LOG("options: %s\n", options);
-       argc = split_args(options, &argv, " \t");
-//             PARA_DEBUG_LOG("argc = %d, argv[0]: %s\n", argc, argv[0]);
-       for (i = argc - 1; i >= 0; i--)
-               argv[i + 1] = argv[i];
-       argv[0] = para_strdup(f->name);
-       argc += 1;
-       *conf = f->parse_config(argc, argv);
-       free(argv[0]);
-       free(argv);
-       return *conf? filter_num : -E_BAD_FILTER_OPTIONS;
-}
-
-/**
- * Check the filter command line options.
- *
- * \param fa The command line options.
- * \param conf Points to the filter configuration upon successful return.
- *
- * Check if \a fa starts with a the name of a supported filter, followed by
- * a colon. If yes, call the command line parser of that filter.
- *
- * \return On success, the number of the filter is returned and \a conf
- * is initialized to point to the filter configuration determined by \a fa.
- * On errors, a negative value is returned.
- *
- * Note: If \a fa specifies a filter that has no command line parser success is
- * returned, and \a conf is initialized to \p NULL.
- *
- * \sa filter::parse_config
- */
-int check_filter_arg(char *fa, void **conf)
-{
-       int j;
-
-       *conf = NULL;
-//     PARA_DEBUG_LOG("arg: %s\n", fa);
-       for (j = 0; filters[j].name; j++) {
-               const char *name = filters[j].name;
-               size_t len = strlen(name);
-               char c;
-               if (strlen(fa) < len)
-                       continue;
-               if (strncmp(name, fa, len))
-                       continue;
-               c = fa[len];
-               if (c && c != ' ')
-                       continue;
-               if (c && !filters[j].parse_config)
-                       return -E_BAD_FILTER_OPTIONS;
-               return parse_filter_args(j, c? fa + len + 1 :
-                       fa + strlen(fa), conf);
-       }
-       return -E_UNSUPPORTED_FILTER;
-}
-
diff --git a/filter_common.c b/filter_common.c
new file mode 100644 (file)
index 0000000..29d6c95
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/** \file filter_common.c Common helper functions for filter input/output. */
+
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "para.h"
+#include "list.h"
+#include "sched.h"
+#include "fd.h"
+#include "filter.h"
+#include "error.h"
+#include "string.h"
+
+/** The array of supported filters. */
+struct filter filters[NUM_SUPPORTED_FILTERS] = {FILTER_ARRAY};
+
+/**
+ * Call the init function of each supported filter.
+ *
+ * \param all_filters the array of all supported filters.
+ *
+ * \sa filter::init
+ */
+void filter_init(struct filter *all_filters)
+{
+       int i;
+
+       FOR_EACH_SUPPORTED_FILTER(i)
+               all_filters[i].init(all_filters + i);
+}
+
+/**
+ * Close and destroy a filter callback.
+ *
+ * \param fcb The filter callback to close.
+ *
+ * This removes \a fcb from the list of filter callbacks and calls
+ * the close callback associated with \a fcb.
+ */
+static void close_filter_callback(struct filter_callback *fcb)
+{
+       PARA_NOTICE_LOG("closing filter_callback %p, data: %p\n", fcb, fcb->data);
+       list_del(&fcb->node);
+       fcb->close(fcb);
+}
+
+/**
+ * Close all callbacks of a filter node.
+ *
+ * \param fn The filter node which contains the filter callbacks to be closed.
+ *
+ * Call close_filter_callback() for each entry in the filter callback list
+ * of \a fn.
+ */
+static void close_callbacks(struct filter_node *fn)
+{
+       struct filter_callback *fcb, *tmp;
+
+       list_for_each_entry_safe(fcb, tmp, &fn->callbacks, node) {
+               PARA_INFO_LOG("closing %s filter callback\n",
+                       filters[fn->filter_num].name);
+               close_filter_callback(fcb);
+       }
+}
+
+static void call_callbacks(struct filter_node *fn, char *inbuf, size_t inlen,
+       char *outbuf, size_t outlen)
+{
+       struct filter_callback *fcb, *tmp;
+       list_for_each_entry_safe(fcb, tmp, &fn->callbacks, node) {
+               int ret;
+               if (inlen && fcb->input_cb) {
+                       ret = fcb->input_cb(inbuf, inlen, fcb);
+                       if (ret < 0) {
+                               close_filter_callback(fcb);
+                               continue;
+                       }
+               }
+               if (!outlen || !fcb->output_cb)
+                       continue;
+               ret = fcb->output_cb(outbuf, outlen, fcb);
+               if (ret < 0)
+                       close_filter_callback(fcb);
+       }
+}
+
+/**
+ * Call the convert function of each filter.
+ *
+ * \param s Unused.
+ * \param t The task identifying the filter chain.
+ *
+ * This is the core function of the filter subsystem. It loops over the list of
+ * filter nodes determined by \a t and calls the filter's convert function if
+ * there is input available for the filter node in question. If the convert
+ * function consumed some or all of its input data, all registered input
+ * callbacks are called.  Similarly, if a convert function produced output, all
+ * registerd output callbacks get called.
+ *
+ * On errors a (negative) error code is stored in t->error.
+ *
+ * \sa filter_node, filter#convert, filter_callback.
+ */
+void filter_pre_select(__a_unused struct sched *s, struct task *t)
+{
+       struct filter_chain *fc = container_of(t, struct filter_chain, task);
+       struct filter_node *fn;
+       char *ib;
+       size_t *loaded;
+       int i, conv, conv_total = 0;
+
+       if (fc->output_error && *fc->output_error < 0) {
+               t->error =  *fc->output_error;
+               return;
+       }
+again:
+       ib = fc->inbuf;
+       loaded = fc->in_loaded;
+       conv = 0;
+       FOR_EACH_FILTER_NODE(fn, fc, i) {
+               struct filter *f = filters + fn->filter_num;
+               if (fn->loaded < fn->bufsize) {
+                       size_t size, old_fn_loaded = fn->loaded;
+//                     PARA_DEBUG_LOG("fc %p loaded: %zd, calling %s convert\n",
+//                             fc, *loaded, fn->filter->name);
+                       t->error = f->convert(ib, *loaded, fn);
+                       if (t->error < 0)
+                               return;
+                       size = t->error;
+                       call_callbacks(fn, ib, size, fn->buf + old_fn_loaded,
+                               fn->loaded - old_fn_loaded);
+                       *loaded -= size;
+                       conv += size;
+                       if (*loaded && size) {
+//                             PARA_DEBUG_LOG("moving %zd bytes in input "
+//                                     "buffer for %s filter\n",
+//                                     *loaded,  fn->filter->name);
+                               memmove(ib, ib + size, *loaded);
+                       }
+               }
+               ib = fn->buf;
+               loaded = &fn->loaded;
+       }
+       conv_total += conv;
+//     PARA_DEBUG_LOG("eof (in/out/fc): %d/%d/%d out_loaded: %zd, "
+//             "conv: %d, conv_total: %d\n", *fc->input_eof,
+//             fc->output_eof? *fc->output_eof : -42,
+//             fc->eof, *fc->out_loaded, conv, conv_total);
+       if (conv)
+               goto again;
+       if (!*fc->input_error)
+               return;
+       if (*fc->out_loaded)
+               return;
+       if (*fc->in_loaded && conv_total)
+               return;
+       t->error = -E_FC_EOF;
+}
+
+/**
+ * Close all filter nodes and their callbacks.
+ *
+ * \param fc The filter chain to close.
+ *
+ * For each filter node determined by \a fc, call the close function of each
+ * registered filter callback as well as the close function of the
+ * corresponding filter.  Free all resources and destroy all callback lists and
+ * the filter node list.
+ *
+ * \sa filter::close, filter_callback::close
+ */
+void close_filters(struct filter_chain *fc)
+{
+       struct filter_node *fn;
+       int i;
+
+       if (!fc)
+               return;
+       PARA_NOTICE_LOG("closing filter chain %p\n", fc);
+       FOR_EACH_FILTER_NODE(fn, fc, i) {
+               struct filter *f = filters + fn->filter_num;
+               close_callbacks(fn);
+               PARA_INFO_LOG("closing %s filter\n", f->name);
+               f->close(fn);
+       }
+       free(fc->filter_nodes);
+}
+
+/*
+ * If the filter has a command line parser and options is not NULL, run it.
+ * Returns filter_num on success, negative on errors
+ */
+static int parse_filter_args(int filter_num, char *options, void **conf)
+{
+       struct filter *f = &filters[filter_num];
+       int ret, i, argc = 2;
+       char **argv;
+
+//     PARA_DEBUG_LOG("%s, options: %s, parser: %p\n", f->name,
+//             options? options : "(none)", f->parse_config);
+       if (!f->parse_config)
+               return strlen(options)? -E_BAD_FILTER_OPTIONS : filter_num;
+//     PARA_DEBUG_LOG("options: %s\n", options);
+       argc = split_args(options, &argv, " \t");
+//             PARA_DEBUG_LOG("argc = %d, argv[0]: %s\n", argc, argv[0]);
+       for (i = argc - 1; i >= 0; i--)
+               argv[i + 1] = argv[i];
+       argv[0] = para_strdup(f->name);
+       argc += 1;
+       ret = f->parse_config(argc, argv, conf);
+       free(argv[0]);
+       free(argv);
+       return ret < 0? ret : filter_num;
+}
+
+/**
+ * Check the filter command line options.
+ *
+ * \param fa The command line options.
+ * \param conf Points to the filter configuration upon successful return.
+ *
+ * Check if \a fa starts with a the name of a supported filter, followed by
+ * a colon. If yes, call the command line parser of that filter.
+ *
+ * \return On success, the number of the filter is returned and \a conf
+ * is initialized to point to the filter configuration determined by \a fa.
+ * On errors, a negative value is returned.
+ *
+ * Note: If \a fa specifies a filter that has no command line parser success is
+ * returned, and \a conf is initialized to \p NULL.
+ *
+ * \sa filter::parse_config
+ */
+int check_filter_arg(char *fa, void **conf)
+{
+       int j;
+
+       *conf = NULL;
+//     PARA_DEBUG_LOG("arg: %s\n", fa);
+       FOR_EACH_SUPPORTED_FILTER(j) {
+               const char *name = filters[j].name;
+               size_t len = strlen(name);
+               char c;
+               if (strlen(fa) < len)
+                       continue;
+               if (strncmp(name, fa, len))
+                       continue;
+               c = fa[len];
+               if (c && c != ' ')
+                       continue;
+               if (c && !filters[j].parse_config)
+                       return -E_BAD_FILTER_OPTIONS;
+               return parse_filter_args(j, c? fa + len + 1 :
+                       fa + strlen(fa), conf);
+       }
+       return -E_UNSUPPORTED_FILTER;
+}
+
diff --git a/hash.h b/hash.h
index 03b45e04db71965dd70dfce56eafce6ad83f163e..2d6de8ab25baedad30a039da8f3fa0dba4d3b165 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -6,8 +6,6 @@
 
 /** \file hash.h Inline functions for hash values. */
 
-#include "portable_io.h"
-
 /** hash arrays are always unsigned char. */
 #define HASH_TYPE unsigned char
 
diff --git a/mp3dec.c b/mp3dec.c
deleted file mode 100644 (file)
index 0006a18..0000000
--- a/mp3dec.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
-
-/** \file mp3dec.c Paraslash's mp3 decoder. */
-
-#include "para.h"
-#include "list.h"
-#include "sched.h"
-#include "filter.h"
-#include "error.h"
-#include <mad.h>
-#include "string.h"
-
-/** The output buffer size. */
-#define MP3_OUTBUF_SIZE (128 * 1024)
-
-/** Convert a sample value from libmad to a signed short. */
-#define MAD_TO_SHORT(f) (f) >= MAD_F_ONE? SHRT_MAX :\
-       (f) <= -MAD_F_ONE? -SHRT_MAX : (signed short) ((f) >> (MAD_F_FRACBITS - 15))
-
-/** Data specific to the mp3dec filter. */
-struct private_mp3dec_data {
-       /** Information on the current mp3 stream. */
-       struct mad_stream stream;
-       /** Information about the frame which is currently decoded. */
-       struct mad_frame frame;
-       /** Contains the PCM output. */
-       struct mad_synth synth;
-};
-
-static ssize_t mp3dec(char *inbuffer, size_t len, struct filter_node *fn)
-{
-       int i, ret;
-       struct private_mp3dec_data *pmd = fn->private_data;
-       size_t copy = PARA_MIN(len, 4096);
-
-       if (fn->loaded > fn->bufsize * 4 / 5)
-               return 0;
-       mad_stream_buffer(&pmd->stream, (unsigned char *) inbuffer, copy);
-       pmd->stream.error = 0;
-next_frame:
-       ret = mad_header_decode(&pmd->frame.header, &pmd->stream);
-       if (ret < 0) {
-               if (pmd->stream.error != MAD_ERROR_BUFLEN &&
-                       pmd->stream.error != MAD_ERROR_LOSTSYNC)
-                       PARA_DEBUG_LOG("header decode: %s\n",
-                               mad_stream_errorstr(&pmd->stream));
-               goto out;
-       }
-       fn->fc->samplerate = pmd->frame.header.samplerate;
-       fn->fc->channels = MAD_NCHANNELS(&pmd->frame.header);
-       ret = mad_frame_decode(&pmd->frame, &pmd->stream);
-       if (ret) {
-               if (MAD_RECOVERABLE(pmd->stream.error) ||
-                       pmd->stream.error == MAD_ERROR_BUFLEN) {
-                       PARA_DEBUG_LOG("frame decode: %s\n",
-                               mad_stream_errorstr(&pmd->stream));
-                       goto out;
-               }
-               PARA_ERROR_LOG("frame decode: %s\n",
-                       mad_stream_errorstr(&pmd->stream));
-               return -E_MAD_FRAME_DECODE;
-       }
-       mad_synth_frame(&pmd->synth, &pmd->frame);
-
-       for (i = 0; i < pmd->synth.pcm.length; i++) {
-               int s = MAD_TO_SHORT(pmd->synth.pcm.samples[0][i]);
-               write_int16_host_endian(fn->buf + fn->loaded, s);
-               fn->loaded += 2;
-               if (MAD_NCHANNELS(&pmd->frame.header) == 2) { /* stereo */
-                       s = MAD_TO_SHORT(pmd->synth.pcm.samples[1][i]);
-                       write_int16_host_endian(fn->buf + fn->loaded, s);
-                       fn->loaded += 2;
-               }
-               if (fn->loaded != fn->bufsize) /* output buffer not full */
-                       continue;
-               PARA_ERROR_LOG("output buffer full: %zd\n", fn->loaded);
-                       return -E_MP3DEC_OVERRUN;
-       }
-       if (fn->loaded <= fn->bufsize * 4 / 5)
-               goto next_frame;
-out:
-       if (pmd->stream.next_frame) { /* we still have some data */
-               size_t off = pmd->stream.bufend - pmd->stream.next_frame;
-//             PARA_INFO_LOG("off: %zd, rate: %u, returning %zd\n", off,
-//                     fn->fc->samplerate, copy - off);
-               return copy - off;
-       }
-       return copy;
-}
-
-static void mp3dec_close(struct filter_node *fn)
-{
-       struct private_mp3dec_data *pmd = fn->private_data;
-
-       mad_synth_finish(&pmd->synth);
-       mad_frame_finish(&pmd->frame);
-       mad_stream_finish(&pmd->stream);
-
-       free(fn->buf);
-       fn->buf = NULL;
-       free(pmd);
-       fn->private_data = NULL;
-}
-
-static void mp3dec_open(struct filter_node *fn)
-{
-       struct private_mp3dec_data *pmd = para_calloc(sizeof(*pmd));
-
-       fn->private_data = pmd;
-       mad_stream_init(&pmd->stream);
-       mad_frame_init(&pmd->frame);
-       mad_synth_init(&pmd->synth);
-       fn->loaded = 0;
-       fn->bufsize = MP3_OUTBUF_SIZE;
-       fn->buf = para_calloc(fn->bufsize);
-}
-
-/**
- * The init function of the mp3dec filter.
- *
- * \param f Pointer to the filter struct to initialize.
- *
- * \sa filter::init.
- */
-void mp3dec_init(struct filter *f)
-{
-       f->open = mp3dec_open;
-       f->convert = mp3dec;
-       f->close = mp3dec_close;
-}
diff --git a/mp3dec_filter.c b/mp3dec_filter.c
new file mode 100644 (file)
index 0000000..50e530e
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/** \file mp3dec_filter.c Paraslash's mp3 decoder. */
+
+#include "para.h"
+#include "list.h"
+#include "sched.h"
+#include "filter.h"
+#include "error.h"
+#include <mad.h>
+#include "string.h"
+
+/** The output buffer size. */
+#define MP3_OUTBUF_SIZE (128 * 1024)
+
+/** Convert a sample value from libmad to a signed short. */
+#define MAD_TO_SHORT(f) (f) >= MAD_F_ONE? SHRT_MAX :\
+       (f) <= -MAD_F_ONE? -SHRT_MAX : (signed short) ((f) >> (MAD_F_FRACBITS - 15))
+
+/** Data specific to the mp3dec filter. */
+struct private_mp3dec_data {
+       /** Information on the current mp3 stream. */
+       struct mad_stream stream;
+       /** Information about the frame which is currently decoded. */
+       struct mad_frame frame;
+       /** Contains the PCM output. */
+       struct mad_synth synth;
+};
+
+static ssize_t mp3dec(char *inbuffer, size_t len, struct filter_node *fn)
+{
+       int i, ret;
+       struct private_mp3dec_data *pmd = fn->private_data;
+       size_t copy = PARA_MIN(len, 4096);
+
+       if (fn->loaded > fn->bufsize * 4 / 5)
+               return 0;
+       mad_stream_buffer(&pmd->stream, (unsigned char *) inbuffer, copy);
+       pmd->stream.error = 0;
+next_frame:
+       ret = mad_header_decode(&pmd->frame.header, &pmd->stream);
+       if (ret < 0) {
+               if (pmd->stream.error != MAD_ERROR_BUFLEN &&
+                       pmd->stream.error != MAD_ERROR_LOSTSYNC)
+                       PARA_DEBUG_LOG("header decode: %s\n",
+                               mad_stream_errorstr(&pmd->stream));
+               goto out;
+       }
+       fn->fc->samplerate = pmd->frame.header.samplerate;
+       fn->fc->channels = MAD_NCHANNELS(&pmd->frame.header);
+       ret = mad_frame_decode(&pmd->frame, &pmd->stream);
+       if (ret) {
+               if (MAD_RECOVERABLE(pmd->stream.error) ||
+                       pmd->stream.error == MAD_ERROR_BUFLEN) {
+                       PARA_DEBUG_LOG("frame decode: %s\n",
+                               mad_stream_errorstr(&pmd->stream));
+                       goto out;
+               }
+               PARA_ERROR_LOG("frame decode: %s\n",
+                       mad_stream_errorstr(&pmd->stream));
+               return -E_MAD_FRAME_DECODE;
+       }
+       mad_synth_frame(&pmd->synth, &pmd->frame);
+
+       for (i = 0; i < pmd->synth.pcm.length; i++) {
+               int s = MAD_TO_SHORT(pmd->synth.pcm.samples[0][i]);
+               write_int16_host_endian(fn->buf + fn->loaded, s);
+               fn->loaded += 2;
+               if (MAD_NCHANNELS(&pmd->frame.header) == 2) { /* stereo */
+                       s = MAD_TO_SHORT(pmd->synth.pcm.samples[1][i]);
+                       write_int16_host_endian(fn->buf + fn->loaded, s);
+                       fn->loaded += 2;
+               }
+               if (fn->loaded != fn->bufsize) /* output buffer not full */
+                       continue;
+               PARA_ERROR_LOG("output buffer full: %zd\n", fn->loaded);
+                       return -E_MP3DEC_OVERRUN;
+       }
+       if (fn->loaded <= fn->bufsize * 4 / 5)
+               goto next_frame;
+out:
+       if (pmd->stream.next_frame) { /* we still have some data */
+               size_t off = pmd->stream.bufend - pmd->stream.next_frame;
+//             PARA_INFO_LOG("off: %zd, rate: %u, returning %zd\n", off,
+//                     fn->fc->samplerate, copy - off);
+               return copy - off;
+       }
+       return copy;
+}
+
+static void mp3dec_close(struct filter_node *fn)
+{
+       struct private_mp3dec_data *pmd = fn->private_data;
+
+       mad_synth_finish(&pmd->synth);
+       mad_frame_finish(&pmd->frame);
+       mad_stream_finish(&pmd->stream);
+
+       free(fn->buf);
+       fn->buf = NULL;
+       free(pmd);
+       fn->private_data = NULL;
+}
+
+static void mp3dec_open(struct filter_node *fn)
+{
+       struct private_mp3dec_data *pmd = para_calloc(sizeof(*pmd));
+
+       fn->private_data = pmd;
+       mad_stream_init(&pmd->stream);
+       mad_frame_init(&pmd->frame);
+       mad_synth_init(&pmd->synth);
+       fn->loaded = 0;
+       fn->bufsize = MP3_OUTBUF_SIZE;
+       fn->buf = para_calloc(fn->bufsize);
+}
+
+/**
+ * The init function of the mp3dec filter.
+ *
+ * \param f Pointer to the filter struct to initialize.
+ *
+ * \sa filter::init.
+ */
+void mp3dec_filter_init(struct filter *f)
+{
+       f->open = mp3dec_open;
+       f->convert = mp3dec;
+       f->close = mp3dec_close;
+}
diff --git a/oggdec.c b/oggdec.c
deleted file mode 100644 (file)
index e22ea1e..0000000
--- a/oggdec.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
-
-/** \file oggdec.c Paraslash's ogg vorbis decoder. */
-
-#include "para.h"
-
-#include "oggdec_filter.cmdline.h"
-#include "list.h"
-#include "sched.h"
-#include "filter.h"
-#include "error.h"
-#include "string.h"
-
-#include <vorbis/vorbisfile.h>
-
-/** Determine byte sex. */
-#ifdef WORDS_BIGENDIAN
-#define ENDIAN 1
-#else
-#define ENDIAN 0
-#endif
-
-/** Data specific to the oggdec filter. */
-struct private_oggdec_data {
-       /** Describes an ogg vorbis file. */
-       OggVorbis_File *vf;
-       /** The input buffer. */
-       char *inbuf;
-       /** The length of \a inbuf. */
-       size_t inbuf_len;
-       /** The number of bytes consumed from the input buffer. */
-       size_t converted;
-};
-
-static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource)
-{
-       struct filter_node *fn = datasource;
-       struct private_oggdec_data *pod = fn->private_data;
-       size_t ret, have = pod->inbuf_len - pod->converted;
-       char *p = pod->inbuf + pod->converted;
-
-//     PARA_DEBUG_LOG("pod = %p\n", pod);
-//     PARA_DEBUG_LOG("vorbis requests %d bytes, have %d\n", size * nmemb, have);
-       if (pod->inbuf_len < size) {
-               if (*fn->fc->input_error)
-                       return 0;
-               errno = EAGAIN;
-               return (size_t)-1;
-       }
-       ret = PARA_MIN(nmemb, have / size) * size;
-       memcpy(buf, p, ret);
-       pod->converted += ret;
-       return ret;
-}
-
-/*
- * Custom data seeking function.
- *
- * Since we want the data source to be treated as unseekable at all
- * times, the provided seek callback always returns -1 (failure).
- */
-static int cb_seek(__a_unused void *datasource, __a_unused ogg_int64_t offset,
-               __a_unused int whence)
-{
-       return -1;
-}
-
-static int cb_close(__a_unused void *datasource)
-{
-       return 0;
-}
-
-static const ov_callbacks ovc = {
-       .read_func = cb_read,
-       .seek_func = cb_seek,
-       .close_func = cb_close,
-       /*
-        * The tell function need not be provided if the data IO abstraction is
-        * not seekable
-        */
-       .tell_func = NULL
-};
-
-static void ogg_open(struct filter_node *fn)
-{
-       struct private_oggdec_data *pod = para_calloc(
-               sizeof(struct private_oggdec_data));
-       struct oggdec_filter_args_info *conf = fn->conf;
-
-       fn->private_data = pod;
-       fn->bufsize = conf->bufsize_arg * 1024;
-       fn->buf = para_malloc(fn->bufsize);
-}
-
-static void ogg_close(struct filter_node *fn)
-{
-       struct private_oggdec_data *pod = fn->private_data;
-       if (pod->vf) {
-               PARA_DEBUG_LOG("ov_clearing %p, pod = %p\n", pod->vf, pod);
-               ov_clear(pod->vf);
-               free(pod->vf);
-               pod->vf = NULL;
-       } else
-               PARA_DEBUG_LOG("nothing to close in fc %p, pod = %p\n", pod->vf, pod);
-       free(fn->buf);
-       fn->buf = NULL;
-       free(fn->private_data);
-       fn->private_data = NULL;
-}
-
-static ssize_t ogg_convert(char *inbuffer, size_t len, struct filter_node *fn)
-{
-       ssize_t ret;
-       struct private_oggdec_data *pod = fn->private_data;
-       struct oggdec_filter_args_info *conf = fn->conf;
-       /* make the buffer known to the read callback cb_read() */
-       pod->inbuf = inbuffer;
-       pod->inbuf_len = len;
-       pod->converted = 0;
-
-       if (!pod->vf) {
-               int ib = 1024 * conf->initial_buffer_arg; /* initial buffer */
-               if (len <ib && !*fn->fc->input_error) {
-                       PARA_DEBUG_LOG("initial input buffer %zd/%d, "
-                               "waiting for more data\n", len, ib);
-                       return 0;
-               }
-               pod->vf = para_malloc(sizeof(struct OggVorbis_File));
-               PARA_NOTICE_LOG("input buffer: %zd, opening ov callbacks\n", len);
-               ret = ov_open_callbacks(fn, pod->vf,
-                       NULL, /* no initial buffer */
-                       0, /* no initial bytes */
-                       ovc); /* the ov_open_callbacks */
-               if (ret == OV_EREAD)
-                       return -E_OGGDEC_READ;
-               if (ret == OV_ENOTVORBIS)
-                       return -E_OGGDEC_NOTVORBIS;
-               if (ret == OV_EVERSION)
-                       return -E_OGGDEC_VERSION;
-               if (ret == OV_EBADHEADER)
-                       return -E_OGGDEC_BADHEADER;
-               if (ret < 0)
-                       return -E_OGGDEC_FAULT;
-               fn->fc->channels = ov_info(pod->vf, 0)->channels;
-               fn->fc->samplerate = ov_info(pod->vf, 0)->rate;
-               PARA_NOTICE_LOG("%d channels, %d Hz\n", fn->fc->channels,
-                       fn->fc->samplerate);
-       }
-       while (fn->loaded < fn->bufsize) {
-               int length = fn->bufsize - fn->loaded;
-               long read_ret = ov_read(pod->vf, fn->buf + fn->loaded, length,
-                       ENDIAN, 2 /* 16 bit */, 1 /* signed */, NULL);
-               if (read_ret == OV_HOLE || !read_ret)
-                       return pod->converted;
-               if (read_ret < 0)
-                       return -E_OGGDEC_BADLINK;
-               fn->loaded += read_ret;
-       }
-       return pod->converted;
-}
-
-static void *oggdec_parse_config(int argc, char **argv)
-{
-       int ret;
-       struct oggdec_filter_args_info *ogg_conf;
-
-       ogg_conf = para_calloc(sizeof(*ogg_conf));
-       ret = oggdec_cmdline_parser(argc, argv, ogg_conf);
-       if (ret)
-               goto err;
-       if (ogg_conf->bufsize_arg < 0)
-               goto err;
-       if (ogg_conf->bufsize_arg >= INT_MAX / 1024)
-               goto err;
-       if (ogg_conf->initial_buffer_arg < 0)
-               goto err;
-       if (ogg_conf->initial_buffer_arg >= INT_MAX / 1024)
-               goto err;
-       return ogg_conf;
-err:
-       free(ogg_conf);
-       return NULL;
-}
-
-/**
- * The init function of the ogg vorbis decoder.
- *
- * \param f Its fields are filled in by the function.
- */
-void oggdec_init(struct filter *f)
-{
-       f->open = ogg_open;
-       f->close = ogg_close;
-       f->convert = ogg_convert;
-       f->print_help = oggdec_cmdline_parser_print_help;
-       f->parse_config = oggdec_parse_config;
-}
diff --git a/oggdec_filter.c b/oggdec_filter.c
new file mode 100644 (file)
index 0000000..689fc7a
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/** \file oggdec_filter.c Paraslash's ogg vorbis decoder. */
+
+#include "para.h"
+
+#include "oggdec_filter.cmdline.h"
+#include "list.h"
+#include "sched.h"
+#include "filter.h"
+#include "error.h"
+#include "string.h"
+
+#include <vorbis/vorbisfile.h>
+
+/** Determine byte sex. */
+#ifdef WORDS_BIGENDIAN
+#define ENDIAN 1
+#else
+#define ENDIAN 0
+#endif
+
+/** Data specific to the oggdec filter. */
+struct private_oggdec_data {
+       /** Describes an ogg vorbis file. */
+       OggVorbis_File *vf;
+       /** The input buffer. */
+       char *inbuf;
+       /** The length of \a inbuf. */
+       size_t inbuf_len;
+       /** The number of bytes consumed from the input buffer. */
+       size_t converted;
+};
+
+static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource)
+{
+       struct filter_node *fn = datasource;
+       struct private_oggdec_data *pod = fn->private_data;
+       size_t ret, have = pod->inbuf_len - pod->converted;
+       char *p = pod->inbuf + pod->converted;
+
+//     PARA_DEBUG_LOG("pod = %p\n", pod);
+//     PARA_DEBUG_LOG("vorbis requests %d bytes, have %d\n", size * nmemb, have);
+       if (pod->inbuf_len < size) {
+               if (*fn->fc->input_error)
+                       return 0;
+               errno = EAGAIN;
+               return (size_t)-1;
+       }
+       ret = PARA_MIN(nmemb, have / size) * size;
+       memcpy(buf, p, ret);
+       pod->converted += ret;
+       return ret;
+}
+
+/*
+ * Custom data seeking function.
+ *
+ * Since we want the data source to be treated as unseekable at all
+ * times, the provided seek callback always returns -1 (failure).
+ */
+static int cb_seek(__a_unused void *datasource, __a_unused ogg_int64_t offset,
+               __a_unused int whence)
+{
+       return -1;
+}
+
+static int cb_close(__a_unused void *datasource)
+{
+       return 0;
+}
+
+static const ov_callbacks ovc = {
+       .read_func = cb_read,
+       .seek_func = cb_seek,
+       .close_func = cb_close,
+       /*
+        * The tell function need not be provided if the data IO abstraction is
+        * not seekable
+        */
+       .tell_func = NULL
+};
+
+static void ogg_open(struct filter_node *fn)
+{
+       struct private_oggdec_data *pod = para_calloc(
+               sizeof(struct private_oggdec_data));
+       struct oggdec_filter_args_info *conf = fn->conf;
+
+       fn->private_data = pod;
+       fn->bufsize = conf->bufsize_arg * 1024;
+       fn->buf = para_malloc(fn->bufsize);
+}
+
+static void ogg_close(struct filter_node *fn)
+{
+       struct private_oggdec_data *pod = fn->private_data;
+       if (pod->vf) {
+               PARA_DEBUG_LOG("ov_clearing %p, pod = %p\n", pod->vf, pod);
+               ov_clear(pod->vf);
+               free(pod->vf);
+               pod->vf = NULL;
+       } else
+               PARA_DEBUG_LOG("nothing to close in fc %p, pod = %p\n", pod->vf, pod);
+       free(fn->buf);
+       fn->buf = NULL;
+       free(fn->private_data);
+       fn->private_data = NULL;
+}
+
+static ssize_t ogg_convert(char *inbuffer, size_t len, struct filter_node *fn)
+{
+       ssize_t ret;
+       struct private_oggdec_data *pod = fn->private_data;
+       struct oggdec_filter_args_info *conf = fn->conf;
+       /* make the buffer known to the read callback cb_read() */
+       pod->inbuf = inbuffer;
+       pod->inbuf_len = len;
+       pod->converted = 0;
+
+       if (!pod->vf) {
+               int ib = 1024 * conf->initial_buffer_arg; /* initial buffer */
+               if (len <ib && !*fn->fc->input_error) {
+                       PARA_DEBUG_LOG("initial input buffer %zd/%d, "
+                               "waiting for more data\n", len, ib);
+                       return 0;
+               }
+               pod->vf = para_malloc(sizeof(struct OggVorbis_File));
+               PARA_NOTICE_LOG("input buffer: %zd, opening ov callbacks\n", len);
+               ret = ov_open_callbacks(fn, pod->vf,
+                       NULL, /* no initial buffer */
+                       0, /* no initial bytes */
+                       ovc); /* the ov_open_callbacks */
+               if (ret == OV_EREAD)
+                       return -E_OGGDEC_READ;
+               if (ret == OV_ENOTVORBIS)
+                       return -E_OGGDEC_NOTVORBIS;
+               if (ret == OV_EVERSION)
+                       return -E_OGGDEC_VERSION;
+               if (ret == OV_EBADHEADER)
+                       return -E_OGGDEC_BADHEADER;
+               if (ret < 0)
+                       return -E_OGGDEC_FAULT;
+               fn->fc->channels = ov_info(pod->vf, 0)->channels;
+               fn->fc->samplerate = ov_info(pod->vf, 0)->rate;
+               PARA_NOTICE_LOG("%d channels, %d Hz\n", fn->fc->channels,
+                       fn->fc->samplerate);
+       }
+       while (fn->loaded < fn->bufsize) {
+               int length = fn->bufsize - fn->loaded;
+               long read_ret = ov_read(pod->vf, fn->buf + fn->loaded, length,
+                       ENDIAN, 2 /* 16 bit */, 1 /* signed */, NULL);
+               if (read_ret == OV_HOLE || !read_ret)
+                       return pod->converted;
+               if (read_ret < 0)
+                       return -E_OGGDEC_BADLINK;
+               fn->loaded += read_ret;
+       }
+       return pod->converted;
+}
+
+static int oggdec_parse_config(int argc, char **argv, void **config)
+{
+       int ret;
+       struct oggdec_filter_args_info *ogg_conf;
+
+       ogg_conf = para_calloc(sizeof(*ogg_conf));
+       ret = -E_OGGDEC_SYNTAX;
+       if (oggdec_cmdline_parser(argc, argv, ogg_conf))
+               goto err;
+       ret = -ERRNO_TO_PARA_ERROR(EINVAL);
+       if (ogg_conf->bufsize_arg < 0)
+               goto err;
+       if (ogg_conf->bufsize_arg >= INT_MAX / 1024)
+               goto err;
+       if (ogg_conf->initial_buffer_arg < 0)
+               goto err;
+       if (ogg_conf->initial_buffer_arg >= INT_MAX / 1024)
+               goto err;
+       *config = ogg_conf;
+       return 1;
+err:
+       free(ogg_conf);
+       return ret;
+}
+
+/**
+ * The init function of the ogg vorbis decoder.
+ *
+ * \param f Its fields are filled in by the function.
+ */
+void oggdec_filter_init(struct filter *f)
+{
+       f->open = ogg_open;
+       f->close = ogg_close;
+       f->convert = ogg_convert;
+       f->print_help = oggdec_cmdline_parser_print_help;
+       f->parse_config = oggdec_parse_config;
+}
index e042665ab9eda67e95f2c5773f11f1311f468805..5e2acaa0dc6fcc2074b9686724020be56d6f822f 100644 (file)
@@ -9,6 +9,7 @@
 #include "rbtree.h"
 #include "osl.h"
 #include "string.h"
+#include "portable_io.h"
 #include "hash.h"
 
 /** Internal representation of a column of an osl table. */
index 915687649f7f84c8a572b2257a7439498d31c873..459f44621bb5c1f8350f2c5192edaa15362b5335 100644 (file)
--- a/server.c
+++ b/server.c
@@ -23,8 +23,8 @@
  * The gory details, listed by topic:
  *
  *     - Audio format handlers: \ref send_common.c \ref mp3_afh.c, \ref ogg_afh.c, \ref aac_afh.c,
- *     - Decoders: \ref mp3dec.c, \ref oggdec.c, \ref aacdec.c,
- *     - Volume normalizer: \ref compress.c,
+ *     - Decoders: \ref mp3dec_filter.c, \ref oggdec_filter.c, \ref aacdec_filter.c,
+ *     - Volume normalizer: \ref compress_filter.c,
  *     - Output: \ref alsa_write.c, \ref osx_write.c,
  *     - http: \ref http_recv.c, \ref http_send.c,
  *     - ortp: \ref ortp_recv.c, \ref ortp_send.c,
diff --git a/wav.c b/wav.c
deleted file mode 100644 (file)
index c03c21d..0000000
--- a/wav.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
-
-/** \file wav.c a filter that inserts a wave header */
-
-#include "para.h"
-
-#include "list.h"
-#include "sched.h"
-#include "filter.h"
-#include "string.h"
-
-/** size of the output buffer */
-#define WAV_OUTBUF_SIZE 81920
-/** a wav header is always 44 bytes */
-#define WAV_HEADER_LEN 44
-/** always write 16 bit header */
-#define BITS 16
-
-/**
- * write a 32 bit unsigned value to a buffer
- *
- * \param buf the buffer to write to
- * \param x the value to write
- */
-#define WRITE_U32(buf, x) (buf)[0] = (unsigned char)((x) & 0xff);\
-       (buf)[1] = (unsigned char)(((x) >> 8) & 0xff);\
-       (buf)[2] = (unsigned char)(((x) >> 16) & 0xff);\
-       (buf)[3] = (unsigned char)(((x) >> 24) & 0xff);
-
-/**
- * write a 16 bit unsigned value to a buffer
- *
- * \param buf the buffer to write to
- * \param x the value to write
- */
-#define WRITE_U16(buf, x) (buf)[0] = (unsigned char)((x) & 0xff);
-
-static void make_wav_header(unsigned int channels, unsigned int samplerate,
-               struct filter_node *fn)
-{
-
-       char *headbuf = fn->buf;
-       unsigned int size = 0x7fffffff;
-       int bytespersec = channels * samplerate * BITS / 8;
-       int align = channels * BITS / 8;
-
-       assert(channels);
-       PARA_DEBUG_LOG("writing wave header: %d channels, %d KHz\n", channels, samplerate);
-       memset(headbuf, 0, WAV_HEADER_LEN);
-       memcpy(headbuf, "RIFF", 4);
-       WRITE_U32(headbuf + 4, size - 8);
-       memcpy(headbuf + 8, "WAVE", 4);
-       memcpy(headbuf + 12, "fmt ", 4);
-       WRITE_U32(headbuf + 16, 16);
-       WRITE_U16(headbuf + 20, 1);     /* format */
-       WRITE_U16(headbuf + 22, channels);
-       WRITE_U32(headbuf + 24, samplerate);
-       WRITE_U32(headbuf + 28, bytespersec);
-       WRITE_U16(headbuf + 32, align);
-       WRITE_U16(headbuf + 34, BITS);
-       memcpy(headbuf + 36, "data", 4);
-       WRITE_U32(headbuf + 40, size - 44);
-}
-
-static ssize_t wav_convert(char *inbuf, size_t len, struct filter_node *fn)
-{
-       size_t copy;
-       int *bof = fn->private_data;
-
-       if (*bof) {
-               if (!len)
-                       return 0;
-               make_wav_header(fn->fc->channels, fn->fc->samplerate, fn);
-               fn->loaded = WAV_HEADER_LEN;
-               *bof = 0;
-//             return 0;
-       }
-       copy = PARA_MIN(len, fn->bufsize - fn->loaded);
-       memmove(fn->buf + fn->loaded, inbuf, copy);
-       fn->loaded += copy;
-//     PARA_DEBUG_LOG("len = %d, copy = %d\n", len, copy);
-       return copy;
-}
-
-static void wav_close(struct filter_node *fn)
-{
-       free(fn->buf);
-       fn->buf = NULL;
-       free(fn->private_data);
-       fn->private_data = NULL;
-}
-
-static void wav_open(struct filter_node *fn)
-{
-       int *bof;
-
-       fn->bufsize = WAV_OUTBUF_SIZE;
-       fn->buf = para_malloc(fn->bufsize);
-       fn->private_data = para_malloc(sizeof(int));
-       bof = fn->private_data;
-       fn->loaded = 0;
-       *bof = 1;
-       PARA_INFO_LOG("wav filter node: %p, output buffer: %p, loaded: %zd\n",
-               fn, fn->buf, fn->loaded);
-}
-
-/**
- * the init function of the wav filter
- *
- * \param f struct to initialize
- */
-void wav_init(struct filter *f)
-{
-       f->convert = wav_convert;
-       f->close = wav_close;
-       f->open = wav_open;
-}
diff --git a/wav_filter.c b/wav_filter.c
new file mode 100644 (file)
index 0000000..3fce556
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/** \file wav_filter.c A filter that inserts a wave header. */
+
+#include "para.h"
+
+#include "list.h"
+#include "sched.h"
+#include "filter.h"
+#include "string.h"
+#include "portable_io.h"
+
+/** size of the output buffer */
+#define WAV_OUTBUF_SIZE 81920
+/** a wav header is always 44 bytes */
+#define WAV_HEADER_LEN 44
+/** always write 16 bit header */
+#define BITS 16
+
+static void make_wav_header(unsigned int channels, unsigned int samplerate,
+               struct filter_node *fn)
+{
+
+       char *headbuf = fn->buf;
+       unsigned int size = 0x7fffffff;
+       int bytespersec = channels * samplerate * BITS / 8;
+       int align = channels * BITS / 8;
+
+       assert(channels);
+       PARA_DEBUG_LOG("writing wave header: %d channels, %d KHz\n", channels, samplerate);
+       memset(headbuf, 0, WAV_HEADER_LEN);
+       memcpy(headbuf, "RIFF", 4);
+       write_u32(headbuf + 4, size - 8);
+       memcpy(headbuf + 8, "WAVE", 4);
+       memcpy(headbuf + 12, "fmt ", 4);
+       write_u32(headbuf + 16, 16);
+       write_u16(headbuf + 20, 1);     /* format */
+       write_u16(headbuf + 22, channels);
+       write_u32(headbuf + 24, samplerate);
+       write_u32(headbuf + 28, bytespersec);
+       write_u16(headbuf + 32, align);
+       write_u16(headbuf + 34, BITS);
+       memcpy(headbuf + 36, "data", 4);
+       write_u32(headbuf + 40, size - 44);
+}
+
+static ssize_t wav_convert(char *inbuf, size_t len, struct filter_node *fn)
+{
+       size_t copy;
+       int *bof = fn->private_data;
+
+       if (*bof) {
+               if (!len)
+                       return 0;
+               make_wav_header(fn->fc->channels, fn->fc->samplerate, fn);
+               fn->loaded = WAV_HEADER_LEN;
+               *bof = 0;
+//             return 0;
+       }
+       copy = PARA_MIN(len, fn->bufsize - fn->loaded);
+       memmove(fn->buf + fn->loaded, inbuf, copy);
+       fn->loaded += copy;
+//     PARA_DEBUG_LOG("len = %d, copy = %d\n", len, copy);
+       return copy;
+}
+
+static void wav_close(struct filter_node *fn)
+{
+       free(fn->buf);
+       fn->buf = NULL;
+       free(fn->private_data);
+       fn->private_data = NULL;
+}
+
+static void wav_open(struct filter_node *fn)
+{
+       int *bof;
+
+       fn->bufsize = WAV_OUTBUF_SIZE;
+       fn->buf = para_malloc(fn->bufsize);
+       fn->private_data = para_malloc(sizeof(int));
+       bof = fn->private_data;
+       fn->loaded = 0;
+       *bof = 1;
+       PARA_INFO_LOG("wav filter node: %p, output buffer: %p, loaded: %zd\n",
+               fn, fn->buf, fn->loaded);
+}
+
+/**
+ * the init function of the wav filter
+ *
+ * \param f struct to initialize
+ */
+void wav_filter_init(struct filter *f)
+{
+       f->convert = wav_convert;
+       f->close = wav_close;
+       f->open = wav_open;
+}