-static void check_timeouts(void)
-{
- struct timeval now;
- int slot_num, timeout = conf.stream_timeout_arg;
-
- gettimeofday(&now, NULL);
- FOR_EACH_SLOT(slot_num) {
- struct slot_info *s = &slot[slot_num];
- if (s->format < 0)
- continue;
- /* check read time */
- if (s->receiver_node &&
- now.tv_sec > s->rtime.tv_sec + timeout) {
- PARA_INFO_LOG("%s input buffer (slot %d) not ready\n",
- audio_formats[s->format], slot_num);
- if (s->fci)
- s->fci->error = 42;
- else
- close_receiver(slot_num);
- }
- /* check write time */
- if (s->wpid > 0 && !s->wkilled &&
- now.tv_sec > s->wtime.tv_sec + timeout) {
- PARA_INFO_LOG("%s output buffer (slot %d) not ready\n",
- audio_formats[s->format], slot_num);
- if (s->fci)
- s->fci->error = 42;
- }
- }
-}
-
-static size_t get_loaded_bytes(int slot_num)
-{
- size_t loaded = 0;
- struct slot_info *s = &slot[slot_num];
- struct receiver_node *rn = s->receiver_node;
-
- if (s->format < 0)
- goto out;
-
- if (afi[s->format].num_filters) {
- if (s->fci)
- loaded = *s->fci->out_loaded;
- } else {
- if (rn)
- loaded = rn->loaded;
- }
-out:
- return loaded;
-}
-
-
-static void close_decoder_if_idle(int slot_num)
-{
- struct slot_info *s = &slot[slot_num];
- struct receiver_node *rn = s->receiver_node;
-
- if (s->format < 0)
- return;
- if (!s->fci)
- return;
- if (!rn->eof && !s->fci->error && s->wpid > 0)
- return;
- if (!s->fci->error && s->wpid > 0) { /* eof */
- if (filter_io(s->fci) > 0)
- return;
- if (get_loaded_bytes(slot_num))
- return;
- }
- if (s->write_fd > 0) {
- PARA_INFO_LOG("slot %d: closing write fd %d\n", slot_num,
- s->write_fd);
- close(s->write_fd);
- del_close_on_fork_list(s->write_fd);
- s->write_fd = -1;
- }
- if (s->wpid > 0)
- return; /* wait until writer dies before closing filters */
- PARA_INFO_LOG("closing all filters in slot %d (filter_chain %p)\n",
- slot_num, s->fci);
- close_filters(s->fci);
- free(s->fci);
- close_receiver(slot_num);
- clear_slot(slot_num);
-}
-
-static int set_stream_fds(fd_set *wfds)
-{
- int i, max_fileno = -1;
-
- check_timeouts();
- FOR_EACH_SLOT(i) {
- struct slot_info *s = &slot[i];
- struct audio_format_info *a;
- struct receiver_node *rn;
-
- close_decoder_if_idle(i);
- s->wcheck = 0;
- if (s->format < 0)
- continue;
- a = &afi[s->format];
- rn = s->receiver_node;
- if (rn && rn->loaded && !s->wpid) {
- PARA_INFO_LOG("no writer in slot %d\n", i);
- start_stream_writer(i);
- }
- if (s->write_fd <= 0)
- continue;
- if (!get_loaded_bytes(i))
- continue;
- FD_SET(s->write_fd, wfds);
- s->wcheck = 1;
- max_fileno = MAX(s->write_fd, max_fileno);
- }
-// PARA_INFO_LOG("return %d\n", max_fileno);
- return max_fileno;
-}
-
-static int write_audio_data(int slot_num)
-{
- struct slot_info *s = &slot[slot_num];
- struct audio_format_info *a = &afi[s->format];
- struct receiver_node *rn = s->receiver_node;
- int rv;
- char **buf;
- size_t *len;
-
- if (a->num_filters) {
- buf = &s->fci->outbuf;
- len = s->fci->out_loaded;
- } else {
- buf = &rn->buf;
- len = &rn->loaded;
- }
- PARA_DEBUG_LOG("writing %p (%zd bytes)\n", *buf, *len);
- rv = write(s->write_fd, *buf, *len);
- PARA_DEBUG_LOG("wrote %d/%zd\n", rv, *len);
- if (rv < 0) {
- PARA_WARNING_LOG("write error in slot %d (fd %d): %s\n",
- slot_num, s->write_fd, strerror(errno));
- *len = 0;
- s->fci->error = E_WRITE_AUDIO_DATA;
- } else if (rv != *len) {
- PARA_DEBUG_LOG("partial %s write (%i/%zd) for slot %d\n",
- audio_formats[s->format], rv, *len, slot_num);
- *len -= rv;
- memmove(*buf, *buf + rv, *len);
- } else
- *len = 0;
- if (rv > 0)
- gettimeofday(&s->wtime, NULL);
- return rv;
-}
-
-static void slot_io(fd_set *wfds)
-{
- int ret, i;
-
- FOR_EACH_SLOT(i) {
- struct slot_info *s = &slot[i];
- struct receiver_node *rn = s->receiver_node;
-
- if (rn && rn->loaded)
- gettimeofday(&s->rtime, NULL);
- if (s->format >= 0 && s->write_fd > 0 && s->fci) {
- ret = filter_io(s->fci);
- if (ret < 0)
- s->fci->error = -ret;
-// PARA_DEBUG_LOG("slot %d, filter io %d bytes, check write: %d, loaded: %d/%d, eof: %d\n",
-// i, ret, s->wcheck, rn->loaded, *s->fci->out_loaded, rn->eof);
- }
- if (s->write_fd <= 0 || !s->wcheck || !FD_ISSET(s->write_fd, wfds))
- continue;
- write_audio_data(i);
- }
-}
-
-static int parse_stream_command(const char *txt, char **cmd)
-{
- char *p = strchr(txt, ':');
- int i;
-
- if (!p)
- return -E_MISSING_COLON;
- p++;
- FOR_EACH_AUDIO_FORMAT(i) {
- if (strncmp(txt, audio_formats[i], strlen(audio_formats[i])))
- continue;
- *cmd = p;
- return i;
- }
- return -E_UNSUPPORTED_AUDIO_FORMAT;
-}
-
-static int add_filter(int format, char *cmdline)