build: making dbus usage optional, by default a socket interface is used
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / dbusif.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5
6 #include <pulsecore/pulsecore-config.h>
7 #include <pulsecore/dbus-shared.h>
8
9 #include "userdata.h"
10 #include "dbusif.h"
11 #include "audiomgr.h"
12
13 #define ADMIN_DBUS_MANAGER          "org.freedesktop.DBus"
14 #define ADMIN_DBUS_PATH             "/org/freedesktop/DBus"
15 #define ADMIN_DBUS_INTERFACE        "org.freedesktop.DBus"
16
17 #define ADMIN_NAME_OWNER_CHANGED    "NameOwnerChanged"
18
19 #define POLICY_DBUS_INTERFACE       "org.tizen.policy"
20 #define POLICY_DBUS_MRPPATH         "/org/tizen/policy"
21 #define POLICY_DBUS_MRPNAME         "org.tizen.murphy"
22
23 #define AUDIOMGR_DBUS_INTERFACE     "org.genivi.audiomanager"
24 #define AUDIOMGR_DBUS_PATH          "/org/genivi/audiomanager"
25 #define AUDIOMGR_DBUS_ROUTE_NAME    "RoutingInterface"
26 #define AUDIOMGR_DBUS_ROUTE_PATH    "RoutingInterface"
27
28 #define PULSE_DBUS_INTERFACE        "org.genivi.pulse"
29 #define PULSE_DBUS_PATH             "/org/genivi/pulse"
30 #define PULSE_DBUS_NAME             "org.genivi.pulse"
31
32
33 #define POLICY_DECISION             "decision"
34 #define POLICY_STREAM_INFO          "stream_info"
35 #define POLICY_ACTIONS              "audio_actions"
36 #define POLICY_STATUS               "status"
37
38 #define PROP_ROUTE_SINK_TARGET      "policy.sink_route.target"
39 #define PROP_ROUTE_SINK_MODE        "policy.sink_route.mode"
40 #define PROP_ROUTE_SINK_HWID        "policy.sink_route.hwid"
41 #define PROP_ROUTE_SOURCE_TARGET    "policy.source_route.target"
42 #define PROP_ROUTE_SOURCE_MODE      "policy.source_route.mode"
43 #define PROP_ROUTE_SOURCE_HWID      "policy.source_route.hwid"
44
45
46 #define STRUCT_OFFSET(s,m) ((char *)&(((s *)0)->m) - (char *)0)
47
48 typedef void (*pending_cb_t)(struct userdata *, const char *,
49                              DBusMessage *, void *);
50 typedef pa_bool_t (*method_t)(struct userdata *, DBusMessage *);
51
52
53 struct pending {
54     PA_LLIST_FIELDS(struct pending);
55     struct userdata  *u;
56     const char       *method;
57     DBusPendingCall  *call;
58     pending_cb_t      cb;
59     void             *data;
60 };
61
62 struct pa_routerif {
63     pa_dbus_connection *conn;
64     char               *ifnam;    /* signal interface */
65     char               *mrppath;  /* murphy signal path */
66     char               *mrpnam;   /* murphy D-Bus name */
67     char               *ampath;   /* audio manager path */
68     char               *amnam;    /* audio manager name */
69     char               *amrpath;  /* audio manager routing path */
70     char               *amrnam;   /* audio manager routing name */
71     char               *admmrule; /* match rule to catch murphy name changes */
72     char               *admarule; /* match rule to catch audiomgr name change*/
73     char               *actrule;  /* match rule to catch action signals */
74     char               *strrule;  /* match rule to catch stream info signals */
75     int                 mregist;  /* are we registered to murphy */
76     int                 amisup;   /* is the audio manager up */
77     PA_LLIST_HEAD(struct pending, pendlist);
78 };
79
80
81
82
83 struct actdsc {                 /* action descriptor */
84     const char         *name;
85     int               (*parser)(struct userdata *u, DBusMessageIter *iter);
86 };
87
88 struct argdsc {                 /* argument descriptor for actions */
89     const char         *name;
90     int                 offs;
91     int                 type;
92 };
93
94 struct argrt {                  /* audio_route arguments */
95     char               *type;
96     char               *device;
97     char               *mode;
98     char               *hwid;
99 };
100
101 struct argvol {                 /* volume_limit arguments */
102     char               *group;
103     int32_t             limit;
104 };
105
106 struct argcork {                /* audio_cork arguments */
107     char               *group;
108     char               *cork;
109 };
110
111 struct argmute {
112     char               *device;
113     char               *mute;
114 };
115
116 struct argctx {                 /* context arguments */
117     char               *variable;
118     char               *value;
119 };
120
121 static void free_routerif(pa_routerif *,struct userdata *);
122
123 static pa_bool_t send_message_with_reply(struct userdata *, 
124                                          DBusConnection *, DBusMessage *,
125                                          pending_cb_t, void *);
126
127
128 static DBusHandlerResult filter(DBusConnection *, DBusMessage *, void *);
129
130 static void handle_admin_message(struct userdata *, DBusMessage *);
131 #if 0
132 static void handle_info_message(struct userdata *, DBusMessage *);
133 static void handle_action_message(struct userdata *, DBusMessage *);
134 #endif
135
136 static void murphy_registration_cb(struct userdata *, const char *,
137                                    DBusMessage *, void *);
138 static pa_bool_t register_to_murphy(struct userdata *);
139 #if 0
140 static int  signal_status(struct userdata *, uint32_t, uint32_t);
141 #endif
142
143 static DBusHandlerResult audiomgr_method_handler(DBusConnection *,
144                                                  DBusMessage *, void *);
145 static void audiomgr_register_domain_cb(struct userdata *, const char *,
146                                         DBusMessage *, void *);
147 static pa_bool_t register_to_audiomgr(struct userdata *);
148 static pa_bool_t unregister_from_audiomgr(struct userdata *);
149
150 static void audiomgr_register_node_cb(struct userdata *, const char *,
151                                       DBusMessage *, void *);
152 static void audiomgr_unregister_node_cb(struct userdata *, const char *,
153                                         DBusMessage *, void *);
154 static pa_bool_t build_sound_properties(DBusMessageIter *,
155                                         struct am_nodereg_data *);
156 static pa_bool_t build_connection_formats(DBusMessageIter *,
157                                           struct am_nodereg_data *);
158 static pa_bool_t routerif_connect(struct userdata *, DBusMessage *);
159 static pa_bool_t routerif_disconnect(struct userdata *, DBusMessage *);
160
161 static const char *method_str(am_method);
162
163
164 pa_routerif *pa_routerif_init(struct userdata *u,
165                               const char      *dbustype,
166                               const char      *ifnam,
167                               const char      *mrppath,
168                               const char      *mrpnam,
169                               const char      *ampath,
170                               const char      *amnam)
171 {
172     static const DBusObjectPathVTable  vtable = {
173         .message_function = audiomgr_method_handler,
174     };
175
176     pa_module      *m = u->module;
177     pa_routerif    *routerif = NULL;
178     DBusBusType     type;
179     DBusConnection *dbusconn;
180     DBusError       error;
181     unsigned int    flags;
182     char            nambuf[128];
183     char            pathbuf[128];
184     char           *amrnam;
185     char           *amrpath;
186     char            actrule[512];
187     char            strrule[512];
188     char            admmrule[512];
189     char            admarule[512];
190     int             result;
191     
192     if (!dbustype || !strcasecmp(dbustype, "session")) {
193         dbustype = "session";
194         type = DBUS_BUS_SESSION;
195     }
196     else if (!strcasecmp(dbustype, "system")) {
197         dbustype = "system";
198         type = DBUS_BUS_SYSTEM;
199     }
200     else {
201         pa_log("invalid dbus type '%s'", dbustype);
202         return NULL;
203     }
204     
205     routerif = pa_xnew0(pa_routerif, 1);
206     PA_LLIST_HEAD_INIT(struct pending, routerif->pendlist);
207
208     dbus_error_init(&error);
209     routerif->conn = pa_dbus_bus_get(m->core, type, &error);
210
211     if (routerif->conn == NULL || dbus_error_is_set(&error)) {
212         pa_log("%s: failed to get %s Bus: %s: %s",
213                __FILE__, dbustype, error.name, error.message);
214         goto fail;
215     }
216
217     dbusconn = pa_dbus_connection_get(routerif->conn);
218
219     flags  = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;
220     result = dbus_bus_request_name(dbusconn, PULSE_DBUS_NAME, flags,&error);
221
222     if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER &&
223         result != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER    ) {
224         pa_log("%s: D-Bus name request failed: %s: %s",
225                __FILE__, error.name, error.message);
226         goto fail;
227     }
228     
229     pa_log_info("%s: now owner of '%s' D-Bus name on %s bus",
230                 __FILE__, PULSE_DBUS_NAME, dbustype);
231  
232     if (!dbus_connection_add_filter(dbusconn, filter,u, NULL)) {
233         pa_log("%s: failed to add filter function", __FILE__);
234         goto fail;
235     }
236
237     if (!ifnam)
238         ifnam = POLICY_DBUS_INTERFACE;
239
240     if (!mrppath)
241         mrppath = POLICY_DBUS_MRPPATH;
242
243     if (!mrpnam)
244         mrpnam = POLICY_DBUS_MRPNAME;
245
246     if (ampath && *ampath) {
247         char *slash = ampath[strlen(ampath)-1] == '/' ? "" : "/";
248         snprintf(pathbuf, sizeof(pathbuf), "%s%s" AUDIOMGR_DBUS_ROUTE_PATH,
249                  ampath, slash);
250         amrpath = pathbuf;
251     }
252     else {
253         ampath  = AUDIOMGR_DBUS_PATH;
254         amrpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_ROUTE_PATH;
255     }
256
257     if (amnam && *amnam){
258         char *dot = amnam[strlen(amnam)-1] == '.' ? "" : ".";
259         snprintf(nambuf, sizeof(nambuf), "%s%s" AUDIOMGR_DBUS_ROUTE_NAME,
260                  amnam, dot);
261         amrnam = nambuf;
262     }
263     else {
264         amnam  = AUDIOMGR_DBUS_INTERFACE;
265         amrnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_ROUTE_NAME;
266     }
267
268
269     snprintf(admmrule, sizeof(admmrule), "type='signal',sender='%s',path='%s',"
270              "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
271              ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
272              mrpnam);
273     dbus_bus_add_match(dbusconn, admmrule, &error);
274
275     snprintf(admarule, sizeof(admarule), "type='signal',sender='%s',path='%s',"
276              "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
277              ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
278              amnam);
279     dbus_bus_add_match(dbusconn, admarule, &error);
280
281     if (dbus_error_is_set(&error)) {
282         pa_log("%s: unable to subscribe name change signals on %s: %s: %s",
283                __FILE__, ADMIN_DBUS_INTERFACE, error.name, error.message);
284         goto fail;
285     }
286
287     snprintf(actrule, sizeof(actrule), "type='signal',interface='%s',"
288              "member='%s',path='%s/%s'", ifnam, POLICY_ACTIONS,
289              mrppath, POLICY_DECISION);
290     dbus_bus_add_match(dbusconn, actrule, &error);
291
292     if (dbus_error_is_set(&error)) {
293         pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
294                __FILE__, POLICY_ACTIONS, ifnam, error.name, error.message);
295         goto fail;
296     }
297
298     snprintf(strrule, sizeof(strrule), "type='signal',interface='%s',"
299              "member='%s',path='%s/%s'", ifnam, POLICY_STREAM_INFO,
300              mrppath, POLICY_DECISION);
301     dbus_bus_add_match(dbusconn, strrule, &error);
302
303     if (dbus_error_is_set(&error)) {
304         pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
305                __FILE__, POLICY_STREAM_INFO, ifnam, error.name, error.message);
306         goto fail;
307     }
308
309     pa_log_info("%s: subscribed policy signals on %s", __FILE__, ifnam);
310
311     dbus_connection_register_object_path(dbusconn, PULSE_DBUS_PATH, &vtable,u);
312
313
314     routerif->ifnam    = pa_xstrdup(ifnam);
315     routerif->mrppath  = pa_xstrdup(mrppath);
316     routerif->mrpnam   = pa_xstrdup(mrpnam);
317     routerif->ampath   = pa_xstrdup(ampath);
318     routerif->amnam    = pa_xstrdup(amnam);
319     routerif->amrpath  = pa_xstrdup(amrpath);
320     routerif->amrnam   = pa_xstrdup(amrnam);
321     routerif->admmrule = pa_xstrdup(admmrule);
322     routerif->admarule = pa_xstrdup(admarule);
323     routerif->actrule  = pa_xstrdup(actrule);
324     routerif->strrule  = pa_xstrdup(strrule);
325
326     u->routerif = routerif; /* Argh.. */
327
328     register_to_murphy(u);
329     register_to_audiomgr(u);
330
331     return routerif;
332
333  fail:
334     free_routerif(routerif, u);
335     dbus_error_free(&error);
336     return NULL;
337 }
338
339 static void free_routerif(pa_routerif *routerif, struct userdata *u)
340 {
341     DBusConnection  *dbusconn;
342     struct pending  *p, *n;
343
344     if (routerif) {
345
346         if (routerif->conn) {
347             dbusconn = pa_dbus_connection_get(routerif->conn);
348
349             PA_LLIST_FOREACH_SAFE(p,n, routerif->pendlist) {
350                 PA_LLIST_REMOVE(struct pending, routerif->pendlist, p);
351                 dbus_pending_call_set_notify(p->call, NULL,NULL, NULL);
352                 dbus_pending_call_unref(p->call);
353             }
354
355             if (u) {
356                 dbus_connection_remove_filter(dbusconn, filter,u);
357             }
358
359             dbus_bus_remove_match(dbusconn, routerif->admmrule, NULL);
360             dbus_bus_remove_match(dbusconn, routerif->admarule, NULL);
361             dbus_bus_remove_match(dbusconn, routerif->actrule, NULL);
362             dbus_bus_remove_match(dbusconn, routerif->strrule, NULL);
363
364             pa_dbus_connection_unref(routerif->conn);
365         }
366
367         pa_xfree(routerif->ifnam);
368         pa_xfree(routerif->mrppath);
369         pa_xfree(routerif->mrpnam);
370         pa_xfree(routerif->ampath);
371         pa_xfree(routerif->amnam);
372         pa_xfree(routerif->amrpath);
373         pa_xfree(routerif->amrnam);
374         pa_xfree(routerif->admmrule);
375         pa_xfree(routerif->admarule);
376         pa_xfree(routerif->actrule);
377         pa_xfree(routerif->strrule);
378
379         pa_xfree(routerif);
380     }
381 }
382
383 void pa_routerif_done(struct userdata *u)
384 {
385     if (u && u->routerif) {
386         free_routerif(u->routerif, u);
387         u->routerif = NULL;
388     }
389 }
390
391
392 static DBusHandlerResult filter(DBusConnection *conn, DBusMessage *msg,
393                                 void *arg)
394 {
395     struct userdata  *u = arg;
396
397     if (dbus_message_is_signal(msg, ADMIN_DBUS_INTERFACE,
398                                ADMIN_NAME_OWNER_CHANGED))
399     {
400         handle_admin_message(u, msg);
401         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
402     }
403
404
405 #if 0
406     if (dbus_message_is_signal(msg, POLICY_DBUS_INTERFACE,POLICY_STREAM_INFO)){
407         handle_info_message(u, msg);
408         return DBUS_HANDLER_RESULT_HANDLED;
409     }
410
411     if (dbus_message_is_signal(msg, POLICY_DBUS_INTERFACE, POLICY_ACTIONS)) {
412         handle_action_message(u, msg);
413         return DBUS_HANDLER_RESULT_HANDLED;
414     }
415 #endif
416
417     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
418 }
419
420
421 static void handle_admin_message(struct userdata *u, DBusMessage *msg)
422 {
423     pa_routerif *routerif;
424     char        *name;
425     char        *before;
426     char        *after;
427     int          success;
428
429     pa_assert(u);
430     pa_assert_se((routerif = u->routerif));
431
432     success = dbus_message_get_args(msg, NULL,
433                                     DBUS_TYPE_STRING, &name,
434                                     DBUS_TYPE_STRING, &before,
435                                     DBUS_TYPE_STRING, &after,
436                                     DBUS_TYPE_INVALID);
437
438     if (!success || !name) {
439         pa_log("Received malformed '%s' message", ADMIN_NAME_OWNER_CHANGED);
440         return;
441     }
442
443     if (!strcmp(name, routerif->mrpnam)) {
444         if (after && strcmp(after, "")) {
445             pa_log_debug("murphy is up");
446
447             if (!routerif->mregist) {
448                 register_to_murphy(u);
449             }
450         }
451
452         if (name && before && (!after || !strcmp(after, ""))) {
453             pa_log_info("murphy is gone");
454             routerif->mregist = 0;
455         } 
456     } else
457
458     if (!strcmp(name, routerif->amnam)) {
459         if (after && strcmp(after, "")) {
460             pa_log_debug("audio manager is up");
461
462             if (!routerif->amisup) {
463                 register_to_audiomgr(u);
464             }
465         }
466
467         if (name && before && (!after || !strcmp(after, ""))) {
468             pa_log_info("audio manager is gone");
469
470             if (routerif->amisup)
471                 unregister_from_audiomgr(u);
472
473             routerif->amisup = 0;
474         } 
475     }
476 }
477
478
479 static void reply_cb(DBusPendingCall *pend, void *data)
480 {
481     struct pending  *pdata = (struct pending *)data;
482     struct userdata *u;
483     pa_routerif     *routerif;
484     DBusMessage     *reply;
485
486     pa_assert(pdata);
487     pa_assert(pdata->call == pend);
488     pa_assert_se((u = pdata->u));
489     pa_assert_se((routerif = u->routerif));
490
491     PA_LLIST_REMOVE(struct pending, routerif->pendlist, pdata);
492
493     if ((reply = dbus_pending_call_steal_reply(pend)) == NULL) {
494         pa_log("%s: Murphy pending call '%s' failed: invalid argument",
495                __FILE__, pdata->method);
496     }
497     else {
498         pdata->cb(u, pdata->method, reply, pdata->data);
499         dbus_message_unref(reply);
500     }
501
502     pa_xfree((void *)pdata->method);
503     pa_xfree((void *)pdata);
504 }
505
506 static pa_bool_t send_message_with_reply(struct userdata *u,
507                                          DBusConnection  *conn,
508                                          DBusMessage     *msg,
509                                          pending_cb_t     cb,
510                                          void            *data)
511 {
512     pa_routerif     *routerif;
513     struct pending  *pdata = NULL;
514     const char      *method;
515     DBusPendingCall *pend;
516
517     pa_assert(u);
518     pa_assert(conn);
519     pa_assert(msg);
520     pa_assert(cb);
521     pa_assert_se((routerif = u->routerif));
522
523     if ((method = dbus_message_get_member(msg)) == NULL)
524         goto failed;
525
526     pdata = pa_xnew0(struct pending, 1);
527     pdata->u      = u;
528     pdata->method = pa_xstrdup(method);
529     pdata->cb     = cb;
530     pdata->data   = data;
531
532     PA_LLIST_PREPEND(struct pending, routerif->pendlist, pdata);
533
534     if (!dbus_connection_send_with_reply(conn, msg, &pend, -1)) {
535         pa_log("%s: Failed to %s", __FILE__, method);
536         goto failed;
537     }
538
539     pdata->call = pend;
540
541     if (!dbus_pending_call_set_notify(pend, reply_cb,pdata, NULL)) {
542         pa_log("%s: Can't set notification for %s", __FILE__, method);
543         goto failed;
544     }
545
546
547     return TRUE;
548
549  failed:
550     if (pdata) {
551         PA_LLIST_REMOVE(struct pending, routerif->pendlist, pdata);
552         pa_xfree((void *)pdata->method);
553         pa_xfree((void *)pdata);
554     }
555     return FALSE;
556 }
557
558
559 /**************************************************************************
560  *
561  * Murphy interfaces
562  *
563  */
564 #if 0
565 void pa_routerif_send_device_state(struct userdata *u, char *state,
566                                    char **types, int ntype)
567 {
568     static char     *path = (char *)"/org/tizen/policy/info";
569
570     pa_routerif     *routerif = u->routerif;
571     DBusConnection  *conn = pa_dbus_connection_get(routerif->conn);
572     DBusMessage     *msg;
573     DBusMessageIter  mit;
574     DBusMessageIter  dit;
575     int              i;
576     int              sts;
577
578     if (!types || ntype < 1)
579         return;
580
581     msg = dbus_message_new_signal(path, routerif->ifnam, "info");
582
583     if (msg == NULL) {
584         pa_log("%s: failed to make new info message", __FILE__);
585         goto fail;
586     }
587
588     dbus_message_iter_init_append(msg, &mit);
589
590     if (!dbus_message_iter_append_basic(&mit, DBUS_TYPE_STRING, &state) ||
591         !dbus_message_iter_open_container(&mit, DBUS_TYPE_ARRAY,"s", &dit)){
592         pa_log("%s: failed to build info message", __FILE__);
593         goto fail;
594     }
595
596     for (i = 0; i < ntype; i++) {
597         if (!dbus_message_iter_append_basic(&dit, DBUS_TYPE_STRING,&types[i])){
598             pa_log("%s: failed to build info message", __FILE__);
599             goto fail;
600         }
601     }
602
603     dbus_message_iter_close_container(&mit, &dit);
604
605     sts = dbus_connection_send(conn, msg, NULL);
606
607     if (!sts) {
608         pa_log("%s: Can't send info message: out of memory", __FILE__);
609     }
610
611  fail:
612     dbus_message_unref(msg);    /* should cope with NULL msg */
613 }
614
615 void pa_routerif_send_media_status(struct userdata *u, const char *media,
616                                         const char *group, int active)
617 {
618     static char        *path = (char *)"/org/tizen/policy/info";
619     static const char  *type = "media";
620
621     pa_routerif    *routerif = u->routerif;
622     DBusConnection *conn   = pa_dbus_connection_get(routerif->conn);
623     DBusMessage    *msg;
624     const char     *state;
625     int             success;
626
627     msg = dbus_message_new_signal(path, routerif->ifnam, "info");
628
629     if (msg == NULL)
630         pa_log("%s: failed to make new info message", __FILE__);
631     else {
632         state = active ? "active" : "inactive";
633
634         success = dbus_message_append_args(msg,
635                                            DBUS_TYPE_STRING, &type,
636                                            DBUS_TYPE_STRING, &media,
637                                            DBUS_TYPE_STRING, &group,
638                                            DBUS_TYPE_STRING, &state,
639                                            DBUS_TYPE_INVALID);
640         
641         if (!success)
642             pa_log("%s: Can't build D-Bus info message", __FILE__);
643         else {
644             if (!dbus_connection_send(conn, msg, NULL)) {
645                 pa_log("%s: Can't send info message: out of memory", __FILE__);
646             }
647         }
648
649         dbus_message_unref(msg);
650     }
651 }
652 #endif
653
654 #if 0
655 static void handle_info_message(struct userdata *u, DBusMessage *msg)
656 {
657     dbus_uint32_t  txid;
658     dbus_uint32_t  pid;
659     char          *oper;
660     char          *group;
661     char          *arg;
662     char          *method_str;
663     enum pa_classify_method method = pa_method_unknown;
664     char          *prop;
665     int            success;
666
667     success = dbus_message_get_args(msg, NULL,
668                                     DBUS_TYPE_UINT32, &txid,
669                                     DBUS_TYPE_STRING, &oper,
670                                     DBUS_TYPE_STRING, &group,
671                                     DBUS_TYPE_UINT32, &pid,
672                                     DBUS_TYPE_STRING, &arg,
673                                     DBUS_TYPE_STRING, &method_str,
674                                     DBUS_TYPE_STRING, &prop,
675                                     DBUS_TYPE_INVALID);
676     if (!success) {
677         pa_log("%s: failed to parse info message", __FILE__);
678         return;
679     }
680
681     if (!method_str)
682         method = pa_method_unknown;
683     else {
684         switch (method_str[0]) {
685         case 'e':
686             if (!strcmp(method_str, "equals"))
687                 method = pa_method_equals;
688             break;
689         case 's':
690             if (!strcmp(method_str, "startswith"))
691                 method = pa_method_startswith;
692             break;
693         case 'm':
694             if (!strcmp(method_str, "matches"))
695                 method = pa_method_matches;
696             break;
697         case 't':
698             if (!strcmp(method_str, "true"))
699                 method = pa_method_true;
700             break;
701         default:
702             method = pa_method_unknown;
703             break;
704         }
705     }
706
707     if (!arg)
708         method = pa_method_unknown;
709     else if (!strcmp(arg, "*"))
710         method = pa_method_true;
711
712     if (!strcmp(oper, "register")) {
713
714         if (pa_policy_group_find(u, group) == NULL) {
715             pa_log_debug("register client (%s|%u) failed: unknown group",
716                          group, pid);
717         }
718         else {
719             pa_log_debug("register client (%s|%u)", group, pid);
720             pa_classify_register_pid(u, (pid_t)pid, prop, method, arg, group);
721         }
722         
723     }
724     else if (!strcmp(oper, "unregister")) {
725         pa_log_debug("unregister client (%s|%u)", group, pid);
726         pa_classify_unregister_pid(u, (pid_t)pid, prop, method, arg);
727     }
728     else {
729         pa_log("%s: invalid operation: '%s'", __FILE__, oper);
730     }
731 }
732
733 static void handle_action_message(struct userdata *u, DBusMessage *msg)
734 {
735     static struct actdsc actions[] = {
736 /*
737         { "org.tizen.policy.audio_route" , audio_route_parser  },
738         { "org.tizen.policy.volume_limit", volume_limit_parser },
739         { "org.tizen.policy.audio_cork"  , audio_cork_parser   },
740         { "org.tizen.policy.audio_mute"  , audio_mute_parser   },
741         { "org.tizen.policy.context"     , context_parser      },
742 */
743         {               NULL             , NULL                }
744     };
745
746     struct actdsc   *act;
747     dbus_uint32_t    txid;
748     char            *actname;
749     DBusMessageIter  msgit;
750     DBusMessageIter  arrit;
751     DBusMessageIter  entit;
752     DBusMessageIter  actit;
753     int              success = TRUE;
754
755     pa_log_debug("got policy actions");
756
757     dbus_message_iter_init(msg, &msgit);
758
759     if (dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_UINT32)
760         return;
761
762     dbus_message_iter_get_basic(&msgit, (void *)&txid);
763
764     pa_log_debug("got actions (txid:%d)", txid);
765
766     if (!dbus_message_iter_next(&msgit) ||
767         dbus_message_iter_get_arg_type(&msgit) != DBUS_TYPE_ARRAY) {
768         success = FALSE;
769         goto send_signal;
770     }
771
772     dbus_message_iter_recurse(&msgit, &arrit);
773
774     do {
775         if (dbus_message_iter_get_arg_type(&arrit) != DBUS_TYPE_DICT_ENTRY) {
776             success = FALSE;
777             continue;
778         }
779
780         dbus_message_iter_recurse(&arrit, &entit);
781
782         do {
783             if (dbus_message_iter_get_arg_type(&entit) != DBUS_TYPE_STRING) {
784                 success = FALSE;
785                 continue;
786             }
787             
788             dbus_message_iter_get_basic(&entit, (void *)&actname);
789             
790             if (!dbus_message_iter_next(&entit) ||
791                 dbus_message_iter_get_arg_type(&entit) != DBUS_TYPE_ARRAY) {
792                 success = FALSE;
793                 continue;
794             }
795             
796             dbus_message_iter_recurse(&entit, &actit);
797             
798             if (dbus_message_iter_get_arg_type(&actit) != DBUS_TYPE_ARRAY) {
799                 success = FALSE;
800                 continue;
801             }
802             
803             for (act = actions;   act->name != NULL;   act++) {
804                 if (!strcmp(actname, act->name))
805                     break;
806             }
807                                     
808             if (act->parser != NULL)
809                 success &= act->parser(u, &actit);
810
811         } while (dbus_message_iter_next(&entit));
812
813     } while (dbus_message_iter_next(&arrit));
814
815  send_signal:
816     signal_status(u, txid, success);
817 }
818 #endif
819
820 static void murphy_registration_cb(struct userdata *u,
821                                    const char      *method,
822                                    DBusMessage     *reply,
823                                    void            *data)
824 {
825     const char      *error_descr;
826     int              success;
827
828     (void)data;
829
830     if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
831         success = dbus_message_get_args(reply, NULL,
832                                         DBUS_TYPE_STRING, &error_descr,
833                                         DBUS_TYPE_INVALID);
834
835         if (!success)
836             error_descr = dbus_message_get_error_name(reply);
837
838         pa_log_info("%s: registration to Murphy failed: %s",
839                     __FILE__, error_descr);
840     }
841     else {
842         pa_log_info("Murphy replied to registration");
843
844         if (u->routerif) {
845             u->routerif->amisup = 1;
846         }
847     }
848 }
849
850 static pa_bool_t register_to_murphy(struct userdata *u)
851 {
852     static const char *name = "pulseaudio";
853
854     pa_routerif    *routerif = u->routerif;
855     DBusConnection *conn   = pa_dbus_connection_get(routerif->conn);
856     DBusMessage    *msg;
857     const char     *signals[4];
858     const char    **v_ARRAY;
859     int             i;
860     int             success;
861
862     pa_log_info("%s: registering to murphy: name='%s' path='%s' if='%s'",
863                 __FILE__, routerif->mrpnam, routerif->mrppath,routerif->ifnam);
864
865     msg = dbus_message_new_method_call(routerif->mrpnam, routerif->mrppath,
866                                        routerif->ifnam, "register");
867
868     if (msg == NULL) {
869         pa_log("%s: Failed to create D-Bus message to register", __FILE__);
870         success = FALSE;
871         goto getout;
872     }
873
874     signals[i=0] = POLICY_ACTIONS;
875     v_ARRAY = signals;
876
877     success = dbus_message_append_args(msg,
878                                        DBUS_TYPE_STRING, &name,
879                                        DBUS_TYPE_ARRAY,
880                                        DBUS_TYPE_STRING, &v_ARRAY, i+1,
881                                        DBUS_TYPE_INVALID);
882     if (!success) {
883         pa_log("%s: Failed to build D-Bus message to register", __FILE__);
884         goto getout;
885     }
886
887     if (!send_message_with_reply(u, conn, msg, murphy_registration_cb, NULL)) {
888         pa_log("%s: Failed to register", __FILE__);
889         goto getout;
890     }
891
892  getout:
893     dbus_message_unref(msg);
894     return success;
895 }
896
897
898 #if 0
899 static int signal_status(struct userdata *u, uint32_t txid, uint32_t status)
900 {
901     pa_routerif    *routerif = u->routerif;
902     DBusConnection *conn = pa_dbus_connection_get(routerif->conn);
903     DBusMessage    *msg;
904     char            path[256];
905     int             ret;
906
907     if (txid == 0) {
908     
909         /* When transaction ID is 0, the policy manager does not expect
910          * a response. */
911         
912         pa_log_debug("Not sending status message since transaction ID is 0");
913         return 0;
914     }
915
916     snprintf(path, sizeof(path), "%s/%s", routerif->mrppath, POLICY_DECISION);
917
918     pa_log_debug("sending signal to: path='%s', if='%s' member='%s' "
919                  "content: txid=%d status=%d", path, routerif->ifnam,
920                  POLICY_STATUS, txid, status);
921
922     msg = dbus_message_new_signal(path, routerif->ifnam, POLICY_STATUS);
923
924     if (msg == NULL) {
925         pa_log("%s: failed to make new status message", __FILE__);
926         goto fail;
927     }
928
929     ret = dbus_message_append_args(msg,
930             DBUS_TYPE_UINT32, &txid,
931             DBUS_TYPE_UINT32, &status,
932             DBUS_TYPE_INVALID);
933
934     if (!ret) {
935         pa_log("%s: Can't build D-Bus status message", __FILE__);
936         goto fail;
937     }
938
939     ret = dbus_connection_send(conn, msg, NULL);
940
941     if (!ret) {
942         pa_log("%s: Can't send status message: out of memory", __FILE__);
943         goto fail;
944     }
945
946     dbus_message_unref(msg);
947
948     return 0;
949
950  fail:
951     dbus_message_unref(msg);    /* should cope with NULL msg */
952     return -1;
953 }
954 #endif
955
956
957 /**************************************************************************
958  *
959  * Audio Manager interfaces
960  *
961  */
962 static DBusHandlerResult audiomgr_method_handler(DBusConnection *conn,
963                                                  DBusMessage    *msg,
964                                                  void           *arg)
965 {
966     struct dispatch {
967         const char *name;
968         method_t    method;
969     };
970
971     static struct dispatch dispatch_tbl[] = {
972         { AUDIOMGR_CONNECT   , routerif_connect    },
973         { AUDIOMGR_DISCONNECT, routerif_disconnect },
974         {        NULL,                 NULL        }
975     };
976
977     struct userdata         *u = (struct userdata *)arg;
978     struct dispatch         *d;
979     const char              *name;
980     method_t                 method;
981     //uint32_t                 serial;
982     dbus_int16_t             errcod;
983     DBusMessage             *reply;
984     pa_bool_t                success;
985
986     pa_assert(conn);
987     pa_assert(msg);
988     pa_assert(u);
989
990     if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
991
992         name = dbus_message_get_member(msg);
993         // serial = dbus_message_get_serial(msg);
994
995         pa_assert(name);
996
997         for (method = NULL, d = dispatch_tbl;  d->name;    d++) {
998             if (!strcmp(name, d->name)) {
999                 method = d->method;
1000                 break;
1001             }
1002         }
1003
1004         errcod = method ? E_OK : E_NOT_POSSIBLE; 
1005         reply  = dbus_message_new_method_return(msg);
1006
1007         // dbus_message_set_reply_serial(reply, serial);
1008                 
1009         success = dbus_message_append_args(reply,
1010                                            DBUS_TYPE_INT16, &errcod,
1011                                            DBUS_TYPE_INVALID);
1012         
1013         if (!success || !dbus_connection_send(conn, reply, NULL))
1014             pa_log("%s: failed to reply '%s'", __FILE__, name);
1015         else
1016             pa_log_debug("'%s' replied (%d)", name, errcod);
1017
1018         dbus_message_unref(reply);
1019
1020         if (method)
1021             d->method(u, msg);
1022         else
1023             pa_log_info("%s: unsupported '%s' method ignored", __FILE__, name);
1024                 
1025         return DBUS_HANDLER_RESULT_HANDLED;
1026     }
1027
1028     pa_log_debug("got some unexpected type of D-Bus message");
1029
1030     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1031 }
1032
1033
1034 static pa_bool_t register_to_audiomgr(struct userdata *u)
1035 {
1036     pa_audiomgr_register_domain(u);
1037     return TRUE;
1038 }
1039
1040 static pa_bool_t unregister_from_audiomgr(struct userdata *u)
1041 {
1042     pa_audiomgr_unregister_domain(u, FALSE);
1043     return TRUE;
1044 }
1045
1046 static void audiomgr_register_domain_cb(struct userdata *u,
1047                                         const char      *method,
1048                                         DBusMessage     *reply,
1049                                         void            *data)
1050 {
1051     const char        *error_descr;
1052     dbus_uint16_t      domain_id;
1053     dbus_uint16_t      status;
1054     int                success;
1055
1056     if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1057         success = dbus_message_get_args(reply, NULL,
1058                                         DBUS_TYPE_STRING, &error_descr,
1059                                         DBUS_TYPE_INVALID);
1060
1061         if (!success)
1062             error_descr = dbus_message_get_error_name(reply);
1063
1064         pa_log_info("%s: AudioManager domain registration failed: %s",
1065                     __FILE__, error_descr);
1066     }
1067     else {
1068         success = dbus_message_get_args(reply, NULL,
1069                                         DBUS_TYPE_UINT16, &domain_id,
1070                                         DBUS_TYPE_UINT16, &status,
1071                                         DBUS_TYPE_INVALID);
1072
1073         if (!success) {
1074             pa_log("got broken message from AudioManager.Registration failed");
1075         }
1076         else {
1077             pa_log_info("AudioManager replied to registration: "
1078                         "domainID %u, status %u", domain_id, status);
1079
1080             if (u->routerif) {
1081                 u->routerif->amisup = 1;
1082                 pa_audiomgr_domain_registered(u, domain_id, status, data);
1083             }
1084         }
1085     }
1086 }
1087
1088
1089
1090 pa_bool_t pa_routerif_register_domain(struct userdata   *u,
1091                                            am_domainreg_data *dr)
1092 {
1093     pa_routerif    *routerif;
1094     DBusConnection *conn;
1095     DBusMessage    *msg;
1096     const char     *dbus_name;
1097     const char     *dbus_path;
1098     const char     *dbus_if;
1099     int             success;
1100
1101     pa_assert(u);
1102     pa_assert(dr);
1103     pa_assert_se((routerif = u->routerif));
1104     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1105
1106     pa_log_info("%s: registering to AudioManager: name='%s' path='%s' if='%s'"
1107                 , __FILE__, routerif->amnam, routerif->amrpath, routerif->amrnam);
1108
1109     msg = dbus_message_new_method_call(routerif->amnam,
1110                                        routerif->amrpath,
1111                                        routerif->amrnam,
1112                                        AUDIOMGR_REGISTER_DOMAIN);
1113     if (msg == NULL) {
1114         pa_log("%s: Failed to create D-Bus message to '%s'",
1115                __FILE__, AUDIOMGR_REGISTER_DOMAIN);
1116         success = FALSE;
1117         goto getout;
1118     }
1119
1120     dbus_name = PULSE_DBUS_NAME;
1121     dbus_path = PULSE_DBUS_PATH;
1122     dbus_if   = PULSE_DBUS_INTERFACE;
1123
1124     success = dbus_message_append_args(msg,
1125                                        DBUS_TYPE_UINT16,  &dr->domain_id,
1126                                        DBUS_TYPE_STRING,  &dr->name,
1127                                        DBUS_TYPE_STRING,  &dr->node_name,
1128                                        DBUS_TYPE_STRING,  &dr->bus_name,
1129                                        DBUS_TYPE_BOOLEAN, &dr->early,
1130                                        DBUS_TYPE_BOOLEAN, &dr->complete,
1131                                        DBUS_TYPE_UINT16 , &dr->state,
1132                                        DBUS_TYPE_STRING , &dbus_name,
1133                                        DBUS_TYPE_STRING , &dbus_path,
1134                                        DBUS_TYPE_STRING , &dbus_if,
1135                                        DBUS_TYPE_INVALID);
1136     if (!success) {
1137         pa_log("%s: Failed to build D-Bus message to register", __FILE__);
1138         goto getout;
1139     }
1140
1141     success = send_message_with_reply(u, conn, msg,
1142                                       audiomgr_register_domain_cb, dr);
1143     if (!success) {
1144         pa_log("%s: Failed to register", __FILE__);
1145         goto getout;
1146     }
1147
1148  getout:
1149     dbus_message_unref(msg);
1150     return success;
1151 }
1152
1153 pa_bool_t pa_routerif_domain_complete(struct userdata *u, uint16_t domain)
1154 {
1155     dbus_int32_t    id32 = domain;
1156     pa_routerif    *routerif;
1157     DBusConnection *conn;
1158     DBusMessage    *msg;
1159     pa_bool_t       success;
1160
1161     pa_assert(u);
1162     pa_assert_se((routerif = u->routerif));
1163     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1164     
1165
1166     pa_log_debug("%s: domain %u AudioManager %s", __FUNCTION__,
1167                  domain, AUDIOMGR_DOMAIN_COMPLETE);
1168
1169     msg = dbus_message_new_method_call(routerif->amnam,
1170                                        routerif->amrpath,
1171                                        routerif->amrnam,
1172                                        AUDIOMGR_DOMAIN_COMPLETE);
1173     if (msg == NULL) {
1174         pa_log("%s: Failed to create D-Bus message for '%s'",
1175                __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1176         success = FALSE;
1177         goto getout;
1178     }
1179
1180     success = dbus_message_append_args(msg,
1181                                        DBUS_TYPE_INT32,  &id32,
1182                                        DBUS_TYPE_INVALID);
1183     if (!success) {
1184         pa_log("%s: Failed to build D-Bus message for '%s'",
1185                __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1186         goto getout;
1187     }
1188
1189     if (!dbus_connection_send(conn, msg, NULL)) {
1190         pa_log("%s: Failed to send '%s'", __FILE__, AUDIOMGR_DOMAIN_COMPLETE);
1191         goto getout;
1192     }
1193
1194     dbus_connection_flush(conn);
1195
1196  getout:
1197     dbus_message_unref(msg);
1198     return success;
1199 }
1200
1201 pa_bool_t pa_routerif_unregister_domain(struct userdata *u, uint16_t domain)
1202 {
1203     pa_routerif    *routerif;
1204     DBusConnection *conn;
1205     DBusMessage    *msg;
1206     pa_bool_t       success;
1207
1208     pa_assert(u);
1209     pa_assert_se((routerif = u->routerif));
1210     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1211
1212     pa_log_info("%s: deregistreing domain %u from AudioManager",
1213                 __FILE__, domain);
1214
1215     msg = dbus_message_new_method_call(routerif->amnam,
1216                                        routerif->amrpath,
1217                                        routerif->amrnam,
1218                                        AUDIOMGR_DEREGISTER_DOMAIN);
1219     if (msg == NULL) {
1220         pa_log("%s: Failed to create D-Bus message for '%s'",
1221                __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1222         success = FALSE;
1223         goto getout;
1224     }
1225
1226     dbus_message_set_no_reply(msg, TRUE);
1227
1228     success = dbus_message_append_args(msg,
1229                                        DBUS_TYPE_UINT16,  &domain,
1230                                        DBUS_TYPE_INVALID);
1231     if (!success) {
1232         pa_log("%s: Failed to build D-Bus message for '%s'",
1233                __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1234         goto getout;
1235     }
1236
1237     if (!dbus_connection_send(conn, msg, NULL)) {
1238         pa_log("%s: Failed to send '%s'", __FILE__,AUDIOMGR_DEREGISTER_DOMAIN);
1239         goto getout;
1240     }
1241
1242     dbus_connection_flush(conn);
1243
1244  getout:
1245     dbus_message_unref(msg);
1246     return success;
1247 }
1248
1249
1250 static void audiomgr_register_node_cb(struct userdata *u,
1251                                       const char      *method,
1252                                       DBusMessage     *reply,
1253                                       void            *data)
1254 {
1255     const char      *error_descr;
1256     dbus_uint16_t    object_id;
1257     dbus_uint16_t    status;
1258     int              success;
1259     const char      *objtype;
1260
1261     pa_assert(u);
1262     pa_assert(method);
1263     pa_assert(reply);
1264     pa_assert(data);
1265
1266     if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1267         success = dbus_message_get_args(reply, NULL,
1268                                         DBUS_TYPE_STRING, &error_descr,
1269                                         DBUS_TYPE_INVALID);
1270
1271         if (!success)
1272             error_descr = dbus_message_get_error_name(reply);
1273
1274         pa_log_info("%s: AudioManager registration failed: %s",
1275                     __FILE__, error_descr);
1276     }
1277     else {
1278         success = dbus_message_get_args(reply, NULL,
1279                                         DBUS_TYPE_UINT16, &object_id,
1280                                         DBUS_TYPE_UINT16, &status,
1281                                         DBUS_TYPE_INVALID);
1282
1283         if (!success) {
1284             pa_log("got broken message from AudioManager.Registration failed");
1285         }
1286         else {
1287             if (!strncasecmp("register", method, 8))
1288                 objtype = method + 8;
1289             else
1290                 objtype = method;
1291
1292             pa_log_info("AudioManager replied to registration: %sID: %u",
1293                         objtype, object_id);
1294
1295             pa_audiomgr_node_registered(u, object_id, status, data);
1296         }
1297     }
1298 }
1299
1300 static pa_bool_t build_sound_properties(DBusMessageIter *mit,
1301                                         struct am_nodereg_data *rd)
1302 {
1303     static int16_t zero;
1304
1305     DBusMessageIter ait, sit;
1306     int i;
1307
1308 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
1309 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
1310 #define CONT_CLOSE(p,c)    dbus_message_iter_close_container(p, c)
1311
1312     if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(nn)", &ait))
1313         return FALSE;
1314
1315     for (i = 1;  i < 3;  i++) {
1316         if (! CONT_OPEN   (&ait, DBUS_TYPE_STRUCT, NULL, &sit) ||
1317             ! CONT_APPEND (&sit, DBUS_TYPE_INT16,  &i        ) ||
1318             ! CONT_APPEND (&sit, DBUS_TYPE_INT16,  &zero     ) ||
1319             ! CONT_CLOSE  (&ait,                         &sit)   )
1320         {
1321             return FALSE;
1322         }
1323     }
1324
1325     if (!CONT_CLOSE(mit, &ait))
1326         return FALSE;
1327
1328 #undef CONT_CLOSE
1329 #undef CONT_APPEND
1330 #undef CONT_OPEN
1331
1332     return TRUE;
1333 }
1334
1335 static pa_bool_t build_connection_formats(DBusMessageIter *mit,
1336                                           struct am_nodereg_data *rd)
1337 {
1338     DBusMessageIter ait;
1339     int i;
1340
1341 #define CONT_OPEN(t,s)   dbus_message_iter_open_container(mit, t, s, &ait)
1342 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&ait, t, v)
1343 #define CONT_CLOSE       dbus_message_iter_close_container(mit, &ait)
1344
1345     if (!CONT_OPEN(DBUS_TYPE_ARRAY, "n")) 
1346         return FALSE;
1347
1348     for (i = 1;  i < 2;  i++) {
1349         if (!CONT_APPEND(DBUS_TYPE_INT16,  &i))
1350             return FALSE;
1351     }
1352
1353     if (!CONT_CLOSE)
1354         return FALSE;
1355
1356 #undef CONT_CLOSE
1357 #undef CONT_APPEND
1358 #undef CONT_OPEN
1359
1360     return TRUE;
1361 }
1362
1363 pa_bool_t pa_routerif_register_node(struct userdata *u,
1364                                     am_method m,
1365                                     am_nodereg_data *rd)
1366 {
1367     const char      *method = method_str(m);
1368     pa_routerif     *routerif;
1369     DBusConnection  *conn;
1370     DBusMessage     *msg;
1371     DBusMessageIter  mit;
1372     DBusMessageIter  cit;
1373     pa_bool_t        success = FALSE;
1374
1375     pa_assert(u);
1376     pa_assert(rd);
1377     pa_assert_se((routerif = u->routerif));
1378     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1379
1380     pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,rd->name);
1381
1382     msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1383                                        routerif->amrnam, method);
1384     
1385     if (msg == NULL) {
1386         pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1387         goto getout;
1388     }
1389
1390
1391 #define MSG_APPEND(t,v)  dbus_message_iter_append_basic(&mit, t, v)
1392 #define CONT_OPEN(t,s)   dbus_message_iter_open_container(&mit, t, s, &cit)
1393 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&cit, t, v)
1394 #define CONT_CLOSE       dbus_message_iter_close_container(&mit, &cit)
1395
1396     dbus_message_iter_init_append(msg, &mit);
1397
1398     if ((!strcmp(method, AUDIOMGR_REGISTER_SINK) &&
1399          (! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->id          ) ||
1400           ! MSG_APPEND  ( DBUS_TYPE_STRING , &rd->name        ) ||
1401           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->domain      ) ||
1402           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->class       ) ||
1403           ! MSG_APPEND  ( DBUS_TYPE_INT16  , &rd->volume      ) ||
1404           ! MSG_APPEND  ( DBUS_TYPE_BOOLEAN, &rd->visible     ) ||
1405           ! CONT_OPEN   ( DBUS_TYPE_STRUCT ,  NULL            ) ||
1406           ! CONT_APPEND ( DBUS_TYPE_INT16  , &rd->avail.status) ||
1407           ! CONT_APPEND ( DBUS_TYPE_INT16  , &rd->avail.reason) ||
1408           ! CONT_CLOSE                                          ||
1409           ! MSG_APPEND  ( DBUS_TYPE_INT16  , &rd->mute        ) ||
1410           ! MSG_APPEND  ( DBUS_TYPE_INT16  , &rd->mainvol     ) ||
1411           ! build_sound_properties(&mit, rd)                    ||
1412           ! build_connection_formats(&mit, rd)                  ||
1413           ! build_sound_properties(&mit, rd)                      )) ||
1414         (!strcmp(method, AUDIOMGR_REGISTER_SOURCE) &&
1415          (! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->id          ) ||
1416           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->domain      ) ||
1417           ! MSG_APPEND  ( DBUS_TYPE_STRING , &rd->name        ) ||
1418           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->class       ) ||
1419           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->state       ) ||
1420           ! MSG_APPEND  ( DBUS_TYPE_INT16  , &rd->volume      ) ||
1421           ! MSG_APPEND  ( DBUS_TYPE_BOOLEAN, &rd->visible     ) ||
1422           ! CONT_OPEN   ( DBUS_TYPE_STRUCT ,  NULL            ) ||
1423           ! CONT_APPEND ( DBUS_TYPE_INT16  , &rd->avail.status) ||
1424           ! CONT_APPEND ( DBUS_TYPE_INT16  , &rd->avail.reason) ||
1425           ! CONT_CLOSE                                          ||
1426           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->interrupt   ) ||
1427           ! build_sound_properties(&mit, rd)                    ||
1428           ! build_connection_formats(&mit, rd)                  ||
1429           ! build_sound_properties(&mit, rd)                      )))
1430     {        
1431         pa_log("%s: failed to build message for AudioManager '%s'",
1432                __FILE__, method);
1433         goto getout;
1434     }
1435     
1436 #undef CONT_CLOSE
1437 #undef CONT_APPEND
1438 #undef CONT_OPEN
1439 #undef MSG_APPEND
1440
1441
1442     success = send_message_with_reply(u, conn, msg,
1443                                       audiomgr_register_node_cb, rd);
1444     if (!success) {
1445         pa_log("%s: Failed to %s", __FILE__, method);
1446         goto getout;
1447     }
1448     
1449  getout:
1450     dbus_message_unref(msg);
1451     return success;
1452 }
1453
1454 static void audiomgr_unregister_node_cb(struct userdata *u,
1455                                         const char      *method,
1456                                         DBusMessage     *reply,
1457                                         void            *data)
1458 {
1459     const char      *error_descr;
1460     dbus_uint16_t    status;
1461     int              success;
1462     const char      *objtype;
1463
1464     pa_assert(u);
1465     pa_assert(method);
1466     pa_assert(reply);
1467     pa_assert(data);
1468
1469     if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1470         success = dbus_message_get_args(reply, NULL,
1471                                         DBUS_TYPE_STRING, &error_descr,
1472                                         DBUS_TYPE_INVALID);
1473
1474         if (!success)
1475             error_descr = dbus_message_get_error_name(reply);
1476
1477         pa_log_info("%s: AudioManager deregistration failed: %s",
1478                     __FILE__, error_descr);
1479     }
1480     else {
1481         success = dbus_message_get_args(reply, NULL,
1482                                         DBUS_TYPE_UINT16, &status,
1483                                         DBUS_TYPE_INVALID);
1484
1485         if (!success) {
1486             pa_log("got broken message from AudioManager. "
1487                    "Deregistration failed");
1488         }
1489         else {
1490             if (!strncasecmp("deregister", method, 10))
1491                 objtype = method + 10;
1492             else
1493                 objtype = method;
1494
1495             pa_log_info("AudioManager replied to %s deregistration: %u",
1496                         objtype, status);
1497
1498             pa_audiomgr_node_unregistered(u, data);
1499         }
1500     }
1501 }
1502
1503 pa_bool_t pa_routerif_unregister_node(struct userdata *u,
1504                                       am_method m,
1505                                       am_nodeunreg_data *ud)
1506 {
1507     const char     *method = method_str(m);
1508     pa_routerif    *routerif;
1509     DBusConnection *conn;
1510     DBusMessage    *msg;
1511     pa_bool_t       success = FALSE;
1512
1513     pa_assert(u);
1514     pa_assert(ud);
1515     pa_assert_se((routerif = u->routerif));
1516     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1517
1518     pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,ud->name);
1519
1520     msg = dbus_message_new_method_call(routerif->amnam, routerif->amrpath,
1521                                        routerif->amrnam, method);
1522     
1523     if (msg == NULL) {
1524         pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1525         goto getout;
1526     }
1527
1528     success = dbus_message_append_args(msg,
1529                                        DBUS_TYPE_INT16, &ud->id,
1530                                        DBUS_TYPE_INVALID);
1531
1532     success = send_message_with_reply(u, conn, msg,
1533                                       audiomgr_unregister_node_cb,ud);
1534     if (!success) {
1535         pa_log("%s: Failed to %s", __FILE__, method);
1536         goto getout;
1537     }
1538     
1539  getout:
1540     dbus_message_unref(msg);
1541     return success;
1542 }
1543
1544 static pa_bool_t routerif_connect(struct userdata *u, DBusMessage *msg)
1545 {
1546     struct am_connect_data ac;
1547     int                    success;
1548
1549     pa_assert(u);
1550     pa_assert(msg);
1551
1552     memset(&ac, 0, sizeof(ac));
1553
1554     success = dbus_message_get_args(msg, NULL,
1555                                     DBUS_TYPE_UINT16, &ac.handle,
1556                                     DBUS_TYPE_UINT16, &ac.connection,
1557                                     DBUS_TYPE_UINT16, &ac.source,
1558                                     DBUS_TYPE_UINT16, &ac.sink,
1559                                     DBUS_TYPE_INT16 , &ac.format,
1560                                     DBUS_TYPE_INVALID);
1561     if (!success) {
1562         pa_log("%s: got broken connect message from AudioManager. "
1563                "Ignoring it", __FILE__);
1564         return FALSE;
1565     }
1566
1567     pa_log_debug("AudioManager connect(%u|%u|%u|%u|%d)",
1568                  ac.handle, ac.connection, ac.source, ac.sink, ac.format);
1569
1570     pa_audiomgr_connect(u, &ac);
1571
1572     return TRUE;
1573 }
1574
1575 static pa_bool_t routerif_disconnect(struct userdata *u, DBusMessage *msg)
1576 {
1577     struct am_connect_data ac;
1578     int                    success;
1579
1580     pa_assert(u);
1581     pa_assert(msg);
1582
1583     memset(&ac, 0, sizeof(ac));
1584
1585     success = dbus_message_get_args(msg, NULL,
1586                                     DBUS_TYPE_UINT16, &ac.handle,
1587                                     DBUS_TYPE_UINT16, &ac.connection,
1588                                     DBUS_TYPE_INVALID);
1589     if (!success) {
1590         pa_log("%s: got broken disconnect message from AudioManager. "
1591                "Ignoring it",  __FILE__);
1592         return FALSE;
1593     }
1594
1595     pa_log_debug("AudioManager disconnect(%u|%u)", ac.handle, ac.connection);
1596
1597     pa_audiomgr_disconnect(u, &ac);
1598
1599     return TRUE;
1600 }
1601
1602 pa_bool_t pa_routerif_acknowledge(struct userdata *u, am_method m,
1603                                   struct am_ack_data *ad)
1604 {
1605     const char     *method = method_str(m);
1606     pa_routerif    *routerif;
1607     DBusConnection *conn;
1608     DBusMessage    *msg;
1609     pa_bool_t       success;
1610
1611     pa_assert(u);
1612     pa_assert(method);
1613     pa_assert_se((routerif = u->routerif));
1614     pa_assert_se((conn = pa_dbus_connection_get(routerif->conn)));
1615
1616     pa_log_debug("%s: sending %s", __FILE__, method);
1617
1618     msg = dbus_message_new_method_call(routerif->amnam,
1619                                        routerif->amrpath,
1620                                        routerif->amrnam,
1621                                        method);
1622     if (msg == NULL) {
1623         pa_log("%s: Failed to create D-Bus message for '%s'",
1624                __FILE__, method);
1625         success = FALSE;
1626         goto getout;
1627     }
1628
1629     success = dbus_message_append_args(msg,
1630                                        DBUS_TYPE_UINT16,  &ad->handle,
1631                                        DBUS_TYPE_UINT16,  &ad->param1,
1632                                        DBUS_TYPE_UINT16,  &ad->error,
1633                                        DBUS_TYPE_INVALID);
1634     if (!success) {
1635         pa_log("%s: Failed to build D-Bus message message '%s'",
1636                __FILE__, method);
1637         goto getout;
1638     }
1639
1640     if (!dbus_connection_send(conn, msg, NULL)) {
1641         pa_log("%s: Failed to send D-Bus message '%s'", __FILE__, method);
1642         goto getout;
1643     }
1644
1645  getout:
1646     dbus_message_unref(msg);
1647     return success;
1648 }
1649
1650
1651 static const char *method_str(am_method m)
1652 {
1653     switch (m) {
1654     case audiomgr_register_domain:   return AUDIOMGR_REGISTER_DOMAIN;
1655     case audiomgr_domain_complete:   return AUDIOMGR_DOMAIN_COMPLETE;
1656     case audiomgr_deregister_domain: return AUDIOMGR_DEREGISTER_DOMAIN;
1657     case audiomgr_register_source:   return AUDIOMGR_REGISTER_SOURCE;
1658     case audiomgr_deregister_source: return AUDIOMGR_DEREGISTER_SOURCE;
1659     case audiomgr_register_sink:     return AUDIOMGR_REGISTER_SINK;
1660     case audiomgr_deregister_sink:   return AUDIOMGR_DEREGISTER_SINK;
1661     case audiomgr_connect:           return AUDIOMGR_CONNECT;
1662     case audiomgr_connect_ack:       return AUDIOMGR_CONNECT_ACK;   
1663     case audiomgr_disconnect:        return AUDIOMGR_DISCONNECT;
1664     case audiomgr_disconnect_ack:    return AUDIOMGR_DISCONNECT_ACK;    
1665     case audiomgr_setsinkvol_ack:    return AUDIOMGR_SETSINKVOL_ACK;
1666     case audiomgr_setsrcvol_ack:     return AUDIOMGR_SETSRCVOL_ACK;
1667     case audiomgr_sinkvoltick_ack:   return AUDIOMGR_SINKVOLTICK_ACK;
1668     case audiomgr_srcvoltick_ack:    return AUDIOMGR_SRCVOLTICK_ACK;
1669     case audiomgr_setsinkprop_ack:   return AUDIOMGR_SETSINKPROP_ACK;
1670     default:                         return "invalid_method";
1671     }
1672 }
1673
1674 /*
1675  * Local Variables:
1676  * c-basic-offset: 4
1677  * indent-tabs-mode: nil
1678  * End:
1679  *
1680  */
1681