summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2004-09-13 23:28:30 +0000
committerLennart Poettering <lennart@poettering.net>2004-09-13 23:28:30 +0000
commit829656c5fcd7169e4c2f86f4ad5098ea9aaa5643 (patch)
treeedbca9829ad4b7dfa67f6d7515b3c3c66cc58338
parentfbefe67d52eb89a429505c653d1ea4ce73d4f4e7 (diff)
new configuration subsystem
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@198 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r--Makefile.am12
-rw-r--r--configure.ac5
-rw-r--r--doc/todo3
-rw-r--r--polyp/Makefile.am27
-rw-r--r--polyp/cmdline.c260
-rw-r--r--polyp/cmdline.h21
-rw-r--r--polyp/conf.c285
-rw-r--r--polyp/conf.h51
-rw-r--r--polyp/config61
-rw-r--r--polyp/core.c9
-rw-r--r--polyp/core.h3
-rwxr-xr-xpolyp/default.pa (renamed from polyp/polypaudio.pa)0
-rw-r--r--polyp/dumpmodules.c (renamed from polyp/pamodinfo.c)45
-rw-r--r--polyp/dumpmodules.h29
-rw-r--r--polyp/main.c85
-rw-r--r--polyp/modargs.c9
-rw-r--r--polyp/module.c4
-rw-r--r--polyp/pacat.c5
-rw-r--r--polyp/polyplib-def.h11
-rw-r--r--polyp/polyplib-stream.c10
-rw-r--r--polyp/socket-util.c24
-rw-r--r--polyp/util.c26
-rw-r--r--polyp/util.h3
23 files changed, 756 insertions, 232 deletions
diff --git a/Makefile.am b/Makefile.am
index c8592f86..b15fbac6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,7 +24,17 @@ MAINTAINERCLEANFILES=README
noinst_DATA = README
pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc
+pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc
+
+if HAVE_GLIB20
+pkgconfig_DATA += \
+ polyplib-glib-mainloop.pc
+endif
+
+if HAVE_GLIB12
+pkgconfig_DATA += \
+ polyplib-glib12-mainloop.pc
+endif
README:
rm -f README
diff --git a/configure.ac b/configure.ac
index 62dc37d4..07b2b96c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,10 +40,12 @@ AC_SUBST(INCLTDL)
AC_SUBST(LIBLTDL)
AC_LIBTOOL_DLOPEN
AC_PROG_LIBTOOL
+AC_PROG_LEX
+AC_PROG_YACC
# Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h])
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h syslog.h])
ACX_PTHREAD
AC_PATH_XTRA
@@ -70,6 +72,7 @@ AC_FUNC_MEMCMP
AC_FUNC_MMAP
AC_FUNC_REALLOC
AC_FUNC_SETPGRP
+AC_FUNC_VPRINTF
AC_TYPE_SIGNAL
AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp])
AC_FUNC_STAT
diff --git a/doc/todo b/doc/todo
index 61cee844..135a336d 100644
--- a/doc/todo
+++ b/doc/todo
@@ -11,15 +11,14 @@
rename streams/contexts
- more complete pactl
- add sample directory
-- config file for command line arguments
- option to use default fragment size on alsa drivers
- lazy sample cache
- per-channel volume
- merge pa_context_connect_*
- input latency
- fix tcp/native
-- suid
- add volume to create_stream command in native protocol
+- udp based protocol
** later ***
- xmlrpc/http
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 99c89491..e9e1c295 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -24,23 +24,24 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@
AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS)
AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\"
-AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\"
+AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\"
+AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/config\"
AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"
AM_LDADD=$(PTHREAD_LIBS) -lm
AM_LIBADD=$(PTHREAD_LIBS) -lm
-EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in
-bin_PROGRAMS = polypaudio pacat pactl pamodinfo
+EXTRA_DIST = default.pa config depmod.py esdcompat.sh.in
+bin_PROGRAMS = polypaudio pacat pactl
bin_SCRIPTS = esdcompat.sh
noinst_PROGRAMS = \
mainloop-test \
pacat-simple \
parec-simple \
cpulimit-test \
- cpulimit-test2
+ cpulimit-test2
-polypconf_DATA=polypaudio.pa
+polypconf_DATA=default.pa config
BUILT_SOURCES=polyplib-version.h
@@ -153,19 +154,15 @@ polypaudio_SOURCES = idxset.c idxset.h \
cpulimit.c cpulimit.h \
log.c log.h \
gcc-printf.h \
- modinfo.c modinfo.h
+ modinfo.c modinfo.h \
+ conf.c conf.h \
+ dumpmodules.c dumpmodules.h
polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
polypaudio_INCLUDES = $(INCLTDL)
-polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS)
+polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(LEXLIB)
polypaudio_LDFLAGS=-export-dynamic
-pamodinfo_SOURCES = log.c log.h pamodinfo.c pamodinfo.h modinfo.c modinfo.h util.c util.h xmalloc.c xmalloc.h
-pamodinfo_CFLAGS = $(AM_CFLAGS)
-pamodinfo_INCLUDES = $(INCLTDL)
-pamodinfo_LDADD = $(AM_LDADD) $(LIBLTDL)
-pamodinfo_LDFLAGS=-export-dynamic
-
libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h
libprotocol_simple_la_LDFLAGS = -avoid-version
libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la
@@ -535,3 +532,7 @@ esdcompat.sh: esdcompat.sh.in Makefile
sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \
-e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \
-e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@
+
+install-exec-hook:
+ chown root:root $(DESTDIR)$(bindir)/polypaudio
+ chmod u+s $(DESTDIR)$(bindir)/polypaudio
diff --git a/polyp/cmdline.c b/polyp/cmdline.c
index b4d58f1f..4e7cde48 100644
--- a/polyp/cmdline.c
+++ b/polyp/cmdline.c
@@ -35,29 +35,48 @@
#include "strbuf.h"
#include "xmalloc.h"
-#define ENV_CONFIG_FILE "POLYP_CONFIG"
+enum {
+ ARG_HELP = 256,
+ ARG_VERSION,
+ ARG_DUMP_CONF,
+ ARG_DUMP_MODULES,
+ ARG_DAEMONIZE,
+ ARG_FAIL,
+ ARG_VERBOSE,
+ ARG_HIGH_PRIORITY,
+ ARG_STAY_ROOT,
+ ARG_DISALLOW_MODULE_LOADING,
+ ARG_EXIT_IDLE_TIME,
+ ARG_MODULE_IDLE_TIME,
+ ARG_LOG_TARGET,
+ ARG_LOAD,
+ ARG_FILE,
+ ARG_DL_SEARCH_PATH,
+};
+
+static struct option long_options[] = {
+ {"help", 0, 0, ARG_HELP},
+ {"version", 0, 0, ARG_VERSION},
+ {"dump-conf", 0, 0, ARG_DUMP_CONF},
+ {"dump-modules", 0, 0, ARG_DUMP_MODULES},
+ {"daemonize", 2, 0, ARG_DAEMONIZE},
+ {"fail", 2, 0, ARG_FAIL},
+ {"verbose", 2, 0, ARG_VERBOSE},
+ {"high-priority", 2, 0, ARG_HIGH_PRIORITY},
+ {"stay-root", 2, 0, ARG_STAY_ROOT},
+ {"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING},
+ {"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME},
+ {"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME},
+ {"log-target", 1, 0, ARG_LOG_TARGET},
+ {"load", 1, 0, ARG_LOAD},
+ {"file", 1, 0, ARG_FILE},
+ {"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH},
+ {NULL, 0, 0, 0}
+};
-char* config_file(void) {
- char *p, *h;
-
- if ((p = getenv(ENV_CONFIG_FILE)))
- return pa_xstrdup(p);
-
- if ((h = getenv("HOME"))) {
- struct stat st;
- p = pa_sprintf_malloc("%s/.polypaudio", h);
- if (stat(p, &st) >= 0)
- return p;
-
- pa_xfree(p);
- }
-
- return pa_xstrdup(DEFAULT_CONFIG_FILE);
-}
void pa_cmdline_help(const char *argv0) {
const char *e;
- char *cfg = config_file();
if ((e = strrchr(argv0, '/')))
e++;
@@ -65,133 +84,170 @@ void pa_cmdline_help(const char *argv0) {
e = argv0;
printf("%s [options]\n"
- " -r Try to set high process priority (only available as root)\n"
- " -R Don't drop root if SETUID root\n"
- " -L MODULE Load the specified plugin module with the specified argument\n"
- " -F FILE Run the specified script\n"
- " -C Open a command line on the running TTY\n"
- " -n Don't load configuration file (%s)\n"
- " -D Daemonize after loading the modules\n"
- " -d Disallow module loading after startup\n"
- " -f Dont quit when the startup fails\n"
- " -v Verbose startup\n"
- " -X SECS Terminate the daemon after the last client quit and this time passed\n"
- " -h Show this help\n"
- " -l TARGET Specify the log target (syslog, stderr, auto)\n"
- " -p DIR Append a directory to the search path for dynamic modules\n"
- " -V Show version\n", e, cfg);
-
- pa_xfree(cfg);
+ " -h, --help Show this help\n"
+ " --version Show version\n"
+ " --dump-conf Dump default configuration\n"
+ " --dump-modules Dump list of available modules\n\n"
+
+ " -D, --daemonize[=BOOL] Daemonize after startup\n"
+ " --fail[=BOOL] Quit when startup fails\n"
+ " --verbose[=BOOL] Be slightly more verbose\n"
+ " --high-priority[=BOOL] Try to set high process priority (only available as root)\n"
+ " --stay-root[=BOOL] Don't drop root if SETUID root\n"
+ " --disallow-module-loading[=BOOL] Disallow module loading after startup\n"
+ " --exit-idle-time=SECS Terminate the daemon when idle and this time passed\n"
+ " --module-idle-time=SECS Unload autoloaded modules when idle and this time passed\n"
+ " --log-target={auto,syslog,stderr} Specify the log target\n"
+ " -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n\n"
+
+ " -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with the specified argument\n"
+ " -F, --file=FILENAME Run the specified script\n"
+ " -C Open a command line on the running TTY after startup\n\n"
+
+ " -n Don't load default script file\n", e);
}
-struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) {
- char c, *cfg;
- struct pa_cmdline *cmdline = NULL;
+int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d) {
struct pa_strbuf *buf = NULL;
- int no_default_config_file = 0;
- assert(argc && argv);
-
- cmdline = pa_xmalloc(sizeof(struct pa_cmdline));
- cmdline->daemonize =
- cmdline->help =
- cmdline->verbose =
- cmdline->high_priority =
- cmdline->stay_root =
- cmdline->version =
- cmdline->disallow_module_loading = 0;
- cmdline->fail = cmdline->auto_log_target = 1;
- cmdline->quit_after_last_client_time = -1;
- cmdline->log_target = -1;
- cmdline->dl_search_path = NULL;
+ int c;
+ assert(conf && argc && argv);
buf = pa_strbuf_new();
assert(buf);
+
+ if (conf->script_commands)
+ pa_strbuf_puts(buf, conf->script_commands);
- while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:l:p:")) != -1) {
+ while ((c = getopt_long(argc, argv, "L:F:ChDnp:", long_options, NULL)) != -1) {
switch (c) {
+ case ARG_HELP:
+ case 'h':
+ conf->help = 1;
+ break;
+
+ case ARG_VERSION:
+ conf->version = 1;
+ break;
+
+ case ARG_DUMP_CONF:
+ conf->dump_conf = 1;
+ break;
+
+ case ARG_DUMP_MODULES:
+ conf->dump_modules = 1;
+ break;
+
+ case ARG_LOAD:
case 'L':
pa_strbuf_printf(buf, "load %s\n", optarg);
break;
+
+ case ARG_FILE:
case 'F':
pa_strbuf_printf(buf, ".include %s\n", optarg);
break;
+
case 'C':
pa_strbuf_puts(buf, "load module-cli\n");
break;
+
+ case ARG_DAEMONIZE:
case 'D':
- cmdline->daemonize = 1;
+ if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ pa_log(__FILE__": --daemonize expects boolean argument\n");
+ goto fail;
+ }
break;
- case 'h':
- cmdline->help = 1;
+
+ case ARG_FAIL:
+ if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ pa_log(__FILE__": --fail expects boolean argument\n");
+ goto fail;
+ }
break;
- case 'f':
- cmdline->fail = 0;
+
+ case ARG_VERBOSE:
+ if ((conf->verbose = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ pa_log(__FILE__": --verbose expects boolean argument\n");
+ goto fail;
+ }
break;
- case 'v':
- cmdline->verbose = 1;
+
+ case ARG_HIGH_PRIORITY:
+ if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ pa_log(__FILE__": --high-priority expects boolean argument\n");
+ goto fail;
+ }
break;
- case 'r':
- cmdline->high_priority = 1;
+
+ case ARG_STAY_ROOT:
+ if ((conf->stay_root = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ pa_log(__FILE__": --stay-root expects boolean argument\n");
+ goto fail;
+ }
break;
- case 'R':
- cmdline->stay_root = 1;
+
+ case ARG_DISALLOW_MODULE_LOADING:
+ if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ pa_log(__FILE__": --disallow-module-loading expects boolean argument\n");
+ goto fail;
+ }
break;
- case 'V':
- cmdline->version = 1;
+
+ case 'p':
+ case ARG_DL_SEARCH_PATH:
+ pa_xfree(conf->dl_search_path);
+ conf->dl_search_path = *optarg ? pa_xstrdup(optarg) : NULL;
break;
+
case 'n':
- no_default_config_file = 1;
- break;
- case 'd':
- cmdline->disallow_module_loading = 1;
- break;
- case 'X':
- cmdline->quit_after_last_client_time = atoi(optarg);
+ pa_xfree(conf->default_script_file);
+ conf->default_script_file = NULL;
break;
- case 'p':
- if (cmdline->dl_search_path)
- pa_xfree(cmdline->dl_search_path);
- cmdline->dl_search_path = pa_xstrdup(optarg);
- break;
- case 'l':
+
+ case ARG_LOG_TARGET:
if (!strcmp(optarg, "syslog")) {
- cmdline->auto_log_target = 0;
- cmdline->log_target = PA_LOG_SYSLOG;
+ conf->auto_log_target = 0;
+ conf->log_target = PA_LOG_SYSLOG;
} else if (!strcmp(optarg, "stderr")) {
- cmdline->auto_log_target = 0;
- cmdline->log_target = PA_LOG_STDERR;
+ conf->auto_log_target = 0;
+ conf->log_target = PA_LOG_STDERR;
} else if (!strcmp(optarg, "auto"))
- cmdline->auto_log_target = 1;
+ conf->auto_log_target = 1;
else {
pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n");
goto fail;
}
break;
+
+ case ARG_EXIT_IDLE_TIME:
+ conf->exit_idle_time = atoi(optarg);
+ break;
+
+ case ARG_MODULE_IDLE_TIME:
+ conf->module_idle_time = atoi(optarg);
+ break;
+
default:
goto fail;
}
}
- if (!no_default_config_file) {
- cfg = config_file();
- pa_strbuf_printf(buf, ".include %s\n", cfg);
- pa_xfree(cfg);
+ pa_xfree(conf->script_commands);
+ conf->script_commands = pa_strbuf_tostring_free(buf);
+
+ if (!conf->script_commands) {
+ pa_xfree(conf->script_commands);
+ conf->script_commands = NULL;
}
- cmdline->cli_commands = pa_strbuf_tostring_free(buf);
- return cmdline;
+ *d = optind;
+
+ return 0;
fail:
- if (cmdline)
- pa_cmdline_free(cmdline);
if (buf)
pa_strbuf_free(buf);
- return NULL;
-}
-
-void pa_cmdline_free(struct pa_cmdline *cmd) {
- assert(cmd);
- pa_xfree(cmd->cli_commands);
- pa_xfree(cmd->dl_search_path);
- pa_xfree(cmd);
+
+ return -1;
}
diff --git a/polyp/cmdline.h b/polyp/cmdline.h
index 5dfe2e0d..e4bd8af6 100644
--- a/polyp/cmdline.h
+++ b/polyp/cmdline.h
@@ -22,26 +22,9 @@
USA.
***/
-#include "log.h"
+#include "conf.h"
-struct pa_cmdline {
- int daemonize,
- help,
- fail,
- verbose,
- high_priority,
- stay_root,
- version,
- disallow_module_loading,
- quit_after_last_client_time,
- auto_log_target;
- char *cli_commands;
- char *dl_search_path;
- enum pa_log_target log_target;
-};
-
-struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []);
-void pa_cmdline_free(struct pa_cmdline *cmd);
+int pa_cmdline_parse(struct pa_conf*c, int argc, char *const argv [], int *d);
void pa_cmdline_help(const char *argv0);
diff --git a/polyp/conf.c b/polyp/conf.c
new file mode 100644
index 00000000..4a11c480
--- /dev/null
+++ b/polyp/conf.c
@@ -0,0 +1,285 @@
+/* $Id$ */
+
+/***
+ This file is part of polypaudio.
+
+ polypaudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ polypaudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with polypaudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/stat.h>
+
+#include "conf.h"
+#include "util.h"
+#include "xmalloc.h"
+#include "strbuf.h"
+
+static const struct pa_conf default_conf = {
+ .help = 0,
+ .daemonize = 0,
+ .dump_conf = 0,
+ .dump_modules = 0,
+ .fail = 1,
+ .verbose = 0,
+ .high_priority = 0,
+ .stay_root = 0,
+ .version = 0,
+ .disallow_module_loading = 0,
+ .exit_idle_time = -1,
+ .module_idle_time = 20,
+ .auto_log_target = 1,
+ .script_commands = NULL,
+ .dl_search_path = NULL,
+ .default_script_file = NULL,
+ .log_target = PA_LOG_SYSLOG,
+};
+
+#define ENV_SCRIPT_FILE "POLYP_SCRIPT"
+#define ENV_CONFIG_FILE "POLYP_CONFIG"
+
+#ifndef DEFAULT_SCRIPT_FILE
+#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa"
+#endif
+
+#ifndef DEFAULT_CONFIG_FILE
+#define DEFAULT_CONFIG_FILE "/etc/polypaudio/config"
+#endif
+
+#define DEFAULT_SCRIPT_FILE_LOCAL ".polypaudio.pa"
+#define DEFAULT_CONFIG_FILE_LOCAL ".polypaudio.conf"
+
+char* default_file(const char *envvar, const char *global, const char *local) {
+ char *p, *h;
+
+ assert(envvar && global && local);
+
+ if ((p = getenv(envvar)))
+ return pa_xstrdup(p);
+
+ if ((h = getenv("HOME"))) {
+ struct stat st;
+ p = pa_sprintf_malloc("%s/%s", h, local);
+ if (stat(p, &st) >= 0)
+ return p;
+
+ pa_xfree(p);
+ }
+
+ return pa_xstrdup(global);
+}
+
+
+struct pa_conf* pa_conf_new(void) {
+ struct pa_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
+ c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL);
+ return c;
+}
+
+void pa_conf_free(struct pa_conf *c) {
+ assert(c);
+ pa_xfree(c->script_commands);
+ pa_xfree(c->dl_search_path);
+ pa_xfree(c->default_script_file);
+ pa_xfree(c);
+}
+
+#define WHITESPACE " \t\n"
+#define COMMENTS "#;\n"
+
+#define PARSE_BOOLEAN(t, v) \
+ do { \
+ if (!strcmp(lvalue, t)) { \
+ int b; \
+ if ((b = pa_parse_boolean(rvalue)) < 0) \
+ goto fail; \
+ c->v = b; \
+ return 0; \
+ } \
+ } while (0)
+
+#define PARSE_STRING(t, v) \
+ do { \
+ if (!strcmp(lvalue, t)) { \
+ pa_xfree(c->v); \
+ c->v = *rvalue ? pa_xstrdup(rvalue) : NULL; \
+ return 0; \
+ } \
+ } while (0)
+
+#define PARSE_INTEGER(t, v) \
+ do { \
+ if (!strcmp(lvalue, t)) { \
+ char *x = NULL; \
+ int i = strtol(rvalue, &x, 0); \
+ if (!x || *x) \
+ goto fail; \
+ c->v = i; \
+ return 0; \
+ } \
+ } while(0)
+
+static int next_assignment(struct pa_conf *c, char *lvalue, char *rvalue, unsigned n) {
+ PARSE_BOOLEAN("daemonize", daemonize);
+ PARSE_BOOLEAN("fail", fail);
+ PARSE_BOOLEAN("verbose", verbose);
+ PARSE_BOOLEAN("high-priority", high_priority);
+ PARSE_BOOLEAN("stay-root", stay_root);
+ PARSE_BOOLEAN("disallow-module-loading", disallow_module_loading);
+
+ PARSE_INTEGER("exit-idle-time", exit_idle_time);
+ PARSE_INTEGER("module-idle-time", module_idle_time);
+
+ PARSE_STRING("dl-search-path", dl_search_path);
+ PARSE_STRING("default-script-file", default_script_file);
+
+ if (!strcmp(lvalue, "log-target")) {
+ if (!strcmp(rvalue, "auto"))
+ c->auto_log_target = 1;
+ else if (!strcmp(rvalue, "syslog")) {
+ c->auto_log_target = 0;
+ c->log_target = PA_LOG_SYSLOG;
+ } else if (!strcmp(rvalue, "stderr")) {
+ c->auto_log_target = 0;
+ c->log_target = PA_LOG_STDERR;
+ } else
+ goto fail;
+
+ return 0;
+ }
+
+fail:
+ pa_log(__FILE__": line %u: parse error.\n", n);
+ return -1;
+}
+
+#undef PARSE_STRING
+#undef PARSE_BOOLEAN
+
+static int in_string(char c, const char *s) {
+ for (; *s; s++)
+ if (*s == c)
+ return 1;
+
+ return 0;
+}
+
+static char *strip(char *s) {
+ char *b = s+strspn(s, WHITESPACE);
+ char *e, *l = NULL;
+
+ for (e = b; *e; e++)
+ if (!in_string(*e, WHITESPACE))
+ l = e;
+
+ if (l)
+ *(l+1) = 0;
+
+ return b;
+}
+
+static int parse_line(struct pa_conf *conf, char *l, unsigned n) {
+ char *e, *c, *b = l+strspn(l, WHITESPACE);
+
+ if ((c = strpbrk(b, COMMENTS)))
+ *c = 0;
+
+ if (!*b)
+ return 0;
+
+ if (!(e = strchr(b, '='))) {
+ pa_log(__FILE__": line %u: missing '='.\n", n);
+ return -1;
+ }
+
+ *e = 0;
+ e++;
+
+ return next_assignment(conf, strip(b), strip(e), n);
+}
+
+
+int pa_conf_load(struct pa_conf *c, const char *filename) {
+ FILE *f;
+ int r = 0;
+ unsigned n = 0;
+ char *def = NULL;
+ assert(c);
+
+ if (!filename)
+ filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL);
+
+ if (!(f = fopen(filename, "r"))) {
+ if (errno != ENOENT)
+ pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno));
+
+ goto finish;
+ }
+
+ while (!feof(f)) {
+ char l[256];
+ if (!fgets(l, sizeof(l), f)) {
+ if (!feof(f))
+ pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno));
+
+ break;
+ }
+
+ if (parse_line(c, l, ++n) < 0)
+ r = -1;
+ }
+
+finish:
+
+ if (f)
+ fclose(f);
+
+ pa_xfree(def);
+
+ return r;
+}
+
+char *pa_conf_dump(struct pa_conf *c) {
+ struct pa_strbuf *s = pa_strbuf_new();
+ char *d;
+
+ d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL);
+ pa_strbuf_printf(s, "### Default configuration file: %s ###\n\n", d);
+
+ pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose);
+ pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize);
+ pa_strbuf_printf(s, "fail = %i\n", !!c->fail);
+ pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority);
+ pa_strbuf_printf(s, "stay-root = %i\n", !!c->stay_root);
+ pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading);
+ pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time);
+ pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time);
+ pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : "");
+ pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file);
+ pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr"));
+
+ pa_strbuf_printf(s, "\n### EOF ###\n");
+
+ pa_xfree(d);
+
+ return pa_strbuf_tostring_free(s);
+}
diff --git a/polyp/conf.h b/polyp/conf.h
new file mode 100644
index 00000000..bbe253c2
--- /dev/null
+++ b/polyp/conf.h
@@ -0,0 +1,51 @@
+#ifndef fooconfhfoo
+#define fooconfhfoo
+
+/* $Id$ */
+
+/***
+ This file is part of polypaudio.
+
+ polypaudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ polypaudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with polypaudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include "log.h"
+
+struct pa_conf {
+ int help,
+ version,
+ dump_conf,
+ dump_modules,
+ daemonize,
+ fail,
+ verbose,
+ high_priority,
+ stay_root,
+ disallow_module_loading,
+ exit_idle_time,
+ module_idle_time,
+ auto_log_target;
+ char *script_commands, *dl_search_path, *default_script_file;
+ enum pa_log_target log_target;
+};
+
+struct pa_conf* pa_conf_new(void);
+void pa_conf_free(struct pa_conf*c);
+
+int pa_conf_load(struct pa_conf *c, const char *filename);
+char *pa_conf_dump(struct pa_conf *c);
+
+#endif
diff --git a/polyp/config b/polyp/config
new file mode 100644
index 00000000..e0f8de50
--- /dev/null
+++ b/polyp/config
@@ -0,0 +1,61 @@
+# $Id$
+#
+# This file is part of polypaudio.
+#
+# polypaudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# polypaudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with polypaudio; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA.
+
+## Configuration file for polypaudio. Default values are commented out.
+## Use either ; or # for commenting
+
+# Extra verbositiy
+; verbose = 0
+
+## Daemonize after startup
+; daemonize = 0
+
+## Quit if startup fails
+; fail = 1
+
+## Renice the daemon to level -15 and try to get SCHED_FIFO
+## scheduling. This a good idea if you hear annyoing noise in the
+## playback. However, this is a certain security issue.
+; high-priority = 0
+
+## Don't drop root rights on startup if called SUID root.
+; stay-root = 0
+
+## Disallow module loading after startup
+; disallow-module-loading = 0
+
+## Terminate the daemon after the last client quit and this time
+## passed. Use a negative value to disable this feature.
+; exit-idle-time = -1
+
+## Unload autoloaded modules after being idle for this time
+module-idle-time = 20
+
+## The path were to look for dynamic shared objects (DSOs aka plugins).
+## Specify an empty string for the default search path.
+; dl-search-path =
+
+## The default script file to load. Specify an empty string for not
+## loading a default script file
+; default-script-file = /etc/polyp/default.pa
+
+## The default log target. Use either "stderr", "syslog" or
+## "auto". The latter is equivalent to "sylog" in case daemonize is
+## true, otherwise to "stderr".
+; log-target = auto
diff --git a/polyp/core.c b/polyp/core.c
index 5d79a365..0b33c107 100644
--- a/polyp/core.c
+++ b/polyp/core.c
@@ -61,7 +61,6 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
c->default_sample_spec.rate = 44100;
c->default_sample_spec.channels = 2;
- c->auto_unload_time = 20;
c->auto_unload_event = NULL;
c->subscription_defer_event = NULL;
@@ -73,7 +72,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
c->disallow_module_loading = 0;
c->quit_event = NULL;
- c->quit_after_last_client_time = -1;
+
+ c->exit_idle_time = -1;
+ c->module_idle_time = 20;
pa_check_for_sigpipe();
@@ -129,10 +130,10 @@ static void quit_callback(struct pa_mainloop_api*m, struct pa_time_event *e, con
void pa_core_check_quit(struct pa_core *c) {
assert(c);
- if (!c->quit_event && c->quit_after_last_client_time >= 0 && pa_idxset_ncontents(c->clients) == 0) {
+ if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_ncontents(c->clients) == 0) {
struct timeval tv;
gettimeofday(&tv, NULL);
- tv.tv_sec+= c->quit_after_last_client_time;
+ tv.tv_sec+= c->exit_idle_time;
c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c);
} else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) {
c->mainloop->time_free(c->quit_event);
diff --git a/polyp/core.h b/polyp/core.h
index ddba6a83..a85dafd4 100644
--- a/polyp/core.h
+++ b/polyp/core.h
@@ -38,7 +38,6 @@ struct pa_core {
char *default_source_name, *default_sink_name;
struct pa_sample_spec default_sample_spec;
- int auto_unload_time;
struct pa_time_event *auto_unload_event;
struct pa_defer_event *subscription_defer_event;
@@ -48,7 +47,7 @@ struct pa_core {
struct pa_memblock_stat *memblock_stat;
int disallow_module_loading;
- int quit_after_last_client_time;
+ int exit_idle_time, module_idle_time;
struct pa_time_event *quit_event;
};
diff --git a/polyp/polypaudio.pa b/polyp/default.pa
index 15434627..15434627 100755
--- a/polyp/polypaudio.pa
+++ b/polyp/default.pa
diff --git a/polyp/pamodinfo.c b/polyp/dumpmodules.c
index 6eb147f0..9ed89692 100644
--- a/polyp/pamodinfo.c
+++ b/polyp/dumpmodules.c
@@ -29,12 +29,11 @@
#include <stdio.h>
#include <ltdl.h>
+#include "dumpmodules.h"
#include "modinfo.h"
#define PREFIX "module-"
-static int verbose = 0;
-
static void short_info(const char *name, const char *path, struct pa_modinfo *i) {
assert(name && i);
printf("%-40s%s\n", name, i->description ? i->description : "n/a");
@@ -79,6 +78,7 @@ static void show_info(const char *name, const char *path, void (*info)(const cha
static int callback(const char *path, lt_ptr data) {
const char *e;
+ struct pa_conf *c = (data);
if ((e = (const char*) strrchr(path, '/')))
e++;
@@ -86,41 +86,16 @@ static int callback(const char *path, lt_ptr data) {
e = path;
if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1))
- show_info(e, path, verbose ? long_info : short_info);
+ show_info(e, path, c->verbose ? long_info : short_info);
return 0;
}
-int main(int argc, char *argv[]) {
- int r = lt_dlinit();
- char *path = NULL;
- int c;
- assert(r == 0);
-
- while ((c = getopt(argc, argv, "p:v")) != -1) {
- switch (c) {
- case 'p':
- path = optarg;
- break;
- case 'v':
- verbose = 1;
- break;
- default:
- return 1;
- }
- }
-
- if (path)
- lt_dlsetsearchpath(path);
-#ifdef DLSEARCHPATH
- else
- lt_dlsetsearchpath(DLSEARCHPATH);
-#endif
-
- if (argc > optind)
- show_info(argv[optind], NULL, long_info);
- else
- lt_dlforeachfile(NULL, callback, NULL);
-
- lt_dlexit();
+void pa_dump_modules(struct pa_conf *c, int argc, char * const argv[]) {
+ if (argc > 0) {
+ int i;
+ for (i = 0; i < argc; i++)
+ show_info(argv[i], NULL, long_info);
+ } else
+ lt_dlforeachfile(NULL, callback, c);
}
diff --git a/polyp/dumpmodules.h b/polyp/dumpmodules.h
new file mode 100644
index 00000000..6b1bd858
--- /dev/null
+++ b/polyp/dumpmodules.h
@@ -0,0 +1,29 @@
+#ifndef foodumpmoduleshfoo
+#define foodumpmoduleshfoo
+
+/* $Id*/
+
+/***
+ This file is part of polypaudio.
+
+ polypaudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ polypaudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with polypaudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include "conf.h"
+
+void pa_dump_modules(struct pa_conf *c, int argc, char * const argv[]);
+
+#endif
diff --git a/polyp/main.c b/polyp/main.c
index a2b3d4c7..148dfac2 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -45,6 +45,8 @@
#include "xmalloc.h"
#include "cpulimit.h"
#include "log.h"
+#include "conf.h"
+#include "dumpmodules.h"
static struct pa_mainloop *mainloop;
@@ -99,40 +101,69 @@ static void close_pipe(int p[2]) {
int main(int argc, char *argv[]) {
struct pa_core *c;
- struct pa_cmdline *cmdline = NULL;
struct pa_strbuf *buf = NULL;
+ struct pa_conf *conf;
char *s;
- int r, retval = 1;
+ int r, retval = 1, d = 0;
int daemon_pipe[2] = { -1, -1 };
+ r = lt_dlinit();
+ assert(r == 0);
+
pa_log_set_ident("polypaudio");
- if (!(cmdline = pa_cmdline_parse(argc, argv))) {
+ conf = pa_conf_new();
+
+ if (pa_conf_load(conf, NULL) < 0)
+ goto finish;
+
+ if (pa_cmdline_parse(conf, argc, argv, &d) < 0) {
pa_log(__FILE__": failed to parse command line.\n");
goto finish;
}
- pa_log_set_target(cmdline->auto_log_target ? PA_LOG_STDERR : cmdline->log_target, NULL);
+ pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL);
+
+ if (conf->dl_search_path)
+ lt_dlsetsearchpath(conf->dl_search_path);
+#ifdef DLSEARCHPATH
+ else
+ lt_dlsetsearchpath(DLSEARCHPATH);
+#endif
+
+ if (conf->dump_modules) {
+ pa_dump_modules(conf, argc-d, argv+d);
+ retval = 0;
+ goto finish;
+ }
+
+ if (conf->dump_conf) {
+ char *s = pa_conf_dump(conf);
+ fputs(s, stdout);
+ pa_xfree(s);
+ retval = 0;
+ goto finish;
+ }
- if (cmdline->help) {
+ if (conf->help) {
pa_cmdline_help(argv[0]);
retval = 0;
goto finish;
}
- if (cmdline->version) {
+ if (conf->version) {
printf(PACKAGE_NAME" "PACKAGE_VERSION"\n");
retval = 0;
goto finish;
}
- if (cmdline->high_priority)
+ if (conf->high_priority)
pa_raise_priority();
- if (!cmdline->stay_root)
+ if (!conf->stay_root)
drop_root();
- if (cmdline->daemonize) {
+ if (conf->daemonize) {
pid_t child;
if (pa_stdio_acquire() < 0) {
@@ -168,7 +199,7 @@ int main(int argc, char *argv[]) {
daemon_pipe[0] = -1;
- if (cmdline->auto_log_target)
+ if (conf->auto_log_target)
pa_log_set_target(PA_LOG_SYSLOG, NULL);
setsid();
@@ -178,15 +209,6 @@ int main(int argc, char *argv[]) {
close(1);
}
- r = lt_dlinit();
- assert(r == 0);
-
- if (cmdline->dl_search_path)
- lt_dlsetsearchpath(cmdline->dl_search_path);
-#ifdef DLSEARCHPATH
- else
- lt_dlsetsearchpath(DLSEARCHPATH);
-#endif
pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t));
@@ -210,25 +232,28 @@ int main(int argc, char *argv[]) {
buf = pa_strbuf_new();
assert(buf);
- r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose);
+ if (conf->default_script_file)
+ pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail, &conf->verbose);
+ r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail, &conf->verbose);
pa_log(s = pa_strbuf_tostring_free(buf));
pa_xfree(s);
- if (r < 0 && cmdline->fail) {
+ if (r < 0 && conf->fail) {
pa_log(__FILE__": failed to initialize daemon.\n");
- if (cmdline->daemonize)
+ if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
} else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) {
pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n");
- if (cmdline->daemonize)
+ if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
} else {
retval = 0;
- if (cmdline->daemonize)
+ if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
- c->disallow_module_loading = cmdline->disallow_module_loading;
- c->quit_after_last_client_time = cmdline->quit_after_last_client_time;
+ c->disallow_module_loading = conf->disallow_module_loading;
+ c->exit_idle_time = conf->exit_idle_time;
+ c->module_idle_time = conf->module_idle_time;
pa_log(__FILE__": Daemon startup complete.\n");
if (pa_mainloop_run(mainloop, &retval) < 0)
@@ -242,16 +267,16 @@ int main(int argc, char *argv[]) {
pa_signal_done();
pa_mainloop_free(mainloop);
- lt_dlexit();
-
pa_log(__FILE__": Daemon terminated.\n");
finish:
- if (cmdline)
- pa_cmdline_free(cmdline);
+ if (conf)
+ pa_conf_free(conf);
close_pipe(daemon_pipe);
+ lt_dlexit();
+
return retval;
}
diff --git a/polyp/modargs.c b/polyp/modargs.c
index 4874d808..e1c2c9b8 100644
--- a/polyp/modargs.c
+++ b/polyp/modargs.c
@@ -36,6 +36,7 @@
#include "sink.h"
#include "source.h"
#include "xmalloc.h"
+#include "util.h"
struct pa_modargs;
@@ -229,6 +230,7 @@ int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *va
int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value) {
const char *v;
+ int r;
assert(ma && key && value);
if (!(v = pa_modargs_get_value(ma, key, NULL)))
@@ -237,13 +239,10 @@ int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *va
if (!*v)
return -1;
- if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on"))
- *value = 1;
- else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off"))
- *value = 0;
- else
+ if ((r = pa_parse_boolean(v)) < 0)
return -1;
+ *value = r;
return 0;
}
diff --git a/polyp/module.c b/polyp/module.c
index c66faeb8..db21f790 100644
--- a/polyp/module.c
+++ b/polyp/module.c
@@ -38,7 +38,7 @@
#define PA_SYMBOL_INIT "pa__init"
#define PA_SYMBOL_DONE "pa__done"
-#define UNLOAD_POLL_TIME 10
+#define UNLOAD_POLL_TIME 2
static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) {
struct pa_core *c = userdata;
@@ -193,7 +193,7 @@ static int unused_callback(void *p, uint32_t index, int *del, void *userdata) {
time_t *now = userdata;
assert(p && del && now);
- if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->auto_unload_time <= *now) {
+ if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) {
pa_module_free(m);
*del = 1;
}
diff --git a/polyp/pacat.c b/polyp/pacat.c
index ed95c2ca..b499f71a 100644
--- a/polyp/pacat.c
+++ b/polyp/pacat.c
@@ -286,7 +286,10 @@ static void stream_get_latency_callback(struct pa_stream *s, const struct pa_lat
return;
}
- fprintf(stderr, "Current latency is %f usecs.\n", (float) (i->buffer_usec+i->sink_usec+i->transport_usec));
+ fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n",
+ (float) i->buffer_usec, (float) i->sink_usec, (float) i->transport_usec,
+ (float) (i->buffer_usec+i->sink_usec+i->transport_usec),
+ i->synchronized_clocks ? "yes" : "no");
}
/* Someone requested that the latency is shown */
diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h
index 176e1d3b..4a49a1f8 100644
--- a/polyp/polyplib-def.h
+++ b/polyp/polyplib-def.h
@@ -144,7 +144,16 @@ struct pa_latency_info {
pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */
pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to the daemon. \since 0.5 */
int playing; /**< Non-zero when the stream is currently playing */
- uint32_t queue_length; /**< Queue size in bytes. */
+ uint32_t queue_length; /**< Queue size in bytes. */
+ int synchronized_clocks; /**< Non-zero if the local and the
+ * remote machine have synchronized
+ * clocks. If synchronized clocks are
+ * detected transport_usec becomes much
+ * more reliable. However, the code that
+ * detects synchronized clocks is very
+ * limited und unreliable itself. \since
+ * 0.5 */
+ struct timeval timestamp; /**< The time when this latency info was current */
};
PA_C_DECL_END
diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c
index 98610d61..b40b7f69 100644
--- a/polyp/polyplib-stream.c
+++ b/polyp/polyplib-stream.c
@@ -347,12 +347,18 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman
gettimeofday(&now, NULL);
- if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now))
+ if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) {
/* local and remote seem to have synchronized clocks */
i.transport_usec = pa_timeval_diff(&remote, &local);
- else
+ i.synchronized_clocks = 1;
+ i.timestamp = remote;
+ } else {
/* clocks are not synchronized, let's estimate latency then */
i.transport_usec = pa_timeval_diff(&now, &local)/2;
+ i.synchronized_clocks = 0;
+ i.timestamp = local;
+ pa_timeval_add(&i.timestamp, i.transport_usec);
+ }
if (o->callback) {
void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback;
diff --git a/polyp/socket-util.c b/polyp/socket-util.c
index 2f082bfb..20380653 100644
--- a/polyp/socket-util.c
+++ b/polyp/socket-util.c
@@ -101,15 +101,15 @@ int pa_socket_low_delay(int fd) {
}
int pa_socket_tcp_low_delay(int fd) {
- int ret, tos;
+ int ret, tos, on;
assert(fd >= 0);
ret = pa_socket_low_delay(fd);
-/* on = 1; */
-/* if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) */
-/* ret = -1; */
+ on = 1;
+ if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
+ ret = -1;
tos = IPTOS_LOWDELAY;
if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
@@ -122,10 +122,10 @@ int pa_socket_tcp_low_delay(int fd) {
int pa_socket_set_rcvbuf(int fd, size_t l) {
assert(fd >= 0);
- if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) {
- pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno));
- return -1;
- }
+/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { */
+/* pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */
+/* return -1; */
+/* } */
return 0;
}
@@ -133,10 +133,10 @@ int pa_socket_set_rcvbuf(int fd, size_t l) {
int pa_socket_set_sndbuf(int fd, size_t l) {
assert(fd >= 0);
- if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) {
- pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno));
- return -1;
- }
+/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { */
+/* pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */
+/* return -1; */
+/* } */
return 0;
}
diff --git a/polyp/util.c b/polyp/util.c
index 1dbb8697..039ec264 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -268,6 +268,22 @@ pa_usec_t pa_age(const struct timeval *tv) {
return pa_timeval_diff(&now, tv);
}
+void pa_timeval_add(struct timeval *tv, pa_usec_t v) {
+ unsigned long secs;
+ assert(tv);
+
+ secs = (v/1000000);
+ tv->tv_sec += (unsigned long) secs;
+ v -= secs*1000000;
+
+ tv->tv_usec += v;
+
+ while (tv->tv_usec >= 1000000) {
+ tv->tv_sec++;
+ tv->tv_usec -= 1000000;
+ }
+}
+
#define NICE_LEVEL (-15)
void pa_raise_priority(void) {
@@ -347,3 +363,13 @@ char *pa_path_get_filename(const char *p) {
return (char*) p;
}
+
+int pa_parse_boolean(const char *v) {
+
+ if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on"))
+ return 1;
+ else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off"))
+ return 0;
+
+ return -1;
+}
diff --git a/polyp/util.h b/polyp/util.h
index f34ba4c0..42e0b22b 100644
--- a/polyp/util.h
+++ b/polyp/util.h
@@ -50,10 +50,13 @@ char *pa_path_get_filename(const char *p);
pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b);
int pa_timeval_cmp(const struct timeval *a, const struct timeval *b);
pa_usec_t pa_age(const struct timeval *tv);
+void pa_timeval_add(struct timeval *tv, pa_usec_t v);
void pa_raise_priority(void);
void pa_reset_priority(void);
int pa_fd_set_cloexec(int fd, int b);
+int pa_parse_boolean(const char *s);
+
#endif