para_write: Own commandline parsers for each writer
authorAndre <maan@p133.(none)>
Fri, 26 May 2006 14:48:15 +0000 (16:48 +0200)
committerAndre <maan@p133.(none)>
Fri, 26 May 2006 14:48:15 +0000 (16:48 +0200)
12 files changed:
Makefile.in
alsa_write.ggo [new file with mode: 0644]
alsa_writer.c
audiod.c
configure.ac
file_write.ggo [new file with mode: 0644]
file_writer.c
write.c
write.ggo
write.h
write_common.c
write_common.h

index c9eb46f..1221039 100644 (file)
@@ -133,6 +133,12 @@ grab_client.cmdline.h grab_client.cmdline.c: grab_client.ggo
                --arg-struct-name=$(subst .ggo,,$<)_args_info \
                --file-name=$(subst .ggo,,$<).cmdline \
                --func-name $(subst _filter.ggo,,$<)_cmdline_parser < $<
+%_write.cmdline.h %_write.cmdline.c: %_write.ggo
+       gengetopt -S $(module_ggo_opts) \
+               --set-package=$(subst .ggo,,$<) \
+               --arg-struct-name=$(subst .ggo,,$<)_args_info \
+               --file-name=$(subst .ggo,,$<).cmdline \
+               --func-name $(subst _write.ggo,,$<)_cmdline_parser < $<
 
 %.cmdline.h %.cmdline.c: %.ggo
        case $< in client.ggo) O="--unamed-opts=command";; \
diff --git a/alsa_write.ggo b/alsa_write.ggo
new file mode 100644 (file)
index 0000000..4863a53
--- /dev/null
@@ -0,0 +1,28 @@
+section "alsa options"
+######################
+
+option "device" d
+#~~~~~~~~~~~~~~~~
+"set PCM device"
+       string typestr="device"
+       default="plughw:0,0"
+       optional
+
+option "channels" c
+#~~~~~~~~~~~~~~~~~~
+"number of channels (only neccessary for raw
+audio)"
+
+       int typestr="num"
+       default="2"
+       optional
+
+option "sample_rate" s
+#~~~~~~~~~~~~~~~~~~~~~
+
+"force given sample rate (only neccessary for
+raw audio)"
+
+       int typestr="num"
+       default="44100"
+       optional
index f05dbbd..617173a 100644 (file)
 
 #include <alsa/asoundlib.h>
 
-#include "write.cmdline.h"
+#include "alsa_write.cmdline.h"
 #include "error.h"
 
-extern struct gengetopt_args_info conf;
 
 #define FORMAT SND_PCM_FORMAT_S16_LE
 
 /** data specific to the alsa writer */
 struct private_alsa_data {
-/** the alsa handle */
-snd_pcm_t *handle;
-/** determined and set by alsa_open() */
-size_t bytes_per_frame;
-struct timeval next_chunk;
+       /** the alsa handle */
+       snd_pcm_t *handle;
+       /** determined and set by alsa_open() */
+       size_t bytes_per_frame;
+       /** don't write anything until this time */
+       struct timeval next_chunk;
 };
 
 /*
@@ -65,10 +65,11 @@ static int alsa_open(struct writer_node *w)
        snd_pcm_info_t *info;
        snd_pcm_uframes_t period_size;
        struct private_alsa_data *pad = para_calloc(sizeof(struct private_alsa_data));
-       w->private_data = pad;
+       struct alsa_write_args_info *conf = w->conf;
 
+       w->private_data = pad;
        snd_pcm_info_alloca(&info);
-       err = snd_pcm_open(&pad->handle, conf.device_arg,
+       err = snd_pcm_open(&pad->handle, conf->device_arg,
                SND_PCM_STREAM_PLAYBACK, 0);
        if (err < 0)
                return -E_PCM_OPEN;
@@ -85,10 +86,10 @@ static int alsa_open(struct writer_node *w)
        if (snd_pcm_hw_params_set_format(pad->handle, hwparams, FORMAT) < 0)
                return -E_SAMPLE_FORMAT;
        if (snd_pcm_hw_params_set_channels(pad->handle, hwparams,
-                       conf.channels_arg) < 0)
+                       conf->channels_arg) < 0)
                return -E_CHANNEL_COUNT;
        if (snd_pcm_hw_params_set_rate_near(pad->handle, hwparams,
-                       (unsigned int*) &conf.sample_rate_arg, 0) < 0)
+                       (unsigned int*) &conf->sample_rate_arg, 0) < 0)
                return -E_SET_RATE;
        err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0);
        if (err < 0 || !buffer_time)
@@ -127,7 +128,7 @@ static int alsa_open(struct writer_node *w)
        if (snd_pcm_sw_params(pad->handle, swparams) < 0)
                return -E_SW_PARAMS;
        pad->bytes_per_frame = snd_pcm_format_physical_width(FORMAT)
-               * conf.channels_arg / 8;
+               * conf->channels_arg / 8;
 //     if (snd_pcm_nonblock(pad->handle, 1))
 //             PARA_ERROR_LOG("%s\n", "failed to set nonblock mode");
        return period_size * pad->bytes_per_frame;
@@ -208,6 +209,21 @@ static void alsa_close(struct writer_node *wn)
        free(pad);
 }
 
+__malloc void *alsa_parse_config(char *options)
+{
+       struct alsa_write_args_info *conf
+               = para_calloc(sizeof(struct alsa_write_args_info));
+       PARA_INFO_LOG("options: %s, %d\n", options, strcspn(options, " \t"));
+       int ret = alsa_cmdline_parser_string(options, conf, "alsa_write");
+       if (ret)
+               goto err_out;
+       PARA_INFO_LOG("help given: %d\n", conf->help_given);
+       return conf;
+err_out:
+       free(conf);
+       return NULL;
+}
+
 /** the init function of the alsa writer */
 void alsa_writer_init(struct writer *w)
 {
@@ -215,5 +231,6 @@ void alsa_writer_init(struct writer *w)
        w->close = alsa_close;
        w->pre_select = alsa_write_pre_select;
        w->post_select = alsa_write_post_select;
+       w->parse_config = alsa_parse_config;
        w->shutdown = NULL; /* nothing to do */
 }
