6 #include <pulsecore/pulsecore-config.h>
7 #include <pulsecore/dbus-shared.h>
13 #define ADMIN_DBUS_MANAGER "org.freedesktop.DBus"
14 #define ADMIN_DBUS_PATH "/org/freedesktop/DBus"
15 #define ADMIN_DBUS_INTERFACE "org.freedesktop.DBus"
17 #define ADMIN_NAME_OWNER_CHANGED "NameOwnerChanged"
19 #define POLICY_DBUS_INTERFACE "org.tizen.policy"
20 #define POLICY_DBUS_MRPPATH "/org/tizen/policy"
21 #define POLICY_DBUS_MRPNAME "org.tizen.murphy"
23 #define AUDIOMGR_DBUS_INTERFACE "org.genivi.audiomanager"
24 #define AUDIOMGR_DBUS_PATH "/org/genivi/audiomanager"
25 #define AUDIOMGR_DBUS_ROUTE_NAME "RoutingInterface"
26 #define AUDIOMGR_DBUS_ROUTE_PATH "RoutingInterface"
28 #define PULSE_DBUS_INTERFACE "org.genivi.pulse"
29 #define PULSE_DBUS_PATH "/org/genivi/pulse"
30 #define PULSE_DBUS_NAME "org.genivi.pulse"
33 #define POLICY_DECISION "decision"
34 #define POLICY_STREAM_INFO "stream_info"
35 #define POLICY_ACTIONS "audio_actions"
36 #define POLICY_STATUS "status"
38 #define PROP_ROUTE_SINK_TARGET "policy.sink_route.target"
39 #define PROP_ROUTE_SINK_MODE "policy.sink_route.mode"
40 #define PROP_ROUTE_SINK_HWID "policy.sink_route.hwid"
41 #define PROP_ROUTE_SOURCE_TARGET "policy.source_route.target"
42 #define PROP_ROUTE_SOURCE_MODE "policy.source_route.mode"
43 #define PROP_ROUTE_SOURCE_HWID "policy.source_route.hwid"
46 #define STRUCT_OFFSET(s,m) ((char *)&(((s *)0)->m) - (char *)0)
48 typedef void (*pending_cb_t)(struct userdata *, const char *,
49 DBusMessage *, void *);
50 typedef pa_bool_t (*method_t)(struct userdata *, DBusMessage *);
54 PA_LLIST_FIELDS(struct pending);
57 DBusPendingCall *call;
62 struct pa_policy_dbusif {
63 pa_dbus_connection *conn;
64 char *ifnam; /* signal interface */
65 char *mrppath; /* murphy signal path */
66 char *mrpnam; /* murphy D-Bus name */
67 char *ampath; /* audio manager path */
68 char *amnam; /* audio manager name */
69 char *amrpath; /* audio manager routing path */
70 char *amrnam; /* audio manager routing name */
71 char *admmrule; /* match rule to catch murphy name changes */
72 char *admarule; /* match rule to catch audiomgr name change*/
73 char *actrule; /* match rule to catch action signals */
74 char *strrule; /* match rule to catch stream info signals */
75 int mregist; /* are we registered to murphy */
76 int amisup; /* is the audio manager up */
77 PA_LLIST_HEAD(struct pending, pendlist);
83 struct actdsc { /* action descriptor */
85 int (*parser)(struct userdata *u, DBusMessageIter *iter);
88 struct argdsc { /* argument descriptor for actions */
94 struct argrt { /* audio_route arguments */
101 struct argvol { /* volume_limit arguments */
106 struct argcork { /* audio_cork arguments */
116 struct argctx { /* context arguments */
121 static void pa_policy_free_dbusif(struct pa_policy_dbusif *,struct userdata *);
123 static pa_bool_t send_message_with_reply(struct userdata *,
124 DBusConnection *, DBusMessage *,
125 pending_cb_t, void *);
128 static DBusHandlerResult filter(DBusConnection *, DBusMessage *, void *);
130 static void handle_admin_message(struct userdata *, DBusMessage *);
132 static void handle_info_message(struct userdata *, DBusMessage *);
133 static void handle_action_message(struct userdata *, DBusMessage *);
136 static void murphy_registration_cb(struct userdata *, const char *,
137 DBusMessage *, void *);
138 static pa_bool_t register_to_murphy(struct userdata *);
140 static int signal_status(struct userdata *, uint32_t, uint32_t);
143 static DBusHandlerResult audiomgr_method_handler(DBusConnection *,
144 DBusMessage *, void *);
145 static void audiomgr_register_domain_cb(struct userdata *, const char *,
146 DBusMessage *, void *);
147 static pa_bool_t register_to_audiomgr(struct userdata *);
148 static pa_bool_t unregister_from_audiomgr(struct userdata *);
150 static void audiomgr_register_node_cb(struct userdata *, const char *,
151 DBusMessage *, void *);
152 static void audiomgr_unregister_node_cb(struct userdata *, const char *,
153 DBusMessage *, void *);
154 static pa_bool_t build_sound_properties(DBusMessageIter *,
155 struct am_nodereg_data *);
156 static pa_bool_t build_connection_formats(DBusMessageIter *,
157 struct am_nodereg_data *);
158 static pa_bool_t dbusif_connect(struct userdata *, DBusMessage *);
159 static pa_bool_t dbusif_disconnect(struct userdata *, DBusMessage *);
163 struct pa_policy_dbusif *pa_policy_dbusif_init(struct userdata *u,
164 const char *dbustype,
171 static const DBusObjectPathVTable vtable = {
172 .message_function = audiomgr_method_handler,
175 pa_module *m = u->module;
176 struct pa_policy_dbusif *dbusif = NULL;
178 DBusConnection *dbusconn;
191 if (!dbustype || !strcasecmp(dbustype, "session")) {
192 dbustype = "session";
193 type = DBUS_BUS_SESSION;
195 else if (!strcasecmp(dbustype, "system")) {
197 type = DBUS_BUS_SYSTEM;
200 pa_log("invalid dbus type '%s'", dbustype);
204 dbusif = pa_xnew0(struct pa_policy_dbusif, 1);
205 PA_LLIST_HEAD_INIT(struct pending, dbusif->pendlist);
207 dbus_error_init(&error);
208 dbusif->conn = pa_dbus_bus_get(m->core, type, &error);
210 if (dbusif->conn == NULL || dbus_error_is_set(&error)) {
211 pa_log("%s: failed to get %s Bus: %s: %s",
212 __FILE__, dbustype, error.name, error.message);
216 dbusconn = pa_dbus_connection_get(dbusif->conn);
218 flags = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;
219 result = dbus_bus_request_name(dbusconn, PULSE_DBUS_NAME, flags,&error);
221 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER &&
222 result != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER ) {
223 pa_log("%s: D-Bus name request failed: %s: %s",
224 __FILE__, error.name, error.message);
228 pa_log_info("%s: now owner of '%s' D-Bus name on %s bus",
229 __FILE__, PULSE_DBUS_NAME, dbustype);
231 if (!dbus_connection_add_filter(dbusconn, filter,u, NULL)) {
232 pa_log("%s: failed to add filter function", __FILE__);
237 ifnam = POLICY_DBUS_INTERFACE;
240 mrppath = POLICY_DBUS_MRPPATH;
243 mrpnam = POLICY_DBUS_MRPNAME;
245 if (ampath && *ampath) {
246 char *slash = ampath[strlen(ampath)-1] == '/' ? "" : "/";
247 snprintf(pathbuf, sizeof(pathbuf), "%s%s" AUDIOMGR_DBUS_ROUTE_PATH,
252 ampath = AUDIOMGR_DBUS_PATH;
253 amrpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_ROUTE_PATH;
256 if (amnam && *amnam){
257 char *dot = amnam[strlen(amnam)-1] == '.' ? "" : ".";
258 snprintf(nambuf, sizeof(nambuf), "%s%s" AUDIOMGR_DBUS_ROUTE_NAME,
263 amnam = AUDIOMGR_DBUS_INTERFACE;
264 amrnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_ROUTE_NAME;
268 snprintf(admmrule, sizeof(admmrule), "type='signal',sender='%s',path='%s',"
269 "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
270 ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
272 dbus_bus_add_match(dbusconn, admmrule, &error);
274 snprintf(admarule, sizeof(admarule), "type='signal',sender='%s',path='%s',"
275 "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
276 ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
278 dbus_bus_add_match(dbusconn, admarule, &error);
280 if (dbus_error_is_set(&error)) {
281 pa_log("%s: unable to subscribe name change signals on %s: %s: %s",
282 __FILE__, ADMIN_DBUS_INTERFACE, error.name, error.message);
286 snprintf(actrule, sizeof(actrule), "type='signal',interface='%s',"
287 "member='%s',path='%s/%s'", ifnam, POLICY_ACTIONS,
288 mrppath, POLICY_DECISION);
289 dbus_bus_add_match(dbusconn, actrule, &error);
291 if (dbus_error_is_set(&error)) {
292 pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
293 __FILE__, POLICY_ACTIONS, ifnam, error.name, error.message);
297 snprintf(strrule, sizeof(strrule), "type='signal',interface='%s',"
298 "member='%s',path='%s/%s'", ifnam, POLICY_STREAM_INFO,
299 mrppath, POLICY_DECISION);
300 dbus_bus_add_match(dbusconn, strrule, &error);
302 if (dbus_error_is_set(&error)) {
303 pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
304 __FILE__, POLICY_STREAM_INFO, ifnam, error.name, error.message);
308 pa_log_info("%s: subscribed policy signals on %s", __FILE__, ifnam);
310 dbus_connection_register_object_path(dbusconn, PULSE_DBUS_PATH, &vtable,u);
313 dbusif->ifnam = pa_xstrdup(ifnam);
314 dbusif->mrppath = pa_xstrdup(mrppath);
315 dbusif->mrpnam = pa_xstrdup(mrpnam);
316 dbusif->ampath = pa_xstrdup(ampath);
317 dbusif->amnam = pa_xstrdup(amnam);
318 dbusif->amrpath = pa_xstrdup(amrpath);
319 dbusif->amrnam = pa_xstrdup(amrnam);
320 dbusif->admmrule = pa_xstrdup(admmrule);
321 dbusif->admarule = pa_xstrdup(admarule);
322 dbusif->actrule = pa_xstrdup(actrule);
323 dbusif->strrule = pa_xstrdup(strrule);
325 u->dbusif = dbusif; /* Argh.. */
327 register_to_murphy(u);
328 register_to_audiomgr(u);
333 pa_policy_free_dbusif(dbusif, u);
334 dbus_error_free(&error);
338 static void pa_policy_free_dbusif(struct pa_policy_dbusif *dbusif,
341 DBusConnection *dbusconn;
342 struct pending *p, *n;
347 dbusconn = pa_dbus_connection_get(dbusif->conn);
349 PA_LLIST_FOREACH_SAFE(p,n, dbusif->pendlist) {
350 PA_LLIST_REMOVE(struct pending, dbusif->pendlist, p);
351 dbus_pending_call_set_notify(p->call, NULL,NULL, NULL);
352 dbus_pending_call_unref(p->call);
356 dbus_connection_remove_filter(dbusconn, filter,u);
359 dbus_bus_remove_match(dbusconn, dbusif->admmrule, NULL);
360 dbus_bus_remove_match(dbusconn, dbusif->admarule, NULL);
361 dbus_bus_remove_match(dbusconn, dbusif->actrule, NULL);
362 dbus_bus_remove_match(dbusconn, dbusif->strrule, NULL);
364 pa_dbus_connection_unref(dbusif->conn);
367 pa_xfree(dbusif->ifnam);
368 pa_xfree(dbusif->mrppath);
369 pa_xfree(dbusif->mrpnam);
370 pa_xfree(dbusif->ampath);
371 pa_xfree(dbusif->amnam);
372 pa_xfree(dbusif->amrpath);
373 pa_xfree(dbusif->amrnam);
374 pa_xfree(dbusif->admmrule);
375 pa_xfree(dbusif->admarule);
376 pa_xfree(dbusif->actrule);
377 pa_xfree(dbusif->strrule);
383 void pa_policy_dbusif_done(struct userdata *u)
385 if (u && u->dbusif) {
386 pa_policy_free_dbusif(u->dbusif, u);
392 static DBusHandlerResult filter(DBusConnection *conn, DBusMessage *msg,
395 struct userdata *u = arg;
397 if (dbus_message_is_signal(msg, ADMIN_DBUS_INTERFACE,
398 ADMIN_NAME_OWNER_CHANGED))
400 handle_admin_message(u, msg);
401 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
406 if (dbus_message_is_signal(msg, POLICY_DBUS_INTERFACE,POLICY_STREAM_INFO)){
407 handle_info_message(u, msg);
408 return DBUS_HANDLER_RESULT_HANDLED;
411 if (dbus_message_is_signal(msg, POLICY_DBUS_INTERFACE, POLICY_ACTIONS)) {
412 handle_action_message(u, msg);
413 return DBUS_HANDLER_RESULT_HANDLED;
417 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
421 static void handle_admin_message(struct userdata *u, DBusMessage *msg)
423 struct pa_policy_dbusif *dbusif;
430 pa_assert_se((dbusif = u->dbusif));
432 success = dbus_message_get_args(msg, NULL,
433 DBUS_TYPE_STRING, &name,
434 DBUS_TYPE_STRING, &before,
435 DBUS_TYPE_STRING, &after,
438 if (!success || !name) {
439 pa_log("Received malformed '%s' message", ADMIN_NAME_OWNER_CHANGED);
443 if (!strcmp(name, dbusif->mrpnam)) {
444 if (after && strcmp(after, "")) {
445 pa_log_debug("murphy is up");
447 if (!dbusif->mregist) {
448 register_to_murphy(u);
452 if (name && before && (!after || !strcmp(after, ""))) {
453 pa_log_info("murphy is gone");
458 if (!strcmp(name, dbusif->amnam)) {
459 if (after && strcmp(after, "")) {
460 pa_log_debug("audio manager is up");
462 if (!dbusif->amisup) {
463 register_to_audiomgr(u);
467 if (name && before && (!after || !strcmp(after, ""))) {
468 pa_log_info("audio manager is gone");
471 unregister_from_audiomgr(u);
479 static void reply_cb(DBusPendingCall *pend, void *data)
481 struct pending *pdata = (struct pending *)data;
483 struct pa_policy_dbusif *dbusif;
487 pa_assert(pdata->call == pend);
488 pa_assert_se((u = pdata->u));
489 pa_assert_se((dbusif = u->dbusif));
491 PA_LLIST_REMOVE(struct pending, dbusif->pendlist, pdata);
493 if ((reply = dbus_pending_call_steal_reply(pend)) == NULL) {
494 pa_log("%s: Murphy pending call '%s' failed: invalid argument",
495 __FILE__, pdata->method);
498 pdata->cb(u, pdata->method, reply, pdata->data);
499 dbus_message_unref(reply);
502 pa_xfree((void *)pdata->method);
503 pa_xfree((void *)pdata);
506 static pa_bool_t send_message_with_reply(struct userdata *u,
507 DBusConnection *conn,
512 struct pa_policy_dbusif *dbusif;
513 struct pending *pdata = NULL;
515 DBusPendingCall *pend;
521 pa_assert_se((dbusif = u->dbusif));
523 if ((method = dbus_message_get_member(msg)) == NULL)
526 pdata = pa_xnew0(struct pending, 1);
528 pdata->method = pa_xstrdup(method);
532 PA_LLIST_PREPEND(struct pending, dbusif->pendlist, pdata);
534 if (!dbus_connection_send_with_reply(conn, msg, &pend, -1)) {
535 pa_log("%s: Failed to %s", __FILE__, method);
541 if (!dbus_pending_call_set_notify(pend, reply_cb,pdata, NULL)) {
542 pa_log("%s: Can't set notification for %s", __FILE__, method);
551 PA_LLIST_REMOVE(struct pending, dbusif->pendlist, pdata);
552 pa_xfree((void *)pdata->method);
553 pa_xfree((void *)pdata);
559 /**************************************************************************
565 void pa_policy_dbusif_send_device_state(struct userdata *u, char *state,
566 char **types, int ntype)
568 static char *path = (char *)"/com/nokia/policy/info";
570 struct pa_policy_dbusif *dbusif = u->dbusif;
571 DBusConnection *conn = pa_dbus_connection_get(dbusif->conn);
578 if (!types || ntype < 1)
581 msg = dbus_message_new_signal(path, dbusif->ifnam, "info");
584 pa_log("%s: failed to make new info message", __FILE__);
588 dbus_message_iter_init_append(msg, &mit);
590 if (!dbus_message_iter_append_basic(&mit, DBUS_TYPE_STRING, &state) ||
591 !dbus_message_iter_open_container(&mit, DBUS_TYPE_ARRAY,"s", &dit)){
592 pa_log("%s: failed to build info message", __FILE__);
596 for (i = 0; i < ntype; i++) {
597 if (!dbus_message_iter_append_basic(&dit, DBUS_TYPE_STRING,&types[i])){
598 pa_log("%s: failed to build info message", __FILE__);
603 dbus_message_iter_close_container(&mit, &dit);
605 sts = dbus_connection_send(conn, msg, NULL);
608 pa_log("%s: Can't send info message: out of memory", __FILE__);
612 dbus_message_unref(msg); /* should cope with NULL msg */
615 void pa_policy_dbusif_send_media_status(struct userdata *u, const char *media,
616 const char *group, int active)
618 static char *path = (char *)"/com/nokia/policy/info";
619 static const char *type = "media";
621 struct pa_policy_dbusif *dbusif = u->dbusif;
622 DBusConnection *conn = pa_dbus_connection_get(dbusif->conn);
627 msg = dbus_message_new_signal(path, dbusif->ifnam, "info");
630 pa_log("%s: failed to make new info message", __FILE__);
632 state = active ? "active" : "inactive";
634 success = dbus_message_append_args(msg,
635 DBUS_TYPE_STRING, &type,
636 DBUS_TYPE_STRING, &media,
637 DBUS_TYPE_STRING, &group,
638 DBUS_TYPE_STRING, &state,
642 pa_log("%s: Can't build D-Bus info message", __FILE__);
644 if (!dbus_connection_send(conn, msg, NULL)) {
645 pa_log("%s: Can't send info message: out of memory", __FILE__);
649 dbus_message_unref(msg);
655 static void handle_info_message(struct userdata *u, DBusMessage *msg)
663 enum pa_classify_method method = pa_method_unknown;
667 success = dbus_message_get_args(msg, NULL,
668 DBUS_TYPE_UINT32, &txid,
669 DBUS_TYPE_STRING, &oper,
670 DBUS_TYPE_STRING, &group,
671 DBUS_TYPE_UINT32, &pid,
672 DBUS_TYPE_STRING, &arg,
673 DBUS_TYPE_STRING, &method_str,
674 DBUS_TYPE_STRING, &prop,
677 pa_log("%s: failed to parse info message", __FILE__);
682 method = pa_method_unknown;
684 switch (method_str[0]) {
686 if (!strcmp(method_str, "equals"))
687 method = pa_method_equals;
690 if (!strcmp(method_str, "startswith"))
691 method = pa_method_startswith;
694 if (!strcmp(method_str, "matches"))
695 method = pa_method_matches;
698 if (!strcmp(method_str, "true"))
699 method = pa_method_true;
702 method = pa_method_unknown;
708 method = pa_method_unknown;
709 else if (!strcmp(arg, "*"))
710 method = pa_method_true;
712 if (!strcmp(oper, "register")) {
714 if (pa_policy_group_find(u, group) == NULL) {
715 pa_log_debug("register client (%s|%u) failed: unknown group",
719 pa_log_debug("register client (%s|%u)", group, pid);
720 pa_classify_register_pid(u, (pid_t)pid, prop, method, arg, group);
724 else if (!strcmp(oper, "unregister")) {
725 pa_log_debug("unregister client (%s|%u)", group, pid);
726 pa_classify_unregister_pid(u, (pid_t)pid, prop, method, arg);
729 pa_log("%s: invalid operation: '%s'", __FILE__, oper);
733 static void handle_action_message(struct userdata *u, DBusMessage *msg)
735 static struct actdsc actions[] = {
737 { "com.nokia.policy.audio_route" , audio_route_parser },
738 { "com.nokia.policy.volume_limit", volume_limit_parser },
739 { "com.nokia.policy.audio_cork" , audio_cork_parser },
740 { "com.nokia.policy.audio_mute" , audio_mute_parser },
741 { "com.nokia.policy.context" , context_parser },
749 DBusMessageIter msgit;
750 DBusMessageIter arrit;
751 DBusMessageIter entit;
752 DBusMessageIter actit;
755 pa_log_debug("got policy actions");
757 dbus_message_iter_init(msg, &msgit);
759 if (dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_UINT32)
762 dbus_message_iter_get_basic(&msgit, (void *)&txid);
764 pa_log_debug("got actions (txid:%d)", txid);
766 if (!dbus_message_iter_next(&msgit) ||
767 dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_ARRAY) {
772 dbus_message_iter_recurse(&msgit, &arrit);
775 if (dbus_message_iter_get_arg_type(&arrit) != DBUS_TYPE_DICT_ENTRY) {
780 dbus_message_iter_recurse(&arrit, &entit);
783 if (dbus_message_iter_get_arg_type(&entit) != DBUS_TYPE_STRING) {
788 dbus_message_iter_get_basic(&entit, (void *)&actname);
790 if (!dbus_message_iter_next(&entit) ||
791 dbus_message_iter_get_arg_type(&entit) != DBUS_TYPE_ARRAY) {
796 dbus_message_iter_recurse(&entit, &actit);
798 if (dbus_message_iter_get_arg_type(&actit) != DBUS_TYPE_ARRAY) {
803 for (act = actions; act->name != NULL; act++) {
804 if (!strcmp(actname, act->name))
808 if (act->parser != NULL)
809 success &= act->parser(u, &actit);
811 } while (dbus_message_iter_next(&entit));
813 } while (dbus_message_iter_next(&arrit));
816 signal_status(u, txid, success);
820 static void murphy_registration_cb(struct userdata *u,
825 const char *error_descr;
830 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
831 success = dbus_message_get_args(reply, NULL,
832 DBUS_TYPE_STRING, &error_descr,
836 error_descr = dbus_message_get_error_name(reply);
838 pa_log_info("%s: registration to Murphy failed: %s",
839 __FILE__, error_descr);
842 pa_log_info("Murphy replied to registration");
845 u->dbusif->amisup = 1;
850 static pa_bool_t register_to_murphy(struct userdata *u)
852 static const char *name = "pulseaudio";
854 pa_policy_dbusif *dbusif = u->dbusif;
855 DBusConnection *conn = pa_dbus_connection_get(dbusif->conn);
857 const char *signals[4];
858 const char **v_ARRAY;
862 pa_log_info("%s: registering to murphy: name='%s' path='%s' if='%s'"
863 , __FILE__, dbusif->mrpnam, dbusif->mrppath, dbusif->ifnam);
865 msg = dbus_message_new_method_call(dbusif->mrpnam, dbusif->mrppath,
866 dbusif->ifnam, "register");
869 pa_log("%s: Failed to create D-Bus message to register", __FILE__);
874 signals[i=0] = POLICY_ACTIONS;
877 success = dbus_message_append_args(msg,
878 DBUS_TYPE_STRING, &name,
880 DBUS_TYPE_STRING, &v_ARRAY, i+1,
883 pa_log("%s: Failed to build D-Bus message to register", __FILE__);
887 if (!send_message_with_reply(u, conn, msg, murphy_registration_cb, NULL)) {
888 pa_log("%s: Failed to register", __FILE__);
893 dbus_message_unref(msg);
899 static int signal_status(struct userdata *u, uint32_t txid, uint32_t status)
901 struct pa_policy_dbusif *dbusif = u->dbusif;
902 DBusConnection *conn = pa_dbus_connection_get(dbusif->conn);
909 /* When transaction ID is 0, the policy manager does not expect
912 pa_log_debug("Not sending status message since transaction ID is 0");
916 snprintf(path, sizeof(path), "%s/%s", dbusif->mrppath, POLICY_DECISION);
918 pa_log_debug("sending signal to: path='%s', if='%s' member='%s' "
919 "content: txid=%d status=%d", path, dbusif->ifnam,
920 POLICY_STATUS, txid, status);
922 msg = dbus_message_new_signal(path, dbusif->ifnam, POLICY_STATUS);
925 pa_log("%s: failed to make new status message", __FILE__);
929 ret = dbus_message_append_args(msg,
930 DBUS_TYPE_UINT32, &txid,
931 DBUS_TYPE_UINT32, &status,
935 pa_log("%s: Can't build D-Bus status message", __FILE__);
939 ret = dbus_connection_send(conn, msg, NULL);
942 pa_log("%s: Can't send status message: out of memory", __FILE__);
946 dbus_message_unref(msg);
951 dbus_message_unref(msg); /* should cope with NULL msg */
957 /**************************************************************************
959 * Audio Manager interfaces
962 static DBusHandlerResult audiomgr_method_handler(DBusConnection *conn,
971 static struct dispatch dispatch_tbl[] = {
972 { AUDIOMGR_CONNECT , dbusif_connect },
973 { AUDIOMGR_DISCONNECT, dbusif_disconnect },
977 struct userdata *u = (struct userdata *)arg;
990 if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
992 name = dbus_message_get_member(msg);
993 // serial = dbus_message_get_serial(msg);
997 for (method = NULL, d = dispatch_tbl; d->name; d++) {
998 if (!strcmp(name, d->name)) {
1004 errcod = method ? E_OK : E_NOT_POSSIBLE;
1005 reply = dbus_message_new_method_return(msg);
1007 // dbus_message_set_reply_serial(reply, serial);
1009 success = dbus_message_append_args(reply,
1010 DBUS_TYPE_INT16, &errcod,
1013 if (!success || !dbus_connection_send(conn, reply, NULL))
1014 pa_log("%s: failed to reply '%s'", __FILE__, name);
1016 pa_log_debug("'%s' replied (%d)", name, errcod);
1018 dbus_message_unref(reply);
1023 pa_log_info("%s: unsupported '%s' method ignored", __FILE__, name);
1025 return DBUS_HANDLER_RESULT_HANDLED;
1028 pa_log_debug("got some unexpected type of D-Bus message");
1030 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1034 static pa_bool_t register_to_audiomgr(struct userdata *u)
1036 pa_audiomgr_register_domain(u);
1040 static pa_bool_t unregister_from_audiomgr(struct userdata *u)
1042 pa_audiomgr_unregister_domain(u, FALSE);
1046 static void audiomgr_register_domain_cb(struct userdata *u,
1051 const char *error_descr;
1052 dbus_uint16_t domain_id;
1053 dbus_uint16_t status;
1056 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1057 success = dbus_message_get_args(reply, NULL,
1058 DBUS_TYPE_STRING, &error_descr,
1062 error_descr = dbus_message_get_error_name(reply);
1064 pa_log_info("%s: AudioManager domain registration failed: %s",
1065 __FILE__, error_descr);
1068 success = dbus_message_get_args(reply, NULL,
1069 DBUS_TYPE_UINT16, &domain_id,
1070 DBUS_TYPE_UINT16, &status,
1074 pa_log("got broken message from AudioManager.Registration failed");
1077 pa_log_info("AudioManager replied to registration: "
1078 "domainID %u, status %u", domain_id, status);
1081 u->dbusif->amisup = 1;
1082 pa_audiomgr_domain_registered(u, domain_id, status, data);
1090 pa_bool_t pa_policy_dbusif_register_domain(struct userdata *u,
1091 am_domainreg_data *dr)
1093 pa_policy_dbusif *dbusif;
1094 DBusConnection *conn;
1096 const char *dbus_name;
1097 const char *dbus_path;
1098 const char *dbus_if;
1103 pa_assert_se((dbusif = u->dbusif));
1104 pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1106 pa_log_info("%s: registering to AudioManager: name='%s' path='%s' if='%s'"
1107 , __FILE__, dbusif->amnam, dbusif->amrpath, dbusif->amrnam);
1109 msg = dbus_message_new_method_call(dbusif->amnam,
1112 AUDIOMGR_REGISTER_DOMAIN);
1114 pa_log("%s: Failed to create D-Bus message to '%s'",
1115 __FILE__, AUDIOMGR_REGISTER_DOMAIN);
1120 dbus_name = PULSE_DBUS_NAME;
1121 dbus_path = PULSE_DBUS_PATH;
1122 dbus_if = PULSE_DBUS_INTERFACE;
1124 success = dbus_message_append_args(msg,
1125 DBUS_TYPE_UINT16, &dr->domain_id,
1126 DBUS_TYPE_STRING, &dr->name,
1127 DBUS_TYPE_STRING, &dr->node_name,
1128 DBUS_TYPE_STRING, &dr->bus_name,
1129 DBUS_TYPE_BOOLEAN, &dr->early,
1130 DBUS_TYPE_BOOLEAN, &dr->complete,
1131 DBUS_TYPE_UINT16 , &dr->state,
1132 DBUS_TYPE_STRING , &dbus_name,
1133 DBUS_TYPE_STRING , &dbus_path,
1134 DBUS_TYPE_STRING , &dbus_if,
1137 pa_log("%s: Failed to build D-Bus message to register", __FILE__);
1141 success = send_message_with_reply(u, conn, msg,
1142 audiomgr_register_domain_cb, dr);
1144 pa_log("%s: Failed to register", __FILE__);
1149 dbus_message_unref(msg);
1153 pa_bool_t pa_policy_dbusif_domain_complete(struct userdata *u, uint16_t domain)
1155 dbus_int32_t id32 = domain;
1156 struct pa_policy_dbusif *dbusif;
1157 DBusConnection *conn;
1162 pa_assert_se((dbusif = u->dbusif));
1163 pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1166 pa_log_debug("%s: domain %u AudioManager %s", __FUNCTION__,
1167 domain, AUDIOMGR_DOMAIN_COMPLETE);
1169 msg = dbus_message_new_method_call(dbusif->amnam,
1172 AUDIOMGR_DOMAIN_COMPLETE);
1174 pa_log("%s: Failed to create D-Bus message for '%s'",
1175 __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1180 success = dbus_message_append_args(msg,
1181 DBUS_TYPE_INT32, &id32,
1184 pa_log("%s: Failed to build D-Bus message for '%s'",
1185 __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1189 if (!dbus_connection_send(conn, msg, NULL)) {
1190 pa_log("%s: Failed to send '%s'", __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1194 dbus_connection_flush(conn);
1197 dbus_message_unref(msg);
1201 pa_bool_t pa_policy_dbusif_unregister_domain(struct userdata *u,
1204 pa_policy_dbusif *dbusif;
1205 DBusConnection *conn;
1210 pa_assert_se((dbusif = u->dbusif));
1211 pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1213 pa_log_info("%s: deregistreing domain %u from AudioManager",
1216 msg = dbus_message_new_method_call(dbusif->amnam,
1219 AUDIOMGR_DEREGISTER_DOMAIN);
1221 pa_log("%s: Failed to create D-Bus message for '%s'",
1222 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1227 dbus_message_set_no_reply(msg, TRUE);
1229 success = dbus_message_append_args(msg,
1230 DBUS_TYPE_UINT16, &domain,
1233 pa_log("%s: Failed to build D-Bus message for '%s'",
1234 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1238 if (!dbus_connection_send(conn, msg, NULL)) {
1239 pa_log("%s: Failed to send '%s'", __FILE__,AUDIOMGR_DEREGISTER_DOMAIN);
1243 dbus_connection_flush(conn);
1246 dbus_message_unref(msg);
1251 static void audiomgr_register_node_cb(struct userdata *u,
1256 const char *error_descr;
1257 dbus_uint16_t object_id;
1258 dbus_uint16_t status;
1260 const char *objtype;
1267 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1268 success = dbus_message_get_args(reply, NULL,
1269 DBUS_TYPE_STRING, &error_descr,
1273 error_descr = dbus_message_get_error_name(reply);
1275 pa_log_info("%s: AudioManager registration failed: %s",
1276 __FILE__, error_descr);
1279 success = dbus_message_get_args(reply, NULL,
1280 DBUS_TYPE_UINT16, &object_id,
1281 DBUS_TYPE_UINT16, &status,
1285 pa_log("got broken message from AudioManager.Registration failed");
1288 if (!strncasecmp("register", method, 8))
1289 objtype = method + 8;
1293 pa_log_info("AudioManager replied to registration: %sID: %u",
1294 objtype, object_id);
1296 pa_audiomgr_node_registered(u, object_id, status, data);
1301 static pa_bool_t build_sound_properties(DBusMessageIter *mit,
1302 struct am_nodereg_data *rd)
1304 static int16_t zero;
1306 DBusMessageIter ait, sit;
1309 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
1310 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
1311 #define CONT_CLOSE(p,c) dbus_message_iter_close_container(p, c)
1313 if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(nn)", &ait))
1316 for (i = 1; i < 3; i++) {
1317 if (! CONT_OPEN (&ait, DBUS_TYPE_STRUCT, NULL, &sit) ||
1318 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &i ) ||
1319 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &zero ) ||
1320 ! CONT_CLOSE (&ait, &sit) )
1326 if (!CONT_CLOSE(mit, &ait))
1336 static pa_bool_t build_connection_formats(DBusMessageIter *mit,
1337 struct am_nodereg_data *rd)
1339 DBusMessageIter ait;
1342 #define CONT_OPEN(t,s) dbus_message_iter_open_container(mit, t, s, &ait)
1343 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&ait, t, v)
1344 #define CONT_CLOSE dbus_message_iter_close_container(mit, &ait)
1346 if (!CONT_OPEN(DBUS_TYPE_ARRAY, "n"))
1349 for (i = 1; i < 2; i++) {
1350 if (!CONT_APPEND(DBUS_TYPE_INT16, &i))
1364 pa_bool_t pa_policy_dbusif_register_node(struct userdata *u,
1366 am_nodereg_data *rd)
1368 struct pa_policy_dbusif *dbusif;
1369 DBusConnection *conn;
1371 DBusMessageIter mit;
1372 DBusMessageIter cit;
1373 pa_bool_t success = FALSE;
1378 pa_assert_se((dbusif = u->dbusif));
1379 pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1381 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,rd->name);
1383 msg = dbus_message_new_method_call(dbusif->amnam, dbusif->amrpath,
1384 dbusif->amrnam, method);
1387 pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1392 #define MSG_APPEND(t,v) dbus_message_iter_append_basic(&mit, t, v)
1393 #define CONT_OPEN(t,s) dbus_message_iter_open_container(&mit, t, s, &cit)
1394 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&cit, t, v)
1395 #define CONT_CLOSE dbus_message_iter_close_container(&mit, &cit)
1397 dbus_message_iter_init_append(msg, &mit);
1399 if ((!strcmp(method, AUDIOMGR_REGISTER_SINK) &&
1400 (! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
1401 ! MSG_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
1402 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
1403 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
1404 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
1405 ! MSG_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
1406 ! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
1407 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.status) ||
1408 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.reason) ||
1410 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->mute ) ||
1411 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->mainvol ) ||
1412 ! build_sound_properties(&mit, rd) ||
1413 ! build_connection_formats(&mit, rd) ||
1414 ! build_sound_properties(&mit, rd) )) ||
1415 (!strcmp(method, AUDIOMGR_REGISTER_SOURCE) &&
1416 (! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
1417 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
1418 ! MSG_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
1419 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
1420 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->state ) ||
1421 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
1422 ! MSG_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
1423 ! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
1424 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.status) ||
1425 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.reason) ||
1427 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->interrupt ) ||
1428 ! build_sound_properties(&mit, rd) ||
1429 ! build_connection_formats(&mit, rd) ||
1430 ! build_sound_properties(&mit, rd) )))
1432 pa_log("%s: failed to build message for AudioManager '%s'",
1443 success = send_message_with_reply(u, conn, msg,
1444 audiomgr_register_node_cb, rd);
1446 pa_log("%s: Failed to %s", __FILE__, method);
1451 dbus_message_unref(msg);
1455 static void audiomgr_unregister_node_cb(struct userdata *u,
1460 const char *error_descr;
1461 dbus_uint16_t status;
1463 const char *objtype;
1470 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1471 success = dbus_message_get_args(reply, NULL,
1472 DBUS_TYPE_STRING, &error_descr,
1476 error_descr = dbus_message_get_error_name(reply);
1478 pa_log_info("%s: AudioManager deregistration failed: %s",
1479 __FILE__, error_descr);
1482 success = dbus_message_get_args(reply, NULL,
1483 DBUS_TYPE_UINT16, &status,
1487 pa_log("got broken message from AudioManager. "
1488 "Deregistration failed");
1491 if (!strncasecmp("deregister", method, 10))
1492 objtype = method + 10;
1496 pa_log_info("AudioManager replied to %s deregistration: %u",
1499 pa_audiomgr_node_unregistered(u, data);
1504 pa_bool_t pa_policy_dbusif_unregister_node(struct userdata *u,
1506 am_nodeunreg_data *ud)
1508 struct pa_policy_dbusif *dbusif;
1509 DBusConnection *conn;
1511 pa_bool_t success = FALSE;
1516 pa_assert_se((dbusif = u->dbusif));
1517 pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1519 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,ud->name);
1521 msg = dbus_message_new_method_call(dbusif->amnam, dbusif->amrpath,
1522 dbusif->amrnam, method);
1525 pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1529 success = dbus_message_append_args(msg,
1530 DBUS_TYPE_INT16, &ud->id,
1533 success = send_message_with_reply(u, conn, msg,
1534 audiomgr_unregister_node_cb,ud);
1536 pa_log("%s: Failed to %s", __FILE__, method);
1541 dbus_message_unref(msg);
1545 static pa_bool_t dbusif_connect(struct userdata *u, DBusMessage *msg)
1547 struct am_connect_data ac;
1553 memset(&ac, 0, sizeof(ac));
1555 success = dbus_message_get_args(msg, NULL,
1556 DBUS_TYPE_UINT16, &ac.handle,
1557 DBUS_TYPE_UINT16, &ac.connection,
1558 DBUS_TYPE_UINT16, &ac.source,
1559 DBUS_TYPE_UINT16, &ac.sink,
1560 DBUS_TYPE_INT16 , &ac.format,
1563 pa_log("%s: got broken connect message from AudioManager. "
1564 "Ignoring it", __FILE__);
1568 pa_log_debug("AudioManager connect(%u|%u|%u|%u|%d)",
1569 ac.handle, ac.connection, ac.source, ac.sink, ac.format);
1571 pa_audiomgr_connect(u, &ac);
1576 static pa_bool_t dbusif_disconnect(struct userdata *u, DBusMessage *msg)
1578 struct am_connect_data ac;
1584 memset(&ac, 0, sizeof(ac));
1586 success = dbus_message_get_args(msg, NULL,
1587 DBUS_TYPE_UINT16, &ac.handle,
1588 DBUS_TYPE_UINT16, &ac.connection,
1591 pa_log("%s: got broken disconnect message from AudioManager. "
1592 "Ignoring it", __FILE__);
1596 pa_log_debug("AudioManager disconnect(%u|%u)", ac.handle, ac.connection);
1598 pa_audiomgr_disconnect(u, &ac);
1603 pa_bool_t pa_policy_dbusif_acknowledge(struct userdata *u, const char *method,
1604 struct am_ack_data *ad)
1606 struct pa_policy_dbusif *dbusif;
1607 DBusConnection *conn;
1613 pa_assert_se((dbusif = u->dbusif));
1614 pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1616 pa_log_debug("%s: sending %s", __FILE__, method);
1618 msg = dbus_message_new_method_call(dbusif->amnam,
1623 pa_log("%s: Failed to create D-Bus message for '%s'",
1629 success = dbus_message_append_args(msg,
1630 DBUS_TYPE_UINT16, &ad->handle,
1631 DBUS_TYPE_UINT16, &ad->param1,
1632 DBUS_TYPE_UINT16, &ad->error,
1635 pa_log("%s: Failed to build D-Bus message message '%s'",
1640 if (!dbus_connection_send(conn, msg, NULL)) {
1641 pa_log("%s: Failed to send D-Bus message '%s'", __FILE__, method);
1646 dbus_message_unref(msg);
1654 * indent-tabs-mode: nil