ggo_descriptions_declared := @ggo_descriptions_declared@
executables := @executables@
-receivers := @receivers@
filters := @filters@
writers := @writers@
unconverted_executables := $(filter-out $(converted_executables), $(executables))
audioc_objs += audioc.lsg.o
-audiod_objs += audiod_cmd.lsg.o
+audiod_objs += audiod_cmd.lsg.o recv_cmd.lsg.o
server_objs += server_cmd.lsg.o
-play_objs += play_cmd.lsg.o
+play_objs += play_cmd.lsg.o recv_cmd.lsg.o
+recv_objs += recv_cmd.lsg.o
m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(unconverted_executables)))
-m4_lls_deps := audiod_cmd server_cmd play_cmd $(converted_executables)
+m4_lls_deps := audiod_cmd server_cmd play_cmd recv_cmd $(converted_executables)
m4_lls_deps := $(addprefix $(lls_suite_dir)/, $(addsuffix .m4d, $(m4_lls_deps)))
# now prefix all objects with object dir
endif
server_command_lists := $(lls_suite_dir)/server_cmd.lsg.man
-audiod_command_lists := $(lls_suite_dir)/audiod_cmd.lsg.man
+audiod_command_lists := \
+ $(lls_suite_dir)/audiod_cmd.lsg.man \
+ $(lls_suite_dir)/recv_cmd.lsg.man
play_command_lists := $(lls_suite_dir)/play_cmd.lsg.man
+recv_command_lists := $(lls_suite_dir)/recv_cmd.lsg.man
$(man_dir)/para_server.1: $(server_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_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)
$(man_dir)/para_%.1: $(lls_suite_dir)/%.lsg.man $(man_util_command_lists) \
$(lls_m4_dir)/copyright.m4 | $(man_dir)
para_audioc \
para_audiod \
para_play \
+para_recv \
para_server \
: LDFLAGS += $(lopsub_ldflags)
#include <regex.h>
#include <sys/types.h>
+#include <lopsub.h>
+#include "recv_cmd.lsg.h"
#include "para.h"
#include "error.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "recv.h"
-#include "afh_recv.cmdline.h"
#include "string.h"
#include "fd.h"
#include "afh.h"
return -E_BTR_NAVAIL;
}
-static void *afh_recv_parse_config(int argc, char **argv)
-{
- struct afh_recv_args_info *tmp = para_calloc(sizeof(*tmp));
-
- afh_recv_cmdline_parser(argc, argv, tmp);
- return tmp;
-}
-
-static void afh_recv_free_config(void *conf)
-{
- if (!conf)
- return;
- afh_recv_cmdline_parser_free(conf);
- free(conf);
-}
-
static int afh_recv_open(struct receiver_node *rn)
{
- struct afh_recv_args_info *conf = rn->conf;
+ struct lls_parse_result *lpr = rn->lpr;
struct private_afh_recv_data *pard;
struct afh_info *afhi;
- char *filename = conf->filename_arg;
-
+ const char *fn = RECV_CMD_OPT_STRING_VAL(AFH, FILENAME, lpr);
+ int32_t bc = RECV_CMD_OPT_INT32_VAL(AFH, BEGIN_CHUNK, lpr);
+ const struct lls_opt_result *r_e = RECV_CMD_OPT_RESULT(AFH, END_CHUNK, lpr);
int ret;
- if (!filename || *filename == '\0')
+ if (!fn || *fn == '\0')
return -E_AFH_RECV_BAD_FILENAME;
rn->private_data = pard = para_calloc(sizeof(*pard));
afhi = &pard->afhi;
- ret = mmap_full_file(filename, O_RDONLY, &pard->map,
+ ret = mmap_full_file(fn, O_RDONLY, &pard->map,
&pard->map_size, &pard->fd);
if (ret < 0)
goto out;
- ret = compute_afhi(filename, pard->map, pard->map_size,
+ ret = compute_afhi(fn, pard->map, pard->map_size,
pard->fd, afhi);
if (ret < 0)
goto out_unmap;
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
if (afhi->chunks_total == 0)
goto out_clear_afhi;
- if (PARA_ABS(conf->begin_chunk_arg) >= afhi->chunks_total)
+ if (PARA_ABS(bc) >= afhi->chunks_total)
goto out_clear_afhi;
- if (conf->begin_chunk_arg >= 0)
- pard->first_chunk = afh_get_start_chunk(
- conf->begin_chunk_arg, &pard->afhi);
+ if (bc >= 0)
+ pard->first_chunk = afh_get_start_chunk(bc, &pard->afhi);
else
- pard->first_chunk = afh_get_start_chunk(
- afhi->chunks_total + conf->begin_chunk_arg,
+ pard->first_chunk = afh_get_start_chunk(afhi->chunks_total + bc,
&pard->afhi);
- if (conf->end_chunk_given) {
+ if (lls_opt_given(r_e)) {
+ int32_t ec = lls_int32_val(0, r_e);
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
- if (PARA_ABS(conf->end_chunk_arg) > afhi->chunks_total)
+ if (PARA_ABS(ec) > afhi->chunks_total)
goto out_clear_afhi;
- if (conf->end_chunk_arg >= 0)
- pard->last_chunk = conf->end_chunk_arg;
+ if (ec >= 0)
+ pard->last_chunk = ec;
else
- pard->last_chunk = afhi->chunks_total + conf->end_chunk_arg;
+ pard->last_chunk = afhi->chunks_total + ec;
} else
pard->last_chunk = afhi->chunks_total - 1;
ret = -ERRNO_TO_PARA_ERROR(EINVAL);
struct receiver_node *rn = context;
struct private_afh_recv_data *pard = rn->private_data;
struct afh_info *afhi = &pard->afhi;
- struct afh_recv_args_info *conf = rn->conf;
+ struct lls_parse_result *lpr = rn->lpr;
struct timeval chunk_time;
int state = generic_recv_pre_select(s, rn);
+ unsigned j_given = RECV_CMD_OPT_GIVEN(AFH, JUST_IN_TIME, lpr);
if (state <= 0)
return;
- if (!conf->just_in_time_given) {
+ if (!j_given) {
sched_min_delay(s);
return;
}
static int afh_recv_post_select(__a_unused struct sched *s, void *context)
{
struct receiver_node *rn = context;
- struct afh_recv_args_info *conf = rn->conf;
+ struct lls_parse_result *lpr = rn->lpr;
struct private_afh_recv_data *pard = rn->private_data;
struct btr_node *btrn = rn->btrn;
struct afh_info *afhi = &pard->afhi;
const char *start, *end;
size_t size;
struct timeval chunk_time;
+ unsigned j_given = RECV_CMD_OPT_GIVEN(AFH, JUST_IN_TIME, lpr);
+ unsigned H_given = RECV_CMD_OPT_GIVEN(AFH, NO_HEADER, lpr);
ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
if (ret <= 0)
goto out;
- if (pard->first_chunk > 0 && !conf->no_header_given) {
+ if (pard->first_chunk > 0 && !H_given) {
char *header;
afh_get_header(afhi, pard->audio_format_num, pard->map,
pard->map_size, &header, &size);
afh_free_header(header, pard->audio_format_num);
}
}
- if (!conf->just_in_time_given) {
+ if (!j_given) {
afh_get_chunk(pard->first_chunk, afhi, pard->map, &start, &size);
afh_get_chunk(pard->last_chunk, afhi, pard->map, &end, &size);
end += size;
return ret;
}
-/**
- * The init function of the afh receiver.
- *
- * \param r Pointer to the receiver struct to initialize.
- *
- * This initializes all function pointers of \a r.
- */
-void afh_recv_init(struct receiver *r)
-{
- struct afh_recv_args_info dummy;
-
- afh_init();
- afh_recv_cmdline_parser_init(&dummy);
- r->open = afh_recv_open;
- r->close = afh_recv_close;
- r->pre_select = afh_recv_pre_select;
- r->post_select = afh_recv_post_select;
- r->parse_config = afh_recv_parse_config;
- r->free_config = afh_recv_free_config;
- r->execute = afh_execute;
- r->help = (struct ggo_help)DEFINE_GGO_HELP(afh_recv);
- afh_recv_cmdline_parser_free(&dummy);
-}
+const struct receiver lsg_recv_cmd_com_afh_user_data = {
+ .init = afh_init,
+ .open = afh_recv_open,
+ .close = afh_recv_close,
+ .pre_select = afh_recv_pre_select,
+ .post_select = afh_recv_post_select,
+ .execute = afh_execute,
+};
#include <pwd.h>
#include <lopsub.h>
+#include "recv_cmd.lsg.h"
#include "para.h"
#include "error.h"
#include "crypt.h"
/** define the array containing all supported audio formats */
const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY NULL};
-DEFINE_RECEIVER_ARRAY;
-
/** Defines how audiod handles one supported audio format. */
struct audio_format_info {
- /** pointer to the receiver for this audio format */
- struct receiver *receiver;
- /** the receiver configuration */
- void *receiver_conf;
+ /** the receiver for this audio format */
+ int receiver_num;
+ /** Parsed receiver command line. */
+ struct lls_parse_result *receiver_lpr;
/** the number of filters that should be activated for this audio format */
unsigned int num_filters;
/** Array of filter numbers to be activated. */
struct writer_node *wns;
};
+#define RECEIVER_CMD(_a) lls_cmd((_a)->receiver_num, recv_cmd_suite)
+#define RECEIVER(_a) ((const struct receiver *)lls_user_data(RECEIVER_CMD(_a)))
+
/** Maximal number of simultaneous instances. */
#define MAX_STREAM_SLOTS 5
a = &afi[s->format];
PARA_NOTICE_LOG("closing %s receiver in slot %d\n",
audio_formats[s->format], slot_num);
- a->receiver->close(s->receiver_node);
+ RECEIVER(a)->close(s->receiver_node);
btr_remove_node(&s->receiver_node->btrn);
task_reap(&s->receiver_node->task);
free(s->receiver_node);
struct audio_format_info *a = &afi[format];
struct slot_info *s;
int ret, slot_num;
- struct receiver *r = a->receiver;
+ const struct receiver *r = RECEIVER(a);
+ const char *name = lls_command_name(RECEIVER_CMD(a));
struct receiver_node *rn;
tv_add(now, &(struct timeval)EMBRACE(2, 0), &a->restart_barrier);
slot_num = ret;
rn = para_calloc(sizeof(*rn));
rn->receiver = r;
- rn->conf = a->receiver_conf;
+ rn->lpr = a->receiver_lpr;
rn->btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = r->name, .context = rn));
+ EMBRACE(.name = name, .context = rn));
ret = r->open(rn);
if (ret < 0) {
btr_remove_node(&rn->btrn);
s->format = format;
s->receiver_node = rn;
PARA_NOTICE_LOG("started %s: %s receiver in slot %d\n",
- audio_formats[format], r->name, slot_num);
+ audio_formats[format], name, slot_num);
rn->task = task_register(&(struct task_info) {
- .name = r->name,
+ .name = name,
.pre_select = r->pre_select,
.post_select = r->post_select,
.context = rn,
return 1;
}
-static int parse_stream_command(const char *txt, char **cmd)
+static int parse_stream_command(const char *txt, const char **cmd)
{
int ret, len;
char *re, *p = strchr(txt, ':');
return ret;
}
-static int add_filter(int format, char *cmdline)
+static int add_filter(int format, const char *cmdline)
{
struct audio_format_info *a = &afi[format];
int filter_num, nf = a->num_filters;
static int parse_writer_args(void)
{
int i, ret;
- char *cmd;
+ const char *cmd;
struct audio_format_info *a;
for (i = 0; i < conf.writer_given; i++) {
static int parse_receiver_args(void)
{
- int i, ret, receiver_num;
- char *cmd = NULL;
+ int i, ret;
+ const char *arg;
struct audio_format_info *a;
+ FOR_EACH_AUDIO_FORMAT(i)
+ afi[i].receiver_num = -1;
for (i = conf.receiver_given - 1; i >= 0; i--) {
- char *arg;
int j, af_mask;
ret = parse_stream_command(conf.receiver_arg[i], &arg);
* config here. Since we are iterating backwards, the winning
* receiver arg is in fact the first one given.
*/
- if (a->receiver_conf)
- a->receiver->free_config(a->receiver_conf);
- a->receiver_conf = check_receiver_arg(arg, &receiver_num);
- ret = -E_RECV_SYNTAX;
- if (!a->receiver_conf)
- goto out;
- a->receiver = receivers + receiver_num;
+ lls_free_parse_result(a->receiver_lpr, RECEIVER_CMD(a));
+ a->receiver_num = check_receiver_arg(arg, &a->receiver_lpr);
}
}
/*
- * Use the first available receiver with no arguments for those audio
- * formats for which no receiver was specified.
+ * Use the default receiver for those audio formats for which no
+ * receiver was specified.
*/
- cmd = para_strdup(receivers[0].name);
FOR_EACH_AUDIO_FORMAT(i) {
- a = &afi[i];
- if (a->receiver_conf)
+ a = afi + i;
+ if (a->receiver_num >= 0)
continue;
- a->receiver_conf = check_receiver_arg(cmd, &receiver_num);
- if (!a->receiver_conf)
- return -E_RECV_SYNTAX;
- a->receiver = &receivers[receiver_num];
+ a->receiver_num = check_receiver_arg(NULL, &a->receiver_lpr);
}
FOR_EACH_AUDIO_FORMAT(i) {
a = afi + i;
PARA_INFO_LOG("receiving %s streams via %s receiver\n",
- audio_formats[i], a->receiver->name);
+ audio_formats[i], lls_command_name(RECEIVER_CMD(a)));
}
ret = 1;
out:
- free(cmd);
return ret;
}
FOR_EACH_AUDIO_FORMAT(i) {
struct audio_format_info *a = &afi[i];
+ const char *name = lls_command_name(RECEIVER_CMD(a));
char *tmp;
int j;
* udp and dccp streams are fec-encoded, so add fecdec as the
* first filter.
*/
- if (strcmp(afi[i].receiver->name, "udp") == 0 ||
- strcmp(afi[i].receiver->name, "dccp") == 0) {
+ if (strcmp(name, "udp") == 0 || strcmp(name, "dccp") == 0) {
tmp = para_strdup("fecdec");
add_filter(i, tmp);
free(tmp);
int i, j, ret, af_mask, num_matches;
for (i = 0; i < conf.filter_given; i++) {
- char *arg;
+ const char *arg;
ret = parse_stream_command(conf.filter_arg[i], &arg);
if (ret < 0)
goto out;
audiod_cmdline_objs="$audiod_cmdline_objs
audiod
compress_filter
- http_recv
- dccp_recv
file_write
client
amp_filter
- udp_recv
prebuffer_filter
sync_filter
"
########################################################################## recv
recv_cmdline_objs="
recv
- http_recv
- dccp_recv
- udp_recv
- afh_recv
"
recv_errlist_objs="
fd
sched
stdout
- ggo
udp_recv
buffer_tree
afh_recv
recv_errlist_objs="$recv_errlist_objs aac_afh aac_common"
fi
recv_objs="add_cmdline($recv_cmdline_objs) $recv_errlist_objs"
-AC_SUBST(receivers, "http dccp udp afh")
AC_SUBST(recv_objs, add_dot_o($recv_objs))
########################################################################### afh
audio_format_handlers="mp3 wma"
sync_filter
"
play_cmdline_objs="
- http_recv
- dccp_recv
- udp_recv
- afh_recv
compress_filter
amp_filter
prebuffer_filter
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
+#include <lopsub.h>
+#include "recv_cmd.lsg.h"
#include "para.h"
#include "error.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "recv.h"
#include "string.h"
#include "net.h"
#include "fd.h"
-#include "dccp_recv.cmdline.h"
-
static void dccp_recv_close(struct receiver_node *rn)
{
if (rn->fd > 0)
btr_pool_free(rn->btrp);
}
+/* Check whether the host supports the requested 'ccid' arguments. */
+static int dccp_recv_ccid_support_check(const struct lls_parse_result *lpr)
+{
+ uint8_t *ccids;
+ int i, j, ret, nccids;
+ unsigned given = RECV_CMD_OPT_GIVEN(DCCP, CCID, lpr);
+
+ ret = dccp_available_ccids(&ccids);
+ if (ret < 0)
+ return ret;
+ nccids = ret;
+ for (i = 0; i < given; i++) {
+ uint32_t val = lls_uint32_val(i,
+ RECV_CMD_OPT_RESULT(DCCP, CCID, lpr));
+ for (j = 0; j < nccids && ccids[j] != val; j++)
+ ;
+ if (j == nccids) {
+ PARA_ERROR_LOG("'CCID-%u' not supported on this host\n",
+ val);
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+ }
+ }
+ return 1;
+}
+
static int dccp_recv_open(struct receiver_node *rn)
{
- struct dccp_recv_args_info *conf = rn->conf;
+ struct lls_parse_result *lpr = rn->lpr;
struct flowopts *fo = NULL;
uint8_t *ccids = NULL;
int fd, ret, i;
+ const struct lls_opt_result *r_c = RECV_CMD_OPT_RESULT(DCCP, CCID, lpr);
+ const char *host = RECV_CMD_OPT_STRING_VAL(DCCP, HOST, lpr);
+ uint32_t port = RECV_CMD_OPT_UINT32_VAL(DCCP, PORT, lpr);
+ unsigned given;
+ ret = dccp_recv_ccid_support_check(lpr);
+ if (ret < 0)
+ return ret;
/* Copy CCID preference list (u8 array required) */
- if (conf->ccid_given) {
- ccids = para_malloc(conf->ccid_given);
- fo = flowopt_new();
-
- for (i = 0; i < conf->ccid_given; i++)
- ccids[i] = conf->ccid_arg[i];
-
+ given = lls_opt_given(r_c);
+ if (given) {
+ ccids = para_malloc(given);
+ fo = flowopt_new();
+ for (i = 0; i < given; i++)
+ ccids[i] = lls_int32_val(i, r_c);
OPT_ADD(fo, SOL_DCCP, DCCP_SOCKOPT_CCID, ccids, i);
}
- fd = makesock(IPPROTO_DCCP, 0, conf->host_arg, conf->port_arg, fo);
+ fd = makesock(IPPROTO_DCCP, 0, host, port, fo);
flowopt_cleanup(fo);
free(ccids);
if (fd < 0)
return ret;
}
-/**
- * Check whether the host supports the requested 'ccid' arguments.
- * \param conf DCCP receiver arguments.
- * \return True if all CCIDs requested in \a conf are supported.
- */
-static bool dccp_recv_ccid_support_check(struct dccp_recv_args_info *conf)
-{
- uint8_t *ccids;
- int i, j, nccids;
-
- nccids = dccp_available_ccids(&ccids);
- if (nccids <= 0)
- return false;
-
- for (i = 0; i < conf->ccid_given; i++) {
- for (j = 0; j < nccids && ccids[j] != conf->ccid_arg[i]; j++)
- ;
- if (j == nccids) {
- PARA_ERROR_LOG("'CCID-%d' not supported on this host.\n",
- conf->ccid_arg[i]);
- return false;
- }
- }
- return true;
-}
-
-static void *dccp_recv_parse_config(int argc, char **argv)
-{
- struct dccp_recv_args_info *tmp = para_calloc(sizeof(*tmp));
-
- dccp_recv_cmdline_parser(argc, argv, tmp);
- if (!dccp_recv_ccid_support_check(tmp))
- exit(EXIT_FAILURE);
- return tmp;
-}
-
static void dccp_recv_pre_select(struct sched *s, void *context)
{
struct receiver_node *rn = context;
return ret;
}
-static void dccp_recv_free_config(void *conf)
-{
- dccp_recv_cmdline_parser_free(conf);
- free(conf);
-}
-
-/**
- * The init function of the dccp receiver.
- *
- * \param r Pointer to the receiver struct to initialize.
- *
- * Initialize all function pointers of \a r.
- */
-void dccp_recv_init(struct receiver *r)
-{
- struct dccp_recv_args_info dummy;
-
- dccp_recv_cmdline_parser_init(&dummy);
- r->open = dccp_recv_open;
- r->close = dccp_recv_close;
- r->pre_select = dccp_recv_pre_select;
- r->post_select = dccp_recv_post_select;
- r->parse_config = dccp_recv_parse_config;
- r->free_config = dccp_recv_free_config;
- r->help = (struct ggo_help)DEFINE_GGO_HELP(dccp_recv);
- dccp_recv_cmdline_parser_free(&dummy);
-}
+const struct receiver lsg_recv_cmd_com_dccp_user_data = {
+ .open = dccp_recv_open,
+ .close = dccp_recv_close,
+ .pre_select = dccp_recv_pre_select,
+ .post_select = dccp_recv_post_select,
+};
PARA_ERROR(READ_PATTERN, "did not read expected pattern"), \
PARA_ERROR(RECV_EOF, "end of file"), \
PARA_ERROR(RECVMSG, "recvmsg() failed"), \
- PARA_ERROR(RECV_SYNTAX, "recv syntax error"), \
PARA_ERROR(REGEX, "regular expression error"), \
PARA_ERROR(RESAMPLE_EOF, "resample filter: end of file"), \
PARA_ERROR(RSA, "RSA error"), \
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
+#include <lopsub.h>
+#include "recv_cmd.lsg.h"
#include "para.h"
#include "error.h"
#include "http.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "recv.h"
-#include "http_recv.cmdline.h"
#include "net.h"
#include "string.h"
#include "fd.h"
free(rn->private_data);
}
-static void *http_recv_parse_config(int argc, char **argv)
-{
- struct http_recv_args_info *tmp = para_calloc(sizeof(*tmp));
-
- http_recv_cmdline_parser(argc, argv, tmp);
- return tmp;
-}
-
static int http_recv_open(struct receiver_node *rn)
{
struct private_http_recv_data *phd;
- struct http_recv_args_info *conf = rn->conf;
- int fd, ret = para_connect_simple(IPPROTO_TCP, conf->host_arg,
- conf->port_arg);
+ struct lls_parse_result *lpr = rn->lpr;
+ const char *r_i = RECV_CMD_OPT_STRING_VAL(HTTP, HOST, lpr);
+ uint32_t r_p = RECV_CMD_OPT_UINT32_VAL(HTTP, PORT, lpr);
+ int fd, ret = para_connect_simple(IPPROTO_TCP, r_i, r_p);
if (ret < 0)
return ret;
return 1;
}
-static void http_recv_free_config(void *conf)
-{
- http_recv_cmdline_parser_free(conf);
- free(conf);
-}
-
-/**
- * The init function of the http receiver.
- *
- * \param r Pointer to the receiver struct to initialize.
- *
- * This initializes all function pointers of \a r.
- */
-void http_recv_init(struct receiver *r)
-{
- struct http_recv_args_info dummy;
-
- http_recv_cmdline_parser_init(&dummy);
- r->open = http_recv_open;
- r->close = http_recv_close;
- r->pre_select = http_recv_pre_select;
- r->post_select = http_recv_post_select;
- r->parse_config = http_recv_parse_config;
- r->free_config = http_recv_free_config;
- r->help = (struct ggo_help)DEFINE_GGO_HELP(http_recv);
- http_recv_cmdline_parser_free(&dummy);
-}
+const struct receiver lsg_recv_cmd_com_http_user_data = {
+ .open = http_recv_open,
+ .close = http_recv_close,
+ .pre_select = http_recv_pre_select,
+ .post_select = http_recv_post_select,
+};
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Make an audio stream from a local file"
-
-description "
- The afh (audio format handler) receiver can be used to write
- selected parts of the given audio file without decoding
- the data.
-
- The selected parts of the content of the audio file are passed
- to the child nodes of the buffer tree. Only complete chunks
- with respect of the underlying audio format are passed.
-"
-
-include(header.m4)
-<qu>
-option "filename" f
-#~~~~~~~~~~~~~~~~~~
-"file to open"
-string typestr = "filename"
-required
-
-option "begin-chunk" b
-#~~~~~~~~~~~~~~~~~~~~~
-"skip the beginning of the file"
-int typestr = "chunk_num"
-default = "0"
-optional
-details = "
- The chunk_num argument must be between -num_chunks and
- num_chunks - 1, inclusively, where num_chunks is the total
- number of chunks of the audio file given by the argument to
- --filename. If chunk_num is negative, the given number of
- chunks are counted backwards from the end of the file. For
- example --begin-chunk -100 instructs the afh receiver to
- start output at chunk num_chunks - 100. This is useful for
- selecting the last part of an audio file.
-"
-
-option "end-chunk" e
-#~~~~~~~~~~~~~~~~~~~
-"only write up to chunk chunk_num"
-int typestr = "chunk_num"
-optional
-details = "
- For the chunk_num argument the same rules as for --begin-chunk
- apply. The default is to write up to the last chunk.
-"
-
-option "just-in-time" j
-#~~~~~~~~~~~~~~~~~~~~~~
-"use timed writes"
-flag off
-details = "
- Write the specified chunks of data 'just in time', i.e. the
- write of each chunk is delayed until the time it is needed
- by the decoder/player in order to guarantee an uninterrupted
- audio stream. This may be useful for third-party software
- that is capable of reading from stdin.
-"
-
-option "no-header" H
-#~~~~~~~~~~~~~~~~~~~
-"do not write an audio file header"
-flag off
-details = "
- If an audio format needs information about the audio file
- in a format-specific header in order to be understood by
- the decoding software, a suitable header is automatically
- send. This option changes the default behaviour, i.e. no
- header is written.
-"
-
-</qu>
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Receive a DCCP audio stream"
-
-option "host" i
-"ip or host"
-string default="localhost"
-optional
-details="
- Both IPv4 and IPv6 addresses are supported.
-"
-
-option "port" p
-"port to connect to"
-int
-default="8000"
-optional
-
-option "ccid" c
-"CCID preference(s) for this connection"
-int
-# restrict the maximum number of times this option can be passed
-optional multiple(-10)
-# currently known CCIDs:
-# - CCID-2 (RFC 4341),
-# - CCID-3 (RFC 4342),
-# - CCID-4 (RFC 5622),
-# - CCID-248 ... CCID-254 are experimental (RFC 4340, 19.5)
-values="2", "3", "4", "248", "249", "250", "251", "252", "253", "254"
-details="
- When present exactly once, this option mandates the CCID for the
- sender-receiver connection. If it is passed more than once, it sets
- a preference list where the order of appearance signifies descending
- priority. For example, passing 4, 2, 3 creates the preference list
- (CCID-4, CCID-2, CCID-3), assigning CCID-4 highest preference.
-
- The request is reconciled with the CCIDs on the server through the
- 'server-priority' mechanism of RFC 4340 6.3.1/10. The server CCIDs
- can be listed by calling 'para_client si'.
-
-"
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Receive an HTTP audio stream"
-
-include(header.m4)
-
-<qu>
-option "host" i
-#~~~~~~~~~~~~~~
-"ip or host"
-string
-default="localhost"
-optional
-details="
- Both IPv4 and IPv6 addresses are supported.
-"
-
-option "port" p
-#~~~~~~~~~~~~~~
-"tcp port to connect to"
-int default="8000"
-optional
-</qu>
+++ /dev/null
-args "--no-version --no-help"
-
-purpose "Receive an UDP audio stream"
-
-option "host" i
-"ip or host to receive udp packets from"
-string default="224.0.1.38"
-optional
-details="
- The default address resolves to DANTZ.MCAST.NET and activates
- multicast.
-"
-
-option "port" p "udp port"
-int typestr="portnumber"
-default="8000"
-optional
-
-option "iface" I "receiving udp multicast interface"
-string
-optional
--- /dev/null
+[option port]
+ short_opt = p
+ summary = TCP port to connect to
+ typestr = portnumber
+ arg_info = required_arg
+ arg_type = uint32
+ default_val = 8000
--- /dev/null
+[suite recv_cmd]
+caption = receivers
+[subcommand afh]
+ purpose = make an audio stream from a local file
+ [description]
+ The afh (audio format handler) receiver extracts selected parts of
+ the given audio file without decoding the file. Only complete chunks
+ with respect to the underlying audio format are extracted.
+ [/description]
+ [option filename]
+ short_opt = f
+ summary = file to open
+ typestr = filename
+ arg_info = required_arg
+ arg_type = string
+ [option begin-chunk]
+ short_opt = b
+ summary = skip the beginning of the file
+ typestr = chunk_num
+ arg_info = required_arg
+ arg_type = int32
+ [help]
+ The argument must be an integer between -num_chunks and num_chunks -
+ 1, inclusively, where num_chunks is the total number of chunks. If
+ chunk_num is negative, the given number of chunks are counted backwards
+ from the end of the file. For example --begin-chunk -100 instructs
+ the afh receiver to start at chunk num_chunks - 100. This is useful
+ for cutting off the beginning of an audio file.
+ [/help]
+ [option end-chunk]
+ short_opt = e
+ summary = only write up to chunk chunk_num
+ typestr = chunk_num
+ arg_info = required_arg
+ arg_type = int32
+ [help]
+ For the chunk_num argument the same rules as for --begin-chunk
+ apply. The default is to write up to the last chunk.
+ [/help]
+ [option just-in-time]
+ short_opt = j
+ summary = use timed writes
+ [help]
+ Write the specified data chunks 'just in time', i.e., delay the write
+ until data is needed by the decoder/player for an uninterrupted audio
+ stream. This may be useful for third-party software.
+ [/help]
+ [option no-header]
+ short_opt = h
+ summary = do not write an audio file header
+ [help]
+ Some audio formats store information about the audio file in
+ a format-specific header which is needed to decode any part of
+ the file. For such formats the afh receiver generates a suitable
+ header. This option changes the default behaviour, i.e. no header
+ is written.
+ [/help]
+[subcommand http]
+ purpose = receive an audio stream over HTTP
+ m4_include(host.m4)
+ m4_include(port.m4)
+[subcommand dccp]
+ purpose = receive an audio stream over DCCP
+ m4_include(host.m4)
+ m4_include(port.m4)
+ [option ccid]
+ short_opt = c
+ summary = CCID preference(s) for this connection
+ typestr = id
+ arg_info = required_arg
+ arg_type = uint32
+ flag multiple
+ [help]
+ When present exactly once, this option mandates the CCID for the
+ sender-receiver connection. If it is passed more than once, it sets
+ a preference list where the order of appearance signifies descending
+ priority. For example, passing 4, 2, 3 creates the preference list
+ (CCID-4, CCID-2, CCID-3), assigning CCID-4 highest preference.
+
+ The request is reconciled with the CCIDs on the server through the
+ 'server-priority' mechanism of RFC 4340 6.3.1/10. The server CCIDs
+ can be listed by calling 'para_client si'.
+ [/help]
+[subcommand udp]
+ purpose = receive an audio stream over UDP
+ [option host]
+ short_opt = i
+ summary = IP address or hostname
+ typestr = host
+ arg_info = required_arg
+ arg_type = string
+ default_val = 224.0.1.38
+ [help]
+ The default address resolves to DANTZ.MCAST.NET and activates
+ multicast.
+ [/help]
+ m4_include(port.m4)
+ [option iface]
+ summary = receiving udp multicast interface
+ typestr = iface-name
+ arg_info = required_arg
+ arg_type = string
#!/usr/bin/env bash
-# Receivers, filters, writers are called "modules" in this script
+# filters, writers are called "modules" in this script
print_modhelp()
{
local ggo="$1"
--set-package "para_$1" \
< "$ggo"
- if [[ "$target" == 'recv' || "$target" == 'audiod' ]]; then
- for module in $RECEIVERS; do
- ggo="$GGO_DIR/${module}_recv.ggo"
- [[ ! -f "$ggo" ]] && continue
- printf "\nOptions for the $module receiver"
- print_modhelp "$ggo"
- done
- fi
if [[ "$target" == 'filter' || "$target" == 'audiod' ]]; then
for module in $FILTERS; do
ggo="$GGO_DIR/${module}_filter.ggo"
#include <inttypes.h>
#include <lopsub.h>
+#include "recv_cmd.lsg.h"
#include "para.h"
#include "list.h"
#include "play.cmdline.h"
.handler = com_ ## _cmd \
};
-/* Activate the afh receiver. */
-extern void afh_recv_init(struct receiver *r);
-#undef AFH_RECEIVER
-/** Initialization code for a receiver struct. */
-#define AFH_RECEIVER {.name = "afh", .init = afh_recv_init},
-/** This expands to the array of all receivers. */
-DEFINE_RECEIVER_ARRAY;
-
static int loglevel = LL_WARNING;
/** The log function which writes log messages to stderr. */
static struct sched sched = {.max_fileno = 0};
static struct play_task play_task;
-static struct receiver *afh_recv;
-static void check_afh_receiver_or_die(void)
-{
- int i;
-
- FOR_EACH_RECEIVER(i) {
- struct receiver *r = receivers + i;
- if (strcmp(r->name, "afh"))
- continue;
- afh_recv = r;
- return;
- }
- PARA_EMERG_LOG("fatal: afh receiver not found\n");
- exit(EXIT_FAILURE);
-}
+#define AFH_RECV_CMD (lls_cmd(LSG_RECV_CMD_CMD_AFH, recv_cmd_suite))
+#define AFH_RECV ((struct receiver *)lls_user_data(AFH_RECV_CMD))
__noreturn static void print_help_and_die(void)
{
return result;
}
+
static void wipe_receiver_node(struct play_task *pt)
{
PARA_NOTICE_LOG("cleaning up receiver node\n");
btr_remove_node(&pt->rn.btrn);
- afh_recv->close(&pt->rn);
- afh_recv->free_config(pt->rn.conf);
+ AFH_RECV->close(&pt->rn);
+ lls_free_parse_result(pt->rn.lpr, AFH_RECV_CMD);
memset(&pt->rn, 0, sizeof(struct receiver_node));
}
static struct btr_node *new_recv_btrn(struct receiver_node *rn)
{
return btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = afh_recv->name, .context = rn,
- .handler = afh_recv->execute));
+ EMBRACE(.name = lls_command_name(AFH_RECV_CMD), .context = rn,
+ .handler = AFH_RECV->execute));
}
static int open_new_file(struct play_task *pt)
{
int ret;
- char *tmp, *path = conf.inputs[pt->next_file], *afh_recv_conf[] =
- {"play", "-f", path, "-b", "0", NULL};
+ char *tmp, *path = conf.inputs[pt->next_file], *errctx = NULL,
+ *argv[] = {"play", "-f", path, "-b", "0", NULL};
PARA_NOTICE_LOG("next file: %s\n", path);
wipe_receiver_node(pt);
pt->start_chunk = 0;
pt->rn.btrn = new_recv_btrn(&pt->rn);
- pt->rn.conf = afh_recv->parse_config(ARRAY_SIZE(afh_recv_conf) - 1,
- afh_recv_conf);
- assert(pt->rn.conf);
- pt->rn.receiver = afh_recv;
- ret = afh_recv->open(&pt->rn);
+ ret = lls(lls_parse(ARRAY_SIZE(argv) - 1, argv, AFH_RECV_CMD,
+ &pt->rn.lpr, &errctx));
+ free(tmp);
+ assert(ret >= 0);
+ pt->rn.receiver = AFH_RECV;
+ ret = AFH_RECV->open(&pt->rn);
if (ret < 0) {
PARA_ERROR_LOG("could not open %s\n", path);
goto fail;
/* success, register tasks */
pt->rn.task = task_register(
&(struct task_info) {
- .name = afh_recv->name,
- .pre_select = afh_recv->pre_select,
- .post_select = afh_recv->post_select,
+ .name = lls_command_name(AFH_RECV_CMD),
+ .pre_select = AFH_RECV->pre_select,
+ .post_select = AFH_RECV->post_select,
.context = &pt->rn
}, &sched);
sprintf(buf, "%s decoder", af);
parse_config_or_die(argc, argv);
if (conf.inputs_num == 0)
print_help_and_die();
- check_afh_receiver_or_die();
-
+ AFH_RECV->init();
session_open(pt);
if (conf.randomize_given)
shuffle(conf.inputs, conf.inputs_num);
#include <regex.h>
#include <sys/types.h>
+#include <inttypes.h>
+#include <lopsub.h>
+#include "recv_cmd.lsg.h"
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "recv.h"
#include "recv.cmdline.h"
/** Array of error strings. */
DEFINE_PARA_ERRLIST;
-extern void afh_recv_init(struct receiver *r);
-#undef AFH_RECEIVER
-#define AFH_RECEIVER {.name = "afh", .init = afh_recv_init},
-DEFINE_RECEIVER_ARRAY;
-
/** The gengetopt args info struct. */
static struct recv_args_info conf;
__noreturn static void print_help_and_die(void)
{
- struct ggo_help h = DEFINE_GGO_HELP(recv);
bool d = conf.detailed_help_given;
-
- ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
- print_receiver_helps(d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS);
- exit(0);
+ if (d)
+ recv_cmdline_parser_print_detailed_help();
+ else
+ recv_cmdline_parser_print_help();
+ print_receiver_helps(d);
+ exit(EXIT_SUCCESS);
}
/**
*/
int main(int argc, char *argv[])
{
- int ret, r_opened = 0, receiver_num;
- struct receiver *r = NULL;
+ int ret;
+ bool r_opened = false;
+ const struct receiver *r = NULL;
struct receiver_node rn;
struct stdout_task sot = {.btrn = NULL};
static struct sched s;
struct task_info ti;
+ const struct lls_command *cmd;
+ struct lls_parse_result *receiver_lpr; /* receiver specific options */
recv_cmdline_parser(argc, argv, &conf);
loglevel = get_loglevel_by_name(conf.loglevel_arg);
print_help_and_die();
memset(&rn, 0, sizeof(struct receiver_node));
- rn.conf = check_receiver_arg(conf.receiver_arg, &receiver_num);
- if (!rn.conf) {
- PARA_EMERG_LOG("invalid receiver specifier\n");
- ret = -E_RECV_SYNTAX;
+ ret = check_receiver_arg(conf.receiver_arg, &receiver_lpr);
+ if (ret < 0)
goto out;
- }
- r = &receivers[receiver_num];
+ cmd = lls_cmd(ret, recv_cmd_suite);
+ r = lls_user_data(cmd);
rn.receiver = r;
+ rn.lpr = receiver_lpr;
rn.btrn = btr_new_node(&(struct btr_node_description)
- EMBRACE(.name = r->name));
+ EMBRACE(.name = lls_command_name(cmd)));
ret = r->open(&rn);
if (ret < 0)
- goto out;
- r_opened = 1;
+ goto free_receiver_lpr;
+ r_opened = true;
sot.btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.parent = rn.btrn, .name = "stdout"));
stdout_task_register(&sot, &s);
- ti.name = r->name;
+ ti.name = lls_command_name(cmd);
ti.pre_select = r->pre_select;
ti.post_select = r->post_select;
ti.context = &rn;
s.default_timeout.tv_usec = 0;
ret = schedule(&s);
sched_shutdown(&s);
+ r->close(&rn);
+ btr_remove_node(&sot.btrn);
+ btr_remove_node(&rn.btrn);
+free_receiver_lpr:
+ lls_free_parse_result(receiver_lpr, cmd);
out:
if (r_opened)
r->close(&rn);
btr_remove_node(&rn.btrn);
btr_remove_node(&sot.btrn);
- if (rn.conf)
- r->free_config(rn.conf);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
*/
struct receiver_node {
/** Points to the corresponding receiver. */
- struct receiver *receiver;
+ const struct receiver *receiver;
/** Receiver-specific data. */
void *private_data;
- /** Pointer to the configuration data for this instance. */
- void *conf;
+ /** The parsed command line options for this instance. */
+ struct lls_parse_result *lpr;
/** The task associated with this instance. */
struct task *task;
/** The receiver node is always the root of the buffer tree. */
*/
struct receiver {
/**
- * The name of the receiver.
- */
- const char *name;
- /**
- * The receiver init function.
+ * The optional receiver init function.
*
- * It must fill in all other function pointers and is assumed to succeed.
+ * Performs any initialization needed before the receiver can be opened.
*
* \sa http_recv_init udp_recv_init.
*/
- void (*init)(struct receiver *r);
- /**
- * The command line parser of the receiver.
- *
- * It should check whether the command line options given by \a argc
- * and \a argv are valid. On success, it should return a pointer to
- * the receiver-specific configuration data determined by \a argc and
- * \a argv. Note that this might be called more than once with
- * different values of \a argc and \a argv.
- */
- void *(*parse_config)(int argc, char **argv);
- /**
- * Deallocate the configuration structure of a receiver node.
- *
- * This calls the receiver-specific cleanup function generated by
- * gengetopt.
- */
- void (*free_config)(void *conf);
+ void (*init)(void);
/**
* Open one instance of the receiver.
*
*/
int (*post_select)(struct sched *s, void *context);
- /** The two help texts of this receiver. */
- struct ggo_help help;
/**
* Answer a buffer tree query.
*
btr_command_handler execute;
};
-/** Define an array of all available receivers. */
-#define DEFINE_RECEIVER_ARRAY struct receiver receivers[] = { \
- HTTP_RECEIVER \
- DCCP_RECEIVER \
- UDP_RECEIVER \
- AFH_RECEIVER \
- {.name = NULL}};
+#define RECV_CMD(_num) (lls_cmd(_num, recv_cmd_suite))
+
+#define RECV_CMD_OPT_RESULT(_recv, _opt, _lpr) \
+ (lls_opt_result(LSG_RECV_CMD_ ## _recv ## _OPT_ ## _opt, _lpr))
+#define RECV_CMD_OPT_GIVEN(_recv, _opt, _lpr) \
+ (lls_opt_given(RECV_CMD_OPT_RESULT(_recv, _opt, _lpr)))
+#define RECV_CMD_OPT_STRING_VAL(_recv, _opt, _lpr) \
+ (lls_string_val(0, RECV_CMD_OPT_RESULT(_recv, _opt, _lpr)))
+#define RECV_CMD_OPT_UINT32_VAL(_recv, _opt, _lpr) \
+ (lls_uint32_val(0, RECV_CMD_OPT_RESULT(_recv, _opt, _lpr)))
+#define RECV_CMD_OPT_INT32_VAL(_recv, _opt, _lpr) \
+ (lls_int32_val(0, RECV_CMD_OPT_RESULT(_recv, _opt, _lpr)))
/** Iterate over all available receivers. */
-#define FOR_EACH_RECEIVER(i) for (i = 0; receivers[i].name; i++)
+#define FOR_EACH_RECEIVER(i) for (i = 1; lls_cmd(i, recv_cmd_suite); i++)
void recv_init(void);
-void *check_receiver_arg(char *ra, int *receiver_num);
-void print_receiver_helps(unsigned flags);
+int check_receiver_arg(const char *ra, struct lls_parse_result **lprp);
+void print_receiver_helps(bool detailed);
int generic_recv_pre_select(struct sched *s, struct receiver_node *rn);
-
-/** \cond receiver */
-extern void http_recv_init(struct receiver *r);
-#define HTTP_RECEIVER {.name = "http", .init = http_recv_init},
-extern void dccp_recv_init(struct receiver *r);
-#define DCCP_RECEIVER {.name = "dccp", .init = dccp_recv_init},
-extern void udp_recv_init(struct receiver *r);
-#define UDP_RECEIVER {.name = "udp", .init = udp_recv_init},
-#define AFH_RECEIVER /* not active by default */
-
-extern struct receiver receivers[];
-/** \endcond receiver */
-
/** \file recv_common.c common functions of para_recv and para_audiod */
#include <regex.h>
+#include <inttypes.h>
+#include <lopsub.h>
+#include "recv_cmd.lsg.h"
#include "para.h"
+#include "error.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "recv.h"
#include "string.h"
{
int i;
- FOR_EACH_RECEIVER(i)
- receivers[i].init(&receivers[i]);
-}
-
-static void *parse_receiver_args(int receiver_num, char *options)
-{
- struct receiver *r = &receivers[receiver_num];
- char **argv;
- int argc;
- void *conf;
-
- if (options) {
- argc = create_shifted_argv(options, " \t", &argv);
- if (argc < 0)
- return NULL;
- } else {
- argc = 1;
- argv = para_malloc(2 * sizeof(char*));
- argv[1] = NULL;
+ FOR_EACH_RECEIVER(i) {
+ const struct lls_command *cmd = RECV_CMD(i);
+ const struct receiver *r = lls_user_data(cmd);
+ if (r && r->init)
+ r->init();
}
- argv[0] = make_message("%s_recv", r->name);
- conf = r->parse_config(argc, argv);
- free_argv(argv);
- return conf;
}
/**
* Check if the given string is a valid receiver specifier.
*
- * \param \ra string of the form receiver_name:options
- * \param receiver_num contains the number of the receiver upon success
+ * \param \ra string of the form receiver_name [options...]
+ * \param lprp Filled in on success, undefined else.
*
* This function checks whether \a ra starts with the name of a receiver,
* optionally followed by options for that receiver. If a valid receiver name
* was found the remaining part of \a ra is passed to the receiver's config
* parser.
*
- * \return On success, a pointer to the receiver-specific gengetopt args info
- * struct is returned and \a receiver_num contains the number of the receiver.
- * On errors, the function returns \p NULL.
+ * If a NULL pointer or an empty string is passed as the first argument, the
+ * hhtp receiver with no options is assumed.
+ *
+ * \return On success the number of the receiver is returned. On errors, the
+ * function calls exit(EXIT_FAILURE).
*/
-void *check_receiver_arg(char *ra, int *receiver_num)
+int check_receiver_arg(const char *ra, struct lls_parse_result **lprp)
{
- int j;
+ int ret, argc, receiver_num;
+ char *errctx = NULL, **argv;
+ const struct lls_command *cmd;
- PARA_DEBUG_LOG("checking %s\n", ra);
- for (j = 0; receivers[j].name; j++) {
- const char *name = receivers[j].name;
- size_t len = strlen(name);
- char c;
- if (strlen(ra) < len)
- continue;
- if (strncmp(name, ra, len))
- continue;
- c = ra[len];
- if (c && c != ' ')
- continue;
- if (c && !receivers[j].parse_config)
- return NULL;
- *receiver_num = j;
- return parse_receiver_args(j, c? ra + len + 1: NULL);
+ *lprp = NULL;
+ if (!ra || !*ra) {
+ argc = 1;
+ argv = para_malloc(2 * sizeof(char*));
+ argv[0] = para_strdup("http");
+ argv[1] = NULL;
+ } else {
+ ret = create_argv(ra, " \t\n", &argv);
+ if (ret < 0) {
+ PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+ exit(EXIT_FAILURE);
+ }
+ argc = ret;
}
- PARA_ERROR_LOG("receiver not found\n");
- return NULL;
+ ret = lls(lls_lookup_subcmd(argv[0], recv_cmd_suite, &errctx));
+ if (ret < 0) {
+ PARA_EMERG_LOG("%s: %s\n", errctx? errctx : argv[0],
+ para_strerror(-ret));
+ exit(EXIT_FAILURE);
+ }
+ receiver_num = ret;
+ cmd = RECV_CMD(receiver_num);
+ ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx));
+ if (ret < 0) {
+ if (errctx)
+ PARA_ERROR_LOG("%s\n", errctx);
+ PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+ exit(EXIT_FAILURE);
+ }
+ ret = receiver_num;
+ free_argv(argv);
+ return ret;
}
/**
* Print out the help texts to all receivers.
*
- * \param flags Passed to \ref ggo_print_help().
+ * \param detailed Whether to print the short or the detailed help.
*/
-void print_receiver_helps(unsigned flags)
+void print_receiver_helps(bool detailed)
{
int i;
- printf_or_die("\nAvailable receivers: ");
- FOR_EACH_RECEIVER(i)
- printf_or_die("%s%s", i? " " : "", receivers[i].name);
- printf_or_die("\n");
+ printf("\nAvailable receivers: ");
+ FOR_EACH_RECEIVER(i) {
+ const struct lls_command *cmd = RECV_CMD(i);
+ printf("%s%s", i? " " : "", lls_command_name(cmd));
+ }
+ printf("\n\n");
FOR_EACH_RECEIVER(i) {
- struct receiver *r = receivers + i;
- if (!r->help.short_help)
+ const struct lls_command *cmd = RECV_CMD(i);
+ char *help = detailed? lls_long_help(cmd) : lls_short_help(cmd);
+ if (!help)
continue;
- printf_or_die("\n%s: %s", r->name,
- r->help.purpose);
- ggo_print_help(&r->help, flags);
+ printf("%s\n", help);
+ free(help);
}
}
# in the man pages
regex="$rfw_regex"
-test_expect_success 'para_recv: receiver options' "grep_man '$regex' recv"
+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_write: writer options' "grep_man '$regex' write"
test_require_objects "audiod"
test_skip 'para_audiod' "missing object(s): $result"
else
test_expect_success 'para_audiod: receivers' \
- "grep_man 'Options for the http receiver' audiod"
+ "grep_man 'RECEIVERS' audiod"
test_expect_success 'para_audiod: filters' \
"grep_man 'Options for the compress filter' audiod"
test_expect_success 'para_audiod: writers' \
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
+#include <lopsub.h>
+#include "recv_cmd.lsg.h"
#include "para.h"
#include "error.h"
#include "portable_io.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "recv.h"
-#include "udp_recv.cmdline.h"
#include "string.h"
#include "net.h"
#include "fd.h"
btr_pool_free(rn->btrp);
}
-static void *udp_recv_parse_config(int argc, char **argv)
-{
- struct udp_recv_args_info *tmp = para_calloc(sizeof(*tmp));
- udp_recv_cmdline_parser(argc, argv, tmp);
- return tmp;
-}
-
/*
* Perform AF-independent joining of multicast receive addresses.
*
static int udp_recv_open(struct receiver_node *rn)
{
- struct udp_recv_args_info *c = rn->conf;
- char *iface = c->iface_given ? c->iface_arg : NULL;
+ struct lls_parse_result *lpr = rn->lpr;
+ const char *iface = RECV_CMD_OPT_STRING_VAL(UDP, IFACE, lpr);
+ const char *host = RECV_CMD_OPT_STRING_VAL(UDP, HOST, lpr);
+ uint32_t port = RECV_CMD_OPT_UINT32_VAL(UDP, PORT, lpr);
int ret;
- ret = makesock(IPPROTO_UDP, 1, c->host_arg, c->port_arg, NULL);
+ ret = makesock(IPPROTO_UDP, 1, host, port, NULL);
if (ret < 0)
- goto err;
+ return ret;
rn->fd = ret;
-
ret = mcast_receiver_setup(rn->fd, iface);
- if (ret < 0) {
- close(rn->fd);
+ if (ret < 0)
goto err;
- }
-
ret = mark_fd_nonblocking(rn->fd);
- if (ret < 0) {
- close(rn->fd);
+ if (ret < 0)
goto err;
- }
- PARA_INFO_LOG("receiving from %s:%d, fd=%d\n", c->host_arg,
- c->port_arg, rn->fd);
+ PARA_INFO_LOG("receiving from %s:%u, fd=%d\n", host, port, rn->fd);
rn->btrp = btr_pool_new("udp_recv", 320 * 1024);
return rn->fd;
err:
+ close(rn->fd);
return ret;
}
-static void udp_recv_free_config(void *conf)
-{
- udp_recv_cmdline_parser_free(conf);
- free(conf);
-}
-
-/**
- * The init function of the udp receiver.
- *
- * \param r Pointer to the receiver struct to initialize.
- *
- * Initialize all function pointers of \a r.
- */
-void udp_recv_init(struct receiver *r)
-{
- struct udp_recv_args_info dummy;
-
- udp_recv_cmdline_parser_init(&dummy);
- r->open = udp_recv_open;
- r->close = udp_recv_close;
- r->pre_select = udp_recv_pre_select;
- r->post_select = udp_recv_post_select;
- r->parse_config = udp_recv_parse_config;
- r->free_config = udp_recv_free_config;
- r->help = (struct ggo_help)DEFINE_GGO_HELP(udp_recv);
- udp_recv_cmdline_parser_free(&dummy);
-}
+const struct receiver lsg_recv_cmd_com_udp_user_data = {
+ .open = udp_recv_open,
+ .close = udp_recv_close,
+ .pre_select = udp_recv_pre_select,
+ .post_select = udp_recv_post_select,
+};