index fcce8ae..dccc2e1 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -1847,7 +1847,7 @@ int main(int argc, char *argv[])
        register_task(&stat_task->task);
        register_task(&at->task);
        s.default_timeout.tv_sec = 0;
-       s.default_timeout.tv_usec = 999 * 1000;
+       s.default_timeout.tv_usec = 99 * 1000;
        ret = sched(&s);
 
        PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
index 5844b7a..c436e84 100644 (file)
@@ -76,7 +76,7 @@ server_errlist_objs="server mp3_afh afs command net string signal random_selecto
        ipc dccp dccp_send fd"
 server_ldflags=""
 
-write_cmdline_objs="write.cmdline"
+write_cmdline_objs="write.cmdline file_write.cmdline"
 write_errlist_objs="write write_common file_writer time fd string sched stdin"
 write_ldflags=""
 write_writers="file"
@@ -274,6 +274,7 @@ AC_CHECK_LIB([asound], [snd_pcm_open], [], [
 ])
 if test "$have_alsa" = "yes"; then
        write_errlist_objs="$write_errlist_objs alsa_writer"
+       write_cmdline_objs="$write_cmdline_objs alsa_write.cmdline"
        write_ldflags="$write_ldflags -lasound"
        write_writers="$write_writers alsa"
 fi
diff --git a/file_write.ggo b/file_write.ggo
new file mode 100644 (file)
index 0000000..a172f75
--- /dev/null
@@ -0,0 +1,11 @@
+section "file writer options"
+
+option "filename" f
+#~~~~~~~~~~~~~~~~~~
+
+"select output file name. Defaults to a
+random filename in ~/.paraslash."
+
+       string typestr="filename"
+       optional
+
index d8fb3e5..9145ef9 100644 (file)
 #include "write.h"
 #include "string.h"
 #include "fd.h"
+#include "file_write.cmdline.h"
 #include "error.h"
 
 /** data specific to the file writer */
 struct private_file_writer_data {
-/** the file descriptor of the output file */
-int fd;
-int check_fd;
+       /** the file descriptor of the output file */
+       int fd;
+       /** non-zero if \a fd was added to the write fd set */
+       int check_fd;
 };
 
 static int file_writer_open(struct writer_node *wn)
 {
        struct private_file_writer_data *pfwd = para_calloc(
                sizeof(struct private_file_writer_data));
-       char *tmp = para_tmpname(), *home = para_homedir(),
-               *filename = make_message("%s/.paraslash/%s", home, tmp);
-
-       free(home);
-       free(tmp);
+       struct file_write_args_info *conf = wn->conf;
+       char *filename;
+       if (conf->filename_given)
+               filename = conf->filename_arg;
+       else {
+               char *tmp = para_tmpname(), *home = para_homedir();
+               filename = make_message("%s/.paraslash/%s", home, tmp);
+               free(home);
+               free(tmp);
+       }
        wn->private_data = pfwd;
        pfwd->fd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
-       free(filename);
+       if (!conf->filename_given)
+               free(filename);
        if (pfwd->fd >= 0)
                return 8192;
        free(pfwd);
@@ -105,6 +113,19 @@ static void file_writer_close(struct writer_node *wn)
        free(pfwd);
 }
 
