router: fix for bluetooth disappearing causing assert in combine
[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_policy_dbusif {
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 pa_policy_free_dbusif(struct pa_policy_dbusif *,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 dbusif_connect(struct userdata *, DBusMessage *);
159 static pa_bool_t dbusif_disconnect(struct userdata *, DBusMessage *);
160
161
162
163 struct pa_policy_dbusif *pa_policy_dbusif_init(struct userdata *u,
164                                                const char      *dbustype,
165                                                const char      *ifnam,
166                                                const char      *mrppath,
167                                                const char      *mrpnam,
168                                                const char      *ampath,
169                                                const char      *amnam)
170 {
171     static const DBusObjectPathVTable  vtable = {
172         .message_function = audiomgr_method_handler,
173     };
174
175     pa_module               *m = u->module;
176     struct pa_policy_dbusif *dbusif = NULL;
177     DBusBusType              type;
178     DBusConnection          *dbusconn;
179     DBusError                error;
180     unsigned int             flags;
181     char                     nambuf[128];
182     char                     pathbuf[128];
183     char                    *amrnam;
184     char                    *amrpath;
185     char                     actrule[512];
186     char                     strrule[512];
187     char                     admmrule[512];
188     char                     admarule[512];
189     int                      result;
190     
191     if (!dbustype || !strcasecmp(dbustype, "session")) {
192         dbustype = "session";
193         type = DBUS_BUS_SESSION;
194     }
195     else if (!strcasecmp(dbustype, "system")) {
196         dbustype = "system";
197         type = DBUS_BUS_SYSTEM;
198     }
199     else {
200         pa_log("invalid dbus type '%s'", dbustype);
201         return NULL;
202     }
203     
204     dbusif = pa_xnew0(struct pa_policy_dbusif, 1);
205     PA_LLIST_HEAD_INIT(struct pending, dbusif->pendlist);
206
207     dbus_error_init(&error);
208     dbusif->conn = pa_dbus_bus_get(m->core, type, &error);
209
210     if (dbusif->conn == NULL || dbus_error_is_set(&error)) {
211         pa_log("%s: failed to get %s Bus: %s: %s",
212                __FILE__, dbustype, error.name, error.message);
213         goto fail;
214     }
215
216     dbusconn = pa_dbus_connection_get(dbusif->conn);
217
218     flags  = DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE;
219     result = dbus_bus_request_name(dbusconn, PULSE_DBUS_NAME, flags,&error);
220
221     if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER &&
222         result != DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER    ) {
223         pa_log("%s: D-Bus name request failed: %s: %s",
224                __FILE__, error.name, error.message);
225         goto fail;
226     }
227     
228     pa_log_info("%s: now owner of '%s' D-Bus name on %s bus",
229                 __FILE__, PULSE_DBUS_NAME, dbustype);
230  
231     if (!dbus_connection_add_filter(dbusconn, filter,u, NULL)) {
232         pa_log("%s: failed to add filter function", __FILE__);
233         goto fail;
234     }
235
236     if (!ifnam)
237         ifnam = POLICY_DBUS_INTERFACE;
238
239     if (!mrppath)
240         mrppath = POLICY_DBUS_MRPPATH;
241
242     if (!mrpnam)
243         mrpnam = POLICY_DBUS_MRPNAME;
244
245     if (ampath && *ampath) {
246         char *slash = ampath[strlen(ampath)-1] == '/' ? "" : "/";
247         snprintf(pathbuf, sizeof(pathbuf), "%s%s" AUDIOMGR_DBUS_ROUTE_PATH,
248                  ampath, slash);
249         amrpath = pathbuf;
250     }
251     else {
252         ampath  = AUDIOMGR_DBUS_PATH;
253         amrpath = AUDIOMGR_DBUS_PATH "/" AUDIOMGR_DBUS_ROUTE_PATH;
254     }
255
256     if (amnam && *amnam){
257         char *dot = amnam[strlen(amnam)-1] == '.' ? "" : ".";
258         snprintf(nambuf, sizeof(nambuf), "%s%s" AUDIOMGR_DBUS_ROUTE_NAME,
259                  amnam, dot);
260         amrnam = nambuf;
261     }
262     else {
263         amnam  = AUDIOMGR_DBUS_INTERFACE;
264         amrnam = AUDIOMGR_DBUS_INTERFACE "." AUDIOMGR_DBUS_ROUTE_NAME;
265     }
266
267
268     snprintf(admmrule, sizeof(admmrule), "type='signal',sender='%s',path='%s',"
269              "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
270              ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
271              mrpnam);
272     dbus_bus_add_match(dbusconn, admmrule, &error);
273
274     snprintf(admarule, sizeof(admarule), "type='signal',sender='%s',path='%s',"
275              "interface='%s',member='%s',arg0='%s'", ADMIN_DBUS_MANAGER,
276              ADMIN_DBUS_PATH, ADMIN_DBUS_INTERFACE, ADMIN_NAME_OWNER_CHANGED,
277              amnam);
278     dbus_bus_add_match(dbusconn, admarule, &error);
279
280     if (dbus_error_is_set(&error)) {
281         pa_log("%s: unable to subscribe name change signals on %s: %s: %s",
282                __FILE__, ADMIN_DBUS_INTERFACE, error.name, error.message);
283         goto fail;
284     }
285
286     snprintf(actrule, sizeof(actrule), "type='signal',interface='%s',"
287              "member='%s',path='%s/%s'", ifnam, POLICY_ACTIONS,
288              mrppath, POLICY_DECISION);
289     dbus_bus_add_match(dbusconn, actrule, &error);
290
291     if (dbus_error_is_set(&error)) {
292         pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
293                __FILE__, POLICY_ACTIONS, ifnam, error.name, error.message);
294         goto fail;
295     }
296
297     snprintf(strrule, sizeof(strrule), "type='signal',interface='%s',"
298              "member='%s',path='%s/%s'", ifnam, POLICY_STREAM_INFO,
299              mrppath, POLICY_DECISION);
300     dbus_bus_add_match(dbusconn, strrule, &error);
301
302     if (dbus_error_is_set(&error)) {
303         pa_log("%s: unable to subscribe policy %s signal on %s: %s: %s",
304                __FILE__, POLICY_STREAM_INFO, ifnam, error.name, error.message);
305         goto fail;
306     }
307
308     pa_log_info("%s: subscribed policy signals on %s", __FILE__, ifnam);
309
310     dbus_connection_register_object_path(dbusconn, PULSE_DBUS_PATH, &vtable,u);
311
312
313     dbusif->ifnam    = pa_xstrdup(ifnam);
314     dbusif->mrppath  = pa_xstrdup(mrppath);
315     dbusif->mrpnam   = pa_xstrdup(mrpnam);
316     dbusif->ampath   = pa_xstrdup(ampath);
317     dbusif->amnam    = pa_xstrdup(amnam);
318     dbusif->amrpath  = pa_xstrdup(amrpath);
319     dbusif->amrnam   = pa_xstrdup(amrnam);
320     dbusif->admmrule = pa_xstrdup(admmrule);
321     dbusif->admarule = pa_xstrdup(admarule);
322     dbusif->actrule  = pa_xstrdup(actrule);
323     dbusif->strrule  = pa_xstrdup(strrule);
324
325     u->dbusif = dbusif; /* Argh.. */
326
327     register_to_murphy(u);
328     register_to_audiomgr(u);
329
330     return dbusif;
331
332  fail:
333     pa_policy_free_dbusif(dbusif, u);
334     dbus_error_free(&error);
335     return NULL;
336 }
337
338 static void pa_policy_free_dbusif(struct pa_policy_dbusif *dbusif,
339                                   struct userdata *u)
340 {
341     DBusConnection  *dbusconn;
342     struct pending  *p, *n;
343
344     if (dbusif) {
345
346         if (dbusif->conn) {
347             dbusconn = pa_dbus_connection_get(dbusif->conn);
348
349             PA_LLIST_FOREACH_SAFE(p,n, dbusif->pendlist) {
350                 PA_LLIST_REMOVE(struct pending, dbusif->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, dbusif->admmrule, NULL);
360             dbus_bus_remove_match(dbusconn, dbusif->admarule, NULL);
361             dbus_bus_remove_match(dbusconn, dbusif->actrule, NULL);
362             dbus_bus_remove_match(dbusconn, dbusif->strrule, NULL);
363
364             pa_dbus_connection_unref(dbusif->conn);
365         }
366
367         pa_xfree(dbusif->ifnam);
368         pa_xfree(dbusif->mrppath);
369         pa_xfree(dbusif->mrpnam);
370         pa_xfree(dbusif->ampath);
371         pa_xfree(dbusif->amnam);
372         pa_xfree(dbusif->amrpath);
373         pa_xfree(dbusif->amrnam);
374         pa_xfree(dbusif->admmrule);
375         pa_xfree(dbusif->admarule);
376         pa_xfree(dbusif->actrule);
377         pa_xfree(dbusif->strrule);
378
379         pa_xfree(dbusif);
380     }
381 }
382
383 void pa_policy_dbusif_done(struct userdata *u)
384 {
385     if (u && u->dbusif) {
386         pa_policy_free_dbusif(u->dbusif, u);
387         u->dbusif = 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     struct pa_policy_dbusif *dbusif;
424     char                    *name;
425     char                    *before;
426     char                    *after;
427     int                      success;
428
429     pa_assert(u);
430     pa_assert_se((dbusif = u->dbusif));
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, dbusif->mrpnam)) {
444         if (after && strcmp(after, "")) {
445             pa_log_debug("murphy is up");
446
447             if (!dbusif->mregist) {
448                 register_to_murphy(u);
449             }
450         }
451
452         if (name && before && (!after || !strcmp(after, ""))) {
453             pa_log_info("murphy is gone");
454             dbusif->mregist = 0;
455         } 
456     } else
457
458     if (!strcmp(name, dbusif->amnam)) {
459         if (after && strcmp(after, "")) {
460             pa_log_debug("audio manager is up");
461
462             if (!dbusif->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 (dbusif->amisup)
471                 unregister_from_audiomgr(u);
472
473             dbusif->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     struct pa_policy_dbusif *dbusif;
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((dbusif = u->dbusif));
490
491     PA_LLIST_REMOVE(struct pending, dbusif->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     struct pa_policy_dbusif  *dbusif;
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((dbusif = u->dbusif));
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, dbusif->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, dbusif->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_policy_dbusif_send_device_state(struct userdata *u, char *state,
566                                         char **types, int ntype)
567 {
568     static char             *path = (char *)"/com/nokia/policy/info";
569
570     struct pa_policy_dbusif *dbusif = u->dbusif;
571     DBusConnection          *conn   = pa_dbus_connection_get(dbusif->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, dbusif->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_policy_dbusif_send_media_status(struct userdata *u, const char *media,
616                                         const char *group, int active)
617 {
618     static char             *path = (char *)"/com/nokia/policy/info";
619     static const char       *type = "media";
620
621     struct pa_policy_dbusif *dbusif = u->dbusif;
622     DBusConnection          *conn   = pa_dbus_connection_get(dbusif->conn);
623     DBusMessage             *msg;
624     const char              *state;
625     int                      success;
626
627     msg = dbus_message_new_signal(path, dbusif->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         { "com.nokia.policy.audio_route" , audio_route_parser  },
738         { "com.nokia.policy.volume_limit", volume_limit_parser },
739         { "com.nokia.policy.audio_cork"  , audio_cork_parser   },
740         { "com.nokia.policy.audio_mute"  , audio_mute_parser   },
741         { "com.nokia.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->dbusif) {
845             u->dbusif->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_policy_dbusif *dbusif = u->dbusif;
855     DBusConnection   *conn   = pa_dbus_connection_get(dbusif->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__, dbusif->mrpnam, dbusif->mrppath, dbusif->ifnam);
864
865     msg = dbus_message_new_method_call(dbusif->mrpnam, dbusif->mrppath,
866                                        dbusif->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     struct pa_policy_dbusif *dbusif = u->dbusif;
902     DBusConnection          *conn   = pa_dbus_connection_get(dbusif->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", dbusif->mrppath, POLICY_DECISION);
917
918     pa_log_debug("sending signal to: path='%s', if='%s' member='%s' "
919                  "content: txid=%d status=%d", path, dbusif->ifnam,
920                  POLICY_STATUS, txid, status);
921
922     msg = dbus_message_new_signal(path, dbusif->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   , dbusif_connect    },
973         { AUDIOMGR_DISCONNECT, dbusif_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->dbusif) {
1081                 u->dbusif->amisup = 1;
1082                 pa_audiomgr_domain_registered(u, domain_id, status, data);
1083             }
1084         }
1085     }
1086 }
1087
1088
1089
1090 pa_bool_t pa_policy_dbusif_register_domain(struct userdata   *u,
1091                                            am_domainreg_data *dr)
1092 {
1093     pa_policy_dbusif *dbusif;
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((dbusif = u->dbusif));
1104     pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1105
1106     pa_log_info("%s: registering to AudioManager: name='%s' path='%s' if='%s'"
1107                 , __FILE__, dbusif->amnam, dbusif->amrpath, dbusif->amrnam);
1108
1109     msg = dbus_message_new_method_call(dbusif->amnam,
1110                                        dbusif->amrpath,
1111                                        dbusif->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_policy_dbusif_domain_complete(struct userdata *u, uint16_t domain)
1154 {
1155     dbus_int32_t             id32 = domain;
1156     struct pa_policy_dbusif *dbusif;
1157     DBusConnection          *conn;
1158     DBusMessage             *msg;
1159     pa_bool_t                success;
1160
1161     pa_assert(u);
1162     pa_assert_se((dbusif = u->dbusif));
1163     pa_assert_se((conn = pa_dbus_connection_get(dbusif->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(dbusif->amnam,
1170                                        dbusif->amrpath,
1171                                        dbusif->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_policy_dbusif_unregister_domain(struct userdata *u,
1202                                              uint16_t domain)
1203 {
1204     pa_policy_dbusif *dbusif;
1205     DBusConnection   *conn;
1206     DBusMessage      *msg;
1207     pa_bool_t         success;
1208
1209     pa_assert(u);
1210     pa_assert_se((dbusif = u->dbusif));
1211     pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1212
1213     pa_log_info("%s: deregistreing domain %u from AudioManager",
1214                 __FILE__, domain);
1215
1216     msg = dbus_message_new_method_call(dbusif->amnam,
1217                                        dbusif->amrpath,
1218                                        dbusif->amrnam,
1219                                        AUDIOMGR_DEREGISTER_DOMAIN);
1220     if (msg == NULL) {
1221         pa_log("%s: Failed to create D-Bus message for '%s'",
1222                __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1223         success = FALSE;
1224         goto getout;
1225     }
1226
1227     dbus_message_set_no_reply(msg, TRUE);
1228
1229     success = dbus_message_append_args(msg,
1230                                        DBUS_TYPE_UINT16,  &domain,
1231                                        DBUS_TYPE_INVALID);
1232     if (!success) {
1233         pa_log("%s: Failed to build D-Bus message for '%s'",
1234                __FILE__, AUDIOMGR_DEREGISTER_DOMAIN);
1235         goto getout;
1236     }
1237
1238     if (!dbus_connection_send(conn, msg, NULL)) {
1239         pa_log("%s: Failed to send '%s'", __FILE__,AUDIOMGR_DEREGISTER_DOMAIN);
1240         goto getout;
1241     }
1242
1243     dbus_connection_flush(conn);
1244
1245  getout:
1246     dbus_message_unref(msg);
1247     return success;
1248 }
1249
1250
1251 static void audiomgr_register_node_cb(struct userdata *u,
1252                                       const char      *method,
1253                                       DBusMessage     *reply,
1254                                       void            *data)
1255 {
1256     const char      *error_descr;
1257     dbus_uint16_t    object_id;
1258     dbus_uint16_t    status;
1259     int              success;
1260     const char      *objtype;
1261
1262     pa_assert(u);
1263     pa_assert(method);
1264     pa_assert(reply);
1265     pa_assert(data);
1266
1267     if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1268         success = dbus_message_get_args(reply, NULL,
1269                                         DBUS_TYPE_STRING, &error_descr,
1270                                         DBUS_TYPE_INVALID);
1271
1272         if (!success)
1273             error_descr = dbus_message_get_error_name(reply);
1274
1275         pa_log_info("%s: AudioManager registration failed: %s",
1276                     __FILE__, error_descr);
1277     }
1278     else {
1279         success = dbus_message_get_args(reply, NULL,
1280                                         DBUS_TYPE_UINT16, &object_id,
1281                                         DBUS_TYPE_UINT16, &status,
1282                                         DBUS_TYPE_INVALID);
1283
1284         if (!success) {
1285             pa_log("got broken message from AudioManager.Registration failed");
1286         }
1287         else {
1288             if (!strncasecmp("register", method, 8))
1289                 objtype = method + 8;
1290             else
1291                 objtype = method;
1292
1293             pa_log_info("AudioManager replied to registration: %sID: %u",
1294                         objtype, object_id);
1295
1296             pa_audiomgr_node_registered(u, object_id, status, data);
1297         }
1298     }
1299 }
1300
1301 static pa_bool_t build_sound_properties(DBusMessageIter *mit,
1302                                         struct am_nodereg_data *rd)
1303 {
1304     static int16_t zero;
1305
1306     DBusMessageIter ait, sit;
1307     int i;
1308
1309 #define CONT_OPEN(p,t,s,c) dbus_message_iter_open_container(p, t, s, c)
1310 #define CONT_APPEND(i,t,v) dbus_message_iter_append_basic(i, t, v)
1311 #define CONT_CLOSE(p,c)    dbus_message_iter_close_container(p, c)
1312
1313     if (!CONT_OPEN(mit, DBUS_TYPE_ARRAY, "(nn)", &ait))
1314         return FALSE;
1315
1316     for (i = 1;  i < 3;  i++) {
1317         if (! CONT_OPEN   (&ait, DBUS_TYPE_STRUCT, NULL, &sit) ||
1318             ! CONT_APPEND (&sit, DBUS_TYPE_INT16,  &i        ) ||
1319             ! CONT_APPEND (&sit, DBUS_TYPE_INT16,  &zero     ) ||
1320             ! CONT_CLOSE  (&ait,                         &sit)   )
1321         {
1322             return FALSE;
1323         }
1324     }
1325
1326     if (!CONT_CLOSE(mit, &ait))
1327         return FALSE;
1328
1329 #undef CONT_CLOSE
1330 #undef CONT_APPEND
1331 #undef CONT_OPEN
1332
1333     return TRUE;
1334 }
1335
1336 static pa_bool_t build_connection_formats(DBusMessageIter *mit,
1337                                           struct am_nodereg_data *rd)
1338 {
1339     DBusMessageIter ait;
1340     int i;
1341
1342 #define CONT_OPEN(t,s)   dbus_message_iter_open_container(mit, t, s, &ait)
1343 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&ait, t, v)
1344 #define CONT_CLOSE       dbus_message_iter_close_container(mit, &ait)
1345
1346     if (!CONT_OPEN(DBUS_TYPE_ARRAY, "n")) 
1347         return FALSE;
1348
1349     for (i = 1;  i < 2;  i++) {
1350         if (!CONT_APPEND(DBUS_TYPE_INT16,  &i))
1351             return FALSE;
1352     }
1353
1354     if (!CONT_CLOSE)
1355         return FALSE;
1356
1357 #undef CONT_CLOSE
1358 #undef CONT_APPEND
1359 #undef CONT_OPEN
1360
1361     return TRUE;
1362 }
1363
1364 pa_bool_t pa_policy_dbusif_register_node(struct userdata *u,
1365                                          const char *method,
1366                                          am_nodereg_data *rd)
1367 {
1368     struct pa_policy_dbusif *dbusif;
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(method);
1377     pa_assert(rd);
1378     pa_assert_se((dbusif = u->dbusif));
1379     pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1380
1381     pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,rd->name);
1382
1383     msg = dbus_message_new_method_call(dbusif->amnam, dbusif->amrpath,
1384                                        dbusif->amrnam, method);
1385     
1386     if (msg == NULL) {
1387         pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1388         goto getout;
1389     }
1390
1391
1392 #define MSG_APPEND(t,v)  dbus_message_iter_append_basic(&mit, t, v)
1393 #define CONT_OPEN(t,s)   dbus_message_iter_open_container(&mit, t, s, &cit)
1394 #define CONT_APPEND(t,v) dbus_message_iter_append_basic(&cit, t, v)
1395 #define CONT_CLOSE       dbus_message_iter_close_container(&mit, &cit)
1396
1397     dbus_message_iter_init_append(msg, &mit);
1398
1399     if ((!strcmp(method, AUDIOMGR_REGISTER_SINK) &&
1400          (! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->id          ) ||
1401           ! MSG_APPEND  ( DBUS_TYPE_STRING , &rd->name        ) ||
1402           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->domain      ) ||
1403           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->class       ) ||
1404           ! MSG_APPEND  ( DBUS_TYPE_INT16  , &rd->volume      ) ||
1405           ! MSG_APPEND  ( DBUS_TYPE_BOOLEAN, &rd->visible     ) ||
1406           ! CONT_OPEN   ( DBUS_TYPE_STRUCT ,  NULL            ) ||
1407           ! CONT_APPEND ( DBUS_TYPE_INT16  , &rd->avail.status) ||
1408           ! CONT_APPEND ( DBUS_TYPE_INT16  , &rd->avail.reason) ||
1409           ! CONT_CLOSE                                          ||
1410           ! MSG_APPEND  ( DBUS_TYPE_INT16  , &rd->mute        ) ||
1411           ! MSG_APPEND  ( DBUS_TYPE_INT16  , &rd->mainvol     ) ||
1412           ! build_sound_properties(&mit, rd)                    ||
1413           ! build_connection_formats(&mit, rd)                  ||
1414           ! build_sound_properties(&mit, rd)                      )) ||
1415         (!strcmp(method, AUDIOMGR_REGISTER_SOURCE) &&
1416          (! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->id          ) ||
1417           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->domain      ) ||
1418           ! MSG_APPEND  ( DBUS_TYPE_STRING , &rd->name        ) ||
1419           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->class       ) ||
1420           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->state       ) ||
1421           ! MSG_APPEND  ( DBUS_TYPE_INT16  , &rd->volume      ) ||
1422           ! MSG_APPEND  ( DBUS_TYPE_BOOLEAN, &rd->visible     ) ||
1423           ! CONT_OPEN   ( DBUS_TYPE_STRUCT ,  NULL            ) ||
1424           ! CONT_APPEND ( DBUS_TYPE_INT16  , &rd->avail.status) ||
1425           ! CONT_APPEND ( DBUS_TYPE_INT16  , &rd->avail.reason) ||
1426           ! CONT_CLOSE                                          ||
1427           ! MSG_APPEND  ( DBUS_TYPE_UINT16 , &rd->interrupt   ) ||
1428           ! build_sound_properties(&mit, rd)                    ||
1429           ! build_connection_formats(&mit, rd)                  ||
1430           ! build_sound_properties(&mit, rd)                      )))
1431     {        
1432         pa_log("%s: failed to build message for AudioManager '%s'",
1433                __FILE__, method);
1434         goto getout;
1435     }
1436     
1437 #undef CONT_CLOSE
1438 #undef CONT_APPEND
1439 #undef CONT_OPEN
1440 #undef MSG_APPEND
1441
1442
1443     success = send_message_with_reply(u, conn, msg,
1444                                       audiomgr_register_node_cb, rd);
1445     if (!success) {
1446         pa_log("%s: Failed to %s", __FILE__, method);
1447         goto getout;
1448     }
1449     
1450  getout:
1451     dbus_message_unref(msg);
1452     return success;
1453 }
1454
1455 static void audiomgr_unregister_node_cb(struct userdata *u,
1456                                         const char      *method,
1457                                         DBusMessage     *reply,
1458                                         void            *data)
1459 {
1460     const char      *error_descr;
1461     dbus_uint16_t    status;
1462     int              success;
1463     const char      *objtype;
1464
1465     pa_assert(u);
1466     pa_assert(method);
1467     pa_assert(reply);
1468     pa_assert(data);
1469
1470     if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
1471         success = dbus_message_get_args(reply, NULL,
1472                                         DBUS_TYPE_STRING, &error_descr,
1473                                         DBUS_TYPE_INVALID);
1474
1475         if (!success)
1476             error_descr = dbus_message_get_error_name(reply);
1477
1478         pa_log_info("%s: AudioManager deregistration failed: %s",
1479                     __FILE__, error_descr);
1480     }
1481     else {
1482         success = dbus_message_get_args(reply, NULL,
1483                                         DBUS_TYPE_UINT16, &status,
1484                                         DBUS_TYPE_INVALID);
1485
1486         if (!success) {
1487             pa_log("got broken message from AudioManager. "
1488                    "Deregistration failed");
1489         }
1490         else {
1491             if (!strncasecmp("deregister", method, 10))
1492                 objtype = method + 10;
1493             else
1494                 objtype = method;
1495
1496             pa_log_info("AudioManager replied to %s deregistration: %u",
1497                         objtype, status);
1498
1499             pa_audiomgr_node_unregistered(u, data);
1500         }
1501     }
1502 }
1503
1504 pa_bool_t pa_policy_dbusif_unregister_node(struct userdata *u,
1505                                            const char *method,
1506                                            am_nodeunreg_data *ud)
1507 {
1508     struct pa_policy_dbusif *dbusif;
1509     DBusConnection          *conn;
1510     DBusMessage             *msg;
1511     pa_bool_t                success = FALSE;
1512
1513     pa_assert(u);
1514     pa_assert(method);
1515     pa_assert(ud);
1516     pa_assert_se((dbusif = u->dbusif));
1517     pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1518
1519     pa_log_debug("%s: %s '%s' to AudioManager", __FUNCTION__, method,ud->name);
1520
1521     msg = dbus_message_new_method_call(dbusif->amnam, dbusif->amrpath,
1522                                        dbusif->amrnam, method);
1523     
1524     if (msg == NULL) {
1525         pa_log("%s: Failed to create D-BUS message to '%s'", __FILE__, method);
1526         goto getout;
1527     }
1528
1529     success = dbus_message_append_args(msg,
1530                                        DBUS_TYPE_INT16, &ud->id,
1531                                        DBUS_TYPE_INVALID);
1532
1533     success = send_message_with_reply(u, conn, msg,
1534                                       audiomgr_unregister_node_cb,ud);
1535     if (!success) {
1536         pa_log("%s: Failed to %s", __FILE__, method);
1537         goto getout;
1538     }
1539     
1540  getout:
1541     dbus_message_unref(msg);
1542     return success;
1543 }
1544
1545 static pa_bool_t dbusif_connect(struct userdata *u, DBusMessage *msg)
1546 {
1547     struct am_connect_data ac;
1548     int                    success;
1549
1550     pa_assert(u);
1551     pa_assert(msg);
1552
1553     memset(&ac, 0, sizeof(ac));
1554
1555     success = dbus_message_get_args(msg, NULL,
1556                                     DBUS_TYPE_UINT16, &ac.handle,
1557                                     DBUS_TYPE_UINT16, &ac.connection,
1558                                     DBUS_TYPE_UINT16, &ac.source,
1559                                     DBUS_TYPE_UINT16, &ac.sink,
1560                                     DBUS_TYPE_INT16 , &ac.format,
1561                                     DBUS_TYPE_INVALID);
1562     if (!success) {
1563         pa_log("%s: got broken connect message from AudioManager. "
1564                "Ignoring it", __FILE__);
1565         return FALSE;
1566     }
1567
1568     pa_log_debug("AudioManager connect(%u|%u|%u|%u|%d)",
1569                  ac.handle, ac.connection, ac.source, ac.sink, ac.format);
1570
1571     pa_audiomgr_connect(u, &ac);
1572
1573     return TRUE;
1574 }
1575
1576 static pa_bool_t dbusif_disconnect(struct userdata *u, DBusMessage *msg)
1577 {
1578     struct am_connect_data ac;
1579     int                    success;
1580
1581     pa_assert(u);
1582     pa_assert(msg);
1583
1584     memset(&ac, 0, sizeof(ac));
1585
1586     success = dbus_message_get_args(msg, NULL,
1587                                     DBUS_TYPE_UINT16, &ac.handle,
1588                                     DBUS_TYPE_UINT16, &ac.connection,
1589                                     DBUS_TYPE_INVALID);
1590     if (!success) {
1591         pa_log("%s: got broken disconnect message from AudioManager. "
1592                "Ignoring it",  __FILE__);
1593         return FALSE;
1594     }
1595
1596     pa_log_debug("AudioManager disconnect(%u|%u)", ac.handle, ac.connection);
1597
1598     pa_audiomgr_disconnect(u, &ac);
1599
1600     return TRUE;
1601 }
1602
1603 pa_bool_t pa_policy_dbusif_acknowledge(struct userdata *u, const char *method,
1604                                        struct am_ack_data *ad)
1605 {
1606     struct pa_policy_dbusif *dbusif;
1607     DBusConnection          *conn;
1608     DBusMessage             *msg;
1609     pa_bool_t                success;
1610
1611     pa_assert(u);
1612     pa_assert(method);
1613     pa_assert_se((dbusif = u->dbusif));
1614     pa_assert_se((conn = pa_dbus_connection_get(dbusif->conn)));
1615
1616     pa_log_debug("%s: sending %s", __FILE__, method);
1617
1618     msg = dbus_message_new_method_call(dbusif->amnam,
1619                                        dbusif->amrpath,
1620                                        dbusif->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 /*
1652  * Local Variables:
1653  * c-basic-offset: 4
1654  * indent-tabs-mode: nil
1655  * End:
1656  *
1657  */
1658