ggo_descriptions_declared := @ggo_descriptions_declared@
executables := @executables@
-writers := @writers@
recv_objs := @recv_objs@
filter_objs := @filter_objs@
unconverted_executables := $(filter-out $(converted_executables), $(executables))
audioc_objs += audioc.lsg.o
-audiod_objs += $(addsuffix _cmd.lsg.o, recv filter audiod) client.lsg.o
+audiod_objs += $(addsuffix _cmd.lsg.o, recv filter audiod write) client.lsg.o
client_objs += client.lsg.o
fade_objs += fade.lsg.o
filter_objs += filter_cmd.lsg.o
-play_objs += $(addsuffix _cmd.lsg.o, recv filter play) play.lsg.o
+play_objs += $(addsuffix _cmd.lsg.o, recv filter play write) play.lsg.o
recv_objs += recv_cmd.lsg.o
server_objs += server_cmd.lsg.o
+write_objs += write_cmd.lsg.o
m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(unconverted_executables)))
m4_lls_deps := \
play_cmd \
recv_cmd \
filter_cmd \
+ write_cmd \
$(converted_executables)
m4_lls_deps := $(addprefix $(lls_suite_dir)/, $(addsuffix .m4d, $(m4_lls_deps)))
endif
audiod_command_lists := $(addprefix $(lls_suite_dir)/, \
- $(addsuffix _cmd.lsg.man, audiod recv filter))
+ $(addsuffix _cmd.lsg.man, audiod recv filter write))
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
+write_command_lists := $(lls_suite_dir)/write_cmd.lsg.man
$(man_dir)/para_server.1: $(server_command_lists)
$(man_dir)/para_filter.1: $(filter_command_lists)
+$(man_dir)/para_write.1: $(write_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_write.1: man_util_command_lists := $(write_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_play \
para_recv \
para_server \
+para_write \
: LDFLAGS += $(lopsub_ldflags)
para_server \
#include <regex.h>
#include <sys/types.h>
#include <alsa/asoundlib.h>
+#include <lopsub.h>
+#include "write_cmd.lsg.h"
#include "para.h"
#include "fd.h"
#include "string.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "write.h"
-#include "write_common.h"
-#include "alsa_write.cmdline.h"
#include "error.h"
/** Data specific to the alsa writer. */
}
/* Install PCM software and hardware configuration. */
-static int alsa_init(struct private_alsa_write_data *pad,
- struct alsa_write_args_info *conf)
+static int alsa_init(struct writer_node *wn)
{
+ struct private_alsa_write_data *pad = wn->private_data;
snd_pcm_hw_params_t *hwparams = NULL;
snd_pcm_sw_params_t *swparams = NULL;
snd_pcm_uframes_t start_threshold, stop_threshold;
snd_pcm_uframes_t buffer_size, period_size;
snd_output_t *output_log;
int ret;
- const char *msg;
+ const char *msg, *dev = WRITE_CMD_OPT_STRING_VAL(ALSA, DEVICE, wn->lpr);
unsigned period_time;
- PARA_INFO_LOG("opening %s\n", conf->device_arg);
+ PARA_INFO_LOG("opening %s\n", dev);
msg = "unable to open pcm";
- ret = snd_pcm_open(&pad->handle, conf->device_arg,
- SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ ret = snd_pcm_open(&pad->handle, dev, SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK);
if (ret < 0)
goto fail;
ret = snd_pcm_hw_params_malloc(&hwparams);
if (ret < 0)
goto fail;
/* alsa wants microseconds */
- pad->buffer_time = conf->buffer_time_arg * 1000;
+ pad->buffer_time = 1000U * WRITE_CMD_OPT_UINT32_VAL(ALSA, BUFFER_TIME,
+ wn->lpr);
msg = "could not set buffer time";
ret = snd_pcm_hw_params_set_buffer_time_near(pad->handle, hwparams,
&pad->buffer_time, NULL);
if (bytes == 0) /* no data available */
return 0;
- pad = para_calloc(sizeof(*pad));
+ pad = wn->private_data = para_calloc(sizeof(*pad));
get_btr_sample_rate(btrn, &val);
pad->sample_rate = val;
get_btr_channels(btrn, &val);
PARA_INFO_LOG("%u channel(s), %uHz\n", pad->channels,
pad->sample_rate);
- ret = alsa_init(pad, wn->conf);
+ ret = alsa_init(wn);
if (ret < 0) {
- free(pad);
+ free(wn->private_data);
+ wn->private_data = NULL;
goto err;
}
- wn->private_data = pad;
wn->min_iqs = pad->bytes_per_frame;
goto again;
}
return ret;
}
-__malloc static void *alsa_parse_config_or_die(int argc, char **argv)
-{
- struct alsa_write_args_info *conf = para_calloc(sizeof(*conf));
-
- /* exits on errors */
- alsa_write_cmdline_parser(argc, argv, conf);
- return conf;
-}
-
-static void alsa_free_config(void *conf)
-{
- alsa_write_cmdline_parser_free(conf);
-}
-
-/**
- * The init function of the alsa writer.
- *
- * \param w Pointer to the writer to initialize.
- *
- * \sa struct \ref writer.
- */
-void alsa_write_init(struct writer *w)
-{
- struct alsa_write_args_info dummy;
+struct writer lsg_write_cmd_com_alsa_user_data = {
- alsa_write_cmdline_parser_init(&dummy);
- w->close = alsa_close;
- w->pre_select = alsa_write_pre_select;
- w->post_select = alsa_write_post_select;
- w->parse_config_or_die = alsa_parse_config_or_die;
- w->free_config = alsa_free_config;
- w->help = (struct ggo_help)DEFINE_GGO_HELP(alsa_write);
- alsa_write_cmdline_parser_free(&dummy);
-}
+ .pre_select = alsa_write_pre_select,
+ .post_select = alsa_write_post_select,
+ .close = alsa_close,
+};
#include <pthread.h>
#include <ao/ao.h>
#include <regex.h>
+#include <lopsub.h>
+#include "write_cmd.lsg.h"
#include "para.h"
#include "fd.h"
#include "string.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "write.h"
-#include "write_common.h"
-#include "ao_write.cmdline.h"
#include "error.h"
struct private_aow_data {
ao_close(pawd->dev);
free(pawd);
wn->private_data = NULL;
+ ao_shutdown();
}
static void aow_pre_select(struct sched *s, void *context)
return -E_AO_OPEN_LIVE;
}
+static void aow_show_drivers(void)
+{
+ int i, j, num_drivers;
+ ao_info **driver_list;
+
+ PARA_DEBUG_LOG("libao drivers available on this host:\n");
+ PARA_DEBUG_LOG("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
+
+ driver_list = ao_driver_info_list(&num_drivers);
+
+ for (i = 0; i < num_drivers; i++) {
+ ao_info *info = driver_list[i];
+ char *keys = NULL, *tmp = NULL;
+
+ if (info->type == AO_TYPE_FILE)
+ continue;
+ PARA_DEBUG_LOG("%s: %s", info->short_name, info->name);
+ PARA_DEBUG_LOG("priority: %d", info->priority);
+ for (j = 0; j < info->option_count; j++) {
+ tmp = make_message("%s%s%s", keys? keys : "",
+ keys? ", " : "",
+ info->options[j]);
+ free(keys);
+ keys = tmp;
+ }
+ PARA_DEBUG_LOG("keys: %s", keys? keys : "[none]");
+ free(keys);
+ PARA_DEBUG_LOG("comment: %s", info->comment?
+ info->comment : "[none]");
+ }
+}
+
static int aow_init(struct writer_node *wn, unsigned sample_rate,
unsigned channels, int sample_format)
{
ao_option *aoo = NULL;
ao_sample_format asf;
ao_info *info;
+ const struct lls_opt_result *r;
+ unsigned n;
struct private_aow_data *pawd = para_malloc(sizeof(*pawd));
- struct ao_write_args_info *conf = wn->conf;
- if (conf->driver_given) {
+ ao_initialize();
+ aow_show_drivers();
+ if (WRITE_CMD_OPT_GIVEN(AO, DRIVER, wn->lpr)) {
ret = -E_AO_BAD_DRIVER;
- id = ao_driver_id(conf->driver_arg);
+ id = ao_driver_id(WRITE_CMD_OPT_STRING_VAL(AO, DRIVER, wn->lpr));
} else {
ret = -E_AO_DEFAULT_DRIVER;
id = ao_default_driver_id();
goto fail;
}
PARA_INFO_LOG("using %s driver\n", info->short_name);
- for (i = 0; i < conf->ao_option_given; i++) {
- char *o = para_strdup(conf->ao_option_arg[i]), *value;
+ r = WRITE_CMD_OPT_RESULT(AO, AO_OPTION, wn->lpr);
+ n = lls_opt_given(r);
+ for (i = 0; i < n; i++) {
+ char *o = para_strdup(lls_string_val(i, r));
+ char *value;
ret = -E_AO_BAD_OPTION;
value = strchr(o, ':');
return ret;
}
-__malloc static void *aow_parse_config_or_die(int argc, char **argv)
-{
- struct ao_write_args_info *conf = para_calloc(sizeof(*conf));
-
- /* exits on errors */
- ao_write_cmdline_parser(argc, argv, conf);
- return conf;
-}
-
-static void aow_free_config(void *conf)
-{
- ao_write_cmdline_parser_free(conf);
-}
-
-/**
- * The init function of the ao writer.
- *
- * \param w Pointer to the writer to initialize.
- *
- * \sa struct writer.
- */
-void ao_write_init(struct writer *w)
-{
- struct ao_write_args_info dummy;
- int i, j, num_drivers, num_lines;
- ao_info **driver_list;
- char **dh; /* detailed help */
-
- ao_write_cmdline_parser_init(&dummy);
- w->close = aow_close;
- w->pre_select = aow_pre_select;
- w->post_select = aow_post_select;
- w->parse_config_or_die = aow_parse_config_or_die;
- w->free_config = aow_free_config;
- w->help = (struct ggo_help)DEFINE_GGO_HELP(ao_write);
- /* create detailed help containing all supported drivers/options */
- for (i = 0; ao_write_args_info_detailed_help[i]; i++)
- ; /* nothing */
- num_lines = i;
- dh = para_malloc((num_lines + 3) * sizeof(char *));
- for (i = 0; i < num_lines; i++)
- dh[i] = para_strdup(ao_write_args_info_detailed_help[i]);
- dh[num_lines++] = para_strdup("libao drivers available on this host:");
- dh[num_lines++] = para_strdup("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
-
- ao_initialize();
- driver_list = ao_driver_info_list(&num_drivers);
-
- for (i = 0; i < num_drivers; i++) {
- ao_info *info = driver_list[i];
- char *keys = NULL, *tmp = NULL;
-
- if (info->type == AO_TYPE_FILE)
- continue;
- for (j = 0; j < info->option_count; j++) {
- tmp = make_message("%s%s%s", keys? keys : "",
- keys? ", " : "",
- info->options[j]);
- free(keys);
- keys = tmp;
- }
- dh = para_realloc(dh, (num_lines + 6) * sizeof(char *));
- dh[num_lines++] = make_message("%s: %s", info->short_name, info->name);
- dh[num_lines++] = make_message("priority: %d", info->priority);
- dh[num_lines++] = make_message("keys: %s", keys? keys : "[none]");
- dh[num_lines++] = make_message("comment: %s", info->comment?
- info->comment : "[none]");
- dh[num_lines++] = para_strdup(NULL);
- free(keys);
- }
- dh[num_lines] = NULL;
- w->help.detailed_help = (const char **)dh;
- ao_write_cmdline_parser_free(&dummy);
-}
+struct writer lsg_write_cmd_com_ao_user_data = {
+ .close = aow_close,
+ .pre_select = aow_pre_select,
+ .post_select = aow_post_select,
+};
#include "string.h"
#include "fd.h"
#include "write.h"
-#include "write_common.h"
#include "signal.h"
#include "version.h"
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. */
- int *writer_nums;
- /** pointer to the array of writer configurations */
- void **writer_conf;
+ /** Array of writer IDs to be activated. */
+ int *wids;
+ /** Parsed writer command line(s) */
+ struct lls_parse_result **writer_lpr;
/** do not start receiver/filters/writer before this time */
struct timeval restart_barrier;
};
static void writer_cleanup(struct writer_node *wn)
{
- struct writer *w;
-
if (!wn)
return;
- w = writers + wn->writer_num;
- PARA_INFO_LOG("closing %s\n", writer_names[wn->writer_num]);
- w->close(wn);
+ PARA_INFO_LOG("closing %s\n", writer_name(wn->wid));
+ writer_get(wn->wid)->close(wn);
btr_remove_node(&wn->btrn);
task_reap(&wn->task);
}
* sizeof(struct writer_node));
for (i = 0; i < a->num_writers; i++) {
wn = s->wns + i;
- wn->conf = a->writer_conf[i];
- wn->writer_num = a->writer_nums[i];
+ wn->wid = a->wids[i];
+ wn->lpr = a->writer_lpr[i];
register_writer_node(wn, parent, &sched);
PARA_NOTICE_LOG("%s writer started in slot %d\n",
- writer_names[a->writer_nums[i]], (int)(s - slot));
+ writer_name(a->wids[i]), (int)(s - slot));
}
}
struct audio_format_info *a;
for (i = 0; i < conf.writer_given; i++) {
- void *wconf;
- int j, nw, writer_num, af_mask;
+ int j, nw, af_mask;
ret = parse_stream_command(conf.writer_arg[i], &cmd);
if (ret < 0)
a = afi + j;
if ((af_mask & (1 << j)) == 0) /* no match */
continue;
- wconf = check_writer_arg_or_die(cmd, &writer_num);
nw = a->num_writers;
- a->writer_nums = para_realloc(a->writer_nums, (nw + 1) * sizeof(int));
- a->writer_conf = para_realloc(a->writer_conf, (nw + 1) * sizeof(void *));
- a->writer_nums[nw] = writer_num;
- a->writer_conf[nw] = wconf;
+ a->wids = para_realloc(a->wids, (nw + 1) * sizeof(int));
+ a->writer_lpr = para_realloc(a->writer_lpr,
+ (nw + 1) * sizeof(struct lls_parse_result *));
+ a->wids[nw] = check_writer_arg_or_die(cmd,
+ a->writer_lpr + nw);
PARA_INFO_LOG("%s writer #%d: %s\n", audio_formats[j],
- nw, writer_names[writer_num]);
+ nw, writer_name(a->wids[nw]));
a->num_writers++;
}
}
/* Use default writer for audio formats which are not yet set up. */
FOR_EACH_AUDIO_FORMAT(i) {
- void *writer_conf;
- int writer_num;
a = afi + i;
if (a->num_writers > 0)
continue; /* already set up */
- writer_conf = check_writer_arg_or_die(NULL, &writer_num);
- a->writer_nums = para_malloc(sizeof(int));
- a->writer_nums[0] = writer_num;
- a->writer_conf = para_malloc(sizeof(void *));
- a->writer_conf[0] = writer_conf;
a->num_writers = 1;
+ a->wids = para_malloc(sizeof(int));
+ a->writer_lpr = para_malloc(sizeof(struct lls_parse_result *));
+ a->wids[0] = check_writer_arg_or_die(NULL, a->writer_lpr);
PARA_INFO_LOG("%s writer: %s (default)\n", audio_formats[i],
- writer_names[writer_num]);
+ writer_name(a->wids[0]));
}
return 1;
}
version_handle_flag("audiod", conf.version_given);
/* init receivers/filters/writers early to make help work */
recv_init();
- writer_init();
if (conf.help_given || conf.detailed_help_given)
print_help_and_die();
daemon_set_priority(conf.priority_arg);
#include "audiod.cmdline.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "filter.h"
#include "grab_client.h"
audiod_audio_formats="wma"
audiod_cmdline_objs="$audiod_cmdline_objs
audiod
- file_write
"
audiod_errlist_objs="$audiod_errlist_objs
audiod
fi
if test "$have_core_audio" = "yes"; then
audiod_errlist_objs="$audiod_errlist_objs osx_write ipc"
- audiod_cmdline_objs="$audiod_cmdline_objs osx_write"
fi
NEED_VORBIS_OBJECTS && {
audiod_errlist_objs="$audiod_errlist_objs oggdec_filter"
fi
if test $HAVE_OSS = yes; then
audiod_errlist_objs="$audiod_errlist_objs oss_write"
- audiod_cmdline_objs="$audiod_cmdline_objs oss_write"
fi
if test $HAVE_ALSA = yes; then
audiod_errlist_objs="$audiod_errlist_objs alsa_write"
- audiod_cmdline_objs="$audiod_cmdline_objs alsa_write"
fi
NEED_AO_OBJECTS && {
audiod_errlist_objs="$audiod_errlist_objs ao_write"
- audiod_cmdline_objs="$audiod_cmdline_objs ao_write"
}
if test $HAVE_SAMPLERATE = yes; then
audiod_errlist_objs="$audiod_errlist_objs resample_filter check_wav"
version
sync_filter
"
-play_cmdline_objs="
- file_write
-"
if test "$have_core_audio" = "yes"; then
play_errlist_objs="$play_errlist_objs osx_write ipc"
- play_cmdline_objs="$play_cmdline_objs osx_write"
fi
NEED_OGG_OBJECTS && play_errlist_objs="$play_errlist_objs ogg_afh_common"
NEED_VORBIS_OBJECTS && {
fi
if test $HAVE_OSS = yes; then
play_errlist_objs="$play_errlist_objs oss_write"
- play_cmdline_objs="$play_cmdline_objs oss_write"
fi
if test $HAVE_ALSA = yes; then
play_errlist_objs="$play_errlist_objs alsa_write"
- play_cmdline_objs="$play_cmdline_objs alsa_write"
fi
NEED_AO_OBJECTS && {
play_errlist_objs="$play_errlist_objs ao_write"
- play_cmdline_objs="$play_cmdline_objs ao_write"
}
if test $HAVE_READLINE = yes; then
play_errlist_objs="$play_errlist_objs interactive"
play_errlist_objs="$play_errlist_objs resample_filter check_wav"
fi
-play_objs="add_cmdline($play_cmdline_objs) $play_errlist_objs"
+play_objs="$play_errlist_objs"
AC_SUBST(play_objs, add_dot_o($play_objs))
######################################################################### write
write_cmdline_objs="
write
- file_write
"
write_errlist_objs="
write
check_wav
version
"
-writers="file"
-default_writer="FILE_WRITE"
if test "$have_core_audio" = "yes"; then
write_errlist_objs="$write_errlist_objs osx_write ipc"
- write_cmdline_objs="$write_cmdline_objs osx_write"
- writers="$writers osx"
- default_writer="OSX_WRITE"
fi
NEED_AO_OBJECTS && {
write_errlist_objs="$write_errlist_objs ao_write"
- write_cmdline_objs="$write_cmdline_objs ao_write"
- writers="$writers ao"
- default_writer="AO_WRITE"
}
if test $HAVE_OSS = yes; then
write_errlist_objs="$write_errlist_objs oss_write"
- write_cmdline_objs="$write_cmdline_objs oss_write"
- writers="$writers oss"
- default_writer="OSS_WRITE"
fi
if test $HAVE_ALSA = yes; then
write_errlist_objs="$write_errlist_objs alsa_write"
- write_cmdline_objs="$write_cmdline_objs alsa_write"
- writers="$writers alsa"
- default_writer="ALSA_WRITE"
fi
-AC_SUBST(writers)
write_objs="add_cmdline($write_cmdline_objs) $write_errlist_objs"
AC_SUBST(write_objs, add_dot_o($write_objs))
-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)
-AC_DEFINE_UNQUOTED(DEFAULT_WRITER, $default_writer, use this writer if none was specified)
-names="$(for i in $writers; do printf \"$i\",' ' ; done)"
-AC_DEFINE_UNQUOTED(WRITER_NAMES, $names, supported writer names)
-inits="$(for i in $writers; do printf 'extern void '$i'_write_init(struct writer *); '; done)"
-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)
######################################################################## audioc
audioc_errlist_objs="
audioc
faad: $HAVE_FAAD
mp4v2: $HAVE_MP4V2
audio format handlers: $audio_format_handlers
-writers: $writers
para_server: $build_server
para_gui: $build_gui
#include <regex.h>
#include <sys/types.h>
+#include <lopsub.h>
+#include "write_cmd.lsg.h"
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "write.h"
-#include "write_common.h"
#include "string.h"
#include "fd.h"
-#include "file_write.cmdline.h"
#include "error.h"
/** Data specific to the file writer. */
static int prepare_output_file(struct writer_node *wn)
{
- struct file_write_args_info *conf = wn->conf;
- char *filename;
- int ret;
- struct private_file_write_data *pfwd = para_calloc(sizeof(*pfwd));
-
- if (conf->filename_given)
- filename = conf->filename_arg;
- else
- filename = random_filename();
- ret = para_open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
- if (!conf->filename_given)
- free(filename);
- if (ret < 0)
- goto out;
- pfwd->fd = ret;
- ret = mark_fd_blocking(pfwd->fd);
+ const unsigned flags = O_WRONLY | O_CREAT, mode = S_IRUSR | S_IWUSR;
+ int ret, fd;
+ struct private_file_write_data *pfwd;
+
+
+ if (WRITE_CMD_OPT_GIVEN(FILE, FILENAME, wn->lpr)) {
+ const char *path = WRITE_CMD_OPT_STRING_VAL(FILE, FILENAME,
+ wn->lpr);
+ ret = para_open(path, flags, mode);
+ } else {
+ char *path = random_filename();
+ ret = para_open(path, flags, mode);
+ free(path);
+ }
if (ret < 0)
- goto out_close;
- wn->private_data = pfwd;
+ return ret;
+ fd = ret;
+ ret = mark_fd_blocking(fd);
+ if (ret < 0) {
+ close(fd);
+ return ret;
+ }
+ pfwd = wn->private_data = para_calloc(sizeof(*pfwd));
+ pfwd->fd = fd;
return 1;
-out_close:
- close(pfwd->fd);
-out:
- free(pfwd);
- return ret;
}
static void file_write_pre_select(struct sched *s, void *context)
return ret;
}
-__malloc static void *file_write_parse_config_or_die(int argc, char **argv)
-{
- struct file_write_args_info *conf = para_calloc(sizeof(*conf));
-
- /* exits on errors */
- file_write_cmdline_parser(argc, argv, conf);
- return conf;
-}
-
-static void file_write_free_config(void *conf)
-{
- file_write_cmdline_parser_free(conf);
-}
-
/** the init function of the file writer */
-void file_write_init(struct writer *w)
-{
- struct file_write_args_info dummy;
-
- file_write_cmdline_parser_init(&dummy);
- w->pre_select = file_write_pre_select;
- w->post_select = file_write_post_select;
- w->parse_config_or_die = file_write_parse_config_or_die;
- w->free_config = file_write_free_config;
- w->close = file_write_close;
- w->help = (struct ggo_help)DEFINE_GGO_HELP(file_write);
- file_write_cmdline_parser_free(&dummy);
-}
+struct writer lsg_write_cmd_com_file_user_data = {
+ .pre_select = file_write_pre_select,
+ .post_select = file_write_post_select,
+ .close = file_write_close,
+};
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Native ALSA output plugin"
-
-include(header.m4)
-
-<qu>
-option "device" d
-#~~~~~~~~~~~~~~~~
-"set PCM device"
-string typestr = "device"
-default = "default"
-optional
-details = "
- Check for the presence of a /proc/asound/ directory to see if
- ALSA is present in your kernel. The file /proc/asound/devices
- contains all devices ALSA knows about.
-"
-
-option "buffer-time" B
-#~~~~~~~~~~~~~~~~~~~~~
-"duration of the ALSA buffer"
-int typestr = "milliseconds"
-default = "170"
-optional
-details = "
- This is only a hint as ALSA might pick a slightly different
- time, depending on the sound hardware. The chosen value is
- shown in debug output as BUFFER_TIME.
-
- If synchronization between multiple clients is desired,
- the same buffer time should be configured for all clients.
-"
-
-</qu>
-
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Output plugin for libao"
-
-include(header.m4)
-<qu>
-
-option "driver" d
-#~~~~~~~~~~~~~~~~
-"Select a output driver by name"
-string typestr = "name"
-optional
-details = "
- If this is not given, the driver with the highest priority
- (see below) will be used.
-"
-
-option "ao-option" o
-#~~~~~~~~~~~~~~~~~~~
-"Pass a key-value pair to the libao driver"
-string typestr = "key:value"
-optional
-multiple
-details = "
- For each time this option is given, the supplied key-value
- pair is appended to the list of options for the driver. Invalid
- keys are silently ignored.
-"
-
-</qu>
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Output plugin that writes to a local file"
-
-option "filename" f
-#~~~~~~~~~~~~~~~~~~
-"specify output file name"
-string typestr="filename"
-optional
-details="
- Defaults to a random filename in ~/.paraslash.
-"
-
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Output plugin for the Open Sound System"
-
-option "device" d
-#~~~~~~~~~~~~~~~~
-"set PCM device"
-string typestr="device"
-default="/dev/dsp"
-optional
-details = ""
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Output plugin for Mac OS coreaudio"
-
-section "osx options"
-#####################
-
-option "numbuffers" n
-#~~~~~~~~~~~~~~~~~~~~~
-
-"number of audio buffers to allocate (increase if
-you get buffer underruns)"
-
- int typestr="num"
- default="20"
- optional
- details = ""
--- /dev/null
+[suite write_cmd]
+caption = writers
+[subcommand alsa]
+ purpose = native ALSA output plugin
+ [option device]
+ short_opt = d
+ summary = set PCM device
+ typestr = device
+ arg_info = required_arg
+ arg_type = string
+ default_val = default
+ [help]
+ Check for the presence of a /proc/asound/ directory to see if ALSA
+ is present in your kernel. The file /proc/asound/devices contains
+ all devices ALSA knows about.
+ [/help]
+ [option buffer-time]
+ short_opt = B
+ summary = duration of the ALSA buffer
+ typestr = milliseconds
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 170
+ [help]
+ This is only a hint as ALSA might pick a slightly different time,
+ depending on the sound hardware. The chosen value is shown in debug
+ output as BUFFER_TIME.
+
+ If synchronization between multiple clients is desired, the same
+ buffer time should be configured for all clients.
+ [/help]
+[subcommand ao]
+ purpose = output plugin for libao
+ [option driver]
+ short_opt = d
+ summary = select a output driver by name
+ typestr = name
+ arg_info = required_arg
+ arg_type = string
+ [help]
+ If this is not given, the driver with the highest priority (see below)
+ will be used.
+ [/help]
+ [option ao-option]
+ short_opt = o
+ summary = pass a key-value pair to the libao driver
+ typestr = key:value
+ arg_info = required_arg
+ arg_type = string
+ flag multiple
+ [help]
+ For each time this option is given, the supplied key-value pair is
+ appended to the list of options for the driver. Invalid keys are
+ silently ignored.
+ [/help]
+[subcommand oss]
+ purpose = output plugin for the Open Sound System
+ [option device]
+ short_opt = d
+ summary = set PCM device
+ typestr = path
+ arg_info = required_arg
+ arg_type = string
+ default_val = /dev/dsp
+[subcommand osx]
+ purpose = output plugin for Mac OS coreaudio
+ [option numbuffers]
+ short_opt = n
+ summary = number of audio buffers to allocate
+ typestr = num
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 20
+ [help]
+ Increase if you get buffer underruns.
+ [/help]
+[subcommand file]
+ purpose = output plugin that writes to a local file
+ [option filename]
+ short_opt = f
+ summary = specify output file name
+ typestr = path
+ arg_info = required_arg
+ arg_type = string
+ [help]
+ Defaults to a random filename in ~/.paraslash.
+ [/help]
--set-package "para_$1" \
< "$ggo"
- if [[ "$target" == 'write' || "$target" == 'audiod' ]]; then
- for module in $WRITERS; do
- ggo="$GGO_DIR/${module}_write.ggo"
- [[ ! -f "$ggo" ]] && continue
- printf "\nOptions for the $module writer"
- print_modhelp "$ggo"
- done
- fi
}
set -u
cl_opts=
tempfiles=
for cl in $COMMAND_LISTS; do
- if [[ "$cl" =~ lsg ]]; then
- tempfiles+=" $cl.man_util.$$"
- sed -e '/^\.SH / s/$/]/1' -e '/^\.SH / s/^\.SH /[/1' "$cl" > "$cl.man_util.$$"
- cl_opts+=" --include $cl.man_util.$$"
- else
- cl_opts+=" --include $cl"
- fi
+ tempfiles+=" $cl.man_util.$$"
+ sed -e '/^\.SH / s/$/]/1' -e '/^\.SH / s/^\.SH /[/1' "$cl" > "$cl.man_util.$$"
+ cl_opts+=" --include $cl.man_util.$$"
done
# Create a symlink para_$target, pointing to this script. This hack is
#include <regex.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
+#include <lopsub.h>
+#include "write_cmd.lsg.h"
#include "para.h"
#include "fd.h"
#include "string.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "write.h"
-#include "write_common.h"
-#include "oss_write.cmdline.h"
#include "error.h"
/** Data specific to the oss writer. */
{
int ret, format;
unsigned ch, rate;
- struct oss_write_args_info *conf = wn->conf;
struct private_oss_write_data *powd = para_calloc(sizeof(*powd));
+ const char *dev = WRITE_CMD_OPT_STRING_VAL(OSS, DEVICE, wn->lpr);
- PARA_INFO_LOG("opening %s\n", conf->device_arg);
- ret = para_open(conf->device_arg, O_WRONLY, 0);
+ PARA_INFO_LOG("opening %s\n", dev);
+ ret = para_open(dev, O_WRONLY, 0);
if (ret < 0)
goto err_free;
powd->fd = ret;
close(powd->fd);
err_free:
free(powd);
- PARA_ERROR_LOG("failed to init %s: %s\n", conf->device_arg,
- para_strerror(-ret));
+ PARA_ERROR_LOG("failed to init %s: %s\n", dev, para_strerror(-ret));
return ret;
}
return ret;
}
-__malloc static void *oss_parse_config_or_die(int argc, char **argv)
-{
- struct oss_write_args_info *conf = para_calloc(sizeof(*conf));
-
- /* exits on errors */
- oss_write_cmdline_parser(argc, argv, conf);
- return conf;
-}
-
-static void oss_free_config(void *conf)
-{
- oss_write_cmdline_parser_free(conf);
-}
-
-/**
- * The init function of the oss writer.
- *
- * \param w Pointer to the writer to initialize.
- *
- * \sa struct writer.
- */
-void oss_write_init(struct writer *w)
-{
- struct oss_write_args_info dummy;
-
- oss_write_cmdline_parser_init(&dummy);
- w->close = oss_close;
- w->pre_select = oss_pre_select;
- w->post_select = oss_post_select;
- w->parse_config_or_die = oss_parse_config_or_die;
- w->free_config = oss_free_config;
- w->help = (struct ggo_help)DEFINE_GGO_HELP(oss_write);
- oss_write_cmdline_parser_free(&dummy);
-}
+const struct writer lsg_write_cmd_com_oss_user_data = {
+ .pre_select = oss_pre_select,
+ .post_select = oss_post_select,
+ .close = oss_close,
+};
#include <regex.h>
#include <sys/types.h>
+#include <lopsub.h>
+#include "write_cmd.lsg.h"
#include "para.h"
#include "fd.h"
#include "string.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "write.h"
-#include "write_common.h"
-#include "osx_write.cmdline.h"
#include "ipc.h"
#include "error.h"
return ret;
}
-__malloc static void *osx_write_parse_config_or_die(int argc, char **argv)
-{
- struct osx_write_args_info *conf = para_calloc(sizeof(*conf));
-
- /* exits on errors */
- osx_write_cmdline_parser(argc, argv, conf);
- return conf;
-}
-
-static void osx_free_config(void *conf)
-{
- osx_write_cmdline_parser_free(conf);
-}
-
static void osx_write_close(struct writer_node *wn)
{
struct private_osx_write_data *powd = wn->private_data;
return ret;
}
-/**
- * The init function of the osx writer.
- *
- * \param w Filled in by the function.
- */
-void osx_write_init(struct writer *w)
-{
- struct osx_write_args_info dummy;
-
- osx_write_cmdline_parser_init(&dummy);
- w->close = osx_write_close;
- w->pre_select = osx_write_pre_select;
- w->post_select = osx_write_post_select;
- w->parse_config_or_die = osx_write_parse_config_or_die;
- w->free_config = osx_free_config;
- w->help = (struct ggo_help)DEFINE_GGO_HELP(osx_write);
- osx_write_cmdline_parser_free(&dummy);
-}
+struct writer lsg_write_cmd_com_osx_user_data = {
+ .close = osx_write_close,
+ .pre_select = osx_write_pre_select,
+ .post_select = osx_write_post_select,
+};
#include "recv_cmd.lsg.h"
#include "play_cmd.lsg.h"
+#include "write_cmd.lsg.h"
#include "play.lsg.h"
#include "para.h"
#include "list.h"
#include "error.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "version.h"
#include "string.h"
#include "afh.h"
#include "recv.h"
#include "write.h"
-#include "write_common.h"
#include "fd.h"
/**
static int eof_cleanup(struct play_task *pt)
{
- struct writer *w = writers + DEFAULT_WRITER;
const struct filter *decoder;
+ const struct writer *w = writer_get(-1); /* default writer */
int ret;
ret = get_playback_error(pt);
task_reap(&pt->wn.task);
w->close(&pt->wn);
btr_remove_node(&pt->wn.btrn);
- w->free_config(pt->wn.conf);
+ lls_free_parse_result(pt->wn.lpr, WRITE_CMD(pt->wn.wid));
memset(&pt->wn, 0, sizeof(struct writer_node));
decoder = filter_get(pt->fn.filter_num);
char *tmp, buf[20];
int ret;
const struct filter *decoder;
- static struct lls_parse_result *filter_lpr;
+ static struct lls_parse_result *filter_lpr, *writer_lpr;
btr_remove_node(&pt->rn.btrn);
if (!pt->rn.receiver || pt->next_file != pt->current_file) {
btr_log_tree(pt->rn.btrn, LL_INFO);
/* setup default writer */
- pt->wn.conf = check_writer_arg_or_die(NULL, &pt->wn.writer_num);
-
+ pt->wn.wid = check_writer_arg_or_die(NULL, &writer_lpr);
+ pt->wn.lpr = writer_lpr;
/* success, register tasks */
pt->rn.task = task_register(
&(struct task_info) {
/* needed this early to make help work */
recv_init();
- writer_init();
sched.default_timeout.tv_sec = 5;
parse_config_or_die(argc, argv);
. ${0%/*}/test-lib.sh
-rfw_regex='Options for .\{100,\}Options for ' # recv/filter/writer
-
grep_man()
{
local regex="$1" exe="$2"
# check that options of all reveivers/filters/writers are contained
# in the man pages
-regex="$rfw_regex"
test_expect_success 'para_recv: receiver options' "grep_man 'RECEIVERS' recv"
test_expect_success 'para_filter: filter options' "grep_man 'FILTERS' filter"
-test_expect_success 'para_write: writer options' "grep_man '$regex' write"
+test_expect_success 'para_write: writer options' "grep_man 'WRITERS' write"
test_require_objects "audiod"
if [[ -n "$result" ]]; then
test_skip 'para_audiod' "missing object(s): $result"
test_expect_success 'para_audiod: filters' \
"grep_man 'FILTERS' audiod"
test_expect_success 'para_audiod: writers' \
- "grep_man 'Options for the file writer' audiod"
+ "grep_man 'WRITERS' audiod"
fi
# check various command lists
#include <regex.h>
#include <sys/types.h>
+#include <lopsub.h>
+#include "write_cmd.lsg.h"
#include "para.h"
#include "string.h"
#include "write.cmdline.h"
#include "stdin.h"
#include "buffer_tree.h"
#include "write.h"
-#include "write_common.h"
#include "fd.h"
#include "error.h"
#include "version.h"
bool d = conf.detailed_help_given;
ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
- print_writer_helps(d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS);
+ print_writer_helps(d);
exit(0);
}
-/*
- * Parse config and register a task for a writer node.
- *
- * \param arg Command line arguments.
- * \param parent The new node will be a child of \a parent.
- * \param wn The writer node.
- *
- * If arg is \p NULL, the OS-dependent default writer is used with no
- * arguments. The default writers are alsa for Linux, osx for OS X, oss for
- * *BSD, and the file writer if the default writer is not supported.
- *
- * Once the writer configuration has been retrieved from the ->parse_config
- * callback a writer node is created, its buffer tree node is added to the
- * buffer tree as a child of the given parent.
- *
- * Finally, the new writer node's task structure is initialized and registered
- * to the paraslash scheduler.
- *
- * \return Standard.
- */
-static void setup_writer_node(const char *arg, struct btr_node *parent,
- struct writer_node *wn, struct sched *s)
-{
- wn->conf = check_writer_arg_or_die(arg, &wn->writer_num);
- register_writer_node(wn, parent, s);
-}
-
struct write_task {
struct task *task;
struct check_wav_context *cwc;
static int setup_and_schedule(void)
{
- int i, ret;
+ int i, n, ret;
struct btr_node *cw_btrn;
struct writer_node *wns;
static struct sched s;
.post_select = write_post_select,
.context = &wt,
}, &s);
- if (!conf.writer_given) {
- wns = para_calloc(sizeof(*wns));
- setup_writer_node(NULL, cw_btrn, wns, &s);
- i = 1;
- } else {
- wns = para_calloc(conf.writer_given * sizeof(*wns));
- for (i = 0; i < conf.writer_given; i++)
- setup_writer_node(conf.writer_arg[i], cw_btrn,
- wns + i, &s);
- }
+ n = conf.writer_given > 0? conf.writer_given : 1;
+ wns = para_calloc(n * sizeof(*wns));
+ for (i = 0; i < n; i++) {
+ char *arg = i < conf.writer_given? conf.writer_arg[i] : NULL;
+ wns[i].wid = check_writer_arg_or_die(arg, &wns[i].lpr);
+ register_writer_node(wns + i, cw_btrn, &s);
+ }
s.default_timeout.tv_sec = 10;
s.default_timeout.tv_usec = 50000;
ret = schedule(&s);
if (ret >= 0) {
int j, ts;
- for (j = 0; j < i; j++) {
+ for (j = 0; j < n; j++) {
struct writer_node *wn = wns + j;
ts = task_status(wn->task);
assert(ts < 0);
if (ts != -E_WRITE_COMMON_EOF && ts != -E_BTR_EOF) {
- const char *name = writer_names[wn->writer_num];
+ const char *name = writer_name(wn->wid);
PARA_ERROR_LOG("%s: %s\n", name,
para_strerror(-ts));
if (ret >= 0)
}
}
}
- for (i--; i >= 0; i--) {
+ for (i = n - 1; i >= 0; i--) {
struct writer_node *wn = wns + i;
- struct writer *w = writers + wn->writer_num;
-
- w->close(wn);
+ writer_get(wn->wid)->close(wn);
btr_remove_node(&wn->btrn);
- w->free_config(wn->conf);
- free(wn->conf);
+ lls_free_parse_result(wns[i].lpr,
+ lls_cmd(wn->wid, write_cmd_suite));
}
free(wns);
check_wav_shutdown(wt.cwc);
write_cmdline_parser(argc, argv, &conf);
loglevel = get_loglevel_by_name(conf.loglevel_arg);
- writer_init();
version_handle_flag("write", conf.version_given);
if (conf.help_given || conf.detailed_help_given)
print_help_and_die();
/** \file write.h Writer-related structures. */
-/** The list of supported writers. */
-enum writer_enum {WRITER_ENUM};
-
/**
* Describes one running instance of a writer.
*/
struct writer_node {
- /** The number of this writer. */
- int writer_num;
+ /** The ID of this writer. */
+ int wid;
/** Writer-specific data. */
void *private_data;
- /** The writer-specific configuration of this node. */
- void *conf;
+ /** The parsed command line, merged with options given in the config file. */
+ struct lls_parse_result *lpr;
/** The buffer tree node associated with this writer node. */
struct btr_node *btrn;
/** The task of this writer node. */
/** Describes one supported writer. */
struct writer {
- /**
- * The init function of the writer.
- *
- * It must fill in all other function pointers of the given
- * writer structure.
- */
- void (*init)(struct writer *w);
- /**
- * The command line parser of the writer.
- *
- * It should check whether the command line options given by \a argv
- * and \a argc are valid and return a pointer to the writer-specific
- * configuration data determined by these options. This function must
- * either succeed or call exit(). Note that parse_config_or_die() might
- * be called more than once with different values of \a options. \sa
- * \ref free_config().
- */
- void *(*parse_config_or_die)(int argc, char **argv);
- /**
- * Deallocate all configuration resources.
- *
- * This should free whatever was allocated by \ref parse_config_or_die().
- */
- void (*free_config)(void *config);
/**
* Prepare the fd sets for select.
*
* This function is assumed to succeed.
*/
void (*close)(struct writer_node *);
- /** The short and the log help text of this writer. */
- struct ggo_help help;
/**
* The callback handler.
*
btr_command_handler execute;
};
-/** Loop over each supported writer. */
-#define FOR_EACH_WRITER(i) for (i = 0; i < NUM_SUPPORTED_WRITERS; i++)
-
-/** Declare the init functions of all supported writers. */
-DECLARE_WRITER_INITS;
+#define WRITE_CMD(_num) (lls_cmd(_num, write_cmd_suite))
-/** Array containing the name of each writer. */
-extern const char *writer_names[];
+#define WRITE_CMD_OPT_RESULT(_cmd, _opt, _lpr) \
+ (lls_opt_result(LSG_WRITE_CMD_ ## _cmd ## _OPT_ ## _opt, _lpr))
+#define WRITE_CMD_OPT_GIVEN(_cmd, _opt, _lpr) \
+ (lls_opt_given(WRITE_CMD_OPT_RESULT(_cmd, _opt, _lpr)))
+#define WRITE_CMD_OPT_UINT32_VAL(_cmd, _opt, _lpr) \
+ (lls_uint32_val(0, WRITE_CMD_OPT_RESULT(_cmd, _opt, (_lpr))))
+#define WRITE_CMD_OPT_STRING_VAL(_cmd, _opt, _lpr) \
+ (lls_string_val(0, WRITE_CMD_OPT_RESULT(_cmd, _opt, (_lpr))))
-/** The writer structure for each supported writer. */
-extern struct writer writers[NUM_SUPPORTED_WRITERS];
+int check_writer_arg_or_die(const char *wa, struct lls_parse_result **lprp);
+const struct writer *writer_get(int wid);
+const char *writer_name(int wid);
+void register_writer_node(struct writer_node *wn, struct btr_node *parent,
+ struct sched *s);
+void get_btr_sample_rate(struct btr_node *btrn, int32_t *result);
+void get_btr_channels(struct btr_node *btrn, int32_t *result);
+void get_btr_sample_format(struct btr_node *btrn, int32_t *result);
+void print_writer_helps(bool detailed);
/** \file write_common.c common functions of para_audiod and para_write */
#include <regex.h>
+#include <lopsub.h>
+#include "write_cmd.lsg.h"
#include "para.h"
#include "string.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "write.h"
#include "error.h"
-#include "write_common.h"
-/** the array containing the names of all supported writers */
-const char *writer_names[] ={WRITER_NAMES};
+/** Loop over all writers. */
+#define FOR_EACH_WRITER(i) for (i = 1; lls_cmd(i, write_cmd_suite); i++)
-/** the array of supported writers */
-struct writer writers[NUM_SUPPORTED_WRITERS] = {WRITER_ARRAY};
-/**
- * Call the init function of each supported paraslash writer.
- */
-void writer_init(void)
+static inline bool writer_supported(int wid)
+{
+ return lls_user_data(WRITE_CMD(wid));
+}
+
+/* simply return the first available writer */
+static int default_writer_id(void)
{
int i;
FOR_EACH_WRITER(i)
- writers[i].init(&writers[i]);
+ if (writer_supported(i))
+ return i;
+ assert(0); /* the file writer should always be available */
}
+
/**
- * Check if given string is a valid command line for any writer.
+ * Return the writer structure from a writer ID.
*
- * \param \wa String of the form writer_name:options.
- * \param writer_num Contains the number of the writer upon success.
+ * \param wid If non-positive, a pointer to the default writer is returned.
*
- * This function checks whether \a wa starts with the name of a supported
- * paraslash writer, optionally followed by a colon and any options for that
- * writer. If a valid writer name was found and further are present, the
- * remaining part of \a wa is passed to that writer's config parser.
+ * \return Pointer to a (constant) struct writer.
+ */
+const struct writer *writer_get(int wid)
+{
+ if (wid < 0)
+ wid = default_writer_id();
+ return lls_user_data(WRITE_CMD(wid));
+}
+
+/**
+ * Return name of the writer identified by a writer ID.
+ *
+ * \param wid If non-positive, the name of the default writer is returned.
*
- * \return On success, a pointer to the gengetopt args info struct is returned
- * and \a writer_num contains the number of the writer. Otherwise this function
- * prints an error message and calls exit().
+ * \return The returned buffer must not be freed by the caller.
*/
-void *check_writer_arg_or_die(const char *wa, int *writer_num)
+const char *writer_name(int wid)
{
- int i, ret, argc;
- const char *cmdline;
- char **argv;
- void *conf;
+ if (wid <= 0)
+ wid = default_writer_id();
+ return lls_command_name(WRITE_CMD(wid));
+}
- if (!wa || !*wa) {
- i = DEFAULT_WRITER;
- cmdline = NULL;
- goto check;
- }
- PARA_INFO_LOG("checking %s\n", wa);
- FOR_EACH_WRITER(i) {
- const char *name = writer_names[i];
- size_t len = strlen(name);
- char c;
+/**
+ * Check if the given string is a valid command line for any writer.
+ *
+ * \param wa String of the form writer_name options.
+ * \param lprp Contains the parsed command line on success.
+ *
+ * If wa is \p NULL, the (configuration-dependent) default writer is assumed.
+ * Otherwise, the function checks whether \a wa starts with the name of a
+ * supported writer. If a valid writer name was found, the rest of the command
+ * line is passed to the config parser of this writer.
+ *
+ * \return On success, the positive writer ID is returned. Otherwise the
+ * function prints an error message and calls exit().
+ */
+int check_writer_arg_or_die(const char *wa, struct lls_parse_result **lprp)
+{
+ int ret, writer_num, argc;
+ char **argv = NULL, *errctx = NULL;
+ const struct lls_command *cmd;
- if (strlen(wa) < len)
- continue;
- if (strncmp(name, wa, len))
- continue;
- c = wa[len];
- if (!c || c == ' ') {
- cmdline = c? wa + len + 1 : NULL;
- goto check;
- }
- }
- PARA_EMERG_LOG("invalid writer %s\n", wa);
- exit(EXIT_FAILURE);
-check:
- ret = create_shifted_argv(cmdline, " \t", &argv);
- if (ret < 0) {
- PARA_EMERG_LOG("%s: %s\n", wa, para_strerror(-ret));
- exit(EXIT_FAILURE);
+ if (!wa || !*wa) {
+ writer_num = default_writer_id();
+ cmd = WRITE_CMD(writer_num);
+ argv = para_malloc(2 * sizeof(char *));
+ argc = 1;
+ argv[0] = para_strdup(lls_command_name(cmd));
+ argv[1] = NULL;
+ goto parse;
}
+ ret = create_argv(wa, " \t\n", &argv);
+ if (ret < 0)
+ goto fail;
argc = ret;
- argv[0] = make_message("%s_write", writer_names[i]);
- *writer_num = i;
- conf = writers[i].parse_config_or_die(argc, argv);
+ ret = lls(lls_lookup_subcmd(argv[0], write_cmd_suite, &errctx));
+ if (ret < 0)
+ goto free_argv;
+ writer_num = ret;
+ cmd = WRITE_CMD(writer_num);
+ if (!writer_supported(writer_num)) {
+ ret = -ERRNO_TO_PARA_ERROR(EINVAL);
+ errctx = make_message("%s writer is not supported",
+ lls_command_name(cmd));
+ goto free_argv;
+ }
+parse:
+ ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx));
+ if (ret >= 0)
+ ret = writer_num;
+free_argv:
free_argv(argv);
- return conf;
+ 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);
}
/**
* \param wn The writer node to open.
* \param parent The parent btr node (the source for the writer node).
* \param s The scheduler instance to register the task to.
- *
- * The configuration of the writer node stored in \p wn->conf must be
- * initialized before this function may be called.
*/
void register_writer_node(struct writer_node *wn, struct btr_node *parent,
struct sched *s)
{
- struct writer *w = writers + wn->writer_num;
+ const struct writer *w = writer_get(wn->wid);
wn->btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = writer_names[wn->writer_num], .parent = parent,
+ EMBRACE(.name = writer_name(wn->wid), .parent = parent,
.handler = w->execute, .context = wn));
wn->task = task_register(&(struct task_info) {
- .name = writer_names[wn->writer_num],
+ .name = writer_name(wn->wid),
.pre_select = w->pre_select,
.post_select = w->post_select,
.context = wn,
/**
* Print the help text of all writers to stdout.
*
- * \param flags Passed to \ref ggo_print_help().
+ * \param detailed Whether to print the short or the detailed help.
*/
-void print_writer_helps(unsigned flags)
+void print_writer_helps(bool detailed)
{
int i;
- printf_or_die("\nAvailable writers: ");
- FOR_EACH_WRITER(i)
- printf_or_die("%s%s", i? " " : "", writer_names[i]);
- printf_or_die("\n");
+ printf("\nAvailable writers: ");
FOR_EACH_WRITER(i) {
- struct writer *w = writers + i;
-
- if (!w->help.short_help)
+ if (!writer_supported(i))
+ continue;
+ printf("%s%s", i? " " : "", writer_name(i));
+ }
+ printf("\n");
+ FOR_EACH_WRITER(i) {
+ const struct lls_command *cmd = WRITE_CMD(i);
+ char *help;
+ if (!writer_supported(i))
+ continue;
+ help = detailed? lls_long_help(cmd) : lls_short_help(cmd);
+ if (!help)
continue;
- printf_or_die("\n%s: %s", writer_names[i],
- w->help.purpose);
- ggo_print_help(&w->help, flags);
+ printf("%s\n", help);
+ free(help);
}
}
+++ /dev/null
-/*
- * Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
-
-/** \file write_common.h Exported symbols from write_common.c. */
-
-void writer_init(void);
-void *check_writer_arg_or_die(const char *wa, int *writer_num);
-void print_writer_helps(unsigned flags);
-void register_writer_node(struct writer_node *wn, struct btr_node *parent,
- struct sched *s);
-void get_btr_sample_rate(struct btr_node *btrn, int32_t *result);
-void get_btr_channels(struct btr_node *btrn, int32_t *result);
-void get_btr_sample_format(struct btr_node *btrn, int32_t *result);