Rewrite grab-client code.
authorAndre Noll <maan@systemlinux.org>
Sun, 5 Jul 2009 20:35:29 +0000 (22:35 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 5 Jul 2009 20:35:29 +0000 (22:35 +0200)
This gets rid of the gengetopt grab client command line parser and all the special
treatment it caused.

13 files changed:
Makefile.in
audiod.c
audiod.cmd
audiod.h
audiod_command.c
configure.ac
error.h
filter.h
filter_common.c
ggo/grab_client.ggo [deleted file]
ggo/makefile
grab_client.c
grab_client.h

index 8921a3c..05d7b3e 100644 (file)
@@ -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)))
 
index 2b6f1e6..29a8aa3 100644 (file)
--- 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)
index 2c6ea9b..94f3ca0 100644 (file)
@@ -14,11 +14,36 @@ H: on -> standby -> off -> on
 N: grab
 D: grab the audio stream
 L:
-U: -- grab [grab_options]
+U: -- grab -[n=<num>] [-m[{s|p|a}]] [-i] [-o] [-f=<format>]
+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
index 8108378..18bf48e 100644 (file)
--- 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};
index e57283c..da5a2dc 100644 (file)
@@ -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.
  */
index fdc0b7c..61421b5 100644 (file)
@@ -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 59d0321..f2e92c6 100644 (file)
--- 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 \
index 0bb51f5..23f47f4 100644 (file)
--- 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.
index 2c74e8c..fbc5b66 100644 (file)
@@ -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 (file)
index 5527143..0000000
+++ /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
index a771520..936b23e 100644 (file)
@@ -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,,$(<F)).cmdline \
-               --func-name $(subst .ggo,,$(<F))_cmdline_parser < $<
-
 %_recv.cmdline.h %_recv.cmdline.c: $(ggo_dir)/%_recv.ggo
        gengetopt $(module_ggo_opts) \
                --set-package=$(subst .ggo,,$(<F)) \
index 9b4ef69..df5b40a 100644 (file)
@@ -15,7 +15,6 @@
 #include <dirent.h>
 
 #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;
 }
 
 /**
index 2832f09..04e0a75 100644 (file)
@@ -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);