Merge branch 'refs/heads/t/afh-preserve'
[paraslash.git] / write_common.c
1 /* Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file write_common.c common functions of para_audiod and para_write */
4
5 #include <regex.h>
6 #include <lopsub.h>
7
8 #include "write_cmd.lsg.h"
9 #include "para.h"
10 #include "string.h"
11 #include "list.h"
12 #include "sched.h"
13 #include "buffer_tree.h"
14 #include "write.h"
15 #include "error.h"
16
17 /** Loop over all writers. */
18 #define FOR_EACH_WRITER(i) for (i = 1; lls_cmd(i, write_cmd_suite); i++)
19
20
21 static inline bool writer_supported(int wid)
22 {
23         return lls_user_data(WRITE_CMD(wid));
24 }
25
26 /* simply return the first available writer */
27 static int default_writer_id(void)
28 {
29         int i;
30
31         FOR_EACH_WRITER(i)
32                 if (writer_supported(i))
33                         return i;
34         assert(0); /* the file writer should always be available */
35 }
36
37 /**
38  * Return the writer structure from a writer ID.
39  *
40  * \param wid If non-positive, a pointer to the default writer is returned.
41  *
42  * \return Pointer to a (constant) struct writer.
43  */
44 const struct writer *writer_get(int wid)
45 {
46         if (wid < 0)
47                 wid = default_writer_id();
48         return lls_user_data(WRITE_CMD(wid));
49 }
50
51 /**
52  * Return name of the writer identified by a writer ID.
53  *
54  * \param wid If non-positive, the name of the default writer is returned.
55  *
56  * \return The returned buffer must not be freed by the caller.
57  */
58 const char *writer_name(int wid)
59 {
60         if (wid <= 0)
61                 wid = default_writer_id();
62         return lls_command_name(WRITE_CMD(wid));
63 }
64
65 /**
66  * Check if the given string is a valid command line for any writer.
67  *
68  * \param wa String of the form writer_name options.
69  * \param lprp Contains the parsed command line on success.
70  *
71  * If wa is \p NULL, the (configuration-dependent) default writer is assumed.
72  * Otherwise, the function checks whether \a wa starts with the name of a
73  * supported writer. If a valid writer name was found, the rest of the command
74  * line is passed to the config parser of this writer.
75  *
76  * \return On success, the positive writer ID is returned. Otherwise the
77  * function prints an error message and calls exit().
78  */
79 int check_writer_arg_or_die(const char *wa, struct lls_parse_result **lprp)
80 {
81         int ret, writer_num, argc;
82         char **argv = NULL, *errctx = NULL;
83         const struct lls_command *cmd;
84
85         if (!wa || !*wa) {
86                 writer_num = default_writer_id();
87                 cmd = WRITE_CMD(writer_num);
88                 argv = para_malloc(2 * sizeof(char *));
89                 argc = 1;
90                 argv[0] = para_strdup(lls_command_name(cmd));
91                 argv[1] = NULL;
92                 goto parse;
93         }
94         ret = create_argv(wa, " \t\n", &argv);
95         if (ret < 0)
96                 goto fail;
97         argc = ret;
98         ret = lls(lls_lookup_subcmd(argv[0], write_cmd_suite, &errctx));
99         if (ret < 0)
100                 goto free_argv;
101         writer_num = ret;
102         cmd = WRITE_CMD(writer_num);
103         if (!writer_supported(writer_num)) {
104                 ret = -ERRNO_TO_PARA_ERROR(EINVAL);
105                 errctx = make_message("%s writer is not supported",
106                         lls_command_name(cmd));
107                 goto free_argv;
108         }
109 parse:
110         ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx));
111         if (ret >= 0)
112                 ret = writer_num;
113 free_argv:
114         free_argv(argv);
115         if (ret >= 0)
116                 return ret;
117 fail:
118         if (errctx)
119                 PARA_ERROR_LOG("%s\n", errctx);
120         free(errctx);
121         PARA_EMERG_LOG("%s\n", para_strerror(-ret));
122         exit(EXIT_FAILURE);
123 }
124
125 /**
126  * Open a writer node and register the corresponding task.
127  *
128  * \param wn The writer node to open.
129  * \param parent The parent btr node (the source for the writer node).
130  * \param s The scheduler instance to register the task to.
131  */
132 void register_writer_node(struct writer_node *wn, struct btr_node *parent,
133                 struct sched *s)
134 {
135         const struct writer *w = writer_get(wn->wid);
136
137         wn->btrn = btr_new_node(&(struct btr_node_description)
138                 EMBRACE(.name = writer_name(wn->wid), .parent = parent,
139                 .handler = w->execute, .context = wn));
140         wn->task = task_register(&(struct task_info) {
141                 .name = writer_name(wn->wid),
142                 .pre_select = w->pre_select,
143                 .post_select = w->post_select,
144                 .context = wn,
145         }, s);
146 }
147
148 /**
149  * Print the help text of all writers to stdout.
150  *
151  * \param detailed Whether to print the short or the detailed help.
152  */
153 void print_writer_helps(bool detailed)
154 {
155         int i;
156
157         printf("\nAvailable writers: ");
158         FOR_EACH_WRITER(i) {
159                 if (!writer_supported(i))
160                         continue;
161                 printf("%s%s", i? " " : "", writer_name(i));
162         }
163         printf("\n");
164         FOR_EACH_WRITER(i) {
165                 const struct lls_command *cmd = WRITE_CMD(i);
166                 char *help;
167                 if (!writer_supported(i))
168                         continue;
169                 help = detailed? lls_long_help(cmd) : lls_short_help(cmd);
170                 if (!help)
171                         continue;
172                 printf("%s\n", help);
173                 free(help);
174         }
175 }
176
177 static void get_btr_value(struct btr_node *btrn, const char *cmd,
178                 int32_t *result)
179 {
180         char *buf = NULL;
181         int ret = btr_exec_up(btrn, cmd, &buf);
182
183         if (ret < 0) {
184                 /*
185                  * This really should not happen. It means one of our parent
186                  * nodes died unexpectedly. Proceed with fingers crossed.
187                  */
188                 PARA_CRIT_LOG("cmd %s: %s\n", cmd, para_strerror(-ret));
189                 *result = 0;
190                 return;
191         }
192         ret = para_atoi32(buf, result);
193         assert(ret >= 0);
194         free(buf);
195 }
196
197 /**
198  * Ask parent btr nodes for the sample rate of the current stream.
199  *
200  * \param btrn Where to start the search.
201  * \param result Filled in by this function.
202  *
203  * This function is assumed to succeed and terminates on errors.
204  */
205 void get_btr_sample_rate(struct btr_node *btrn, int32_t *result)
206 {
207         get_btr_value(btrn, "sample_rate", result);
208 }
209
210 /**
211  * Ask parent btr nodes for the channel count of the current stream.
212  *
213  * \param btrn See \ref get_btr_sample_rate.
214  * \param result See \ref get_btr_sample_rate.
215  */
216 void get_btr_channels(struct btr_node *btrn, int32_t *result)
217 {
218         get_btr_value(btrn, "channels", result);
219 }
220
221 /**
222  * Ask parent btr nodes for the number of bits per sample and the byte sex.
223  *
224  * \param btrn See \ref get_btr_sample_rate.
225  * \param result Contains the sample format as an enum sample_format type.
226  */
227 void get_btr_sample_format(struct btr_node *btrn, int32_t *result)
228 {
229         get_btr_value(btrn, "sample_format", result);
230 }