2 * Copyright (c) 2012, 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>
47 #define RESOURCE_NAME "audio_playback"
48 #define ACTIVE_SCREEN_TABLE "active_screen"
50 #define ACTIVE_SCREEN_MAX 32
52 #define BIT(i) ((uint32_t)1 << (i))
53 #define MASK(w) (((uint32_t)1 << (w)) - 1)
55 #define PRIORITY_BITS 8
56 #define CATEGORY_BITS 8
57 #define ZORDER_BITS 16
59 #define PRIORITY_POSITION 0
60 #define CATEGORY_POSITION (PRIORITY_POSITION + PRIORITY_BITS)
61 #define ZORDER_POSITION (CATEGORY_POSITION + CATEGORY_BITS)
63 #define PRIORITY_MASK MASK(PRIORITY_BITS)
64 #define CATEGORY_MASK MASK(CATEGORY_BITS)
65 #define ZORDER_MASK MASK(ZORDER_BITS)
68 #define ACQUIRE_BITS 1
71 #define STAMP_POSITION 0
72 #define ACQUIRE_POSITION (STAMP_POSITION + STAMP_BITS)
73 #define SHARE_POSITION (ACQUIRE_POSITION + ACQUIRE_BITS)
75 #define STAMP_MASK MASK(STAMP_BITS)
76 #define ACQUIRE_MASK MASK(ACQUIRE_BITS)
77 #define SHARE_MASK MASK(SHARE_BITS)
80 #define ATTRIBUTE(n,t,v) {n, MRP_RESOURCE_RW, mqi_##t, {.t=v}}
81 #define ATTR_END {NULL, 0, 0, {.string=NULL}}
83 typedef struct audio_resource_s audio_resource_t;
84 typedef struct active_screen_s active_screen_t;
86 struct active_screen_s {
90 struct mrp_resmgr_audio_s {
91 mrp_resmgr_data_t *data;
93 mrp_list_hook_t classes[MRP_ZONE_MAX];
94 int nactive[MRP_ZONE_MAX];
95 active_screen_t actives[MRP_ZONE_MAX][ACTIVE_SCREEN_MAX];
97 uint32_t grantids[MRP_ZONE_MAX];
100 struct audio_resource_s {
101 mrp_list_hook_t link;
103 mrp_resmgr_audio_t *audio;
104 mrp_resmgr_class_t *class;
111 static audio_resource_t *audio_resource_create(mrp_resmgr_audio_t *,
112 mrp_zone_t *,mrp_resource_t *,
113 mrp_application_class_t *);
114 static void audio_resource_destroy(mrp_resmgr_audio_t *, mrp_zone_t *,
116 static audio_resource_t *audio_resource_lookup(mrp_resmgr_audio_t *,
118 static void audio_update_resources(mrp_resmgr_audio_t *, mrp_zone_t *);
119 static void audio_grant_resources(mrp_resmgr_audio_t *, mrp_zone_t *);
121 static void resource_class_move_resource(mrp_resmgr_class_t *,
123 static uint32_t resource_key(audio_resource_t *);
124 static bool resource_is_active(mrp_resmgr_audio_t *, uint32_t,
126 static void resource_fix_appid(mrp_resmgr_audio_t *, mrp_resource_t *);
128 static void get_active_screens(mrp_resmgr_audio_t *, mrp_zone_t *);
130 static void audio_notify(mrp_resource_event_t, mrp_zone_t *,
131 mrp_application_class_t *, mrp_resource_t *, void *);
132 static void audio_init(mrp_zone_t *, void *);
133 static bool audio_allocate(mrp_zone_t *, mrp_resource_t *, void *);
134 static void audio_free(mrp_zone_t *, mrp_resource_t *, void *);
135 static bool audio_advice(mrp_zone_t *, mrp_resource_t *, void *);
136 static void audio_commit(mrp_zone_t *, void *);
139 #define PRIORITY_ATTRIDX 0
140 #define CATEGORY_ATTRIDX 1
141 #define APPID_ATTRIDX 2
142 #define ROLE_ATTRIDX 3
143 #define PID_ATTRIDX 4
144 #define POLICY_ATTRIDX 5
146 static mrp_attr_def_t audio_attrs[] = {
147 ATTRIBUTE("priority" , integer, 0 ),
148 ATTRIBUTE("cathegory", integer, 0 ),
149 ATTRIBUTE("appid" , string , "<undefined>"),
150 ATTRIBUTE("role" , string , "music" ),
151 ATTRIBUTE("pid" , string , "<unknown>" ),
152 ATTRIBUTE("policy" , string , "relaxed" ),
157 static mrp_resource_mgr_ftbl_t audio_ftbl = {
167 static uint32_t request_stamp;
170 mrp_resmgr_audio_t *mrp_resmgr_audio_create(mrp_resmgr_data_t *data)
172 mrp_resmgr_audio_t *audio;
176 if ((audio = mrp_allocz(sizeof(*audio)))) {
177 resid = mrp_resource_definition_create(RESOURCE_NAME,true,audio_attrs,
179 mrp_lua_resclass_create_from_c(resid);
182 audio->resid = resid;
183 audio->dbtbl = MQI_HANDLE_INVALID;
185 for (i = 0; i < MRP_ZONE_MAX; i++)
186 mrp_list_init(audio->classes + i);
190 mrp_resmgr_register_dependency(data, ACTIVE_SCREEN_TABLE);
197 void mrp_resmgr_audio_destroy(mrp_resmgr_audio_t *audio)
205 int mrp_resmgr_audio_print(mrp_resmgr_audio_t *audio,
211 p += snprintf(p, e-p, __VA_ARGS__); \
217 mrp_list_hook_t *classes, *centry, *cn;
218 mrp_list_hook_t *resources, *rentry, *rn;
219 mrp_resmgr_class_t *class;
220 audio_resource_t *ar;
221 const char *class_name;
225 MRP_ASSERT(audio && buf && len > 0, "invalid argument");
228 classes = audio->classes + zoneid;
230 PRINT(" Resource 'audio' - grantid:%u\n", audio->grantids[zoneid]);
232 if (mrp_list_empty(classes))
233 PRINT(" No resources\n");
235 mrp_list_foreach_back(classes, centry, cn) {
236 class = mrp_list_entry(centry, mrp_resmgr_class_t, link);
237 class_name = mrp_application_class_get_name(class->class);
238 resources = &class->resources;
240 PRINT(" Class '%s':\n", class_name);
242 mrp_list_foreach_back(resources, rentry, rn) {
243 ar = mrp_list_entry(rentry, audio_resource_t, link);
245 PRINT(" 0x%08x %s %u",
246 ar->key, ar->acquire ? "acquire":"release", ar->grantid);
248 for (i = 0; i < (int)MRP_ARRAY_SIZE(audio_attrs) - 1; i++) {
249 if ((mrp_resource_read_attribute(ar->res, i, &a))) {
250 PRINT(" %s:", a.name);
253 case mqi_string: PRINT("'%s'",a.value.string); break;
254 case mqi_integer: PRINT("%d",a.value.integer); break;
255 case mqi_unsignd: PRINT("%u",a.value.unsignd); break;
256 case mqi_floating: PRINT("%lf",a.value.floating);break;
257 default: PRINT("<unsupported type>"); break;
272 static audio_resource_t *audio_resource_create(mrp_resmgr_audio_t *audio,
275 mrp_application_class_t *ac)
277 mrp_resmgr_data_t *data;
279 mrp_list_hook_t *classes;
280 mrp_resmgr_class_t *rc;
281 audio_resource_t *ar;
283 MRP_ASSERT(audio && zone && res && ac, "invalid argument");
284 MRP_ASSERT(audio->data, "confused with data structures");
288 zone_id = mrp_zone_get_id(zone);
289 classes = audio->classes + zone_id;
291 if (!(rc = mrp_resmgr_class_find(classes, ac)) &&
292 !(rc = mrp_resmgr_class_create(classes, ac)) )
294 mrp_log_error("ivi-resource-manager: can't obtain resmgr class");
297 resource_fix_appid(audio, res);
299 if ((ar = mrp_allocz(sizeof(*ar)))) {
300 mrp_list_init(&ar->link);
304 ar->key = resource_key(ar);
306 resource_class_move_resource(rc, ar);
308 mrp_resmgr_insert_resource(data, zone, res, ar);
316 static void audio_resource_destroy(mrp_resmgr_audio_t *audio,
320 audio_resource_t *ar;
322 MRP_ASSERT(res && audio, "invalid argument");
323 MRP_ASSERT(audio->data, "confused with data structures");
325 if ((ar = mrp_resmgr_remove_resource(audio->data, zone, res))) {
326 mrp_list_delete(&ar->link);
332 static audio_resource_t *audio_resource_lookup(mrp_resmgr_audio_t *audio,
335 audio_resource_t *ar;
337 MRP_ASSERT(res && audio, "invalid argument");
338 MRP_ASSERT(audio->data, "confused with data structures");
340 ar = mrp_resmgr_lookup_resource(audio->data, res);
345 static void audio_update_resources(mrp_resmgr_audio_t *audio,
349 mrp_list_hook_t *classes, *centry, *cn;
350 mrp_list_hook_t *resources, *rentry, *rn;
351 mrp_resmgr_class_t *class;
352 const char *class_name;
353 audio_resource_t *ar, *ars[4096];
358 zoneid = mrp_zone_get_id(zone);
359 classes = audio->classes + zoneid;
361 mrp_list_foreach_back(classes, centry, cn) {
362 class = mrp_list_entry(centry, mrp_resmgr_class_t, link);
363 class_name = mrp_application_class_get_name(class->class);
364 resources = &class->resources;
366 if (!strcmp(class_name, "player") || !strcmp(class_name, "base")) {
369 mrp_list_foreach_back(resources, rentry, rn) {
370 ar = mrp_list_entry(rentry, audio_resource_t, link);
372 if (resource_is_active(audio, zoneid, ar)) {
373 ar->key |= (ZORDER_MASK << ZORDER_POSITION);
374 if (nar >= (int)MRP_ARRAY_SIZE(ars)) {
375 mrp_log_error("ivi-resource-manager: "
376 "too many active audios");
379 mrp_list_delete(&ar->link);
383 zorder = (ar->key >> ZORDER_POSITION) & ZORDER_MASK;
384 zorder -= (zorder > 0) ? 1 : 0;
386 ar->key &= ~(ZORDER_MASK << ZORDER_POSITION);
387 ar->key |= (zorder << ZORDER_POSITION);
389 } /* foreach resource */
391 for (i = 0; i < nar; i++)
392 resource_class_move_resource(class, ars[i]);
393 } /* if class is 'player' or 'base' */
395 } /* foreach class */
398 static void audio_grant_resources(mrp_resmgr_audio_t *audio,
403 mrp_list_hook_t *classes, *centry, *cn;
404 mrp_list_hook_t *resources, *rentry, *rn;
405 mrp_resmgr_class_t *class;
406 const char *class_name;
408 audio_resource_t *ar;
410 zoneid = mrp_zone_get_id(zone);
411 classes = audio->classes + zoneid;
412 grantid = ++audio->grantids[zoneid];
414 mrp_list_foreach_back(classes, centry, cn) {
415 class = mrp_list_entry(centry, mrp_resmgr_class_t, link);
416 class_name = mrp_application_class_get_name(class->class);
417 resources = &class->resources;
418 base_class = !strcmp(class_name, "player") ||
419 !strcmp(class_name, "base");
421 if (!base_class || audio->nactive[zoneid]) {
422 mrp_list_foreach_back(resources, rentry, rn) {
423 ar = mrp_list_entry(rentry, audio_resource_t, link);
428 if (base_class && !resource_is_active(audio,zoneid,ar))
431 ar->grantid = grantid;
433 if (!mrp_resource_is_shared(ar->res))
440 static void resource_class_move_resource(mrp_resmgr_class_t *class,
441 audio_resource_t *resource)
443 mrp_list_hook_t *list, *entry, *n, *insert_before;
444 audio_resource_t *ar;
446 mrp_list_delete(&resource->link);
448 list = insert_before = &class->resources;
450 mrp_list_foreach_back(list, entry, n) {
451 ar = mrp_list_entry(entry, audio_resource_t, link);
453 if (resource->key >= ar->key)
456 insert_before = entry;
459 mrp_list_append(insert_before, &resource->link);
463 static uint32_t resource_key(audio_resource_t *ar)
465 mrp_resmgr_class_t *class;
466 const char *class_name;
477 if (!(class = ar->class))
480 class_name = mrp_application_class_get_name(class->class);
481 base_class = !strcmp(class_name, "player") ||
482 !strcmp(class_name, "base");
485 if (!(res = ar->res))
489 if (!mrp_resource_read_attribute(res, PRIORITY_ATTRIDX, &a))
491 if (a.type != mqi_integer || a.value.integer < 0)
494 priority = (a.value.integer & PRIORITY_MASK) << PRIORITY_POSITION;
496 if (!mrp_resource_read_attribute(res, CATEGORY_ATTRIDX, &a))
498 if (a.type != mqi_integer || a.value.integer < 0)
501 category = (a.value.integer & CATEGORY_MASK) << CATEGORY_POSITION;
503 key = (priority | category);
506 acquire = ar->acquire;
507 share = mrp_resource_is_shared(res);
509 key = (++request_stamp & STAMP_MASK);
510 key |= (acquire ? (ACQUIRE_BITS << ACQUIRE_POSITION) : 0);
511 key |= (share ? (SHARE_BITS << SHARE_POSITION) : 0);
519 static bool resource_is_active(mrp_resmgr_audio_t *audio,
521 audio_resource_t *ar)
528 if (mrp_resource_read_attribute(ar->res, APPID_ATTRIDX, &a)) {
529 appid = a.value.string;
531 for (i = 0, n = audio->nactive[zoneid]; i < n; i++) {
532 as = &audio->actives[zoneid][i];
534 if (!strcmp(appid, as->appid))
542 static void resource_fix_appid(mrp_resmgr_audio_t *audio, mrp_resource_t *res)
544 mrp_resmgr_data_t *data;
545 mrp_attr_t attr, attrs[2];
553 if (mrp_resource_read_attribute(res, PID_ATTRIDX, &attr)) {
554 if (attr.type == mqi_string) {
555 if (strcmp(attr.value.string, "<unknown>"))
556 pid = attr.value.string;
560 if (mrp_resource_read_attribute(res, APPID_ATTRIDX, &attr)) {
561 if (attr.type == mqi_string) {
562 if (strcmp(attr.value.string, "<undefined>"))
563 appid = attr.value.string;
568 appid = mrp_resmgr_appid_find_by_pid(mrp_resmgr_get_appid(data), pid);
571 memset(attrs, 0, sizeof(attrs));
572 attrs[0].name = audio_attrs[APPID_ATTRIDX].name;
573 attrs[0].type = mqi_string;
574 attrs[0].value.string = appid;
576 mrp_resource_write_attributes(res, attrs);
581 static void get_active_screens(mrp_resmgr_audio_t *audio, mrp_zone_t *zone)
583 static const char *zone_name;
585 MQI_COLUMN_SELECTION_LIST(columns,
586 MQI_COLUMN_SELECTOR( 1, active_screen_t, appid )
589 MQI_WHERE_CLAUSE(where,
590 MQI_EQUAL( MQI_COLUMN(0), MQI_STRING_VAR(zone_name) )
596 active_screen_t rows[MRP_ZONE_MAX * ACTIVE_SCREEN_MAX];
597 active_screen_t *as, *from, *to;
603 zone_id = mrp_zone_get_id(zone);
604 zone_name = mrp_zone_get_name(zone);
606 for (i = 0, n = audio->nactive[zone_id]; i < n; i++) {
607 as = &audio->actives[zone_id][i];
608 mrp_free((void *)as->appid);
612 audio->nactive[zone_id] = 0;
614 if (audio->dbtbl == MQI_HANDLE_INVALID) {
615 audio->dbtbl = mqi_get_table_handle(ACTIVE_SCREEN_TABLE);
617 if (audio->dbtbl == MQI_HANDLE_INVALID)
620 mrp_log_info("ivi-resource-manager: audio resource: "
621 "'active_screen' table found");
624 if ((size_t)mqi_get_table_size(audio->dbtbl) > MRP_ARRAY_SIZE(rows)) {
625 mrp_log_error("ivi-resource-manager: audio resource: "
626 "table size exceeds the max.");
630 if ((nrow = MQI_SELECT(columns, audio->dbtbl, where, rows)) < 0) {
631 mrp_log_error("ivi-resource-manager: audio resource: "
632 "DB select failed: %s", strerror(errno));
636 if (nrow > ACTIVE_SCREEN_MAX) {
637 mrp_log_error("ivi-resource-manager: audio resource: "
638 "DB select result is too large (%d). "
639 "Will be truncated to %d", nrow, ACTIVE_SCREEN_MAX);
640 nrow = ACTIVE_SCREEN_MAX;
643 for (i = 0; i < nrow; i++) {
645 to = &audio->actives[zone_id][i];
647 to->appid = mrp_strdup(from->appid);
650 audio->nactive[zone_id] = nrow;
654 static void audio_notify(mrp_resource_event_t event,
656 mrp_application_class_t *ac,
660 mrp_resmgr_audio_t *audio = (mrp_resmgr_audio_t *)userdata;
661 const char *zone_name = mrp_zone_get_name(zone);
662 audio_resource_t *ar;
664 MRP_ASSERT(zone && ac && res && audio, "invalid argument");
668 case MRP_RESOURCE_EVENT_CREATED:
669 mrp_log_info("audio resource in zone '%s' created", zone_name);
670 audio_resource_create(audio, zone, res, ac);
673 case MRP_RESOURCE_EVENT_DESTROYED:
674 mrp_log_info("audio resource in zone '%s' destroyed", zone_name);
675 audio_resource_destroy(audio, zone, res);
678 case MRP_RESOURCE_EVENT_ACQUIRE:
679 mrp_log_info("audio resource in zone '%s' is acquiring", zone_name);
680 if (!(ar = audio_resource_lookup(audio, res)))
681 goto no_audio_resource;
687 case MRP_RESOURCE_EVENT_RELEASE:
688 mrp_log_info("audio resource in zone '%s' is released", zone_name);
689 if (!(ar = audio_resource_lookup(audio, res)))
690 goto no_audio_resource;
697 mrp_log_error("ivi-resource-manager: can't find audio resource "
698 "in zone '%s'", zone_name);
702 mrp_log_error("ivi-resource-manager: invalid event %d at audio "
703 "notification (zone '%s')", event, zone_name);
708 static void audio_init(mrp_zone_t *zone, void *userdata)
710 mrp_resmgr_audio_t *audio = (mrp_resmgr_audio_t *)userdata;
711 const char *zone_name = mrp_zone_get_name(zone);
713 MRP_ASSERT(audio, "invalid argument");
715 mrp_log_info("audio init in zone '%s'", zone_name);
717 get_active_screens(audio, zone);
718 audio_update_resources(audio, zone);
720 audio_grant_resources(audio, zone);
723 static bool audio_allocate(mrp_zone_t *zone,
727 mrp_resmgr_audio_t *audio = (mrp_resmgr_audio_t *)userdata;
729 const char *zonenam = mrp_zone_get_name(zone);
730 audio_resource_t *ar;
733 MRP_ASSERT(res && audio, "invalid argument");
735 zoneid = mrp_zone_get_id(zone);
736 zonenam = mrp_zone_get_name(zone);
737 grantid = audio->grantids[zoneid];
739 mrp_log_info("audio allocate in zone '%s'", zonenam);
741 if ((ar = audio_resource_lookup(audio, res))) {
742 return (ar->grantid == grantid);
745 mrp_log_error("ivi-resource-manager: attempt to allocate "
746 "untracked resource");
752 static void audio_free(mrp_zone_t *zone, mrp_resource_t *res, void *userdata)
754 mrp_resmgr_audio_t *audio = (mrp_resmgr_audio_t *)userdata;
755 const char *zone_name = mrp_zone_get_name(zone);
759 MRP_ASSERT(audio, "invalid argument");
761 mrp_log_info("audio free in zone '%s'", zone_name);
764 static bool audio_advice(mrp_zone_t *zone,mrp_resource_t *res,void *userdata)
766 mrp_resmgr_audio_t *audio = (mrp_resmgr_audio_t *)userdata;
767 const char *zone_name = mrp_zone_get_name(zone);
771 MRP_ASSERT(audio, "invalid argument");
773 mrp_log_info("audio advice in zone '%s'", zone_name);
778 static void audio_commit(mrp_zone_t *zone, void *userdata)
780 mrp_resmgr_audio_t *audio = (mrp_resmgr_audio_t *)userdata;
781 const char *zone_name = mrp_zone_get_name(zone);
783 MRP_ASSERT(audio, "invalid argument");
785 mrp_log_info("audio commit in zone '%s'", zone_name);
792 * indent-tabs-mode: nil