2 * Copyright (c) 2014, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <murphy/common.h>
37 #include <murphy-db/mqi.h>
39 #include <murphy/resource/config-api.h>
40 #include <murphy/resource/manager-api.h>
41 #include <murphy/resource/client-api.h>
48 #define ANY_ZONE (~((uint32_t)0))
51 #define ATTRIBUTE(n,t,v) {n, MRP_RESOURCE_RW, mqi_##t, {.t=v}}
52 #define ATTR_END {NULL, 0, 0, {.string=NULL}}
55 typedef enum decision_value_e decision_value_t;
56 typedef enum state_value_e state_value_t;
57 typedef struct resource_s resource_t;
58 typedef struct resource_type_s resource_type_t;
59 typedef struct decision_s decision_t;
60 typedef struct state_s state_t;
62 enum decision_value_e {
75 DECISION_TEARDOWN = 0,
76 DECISION_DISCONNECTED,
83 struct resource_type_s {
89 struct mrp_resmgr_backend_s {
91 resource_type_t types[MRP_RESMGR_RESOURCE_TYPE_MAX];
93 mrp_htbl_t *by_pointer;
94 mrp_htbl_t *by_connid;
108 struct mrp_resmgr_resource_s {
110 mrp_resmgr_backend_t *backend;
112 resource_type_t *type;
113 mrp_resmgr_source_t *source;
114 mrp_resmgr_sink_t *sink;
115 mrp_list_hook_t source_link;
124 static void make_resource_definition(mrp_resmgr_backend_t *, int, const char*);
125 static resource_type_t *find_resource_definition_by_id(mrp_resmgr_backend_t *,
128 static int hash_compare(const void *, const void *);
129 static uint32_t ptr_hash_function(const void *);
130 static uint32_t id_hash_function(const void *);
132 //static const char *get_resource_appid(mrp_resource_t *);
133 static int32_t get_resource_sourceid(mrp_resource_t *);
134 static int32_t get_resource_sinkid(mrp_resource_t *);
135 static int32_t get_resource_connid(mrp_resource_t *);
136 static int32_t get_resource_connno(mrp_resource_t *);
137 static int32_t get_resource_stamp(mrp_resource_t *);
139 static bool set_resource_source_and_sink(mrp_resource_t *,
140 mrp_resmgr_source_t *,
141 mrp_resmgr_sink_t *);
142 static bool set_resource_stamp(mrp_resource_t *, int32_t);
143 static bool set_resource_decision(mrp_resource_t *, int32_t);
146 static void resource_create(mrp_resmgr_backend_t *, mrp_application_class_t *,
147 mrp_zone_t *, mrp_resource_t *);
148 static void resource_destroy(mrp_resmgr_backend_t *, mrp_zone_t *,
150 static bool resource_acquire(mrp_resmgr_backend_t *, mrp_zone_t *,
152 static bool resource_release(mrp_resmgr_backend_t *, mrp_zone_t *,
155 static bool resource_register_by_id(mrp_resmgr_backend_t *,
156 mrp_resmgr_resource_t *);
157 static mrp_resmgr_resource_t *resource_lookup_by_pointer(mrp_resmgr_backend_t*,
160 static size_t resource_print_name(mrp_resmgr_source_t *,uint32_t,char *,size_t);
163 static void make_decisions(mrp_resmgr_backend_t *);
164 static void commit_decisions(mrp_resmgr_backend_t *);
165 static size_t print_decision(mrp_resmgr_resource_t *, char *, size_t);
166 static size_t print_commit(mrp_resmgr_resource_t *, char *, size_t);
168 static void backend_notify(mrp_resource_event_t, mrp_zone_t *,
169 mrp_application_class_t *, mrp_resource_t *, void*);
170 static void backend_init(mrp_zone_t *, void *);
171 static bool backend_allocate(mrp_zone_t *, mrp_resource_t *, void *);
172 static void backend_free(mrp_zone_t *, mrp_resource_t *, void *);
173 static bool backend_advice(mrp_zone_t *, mrp_resource_t *, void *);
174 static void backend_commit(mrp_zone_t *, void *);
178 #define APPID_ATTRIDX 0
179 #define ROLE_ATTRIDX 1
180 #define PID_ATTRIDX 2
181 #define POLICY_ATTRIDX 3
182 #define SRCNAM_ATTRIDX 4
183 #define SRCID_ATTRIDX 5
184 #define SINKNAM_ATTRIDX 6
185 #define SINKID_ATTRIDX 7
186 #define CONNID_ATTRIDX 8
187 #define CONNNO_ATTRIDX 9
188 #define STAMP_ATTRIDX 10
189 #define DECISION_ATTRIDX 11
193 static mrp_attr_def_t audio_attrs[] = {
194 ATTRIBUTE( "appid" , string , "<undefined>" ),
195 ATTRIBUTE( "role" , string , "music" ),
196 ATTRIBUTE( "pid" , string , "<unknown>" ),
197 ATTRIBUTE( "policy" , string , "relaxed" ),
198 ATTRIBUTE( "source_name", string , "<undefined>" ),
199 ATTRIBUTE( "source_id" , integer, 0 ),
200 ATTRIBUTE( "sink_name" , string , "<undefined>" ),
201 ATTRIBUTE( "sink_id" , integer, 0 ),
202 ATTRIBUTE( "connid" , integer, 0 ),
203 ATTRIBUTE( "connno" , integer, 0 ),
204 ATTRIBUTE( "stamp" , integer, 0 ),
205 ATTRIBUTE( "decision" , string , "<not yet>" ),
209 static mrp_resource_mgr_ftbl_t playback_ftbl = {
210 backend_notify, /* notify */
211 backend_init, /* init */
212 backend_allocate, /* allocate */
213 backend_free, /* free */
214 backend_advice, /* advice */
218 static mrp_resource_mgr_ftbl_t recording_ftbl = {
219 backend_notify, /* notify */
221 backend_allocate, /* allocate */
222 backend_free, /* free */
223 backend_advice, /* advice */
224 backend_commit /* commit */
227 static mrp_resource_mgr_ftbl_t *backend_ftbl[MRP_RESMGR_RESOURCE_TYPE_MAX] = {
228 [ MRP_RESMGR_RESOURCE_TYPE_PLAYBACK ] = &playback_ftbl ,
229 [ MRP_RESMGR_RESOURCE_TYPE_RECORDING ] = &recording_ftbl,
233 static const char *decision_names[DECISION_MAX + 1] = {
234 [ DECISION_TEARDOWN ] = "teardown" ,
235 [ DECISION_DISCONNECTED ] = "disconnected",
236 [ DECISION_CONNECTED ] = "connected" ,
237 [ DECISION_SUSPENDED ] = "suspended" ,
240 static const char *state_names[STATE_MAX + 1] = {
241 [ STATE_STOP ] = "stop" ,
242 [ STATE_PAUSE ] = "pause",
243 [ STATE_PLAY ] = "play" ,
246 static state_value_t decision2state[DECISION_MAX] = {
247 [ DECISION_TEARDOWN ] = STATE_STOP ,
248 [ DECISION_DISCONNECTED ] = STATE_STOP ,
249 [ DECISION_CONNECTED ] = STATE_PLAY ,
250 [ DECISION_SUSPENDED ] = STATE_PAUSE,
254 mrp_resmgr_backend_t *mrp_resmgr_backend_create(mrp_resmgr_t *resmgr)
256 mrp_resmgr_backend_t *backend;
257 mrp_htbl_config_t pcfg, icfg;
259 MRP_ASSERT(resmgr, "invalid argument");
261 if ((backend = mrp_allocz(sizeof(mrp_resmgr_backend_t)))) {
262 pcfg.nentry = MRP_RESMGR_RESOURCE_MAX;
263 pcfg.comp = hash_compare;
264 pcfg.hash = ptr_hash_function;
266 pcfg.nbucket = MRP_RESMGR_RESOURCE_BUCKETS;
268 icfg.nentry = MRP_RESMGR_RESOURCE_MAX;
269 icfg.comp = hash_compare;
270 icfg.hash = id_hash_function;
272 icfg.nbucket = MRP_RESMGR_RESOURCE_BUCKETS;
274 backend->resmgr = resmgr;
275 backend->resources.by_pointer = mrp_htbl_create(&pcfg);
276 backend->resources.by_connid = mrp_htbl_create(&icfg);
278 make_resource_definition(backend, MRP_RESMGR_RESOURCE_TYPE_PLAYBACK,
279 MRP_RESMGR_PLAYBACK_RESOURCE);
280 make_resource_definition(backend, MRP_RESMGR_RESOURCE_TYPE_RECORDING,
281 MRP_RESMGR_RECORDING_RESOURCE);
287 void mrp_resmgr_backend_destroy(mrp_resmgr_backend_t *backend)
294 const char **mrp_resmgr_backend_get_decision_names(void)
296 return decision_names;
299 uint32_t mrp_resmgr_backend_get_resource_connid(mrp_resmgr_resource_t *ar)
301 MRP_ASSERT(ar, "invalid argument");
306 uint32_t mrp_resmgr_backend_get_resource_connno(mrp_resmgr_resource_t *ar)
308 MRP_ASSERT(ar, "invalid argument");
313 int32_t mrp_resmgr_backend_get_resource_state(mrp_resmgr_resource_t *ar)
315 MRP_ASSERT(ar, "invalid argument");
317 if (get_resource_stamp(ar->res) == 0)
320 return ar->state.current;
323 int32_t mrp_resmgr_backend_get_resource_decision_id(mrp_resmgr_resource_t *ar)
325 MRP_ASSERT(ar, "invalid argument");
327 if (get_resource_stamp(ar->res) == 0)
330 return mrp_resmgr_sink_get_decision_id(ar->sink, ar->source);
334 uint32_t mrp_resmgr_backend_get_attribute_index(const char *name,
335 mqi_data_type_t type)
337 mrp_attr_def_t *attrd;
341 for (idx = 0; (attrd = audio_attrs + idx)->name; idx++) {
342 if (!strcmp(name, attrd->name)) {
343 if (attrd->type == type)
350 return MRP_RESMGR_RESOURCE_FIELD_INVALID;
354 int32_t mrp_resmgr_backend_get_integer_attribute(mrp_resmgr_resource_t *ar,
359 if (mrp_resource_read_attribute(ar->res, idx, &attr)) {
360 if (attr.type == mqi_integer)
361 return attr.value.integer;
367 const char *mrp_resmgr_backend_get_string_attribute(mrp_resmgr_resource_t *ar,
372 if (mrp_resource_read_attribute(ar->res, idx, &attr)) {
373 if (attr.type == mqi_string)
374 return attr.value.string;
381 mrp_resmgr_resource_t *mrp_resmgr_backend_resource_list_entry(
382 mrp_list_hook_t *entry)
384 MRP_ASSERT(entry, "invalid argument");
386 return mrp_list_entry(entry, mrp_resmgr_resource_t, source_link);
395 int mrp_resmgr_backend_print(mrp_resmgr_backend_t *backend,
401 p += snprintf(p, e-p, __VA_ARGS__); \
408 mrp_list_hook_t *resources, *rentry, *rn;
409 mrp_resmgr_resource_t *ar;
413 char requisite[1024];
415 MRP_ASSERT(backend && buf && len > 0, "invalid argument");
420 if (zoneid < MRP_ZONE_MAX) {
421 resources = backend->zones + zoneid;
422 grantid = backend->grantids[zoneid];
429 PRINT(" Resource '%s' - grantid:%u\n",
430 MRP_SYSCTL_AUDIO_RESOURCE, grantid);
432 if (!resources || mrp_list_empty(resources))
433 PRINT(" No resources\n");
435 mrp_list_foreach_back(resources, rentry, rn) {
436 ar = mrp_list_entry(rentry, mrp_resmgr_resource_t, link);
438 mrp_resmgr_disable_print(ar->disable, disable,
440 mrp_application_requisite_print(ar->requisite, requisite,
444 "key:0x%08x %s %s grantid:%u requisite:%s disable:%s",
446 ar->interrupt ? "interrupt" : "base",
447 ar->acquire ? "acquire":"release",
452 for (i = 0; i < MRP_ARRAY_SIZE(audio_attrs) - 1; i++) {
453 if ((mrp_resource_read_attribute(ar->res, i, &a))) {
454 PRINT(" %s:", a.name);
457 case mqi_string: PRINT("'%s'",a.value.string); break;
458 case mqi_integer: PRINT("%d",a.value.integer); break;
459 case mqi_unsignd: PRINT("%u",a.value.unsignd); break;
460 case mqi_floating: PRINT("%lf",a.value.floating);break;
461 default: PRINT("<unsupported type>"); break;
467 } /* mrp_list_foreach_back - resources */
474 static void make_resource_definition(mrp_resmgr_backend_t *backend,
478 resource_type_t *type = backend->types + id;
480 MRP_ASSERT(backend && id >= 0 && id < MRP_RESMGR_RESOURCE_TYPE_MAX,
481 "invalid attribute");
484 type->name = mrp_strdup(name);
485 type->resid = mrp_resource_definition_create(type->name, true, /* share */
486 audio_attrs, backend_ftbl[id],
489 mrp_lua_resclass_create_from_c(type->resid);
492 static resource_type_t *find_resource_definition_by_id(
493 mrp_resmgr_backend_t *backend,
496 resource_type_t *type;
499 MRP_ASSERT(backend, "invalid argument");
501 for (i = 0; i < MRP_RESMGR_RESOURCE_TYPE_MAX; i++) {
502 type = backend->types + i;
511 static int hash_compare(const void *key1, const void *key2)
520 static uint32_t ptr_hash_function(const void *key)
522 return (uint32_t)(((size_t)key >> 4) & 0xffffffff);
525 static uint32_t id_hash_function(const void *key)
527 return (uint32_t)(key - (const void *)0);
532 static const char *get_resource_appid(mrp_resource_t *res)
537 if (!mrp_resource_read_attribute(res, APPID_ATTRIDX, &attr) ||
538 attr.type != mqi_string || !(appid = attr.value.string) )
545 static int32_t get_resource_sourceid(mrp_resource_t *res)
549 if (!mrp_resource_read_attribute(res, SRCID_ATTRIDX, &attr) ||
550 attr.type != mqi_integer)
555 return attr.value.integer;
558 static int32_t get_resource_sinkid(mrp_resource_t *res)
562 if (!mrp_resource_read_attribute(res, SINKID_ATTRIDX, &attr) ||
563 attr.type != mqi_integer)
568 return attr.value.integer;
572 static int32_t get_resource_connid(mrp_resource_t *res)
576 if (!mrp_resource_read_attribute(res, CONNID_ATTRIDX, &attr) ||
577 attr.type != mqi_integer)
582 return attr.value.integer;
585 static int32_t get_resource_connno(mrp_resource_t *res)
589 if (!mrp_resource_read_attribute(res, CONNNO_ATTRIDX, &attr) ||
590 attr.type != mqi_integer)
595 return attr.value.integer;
598 static int32_t get_resource_stamp(mrp_resource_t *res)
602 if (!mrp_resource_read_attribute(res, STAMP_ATTRIDX, &attr) ||
603 attr.type != mqi_integer)
608 return attr.value.integer;
611 static bool set_resource_source_and_sink(mrp_resource_t *res,
612 mrp_resmgr_source_t *source,
613 mrp_resmgr_sink_t *sink)
615 const char *source_name;
616 const char *sink_name;
617 mrp_attr_t attrs[ATTR_MAX+1];
619 memset(attrs, 0, sizeof(attrs));
621 if (!mrp_resource_read_all_attributes(res, ATTR_MAX+1, attrs))
624 if (source && (source_name = mrp_resmgr_source_get_name(source)))
625 attrs[SRCNAM_ATTRIDX].value.string = source_name;
627 if (sink && (sink_name = mrp_resmgr_sink_get_name(sink)))
628 attrs[SINKNAM_ATTRIDX].value.string = sink_name;
630 if (mrp_resource_write_attributes(res, attrs) < 0)
637 static bool set_resource_stamp(mrp_resource_t *res, int32_t stamp)
639 mrp_attr_t attrs[ATTR_MAX+1];
641 memset(attrs, 0, sizeof(attrs));
643 if (!mrp_resource_read_all_attributes(res, ATTR_MAX+1, attrs))
646 attrs[STAMP_ATTRIDX].value.integer = stamp;
648 if (mrp_resource_write_attributes(res, attrs) < 0)
654 static bool set_resource_decision(mrp_resource_t *res, int32_t decision)
656 const char *decision_name;
657 mrp_attr_t attrs[ATTR_MAX+1];
659 if (decision < 0 || decision >= DECISION_MAX)
660 decision_name = "<error>";
662 decision_name = decision_names[decision];
664 memset(attrs, 0, sizeof(attrs));
666 if (!mrp_resource_read_all_attributes(res, ATTR_MAX+1, attrs))
669 attrs[DECISION_ATTRIDX].value.string = decision_name;
671 if (mrp_resource_write_attributes(res, attrs) < 0)
678 static void resource_create(mrp_resmgr_backend_t *backend,
679 mrp_application_class_t *ac,
683 mrp_resmgr_t *resmgr;
684 mrp_resmgr_resource_t *ar;
687 resource_type_t *type;
688 uint32_t srcid, sinkid;
689 mrp_resmgr_source_t *src;
690 mrp_resmgr_sink_t *sink;
698 MRP_ASSERT(backend && backend->resmgr && res, "invalid argument");
700 resmgr = backend->resmgr;
701 zoneid = mrp_zone_get_id(zone);
702 resid = mrp_resource_get_id(res);
703 type = find_resource_definition_by_id(backend, resid);
704 srcid = get_resource_sourceid(res);
705 sinkid = get_resource_sinkid(res);
706 src = (srcid > 0) ? mrp_resmgr_source_find_by_id(resmgr, srcid):NULL;
707 sink = (sinkid > 0) ? mrp_resmgr_sink_find_by_gam_id(resmgr,sinkid):NULL;
708 connid = get_resource_connid(res);
709 connno = get_resource_connno(res);
714 resource_print_name(src, connno, name, sizeof(name));
717 if (!(ar = mrp_allocz(sizeof(mrp_resmgr_resource_t))))
720 ar->name = mrp_strdup(name);
721 ar->backend = backend;
730 mrp_list_init(&ar->source_link);
732 if (!mrp_htbl_insert(backend->resources.by_pointer, res, ar)) {
733 mrp_log_error("gam-resource-manager: can't add resource %s"
734 "to hash (by pointer)", ar->name);
739 resource_register_by_id(backend, ar);
741 set_resource_source_and_sink(ar->res, ar->source, ar->sink);
744 static void resource_destroy(mrp_resmgr_backend_t *backend,
748 mrp_resmgr_usecase_t *usecase;
749 mrp_resmgr_resource_t *ar;
752 MRP_ASSERT(backend && backend->resmgr && zone && res,"invalid argument");
754 if (!(hash = backend->resources.by_pointer) ||
755 !(ar = mrp_htbl_remove(hash, res, false)))
757 mrp_debug("failed to destroy audio resource: can't find it");
761 mrp_debug("%s resource '%s' going to be destroyed",
762 ar->type->name, ar->name);
764 if (ar->connid > 0 && (hash = backend->resources.by_connid)) {
765 if (ar != mrp_htbl_remove(hash, NULL + ar->connid, false)) {
766 mrp_log_error("gam-resource-manager: confused with data "
767 "structures when attempting to remove "
768 "resource '%s' from ID hash", ar->name);
772 mrp_list_delete(&ar->source_link);
774 mrp_free((void *)ar->name);
778 usecase = mrp_resmgr_get_usecase(backend->resmgr);
779 mrp_resmgr_usecase_update(usecase);
782 static bool resource_acquire(mrp_resmgr_backend_t *backend,
786 static int32_t stamp;
788 mrp_resmgr_resource_t *ar;
790 MRP_ASSERT(backend && zone && res, "invalid argument");
792 if (!(ar = resource_lookup_by_pointer(backend, res))) {
793 mrp_debug("failed to acquire audio resource: can't find it");
797 if (!set_resource_stamp(ar->res, ++stamp)) {
798 mrp_log_error("gam-resource-manager: failed to set 'stamp' "
799 "property for '%s' when acquiring", ar->name);
807 static bool resource_release(mrp_resmgr_backend_t *backend,
811 mrp_resmgr_resource_t *ar;
813 MRP_ASSERT(backend && zone && res, "invalid argument");
815 if (!(ar = resource_lookup_by_pointer(backend, res))) {
816 mrp_debug("failed to release audio resource: can't find it");
820 if (!set_resource_stamp(ar->res, 0)) {
821 mrp_log_error("gam-resource-manager: failed to set 'stamp' "
822 "property for '%s' when releasing", ar->name);
830 static bool resource_register_by_id(mrp_resmgr_backend_t *backend,
831 mrp_resmgr_resource_t *ar)
836 if (!mrp_htbl_insert(backend->resources.by_connid, NULL + ar->connid, ar)) {
837 mrp_log_error("gam-resource-manager: can't add resource '%s'"
838 "to hash (by connid)", ar->name);
842 if (!mrp_resmgr_source_add_resource(ar->source, &ar->source_link)) {
843 mrp_log_error("gam-resource-manager: can't add resource '%s'"
844 "to source", ar->name);
851 static mrp_resmgr_resource_t *resource_lookup_by_pointer(mrp_resmgr_backend_t *backend,
856 if (!backend || !(htbl = backend->resources.by_pointer) || !res)
859 return mrp_htbl_lookup(htbl, res);
862 static size_t resource_print_name(mrp_resmgr_source_t *src,
870 ret = snprintf(name, len, "<invalid>");
872 ret = snprintf(name, len, "%s", mrp_resmgr_source_get_name(src));
874 ret = snprintf(name, len, "%s%d", mrp_resmgr_source_get_name(src),
882 static int decision_cb(void *key, void *object, void *user_data)
884 mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)user_data;
885 mrp_resmgr_resource_t *ar = (mrp_resmgr_resource_t *)object;
886 mrp_resmgr_t *resmgr;
887 mrp_resmgr_usecase_t *usecase;
888 bool sink_available, source_available;
889 int32_t decision_new, state_new;
890 mrp_attr_t attrs[ATTR_MAX+1];
891 uint16_t src_id, sink_id;
893 mrp_resmgr_source_t *src;
898 MRP_UNUSED(user_data);
900 MRP_ASSERT(ar && ar->backend == backend, "confused with data structures");
902 if (!ar->sink || !ar->source || !ar->connno) {
903 memset(attrs, 0, sizeof(attrs));
906 if (mrp_resource_read_all_attributes(ar->res, ATTR_MAX+1, attrs)) {
907 src_id = attrs[SRCID_ATTRIDX].value.integer;
908 sink_id = attrs[SINKID_ATTRIDX].value.integer;
909 connid = attrs[CONNID_ATTRIDX].value.integer;
911 if (!ar->source && src_id > 0) {
912 src = mrp_resmgr_source_find_by_id(backend->resmgr, src_id);
914 if (src && mrp_resmgr_source_add_resource(src,&ar->source_link)) {
915 resource_print_name(src, ar->connno, buf, sizeof(buf));
916 mrp_free((void *)ar->name);
918 ar->name = mrp_strdup(buf);
921 mrp_debug("update resource %s source to '%s'",
922 ar->name, mrp_resmgr_source_get_name(src));
928 if (!ar->sink && sink_id > 0) {
929 ar->sink = mrp_resmgr_sink_find_by_gam_id(backend->resmgr,
931 mrp_debug("update resource %s sink to '%s'",
932 ar->name, mrp_resmgr_sink_get_name(ar->sink));
937 if (!ar->connid && connid > 0) {
939 mrp_debug("update resource %s connid to %u",
946 resmgr = backend->resmgr;
948 if ((usecase = mrp_resmgr_get_usecase(resmgr)))
949 mrp_resmgr_usecase_update(usecase);
954 source_available = mrp_resmgr_source_get_availability(ar->source);
955 sink_available = mrp_resmgr_sink_get_availability(ar->sink);
957 if (!source_available || !sink_available)
958 decision_new = DECISION_DISCONNECTED; /* or teardown ? */
959 else if (ar->connno != 0 || ar->connid < 1)
960 decision_new = DECISION_DISCONNECTED;
962 decision_new = mrp_resmgr_source_make_decision(ar->source);
964 if (decision_new < 0 || decision_new >= DECISION_MAX)
965 decision_new = ar->decision.current;
967 if (decision_new < 0 || decision_new >= DECISION_MAX)
970 state_new = decision2state[decision_new];
972 ar->decision.new = decision_new;
973 ar->state.new = state_new;
975 print_decision(ar, buf, sizeof(buf));
976 mrp_debug(" %s", buf);
978 return MRP_HTBL_ITER_MORE;
981 static void make_decisions(mrp_resmgr_backend_t *backend)
983 mrp_resmgr_usecase_t *usecase;
985 usecase = mrp_resmgr_get_usecase(backend->resmgr);
986 mrp_resmgr_usecase_update(usecase);
988 mrp_htbl_foreach(backend->resources.by_pointer, decision_cb, backend);
991 static int commit_cb(void *key, void *object, void *user_data)
993 mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)user_data;
994 mrp_resmgr_resource_t *ar = (mrp_resmgr_resource_t *)object;
998 MRP_UNUSED(user_data);
1000 MRP_ASSERT(ar && ar->backend == backend, "confused with data structures");
1003 print_commit(ar, buf, sizeof(buf));
1004 mrp_debug(" %s", buf);
1006 ar->decision.current = ar->decision.new;
1007 ar->state.current = ar->state.new;
1009 set_resource_decision(ar->res, ar->decision.current);
1012 return MRP_HTBL_ITER_MORE;
1015 static void commit_decisions(mrp_resmgr_backend_t *backend)
1017 mrp_resmgr_usecase_t *usecase;
1019 mrp_htbl_foreach(backend->resources.by_pointer, commit_cb, backend);
1021 usecase = mrp_resmgr_get_usecase(backend->resmgr);
1022 mrp_resmgr_usecase_update(usecase);
1026 static size_t print_decision(mrp_resmgr_resource_t *ar, char *buf, size_t len)
1032 snprintf(name, sizeof(name), "%s:", ar->name);
1034 if (ar->decision.new == ar->decision.current) {
1035 snprintf(decision, sizeof(decision), "%s (no change)",
1036 decision_names[ar->decision.new]);
1039 snprintf(decision, sizeof(decision), "%s => %s",
1040 decision_names[ar->decision.current],
1041 decision_names[ar->decision.new]);
1044 if (ar->state.new == ar->state.current)
1047 snprintf(state, sizeof(state), "%s => %s",
1048 state_names[ar->state.current],
1049 state_names[ar->state.new]);
1052 return snprintf(buf, len, "%-24s %-28s %s", name, decision, state);
1056 static size_t print_commit(mrp_resmgr_resource_t *ar, char *buf, size_t len)
1058 const char *decision;
1062 snprintf(name, sizeof(name), "%s:", ar->name);
1064 decision = decision_names[ar->decision.new];
1065 state = state_names[ar->state.new];
1067 return snprintf(buf, len, "%-24s %-12s %s", name, decision, state);
1071 static void backend_notify(mrp_resource_event_t event,
1073 mrp_application_class_t *ac,
1074 mrp_resource_t *res,
1077 mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
1078 const char *zonename = mrp_zone_get_name(zone);
1080 MRP_ASSERT(zone && ac && res && backend, "invalid argument");
1084 case MRP_RESOURCE_EVENT_CREATED:
1085 mrp_debug("audio resource in zone '%s' created", zonename);
1086 resource_create(backend, ac, zone, res);
1089 case MRP_RESOURCE_EVENT_DESTROYED:
1090 mrp_debug("audio resource in zone '%s' destroyed", zonename);
1091 resource_destroy(backend, zone, res);
1094 case MRP_RESOURCE_EVENT_ACQUIRE:
1095 mrp_debug("audio resource in zone '%s' is acquiring", zonename);
1096 resource_acquire(backend, zone, res);
1099 case MRP_RESOURCE_EVENT_RELEASE:
1100 mrp_debug("audio resource in zone '%s' is released", zonename);
1101 resource_release(backend, zone, res);
1105 mrp_log_error("gam-resource-manager: invalid event %d at audio "
1106 "notification (zone '%s')", event, zonename);
1111 static void backend_init(mrp_zone_t *zone, void *userdata)
1113 mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
1115 const char *zonename;
1117 MRP_ASSERT(zone && backend && backend->resmgr, "invalid argument");
1119 // zoneid = mrp_zone_get_id(zone);
1120 zonename = mrp_zone_get_name(zone);
1123 zonename = "<unknown>";
1125 mrp_debug("audio init in zone '%s'", zonename);
1127 make_decisions(backend);
1130 static bool backend_allocate(mrp_zone_t *zone,
1131 mrp_resource_t *res,
1134 mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
1136 const char *zonename;
1137 mrp_resmgr_resource_t *ar;
1140 MRP_ASSERT(zone && res && backend && backend->resmgr, "invalid argument");
1142 // zoneid = mrp_zone_get_id(zone);
1144 if (!(zonename = mrp_zone_get_name(zone)))
1145 zonename = "<unknown>";
1147 if ((ar = resource_lookup_by_pointer(backend, res))) {
1148 allocated = (ar->state.new == STATE_PLAY);
1150 mrp_debug("%s allocation for '%s' in zone '%s' %s",
1151 ar->type->name, ar->name, zonename,
1152 allocated ? "succeeded":"failed");
1157 mrp_log_error("gam-resource-manager: attempt to allocate untracked "
1158 "resource in zone '%s'", zonename);
1163 static void backend_free(mrp_zone_t *zone, mrp_resource_t *res, void *userdata)
1165 mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
1166 const char *zonename;
1167 mrp_resmgr_resource_t *ar;
1169 MRP_ASSERT(zone && res && backend, "invalid argument");
1171 if (!(zonename = mrp_zone_get_name(zone)))
1172 zonename = "<unknown>";
1174 if ((ar = resource_lookup_by_pointer(backend, res))) {
1175 ar->decision.new = DECISION_DISCONNECTED;
1176 ar->state.new = decision2state[ar->decision.new];
1178 mrp_debug("free %s of '%s' in zone '%s'",
1179 ar->type->name, ar->name, zonename);
1184 mrp_log_error("gam-resource-manager: attempt to free untracked "
1185 "resource in zone '%s'", zonename);
1188 static bool backend_advice(mrp_zone_t *zone,mrp_resource_t *res,void *userdata)
1193 MRP_UNUSED(userdata);
1195 mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
1196 const char *zonename;
1199 MRP_ASSERT(zone && res && backend, "invalid argument");
1201 if (!(zonename = mrp_zone_get_name(zone)))
1202 zonename = "<unknown>";
1203 if (!(appid = get_resource_appid(res)))
1204 appid = "<unknown>";
1206 mrp_debug("audio advice for '%s' in zone '%s'", appid, zonename);
1212 static void backend_commit(mrp_zone_t *zone, void *userdata)
1214 mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
1215 const char *zonename;
1218 MRP_ASSERT(zone && backend && backend->resmgr, "invalid argument");
1220 // zoneid = mrp_zone_get_id(zone);
1222 if (!(zonename = mrp_zone_get_name(zone)))
1223 zonename = "<unknown>";
1225 mrp_debug("audio commit in zone '%s'", zonename);
1227 commit_decisions(backend);