+__malloc void *file_writer_parse_config(char *options)
+{
+       PARA_INFO_LOG("options: %s\n", options);
+       struct file_write_args_info *conf
+               = para_calloc(sizeof(struct file_write_args_info));
+       int ret = file_cmdline_parser_string(options, conf, "file_write");
+       PARA_INFO_LOG("conf->filename_given: %d\n", conf->filename_given);
+       if (!ret)
+               return conf;
+       free(conf);
+       return NULL;
+}
+
 /** the init function of the file writer */
 void file_writer_init(struct writer *w)
 {
@@ -112,6 +133,7 @@ void file_writer_init(struct writer *w)
        w->write = file_writer_write;
        w->pre_select = file_writer_pre_select;
        w->post_select = file_writer_post_select;
+       w->parse_config = file_writer_parse_config;
        w->close = file_writer_close;
        w->shutdown = NULL; /* nothing to do */
 }
diff --git a/write.c b/write.c
index a3cd4b5..b692ac5 100644 (file)
--- a/write.c
+++ b/write.c
@@ -43,7 +43,7 @@ struct initial_delay_task {
        struct task task;
 };
 
-struct gengetopt_args_info conf;
+static struct gengetopt_args_info conf;
 struct stdin_task sit;
 struct check_wav_task cwt;
 struct initial_delay_task idt;
@@ -66,6 +66,8 @@ static void check_wav_pre_select(struct sched *s, struct task *t)
                t->ret = *cwt->eof? -E_PREMATURE_END : 1;
                return;
        }
+       cwt->channels = 2;
+       cwt->sample_rate = 44100;
        a = (unsigned char*)cwt->buf;
        t->ret = -E_NO_WAV_HEADER;
        if (a[0] != 'R' || a[1] != 'I' || a[2] != 'F' || a[3] != 'F')
@@ -124,8 +126,8 @@ static struct writer_node_group *check_args(void)
                free(msg);
                exit(EXIT_SUCCESS);
        }
-       if (conf.prebuffer_arg < 0 || conf.prebuffer_arg > 100)
-               goto out;
+//     if (conf.prebuffer_arg < 0 || conf.prebuffer_arg > 100)
+//             goto out;
        if (conf.start_time_given) {
                long unsigned sec, usec;
                if (sscanf(conf.start_time_arg, "%lu:%lu",
@@ -140,13 +142,16 @@ static struct writer_node_group *check_args(void)
                goto out;
        }
        wng = wng_new(conf.writer_given);
+       ret = -E_WRITE_SYNTAX;
        for (i = 0; i < conf.writer_given; i++) {
-               ret = check_writer_arg(conf.writer_arg[i]);
-               if (ret < 0)
+               int writer_num;
+               wng->writer_nodes[i].conf = check_writer_arg(
+                       conf.writer_arg[i], &writer_num);
+               if (!wng->writer_nodes[i].conf)
                        goto out;
-               wng->writer_nodes[i].writer = &writers[ret];
+               wng->writer_nodes[i].writer = &writers[writer_num];
                sprintf(wng->writer_nodes[i].task.status, "%s",
-                       writer_names[ret]);
+                       writer_names[writer_num]);
        }
        ret = 1;
 out:
@@ -180,10 +185,10 @@ static void cwt_event_handler(struct task *t)
        }
        PARA_INFO_LOG("%s\n", PARA_STRERROR(-t->ret));
        unregister_task(t);
-       if (t->ret == -E_WAV_HEADER_SUCCESS) {
-               conf.channels_arg = cwt.channels;
-               conf.sample_rate_arg = cwt.sample_rate;
-       }
+//     if (t->ret == -E_WAV_HEADER_SUCCESS) {
+//             conf.channels_arg = cwt.channels;
+//             conf.sample_rate_arg = cwt.sample_rate;
+//     }
        idt.task.pre_select = initial_delay_pre_select;
        idt.task.private_data = &idt;
        idt.task.event_handler = idt_event_handler;
@@ -197,13 +202,15 @@ int main(int argc, char *argv[])
        struct sched s;
 
        cmdline_parser(argc, argv, &conf);
-       wng = check_args();
-       if (!wng)
-               goto out;
        init_supported_writers();
        init_sched();
 
+       wng = check_args();
+       if (!wng)
+               goto out;
        stdin_set_defaults(&sit);
+       if (conf.bufsize_given)
+               sit.bufsize = conf.bufsize_arg;
        sit.buf = para_malloc(sit.bufsize),
        register_task(&sit.task);
 
index 4afff0c..02d1a16 100644 (file)
--- a/write.ggo
+++ b/write.ggo
@@ -24,14 +24,6 @@ option "bufsize" b
        default="64"
        optional
 
-option "prebuffer" p
-#~~~~~~~~~~~~~~~~~~~
-"delay playback until buffer is filled"
-
-       int typestr="percent"
-       default="100"
-       optional
-
 option "writer" w
 #~~~~~~~~~~~~~~~~
 
