/* SPDX-License-Identifier: GPL-2.0 */ /** \file recv.c the stand-alone audio stream receiver * * This file contains the main function of para_recv(1). All receivers and * the stdout buffer tree node are linked into the executable. The file * does not define any public symbols, but calls some of the helpers of * \ref recv_common.c to check the receiver arguments, then calls into \ref * stdout.c to register the stdout task. * * \cond doxygen_ignore */ #include #include #include "recv_cmd.lsg.h" #include "recv.lsg.h" #include "para.h" #include "list.h" #include "sched.h" #include "buffer_tree.h" #include "recv.h" #include "string.h" #include "error.h" #include "stdout.h" /* Array of error strings. */ DEFINE_PARA_ERRLIST; #define CMD_PTR (lls_cmd(0, recv_suite)) #define OPT_RESULT(_name, _lpr) \ (lls_opt_result(LSG_RECV_PARA_RECV_OPT_ ## _name, lpr)) #define OPT_GIVEN(_name, _lpr) (lls_opt_given(OPT_RESULT(_name, _lpr))) #define OPT_UINT32_VAL(_name, _lpr) (lls_uint32_val(0, OPT_RESULT(_name, _lpr))) #define OPT_STRING_VAL(_name, _lpr) (lls_string_val(0, OPT_RESULT(_name, _lpr))) static int loglevel; /* Always log to stderr. */ INIT_STDERR_LOGGING(loglevel); static void handle_help_flag(struct lls_parse_result *lpr) { char *help; if (OPT_GIVEN(DETAILED_HELP, lpr)) help = lls_long_help(CMD_PTR); else if (OPT_GIVEN(HELP, lpr)) help = lls_short_help(CMD_PTR); else return; printf("%s\n", help); free(help); print_receiver_helps(OPT_GIVEN(DETAILED_HELP, lpr)); exit(EXIT_SUCCESS); } /** \endcond * * The main function of para_recv(1). * * \param argc Options are defined in the recv lopsub suite. * * \param argv The recv_cmd suite file defines the various receivers and their * options. Each receiver corresponds to a lopsub subcommand of this suite. * * para_recv receives an audio stream and writes received it to stdout. * If the afh receiver is specified, the stream is "received" from a local * audio file. Otherwise, it is received from the network. In any case, * a buffer tree with two nodes is created where the root node corresponds * to the given receiver. Its child node corresponds to the stdout task. * * \return EXIT_SUCCESS on success, EXIT_FAILURE on errors. */ int main(int argc, char *argv[]) { int ret; const struct receiver *r = NULL; struct receiver_node rn; struct stdout_task *sot; static struct sched *s; struct task_info ti; const struct lls_command *cmd; struct lls_parse_result *lpr; /* command line */ struct lls_parse_result *receiver_lpr; /* receiver specific options */ char *errctx; ret = lls(lls_parse(argc, argv, CMD_PTR, &lpr, &errctx)); if (ret < 0) goto out; loglevel = OPT_UINT32_VAL(LOGLEVEL, lpr); version_handle_flag("recv", OPT_GIVEN(VERSION, lpr)); handle_help_flag(lpr); memset(&rn, 0, sizeof(struct receiver_node)); ret = check_receiver_arg(OPT_STRING_VAL(RECEIVER, lpr), &receiver_lpr); if (ret < 0) goto free_lpr; 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 = lls_command_name(cmd))); ret = r->open(&rn); if (ret < 0) goto remove_btrn; s = sched_new(NULL); sot = stdout_new(rn.btrn); stdout_register(sot, s); ti.name = lls_command_name(cmd); ti.pre_monitor = r->pre_monitor; ti.post_monitor = r->post_monitor; ti.context = &rn; rn.task = task_register(&ti, s); ret = schedule(s); sched_shutdown(s); r->close(&rn); stdout_free(sot); remove_btrn: btr_remove_node(&rn.btrn); lls_free_parse_result(receiver_lpr, cmd); free_lpr: lls_free_parse_result(lpr, CMD_PTR); out: if (ret < 0) { if (errctx) PARA_ERROR_LOG("%s\n", errctx); free(errctx); PARA_ERROR_LOG("%s\n", para_strerror(-ret)); } return ret < 0? EXIT_FAILURE : EXIT_SUCCESS; }