add support for implicit audio resources
authorJanos Kovacs <jankovac503@gmail.com>
Tue, 29 Jan 2013 09:30:31 +0000 (11:30 +0200)
committerJanos Kovacs <jankovac503@gmail.com>
Fri, 1 Feb 2013 21:18:39 +0000 (23:18 +0200)
murphy/discover.c
murphy/module-murphy-ivi.c
murphy/murphyif.c
murphy/murphyif.h
murphy/node.c
murphy/node.h
murphy/userdata.h

index 6a6e992..f4eef5e 100644 (file)
@@ -736,6 +736,7 @@ void pa_discover_register_sink_input(struct userdata *u, pa_sink_input *sinp)
     data.amid      = AM_ID_INVALID;
     data.paname    = name;
     data.paidx     = sinp->index;
+    data.rsetid    = (char *)pa_proplist_gets(pl, PA_PROP_RESOURCE_SET_ID);
 
     /*
      * here we can't guess whether the application requested an explicit
@@ -953,6 +954,7 @@ void pa_discover_add_sink_input(struct userdata *u, pa_sink_input *sinp)
         data.paidx     = sinp->index;
         data.mux       = pa_multiplex_find_by_sink(u->multiplex,
                                                    sinp->sink->index);
+        data.rsetid    = (char *)pa_proplist_gets(pl, PA_PROP_RESOURCE_SET_ID);
         node = create_node(u, &data, &created);
 
         pa_assert(node);
@@ -1090,6 +1092,7 @@ void pa_discover_register_source_output(struct userdata  *u,
     data.amid      = AM_ID_INVALID;
     data.paname    = name;
     data.paidx     = sout->index;
+    data.rsetid    = (char *)pa_proplist_gets(pl, PA_PROP_RESOURCE_SET_ID);
 
     /*
      * here we can't guess whether the application requested an explicit
@@ -1262,6 +1265,7 @@ void pa_discover_add_source_output(struct userdata *u, pa_source_output *sout)
         data.amid      = AM_ID_INVALID;
         data.paname    = name;
         data.paidx     = sout->index;
+        data.rsetid    = (char *)pa_proplist_gets(pl, PA_PROP_RESOURCE_SET_ID);
 
         node = create_node(u, &data, &created);
 
index 10fec71..a798bb2 100644 (file)
 #define DEFAULT_CONFIG_FILE "murphy-ivi.lua"
 #endif
 
+#ifdef WITH_MURPHYIF
+#define WITH_DOMCTL
+#define WITH_RESOURCES
+#endif
+
 
 PA_MODULE_AUTHOR("Janos Kovacs");
 PA_MODULE_DESCRIPTION("Murphy and GenIVI compliant audio policy module");
@@ -81,6 +86,12 @@ PA_MODULE_USAGE(
     "config_file=<policy configuration file> "
     "fade_out=<stream fade-out time in msec> "
     "fade_in=<stream fade-in time in msec> "
+#ifdef WITH_DOMCTL
+    "murphy_domain_controller=<address of Murphy's domain controller service> "
+#endif
+#ifdef WITH_RESOURCES
+    "murphy_resources=<address of Murphy's native resource service> "
+#endif
 #ifdef WITH_DBUS
     "dbus_bus_type=<system|session> "
     "dbus_if_name=<policy dbus interface> "
@@ -101,6 +112,12 @@ static const char* const valid_modargs[] = {
     "config_file",
     "fade_out",
     "fade_in",
+#ifdef WITH_DOMCTL
+    "murphy_domain_controller",
+#endif
+#ifdef WITH_RESOURCES
+    "murphy_resources",
+#endif
 #ifdef WITH_DBUS
     "dbus_bus_type",
     "dbus_if_name",
@@ -125,6 +142,12 @@ int pa__init(pa_module *m) {
     const char      *cfgfile;
     const char      *fadeout;
     const char      *fadein;
+#ifdef WITH_DOMCTL
+    const char      *ctladdr;
+#endif
+#ifdef WITH_RESOURCES
+    const char      *resaddr;
+#endif
 #ifdef WITH_DBUS
     const char      *dbustype;
     const char      *ifnam;
@@ -140,7 +163,6 @@ int pa__init(pa_module *m) {
     const char      *nsnam;
     const char      *cfgpath;
     char             buf[4096];
-    const char      *mrpaddr;
 
     
     pa_assert(m);
@@ -154,6 +176,12 @@ int pa__init(pa_module *m) {
     cfgfile  = pa_modargs_get_value(ma, "config_file", DEFAULT_CONFIG_FILE);
     fadeout  = pa_modargs_get_value(ma, "fade_out", NULL);
     fadein   = pa_modargs_get_value(ma, "fade_in", NULL);
+#ifdef WITH_DOMCTL
+    ctladdr  = pa_modargs_get_value(ma, "murphy_domain_controller", NULL);
+#endif
+#ifdef WITH_RESOURCES
+    resaddr  = pa_modargs_get_value(ma, "murphy_resources", NULL);
+#endif
 #ifdef WITH_DBUS
     dbustype = pa_modargs_get_value(ma, "dbus_bus_type", NULL);
     ifnam    = pa_modargs_get_value(ma, "dbus_if_name", NULL);
@@ -191,17 +219,16 @@ int pa__init(pa_module *m) {
     u->scripting = pa_scripting_init(u);
     u->config    = pa_mir_config_init(u);
     u->extapi    = pa_extapi_init(u);
+    u->murphyif  = pa_murphyif_init(u, ctladdr, resaddr);
 
     u->state.sink   = PA_IDXSET_INVALID;
     u->state.source = PA_IDXSET_INVALID;
 
     if (u->nullsink == NULL || u->routerif == NULL  ||
-        u->audiomgr == NULL || u->discover == NULL)
+        u->audiomgr == NULL || u->discover == NULL  ||
+        u->murphyif == NULL)
         goto fail;
 
-    mrpaddr   = pa_modargs_get_value(ma, "murphy_address", NULL);
-    u->domctl = pa_murphyif_init(u, mrpaddr);
-
     m->userdata = u;
 
     /* register ext api callback */
index 0475334..6ad2281 100644 (file)
  * MA 02110-1301 USA.
  *
  */
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <pulse/utf8.h>
 #include <pulsecore/pulsecore-config.h>
 #include <pulsecore/module.h>
+#include <pulsecore/llist.h>
+#include <pulsecore/idxset.h>
+#include <pulsecore/hashmap.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/sink-input.h>
+#include <pulsecore/source-output.h>
 
 #ifdef WITH_MURPHYIF
+#define WITH_DOMCTL
+#define WITH_RESOURCES
+#endif
+
+#if defined(WITH_DOMCTL) || defined(WITH_RESOURCES)
 #include <murphy/common/macros.h>
 #include <murphy/common/mainloop.h>
 #include <murphy/pulse/pulse-glue.h>
 #endif
 
+#ifdef WITH_RESOURCES
+#include <murphy/resource/protocol.h>
+#include <murphy/common/transport.h>
+#include <murphy/resource/protocol.h>
+#include <murphy/resource/data-types.h>
+#endif
+
 #include "murphyif.h"
