/* SPDX-License-Identifier: GPL-2.0 */ /** \file write_common.c common functions of para_audiod and para_write */ #include #include "write_cmd.lsg.h" #include "para.h" #include "string.h" #include "list.h" #include "sched.h" #include "buffer_tree.h" #include "write.h" #include "error.h" /* Loop over all writers. */ #define FOR_EACH_WRITER(i) for (i = 1; lls_cmd(i, write_cmd_suite); i++) static inline bool writer_supported(int wid) { return lls_user_data(WRITE_CMD(wid)); } /* simply return the first available writer */ static int default_writer_id(void) { int i; FOR_EACH_WRITER(i) if (writer_supported(i)) return i; assert(0); /* the file writer should always be available */ } /** * Return the writer structure from a writer ID. * * \param wid If non-positive, a pointer to the default writer is returned. * * \return Pointer to a (constant) struct writer. */ const struct writer *writer_get(int wid) { if (wid <= 0) wid = default_writer_id(); return lls_user_data(WRITE_CMD(wid)); } /** * Return name of the writer identified by a writer ID. * * \param wid If non-positive, the name of the default writer is returned. * * \return The returned buffer must not be freed by the caller. */ const char *writer_name(int wid) { if (wid <= 0) wid = default_writer_id(); return lls_command_name(WRITE_CMD(wid)); } /** * Check if the given string is a valid writer argument. * * \param wa String of the form writer_name options. * \param lprp Contains the parsed command line on success. * * If the argument is NULL, the (configuration-dependent) default writer * and no arguments are assumed. Otherwise, the function makes sure that * the argument starts with the name of a supported writer and splits the * remaining part of the argument. In the second step the thusly obtained * arguments are passed to the configuration parser determined in the first * step, returning the parse result via the second argument to the function. * * \return On success, the positive writer ID is returned. Otherwise the * function prints an error message and calls exit(3). */ int check_writer_arg_or_die(const char *wa, struct lls_parse_result **lprp) { int ret, writer_num, argc; char **argv = NULL, *errctx = NULL; const struct lls_command *cmd; if (!wa || !*wa) { writer_num = default_writer_id(); cmd = WRITE_CMD(writer_num); argv = alloc(2 * sizeof(char *)); argc = 1; argv[0] = para_strdup(lls_command_name(cmd)); argv[1] = NULL; goto parse; } ret = create_argv(wa, " \t\n", &argv); if (ret < 0) goto fail; argc = ret; ret = lls(lls_lookup_subcmd(argv[0], write_cmd_suite, &errctx)); if (ret < 0) goto free_argv; writer_num = ret; cmd = WRITE_CMD(writer_num); if (!writer_supported(writer_num)) { ret = -ERRNO_TO_PARA_ERROR(EINVAL); errctx = make_message("%s writer is not supported", lls_command_name(cmd)); goto free_argv; } parse: ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx)); if (ret >= 0) ret = writer_num; free_argv: free_argv(argv); if (ret >= 0) return ret; fail: if (errctx) PARA_ERROR_LOG("%s\n", errctx); free(errctx); PARA_EMERG_LOG("%s\n", para_strerror(-ret)); exit(EXIT_FAILURE); } /** * Open a writer node and register the corresponding task. * * \param wn The writer node to open. * \param parent The parent btr node (the source for the writer node). * \param s The scheduler instance to register the task to. */ void register_writer_node(struct writer_node *wn, struct btr_node *parent, struct sched *s) { const struct writer *w = writer_get(wn->wid); wn->btrn = btr_new_node(&(struct btr_node_description) EMBRACE(.name = writer_name(wn->wid), .parent = parent, .context = wn)); wn->task = task_register(&(struct task_info) { .name = writer_name(wn->wid), .pre_monitor = w->pre_monitor, .post_monitor = w->post_monitor, .context = wn, }, s); } /** * Print the help text of all writers to stdout. * * \param detailed Whether to print the short or the detailed help. */ void print_writer_helps(bool detailed) { int i; printf("\nAvailable writers: "); FOR_EACH_WRITER(i) { if (!writer_supported(i)) continue; printf("%s%s", i? " " : "", writer_name(i)); } printf("\n"); FOR_EACH_WRITER(i) { const struct lls_command *cmd = WRITE_CMD(i); char *help; if (!writer_supported(i)) continue; help = detailed? lls_long_help(cmd) : lls_short_help(cmd); if (!help) continue; printf("%s\n", help); free(help); } } static int get_btr_value(struct btr_node *btrn, const char *cmd, int32_t *result) { char *buf = NULL; int ret = btr_exec_up(btrn, cmd, &buf); *result = 0; /* * Errors may happen when the decoder returns EOF before the writer had * a chance to query the buffer tree for the channel count, sample rate * etc. */ if (ret < 0) return ret; ret = para_atoi32(buf, result); assert(ret >= 0); free(buf); return ret; } /** * Ask parent buffer tree nodes for the sample rate of the current stream. * * \param btrn Where to start the search. * \param result Filled in by this function. * * \return Standard. */ int get_btr_sample_rate(struct btr_node *btrn, int32_t *result) { return get_btr_value(btrn, "sample_rate", result); } /** * Ask parent buffer tree nodes for the channel count of the current stream. * * \param btrn See \ref get_btr_sample_rate. * \param result See \ref get_btr_sample_rate. * * \return Standard. */ int get_btr_channels(struct btr_node *btrn, int32_t *result) { return get_btr_value(btrn, "channels", result); } /** * Ask parent nodes for the number of bits per sample and the byte sex. * * \param btrn See \ref get_btr_sample_rate. * \param result Contains the sample format as an enum sample_format type. * * \return Standard. */ int get_btr_sample_format(struct btr_node *btrn, int32_t *result) { return get_btr_value(btrn, "sample_format", result); }