murphyif: Free the connect timer when unloading
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / dbusif.c
1 /*
2  * Module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
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.
8  *
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.
13  *
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,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #include <pulsecore/pulsecore-config.h>
26 #include <pulsecore/dbus-shared.h>
27
28 #include "userdata.h"
29 #include "dbusif.h"
30 #include "audiomgr.h"
31
32 #define ADMIN_DBUS_MANAGER          "org.freedesktop.DBus"
33 #define ADMIN_DBUS_PATH             "/org/freedesktop/DBus"
34 #define ADMIN_DBUS_INTERFACE        "org.freedesktop.DBus"
35
36 #define ADMIN_NAME_OWNER_CHANGED    "NameOwnerChanged"
37
38 #define AUDIOMGR_DBUS_INTERFACE     "org.genivi.audiomanager"
39 #define AUDIOMGR_DBUS_PATH          "/org/genivi/audiomanager"
40
41 #define AUDIOMGR_DBUS_ROUTE_NAME    "routinginterface"
42 #define AUDIOMGR_DBUS_ROUTE_PATH    "routinginterface"
43
44 #define AUDIOMGR_DBUS_CONTROL_NAME    "controlinterface"
45 #define AUDIOMGR_DBUS_CONTROL_PATH    "controlinterface"
46
47 #define PULSE_DBUS_INTERFACE        "org.genivi.pulse"
48 #define PULSE_DBUS_PATH             "/org/genivi/pulse"
49 #define PULSE_DBUS_NAME             "org.genivi.pulse"
50
51 #define STRUCT_OFFSET(s,m) ((char *)&(((s *)0)->m) - (char *)0)
52
53 typedef void (*pending_cb_t)(struct userdata *, const char *,
54                              DBusMessage *, void *);
55 typedef bool (*method_t)(struct userdata *, DBusMessage *);
56
57 struct pending {
58     PA_LLIST_FIELDS(struct pending);
59     struct userdata  *u;
60     const char       *method;
61     DBusPendingCall  *call;
62     pending_cb_t      cb;
63     void             *data;
64 };
65
66 struct pa_routerif {
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);
77 };
78
79 struct actdsc {                 /* action descriptor */
80     const char         *name;
81     int               (*parser)(struct userdata *u, DBusMessageIter *iter);
82 };
83
84 struct argdsc {                 /* argument descriptor for actions */
85     const char         *name;
86     int                 offs;
87     int                 type;
88 };
89
90 struct argrt {                  /* audio_route arguments */
91     char               *type;
92     char               *device;
93     char               *mode;
94     char               *hwid;
95 };
96
97 struct argvol {                 /* volume_limit arguments */
98     char               *group;
99     int32_t             limit;
100 };
101
102 struct argcork {                /* audio_cork arguments */
103     char               *group;
104     char               *cork;
105 };
106
107 struct argmute {
108     char               *device;
109     char               *mute;
110 };
111
112 struct argctx {                 /* context arguments */
113     char               *variable;
114     char               *value;
115 };
116
117 static void free_routerif(pa_routerif *,struct userdata *);
118
119 static bool send_message_with_reply(struct userdata *, 
120                                          DBusConnection *, DBusMessage *,
121                                          pending_cb_t, void *);
122
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 *);
142
143 static const char *method_str(am_method);
144
145 pa_routerif *pa_routerif_init(struct userdata *u,
146                               const char      *dbustype,
147                               const char      *ampath,
148                               const char      *amnam)
149 {
150     static const DBusObjectPathVTable  vtable = {
151         .message_function = audiomgr_method_handler,
152     };
153
154     pa_module      *m = u->module;
155     pa_routerif    *routerif = NULL;
156     DBusBusType     type;
157     DBusConnection *dbusconn;
158     DBusError       error;
159     unsigned int    flags;
160     char            nambuf[128];
161     char            pathbuf[128];
162     char            ctlnambuf[128];
163     char            ctlpathbuf[128];
164     char           *amrnam;
165     char           *amrpath;
166     char           *amcnam;
167     char           *amcpath;
168     char            admarule[512];
169     int             result;
170     
171     if (!dbustype || !strcasecmp(dbustype, "session")) {
172         dbustype = "session";
173         type = DBUS_BUS_SESSION;
174     }
175     else if (!strcasecmp(dbustype, "system")) {
176         dbustype = "system";
177         type = DBUS_BUS_SYSTEM;
178     }
179     else {
180         pa_log("invalid dbus type '%s'", dbustype);
181         return NULL;
182     }
183     
184     routerif = pa_xnew0(pa_routerif, 1);
185     PA_LLIST_HEAD_INIT(struct pending, routerif->pendlist);
186
187     dbus_error_init(&error);
188     routerif->conn = pa_dbus_bus_get(m->core, type, &error);
189
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);
193         goto fail;
194     }
195
196     dbusconn = pa_dbus_connection_get(routerif->conn);
197
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);
200
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);
205         goto fail;
206     }
207     
208     pa_log_info("%s: now owner of '%s' D-Bus name on %s bus",
209                 __FILE__, PULSE_DBUS_NAME, dbustype);
210  
211     if (!dbus_connection_add_filter(dbusconn, filter,u, NULL)) {
212         pa_log("%s: failed to add filter function", __FILE__);
213         goto fail;
214     }
215
216     if (ampath && *ampath) {
217         char *slash = ampath[strlen(ampath)-1] == '/' ? "" : "/";
218         snprintf(pathbuf, sizeof(pathbuf), "%s%s" AUDIOMGR_DBUS_ROUTE_PATH,
219                  ampath, slash);
220         amrpath = pathbuf;
221         snprintf(ctlpathbuf, sizeof(ctlpathbuf), "%s%s" AUDIOMGR_DBUS_CONTROL_PATH,
222                  ampath, slash);
223         amcpath = ctlpathbuf;
224     }
225     else {
226         ampath  = AUDIOMGR_DBUS_PATH;
227         amrpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_ROUTE_PATH;
228         amcpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_CONTROL_PATH;
229     }
230
231     if (amnam && *amnam){
232         char *dot = amnam[strlen(amnam)-1] == '.' ? "" : ".";
233         snprintf(nambuf, sizeof(nambuf), "%s%s" AUDIOMGR_DBUS_ROUTE_NAME,
234                  amnam, dot);
235         amrnam = nambuf;
236         snprintf(ctlnambuf, sizeof(ctlnambuf), "%s%s" AUDIOMGR_DBUS_CONTROL_NAME,
237                  amnam, dot);
238         amcnam = ctlnambuf;
239     }
240     else {
241         amnam  = AUDIOMGR_DBUS_INTERFACE;
242         amrnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_ROUTE_NAME;
243         amcnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_CONTROL_NAME;
244     }
245
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,
249              amnam);
250     dbus_bus_add_match(dbusconn, admarule, &error);
251
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);
255         goto fail;
256     }
257
258     dbus_connection_register_object_path(dbusconn, PULSE_DBUS_PATH, &vtable,u);
259
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);
267
268     u->routerif = routerif; /* Argh.. */
269
270     register_to_controlif(u);
271     register_to_audiomgr(u);
272
273     return routerif;
274
275  fail:
276     free_routerif(routerif, u);
277     dbus_error_free(&error);
278     return NULL;
279 }
280
281 static void free_routerif(pa_routerif *routerif, struct userdata *u)
282 {
283     DBusConnection  *dbusconn;
284     struct pending  *p, *n;
285
286     if (routerif) {
287
288         if (routerif->conn) {
289             dbusconn = pa_dbus_connection_get(routerif->conn);
290
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);
295             }
296
297             if (u) {
298                 dbus_connection_remove_filter(dbusconn, filter,u);
299             }
300
301             dbus_bus_remove_match(dbusconn, routerif->admarule, NULL);
302
303             pa_dbus_connection_unref(routerif->conn);
304         }
305
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);
313
314         pa_xfree(routerif);
315     }
316 }
317
318 void pa_routerif_done(struct userdata *u)
319 {
320     if (u && u->routerif) {
321         free_routerif(u->routerif, u);
322         u->routerif = NULL;
323     }
324 }
325
326 static DBusHandlerResult filter(DBusConnection *conn, DBusMessage *msg,
327                                 void *arg)
328 {
329     struct userdata  *u = arg;
330
331     if (dbus_message_is_signal(msg, ADMIN_DBUS_INTERFACE,
332                                ADMIN_NAME_OWNER_CHANGED))
333     {
334         handle_admin_message(u, msg);
335         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
336     }
337
338     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
339 }
340
341
342 static void handle_admin_message(struct userdata *u, DBusMessage *msg)
343 {
344     pa_routerif *routerif;
345     char        *name;
346     char        *before;
347     char        *after;
348     int          success;
349
350     pa_assert(u);
351     pa_assert_se((routerif = u->routerif));
352
353     success = dbus_message_get_args(msg, NULL,
354                                     DBUS_TYPE_STRING, &name,
355                                     DBUS_TYPE_STRING, &before,
356                                     DBUS_TYPE_STRING, &after,
357                                     DBUS_TYPE_INVALID);
358
359     if (!success || !name) {
360         pa_log("Received malformed '%s' message", ADMIN_NAME_OWNER_CHANGED);
361         return;
362     }
363
364     if (!strcmp(name, routerif->amnam)) {
365         if (after && strcmp(after, "")) {
366             pa_log_debug("audio manager is up");
367
368             if (!routerif->amisup) {
369                 register_to_audiomgr(u);
370             }
371         }
372
373         if (name && before && (!after || !strcmp(after, ""))) {
374             pa_log_info("audio manager is gone");
375
376             if (routerif->amisup)
377                 unregister_from_audiomgr(u);
378
379             routerif->amisup = 0;
380         } 
381     }
382 }
383
384 static void reply_cb(DBusPendingCall *pend, void *data)
385 {
386     struct pending  *pdata = (struct pending *)data;
387     struct userdata *u;
388     pa_routerif     *routerif;
389     DBusMessage     *reply;
390
391     pa_assert(pdata);
392     pa_assert(pdata->call == pend);
393     pa_assert_se((u = pdata->u));
394     pa_assert_se((routerif = u->routerif));
395
396     PA_LLIST_REMOVE(struct pending, routerif->pendlist, pdata);
397
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);
401     }
402     else {
403         pdata->cb(u, pdata->method, reply, pdata->data);
404         dbus_message_unref(reply);
405     }
406
407     pa_xfree((void *)pdata->method);
408     pa_xfree((void *)pdata);
409 }
410
411 static bool send_message_with_reply(struct userdata *u,
412                                          DBusConnection  *conn,
413                                          DBusMessage     *msg,
414                                          pending_cb_t     cb,
415                                          void            *data)
416 {
417     pa_routerif     *routerif;
418     struct pending  *pdata = NULL;
419     const char      *method;
420     DBusPendingCall *pend;
421
422     pa_assert(u);
423     pa_assert(conn);
424     pa_assert(msg);
425     pa_assert(cb);
426     pa_assert_se((routerif = u->routerif));
427
428     if ((method = dbus_message_get_member(msg)) == NULL)
429         goto failed;
430
431     pdata = pa_xnew0(struct pending, 1);
432     pdata->u      = u;
433     pdata->method = pa_xstrdup(method);
434     pdata->cb     = cb;
435     pdata->data   = data;
436
437     PA_LLIST_PREPEND(struct pending, routerif->pendlist, pdata);
438
439     if (!dbus_connection_send_with_reply(conn, msg, &pend, -1)) {
440         pa_log("%s: Failed to %s", __FILE__, method);
441         goto failed;
442     }
443
444     pdata->call = pend;
445
446     if (!dbus_pending_call_set_notify(pend, reply_cb,pdata, NULL)) {
447         pa_log("%s: Can't set notification for %s", __FILE__, method);
448         goto failed;
449     }
450
451
452     return true;
453
454  failed:
455     if (pdata) {
456         PA_LLIST_REMOVE(struct pending, routerif->pendlist, pdata);
457         pa_xfree((void *)pdata->method);
458         pa_xfree((void *)pdata);
459     }
460     return false;
461 }
462
463 static bool register_to_controlif(struct userdata *u)
464 {
465     return true;
466 }
467
468 /**************************************************************************
469  *
470  * Audio Manager interfaces
471  *
472  */
473 static DBusHandlerResult audiomgr_method_handler(DBusConnection *conn,
474                                                  DBusMessage    *msg,
475                                                  void           *arg)
476 {
477     struct dispatch {
478         const char *name;
479         method_t    method;
480     };
481
482     static struct dispatch dispatch_tbl[] = {
483         { AUDIOMGR_CONNECT   , routerif_connect    },
484         { AUDIOMGR_DISCONNECT, routerif_disconnect },
485         {        NULL,                 NULL        }
486     };
487
488     struct userdata         *u = (struct userdata *)arg;
489     struct dispatch         *d;
490     const char              *name;
491     method_t                 method;
492     //uint32_t                 serial;
493     dbus_int16_t             errcod;
494     DBusMessage             *reply;
495     bool                success;
496
497     pa_assert(conn);
498     pa_assert(msg);
499     pa_assert(u);
500
501     if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
502
503         name = dbus_message_get_member(msg);
504         // serial = dbus_message_get_serial(msg);
505
506         pa_assert(name);
507
508         for (method = NULL, d = dispatch_tbl;  d->name;    d++) {
509             if (!strcmp(name, d->name)) {
510                 method = d->method;
511                 break;
512             }
513         }
514
515         errcod = method ? E_OK : E_NOT_POSSIBLE; 
516         reply  = dbus_message_new_method_return(msg);
517
518         // dbus_message_set_reply_serial(reply, serial);
519                 
520         success = dbus_message_append_args(reply,
521                                            DBUS_TYPE_INT16, &errcod,
522                                            DBUS_TYPE_INVALID);
523         
524         if (!success || !dbus_connection_send(conn, reply, NULL))
525             pa_log("%s: failed to reply '%s'", __FILE__, name);
526         else
527             pa_log_debug("'%s' replied (%d)", name, errcod);
528
529         dbus_message_unref(reply);
530
531         if (method)
532             d->method(u, msg);
533         else
534             pa_log_info("%s: unsupported '%s' method ignored", __FILE__, name);
535                 
536         return DBUS_HANDLER_RESULT_HANDLED;
537     }
538
539     pa_log_debug("got some unexpected type of D-Bus message");
540
541     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
542 }
543
544
545 static bool register_to_audiomgr(struct userdata *u)
546 {
547     pa_audiomgr_register_domain(u);
548     return true;
549 }
550
551 static bool unregister_from_audiomgr(struct userdata *u)
552 {
553     pa_audiomgr_unregister_domain(u, false);
554     return true;
555 }
556
557 static void audiomgr_register_domain_cb(struct userdata *u,
558                                         const char      *method,
559                                         DBusMessage     *reply,
560                                         void            *data)
561 {
562     const char        *error_descr;
563     dbus_uint16_t      domain_id;
564     dbus_uint16_t      status;
565     int                success;
566
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,
570                                         DBUS_TYPE_INVALID);
571
572         if (!success)
573             error_descr = dbus_message_get_error_name(reply);
574
575         pa_log_info("%s: AudioManager domain registration failed: %s",
576                     __FILE__, error_descr);
577     }
578     else {
579         success = dbus_message_get_args(reply, NULL,
580                                         DBUS_TYPE_UINT16, &domain_id,
581                                         DBUS_TYPE_UINT16, &status,
582                                         DBUS_TYPE_INVALID);
583
584         if (!success) {
585             pa_log("got broken message from AudioManager.Registration failed");
586         }
587         else {
588             pa_log_info("AudioManager replied to registration: "
589                         "domainID %u, status %u", domain_id, status);
590
591             if (u->routerif) {
592                 u->routerif->amisup = 1;
593                 pa_audiomgr_domain_registered(u, domain_id, status, data);
594             }
595         }
596     }
597 }
598
599 bool pa_routerif_register_domain(struct userdata   *u,
600                                  am_domainreg_data *dr)
601 {
602     pa_routerif    *routerif;
603     DBusConnection *conn;
604     DBusMessage    *msg;
605     DBusMessageIter iter;
606     DBusMessageIter sub_iter;
607     const char     *dbus_name;
608     const char     *dbus_path;
609     const char     *dbus_if;
610     int             success;
611     uint16_t         error = 0;
612
613     pa_assert(u);
614     pa_assert(dr);
615     pa_assert_se((routerif = u->routerif));
616     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
617
618     pa_log_info("%s: registering to AudioManager: name='%s' path='%s' if='%s'"
619                 , __FILE__, routerif->amnam, routerif->amrpath, routerif->amrnam);
620
621     msg = dbus_message_new_method_call(routerif->amnam,
622                                        routerif->amrpath,
623                                        routerif->amrnam,
624                                        AUDIOMGR_REGISTER_DOMAIN);
625     if (msg == NULL) {
626         pa_log("%s: Failed to create D-Bus message to '%s'",
627                __FILE__, AUDIOMGR_REGISTER_DOMAIN);
628         success = false;
629         goto getout;
630     }
631
632     dbus_name = PULSE_DBUS_NAME;
633     dbus_path = PULSE_DBUS_PATH;
634     dbus_if   = PULSE_DBUS_INTERFACE;
635
636     dbus_message_iter_init_append(msg, &iter);
637     success = dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, NULL, &sub_iter);
638
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);
646
647     success = success && dbus_message_iter_close_container(&iter, &sub_iter);
648
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);
652
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);
655
656     if (!success) {
657         pa_log("%s: Failed to build D-Bus message to register", __FILE__);
658         goto getout;
659     }
660
661     success = send_message_with_reply(u, conn, msg,
662                                       audiomgr_register_domain_cb, dr);
663     if (!success) {
664         pa_log("%s: Failed to register", __FILE__);
665         goto getout;
666     }
667
668  getout:
669     dbus_message_unref(msg);
670     return success;
671 }
672
673 bool pa_routerif_domain_complete(struct userdata *u, uint16_t domain)
674 {
675     dbus_int32_t    id32 = domain;
676     pa_routerif    *routerif;
677     DBusConnection *conn;
678     DBusMessage    *msg;
679     bool       success;
680
681     pa_assert(u);
682     pa_assert_se((routerif = u->routerif));
683     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
684     
685
686     pa_log_debug("%s: domain %u AudioManager %s", __FUNCTION__,
687                  domain, AUDIOMGR_DOMAIN_COMPLETE);
688
689     msg = dbus_message_new_method_call(routerif->amnam,
690                                        routerif->amrpath,
691                                        routerif->amrnam,
692                                        AUDIOMGR_DOMAIN_COMPLETE);
693     if (msg == NULL) {
694         pa_log("%s: Failed to create D-Bus message for '%s'",
695                __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
696         success = false;
697         goto getout;
698     }
699
700     success = dbus_message_append_args(msg,
701                                        DBUS_TYPE_UINT16,  &id32,
702                                        DBUS_TYPE_INVALID);
703     if (!success) {
704         pa_log("%s: Failed to build D-Bus message for '%s'",
705                __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
706         goto getout;
707     }
708
709     if (!dbus_connection_send(conn, msg, NULL)) {
710         pa_log("%s: Failed to send '%s'", __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
711         goto getout;
712     }
713
714     dbus_connection_flush(conn);
715
716  getout:
717     dbus_message_unref(msg);
718     return success;
719 }
720
721 bool pa_routerif_unregister_domain(struct userdata *u, uint16_t domain)
722 {
723     pa_routerif    *routerif;
724     DBusConnection *conn;
725     DBusMessage    *msg;
726     bool       success;
727
728     pa_assert(u);
729     pa_assert_se((routerif = u->routerif));
730     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
731
732     pa_log_info("%s: deregistreing domain %u from AudioManager",
733                 __FILE__, domain);
734
735     msg = dbus_message_new_method_call(routerif->amnam,
736                                        routerif->amrpath,
737                                        routerif->amrnam,
738                                        AUDIOMGR_DEREGISTER_DOMAIN);
739     if (msg == NULL) {
740         pa_log("%s: Failed to create D-Bus message for '%s'",
741                __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
742         success = false;
743         goto getout;
744     }
745
746     dbus_message_set_no_reply(msg, true);
747
748     success = dbus_message_append_args(msg,
749                                        DBUS_TYPE_UINT16,  &domain,
750                                        DBUS_TYPE_INVALID);
751     if (!success) {
752         pa_log("%s: Failed to build D-Bus message for '%s'",
753                __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
754         goto getout;
755     }
756
757     if (!dbus_connection_send(conn, msg, NULL)) {
758         pa_log("%s: Failed to send '%s'", __FILE__,AUDIOMGR_DEREGISTER_DOMAIN);
759         goto getout;
760     }
761
762     dbus_connection_flush(conn);
763
764  getout:
765     dbus_message_unref(msg);
766     return success;
767 }
768
769
770 static void audiomgr_register_node_cb(struct userdata *u,
771                                       const char      *method,
772                                       DBusMessage     *reply,
773                                       void            *data)
774 {
775     const char      *error_descr;
776     dbus_uint16_t    object_id;
777     dbus_uint16_t    status;
778     int              success;
779     const char      *objtype;
780
781     pa_assert(u);
782     pa_assert(method);
783     pa_assert(reply);
784     pa_assert(data);
785
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,
789                                         DBUS_TYPE_INVALID);
790
791         if (!success)
792             error_descr = dbus_message_get_error_name(reply);
793
794         pa_log_info("%s: AudioManager registration failed: %s",
795                     __FILE__, error_descr);
796     }
797     else {
798         success = dbus_message_get_args(reply, NULL,
799                                         DBUS_TYPE_UINT16, &object_id,
800                                         DBUS_TYPE_UINT16, &status,
801                                         DBUS_TYPE_INVALID);
802
803         if (!success) {
804             pa_log("got broken message from AudioManager.Registration failed");
805         }
806         else {
807             if (!strncasecmp("register", method, 8))
808                 objtype = method + 8;
809             else
810                 objtype = method;
811
812             pa_log_info("AudioManager replied to registration: %sID: %u",
813                         objtype, object_id);
814
815             pa_audiomgr_node_registered(u, object_id, status, data);
816         }
817     }
818 }
819
820 static bool build_sound_properties(DBusMessageIter *mit,
821                                         struct am_nodereg_data *rd)
822 {
823     static int16_t zero;
824
825     DBusMessageIter ait, sit;
826     int i;
827
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)
831
832     if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(in)", &ait))
833         return false;
834
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)   )
840         {
841             return false;
842         }
843     }
844
845     if (!CONT_CLOSE(mit, &ait))
846         return false;
847
848 #undef CONT_CLOSE
849 #undef CONT_APPEND
850 #undef CONT_OPEN
851
852     return true;
853 }
854
855 static bool build_connection_formats(DBusMessageIter *mit,
856                                           struct am_nodereg_data *rd)
857 {
858     DBusMessageIter ait;
859     int i;
860
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)
864
865     if (!CONT_OPEN(DBUS_TYPE_ARRAY, "i")) 
866         return false;
867
868     for (i = 1;  i < 2;  i++) {
869         if (!CONT_APPEND(DBUS_TYPE_INT32,  &i))
870             return false;
871     }
872
873     if (!CONT_CLOSE)
874         return false;
875
876 #undef CONT_CLOSE
877 #undef CONT_APPEND
878 #undef CONT_OPEN
879
880     return true;
881 }
882
883 static bool build_notification_properties(DBusMessageIter *mit,
884                                           struct am_nodereg_data *rd)
885 {
886     static int16_t zero;
887
888     DBusMessageIter ait, sit;
889     int i;
890
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)
894
895     if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(iin)", &ait))
896         return false;
897
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)   )
904         {
905             return false;
906         }
907     }
908
909     if (!CONT_CLOSE(mit, &ait))
910         return false;
911
912 #undef CONT_CLOSE
913 #undef CONT_APPEND
914 #undef CONT_OPEN
915
916     return true;
917 }
918
919 bool pa_routerif_register_node(struct userdata *u,
920                                     am_method m,
921                                     am_nodereg_data *rd)
922 {
923     const char      *method = method_str(m);
924     pa_routerif     *routerif;
925     DBusConnection  *conn;
926     DBusMessage     *msg;
927     DBusMessageIter  mit;
928     DBusMessageIter  cit;
929     DBusMessageIter  dit;
930     bool        success = false;
931
932     pa_assert(u);
933     pa_assert(rd);
934     pa_assert_se((routerif = u->routerif));
935     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
936
937     pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,rd->name);
938
939     msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
940                                        routerif->amrnam, method);
941     
942     if (msg == NULL) {
943         pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
944         goto getout;
945     }
946
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)
951
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)
955
956     dbus_message_iter_init_append(msg, &mit);
957
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) ||
969           ! CONT_CLOSE_1                                          ||
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)             ||
977           ! CONT_CLOSE                                          )) ||
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) ||
990           ! CONT_CLOSE_1                                          ||
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)             ||  
997           ! CONT_CLOSE                                          )))
998     {        
999         pa_log("%s: failed to build message for AudioManager '%s'",
1000                __FILE__, method);
1001         goto getout;
1002     }
1003
1004 #undef CONT_CLOSE
1005 #undef CONT_APPEND
1006 #undef CONT_OPEN
1007 #undef MSG_APPEND
1008
1009 #undef CONT_CLOSE_1
1010 #undef CONT_APPEND_1
1011 #undef CONT_OPEN_1
1012
1013     success = send_message_with_reply(u, conn, msg,
1014                                       audiomgr_register_node_cb, rd);
1015     if (!success) {
1016         pa_log("%s: Failed to %s", __FILE__, method);
1017         goto getout;
1018     }
1019     
1020  getout:
1021     dbus_message_unref(msg);
1022     return success;
1023 }
1024
1025 static void audiomgr_unregister_node_cb(struct userdata *u,
1026                                         const char      *method,
1027                                         DBusMessage     *reply,
1028                                         void            *data)
1029 {
1030     const char      *error_descr;
1031     dbus_uint16_t    status;
1032     int              success;
1033     const char      *objtype;
1034
1035     pa_assert(u);
1036     pa_assert(method);
1037     pa_assert(reply);
1038     pa_assert(data);
1039
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,
1043                                         DBUS_TYPE_INVALID);
1044
1045         if (!success)
1046             error_descr = dbus_message_get_error_name(reply);
1047
1048         pa_log_info("%s: AudioManager deregistration failed: %s",
1049                     __FILE__, error_descr);
1050     }
1051     else {
1052         success = dbus_message_get_args(reply, NULL,
1053                                         DBUS_TYPE_UINT16, &status,
1054                                         DBUS_TYPE_INVALID);
1055
1056         if (!success) {
1057             pa_log("got broken message from AudioManager. "
1058                    "Deregistration failed");
1059         }
1060         else {
1061             if (!strncasecmp("deregister", method, 10))
1062                 objtype = method + 10;
1063             else
1064                 objtype = method;
1065
1066             pa_log_info("AudioManager replied to %s deregistration: %u",
1067                         objtype, status);
1068
1069             pa_audiomgr_node_unregistered(u, data);
1070         }
1071     }
1072 }
1073
1074 bool pa_routerif_unregister_node(struct userdata *u,
1075                                       am_method m,
1076                                       am_nodeunreg_data *ud)
1077 {
1078     const char     *method = method_str(m);
1079     pa_routerif    *routerif;
1080     DBusConnection *conn;
1081     DBusMessage    *msg;
1082     bool       success = false;
1083
1084     pa_assert(u);
1085     pa_assert(ud);
1086     pa_assert_se((routerif = u->routerif));
1087     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1088
1089     pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,ud->name);
1090
1091     msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1092                                        routerif->amrnam, method);
1093     
1094     if (msg == NULL) {
1095         pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1096         goto getout;
1097     }
1098
1099     success = dbus_message_append_args(msg,
1100                                        DBUS_TYPE_INT16, &ud->id,
1101                                        DBUS_TYPE_INVALID);
1102
1103     success = send_message_with_reply(u, conn, msg,
1104                                       audiomgr_unregister_node_cb,ud);
1105     if (!success) {
1106         pa_log("%s: Failed to %s", __FILE__, method);
1107         goto getout;
1108     }
1109     
1110  getout:
1111     dbus_message_unref(msg);
1112     return success;
1113 }
1114
1115 bool pa_routerif_register_implicit_connection(struct userdata *u,
1116                                               am_connect_data *cd)
1117 {
1118     static const char    *method = AUDIOMGR_IMPLICIT_CONNECTION;
1119
1120     pa_routerif     *routerif;
1121     DBusConnection  *conn;
1122     DBusMessage     *msg;
1123     bool             success = false;
1124
1125     pa_assert(u);
1126     pa_assert(cd);
1127     pa_assert_se((routerif = u->routerif));
1128     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1129
1130     pa_log_debug("%s: register implicit connection", __FUNCTION__);
1131
1132     msg = dbus_message_new_method_call(routerif->amnam, routerif->amcpath,
1133                                        routerif->amcnam, method);
1134     if (msg == NULL) {
1135         pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1136         goto getout;
1137     }
1138
1139     dbus_message_set_no_reply(msg, true);
1140
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,
1145                                        DBUS_TYPE_INVALID);
1146     if (!success) {
1147         pa_log("%s: failed to build message for %s", __FILE__, method);
1148         goto getout;
1149     }
1150
1151     success = dbus_connection_send(conn, msg, NULL);
1152
1153     if (!success) {
1154         pa_log("%s: Failed to %s", __FILE__, method);
1155         goto getout;
1156     }
1157
1158  getout:
1159     dbus_message_unref(msg);
1160     return success;
1161 }
1162
1163 bool pa_routerif_register_implicit_connections(struct userdata *u,
1164                                                int              nconn,
1165                                                am_connect_data *conns)
1166 {
1167 #if 0
1168     static const char    *method = AUDIOMGR_IMPLICIT_CONNECTIONS;
1169     static dbus_uint16_t  zero;
1170
1171     pa_routerif     *routerif;
1172     DBusConnection  *conn;
1173     DBusMessage     *msg;
1174     DBusMessageIter  mit;
1175     DBusMessageIter  ait;
1176     DBusMessageIter  sit;
1177     am_connect_data *cd;
1178     int              i;
1179     bool             success = false;
1180
1181     pa_assert(u);
1182     pa_assert(nconn > 0);
1183     pa_assert(conns);
1184     pa_assert_se((routerif = u->routerif));
1185     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1186
1187     pa_log_debug("%s: register %d implicit connections", __FUNCTION__, nconn);
1188
1189     msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1190                                        routerif->amrnam, method);
1191     if (msg == NULL) {
1192         pa_log("%s: Failed to create D-Bus message for '%s'", __FILE__,method);
1193         goto getout;
1194     }
1195
1196     dbus_message_set_no_reply(msg, true);
1197     dbus_message_iter_init_append(msg, &mit);
1198
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)
1202
1203     if (!CONT_OPEN(&mit, DBUS_TYPE_ARRAY, "(qqqqn)", &ait)) {
1204         pa_log("%s: failed to open array iterator for %s", __FILE__, method);
1205         goto getout;
1206     }
1207
1208     for (i = 0;   i < nconn;   i++) {
1209         cd = conns + i;
1210         
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    )   )
1218         {
1219             pa_log("%s: failed to build conn struct for %s", __FILE__, method);
1220             goto getout;
1221         }
1222     }
1223
1224     if (!CONT_CLOSE(&mit, &ait)) {
1225         pa_log("%s: failed to close array iterator for %s", __FILE__, method);
1226         goto getout;
1227     } 
1228
1229 #undef CONT_CLOSE
1230 #undef CONT_APPEND
1231 #undef CONT_OPEN
1232
1233
1234     success = dbus_connection_send(conn, msg, NULL);
1235
1236     if (!success) {
1237         pa_log("%s: Failed to %s", __FILE__, method);
1238         goto getout;
1239     }
1240
1241  getout:
1242     dbus_message_unref(msg);
1243     return success;
1244 #endif
1245     return true;
1246 }
1247
1248 static bool routerif_connect(struct userdata *u, DBusMessage *msg)
1249 {
1250     struct am_connect_data ac;
1251     int                    success;
1252
1253     pa_assert(u);
1254     pa_assert(msg);
1255
1256     memset(&ac, 0, sizeof(ac));
1257
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,
1264                                     DBUS_TYPE_INVALID);
1265     if (!success) {
1266         pa_log("%s: got broken connect message from AudioManager. "
1267                "Ignoring it", __FILE__);
1268         return false;
1269     }
1270
1271     pa_log_debug("AudioManager connect(%u|%u|%u|%u|%d)",
1272                  ac.handle, ac.connection, ac.source, ac.sink, ac.format);
1273
1274     pa_audiomgr_connect(u, &ac);
1275
1276     return true;
1277 }
1278
1279 static bool routerif_disconnect(struct userdata *u, DBusMessage *msg)
1280 {
1281     struct am_connect_data ac;
1282     int                    success;
1283
1284     pa_assert(u);
1285     pa_assert(msg);
1286
1287     memset(&ac, 0, sizeof(ac));
1288
1289     success = dbus_message_get_args(msg, NULL,
1290                                     DBUS_TYPE_UINT16, &ac.handle,
1291                                     DBUS_TYPE_UINT16, &ac.connection,
1292                                     DBUS_TYPE_INVALID);
1293     if (!success) {
1294         pa_log("%s: got broken disconnect message from AudioManager. "
1295                "Ignoring it",  __FILE__);
1296         return false;
1297     }
1298
1299     pa_log_debug("AudioManager disconnect(%u|%u)", ac.handle, ac.connection);
1300
1301     pa_audiomgr_disconnect(u, &ac);
1302
1303     return true;
1304 }
1305
1306 bool pa_routerif_acknowledge(struct userdata *u, am_method m,
1307                                   struct am_ack_data *ad)
1308 {
1309     const char     *method = method_str(m);
1310     pa_routerif    *routerif;
1311     DBusConnection *conn;
1312     DBusMessage    *msg;
1313     bool       success;
1314
1315     pa_assert(u);
1316     pa_assert(method);
1317     pa_assert_se((routerif = u->routerif));
1318     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1319
1320     pa_log_debug("%s: sending %s", __FILE__, method);
1321
1322     msg = dbus_message_new_method_call(routerif->amnam,
1323                                        routerif->amrpath,
1324                                        routerif->amrnam,
1325                                        method);
1326     if (msg == NULL) {
1327         pa_log("%s: Failed to create D-Bus message for '%s'",
1328                __FILE__, method);
1329         success = false;
1330         goto getout;
1331     }
1332
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,
1337                                        DBUS_TYPE_INVALID);
1338     if (!success) {
1339         pa_log("%s: Failed to build D-Bus message message '%s'",
1340                __FILE__, method);
1341         goto getout;
1342     }
1343
1344     if (!dbus_connection_send(conn, msg, NULL)) {
1345         pa_log("%s: Failed to send D-Bus message '%s'", __FILE__, method);
1346         goto getout;
1347     }
1348
1349  getout:
1350     dbus_message_unref(msg);
1351     return success;
1352 }
1353
1354
1355 static const char *method_str(am_method m)
1356 {
1357     switch (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";
1377     }
1378 }
1379
1380 /*
1381  * Local Variables:
1382  * c-basic-offset: 4
1383  * indent-tabs-mode: nil
1384  * End:
1385  *
1386  */
1387