summaryrefslogtreecommitdiff
path: root/recv.c
blob: 31908bf3421ecfb6f05e782e1297f23bae95112e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* 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 <sys/types.h>
#include <lopsub.h>

#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;
}