Switch audiod over to the buffer tree API.
[paraslash.git] / buffer_tree.c
index 1a6b6e60d3f977d2d99f600d7a872a1b95250312..1be2037f5a7f3b9a2eb231debebdcf0be0ecedba 100644 (file)
@@ -6,6 +6,7 @@
 #include "string.h"
 #include "buffer_tree.h"
 #include "error.h"
+#include "sched.h"
 
 
 struct btr_buffer {
@@ -29,6 +30,8 @@ struct btr_node {
        struct list_head node;
        /* The children nodes of this btr node are linked together in a list. */
        struct list_head children;
+       /* Time of first data transfer. */
+       struct timeval start;
        /**
         * The input queue is a list of references to btr buffers. Each item on
         * the list represents an input buffer which has not been completely
@@ -58,6 +61,8 @@ struct btr_node *btr_new_node(const char *name, struct btr_node *parent,
        btrn->parent = parent;
        btrn->execute = handler;
        btrn->context = context;
+       btrn->start.tv_sec = 0;
+       btrn->start.tv_usec = 0;
        if (parent)
                list_add_tail(&btrn->node, &parent->children);
        INIT_LIST_HEAD(&btrn->children);
@@ -106,12 +111,16 @@ static void add_btrb_to_children(struct btr_buffer *btrb,
 {
        struct btr_node *ch;
 
+       if (btrn->start.tv_sec == 0)
+               btrn->start = *now;
        FOR_EACH_CHILD(ch, btrn) {
                struct btr_buffer_reference *br = para_malloc(sizeof(*br));
                br->btrb = btrb;
                br->consumed = consumed;
                list_add_tail(&br->node, &ch->input_queue);
                btrb->refcount++;
+               if (ch->start.tv_sec == 0)
+                       ch->start = *now;
        }
 }
 
@@ -119,6 +128,11 @@ void btr_add_output(char *buf, size_t size, struct btr_node *btrn)
 {
        struct btr_buffer *btrb;
 
+       assert(size != 0);
+       if (list_empty(&btrn->children)) {
+               free(buf);
+               return;
+       }
        btrb = new_btrb(buf, size);
        add_btrb_to_children(btrb, btrn, 0);
 }
@@ -211,20 +225,26 @@ static void flush_input_queue(struct btr_node *btrn)
                btr_drop_buffer_reference(br);
 }
 
-void btr_del_node(struct btr_node *btrn)
+void btr_free_node(struct btr_node *btrn)
+{
+       if (!btrn)
+               return;
+       free(btrn->name);
+       free(btrn);
+}
+
+void btr_remove_node(struct btr_node *btrn)
 {
        struct btr_node *ch;
 
        if (!btrn)
                return;
-       PARA_NOTICE_LOG("deleting %s\n", btrn->name);
+       PARA_NOTICE_LOG("removing btr node %s from buffer tree\n", btrn->name);
        FOR_EACH_CHILD(ch, btrn)
                ch->parent = NULL;
        flush_input_queue(btrn);
        if (btrn->parent)
                list_del(&btrn->node);
-       free(btrn->name);
-       free(btrn);
 }
 
 size_t btr_get_input_queue_size(struct btr_node *btrn)
@@ -256,8 +276,6 @@ void btr_splice_out_node(struct btr_node *btrn)
                        list_move(&ch->node, &btrn->parent->children);
        }
        assert(list_empty(&btrn->children));
-       free(btrn->name);
-       free(btrn);
 }
 
 /**
@@ -344,8 +362,8 @@ static int merge_input(struct btr_node *btrn)
        }
        /* make a new btrb that combines the two buffers and a br to it. */
        sz = szs[0] + szs[1];
-       //PARA_CRIT_LOG("merging input buffers: (%zu, %zu) -> %zu\n",
-       //      szs[0], szs[1], sz);
+       PARA_DEBUG_LOG("merging input buffers: (%zu, %zu) -> %zu\n",
+               szs[0], szs[1], sz);
        buf = para_malloc(sz);
        /* TODO: Avoid this memcopy by introducing btr buffer pool. */
        memcpy(buf, bufs[0], szs[0]);
@@ -370,6 +388,7 @@ void btr_merge(struct btr_node *btrn, size_t dest_size)
                size_t len = btr_next_buffer(btrn, &buf);
                if (len >= dest_size)
                        return;
+               PARA_DEBUG_LOG("input size = %zu < %zu = dest\n", len, dest_size);
                if (merge_input(btrn) < 2)
                        return;
        }
@@ -399,3 +418,34 @@ void btr_log_tree(struct btr_node *btrn, int loglevel)
 {
        return log_tree_recursively(btrn, loglevel, 0);
 }
+
+/** 640K ought to be enough for everybody ;) */
+#define BTRN_MAX_PENDING (640 * 1024)
+
+int btr_node_status(struct btr_node *btrn, size_t min_iqs,
+       enum btr_node_type type)
+{
+       size_t iqs;
+
+       if (type != BTR_NT_LEAF) {
+               if (btr_no_children(btrn))
+                       return -E_BTR_NO_CHILD;
+               if (btr_bytes_pending(btrn) > BTRN_MAX_PENDING)
+                       return 0;
+       }
+       if (type != BTR_NT_ROOT) {
+               if (btr_eof(btrn))
+                       return -E_BTR_EOF;
+               iqs = btr_get_input_queue_size(btrn);
+               if (iqs == 0) /* we have a parent, because not eof */
+                       return 0;
+               if (iqs < min_iqs && !btr_no_parent(btrn))
+                       return 0;
+       }
+       return 1;
+}
+
+void btr_get_node_start(struct btr_node *btrn, struct timeval *tv)
+{
+       *tv = btrn->start;
+}