@@ -52,34 +44,3 @@ denotes microseconds since the epoch"
 
        string typestr="timeval"
        optional
-
-
-section "alsa options"
-######################
-
-option "device" d
-#~~~~~~~~~~~~~~~~
-"set PCM device"
-       string typestr="device"
-       default="plughw:0,0"
-       optional
-
-option "channels" c
-#~~~~~~~~~~~~~~~~~~
-"number of channels (only neccessary for raw
-audio)"
-
-       int typestr="num"
-       default="2"
-       optional
-
-option "sample_rate" s
-#~~~~~~~~~~~~~~~~~~~~~
-
-"force given sample rate (only neccessary for
-raw audio)"
-
-       int typestr="num"
-       default="44100"
-       optional
-
diff --git a/write.h b/write.h
index 04ad09d..f4c54ca 100644 (file)
--- a/write.h
+++ b/write.h
@@ -25,14 +25,16 @@ enum writer_enum {WRITER_ENUM};
  * decbribes one running instance of a writer
  */
 struct writer_node {
-/** points to the writer structure associated with this node */
+       /** points to the writer structure associated with this node */
        struct writer *writer;
-/** writer-specific data */
+       /** writer-specific data */
        void *private_data;
-/** send that many bytes in one go */
+       /** send that many bytes in one go */
        int chunk_bytes;
        struct task task;
        struct writer_node_group *wng;
+       /** the writer-specific configuration of this node */
+       void *conf;
 };
 
 /** describes one supported writer */
@@ -45,6 +47,18 @@ struct writer {
  *
  */
 void (*init)(struct writer *w);
+/**
+ *
+ *
+ * the command line parser of the writer
+ *
+ * It should check whether the command line options given by \a options are
+ * valid.  On success, it should return a pointer to the writer-specific
+ * configuration data determined by \a options.  Note that this might be called
+ * more than once with different values of \a options.
+ *
+ */
+       void * (*parse_config)(char *options);
 /**
  *
  * open one instance of this writer
index 6c0faa7..de0502f 100644 (file)
@@ -28,7 +28,7 @@
 const char *writer_names[] ={WRITER_NAMES};
 struct writer writers[NUM_SUPPORTED_WRITERS] = {WRITER_ARRAY};
 
-static void wng_post_select(struct sched *s, struct task *t)
+static void wng_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct writer_node_group *g = t->private_data;
        int i;
@@ -131,22 +131,29 @@ void init_supported_writers(void)
                writers[i].init(&writers[i]);
 }
 
-int check_writer_arg(const char *arg)
+void *check_writer_arg(char *wa, int *writer_num)
 {
-       int i, ret = -E_WRITE_COMMON_SYNTAX;
-       char *a = para_strdup(arg), *p = strchr(a, ':');
-       if (p)
-               *p = '\0';
-       p++;
+       int i;
+
+       PARA_INFO_LOG("checking  %s\n", wa);
        FOR_EACH_WRITER(i) {
-               if (strcmp(writer_names[i], a))
+               const char *name = writer_names[i];
+               size_t len = strlen(name);
+               char c;
+               if (strlen(wa) < len)
+                       continue;
+               if (strncmp(name, wa, len))
+                       continue;
+               c = wa[len];
+               if (c && c != ' ')
                        continue;
-               ret = i;
-               goto out;
+               if (c && !writers[i].parse_config)
+                       return NULL;
+               *writer_num = i;
+               return writers[i].parse_config(c? wa + len + 1 : "");
        }
-out:
-       free(a);
-       return ret;
+       PARA_ERROR_LOG("%s", "writer not found\n");
+       return NULL;
 }
 
 struct writer_node_group *setup_default_wng(void)
@@ -161,7 +168,8 @@ struct writer_node_group *setup_default_wng(void)
        wng->writer_nodes[0].writer = &writers[default_writer];
        sprintf(wng->writer_nodes[0].task.status, "%s",
                writer_names[default_writer]);
-       PARA_INFO_LOG("using default writer: %s\n",
-               writer_names[default_writer]);
+       PARA_INFO_LOG("using default writer: %s %p\n",
+               writer_names[default_writer], writers[default_writer].parse_config);
+       wng->writer_nodes[0].conf = writers[default_writer].parse_config("");
        return wng;
 }
index 0eb2ae7..d9a8b59 100644 (file)
@@ -24,5 +24,5 @@ void wng_close(struct writer_node_group *g);
 struct writer_node_group *wng_new(unsigned num_writers);
 void wng_destroy(struct writer_node_group *g);
 void init_supported_writers(void);
-int check_writer_arg(const char *arg);
+void *check_writer_arg(char *wa, int *writer_num);
 struct writer_node_group *setup_default_wng(void);