]> code.delx.au - pulseaudio/commitdiff
new configuration subsystem
authorLennart Poettering <lennart@poettering.net>
Mon, 13 Sep 2004 23:28:30 +0000 (23:28 +0000)
committerLennart Poettering <lennart@poettering.net>
Mon, 13 Sep 2004 23:28:30 +0000 (23:28 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@198 fefdeb5f-60dc-0310-8127-8f9354f1896f

23 files changed:
Makefile.am
configure.ac
doc/todo
polyp/Makefile.am
polyp/cmdline.c
polyp/cmdline.h
polyp/conf.c [new file with mode: 0644]
polyp/conf.h [new file with mode: 0644]
polyp/config [new file with mode: 0644]
polyp/core.c
polyp/core.h
polyp/default.pa [moved from polyp/polypaudio.pa with 100% similarity]
polyp/dumpmodules.c [moved from polyp/pamodinfo.c with 75% similarity]
polyp/dumpmodules.h [new file with mode: 0644]
polyp/main.c
polyp/modargs.c
polyp/module.c
polyp/pacat.c
polyp/polyplib-def.h
polyp/polyplib-stream.c
polyp/socket-util.c
polyp/util.c
polyp/util.h

index c8592f863ea0dea9b2ee50e634a96972c1946ef4..b15fbac63988b2d1ae495ef67d805ead69eb691f 100644 (file)
@@ -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
index 62dc37d4d6f75a39edde143b4ad262e1ede3798e..07b2b96ce88773c3f61fdb8d278fe992979dafe3 100644 (file)
@@ -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
index 61cee8444dc6d86567158d7b1d1580771fd1aac5..135a336d2548804f35fb96b074f7eab93451ef36 100644 (file)
--- a/doc/todo
+++ b/doc/todo
    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
index 99c894913e9cdc420f124a5600757486baeccfff..e9e1c295f81c7eba7d0d382e014dcbea59d4d39c 100644 (file)
@@ -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
index b4d58f1fb75c7fbdeab608c068fd28f09dc076fd..4e7cde48f41f7cdf2565a90b0d0161560e05791b 100644 (file)
 #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;
 }
index 5dfe2e0d3672c72c077b3b1e17ea9b1ef87da478..e4bd8af6ad1481f749af0a4fcd9e8ebbb52cf7c3 100644 (file)
   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 (file)
index 0000000..4a11c48
--- /dev/null
@@ -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 (file)
index 0000000..bbe253c
--- /dev/null
@@ -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 (file)
index 0000000..e0f8de5
--- /dev/null
@@ -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
index 5d79a365012ebe8ef8a1f49ce1890ed635da0283..0b33c1070af7c8152a260f991b87b4f50ae6be57 100644 (file)
@@ -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);
index ddba6a833cdd174a88030a5fb3095104a9abd1a8..a85dafd4cadf56a35a7b9f038e558f301a38a9c1 100644 (file)
@@ -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;
 };
similarity index 100%
rename from polyp/polypaudio.pa
rename to polyp/default.pa
similarity index 75%
rename from polyp/pamodinfo.c
rename to polyp/dumpmodules.c
index 6eb147f08df4ad6f811f344a6e1d903924d1ddcf..9ed89692a5d4fb41d0910ff36a3880d2498e8a7b 100644 (file)
 #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 (file)
index 0000000..6b1bd85
--- /dev/null
@@ -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
index a2b3d4c70dab817cb5939e81118528b653d9d82b..148dfac2fb062c4eef991a56888e4be53fe500a1 100644 (file)
@@ -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;
 }
index 4874d808e95a289a986c24b7ba764d6f76e8aec3..e1c2c9b8a33381efac3dff7d3af2b60ffedc6ecd 100644 (file)
@@ -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;
 }
 
index c66faeb896c218b0f34e3df1f15948c98290a4bf..db21f790117c644ad617f9f5f6a1a26e62301634 100644 (file)
@@ -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;
     }
index ed95c2cacaec204af0c5ce0656cda7867d8c078a..b499f71a0bcc03a7bc6691353aaf1bfbb153d290 100644 (file)
@@ -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 */
index 176e1d3b56f6a1ad2c7845a7f2c0c171d550f326..4a49a1f81c38ac112dd53a2173e329f1f69de86b 100644 (file)
@@ -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
index 98610d61240f3ac9ed536173462660534d8d0ac7..b40b7f69cca9c2881a71891d62f792ddc888c5da 100644 (file)
@@ -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;
index 2f082bfbe2fa2bb5f621875754c5d95e124dbc66..20380653d9a57e9146ac0a9058431d38cea3f426 100644 (file)
@@ -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;
 }
index 1dbb8697acc8321025c6d46ff16dca0d2d4ad0fb..039ec264ddd22205430a2786ff3dba4f414cc7cb 100644 (file)
@@ -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;
+}
index f34ba4c082fefb687946100ccfa17e0f4e17c393..42e0b22ba0bb44b3d87d490a5795ff9ece2c1926 100644 (file)
@@ -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