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