X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=check_wav.c;h=a36cea9ab34fb319bf7070eaa43e8bb65dcfcd24;hp=0ed79e43534792c3b82049606f2c1e31ee09f8cd;hb=69a294cd641c623db61f46ee86901845789a1c7b;hpb=1af65c31171b35e5a5e931e3a4467786e932e145 diff --git a/check_wav.c b/check_wav.c index 0ed79e43..a36cea9a 100644 --- a/check_wav.c +++ b/check_wav.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2012 Andre Noll + * Copyright (C) 2005-2014 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -19,15 +19,18 @@ /** Length of a standard wav header. */ #define WAV_HEADER_LEN 44 +/** The possible states of a check_wav instance. */ enum check_wav_state { + /** Initial state, less than \p WAV_HEADER_LEN bytes available. */ CWS_NEED_HEADER, + /** Wav hader was detected. */ CWS_HAVE_HEADER, + /** First part of the stream did not look like a wav header. */ CWS_NO_HEADER, }; -struct check_wav_task { +struct check_wav_context { enum check_wav_state state; - struct task task; struct btr_node *btrn; size_t min_iqs; /* Command line args. */ @@ -38,36 +41,42 @@ struct check_wav_task { unsigned sample_rate; }; -static void check_wav_pre_select(struct sched *s, struct task *t) +/** + * Set select timeout according to the given context. + * + * \param s Contains the timeval that should be set. + * \param cwc Contains a pointer to the buffer tree node. + * + * This requests a minimal timeout from the scheduler if btrn of \a cwc is not + * idle. + */ +void check_wav_pre_select(struct sched *s, struct check_wav_context *cwc) { - struct check_wav_task *cwt = container_of(t, struct check_wav_task, task); - int ret; - - ret = btr_node_status(cwt->btrn, cwt->min_iqs, BTR_NT_INTERNAL); + int ret = btr_node_status(cwc->btrn, cwc->min_iqs, BTR_NT_INTERNAL); if (ret != 0) sched_min_delay(s); } static int check_wav_exec(struct btr_node *btrn, const char *cmd, char **result) { - struct check_wav_task *cwt = btr_context(btrn); + struct check_wav_context *cwc = btr_context(btrn); int val, header_val, given, arg; - header_val = cwt->channels; - arg = cwt->params.channels_arg; - given = cwt->params.channels_given; + header_val = cwc->channels; + arg = cwc->params.channels_arg; + given = cwc->params.channels_given; if (!strcmp(cmd, "channels")) goto out; - header_val = cwt->sample_rate; - arg = cwt->params.sample_rate_arg; - given = cwt->params.sample_rate_given; + header_val = cwc->sample_rate; + arg = cwc->params.sample_rate_arg; + given = cwc->params.sample_rate_given; if (!strcmp(cmd, "sample_rate")) goto out; - header_val = cwt->sample_format; - arg = cwt->params.sample_format_arg; - given = cwt->params.sample_format_given; + header_val = cwc->sample_format; + arg = cwc->params.sample_format_arg; + given = cwc->params.sample_format_given; if (!strcmp(cmd, "sample_format")) goto out; @@ -76,11 +85,18 @@ out: if (given) val = arg; else { - switch (cwt->state) { + switch (cwc->state) { case CWS_HAVE_HEADER: val = header_val; break; case CWS_NO_HEADER: + /* + * No wav header available and no value specified at + * the command line. Maybe one of our parent nodes + * knows. + */ + if (btr_exec_up(btr_parent(cwc->btrn), cmd, result) >= 0) + return 1; /* Use default value */ val = arg; break; @@ -92,27 +108,43 @@ out: return 1; } -static void check_wav_post_select(__a_unused struct sched *s, struct task *t) +/** + * Filter out the wav header, pushdown everything else. + * + * \param cwc The context of this instance. + * + * This function looks at the first \p WAV_HEADER_SIZE bytes of the input queue + * of the btrn of \a cwc. If they look like a wav header, the function extracts + * the information of interest and swallows this part of the stream. Otherwise + * it is pushed down to all children. In either case the rest of the input is + * pushed down as well. + * + * Once the first part has been processed this way, the state of the instance + * changes from \p CWS_NEED_HEADER to \p CWS_HAVE_HEADER or \p CWS_NO_HEADER. + * + * \return Standard. + */ +int check_wav_post_select(struct check_wav_context *cwc) { - struct check_wav_task *cwt = container_of(t, struct check_wav_task, task); - struct btr_node *btrn = cwt->btrn; + struct btr_node *btrn = cwc->btrn; unsigned char *a; size_t sz; int ret; uint16_t bps; /* bits per sample */ const char *sample_formats[] = {SAMPLE_FORMATS}; - t->error = 0; - ret = btr_node_status(btrn, cwt->min_iqs, BTR_NT_INTERNAL); + if (!btrn) + return 0; + ret = btr_node_status(btrn, cwc->min_iqs, BTR_NT_INTERNAL); if (ret <= 0) goto out; - if (cwt->state != CWS_NEED_HEADER) + if (cwc->state != CWS_NEED_HEADER) goto pushdown; - btr_merge(btrn, cwt->min_iqs); + btr_merge(btrn, cwc->min_iqs); sz = btr_next_buffer(btrn, (char **)&a); - if (sz < cwt->min_iqs) /* file size less than WAV_HEADER_SIZE */ + if (sz < cwc->min_iqs) /* file size less than WAV_HEADER_SIZE */ goto pushdown; - cwt->min_iqs = 0; + cwc->min_iqs = 0; /* * The default byte ordering assumed for WAVE data files is * little-endian. Files written using the big-endian byte ordering @@ -121,16 +153,14 @@ static void check_wav_post_select(__a_unused struct sched *s, struct task *t) if (a[0] != 'R' || a[1] != 'I' || a[2] != 'F' || (a[3] != 'F' && a[3] != 'X')) { PARA_NOTICE_LOG("wav header not found\n"); - cwt->state = CWS_NO_HEADER; - sprintf(t->status, "check wav: no header"); + cwc->state = CWS_NO_HEADER; goto out; } PARA_INFO_LOG("found wav header\n"); - cwt->state = CWS_HAVE_HEADER; - sprintf(t->status, "check wav: have header"); + cwc->state = CWS_HAVE_HEADER; /* Only set those values which have not already been set. */ - cwt->channels = (unsigned)a[22]; - cwt->sample_rate = a[24] + (a[25] << 8) + (a[26] << 16) + (a[27] << 24); + cwc->channels = (unsigned)a[22]; + cwc->sample_rate = a[24] + (a[25] << 8) + (a[26] << 16) + (a[27] << 24); bps = a[34] + ((unsigned)a[35] << 8); if (bps != 8 && bps != 16) { PARA_WARNING_LOG("%u bps not supported, assuming 16\n", @@ -143,43 +173,65 @@ static void check_wav_post_select(__a_unused struct sched *s, struct task *t) * integers, ranging from -32768 to 32767. */ if (bps == 8) - cwt->sample_format = SF_U8; + cwc->sample_format = SF_U8; else - cwt->sample_format = (a[3] == 'F')? + cwc->sample_format = (a[3] == 'F')? SF_S16_LE : SF_S16_BE; - PARA_NOTICE_LOG("%dHz, %s, %s\n", cwt->sample_rate, - cwt->channels == 1? "mono" : "stereo", - sample_formats[cwt->sample_format]); + PARA_NOTICE_LOG("%dHz, %s, %s\n", cwc->sample_rate, + cwc->channels == 1? "mono" : "stereo", + sample_formats[cwc->sample_format]); btr_consume(btrn, WAV_HEADER_LEN); pushdown: btr_pushdown(btrn); out: - t->error = ret; if (ret < 0) - btr_remove_node(&cwt->btrn); + btr_remove_node(&cwc->btrn); + return ret; } -struct check_wav_task *check_wav_init(struct sched *s, struct btr_node *parent, - struct wav_params *params, struct btr_node **cwt_btrn) +/** + * Allocate and set up a new check_wav instance. + * + * \param parent This buffer tree node will be the parent of the new node. + * \param child The child of the new node. + * \param params Default values and options. + * \param cw_btrn A pointer to the check wav node is returned here. + * + * This function also sets up the ->execute handler of the btrn so that all + * children of this node can figure out channel count, sample rate, etc. + * + * \return The (opaque) handle of the newly created check_wav instance. It is + * supposed to be passed to \ref check_wav_pre_select() and \ref + * check_wav_post_select(). + * + * \sa \ref btr_new_node. + */ +struct check_wav_context *check_wav_init(struct btr_node *parent, + struct btr_node *child, struct wav_params *params, + struct btr_node **cw_btrn) { - struct check_wav_task *cwt = para_calloc(sizeof(*cwt)); - - cwt->state = CWS_NEED_HEADER; - cwt->min_iqs = WAV_HEADER_LEN; - cwt->params = *params; - cwt->btrn = btr_new_node(&(struct btr_node_description) - EMBRACE(.name = "check_wav", .parent = parent, - .handler = check_wav_exec, .context = cwt)); - sprintf(cwt->task.status, "check_wav"); - cwt->task.pre_select = check_wav_pre_select; - cwt->task.post_select = check_wav_post_select; - if (cwt_btrn) - *cwt_btrn = cwt->btrn; - register_task(s, &cwt->task); - return cwt; + struct check_wav_context *cwc = para_calloc(sizeof(*cwc)); + + cwc->state = CWS_NEED_HEADER; + cwc->min_iqs = WAV_HEADER_LEN; + cwc->params = *params; + cwc->btrn = btr_new_node(&(struct btr_node_description) + EMBRACE(.name = "check_wav", .parent = parent, .child = child, + .handler = check_wav_exec, .context = cwc)); + if (cw_btrn) + *cw_btrn = cwc->btrn; + return cwc; } -void check_wav_shutdown(struct check_wav_task *cwt) +/** + * Dellocate all ressources of a check_wav instance. + * + * \param cwc Determines the instance to shut down. + * + * This function may only be called after check_wav_post_select() has returned + * negative. + */ +void check_wav_shutdown(struct check_wav_context *cwc) { - free(cwt); + free(cwc); }