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 AUDIOMGR_DBUS_INTERFACE "org.genivi.audiomanager"
39 #define AUDIOMGR_DBUS_PATH "/org/genivi/audiomanager"
41 #define AUDIOMGR_DBUS_ROUTE_NAME "RoutingInterface"
42 #define AUDIOMGR_DBUS_ROUTE_PATH "RoutingInterface"
44 #define AUDIOMGR_DBUS_CONTROL_NAME "ControlInterface"
45 #define AUDIOMGR_DBUS_CONTROL_PATH "ControlInterface"
47 #define PULSE_DBUS_INTERFACE "org.genivi.pulse"
48 #define PULSE_DBUS_PATH "/org/genivi/pulse"
49 #define PULSE_DBUS_NAME "org.genivi.pulse"
51 #define STRUCT_OFFSET(s,m) ((char *)&(((s *)0)->m) - (char *)0)
53 typedef void (*pending_cb_t)(struct userdata *, const char *,
54 DBusMessage *, void *);
55 typedef bool (*method_t)(struct userdata *, DBusMessage *);
58 PA_LLIST_FIELDS(struct pending);
61 DBusPendingCall *call;
67 pa_dbus_connection *conn;
68 char *ampath; /* audio manager path */
69 char *amnam; /* audio manager name */
70 char *amrpath; /* audio manager routing path */
71 char *amrnam; /* audio manager routing name */
72 char *amcpath; /* audio manager control path */
73 char *amcnam; /* audio manager control name */
74 char *admarule; /* match rule to catch audiomgr name change*/
75 int amisup; /* is the audio manager up */
76 PA_LLIST_HEAD(struct pending, pendlist);
79 struct actdsc { /* action descriptor */
81 int (*parser)(struct userdata *u, DBusMessageIter *iter);
84 struct argdsc { /* argument descriptor for actions */
90 struct argrt { /* audio_route arguments */
97 struct argvol { /* volume_limit arguments */
102 struct argcork { /* audio_cork arguments */
112 struct argctx { /* context arguments */
117 static void free_routerif(pa_routerif *,struct userdata *);
119 static bool send_message_with_reply(struct userdata *,
120 DBusConnection *, DBusMessage *,
121 pending_cb_t, void *);
123 static DBusHandlerResult filter(DBusConnection *, DBusMessage *, void *);
124 static void handle_admin_message(struct userdata *, DBusMessage *);
125 static bool register_to_controlif(struct userdata *);
126 static DBusHandlerResult audiomgr_method_handler(DBusConnection *,
127 DBusMessage *, void *);
128 static void audiomgr_register_domain_cb(struct userdata *, const char *,
129 DBusMessage *, void *);
130 static bool register_to_audiomgr(struct userdata *);
131 static bool unregister_from_audiomgr(struct userdata *);
132 static void audiomgr_register_node_cb(struct userdata *, const char *,
133 DBusMessage *, void *);
134 static void audiomgr_unregister_node_cb(struct userdata *, const char *,
135 DBusMessage *, void *);
136 static bool build_sound_properties(DBusMessageIter *,
137 struct am_nodereg_data *);
138 static bool build_connection_formats(DBusMessageIter *,
139 struct am_nodereg_data *);
140 static bool routerif_connect(struct userdata *, DBusMessage *);
141 static bool routerif_disconnect(struct userdata *, DBusMessage *);
143 static const char *method_str(am_method);
145 pa_routerif *pa_routerif_init(struct userdata *u,
146 const char *dbustype,
150 static const DBusObjectPathVTable vtable = {
151 .message_function = audiomgr_method_handler,
154 pa_module *m = u->module;
155 pa_routerif *routerif = NULL;
157 DBusConnection *dbusconn;
163 char ctlpathbuf[128];
171 if (!dbustype || !strcasecmp(dbustype, "session")) {
172 dbustype = "session";
173 type = DBUS_BUS_SESSION;
175 else if (!strcasecmp(dbustype, "system")) {
177 type = DBUS_BUS_SYSTEM;
180 pa_log("invalid dbus type '%s'", dbustype);
184 routerif = pa_xnew0(pa_routerif, 1);
185 PA_LLIST_HEAD_INIT(struct pending, routerif->pendlist);
187 dbus_error_init(&error);
188 routerif->conn = pa_dbus_bus_get(m->core, type, &error);
190 if (routerif->conn == NULL || dbus_error_is_set(&error)) {
191 pa_log("%s: failed to get %s Bus: %s: %s",
192 __FILE__, dbustype, error.name, error.message);
196 dbusconn = pa_dbus_connection_get(routerif->conn);
198 flags = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;
199 result = dbus_bus_request_name(dbusconn, PULSE_DBUS_NAME, flags,&error);
201 if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER &&
202 result != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER ) {
203 pa_log("%s: D-Bus name request failed: %s: %s",
204 __FILE__, error.name, error.message);
208 pa_log_info("%s: now owner of '%s' D-Bus name on %s bus",
209 __FILE__, PULSE_DBUS_NAME, dbustype);
211 if (!dbus_connection_add_filter(dbusconn, filter,u, NULL)) {
212 pa_log("%s: failed to add filter function", __FILE__);
216 if (ampath && *ampath) {
217 char *slash = ampath[strlen(ampath)-1] == '/' ? "" : "/";
218 snprintf(pathbuf, sizeof(pathbuf), "%s%s" AUDIOMGR_DBUS_ROUTE_PATH,
221 snprintf(ctlpathbuf, sizeof(ctlpathbuf), "%s%s" AUDIOMGR_DBUS_CONTROL_PATH,
223 amcpath = ctlpathbuf;
226 ampath = AUDIOMGR_DBUS_PATH;
227 amrpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_ROUTE_PATH;
228 amcpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_CONTROL_PATH;
231 if (amnam && *amnam){
232 char *dot = amnam[strlen(amnam)-1] == '.' ? "" : ".";
233 snprintf(nambuf, sizeof(nambuf), "%s%s" AUDIOMGR_DBUS_ROUTE_NAME,
236 snprintf(ctlnambuf, sizeof(ctlnambuf), "%s%s" AUDIOMGR_DBUS_CONTROL_NAME,
241 amnam = AUDIOMGR_DBUS_INTERFACE;
242 amrnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_ROUTE_NAME;
243 amcnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_CONTROL_NAME;
246 snprintf(admarule, sizeof(admarule), "type='signal',sender='%s',path='%s',"
247 "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
248 ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
250 dbus_bus_add_match(dbusconn, admarule, &error);
252 if (dbus_error_is_set(&error)) {
253 pa_log("%s: unable to subscribe name change signals on %s: %s: %s",
254 __FILE__, ADMIN_DBUS_INTERFACE, error.name, error.message);
258 dbus_connection_register_object_path(dbusconn, PULSE_DBUS_PATH, &vtable,u);
260 routerif->ampath = pa_xstrdup(ampath);
261 routerif->amnam = pa_xstrdup(amnam);
262 routerif->amrpath = pa_xstrdup(amrpath);
263 routerif->amrnam = pa_xstrdup(amrnam);
264 routerif->amcpath = pa_xstrdup(amcpath);
265 routerif->amcnam = pa_xstrdup(amcnam);
266 routerif->admarule = pa_xstrdup(admarule);
268 u->routerif = routerif; /* Argh.. */
270 register_to_controlif(u);
271 register_to_audiomgr(u);
276 free_routerif(routerif, u);
277 dbus_error_free(&error);
281 static void free_routerif(pa_routerif *routerif, struct userdata *u)
283 DBusConnection *dbusconn;
284 struct pending *p, *n;
288 if (routerif->conn) {
289 dbusconn = pa_dbus_connection_get(routerif->conn);
291 PA_LLIST_FOREACH_SAFE(p,n, routerif->pendlist) {
292 PA_LLIST_REMOVE(struct pending, routerif->pendlist, p);
293 dbus_pending_call_set_notify(p->call, NULL,NULL, NULL);
294 dbus_pending_call_unref(p->call);
298 dbus_connection_remove_filter(dbusconn, filter,u);
301 dbus_bus_remove_match(dbusconn, routerif->admarule, NULL);
303 pa_dbus_connection_unref(routerif->conn);
306 pa_xfree(routerif->ampath);
307 pa_xfree(routerif->amnam);
308 pa_xfree(routerif->amrpath);
309 pa_xfree(routerif->amrnam);
310 pa_xfree(routerif->amcpath);
311 pa_xfree(routerif->amcnam);
312 pa_xfree(routerif->admarule);
318 void pa_routerif_done(struct userdata *u)
320 if (u && u->routerif) {
321 free_routerif(u->routerif, u);
326 static DBusHandlerResult filter(DBusConnection *conn, DBusMessage *msg,
329 struct userdata *u = arg;
331 if (dbus_message_is_signal(msg, ADMIN_DBUS_INTERFACE,
332 ADMIN_NAME_OWNER_CHANGED))
334 handle_admin_message(u, msg);
335 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
338 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
342 static void handle_admin_message(struct userdata *u, DBusMessage *msg)
344 pa_routerif *routerif;
351 pa_assert_se((routerif = u->routerif));
353 success = dbus_message_get_args(msg, NULL,
354 DBUS_TYPE_STRING, &name,
355 DBUS_TYPE_STRING, &before,
356 DBUS_TYPE_STRING, &after,
359 if (!success || !name) {
360 pa_log("Received malformed '%s' message", ADMIN_NAME_OWNER_CHANGED);
364 if (!strcmp(name, routerif->amnam)) {
365 if (after && strcmp(after, "")) {
366 pa_log_debug("audio manager is up");
368 if (!routerif->amisup) {
369 register_to_audiomgr(u);
373 if (name && before && (!after || !strcmp(after, ""))) {
374 pa_log_info("audio manager is gone");
376 if (routerif->amisup)
377 unregister_from_audiomgr(u);
379 routerif->amisup = 0;
384 static void reply_cb(DBusPendingCall *pend, void *data)
386 struct pending *pdata = (struct pending *)data;
388 pa_routerif *routerif;
392 pa_assert(pdata->call == pend);
393 pa_assert_se((u = pdata->u));
394 pa_assert_se((routerif = u->routerif));
396 PA_LLIST_REMOVE(struct pending, routerif->pendlist, pdata);
398 if ((reply = dbus_pending_call_steal_reply(pend)) == NULL) {
399 pa_log("%s: Murphy pending call '%s' failed: invalid argument",
400 __FILE__, pdata->method);
403 pdata->cb(u, pdata->method, reply, pdata->data);
404 dbus_message_unref(reply);
407 pa_xfree((void *)pdata->method);
408 pa_xfree((void *)pdata);
411 static bool send_message_with_reply(struct userdata *u,
412 DBusConnection *conn,
417 pa_routerif *routerif;
418 struct pending *pdata = NULL;
420 DBusPendingCall *pend;
426 pa_assert_se((routerif = u->routerif));
428 if ((method = dbus_message_get_member(msg)) == NULL)
431 pdata = pa_xnew0(struct pending, 1);
433 pdata->method = pa_xstrdup(method);
437 PA_LLIST_PREPEND(struct pending, routerif->pendlist, pdata);
439 if (!dbus_connection_send_with_reply(conn, msg, &pend, -1)) {
440 pa_log("%s: Failed to %s", __FILE__, method);
446 if (!dbus_pending_call_set_notify(pend, reply_cb,pdata, NULL)) {
447 pa_log("%s: Can't set notification for %s", __FILE__, method);
456 PA_LLIST_REMOVE(struct pending, routerif->pendlist, pdata);
457 pa_xfree((void *)pdata->method);
458 pa_xfree((void *)pdata);
463 static bool register_to_controlif(struct userdata *u)
468 /**************************************************************************
470 * Audio Manager interfaces
473 static DBusHandlerResult audiomgr_method_handler(DBusConnection *conn,
482 static struct dispatch dispatch_tbl[] = {
483 { AUDIOMGR_CONNECT , routerif_connect },
484 { AUDIOMGR_DISCONNECT, routerif_disconnect },
488 struct userdata *u = (struct userdata *)arg;
501 if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
503 name = dbus_message_get_member(msg);
504 // serial = dbus_message_get_serial(msg);
508 for (method = NULL, d = dispatch_tbl; d->name; d++) {
509 if (!strcmp(name, d->name)) {
515 errcod = method ? E_OK : E_NOT_POSSIBLE;
516 reply = dbus_message_new_method_return(msg);
518 // dbus_message_set_reply_serial(reply, serial);
520 success = dbus_message_append_args(reply,
521 DBUS_TYPE_INT16, &errcod,
524 if (!success || !dbus_connection_send(conn, reply, NULL))
525 pa_log("%s: failed to reply '%s'", __FILE__, name);
527 pa_log_debug("'%s' replied (%d)", name, errcod);
529 dbus_message_unref(reply);
534 pa_log_info("%s: unsupported '%s' method ignored", __FILE__, name);
536 return DBUS_HANDLER_RESULT_HANDLED;
539 pa_log_debug("got some unexpected type of D-Bus message");
541 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
545 static bool register_to_audiomgr(struct userdata *u)
547 pa_audiomgr_register_domain(u);
551 static bool unregister_from_audiomgr(struct userdata *u)
553 pa_audiomgr_unregister_domain(u, false);
557 static void audiomgr_register_domain_cb(struct userdata *u,
562 const char *error_descr;
563 dbus_uint16_t domain_id;
564 dbus_uint16_t status;
567 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
568 success = dbus_message_get_args(reply, NULL,
569 DBUS_TYPE_STRING, &error_descr,
573 error_descr = dbus_message_get_error_name(reply);
575 pa_log_info("%s: AudioManager domain registration failed: %s",
576 __FILE__, error_descr);
579 success = dbus_message_get_args(reply, NULL,
580 DBUS_TYPE_UINT16, &domain_id,
581 DBUS_TYPE_UINT16, &status,
585 pa_log("got broken message from AudioManager.Registration failed");
588 pa_log_info("AudioManager replied to registration: "
589 "domainID %u, status %u", domain_id, status);
592 u->routerif->amisup = 1;
593 pa_audiomgr_domain_registered(u, domain_id, status, data);
599 bool pa_routerif_register_domain(struct userdata *u,
600 am_domainreg_data *dr)
602 pa_routerif *routerif;
603 DBusConnection *conn;
605 DBusMessageIter iter;
606 DBusMessageIter sub_iter;
607 const char *dbus_name;
608 const char *dbus_path;
614 pa_assert_se((routerif = u->routerif));
615 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
617 pa_log_info("%s: registering to AudioManager: name='%s' path='%s' if='%s'"
618 , __FILE__, routerif->amnam, routerif->amrpath, routerif->amrnam);
620 msg = dbus_message_new_method_call(routerif->amnam,
623 AUDIOMGR_REGISTER_DOMAIN);
625 pa_log("%s: Failed to create D-Bus message to '%s'",
626 __FILE__, AUDIOMGR_REGISTER_DOMAIN);
631 dbus_name = PULSE_DBUS_NAME;
632 dbus_path = PULSE_DBUS_PATH;
633 dbus_if = PULSE_DBUS_INTERFACE;
635 dbus_message_iter_init_append(msg, &iter);
636 success = dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &sub_iter);
638 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_UINT16, &dr->domain_id);
639 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &dr->name);
640 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &dr->bus_name);
641 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &dr->node_name);
642 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_BOOLEAN, &dr->early);
643 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_BOOLEAN, &dr->complete);
644 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_UINT16 , &dr->state);
646 success = success && dbus_message_iter_close_container(&iter, &sub_iter);
648 success = success && dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING , &dbus_name);
649 success = success && dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING , &dbus_path);
650 success = success && dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING , &dbus_if);
653 pa_log("%s: Failed to build D-Bus message to register", __FILE__);
657 success = send_message_with_reply(u, conn, msg,
658 audiomgr_register_domain_cb, dr);
660 pa_log("%s: Failed to register", __FILE__);
665 dbus_message_unref(msg);
669 bool pa_routerif_domain_complete(struct userdata *u, uint16_t domain)
671 dbus_int32_t id32 = domain;
672 pa_routerif *routerif;
673 DBusConnection *conn;
678 pa_assert_se((routerif = u->routerif));
679 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
682 pa_log_debug("%s: domain %u AudioManager %s", __FUNCTION__,
683 domain, AUDIOMGR_DOMAIN_COMPLETE);
685 msg = dbus_message_new_method_call(routerif->amnam,
688 AUDIOMGR_DOMAIN_COMPLETE);
690 pa_log("%s: Failed to create D-Bus message for '%s'",
691 __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
696 success = dbus_message_append_args(msg,
697 DBUS_TYPE_UINT16, &id32,
700 pa_log("%s: Failed to build D-Bus message for '%s'",
701 __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
705 if (!dbus_connection_send(conn, msg, NULL)) {
706 pa_log("%s: Failed to send '%s'", __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
710 dbus_connection_flush(conn);
713 dbus_message_unref(msg);
717 bool pa_routerif_unregister_domain(struct userdata *u, uint16_t domain)
719 pa_routerif *routerif;
720 DBusConnection *conn;
725 pa_assert_se((routerif = u->routerif));
726 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
728 pa_log_info("%s: deregistreing domain %u from AudioManager",
731 msg = dbus_message_new_method_call(routerif->amnam,
734 AUDIOMGR_DEREGISTER_DOMAIN);
736 pa_log("%s: Failed to create D-Bus message for '%s'",
737 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
742 dbus_message_set_no_reply(msg, true);
744 success = dbus_message_append_args(msg,
745 DBUS_TYPE_UINT16, &domain,
748 pa_log("%s: Failed to build D-Bus message for '%s'",
749 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
753 if (!dbus_connection_send(conn, msg, NULL)) {
754 pa_log("%s: Failed to send '%s'", __FILE__,AUDIOMGR_DEREGISTER_DOMAIN);
758 dbus_connection_flush(conn);
761 dbus_message_unref(msg);
766 static void audiomgr_register_node_cb(struct userdata *u,
771 const char *error_descr;
772 dbus_uint16_t object_id;
773 dbus_uint16_t status;
782 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
783 success = dbus_message_get_args(reply, NULL,
784 DBUS_TYPE_STRING, &error_descr,
788 error_descr = dbus_message_get_error_name(reply);
790 pa_log_info("%s: AudioManager registration failed: %s",
791 __FILE__, error_descr);
794 success = dbus_message_get_args(reply, NULL,
795 DBUS_TYPE_UINT16, &object_id,
796 DBUS_TYPE_UINT16, &status,
800 pa_log("got broken message from AudioManager.Registration failed");
803 if (!strncasecmp("register", method, 8))
804 objtype = method + 8;
808 pa_log_info("AudioManager replied to registration: %sID: %u",
811 pa_audiomgr_node_registered(u, object_id, status, data);
816 static bool build_sound_properties(DBusMessageIter *mit,
817 struct am_nodereg_data *rd)
821 DBusMessageIter ait, sit;
824 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
825 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
826 #define CONT_CLOSE(p,c) dbus_message_iter_close_container(p, c)
828 if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(nn)", &ait))
831 for (i = 1; i < 3; i++) {
832 if (! CONT_OPEN (&ait, DBUS_TYPE_STRUCT, NULL, &sit) ||
833 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &i ) ||
834 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &zero ) ||
835 ! CONT_CLOSE (&ait, &sit) )
841 if (!CONT_CLOSE(mit, &ait))
851 static bool build_connection_formats(DBusMessageIter *mit,
852 struct am_nodereg_data *rd)
857 #define CONT_OPEN(t,s) dbus_message_iter_open_container(mit, t, s, &ait)
858 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&ait, t, v)
859 #define CONT_CLOSE dbus_message_iter_close_container(mit, &ait)
861 if (!CONT_OPEN(DBUS_TYPE_ARRAY, "n"))
864 for (i = 1; i < 2; i++) {
865 if (!CONT_APPEND(DBUS_TYPE_INT16, &i))
879 bool pa_routerif_register_node(struct userdata *u,
883 const char *method = method_str(m);
884 pa_routerif *routerif;
885 DBusConnection *conn;
890 bool success = false;
894 pa_assert_se((routerif = u->routerif));
895 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
897 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,rd->name);
899 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
900 routerif->amrnam, method);
903 pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
907 #define MSG_APPEND(t,v) dbus_message_iter_append_basic(&mit, t, v)
908 #define CONT_OPEN(t,s) dbus_message_iter_open_container(&mit, t, s, &cit)
909 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&cit, t, v)
910 #define CONT_CLOSE dbus_message_iter_close_container(&mit, &cit)
912 #define CONT_OPEN_1(t,s) dbus_message_iter_open_container(&cit, t, s, &dit)
913 #define CONT_APPEND_1(t,v) dbus_message_iter_append_basic(&dit, t, v)
914 #define CONT_CLOSE_1 dbus_message_iter_close_container(&cit, &dit)
916 dbus_message_iter_init_append(msg, &mit);
918 if ((!strcmp(method, AUDIOMGR_REGISTER_SINK) &&
919 (! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
920 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
921 ! CONT_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
922 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
923 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
924 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
925 ! CONT_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
926 ! CONT_OPEN_1 ( DBUS_TYPE_STRUCT , NULL ) ||
927 ! CONT_APPEND_1 ( DBUS_TYPE_INT16 , &rd->avail.status) ||
928 ! CONT_APPEND_1 ( DBUS_TYPE_INT16 , &rd->avail.reason) ||
930 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->mute ) ||
931 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->mainvol ) ||
932 ! build_sound_properties(&cit, rd) ||
933 ! build_connection_formats(&cit, rd) ||
934 ! build_sound_properties(&cit, rd) ||
936 (!strcmp(method, AUDIOMGR_REGISTER_SOURCE) &&
937 (! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
938 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
939 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
940 ! CONT_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
941 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
942 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->state ) ||
943 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
944 ! CONT_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
945 ! CONT_OPEN_1 ( DBUS_TYPE_STRUCT , NULL ) ||
946 ! CONT_APPEND_1 ( DBUS_TYPE_INT16 , &rd->avail.status) ||
947 ! CONT_APPEND_1 ( DBUS_TYPE_INT16 , &rd->avail.reason) ||
949 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->interrupt ) ||
950 ! build_sound_properties(&cit, rd) ||
951 ! build_connection_formats(&cit, rd) ||
952 ! build_sound_properties(&cit, rd) ||
955 pa_log("%s: failed to build message for AudioManager '%s'",
969 success = send_message_with_reply(u, conn, msg,
970 audiomgr_register_node_cb, rd);
972 pa_log("%s: Failed to %s", __FILE__, method);
977 dbus_message_unref(msg);
981 static void audiomgr_unregister_node_cb(struct userdata *u,
986 const char *error_descr;
987 dbus_uint16_t status;
996 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
997 success = dbus_message_get_args(reply, NULL,
998 DBUS_TYPE_STRING, &error_descr,
1002 error_descr = dbus_message_get_error_name(reply);
1004 pa_log_info("%s: AudioManager deregistration failed: %s",
1005 __FILE__, error_descr);
1008 success = dbus_message_get_args(reply, NULL,
1009 DBUS_TYPE_UINT16, &status,
1013 pa_log("got broken message from AudioManager. "
1014 "Deregistration failed");
1017 if (!strncasecmp("deregister", method, 10))
1018 objtype = method + 10;
1022 pa_log_info("AudioManager replied to %s deregistration: %u",
1025 pa_audiomgr_node_unregistered(u, data);
1030 bool pa_routerif_unregister_node(struct userdata *u,
1032 am_nodeunreg_data *ud)
1034 const char *method = method_str(m);
1035 pa_routerif *routerif;
1036 DBusConnection *conn;
1038 bool success = false;
1042 pa_assert_se((routerif = u->routerif));
1043 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1045 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,ud->name);
1047 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1048 routerif->amrnam, method);
1051 pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1055 success = dbus_message_append_args(msg,
1056 DBUS_TYPE_INT16, &ud->id,
1059 success = send_message_with_reply(u, conn, msg,
1060 audiomgr_unregister_node_cb,ud);
1062 pa_log("%s: Failed to %s", __FILE__, method);
1067 dbus_message_unref(msg);
1071 bool pa_routerif_register_implicit_connection(struct userdata *u,
1072 am_connect_data *cd)
1074 static const char *method = AUDIOMGR_IMPLICIT_CONNECTION;
1076 pa_routerif *routerif;
1077 DBusConnection *conn;
1079 bool success = false;
1083 pa_assert_se((routerif = u->routerif));
1084 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1086 pa_log_debug("%s: register implicit connection", __FUNCTION__);
1088 msg = dbus_message_new_method_call(routerif->amnam, routerif->amcpath,
1089 routerif->amcnam, method);
1091 pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1095 dbus_message_set_no_reply(msg, true);
1097 success = dbus_message_append_args(msg,
1098 DBUS_TYPE_INT16 , &cd->format,
1099 DBUS_TYPE_UINT16, &cd->source,
1100 DBUS_TYPE_UINT16, &cd->sink,
1103 pa_log("%s: failed to build message for %s", __FILE__, method);
1107 success = dbus_connection_send(conn, msg, NULL);
1110 pa_log("%s: Failed to %s", __FILE__, method);
1115 dbus_message_unref(msg);
1119 bool pa_routerif_register_implicit_connections(struct userdata *u,
1121 am_connect_data *conns)
1124 static const char *method = AUDIOMGR_IMPLICIT_CONNECTIONS;
1125 static dbus_uint16_t zero;
1127 pa_routerif *routerif;
1128 DBusConnection *conn;
1130 DBusMessageIter mit;
1131 DBusMessageIter ait;
1132 DBusMessageIter sit;
1133 am_connect_data *cd;
1135 bool success = false;
1138 pa_assert(nconn > 0);
1140 pa_assert_se((routerif = u->routerif));
1141 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1143 pa_log_debug("%s: register %d implicit connections", __FUNCTION__, nconn);
1145 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1146 routerif->amrnam, method);
1148 pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1152 dbus_message_set_no_reply(msg, true);
1153 dbus_message_iter_init_append(msg, &mit);
1155 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
1156 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
1157 #define CONT_CLOSE(p,c) dbus_message_iter_close_container(p, c)
1159 if (!CONT_OPEN(&mit, DBUS_TYPE_ARRAY, "(qqqqn)", &ait)) {
1160 pa_log("%s: failed to open array iterator for %s", __FILE__, method);
1164 for (i = 0; i < nconn; i++) {
1167 if (! CONT_OPEN (&ait, DBUS_TYPE_STRUCT, NULL, &sit ) ||
1168 ! CONT_APPEND (&sit, DBUS_TYPE_UINT16, &cd->connection) ||
1169 ! CONT_APPEND (&sit, DBUS_TYPE_UINT16, &cd->source ) ||
1170 ! CONT_APPEND (&sit, DBUS_TYPE_UINT16, &cd->sink ) ||
1171 ! CONT_APPEND (&sit, DBUS_TYPE_UINT16, &zero ) ||
1172 ! CONT_APPEND (&sit, DBUS_TYPE_INT16 , &cd->format ) ||
1173 ! CONT_CLOSE (&ait, &sit ) )
1175 pa_log("%s: failed to build conn struct for %s", __FILE__, method);
1180 if (!CONT_CLOSE(&mit, &ait)) {
1181 pa_log("%s: failed to close array iterator for %s", __FILE__, method);
1190 success = dbus_connection_send(conn, msg, NULL);
1193 pa_log("%s: Failed to %s", __FILE__, method);
1198 dbus_message_unref(msg);
1204 static bool routerif_connect(struct userdata *u, DBusMessage *msg)
1206 struct am_connect_data ac;
1212 memset(&ac, 0, sizeof(ac));
1214 success = dbus_message_get_args(msg, NULL,
1215 DBUS_TYPE_UINT16, &ac.handle,
1216 DBUS_TYPE_UINT16, &ac.connection,
1217 DBUS_TYPE_UINT16, &ac.source,
1218 DBUS_TYPE_UINT16, &ac.sink,
1219 DBUS_TYPE_INT16 , &ac.format,
1222 pa_log("%s: got broken connect message from AudioManager. "
1223 "Ignoring it", __FILE__);
1227 pa_log_debug("AudioManager connect(%u|%u|%u|%u|%d)",
1228 ac.handle, ac.connection, ac.source, ac.sink, ac.format);
1230 pa_audiomgr_connect(u, &ac);
1235 static bool routerif_disconnect(struct userdata *u, DBusMessage *msg)
1237 struct am_connect_data ac;
1243 memset(&ac, 0, sizeof(ac));
1245 success = dbus_message_get_args(msg, NULL,
1246 DBUS_TYPE_UINT16, &ac.handle,
1247 DBUS_TYPE_UINT16, &ac.connection,
1250 pa_log("%s: got broken disconnect message from AudioManager. "
1251 "Ignoring it", __FILE__);
1255 pa_log_debug("AudioManager disconnect(%u|%u)", ac.handle, ac.connection);
1257 pa_audiomgr_disconnect(u, &ac);
1262 bool pa_routerif_acknowledge(struct userdata *u, am_method m,
1263 struct am_ack_data *ad)
1265 const char *method = method_str(m);
1266 pa_routerif *routerif;
1267 DBusConnection *conn;
1273 pa_assert_se((routerif = u->routerif));
1274 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1276 pa_log_debug("%s: sending %s", __FILE__, method);
1278 msg = dbus_message_new_method_call(routerif->amnam,
1283 pa_log("%s: Failed to create D-Bus message for '%s'",
1289 success = dbus_message_append_args(msg,
1290 DBUS_TYPE_UINT16, &ad->handle,
1291 DBUS_TYPE_UINT16, &ad->param1,
1292 DBUS_TYPE_UINT16, &ad->error,
1295 pa_log("%s: Failed to build D-Bus message message '%s'",
1300 if (!dbus_connection_send(conn, msg, NULL)) {
1301 pa_log("%s: Failed to send D-Bus message '%s'", __FILE__, method);
1306 dbus_message_unref(msg);
1311 static const char *method_str(am_method m)
1314 case audiomgr_register_domain: return AUDIOMGR_REGISTER_DOMAIN;
1315 case audiomgr_domain_complete: return AUDIOMGR_DOMAIN_COMPLETE;
1316 case audiomgr_deregister_domain: return AUDIOMGR_DEREGISTER_DOMAIN;
1317 case audiomgr_register_source: return AUDIOMGR_REGISTER_SOURCE;
1318 case audiomgr_deregister_source: return AUDIOMGR_DEREGISTER_SOURCE;
1319 case audiomgr_register_sink: return AUDIOMGR_REGISTER_SINK;
1320 case audiomgr_deregister_sink: return AUDIOMGR_DEREGISTER_SINK;
1321 case audiomgr_implicit_connection: return AUDIOMGR_IMPLICIT_CONNECTION;
1322 case audiomgr_implicit_connections: return AUDIOMGR_IMPLICIT_CONNECTIONS;
1323 case audiomgr_connect: return AUDIOMGR_CONNECT;
1324 case audiomgr_connect_ack: return AUDIOMGR_CONNECT_ACK;
1325 case audiomgr_disconnect: return AUDIOMGR_DISCONNECT;
1326 case audiomgr_disconnect_ack: return AUDIOMGR_DISCONNECT_ACK;
1327 case audiomgr_setsinkvol_ack: return AUDIOMGR_SETSINKVOL_ACK;
1328 case audiomgr_setsrcvol_ack: return AUDIOMGR_SETSRCVOL_ACK;
1329 case audiomgr_sinkvoltick_ack: return AUDIOMGR_SINKVOLTICK_ACK;
1330 case audiomgr_srcvoltick_ack: return AUDIOMGR_SRCVOLTICK_ACK;
1331 case audiomgr_setsinkprop_ack: return AUDIOMGR_SETSINKPROP_ACK;
1332 default: return "invalid_method";
1339 * indent-tabs-mode: nil