AC_MSG_NOTICE([D-Bus support is disabled.])
fi
+if test "$enable_dbus" = "yes"; then
+ AC_DEFINE([DBUS_ENABLED], 1, [Enable D-BUS support ?])
+fi
+
AM_CONDITIONAL(DBUS_ENABLED, [test "$enable_dbus" = "yes"])
AC_SUBST(DBUS_ENABLED)
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
+# Check if PulseAudio mainloop support was enabled.
+AC_ARG_ENABLE(pulse,
+ [ --enable-pulse enable PulseAudio mainloop support],
+ [enable_pulse=$enableval], [enable_pulse=auto])
+
+if test "$enable_pulse" != "no"; then
+ PKG_CHECK_MODULES(PULSE, libpulse >= 0.9.22,
+ [have_pulse=yes], [have_pulse=no])
+ if test "$have_pulse" = "no" -a "$enable_pulse" != "yes"; then
+ AC_MSG_ERROR([PulseAudio development libraries not found.])
+ else
+ enable_pulse="$have_pulse"
+ fi
+else
+ AC_MSG_NOTICE([PulseAudio mainloop support is disabled.])
+fi
+
+if test "$enable_pulse" = "yes"; then
+ AC_DEFINE([PULSE_ENABLED], 1, [Enable PulseAudio mainloop support ?])
+fi
+AM_CONDITIONAL(PULSE_ENABLED, [test "$enable_pulse" = "yes"])
+AC_SUBST(PULSE_ENABLED)
+AC_SUBST(PULSE_CFLAGS)
+AC_SUBST(PULSE_LIBS)
+
# Set up murphy CFLAGS and LIBS.
MURPHY_CFLAGS="$GLIB_CFLAGS $DBUS_CFLAGS"
MURPHY_LIBS="$GLIB_LIBS $DBUS_LIBS"
src/daemon/tests/Makefile
src/common/murphy-common.pc
src/common/murphy-dbus.pc
+ src/common/murphy-pulse.pc
src/core/murphy-core.pc
src/murphy-db/Makefile
src/murphy-db/mdb/Makefile
echo "----- configuration -----"
echo "Extra C warnings flags: $WARNING_CFLAGS"
echo "D-Bus support: $enable_dbus"
+echo "PulseAudio mainloop support: $enable_pulse"
echo "Plugins:"
echo " - linked-in:"
for plugin in ${INTERNAL_PLUGINS:-none}; do
$(includedir)/murphy
libmurphy_commonh_la_HEADERS = \
- common.h
+ common.h \
+ config.h
libmurphy_common_ladir = \
$(includedir)/murphy/common
endif
###################################
+# murphy pulse glue library
+#
+
+if PULSE_ENABLED
+lib_LTLIBRARIES += libmurphy-pulse.la
+EXTRA_DIST += common/murphy-pulse.pc
+pkgconfig_DATA += common/murphy-pulse.pc
+
+libmurphy_pulse_ladir = \
+ $(includedir)/murphy/common
+
+libmurphy_pulse_la_HEADERS = \
+ common/pulse-glue.h
+
+libmurphy_pulse_la_SOURCES = \
+ common/pulse-glue.c
+
+libmurphy_pulse_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(PULSE_CFLAGS)
+
+libmurphy_pulse_la_LDFLAGS = \
+ -Wl,-version-script=linker-script.pulse \
+ -version-info @MURPHY_VERSION_INFO@
+
+libmurphy_pulse_la_LIBADD =
+
+libmurphy_pulse_la_DEPENDENCIES = linker-script.pulse
+
+libpulseincludedir = $(includedir)/murphy/pulse
+libpulseinclude_HEADERS = $(libmurphy_pulse_la_HEADERS)
+
+# linker script generation
+linker-script.pulse: $(libmurphy_pulse_la_HEADERS)
+ $(QUIET_GEN)$(top_builddir)/build-aux/gen-linker-script -q -o $@ $^
+
+clean-linker-script::
+ -rm -f linker-script.pulse
+endif
+
+###################################
# murphy plugins
#
--- /dev/null
+
+#include <pulse/mainloop-api.h>
+#include <pulse/timeval.h>
+
+#include <murphy/common/mm.h>
+#include <murphy/common/mainloop.h>
+
+
+
+
+typedef struct {
+ mrp_mainloop_t *ml;
+ pa_mainloop_api *pa;
+} pulse_glue_t;
+
+
+typedef struct {
+ pa_io_event *pa_io;
+ void (*cb)(void *glue_data,
+ void *id, int fd, mrp_io_event_t events,
+ void *user_data);
+ void *user_data;
+ void *glue_data;
+} io_t;
+
+
+typedef struct {
+ pa_time_event *pa_t;
+ void (*cb)(void *glue_data, void *id, void *user_data);
+ void *user_data;
+ void *glue_data;
+} tmr_t;
+
+
+typedef struct {
+ pa_defer_event *pa_d;
+ void (*cb)(void *glue_data, void *id, void *user_data);
+ void *user_data;
+ void *glue_data;
+} dfr_t;
+
+
+static void *add_io(void *glue_data, int fd, mrp_io_event_t events,
+ void (*cb)(void *glue_data, void *id, int fd,
+ mrp_io_event_t events, void *user_data),
+ void *user_data);
+static void del_io(void *glue_data, void *id);
+
+static void *add_timer(void *glue_data, unsigned int msecs,
+ void (*cb)(void *glue_data, void *id, void *user_data),
+ void *user_data);
+static void del_timer(void *glue_data, void *id);
+static void mod_timer(void *glue_data, void *id, unsigned int msecs);
+
+static void *add_defer(void *glue_data,
+ void (*cb)(void *glue_data, void *id, void *user_data),
+ void *user_data);
+static void del_defer(void *glue_data, void *id);
+static void mod_defer(void *glue_data, void *id, int enabled);
+
+
+static void io_cb(pa_mainloop_api *pa, pa_io_event *e, int fd,
+ pa_io_event_flags_t mask, void *user_data)
+{
+ io_t *io = (io_t *)user_data;
+ mrp_io_event_t events = MRP_IO_EVENT_NONE;
+
+ MRP_UNUSED(pa);
+ MRP_UNUSED(e);
+
+ if (mask & PA_IO_EVENT_INPUT) events |= MRP_IO_EVENT_IN;
+ if (mask & PA_IO_EVENT_OUTPUT) events |= MRP_IO_EVENT_OUT;
+ if (mask & PA_IO_EVENT_HANGUP) events |= MRP_IO_EVENT_HUP;
+ if (mask & PA_IO_EVENT_ERROR) events |= MRP_IO_EVENT_ERR;
+
+ io->cb(io->glue_data, io, fd, events, io->user_data);
+}
+
+
+static void *add_io(void *glue_data, int fd, mrp_io_event_t events,
+ void (*cb)(void *glue_data, void *id, int fd,
+ mrp_io_event_t events, void *user_data),
+ void *user_data)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)glue_data;
+ pa_mainloop_api *pa = glue->pa;
+ pa_io_event_flags_t mask = PA_IO_EVENT_NULL;
+ io_t *io;
+
+ io = mrp_allocz(sizeof(*io));
+
+ if (io != NULL) {
+ if (events & MRP_IO_EVENT_IN) mask |= PA_IO_EVENT_INPUT;
+ if (events & MRP_IO_EVENT_OUT) mask |= PA_IO_EVENT_OUTPUT;
+ if (events & MRP_IO_EVENT_HUP) mask |= PA_IO_EVENT_HANGUP;
+ if (events & MRP_IO_EVENT_ERR) mask |= PA_IO_EVENT_ERROR;
+
+ io->pa_io = pa->io_new(pa, fd, mask, io_cb, io);
+
+ if (io->pa_io != NULL) {
+ io->cb = cb;
+ io->user_data = user_data;
+ io->glue_data = glue_data;
+
+ return io;
+ }
+ else
+ mrp_free(io);
+ }
+
+ return NULL;
+}
+
+
+static void del_io(void *glue_data, void *id)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)glue_data;
+ pa_mainloop_api *pa = glue->pa;
+ io_t *io = (io_t *)id;
+
+ pa->io_free(io->pa_io);
+ mrp_free(io);
+}
+
+
+static void timer_cb(pa_mainloop_api *pa, pa_time_event *e,
+ const struct timeval *tv, void *user_data)
+{
+ tmr_t *t = (tmr_t *)user_data;
+
+ MRP_UNUSED(pa);
+ MRP_UNUSED(e);
+ MRP_UNUSED(tv);
+
+ t->cb(t->glue_data, t, t->user_data);
+}
+
+
+static void *add_timer(void *glue_data, unsigned int msecs,
+ void (*cb)(void *glue_data, void *id, void *user_data),
+ void *user_data)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)glue_data;
+ pa_mainloop_api *pa = glue->pa;
+ struct timeval tv;
+ tmr_t *t;
+
+ t = mrp_allocz(sizeof(*t));
+
+ if (t != NULL) {
+ pa_gettimeofday(&tv);
+
+ tv.tv_sec += msecs / 1000;
+ tv.tv_usec += 1000 * (msecs % 1000);
+
+ t->pa_t = pa->time_new(pa, &tv, timer_cb, t);
+
+ if (t->pa_t != NULL) {
+ t->cb = cb;
+ t->user_data = user_data;
+ t->glue_data = glue_data;
+
+ return t;
+ }
+ else
+ mrp_free(t);
+ }
+
+ return NULL;
+}
+
+
+static void del_timer(void *glue_data, void *id)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)glue_data;
+ pa_mainloop_api *pa = glue->pa;
+ tmr_t *t = (tmr_t *)id;
+
+ pa->time_free(t->pa_t);
+ mrp_free(t);
+}
+
+
+static void mod_timer(void *glue_data, void *id, unsigned int msecs)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)glue_data;
+ pa_mainloop_api *pa = glue->pa;
+ tmr_t *t = (tmr_t *)id;
+ struct timeval tv;
+
+ if (t != NULL) {
+ pa_gettimeofday(&tv);
+
+ tv.tv_sec += msecs / 1000;
+ tv.tv_usec += 1000 * (msecs % 1000);
+
+ pa->time_restart(t->pa_t, &tv);
+ }
+}
+
+
+void defer_cb(pa_mainloop_api *pa, pa_defer_event *e, void *user_data)
+{
+ dfr_t *d = (dfr_t *)user_data;
+
+ MRP_UNUSED(pa);
+ MRP_UNUSED(e);
+
+ d->cb(d->glue_data, d, d->user_data);
+}
+
+
+static void *add_defer(void *glue_data,
+ void (*cb)(void *glue_data, void *id, void *user_data),
+ void *user_data)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)glue_data;
+ pa_mainloop_api *pa = glue->pa;
+ dfr_t *d;
+
+ d = mrp_allocz(sizeof(*d));
+
+ if (d != NULL) {
+ d->pa_d = pa->defer_new(pa, defer_cb, d);
+
+ if (d->pa_d != NULL) {
+ d->cb = cb;
+ d->user_data = user_data;
+ d->glue_data = glue_data;
+
+ return d;
+ }
+ else
+ mrp_free(d);
+ }
+
+ return NULL;
+}
+
+
+static void del_defer(void *glue_data, void *id)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)glue_data;
+ pa_mainloop_api *pa = glue->pa;
+ dfr_t *d = (dfr_t *)id;
+
+ pa->defer_free(d->pa_d);
+ mrp_free(d);
+}
+
+
+static void mod_defer(void *glue_data, void *id, int enabled)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)glue_data;
+ pa_mainloop_api *pa = glue->pa;
+ dfr_t *d = (dfr_t *)id;
+
+ pa->defer_enable(d->pa_d, !!enabled);
+}
+
+
+static mrp_superloop_ops_t pa_ops = {
+ .add_io = add_io,
+ .del_io = del_io,
+ .add_timer = add_timer,
+ .del_timer = del_timer,
+ .mod_timer = mod_timer,
+ .add_defer = add_defer,
+ .del_defer = del_defer,
+ .mod_defer = mod_defer,
+};
+
+
+void *mrp_mainloop_register_with_pulse(mrp_mainloop_t *ml, pa_mainloop_api *pa)
+{
+ pulse_glue_t *glue;
+
+ glue = mrp_allocz(sizeof(*glue));
+
+ if (glue != NULL) {
+ glue->ml = ml;
+ glue->pa = pa;
+
+ if (mrp_set_superloop(ml, &pa_ops, glue))
+ return glue;
+ else
+ mrp_free(glue);
+ }
+
+ return NULL;
+}
+
+
+int mrp_mainloop_unregister_from_pulse(mrp_mainloop_t *ml, pa_mainloop_api *pa,
+ void *data)
+{
+ pulse_glue_t *glue = (pulse_glue_t *)data;
+
+ if (glue->ml == ml && glue->pa == pa) {
+ if (mrp_clear_superloop(ml, &pa_ops, data)) {
+ mrp_free(glue);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
--- /dev/null
+#ifndef __MURPHY_PULSE_H__
+#define __MURPHY_PULSE_H__
+
+/** Register the given murphy mainloop with the given pulse mainloop. */
+int mrp_mainloop_register_with_pulse(mrp_mainloop_t *ml, pa_mainloop_api *pa);
+
+/** Unrgister the given murphy mainloop from the given pulse mainloop. */
+int mrp_mainloop_unregister_from_pulse(mrp_mainloop_t *ml, pa_mainloop_api *pa);
+
+#endif /* __MURPHY_PULSE_H__ */
mainloop_test_SOURCES = mainloop-test.c
mainloop_test_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS)
mainloop_test_LDADD = ../../libmurphy-common.la $(GLIB_LIBS) $(DBUS_LIBS)
+if PULSE_ENABLED
+mainloop_test_CFLAGS += $(PULSE_CFLAGS)
+mainloop_test_LDADD += ../../libmurphy-pulse.la $(PULSE_LIBS)
+endif
# msg test
msg_test_SOURCES = msg-test.c
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include <stdint.h>
#include <string.h>
+#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
+#include <getopt.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <glib.h>
#include <dbus/dbus.h>
+#include <murphy/config.h>
#include <murphy/common/macros.h>
#include <murphy/common/mm.h>
#include <murphy/common/mainloop.h>
+#ifdef PULSE_ENABLED
+# include <pulse/mainloop.h>
+# include <murphy/common/pulse-glue.h>
+#endif
#define info(fmt, args...) do { \
fprintf(stdout, "I: "fmt"\n" , ## args); \
int ndbus_method;
int ndbus_signal;
+ int log_mask;
+ const char *log_target;
+
+#ifdef PULSE_ENABLED
+ pa_mainloop *pa_main;
+ pa_mainloop_api *pa;
+#endif
+
int nrunning;
int runtime;
} test_config_t;
if (cfg.nrunning <= 0) {
mrp_del_timer(timer);
+#ifdef PULSE_ENABLED
+ MRP_UNUSED(ml);
+
+ if (cfg.pa_main != NULL)
+ pa_mainloop_quit(cfg.pa_main, 0);
+ else
+#endif
mrp_mainloop_quit(ml, 0);
}
}
#include "glib-pump.c"
#include "dbus-pump.c"
-int main(int argc, char *argv[])
+
+
+static void config_set_defaults(test_config_t *cfg)
{
- mrp_mainloop_t *ml;
+ mrp_clear(cfg);
- mrp_clear(&cfg);
+ cfg->nio = 5;
+ cfg->ntimer = 10;
+ cfg->nsignal = 5;
+ cfg->ngio = 5;
+ cfg->ngtimer = 10;
- cfg.nio = 5;
- cfg.ntimer = 10;
- cfg.nsignal = 5;
- cfg.ngio = 5;
- cfg.ngtimer = 10;
+ cfg->ndbus_method = 10;
+ cfg->ndbus_signal = 10;
- cfg.ndbus_method = 10;
- cfg.ndbus_signal = 10;
+ cfg->log_mask = MRP_LOG_UPTO(MRP_LOG_DEBUG);
+ cfg->log_target = MRP_LOG_TO_STDERR;
- if (argc == 2)
- cfg.runtime = (int)strtoul(argv[1], NULL, 10);
+ cfg->runtime = DEFAULT_RUNTIME;
+}
+
+
+static void print_usage(const char *argv0, int exit_code, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (fmt && *fmt) {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ }
+
+ printf("usage: %s [options]\n\n"
+ "The possible options are:\n"
+ " -r, --runtime how many seconds to run tests\n"
+ " -i, --ios number of I/O watches\n"
+ " -t, --timers number of timers\n"
+ " -I, --glib-ios number of glib I/O watches\n"
+ " -T, --glib-timers number of glib timers\n"
+ " -S, --dbus-signals number of D-Bus signals\n"
+ " -M, --dbus-methods number of D-Bus methods\n"
+ " -o, --log-target=TARGET log target to use\n"
+ " TARGET is one of stderr,stdout,syslog, or a logfile path\n"
+ " -l, --log-level=LEVELS logging level to use\n"
+ " LEVELS is a comma separated list of info, error and warning\n"
+ " -v, --verbose increase logging verbosity\n"
+ " -d, --debug enable debug messages\n"
+#ifdef PULSE_ENABLED
+ " -p, --pulse use pulse mainloop\n"
+#endif
+ " -h, --help show help on usage\n",
+ argv0);
+
+ if (exit_code < 0)
+ return;
else
- cfg.runtime = DEFAULT_RUNTIME;
+ exit(exit_code);
+}
+
+
+int parse_cmdline(test_config_t *cfg, int argc, char **argv)
+{
+#ifdef PULSE_ENABLED
+# define PULSE_OPTION "p"
+#else
+# define PULSE_OPTION ""
+#endif
+# define OPTIONS "r:i:t:s:I:T:S:M:l:o:vdh"PULSE_OPTION
+ struct option options[] = {
+ { "runtime" , required_argument, NULL, 'r' },
+ { "ios" , required_argument, NULL, 'i' },
+ { "timers" , required_argument, NULL, 't' },
+ { "signals" , required_argument, NULL, 's' },
+ { "glib-ios" , required_argument, NULL, 'I' },
+ { "glib-timers" , required_argument, NULL, 'T' },
+ { "dbus-signals", required_argument, NULL, 'S' },
+ { "dbus-methods", required_argument, NULL, 'M' },
+#ifdef PULSE_ENABLED
+ { "pulse-main" , no_argument , NULL, 'p' },
+#endif
+ { "log-level" , required_argument, NULL, 'l' },
+ { "log-target" , required_argument, NULL, 'o' },
+ { "verbose" , optional_argument, NULL, 'v' },
+ { "debug" , no_argument , NULL, 'd' },
+ { "help" , no_argument , NULL, 'h' },
+ { NULL, 0, NULL, 0 }
+ };
+ char *end;
+ int opt, debug;
+
+ debug = FALSE;
+ config_set_defaults(cfg);
+
+ while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) {
+ switch (opt) {
+ case 'r':
+ cfg->runtime = (int)strtoul(optarg, &end, 10);
+ if (end && *end)
+ print_usage(argv[0], EINVAL,
+ "invalid runtime length '%s'.", optarg);
+ break;
+
+ case 'i':
+ cfg->nio = (int)strtoul(optarg, &end, 10);
+ if (end && *end)
+ print_usage(argv[0], EINVAL,
+ "invalid number of I/O watches '%s'.", optarg);
+ break;
+
+ case 't':
+ cfg->ntimer = (int)strtoul(optarg, &end, 10);
+ if (end && *end)
+ print_usage(argv[0], EINVAL,
+ "invalid number of timers '%s'.", optarg);
+ break;
+
+ case 's':
+ cfg->nsignal = (int)strtoul(optarg, &end, 10);
+ if (end && *end)
+ print_usage(argv[0], EINVAL,
+ "invalid number of signals '%s'.", optarg);
+ break;
+
+ case 'I':
+ cfg->ngio = (int)strtoul(optarg, &end, 10);
+ if (end && *end)
+ print_usage(argv[0], EINVAL,
+ "invalid number of glib I/O watches '%s'.", optarg);
+ break;
+
+ case 'T':
+ cfg->ngtimer = (int)strtoul(optarg, &end, 10);
+ if (end && *end)
+ print_usage(argv[0], EINVAL,
+ "invalid number of glib timers '%s'.", optarg);
+ break;
+
+ case 'S':
+ cfg->ndbus_signal = (int)strtoul(optarg, &end, 10);
+ if (end && *end)
+ print_usage(argv[0], EINVAL,
+ "invalid number of DBUS signals '%s'.", optarg);
+ break;
+
+ case 'M':
+ cfg->ndbus_method = (int)strtoul(optarg, &end, 10);
+ if (end && *end)
+ print_usage(argv[0], EINVAL,
+ "invalid number of DBUS methods '%s'.", optarg);
+ break;
+
+#ifdef PULSE_ENABLED
+ case 'p':
+ cfg->pa_main = pa_mainloop_new();
+ if (cfg->pa_main == NULL) {
+ mrp_log_error("Failed to create PulseAudio mainloop.");
+ exit(1);
+ }
+ cfg->pa = pa_mainloop_get_api(cfg->pa_main);
+ break;
+#endif
- mrp_log_set_mask(MRP_LOG_UPTO(MRP_LOG_INFO));
- mrp_log_set_target(MRP_LOG_TO_STDOUT);
+ case 'v':
+ cfg->log_mask <<= 1;
+ cfg->log_mask |= 1;
+ break;
+ case 'l':
+ cfg->log_mask = mrp_log_parse_levels(optarg);
+ if (cfg->log_mask < 0)
+ print_usage(argv[0], EINVAL, "invalid log level '%s'", optarg);
+ break;
+
+ case 'o':
+ cfg->log_target = mrp_log_parse_target(optarg);
+ if (!cfg->log_target)
+ print_usage(argv[0], EINVAL, "invalid log target '%s'", optarg);
+ break;
+
+ case 'd':
+ debug = TRUE;
+ break;
+
+ case 'h':
+ print_usage(argv[0], -1, "");
+ exit(0);
+ break;
+
+ default:
+ print_usage(argv[0], EINVAL, "invalid option '%c'", opt);
+ }
+ }
+
+ if (debug)
+ cfg->log_mask |= MRP_LOG_MASK_DEBUG;
+
+ return TRUE;
+}
+
+
+int main(int argc, char *argv[])
+{
+ mrp_mainloop_t *ml;
+ int retval;
+
+ mrp_clear(&cfg);
+ parse_cmdline(&cfg, argc, argv);
+
+ mrp_log_set_mask(cfg.log_mask);
+ mrp_log_set_target(cfg.log_target);
if ((ml = mrp_mainloop_create()) == NULL)
fatal("failed to create main loop.");
if (mrp_add_timer(ml, 1000, check_quit, NULL) == NULL)
fatal("failed to create quit-check timer");
- mrp_mainloop_run(ml);
+#ifdef PULSE_ENABLED
+ if (cfg.pa != NULL) {
+ mrp_log_info("Running with PulseAudio mainloop.");
+
+ if (!mrp_mainloop_register_with_pulse(ml, cfg.pa)) {
+ mrp_log_error("Failed to register with PulseAudio mainloop.");
+ exit(1);
+ }
+
+ pa_mainloop_run(cfg.pa_main, &retval);
+
+ mrp_log_info("PulseAudio mainloop exited with status %d.", retval);
+ mrp_mainloop_unregister_from_pulse(ml, cfg.pa);
+
+ pa_mainloop_free(cfg.pa_main);
+ }
+ else
+#endif
+ retval = mrp_mainloop_run(ml);
+
check_io();
check_timers();
check_signals();