A new concept in scheduling is that of chains of elements that need to be schedule separately, even in the same set of managed elements (which is the set of elements that the Bin in question [a pipeline or thread] is responsible for). An example would by anywhere you have a non-blocking queue in place for buffering. This kind of element might be useful in cases where the scheduling on a buffer level is tight enough that deadlocks might occur. The scheduler will find chains by traversing the pipeline through the list of managed elements. A chain boundary is anywhere you have a 'DECOUPLED' element. A DECOUPLED element is one where there is no direct correlation between the activities of the various pads. A source fits this description, although the normal single-pad source is the degenerate case. A queue more properly fits the bill, since pushing a buffer at the sink pad doesn't trigger anything on the src pad, and vice versa. A multi-src async source is probably the best example, since you want to leave the scheduling up to the elements connected to it. Anyway, first the simple case: fakesrc -> fakesink Both of them should probably have the DECOUPLED bit set, at least to be true to the nature of the actual fake elements. These two end up being a chain, and scheduling has to be set up for the chain. There are no cothreaded elements in the chain, which means it's relatively easy. The goal is to find a single entry into the chain, which can be called in a loop to get things done. Since the fakesrc is DECOUPLED, and we'd be messing with the source pad, it has lower priority than a DECOUPLED sink pad, so the fakesrc's sink pad is the ideal entry into the chain. This can be simplified into saying that the fakesink is the entry. In the end, the code to do this boils down to: buf = gst_pad_pull (fakesink->sinkpad); gst_pad_push (fakesink->sinkpad, buf); Because of the way things are no implemented for scheduling, turning it around and making the source the entry has no effect as far as the efficiency. That's because _get no longer directly calls gst_pad_push(), so we have to do it outside. No big deal, it boils down to the same thing I think, modulo a cache-line of stack (i.e. one or two fewer this way). If we put an identity in the middle: fakesrc -> identity -> fakesink then we have the same thing, except that there's now an element that isn't DECOUPLED, so it gets higher priority. That means the identity is now the entry, and when we push the buffer into its chain function, the fakesink gets called. Now, we can make this much more complex, with the following elementary echo meta-filter: |=====| -> delay1 -> |=====| | | | | -> queue -> | tee | -> delay2 -> | mix | -> queue -> | | | | |=====| -> delay3 -> |=====| The tee takes a buffer in and spits three out, delay shifts the timestamps around and possibly reframes things to be friendly. mix takes the three buffers and simply sums them (they're all audio). The tee element takes one buffer in and promptly spits three out, one after another. Delay takes an element and immediately spits out a buffer (it zero-pads at the beginning [the duration of the delay] for the sake of argument). Mix in this case is chained, but assumes that buffer will arrive in order. On the last chain, it does a push of the newly mixed audio buffer. The queues are both DECOUPLED, so they have lower weight. That leaves a bunch of other elements sitting there ripe for entry. But if we were to take delay1, what would happen? Well we can't, since there's no _get function on the tee's src pads. This just re-enforces the idea that the left-most (closest to the source, for you right-to-left people) element should get to be the entry. But what if we have multiple left-most elements?: -> queue -> eq1 -> |=====| | mix | -> queue -> queue -> eq2 -> |=====| If eq1 is the only entry, we call pull on the queue, then chain over to mix. Mix then doesn't do anything with it, since it's waiting for another buffer before doing anything. That means we have to do the same with eq2, and have it chain to mix, at which point mix will do its magic and chain out to the right-hand side. Figure out to actually use both entries is hard, because the idea at this point is that there's only a single entry to a chain. Does this mean that we should make mix a DECOUPLED element? That would fix it to some extent, giving us three chains in the above case. Each eq chain would be driven by the eq element, pulling from the queue and pushing into the mixer. The mixer -> queue chain is problematic, because there is no possibly entry. The mixer side has no _get function (since the push always happens upon the receipt of a buffer from the second sink pad), which means that that those two pads have no possible entrance. Cothreads make this case much easier, since the mix element would drive things, forcing the eq elements to pull and process buffers in order as needed. It may be that the best option in the case where there are any multi-sinkpad elements is to turn them into cothreads. Now, on to cothreaded cases. The simplest possible is to turn all the elements into cothreads. I may punt on this and do just that for the moment, but there's still the question of what to do at the ends of the chain, where the DECOUPLED elements are. The easiest is to simply always make then chained, so there's never any worry about who owns the cothread context for the element, simply because there never will be one. fakesrc -> queue -> @identity -> fakesink We just set it up so both ends of the queue are chained, and all is well.