From: Andre Date: Fri, 26 May 2006 14:48:15 +0000 (+0200) Subject: para_write: Own commandline parsers for each writer X-Git-Tag: v0.2.14~101^2~20 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=14f817d233309fe9ca2580fa8e4b78fd823b9ab9 para_write: Own commandline parsers for each writer --- diff --git a/Makefile.in b/Makefile.in index c9eb46fd..12210396 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 index 00000000..4863a53a --- /dev/null +++ b/alsa_write.ggo @@ -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 diff --git a/alsa_writer.c b/alsa_writer.c index f05dbbd0..617173a8 100644 --- a/alsa_writer.c +++ b/alsa_writer.c @@ -33,20 +33,20 @@ #include -#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 */ } diff --git a/audiod.c b/audiod.c index fcce8ae9..dccc2e15 100644 --- 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)); diff --git a/configure.ac b/configure.ac index 5844b7a7..c436e848 100644 --- a/configure.ac +++ b/configure.ac @@ -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 index 00000000..a172f757 --- /dev/null +++ b/file_write.ggo @@ -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 + diff --git a/file_writer.c b/file_writer.c index d8fb3e54..9145ef9f 100644 --- a/file_writer.c +++ b/file_writer.c @@ -24,27 +24,35 @@ #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 a3cd4b5d..b692ac50 100644 --- 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); diff --git a/write.ggo b/write.ggo index 4afff0c0..02d1a164 100644 --- 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 04ad09d5..f4c54ca3 100644 --- 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 diff --git a/write_common.c b/write_common.c index 6c0faa7c..de0502f5 100644 --- a/write_common.c +++ b/write_common.c @@ -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; } diff --git a/write_common.h b/write_common.h index 0eb2ae71..d9a8b590 100644 --- a/write_common.h +++ b/write_common.h @@ -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);