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;
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 free_routerif(pa_routerif *,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 routerif_connect(struct userdata *, DBusMessage *);
159 static pa_bool_t routerif_disconnect(struct userdata *, DBusMessage *);
161 static const char *method_str(am_method);
164 pa_routerif *pa_routerif_init(struct userdata *u,
165 const char *dbustype,
172 static const DBusObjectPathVTable vtable = {
173 .message_function = audiomgr_method_handler,
176 pa_module *m = u->module;
177 pa_routerif *routerif = NULL;
179 DBusConnection *dbusconn;
192 if (!dbustype || !strcasecmp(dbustype, "session")) {
193 dbustype = "session";
194 type = DBUS_BUS_SESSION;
196 else if (!strcasecmp(dbustype, "system")) {
198 type = DBUS_BUS_SYSTEM;
201 pa_log("invalid dbus type '%s'", dbustype);
205 routerif = pa_xnew0(pa_routerif, 1);
206 PA_LLIST_HEAD_INIT(struct pending, routerif->pendlist);
208 dbus_error_init(&error);
209 routerif->conn = pa_dbus_bus_get(m->core, type, &error);
211 if (routerif->conn == NULL || dbus_error_is_set(&error)) {
212 pa_log("%s: failed to get %s Bus: %s: %s",
213 __FILE__, dbustype, error.name, error.message);
217 dbusconn = pa_dbus_connection_get(routerif->conn);
219 flags = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;
220 result = dbus_bus_request_name(dbusconn, PULSE_DBUS_NAME, flags,&error);
222 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER &&
223 result != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER ) {
224 pa_log("%s: D-Bus name request failed: %s: %s",
225 __FILE__, error.name, error.message);
229 pa_log_info("%s: now owner of '%s' D-Bus name on %s bus",
230 __FILE__, PULSE_DBUS_NAME, dbustype);
232 if (!dbus_connection_add_filter(dbusconn, filter,u, NULL)) {
233 pa_log("%s: failed to add filter function", __FILE__);
238 ifnam = POLICY_DBUS_INTERFACE;
241 mrppath = POLICY_DBUS_MRPPATH;
244 mrpnam = POLICY_DBUS_MRPNAME;
246 if (ampath && *ampath) {
247 char *slash = ampath[strlen(ampath)-1] == '/' ? "" : "/";
248 snprintf(pathbuf, sizeof(pathbuf), "%s%s" AUDIOMGR_DBUS_ROUTE_PATH,
253 ampath = AUDIOMGR_DBUS_PATH;
254 amrpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_ROUTE_PATH;
257 if (amnam && *amnam){
258 char *dot = amnam[strlen(amnam)-1] == '.' ? "" : ".";
259 snprintf(nambuf, sizeof(nambuf), "%s%s" AUDIOMGR_DBUS_ROUTE_NAME,
264 amnam = AUDIOMGR_DBUS_INTERFACE;
265 amrnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_ROUTE_NAME;
269 snprintf(admmrule, sizeof(admmrule), "type='signal',sender='%s',path='%s',"
270 "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
271 ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
273 dbus_bus_add_match(dbusconn, admmrule, &error);
275 snprintf(admarule, sizeof(admarule), "type='signal',sender='%s',path='%s',"
276 "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
277 ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
279 dbus_bus_add_match(dbusconn, admarule, &error);
281 if (dbus_error_is_set(&error)) {
282 pa_log("%s: unable to subscribe name change signals on %s: %s: %s",
283 __FILE__, ADMIN_DBUS_INTERFACE, error.name, error.message);
287 snprintf(actrule, sizeof(actrule), "type='signal',interface='%s',"
288 "member='%s',path='%s/%s'", ifnam, POLICY_ACTIONS,
289 mrppath, POLICY_DECISION);
290 dbus_bus_add_match(dbusconn, actrule, &error);
292 if (dbus_error_is_set(&error)) {
293 pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
294 __FILE__, POLICY_ACTIONS, ifnam, error.name, error.message);
298 snprintf(strrule, sizeof(strrule), "type='signal',interface='%s',"
299 "member='%s',path='%s/%s'", ifnam, POLICY_STREAM_INFO,
300 mrppath, POLICY_DECISION);
301 dbus_bus_add_match(dbusconn, strrule, &error);
303 if (dbus_error_is_set(&error)) {
304 pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
305 __FILE__, POLICY_STREAM_INFO, ifnam, error.name, error.message);
309 pa_log_info("%s: subscribed policy signals on %s", __FILE__, ifnam);
311 dbus_connection_register_object_path(dbusconn, PULSE_DBUS_PATH, &vtable,u);
314 routerif->ifnam = pa_xstrdup(ifnam);
315 routerif->mrppath = pa_xstrdup(mrppath);
316 routerif->mrpnam = pa_xstrdup(mrpnam);
317 routerif->ampath = pa_xstrdup(ampath);
318 routerif->amnam = pa_xstrdup(amnam);
319 routerif->amrpath = pa_xstrdup(amrpath);
320 routerif->amrnam = pa_xstrdup(amrnam);
321 routerif->admmrule = pa_xstrdup(admmrule);
322 routerif->admarule = pa_xstrdup(admarule);
323 routerif->actrule = pa_xstrdup(actrule);
324 routerif->strrule = pa_xstrdup(strrule);
326 u->routerif = routerif; /* Argh.. */
328 register_to_murphy(u);
329 register_to_audiomgr(u);
334 free_routerif(routerif, u);
335 dbus_error_free(&error);
339 static void free_routerif(pa_routerif *routerif, struct userdata *u)
341 DBusConnection *dbusconn;
342 struct pending *p, *n;
346 if (routerif->conn) {
347 dbusconn = pa_dbus_connection_get(routerif->conn);
349 PA_LLIST_FOREACH_SAFE(p,n, routerif->pendlist) {
350 PA_LLIST_REMOVE(struct pending, routerif->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, routerif->admmrule, NULL);
360 dbus_bus_remove_match(dbusconn, routerif->admarule, NULL);
361 dbus_bus_remove_match(dbusconn, routerif->actrule, NULL);
362 dbus_bus_remove_match(dbusconn, routerif->strrule, NULL);
364 pa_dbus_connection_unref(routerif->conn);
367 pa_xfree(routerif->ifnam);
368 pa_xfree(routerif->mrppath);
369 pa_xfree(routerif->mrpnam);
370 pa_xfree(routerif->ampath);
371 pa_xfree(routerif->amnam);
372 pa_xfree(routerif->amrpath);
373 pa_xfree(routerif->amrnam);
374 pa_xfree(routerif->admmrule);
375 pa_xfree(routerif->admarule);
376 pa_xfree(routerif->actrule);
377 pa_xfree(routerif->strrule);
383 void pa_routerif_done(struct userdata *u)
385 if (u && u->routerif) {
386 free_routerif(u->routerif, 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 pa_routerif *routerif;
430 pa_assert_se((routerif = u->routerif));
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, routerif->mrpnam)) {
444 if (after && strcmp(after, "")) {
445 pa_log_debug("murphy is up");
447 if (!routerif->mregist) {
448 register_to_murphy(u);
452 if (name && before && (!after || !strcmp(after, ""))) {
453 pa_log_info("murphy is gone");
454 routerif->mregist = 0;
458 if (!strcmp(name, routerif->amnam)) {
459 if (after && strcmp(after, "")) {
460 pa_log_debug("audio manager is up");
462 if (!routerif->amisup) {
463 register_to_audiomgr(u);
467 if (name && before && (!after || !strcmp(after, ""))) {
468 pa_log_info("audio manager is gone");
470 if (routerif->amisup)
471 unregister_from_audiomgr(u);
473 routerif->amisup = 0;
479 static void reply_cb(DBusPendingCall *pend, void *data)
481 struct pending *pdata = (struct pending *)data;
483 pa_routerif *routerif;
487 pa_assert(pdata->call == pend);
488 pa_assert_se((u = pdata->u));
489 pa_assert_se((routerif = u->routerif));
491 PA_LLIST_REMOVE(struct pending, routerif->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 pa_routerif *routerif;
513 struct pending *pdata = NULL;
515 DBusPendingCall *pend;
521 pa_assert_se((routerif = u->routerif));
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, routerif->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, routerif->pendlist, pdata);
552 pa_xfree((void *)pdata->method);
553 pa_xfree((void *)pdata);
559 /**************************************************************************
565 void pa_routerif_send_device_state(struct userdata *u, char *state,
566 char **types, int ntype)
568 static char *path = (char *)"/org/tizen/policy/info";
570 pa_routerif *routerif = u->routerif;
571 DBusConnection *conn = pa_dbus_connection_get(routerif->conn);
578 if (!types || ntype < 1)
581 msg = dbus_message_new_signal(path, routerif->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_routerif_send_media_status(struct userdata *u, const char *media,
616 const char *group, int active)
618 static char *path = (char *)"/org/tizen/policy/info";
619 static const char *type = "media";
621 pa_routerif *routerif = u->routerif;
622 DBusConnection *conn = pa_dbus_connection_get(routerif->conn);
627 msg = dbus_message_new_signal(path, routerif->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 { "org.tizen.policy.audio_route" , audio_route_parser },
738 { "org.tizen.policy.volume_limit", volume_limit_parser },
739 { "org.tizen.policy.audio_cork" , audio_cork_parser },
740 { "org.tizen.policy.audio_mute" , audio_mute_parser },
741 { "org.tizen.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->routerif->amisup = 1;
850 static pa_bool_t register_to_murphy(struct userdata *u)
852 static const char *name = "pulseaudio";
854 pa_routerif *routerif = u->routerif;
855 DBusConnection *conn = pa_dbus_connection_get(routerif->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__, routerif->mrpnam, routerif->mrppath,routerif->ifnam);
865 msg = dbus_message_new_method_call(routerif->mrpnam, routerif->mrppath,
866 routerif->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 pa_routerif *routerif = u->routerif;
902 DBusConnection *conn = pa_dbus_connection_get(routerif->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", routerif->mrppath, POLICY_DECISION);
918 pa_log_debug("sending signal to: path='%s', if='%s' member='%s' "
919 "content: txid=%d status=%d", path, routerif->ifnam,
920 POLICY_STATUS, txid, status);
922 msg = dbus_message_new_signal(path, routerif->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 , routerif_connect },
973 { AUDIOMGR_DISCONNECT, routerif_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->routerif->amisup = 1;
1082 pa_audiomgr_domain_registered(u, domain_id, status, data);
1090 pa_bool_t pa_routerif_register_domain(struct userdata *u,
1091 am_domainreg_data *dr)
1093 pa_routerif *routerif;
1094 DBusConnection *conn;
1096 const char *dbus_name;
1097 const char *dbus_path;
1098 const char *dbus_if;
1103 pa_assert_se((routerif = u->routerif));
1104 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1106 pa_log_info("%s: registering to AudioManager: name='%s' path='%s' if='%s'"
1107 , __FILE__, routerif->amnam, routerif->amrpath, routerif->amrnam);
1109 msg = dbus_message_new_method_call(routerif->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_routerif_domain_complete(struct userdata *u, uint16_t domain)
1155 dbus_int32_t id32 = domain;
1156 pa_routerif *routerif;
1157 DBusConnection *conn;
1162 pa_assert_se((routerif = u->routerif));
1163 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1166 pa_log_debug("%s: domain %u AudioManager %s", __FUNCTION__,
1167 domain, AUDIOMGR_DOMAIN_COMPLETE);
1169 msg = dbus_message_new_method_call(routerif->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_routerif_unregister_domain(struct userdata *u, uint16_t domain)
1203 pa_routerif *routerif;
1204 DBusConnection *conn;
1209 pa_assert_se((routerif = u->routerif));
1210 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1212 pa_log_info("%s: deregistreing domain %u from AudioManager",
1215 msg = dbus_message_new_method_call(routerif->amnam,
1218 AUDIOMGR_DEREGISTER_DOMAIN);
1220 pa_log("%s: Failed to create D-Bus message for '%s'",
1221 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1226 dbus_message_set_no_reply(msg, TRUE);
1228 success = dbus_message_append_args(msg,
1229 DBUS_TYPE_UINT16, &domain,
1232 pa_log("%s: Failed to build D-Bus message for '%s'",
1233 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1237 if (!dbus_connection_send(conn, msg, NULL)) {
1238 pa_log("%s: Failed to send '%s'", __FILE__,AUDIOMGR_DEREGISTER_DOMAIN);
1242 dbus_connection_flush(conn);
1245 dbus_message_unref(msg);
1250 static void audiomgr_register_node_cb(struct userdata *u,
1255 const char *error_descr;
1256 dbus_uint16_t object_id;
1257 dbus_uint16_t status;
1259 const char *objtype;
1266 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1267 success = dbus_message_get_args(reply, NULL,
1268 DBUS_TYPE_STRING, &error_descr,
1272 error_descr = dbus_message_get_error_name(reply);
1274 pa_log_info("%s: AudioManager registration failed: %s",
1275 __FILE__, error_descr);
1278 success = dbus_message_get_args(reply, NULL,
1279 DBUS_TYPE_UINT16, &object_id,
1280 DBUS_TYPE_UINT16, &status,
1284 pa_log("got broken message from AudioManager.Registration failed");
1287 if (!strncasecmp("register", method, 8))
1288 objtype = method + 8;
1292 pa_log_info("AudioManager replied to registration: %sID: %u",
1293 objtype, object_id);
1295 pa_audiomgr_node_registered(u, object_id, status, data);
1300 static pa_bool_t build_sound_properties(DBusMessageIter *mit,
1301 struct am_nodereg_data *rd)
1303 static int16_t zero;
1305 DBusMessageIter ait, sit;
1308 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
1309 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
1310 #define CONT_CLOSE(p,c) dbus_message_iter_close_container(p, c)
1312 if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(nn)", &ait))
1315 for (i = 1; i < 3; i++) {
1316 if (! CONT_OPEN (&ait, DBUS_TYPE_STRUCT, NULL, &sit) ||
1317 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &i ) ||
1318 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &zero ) ||
1319 ! CONT_CLOSE (&ait, &sit) )
1325 if (!CONT_CLOSE(mit, &ait))
1335 static pa_bool_t build_connection_formats(DBusMessageIter *mit,
1336 struct am_nodereg_data *rd)
1338 DBusMessageIter ait;
1341 #define CONT_OPEN(t,s) dbus_message_iter_open_container(mit, t, s, &ait)
1342 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&ait, t, v)
1343 #define CONT_CLOSE dbus_message_iter_close_container(mit, &ait)
1345 if (!CONT_OPEN(DBUS_TYPE_ARRAY, "n"))
1348 for (i = 1; i < 2; i++) {
1349 if (!CONT_APPEND(DBUS_TYPE_INT16, &i))
1363 pa_bool_t pa_routerif_register_node(struct userdata *u,
1365 am_nodereg_data *rd)
1367 const char *method = method_str(m);
1368 pa_routerif *routerif;
1369 DBusConnection *conn;
1371 DBusMessageIter mit;
1372 DBusMessageIter cit;
1373 pa_bool_t success = FALSE;
1377 pa_assert_se((routerif = u->routerif));
1378 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1380 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,rd->name);
1382 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1383 routerif->amrnam, method);
1386 pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1391 #define MSG_APPEND(t,v) dbus_message_iter_append_basic(&mit, t, v)
1392 #define CONT_OPEN(t,s) dbus_message_iter_open_container(&mit, t, s, &cit)
1393 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&cit, t, v)
1394 #define CONT_CLOSE dbus_message_iter_close_container(&mit, &cit)
1396 dbus_message_iter_init_append(msg, &mit);
1398 if ((!strcmp(method, AUDIOMGR_REGISTER_SINK) &&
1399 (! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
1400 ! MSG_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
1401 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
1402 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
1403 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
1404 ! MSG_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
1405 ! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
1406 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.status) ||
1407 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.reason) ||
1409 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->mute ) ||
1410 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->mainvol ) ||
1411 ! build_sound_properties(&mit, rd) ||
1412 ! build_connection_formats(&mit, rd) ||
1413 ! build_sound_properties(&mit, rd) )) ||
1414 (!strcmp(method, AUDIOMGR_REGISTER_SOURCE) &&
1415 (! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
1416 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
1417 ! MSG_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
1418 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
1419 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->state ) ||
1420 ! MSG_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
1421 ! MSG_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
1422 ! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
1423 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.status) ||
1424 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->avail.reason) ||
1426 ! MSG_APPEND ( DBUS_TYPE_UINT16 , &rd->interrupt ) ||
1427 ! build_sound_properties(&mit, rd) ||
1428 ! build_connection_formats(&mit, rd) ||
1429 ! build_sound_properties(&mit, rd) )))
1431 pa_log("%s: failed to build message for AudioManager '%s'",
1442 success = send_message_with_reply(u, conn, msg,
1443 audiomgr_register_node_cb, rd);
1445 pa_log("%s: Failed to %s", __FILE__, method);
1450 dbus_message_unref(msg);
1454 static void audiomgr_unregister_node_cb(struct userdata *u,
1459 const char *error_descr;
1460 dbus_uint16_t status;
1462 const char *objtype;
1469 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1470 success = dbus_message_get_args(reply, NULL,
1471 DBUS_TYPE_STRING, &error_descr,
1475 error_descr = dbus_message_get_error_name(reply);
1477 pa_log_info("%s: AudioManager deregistration failed: %s",
1478 __FILE__, error_descr);
1481 success = dbus_message_get_args(reply, NULL,
1482 DBUS_TYPE_UINT16, &status,
1486 pa_log("got broken message from AudioManager. "
1487 "Deregistration failed");
1490 if (!strncasecmp("deregister", method, 10))
1491 objtype = method + 10;
1495 pa_log_info("AudioManager replied to %s deregistration: %u",
1498 pa_audiomgr_node_unregistered(u, data);
1503 pa_bool_t pa_routerif_unregister_node(struct userdata *u,
1505 am_nodeunreg_data *ud)
1507 const char *method = method_str(m);
1508 pa_routerif *routerif;
1509 DBusConnection *conn;
1511 pa_bool_t success = FALSE;
1515 pa_assert_se((routerif = u->routerif));
1516 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1518 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,ud->name);
1520 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1521 routerif->amrnam, method);
1524 pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1528 success = dbus_message_append_args(msg,
1529 DBUS_TYPE_INT16, &ud->id,
1532 success = send_message_with_reply(u, conn, msg,
1533 audiomgr_unregister_node_cb,ud);
1535 pa_log("%s: Failed to %s", __FILE__, method);
1540 dbus_message_unref(msg);
1544 static pa_bool_t routerif_connect(struct userdata *u, DBusMessage *msg)
1546 struct am_connect_data ac;
1552 memset(&ac, 0, sizeof(ac));
1554 success = dbus_message_get_args(msg, NULL,
1555 DBUS_TYPE_UINT16, &ac.handle,
1556 DBUS_TYPE_UINT16, &ac.connection,
1557 DBUS_TYPE_UINT16, &ac.source,
1558 DBUS_TYPE_UINT16, &ac.sink,
1559 DBUS_TYPE_INT16 , &ac.format,
1562 pa_log("%s: got broken connect message from AudioManager. "
1563 "Ignoring it", __FILE__);
1567 pa_log_debug("AudioManager connect(%u|%u|%u|%u|%d)",
1568 ac.handle, ac.connection, ac.source, ac.sink, ac.format);
1570 pa_audiomgr_connect(u, &ac);
1575 static pa_bool_t routerif_disconnect(struct userdata *u, DBusMessage *msg)
1577 struct am_connect_data ac;
1583 memset(&ac, 0, sizeof(ac));
1585 success = dbus_message_get_args(msg, NULL,
1586 DBUS_TYPE_UINT16, &ac.handle,
1587 DBUS_TYPE_UINT16, &ac.connection,
1590 pa_log("%s: got broken disconnect message from AudioManager. "
1591 "Ignoring it", __FILE__);
1595 pa_log_debug("AudioManager disconnect(%u|%u)", ac.handle, ac.connection);
1597 pa_audiomgr_disconnect(u, &ac);
1602 pa_bool_t pa_routerif_acknowledge(struct userdata *u, am_method m,
1603 struct am_ack_data *ad)
1605 const char *method = method_str(m);
1606 pa_routerif *routerif;
1607 DBusConnection *conn;
1613 pa_assert_se((routerif = u->routerif));
1614 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1616 pa_log_debug("%s: sending %s", __FILE__, method);
1618 msg = dbus_message_new_method_call(routerif->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);
1651 static const char *method_str(am_method m)
1654 case audiomgr_register_domain: return AUDIOMGR_REGISTER_DOMAIN;
1655 case audiomgr_domain_complete: return AUDIOMGR_DOMAIN_COMPLETE;
1656 case audiomgr_deregister_domain: return AUDIOMGR_DEREGISTER_DOMAIN;
1657 case audiomgr_register_source: return AUDIOMGR_REGISTER_SOURCE;
1658 case audiomgr_deregister_source: return AUDIOMGR_DEREGISTER_SOURCE;
1659 case audiomgr_register_sink: return AUDIOMGR_REGISTER_SINK;
1660 case audiomgr_deregister_sink: return AUDIOMGR_DEREGISTER_SINK;
1661 case audiomgr_connect: return AUDIOMGR_CONNECT;
1662 case audiomgr_connect_ack: return AUDIOMGR_CONNECT_ACK;
1663 case audiomgr_disconnect: return AUDIOMGR_DISCONNECT;
1664 case audiomgr_disconnect_ack: return AUDIOMGR_DISCONNECT_ACK;
1665 case audiomgr_setsinkvol_ack: return AUDIOMGR_SETSINKVOL_ACK;
1666 case audiomgr_setsrcvol_ack: return AUDIOMGR_SETSRCVOL_ACK;
1667 case audiomgr_sinkvoltick_ack: return AUDIOMGR_SINKVOLTICK_ACK;
1668 case audiomgr_srcvoltick_ack: return AUDIOMGR_SRCVOLTICK_ACK;
1669 case audiomgr_setsinkprop_ack: return AUDIOMGR_SETSINKPROP_ACK;
1670 default: return "invalid_method";
1677 * indent-tabs-mode: nil