+#include "node.h"
 
+#ifdef WITH_RESOURCES
+#define INVALID_ID      (~(uint32_t)0)
+#define INVALID_INDEX   (~(uint32_t)0)
+#define INVALID_SEQNO   (~(uint32_t)0)
+#define INVALID_REQUEST (~(uint16_t)0)
+
+#define PUSH_VALUE(msg, tag, typ, val) \
+    mrp_msg_append(msg, MRP_MSG_TAG_##typ(RESPROTO_##tag, val))
+
+#define PUSH_ATTRS(msg, rif, proplist)                  \
+    resource_push_attributes(msg, rif, proplist)
+
+typedef struct resource_attribute  resource_attribute;
+typedef struct resource_request    resource_request;
+
+struct resource_attribute {
+    PA_LLIST_FIELDS(resource_attribute);
+    const char *prop;
+    mrp_attr_t  def;
+};
 
-struct pa_domctl {
+struct resource_request {
+    PA_LLIST_FIELDS(resource_request);
+    uint32_t nodidx;
+    uint16_t reqid;
+    uint32_t seqno;
+};
+
+#endif
+
+typedef struct {
     const char           *addr;
-#ifdef WITH_MURPHYIF
-    mrp_mainloop_t       *ml;
+#ifdef WITH_DOMCTL
     mrp_domctl_t         *ctl;
     int                   ntable;
     mrp_domctl_table_t   *tables;
@@ -40,21 +93,96 @@ struct pa_domctl {
     mrp_domctl_watch_t   *watches;
     pa_murphyif_watch_cb  watchcb;
 #endif
+} domctl_interface;
+
+typedef struct {
+    const char      *addr;
+    const char      *inpres;
+    const char      *outres;
+#ifdef WITH_RESOURCES
+    mrp_transport_t *transp;
+    mrp_sockaddr_t   saddr;
+    socklen_t        alen;
+    const char      *atype;
+    pa_bool_t        connected;
+    struct {
+        uint32_t request;
+        uint32_t reply;
+    }                seqno;
+    pa_hashmap      *nodes;
+    PA_LLIST_HEAD(resource_attribute, attrs);
+    PA_LLIST_HEAD(resource_request, reqs);
+#endif
+} resource_interface;
+
+
+struct pa_murphyif {
+#if defined(WITH_DOMCTL) || defined(WITH_RESOURCES)
+    mrp_mainloop_t *ml;
+#endif
+    domctl_interface domctl;
+    resource_interface resource;
+    pa_hashmap *nodes;
 };
 
 
-#ifdef WITH_MURPHYIF
-static void connect_notify(mrp_domctl_t *, int, int, const char *, void *);
-static void watch_notify(mrp_domctl_t *, mrp_domctl_data_t *, int, void *);
-static void dump_data(mrp_domctl_data_t *);
+#ifdef WITH_DOMCTL
+static void domctl_connect_notify(mrp_domctl_t *,int,int,const char *,void *);
+static void domctl_watch_notify(mrp_domctl_t *,mrp_domctl_data_t *,int,void *);
+static void domctl_dump_data(mrp_domctl_data_t *);
 #endif
 
+#ifdef WITH_RESOURCES
+static void       resource_attribute_destroy(resource_interface *,
+                                             resource_attribute *);
+static pa_bool_t  resource_transport_connect(resource_interface *);
+static void       resource_xport_closed_evt(mrp_transport_t *, int, void *);
+
+static mrp_msg_t *resource_create_request(uint32_t, mrp_resproto_request_t);
+static pa_bool_t  resource_send_message(resource_interface *, mrp_msg_t *,
+                                        uint32_t, uint16_t, uint32_t);
+static pa_bool_t  resource_set_create(struct userdata *, uint32_t,
+                                      mir_direction, const char *,
+                                      const char *, uint32_t, pa_proplist *);
+static pa_bool_t  resource_set_destroy(struct userdata *, uint32_t);
+static pa_bool_t  resource_set_acquire(struct userdata *, uint32_t, uint32_t);
+static pa_bool_t  resource_push_attributes(mrp_msg_t *, resource_interface *,
+                                           pa_proplist *);
+
+static void       resource_recv_msg(mrp_transport_t *, mrp_msg_t *, void *);
+static void       resource_recvfrom_msg(mrp_transport_t *, mrp_msg_t *,
+                                        mrp_sockaddr_t *, socklen_t, void *);
+static void       resource_set_create_response(struct userdata *, mir_node *,
+                                               mrp_msg_t *, void **);
+
+static pa_bool_t  resource_fetch_seqno(mrp_msg_t *, void **, uint32_t *);
+static pa_bool_t  resource_fetch_request(mrp_msg_t *, void **, uint16_t *);
+static pa_bool_t  resource_fetch_status(mrp_msg_t *, void **, int *);
+static pa_bool_t  resource_fetch_rset_id(mrp_msg_t *, void **, uint32_t*);
+static pa_bool_t  resource_fetch_rset_state(mrp_msg_t *, void **,
+                                            mrp_resproto_state_t *);
+static pa_bool_t  resource_fetch_rset_mask(mrp_msg_t *, void **,
+                                           mrp_resproto_state_t *);
+#endif
 
 
-pa_domctl *pa_murphyif_init(struct userdata *u, const char *addr)
+pa_murphyif *pa_murphyif_init(struct userdata *u,
+                              const char *ctl_addr,
+                              const char *res_addr)
 {
-    pa_domctl *domctl;
-#ifdef WITH_MURPHYIF
+#ifdef WITH_RESOURCES
+    static mrp_transport_evt_t ev = {
+        { .recvmsg     = resource_recv_msg },
+        { .recvmsgfrom = resource_recvfrom_msg },
+        .closed        = resource_xport_closed_evt,
+        .connection    = NULL
+    };
+#endif
+
+    pa_murphyif *murphyif;
+    domctl_interface *dif;
+    resource_interface *rif;
+#if defined(WITH_DOMCTL) || defined(WITH_RESOURCES)
     mrp_mainloop_t *ml;
 
     if (!(ml = mrp_mainloop_pulse_get(u->core->mainloop))) {
@@ -62,62 +190,122 @@ pa_domctl *pa_murphyif_init(struct userdata *u, const char *addr)
         return NULL;
     }
 #endif
+#ifdef WITH_RESOURCES
+#endif
 
-    domctl = pa_xnew0(pa_domctl, 1);
-    domctl->addr = pa_xstrdup(addr ? addr : MRP_DEFAULT_DOMCTL_ADDRESS);
-#ifdef WITH_MURPHYIF
-    domctl->ml = ml;
+    murphyif = pa_xnew0(pa_murphyif, 1);
+    dif = &murphyif->domctl;
+    rif = &murphyif->resource;
+
+#if defined(WITH_DOMCTL) || defined(WITH_RESOURCES)
+    murphyif->ml = ml;
+#endif
+
+    dif->addr = pa_xstrdup(ctl_addr ? ctl_addr:MRP_DEFAULT_DOMCTL_ADDRESS);
+#ifdef WITH_DOMCTL
+#endif
+
+    rif->addr = pa_xstrdup(res_addr ? res_addr:RESPROTO_DEFAULT_ADDRESS);
+#ifdef WITH_RESOURCES
+    rif->alen = mrp_transport_resolve(NULL, rif->addr, &rif->saddr,
+                                      sizeof(rif->saddr), &rif->atype);
+    if (rif->alen <= 0) {
+        pa_log("can't resolve resource transport address '%s'", rif->addr);
+    }
+    else {
+        rif->transp = mrp_transport_create(murphyif->ml, rif->atype, &ev, u,0);
+
+        if ((rif->transp))
+            resource_transport_connect(rif);
+        else
+            pa_log("failed to create resource transport");
+    }    
+
+    rif->seqno.request = 1;
+    rif->nodes = pa_hashmap_new(pa_idxset_trivial_hash_func,
+                                pa_idxset_trivial_compare_func);
+    PA_LLIST_HEAD_INIT(resource_attribute, rif->attrs);
+    PA_LLIST_HEAD_INIT(resource_request, rif->reqs);
 #endif
 
-    return domctl;
+    murphyif->nodes = pa_hashmap_new(pa_idxset_trivial_hash_func,
+                                     pa_idxset_trivial_compare_func);
+    return murphyif;
 }
 
 
 void pa_murphyif_done(struct userdata *u)
 {
-    pa_domctl *domctl;
+    pa_murphyif *murphyif;
+    domctl_interface *dif;
+    resource_interface *rif;
+#ifdef WITH_RESOURCES
+    resource_attribute *attr, *a;
+    resource_request *req, *r;
+#endif
 
-    if (u && (domctl = u->domctl)) {
-#ifdef WITH_MURPHYIF
+    if (u && (murphyif = u->murphyif)) {
+#ifdef WITH_DOMCTL
         mrp_domctl_table_t *t;
         mrp_domctl_watch_t *w;
         int i;
 
-        mrp_domctl_destroy(domctl->ctl);
-        mrp_mainloop_destroy(domctl->ml);
+        dif = &murphyif->domctl;
+        rif = &murphyif->resource;
 
-        if (domctl->ntable > 0 && domctl->tables) {
-            for (i = 0;  i < domctl->ntable;  i++) {
-                t = domctl->tables + i;
+        mrp_domctl_destroy(dif->ctl);
+        mrp_mainloop_destroy(murphyif->ml);
+
+        if (dif->ntable > 0 && dif->tables) {
+            for (i = 0;  i < dif->ntable;  i++) {
+                t = dif->tables + i;
                 pa_xfree((void *)t->table);
                 pa_xfree((void *)t->mql_columns);
                 pa_xfree((void *)t->mql_index);
             }
-            pa_xfree(domctl->tables);
+            pa_xfree(dif->tables);
         }
 
-        if (domctl->nwatch > 0 && domctl->watches) {
-            for (i = 0;  i < domctl->nwatch;  i++) {
-                w = domctl->watches + i;
+        if (dif->nwatch > 0 && dif->watches) {
+            for (i = 0;  i < dif->nwatch;  i++) {
+                w = dif->watches + i;
                 pa_xfree((void *)w->table);
                 pa_xfree((void *)w->mql_columns);
                 pa_xfree((void *)w->mql_where);
             }
-            pa_xfree(domctl->watches);
+            pa_xfree(dif->watches);
         }
 #endif
-        pa_xfree((void *)domctl->addr);
 
-        pa_xfree(domctl);
+#ifdef WITH_RESOURCES
+        pa_xfree((void *)rif->atype);
+        pa_hashmap_free(rif->nodes, NULL, NULL);
+
+        PA_LLIST_FOREACH_SAFE(attr, a, rif->attrs)
+            resource_attribute_destroy(rif, attr);
+
+        PA_LLIST_FOREACH_SAFE(req, r, rif->reqs)
+            pa_xfree(req);
+#endif
+
+        pa_xfree((void *)dif->addr);
+        pa_xfree((void *)rif->addr);
+
+        pa_hashmap_free(murphyif->nodes, NULL, NULL);
+
+        pa_xfree(murphyif);
     }
 }
 
+
+
 void pa_murphyif_add_table(struct userdata *u,
                            const char *table,
                            const char *columns,
                            const char *index)
 {
-    pa_domctl *domctl;
+    pa_murphyif *murphyif;
+    domctl_interface *dif;
     mrp_domctl_table_t *t;
     size_t size;
     size_t idx;
@@ -125,11 +313,13 @@ void pa_murphyif_add_table(struct userdata *u,
     pa_assert(u);
     pa_assert(table);
     pa_assert(columns);
-    pa_assert_se((domctl = u->domctl));
+    pa_assert_se((murphyif = u->murphyif));
+
+    dif = &murphyif->domctl;
 
-    idx = domctl->ntable++;
-    size = sizeof(mrp_domctl_table_t) * domctl->ntable;
-    t = (domctl->tables = pa_xrealloc(domctl->tables, size)) + idx;
+    idx = dif->ntable++;
+    size = sizeof(mrp_domctl_table_t) * dif->ntable;
+    t = (dif->tables = pa_xrealloc(dif->tables, size)) + idx;
 
     t->table = pa_xstrdup(table);
     t->mql_columns = pa_xstrdup(columns);
@@ -142,7 +332,8 @@ void pa_murphyif_add_watch(struct userdata *u,
                            const char *where,
                            int max_rows)
 {
-    pa_domctl *domctl;
+    pa_murphyif *murphyif;
+    domctl_interface *dif;
     mrp_domctl_watch_t *w;
     size_t size;
     size_t idx;
@@ -151,11 +342,13 @@ void pa_murphyif_add_watch(struct userdata *u,
     pa_assert(table);
     pa_assert(columns);
     pa_assert(max_rows > 0 && max_rows < MQI_QUERY_RESULT_MAX);
-    pa_assert_se((domctl = u->domctl));
+    pa_assert_se((murphyif = u->murphyif));
 
-    idx = domctl->nwatch++;
-    size = sizeof(mrp_domctl_watch_t) * domctl->nwatch;
-    w = (domctl->watches = pa_xrealloc(domctl->watches, size)) + idx;
+    dif = &murphyif->domctl;
+
+    idx = dif->nwatch++;
+    size = sizeof(mrp_domctl_watch_t) * dif->nwatch;
+    w = (dif->watches = pa_xrealloc(dif->watches, size)) + idx;
 
     w->table = pa_xstrdup(table);
     w->mql_columns = pa_xstrdup(columns);
@@ -167,37 +360,257 @@ void pa_murphyif_setup_domainctl(struct userdata *u, pa_murphyif_watch_cb wcb)
 {
     static const char *name = "pulse";
 
-    pa_domctl *domctl;
+    pa_murphyif *murphyif;
+    domctl_interface *dif;
 
     pa_assert(u);
     pa_assert(wcb);
-    pa_assert_se((domctl = u->domctl));
+    pa_assert_se((murphyif = u->murphyif));
 
-#ifdef WITH_MURPHYIF
-    if (domctl->ntable || domctl->nwatch) {
-        domctl->ctl = mrp_domctl_create(name, domctl->ml,
-                                        domctl->tables, domctl->ntable,
-                                        domctl->watches, domctl->nwatch,
-                                        connect_notify, watch_notify, u);
-        if (!domctl->ctl) {
+    dif = &murphyif->domctl;
+
+#ifdef WITH_DOMCTL
+    if (dif->ntable || dif->nwatch) {
+        dif->ctl = mrp_domctl_create(name, murphyif->ml,
+                                     dif->tables, dif->ntable,
+                                     dif->watches, dif->nwatch,
+                                     domctl_connect_notify,
+                                     domctl_watch_notify, u);
+        if (!dif->ctl) {
             pa_log("failed to create '%s' domain controller", name);
             return;
         }
 
-        if (!mrp_domctl_connect(domctl->ctl, domctl->addr, 0)) {
+        if (!mrp_domctl_connect(dif->ctl, dif->addr, 0)) {
             pa_log("failed to conect to murphyd");
             return;
         }
 
-        domctl->watchcb = wcb;
+        dif->watchcb = wcb;
         pa_log_info("'%s' domain controller sucessfully created", name);
     }
 #endif
 }
 
-#ifdef WITH_MURPHYIF
-static void connect_notify(mrp_domctl_t *dc, int connected, int errcode,
-                           const char *errmsg, void *user_data)
+void  pa_murphyif_add_audio_resource(struct userdata *u,
+                                     mir_direction dir,
+                                     const char *name)
+{
+    pa_murphyif *murphyif;
+    resource_interface *rif;
+
+    pa_assert(u);
+    pa_assert(dir == mir_input || dir == mir_output);
+    pa_assert(name);
+
+    pa_assert_se((murphyif = u->murphyif));
+    rif = &murphyif->resource;
+
+    if (dir == mir_input) {
+        if (rif->inpres)
+            pa_log("attempt to register playback resource multiple time");
+        else
+            rif->inpres = pa_xstrdup(name);
+    }
+    else {
+        if (rif->outres)
+            pa_log("attempt to register recording resource multiple time");
+        else
+            rif->outres = pa_xstrdup(name);
+    }
+}
+
+void pa_murphyif_add_audio_attribute(struct userdata *u,
+                                     const char *propnam,
+                                     const char *attrnam,
+                                     mqi_data_type_t type,
+                                     ... ) /* default value */
+{
+#ifdef WITH_RESOURCES
+    pa_murphyif *murphyif;
+    resource_interface *rif;
+    resource_attribute *attr;
+    mrp_attr_value_t *val;
+    va_list ap;
+
+    pa_assert(u);
+    pa_assert(propnam);
+    pa_assert(attrnam);
+    pa_assert(type == mqi_string  || type == mqi_integer ||
+              type == mqi_unsignd || type == mqi_floating);
+
+    pa_assert_se((murphyif = u->murphyif));
+    rif = &murphyif->resource;
+
+    attr = pa_xnew0(resource_attribute, 1);
+    val  = &attr->def.value;
+
+    attr->prop = pa_xstrdup(propnam);
+    attr->def.name = pa_xstrdup(attrnam);
+    attr->def.type = type;
+
+    va_start(ap, type);
+
+    switch (type){
+    case mqi_string:   val->string    = pa_xstrdup(va_arg(ap, char *));  break;
+    case mqi_integer:  val->integer   = va_arg(ap, int32_t);             break;
+    case mqi_unsignd:  val->unsignd   = va_arg(ap, uint32_t);            break;
+    case mqi_floating: val->floating  = va_arg(ap, double);              break;
+    default:           attr->def.type = mqi_error;                       break;
+    }
+
+    va_end(ap);
+
+     if (attr->def.type == mqi_error)
+         resource_attribute_destroy(rif, attr);
+     else
+         PA_LLIST_PREPEND(resource_attribute, rif->attrs, attr);
+#endif
+}
+
+void pa_murphyif_create_resource_set(struct userdata *u, mir_node *node)
+{
+    pa_core *core;
+    pa_murphyif *murphyif;
+    resource_interface *rif;
+    const char *class;
+    uint32_t audio_flags = 0;
+    pa_proplist *proplist = NULL;
+    pa_sink_input *sinp;
+    pa_source_output *sout;
+
+    pa_assert(u);
+    pa_assert(node);
+    pa_assert(node->implement = mir_stream);
+    pa_assert(node->direction == mir_input || node->direction == mir_output);
+    pa_assert(node->zone);
+    pa_assert(!node->rsetid);
+
+    pa_assert_se((core = u->core));
+    pa_assert_se((class = pa_nodeset_get_class(u, node->type)));
+
+    pa_assert_se((murphyif = u->murphyif));
+    rif = &murphyif->resource;
+
+    resource_transport_connect(rif);
+
+    if (node->direction == mir_output) {
+        if ((sout = pa_idxset_get_by_index(core->source_outputs, node->paidx)))
+            proplist = sout->proplist;
+    }
+    else {
+        if ((sinp = pa_idxset_get_by_index(core->sink_inputs, node->paidx)))
+            proplist = sinp->proplist;
+    }
+
+    node->localrset = resource_set_create(u, node->index, node->direction,
+                                          class, node->zone, audio_flags,
+                                          proplist);
+}
+
+void pa_murphyif_destroy_resource_set(struct userdata *u, mir_node *node)
+{
+    pa_murphyif *murphyif;
+    uint32_t rsetid;
+    char *e;
+
+    pa_assert(u);
+    pa_assert(node);
+    pa_assert_se((murphyif = u->murphyif));
+
+    if (node->localrset && node->rsetid) {
+        rsetid = strtoul(node->rsetid, &e, 10);
+
+        if (e == node->rsetid || *e) {
+            pa_log("can't destroy resource set: invalid rsetid '%s'",
+                   node->rsetid);
+        }
+        else {
+            if (resource_set_destroy(u, rsetid))
+                pa_log_debug("resource set %u destruction request", rsetid);
+            else {
+                pa_log("falied to destroy resourse set %u for node '%s'",
+                       rsetid, node->amname);
+            }
+        }
+
+        pa_murphyif_delete_node(u, node);
+    }
+}
+
+int pa_murphyif_add_node(struct userdata *u, mir_node *node)
+{
+#ifdef WITH_RESOURCES
+    pa_murphyif *murphyif;
+
+    pa_assert(u);
+    pa_assert(node);
+    pa_assert(node->implement == mir_stream);
+
+    pa_assert_se((murphyif = u->murphyif));
+
+    if (!node->rsetid) {
+        pa_log("can't register resource set for node '%s'.: missing rsetid",
+               node->amname);
+    }
+    else {
+        if (pa_hashmap_put(murphyif->nodes, node->rsetid, node) == 0)
+            return 0;
+        else {
+            pa_log("can't register resource set for node '%s': conflicting "
+                   "resource id '%s'", node->amname, node->rsetid);
+        } 
+    }
+
+    return -1;
+#else
+    return 0;
+#endif
+}
+
+void pa_murphyif_delete_node(struct userdata *u, mir_node *node)
+{
+#ifdef WITH_RESOURCES
+    pa_murphyif *murphyif;
+    mir_node *deleted;
+
+    pa_assert(u);
+    pa_assert(node);
+    pa_assert(node->implement == mir_stream);
+
+    pa_assert_se((murphyif = u->murphyif));
+
+    if (node->rsetid) {
+        deleted = pa_hashmap_remove(murphyif->nodes, node->rsetid);
+        pa_assert(deleted == node);
+    }
+#endif
+}
+
+mir_node *pa_murphyif_find_node(struct userdata *u, const char *rsetid)
+{
+#ifdef WITH_RESOURCES
+    pa_murphyif *murphyif;
+    mir_node *node;
+
+    pa_assert(u);
+    pa_assert_se((murphyif = u->murphyif));
+
+    if (!rsetid)
+        node = NULL;
+    else
+        node = pa_hashmap_get(murphyif->nodes, rsetid);
+
+    return node;
+#else
+    return NULL;
+#endif
+}
+
+
+#ifdef WITH_DOMCTL
+static void domctl_connect_notify(mrp_domctl_t *dc, int connected, int errcode,
+                                  const char *errmsg, void *user_data)
 {
     MRP_UNUSED(dc);
     MRP_UNUSED(user_data);
@@ -209,11 +622,12 @@ static void connect_notify(mrp_domctl_t *dc, int connected, int errcode,
         pa_log_error("Connection to Murphy failed (%d: %s).", errcode, errmsg);
 }
 
-static void watch_notify(mrp_domctl_t *dc, mrp_domctl_data_t *tables,
-                         int ntable, void *user_data)
+static void domctl_watch_notify(mrp_domctl_t *dc, mrp_domctl_data_t *tables,
+                                int ntable, void *user_data)
 {
     struct userdata *u = (struct userdata *)user_data;
-    pa_domctl *domctl;
+    pa_murphyif *murphyif;
+    domctl_interface *dif;
     mrp_domctl_data_t *t;
     mrp_domctl_watch_t *w;
     int i;
@@ -223,25 +637,27 @@ static void watch_notify(mrp_domctl_t *dc, mrp_domctl_data_t *tables,
     pa_assert(tables);
     pa_assert(ntable > 0);
     pa_assert(u);
-    pa_assert_se((domctl = u->domctl));
+    pa_assert_se((murphyif = u->murphyif));
+
+    dif = &murphyif->domctl;
 
     pa_log_info("Received change notification for %d tables.", ntable);
 
     for (i = 0; i < ntable; i++) {
         t = tables + i;
 
-        dump_data(t);
+        domctl_dump_data(t);
 
         pa_assert(t->id >= 0);
-        pa_assert(t->id < domctl->nwatch);
+        pa_assert(t->id < dif->nwatch);
 
-        w = domctl->watches + t->id;
+        w = dif->watches + t->id;
 
-        domctl->watchcb(u, w->table, t->nrow, t->rows);
+        dif->watchcb(u, w->table, t->nrow, t->rows);
     }
 }
 
-static void dump_data(mrp_domctl_data_t *table)
+static void domctl_dump_data(mrp_domctl_data_t *table)
 {
     mrp_domctl_value_t *row;
     int                 i, j;
@@ -292,6 +708,555 @@ static void dump_data(mrp_domctl_data_t *table)
 }
 #endif
 
+#ifdef WITH_RESOURCES
+static void resource_attribute_destroy(resource_interface *rif,
+                                       resource_attribute *attr)
+{
+    if (attr) {
+       if (rif)
+           PA_LLIST_REMOVE(resource_attribute, rif->attrs, attr);
+
+       pa_xfree((void *)attr->prop);
+       pa_xfree((void *)attr->def.name);
+
+       if (attr->def.type == mqi_string)
+           pa_xfree((void *)attr->def.value.string);
+
+       pa_xfree(attr);
+    }
+}
+
+static pa_bool_t resource_transport_connect(resource_interface *rif)
+{
+    pa_assert(rif);
+
+    if (!rif->connected) {
+        if (mrp_transport_connect(rif->transp, &rif->saddr, rif->alen)) {
+            pa_log_info("resource transport connected to '%s'", rif->addr);
+            rif->connected = TRUE;
+        }
+        else {
+            pa_log("can't connect resource transport to '%s'", rif->addr);
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+static void resource_xport_closed_evt(mrp_transport_t *transp, int error,
+                                      void *void_u)
+{
+    struct userdata *u = (struct userdata *)void_u;
+    pa_murphyif *murphyif;
+    resource_interface *rif;
+
+    MRP_UNUSED(transp);
+
+    pa_assert(u);
+    pa_assert_se((murphyif = u->murphyif));
+
+    rif = &murphyif->resource;
+
+    if (!error)
+        pa_log("peer has closed the resource transport connection");
+    else {
+        pa_log("resource transport connection closed with error %d (%s)",
+               error, strerror(error));
+    }
+
+    rif->connected = FALSE;
+}
+
+static mrp_msg_t *resource_create_request(uint32_t seqno,
+                                          mrp_resproto_request_t req)
+{
+    uint16_t   type  = req;
+    mrp_msg_t *msg;
+
+    msg = mrp_msg_create(RESPROTO_SEQUENCE_NO , MRP_MSG_FIELD_UINT32, seqno,
+                         RESPROTO_REQUEST_TYPE, MRP_MSG_FIELD_UINT16, type ,
+                         RESPROTO_MESSAGE_END                               );
+
+    if (!msg)
+        pa_log("can't to create new resource message");
+    return msg;
+}
+
+static pa_bool_t resource_send_message(resource_interface *rif,
+                                       mrp_msg_t          *msg,
+                                       uint32_t            nodidx,
+                                       uint16_t            reqid,
+                                       uint32_t            seqno)
+{
+    resource_request *req;
+    pa_bool_t success = TRUE;
+
+    if (!mrp_transport_send(rif->transp, msg)) {
+        pa_log("failed to send resource message");
+        success = FALSE;
+    }
+    else {
+        req = pa_xnew0(resource_request, 1);
+        req->nodidx = nodidx;
+        req->reqid  = reqid;
+        req->seqno  = seqno;
+
+        PA_LLIST_PREPEND(resource_request, rif->reqs, req);
+    }
+
+    mrp_msg_unref(msg);
+
+    return success;
+}
+
+
+static pa_bool_t resource_set_create(struct userdata *u,
+                                     uint32_t nodidx,
+                                     mir_direction dir,
+                                     const char *class,
+                                     const char *zone,
+                                     uint32_t audio_flags,
+                                     pa_proplist *proplist)
+{
+    static uint32_t rset_flags = 0 /* RESPROTO_RSETFLAG_AUTORELEASE */ ;
+
+    pa_murphyif *murphyif;
+    resource_interface *rif;
+    resource_request *req;
+    mrp_msg_t *msg;
+    uint16_t reqid;
+    uint32_t seqno;
+    const char *resnam;
+    pa_bool_t success = TRUE;
+
+    pa_assert(u);
+    pa_assert(nodidx != PA_IDXSET_INVALID);
+    pa_assert(dir == mir_input || dir == mir_output);
+    pa_assert(class);
+    pa_assert(zone);
+
+    pa_assert_se((murphyif = u->murphyif));
+    rif = &murphyif->resource;
+
+    reqid  = RESPROTO_CREATE_RESOURCE_SET;
+    seqno  = rif->seqno.request++;
+    resnam = (dir == mir_input) ? rif->inpres : rif->outres;
+
+    pa_assert(resnam);
+
+    msg = resource_create_request(seqno, reqid);
+
+    if (PUSH_VALUE(msg,   RESOURCE_FLAGS   , UINT32, rset_flags)  &&
+        PUSH_VALUE(msg,   RESOURCE_PRIORITY, UINT32, 0)           &&
+        PUSH_VALUE(msg,   CLASS_NAME       , STRING, class)       &&
+        PUSH_VALUE(msg,   ZONE_NAME        , STRING, zone)        &&
+        PUSH_VALUE(msg,   RESOURCE_NAME    , STRING, resnam)      &&
+        PUSH_VALUE(msg,   RESOURCE_FLAGS   , UINT32, audio_flags) &&
+        PUSH_ATTRS(msg,   rif, proplist)                          &&
+        PUSH_VALUE(msg,   SECTION_END      , UINT8 , 0)            )
+    {
+        success = resource_send_message(rif, msg, nodidx, reqid, seqno);
+    }
+    else {
+        success = FALSE;
+        mrp_msg_unref(msg);
+    }
+
+    return success;
+}
+
+static pa_bool_t resource_set_destroy(struct userdata *u, uint32_t rsetid)
+{
+    pa_murphyif *murphyif;
+    resource_interface *rif;
+    mrp_msg_t *msg;
+    uint16_t reqid;
+    uint32_t seqno;
+    uint32_t nodidx;
+    pa_bool_t success;
+
+    pa_assert(u);
+
+    pa_assert_se((murphyif = u->murphyif));
+    rif = &murphyif->resource;
+
+    reqid = RESPROTO_DESTROY_RESOURCE_SET;
+    seqno = rif->seqno.request++;
+    nodidx = PA_IDXSET_INVALID;
+    msg = resource_create_request(seqno, reqid);
+
+    if (PUSH_VALUE(msg, RESOURCE_SET_ID, UINT32, rsetid))
+        success = resource_send_message(rif, msg, nodidx, reqid, seqno);
+    else {
+        success = FALSE;
+        mrp_msg_unref(msg);
+    }
+
+    return success;
+}
+
+static pa_bool_t resource_set_acquire(struct userdata *u,
+                                      uint32_t nodidx,
+                                      uint32_t rsetid)
+{
+    pa_murphyif *murphyif;
+    resource_interface *rif;
+    mrp_msg_t *msg;
+    uint16_t reqid;
+    uint32_t seqno;
+    pa_bool_t success;
+
+    pa_assert(u);
+
+    pa_assert_se((murphyif = u->murphyif));
+    rif = &murphyif->resource;
+
+    reqid = RESPROTO_ACQUIRE_RESOURCE_SET;
+    seqno = rif->seqno.request++;
+    msg = resource_create_request(seqno, reqid);
+
+    if (PUSH_VALUE(msg, RESOURCE_SET_ID, UINT32, rsetid))
+        success = resource_send_message(rif, msg, nodidx, reqid, seqno);
+    else {
+        success = FALSE;
+        mrp_msg_unref(msg);
+    }
+
+    return success;
+}
+
+static pa_bool_t resource_push_attributes(mrp_msg_t *msg,
+                                          resource_interface *rif,
+                                          pa_proplist *proplist)
+{
+    resource_attribute *attr;
+    union {
+        const void *ptr;
+        const char *str;
+        int32_t    *i32;
+        uint32_t   *u32;
+        double     *dbl;
+    } v;
+    size_t size;
+    int sts;
+
+    pa_assert(msg);
+    pa_assert(rif);
+
+    PA_LLIST_FOREACH(attr, rif->attrs) {
+        if (!PUSH_VALUE(msg, ATTRIBUTE_NAME, STRING, attr->def.name))
+            return FALSE;
+
+        if (proplist)
+            sts = pa_proplist_get(proplist, attr->prop, &v.ptr, &size);
+        else
+            sts = -1;
+
+        switch (attr->def.type) {
+        case mqi_string:
+            if (sts < 0)
+                v.str = attr->def.value.string;
+            else if (v.str[size-1] != '\0' || strlen(v.str) != (size-1) ||
+                     !pa_utf8_valid(v.str))
+                return FALSE;
+            if (!PUSH_VALUE(msg, ATTRIBUTE_VALUE, STRING, v.str))
+                return FALSE;
+            break;
+
+        case mqi_integer:
+            if (sts < 0)
+                v.i32 = &attr->def.value.integer;
+            else if (size != sizeof(*v.i32))
+                return FALSE;
+            if (!PUSH_VALUE(msg, ATTRIBUTE_VALUE, SINT8, *v.i32))
+                return FALSE;
+            break;
+            
+        case mqi_unsignd:
+            if (sts < 0)
+                v.u32 = &attr->def.value.unsignd;
+            else if (size != sizeof(*v.u32))
+                return FALSE;
+            if (!PUSH_VALUE(msg, ATTRIBUTE_VALUE, SINT8, *v.u32))
+                return FALSE;
+            break;
+            
+        case mqi_floating:
+            if (sts < 0)
+                v.dbl = &attr->def.value.floating;
+            else if (size != sizeof(*v.dbl))
+                return FALSE;
+            if (!PUSH_VALUE(msg, ATTRIBUTE_VALUE, SINT8, *v.dbl))
+                return FALSE;
+            break;
+
+        default: /* we should never get here */
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+
+
+static void resource_recv_msg(mrp_transport_t *t, mrp_msg_t *msg, void *void_u)
+{
+    return resource_recvfrom_msg(t, msg, NULL, 0, void_u);
+}
+
+static void resource_recvfrom_msg(mrp_transport_t *transp, mrp_msg_t *msg,
+                                  mrp_sockaddr_t *addr, socklen_t addrlen,
+                                  void *void_u)
+{
+    struct userdata *u = (struct userdata *)void_u;
+    pa_core *core;
+    pa_murphyif *murphyif;
+    resource_interface *rif;
+    void     *curs = NULL;
+    uint32_t  seqno;
+    uint16_t  reqid;
+    uint32_t  nodidx;
+    resource_request *req, *n;
+    mir_node *node;
+
+    MRP_UNUSED(transp);
+    MRP_UNUSED(addr);
+    MRP_UNUSED(addrlen);
+
+    pa_assert(u);
+    pa_assert_se((core = u->core));
+    pa_assert_se((murphyif = u->murphyif));
+
+    rif = &murphyif->resource;
+
+    if (!resource_fetch_seqno   (msg, &curs, &seqno) ||
+        !resource_fetch_request (msg, &curs, &reqid)   )
+    {
+        pa_log("ignoring malformed message");
+        return;
+    }
+
+    PA_LLIST_FOREACH_SAFE(req, n, rif->reqs) {
+        if (req->seqno <= seqno) {
+            nodidx = req->nodidx;
+            
+            if (req->reqid == reqid) {
+                PA_LLIST_REMOVE(resource_request, rif->reqs, req);
+                pa_xfree(req);
+            }
+            
+            if (!(node = mir_node_find_by_index(u, nodidx))) {
+                if (reqid != RESPROTO_DESTROY_RESOURCE_SET) {
+                    pa_log("got response (reqid:%u seqno:%u) but can't "
+                           "find the corresponding node", reqid, seqno);
+                }
+            }
+            else {
+                if (req->seqno < seqno) {
+                    pa_log("unanswered request %d", req->seqno);
+                }
+                else {
+                    pa_log_debug("got response (reqid:%u seqno:%u "
+                                 "node:'%s')", reqid, seqno,
+                                 node ? node->amname : "<unknown>");
+                    
+                    switch (reqid) {
+                    case RESPROTO_CREATE_RESOURCE_SET:
+                        resource_set_create_response(u,node,msg,&curs);
+                        break;
+#if 0
+                    case RESPROTO_ACQUIRE_RESOURCE_SET:
+                        resource_set_acquire_response(u,node,msg,&curs);
+                        break;
+                    case RESPROTO_RELEASE_RESOURCE_SET:
+                        resource_set_release_response(u,node,msg,&curs);
+                        break;
+                    case RESPROTO_RESOURCES_EVENT:
+                        resource_event(u, seqno, msg, &curs);
+                        break;
+#endif
+                    default:
+                        pa_log("ignoring unsupported resource request "
+                               "type %u", reqid);
+                        break;
+                    }
+                }
+            }
+        } /* PA_LLIST_FOREACH_SAFE */
+    }
+}
+
+static void resource_set_create_response(struct userdata *u, mir_node *node,
+                                         mrp_msg_t *msg, void **pcursor)
+{
+    int status;
+    uint32_t rsetid;
+    char buf[4096];
+
+    pa_assert(u);
+    pa_assert(node);
+    pa_assert(msg);
+    pa_assert(pcursor);
+
+    if (!resource_fetch_status(msg, pcursor, &status) || (status == 0 &&
+        !resource_fetch_rset_id(msg, pcursor, &rsetid)))
+    {
+        pa_log("ignoring malformed response to resource set creation");
+        return;
+    }
+
+    if (status) {
+        pa_log("creation of resource set failed. error code %u", status);
+        return;
+    }
+
+    node->rsetid = pa_sprintf_malloc("%d", rsetid);
+                
+    if (pa_murphyif_add_node(u, node) == 0) {
+        pa_log_debug("resource set was successfully created");
+        mir_node_print(node, buf, sizeof(buf));
+        pa_log_debug("modified node:\n%s", buf);
+
+        if (resource_set_acquire(u, node->index, rsetid))
+            pa_log_debug("acquire request sent");
+        else
+            pa_log("failed to send acquire request");
+    }
+    else {
+        pa_log("failed to create resource set: "
+               "conflicting resource set id");
+    }
+}
+
+
+static pa_bool_t resource_fetch_seqno(mrp_msg_t *msg,
+                                      void **pcursor,
+                                      uint32_t *pseqno)
+{
+    uint16_t tag;
+    uint16_t type;
+    mrp_msg_value_t value;
+    size_t size;
+
+    if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
+        tag != RESPROTO_SEQUENCE_NO || type != MRP_MSG_FIELD_UINT32)
+    {
+        *pseqno = INVALID_SEQNO;
+        return false;
+    }
+
+    *pseqno = value.u32;
+    return true;
+}
+
+
+static pa_bool_t resource_fetch_request(mrp_msg_t *msg,
+                                        void **pcursor,
+                                        uint16_t *preqtype)
+{
+    uint16_t tag;
+    uint16_t type;
+    mrp_msg_value_t value;
+    size_t size;
+
+    if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
+        tag != RESPROTO_REQUEST_TYPE || type != MRP_MSG_FIELD_UINT16)
+    {
+        *preqtype = INVALID_REQUEST;
+        return false;
+    }
+
+    *preqtype = value.u16;
+    return true;
+}
+
+static pa_bool_t resource_fetch_status(mrp_msg_t *msg,
+                                       void **pcursor,
+                                       int *pstatus)
+{
+    uint16_t tag;
+    uint16_t type;
+    mrp_msg_value_t value;
+    size_t size;
+
+    if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
+        tag != RESPROTO_REQUEST_STATUS || type != MRP_MSG_FIELD_SINT16)
+    {
+        *pstatus = EINVAL;
+        return FALSE;
+    }
+
+    *pstatus = value.s16;
+    return TRUE;
+}
+
+static pa_bool_t resource_fetch_rset_id(mrp_msg_t *msg,
+                                        void **pcursor,
+                                        uint32_t *pid)
+{
+    uint16_t tag;
+    uint16_t type;
+    mrp_msg_value_t value;
+    size_t size;
+
+    if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
+        tag != RESPROTO_RESOURCE_SET_ID || type != MRP_MSG_FIELD_UINT32)
+    {
+        *pid = INVALID_ID;
+        return FALSE;
+    }
+
+    *pid = value.u32;
+    return TRUE;
+}
+
+static pa_bool_t resource_fetch_rset_state(mrp_msg_t *msg,
+                                           void **pcursor,
+                                           mrp_resproto_state_t *pstate)
+{
+    uint16_t tag;
+    uint16_t type;
+    mrp_msg_value_t value;
+    size_t size;
+
+    if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
+        tag != RESPROTO_RESOURCE_STATE || type != MRP_MSG_FIELD_UINT16)
+    {
+        *pstate = 0;
+        return FALSE;
+    }
+
+    *pstate = value.u16;
+    return TRUE;
+}
+
+
+static pa_bool_t resource_fetch_rset_mask(mrp_msg_t *msg,
+                                          void **pcursor,
+                                          mrp_resproto_state_t *pmask)
+{
+    uint16_t tag;
+    uint16_t type;
+    mrp_msg_value_t value;
+    size_t size;
+
+    if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
+        tag != RESPROTO_RESOURCE_GRANT || type != MRP_MSG_FIELD_UINT32)
+    {
+        *pmask = 0;
+        return FALSE;
+    }
+
+    *pmask = value.u32;
+    return TRUE;
+}
+
+
+#endif
+
 /*
  * Local Variables:
  * c-basic-offset: 4
index 872f759..e447023 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef foomurphyiffoo
 #define foomurphyiffoo
 
+#include <stdarg.h>
+
 #ifdef WITH_MURPHYIF
 #include <murphy/domain-control/client.h>
 #else
@@ -31,7 +33,7 @@ typedef void mrp_domctl_value_t;
 typedef void (*pa_murphyif_watch_cb)(struct userdata *u, const char *,
                                          int, mrp_domctl_value_t **);
 
-pa_domctl *pa_murphyif_init(struct userdata *, const char *);
+pa_murphyif *pa_murphyif_init(struct userdata *, const char *, const char *);
 void pa_murphyif_done(struct userdata *);
 
 void pa_murphyif_add_table(struct userdata *, const char *, const char *,
@@ -40,6 +42,18 @@ void pa_murphyif_add_watch(struct userdata *, const char *, const char *,
                            const char *, int);
 void pa_murphyif_setup_domainctl(struct userdata *, pa_murphyif_watch_cb);
 
+void pa_murphyif_add_audio_resource(struct userdata *, mir_direction,
+                                    const char *);
+void pa_murphyif_add_audio_attribute(struct userdata *, const char *,
+                                     const char *, mqi_data_type_t, ... );
+void pa_murphyif_create_resource_set(struct userdata *, mir_node *);
+void pa_murphyif_destroy_resource_set(struct userdata *, mir_node *);
+
+int pa_murphyif_add_node(struct userdata *, mir_node *);
+void pa_murphyif_delete_node(struct userdata *, mir_node *);
+mir_node *pa_murphyif_find_node(struct userdata *, const char *);
+
+
 #endif /* foomurphyiffoo */
 
 /*
index 230b2bc..8ef5e4d 100644 (file)
@@ -255,6 +255,7 @@ mir_node *mir_node_create(struct userdata *u, mir_node *data)
     node->mux       = data->mux;
     node->loop      = data->loop;
     node->stamp     = data->stamp;
+    node->rsetid    = data->rsetid ? pa_xstrdup(data->rsetid) : NULL;
     node->scripting = pa_scripting_node_create(u, node);
     MIR_DLIST_INIT(node->rtentries);
     MIR_DLIST_INIT(node->rtprilist);
@@ -270,6 +271,18 @@ mir_node *mir_node_create(struct userdata *u, mir_node *data)
 
     mir_router_register_node(u, node);
     
+    if (node->implement == mir_stream) {
+        if (node->type >= mir_application_class_begin &&
+            node->type <  mir_application_class_end   &&
+            !node->rsetid && ns->need_resource[node->type])
+        {
+            pa_murphyif_create_resource_set(u, node);
+        }
+        else {
+            pa_murphyif_add_node(u, node);
+        }
+    }
+
     return node;
 }
 
@@ -281,6 +294,18 @@ void mir_node_destroy(struct userdata *u, mir_node *node)
     pa_assert_se((ns = u->nodeset));
 
     if (node) {
+        if (node->implement == mir_stream) {
+            if (node->type >= mir_application_class_begin &&
+                node->type <  mir_application_class_end   &&
+                ns->need_resource[node->type])
+            {
+                pa_murphyif_destroy_resource_set(u, node);
+            }
+            else {
+                pa_murphyif_delete_node(u, node);
+            }
+        }
+
         mir_router_unregister_node(u, node);
         pa_scripting_node_destroy(u, node);
 
@@ -293,6 +318,7 @@ void mir_node_destroy(struct userdata *u, mir_node *node)
         pa_xfree(node->paname);
         pa_xfree(node->pacard.profile);
         pa_xfree(node->paport);
+        pa_xfree(node->rsetid);
 
         pa_xfree(node);
     }
@@ -341,6 +367,8 @@ int mir_node_print(mir_node *node, char *buf, int len)
     PRINT("   zone          : '%s'",  node->zone ? node->zone : "");
     PRINT("   visible       : %s"  ,  node->visible ? "yes" : "no");
     PRINT("   available     : %s"  ,  node->available ? "yes" : "no");
+    PRINT("   ignore        : %s"  ,  node->ignore ? "yes" : "no");
+    PRINT("   localrset     : %s"  ,  node->localrset ? "yes" : "no");
     PRINT("   amname        : '%s'",  node->amname ? node->amname : "");
     PRINT("   amdescr       : '%s'",  node->amdescr ? node->amdescr : "");
     PRINT("   amid          : %u"  ,  node->amid);
@@ -353,6 +381,7 @@ int mir_node_print(mir_node *node, char *buf, int len)
     PRINT("   mux           : %s"  ,  mux);
     PRINT("   loop          : %s"  ,  loop);
     PRINT("   constrain     : %s"  ,  constr);
+    PRINT("   rsetid        : '%s'",  node->rsetid ? node->rsetid : "");
     PRINT("   stamp         : %u"  ,  node->stamp);
 
 #undef PRINT
index a42fbde..0d50fad 100644 (file)
@@ -126,6 +126,7 @@ struct mir_node {
     pa_bool_t      visible;   /**< internal or can appear on UI  */
     pa_bool_t      available; /**< eg. is the headset connected?  */
     pa_bool_t      ignore;    /**< do not consider it while routing  */
+    pa_bool_t      localrset; /**< locally generated resource set */
     char          *amname;    /**< audiomanager name */
     char          *amdescr;   /**< UI description */
     uint16_t       amid;      /**< handle to audiomanager, if any */
@@ -140,6 +141,7 @@ struct mir_node {
                                                                    pa_router)*/
     mir_dlist      constrains;/**< listhead of constrains */
     mir_vlim       vlim;      /**< volume limit */
+    char          *rsetid;    /**< resource set id, if any */
     uint32_t       stamp;
     scripting_node *scripting;/** scripting data, if any */
 };
index 619550e..2b6a3a2 100644 (file)
@@ -40,6 +40,7 @@
 #define PA_PROP_NODE_INDEX             "node.index"
 #define PA_PROP_NODE_TYPE              "node.type"
 #define PA_PROP_NODE_ROLE              "node.role"
+#define PA_PROP_RESOURCE_SET_ID        "resource.set.id"
 
 #define PA_ZONE_NAME_DEFAULT           "driver"
 
@@ -68,7 +69,7 @@ typedef struct pa_source_hooks          pa_source_hooks;
 typedef struct pa_sink_input_hooks      pa_sink_input_hooks;
 typedef struct pa_source_output_hooks   pa_source_output_hooks;
 typedef struct pa_extapi                pa_extapi;
-typedef struct pa_domctl                pa_domctl;
+typedef struct pa_murphyif              pa_murphyif;
 
 typedef enum   mir_direction            mir_direction;
 typedef enum   mir_implement            mir_implement;
@@ -84,11 +85,12 @@ typedef struct mir_constr_def           mir_constr_def;
 typedef struct mir_vlim                 mir_vlim;
 typedef struct mir_volume_suppress_arg  mir_volume_suppress_arg;
 
+typedef struct scripting_import         scripting_import;
 typedef struct scripting_node           scripting_node;
+typedef struct scripting_resource       scripting_resource;
 typedef struct scripting_rtgroup        scripting_rtgroup;
 typedef struct scripting_apclass        scripting_apclass;
 typedef struct scripting_vollim         scripting_vollim;
-typedef struct scripting_import         scripting_import;
 
 typedef enum   am_method                am_method;
 typedef struct am_domainreg_data        am_domainreg_data;
@@ -151,7 +153,7 @@ struct userdata {
     pa_mir_state   state;
     pa_extapi     *extapi;
     pa_native_protocol *protocol;
-    pa_domctl     *domctl;
+    pa_murphyif   *murphyif;
 };
 
 #endif