+static pa_bool_t resource_transport_create(struct userdata *u,
+ pa_murphyif *murphyif)
+{
+ static mrp_transport_evt_t ev = {
+ { .recvmsg = resource_recv_msg },
+ { .recvmsgfrom = resource_recvfrom_msg },
+ .closed = resource_xport_closed_evt,
+ .connection = NULL
+ };
+
+ resource_interface *rif;
+
+ pa_assert(u);
+ pa_assert(murphyif);
+
+ rif = &murphyif->resource;
+
+ if (!rif->transp)
+ rif->transp = mrp_transport_create(murphyif->ml, rif->atype, &ev, u,0);
+
+ return rif->transp ? TRUE : FALSE;
+}
+
+static void resource_transport_destroy(pa_murphyif *murphyif)
+{
+ resource_interface *rif;
+
+ pa_assert(murphyif);
+ rif = &murphyif->resource;
+
+ if (rif->transp)
+ mrp_transport_destroy(rif->transp);
+
+ rif->transp = NULL;
+ rif->connected = FALSE;
+}
+
+static void connect_attempt(pa_mainloop_api *a,
+ pa_time_event *e,
+ const struct timeval *t,
+ void *data)
+{
+ struct userdata *u = (struct userdata *)data;
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+
+ int state;
+
+ pa_assert(u);
+ pa_assert_se((murphyif = u->murphyif));
+
+ rif = &murphyif->resource;
+
+ if (!resource_transport_create(u, murphyif))
+ schedule_connect(u, rif);
+ else {
+ state = resource_transport_connect(rif);
+
+ switch (state) {
+
+ case CONNECTING:
+ resource_set_create_all(u);
+ cancel_schedule(u, rif);
+ break;
+
+ case CONNECTED:
+ cancel_schedule(u, rif);
+ break;
+
+ case DISCONNECTED:
+ schedule_connect(u, rif);
+ break;
+ }
+ }
+}
+
+static void schedule_connect(struct userdata *u, resource_interface *rif)
+{
+ pa_core *core;
+ pa_mainloop_api *mainloop;
+ struct timeval when;
+ pa_time_event *tev;
+
+ pa_assert(u);
+ pa_assert(rif);
+ pa_assert_se((core = u->core));
+ pa_assert_se((mainloop = core->mainloop));
+
+ pa_gettimeofday(&when);
+ pa_timeval_add(&when, rif->connect.period);
+
+ if ((tev = rif->connect.evt))
+ mainloop->time_restart(tev, &when);
+ else {
+ rif->connect.evt = mainloop->time_new(mainloop, &when,
+ connect_attempt, u);
+ }
+}
+
+static void cancel_schedule(struct userdata *u, resource_interface *rif)
+{
+ pa_core *core;
+ pa_mainloop_api *mainloop;
+ pa_time_event *tev;
+
+ pa_assert(u);
+ pa_assert(rif);
+ pa_assert_se((core = u->core));
+ pa_assert_se((mainloop = core->mainloop));
+
+ if ((tev = rif->connect.evt)) {
+ mainloop->time_free(tev);
+ rif->connect.evt = NULL;
+ }
+}
+
+static rset_hash *node_put_rset(struct userdata *u, mir_node *node, rset_data *rset)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ pa_proplist *pl;
+ rset_hash *rh;
+
+ pa_assert(u);
+ pa_assert(node);
+ pa_assert(rset);
+ pa_assert(rset->id);
+
+ pa_assert(node->implement == mir_stream);
+ pa_assert(node->direction == mir_input || node->direction == mir_output);
+
+ pa_assert_se((murphyif = u->murphyif));
+ rif = &murphyif->resource;
+
+ pa_log_debug("setting rsetid %s for node %s", rset->id, node->amname);
+
+ if (node->rsetid) {
+ pa_xfree(node->rsetid);
+ }
+ node->rsetid = pa_xstrdup(rset->id);
+
+ if (!(pl = get_node_proplist(u, node))) {
+ pa_log("can't obtain property list for node %s", node->amname);
+ return NULL;
+ }
+
+ if ((pa_proplist_sets(pl, PA_PROP_RESOURCE_SET_ID, node->rsetid) < 0)) {
+ pa_log("failed to set '" PA_PROP_RESOURCE_SET_ID "' property "
+ "of '%s' node", node->amname);
+ return NULL;
+ }
+
+ if (!(rh = rset_hashmap_put(u, node->rsetid, node))) {
+ pa_log("conflicting rsetid %s for %s", node->rsetid, node->amname);
+ return NULL;
+ }
+
+ return rh;
+}
+
+static void node_enforce_resource_policy(struct userdata *u,
+ mir_node *node,
+ rset_data *rset)
+{
+ int req;
+
+ pa_assert(node);
+ pa_assert(rset);
+ pa_assert(rset->policy);
+
+
+ if (pa_streq(rset->policy, "relaxed"))
+ req = PA_STREAM_RUN;
+ else if (pa_streq(rset->policy, "strict")) {
+ if (rset->state == RSET_RELEASE)
+ req = PA_STREAM_KILL;
+ else {
+ if (rset->grant)
+ req = PA_STREAM_RUN;
+ else
+ req = PA_STREAM_BLOCK;
+ }
+ }
+ else {
+ req = PA_STREAM_BLOCK;
+ }
+
+ pa_stream_state_change(u, node, req);
+}
+
+static rset_data *rset_data_dup(rset_data *orig)
+{
+ rset_data *dup;
+
+ pa_assert(orig);
+ pa_assert(orig->id);
+ pa_assert(orig->policy);
+
+ dup = pa_xnew0(rset_data, 1);
+
+ dup->id = pa_xstrdup(orig->id);
+ dup->autorel = orig->autorel;
+ dup->state = orig->state;
+ dup->grant = orig->grant;
+ dup->policy = pa_xstrdup(orig->policy);
+
+ return dup;
+}
+
+static void rset_data_copy(rset_data *dst, rset_data *src)
+{
+ rset_data *dup;
+
+ pa_assert(dst);
+ pa_assert(src);
+ pa_assert(src->id);
+ pa_assert(src->policy);
+
+ pa_xfree((void *)dst->id);
+ pa_xfree((void *)dst->policy);
+
+ dst->id = pa_xstrdup(src->id);
+ dst->autorel = src->autorel;
+ dst->state = src->state;
+ dst->grant = src->grant;
+ dst->policy = pa_xstrdup(src->policy);
+}
+
+
+static void rset_data_update(rset_data *dst, rset_data *src)
+{
+ rset_data *dup;
+
+ pa_assert(dst);
+ pa_assert(dst->id);
+ pa_assert(src);
+ pa_assert(src->id);
+ pa_assert(src->policy);
+
+ pa_assert_se(pa_streq(src->id, dst->id));
+
+ pa_xfree((void *)dst->policy);
+
+ dst->autorel = src->autorel;
+ dst->state = src->state;
+ dst->grant = src->grant;
+ dst->policy = pa_xstrdup(src->policy);
+}
+
+
+static void rset_data_free(rset_data *rset)
+{
+ if (rset) {
+ pa_xfree((void *)rset->id);
+ pa_xfree((void *)rset->policy);
+ pa_xfree(rset);
+ }
+}
+
+static void pid_hashmap_free(void *p, void *userdata)
+{
+ pid_hash *ph = (pid_hash *)p;
+
+ (void)userdata;
+
+ if (ph) {
+ pa_xfree((void *)ph->pid);
+ rset_data_free(ph->rset);
+ pa_xfree(ph);
+ }
+}
+
+static int pid_hashmap_put(struct userdata *u, const char *pid,
+ mir_node *node, rset_data *rset)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ pid_hash *ph;
+
+ pa_assert(u);
+ pa_assert(pid);
+ pa_assert(node || rset);
+ pa_assert_se((murphyif = u->murphyif));
+
+ rif = &murphyif->resource;
+
+ ph = pa_xnew0(pid_hash, 1);
+ ph->pid = pa_xstrdup(pid);
+ ph->node = node;
+ ph->rset = rset;
+
+ if (pa_hashmap_put(rif->nodes.pid, ph->pid, ph) == 0)
+ return 0;
+ else
+ pid_hashmap_free(ph, NULL);
+
+ return -1;
+}
+
+static mir_node *pid_hashmap_get_node(struct userdata *u, const char *pid)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ pid_hash *ph;
+
+ pa_assert(u);
+ pa_assert(pid);
+ pa_assert(murphyif = u->murphyif);
+
+ rif = &murphyif->resource;
+
+ if ((ph = pa_hashmap_get(rif->nodes.pid, pid)))
+ return ph->node;
+
+ return NULL;
+}
+
+static rset_data *pid_hashmap_get_rset(struct userdata *u, const char *pid)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ pid_hash *ph;
+
+ pa_assert(u);
+ pa_assert(pid);
+ pa_assert(murphyif = u->murphyif);
+
+ rif = &murphyif->resource;
+
+ if ((ph = pa_hashmap_get(rif->nodes.pid, pid)))
+ return ph->rset;
+
+ return NULL;
+}
+
+static mir_node *pid_hashmap_remove_node(struct userdata *u, const char *pid)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ mir_node *node;
+ pid_hash *ph;
+
+ pa_assert(u);
+ pa_assert_se((murphyif = u->murphyif));
+
+ rif = &murphyif->resource;
+
+ if (!(ph = pa_hashmap_remove(rif->nodes.pid, pid)))
+ node = NULL;
+ else if (!(node = ph->node))
+ pa_hashmap_put(rif->nodes.pid, ph->pid, ph);
+ else
+ pid_hashmap_free(ph, NULL);
+
+ return node;
+}
+
+static rset_data *pid_hashmap_remove_rset(struct userdata *u, const char *pid)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ rset_data *rset;
+ pid_hash *ph;
+
+ pa_assert(u);
+ pa_assert(pid);
+
+ pa_assert_se((murphyif = u->murphyif));
+
+ rif = &murphyif->resource;
+
+ if (!(ph = pa_hashmap_remove(rif->nodes.pid, pid)))
+ rset = NULL;
+ else if (!(rset = ph->rset))
+ pa_hashmap_put(rif->nodes.pid, ph->pid, ph);
+ else {
+ ph->rset = NULL;
+ pid_hashmap_free(ph, NULL);
+ }
+
+ return rset;
+}
+
+
+static void rset_hashmap_free(void *r, void *userdata)
+{
+ rset_hash *rh = (rset_hash *)r;
+
+ (void)userdata;
+
+ if (rh) {
+ pa_xfree(rh->nodes);
+ rset_data_free(rh->rset);
+ pa_xfree(rh);
+ }
+}
+
+static rset_hash *rset_hashmap_put(struct userdata *u,
+ const char *rsetid,
+ mir_node *node)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ rset_hash *rh;
+ rset_data *rset;
+ size_t i;
+
+ pa_assert(u);
+ pa_assert(rsetid);
+ pa_assert(node);
+ pa_assert_se((murphyif = u->murphyif));
+
+ rif = &murphyif->resource;
+
+ if ((rh = pa_hashmap_get(rif->nodes.rsetid, rsetid))) {
+ for (i = 0; i < rh->nnode; i++) {
+ if (rh->nodes[i] == node)
+ return NULL;
+ }
+
+ i = rh->nnode++;
+ rh->nodes = pa_xrealloc(rh->nodes, sizeof(mir_node *) * (rh->nnode+1));
+ }
+ else {
+ rset = pa_xnew0(rset_data, 1);
+
+ rset->id = pa_xstrdup(rsetid);
+ rset->policy = pa_xstrdup("unknown");
+
+ rh = pa_xnew0(rset_hash, 1);
+
+ rh->nnode = 1;
+ rh->nodes = pa_xnew0(mir_node *, 2);
+ rh->rset = rset;
+
+ pa_hashmap_put(rif->nodes.rsetid, rh->rset->id, rh);
+
+ i = 0;
+ }
+
+
+ rh->nodes[i+0] = node;
+ rh->nodes[i+1] = NULL;
+
+ return rh;
+}
+
+static rset_hash *rset_hashmap_get(struct userdata *u, const char *rsetid)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ rset_hash *rh;
+
+ pa_assert(u);
+ pa_assert(rsetid);
+ pa_assert(murphyif = u->murphyif);
+
+ rif = &murphyif->resource;
+
+ if ((rh = pa_hashmap_get(rif->nodes.rsetid, rsetid)))
+ return rh;
+
+ return NULL;
+}
+
+static int rset_hashmap_remove(struct userdata *u,
+ const char *rsetid,
+ mir_node *node)
+{
+ pa_murphyif *murphyif;
+ resource_interface *rif;
+ rset_hash *rh;
+ size_t i,j;
+
+ pa_assert(u);
+ pa_assert_se((murphyif = u->murphyif));
+
+ rif = &murphyif->resource;
+
+ if ((rh = pa_hashmap_get(rif->nodes.rsetid, rsetid))) {
+
+ for (i = 0; i < rh->nnode; i++) {
+ if (node == rh->nodes[i]) {
+ if (rh->nnode <= 1) {
+ pa_hashmap_remove(rif->nodes.rsetid, rsetid);
+ rset_hashmap_free(rh, NULL);
+ return 0;
+ }
+ else {
+ for (j = i; j < rh->nnode; j++)
+ rh->nodes[j] = rh->nodes[j+1];
+
+ rh->nnode--;
+
+ return 0;
+ }
+ }
+ }
+ }
+
+ return -1;
+}