From a601afd9c3c5819a0f2361bf073b7c737dcdab45 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sun, 5 Jul 2009 22:35:29 +0200 Subject: [PATCH] Rewrite grab-client code. This gets rid of the gengetopt grab client command line parser and all the special treatment it caused. --- Makefile.in | 2 +- audiod.c | 5 +- audiod.cmd | 33 +++++- audiod.h | 2 +- audiod_command.c | 65 +----------- configure.ac | 2 +- error.h | 3 - filter.h | 10 +- filter_common.c | 2 +- ggo/grab_client.ggo | 33 ------ ggo/makefile | 11 -- grab_client.c | 242 +++++++++++++++++++++++--------------------- grab_client.h | 58 ++++++----- 13 files changed, 197 insertions(+), 271 deletions(-) delete mode 100644 ggo/grab_client.ggo diff --git a/Makefile.in b/Makefile.in index 8921a3c6..05d7b3e0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68,7 +68,7 @@ ggo_dir := ggo m4_ggos := afh audioc audiod client filter gui recv server write all_ggos := $(m4_ggos) dccp_recv oggdec_filter alsa_write oss_write fade http_recv \ osx_write udp_recv amp_filter compress_filter file_write \ - grab_client mp3dec_filter + mp3dec_filter ggo_generated := $(addsuffix .cmdline.c, $(all_ggos)) $(addsuffix .cmdline.h, $(all_ggos)) \ $(addsuffix .ggo, $(addprefix $(ggo_dir)/,$(m4_ggos))) diff --git a/audiod.c b/audiod.c index 2b6f1e69..29a8aa30 100644 --- a/audiod.c +++ b/audiod.c @@ -19,7 +19,6 @@ #include "ggo.h" #include "recv.h" #include "filter.h" -#include "grab_client.cmdline.h" #include "grab_client.h" #include "client.cmdline.h" #include "client.h" @@ -162,7 +161,7 @@ struct command_task { * \return The audio format number on success, -E_UNSUPPORTED_AUDIO_FORMAT if * \a name is not a supported audio format. */ -int get_audio_format_num(char *name) +int get_audio_format_num(const char *name) { int i; @@ -445,7 +444,7 @@ static void open_writers(int slot_num) stat_task->server_stream_start : *now; s->offset_seconds = stat_task->offset_seconds; s->seconds_total = stat_task->length_seconds; - activate_inactive_grab_clients(slot_num, s->format, s->fc); + activate_inactive_grab_clients(s->format, s->fc); } static int open_receiver(int format) diff --git a/audiod.cmd b/audiod.cmd index 2c6ea9b1..94f3ca04 100644 --- a/audiod.cmd +++ b/audiod.cmd @@ -14,11 +14,36 @@ H: on -> standby -> off -> on N: grab D: grab the audio stream L: -U: -- grab [grab_options] +U: -- grab -[n=] [-m[{s|p|a}]] [-i] [-o] [-f=] +H: H: grab ('splice') the audio stream at any position in the filter -H: chain and send that data back to the client. Try -H: para_audioc -- grab -h -H: for the list of available options. +H: chain and send that data back to the client. +H: +H: Options: +H: +H: -n Point of the filter chain to grab. Filters count from zero. +H: +H: -m Change grab mode. Defaults to sloppy grab if not given. +H: +H: -ms: sloppy grab +H: +H: -mp: pedantic grab +H: +H: -ma: aggressive grab +H: +H: The various grab modes only differ in what happens if the +H: file descriptor to write the grabbed audio data to is not +H: ready for writing (i.e. would block). Sloppy mode ignores +H: the write, pedantic mode aborts and aggressive mode tries +H: to write anyway. +H: +H: -i Grab the filter input instead of its output. +H: +H: -o One-shot mode: Stop grabbing if audio file changes. +H: +H: -f Only grab streams of this format (mp3, ogg, aac). The default is to +H: grab any stream. +H: --- N: help D: display command list or help for given command diff --git a/audiod.h b/audiod.h index 8108378a..18bf48ed 100644 --- a/audiod.h +++ b/audiod.h @@ -8,7 +8,7 @@ int num_filters(int audio_format_num); -int get_audio_format_num(char *name); +int get_audio_format_num(const char *name); /** enum of audio formats supported by para_audiod */ enum {AUDIOD_AUDIO_FORMATS_ENUM}; diff --git a/audiod_command.c b/audiod_command.c index e57283ce..da5a2dc5 100644 --- a/audiod_command.c +++ b/audiod_command.c @@ -16,7 +16,6 @@ #include "sched.h" #include "ggo.h" #include "filter.h" -#include "grab_client.cmdline.h" #include "grab_client.h" #include "error.h" @@ -214,68 +213,9 @@ int com_stat(int fd, int argc, char **argv) return ret; } -#if 0 -static struct filter_node *find_filter_node(int slot_num, int format, int filternum) +int com_grab(int fd, int argc, char **argv) { - int i; - - FOR_EACH_SLOT(i) { - struct slot_info *s = &slot[i]; - if (s->format < 0 || !s->fc) - continue; - if (slot_num >= 0 && slot_num != i) - continue; - if (format >= 0 && s->format != format) - continue; - if (num_filters(i) <= filternum) - continue; - /* success */ - return s->fc->filter_nodes + filternum; - } - return NULL; -} -#endif - -int com_grab(int fd, __a_unused int argc, __a_unused char **argv) -{ - client_write(fd, "grab is currently b0rken\n"); - close(fd); - return 1; -#if 0 - struct grab_client *gc; - struct filter_node *fn; - int i, err; - char *msg; - - gc = grab_client_new(fd, cmdline, &err); - if (!gc) - goto err_out; - fn = find_filter_node(gc->conf->slot_arg, gc->audio_format_num, gc->conf->filter_num_arg); - if (fn) - activate_grab_client(gc, fn); - return 1; -err_out: - if (err != -E_GC_HELP_GIVEN && err != -E_GC_VERSION_GIVEN) - return err; - if (err == -E_GC_HELP_GIVEN) { - msg = make_message("%s\n\n", grab_client_args_info_usage); - for (i = 0; grab_client_args_info_help[i]; i++) { - char *tmp = make_message("%s%s\n", msg, - grab_client_args_info_help[i]); - free(msg); - msg = tmp; - } - } else - msg = make_message("%s %s\n", - GRAB_CLIENT_CMDLINE_PARSER_PACKAGE, - GRAB_CLIENT_CMDLINE_PARSER_VERSION); - err = client_write(fd, msg); - free(msg); - if (err < 0) - return err; - close(fd); - return 1; -#endif + return grab_client_new(fd, argc, argv); } __noreturn int com_term(int fd, __a_unused int argc, __a_unused char **argv) @@ -390,6 +330,7 @@ out: } return ret; } + /** * Send the current audiod status to all connected stat clients. */ diff --git a/configure.ac b/configure.ac index fdc0b7ce..61421b5d 100644 --- a/configure.ac +++ b/configure.ac @@ -108,7 +108,7 @@ audioc_cmdline_objs="audioc.cmdline" audioc_errlist_objs="audioc string net fd" audioc_ldflags="" -audiod_cmdline_objs="audiod.cmdline grab_client.cmdline compress_filter.cmdline +audiod_cmdline_objs="audiod.cmdline compress_filter.cmdline http_recv.cmdline dccp_recv.cmdline file_write.cmdline client.cmdline audiod_command_list amp_filter.cmdline udp_recv.cmdline prebuffer_filter.cmdline sha1" diff --git a/error.h b/error.h index 59d0321f..f2e92c61 100644 --- a/error.h +++ b/error.h @@ -252,13 +252,10 @@ extern const char **para_errlist[]; #define GRAB_CLIENT_ERRORS \ - PARA_ERROR(PEDANTIC_GRAB, "fd not ready and pedantic grab requested"), \ PARA_ERROR(GC_WRITE, "grab client write error"), \ PARA_ERROR(BAD_GC_SLOT, "invalid slot requested by grab client"), \ PARA_ERROR(BAD_GC_FILTER_NUM, "invalid filter number given"), \ PARA_ERROR(GC_SYNTAX, "grab client syntax error"), \ - PARA_ERROR(GC_HELP_GIVEN, ""), /* not really an error */ \ - PARA_ERROR(GC_VERSION_GIVEN, ""), /* not really an error */ \ #define MP3DEC_FILTER_ERRORS \ diff --git a/filter.h b/filter.h index 0bb51f5a..23f47f44 100644 --- a/filter.h +++ b/filter.h @@ -95,18 +95,10 @@ struct filter_chain { struct filter_callback { /** All callbacks are organized in a doubly linked list. */ struct list_head node; - /** - * Private data. - * - * May be initialized by the application before registering the callback. This - * pointer is not used by the filter subsystem. It is provided for use within - * the input/output/close callback functions. - */ - void *data; /** * The input callback. * - * In not \p NULL, the filter subsystem calls this function whenever the filter + * If not \p NULL, the filter subsystem calls this function whenever the filter * consumed some or all of its input buffer. A pointer to the buffer of consumed * data, its length and a pointer to the own \a filter_callback structure are passed * to \a input_cb. The input callback is expected to return a negative value on errors. diff --git a/filter_common.c b/filter_common.c index 2c74e8c7..fbc5b66b 100644 --- a/filter_common.c +++ b/filter_common.c @@ -43,7 +43,7 @@ void filter_init(void) */ static void close_filter_callback(struct filter_callback *fcb) { - PARA_NOTICE_LOG("closing filter_callback %p, data: %p\n", fcb, fcb->data); + PARA_NOTICE_LOG("closing filter_callback %p\n", fcb); list_del(&fcb->node); fcb->close(fcb); } diff --git a/ggo/grab_client.ggo b/ggo/grab_client.ggo deleted file mode 100644 index 5527143b..00000000 --- a/ggo/grab_client.ggo +++ /dev/null @@ -1,33 +0,0 @@ -option "filter_num" f - "point of filter chain to grab" - int typestr="num" - default="0" - optional - -option "slot" s - "only grab this slot; grab any slot if negative" - int typestr="num" - default="-1" - optional - -option "audio_format" a - "only grab this type of input stream; - grab any if empty" - string typestr="name" - default="" - optional - -option "input_grab" i - "grab the filter input instead of its output" - flag off - -option "one_shot" o - "stop grabbing if audio file changes" - flag off - -option "mode" m - "select grab mode" - typestr="grab_mode" - values="sloppy","aggressive","pedantic" - default="sloppy" - optional diff --git a/ggo/makefile b/ggo/makefile index a7715208..936b23eb 100644 --- a/ggo/makefile +++ b/ggo/makefile @@ -1,16 +1,5 @@ module_ggo_opts := --set-version="($(PACKAGE_STRING), $(codename))" -grab_client.cmdline.h grab_client.cmdline.c: $(ggo_dir)/grab_client.ggo - gengetopt $(module_ggo_opts) \ - -S \ - --set-package=grab \ - --no-handle-help \ - --no-handle-error \ - --no-handle-version \ - --arg-struct-name=grab_client_args_info \ - --file-name=$(subst .ggo,,$( #include "para.h" -#include "grab_client.cmdline.h" #include "list.h" #include "sched.h" #include "ggo.h" @@ -32,6 +31,7 @@ struct list_head inactive_grab_client_list; static int max_num_filters(void) { int i, ret = 0; + for (i = 0; audio_formats[i]; i++) { PARA_INFO_LOG("%s filter chain length: %d\n", audio_formats[i], num_filters(i)); @@ -41,74 +41,54 @@ static int max_num_filters(void) return ret; } -static int gc_write(char *buf, size_t len, struct filter_callback *fcb) +static struct filter_node *find_filter_node(int format, int filternum) { - struct grab_client *gc = fcb->data; - struct timeval tv = {0, 100}; - int ret; + int i; -// PARA_INFO_LOG("writing %d bytes to fd %d\n", len, gc->fd); - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(gc->fd, &wfds); - ret = para_select(gc->fd + 1, NULL, &wfds, &tv); - if (ret <= 0) { - if (gc->mode == GRAB_PEDANTIC) - return -E_PEDANTIC_GRAB; - if (gc->mode == GRAB_SLOPPY) - return 1; - } -rewrite: - ret = write(gc->fd, buf, len); - if (ret < 0) { - ret = -E_GC_WRITE; - gc->error = E_GC_WRITE; - } else { - if (ret != len) { - if (gc->mode == GRAB_PEDANTIC) - return -E_PEDANTIC_GRAB; - if (gc->mode == GRAB_AGGRESSIVE) { - len -= ret; - memmove(buf, buf + ret, len); - goto rewrite; - } - } + FOR_EACH_SLOT(i) { + struct slot_info *s = &slot[i]; + if (s->format < 0 || !s->fc) + continue; + if (format >= 0 && s->format != format) + continue; + if (num_filters(i) <= filternum) + continue; + /* success */ + return s->fc->filter_nodes + filternum; } - return ret; + return NULL; } -/* TODO: gengetopt can handle the grab client modes */ -static int check_gc_args(struct grab_client *gc) +static int gc_write(char *buf, size_t len, struct filter_callback *fcb) { - int i; - struct grab_client_args_info *c = gc->conf; - const char **mv = grab_client_cmdline_parser_mode_values; + struct grab_client *gc = container_of(fcb, struct grab_client, fcb); + size_t written = 0; - PARA_INFO_LOG("filter_num: %d\n", c->filter_num_arg); - for (i = 0; mv[i]; i++) - if (!strcmp(c->mode_arg, mv[i])) - break; - if (!mv[i]) - return -E_GC_SYNTAX; - gc->mode = i; - gc->audio_format_num = -1; - if (c->audio_format_given) { - gc->audio_format_num = get_audio_format_num(c->audio_format_arg); - if (gc->audio_format_num < 0) - return gc->audio_format_num; + while (written < len) { + int ret = write_ok(gc->fd); + if (ret < 0) + goto err; + if (ret == 0) { /* fd not ready */ + if (gc->mode == GM_PEDANTIC) + goto err; + if (gc->mode == GM_SLOPPY) + return 1; + } + ret = write(gc->fd, buf + written, len - written); + if (ret < 0) { + if (errno != EAGAIN && errno != EINTR) + goto err; + if (gc->mode == GM_PEDANTIC) + goto err; + if (gc->mode == GM_SLOPPY) + return 1; + } else + written += ret; } - if (c->slot_arg >= MAX_STREAM_SLOTS) - return -E_BAD_GC_SLOT; - if (c->filter_num_arg < 0) - return -E_BAD_GC_FILTER_NUM; - if (c->audio_format_given) { - if (num_filters(gc->audio_format_num) <= c->filter_num_arg) - return -E_BAD_GC_FILTER_NUM; - } else - if (c->filter_num_arg >= max_num_filters()) - return -E_BAD_GC_FILTER_NUM; - return 1; +err: + gc->error = -E_GC_WRITE; + return -E_GC_WRITE; } static void add_inactive_gc(struct grab_client *gc) @@ -118,27 +98,14 @@ static void add_inactive_gc(struct grab_client *gc) para_list_add(&gc->node, &inactive_grab_client_list); } -static void gc_free(struct grab_client *gc) -{ - int i; - - for (i = 0; i < gc->argc; i++) - free(gc->argv[i]); - free(gc->argv); - free(gc->conf); - free(gc); - -} - static void gc_close(struct filter_callback *fcb) { - struct grab_client *gc = fcb->data; + struct grab_client *gc = container_of(fcb, struct grab_client, fcb); - if (gc->conf->one_shot_given || gc->error) { + if ((gc->flags & GF_ONE_SHOT) || gc->error < 0) { PARA_INFO_LOG("closing fd %d (grab client %p)\n", gc->fd, gc); close(gc->fd); - gc_free(gc); - /* close on fork ?*/ + free(gc); return; } add_inactive_gc(gc); @@ -162,7 +129,6 @@ void activate_grab_client(struct grab_client *gc, struct filter_node *fn) /** * Activate inactive grab clients if possible. * - * \param slot_num Audiod's slot for the new audio file. * \param audio_format_num The number of the audio format of the new audio file. * \param fc The filter chain containing the activated filters. * @@ -175,85 +141,125 @@ void activate_grab_client(struct grab_client *gc, struct filter_node *fn) * \sa filter_chain_info::filters, inactive_grab_client_list, * activate_grab_client. */ -void activate_inactive_grab_clients(int slot_num, int audio_format_num, +void activate_inactive_grab_clients(int audio_format_num, struct filter_chain *fc) { struct grab_client *gc, *tmp; - int filter_num; struct filter_node *fn; list_for_each_entry_safe(gc, tmp, &inactive_grab_client_list, node) { -// PARA_INFO_LOG("checking inactive grab client %p\n", gc); - if (gc->conf->slot_arg >= 0 && gc->conf->slot_arg != slot_num) - continue; if (gc->audio_format_num >= 0 && gc->audio_format_num != audio_format_num) continue; - filter_num = gc->conf->filter_num_arg; - if (filter_num >= num_filters(gc->audio_format_num)) + if (gc->filter_num >= num_filters(audio_format_num)) continue; - fn = fc->filter_nodes + filter_num; + fn = fc->filter_nodes + gc->filter_num; activate_grab_client(gc, fn); } } +static int check_gc_args(int argc, char **argv, struct grab_client *gc) +{ + int i, ret; + + gc->audio_format_num = -1; /* default: grab any audio format */ + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (arg[0] != '-') + break; + if (!strcmp(arg, "--")) { + i++; + break; + } + if (!strncmp(arg, "-n=", 3)) { + ret = para_atoi32(arg + 3, &gc->filter_num); + if (ret < 0) + return ret; + if (gc->filter_num < 0) + return -E_BAD_GC_FILTER_NUM; + if (gc->filter_num >= max_num_filters()) + return -E_BAD_GC_FILTER_NUM; + continue; + } + if (!strncmp(arg, "-m", 2)) { + if (*(arg + 3)) + return -E_GC_SYNTAX; + switch(*(arg + 2)) { + case 's': + gc->mode = GM_SLOPPY; + continue; + case 'a': + gc->mode = GM_AGGRESSIVE; + continue; + case 'p': + gc->mode = GM_PEDANTIC; + continue; + default: + return -E_GC_SYNTAX; + } + } + if (!strcmp(arg, "-i")) { + gc->flags |= GF_INPUT_GRAB; + continue; + } + if (!strcmp(arg, "-o")) { + gc->flags |= GF_ONE_SHOT; + continue; + } + if (!strncmp(arg, "-f=", 3)) { + ret = get_audio_format_num(arg + 3); + if (ret < 0) + return ret; + gc->audio_format_num = ret; + continue; + } + return -E_GC_SYNTAX; + } + if (i != argc) + return -E_GC_SYNTAX; + return 1; +} + /** * Check the command line options and allocate a grab_client structure. * * \param fd The file descriptor of the client. - * \param line The command line. - * \param err Non-zero if an error occurred. + * \param argc Argument count. + * \param argv Argument vector. * * If the command line options given by \a argc and \a argv are valid. * allocate a struct grab_client and initialize it with this valid * configuration. Moreover, add the new grab client to the inactive list. * - * \return On success, this function returns a pointer to the newly created - * struct. On errors, it returns NULL and sets \a err appropriately. + * \return Standard. * * \sa grab_client, inactive_grab_client_list, activate_grab_client, * filter_node::callbacks. */ -/* - * argc, argv get freed when com_grab() returns, so we have to make a - * copy. - */ -struct grab_client *grab_client_new(int fd, char *line, int *err) +int grab_client_new(int fd, int argc, char **argv) { int ret; struct grab_client *gc = para_calloc(sizeof(struct grab_client)); + struct filter_node *fn; - gc->conf = para_calloc(sizeof(struct grab_client_args_info)); - - ret = grab_client_cmdline_parser_string(line, gc->conf, "grab"); - *err = -E_GC_SYNTAX; - if (ret) - goto err_out; - *err = -E_GC_HELP_GIVEN; - if (gc->conf->help_given) + ret = check_gc_args(argc, argv, gc); + if (ret < 0) goto err_out; - *err = -E_GC_VERSION_GIVEN; - if (gc->conf->version_given) - goto err_out; - *err = check_gc_args(gc); - if (*err < 0) - goto err_out; - if (gc->conf->input_grab_given) { + if (gc->flags & GF_INPUT_GRAB) gc->fcb.input_cb = gc_write; - gc->fcb.output_cb = NULL; - } else { + else gc->fcb.output_cb = gc_write; - gc->fcb.input_cb = NULL; - } gc->fd = fd; gc->fcb.close = gc_close; - gc->fcb.data = gc; - add_inactive_gc(gc); - return gc; + fn = find_filter_node(gc->audio_format_num, gc->filter_num); + if (fn) + para_list_add(&gc->fcb.node, &fn->callbacks); + else + add_inactive_gc(gc); + return 1; err_out: - free(gc->conf); free(gc); - return NULL; + return ret; } /** diff --git a/grab_client.h b/grab_client.h index 2832f093..04e0a75b 100644 --- a/grab_client.h +++ b/grab_client.h @@ -7,43 +7,53 @@ /** \file grab_client.h exported symbols from grab_client.c */ #include "config.h" + /** - * handle blocking writes for the grab client fds - * - * - pedantic: close fd if write would block - * - sloppy: ignore the data and do not write - * - aggressive: write anyway (default) - * + * How to handle blocking writes for the grab client fds. */ -enum grab_mode {GRAB_SLOPPY, GRAB_AGGRESSIVE, GRAB_PEDANTIC}; +enum grab_mode { + /** Ignore the data and do not write. */ + GM_SLOPPY, + /** Write anyway (default). */ + GM_AGGRESSIVE, + /** Close fd if write would block. */ + GM_PEDANTIC, +}; -/** describes one active grab client +/** Flags specified as arguments to the grab command. */ +enum grab_flags { + /** Grab the filter input instead of its output. */ + GF_INPUT_GRAB = 1, + /** Stop grabbing if audio file changes. */ + GF_ONE_SHOT = 2, +}; + +/** + * Describes one active grab client. * - * \sa filter_callback, filter_node::callbacks + * \sa filter_callback, filter_node::callbacks. */ struct grab_client { -/** the file descriptor to send the grabbed stream to */ + /** The file descriptor to send the grabbed stream to. */ int fd; -/** the command line options for this grab client */ - struct grab_client_args_info *conf; -/** pedantic, sloppy, or aggressive, computed from command line */ - enum grab_mode mode; -/** non-zero if the write() to \a fd failed */ + /** Non-zero if the write() to \a fd failed. */ int error; -/** the number of the desired audio format, computed from command line */ + /** See \ref grab_mode. */ + enum grab_mode mode; + /** Point of filter chain to grab. */ + int32_t filter_num; + /** The number of the desired audio format. */ int audio_format_num; -/** the callback data which gets attached to a suitable filter_node */ + /** Flags given at the command line. */ + enum grab_flags flags; + /** The callback data which gets attached to a suitable filter_node. */ struct filter_callback fcb; -/** all grab clients belong either to a filter node or to the inactive list */ + /** All grab clients belong either to a filter node or to the inactive list. */ struct list_head node; -/** the number of command line options */ - int argc; -/** pointers to the command line options */ - char **argv; }; -__malloc struct grab_client *grab_client_new(int fd, char *line, int *err); -void activate_inactive_grab_clients(int slot_num, int audio_format_num, +int grab_client_new(int fd, int argc, char **argv); +void activate_inactive_grab_clients(int audio_format_num, struct filter_chain *fc); void activate_grab_client(struct grab_client *gc, struct filter_node *fn); void init_grabbing(void); -- 2.30.2