2 * module-murphy-ivi -- PulseAudio module for providing audio routing support
3 * Copyright (c) 2012, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU Lesser General Public License,
7 * version 2.1, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
20 #include <sys/types.h>
25 #include <pulse/utf8.h>
26 #include <pulsecore/pulsecore-config.h>
27 #include <pulsecore/module.h>
28 #include <pulsecore/llist.h>
29 #include <pulsecore/idxset.h>
30 #include <pulsecore/hashmap.h>
31 #include <pulsecore/core-util.h>
32 #include <pulsecore/sink-input.h>
33 #include <pulsecore/source-output.h>
37 #define WITH_RESOURCES
40 #if defined(WITH_DOMCTL) || defined(WITH_RESOURCES)
41 #include <murphy/common/macros.h>
42 #include <murphy/common/mainloop.h>
43 #include <murphy/pulse/pulse-glue.h>
47 #include <murphy/resource/protocol.h>
48 #include <murphy/common/transport.h>
49 #include <murphy/resource/protocol.h>
50 #include <murphy/resource/data-types.h>
57 #define INVALID_ID (~(uint32_t)0)
58 #define INVALID_INDEX (~(uint32_t)0)
59 #define INVALID_SEQNO (~(uint32_t)0)
60 #define INVALID_REQUEST (~(uint16_t)0)
62 #define PUSH_VALUE(msg, tag, typ, val) \
63 mrp_msg_append(msg, MRP_MSG_TAG_##typ(RESPROTO_##tag, val))
65 #define PUSH_ATTRS(msg, rif, proplist) \
66 resource_push_attributes(msg, rif, proplist)
68 typedef struct resource_attribute resource_attribute;
69 typedef struct resource_request resource_request;
71 struct resource_attribute {
72 PA_LLIST_FIELDS(resource_attribute);
77 struct resource_request {
78 PA_LLIST_FIELDS(resource_request);
91 mrp_domctl_table_t *tables;
93 mrp_domctl_watch_t *watches;
94 pa_murphyif_watch_cb watchcb;
102 #ifdef WITH_RESOURCES
103 mrp_transport_t *transp;
104 mrp_sockaddr_t saddr;
113 PA_LLIST_HEAD(resource_attribute, attrs);
114 PA_LLIST_HEAD(resource_request, reqs);
116 } resource_interface;
120 #if defined(WITH_DOMCTL) || defined(WITH_RESOURCES)
123 domctl_interface domctl;
124 resource_interface resource;
130 static void domctl_connect_notify(mrp_domctl_t *,int,int,const char *,void *);
131 static void domctl_watch_notify(mrp_domctl_t *,mrp_domctl_data_t *,int,void *);
132 static void domctl_dump_data(mrp_domctl_data_t *);
135 #ifdef WITH_RESOURCES
136 static void resource_attribute_destroy(resource_interface *,
137 resource_attribute *);
138 static pa_bool_t resource_transport_connect(resource_interface *);
139 static void resource_xport_closed_evt(mrp_transport_t *, int, void *);
141 static mrp_msg_t *resource_create_request(uint32_t, mrp_resproto_request_t);
142 static pa_bool_t resource_send_message(resource_interface *, mrp_msg_t *,
143 uint32_t, uint16_t, uint32_t);
144 static pa_bool_t resource_set_create(struct userdata *, uint32_t,
145 mir_direction, const char *,
146 const char *, uint32_t, pa_proplist *);
147 static pa_bool_t resource_set_destroy(struct userdata *, uint32_t);
148 static pa_bool_t resource_set_acquire(struct userdata *, uint32_t, uint32_t);
149 static pa_bool_t resource_push_attributes(mrp_msg_t *, resource_interface *,
152 static void resource_recv_msg(mrp_transport_t *, mrp_msg_t *, void *);
153 static void resource_recvfrom_msg(mrp_transport_t *, mrp_msg_t *,
154 mrp_sockaddr_t *, socklen_t, void *);
155 static void resource_set_create_response(struct userdata *, mir_node *,
156 mrp_msg_t *, void **);
158 static pa_bool_t resource_fetch_seqno(mrp_msg_t *, void **, uint32_t *);
159 static pa_bool_t resource_fetch_request(mrp_msg_t *, void **, uint16_t *);
160 static pa_bool_t resource_fetch_status(mrp_msg_t *, void **, int *);
161 static pa_bool_t resource_fetch_rset_id(mrp_msg_t *, void **, uint32_t*);
162 static pa_bool_t resource_fetch_rset_state(mrp_msg_t *, void **,
163 mrp_resproto_state_t *);
164 static pa_bool_t resource_fetch_rset_mask(mrp_msg_t *, void **,
165 mrp_resproto_state_t *);
169 pa_murphyif *pa_murphyif_init(struct userdata *u,
170 const char *ctl_addr,
171 const char *res_addr)
173 #ifdef WITH_RESOURCES
174 static mrp_transport_evt_t ev = {
175 { .recvmsg = resource_recv_msg },
176 { .recvmsgfrom = resource_recvfrom_msg },
177 .closed = resource_xport_closed_evt,
182 pa_murphyif *murphyif;
183 domctl_interface *dif;
184 resource_interface *rif;
185 #if defined(WITH_DOMCTL) || defined(WITH_RESOURCES)
188 if (!(ml = mrp_mainloop_pulse_get(u->core->mainloop))) {
189 pa_log_error("Failed to set up murphy mainloop.");
193 #ifdef WITH_RESOURCES
196 murphyif = pa_xnew0(pa_murphyif, 1);
197 dif = &murphyif->domctl;
198 rif = &murphyif->resource;
200 #if defined(WITH_DOMCTL) || defined(WITH_RESOURCES)
204 dif->addr = pa_xstrdup(ctl_addr ? ctl_addr:MRP_DEFAULT_DOMCTL_ADDRESS);
208 rif->addr = pa_xstrdup(res_addr ? res_addr:RESPROTO_DEFAULT_ADDRESS);
209 #ifdef WITH_RESOURCES
210 rif->alen = mrp_transport_resolve(NULL, rif->addr, &rif->saddr,
211 sizeof(rif->saddr), &rif->atype);
212 if (rif->alen <= 0) {
213 pa_log("can't resolve resource transport address '%s'", rif->addr);
216 rif->transp = mrp_transport_create(murphyif->ml, rif->atype, &ev, u,0);
219 resource_transport_connect(rif);
221 pa_log("failed to create resource transport");
224 rif->seqno.request = 1;
225 rif->nodes = pa_hashmap_new(pa_idxset_trivial_hash_func,
226 pa_idxset_trivial_compare_func);
227 PA_LLIST_HEAD_INIT(resource_attribute, rif->attrs);
228 PA_LLIST_HEAD_INIT(resource_request, rif->reqs);
231 murphyif->nodes = pa_hashmap_new(pa_idxset_trivial_hash_func,
232 pa_idxset_trivial_compare_func);
237 void pa_murphyif_done(struct userdata *u)
239 pa_murphyif *murphyif;
240 domctl_interface *dif;
241 resource_interface *rif;
242 #ifdef WITH_RESOURCES
243 resource_attribute *attr, *a;
244 resource_request *req, *r;
247 if (u && (murphyif = u->murphyif)) {
249 mrp_domctl_table_t *t;
250 mrp_domctl_watch_t *w;
253 dif = &murphyif->domctl;
254 rif = &murphyif->resource;
256 mrp_domctl_destroy(dif->ctl);
257 mrp_mainloop_destroy(murphyif->ml);
259 if (dif->ntable > 0 && dif->tables) {
260 for (i = 0; i < dif->ntable; i++) {
262 pa_xfree((void *)t->table);
263 pa_xfree((void *)t->mql_columns);
264 pa_xfree((void *)t->mql_index);
266 pa_xfree(dif->tables);
269 if (dif->nwatch > 0 && dif->watches) {
270 for (i = 0; i < dif->nwatch; i++) {
271 w = dif->watches + i;
272 pa_xfree((void *)w->table);
273 pa_xfree((void *)w->mql_columns);
274 pa_xfree((void *)w->mql_where);
276 pa_xfree(dif->watches);
280 #ifdef WITH_RESOURCES
281 pa_xfree((void *)rif->atype);
282 pa_hashmap_free(rif->nodes, NULL, NULL);
284 PA_LLIST_FOREACH_SAFE(attr, a, rif->attrs)
285 resource_attribute_destroy(rif, attr);
287 PA_LLIST_FOREACH_SAFE(req, r, rif->reqs)
291 pa_xfree((void *)dif->addr);
292 pa_xfree((void *)rif->addr);
294 pa_hashmap_free(murphyif->nodes, NULL, NULL);
302 void pa_murphyif_add_table(struct userdata *u,
307 pa_murphyif *murphyif;
308 domctl_interface *dif;
309 mrp_domctl_table_t *t;
316 pa_assert_se((murphyif = u->murphyif));
318 dif = &murphyif->domctl;
321 size = sizeof(mrp_domctl_table_t) * dif->ntable;
322 t = (dif->tables = pa_xrealloc(dif->tables, size)) + idx;
324 t->table = pa_xstrdup(table);
325 t->mql_columns = pa_xstrdup(columns);
326 t->mql_index = index ? pa_xstrdup(index) : NULL;
329 void pa_murphyif_add_watch(struct userdata *u,
335 pa_murphyif *murphyif;
336 domctl_interface *dif;
337 mrp_domctl_watch_t *w;
344 pa_assert(max_rows > 0 && max_rows < MQI_QUERY_RESULT_MAX);
345 pa_assert_se((murphyif = u->murphyif));
347 dif = &murphyif->domctl;
350 size = sizeof(mrp_domctl_watch_t) * dif->nwatch;
351 w = (dif->watches = pa_xrealloc(dif->watches, size)) + idx;
353 w->table = pa_xstrdup(table);
354 w->mql_columns = pa_xstrdup(columns);
355 w->mql_where = where ? pa_xstrdup(where) : NULL;
356 w->max_rows = max_rows;
359 void pa_murphyif_setup_domainctl(struct userdata *u, pa_murphyif_watch_cb wcb)
361 static const char *name = "pulse";
363 pa_murphyif *murphyif;
364 domctl_interface *dif;
368 pa_assert_se((murphyif = u->murphyif));
370 dif = &murphyif->domctl;
373 if (dif->ntable || dif->nwatch) {
374 dif->ctl = mrp_domctl_create(name, murphyif->ml,
375 dif->tables, dif->ntable,
376 dif->watches, dif->nwatch,
377 domctl_connect_notify,
378 domctl_watch_notify, u);
380 pa_log("failed to create '%s' domain controller", name);
384 if (!mrp_domctl_connect(dif->ctl, dif->addr, 0)) {
385 pa_log("failed to conect to murphyd");
390 pa_log_info("'%s' domain controller sucessfully created", name);
395 void pa_murphyif_add_audio_resource(struct userdata *u,
399 pa_murphyif *murphyif;
400 resource_interface *rif;
403 pa_assert(dir == mir_input || dir == mir_output);
406 pa_assert_se((murphyif = u->murphyif));
407 rif = &murphyif->resource;
409 if (dir == mir_input) {
411 pa_log("attempt to register playback resource multiple time");
413 rif->inpres = pa_xstrdup(name);
417 pa_log("attempt to register recording resource multiple time");
419 rif->outres = pa_xstrdup(name);
423 void pa_murphyif_add_audio_attribute(struct userdata *u,
426 mqi_data_type_t type,
427 ... ) /* default value */
429 #ifdef WITH_RESOURCES
430 pa_murphyif *murphyif;
431 resource_interface *rif;
432 resource_attribute *attr;
433 mrp_attr_value_t *val;
439 pa_assert(type == mqi_string || type == mqi_integer ||
440 type == mqi_unsignd || type == mqi_floating);
442 pa_assert_se((murphyif = u->murphyif));
443 rif = &murphyif->resource;
445 attr = pa_xnew0(resource_attribute, 1);
446 val = &attr->def.value;
448 attr->prop = pa_xstrdup(propnam);
449 attr->def.name = pa_xstrdup(attrnam);
450 attr->def.type = type;
455 case mqi_string: val->string = pa_xstrdup(va_arg(ap, char *)); break;
456 case mqi_integer: val->integer = va_arg(ap, int32_t); break;
457 case mqi_unsignd: val->unsignd = va_arg(ap, uint32_t); break;
458 case mqi_floating: val->floating = va_arg(ap, double); break;
459 default: attr->def.type = mqi_error; break;
464 if (attr->def.type == mqi_error)
465 resource_attribute_destroy(rif, attr);
467 PA_LLIST_PREPEND(resource_attribute, rif->attrs, attr);
471 void pa_murphyif_create_resource_set(struct userdata *u, mir_node *node)
474 pa_murphyif *murphyif;
475 resource_interface *rif;
477 uint32_t audio_flags = 0;
478 pa_proplist *proplist = NULL;
480 pa_source_output *sout;
484 pa_assert(node->implement = mir_stream);
485 pa_assert(node->direction == mir_input || node->direction == mir_output);
486 pa_assert(node->zone);
487 pa_assert(!node->rsetid);
489 pa_assert_se((core = u->core));
490 pa_assert_se((class = pa_nodeset_get_class(u, node->type)));
492 pa_assert_se((murphyif = u->murphyif));
493 rif = &murphyif->resource;
495 resource_transport_connect(rif);
497 if (node->direction == mir_output) {
498 if ((sout = pa_idxset_get_by_index(core->source_outputs, node->paidx)))
499 proplist = sout->proplist;
502 if ((sinp = pa_idxset_get_by_index(core->sink_inputs, node->paidx)))
503 proplist = sinp->proplist;
506 node->localrset = resource_set_create(u, node->index, node->direction,
507 class, node->zone, audio_flags,
511 void pa_murphyif_destroy_resource_set(struct userdata *u, mir_node *node)
513 pa_murphyif *murphyif;
519 pa_assert_se((murphyif = u->murphyif));
521 if (node->localrset && node->rsetid) {
522 rsetid = strtoul(node->rsetid, &e, 10);
524 if (e == node->rsetid || *e) {
525 pa_log("can't destroy resource set: invalid rsetid '%s'",
529 if (resource_set_destroy(u, rsetid))
530 pa_log_debug("resource set %u destruction request", rsetid);
532 pa_log("falied to destroy resourse set %u for node '%s'",
533 rsetid, node->amname);
537 pa_murphyif_delete_node(u, node);
541 int pa_murphyif_add_node(struct userdata *u, mir_node *node)
543 #ifdef WITH_RESOURCES
544 pa_murphyif *murphyif;
548 pa_assert(node->implement == mir_stream);
550 pa_assert_se((murphyif = u->murphyif));
553 pa_log("can't register resource set for node '%s'.: missing rsetid",
557 if (pa_hashmap_put(murphyif->nodes, node->rsetid, node) == 0)
560 pa_log("can't register resource set for node '%s': conflicting "
561 "resource id '%s'", node->amname, node->rsetid);
571 void pa_murphyif_delete_node(struct userdata *u, mir_node *node)
573 #ifdef WITH_RESOURCES
574 pa_murphyif *murphyif;
579 pa_assert(node->implement == mir_stream);
581 pa_assert_se((murphyif = u->murphyif));
584 deleted = pa_hashmap_remove(murphyif->nodes, node->rsetid);
585 pa_assert(deleted == node);
590 mir_node *pa_murphyif_find_node(struct userdata *u, const char *rsetid)
592 #ifdef WITH_RESOURCES
593 pa_murphyif *murphyif;
597 pa_assert_se((murphyif = u->murphyif));
602 node = pa_hashmap_get(murphyif->nodes, rsetid);
612 static void domctl_connect_notify(mrp_domctl_t *dc, int connected, int errcode,
613 const char *errmsg, void *user_data)
616 MRP_UNUSED(user_data);
619 pa_log_info("Successfully registered to Murphy.");
622 pa_log_error("Connection to Murphy failed (%d: %s).", errcode, errmsg);
625 static void domctl_watch_notify(mrp_domctl_t *dc, mrp_domctl_data_t *tables,
626 int ntable, void *user_data)
628 struct userdata *u = (struct userdata *)user_data;
629 pa_murphyif *murphyif;
630 domctl_interface *dif;
631 mrp_domctl_data_t *t;
632 mrp_domctl_watch_t *w;
638 pa_assert(ntable > 0);
640 pa_assert_se((murphyif = u->murphyif));
642 dif = &murphyif->domctl;
644 pa_log_info("Received change notification for %d tables.", ntable);
646 for (i = 0; i < ntable; i++) {
651 pa_assert(t->id >= 0);
652 pa_assert(t->id < dif->nwatch);
654 w = dif->watches + t->id;
656 dif->watchcb(u, w->table, t->nrow, t->rows);
660 static void domctl_dump_data(mrp_domctl_data_t *table)
662 mrp_domctl_value_t *row;
668 pa_log_debug("Table #%d: %d rows x %d columns", table->id,
669 table->nrow, table->ncolumn);
671 for (i = 0; i < table->nrow; i++) {
672 row = table->rows[i];
676 for (j = 0, t = ""; j < table->ncolumn; j++, t = ", ") {
677 switch (row[j].type) {
678 case MRP_DOMCTL_STRING:
679 l = snprintf(p, n, "%s'%s'", t, row[j].str);
683 case MRP_DOMCTL_INTEGER:
684 l = snprintf(p, n, "%s%d", t, row[j].s32);
688 case MRP_DOMCTL_UNSIGNED:
689 l = snprintf(p, n, "%s%u", t, row[j].u32);
693 case MRP_DOMCTL_DOUBLE:
694 l = snprintf(p, n, "%s%f", t, row[j].dbl);
699 l = snprintf(p, n, "%s<invalid column 0x%x>",
706 pa_log_debug("row #%d: { %s }", i, buf);
711 #ifdef WITH_RESOURCES
712 static void resource_attribute_destroy(resource_interface *rif,
713 resource_attribute *attr)
717 PA_LLIST_REMOVE(resource_attribute, rif->attrs, attr);
719 pa_xfree((void *)attr->prop);
720 pa_xfree((void *)attr->def.name);
722 if (attr->def.type == mqi_string)
723 pa_xfree((void *)attr->def.value.string);
729 static pa_bool_t resource_transport_connect(resource_interface *rif)
733 if (!rif->connected) {
734 if (mrp_transport_connect(rif->transp, &rif->saddr, rif->alen)) {
735 pa_log_info("resource transport connected to '%s'", rif->addr);
736 rif->connected = TRUE;
739 pa_log("can't connect resource transport to '%s'", rif->addr);
747 static void resource_xport_closed_evt(mrp_transport_t *transp, int error,
750 struct userdata *u = (struct userdata *)void_u;
751 pa_murphyif *murphyif;
752 resource_interface *rif;
757 pa_assert_se((murphyif = u->murphyif));
759 rif = &murphyif->resource;
762 pa_log("peer has closed the resource transport connection");
764 pa_log("resource transport connection closed with error %d (%s)",
765 error, strerror(error));
768 rif->connected = FALSE;
771 static mrp_msg_t *resource_create_request(uint32_t seqno,
772 mrp_resproto_request_t req)
777 msg = mrp_msg_create(RESPROTO_SEQUENCE_NO , MRP_MSG_FIELD_UINT32, seqno,
778 RESPROTO_REQUEST_TYPE, MRP_MSG_FIELD_UINT16, type ,
779 RESPROTO_MESSAGE_END );
782 pa_log("can't to create new resource message");
787 static pa_bool_t resource_send_message(resource_interface *rif,
793 resource_request *req;
794 pa_bool_t success = TRUE;
796 if (!mrp_transport_send(rif->transp, msg)) {
797 pa_log("failed to send resource message");
801 req = pa_xnew0(resource_request, 1);
802 req->nodidx = nodidx;
806 PA_LLIST_PREPEND(resource_request, rif->reqs, req);
815 static pa_bool_t resource_set_create(struct userdata *u,
820 uint32_t audio_flags,
821 pa_proplist *proplist)
823 static uint32_t rset_flags = 0 /* RESPROTO_RSETFLAG_AUTORELEASE */ ;
825 pa_murphyif *murphyif;
826 resource_interface *rif;
827 resource_request *req;
832 pa_bool_t success = TRUE;
835 pa_assert(nodidx != PA_IDXSET_INVALID);
836 pa_assert(dir == mir_input || dir == mir_output);
840 pa_assert_se((murphyif = u->murphyif));
841 rif = &murphyif->resource;
843 reqid = RESPROTO_CREATE_RESOURCE_SET;
844 seqno = rif->seqno.request++;
845 resnam = (dir == mir_input) ? rif->inpres : rif->outres;
849 msg = resource_create_request(seqno, reqid);
851 if (PUSH_VALUE(msg, RESOURCE_FLAGS , UINT32, rset_flags) &&
852 PUSH_VALUE(msg, RESOURCE_PRIORITY, UINT32, 0) &&
853 PUSH_VALUE(msg, CLASS_NAME , STRING, class) &&
854 PUSH_VALUE(msg, ZONE_NAME , STRING, zone) &&
855 PUSH_VALUE(msg, RESOURCE_NAME , STRING, resnam) &&
856 PUSH_VALUE(msg, RESOURCE_FLAGS , UINT32, audio_flags) &&
857 PUSH_ATTRS(msg, rif, proplist) &&
858 PUSH_VALUE(msg, SECTION_END , UINT8 , 0) )
860 success = resource_send_message(rif, msg, nodidx, reqid, seqno);
870 static pa_bool_t resource_set_destroy(struct userdata *u, uint32_t rsetid)
872 pa_murphyif *murphyif;
873 resource_interface *rif;
882 pa_assert_se((murphyif = u->murphyif));
883 rif = &murphyif->resource;
885 reqid = RESPROTO_DESTROY_RESOURCE_SET;
886 seqno = rif->seqno.request++;
887 nodidx = PA_IDXSET_INVALID;
888 msg = resource_create_request(seqno, reqid);
890 if (PUSH_VALUE(msg, RESOURCE_SET_ID, UINT32, rsetid))
891 success = resource_send_message(rif, msg, nodidx, reqid, seqno);
900 static pa_bool_t resource_set_acquire(struct userdata *u,
904 pa_murphyif *murphyif;
905 resource_interface *rif;
913 pa_assert_se((murphyif = u->murphyif));
914 rif = &murphyif->resource;
916 reqid = RESPROTO_ACQUIRE_RESOURCE_SET;
917 seqno = rif->seqno.request++;
918 msg = resource_create_request(seqno, reqid);
920 if (PUSH_VALUE(msg, RESOURCE_SET_ID, UINT32, rsetid))
921 success = resource_send_message(rif, msg, nodidx, reqid, seqno);
930 static pa_bool_t resource_push_attributes(mrp_msg_t *msg,
931 resource_interface *rif,
932 pa_proplist *proplist)
934 resource_attribute *attr;
948 PA_LLIST_FOREACH(attr, rif->attrs) {
949 if (!PUSH_VALUE(msg, ATTRIBUTE_NAME, STRING, attr->def.name))
953 sts = pa_proplist_get(proplist, attr->prop, &v.ptr, &size);
957 switch (attr->def.type) {
960 v.str = attr->def.value.string;
961 else if (v.str[size-1] != '\0' || strlen(v.str) != (size-1) ||
962 !pa_utf8_valid(v.str))
964 if (!PUSH_VALUE(msg, ATTRIBUTE_VALUE, STRING, v.str))
970 v.i32 = &attr->def.value.integer;
971 else if (size != sizeof(*v.i32))
973 if (!PUSH_VALUE(msg, ATTRIBUTE_VALUE, SINT8, *v.i32))
979 v.u32 = &attr->def.value.unsignd;
980 else if (size != sizeof(*v.u32))
982 if (!PUSH_VALUE(msg, ATTRIBUTE_VALUE, SINT8, *v.u32))
988 v.dbl = &attr->def.value.floating;
989 else if (size != sizeof(*v.dbl))
991 if (!PUSH_VALUE(msg, ATTRIBUTE_VALUE, SINT8, *v.dbl))
995 default: /* we should never get here */
1005 static void resource_recv_msg(mrp_transport_t *t, mrp_msg_t *msg, void *void_u)
1007 return resource_recvfrom_msg(t, msg, NULL, 0, void_u);
1010 static void resource_recvfrom_msg(mrp_transport_t *transp, mrp_msg_t *msg,
1011 mrp_sockaddr_t *addr, socklen_t addrlen,
1014 struct userdata *u = (struct userdata *)void_u;
1016 pa_murphyif *murphyif;
1017 resource_interface *rif;
1022 resource_request *req, *n;
1027 MRP_UNUSED(addrlen);
1030 pa_assert_se((core = u->core));
1031 pa_assert_se((murphyif = u->murphyif));
1033 rif = &murphyif->resource;
1035 if (!resource_fetch_seqno (msg, &curs, &seqno) ||
1036 !resource_fetch_request (msg, &curs, &reqid) )
1038 pa_log("ignoring malformed message");
1042 PA_LLIST_FOREACH_SAFE(req, n, rif->reqs) {
1043 if (req->seqno <= seqno) {
1044 nodidx = req->nodidx;
1046 if (req->reqid == reqid) {
1047 PA_LLIST_REMOVE(resource_request, rif->reqs, req);
1051 if (!(node = mir_node_find_by_index(u, nodidx))) {
1052 if (reqid != RESPROTO_DESTROY_RESOURCE_SET) {
1053 pa_log("got response (reqid:%u seqno:%u) but can't "
1054 "find the corresponding node", reqid, seqno);
1058 if (req->seqno < seqno) {
1059 pa_log("unanswered request %d", req->seqno);
1062 pa_log_debug("got response (reqid:%u seqno:%u "
1063 "node:'%s')", reqid, seqno,
1064 node ? node->amname : "<unknown>");
1067 case RESPROTO_CREATE_RESOURCE_SET:
1068 resource_set_create_response(u,node,msg,&curs);
1071 case RESPROTO_ACQUIRE_RESOURCE_SET:
1072 resource_set_acquire_response(u,node,msg,&curs);
1074 case RESPROTO_RELEASE_RESOURCE_SET:
1075 resource_set_release_response(u,node,msg,&curs);
1077 case RESPROTO_RESOURCES_EVENT:
1078 resource_event(u, seqno, msg, &curs);
1082 pa_log("ignoring unsupported resource request "
1088 } /* PA_LLIST_FOREACH_SAFE */
1092 static void resource_set_create_response(struct userdata *u, mir_node *node,
1093 mrp_msg_t *msg, void **pcursor)
1104 if (!resource_fetch_status(msg, pcursor, &status) || (status == 0 &&
1105 !resource_fetch_rset_id(msg, pcursor, &rsetid)))
1107 pa_log("ignoring malformed response to resource set creation");
1112 pa_log("creation of resource set failed. error code %u", status);
1116 node->rsetid = pa_sprintf_malloc("%d", rsetid);
1118 if (pa_murphyif_add_node(u, node) == 0) {
1119 pa_log_debug("resource set was successfully created");
1120 mir_node_print(node, buf, sizeof(buf));
1121 pa_log_debug("modified node:\n%s", buf);
1123 if (resource_set_acquire(u, node->index, rsetid))
1124 pa_log_debug("acquire request sent");
1126 pa_log("failed to send acquire request");
1129 pa_log("failed to create resource set: "
1130 "conflicting resource set id");
1135 static pa_bool_t resource_fetch_seqno(mrp_msg_t *msg,
1141 mrp_msg_value_t value;
1144 if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
1145 tag != RESPROTO_SEQUENCE_NO || type != MRP_MSG_FIELD_UINT32)
1147 *pseqno = INVALID_SEQNO;
1151 *pseqno = value.u32;
1156 static pa_bool_t resource_fetch_request(mrp_msg_t *msg,
1162 mrp_msg_value_t value;
1165 if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
1166 tag != RESPROTO_REQUEST_TYPE || type != MRP_MSG_FIELD_UINT16)
1168 *preqtype = INVALID_REQUEST;
1172 *preqtype = value.u16;
1176 static pa_bool_t resource_fetch_status(mrp_msg_t *msg,
1182 mrp_msg_value_t value;
1185 if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
1186 tag != RESPROTO_REQUEST_STATUS || type != MRP_MSG_FIELD_SINT16)
1192 *pstatus = value.s16;
1196 static pa_bool_t resource_fetch_rset_id(mrp_msg_t *msg,
1202 mrp_msg_value_t value;
1205 if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
1206 tag != RESPROTO_RESOURCE_SET_ID || type != MRP_MSG_FIELD_UINT32)
1216 static pa_bool_t resource_fetch_rset_state(mrp_msg_t *msg,
1218 mrp_resproto_state_t *pstate)
1222 mrp_msg_value_t value;
1225 if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
1226 tag != RESPROTO_RESOURCE_STATE || type != MRP_MSG_FIELD_UINT16)
1232 *pstate = value.u16;
1237 static pa_bool_t resource_fetch_rset_mask(mrp_msg_t *msg,
1239 mrp_resproto_state_t *pmask)
1243 mrp_msg_value_t value;
1246 if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
1247 tag != RESPROTO_RESOURCE_GRANT || type != MRP_MSG_FIELD_UINT32)
1263 * indent-tabs-mode: nil