ggo_descriptions_declared := @ggo_descriptions_declared@
executables := @executables@
-filters := @filters@
writers := @writers@
recv_objs := @recv_objs@
unconverted_executables := $(filter-out $(converted_executables), $(executables))
audioc_objs += audioc.lsg.o
-audiod_objs += audiod_cmd.lsg.o recv_cmd.lsg.o client.lsg.o
+audiod_objs += $(addsuffix _cmd.lsg.o, recv filter audiod) client.lsg.o
+client_objs += client.lsg.o
fade_objs += fade.lsg.o
-server_objs += server_cmd.lsg.o
-play_objs += play_cmd.lsg.o recv_cmd.lsg.o play.lsg.o
+filter_objs += filter_cmd.lsg.o
+play_objs += $(addsuffix _cmd.lsg.o, recv filter play) play.lsg.o
recv_objs += recv_cmd.lsg.o
-client_objs += client.lsg.o
+server_objs += server_cmd.lsg.o
m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(unconverted_executables)))
-m4_lls_deps := audiod_cmd server_cmd play_cmd recv_cmd $(converted_executables)
+m4_lls_deps := \
+ audiod_cmd \
+ server_cmd \
+ play_cmd \
+ recv_cmd \
+ filter_cmd \
+ $(converted_executables)
m4_lls_deps := $(addprefix $(lls_suite_dir)/, $(addsuffix .m4d, $(m4_lls_deps)))
# now prefix all objects with object dir
Q := @
endif
-server_command_lists := $(lls_suite_dir)/server_cmd.lsg.man
-audiod_command_lists := \
- $(lls_suite_dir)/audiod_cmd.lsg.man \
- $(lls_suite_dir)/recv_cmd.lsg.man
+audiod_command_lists := $(addprefix $(lls_suite_dir)/, \
+ $(addsuffix _cmd.lsg.man, audiod recv filter))
+filter_command_lists := $(lls_suite_dir)/filter_cmd.lsg.man
play_command_lists := $(lls_suite_dir)/play_cmd.lsg.man
recv_command_lists := $(lls_suite_dir)/recv_cmd.lsg.man
+server_command_lists := $(lls_suite_dir)/server_cmd.lsg.man
$(man_dir)/para_server.1: $(server_command_lists)
+$(man_dir)/para_filter.1: $(filter_command_lists)
$(man_dir)/para_audiod.1: $(audiod_command_lists)
$(man_dir)/para_play.1: $(play_command_lists)
$(man_dir)/para_recv.1: $(recv_command_lists)
$(man_dir)/para_server.1: man_util_command_lists := $(server_command_lists)
+$(man_dir)/para_filter.1: man_util_command_lists := $(filter_command_lists)
$(man_dir)/para_audiod.1: man_util_command_lists := $(audiod_command_lists)
$(man_dir)/para_play.1: man_util_command_lists := $(play_command_lists)
$(man_dir)/para_recv.1: man_util_command_lists := $(recv_command_lists)
para_audiod \
para_client \
para_fade \
+para_filter \
para_play \
para_recv \
para_server \
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
return ret;
}
-/**
- * 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->close = aacdec_close;
- f->pre_select = generic_filter_pre_select;
- f->post_select = aacdec_post_select;
- f->execute = aacdec_execute;
-}
+const struct filter lsg_filter_cmd_com_aacdec_user_data = {
+ .open = aacdec_open,
+ .close = aacdec_close,
+ .pre_select = generic_filter_pre_select,
+ .post_select = aacdec_post_select,
+ .execute = aacdec_execute
+};
/** \file amp_filter.c Paraslash's amplify filter. */
#include <regex.h>
+#include <lopsub.h>
+#include "filter_cmd.lsg.h"
#include "para.h"
-#include "amp_filter.cmdline.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
free(fn->private_data);
}
-static int amp_parse_config(int argc, char **argv, void **config)
-{
- struct amp_filter_args_info *conf = para_calloc(sizeof(*conf));
- int ret;
-
- amp_filter_cmdline_parser(argc, argv, conf);
- ret = -ERRNO_TO_PARA_ERROR(EINVAL);
- if (conf->amp_arg < 0)
- goto err;
- *config = conf;
- return 1;
-err:
- free(conf);
- return ret;
-}
-
static void amp_open(struct filter_node *fn)
{
struct private_amp_data *pad = para_calloc(sizeof(*pad));
- struct amp_filter_args_info *conf = fn->conf;
+ unsigned given = FILTER_CMD_OPT_GIVEN(AMP, AMP, fn->lpr);
+ uint32_t amp_arg = FILTER_CMD_OPT_UINT32_VAL(AMP, AMP, fn->lpr);
fn->private_data = pad;
fn->min_iqs = 2;
- if (!conf->amp_given && stat_item_values[SI_AMPLIFICATION])
+ if (!given && stat_item_values[SI_AMPLIFICATION])
sscanf(stat_item_values[SI_AMPLIFICATION], "%u", &pad->amp);
else
- pad->amp = conf->amp_arg;
+ pad->amp = amp_arg;
PARA_INFO_LOG("amplification: %u (scaling factor: %1.2f)\n",
pad->amp, pad->amp / 64.0 + 1.0);
}
return ret;
}
-static void amp_free_config(void *conf)
-{
- amp_filter_cmdline_parser_free(conf);
-}
-
-/**
- * The init function of the amplify filter.
- *
- * \param f Pointer to the struct to initialize.
- */
-void amp_filter_init(struct filter *f)
-{
- struct amp_filter_args_info dummy;
-
- amp_filter_cmdline_parser_init(&dummy);
- f->open = amp_open;
- f->close = amp_close;
- f->pre_select = generic_filter_pre_select;
- f->post_select = amp_post_select;
- f->parse_config = amp_parse_config;
- f->free_config = amp_free_config;
- f->help = (struct ggo_help)DEFINE_GGO_HELP(amp_filter);
-}
+const struct filter lsg_filter_cmd_com_amp_user_data = {
+ .open = amp_open,
+ .close = amp_close,
+ .pre_select = generic_filter_pre_select,
+ .post_select = amp_post_select,
+};
unsigned *filter_nums;
/** Pointer to the array of filter configurations. */
void **filter_conf;
+ /** Parsed filter command line, one parse result per filter. */
+ struct lls_parse_result **filter_lpr;
/** the number of filters that should be activated for this audio format */
unsigned int num_writers;
/** Array of writer numbers to be activated. */
parent = s->receiver_node->btrn;
for (i = 0; i < nf; i++) {
char buf[20];
+ const char *name;
const struct filter *f = filter_get(a->filter_nums[i]);
fn = s->fns + i;
fn->filter_num = a->filter_nums[i];
fn->conf = a->filter_conf[i];
+ fn->lpr = a->filter_lpr[i];
+ name = filter_name(fn->filter_num);
fn->btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = f->name, .parent = parent,
+ EMBRACE(.name = name, .parent = parent,
.handler = f->execute, .context = fn));
if (f->open)
f->open(fn);
- sprintf(buf, "%s (slot %d)", f->name, (int)(s - slot));
+ sprintf(buf, "%s (slot %d)", name, (int)(s - slot));
fn->task = task_register(&(struct task_info) {
.name = buf,
.pre_select = f->pre_select,
}, &sched);
parent = fn->btrn;
PARA_NOTICE_LOG("%s filter %d/%d (%s) started in slot %d\n",
- audio_formats[s->format], i, nf, f->name, (int)(s - slot));
+ audio_formats[s->format], i, nf, name, (int)(s - slot));
}
}
struct audio_format_info *a = &afi[format];
int filter_num, nf = a->num_filters;
void *cfg;
+ struct lls_parse_result *flpr;
- filter_num = check_filter_arg(cmdline, &cfg);
- if (filter_num < 0)
- return filter_num;
+ filter_num = filter_setup(cmdline, &cfg, &flpr);
+ a->filter_lpr = para_realloc(a->filter_lpr,
+ (nf + 1) * sizeof(flpr));
a->filter_conf = para_realloc(a->filter_conf,
(nf + 1) * sizeof(void *));
a->filter_nums = para_realloc(a->filter_nums,
(nf + 1) * sizeof(unsigned));
+
a->filter_nums[nf] = filter_num;
a->filter_conf[nf] = cfg;
+ a->filter_lpr[nf] = flpr;
a->num_filters++;
PARA_INFO_LOG("%s filter %d: %s\n", audio_formats[format], nf,
- filter_get(filter_num)->name);
+ filter_name(filter_num));
return filter_num;
}
/* add "dec" to audio format name */
tmp = make_message("%sdec", audio_formats[i]);
for (j = 0; filter_get(j); j++)
- if (!strcmp(tmp, filter_get(j)->name))
+ if (!strcmp(tmp, filter_name(j)))
break;
free(tmp);
ret = -E_UNSUPPORTED_FILTER;
if (!filter_get(j))
goto out;
- tmp = para_strdup(filter_get(j)->name);
+ tmp = para_strdup(filter_name(j));
ret = add_filter(i, tmp);
free(tmp);
if (ret < 0)
goto out;
PARA_INFO_LOG("%s -> default filter: %s\n", audio_formats[i],
- filter_get(j)->name);
+ filter_name(j));
}
out:
return ret;
version_handle_flag("audiod", conf.version_given);
/* init receivers/filters/writers early to make help work */
recv_init();
- filter_init();
writer_init();
if (conf.help_given || conf.detailed_help_given)
print_help_and_die();
(dst)->sample_format_arg = (src)->sample_format_arg; \
(dst)->sample_format_given = (src)->sample_format_given;
+#define LLS_COPY_WAV_PARMS(_dst, _pfx, _lpr) \
+ (_dst)->channels_given = lls_opt_given(lls_opt_result( \
+ _pfx ## _OPT_CHANNELS, (_lpr))); \
+ (_dst)->sample_rate_given = lls_opt_given(lls_opt_result( \
+ _pfx ## _OPT_SAMPLE_RATE, (_lpr))); \
+ (_dst)->sample_format_given = lls_opt_given(lls_opt_result( \
+ _pfx ## _OPT_SAMPLE_FORMAT, (_lpr))); \
+ (_dst)->channels_arg = lls_uint32_val(0, lls_opt_result( \
+ _pfx ## _OPT_CHANNELS, (_lpr))); \
+ (_dst)->sample_rate_arg = lls_uint32_val(0, lls_opt_result( \
+ _pfx ## _OPT_SAMPLE_RATE, (_lpr))); \
+ (_dst)->sample_format_arg = lls_uint32_val(0, lls_opt_result( \
+ _pfx ## _OPT_SAMPLE_FORMAT, (_lpr)));
+
struct check_wav_context *check_wav_init(struct btr_node *parent,
struct btr_node *child, struct wav_params *params,
struct btr_node **cw_btrn);
*/
#include <regex.h>
+#include <lopsub.h>
+#include "filter_cmd.lsg.h"
#include "para.h"
-#include "compress_filter.cmdline.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
#include "error.h"
+#define U32_OPTVAL(_opt, _lpr) (FILTER_CMD_OPT_UINT32_VAL(COMPRESS, _opt, _lpr))
+
/** 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. */
char *inbuf;
size_t length, i;
int16_t *ip, *op;
- unsigned gain_shift = pcd->conf->inertia_arg + pcd->conf->damp_arg,
- mask = (1 << pcd->conf->blocksize_arg) - 1;
-
+ uint32_t inertia = U32_OPTVAL(INERTIA, fn->lpr);
+ unsigned gain_shift = inertia + U32_OPTVAL(DAMP, fn->lpr),
+ mask = (1 << U32_OPTVAL(BLOCKSIZE, fn->lpr)) - 1;
//inplace = false;
next_buffer:
ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
if (sample > 32767) { /* clip */
sample = 32767;
pcd->current_gain = (3 * pcd->current_gain +
- (1 << pcd->conf->inertia_arg)) / 4;
+ (1 << inertia)) / 4;
pcd->peak = 0;
} else if (sample > pcd->peak)
pcd->peak = sample;
continue;
// PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
// pcd->peak);
- if (pcd->peak < pcd->conf->target_level_arg) {
+ if (pcd->peak < U32_OPTVAL(TARGET_LEVEL, fn->lpr)) {
if (pcd->current_gain < pcd->max_gain)
pcd->current_gain++;
} else
pcd->current_gain = PARA_MAX(pcd->current_gain - 2,
- 1U << pcd->conf->inertia_arg);
+ 1U << inertia);
pcd->peak = 0;
}
if (inplace)
return ret;
}
-/** TODO: Add sanity checks */
-static int compress_parse_config(int argc, char **argv, void **config)
-{
- struct compress_filter_args_info *conf = para_calloc(sizeof(*conf));
-
- compress_filter_cmdline_parser(argc, argv, conf);
- *config = conf;
- return 1;
-}
-
static void compress_open(struct filter_node *fn)
{
- struct private_compress_data *pcd = para_calloc(
- sizeof(struct private_compress_data));
- pcd->conf = fn->conf;
+ struct private_compress_data *pcd = para_calloc(sizeof(*pcd));
+ uint32_t inertia = U32_OPTVAL(INERTIA, fn->lpr);
+ uint32_t aggressiveness = U32_OPTVAL(AGGRESSIVENESS, fn->lpr);
+
fn->private_data = pcd;
fn->min_iqs = 2; /* 16 bit audio */
- pcd->current_gain = 1 << pcd->conf->inertia_arg;
- pcd->max_gain = 1 << (pcd->conf->inertia_arg + pcd->conf->aggressiveness_arg);
-}
-
-static void compress_free_config(void *conf)
-{
- compress_filter_cmdline_parser_free(conf);
+ pcd->current_gain = 1U << inertia;
+ pcd->max_gain = 1U << (inertia + aggressiveness);
}
-/**
- * The init function of the compress filter.
- *
- * \param f Pointer to the struct to initialize.
- */
-void compress_filter_init(struct filter *f)
-{
- struct compress_filter_args_info dummy;
-
- compress_filter_cmdline_parser_init(&dummy);
- f->open = compress_open;
- f->close = compress_close;
- f->pre_select = generic_filter_pre_select;
- f->post_select = compress_post_select;
- f->parse_config = compress_parse_config;
- f->free_config = compress_free_config;
- f->help = (struct ggo_help)DEFINE_GGO_HELP(compress_filter);
-}
+const struct filter lsg_filter_cmd_com_compress_user_data = {
+ .open = compress_open,
+ .close = compress_close,
+ .pre_select = generic_filter_pre_select,
+ .post_select = compress_post_select,
+};
audiod_audio_formats="wma"
audiod_cmdline_objs="$audiod_cmdline_objs
audiod
- compress_filter
file_write
- amp_filter
- prebuffer_filter
- sync_filter
"
audiod_errlist_objs="$audiod_errlist_objs
audiod
fi
if test $HAVE_MAD = yes; then
audiod_audio_formats="$audiod_audio_formats mp3"
- audiod_cmdline_objs="$audiod_cmdline_objs mp3dec_filter"
audiod_errlist_objs="$audiod_errlist_objs mp3dec_filter"
fi
if test $HAVE_OSS = yes; then
}
if test $HAVE_SAMPLERATE = yes; then
audiod_errlist_objs="$audiod_errlist_objs resample_filter check_wav"
- audiod_cmdline_objs="$audiod_cmdline_objs resample_filter"
fi
audiod_objs="add_cmdline($audiod_cmdline_objs) $audiod_errlist_objs"
AC_SUBST(audiod_objs, add_dot_o($audiod_objs))
AC_MSG_WARN([no curses lib, cannot build para_gui])
fi
######################################################################## filter
-filters="
- compress
- wav
- amp
- fecdec
- wmadec
- prebuffer
- sync
-"
filter_errlist_objs="
filter_common
wav_filter
"
filter_cmdline_objs="
filter
- compress_filter
- amp_filter
- prebuffer_filter
- sync_filter
"
-NEED_VORBIS_OBJECTS && {
- filters="$filters oggdec"
- filter_errlist_objs="$filter_errlist_objs oggdec_filter"
-}
-NEED_SPEEX_OBJECTS && {
- filters="$filters spxdec"
- filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common"
-}
-NEED_OPUS_OBJECTS && {
- filters="$filters opusdec"
- filter_errlist_objs="$filter_errlist_objs opusdec_filter opus_common"
-}
-NEED_FLAC_OBJECTS && {
- filter_errlist_objs="$filter_errlist_objs flacdec_filter"
- filters="$filters flacdec"
-}
+NEED_VORBIS_OBJECTS && filter_errlist_objs="$filter_errlist_objs oggdec_filter"
+NEED_SPEEX_OBJECTS && filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common"
+NEED_OPUS_OBJECTS && filter_errlist_objs="$filter_errlist_objs opusdec_filter opus_common"
+NEED_FLAC_OBJECTS && filter_errlist_objs="$filter_errlist_objs flacdec_filter"
if test $HAVE_FAAD = yes; then
filter_errlist_objs="$filter_errlist_objs aacdec_filter aac_common"
- filters="$filters aacdec"
fi
if test $HAVE_MAD = yes; then
- filter_cmdline_objs="$filter_cmdline_objs mp3dec_filter"
filter_errlist_objs="$filter_errlist_objs mp3dec_filter"
- filters="$filters mp3dec"
fi
if test $HAVE_SAMPLERATE = yes; then
filter_errlist_objs="$filter_errlist_objs resample_filter check_wav"
- filter_cmdline_objs="$filter_cmdline_objs resample_filter"
- filters="$filters resample"
fi
-filters="$(echo $filters)"
-AC_SUBST(filters)
filter_objs="add_cmdline($filter_cmdline_objs) $filter_errlist_objs"
AC_SUBST(filter_objs, add_dot_o($filter_objs))
-
-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)
########################################################################## recv
recv_cmdline_objs="
recv
sync_filter
"
play_cmdline_objs="
- compress_filter
- amp_filter
- prebuffer_filter
file_write
- sync_filter
"
if test "$have_core_audio" = "yes"; then
play_errlist_objs="$play_errlist_objs osx_write ipc"
play_errlist_objs="$play_errlist_objs aac_common"
fi
if test $HAVE_MAD = yes; then
- play_cmdline_objs="$play_cmdline_objs mp3dec_filter"
play_errlist_objs="$play_errlist_objs mp3dec_filter"
fi
if test $HAVE_OSS = yes; then
fi
if test $HAVE_SAMPLERATE = yes; then
play_errlist_objs="$play_errlist_objs resample_filter check_wav"
- play_cmdline_objs="$play_cmdline_objs resample_filter"
fi
play_objs="add_cmdline($play_cmdline_objs) $play_errlist_objs"
id3 version 2 support: $HAVE_ID3TAG
faad: $HAVE_FAAD
mp4v2: $HAVE_MP4V2
-
audio format handlers: $audio_format_handlers
-filters: $(echo $filters)
writers: $writers
para_server: $build_server
PARA_ERROR(BAD_CT, "invalid chunk table or bad FEC configuration"), \
PARA_ERROR(BAD_FEATURE, "invalid feature request"), \
PARA_ERROR(BAD_FEC_HEADER, "invalid fec header"), \
- PARA_ERROR(BAD_FILTER_OPTIONS, "invalid filter option given"), \
PARA_ERROR(BAD_LL, "invalid loglevel"), \
PARA_ERROR(BAD_PATH, "invalid path"), \
PARA_ERROR(BAD_PRIVATE_KEY, "invalid private key"), \
#include "error.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
fn->min_iqs = FEC_HEADER_SIZE;
}
-/**
- * The init function of the fecdec filter.
- *
- * \param f Struct to initialize.
- */
-void fecdec_filter_init(struct filter *f)
-{
- f->close = fecdec_close;
- f->open = fecdec_open;
- f->pre_select = generic_filter_pre_select;
- f->post_select = fecdec_post_select;
-}
+const struct filter lsg_filter_cmd_com_fecdec_user_data = {
+ .open = fecdec_open,
+ .pre_select = generic_filter_pre_select,
+ .post_select = fecdec_post_select,
+ .close = fecdec_close,
+};
bool d = conf.detailed_help_given;
ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
- print_filter_helps(d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS);
+ print_filter_helps(d);
exit(EXIT_SUCCESS);
}
const struct filter *f;
struct btr_node *parent;
struct filter_node **fns;
+ struct lls_parse_result *filter_lpr;
filter_cmdline_parser(argc, argv, &conf); /* aborts on errors */
loglevel = get_loglevel_by_name(conf.loglevel_arg);
- filter_init();
ret = parse_config();
if (ret < 0)
goto out;
fns = para_malloc(conf.filter_given * sizeof(*fns));
for (i = 0, parent = sit->btrn; i < conf.filter_given; i++) {
char *fa = conf.filter_arg[i];
+ const char *name;
struct filter_node *fn;
struct task_info ti;
fn = fns[i] = para_calloc(sizeof(*fn));
- ret = check_filter_arg(fa, &fn->conf);
- if (ret < 0) {
- free(fn);
- goto out_cleanup;
- }
- fn->filter_num = ret;
+ fn->filter_num = filter_setup(fa, &fn->conf, &filter_lpr);
+ name = filter_name(fn->filter_num);
+ fn->lpr = filter_lpr;
+ PARA_DEBUG_LOG("filter #%d: %s\n", i, name);
f = filter_get(fn->filter_num);
- PARA_DEBUG_LOG("filter #%d: %s\n", i, f->name);
fn->btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = f->name, .parent = parent,
+ EMBRACE(.name = name, .parent = parent,
.handler = f->execute, .context = fn));
- ti.name = f->name;
+ ti.name = name;
ti.pre_select = f->pre_select;
ti.post_select = f->post_select;
ti.context = fn;
btr_log_tree(sit->btrn, LL_INFO);
ret = schedule(&s);
sched_shutdown(&s);
-out_cleanup:
for (i--; i >= 0; i--) {
struct filter_node *fn = fns[i];
if (f->close)
f->close(fn);
btr_remove_node(&fn->btrn);
- if (f->free_config)
- f->free_config(fn->conf);
+ if (f->teardown)
+ f->teardown(fn->lpr, fn->conf);
free(fn);
}
free(fns);
/** \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.
*/
struct list_head callbacks;
/** A pointer to the configuration of this instance. */
void *conf;
+ /** The parsed command line, merged with options given in the config file. */
+ struct lls_parse_result *lpr;
/** The buffer tree node. */
struct btr_node *btrn;
/** The task corresponding to this filter node. */
/**
* The structure associated with a paraslash filter.
*
- * Paraslash filters are "modules" which are used to transform an audio stream.
- * struct filter contains pointers to functions that must be supplied by the
- * filter code in order to be used by the driving application (currently
- * para_audiod and para_filter).
+ * Paraslash filters are "modules" which transform an audio stream. struct
+ * filter contains methods which are implemented by each filter.
*
* 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_filter.c, oggdec_filter.c, wav_filter.c, compress_filter.c, filter_node
*/
struct filter {
- /** The name of the filter. */
- const char *name;
- /**
- * Pointer to the filter init routine.
- *
- * This function is only called once at startup. It must initialize the
- * other non-optional function pointers of this structure.
- */
- void (*init)(struct filter *f);
/**
* Open one instance of this filter.
*
*/
void (*close)(struct filter_node *fn);
/**
- * A pointer to the filter's command line parser.
+ * Prepare the filter according to command line options.
*
- * 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.
+ * In addition to the syntactic checks which are automatically performed
+ * by the lopsub functions, some filters like to also check the command
+ * line arguments semantically. Moreover, since applications may open
+ * the filter many times with the same options, filters need a method
+ * which allows them to precompute once those parts of the setup which
+ * depend only on the command line options.
+ *
+ * If this function pointer is not NULL, the function is called once at
+ * startup. The returned pointer value is made available to the ->open
+ * method via the ->conf pointer of struct filter_node.
+ *
+ * Filters are supposed to abort if the setup fails. If the function
+ * returns, it is assumed to have succeeded.
*/
- int (*parse_config)(int argc, char **argv, void **config);
+ void *(*setup)(const struct lls_parse_result *lpr);
/**
- * Deallocate the memory for the configuration.
+ * Deallocate precomputed resources.
*
- * This is called to free whatever ->parse_config() has allocated.
+ * This should free whatever ->setup() has allocated.
*/
- void (*free_config)(void *conf);
-
- /** The help texts for this filter. */
- struct ggo_help help;
+ void (*teardown)(const struct lls_parse_result *lpr, void *conf);
/**
* Set scheduler timeout and add file descriptors to fd sets.
*
btr_command_handler execute;
};
-void filter_init(void);
-int check_filter_arg(const char *fa, void **conf);
-void print_filter_helps(unsigned flags);
+void print_filter_helps(bool detailed);
+int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp);
+#define FILTER_CMD(_num) (lls_cmd(_num, filter_cmd_suite))
+#define FILTER_CMD_OPT_RESULT(_cmd, _opt, _lpr) \
+ (lls_opt_result(LSG_FILTER_CMD_ ## _cmd ## _OPT_ ## _opt, _lpr))
+#define FILTER_CMD_OPT_GIVEN(_cmd, _opt, _lpr) \
+ (lls_opt_given(FILTER_CMD_OPT_RESULT(_cmd, _opt, _lpr)))
+#define FILTER_CMD_OPT_UINT32_VAL(_cmd, _opt, _lpr) \
+ (lls_uint32_val(0, FILTER_CMD_OPT_RESULT(_cmd, _opt, _lpr)))
+#define FILTER_CMD_OPT_STRING_VAL(_cmd, _opt, _lpr) \
+ (lls_string_val(0, FILTER_CMD_OPT_RESULT(_cmd, _opt, _lpr)))
+
void generic_filter_pre_select(struct sched *s, void *context);
int decoder_execute(const char *cmd, unsigned sample_rate, unsigned channels,
char **result);
#endif
}
-DECLARE_FILTER_INITS
-
+/** Make a filter pointer from the filter number. */
const struct filter *filter_get(int filter_num);
+const char *filter_name(int filter_num);
#include <regex.h>
#include <sys/types.h>
+#include <lopsub.h>
+#include "filter_cmd.lsg.h"
#include "para.h"
#include "list.h"
#include "sched.h"
#include "fd.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
#include "string.h"
-/** Iterate over the array of supported filters. */
-#define FOR_EACH_SUPPORTED_FILTER(j) for (j = 0; j < NUM_SUPPORTED_FILTERS; j++)
-
-/** The array of supported filters. */
-static struct filter filters[NUM_SUPPORTED_FILTERS] = {FILTER_ARRAY};
+/** Iterate over all filters. */
+#define FOR_EACH_FILTER(j) for (j = 1; lls_cmd(j, filter_cmd_suite); j++)
/**
* Obtain a reference to a filter structure.
*/
const struct filter *filter_get(int filter_num)
{
- assert(filter_num >= 0);
- assert(filter_num < NUM_SUPPORTED_FILTERS);
- return filters + filter_num;
+ assert(filter_num >= 1);
+ assert(filter_num <= LSG_NUM_FILTER_CMD_SUBCOMMANDS);
+ return lls_user_data(FILTER_CMD(filter_num));
}
-/**
- * Call the init function of each supported filter.
- * \sa filter::init
- */
-void filter_init(void)
+static inline bool filter_supported(int filter_num)
{
- int i;
-
- FOR_EACH_SUPPORTED_FILTER(i)
- filter_get(i)->init((struct filter *)filter_get(i));
+ return lls_user_data(FILTER_CMD(filter_num));
}
-/*
- * 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, const char *options, void **conf)
+const char *filter_name(int filter_num)
{
- const struct filter *f = filter_get(filter_num);
- int ret, argc;
- char **argv;
-
- if (!f->parse_config)
- return strlen(options)? -E_BAD_FILTER_OPTIONS : filter_num;
- argc = create_shifted_argv(options, " \t", &argv);
- if (argc < 0)
- return -E_BAD_FILTER_OPTIONS;
- argv[0] = para_strdup(f->name);
- ret = f->parse_config(argc, argv, conf);
- free_argv(argv);
- return ret < 0? ret : filter_num;
+ return lls_command_name(FILTER_CMD(filter_num));
}
/**
- * Check the filter command line options.
+ * Parse a filter command line and call the corresponding ->setup method.
*
* \param fa The filter argument.
- * \param conf Points to the filter configuration upon successful return.
+ * \param conf Points to filter-specific setup upon successful return.
+ * \param lprp Parsed command line options are returned here.
*
* Check if the given filter argument starts with the name of a supported
* filter, optionally followed by options for this filter. 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.
+ * command line parser of that filter and its ->setup method.
*
- * 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
+ * \return This function either succeeds or does not return. On success, the
+ * number of the filter is returned and conf is initialized to point to the
+ * filter configuration as returned by the filter's ->setup() method, if any.
+ * Moreover, *lprp is initialized to contain the parsed command line options.
+ * On errors, the function calls exit(EXIT_FAILURE).
*/
-int check_filter_arg(const char *fa, void **conf)
+int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp)
{
- int j;
-
- *conf = NULL;
-// PARA_DEBUG_LOG("arg: %s\n", fa);
- FOR_EACH_SUPPORTED_FILTER(j) {
- const char *name = filter_get(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 && !filter_get(j)->parse_config)
- return -E_BAD_FILTER_OPTIONS;
- return parse_filter_args(j, c? fa + len + 1 :
- fa + strlen(fa), conf);
+ int ret, filter_num, argc;
+ char *errctx = NULL, **argv;
+ const struct lls_command *cmd;
+ const struct filter *f;
+
+ ret = create_argv(fa, " \t\n", &argv);
+ if (ret < 0)
+ goto fail;
+ argc = ret;
+ ret = lls(lls_lookup_subcmd(argv[0], filter_cmd_suite, &errctx));
+ if (ret < 0)
+ goto free_argv;
+ filter_num = ret;
+ cmd = FILTER_CMD(filter_num);
+ if (!filter_supported(filter_num)) {
+ ret = -E_UNSUPPORTED_FILTER;
+ errctx = make_message("bad filter name: %s",
+ lls_command_name(cmd));
+ goto free_argv;
}
- return -E_UNSUPPORTED_FILTER;
+ ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx));
+ if (ret < 0)
+ goto free_argv;
+ f = filter_get(filter_num);
+ *conf = f->setup? f->setup(*lprp) : NULL;
+ ret = filter_num;
+free_argv:
+ free_argv(argv);
+ if (ret >= 0)
+ return ret;
+fail:
+ if (errctx)
+ PARA_ERROR_LOG("%s\n", errctx);
+ free(errctx);
+ PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+ exit(EXIT_FAILURE);
}
/**
* Print help text of each filter to stdout.
*
- * \param flags Passed to \ref ggo_print_help().
+ * \param detailed Whether to print short or long help.
*/
-void print_filter_helps(unsigned flags)
+void print_filter_helps(bool detailed)
{
int i, num = 0;
- printf_or_die("\nAvailable filters: ");
- FOR_EACH_SUPPORTED_FILTER(i) {
+ printf("\nAvailable filters: ");
+ FOR_EACH_FILTER(i) {
+ if (!filter_supported(i))
+ continue;
if (num > 50) {
- printf_or_die("\n ");
+ printf("\n ");
num = 0;
}
- num += printf_or_die("%s%s", i? " " : "", filter_get(i)->name);
+ num += printf("%s%s", i? " " : "", filter_name(i));
}
- printf_or_die("\n");
+ printf("\n");
- FOR_EACH_SUPPORTED_FILTER(i) {
- struct filter *f = (struct filter *)filter_get(i);
+ FOR_EACH_FILTER(i) {
+ const struct lls_command *cmd = FILTER_CMD(i);
+ char *help;
- if (!f->help.short_help)
+ if (!filter_supported(i))
+ continue;
+ help = detailed? lls_long_help(cmd) : lls_short_help(cmd);
+ if (!help)
continue;
- printf_or_die("\nOptions for %s (%s):", f->name,
- f->help.purpose);
- ggo_print_help(&f->help, flags);
+ printf("%s\n", help);
+ free(help);
}
}
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
fn->min_iqs = 0;
}
-/**
- * The init function of the flacdec filter.
- *
- * \param f Pointer to the filter struct to initialize.
- *
- * \sa filter::init.
- */
-void flacdec_filter_init(struct filter *f)
-{
- f->open = flacdec_open;
- f->close = flacdec_close;
- f->pre_select = flacdec_pre_select;
- f->post_select = flacdec_post_select;
- f->execute = flacdec_execute;
-}
+const struct filter lsg_filter_cmd_com_flacdec_user_data = {
+ .open = flacdec_open,
+ .close = flacdec_close,
+ .pre_select = flacdec_pre_select,
+ .post_select = flacdec_post_select,
+ .execute = flacdec_execute,
+};
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Amplify the decoded audio stream"
-
-option "amp" a
-#~~~~~~~~~~~~~
-"amplification value"
-int typestr="number"
-default="32"
-optional
-details="
- The amplification value determines the scaling factor by
- which the amplitude of the audio stream is multiplied. The
- formula for the scaling factor is
-
- factor = 1 + amp / 64.
-
- For example, an amplifiction value of zero results in a
- scaling factor of one while an amplification value of 64
- means to double the volume.
-"
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Dynamically adjust the volume of an audio stream"
-
-option "blocksize" b
-#~~~~~~~~~~~~~~~~~~~
-"adjust block size"
-int typestr="number"
-default="15"
-optional
-details = "
- Larger blocksize means fewer volume adjustments per time unit.
-"
-
-option "aggressiveness" a
-#~~~~~~~~~~~~~~~~~~~~~~~~
- "controls the maximum amount to amplify by"
-int typestr="number"
-default="4"
-optional
-
-option "inertia" i
-#~~~~~~~~~~~~~~~~~
- "how much inertia ramping has"
- int typestr="number"
-default="6"
-optional
-
-option "target-level" t
-#~~~~~~~~~~~~~~~~~~~~~~
-"target signal level (0-32768)"
-int typestr="number"
-default="20000"
-optional
-
-option "damp" d
-#~~~~~~~~~~~~~~
-"if non-zero, scale down after normalizing"
-int typestr="number"
-default="0"
-optional
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Decode an mp3 stream"
-
-include(header.m4)
-
-<qu>
-option "ignore-crc" i
-#~~~~~~~~~~~~~~~~~~~~
-"ignore CRC information in the audio stream."
-flag off
-details="
- This causes frames with CRC errors to be decoded and played
- anyway. This option is not recommended, but since some encoders
- have been known to generate bad CRC information, this option
- is a work-around to play streams from such encoders.
-"
-</qu>
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Delay processing of an audio stream"
-
-option "duration" d
-#~~~~~~~~~~~~~~~~~~
-"prebuffer time"
-int typestr="milliseconds"
-default="200"
-optional
-details="
- Wait that many milliseconds before letting data go through.
- The time interval starts when the first data byte is seen by
- this filter.
-"
-
-option "size" s
-#~~~~~~~~~~~~~~
-"amount of data to prebuffer"
-int typestr="bytes"
-default="0"
-optional
-details="
- Wait until that many data bytes are available in the input buffer.
- The default value of zero means to not prebuffer by size at all.
- If both --duration and --size options are given and non-zero, the
- filter waits until both conditions are met.
-"
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Transform raw audio to a different sample rate"
-
-include(header.m4)
-
-option "converter" C
-#~~~~~~~~~~~~~~~~~~~
-"choose converter type"
-enum typestr = "type"
-values = "best", "medium", "fastest", "zero_order_hold", "linear"
-default = "medium"
-optional
-
-details = "
- best: This is a bandlimited interpolator derived from the
- mathematical sinc function and this is the highest quality
- sinc based converter, providing a worst case Signal-to-Noise
- Ratio (SNR) of 97 decibels (dB) at a bandwidth of 97%.
-
- medium: This is another bandlimited interpolator much like the
- previous one. It has an SNR of 97dB and a bandwidth of 90%. The
- speed of the conversion is much faster than the previous one.
-
- fastest: This is the fastest bandlimited interpolator and
- has an SNR of 97dB and a bandwidth of 80%.
-
- zero_order_hold: A Zero Order Hold converter (interpolated
- value is equal to the last value). The quality is poor but
- the conversion speed is blindlingly fast.
-
- linear: A linear converter. Again the quality is poor, but
- the conversion speed is blindingly fast.
-"
-
-include(channels.m4)
-include(sample_rate.m4)
-include(sample_format.m4)
-
-option "dest-sample-rate" d
-#~~~~~~~~~~~~~~~~~~~~~~~~~~
-"sample rate to convert to"
-int typestr = "rate"
-default = "44100"
-optional
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Synchronize playback between multiple clients."
-
-option "buddy" b
-#~~~~~~~~~~~~~~~
-"host to synchronize with"
-multiple
-string typestr = "url"
-optional
-details = "
- This option may be given multiple times, one per buddy. Each
- value may be given as a host, port pair in either IPv4 or
- IPv6 form, with port being optional. If no port was specified
- the listening port (as specified with --port, see below)
- is used to send the synchronization packet to this buddy.
-"
-
-option "port" p
-#~~~~~~~~~~~~~~
-"UDP port for incoming synchronization packets"
-int typestr = "portnumber"
-default = "29900"
-optional
-details = "
- The sync filter receives incoming synchronization packets on
- this UDP port.
-"
-
-option "timeout" t
-#~~~~~~~~~~~~~~~~~
-"how long to wait for other clients"
-int typestr = "milliseconds"
-default = "2000"
-optional
-details = "
- Once the sync filter receives its first chunk of input, a
- synchronization period of the given number of milliseconds
- begins. Playback is deferred until a synchronization packet
- has been received from each defined buddy, or until the end
- of the period. Buddies which did not send a synchronization
- packet in time are temporarily disabled and are not waited for
- during subsequent synchronization periods. They are re-enabled
- automatically when another synchronization packet arrives.
-"
--- /dev/null
+[suite filter_cmd]
+caption = filters
+[subcommand aacdec]
+ purpose = decode an aac stream
+[subcommand amp]
+ purpose = amplify (scale) a raw audio stream
+ [option amp]
+ short_opt = a
+ summary = amplification value
+ typestr = number
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 32
+ [help]
+ The amplification value determines the scaling factor by which the
+ amplitude of the audio stream is multiplied. The formula for the
+ scaling factor is
+
+ factor = 1 + amp / 64.
+
+ For example, an amplification value of zero results in a scaling factor
+ of one while an amplification value of 64 means to double the volume.
+ [/help]
+[subcommand compress]
+ purpose = dynamically adjust the volume of an audio stream
+ [option blocksize]
+ short_opt = b
+ summary = use blocks of size 2**bits
+ typestr = bits
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 15
+ [help]
+ Larger blocksize means fewer volume adjustments per time unit.
+ [/help]
+ [option aggressiveness]
+ short_opt = a
+ summary = controls the maximum amount to amplify by
+ typestr = bits
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 4
+ [option inertia]
+ short_opt = i
+ summary = how much inertia ramping has
+ typestr = bits
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 6
+ [option target-level]
+ short_opt = t
+ summary = target signal level (0-32768)
+ typestr = level
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 20000
+ [option damp]
+ short_opt = d
+ summary = if non-zero, scale down after normalizing
+ typestr = bits
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 0
+[subcommand fecdec]
+ purpose = decode a (lossy) input stream using forward error correction
+[subcommand flacdec]
+ purpose = decode a flac stream
+[subcommand mp3dec]
+ purpose = decode an mp3 stream
+ [option ignore-crc]
+ short_opt = i
+ summary = ignore CRC information in the audio stream
+ [help]
+ This causes frames with CRC errors to be decoded and played
+ anyway. This option is not recommended, but since some encoders
+ have been known to generate bad CRC information, this option is a
+ work-around to play streams from such encoders.
+ [/help]
+[subcommand oggdec]
+ purpose = decode an ogg/vorbis stream
+[subcommand opusdec]
+ purpose = decode an ogg/opus stream
+[subcommand prebuffer]
+ purpose = delay processing of an audio stream
+ [option duration]
+ short_opt = d
+ summary = length of the prebuffer period
+ typestr = milliseconds
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 200
+ [help]
+ Wait this many milliseconds before letting data go through. The time
+ interval starts when the first data byte is seen in the input queue.
+ [/help]
+ [option size]
+ short_opt = s
+ summary = amount of data to prebuffer
+ typestr = bytes
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 0
+ [help]
+ Wait until this many data bytes are available in the input queue. The
+ default value of zero means to not prebuffer by size. If both
+ --duration and --size are given and non-zero, the prebuffer filter
+ waits until both conditions are met.
+ [/help]
+[subcommand resample]
+ purpose = transform raw audio to a different sample rate
+ [option converter]
+ short_opt = C
+ summary = set conversion algorithm
+ typestr = type
+ arg_info = required_arg
+ arg_type = string
+ default_val = medium
+ [help]
+ best: This is a bandlimited interpolator derived from the mathematical
+ sinc function and this is the highest quality sinc based converter,
+ providing a worst case Signal-to-Noise Ratio (SNR) of 97 decibels
+ (dB) at a bandwidth of 97%.
+
+ medium: This is another bandlimited interpolator much like the previous
+ one. It has an SNR of 97dB and a bandwidth of 90%. The speed of the
+ conversion is much faster than the previous one.
+
+ fastest: This is the fastest bandlimited interpolator and has an SNR
+ of 97dB and a bandwidth of 80%.
+
+ zero_order_hold: A Zero Order Hold converter (interpolated value
+ is equal to the last value). The quality is poor but the conversion
+ speed is blindlingly fast.
+
+ linear: A linear converter. Again the quality is poor, but the
+ conversion speed is blindingly fast.
+ [/help]
+ [option dest-sample-rate]
+ short_opt = d
+ summary = sample rate to convert to
+ typestr = rate
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 44100
+ m4_include(channels.m4)
+ m4_include(sample-rate.m4)
+ m4_include(sample-format.m4)
+[subcommand spxdec]
+ purpose = decode an ogg/speex stream
+[subcommand sync]
+ purpose = synchronize playback between multiple clients
+ [option buddy]
+ short_opt = b
+ summary = client to synchronize with
+ typestr = url
+ arg_info = required_arg
+ arg_type = string
+ flag multiple
+ [help]
+ This option may be given multiple times, one per buddy. Each value
+ may be given as a host, port pair in either IPv4 or IPv6 form, with
+ port being optional. If no port was specified the listening port (as
+ specified with --port, see below) is used to send the synchronization
+ packet to this buddy.
+ [/help]
+ [option port]
+ short_opt = p
+ summary = UDP port for incoming synchronization packets
+ typestr = portnumber
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 29900
+ [help]
+ The sync filter expects incoming synchronization packets on this
+ UDP port.
+ [/help]
+ [option timeout]
+ short_opt = t
+ summary = how long to wait for other clients
+ typestr = milliseconds
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 2000
+ [help]
+ Once the sync filter receives its first chunk of input,
+ a synchronization period of the given number of milliseconds
+ begins. Playback is deferred until a synchronization packet has
+ been received from each defined buddy, or until the end of the
+ period. Buddies which did not send a synchronization packet in time
+ are temporarily disabled and are not waited for during subsequent
+ synchronization periods. They are re-enabled automatically when
+ another synchronization packet arrives.
+ [/help]
+[subcommand wav]
+ purpose = insert a Microsoft wave header into a raw audio stream
+[subcommand wmadec]
+ purpose = decode a wma stream
--- /dev/null
+[option channels]
+ short_opt = c
+ summary = specify number of channels
+ typestr = num
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 2
+ [help]
+ It is only necessary to specify this option for raw audio. If it is
+ not given, the channel count is queried from the parent buffer tree
+ nodes (e.g. the decoder) or the wav header. Only if this query fails,
+ the default value applies.
+ [/help]
--- /dev/null
+[option sample-format]
+ short_opt = f
+ summary = specify sample format
+ typestr = format
+ arg_info = required_arg
+ arg_type = string
+ # TODO: dedup this from enum in para.h.
+ values = {
+ SAMPLE_FORMAT_S8 = "S8",
+ SAMPLE_FORMAT_U8 = "U8",
+ SAMPLE_FORMAT_S16_LE = "S16_LE",
+ SAMPLE_FORMAT_S16_BE = "S16_BE",
+ SAMPLE_FORMAT_U16_LE = "U16_LE",
+ SAMPLE_FORMAT_U16_BE = "U16_BE"
+ }
+ default_val = S16_LE
+ [help]
+ It is only necessary to specify this for raw audio. See the discussion
+ of the --channels option.
+ [/help]
--- /dev/null
+[option sample-rate]
+ short_opt = s
+ summary = do not guess the input sample rate
+ typestr = rate
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 44100
+ [help]
+ It is only necessary to specify this for raw audio. See the discussion
+ of the --channels option.
+ [/help]
#!/usr/bin/env bash
-# filters, writers are called "modules" in this script
+# writers are called "modules" in this script
print_modhelp()
{
local ggo="$1"
--set-package "para_$1" \
< "$ggo"
- if [[ "$target" == 'filter' || "$target" == 'audiod' ]]; then
- for module in $FILTERS; do
- ggo="$GGO_DIR/${module}_filter.ggo"
- [[ ! -f "$ggo" ]] && continue
- printf "\nOptions for the $module filter"
- print_modhelp "$ggo"
- done
- fi
if [[ "$target" == 'write' || "$target" == 'audiod' ]]; then
for module in $WRITERS; do
ggo="$GGO_DIR/${module}_write.ggo"
#include <mad.h>
#include <regex.h>
+#include <lopsub.h>
+#include "filter_cmd.lsg.h"
#include "para.h"
-#include "mp3dec_filter.cmdline.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
static void mp3dec_open(struct filter_node *fn)
{
struct private_mp3dec_data *pmd = para_calloc(sizeof(*pmd));
- struct mp3dec_filter_args_info *mp3_conf = fn->conf;
fn->private_data = pmd;
mad_stream_init(&pmd->stream);
mad_frame_init(&pmd->frame);
mad_synth_init(&pmd->synth);
- if (mp3_conf->ignore_crc_given)
+ if (FILTER_CMD_OPT_GIVEN(MP3DEC, IGNORE_CRC, fn->lpr))
mad_stream_options(&pmd->stream, MAD_OPTION_IGNORECRC);
}
-static int mp3dec_parse_config(int argc, char **argv, void **config)
-{
- struct mp3dec_filter_args_info *conf = para_calloc(sizeof(*conf));
-
- mp3dec_filter_cmdline_parser(argc, argv, conf);
- *config = conf;
- return 1;
-}
-
static int mp3dec_execute(struct btr_node *btrn, const char *cmd, char **result)
{
struct filter_node *fn = btr_context(btrn);
return decoder_execute(cmd, pmd->sample_rate, pmd->channels, result);
}
-static void mp3dec_free_config(void *conf)
-{
- mp3dec_filter_cmdline_parser_free(conf);
-}
-/**
- * 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)
-{
- struct mp3dec_filter_args_info dummy;
-
- mp3dec_filter_cmdline_parser_init(&dummy);
- f->open = mp3dec_open;
- f->close = mp3dec_close;
- f->parse_config = mp3dec_parse_config;
- f->free_config = mp3dec_free_config;
- f->pre_select = generic_filter_pre_select;
- f->post_select = mp3dec_post_select;
- f->execute = mp3dec_execute;
- f->help = (struct ggo_help)DEFINE_GGO_HELP(mp3dec_filter);
-}
+const struct filter lsg_filter_cmd_com_mp3dec_user_data = {
+ .open = mp3dec_open,
+ .close = mp3dec_close,
+ .pre_select = generic_filter_pre_select,
+ .post_select = mp3dec_post_select,
+ .execute = mp3dec_execute,
+};
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
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->pre_select = ogg_pre_select;
- f->post_select = ogg_post_select;
- f->execute = oggdec_execute;
-}
+const struct filter lsg_filter_cmd_com_oggdec_user_data = {
+ .open = ogg_open,
+ .close = ogg_close,
+ .pre_select = ogg_pre_select,
+ .post_select = ogg_post_select,
+ .execute = oggdec_execute
+};
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
return sched_min_delay(s);
}
-/**
- * The init function of the opusdec filter.
- *
- * \param f Pointer to the filter struct to initialize.
- *
- * \sa filter::init.
- */
-void opusdec_filter_init(struct filter *f)
-{
- f->open = opusdec_open;
- f->close = opusdec_close;
- f->pre_select = opusdec_pre_select;
- f->post_select = opusdec_post_select;
- f->execute = opusdec_execute;
-}
+const struct filter lsg_filter_cmd_com_opusdec_user_data = {
+ .open = opusdec_open,
+ .close = opusdec_close,
+ .pre_select = opusdec_pre_select,
+ .post_select = opusdec_post_select,
+ .execute = opusdec_execute,
+};
static int eof_cleanup(struct play_task *pt)
{
struct writer *w = writers + DEFAULT_WRITER;
- const struct filter *decoder = filter_get(pt->fn.filter_num);
+ const struct filter *decoder;
int ret;
ret = get_playback_error(pt);
w->free_config(pt->wn.conf);
memset(&pt->wn, 0, sizeof(struct writer_node));
+ decoder = filter_get(pt->fn.filter_num);
task_reap(&pt->fn.task);
if (decoder->close)
decoder->close(&pt->fn);
char *tmp, buf[20];
int ret;
const struct filter *decoder;
+ static struct lls_parse_result *filter_lpr;
btr_remove_node(&pt->rn.btrn);
if (!pt->rn.receiver || pt->next_file != pt->current_file) {
/* set up decoding filter */
af = audio_format_name(pt->audio_format_num);
tmp = make_message("%sdec", af);
- PARA_INFO_LOG("decoder: %s\n", tmp);
- ret = check_filter_arg(tmp, &pt->fn.conf);
+ ret = filter_setup(tmp, &pt->fn.conf, &filter_lpr);
freep(&tmp);
if (ret < 0)
goto fail;
pt->fn.filter_num = ret;
+ pt->fn.lpr = filter_lpr;
decoder = filter_get(ret);
pt->fn.btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = decoder->name, .parent = pt->rn.btrn,
- .handler = decoder->execute, .context = &pt->fn));
+ EMBRACE(.name = filter_name(pt->fn.filter_num),
+ .parent = pt->rn.btrn, .handler = decoder->execute,
+ .context = &pt->fn));
if (decoder->open)
decoder->open(&pt->fn);
PARA_INFO_LOG("buffer tree:\n");
/* needed this early to make help work */
recv_init();
- filter_init();
writer_init();
sched.default_timeout.tv_sec = 5;
/** \file prebuffer_filter.c Paraslash's prebuffering filter. */
#include <regex.h>
+#include <lopsub.h>
#include "para.h"
-#include "prebuffer_filter.cmdline.h"
+#include "filter_cmd.lsg.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
/** Data specific to the prebuffer filter. */
struct private_prebuffer_data {
- /** The configuration data for this instance of the filter. */
- struct prebuffer_filter_args_info *conf;
/** Number of bytes prebuffered or -1 if no longer prebuffering. */
int prebuffered;
/** End of prebuffering period. */
struct btr_node *btrn = fn->btrn;
size_t iqs = btr_get_input_queue_size(btrn);
struct private_prebuffer_data *ppd = fn->private_data;
- struct prebuffer_filter_args_info *conf = ppd->conf;
struct timeval diff;
if (iqs == 0)
return;
if (ppd->barrier.tv_sec == 0) {
+ uint32_t duration = FILTER_CMD_OPT_UINT32_VAL(PREBUFFER,
+ DURATION, fn->lpr);
struct timeval tv;
- PARA_INFO_LOG("prebuffer period %dms\n",
- conf->duration_arg);
- ms2tv(conf->duration_arg, &tv);
+ PARA_INFO_LOG("prebuffer period %" PRIu32 "ms\n", duration);
+ ms2tv(duration, &tv);
tv_add(&tv, now, &ppd->barrier);
}
if (tv_diff(&ppd->barrier, now, &diff) < 0)
struct btr_node *btrn = fn->btrn;
size_t iqs = btr_get_input_queue_size(btrn);
struct private_prebuffer_data *ppd = fn->private_data;
- struct prebuffer_filter_args_info *conf = ppd->conf;
+ uint32_t size = FILTER_CMD_OPT_UINT32_VAL(PREBUFFER, SIZE, fn->lpr);
if (ppd->barrier.tv_sec == 0)
return 0;
if (tv_diff(now, &ppd->barrier, NULL) < 0)
return 0;
- if (iqs < conf->size_arg)
+ if (iqs < size)
return 0;
btr_splice_out_node(&fn->btrn);
return -E_PREBUFFER_SUCCESS;
}
-static int prebuffer_parse_config(int argc, char **argv, void **config)
-{
- struct prebuffer_filter_args_info *conf = para_calloc(sizeof(*conf));
- int ret;
-
- prebuffer_filter_cmdline_parser(argc, argv, conf);
- ret = -ERRNO_TO_PARA_ERROR(EINVAL);
- if (conf->duration_arg < 0)
- goto err;
- if (conf->size_arg < 0)
- goto err;
- PARA_NOTICE_LOG("prebuffering %ims, %i bytes\n", conf->duration_arg,
- conf->size_arg);
- *config = conf;
- return 1;
-err:
- free(conf);
- return ret;
-}
-
static void prebuffer_open(struct filter_node *fn)
{
struct private_prebuffer_data *ppd = para_calloc(sizeof(*ppd));
-
- ppd->conf = fn->conf;
fn->private_data = ppd;
}
-static void prebuffer_free_config(void *conf)
-{
- prebuffer_filter_cmdline_parser_free(conf);
-}
-
-/**
- * The init function of the prebuffer filter.
- *
- * \param f Pointer to the struct to initialize.
- */
-void prebuffer_filter_init(struct filter *f)
-{
- struct prebuffer_filter_args_info dummy;
-
- prebuffer_filter_cmdline_parser_init(&dummy);
- f->open = prebuffer_open;
- f->close = prebuffer_close;
- f->parse_config = prebuffer_parse_config;
- f->free_config = prebuffer_free_config;
- f->pre_select = prebuffer_pre_select;
- f->post_select = prebuffer_post_select;
- f->help = (struct ggo_help)DEFINE_GGO_HELP(prebuffer_filter);
-}
+const struct filter lsg_filter_cmd_com_prebuffer_user_data = {
+ .open = prebuffer_open,
+ .close = prebuffer_close,
+ .pre_select = prebuffer_pre_select,
+ .post_select = prebuffer_post_select,
+};
#include <regex.h>
#include <samplerate.h>
+#include <lopsub.h>
-#include "resample_filter.cmdline.h"
+#include "filter_cmd.lsg.h"
#include "para.h"
#include "error.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
#include "check_wav.h"
+#define U32_OPTVAL(_opt, _lpr) (FILTER_CMD_OPT_UINT32_VAL(RESAMPLE, _opt, _lpr))
+#define OPT_GIVEN(_opt, _lpr) (FILTER_CMD_OPT_GIVEN(RESAMPLE, _opt, _lpr))
+
+/* effective values, may differ from config arg */
struct resample_context {
- int channels;
+ uint32_t channels;
int source_sample_rate;
float ratio;
SRC_STATE *src_state;
{
struct filter_node *fn = btr_context(btrn);
struct resample_context *ctx = fn->private_data;
- struct resample_filter_args_info *conf = fn->conf;
-
- return decoder_execute(cmd, conf->dest_sample_rate_arg, ctx->channels,
- result);
+ uint32_t dsr = U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr);
+ return decoder_execute(cmd, dsr, ctx->channels, result);
}
static void resample_close(struct filter_node *fn)
static void resample_open(struct filter_node *fn)
{
struct resample_context *ctx = para_calloc(sizeof(*ctx));
- struct resample_filter_args_info *conf = fn->conf;
struct btr_node *btrn = fn->btrn;
struct wav_params wp;
fn->private_data = ctx;
fn->min_iqs = 2;
- COPY_WAV_PARMS(&wp, conf);
+ LLS_COPY_WAV_PARMS(&wp, LSG_FILTER_CMD_RESAMPLE, fn->lpr);
ctx->cwc = check_wav_init(btr_parent(btrn), btrn, &wp, NULL);
btr_log_tree(btr_parent(btr_parent(btrn)), LL_INFO);
}
{
int ret;
struct resample_context *ctx = fn->private_data;
- struct resample_filter_args_info *conf = fn->conf;
struct btr_node *btrn = fn->btrn;
+ struct lls_parse_result *lpr = fn->lpr;
- ctx->channels = conf->channels_arg;
- if (!conf->channels_given) {
+ ctx->channels = U32_OPTVAL(CHANNELS, lpr);
+ if (!OPT_GIVEN(CHANNELS, lpr)) {
ret = get_btr_val("channels", btrn);
if (ret >= 0)
ctx->channels = ret;
}
-
- ctx->source_sample_rate = conf->sample_rate_arg;
- if (!conf->sample_rate_given) {
+ ctx->source_sample_rate = U32_OPTVAL(SAMPLE_RATE, lpr);
+ if (!OPT_GIVEN(SAMPLE_RATE, lpr)) {
ret = get_btr_val("sample_rate", btrn);
if (ret >= 0)
ctx->source_sample_rate = ret;
/* reject all sample formats except 16 bit signed, little endian */
ret = get_btr_val("sample_format", btrn);
if (ret >= 0 && ret != SF_S16_LE) {
- const char *sample_formats[] = {SAMPLE_FORMATS};
+ const char * const sample_formats[] = {SAMPLE_FORMATS};
PARA_ERROR_LOG("unsupported sample format: %s\n",
sample_formats[ret]);
return -ERRNO_TO_PARA_ERROR(EINVAL);
}
- ctx->ratio = (float)conf->dest_sample_rate_arg / ctx->source_sample_rate;
+ ctx->ratio = U32_OPTVAL(DEST_SAMPLE_RATE, lpr)
+ / (float)ctx->source_sample_rate;
return 1;
}
static int resample_init(struct filter_node *fn)
{
- int ret, converter;
+ int ret, converter = *(int *)fn->conf;
struct resample_context *ctx = fn->private_data;
- struct resample_filter_args_info *conf = fn->conf;
ret = resample_set_params(fn);
if (ret < 0)
return ret;
- switch (conf->converter_arg) {
- case converter_arg_best:
- converter = SRC_SINC_BEST_QUALITY;
- break;
- case converter_arg_medium:
- converter = SRC_SINC_MEDIUM_QUALITY;
- break;
- case converter_arg_fastest:
- converter = SRC_SINC_FASTEST;
- break;
- case converter_arg_zero_order_hold:
- converter = SRC_ZERO_ORDER_HOLD;
- break;
- case converter_arg_linear:
- converter = SRC_LINEAR;
- break;
- default:
- assert(0);
- }
- ctx->src_state = src_new(converter, conf->channels_arg, &ret);
+ ctx->src_state = src_new(converter, U32_OPTVAL(CHANNELS, fn->lpr), &ret);
if (!ctx->src_state) {
PARA_ERROR_LOG("%s\n", src_strerror(ret));
return -E_LIBSAMPLERATE;
int ret;
struct filter_node *fn = context;
struct resample_context *ctx = fn->private_data;
- struct resample_filter_args_info *conf = fn->conf;
struct btr_node *btrn = fn->btrn;
int16_t *in, *out;
size_t in_bytes, num_frames;
if (ret <= 0)
goto out;
}
- if (ctx->source_sample_rate == conf->dest_sample_rate_arg) {
+ if (ctx->source_sample_rate == U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr)) {
/*
* No resampling necessary. We do not splice ourselves out
* though, since our children might want to ask us through the
return ret;
}
-static int resample_parse_config(int argc, char **argv, void **config)
+static void *resample_setup(const struct lls_parse_result *lpr)
{
- int ret, val, given;
- struct resample_filter_args_info *conf = para_calloc(sizeof(*conf));
-
- resample_filter_cmdline_parser(argc, argv, conf);
+ int given, *converter;
+ const char *converter_arg;
+ uint32_t u32;
/* sanity checks */
- ret = -ERRNO_TO_PARA_ERROR(EINVAL);
- val = conf->channels_arg;
- given = conf->channels_given;
- if (val < 0 || (val == 0 && given))
- goto err;
- val = conf->sample_rate_arg;
- given = conf->sample_rate_given;
- if (val < 0 || (val == 0 && given))
- goto err;
- val = conf->dest_sample_rate_arg;
- given = conf->dest_sample_rate_given;
- if (val < 0 || (val == 0 && given))
- goto err;
- *config = conf;
- return 1;
-err:
- free(conf);
- return ret;
+ u32 = U32_OPTVAL(CHANNELS, lpr);
+ given = OPT_GIVEN(CHANNELS, lpr);
+ if (u32 == 0 && given) {
+ PARA_EMERG_LOG("fatal: zero channels?!\n");
+ exit(EXIT_FAILURE);
+ }
+ u32 = U32_OPTVAL(SAMPLE_RATE, lpr);
+ given = OPT_GIVEN(SAMPLE_RATE, lpr);
+ if (u32 == 0 && given) {
+ PARA_EMERG_LOG("fatal: input sample rate can not be 0\n");
+ exit(EXIT_FAILURE);
+ }
+ u32 = U32_OPTVAL(DEST_SAMPLE_RATE, lpr);
+ given = OPT_GIVEN(DEST_SAMPLE_RATE, lpr);
+ if (u32 == 0 && given) {
+ PARA_EMERG_LOG("fatal: destination sample rate can not be 0\n");
+ exit(EXIT_FAILURE);
+ }
+ converter = para_malloc(sizeof(int));
+ converter_arg = FILTER_CMD_OPT_STRING_VAL(RESAMPLE, CONVERTER, lpr);
+ if (!strcmp(converter_arg, "best"))
+ *converter = SRC_SINC_BEST_QUALITY;
+ else if (!strcmp(converter_arg, "medium"))
+ *converter = SRC_SINC_MEDIUM_QUALITY;
+ else if (!strcmp(converter_arg, "fastest"))
+ *converter = SRC_SINC_FASTEST;
+ else if (!strcmp(converter_arg, "zero_order_hold"))
+ *converter = SRC_ZERO_ORDER_HOLD;
+ else if (!strcmp(converter_arg, "linear"))
+ *converter = SRC_LINEAR;
+ else {
+ PARA_EMERG_LOG("invalid converter type: %s\n", converter_arg);
+ exit(EXIT_FAILURE);
+ }
+ return converter;
}
-static void resample_free_config(void *conf)
+static void resample_teardown(__a_unused const struct lls_parse_result *lpr,
+ void *conf)
{
- if (!conf)
- return;
- resample_filter_cmdline_parser_free(conf);
free(conf);
}
-/**
- * The init function of the resample filter.
- *
- * \param f Structure to initialize.
- */
-void resample_filter_init(struct filter *f)
-{
- struct resample_filter_args_info dummy;
-
- resample_filter_cmdline_parser_init(&dummy);
- f->close = resample_close;
- f->open = resample_open;
- f->pre_select = resample_pre_select;
- f->post_select = resample_post_select;
- f->parse_config = resample_parse_config;
- f->free_config = resample_free_config;
- f->execute = resample_execute;
- f->help = (struct ggo_help)DEFINE_GGO_HELP(resample_filter);
-}
+const struct filter lsg_filter_cmd_com_resample_user_data = {
+ .setup = resample_setup,
+ .open = resample_open,
+ .pre_select = resample_pre_select,
+ .post_select = resample_post_select,
+ .close = resample_close,
+ .teardown = resample_teardown,
+ .execute = resample_execute
+};
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
return ret;
}
-/**
- * The init function of the ogg/speex decoder.
- *
- * \param f Its fields are filled in by the function.
- */
-void spxdec_filter_init(struct filter *f)
-{
- f->open = spxdec_open;
- f->close = speexdec_close;
- f->pre_select = generic_filter_pre_select;
- f->post_select = speexdec_post_select;
- f->execute = speexdec_execute;
-}
+const struct filter lsg_filter_cmd_com_spxdec_user_data = {
+ .open = spxdec_open,
+ .close = speexdec_close,
+ .pre_select = generic_filter_pre_select,
+ .post_select = speexdec_post_select,
+ .execute = speexdec_execute,
+};
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
+#include <lopsub.h>
+#include "filter_cmd.lsg.h"
#include "para.h"
-#include "sync_filter.cmdline.h"
#include "list.h"
#include "net.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
struct list_head node;
};
-/* Allocated in ->open() */
+/* Allocated in ->open(), stored in fn->private_data */
struct sync_filter_context {
int listen_fd;
struct list_head buddies;
bool ping_sent;
};
-/* Allocated and freed in ->parse_config() and ->free_config(). */
-struct sync_filter_config {
- struct sync_filter_args_info *conf;
- struct sync_buddy_info *buddy_info;
-};
-
#define FOR_EACH_BUDDY(_buddy, _list) \
list_for_each_entry(_buddy, _list, node)
#define FOR_EACH_BUDDY_SAFE(_buddy, _tmp_buddy, _list) \
fn->private_data = NULL;
}
-static void sync_free_config(void *conf)
+static void sync_teardown(const struct lls_parse_result *lpr, void *conf)
{
- struct sync_filter_config *sfc = conf;
- int i;
+ struct sync_buddy_info *sbi = conf;
+ int i, num_buddies = FILTER_CMD_OPT_GIVEN(SYNC, BUDDY, lpr);
- for (i = 0; i < sfc->conf->buddy_given; i++) {
- free(sfc->buddy_info[i].host);
- freeaddrinfo(sfc->buddy_info[i].ai);
+ for (i = 0; i < num_buddies; i++) {
+ free(sbi[i].host);
+ freeaddrinfo(sbi[i].ai);
}
- sync_filter_cmdline_parser_free(sfc->conf);
- free(sfc);
+ free(sbi);
}
static void sync_open(struct filter_node *fn)
{
int i, ret;
- struct sync_filter_config *sfc = fn->conf;
struct sync_buddy *buddy;
struct sync_filter_context *ctx;
-
- assert(sfc);
+ struct sync_buddy_info *sbi = fn->conf;
+ uint32_t port = FILTER_CMD_OPT_UINT32_VAL(SYNC, PORT, fn->lpr);
+ unsigned buddy_given;
+ const struct lls_opt_result *r_b;
ctx = fn->private_data = para_calloc(sizeof(*ctx));
INIT_LIST_HEAD(&ctx->buddies);
- ctx->listen_fd = -1;
/* create socket to listen for incoming packets */
ret = makesock(
IPPROTO_UDP,
true /* passive */,
NULL /* no host required */,
- sfc->conf->port_arg,
+ port,
NULL /* no flowopts */
);
if (ret < 0) {
- PARA_ERROR_LOG("could not create UDP listening socket %d\n",
- sfc->conf->port_arg);
+ PARA_ERROR_LOG("could not create UDP listening socket %u\n",
+ port);
return;
}
ctx->listen_fd = ret;
PARA_INFO_LOG("listening on fd %d\n", ctx->listen_fd);
- for (i = 0; i < sfc->conf->buddy_given; i++) {
- struct sync_buddy_info *sbi = sfc->buddy_info + i;
- const char *url = sfc->conf->buddy_arg[i];
+ r_b = FILTER_CMD_OPT_RESULT(SYNC, BUDDY, fn->lpr);
+ buddy_given = lls_opt_given(r_b);
+ for (i = 0; i < buddy_given; i++) {
int fd;
+ const char *url = lls_string_val(i, r_b);
/* make buddy udp socket from address info */
assert(sbi->ai);
ret = makesock_addrinfo(
IPPROTO_UDP,
false /* not passive */,
- sbi->ai,
+ sbi[i].ai,
NULL /* no flowopts */
);
if (ret < 0) {
}
buddy = para_malloc(sizeof(*buddy));
buddy->fd = fd;
- buddy->sbi = sbi;
+ buddy->sbi = sbi + i;
buddy->ping_received = false;
para_list_add(&buddy->node, &ctx->buddies);
}
/*
- * At parse config time, we build an array of struct sync_buddy_info with one
- * entry for each buddy given in the arguments. This array is not affected by
- * sync_close(), so information stored there can be used for multiple instances
- * (para_audiod). We store the resolved url and the ->disabled bit in this
- * array.
+ * Build an array of struct sync_buddy_info with one entry for each buddy given
+ * in the arguments. This array is not affected by sync_close(), so information
+ * stored there can be used for multiple instances (para_audiod). We store the
+ * resolved url and the ->disabled bit in this array.
*/
-static int sync_parse_config(int argc, char **argv, void **result)
+static void *sync_setup(const struct lls_parse_result *lpr)
{
- int i, ret, n;
- struct sync_filter_config *sfc;
- struct sync_filter_args_info *conf = para_malloc(sizeof(*conf));
-
- sync_filter_cmdline_parser(argc, argv, conf); /* exits on error */
- sfc = para_calloc(sizeof(*sfc));
- sfc->conf = conf;
- n = conf->buddy_given;
- sfc->buddy_info = para_malloc((n + 1) * sizeof(*sfc->buddy_info));
- PARA_INFO_LOG("initializing buddy info array of length %d\n", n);
+ int i, ret;
+ unsigned n;
+ struct sync_buddy_info *sbi;
+ const struct lls_opt_result *r_b;
+
+ r_b = FILTER_CMD_OPT_RESULT(SYNC, BUDDY, lpr);
+ n = lls_opt_given(r_b);
+ sbi = para_malloc(n * sizeof(*sbi));
+ PARA_INFO_LOG("initializing buddy info array of length %u\n", n);
for (i = 0; i < n; i++) {
- const char *url = conf->buddy_arg[i];
+ const char *url = lls_string_val(i, r_b);
size_t len = strlen(url);
char *host = para_malloc(len + 1);
int port;
struct addrinfo *ai;
- struct sync_buddy_info *sbi = sfc->buddy_info + i;
if (!parse_url(url, host, len, &port)) {
- free(host);
PARA_ERROR_LOG("could not parse url %s\n", url);
- ret = -ERRNO_TO_PARA_ERROR(EINVAL);
- goto fail;
+ exit(EXIT_FAILURE);
}
if (port < 0)
- port = conf->port_arg;
+ port = FILTER_CMD_OPT_UINT32_VAL(SYNC, PORT, lpr);
ret = lookup_address(IPPROTO_UDP, false /* not passive */,
host, port, &ai);
if (ret < 0) {
- PARA_ERROR_LOG("host lookup failure for %s\n", url);
- free(host);
- goto fail;
+ PARA_ERROR_LOG("host lookup failure for %s: %s\n",
+ url, para_strerror(-ret));
+ exit(EXIT_FAILURE);
}
- sbi->url = url;
- sbi->host = host;
- sbi->port = port;
- sbi->ai = ai;
- sbi->disabled = false;
+ sbi[i].url = url;
+ sbi[i].host = host;
+ sbi[i].port = port;
+ sbi[i].ai = ai;
+ sbi[i].disabled = false;
PARA_DEBUG_LOG("buddy #%d: %s\n", i, url);
}
- *result = sfc;
- return 1;
-fail:
- assert(ret < 0);
- PARA_ERROR_LOG("%s\n", para_strerror(-ret));
- sync_free_config(sfc);
- return ret;
+ return sbi;
}
/*
}
static void sync_set_timeout(struct sync_filter_context *ctx,
- struct sync_filter_config *sfc)
+ struct lls_parse_result *lpr)
{
+ uint32_t ms = FILTER_CMD_OPT_UINT32_VAL(SYNC, TIMEOUT, lpr);
struct timeval to;
- ms2tv(sfc->conf->timeout_arg, &to);
+ ms2tv(ms, &to);
tv_add(now, &to, &ctx->timeout);
}
int ret;
struct filter_node *fn = context;
struct sync_filter_context *ctx = fn->private_data;
- struct sync_filter_config *sfc = fn->conf;
if (list_empty(&ctx->buddies))
return sched_min_delay(s);
if (ret == 0)
return;
if (ctx->timeout.tv_sec == 0) { /* must ping buddies */
- sync_set_timeout(ctx, sfc);
+ sync_set_timeout(ctx, fn->lpr);
return sched_min_delay(s);
}
if (sync_complete(ctx)) /* push down what we have */
int ret;
struct filter_node *fn = context;
struct sync_filter_context *ctx = fn->private_data;
- struct sync_filter_config *sfc = fn->conf;
struct sync_buddy *buddy, *tmp;
if (list_empty(&ctx->buddies))
if (ret == 0)
return 0;
if (ctx->timeout.tv_sec == 0)
- sync_set_timeout(ctx, sfc);
+ sync_set_timeout(ctx, fn->lpr);
else {
if (tv_diff(&ctx->timeout, now, NULL) < 0) {
sync_disable_active_buddies(ctx);
return ret;
}
-/**
- * The synchronization filter.
- *
- * \param f Pointer to the struct to initialize.
- */
-void sync_filter_init(struct filter *f)
-{
- struct sync_filter_args_info dummy;
-
- sync_filter_cmdline_parser_init(&dummy);
- f->open = sync_open;
- f->close = sync_close;
- f->pre_select = sync_pre_select;
- f->post_select = sync_post_select;
- f->parse_config = sync_parse_config;
- f->free_config = sync_free_config;
- f->help = (struct ggo_help)DEFINE_GGO_HELP(sync_filter);
-}
+const struct filter lsg_filter_cmd_com_sync_user_data = {
+ .setup = sync_setup,
+ .open = sync_open,
+ .pre_select = sync_pre_select,
+ .post_select = sync_post_select,
+ .close = sync_close,
+ .teardown = sync_teardown
+};
regex="$rfw_regex"
test_expect_success 'para_recv: receiver options' "grep_man 'RECEIVERS' recv"
-test_expect_success 'para_filter: filter options' "grep_man '$regex' filter"
+test_expect_success 'para_filter: filter options' "grep_man 'FILTERS' filter"
test_expect_success 'para_write: writer options' "grep_man '$regex' write"
test_require_objects "audiod"
if [[ -n "$result" ]]; then
test_expect_success 'para_audiod: receivers' \
"grep_man 'RECEIVERS' audiod"
test_expect_success 'para_audiod: filters' \
- "grep_man 'Options for the compress filter' audiod"
+ "grep_man 'FILTERS' audiod"
test_expect_success 'para_audiod: writers' \
"grep_man 'Options for the file writer' audiod"
fi
#include "error.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "string.h"
return ret;
}
-/**
- * The init function of the wav filter.
- *
- * \param f Structure to initialize.
- */
-void wav_filter_init(struct filter *f)
-{
- f->close = wav_close;
- f->open = wav_open;
- f->pre_select = wav_pre_select;
- f->post_select = wav_post_select;
-}
+const struct filter lsg_filter_cmd_com_wav_user_data = {
+ .close = wav_close,
+ .open = wav_open,
+ .pre_select = wav_pre_select,
+ .post_select = wav_post_select,
+};
#include "para.h"
#include "error.h"
#include "list.h"
-#include "ggo.h"
#include "string.h"
#include "sched.h"
#include "buffer_tree.h"
fn->min_iqs = 4096;
}
-/**
- * The init function of the wma decoder.
- *
- * \param f Its fields are filled in by the function.
- */
-void wmadec_filter_init(struct filter *f)
-{
- f->open = wmadec_open;
- f->close = wmadec_close;
- f->execute = wmadec_execute;
- f->pre_select = generic_filter_pre_select;
- f->post_select = wmadec_post_select;
-}
+const struct filter lsg_filter_cmd_com_wmadec_user_data = {
+ .open = wmadec_open,
+ .close = wmadec_close,
+ .execute = wmadec_execute,
+ .pre_select = generic_filter_pre_select,
+ .post_select = wmadec_post_select,
+};