2 * Copyright (c) 2014, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/types.h>
35 #include <murphy/common.h>
36 #include <murphy/common/dbus-libdbus.h>
38 #include "ini-parser.h"
40 /* from audiomanagertypes.h */
44 #define DS_CONTROLLED 1
50 #define IS_INTERRUPTED 2
52 /* availability status */
53 #define AS_AVAILABLE 1
54 #define AS_UNAVAILABLE 2
56 /* availability reason */
58 #define AR_SAMEMEDIA 2
60 #define AR_TEMPERATURE 4
62 #define AR_ERRORMEDIA 6
68 /* connection format */
76 #define E_OUT_OF_RANGE 2
78 #define E_DATABSE_ERROR 4
79 #define E_ALREADY_EXISTS 5
81 #define E_NOT_POSSIBLE 7
82 #define E_NON_EXISTENT 8
84 #define E_WRONG_FORMAT 10
86 /* D-Bus names, paths and interfaces */
87 #define AUDIOMGR_DBUS_NAME "org.genivi.audiomanager"
88 #define AUDIOMGR_DBUS_INTERFACE "org.genivi.audiomanager"
89 #define AUDIOMGR_DBUS_PATH "/org/genivi/audiomanager"
91 #define AUDIOMGR_DBUS_ROUTE_NAME "RoutingInterface"
92 #define AUDIOMGR_DBUS_ROUTE_PATH AUDIOMGR_DBUS_PATH "/routinginterface"
94 #define OWN_DBUS_NAME "test.audiomanager.domain"
95 #define OWN_DBUS_INTERFACE "test.audiomanager.route"
96 #define OWN_DBUS_PATH "/"
98 /* audiomanager router methods */
100 #define AUDIOMGR_REGISTER_DOMAIN "registerDomain"
101 #define AUDIOMGR_DOMAIN_COMPLETE "hookDomainRegistrationComplete"
102 #define AUDIOMGR_DEREGISTER_DOMAIN "deregisterDomain"
104 #define AUDIOMGR_REGISTER_SOURCE "registerSource"
105 #define AUDIOMGR_DEREGISTER_SOURCE "deregisterSource"
107 #define AUDIOMGR_REGISTER_SINK "registerSink"
108 #define AUDIOMGR_DEREGISTER_SINK "deregisterSink"
110 #define AUDIOMGR_REGISTER_GATEWAY "registerGateway"
111 #define AUDIOMGR_DEREGISTER_GATEWAY "deregisterGateway"
113 #define AUDIOMGR_CONNECT "asyncConnect"
114 #define AUDIOMGR_CONNECT_ACK "ackConnect"
116 #define AUDIOMGR_DISCONNECT "asyncDisconnect"
117 #define AUDIOMGR_DISCONNECT_ACK "ackDisconnect"
119 #define AUDIOMGR_PEEK_DOMAIN "peekDomain"
120 #define AUDIOMGR_PEEK_SINK "peekSink"
121 #define AUDIOMGR_PEEK_SOURCE "peekSource"
123 #define AUDIOMGR_SETSINKVOL_ACK "ackSetSinkVolume"
124 #define AUDIOMGR_SETSRCVOL_ACK "ackSetSourceVolume"
125 #define AUDIOMGR_SINKVOLTICK_ACK "ackSinkVolumeTick"
126 #define AUDIOMGR_SRCVOLTICK_ACK "ackSourceVolumeTick"
127 #define AUDIOMGR_SETSINKPROP_ACK "ackSetSinkSoundProperty"
129 /* config file sections */
131 #define CONFIG_SINK "sink"
132 #define CONFIG_SOURCE "source"
133 #define CONFIG_DOMAIN "domain"
134 #define CONFIG_GATEWAY "gateway"
135 #define CONFIG_CONFIG "config"
137 /* config file keys */
139 #define CONFIG_DBUS_BUS "dbus_bus"
140 #define CONFIG_DBUS_ADDRESS "dbus_address"
141 #define CONFIG_DBUS_PATH "dbus_path"
142 #define CONFIG_DBUS_INTERFACE "dbus_interface"
143 #define CONFIG_NAME "name"
144 #define CONFIG_BUS_NAME "bus_name"
145 #define CONFIG_NODE_NAME "node_name"
146 #define CONFIG_EARLY "early"
147 #define CONFIG_NAME "name"
148 #define CONFIG_DOMAIN_NAME "domain_name"
149 #define CONFIG_CONNECTION_SCRIPT "connection_script"
150 #define CONFIG_DISCONNECTION_SCRIPT "disconnection_script"
151 #define CONFIG_CLASS "class"
152 #define CONFIG_VOLUME "volume"
153 #define CONFIG_MAIN_VOLUME "main_volume"
154 #define CONFIG_VISIBLE "visible"
155 #define CONFIG_AVAILABILITY_STATUS "availability_status"
156 #define CONFIG_AVAILABILITY_REASON "availability_reason"
157 #define CONFIG_MUTE "mute"
158 #define CONFIG_INTERRUPT "interrupt"
160 #define CONFIG_SINK_DOMAIN "sink_domain"
161 #define CONFIG_SOURCE_DOMAIN "source_domain"
166 mrp_sighandler_t *sighandler;
171 int pending_dbus_calls;
173 mrp_list_hook_t domains;
177 /* configuration file */
184 char *dbus_interface;
185 char *connection_script;
186 char *disconnection_script;
192 mrp_list_hook_t sources;
193 mrp_list_hook_t sinks;
194 mrp_list_hook_t gateways;
195 mrp_list_hook_t connections;
197 mrp_list_hook_t hook;
206 mrp_list_hook_t hook;
217 char *sink_domain_name;
218 char *source_domain_name;
220 /* these are found only after registration */
223 uint16_t domain_sink_id;
224 uint16_t domain_source_id;
226 mrp_list_hook_t hook;
242 int16_t availability_reason;
243 int16_t availability_status;
245 mrp_list_hook_t hook;
261 int16_t availability_reason;
262 int16_t availability_status;
264 mrp_list_hook_t hook;
269 void destroy_sink(sink_t *s)
274 mrp_list_delete(&s->hook);
280 void destroy_source(source_t *s)
285 mrp_list_delete(&s->hook);
291 void destroy_connection(connection_t *c)
296 mrp_list_delete(&c->hook);
303 void destroy_gateway(gateway_t *gw)
309 mrp_free(gw->sink_name);
310 mrp_free(gw->source_name);
311 mrp_free(gw->sink_domain_name);
312 mrp_free(gw->source_domain_name);
317 void destroy_domain(domain_t *d)
319 mrp_list_hook_t *sp, *sn;
324 mrp_list_delete(&d->hook);
326 mrp_list_foreach(&d->sinks, sp, sn) {
327 sink_t *s = mrp_list_entry(sp, typeof(*s), hook);
331 mrp_list_foreach(&d->sources, sp, sn) {
332 source_t *s = mrp_list_entry(sp, typeof(*s), hook);
336 mrp_list_foreach(&d->gateways, sp, sn) {
337 gateway_t *gw = mrp_list_entry(sp, typeof(*gw), hook);
341 mrp_list_foreach(&d->connections, sp, sn) {
342 connection_t *c = mrp_list_entry(sp, typeof(*c), hook);
343 destroy_connection(c);
346 mrp_free(d->connection_script);
347 mrp_free(d->disconnection_script);
349 mrp_free(d->node_name);
350 mrp_free(d->bus_name);
351 mrp_free(d->dbus_path);
352 mrp_free(d->dbus_interface);
356 static int method_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *msg, void *data)
358 const char *member = mrp_dbus_msg_member(msg);
359 const char *iface = mrp_dbus_msg_interface(msg);
360 const char *path = mrp_dbus_msg_path(msg);
362 uint16_t error_code = E_NOT_POSSIBLE;
363 mrp_dbus_msg_t *reply;
367 printf("Method callback called -- member: '%s', path: '%s',"
368 " interface: '%s'\n", member, path, iface);
370 if (strcmp(member, AUDIOMGR_CONNECT) == 0) {
373 char *sink_name = NULL;
374 char *source_name = NULL;
382 domain_t *connection_domain = NULL;
383 sink_t *domain_sink = NULL;
384 source_t *domain_source = NULL;
386 mrp_list_hook_t *sp, *sn, *kp, *kn;
388 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_UINT16, &handle);
389 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_UINT16, &connection);
390 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_UINT16, &source);
391 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_UINT16, &sink);
392 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_INT32, &format);
396 mrp_dbus_reply(dbus, msg, MRP_DBUS_TYPE_INT16, &error_code,
397 MRP_DBUS_TYPE_INVALID);
399 /* find the gateway */
401 printf("connect! h: %u, conn: %u, source: %u, sink: %u, format: %i\n",
402 handle, connection, source, sink, format);
404 mrp_list_foreach(&ctx->domains, kp, kn) {
406 d = mrp_list_entry(kp, typeof(*d), hook);
408 if (strcmp(iface, d->dbus_interface) == 0 &&
409 strcmp(path, d->dbus_path) == 0) {
410 connection_domain = d;
415 mrp_list_foreach(&ctx->domains, kp, kn) {
417 d = mrp_list_entry(kp, typeof(*d), hook);
418 mrp_list_foreach(&d->sinks, sp, sn) {
420 s = mrp_list_entry(sp, typeof(*s), hook);
426 mrp_list_foreach(&d->sources, sp, sn) {
428 s = mrp_list_entry(sp, typeof(*s), hook);
429 if (s->id == source) {
430 source_name = s->name;
436 printf("sink: %s, source: %s\n",
437 sink_name ? sink_name : "(NULL)",
438 source_name ? source_name : "(NULL)");
440 if (!sink_name || !source_name) {
441 error_code = E_NOT_POSSIBLE;
444 /* create connection struct for book keeping */
446 connection_t *c = mrp_allocz(sizeof(connection_t));
449 c->sink = mrp_strdup(sink_name);
450 c->source = mrp_strdup(source_name);
451 mrp_list_init(&c->hook);
453 mrp_list_append(&connection_domain->connections, &c->hook);
455 if (connection_domain->connection_script) {
459 /* FIXME: sanity check of the string */
461 ret = snprintf(buf, 256, "%s %s %s %i %i %i %i %u",
462 connection_domain->connection_script,
463 source_name, sink_name,
464 domain_source->volume, domain_source->main_volume,
465 domain_sink->volume, domain_sink->main_volume,
468 if (ret > 0 && ret != 256) {
469 printf("calling: '%s'\n", buf);
475 /* send back the ack after processing */
477 ack = mrp_dbus_msg_method_call(dbus, AUDIOMGR_DBUS_NAME,
478 AUDIOMGR_DBUS_ROUTE_PATH, AUDIOMGR_DBUS_INTERFACE,
479 AUDIOMGR_CONNECT_ACK);
481 mrp_dbus_msg_append_basic(ack, MRP_DBUS_TYPE_UINT16, &handle);
482 mrp_dbus_msg_append_basic(ack, MRP_DBUS_TYPE_UINT16, &connection);
483 mrp_dbus_msg_append_basic(ack, MRP_DBUS_TYPE_UINT16, &error_code);
485 mrp_dbus_send_msg(dbus, ack);
487 else if (strcmp(member, AUDIOMGR_DISCONNECT) == 0) {
493 mrp_list_hook_t *sp, *sn, *kp, *kn;
495 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_UINT16, &handle);
496 mrp_dbus_msg_read_basic(msg, MRP_DBUS_TYPE_UINT16, &connection);
500 mrp_dbus_reply(dbus, msg, MRP_DBUS_TYPE_INT16, &error_code,
501 MRP_DBUS_TYPE_INVALID);
503 /* TODO: process command here */
505 mrp_list_foreach(&ctx->domains, sp, sn) {
507 d = mrp_list_entry(sp, typeof(*d), hook);
508 mrp_list_foreach(&d->connections, kp, kn) {
509 connection_t *c = mrp_list_entry(kp, typeof(*c), hook);
510 if (c->id == connection) {
511 if (d->disconnection_script) {
515 /* FIXME: sanity check of the string */
517 ret = snprintf(buf, 256, "%s %s %s %u",
518 d->disconnection_script,
519 c->source, c->sink, c->id);
521 if (ret > 0 && ret != 256) {
522 printf("calling: '%s'\n", buf);
527 destroy_connection(c);
532 /* send back the ack after processing */
534 ack = mrp_dbus_msg_method_call(dbus, AUDIOMGR_DBUS_NAME,
535 AUDIOMGR_DBUS_ROUTE_PATH, AUDIOMGR_DBUS_INTERFACE,
536 AUDIOMGR_DISCONNECT_ACK);
538 mrp_dbus_msg_append_basic(ack, MRP_DBUS_TYPE_UINT16, &handle);
539 mrp_dbus_msg_append_basic(ack, MRP_DBUS_TYPE_UINT16, &connection);
540 mrp_dbus_msg_append_basic(ack, MRP_DBUS_TYPE_UINT16, &error_code);
542 mrp_dbus_send_msg(dbus, ack);
548 void register_gateway_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *reply,
551 gateway_t *gw = user_data;
553 if (mrp_dbus_msg_is_error(reply)) {
554 printf("ERROR register gateway cb\n");
558 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &gw->id);
559 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &gw->state);
561 printf("register gateway cb: id %u, state %u\n",
565 static bool register_gateway(gateway_t *gw, uint16_t id, char *name,
566 uint16_t sink_id, uint16_t source_id, uint16_t domain_sink_id,
567 uint16_t domain_source_id, uint16_t control_domain_id)
570 uint16_t error = E_OK;
572 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(gw->d->ctx->dbus,
573 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
574 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_REGISTER_GATEWAY);
576 /* Source domain has to be the domain from which the stream is coming:
577 * the routing algorithm builds a tree coming from source domain to all
580 printf("register gateway: %u, %s, %u, %u, %u, %u, %u\n",
581 id, name, sink_id, source_id, domain_sink_id, domain_source_id,
584 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
587 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &id);
588 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, name);
589 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &sink_id);
590 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &source_id);
591 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &domain_sink_id);
592 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &domain_source_id);
593 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &gw->d->domain_id);
595 /* source connection formats ai */
597 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "i");
601 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &one);
604 mrp_dbus_msg_close_container(msg);
606 /* sink connection formats ai */
608 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "i");
612 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &one);
615 mrp_dbus_msg_close_container(msg);
617 /* conversion matrix ab*/
619 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "b");
621 for (i = 1; i < 2; i++) {
623 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_BOOLEAN, &b);
626 mrp_dbus_msg_close_container(msg);
628 mrp_dbus_msg_close_container(msg);
630 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &id);
631 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &error);
633 mrp_dbus_send(gw->d->ctx->dbus, AUDIOMGR_DBUS_NAME,
634 AUDIOMGR_DBUS_ROUTE_PATH,
635 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_REGISTER_GATEWAY, -1,
636 register_gateway_cb, gw, msg);
638 mrp_dbus_msg_unref(msg);
640 gw->d->ctx->pending_dbus_calls++;
645 static bool unregister_gateway(ctx_t *ctx, uint16_t id)
647 uint16_t error = E_OK;
649 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(ctx->dbus,
650 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
651 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_DEREGISTER_GATEWAY);
653 printf("unregistering gateway %u\n", id);
655 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &id);
656 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &error);
658 mrp_dbus_send_msg(ctx->dbus, msg);
660 mrp_dbus_msg_unref(msg);
665 static bool unregister_sink(ctx_t *ctx, int16_t id)
667 uint16_t error = E_OK;
669 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(ctx->dbus,
670 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
671 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_DEREGISTER_SINK);
673 printf("unregistering sink %i\n", id);
675 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &id);
676 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &error);
678 mrp_dbus_send_msg(ctx->dbus, msg);
680 mrp_dbus_msg_unref(msg);
685 static bool unregister_source(ctx_t *ctx, int16_t id)
687 uint16_t error = E_OK;
689 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(ctx->dbus,
690 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
691 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_DEREGISTER_SOURCE);
693 printf("unregistering source %i\n", id);
695 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &id);
696 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &error);
698 mrp_dbus_send_msg(ctx->dbus, msg);
700 mrp_dbus_msg_unref(msg);
705 static bool register_gateways(ctx_t *ctx)
707 mrp_list_hook_t *sp, *sn, *kp, *kn;
709 mrp_list_foreach(&ctx->domains, kp, kn) {
711 d = mrp_list_entry(kp, typeof(*d), hook);
713 mrp_list_foreach(&d->gateways, sp, sn) {
715 gw = mrp_list_entry(sp, typeof(*gw), hook);
717 register_gateway(gw, 0, gw->name, gw->sink_id, gw->source_id,
718 gw->domain_sink_id, gw->domain_source_id, gw->d->domain_id);
725 static void peek_sink_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *reply,
728 gateway_t *gw = user_data;
730 if (mrp_dbus_msg_is_error(reply)) {
731 printf("ERROR peek_sink cb\n");
735 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &gw->sink_id);
737 printf("peek_sink cb got id %d\n", gw->sink_id);
739 gw->d->ctx->pending_dbus_calls--;
741 if (gw->d->ctx->pending_dbus_calls > 0)
744 /* start creating gateways now when the sinks and sources have been
747 register_gateways(gw->d->ctx);
750 static void peek_source_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *reply,
753 gateway_t *gw = user_data;
755 if (mrp_dbus_msg_is_error(reply)) {
756 printf("ERROR peek_sink cb\n");
760 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &gw->source_id);
762 gw->d->ctx->pending_dbus_calls--;
764 if (gw->d->ctx->pending_dbus_calls > 0)
767 /* start creating gateways now when the sinks and sources have been
770 register_gateways(gw->d->ctx);
773 static void peek_sink_domain_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *reply,
776 gateway_t *gw = user_data;
778 if (mrp_dbus_msg_is_error(reply)) {
779 printf("ERROR peek_sink cb\n");
783 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &gw->domain_sink_id);
785 gw->d->ctx->pending_dbus_calls--;
787 if (gw->d->ctx->pending_dbus_calls > 0)
790 /* start creating gateways now when the sinks and sources have been
793 register_gateways(gw->d->ctx);
796 static void peek_source_domain_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *reply,
799 gateway_t *gw = user_data;
801 if (mrp_dbus_msg_is_error(reply)) {
802 printf("ERROR peek_sink cb\n");
806 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &gw->domain_source_id);
808 gw->d->ctx->pending_dbus_calls--;
810 if (gw->d->ctx->pending_dbus_calls > 0)
813 /* start creating gateways now when the sinks and sources have been
816 register_gateways(gw->d->ctx);
819 static bool peek_gw_sink(gateway_t *gw)
821 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(gw->d->ctx->dbus,
822 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
823 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_PEEK_SINK);
825 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, gw->sink_name);
827 mrp_dbus_send(gw->d->ctx->dbus, AUDIOMGR_DBUS_NAME,
828 AUDIOMGR_DBUS_ROUTE_PATH,
829 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_PEEK_SINK, -1,
830 peek_sink_cb, gw, msg);
832 mrp_dbus_msg_unref(msg);
834 gw->d->ctx->pending_dbus_calls++;
839 static bool peek_gw_source(gateway_t *gw)
841 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(gw->d->ctx->dbus,
842 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
843 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_PEEK_SOURCE);
845 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, gw->source_name);
847 mrp_dbus_send(gw->d->ctx->dbus, AUDIOMGR_DBUS_NAME,
848 AUDIOMGR_DBUS_ROUTE_PATH,
849 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_PEEK_SOURCE, -1,
850 peek_source_cb, gw, msg);
852 mrp_dbus_msg_unref(msg);
854 gw->d->ctx->pending_dbus_calls++;
859 static bool peek_gw_source_domain(gateway_t *gw)
861 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(gw->d->ctx->dbus,
862 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
863 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_PEEK_DOMAIN);
865 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING,
866 gw->source_domain_name);
868 mrp_dbus_send(gw->d->ctx->dbus, AUDIOMGR_DBUS_NAME,
869 AUDIOMGR_DBUS_ROUTE_PATH,
870 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_PEEK_DOMAIN, -1,
871 peek_source_domain_cb, gw, msg);
873 mrp_dbus_msg_unref(msg);
875 gw->d->ctx->pending_dbus_calls++;
880 static bool peek_gw_sink_domain(gateway_t *gw)
882 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(gw->d->ctx->dbus,
883 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
884 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_PEEK_DOMAIN);
886 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, gw->sink_domain_name);
888 mrp_dbus_send(gw->d->ctx->dbus, AUDIOMGR_DBUS_NAME,
889 AUDIOMGR_DBUS_ROUTE_PATH,
890 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_PEEK_DOMAIN, -1,
891 peek_sink_domain_cb, gw, msg);
893 mrp_dbus_msg_unref(msg);
895 gw->d->ctx->pending_dbus_calls++;
900 static bool find_id_mapping(gateway_t *gw)
902 mrp_list_hook_t *kp, *kn, *sp, *sn;
903 domain_t *domain = gw->d;
905 domain_t *sink_domain = NULL;
906 domain_t *source_domain = NULL;
908 /* need to go through both domains: sink and source */
910 mrp_list_foreach(&gw->d->ctx->domains, sp, sn) {
911 domain_t *d = mrp_list_entry(sp, typeof(*d), hook);
912 if (strcmp(gw->sink_domain_name, d->name) == 0) {
915 if (strcmp(gw->source_domain_name, d->name) == 0) {
921 printf("peeking sink\n");
922 peek_gw_sink_domain(gw);
926 mrp_list_foreach(&sink_domain->sinks, sp, sn) {
927 sink_t *s = mrp_list_entry(sp, typeof(*s), hook);
928 if (strcmp(s->name, gw->sink_name) == 0) {
929 gw->domain_sink_id = s->d->domain_id;
931 printf("found GW sink (%s / %u), domain (%s / %u)\n",
932 s->name, s->id, s->d->name, s->d->domain_id);
939 if (!found && sink_domain) {
940 printf("ERROR finding sink %s for gateway\n", gw->sink_name);
946 if (!source_domain) {
947 printf("peeking source\n");
948 peek_gw_source_domain(gw);
952 mrp_list_foreach(&source_domain->sources, sp, sn) {
953 source_t *s = mrp_list_entry(sp, typeof(*s), hook);
955 if (strcmp(s->name, gw->source_name) == 0) {
956 gw->domain_source_id = s->d->domain_id;
957 gw->source_id = s->id;
958 printf("found GW source (%s / %u), domain (%s / %u)\n",
959 s->name, s->id, s->d->name, s->d->domain_id);
967 printf("ERROR finding source for gateway %u\n", gw->id);
978 static void find_gateway_ids(ctx_t *ctx)
980 mrp_list_hook_t *sp, *sn, *kp, *kn;
982 mrp_list_foreach(&ctx->domains, kp, kn) {
984 d = mrp_list_entry(kp, typeof(*d), hook);
986 mrp_list_foreach(&d->gateways, sp, sn) {
988 gw = mrp_list_entry(sp, typeof(*gw), hook);
995 static void register_source_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *reply,
998 source_t *s = user_data;
999 mrp_list_hook_t *sp, *sn;
1001 if (mrp_dbus_msg_is_error(reply)) {
1002 printf("ERROR register source cb\n");
1006 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &s->id);
1007 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &s->state);
1009 printf("register source cb: id %u, state %u\n",
1012 s->d->ctx->pending_dbus_calls--;
1014 if (s->d->ctx->pending_dbus_calls > 0)
1017 /* start creating gateways now when the sinks and sources have been
1020 find_gateway_ids(s->d->ctx);
1022 if (s->d->ctx->pending_dbus_calls > 0)
1025 /* no extra queries needed to me made */
1027 register_gateways(s->d->ctx);
1030 void register_sink_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *reply,
1033 sink_t *s = user_data;
1034 mrp_list_hook_t *sp, *sn;
1036 if (mrp_dbus_msg_is_error(reply)) {
1037 printf("ERROR register sink cb\n");
1041 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &s->id);
1042 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &s->state);
1044 printf("register sink cb: id %u, state %u\n",
1047 s->d->ctx->pending_dbus_calls--;
1049 if (s->d->ctx->pending_dbus_calls > 0)
1052 /* start creating gateways now when the sinks and sources have been
1055 find_gateway_ids(s->d->ctx);
1057 if (s->d->ctx->pending_dbus_calls > 0)
1060 /* no extra queries needed to me made */
1062 register_gateways(s->d->ctx);
1065 static bool register_sink(sink_t *s, uint16_t id, char *name, uint16_t domain_id,
1066 int32_t klass, int16_t volume, bool visible, int32_t avail_status,
1067 int32_t avail_reason, int16_t mute, int16_t mainvolume)
1070 uint32_t visible_u = !!visible;
1074 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(s->d->ctx->dbus,
1075 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
1076 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_REGISTER_SINK);
1078 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1082 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &id);
1083 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, name);
1084 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &domain_id);
1085 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &klass);
1086 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &volume);
1087 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_BOOLEAN, &visible_u);
1089 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1091 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &avail_status);
1092 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &avail_reason);
1094 mrp_dbus_msg_close_container(msg);
1096 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &mute);
1097 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &mainvolume);
1099 /* sound properties a(in) */
1101 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "(in)");
1103 for (i = 1; i < 3; i++) {
1104 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1106 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &i);
1107 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &zero);
1109 mrp_dbus_msg_close_container(msg);
1112 mrp_dbus_msg_close_container(msg);
1114 /* connection formats ai */
1116 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "i");
1118 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &one);
1121 mrp_dbus_msg_close_container(msg);
1123 /* main sound properties a(in) */
1125 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "(in)");
1127 for (i = 1; i < 3; i++) {
1128 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1130 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &i);
1131 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &zero);
1133 mrp_dbus_msg_close_container(msg);
1136 mrp_dbus_msg_close_container(msg);
1138 /* main notification a(iin) */
1140 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "(iin)");
1142 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1144 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &zero);
1145 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &zero);
1146 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &zero);
1148 mrp_dbus_msg_close_container(msg);
1150 mrp_dbus_msg_close_container(msg);
1152 /* notification a(iin) */
1154 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "(iin)");
1156 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1158 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &zero);
1159 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &zero);
1160 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &zero);
1162 mrp_dbus_msg_close_container(msg);
1164 mrp_dbus_msg_close_container(msg);
1166 /* close the main container */
1167 mrp_dbus_msg_close_container(msg);
1169 mrp_dbus_send(s->d->ctx->dbus, AUDIOMGR_DBUS_NAME,
1170 AUDIOMGR_DBUS_ROUTE_PATH,
1171 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_REGISTER_SINK, -1,
1172 register_sink_cb, s, msg);
1174 mrp_dbus_msg_unref(msg);
1176 s->d->ctx->pending_dbus_calls++;
1181 static bool register_source(source_t *s, uint16_t id, char *name,
1182 uint16_t domain_id, uint16_t klass, uint16_t state, int16_t volume,
1183 bool visible, int16_t avail_status, int16_t avail_reason,
1187 uint32_t visible_u = !!visible;
1191 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(s->d->ctx->dbus,
1192 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
1193 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_REGISTER_SOURCE);
1195 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1199 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &id);
1200 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &domain_id);
1201 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, name);
1202 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &klass);
1203 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &state);
1204 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &volume);
1205 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_BOOLEAN, &visible_u);
1207 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1209 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &avail_status);
1210 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &avail_reason);
1212 mrp_dbus_msg_close_container(msg);
1214 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &interrupt);
1216 /* sound properties a(in) */
1218 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "(in)");
1220 for (i = 1; i < 3; i++) {
1222 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1224 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &i);
1225 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &zero);
1227 mrp_dbus_msg_close_container(msg);
1230 mrp_dbus_msg_close_container(msg);
1232 /* connection formats ai */
1234 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "i");
1236 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &one);
1239 mrp_dbus_msg_close_container(msg);
1241 /* main sound properties a(in) */
1243 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "(in)");
1245 for (i = 1; i < 3; i++) {
1247 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1249 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &i);
1250 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &zero);
1252 mrp_dbus_msg_close_container(msg);
1255 mrp_dbus_msg_close_container(msg);
1257 /* main notification a(iin) */
1259 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "(iin)");
1261 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1263 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &zero);
1264 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &zero);
1265 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &zero);
1267 mrp_dbus_msg_close_container(msg);
1269 mrp_dbus_msg_close_container(msg);
1271 /* notification a(iin) */
1273 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_ARRAY, "(iin)");
1275 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1277 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &zero);
1278 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT32, &zero);
1279 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &zero);
1281 mrp_dbus_msg_close_container(msg);
1283 mrp_dbus_msg_close_container(msg);
1285 /* close the main container */
1286 mrp_dbus_msg_close_container(msg);
1288 mrp_dbus_send(s->d->ctx->dbus, AUDIOMGR_DBUS_NAME,
1289 AUDIOMGR_DBUS_ROUTE_PATH,
1290 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_REGISTER_SOURCE, -1,
1291 register_source_cb, s, msg);
1293 mrp_dbus_msg_unref(msg);
1295 s->d->ctx->pending_dbus_calls++;
1300 static bool unregister_domain(domain_t *d, uint16_t domain_id)
1302 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(d->ctx->dbus,
1303 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
1304 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_DEREGISTER_DOMAIN);
1306 printf("unregistering domain %u\n", domain_id);
1308 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &domain_id);
1310 mrp_dbus_send_msg(d->ctx->dbus, msg);
1312 mrp_dbus_msg_unref(msg);
1314 mrp_dbus_remove_method(d->ctx->dbus, d->dbus_path, d->dbus_interface,
1315 AUDIOMGR_CONNECT_ACK, method_cb, d->ctx);
1317 mrp_dbus_remove_method(d->ctx->dbus, d->dbus_path, d->dbus_interface,
1318 AUDIOMGR_DISCONNECT_ACK, method_cb, d->ctx);
1323 void register_domain_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *reply,
1326 domain_t *domain = user_data;
1327 ctx_t *ctx = domain->ctx;
1328 mrp_list_hook_t *kp, *kn, *sp, *sn;
1330 if (mrp_dbus_msg_is_error(reply)) {
1331 printf("ERROR registering domain cb\n");
1335 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &domain->domain_id);
1336 mrp_dbus_msg_read_basic(reply, DBUS_TYPE_UINT16, &domain->state);
1338 printf("register domain cb: domain %u, state %u\n",
1339 domain->domain_id, domain->state);
1341 ctx->pending_dbus_calls--;
1343 if (ctx->pending_dbus_calls > 0)
1344 return; /* still domains to register */
1346 /* register sinks and sources that belong to all domains */
1348 printf("All domains are now registered, register sinks and sources next\n");
1350 mrp_list_foreach(&ctx->domains, kp, kn) {
1352 d = mrp_list_entry(kp, typeof(*d), hook);
1354 mrp_list_foreach(&d->sinks, sp, sn) {
1356 s = mrp_list_entry(sp, typeof(*s), hook);
1358 register_sink(s, 0, s->name, d->domain_id, s->klass, s->volume,
1359 s->visible, s->availability_status, s->availability_reason,
1360 s->mute, s->main_volume);
1363 mrp_list_foreach(&d->sources, sp, sn) {
1365 s = mrp_list_entry(sp, typeof(*s), hook);
1367 register_source(s, 0, s->name, d->domain_id, s->klass, 1,
1368 s->volume, s->visible, s->availability_status,
1369 s->availability_reason, s->interrupt);
1375 static bool register_domain(domain_t *d, uint16_t domain_id, char *name,
1376 char *bus_name, char *node_name, bool early, int16_t state)
1378 mrp_dbus_msg_t *msg = mrp_dbus_msg_method_call(d->ctx->dbus,
1379 AUDIOMGR_DBUS_NAME, AUDIOMGR_DBUS_ROUTE_PATH,
1380 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_REGISTER_DOMAIN);
1382 uint32_t early_u = !!early;
1383 uint32_t complete_u = 1;
1384 uint32_t error = E_OK;
1386 /* register methods */
1388 if (!mrp_dbus_export_method(d->ctx->dbus,
1389 d->dbus_path, d->dbus_interface, AUDIOMGR_CONNECT,
1390 method_cb, d->ctx)) {
1391 printf("Failed to register " AUDIOMGR_CONNECT " method\n");
1395 if (!mrp_dbus_export_method(d->ctx->dbus,
1396 d->dbus_path, d->dbus_interface, AUDIOMGR_DISCONNECT,
1397 method_cb, d->ctx)) {
1398 printf("Failed to register " AUDIOMGR_DISCONNECT " method\n");
1402 mrp_dbus_msg_open_container(msg, MRP_DBUS_TYPE_STRUCT, NULL);
1406 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &domain_id);
1407 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, name);
1408 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, bus_name);
1409 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, node_name);
1410 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_BOOLEAN, &early_u);
1411 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_BOOLEAN, &complete_u);
1412 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_INT16, &state);
1414 mrp_dbus_msg_close_container(msg);
1416 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, d->ctx->dbus_address);
1417 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, d->dbus_path);
1418 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_STRING, d->dbus_interface);
1419 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &domain_id);
1420 mrp_dbus_msg_append_basic(msg, MRP_DBUS_TYPE_UINT16, &error);
1422 mrp_dbus_send(d->ctx->dbus, AUDIOMGR_DBUS_NAME,
1423 AUDIOMGR_DBUS_ROUTE_PATH,
1424 AUDIOMGR_DBUS_INTERFACE, AUDIOMGR_REGISTER_DOMAIN, -1,
1425 register_domain_cb, d, msg);
1427 mrp_dbus_msg_unref(msg);
1429 d->ctx->pending_dbus_calls++;
1434 char *get_string_value(ini_parser_keyvaluepair_t *pair)
1436 int len = strlen(pair->value);
1438 /* remove '"' characters */
1441 return strndup(pair->value+1, len-2);
1446 bool get_boolean_value(ini_parser_keyvaluepair_t *pair)
1448 if (strcmp(pair->value, "TRUE") == 0)
1454 int32_t get_number_value(ini_parser_keyvaluepair_t *pair)
1459 v = strtold(pair->value, &endptr);
1461 if (pair->value == endptr)
1467 bool parse_gateway(ctx_t *ctx, ini_parser_section_t *section)
1469 mrp_list_hook_t *kp, *kn, *sp, *sn;
1471 gateway_t *gw = mrp_allocz(sizeof(gateway_t));
1472 char *domain_name = NULL;
1478 mrp_list_init(&gw->hook);
1480 mrp_list_foreach(§ion->pairs, kp, kn) {
1482 ini_parser_keyvaluepair_t *pair;
1484 pair = mrp_list_entry(kp, typeof(*pair), hook);
1486 if (strcmp(pair->key, CONFIG_NAME) == 0) {
1487 gw->name = get_string_value(pair);
1489 else if (strcmp(pair->key, CONFIG_DOMAIN_NAME) == 0) {
1490 domain_name = get_string_value(pair);
1492 else if (strcmp(pair->key, CONFIG_SINK_DOMAIN) == 0) {
1493 gw->sink_domain_name = get_string_value(pair);
1495 else if (strcmp(pair->key, CONFIG_SOURCE_DOMAIN) == 0) {
1496 gw->source_domain_name = get_string_value(pair);
1498 else if (strcmp(pair->key, CONFIG_SINK) == 0) {
1499 gw->sink_name = get_string_value(pair);
1501 else if (strcmp(pair->key, CONFIG_SOURCE) == 0) {
1502 gw->source_name = get_string_value(pair);
1506 if (!domain_name || !gw->sink_name || !gw->source_name ||
1507 !gw->sink_domain_name || !gw->source_domain_name) {
1508 printf("ERROR: all mandatory strings not in place\n");
1512 mrp_list_foreach(&ctx->domains, sp, sn) {
1513 d = mrp_list_entry(sp, typeof(*d), hook);
1515 if (strcmp(d->name, domain_name) == 0) {
1517 mrp_list_append(&d->gateways, &gw->hook);
1518 printf("found GW domain (%s / %u)\n",
1519 d->name, d->domain_id);
1526 printf("ERROR: domain for gateway not found\n");
1530 printf("adding gateway %s to list\n", gw->name);
1531 mrp_list_append(&d->gateways, &gw->hook);
1533 mrp_free(domain_name);
1538 mrp_free(domain_name);
1543 bool parse_sink(ctx_t *ctx, ini_parser_section_t *section)
1545 mrp_list_hook_t *kp, *kn, *sp, *sn;
1547 sink_t *s = mrp_allocz(sizeof(sink_t));
1548 char *domain_name = NULL;
1553 mrp_list_init(&s->hook);
1555 mrp_list_foreach(§ion->pairs, kp, kn) {
1557 ini_parser_keyvaluepair_t *pair;
1559 pair = mrp_list_entry(kp, typeof(*pair), hook);
1561 if (strcmp(pair->key, CONFIG_NAME) == 0) {
1562 s->name = get_string_value(pair);
1564 else if (strcmp(pair->key, CONFIG_DOMAIN_NAME) == 0) {
1565 domain_name = get_string_value(pair);
1567 else if (strcmp(pair->key, CONFIG_CLASS) == 0) {
1568 s->klass = get_number_value(pair);
1570 else if (strcmp(pair->key, CONFIG_VOLUME) == 0) {
1571 s->volume = get_number_value(pair);
1573 else if (strcmp(pair->key, CONFIG_MAIN_VOLUME) == 0) {
1574 s->main_volume = get_number_value(pair);
1576 else if (strcmp(pair->key, CONFIG_VISIBLE) == 0) {
1577 s->visible = get_boolean_value(pair);
1579 else if (strcmp(pair->key, CONFIG_MUTE) == 0) {
1580 s->mute = get_number_value(pair);
1582 else if (strcmp(pair->key, CONFIG_AVAILABILITY_REASON) == 0) {
1583 s->availability_reason = get_number_value(pair);
1585 else if (strcmp(pair->key, CONFIG_AVAILABILITY_STATUS) == 0) {
1586 s->availability_status = get_number_value(pair);
1590 /* TODO: check that we have all the strings */
1592 if (!s->name || !domain_name)
1595 mrp_list_foreach(&ctx->domains, sp, sn) {
1596 domain_t *d = mrp_list_entry(sp, typeof(*d), hook);
1598 if (strcmp(d->name, domain_name) == 0) {
1600 mrp_list_append(&d->sinks, &s->hook);
1609 mrp_free(domain_name);
1614 mrp_free(domain_name);
1618 bool parse_source(ctx_t *ctx, ini_parser_section_t *section)
1620 mrp_list_hook_t *kp, *kn, *sp, *sn;
1622 source_t *s = mrp_allocz(sizeof(source_t));
1623 char *domain_name = NULL;
1628 mrp_list_init(&s->hook);
1630 mrp_list_foreach(§ion->pairs, kp, kn) {
1632 ini_parser_keyvaluepair_t *pair;
1634 pair = mrp_list_entry(kp, typeof(*pair), hook);
1636 if (strcmp(pair->key, CONFIG_NAME) == 0) {
1637 s->name = get_string_value(pair);
1639 else if (strcmp(pair->key, CONFIG_DOMAIN_NAME) == 0) {
1640 domain_name = get_string_value(pair);
1642 else if (strcmp(pair->key, CONFIG_CLASS) == 0) {
1643 s->klass = get_number_value(pair);
1645 else if (strcmp(pair->key, CONFIG_VOLUME) == 0) {
1646 s->volume = get_number_value(pair);
1648 else if (strcmp(pair->key, CONFIG_MAIN_VOLUME) == 0) {
1649 s->main_volume = get_number_value(pair);
1651 else if (strcmp(pair->key, CONFIG_VISIBLE) == 0) {
1652 s->visible = get_boolean_value(pair);
1654 else if (strcmp(pair->key, CONFIG_INTERRUPT) == 0) {
1655 s->interrupt = get_number_value(pair);
1657 else if (strcmp(pair->key, CONFIG_AVAILABILITY_REASON) == 0) {
1658 s->availability_reason = get_number_value(pair);
1660 else if (strcmp(pair->key, CONFIG_AVAILABILITY_STATUS) == 0) {
1661 s->availability_status = get_number_value(pair);
1665 /* TODO: check that we have all the strings */
1667 if (!s->name || !domain_name)
1670 mrp_list_foreach(&ctx->domains, sp, sn) {
1671 domain_t *d = mrp_list_entry(sp, typeof(*d), hook);
1673 if (strcmp(d->name, domain_name) == 0) {
1675 mrp_list_append(&d->sources, &s->hook);
1684 mrp_free(domain_name);
1689 mrp_free(domain_name);
1693 bool parse_domain(ctx_t *ctx, ini_parser_section_t *section)
1695 mrp_list_hook_t *kp, *kn;
1697 domain_t *d = mrp_allocz(sizeof(domain_t));
1702 mrp_list_init(&d->hook);
1703 mrp_list_init(&d->sinks);
1704 mrp_list_init(&d->sources);
1705 mrp_list_init(&d->gateways);
1706 mrp_list_init(&d->connections);
1708 mrp_list_foreach(§ion->pairs, kp, kn) {
1710 ini_parser_keyvaluepair_t *pair;
1712 pair = mrp_list_entry(kp, typeof(*pair), hook);
1714 if (strcmp(pair->key, CONFIG_NAME) == 0) {
1715 d->name = get_string_value(pair);
1717 else if (strcmp(pair->key, CONFIG_BUS_NAME) == 0) {
1718 d->bus_name = get_string_value(pair);
1720 else if (strcmp(pair->key, CONFIG_NODE_NAME) == 0) {
1721 d->node_name = get_string_value(pair);
1723 else if (strcmp(pair->key, CONFIG_EARLY) == 0) {
1724 d->early = get_boolean_value(pair);
1726 else if (strcmp(pair->key, CONFIG_DBUS_PATH) == 0) {
1727 d->dbus_path = get_string_value(pair);
1729 else if (strcmp(pair->key, CONFIG_DBUS_INTERFACE) == 0) {
1730 d->dbus_interface = get_string_value(pair);
1732 else if (strcmp(pair->key, CONFIG_CONNECTION_SCRIPT) == 0) {
1733 d->connection_script = get_string_value(pair);
1735 else if (strcmp(pair->key, CONFIG_DISCONNECTION_SCRIPT) == 0) {
1736 d->disconnection_script = get_string_value(pair);
1740 if (!d->name || !d->bus_name || !d->node_name || !d->dbus_path
1741 || !d->dbus_interface)
1744 /* add domain to the context domain list */
1748 mrp_list_append(&ctx->domains, &d->hook);
1753 printf("ERROR parsing domain section\n");
1758 bool parse_config(ctx_t *ctx, ini_parser_section_t *section)
1760 mrp_list_hook_t *kp, *kn;
1762 mrp_list_foreach(§ion->pairs, kp, kn) {
1764 ini_parser_keyvaluepair_t *pair;
1766 pair = mrp_list_entry(kp, typeof(*pair), hook);
1768 if (strcmp(pair->key, CONFIG_DBUS_BUS) == 0) {
1769 ctx->dbus_bus = get_string_value(pair);
1771 else if (strcmp(pair->key, CONFIG_DBUS_ADDRESS) == 0) {
1772 ctx->dbus_address = get_string_value(pair);
1776 if (!ctx->dbus_bus || !ctx->dbus_address)
1782 printf("ERROR parsing configuration section\n");
1786 bool init_data_structures(ctx_t *ctx, ini_parser_result_t *result)
1788 mrp_list_hook_t *sp, *sn;
1790 mrp_list_foreach(&result->sections, sp, sn) {
1792 ini_parser_section_t *section;
1794 section = mrp_list_entry(sp, typeof(*section), hook);
1796 if (strcmp(section->name, CONFIG_CONFIG) == 0) {
1797 if (!parse_config(ctx, section))
1800 else if (strcmp(section->name, CONFIG_DOMAIN) == 0) {
1801 if (!parse_domain(ctx, section))
1804 else if (strcmp(section->name, CONFIG_SINK) == 0) {
1805 if (!parse_sink(ctx, section))
1808 else if (strcmp(section->name, CONFIG_SOURCE) == 0) {
1809 if (!parse_source(ctx, section))
1812 else if (strcmp(section->name, CONFIG_GATEWAY) == 0) {
1813 if (!parse_gateway(ctx, section))
1817 printf("WARNING: unknown section '%s' in configuration file\n",
1828 void sig_cb(mrp_sighandler_t *sighandler, int sig, void *user_data)
1830 ctx_t *ctx = (ctx_t *) user_data;
1832 if (sig == SIGINT) {
1833 mrp_mainloop_quit(ctx->ml, 0);
1837 int main(int argc, char **argv)
1841 ini_parser_result_t result;
1842 mrp_list_hook_t *sp, *sn, *kp, *kn;
1844 char *bus = "session";
1845 char *filename = "config.ini";
1855 /* parse configuration file */
1857 init_result(&result);
1859 if (!mrp_parse_ini_file(filename, &result)) {
1860 printf("failed to parse configuration file '%s'\n", filename);
1864 /* initialize the context */
1866 ctx.ml = mrp_mainloop_create();
1868 ctx.sighandler = mrp_add_sighandler(ctx.ml, SIGINT, sig_cb, &ctx);
1870 mrp_list_init(&ctx.domains);
1872 ctx.pending_dbus_calls = 0;
1874 if (!init_data_structures(&ctx, &result)) {
1875 printf("failed to get required information from configuration file\n");
1879 /* connect to D-Bus */
1881 ctx.dbus = mrp_dbus_connect(ctx.ml, bus, mrp_dbus_error_init(&err));
1884 printf("failed to connect to '%s' bus: %s\n", bus, err.message);
1888 if (!mrp_dbus_acquire_name(ctx.dbus, ctx.dbus_address, NULL)) {
1889 printf("Failed to acquire name %s on D-Bus\n", ctx.dbus_address);
1893 mrp_list_foreach(&ctx.domains, sp, sn) {
1894 domain_t *d = mrp_list_entry(sp, typeof(*d), hook);
1896 register_domain(d, 0, d->name, d->bus_name, d->node_name, d->early,
1900 mrp_mainloop_run(ctx.ml);
1902 mrp_list_foreach(&ctx.domains, sp, sn) {
1903 domain_t *d = mrp_list_entry(sp, typeof(*d), hook);
1905 mrp_list_foreach(&d->sinks, kp, kn) {
1906 sink_t *s = mrp_list_entry(kp, typeof(*s), hook);
1907 unregister_sink(d->ctx, s->id);
1910 mrp_list_foreach(&d->sources, kp, kn) {
1911 source_t *s = mrp_list_entry(kp, typeof(*s), hook);
1912 unregister_source(d->ctx, s->id);
1915 mrp_list_foreach(&d->gateways, kp, kn) {
1916 gateway_t *gw = mrp_list_entry(kp, typeof(*gw), hook);
1917 unregister_gateway(d->ctx, gw->id);
1920 unregister_domain(d, d->domain_id);
1923 mrp_list_foreach(&ctx.domains, sp, sn) {
1924 domain_t *d = mrp_list_entry(sp, typeof(*d), hook);
1926 /* TODO: free memory in the unregister callbacks? */
1930 mrp_dbus_release_name(ctx.dbus, ctx.dbus_address, NULL);
1931 mrp_del_sighandler(ctx.sighandler);
1932 mrp_mainloop_destroy(ctx.ml);
1934 printf("Exiting\n");