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;
615 pa_assert_se((routerif = u->routerif));
616 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
618 pa_log_info("%s: registering to AudioManager: name='%s' path='%s' if='%s'"
619 , __FILE__, routerif->amnam, routerif->amrpath, routerif->amrnam);
621 msg = dbus_message_new_method_call(routerif->amnam,
624 AUDIOMGR_REGISTER_DOMAIN);
626 pa_log("%s: Failed to create D-Bus message to '%s'",
627 __FILE__, AUDIOMGR_REGISTER_DOMAIN);
632 dbus_name = PULSE_DBUS_NAME;
633 dbus_path = PULSE_DBUS_PATH;
634 dbus_if = PULSE_DBUS_INTERFACE;
636 dbus_message_iter_init_append(msg, &iter);
637 success = dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &sub_iter);
639 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_UINT16, &dr->domain_id);
640 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &dr->name);
641 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &dr->bus_name);
642 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_STRING, &dr->node_name);
643 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_BOOLEAN, &dr->early);
644 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_BOOLEAN, &dr->complete);
645 success = success && dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_INT16 , &dr->state);
647 success = success && dbus_message_iter_close_container(&iter, &sub_iter);
649 success = success && dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING , &dbus_name);
650 success = success && dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING , &dbus_path);
651 success = success && dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING , &dbus_if);
653 success = success && dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16, &dr->domain_id);
654 success = success && dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16, &error);
657 pa_log("%s: Failed to build D-Bus message to register", __FILE__);
661 success = send_message_with_reply(u, conn, msg,
662 audiomgr_register_domain_cb, dr);
664 pa_log("%s: Failed to register", __FILE__);
669 dbus_message_unref(msg);
673 bool pa_routerif_domain_complete(struct userdata *u, uint16_t domain)
675 dbus_int32_t id32 = domain;
676 pa_routerif *routerif;
677 DBusConnection *conn;
682 pa_assert_se((routerif = u->routerif));
683 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
686 pa_log_debug("%s: domain %u AudioManager %s", __FUNCTION__,
687 domain, AUDIOMGR_DOMAIN_COMPLETE);
689 msg = dbus_message_new_method_call(routerif->amnam,
692 AUDIOMGR_DOMAIN_COMPLETE);
694 pa_log("%s: Failed to create D-Bus message for '%s'",
695 __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
700 success = dbus_message_append_args(msg,
701 DBUS_TYPE_UINT16, &id32,
704 pa_log("%s: Failed to build D-Bus message for '%s'",
705 __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
709 if (!dbus_connection_send(conn, msg, NULL)) {
710 pa_log("%s: Failed to send '%s'", __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
714 dbus_connection_flush(conn);
717 dbus_message_unref(msg);
721 bool pa_routerif_unregister_domain(struct userdata *u, uint16_t domain)
723 pa_routerif *routerif;
724 DBusConnection *conn;
729 pa_assert_se((routerif = u->routerif));
730 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
732 pa_log_info("%s: deregistreing domain %u from AudioManager",
735 msg = dbus_message_new_method_call(routerif->amnam,
738 AUDIOMGR_DEREGISTER_DOMAIN);
740 pa_log("%s: Failed to create D-Bus message for '%s'",
741 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
746 dbus_message_set_no_reply(msg, true);
748 success = dbus_message_append_args(msg,
749 DBUS_TYPE_UINT16, &domain,
752 pa_log("%s: Failed to build D-Bus message for '%s'",
753 __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
757 if (!dbus_connection_send(conn, msg, NULL)) {
758 pa_log("%s: Failed to send '%s'", __FILE__,AUDIOMGR_DEREGISTER_DOMAIN);
762 dbus_connection_flush(conn);
765 dbus_message_unref(msg);
770 static void audiomgr_register_node_cb(struct userdata *u,
775 const char *error_descr;
776 dbus_uint16_t object_id;
777 dbus_uint16_t status;
786 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
787 success = dbus_message_get_args(reply, NULL,
788 DBUS_TYPE_STRING, &error_descr,
792 error_descr = dbus_message_get_error_name(reply);
794 pa_log_info("%s: AudioManager registration failed: %s",
795 __FILE__, error_descr);
798 success = dbus_message_get_args(reply, NULL,
799 DBUS_TYPE_UINT16, &object_id,
800 DBUS_TYPE_UINT16, &status,
804 pa_log("got broken message from AudioManager.Registration failed");
807 if (!strncasecmp("register", method, 8))
808 objtype = method + 8;
812 pa_log_info("AudioManager replied to registration: %sID: %u",
815 pa_audiomgr_node_registered(u, object_id, status, data);
820 static bool build_sound_properties(DBusMessageIter *mit,
821 struct am_nodereg_data *rd)
825 DBusMessageIter ait, sit;
828 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
829 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
830 #define CONT_CLOSE(p,c) dbus_message_iter_close_container(p, c)
832 if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(in)", &ait))
835 for (i = 1; i < 3; i++) {
836 if (! CONT_OPEN (&ait, DBUS_TYPE_STRUCT, NULL, &sit) ||
837 ! CONT_APPEND (&sit, DBUS_TYPE_INT32, &i ) ||
838 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &zero ) ||
839 ! CONT_CLOSE (&ait, &sit) )
845 if (!CONT_CLOSE(mit, &ait))
855 static bool build_connection_formats(DBusMessageIter *mit,
856 struct am_nodereg_data *rd)
861 #define CONT_OPEN(t,s) dbus_message_iter_open_container(mit, t, s, &ait)
862 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&ait, t, v)
863 #define CONT_CLOSE dbus_message_iter_close_container(mit, &ait)
865 if (!CONT_OPEN(DBUS_TYPE_ARRAY, "i"))
868 for (i = 1; i < 2; i++) {
869 if (!CONT_APPEND(DBUS_TYPE_INT32, &i))
883 static bool build_notification_properties(DBusMessageIter *mit,
884 struct am_nodereg_data *rd)
888 DBusMessageIter ait, sit;
891 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
892 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
893 #define CONT_CLOSE(p,c) dbus_message_iter_close_container(p, c)
895 if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(iin)", &ait))
898 for (i = 1; i < 3; i++) {
899 if (! CONT_OPEN (&ait, DBUS_TYPE_STRUCT, NULL, &sit) ||
900 ! CONT_APPEND (&sit, DBUS_TYPE_INT32, &i ) ||
901 ! CONT_APPEND (&sit, DBUS_TYPE_INT32, &i ) ||
902 ! CONT_APPEND (&sit, DBUS_TYPE_INT16, &zero ) ||
903 ! CONT_CLOSE (&ait, &sit) )
909 if (!CONT_CLOSE(mit, &ait))
919 bool pa_routerif_register_node(struct userdata *u,
923 const char *method = method_str(m);
924 pa_routerif *routerif;
925 DBusConnection *conn;
930 bool success = false;
934 pa_assert_se((routerif = u->routerif));
935 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
937 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,rd->name);
939 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
940 routerif->amrnam, method);
943 pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
947 #define MSG_APPEND(t,v) dbus_message_iter_append_basic(&mit, t, v)
948 #define CONT_OPEN(t,s) dbus_message_iter_open_container(&mit, t, s, &cit)
949 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&cit, t, v)
950 #define CONT_CLOSE dbus_message_iter_close_container(&mit, &cit)
952 #define CONT_OPEN_1(t,s) dbus_message_iter_open_container(&cit, t, s, &dit)
953 #define CONT_APPEND_1(t,v) dbus_message_iter_append_basic(&dit, t, v)
954 #define CONT_CLOSE_1 dbus_message_iter_close_container(&cit, &dit)
956 dbus_message_iter_init_append(msg, &mit);
958 if ((!strcmp(method, AUDIOMGR_REGISTER_SINK) &&
959 (! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
960 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
961 ! CONT_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
962 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
963 ! CONT_APPEND ( DBUS_TYPE_INT32 , &rd->class ) ||
964 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
965 ! CONT_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
966 ! CONT_OPEN_1 ( DBUS_TYPE_STRUCT , NULL ) ||
967 ! CONT_APPEND_1 ( DBUS_TYPE_INT32 , &rd->avail.status) ||
968 ! CONT_APPEND_1 ( DBUS_TYPE_INT32 , &rd->avail.reason) ||
970 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->mute ) ||
971 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->mainvol ) ||
972 ! build_sound_properties(&cit, rd) ||
973 ! build_connection_formats(&cit, rd) ||
974 ! build_sound_properties(&cit, rd) ||
975 ! build_notification_properties(&cit, rd) ||
976 ! build_notification_properties(&cit, rd) ||
978 (!strcmp(method, AUDIOMGR_REGISTER_SOURCE) &&
979 (! CONT_OPEN ( DBUS_TYPE_STRUCT , NULL ) ||
980 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->id ) ||
981 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->domain ) ||
982 ! CONT_APPEND ( DBUS_TYPE_STRING , &rd->name ) ||
983 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->class ) ||
984 ! CONT_APPEND ( DBUS_TYPE_INT32 , &rd->state ) ||
985 ! CONT_APPEND ( DBUS_TYPE_INT16 , &rd->volume ) ||
986 ! CONT_APPEND ( DBUS_TYPE_BOOLEAN, &rd->visible ) ||
987 ! CONT_OPEN_1 ( DBUS_TYPE_STRUCT , NULL ) ||
988 ! CONT_APPEND_1 ( DBUS_TYPE_INT32 , &rd->avail.status) ||
989 ! CONT_APPEND_1 ( DBUS_TYPE_INT32 , &rd->avail.reason) ||
991 ! CONT_APPEND ( DBUS_TYPE_UINT16 , &rd->interrupt ) ||
992 ! build_sound_properties(&cit, rd) ||
993 ! build_connection_formats(&cit, rd) ||
994 ! build_sound_properties(&cit, rd) ||
995 ! build_notification_properties(&cit, rd) ||
996 ! build_notification_properties(&cit, rd) ||
999 pa_log("%s: failed to build message for AudioManager '%s'",
1010 #undef CONT_APPEND_1
1013 success = send_message_with_reply(u, conn, msg,
1014 audiomgr_register_node_cb, rd);
1016 pa_log("%s: Failed to %s", __FILE__, method);
1021 dbus_message_unref(msg);
1025 static void audiomgr_unregister_node_cb(struct userdata *u,
1030 const char *error_descr;
1031 dbus_uint16_t status;
1033 const char *objtype;
1040 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1041 success = dbus_message_get_args(reply, NULL,
1042 DBUS_TYPE_STRING, &error_descr,
1046 error_descr = dbus_message_get_error_name(reply);
1048 pa_log_info("%s: AudioManager deregistration failed: %s",
1049 __FILE__, error_descr);
1052 success = dbus_message_get_args(reply, NULL,
1053 DBUS_TYPE_UINT16, &status,
1057 pa_log("got broken message from AudioManager. "
1058 "Deregistration failed");
1061 if (!strncasecmp("deregister", method, 10))
1062 objtype = method + 10;
1066 pa_log_info("AudioManager replied to %s deregistration: %u",
1069 pa_audiomgr_node_unregistered(u, data);
1074 bool pa_routerif_unregister_node(struct userdata *u,
1076 am_nodeunreg_data *ud)
1078 const char *method = method_str(m);
1079 pa_routerif *routerif;
1080 DBusConnection *conn;
1082 bool success = false;
1086 pa_assert_se((routerif = u->routerif));
1087 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1089 pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,ud->name);
1091 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1092 routerif->amrnam, method);
1095 pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1099 success = dbus_message_append_args(msg,
1100 DBUS_TYPE_INT16, &ud->id,
1103 success = send_message_with_reply(u, conn, msg,
1104 audiomgr_unregister_node_cb,ud);
1106 pa_log("%s: Failed to %s", __FILE__, method);
1111 dbus_message_unref(msg);
1115 bool pa_routerif_register_implicit_connection(struct userdata *u,
1116 am_connect_data *cd)
1118 static const char *method = AUDIOMGR_IMPLICIT_CONNECTION;
1120 pa_routerif *routerif;
1121 DBusConnection *conn;
1123 bool success = false;
1127 pa_assert_se((routerif = u->routerif));
1128 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1130 pa_log_debug("%s: register implicit connection", __FUNCTION__);
1132 msg = dbus_message_new_method_call(routerif->amnam, routerif->amcpath,
1133 routerif->amcnam, method);
1135 pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1139 dbus_message_set_no_reply(msg, true);
1141 success = dbus_message_append_args(msg,
1142 DBUS_TYPE_INT16 , &cd->format,
1143 DBUS_TYPE_UINT16, &cd->source,
1144 DBUS_TYPE_UINT16, &cd->sink,
1147 pa_log("%s: failed to build message for %s", __FILE__, method);
1151 success = dbus_connection_send(conn, msg, NULL);
1154 pa_log("%s: Failed to %s", __FILE__, method);
1159 dbus_message_unref(msg);
1163 bool pa_routerif_register_implicit_connections(struct userdata *u,
1165 am_connect_data *conns)
1168 static const char *method = AUDIOMGR_IMPLICIT_CONNECTIONS;
1169 static dbus_uint16_t zero;
1171 pa_routerif *routerif;
1172 DBusConnection *conn;
1174 DBusMessageIter mit;
1175 DBusMessageIter ait;
1176 DBusMessageIter sit;
1177 am_connect_data *cd;
1179 bool success = false;
1182 pa_assert(nconn > 0);
1184 pa_assert_se((routerif = u->routerif));
1185 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1187 pa_log_debug("%s: register %d implicit connections", __FUNCTION__, nconn);
1189 msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1190 routerif->amrnam, method);
1192 pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1196 dbus_message_set_no_reply(msg, true);
1197 dbus_message_iter_init_append(msg, &mit);
1199 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
1200 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
1201 #define CONT_CLOSE(p,c) dbus_message_iter_close_container(p, c)
1203 if (!CONT_OPEN(&mit, DBUS_TYPE_ARRAY, "(qqqqn)", &ait)) {
1204 pa_log("%s: failed to open array iterator for %s", __FILE__, method);
1208 for (i = 0; i < nconn; i++) {
1211 if (! CONT_OPEN (&ait, DBUS_TYPE_STRUCT, NULL, &sit ) ||
1212 ! CONT_APPEND (&sit, DBUS_TYPE_UINT16, &cd->connection) ||
1213 ! CONT_APPEND (&sit, DBUS_TYPE_UINT16, &cd->source ) ||
1214 ! CONT_APPEND (&sit, DBUS_TYPE_UINT16, &cd->sink ) ||
1215 ! CONT_APPEND (&sit, DBUS_TYPE_UINT16, &zero ) ||
1216 ! CONT_APPEND (&sit, DBUS_TYPE_INT16 , &cd->format ) ||
1217 ! CONT_CLOSE (&ait, &sit ) )
1219 pa_log("%s: failed to build conn struct for %s", __FILE__, method);
1224 if (!CONT_CLOSE(&mit, &ait)) {
1225 pa_log("%s: failed to close array iterator for %s", __FILE__, method);
1234 success = dbus_connection_send(conn, msg, NULL);
1237 pa_log("%s: Failed to %s", __FILE__, method);
1242 dbus_message_unref(msg);
1248 static bool routerif_connect(struct userdata *u, DBusMessage *msg)
1250 struct am_connect_data ac;
1256 memset(&ac, 0, sizeof(ac));
1258 success = dbus_message_get_args(msg, NULL,
1259 DBUS_TYPE_UINT16, &ac.handle,
1260 DBUS_TYPE_UINT16, &ac.connection,
1261 DBUS_TYPE_UINT16, &ac.source,
1262 DBUS_TYPE_UINT16, &ac.sink,
1263 DBUS_TYPE_INT32 , &ac.format,
1266 pa_log("%s: got broken connect message from AudioManager. "
1267 "Ignoring it", __FILE__);
1271 pa_log_debug("AudioManager connect(%u|%u|%u|%u|%d)",
1272 ac.handle, ac.connection, ac.source, ac.sink, ac.format);
1274 pa_audiomgr_connect(u, &ac);
1279 static bool routerif_disconnect(struct userdata *u, DBusMessage *msg)
1281 struct am_connect_data ac;
1287 memset(&ac, 0, sizeof(ac));
1289 success = dbus_message_get_args(msg, NULL,
1290 DBUS_TYPE_UINT16, &ac.handle,
1291 DBUS_TYPE_UINT16, &ac.connection,
1294 pa_log("%s: got broken disconnect message from AudioManager. "
1295 "Ignoring it", __FILE__);
1299 pa_log_debug("AudioManager disconnect(%u|%u)", ac.handle, ac.connection);
1301 pa_audiomgr_disconnect(u, &ac);
1306 bool pa_routerif_acknowledge(struct userdata *u, am_method m,
1307 struct am_ack_data *ad)
1309 const char *method = method_str(m);
1310 pa_routerif *routerif;
1311 DBusConnection *conn;
1317 pa_assert_se((routerif = u->routerif));
1318 pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1320 pa_log_debug("%s: sending %s", __FILE__, method);
1322 msg = dbus_message_new_method_call(routerif->amnam,
1327 pa_log("%s: Failed to create D-Bus message for '%s'",
1333 success = dbus_message_append_args(msg,
1334 DBUS_TYPE_UINT16, &ad->handle,
1335 DBUS_TYPE_UINT16, &ad->param1,
1336 DBUS_TYPE_UINT16, &ad->error,
1339 pa_log("%s: Failed to build D-Bus message message '%s'",
1344 if (!dbus_connection_send(conn, msg, NULL)) {
1345 pa_log("%s: Failed to send D-Bus message '%s'", __FILE__, method);
1350 dbus_message_unref(msg);
1355 static const char *method_str(am_method m)
1358 case audiomgr_register_domain: return AUDIOMGR_REGISTER_DOMAIN;
1359 case audiomgr_domain_complete: return AUDIOMGR_DOMAIN_COMPLETE;
1360 case audiomgr_deregister_domain: return AUDIOMGR_DEREGISTER_DOMAIN;
1361 case audiomgr_register_source: return AUDIOMGR_REGISTER_SOURCE;
1362 case audiomgr_deregister_source: return AUDIOMGR_DEREGISTER_SOURCE;
1363 case audiomgr_register_sink: return AUDIOMGR_REGISTER_SINK;
1364 case audiomgr_deregister_sink: return AUDIOMGR_DEREGISTER_SINK;
1365 case audiomgr_implicit_connection: return AUDIOMGR_IMPLICIT_CONNECTION;
1366 case audiomgr_implicit_connections: return AUDIOMGR_IMPLICIT_CONNECTIONS;
1367 case audiomgr_connect: return AUDIOMGR_CONNECT;
1368 case audiomgr_connect_ack: return AUDIOMGR_CONNECT_ACK;
1369 case audiomgr_disconnect: return AUDIOMGR_DISCONNECT;
1370 case audiomgr_disconnect_ack: return AUDIOMGR_DISCONNECT_ACK;
1371 case audiomgr_setsinkvol_ack: return AUDIOMGR_SETSINKVOL_ACK;
1372 case audiomgr_setsrcvol_ack: return AUDIOMGR_SETSRCVOL_ACK;
1373 case audiomgr_sinkvoltick_ack: return AUDIOMGR_SINKVOLTICK_ACK;
1374 case audiomgr_srcvoltick_ack: return AUDIOMGR_SRCVOLTICK_ACK;
1375 case audiomgr_setsinkprop_ack: return AUDIOMGR_SETSINKPROP_ACK;
1376 default: return "invalid_method";
1383 * indent-tabs-mode: nil