On 06/20/2013 09:29 AM, Tanu Kaskinen wrote: > On Thu, 2013-06-20 at 06:22 +0200, David Henningsson wrote: >> On 06/19/2013 08:11 PM, Tanu Kaskinen wrote: >>> On Wed, 2013-06-19 at 19:50 +0200, David Henningsson wrote: >>>> On 06/19/2013 05:40 PM, Tanu Kaskinen wrote: >>>>> pa_port_node takes care of things that are common to all port nodes. >>>>> The port device class is used in the node name for some extra >>>>> user-friendliness. The goal is to avoid the long and cryptic names >>>>> that are currently generated for sinks, sources and cards. >>>> >>>> I'm not following. Why do we need extra pa_port_node and pa_sink_node >>>> objects? Why don't we just have a pa_node pointer (or even embedded >>>> struct, if that makes sense) in pa_device_port / pa_sink instead? >>> >>> pa_node will probably have some callbacks, at least for activating the >>> node. I expect that e.g. pa_port_node would have a common implementation >>> for activating ports. There may or may not be need for further >>> specializing the activation code by adding an activation callback also >>> to pa_port_node. This is largely speculation, however, because this >>> hasn't been fully designed yet. >> >> Hmm, I'm still not seeing why all types of specialization and callbacks >> can't just be handled by code taking just a node pointer, like: >> >> /* In device-port.c */ >> >> void activate_node_cb(pa_node *n) >> { >> pa_device_port *p = n->userdata; >> >> /* Do some specialized node related stuff here */ >> >> activate_port(p); >> } >> >> If necessary, this method can also call p's callbacks if you need to >> something differently for alsa and bt (although it would be more elegant >> if such code was inside activate_port() rather than activate_node_cb). > > I think my original answer was just a reflex to defend my choice, > however bad it might have been. After thinking a bit more, I believe the > reason why I chose this approach was that it was the first thing that > came to my mind, given the requirement that "there probably will be code > that is specific to port nodes". Having a class for port nodes then > seemed obvious, but I agree that it seems to be unnecessarily heavy and > complicated. > > Instead of implementing the port node callbacks in device-port.c, I'd > like to reserve the callbacks to module code. What kind of module is this referring to? Policy modules? > I propose that any generic > port node code is put to node.c. There will be a node type field that > node.c can use to determine how e.g. activation should be handled. The > type field was in the plans anyway (and I have already implemented it), > it's needed for other purposes too. I'm okay with this approach too - code can easily be moved from node.c to device-port.c if we think this is better at some other time. If we're going to have owner types, this also opens up for inline functions such as static inline pa_device_port *node2port(pa_node *n) { pa_assert(n->type = PA_NODE_TYPE_DEVICE_PORT); return (pa_device_port *) n->owner; } (Owner is probably a better name than "userdata" if it always refer to the node owner.) I would prefer a vtable over a big switch on "type" though. >>> If you think pa_port_node is bad, we >>> could try going without it until we actually need it. >> >> At this point the struct looks very superfluous to me. >> >>>> If every sink, source and port have exactly one node, that seems to be >>>> the logical object model. Or can sinks, sources and ports have more than >>>> one node attached to them? >>> >>> I don't think it's likely that we would some day need one port or sink >>> to have multiple nodes - we certainly don't need it today. It's entirely >>> possible that a port or a sink could have zero nodes, however (or at >>> least it's possible for sinks - e.g. bluetooth sinks don't have nodes, >>> and neither do alsa sinks if ports are present). >> >> Ok, then the logical object model to me seems to have a pa_node pointer >> in pa_device_port and pa_sink. That also simplifies code because you >> don't have to do anything in the alsa/jack/bluetooth backends - just >> initialize the node in e g pa_sink_new and/or pa_sink_put. > > This is one thing to discuss - should nodes be created in > pa_sink_new/put(), or should the backend create the nodes (and if the > latter, at what time)? > > The backend needs to control the creation anyway, because not every sink > is going to have a node, so the backend has to decide whether a node > will be created. The backend also needs to customize the node > initialization (at least the node name, but I expect there to be need > for custom callbacks too and possibly other properties). For that reason > it seems better that the backend creates and owns the node. The primary reason I prefer to put it in the port/sink/source rather than the backend is that we get a lot less code duplication between backends. If the backend needs to customise something, it could do that, but if it does not, why not have code in the port/sink/source objects that deals with the generic case? We could consider having a node_new_data struct inside port/sink/source_new_data struct, and also a flag for whether to create it or not. What do you think of that? > As for when the backend should create the node: I have so far chosen the > approach that nodes are created after pa_sink_put() (and other similar > put() calls), because it was simple that way. However, at least in case > of streams, the node creation should happen with careful cooperation > with sink input creation, because the routing is decided before > pa_sink_input_put(). If the routing policy operates on nodes, the node > creation must happen before pa_sink_input_put(), otherwise the stream > will be incorrectly routed for a short time. > > How to proceed? I will definitely get rid of pa_port_node and friends. I > guess I should also rework the node creation order, since it needs to be > changed anyway at some point. Should sink-input.c call pa_node_new(), or > should the backend do that? As I said, my preference is to do it in the > backend, but do you have different opinion? > -- David Henningsson, Canonical Ltd. https://launchpad.net/~diwic