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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
/* SPDX-License-Identifier: GPL-2.0 */
/** \file filter_common.c Common helper functions for filter input/output. */
#include <sys/types.h>
#include <lopsub.h>
#include "filter_cmd.lsg.h"
#include "para.h"
#include "list.h"
#include "sched.h"
#include "fd.h"
#include "buffer_tree.h"
#include "filter.h"
#include "error.h"
#include "string.h"
/** Iterate over all filters. */
#define FOR_EACH_FILTER(j) for (j = 1; FILTER_CMD(j); j++)
/**
* Obtain a reference to a filter structure.
*
* \param filter_num Between zero and NUM_SUPPORTED_FILTERS, inclusively.
*
* \return Pointer to the filter identified by the given filter number, or
* NULL if the filter number is out of range.
*
* \sa filter_name().
*/
const struct filter *filter_get(int filter_num)
{
if (filter_num < 1 || filter_num > LSG_NUM_FILTER_CMD_SUBCOMMANDS)
return NULL;
return lls_user_data(FILTER_CMD(filter_num));
}
static inline bool filter_supported(int filter_num)
{
return lls_user_data(FILTER_CMD(filter_num));
}
/**
* Return the name of a filter, given its number.
*
* \param filter_num See \ref filter_get().
*
* \return A pointer to a string literal, or NULL if filter_num is out of
* range. The caller must not attempt to call free(3) on the returned pointer.
*/
const char *filter_name(int filter_num)
{
if (filter_num < 1 || filter_num > LSG_NUM_FILTER_CMD_SUBCOMMANDS)
return NULL;
return lls_command_name(FILTER_CMD(filter_num));
}
/**
* Parse a filter command line and call the corresponding ->setup method.
*
* \param fa The filter argument.
* \param conf Points to filter-specific setup upon successful return.
* \param lprp Parsed command line options are returned here.
*
* Check if the given filter argument starts with the name of a supported
* filter, optionally followed by options for this filter. If yes, call the
* command line parser of that filter and its ->setup method.
*
* \return On success, the number of the filter is returned and conf is
* initialized to point to the filter configuration as returned by the filter's
* ->setup() method, if any. Moreover, *lprp is initialized to contain the
* parsed command line options. On errors a negative paraslash error code is
* returned.
*/
int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp)
{
int ret, filter_num, argc;
char *errctx = NULL, **argv;
const struct lls_command *cmd;
const struct filter *f;
*lprp = NULL;
ret = create_argv(fa, " \t\n", &argv);
if (ret < 0)
return ret;
argc = ret;
ret = lls(lls_lookup_subcmd(argv[0], filter_cmd_suite, &errctx));
if (ret < 0)
goto free_argv;
filter_num = ret;
cmd = FILTER_CMD(filter_num);
if (!filter_supported(filter_num)) {
ret = -E_UNSUPPORTED_FILTER;
errctx = make_message("bad filter name: %s",
lls_command_name(cmd));
goto free_argv;
}
ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx));
if (ret < 0)
goto free_argv;
f = filter_get(filter_num);
assert(f);
*conf = f->setup? f->setup(*lprp) : NULL;
ret = filter_num;
free_argv:
free_argv(argv);
if (ret >= 0)
return ret;
if (errctx)
PARA_ERROR_LOG("%s\n", errctx);
free(errctx);
return ret;
}
/**
* Print help text of each filter to stdout.
*
* \param detailed Whether to print short or long help.
*/
void print_filter_helps(bool detailed)
{
int i, num = 0;
printf("\nAvailable filters: ");
FOR_EACH_FILTER(i) {
if (!filter_supported(i))
continue;
if (num > 50) {
printf("\n ");
num = 0;
}
num += printf("%s%s", i? " " : "", filter_name(i));
}
printf("\n");
FOR_EACH_FILTER(i) {
const struct lls_command *cmd = FILTER_CMD(i);
char *help;
if (!filter_supported(i))
continue;
help = detailed? lls_long_help(cmd) : lls_short_help(cmd);
if (!help)
continue;
printf("%s\n", help);
free(help);
}
}
/**
* Print a short summary of all available filters to stdout.
*
* For each supported filter, the filter name and the purpose text is printed
* in a single line. Since no options are shown, the filter list is more
* concise than the text obtained from print_filter_helps().
*/
void print_filter_list(void)
{
int i;
printf("Available filters:\n");
FOR_EACH_FILTER(i) {
const struct lls_command *cmd = FILTER_CMD(i);
if (!filter_supported(i))
continue;
printf("%-9s %s\n", filter_name(i), lls_purpose(cmd));
}
}
/**
* Request a minimal timeout if not idle.
*
* \param s The scheduler instance.
* \param context Pointer to the filter node.
*
* If the buffer tree node of the given filter node has data available (or is
* in error state) a minimal I/O timeout is requested from the scheduler.
* Otherwise the function does nothing.
*/
void generic_filter_pre_monitor(struct sched *s, void *context)
{
struct filter_node *fn = context;
if (btr_node_status(fn->btrn, fn->min_iqs, BTR_NT_INTERNAL) != 0)
sched_min_delay(s);
}
#ifdef WORDS_BIGENDIAN
#define DECODER_SAMPLE_FORMAT SF_S16_BE
#else
#define DECODER_SAMPLE_FORMAT SF_S16_LE
#endif
/**
* Execute a btr command for a decoder.
*
* The buffer tree nodes of the writers ask the parent nodes about sample_rate,
* channels count and sample format. This function is called by all decoders to
* answer these queries.
*
* \param cmd The command to be executed by the child node.
* \param sample_rate Known to the decoder.
* \param channels Known to the decoder.
* \param result Ascii representation on the answer is stored here.
*
* \return Standard.
*/
int decoder_execute(const char *cmd, unsigned sample_rate, unsigned channels,
char **result)
{
if (!strcmp(cmd, "sample_rate")) {
if (sample_rate == 0)
return -E_BTR_NAVAIL;
*result = make_message("%u", sample_rate);
return 1;
}
if (!strcmp(cmd, "channels")) {
if (channels == 0)
return -E_BTR_NAVAIL;
*result = make_message("%u", channels);
return 1;
}
if (!strcmp(cmd, "sample_format")) {
*result = make_message("%d", DECODER_SAMPLE_FORMAT);
return 1;
}
return -ERRNO_TO_PARA_ERROR(ENOTSUP);
}
|