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,
22 #include <sys/types.h>
25 #include <pulsecore/pulsecore-config.h>
26 #include <pulsecore/dbus-shared.h>
32 #define ADMIN_DBUS_MANAGER "org.freedesktop.DBus"
33 #define ADMIN_DBUS_PATH "/org/freedesktop/DBus"
34 #define ADMIN_DBUS_INTERFACE "org.freedesktop.DBus"
36 #define ADMIN_NAME_OWNER_CHANGED "NameOwnerChanged"
38 #define POLICY_DBUS_INTERFACE "org.tizen.policy"
39 #define POLICY_DBUS_MRPPATH "/org/tizen/policy"
40 #define POLICY_DBUS_MRPNAME "org.tizen.murphy"
42 #define AUDIOMGR_DBUS_INTERFACE "org.genivi.audiomanager"
43 #define AUDIOMGR_DBUS_PATH "/org/genivi/audiomanager"
44 #define AUDIOMGR_DBUS_ROUTE_NAME "RoutingInterface"
45 #define AUDIOMGR_DBUS_ROUTE_PATH "RoutingInterface"
47 #define PULSE_DBUS_INTERFACE "org.genivi.pulse"
48 #define PULSE_DBUS_PATH "/org/genivi/pulse"
49 #define PULSE_DBUS_NAME "org.genivi.pulse"
52 #define POLICY_DECISION "decision"
53 #define POLICY_STREAM_INFO "stream_info"
54 #define POLICY_ACTIONS "audio_actions"
55 #define POLICY_STATUS "status"
57 #define PROP_ROUTE_SINK_TARGET "policy.sink_route.target"
58 #define PROP_ROUTE_SINK_MODE "policy.sink_route.mode"
59 #define PROP_ROUTE_SINK_HWID "policy.sink_route.hwid"
60 #define PROP_ROUTE_SOURCE_TARGET "policy.source_route.target"
61 #define PROP_ROUTE_SOURCE_MODE "policy.source_route.mode"
62 #define PROP_ROUTE_SOURCE_HWID "policy.source_route.hwid"
65 #define STRUCT_OFFSET(s,m) ((char *)&(((s *)0)->m) - (char *)0)
67 typedef void (*pending_cb_t)(struct userdata *, const char *,
68 DBusMessage *, void *);
69 typedef pa_bool_t (*method_t)(struct userdata *, DBusMessage *);
73 PA_LLIST_FIELDS(struct pending);
76 DBusPendingCall *call;
82 pa_dbus_connection *conn;
83 char *ifnam; /* signal interface */
84 char *mrppath; /* murphy signal path */
85 char *mrpnam; /* murphy D-Bus name */
86 char *ampath; /* audio manager path */
87 char *amnam; /* audio manager name */
88 char *amrpath; /* audio manager routing path */
89 char *amrnam; /* audio manager routing name */
90 char *admmrule; /* match rule to catch murphy name changes */
91 char *admarule; /* match rule to catch audiomgr name change*/
92 char *actrule; /* match rule to catch action signals */
93 char *strrule; /* match rule to catch stream info signals */
94 int mregist; /* are we registered to murphy */
95 int amisup; /* is the audio manager up */
96 PA_LLIST_HEAD(struct pending, pendlist);
102 struct actdsc { /* action descriptor */
104 int (*parser)(struct userdata *u, DBusMessageIter *iter);
107 struct argdsc { /* argument descriptor for actions */
113 struct argrt { /* audio_route arguments */
120 struct argvol { /* volume_limit arguments */
125 struct argcork { /* audio_cork arguments */
135 struct argctx { /* context arguments */
140 static void free_routerif(pa_routerif *,struct userdata *);
142 static pa_bool_t send_message_with_reply(struct userdata *,
143 DBusConnection *, DBusMessage *,
144 pending_cb_t, void *);
147 static DBusHandlerResult filter(DBusConnection *, DBusMessage *, void *);
149 static void handle_admin_message(struct userdata *, DBusMessage *);
151 static void handle_info_message(struct userdata *, DBusMessage *);
152 static void handle_action_message(struct userdata *, DBusMessage *);
155 static void murphy_registration_cb(struct userdata *, const char *,
156 DBusMessage *, void *);
157 static pa_bool_t register_to_murphy(struct userdata *);
159 static int signal_status(struct userdata *, uint32_t, uint32_t);
162 static DBusHandlerResult audiomgr_method_handler(DBusConnection *,
163 DBusMessage *, void *);
164 static void audiomgr_register_domain_cb(struct userdata *, const char *,
165 DBusMessage *, void *);
166 static pa_bool_t register_to_audiomgr(struct userdata *);
167 static pa_bool_t unregister_from_audiomgr(struct userdata *);
169 static void audiomgr_register_node_cb(struct userdata *, const char *,
170 DBusMessage *, void *);
171 static void audiomgr_unregister_node_cb(struct userdata *, const char *,
172 DBusMessage *, void *);
173 static pa_bool_t build_sound_properties(DBusMessageIter *,
174 struct am_nodereg_data *);
175 static pa_bool_t build_connection_formats(DBusMessageIter *,
176 struct am_nodereg_data *);
177 static pa_bool_t routerif_connect(struct userdata *, DBusMessage *);
178 static pa_bool_t routerif_disconnect(struct userdata *, DBusMessage *);
180 static const char *method_str(am_method);
183 pa_routerif *pa_routerif_init(struct userdata *u,
184 const char *dbustype,
191 static const DBusObjectPathVTable vtable = {
192 .message_function = audiomgr_method_handler,
195 pa_module *m = u->module;
196 pa_routerif *routerif = NULL;
198 DBusConnection *dbusconn;
211 if (!dbustype || !strcasecmp(dbustype, "session")) {
212 dbustype = "session";
213 type = DBUS_BUS_SESSION;
215 else if (!strcasecmp(dbustype, "system")) {
217 type = DBUS_BUS_SYSTEM;
220 pa_log("invalid dbus type '%s'", dbustype);
224 routerif = pa_xnew0(pa_routerif, 1);
225 PA_LLIST_HEAD_INIT(struct pending, routerif->pendlist);
227 dbus_error_init(&error);
228 routerif->conn = pa_dbus_bus_get(m->core, type, &error);
230 if (routerif->conn == NULL || dbus_error_is_set(&error)) {
231 pa_log("%s: failed to get %s Bus: %s: %s",
232 __FILE__, dbustype, error.name, error.message);
236 dbusconn = pa_dbus_connection_get(routerif->conn);
238 flags = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;
239 result = dbus_bus_request_name(dbusconn, PULSE_DBUS_NAME, flags,&error);
241 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER &&
242 result != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER ) {
243 pa_log("%s: D-Bus name request failed: %s: %s",
244 __FILE__, error.name, error.message);
248 pa_log_info("%s: now owner of '%s' D-Bus name on %s bus",
249 __FILE__, PULSE_DBUS_NAME, dbustype);
251 if (!dbus_connection_add_filter(dbusconn, filter,u, NULL)) {
252 pa_log("%s: failed to add filter function", __FILE__);
257 ifnam = POLICY_DBUS_INTERFACE;
260 mrppath = POLICY_DBUS_MRPPATH;
263 mrpnam = POLICY_DBUS_MRPNAME;
265 if (ampath && *ampath) {
266 char *slash = ampath[strlen(ampath)-1] == '/' ? "" : "/";
267 snprintf(pathbuf, sizeof(pathbuf), "%s%s" AUDIOMGR_DBUS_ROUTE_PATH,
272 ampath = AUDIOMGR_DBUS_PATH;
273 amrpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_ROUTE_PATH;
276 if (amnam && *amnam){
277 char *dot = amnam[strlen(amnam)-1] == '.' ? "" : ".";
278 snprintf(nambuf, sizeof(nambuf), "%s%s" AUDIOMGR_DBUS_ROUTE_NAME,
283 amnam = AUDIOMGR_DBUS_INTERFACE;
284 amrnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_ROUTE_NAME;
288 snprintf(admmrule, sizeof(admmrule), "type='signal',sender='%s',path='%s',"
289 "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
290 ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
292 dbus_bus_add_match(dbusconn, admmrule, &error);
294 snprintf(admarule, sizeof(admarule), "type='signal',sender='%s',path='%s',"
295 "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
296 ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
298 dbus_bus_add_match(dbusconn, admarule, &error);
300 if (dbus_error_is_set(&error)) {
301 pa_log("%s: unable to subscribe name change signals on %s: %s: %s",
302 __FILE__, ADMIN_DBUS_INTERFACE, error.name, error.message);
306 snprintf(actrule, sizeof(actrule), "type='signal',interface='%s',"
307 "member='%s',path='%s/%s'", ifnam, POLICY_ACTIONS,
308 mrppath, POLICY_DECISION);
309 dbus_bus_add_match(dbusconn, actrule, &error);
311 if (dbus_error_is_set(&error)) {
312 pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
313 __FILE__, POLICY_ACTIONS, ifnam, error.name, error.message);
317 snprintf(strrule, sizeof(strrule), "type='signal',interface='%s',"
318 "member='%s',path='%s/%s'", ifnam, POLICY_STREAM_INFO,
319 mrppath, POLICY_DECISION);
320 dbus_bus_add_match(dbusconn, strrule, &error);
322 if (dbus_error_is_set(&error)) {
323 pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
324 __FILE__, POLICY_STREAM_INFO, ifnam, error.name, error.message);
328 pa_log_info("%s: subscribed policy signals on %s", __FILE__, ifnam);
330 dbus_connection_register_object_path(dbusconn, PULSE_DBUS_PATH, &vtable,u);
333 routerif->ifnam = pa_xstrdup(ifnam);
334 routerif->mrppath = pa_xstrdup(mrppath);
335 routerif->mrpnam = pa_xstrdup(mrpnam);
336 routerif->ampath = pa_xstrdup(ampath);
337 routerif->amnam = pa_xstrdup(amnam);
338 routerif->amrpath = pa_xstrdup(amrpath);
339 routerif->amrnam = pa_xstrdup(amrnam);
340 routerif->admmrule = pa_xstrdup(admmrule);
341 routerif->admarule = pa_xstrdup(admarule);
342 routerif->actrule = pa_xstrdup(actrule);
343 routerif->strrule = pa_xstrdup(strrule);
345 u->routerif = routerif; /* Argh.. */
347 register_to_murphy(u);
348 register_to_audiomgr(u);
353 free_routerif(routerif, u);
354 dbus_error_free(&error);
358 static void free_routerif(pa_routerif *routerif, struct userdata *u)
360 DBusConnection *dbusconn;
361 struct pending *p, *n;
365 if (routerif->conn) {
366 dbusconn = pa_dbus_connection_get(routerif->conn);
368 PA_LLIST_FOREACH_SAFE(p,n, routerif->pendlist) {
369 PA_LLIST_REMOVE(struct pending, routerif->pendlist, p);
370 dbus_pending_call_set_notify(p->call, NULL,NULL, NULL);
371 dbus_pending_call_unref(p->call);
375 dbus_connection_remove_filter(dbusconn, filter,u);
378 dbus_bus_remove_match(dbusconn, routerif->admmrule, NULL);
379 dbus_bus_remove_match(dbusconn, routerif->admarule, NULL);
380 dbus_bus_remove_match(dbusconn, routerif->actrule, NULL);
381 dbus_bus_remove_match(dbusconn, routerif->strrule, NULL);
383 pa_dbus_connection_unref(routerif->conn);
386 pa_xfree(routerif->ifnam);
387 pa_xfree(routerif->mrppath);
388 pa_xfree(routerif->mrpnam);
389 pa_xfree(routerif->ampath);
390 pa_xfree(routerif->amnam);
391 pa_xfree(routerif->amrpath);
392 pa_xfree(routerif->amrnam);
393 pa_xfree(routerif->admmrule);
394 pa_xfree(routerif->admarule);
395 pa_xfree(routerif->actrule);
396 pa_xfree(routerif->strrule);
402 void pa_routerif_done(struct userdata *u)
404 if (u && u->routerif) {
405 free_routerif(u->routerif, u);
411 static DBusHandlerResult filter(DBusConnection *conn, DBusMessage *msg,
414 struct userdata *u = arg;
416 if (dbus_message_is_signal(msg, ADMIN_DBUS_INTERFACE,
417 ADMIN_NAME_OWNER_CHANGED))
419 handle_admin_message(u, msg);
420 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
425 if (dbus_message_is_signal(msg, POLICY_DBUS_INTERFACE,POLICY_STREAM_INFO)){
426 handle_info_message(u, msg);
427 return DBUS_HANDLER_RESULT_HANDLED;
430 if (dbus_message_is_signal(msg, POLICY_DBUS_INTERFACE, POLICY_ACTIONS)) {
431 handle_action_message(u, msg);
432 return DBUS_HANDLER_RESULT_HANDLED;
436 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
440 static void handle_admin_message(struct userdata *u, DBusMessage *msg)
442 pa_routerif *routerif;
449 pa_assert_se((routerif = u->routerif));
451 success = dbus_message_get_args(msg, NULL,
452 DBUS_TYPE_STRING, &name,
453 DBUS_TYPE_STRING, &before,
454 DBUS_TYPE_STRING, &after,
457 if (!success || !name) {
458 pa_log("Received malformed '%s' message", ADMIN_NAME_OWNER_CHANGED);
462 if (!strcmp(name, routerif->mrpnam)) {
463 if (after && strcmp(after, "")) {
464 pa_log_debug("murphy is up");
466 if (!routerif->mregist) {
467 register_to_murphy(u);
471 if (name && before && (!after || !strcmp(after, ""))) {
472 pa_log_info("murphy is gone");
473 routerif->mregist = 0;
477 if (!strcmp(name, routerif->amnam)) {
478 if (after && strcmp(after, "")) {
479 pa_log_debug("audio manager is up");
481 if (!routerif->amisup) {
482 register_to_audiomgr(u);
486 if (name && before && (!after || !strcmp(after, ""))) {
487 pa_log_info("audio manager is gone");
489 if (routerif->amisup)
490 unregister_from_audiomgr(u);
492 routerif->amisup = 0;
498 static void reply_cb(DBusPendingCall *pend, void *data)
500 struct pending *pdata = (struct pending *)data;
502 pa_routerif *routerif;
506 pa_assert(pdata->call == pend);
507 pa_assert_se((u = pdata->u));
508 pa_assert_se((routerif = u->routerif));
510 PA_LLIST_REMOVE(struct pending, routerif->pendlist, pdata);
512 if ((reply = dbus_pending_call_steal_reply(pend)) == NULL) {
513 pa_log("%s: Murphy pending call '%s' failed: invalid argument",
514 __FILE__, pdata->method);
517 pdata->cb(u, pdata->method, reply, pdata->data);
518 dbus_message_unref(reply);
521 pa_xfree((void *)pdata->method);
522 pa_xfree((void *)pdata);
525 static pa_bool_t send_message_with_reply(struct userdata *u,
526 DBusConnection *conn,
531 pa_routerif *routerif;
532 struct pending *pdata = NULL;
534 DBusPendingCall *pend;
540 pa_assert_se((routerif = u->routerif));
542 if ((method = dbus_message_get_member(msg)) == NULL)
545 pdata = pa_xnew0(struct pending, 1);
547 pdata->method = pa_xstrdup(method);
551 PA_LLIST_PREPEND(struct pending, routerif->pendlist, pdata);
553 if (!dbus_connection_send_with_reply(conn, msg, &pend, -1)) {
554 pa_log("%s: Failed to %s", __FILE__, method);
560 if (!dbus_pending_call_set_notify(pend, reply_cb,pdata, NULL)) {
561 pa_log("%s: Can't set notification for %s", __FILE__, method);
570 PA_LLIST_REMOVE(struct pending, routerif->pendlist, pdata);
571 pa_xfree((void *)pdata->method);
572 pa_xfree((void *)pdata);
578 /**************************************************************************
584 void pa_routerif_send_device_state(struct userdata *u, char *state,
585 char **types, int ntype)
587 static char *path = (char *)"/org/tizen/policy/info";
589 pa_routerif *routerif = u->routerif;
590 DBusConnection *conn = pa_dbus_connection_get(routerif->conn);
597 if (!types || ntype < 1)
600 msg = dbus_message_new_signal(path, routerif->ifnam, "info");
603 pa_log("%s: failed to make new info message", __FILE__);
607 dbus_message_iter_init_append(msg, &mit);
609 if (!dbus_message_iter_append_basic(&mit, DBUS_TYPE_STRING, &state) ||
610 !dbus_message_iter_open_container(&mit, DBUS_TYPE_ARRAY,"s", &dit)){
611 pa_log("%s: failed to build info message", __FILE__);
615 for (i = 0; i < ntype; i++) {
616 if (!dbus_message_iter_append_basic(&dit, DBUS_TYPE_STRING,&types[i])){
617 pa_log("%s: failed to build info message", __FILE__);
622 dbus_message_iter_close_container(&mit, &dit);
624 sts = dbus_connection_send(conn, msg, NULL);
627 pa_log("%s: Can't send info message: out of memory", __FILE__);
631 dbus_message_unref(msg); /* should cope with NULL msg */
634 void pa_routerif_send_media_status(struct userdata *u, const char *media,
635 const char *group, int active)
637 static char *path = (char *)"/org/tizen/policy/info";
638 static const char *type = "media";
640 pa_routerif *routerif = u->routerif;
641 DBusConnection *conn = pa_dbus_connection_get(routerif->conn);
646 msg = dbus_message_new_signal(path, routerif->ifnam, "info");
649 pa_log("%s: failed to make new info message", __FILE__);
651 state = active ? "active" : "inactive";
653 success = dbus_message_append_args(msg,
654 DBUS_TYPE_STRING, &type,
655 DBUS_TYPE_STRING, &media,
656 DBUS_TYPE_STRING, &group,
657 DBUS_TYPE_STRING, &state,
661 pa_log("%s: Can't build D-Bus info message", __FILE__);
663 if (!dbus_connection_send(conn, msg, NULL)) {
664 pa_log("%s: Can't send info message: out of memory", __FILE__);
668 dbus_message_unref(msg);
674 static void handle_info_message(struct userdata *u, DBusMessage *msg)
682 enum pa_classify_method method = pa_method_unknown;
686 success = dbus_message_get_args(msg, NULL,
687 DBUS_TYPE_UINT32, &txid,
688 DBUS_TYPE_STRING, &oper,
689 DBUS_TYPE_STRING, &group,
690 DBUS_TYPE_UINT32, &pid,
691 DBUS_TYPE_STRING, &arg,
692 DBUS_TYPE_STRING, &method_str,
693 DBUS_TYPE_STRING, &prop,
696 pa_log("%s: failed to parse info message", __FILE__);
701 method = pa_method_unknown;
703 switch (method_str[0]) {
705 if (!strcmp(method_str, "equals"))
706 method = pa_method_equals;
709 if (!strcmp(method_str, "startswith"))
710 method = pa_method_startswith;
713 if (!strcmp(method_str, "matches"))
714 method = pa_method_matches;
717 if (!strcmp(method_str, "true"))
718 method = pa_method_true;
721 method = pa_method_unknown;
727 method = pa_method_unknown;
728 else if (!strcmp(arg, "*"))
729 method = pa_method_true;
731 if (!strcmp(oper, "register")) {
733 if (pa_policy_group_find(u, group) == NULL) {
734 pa_log_debug("register client (%s|%u) failed: unknown group",
738 pa_log_debug("register client (%s|%u)", group, pid);
739 pa_classify_register_pid(u, (pid_t)pid, prop, method, arg, group);
743 else if (!strcmp(oper, "unregister")) {
744 pa_log_debug("unregister client (%s|%u)", group, pid);
745 pa_classify_unregister_pid(u, (pid_t)pid, prop, method, arg);
748 pa_log("%s: invalid operation: '%s'", __FILE__, oper);
752 static void handle_action_message(struct userdata *u, DBusMessage *msg)
754 static struct actdsc actions[] = {
756 { "org.tizen.policy.audio_route" , audio_route_parser },
757 { "org.tizen.policy.volume_limit", volume_limit_parser },
758 { "org.tizen.policy.audio_cork" , audio_cork_parser },
759 { "org.tizen.policy.audio_mute" , audio_mute_parser },
760 { "org.tizen.policy.context" , context_parser },
768 DBusMessageIter msgit;
769 DBusMessageIter arrit;
770 DBusMessageIter entit;
771 DBusMessageIter actit;
774 pa_log_debug("got policy actions");
776 dbus_message_iter_init(msg, &msgit);
778 if (dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_UINT32)
781 dbus_message_iter_get_basic(&msgit, (void *)&txid);
783 pa_log_debug("got actions (txid:%d)", txid);
785 if (!dbus_message_iter_next(&msgit) ||
786 dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_ARRAY) {
791 dbus_message_iter_recurse(&msgit, &arrit);
794 if (dbus_message_iter_get_arg_type(&arrit) != DBUS_TYPE_DICT_ENTRY) {
799 dbus_message_iter_recurse(&arrit, &entit);
802 if (dbus_message_iter_get_arg_type(&entit) != DBUS_TYPE_STRING) {
807 dbus_message_iter_get_basic(&entit, (void *)&actname);
809 if (!dbus_message_iter_next(&entit) ||
810 dbus_message_iter_get_arg_type(&entit) != DBUS_TYPE_ARRAY) {
815 dbus_message_iter_recurse(&entit, &actit);
817 if (dbus_message_iter_get_arg_type(&actit) != DBUS_TYPE_ARRAY) {
822 for (act = actions; act->name != NULL; act++) {
823 if (!strcmp(actname, act->name))
827 if (act->parser != NULL)
828 success &= act->parser(u, &actit);
830 } while (dbus_message_iter_next(&entit));
832 } while (dbus_message_iter_next(&arrit));
835 signal_status(u, txid, success);
839 static void murphy_registration_cb(struct userdata *u,
844 const char *error_descr;
849 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
850 success = dbus_message_get_args(reply, NULL,
851 DBUS_TYPE_STRING, &error_descr,
855 error_descr = dbus_message_get_error_name(reply);
857 pa_log_info("%s: registration to Murphy failed: %s",
858 __FILE__, error_descr);
861 pa_log_info("Murphy replied to registration");
864 u->routerif->amisup = 1;
869 static pa_bool_t register_to_murphy(struct userdata *u)
871 static const char *name = "pulseaudio";
873 pa_routerif *routerif = u->routerif;
874 DBusConnection *conn = pa_dbus_connection_get(routerif->conn);
876 const char *signals[4];
877 const char **v_ARRAY;
881 pa_log_info("%s: registering to murphy: name='%s' path='%s' if='%s'",
882 __FILE__, routerif->mrpnam, routerif->mrppath,routerif->ifnam);
884 msg = dbus_message_new_method_call(routerif->mrpnam, routerif->mrppath,
885 routerif->ifnam, "register");
888 pa_log("%s: Failed to create D-Bus message to register", __FILE__);
893 signals[i=0] = POLICY_ACTIONS;
896 success = dbus_message_append_args(msg,
897 DBUS_TYPE_STRING, &name,
899 DBUS_TYPE_STRING, &v_ARRAY, i+1,
902 pa_log("%s: Failed to build D-Bus message to register", __FILE__);
906 if (!send_message_with_reply(u, conn, msg, murphy_registration_cb, NULL)) {
907 pa_log("%s: Failed to register", __FILE__);
912 dbus_message_unref(msg);
918 static int signal_status(struct userdata *u, uint32_t txid, uint32_t status)
920 pa_routerif *routerif = u->routerif;
921 DBusConnection *conn = pa_dbus_connection_get(routerif->conn);
928 /* When transaction ID is 0, the policy manager does not expect
931 pa_log_debug("Not sending status message since transaction ID is 0");
935 snprintf(path, sizeof(path), "%s/%s", routerif->mrppath, POLICY_DECISION);
937 pa_log_debug("sending signal to: path='%s', if='%s' member='%s' "
938 "content: txid=%d status=%d", path, routerif->ifnam,
939 POLICY_STATUS, txid, status);
941 msg = dbus_message_new_signal(path, routerif->ifnam, POLICY_STATUS);
944 pa_log("%s: failed to make new status message", __FILE__);
948 ret = dbus_message_append_args(msg,
949 DBUS_TYPE_UINT32, &txid,
950 DBUS_TYPE_UINT32, &status,
954 pa_log("%s: Can't build D-Bus status message", __FILE__);
958 ret = dbus_connection_send(conn, msg, NULL);
961 pa_log("%s: Can't send status message: out of memory", __FILE__);
965 dbus_message_unref(msg);
970 dbus_message_unref(msg); /* should cope with NULL msg */
976 /**************************************************************************
978 * Audio Manager interfaces
981 static DBusHandlerResult audiomgr_method_handler(DBusConnection *conn,
990 static struct dispatch dispatch_tbl[] = {
991 { AUDIOMGR_CONNECT , routerif_connect },
992 { AUDIOMGR_DISCONNECT, routerif_disconnect },
996 struct userdata *u = (struct userdata *)arg;
1001 dbus_int16_t errcod;
1009 if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
1011 name = dbus_message_get_member(msg);
1012 // serial = dbus_message_get_serial(msg);
1016 for (method = NULL, d = dispatch_tbl; d->name; d++) {
1017 if (!strcmp(name, d->name)) {
1023 errcod = method ? E_OK : E_NOT_POSSIBLE;
1024 reply = dbus_message_new_method_return(msg);
1026 // dbus_message_set_reply_serial(reply, serial);
1028 success = dbus_message_append_args(reply,
1029 DBUS_TYPE_INT16, &errcod,
1032 if (!success || !dbus_connection_send(conn, reply, NULL))
1033 pa_log("%s: failed to reply '%s'", __FILE__, name);
1035 pa_log_debug("'%s' replied (%d)", name, errcod);
1037 dbus_message_unref(reply);
1042 pa_log_info("%s: unsupported '%s' method ignored", __FILE__, name);
1044 return DBUS_HANDLER_RESULT_HANDLED;
1047 pa_log_debug("got some unexpected type of D-Bus message");
1049 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1053 static pa_bool_t register_to_audiomgr(struct userdata *u)
1055 pa_audiomgr_register_domain(u);
1059 static pa_bool_t unregister_from_audiomgr(struct userdata *u)
1061 pa_audiomgr_unregister_domain(u, FALSE);
1065 static void audiomgr_register_domain_cb(struct userdata *u,
1070 const char *error_descr;
1071 dbus_uint16_t domain_id;
1072 dbus_uint16_t status;
1075 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1076 success = dbus_message_get_args(reply, NULL,
1077 DBUS_TYPE_STRING, &error_descr,
1081 error_descr = dbus_message_get_error_name(reply);
1083 pa_log_info("%s: AudioManager domain registration failed: %s",
1084 __FILE__, error_descr);
1087 success = dbus_message_get_args(reply, NULL,
1088 DBUS_TYPE_UINT16, &domain_id,
1089 DBUS_TYPE_UINT16, &status,
1093 pa_log("got broken message from AudioManager.Registration failed");
1096 pa_log_info("AudioManager replied to registration: "
1097 "domainID %u, status %u", domain_id, status);
1100 u->routerif->amisup = 1;
1101 pa_audiomgr_domain_registered(u, domain_id, status, data);
1109 pa_bool_t pa_routerif_register_domain(struct userdata *u,
1110 am_domainreg_data *dr)
1112 pa_routerif *routerif;
1113 DBusConnection *conn;
1115 const char *dbus_name;
1116 const char *dbus_path;
1117 const char *dbus_if;
1122 pa_assert_se((routerif = u->routerif));
1123 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1125 pa_log_info("%s: registering to AudioManager: name='%s' path='%s' if='%s'"
1126 , __FILE__, routerif->amnam, routerif->amrpath, routerif->amrnam);
1128 msg = dbus_message_new_method_call(routerif->amnam,
1131 AUDIOMGR_REGISTER_DOMAIN);
1133 pa_log("%s: Failed to create D-Bus message to '%s'",
1134 __FILE__, AUDIOMGR_REGISTER_DOMAIN);
1139 dbus_name = PULSE_DBUS_NAME;
1140 dbus_path = PULSE_DBUS_PATH;
1141 dbus_if = PULSE_DBUS_INTERFACE;
1143 success = dbus_message_append_args(msg,
1144 DBUS_TYPE_UINT16, &dr->domain_id,
1145 DBUS_TYPE_STRING, &dr->name,
1146 DBUS_TYPE_STRING, &dr->node_name,
1147 DBUS_TYPE_STRING, &dr->bus_name,
1148 DBUS_TYPE_BOOLEAN, &dr->early,
1149 DBUS_TYPE_BOOLEAN, &dr->complete,
1150 DBUS_TYPE_UINT16 , &dr->state,
1151 DBUS_TYPE_STRING , &dbus_name,
1152 DBUS_TYPE_STRING , &dbus_path,
1153 DBUS_TYPE_STRING , &dbus_if,
1156 pa_log("%s: Failed to build D-Bus message to register", __FILE__);
1160 success = send_message_with_reply(u, conn, msg,
1161 audiomgr_register_domain_cb, dr);
1163 pa_log("%s: Failed to register", __FILE__);
1168 dbus_message_unref(msg);
1172 pa_bool_t pa_routerif_domain_complete(struct userdata *u, uint16_t domain)
1174 dbus_int32_t id32 = domain;
1175 pa_routerif *routerif;
1176 DBusConnection *conn;
1181 pa_assert_se((routerif = u->routerif));
1182 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1185 pa_log_debug("%s: domain %u AudioManager %s", __FUNCTION__,
1186 domain, AUDIOMGR_DOMAIN_COMPLETE);
1188 msg = dbus_message_new_method_call(routerif->amnam,
1191 AUDIOMGR_DOMAIN_COMPLETE);
1193 pa_log("%s: Failed to create D-Bus message for '%s'",
1194 __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1199 success = dbus_message_append_args(msg,
1200 DBUS_TYPE_INT32, &id32,
1203 pa_log("%s: Failed to build D-Bus message for '%s'",
1204 __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1208 if (!dbus_connection_send(conn, msg, NULL)) {
1209 pa_log("%s: Failed to send '%s'", __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1213 dbus_connection_flush(conn);
1216 dbus_message_unref(msg);
1220 pa_bool_t pa_routerif_unregister_domain(struct userdata *u, uint16_t domain)
1222 pa_routerif *routerif;
1223 DBusConnection *conn;
1228 pa_assert_se((routerif = u->routerif));
1229 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1231 pa_log_info("%s: deregistreing domain %u from AudioManager",
1234 msg = dbus_message_new_method_call(routerif->amnam,
1237 AUDIOMGR_DEREGISTER_DOMAIN);
1239 pa_log("%s: Failed to create D-Bus message for '%s'",
1240 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1245 dbus_message_set_no_reply(msg, TRUE);
1247 success = dbus_message_append_args(msg,
1248 DBUS_TYPE_UINT16, &domain,
1251 pa_log("%s: Failed to build D-Bus message for '%s'",
1252 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1256 if (!dbus_connection_send(conn, msg, NULL)) {
1257 pa_log("%s: Failed to send '%s'", __FILE__,AUDIOMGR_DEREGISTER_DOMAIN);
1261 dbus_connection_flush(conn);
1264 dbus_message_unref(msg);
1269 static void audiomgr_register_node_cb(struct userdata *u,
1274 const char *error_descr;
1275 dbus_uint16_t object_id;
1276 dbus_uint16_t status;
1278 const char *objtype;
1285 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1286 success = dbus_message_get_args(reply, NULL,
1287 DBUS_TYPE_STRING, &error_descr,
1291 error_descr = dbus_message_get_error_name(reply);
1293 pa_log_info("%s: AudioManager registration failed: %s",
1294 __FILE__, error_descr);
1297 success = dbus_message_get_args(reply, NULL,
1298 DBUS_TYPE_UINT16, &object_id,
1299 DBUS_TYPE_UINT16, &status,
1303 pa_log("got broken message from AudioManager.Registration failed");
1306 if (!strncasecmp("register", method, 8))
1307 objtype = method + 8;
1311 pa_log_info("AudioManager replied to registration: %sID: %u",
1312 objtype, object_id);
1314 pa_audiomgr_node_registered(u, object_id, status, data);
1319 static pa_bool_t build_sound_properties(DBusMessageIter *mit,
1320 struct am_nodereg_data *rd)
1322 static int16_t zero;
1324 DBusMessageIter ait, sit;
1327 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
1328 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
1329 #define CONT_CLOSE(p,c) dbus_message_iter_close_container(p, c)
1331 if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(nn)", &ait))
1334 for (i = 1; i < 3; i++) {
1335 if (! CONT_OPEN (&ait, DBUS_TYPE_STRUCT, NULL, &sit) ||
1336 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &i ) ||
1337 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &zero ) ||
1338 ! CONT_CLOSE (&ait, &sit) )
1344 if (!CONT_CLOSE(mit, &ait))
1354 static pa_bool_t build_connection_formats(DBusMessageIter *mit,
1355 struct am_nodereg_data *rd)
1357 DBusMessageIter ait;
1360 #define CONT_OPEN(t,s) dbus_message_iter_open_container(mit, t, s, &ait)
1361 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&ait, t, v)
1362 #define CONT_CLOSE dbus_message_iter_close_container(mit, &ait)
1364 if (!CONT_OPEN(DBUS_TYPE_ARRAY, "n"))
1367 for (i = 1; i < 2; i++) {
1368 if (!CONT_APPEND(DBUS_TYPE_INT16, &i))
1382 pa_bool_t pa_routerif_register_node(struct userdata *u,
1384 am_nodereg_data *rd)
1386 const char *method = method_str(m);
1387 pa_routerif *routerif;
1388 DBusConnection *conn;
1390 DBusMessageIter mit;
1391 DBusMessageIter cit;
1392 pa_bool_t success = FALSE;
1396 pa_assert_se((routerif = u->routerif));
1397 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1399 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,rd->name);
1401 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1402 routerif->amrnam, method);
1405 pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1410 #define MSG_APPEND(t,v) dbus_message_iter_append_basic(&mit, t, v)
1411 #define CONT_OPEN(t,s) dbus_message_iter_open_container(&mit, t, s, &cit)
1412 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&cit, t, v)
1413 #define CONT_CLOSE dbus_message_iter_close_container(&mit, &cit)
1415 dbus_message_iter_init_append(msg, &mit);
1417 if ((!strcmp(method, AUDIOMGR_REGISTER_SINK) &&
1418 (! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
1419 ! MSG_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
1420 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
1421 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
1422 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
1423 ! MSG_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
1424 ! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
1425 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.status) ||
1426 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.reason) ||
1428 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->mute ) ||
1429 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->mainvol ) ||
1430 ! build_sound_properties(&mit, rd) ||
1431 ! build_connection_formats(&mit, rd) ||
1432 ! build_sound_properties(&mit, rd) )) ||
1433 (!strcmp(method, AUDIOMGR_REGISTER_SOURCE) &&
1434 (! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
1435 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
1436 ! MSG_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
1437 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
1438 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->state ) ||
1439 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
1440 ! MSG_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
1441 ! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
1442 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.status) ||
1443 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.reason) ||
1445 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->interrupt ) ||
1446 ! build_sound_properties(&mit, rd) ||
1447 ! build_connection_formats(&mit, rd) ||
1448 ! build_sound_properties(&mit, rd) )))
1450 pa_log("%s: failed to build message for AudioManager '%s'",
1461 success = send_message_with_reply(u, conn, msg,
1462 audiomgr_register_node_cb, rd);
1464 pa_log("%s: Failed to %s", __FILE__, method);
1469 dbus_message_unref(msg);
1473 static void audiomgr_unregister_node_cb(struct userdata *u,
1478 const char *error_descr;
1479 dbus_uint16_t status;
1481 const char *objtype;
1488 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1489 success = dbus_message_get_args(reply, NULL,
1490 DBUS_TYPE_STRING, &error_descr,
1494 error_descr = dbus_message_get_error_name(reply);
1496 pa_log_info("%s: AudioManager deregistration failed: %s",
1497 __FILE__, error_descr);
1500 success = dbus_message_get_args(reply, NULL,
1501 DBUS_TYPE_UINT16, &status,
1505 pa_log("got broken message from AudioManager. "
1506 "Deregistration failed");
1509 if (!strncasecmp("deregister", method, 10))
1510 objtype = method + 10;
1514 pa_log_info("AudioManager replied to %s deregistration: %u",
1517 pa_audiomgr_node_unregistered(u, data);
1522 pa_bool_t pa_routerif_unregister_node(struct userdata *u,
1524 am_nodeunreg_data *ud)
1526 const char *method = method_str(m);
1527 pa_routerif *routerif;
1528 DBusConnection *conn;
1530 pa_bool_t success = FALSE;
1534 pa_assert_se((routerif = u->routerif));
1535 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1537 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,ud->name);
1539 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1540 routerif->amrnam, method);
1543 pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1547 success = dbus_message_append_args(msg,
1548 DBUS_TYPE_INT16, &ud->id,
1551 success = send_message_with_reply(u, conn, msg,
1552 audiomgr_unregister_node_cb,ud);
1554 pa_log("%s: Failed to %s", __FILE__, method);
1559 dbus_message_unref(msg);
1563 static pa_bool_t routerif_connect(struct userdata *u, DBusMessage *msg)
1565 struct am_connect_data ac;
1571 memset(&ac, 0, sizeof(ac));
1573 success = dbus_message_get_args(msg, NULL,
1574 DBUS_TYPE_UINT16, &ac.handle,
1575 DBUS_TYPE_UINT16, &ac.connection,
1576 DBUS_TYPE_UINT16, &ac.source,
1577 DBUS_TYPE_UINT16, &ac.sink,
1578 DBUS_TYPE_INT16 , &ac.format,
1581 pa_log("%s: got broken connect message from AudioManager. "
1582 "Ignoring it", __FILE__);
1586 pa_log_debug("AudioManager connect(%u|%u|%u|%u|%d)",
1587 ac.handle, ac.connection, ac.source, ac.sink, ac.format);
1589 pa_audiomgr_connect(u, &ac);
1594 static pa_bool_t routerif_disconnect(struct userdata *u, DBusMessage *msg)
1596 struct am_connect_data ac;
1602 memset(&ac, 0, sizeof(ac));
1604 success = dbus_message_get_args(msg, NULL,
1605 DBUS_TYPE_UINT16, &ac.handle,
1606 DBUS_TYPE_UINT16, &ac.connection,
1609 pa_log("%s: got broken disconnect message from AudioManager. "
1610 "Ignoring it", __FILE__);
1614 pa_log_debug("AudioManager disconnect(%u|%u)", ac.handle, ac.connection);
1616 pa_audiomgr_disconnect(u, &ac);
1621 pa_bool_t pa_routerif_acknowledge(struct userdata *u, am_method m,
1622 struct am_ack_data *ad)
1624 const char *method = method_str(m);
1625 pa_routerif *routerif;
1626 DBusConnection *conn;
1632 pa_assert_se((routerif = u->routerif));
1633 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1635 pa_log_debug("%s: sending %s", __FILE__, method);
1637 msg = dbus_message_new_method_call(routerif->amnam,
1642 pa_log("%s: Failed to create D-Bus message for '%s'",
1648 success = dbus_message_append_args(msg,
1649 DBUS_TYPE_UINT16, &ad->handle,
1650 DBUS_TYPE_UINT16, &ad->param1,
1651 DBUS_TYPE_UINT16, &ad->error,
1654 pa_log("%s: Failed to build D-Bus message message '%s'",
1659 if (!dbus_connection_send(conn, msg, NULL)) {
1660 pa_log("%s: Failed to send D-Bus message '%s'", __FILE__, method);
1665 dbus_message_unref(msg);
1670 static const char *method_str(am_method m)
1673 case audiomgr_register_domain: return AUDIOMGR_REGISTER_DOMAIN;
1674 case audiomgr_domain_complete: return AUDIOMGR_DOMAIN_COMPLETE;
1675 case audiomgr_deregister_domain: return AUDIOMGR_DEREGISTER_DOMAIN;
1676 case audiomgr_register_source: return AUDIOMGR_REGISTER_SOURCE;
1677 case audiomgr_deregister_source: return AUDIOMGR_DEREGISTER_SOURCE;
1678 case audiomgr_register_sink: return AUDIOMGR_REGISTER_SINK;
1679 case audiomgr_deregister_sink: return AUDIOMGR_DEREGISTER_SINK;
1680 case audiomgr_connect: return AUDIOMGR_CONNECT;
1681 case audiomgr_connect_ack: return AUDIOMGR_CONNECT_ACK;
1682 case audiomgr_disconnect: return AUDIOMGR_DISCONNECT;
1683 case audiomgr_disconnect_ack: return AUDIOMGR_DISCONNECT_ACK;
1684 case audiomgr_setsinkvol_ack: return AUDIOMGR_SETSINKVOL_ACK;
1685 case audiomgr_setsrcvol_ack: return AUDIOMGR_SETSRCVOL_ACK;
1686 case audiomgr_sinkvoltick_ack: return AUDIOMGR_SINKVOLTICK_ACK;
1687 case audiomgr_srcvoltick_ack: return AUDIOMGR_SRCVOLTICK_ACK;
1688 case audiomgr_setsinkprop_ack: return AUDIOMGR_SETSINKPROP_ACK;
1689 default: return "invalid_method";
1696 * indent-tabs-mode: nil