From: Andre Date: Tue, 18 Apr 2006 18:42:15 +0000 (+0200) Subject: add new writer to para_play: file X-Git-Tag: v0.2.12~69 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=773bdfd137b4d4bb350903a1cb6b25ef304b3e0a;hp=263c9ec8129b345b3e9310f544a1e3dbcf425c6f add new writer to para_play: file It simply writes the input to a random filename under ~/.paraslash. Also, add some writer-related macros to config.h and two new options for para_play: --writer and --list_writers. --- diff --git a/configure.ac b/configure.ac index 61b1808a..bfd659f1 100644 --- a/configure.ac +++ b/configure.ac @@ -79,6 +79,8 @@ server_ldflags="" play_cmdline_objs="play.cmdline" play_errlist_objs="play time fd string" play_ldflags="" +write_writers="file" + ########################################################################### ssl dnl @synopsis CHECK_SSL @@ -230,6 +232,7 @@ AC_CHECK_LIB([asound], [snd_pcm_open], [], [ if test "$have_alsa" = "yes"; then extras="$extras para_play" play_ldflags="$play_ldflags -lasound" + write_writers="$write_writers alsa" fi ########################################################################### ortp have_ortp="yes" @@ -320,6 +323,16 @@ AC_SUBST(play_ldflags, $play_ldflags) AC_DEFINE_UNQUOTED(INIT_PLAY_ERRLISTS, objlist_to_errlist($play_errlist_objs), errors used by para_play) +enum="$(for i in $write_writers; do printf "${i}_WRITE, " | tr '[a-z]' '[A-Z]'; done)" +AC_DEFINE_UNQUOTED(WRITER_ENUM, $enum NUM_SUPPORTED_WRITERS, + enum of supported writers) +names="$(for i in $write_writers; do printf '\"'$i'\", ' ; done)" +AC_DEFINE_UNQUOTED(WRITER_NAMES, $names, supported writer names) +inits="$(for i in $write_writers; do printf 'extern void '$i'_writer_init(struct writer *); '; done)" +AC_DEFINE_UNQUOTED(DECLARE_WRITER_INITS, $inits, init functions of the supported writers) +array="$(for i in $write_writers; do printf '{.init = '$i'_writer_init},'; done)" +AC_DEFINE_UNQUOTED(WRITER_ARRAY, $array, array of supported writers) + gui_cmdline_objs="gui.cmdline" gui_errlist_objs="exec close_on_fork signal string stat ringbuffer fd" gui_other_objs="gui gui_common gui_theme" diff --git a/error.h b/error.h index 880df55b..81691667 100644 --- a/error.h +++ b/error.h @@ -302,6 +302,7 @@ extern const char **para_errlist[]; PARA_ERROR(READ_STDIN, "failed to read from stdin"), \ PARA_ERROR(PLAY_SYNTAX, "syntax error"), \ PARA_ERROR(PLAY_OVERRUN, "buffer overrun"), \ + PARA_ERROR(LIST_WRITERS_GIVEN, ""), \ PARA_ERROR(PREMATURE_END, "premature end of audio file"), \ PARA_ERROR(BROKEN_CONF, "Broken alsa configuration"), \ PARA_ERROR(ACCESS_TYPE, "alsa access type not available"), \ @@ -321,6 +322,8 @@ extern const char **para_errlist[]; PARA_ERROR(START_THRESHOLD, "snd_pcm_sw_params_set_start_threshold() failed"), \ PARA_ERROR(STOP_THRESHOLD, "snd_pcm_sw_params_set_stop_threshold() failed"), \ PARA_ERROR(ALSA_LOG, "snd_output_stdio_attach() failed"), \ + PARA_ERROR(FW_WRITE, "file writer write error"), \ + PARA_ERROR(FW_OPEN, "file writer: can not open output file"), \ diff --git a/play.c b/play.c index f312626c..e1fdb2ef 100644 --- a/play.c +++ b/play.c @@ -31,26 +31,36 @@ #include "string.h" #include "error.h" -#define FORMAT SND_PCM_FORMAT_S16_LE - -struct private_alsa_data { - snd_pcm_t *handle; - size_t bytes_per_frame; -}; - +/* +files: +~~~~~~ +write.c +write.h wr +write_common.c +write_common.h: decratation of the wng funcs +alsa_writer.c +*/ + +/* write.h */ +enum writer_enum {WRITER_ENUM}; + +/* write.h */ struct writer_node { struct writer *writer; void *private_data; int chunk_bytes; }; +/* write.h */ struct writer { + void (*init)(struct writer *w); int (*open)(struct writer_node *); int (*write)(char *data, size_t nbytes, struct writer_node *); void (*close)(struct writer_node *); void (*shutdown)(struct writer_node *); }; +/* write.h */ struct writer_node_group { unsigned num_writers; struct writer_node *writer_nodes; @@ -59,20 +69,22 @@ struct writer_node_group { int eof; }; - +/* write.h */ #define FOR_EACH_WRITER_NODE(i, wng) for (i = 0; i < (wng)->num_writers; i++) +#define FOR_EACH_WRITER(i) for (i = 0; i < NUM_SUPPORTED_WRITERS; i++) -#define NUM_WRITERS 1 -static struct writer writers[NUM_WRITERS]; -#define FOR_EACH_WRITER(i) for (i = 0; i < NUM_WRITERS, i++) +DECLARE_WRITER_INITS; +/* write.c */ static unsigned char *audiobuf; static struct timeval *start_time; static struct gengetopt_args_info conf; +/* write.c */ INIT_PLAY_ERRLISTS; +/* write.c */ void para_log(int ll, const char* fmt,...) { va_list argp; @@ -84,6 +96,7 @@ void para_log(int ll, const char* fmt,...) va_end(argp); } +/* write.c */ /** * read WAV_HEADER_LEN bytes from stdin to audio buffer * @@ -103,6 +116,13 @@ static int read_wav_header(void) return 1; } +/* alsa_writer.c */ +#define FORMAT SND_PCM_FORMAT_S16_LE +struct private_alsa_data { + snd_pcm_t *handle; + size_t bytes_per_frame; +}; + /* * open and prepare the PCM handle for writing * @@ -188,6 +208,7 @@ static int alsa_open(struct writer_node *w) return period_size * pad->bytes_per_frame; } +/* alsa_writer.c */ /** * push out pcm frames * \param data pointer do data to be written @@ -222,6 +243,7 @@ static int alsa_write(char *data, size_t nbytes, struct writer_node *wn) return result * pad->bytes_per_frame; } +/* alsa_writer.c */ static void alsa_close(struct writer_node *wn) { struct private_alsa_data *pad = wn->private_data; @@ -231,6 +253,7 @@ static void alsa_close(struct writer_node *wn) free(pad); } +/* alsa_writer.c */ void alsa_writer_init(struct writer *w) { w->open = alsa_open; @@ -240,6 +263,57 @@ void alsa_writer_init(struct writer *w) } + + +/* file_writer.c */ + +struct private_file_writer_data { + int fd; +}; +static int file_writer_open(struct writer_node *w) +{ + 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); + w->private_data = pfwd; + pfwd->fd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + free(filename); + if (pfwd->fd >= 0) + return 8192; + free(pfwd); + return -E_FW_OPEN; +} + +static int file_writer_write(char *data, size_t nbytes, struct writer_node *wn) +{ + struct private_file_writer_data *pfwd = wn->private_data; + int ret = write(pfwd->fd, data, nbytes); + if (ret < 0) + ret = -E_FW_WRITE; + return ret; +} + +static void file_writer_close(struct writer_node *wn) +{ + struct private_file_writer_data *pfwd = wn->private_data; + close(pfwd->fd); + free(pfwd); +} + +void file_writer_init(struct writer *w) +{ + w->open = file_writer_open; + w->write = file_writer_write; + w->close = file_writer_close; + w->shutdown = NULL; /* nothing to do */ +} + + +/* write.c */ /** * check if current time is later than start_time * \param diff pointer to write remaining time to @@ -260,6 +334,7 @@ static int start_time_in_future(struct timeval *diff) return tv_diff(start_time, &now, diff) > 0? 1 : 0; } +/* write.c */ /** * sleep until time given at command line * @@ -275,6 +350,7 @@ static void do_initial_delay(struct timeval *delay) while (start_time_in_future(delay)); } +/* write.c */ static int read_stdin(char *buf, size_t bytes_to_load, size_t *loaded) { ssize_t ret; @@ -291,6 +367,11 @@ static int read_stdin(char *buf, size_t bytes_to_load, size_t *loaded) return 1; } +/* write_common.c */ + +const char *writer_names[] ={WRITER_NAMES}; +static struct writer writers[NUM_SUPPORTED_WRITERS] = {WRITER_ARRAY}; + int wng_write(struct writer_node_group *g, char *buf, size_t *loaded) { int ret, i, need_more_writes = 1; @@ -336,6 +417,7 @@ out: return ret; } +/* write_common.c */ int wng_open(struct writer_node_group *g) { int i, ret = 1; @@ -352,6 +434,7 @@ out: return ret; } +/* write_common.c */ void wng_close(struct writer_node_group *g) { int i; @@ -362,6 +445,7 @@ void wng_close(struct writer_node_group *g) } } +/* write.c */ /** * play raw pcm data * \param loaded number of bytes already loaded @@ -415,6 +499,7 @@ out: return ret; } +/* writer_node.c */ struct writer_node_group *wng_new(unsigned num_writers) { struct writer_node_group *g = para_calloc(sizeof(struct writer_node_group)); @@ -425,6 +510,7 @@ struct writer_node_group *wng_new(unsigned num_writers) return g; } +/* writer_node.c */ void wng_destroy(struct writer_node_group *g) { if (!g) @@ -434,6 +520,100 @@ void wng_destroy(struct writer_node_group *g) free(g); } +void init_supported_writers(void) +{ + int i; + + FOR_EACH_WRITER(i) + writers[i].init(&writers[i]); +} + +int check_writer_arg(const char *arg) +{ + int i, ret = -E_PLAY_SYNTAX; + char *a = para_strdup(arg), *p = strchr(a, ':'); + if (p) + *p = '\0'; + p++; + FOR_EACH_WRITER(i) { + if (strcmp(writer_names[i], a)) + continue; + ret = i; + goto out; + } +out: + free(a); + return ret; +} + +struct writer_node_group *setup_default_wng(void) +{ + struct writer_node_group *wng = wng_new(1); + enum writer_enum default_writer; + + if (NUM_SUPPORTED_WRITERS == 1) + default_writer = FILE_WRITE; + else + default_writer = 1; + wng->writer_nodes[0].writer = &writers[default_writer]; + PARA_INFO_LOG("using default writer: %s\n", + writer_names[default_writer]); + return wng; +} + +/* write.c */ + +struct writer_node_group *check_args(void) +{ + int i, ret = -E_PLAY_SYNTAX; + static struct timeval tv; + struct writer_node_group *wng = NULL; + + if (conf.list_writers_given) { + char *msg = NULL; + FOR_EACH_WRITER(i) { + char *tmp = make_message("%s%s%s", + i? msg : "", + i? " " : "", + writer_names[i]); + free(msg); + msg = tmp; + } + fprintf(stderr, "%s\n", msg); + free(msg); + exit(EXIT_SUCCESS); + } + 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", + &sec, &usec) != 2) + goto out; + tv.tv_sec = sec; + tv.tv_usec = usec; + start_time = &tv; + } + if (!conf.writer_given) { + wng = setup_default_wng(); + ret = 1; + goto out; + } + wng = wng_new(conf.writer_given); + for (i = 0; i < conf.writer_given; i++) { + ret = check_writer_arg(conf.writer_arg[i]); + if (ret < 0) + goto out; + wng->writer_nodes[i].writer = &writers[ret]; + } + ret = 1; +out: + if (ret > 0) + return wng; + free(wng); + return NULL; +} + /** * test if audio buffer contains a valid wave header * @@ -450,27 +630,17 @@ static size_t check_wave(void) return 0; } +/* write.c */ int main(int argc, char *argv[]) { - struct timeval tv; int ret = -E_PLAY_SYNTAX; struct writer_node_group *wng = NULL; cmdline_parser(argc, argv, &conf); - if (conf.prebuffer_arg < 0 || conf.prebuffer_arg > 100) + wng = check_args(); + if (!wng) goto out; - if (conf.start_time_given) { - if (sscanf(conf.start_time_arg, "%lu:%lu", - &tv.tv_sec, &tv.tv_usec) != 2) - goto out; - start_time = &tv; - } - /* call init for each supported writer */ - alsa_writer_init(&writers[0]); - - wng = wng_new(1); - wng->writer_nodes[0].writer = &writers[0]; /* alsa */ - + init_supported_writers(); audiobuf = para_malloc(WAV_HEADER_LEN); ret = read_wav_header(); if (ret < 0) diff --git a/play.ggo b/play.ggo index 23cd64ee..b1c80839 100644 --- a/play.ggo +++ b/play.ggo @@ -14,3 +14,20 @@ option "loglevel" l default="4" optional + +option "writer" w +#~~~~~~~~~~~~~~~ + +"select stream writer" + + string typestr="name" + default="alsa (file if alsa is unsupported)" + optional + multiple + +option "list_writers" L +#~~~~~~~~~~~~~~~~~~~~~~ +"print available writers and exit" + + flag off + optional