It's not neccessary to register a task for each writer in the wng.
So use only one task for the wng that calls the writer's pre_select()
and post_select().
PARA_ERROR_LOG("%s\n", "failed to set nonblock mode");
return period_size * pad->bytes_per_frame;
}
-static void alsa_write_pre_select(struct sched *s, struct task *t)
+
+static int alsa_write_pre_select(struct sched *s, struct writer_node *wn)
{
- struct writer_node *wn = t->private_data;
struct private_alsa_data *pad = wn->private_data;
struct writer_node_group *wng = wn->wng;
struct timeval diff;
- t->ret = 1;
if (*wng->loaded < pad->bytes_per_frame)
- return;
+ return 1;
if (tv_diff(&s->now, &pad->next_chunk, &diff) < 0) {
if (tv_diff(&s->timeout, &diff, NULL) > 0)
s->timeout = diff;
s->timeout.tv_sec = 0;
s->timeout.tv_usec = 1;
}
+ return 1;
// PARA_INFO_LOG("timeout: %lu\n", tv2ms(&s->timeout));
}
-static void alsa_write_post_select(struct sched *s, struct task *t)
+static int alsa_write_post_select(struct sched *s, struct writer_node *wn)
{
- struct writer_node *wn = t->private_data;
struct private_alsa_data *pad = wn->private_data;
struct writer_node_group *wng = wn->wng;
size_t frames = *wng->loaded / pad->bytes_per_frame;
unsigned char *data = (unsigned char*)wng->buf;
struct timeval tv;
- t->ret = 0;
// PARA_INFO_LOG("%zd frames\n", frames);
if (!frames) {
if (*wng->input_eof)
- t->ret = *wng->loaded;
- return;
+ ret = *wng->loaded;
+ return 0;
}
if (tv_diff(&s->now, &pad->next_chunk, NULL) < 0)
- return;
+ return 0;
ret = snd_pcm_writei(pad->handle, data, frames);
if (ret == -EPIPE) {
PARA_WARNING_LOG("%s", "EPIPE\n");
snd_pcm_prepare(pad->handle);
- return;
+ return 0;
}
if (ret < 0) {
PARA_WARNING_LOG("%s", "ALSA ERROR\n");
- t->ret = -E_ALSA_WRITE;
- return;
+ return -E_ALSA_WRITE;
}
ms2tv(pad->buffer_time / 4000, &tv);
// ms2tv(1, &tv);
tv_add(&s->now, &tv, &pad->next_chunk);
- t->ret = ret * pad->bytes_per_frame;
-// PARA_INFO_LOG("ret: %d, frames: %zd\n", t->ret, frames);
+ return ret * pad->bytes_per_frame;
}
static void alsa_close(struct writer_node *wn)
for (i = 0; i < a->num_writers; i++) {
s->wng->writer_nodes[i].conf = a->writer_conf[i];
s->wng->writer_nodes[i].writer = a->writers[i];
- sprintf(s->wng->writer_nodes[i].task.status, "writer_node");
}
ret = wng_open(s->wng);
if (ret < 0) {
return ret;
}
-static void file_writer_pre_select(struct sched *s, struct task *t)
+static int file_writer_pre_select(struct sched *s, struct writer_node *wn)
{
- struct writer_node *wn = t->private_data;
struct private_file_writer_data *pfwd = wn->private_data;
struct writer_node_group *wng = wn->wng;
-// PARA_INFO_LOG("task %p check_fd: %d\n", t, pfwd->check_fd);
pfwd->check_fd = 0;
- t->ret = -E_FW_NO_FILE;
if (pfwd->fd <= 0)
- return;
- t->ret = 0;
+ return -E_FW_NO_FILE;
if (!*wng->loaded)
- return;
- t->ret = 1;
+ return 1;
para_fd_set(pfwd->fd, &s->wfds, &s->max_fileno);
pfwd->check_fd = 1;
+ return 1;
}
-static void file_writer_post_select(struct sched *s, struct task *t)
+static int file_writer_post_select(struct sched *s, struct writer_node *wn)
{
- struct writer_node *wn = t->private_data;
struct private_file_writer_data *pfwd = wn->private_data;
struct writer_node_group *wng = wn->wng;
+ int ret = 0;
- t->ret = 0;
if (!pfwd->check_fd)
- return;
+ return 0;
if (!*wng->loaded)
- return;
+ return 0;
if (!FD_ISSET(pfwd->fd, &s->wfds))
- return;
+ return 0;
// PARA_INFO_LOG("writing %zd\n", *wng->loaded);
- t->ret = write(pfwd->fd, wng->buf, *wng->loaded);
- if (t->ret < 0)
- t->ret = -E_FW_WRITE;
+ ret = write(pfwd->fd, wng->buf, *wng->loaded);
+ if (ret < 0)
+ ret = -E_FW_WRITE;
+ return ret;
}
static void file_writer_close(struct writer_node *wn)
if (!wng->writer_nodes[i].conf)
goto out;
wng->writer_nodes[i].writer = &writers[writer_num];
- sprintf(wng->writer_nodes[i].task.status, "%s",
- writer_names[writer_num]);
}
ret = 1;
out:
*/
struct writer_node {
/** points to the writer structure associated with this node */
- struct writer *writer;
+ struct writer *writer; /* FIXME: Should better be only the number */
/** writer-specific data */
void *private_data;
/** 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 */
struct writer {
-/**
- * the init function of the writer
- *
- * It must fill in all other function pointers of the given
- * writer structure.
- *
- */
-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
- *
- * This function should perform any work necessary to write the incoming
- * stream. If To this aim, it may allocate its private data structure and store
- * a pointer to that structure via the given writer_node paramenter.
- */
-int (*open)(struct writer_node *);
-/**
- *
- * write a chunk of audio data
- *
- * This is called from the driving application whenever a data block of \a
- * chunk_bytes is available. It must return the number of bytes consumed from
- * \a data on success, and negative on errors.
- *
- */
-int (*write)(char *data, size_t nbytes, struct writer_node *);
-void (*pre_select)(struct sched *s, struct task *t);
-void (*post_select)(struct sched *s, struct task *t);
-/**
- * close one instance of the writer
- *
- * This function is assumed to succeed.
- */
-void (*close)(struct writer_node *);
-/**
- * shutdown the writer
- *
- * This is a optional function pointer used for cleaning
- * up.
- */
-void (*shutdown)(struct writer_node *);
+ /**
+ * the init function of the writer
+ *
+ * It must fill in all other function pointers of the given
+ * writer structure.
+ *
+ */
+ 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
+ *
+ * This function should perform any work necessary to write the incoming
+ * stream. If To this aim, it may allocate its private data structure and store
+ * a pointer to that structure via the given writer_node paramenter.
+ */
+ int (*open)(struct writer_node *);
+ /**
+ *
+ * write a chunk of audio data
+ *
+ * This is called from the driving application whenever a data block of \a
+ * chunk_bytes is available. It must return the number of bytes consumed from
+ * \a data on success, and negative on errors.
+ *
+ */
+ int (*write)(char *data, size_t nbytes, struct writer_node *);
+ int (*pre_select)(struct sched *s, struct writer_node *wn);
+ int (*post_select)(struct sched *s, struct writer_node *wn);
+ /**
+ * close one instance of the writer
+ *
+ * This function is assumed to succeed.
+ */
+ void (*close)(struct writer_node *);
+ /**
+ * shutdown the writer
+ *
+ * This is a optional function pointer used for cleaning
+ * up.
+ */
+ void (*shutdown)(struct writer_node *);
};
/**
const char *writer_names[] ={WRITER_NAMES};
struct writer writers[NUM_SUPPORTED_WRITERS] = {WRITER_ARRAY};
-static void wng_post_select(__a_unused struct sched *s, struct task *t)
+static void wng_pre_select(__a_unused struct sched *s, struct task *t)
+{
+ struct writer_node_group *g = t->private_data;
+ int i;
+
+ FOR_EACH_WRITER_NODE(i, g) {
+ struct writer_node *wn = &g->writer_nodes[i];
+ t->ret = wn->writer->pre_select(s, wn);
+ if (t->ret < 0) {
+ g->eof = 1;
+ return;
+ }
+ }
+}
+
+static void wng_post_select(struct sched *s, struct task *t)
{
struct writer_node_group *g = t->private_data;
int i;
FOR_EACH_WRITER_NODE(i, g) {
struct writer_node *wn = &g->writer_nodes[i];
- t->ret = wn->task.ret;
+ t->ret = wn->writer->post_select(s, wn);
if (t->ret < 0) {
g->eof = 1;
return;
goto err_out;
wn->chunk_bytes = ret;
g->max_chunk_bytes = PARA_MAX(g->max_chunk_bytes, ret);
- wn->task.pre_select = wn->writer->pre_select;
- wn->task.post_select = wn->writer->post_select;
- wn->task.private_data = wn;
- register_task(&wn->task);
}
sprintf(g->task.status, "%s", "writer node group");
g->eof = 0;
unregister_task(&g->task);
while (i > 0) {
struct writer_node *wn = &g->writer_nodes[--i];
- unregister_task(&wn->task);
wn->writer->close(wn);
}
g->num_writers = 0;
void wng_unregister(struct writer_node_group *g)
{
- int i;
-
- FOR_EACH_WRITER_NODE(i, g) {
- struct writer_node *wn = &g->writer_nodes[i];
- unregister_task(&wn->task);
- }
unregister_task(&g->task);
g->eof = 1;
}
g->written = para_calloc(num_writers * sizeof(size_t));
g->task.private_data = g;
g->task.post_select = wng_post_select;
+ g->task.pre_select = wng_pre_select;
return g;
}
else
default_writer = 1;
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 %p\n",
writer_names[default_writer], writers[default_writer].parse_config);
wng->writer_nodes[0].conf = writers[default_writer].parse_config("");