]> code.delx.au - pulseaudio/commitdiff
new configuration subsystem
authorLennart Poettering <lennart@poettering.net>
Fri, 17 Sep 2004 19:45:44 +0000 (19:45 +0000)
committerLennart Poettering <lennart@poettering.net>
Fri, 17 Sep 2004 19:45:44 +0000 (19:45 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@210 fefdeb5f-60dc-0310-8127-8f9354f1896f

23 files changed:
doc/todo
polyp/Makefile.am
polyp/client.conf [new file with mode: 0644]
polyp/conf.c
polyp/conf.h
polyp/config-client.c [new file with mode: 0644]
polyp/config-client.h [new file with mode: 0644]
polyp/confparser.c [new file with mode: 0644]
polyp/confparser.h [new file with mode: 0644]
polyp/core.c
polyp/core.h
polyp/daemon.conf [moved from polyp/config with 73% similarity]
polyp/main.c
polyp/polyplib-context.c
polyp/polyplib-internal.h
polyp/polyplib-scache.c
polyp/polyplib-stream.c
polyp/resampler.c
polyp/resampler.h
polyp/sink-input.c
polyp/source-output.c
polyp/util.c
polyp/util.h

index bcc78f51b243b081f4200319faebb14d2053e60b..fe06df7803e95cbd27160329c52ff0816646cee2 100644 (file)
--- a/doc/todo
+++ b/doc/todo
@@ -5,6 +5,7 @@
 - fix tcp/native in regard to latencies
 - add client config file
 - remove autospawn stuff in conf.c
+- make resampler configurable
 
 *** 0.6 ****
 - per-channel volume
index fc3fb18d26a55a16edd1a76fd6a0552f7a11ce47..d49c7c48182382357cca10213453ad2b9f6b9b3a 100644 (file)
@@ -25,14 +25,14 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@
 AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS)
 AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\"
 AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\"
-AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/default.conf\"
-AM_CFLAGS+=-DAUTOSPAWN_CONFIG_FILE=\"$(polypconfdir)/autospawn.conf\"
+AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/daemon.conf\"
+AM_CFLAGS+=-DDEFAULT_CLIENT_CONFIG_FILE=\"$(polypconfdir)/client.conf\"
 AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"
 
 AM_LDADD=$(PTHREAD_LIBS) -lm
 AM_LIBADD=$(PTHREAD_LIBS) -lm
 
-EXTRA_DIST = default.pa config depmod.py esdcompat.sh.in
+EXTRA_DIST = default.pa daemon.conf client.conf config depmod.py esdcompat.sh.in
 bin_PROGRAMS = polypaudio pacat pactl
 bin_SCRIPTS = esdcompat.sh
 noinst_PROGRAMS = \
@@ -42,7 +42,7 @@ noinst_PROGRAMS = \
                cpulimit-test \
                cpulimit-test2
 
-polypconf_DATA=default.pa config
+polypconf_DATA=default.pa daemon.conf client.conf
 
 BUILT_SOURCES=polyplib-version.h
 
@@ -158,7 +158,8 @@ polypaudio_SOURCES = idxset.c idxset.h \
                gcc-printf.h \
                modinfo.c modinfo.h \
                conf.c conf.h \
-               dumpmodules.c dumpmodules.h
+               dumpmodules.c dumpmodules.h \
+               conparser.h confparser.c 
 
 polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
 polypaudio_INCLUDES = $(INCLTDL)
@@ -332,7 +333,9 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \
                cdecl.h \
                llist.h \
                log.c log.h \
-               gcc-printf.h
+               gcc-printf.h \
+        config-client.c config-client.h \
+               confparser.c confparser.h
 
 libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
 libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
diff --git a/polyp/client.conf b/polyp/client.conf
new file mode 100644 (file)
index 0000000..070d75b
--- /dev/null
@@ -0,0 +1,39 @@
+# $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 clients. Default values are
+## commented out.  Use either ; or # for commenting
+
+## Path to the polypaudio daemon to run when autospawning.
+; daemon_binary = @POLYPAUDIO_BINARY
+
+## Extra arguments to pass to the polypaudio daemon
+; extra_arguments = --daemonize=yes --log-target=syslog
+
+## The default sink to connect to
+; default_sink = 
+
+## The default source to connect to
+; default_source =
+
+## The default sever to connect to
+; default_server =
+
+## Autospawn daemons?
+; autospawn = 0
index b74a5ede2191aa456ae87da975b17f22a2a4d689..efc471af790b3f7170a1486cec4eae6665add599 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
-#include <sys/stat.h>
+#include <unistd.h>
+#include <samplerate.h>
 
 #include "conf.h"
 #include "util.h"
 #include "xmalloc.h"
 #include "strbuf.h"
+#include "confparser.h"
+
+#ifndef DEFAULT_SCRIPT_FILE
+#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa"
+#endif
+
+#ifndef DEFAULT_SCRIPT_FILE_USER
+#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa"
+#endif
+
+#ifndef DEFAULT_CONFIG_FILE
+#define DEFAULT_CONFIG_FILE "/etc/polypaudio/daemon.conf"
+#endif
+
+#ifndef DEFAULT_CONFIG_FILE_USER
+#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf"
+#endif
+
+#define ENV_SCRIPT_FILE "POLYP_SCRIPT"
+#define ENV_CONFIG_FILE "POLYP_CONFIG"
+#define ENV_DL_SEARCH_PATH "POLYP_DLPATH"
 
 static const struct pa_conf default_conf = {
     .cmd = PA_CMD_DAEMON,
@@ -49,28 +71,9 @@ static const struct pa_conf default_conf = {
     .dl_search_path = NULL,
     .default_script_file = NULL,
     .log_target = PA_LOG_SYSLOG,
+    .resample_method = SRC_SINC_FASTEST
 };
 
-#define ENV_SCRIPT_FILE "POLYP_SCRIPT"
-#define ENV_CONFIG_FILE "POLYP_CONFIG"
-#define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED"
-
-#ifndef DEFAULT_SCRIPT_FILE
-#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa"
-#endif
-
-#ifndef DEFAULT_CONFIG_FILE
-#define DEFAULT_CONFIG_FILE "/etc/polypaudio/default.conf"
-#endif
-
-#ifndef AUTOSPAWN_CONFIG_FILE
-#define AUTOSPAWN_CONFIG_FILE "/etc/polypaudio/autospawn.conf"
-#endif
-
-#define DEFAULT_SCRIPT_FILE_LOCAL ".polypaudio.pa"
-#define DEFAULT_CONFIG_FILE_LOCAL ".polypaudio.conf"
-#define AUTOSPAWN_CONFIG_FILE_LOCAL ".polypaudio-autospawn.conf"
-
 char* default_file(const char *envvar, const char *global, const char *local) {
     char *p, *h;
 
@@ -80,9 +83,8 @@ char* default_file(const char *envvar, const char *global, const char *local) {
         return pa_xstrdup(p);
 
     if ((h = getenv("HOME"))) {
-        struct stat st;
         p = pa_sprintf_malloc("%s/%s", h, local);
-        if (stat(p, &st) >= 0)
+        if (!access(p, F_OK)) 
             return p;
         
         pa_xfree(p);
@@ -91,26 +93,12 @@ char* default_file(const char *envvar, const char *global, const char *local) {
     return pa_xstrdup(global);
 }
 
-char *default_config_file(void) {
-    char *b;
-    int autospawned = 0;
-    
-    if ((b = getenv(ENV_AUTOSPAWNED)))
-        autospawned = pa_parse_boolean(b) > 0;
-    
-    return default_file(ENV_CONFIG_FILE,
-                        autospawned ? AUTOSPAWN_CONFIG_FILE : DEFAULT_CONFIG_FILE,
-                        autospawned ? AUTOSPAWN_CONFIG_FILE_LOCAL : DEFAULT_CONFIG_FILE_LOCAL);
-
-}
-
-char *default_script_file(void) {
-    return default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL);
-}
-
 struct pa_conf* pa_conf_new(void) {
     struct pa_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
-    c->default_script_file = default_script_file();
+    c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER);
+#ifdef DLSEARCHPATH
+    c->dl_search_path = pa_xstrdup(DLSEARCHPATH);
+#endif
     return c;
 }
 
@@ -122,166 +110,104 @@ void pa_conf_free(struct pa_conf *c) {
     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("disallow-module-loading", disallow_module_loading);
-
-    PARSE_INTEGER("exit-idle-time", exit_idle_time);
-    PARSE_INTEGER("module-idle-time", module_idle_time);
-    PARSE_INTEGER("scache-idle-time", scache_idle_time);
+int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+    struct pa_conf *c = data;
+    assert(filename && lvalue && rvalue && data);
     
-    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;
+    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 {
+        pa_log(__FILE__": [%s:%u] Invalid log target '%s'.\n", filename, line, rvalue);
+        return -1;
     }
-    
-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);
+int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+    struct pa_conf *c = data;
+    assert(filename && lvalue && rvalue && data);
+
+    if (!strcmp(rvalue, "sinc-best-quality"))
+        c->resample_method = SRC_SINC_BEST_QUALITY;
+    else if (!strcmp(rvalue, "sinc-medium-quality"))
+        c->resample_method = SRC_SINC_MEDIUM_QUALITY;
+    else if (!strcmp(rvalue, "sinc-fastest"))
+        c->resample_method = SRC_SINC_FASTEST;
+    else if (!strcmp(rvalue, "zero-order-hold"))
+        c->resample_method = SRC_ZERO_ORDER_HOLD;
+    else if (!strcmp(rvalue, "linear"))
+        c->resample_method = SRC_LINEAR;
+    else {
+        pa_log(__FILE__": [%s:%u] Inavalid resample method '%s'.\n", filename, line, rvalue);
         return -1;
     }
 
-    *e = 0;
-    e++;
-
-    return next_assignment(conf, strip(b), strip(e), n);
+    return 0;
 }
 
-
 int pa_conf_load(struct pa_conf *c, const char *filename) {
-    FILE *f;
-    int r = 0;
-    unsigned n = 0;
     char *def = NULL;
-    assert(c);
+    int r;
     
+    const struct pa_config_item table[] = {
+        { "verbose",                 pa_config_parse_bool,    &c->verbose },
+        { "daemonize",               pa_config_parse_bool,    &c->daemonize },
+        { "fail",                    pa_config_parse_bool,    &c->fail },
+        { "high-priority",           pa_config_parse_bool,    &c->high_priority },
+        { "disallow-module-loading", pa_config_parse_bool,    &c->disallow_module_loading },
+        { "exit-idle-time",          pa_config_parse_int,     &c->exit_idle_time },
+        { "module-idle-time",        pa_config_parse_int,     &c->module_idle_time },
+        { "scache-idle-time",        pa_config_parse_int,     &c->scache_idle_time },
+        { "dl-search-path",          pa_config_parse_string,  &c->dl_search_path },
+        { "default-script-file",     pa_config_parse_string,  &c->default_script_file },
+        { "log-target",              parse_log_target,        c },
+        { "resample-method",         parse_resample_method,   c },
+        { NULL,                      NULL,                    NULL },
+    };
+
     if (!filename)
-        filename = def = default_config_file();
+        filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER);
+    
+    r = pa_config_parse(filename, table, NULL);
+    pa_xfree(def);
+    return r;
+}
 
-    if (!(f = fopen(filename, "r"))) {
-        if (errno != ENOENT)
-            pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno));
+int pa_conf_env(struct pa_conf *c) {
+    char *e;
 
-        goto finish;
+    if ((e = getenv(ENV_DL_SEARCH_PATH))) {
+        pa_xfree(c->dl_search_path);
+        c->dl_search_path = pa_xstrdup(e);
     }
-
-    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;
+    if ((e = getenv(ENV_SCRIPT_FILE))) {
+        pa_xfree(c->default_script_file);
+        c->default_script_file = pa_xstrdup(e);
     }
-    
-finish:
 
-    if (f)
-        fclose(f);
-    
-    pa_xfree(def);
-    
-    return r;
+    return 0;
 }
 
 char *pa_conf_dump(struct pa_conf *c) {
     struct pa_strbuf *s = pa_strbuf_new();
     char *d;
 
-    d = default_config_file();
+    static const char const* resample_methods[] = {
+        "sinc-best-quality",
+        "sinc-medium-quality",
+        "sinc-fastest",
+        "zero-order-hold",
+        "linear"
+    };
+
+    d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER);
     pa_strbuf_printf(s, "### Default configuration file: %s ###\n", d);
     
     pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose);
@@ -295,6 +221,9 @@ char *pa_conf_dump(struct pa_conf *c) {
     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"));
+
+    assert(c->resample_method <= 4 && c->resample_method >= 0);
+    pa_strbuf_printf(s, "resample-method = %s\n", resample_methods[c->resample_method]);
     
     pa_xfree(d);
     
index dafb3797a5f5ba30e5e12819e268afb33d3ae170..ace5396d4b09881d49f3ea954ddc93ef42630939 100644 (file)
@@ -45,6 +45,7 @@ struct pa_conf {
         auto_log_target;
     char *script_commands, *dl_search_path, *default_script_file;
     enum pa_log_target log_target;
+    int resample_method;
 };
 
 struct pa_conf* pa_conf_new(void);
diff --git a/polyp/config-client.c b/polyp/config-client.c
new file mode 100644 (file)
index 0000000..758927f
--- /dev/null
@@ -0,0 +1,138 @@
+/* $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 <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "config-client.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "confparser.h"
+#include "util.h"
+
+#ifndef DEFAULT_CLIENT_CONFIG_FILE
+#define DEFAULT_CLIENT_CONFIG_FILE "/etc/polypaudio/client.conf"
+#endif
+
+#ifndef DEFAULT_CLIENT_CONFIG_FILE_USER
+#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf"
+#endif
+
+#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG"
+#define ENV_DEFAULT_SINK "POLYP_SINK"
+#define ENV_DEFAULT_SOURCE "POLYP_SOURCE"
+#define ENV_DEFAULT_SERVER "POLYP_SERVER"
+#define ENV_DAEMON_BINARY "POLYP_BINARY"
+
+
+static const struct pa_client_conf default_conf = {
+    .daemon_binary = NULL,
+    .extra_arguments = NULL,
+    .default_sink = NULL,
+    .default_source = NULL,
+    .default_server = NULL,
+    .autospawn = 0
+};
+
+struct pa_client_conf *pa_client_conf_new(void) {
+    struct pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
+
+    c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY);
+    c->extra_arguments = pa_xstrdup("--daemonize=yes --log-target=syslog");
+    
+    return c;
+}
+
+void pa_client_conf_free(struct pa_client_conf *c) {
+    assert(c);
+    pa_xfree(c->daemon_binary);
+    pa_xfree(c->extra_arguments);
+    pa_xfree(c->default_sink);
+    pa_xfree(c->default_source);
+    pa_xfree(c->default_server);
+    pa_xfree(c);
+}
+int pa_client_conf_load(struct pa_client_conf *c, const char *filename) {
+    char *def = NULL;
+    int r;
+
+    const struct pa_config_item table[] = {
+        { "daemon-binary",          pa_config_parse_string,  &c->daemon_binary },
+        { "extra-arguments",        pa_config_parse_string,  &c->extra_arguments },
+        { "default-sink",           pa_config_parse_string,  &c->default_sink },
+        { "default-source",         pa_config_parse_string,  &c->default_source },
+        { "default-server",         pa_config_parse_string,  &c->default_server },
+        { "autospawn",              pa_config_parse_bool,    &c->autospawn },
+        { NULL,                     NULL,                    NULL },
+    };
+
+    if (!filename)
+        filename = getenv(ENV_CLIENT_CONFIG_FILE);
+
+    if (!filename) {
+        char *h;
+        
+        if ((h = getenv("HOME"))) {
+            def = pa_sprintf_malloc("%s/%s", h, DEFAULT_CLIENT_CONFIG_FILE_USER);
+            
+            if (!access(def, F_OK)) 
+                filename = def;
+            else {
+                pa_xfree(def);
+                def = NULL;
+            }
+        }
+    }
+
+    if (!filename)
+        filename = DEFAULT_CLIENT_CONFIG_FILE;
+    
+    r = pa_config_parse(filename, table, NULL);
+    pa_xfree(def);
+    return r;
+}
+
+int pa_client_conf_env(struct pa_client_conf *c) {
+    char *e;
+    
+    if ((e = getenv(ENV_DEFAULT_SINK))) {
+        pa_xfree(c->default_sink);
+        c->default_sink = pa_xstrdup(e);
+    }
+
+    if ((e = getenv(ENV_DEFAULT_SOURCE))) {
+        pa_xfree(c->default_source);
+        c->default_source = pa_xstrdup(e);
+    }
+
+    if ((e = getenv(ENV_DEFAULT_SERVER))) {
+        pa_xfree(c->default_server);
+        c->default_server = pa_xstrdup(e);
+    }
+    
+    if ((e = getenv(ENV_DAEMON_BINARY))) {
+        pa_xfree(c->daemon_binary);
+        c->daemon_binary = pa_xstrdup(e);
+    }
+
+    return 0;
+}
diff --git a/polyp/config-client.h b/polyp/config-client.h
new file mode 100644 (file)
index 0000000..1b1c519
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef fooconfigclienthfoo
+#define fooconfigclienthfoo
+
+/* $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.
+***/
+
+struct pa_client_conf {
+    char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server;
+    int autospawn;
+};
+
+struct pa_client_conf *pa_client_conf_new(void);
+void pa_client_conf_free(struct pa_client_conf *c);
+
+int pa_client_conf_load(struct pa_client_conf *c, const char *filename);
+int pa_client_conf_env(struct pa_client_conf *c);
+
+#endif
diff --git a/polyp/confparser.c b/polyp/confparser.c
new file mode 100644 (file)
index 0000000..8f551b9
--- /dev/null
@@ -0,0 +1,168 @@
+/* $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 <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "confparser.h"
+#include "log.h"
+#include "util.h"
+#include "xmalloc.h"
+
+#define WHITESPACE " \t\n"
+#define COMMENTS "#;\n"
+
+static int next_assignment(const char *filename, unsigned line, const struct pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) {
+    assert(filename && t && lvalue && rvalue);
+    
+    for (; t->parse; t++)
+        if (!strcmp(lvalue, t->lvalue))
+            return t->parse(filename, line, lvalue, rvalue, t->data, userdata);
+
+    pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.\n", filename, line, lvalue);
+    
+    return -1;
+}
+
+static int in_string(char c, const char *s) {
+    assert(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(const char *filename, unsigned line, const struct pa_config_item *t, char *l, void *userdata) {
+    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__": [%s:%u] Missing '='.\n", filename, line);
+        return -1;
+    }
+
+    *e = 0;
+    e++;
+
+    return next_assignment(filename, line, t, strip(b), strip(e), userdata);
+}
+
+
+int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata) {
+    FILE *f;
+    int r = -1;
+    unsigned line = 0;
+    assert(filename && t);
+    
+    if (!(f = fopen(filename, "r"))) {
+        if (errno == ENOENT) {
+            r = 0;
+            goto finish;
+        }
+        
+        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))
+                break;
+            
+            pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno));
+            goto finish;
+        }
+            
+        if (parse_line(filename, ++line, t,  l, userdata) < 0)
+            goto finish;
+    }
+    
+    r = 0;
+    
+finish:
+
+    if (f)
+        fclose(f);
+    
+    return r;
+}
+
+int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+    int *i = data, k;
+    char *x = NULL;
+    assert(filename && lvalue && rvalue && data);
+    
+    k = strtol(rvalue, &x, 0); 
+    if (!*rvalue || !x || *x) {
+        pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s\n", filename, line, rvalue);
+        return -1;
+    }
+    
+    *i = k;
+    return 0; 
+}
+
+int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+    int *b = data, k;
+    assert(filename && lvalue && rvalue && data);
+    
+    if ((k = pa_parse_boolean(rvalue)) < 0) {
+        pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s\n", filename, line, rvalue);
+        return -1;
+    }
+    
+    *b = k;
+    
+    return 0;
+}
+
+int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+    char **s = data;
+    assert(filename && lvalue && rvalue && data);
+
+    pa_xfree(*s);
+    *s = *rvalue ? pa_xstrdup(rvalue) : NULL;
+    return 0;
+}
diff --git a/polyp/confparser.h b/polyp/confparser.h
new file mode 100644 (file)
index 0000000..a0eb52d
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef fooconfparserhfoo
+#define fooconfparserhfoo
+
+/* $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.
+***/
+
+struct pa_config_item {
+    const char *lvalue;
+    int (*parse)(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
+    void *data;
+};
+
+int pa_config_parse(const char *filename, const struct pa_config_item *t, void *userdata);
+
+int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
+
+#endif
index 58035087a4f30a54426505c0cbbdb0cf870cbf69..cf2d383c4870dab05fe74097b829b0bfe4c7b688 100644 (file)
@@ -27,6 +27,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <signal.h>
+#include <samplerate.h>
 
 #include "core.h"
 #include "module.h"
@@ -79,6 +80,8 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
     c->exit_idle_time = -1;
     c->module_idle_time = 20;
     c->scache_idle_time = 20;
+
+    c->resample_method = SRC_SINC_FASTEST;
     
     pa_check_signal_is_blocked(SIGPIPE);
     
index 980888f62ee72f642a2591c2af010bdaa4b10940..62959d0afece1a48b324ef7e9b6feffd310a7a18 100644 (file)
@@ -53,6 +53,8 @@ struct pa_core {
     struct pa_time_event *quit_event;
 
     struct pa_time_event *scache_auto_unload_event;
+
+    int resample_method;
 };
 
 struct pa_core* pa_core_new(struct pa_mainloop_api *m);
similarity index 73%
rename from polyp/config
rename to polyp/daemon.conf
index b404bc408ff6da09b078e9d0b1c2906c86a41525..a277bb4fd464cf1e98275e46517382e571f9c8a0 100644 (file)
@@ -17,8 +17,8 @@
 # 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
+## Configuration file for the polypaudio daemon. Default values are
+## commented out.  Use either ; or # for commenting
 
 # Extra verbositiy
 ; verbose = 0
@@ -46,16 +46,22 @@ high-priority = 0
 ## 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. You may specify 
-## more than one path seperated by colons.
-; dl-search-path =
+## The path were to look for dynamic shared objects (DSOs aka
+## plugins).  You may specify more than one path seperated by
+## colons. 
+; dl-search-path = @DLSEARCHPATH@
 
 ## The default script file to load. Specify an empty string for not
-## loading a default script file
-; default-script-file = /etc/polyp/default.pa 
+## loading a default script file. The 
+; default-script-file = @DEFAULT_CONFIG_FILE@
 
 ## 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
+
+## The resampling algorithm to use. Use one of sinc-best-quality,
+## sinc-medium-quality, sinc-fastest, zero-order-hold, linear.  See
+## the documentation of libsamplerate for an explanation fot the
+## different methods.
+; resample-method = sinc-fastest
index e44fc01342ad7bdfc09054a5ae27caa3bfcc105e..3b25a030ebc37ba29bc94e890853f2fb110bfc0a 100644 (file)
@@ -119,10 +119,6 @@ int main(int argc, char *argv[]) {
     
     if (conf->dl_search_path)
         lt_dlsetsearchpath(conf->dl_search_path);
-#ifdef DLSEARCHPATH
-    else
-        lt_dlsetsearchpath(DLSEARCHPATH);
-#endif
 
     switch (conf->cmd) {
         case PA_CMD_DUMP_MODULES:
@@ -245,6 +241,8 @@ int main(int argc, char *argv[]) {
         c->disallow_module_loading = conf->disallow_module_loading;
         c->exit_idle_time = conf->exit_idle_time;
         c->module_idle_time = conf->module_idle_time;
+        c->scache_idle_time = conf->scache_idle_time;
+        c->resample_method = conf->resample_method;
         
         pa_log(__FILE__": Daemon startup complete.\n");
         if (pa_mainloop_run(mainloop, &retval) < 0)
index 64f9074c79b0155ee3b98fc9c044779e990becfa..04ee3d89739ab8b375ff9a8d8c495086b89ab448 100644 (file)
@@ -47,6 +47,9 @@
 #include "util.h"
 #include "xmalloc.h"
 #include "log.h"
+#include "config-client.h"
+
+#define DEFAULT_SERVER "/tmp/polypaudio/native"
 
 static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_REQUEST] = { pa_command_request },
@@ -87,6 +90,11 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
     c->local = -1;
     
     pa_check_signal_is_blocked(SIGPIPE);
+
+    c->conf = pa_client_conf_new();
+    pa_client_conf_load(c->conf, NULL);
+    pa_client_conf_env(c->conf);
+    
     return c;
 }
 
@@ -114,6 +122,9 @@ static void context_free(struct pa_context *c) {
         pa_dynarray_free(c->playback_streams, NULL, NULL);
 
     pa_memblock_stat_unref(c->memblock_stat);
+
+    if (c->conf)
+        pa_client_conf_free(c->conf);
     
     pa_xfree(c->name);
     pa_xfree(c);
@@ -366,7 +377,7 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) {
     return sa;
 }
 
-static int is_running(void) {
+static int default_server_is_running(void) {
     struct stat st;
     
     if (DEFAULT_SERVER[0] != '/')
@@ -404,24 +415,39 @@ static int context_connect_spawn(struct pa_context *c, const struct pa_spawn_api
         
         goto fail;
     } else if (!pid) {
-        char t[128];
-        char *p;
         /* Child */
+        
+        char t[128];
+        const char *state = NULL;
+#define MAX_ARGS 64
+        char *argv[MAX_ARGS+1];
+        int n = 0;
 
         close(fds[0]);
         
         if (api && api->atfork)
             api->atfork();
 
-        if (!(p = getenv(ENV_DEFAULT_BINARY)))
-            p = POLYPAUDIO_BINARY;
-
         snprintf(t, sizeof(t), "%s=1", ENV_AUTOSPAWNED);
-        putenv(t); 
-        
+        putenv(t);
+
+        argv[n++] = c->conf->daemon_binary;
+
         snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]);
-        execl(p, p, "--daemonize=yes", "--log-target=syslog", t, NULL);
-        
+        argv[n++] = pa_xstrdup(t);
+
+        while (n < MAX_ARGS) {
+            char *a;
+
+            if (!(a = pa_split_spaces(c->conf->extra_arguments, &state)))
+                break;
+
+            argv[n++] = a;
+        }
+
+        argv[n++] = NULL;
+
+        execv(argv[0], argv);
         exit(1);
     } 
 
@@ -468,19 +494,12 @@ int pa_context_connect(struct pa_context *c, const char *server, int spawn, cons
     assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED);
 
     if (!server)
-        if (!(server = getenv(ENV_DEFAULT_SERVER))) {
-            if (spawn && !is_running()) {
-                char *b;
-                
-                if ((b = getenv(ENV_DISABLE_AUTOSPAWN)))
-                    if (pa_parse_boolean(b) > 1)
-                        return -1;
-                
-                return context_connect_spawn(c, api);
-            }
+        server = c->conf->default_server;
 
-            server = DEFAULT_SERVER;
-        }
+    if (!server && spawn && c->conf->autospawn && !default_server_is_running())
+        return context_connect_spawn(c, api);
+
+    server = DEFAULT_SERVER;
 
     pa_context_ref(c);
 
index 4c44ee98d1e146b9547968ee08dbe19bdd6c0bc0..1d0e41d8af1c3d9ff015c1e39204c0b8b5344eb3 100644 (file)
@@ -33,6 +33,7 @@
 #include "polyplib-operation.h"
 #include "llist.h"
 #include "native-common.h"
+#include "config-client.h"
 
 #define DEFAULT_TLENGTH (10240*8)
 #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2)
 #define DEFAULT_FRAGSIZE 1024
 
 #define DEFAULT_TIMEOUT (5*60)
-#define DEFAULT_SERVER "/tmp/polypaudio/native"
 #define DEFAULT_PORT "4713"
 
-#define ENV_DEFAULT_SINK "POLYP_SINK"
-#define ENV_DEFAULT_SOURCE "POLYP_SOURCE"
-#define ENV_DEFAULT_SERVER "POLYP_SERVER"
-#define ENV_DEFAULT_BINARY "POLYP_BINARY"
-#define ENV_DISABLE_AUTOSPAWN "POLYP_NOAUTOSPAWN"
 #define ENV_AUTOSPAWNED "POLYP_AUTOSPAWNED"
 
 struct pa_context {
@@ -80,6 +75,8 @@ struct pa_context {
     struct pa_memblock_stat *memblock_stat;
 
     int local;
+
+    struct pa_client_conf *conf;
 };
 
 struct pa_stream {
index 8215eaec1aef3ec90fc10cdd3b8ff6a9f1203083..7221420c8a38ce6cdb3d1ec919ac18457e0241c9 100644 (file)
@@ -88,7 +88,7 @@ struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *n
     o->userdata = userdata;
 
     if (!dev)
-        dev = getenv(ENV_DEFAULT_SINK);
+        dev = c->conf->default_sink;
     
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
index 532d1700f2f9633c96f351a810a77abd3c4dbdbf..6055a2204c09ef06556c17828c4f03a8099466f9 100644 (file)
@@ -217,7 +217,7 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_
     assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED);
 
     pa_stream_ref(s);
-    
+
     if (attr)
         s->buffer_attr = *attr;
     else {
@@ -235,9 +235,9 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_
 
     if (!dev) {
         if (s->direction == PA_STREAM_PLAYBACK)
-            dev = getenv(ENV_DEFAULT_SINK);
+            dev = s->context->conf->default_sink;
         else
-            dev = getenv(ENV_DEFAULT_SOURCE);
+            dev = s->context->conf->default_source;
     }
     
     pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
index 4742ce212ee039d3d9b8a6b0a822f4a36f7d22d4..e8dd01b9f3ff7c984ff0a7f9666b06191feb4bec 100644 (file)
@@ -47,7 +47,7 @@ struct pa_resampler {
     struct pa_memblock_stat *memblock_stat;
 };
 
-struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s) {
+struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method) {
     struct pa_resampler *r = NULL;
     int err;
     assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b));
@@ -67,7 +67,7 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru
     r->i_buf = r->o_buf = NULL;
     r->i_alloc = r->o_alloc = 0;
 
-    r->src_state = src_new(SRC_SINC_FASTEST, r->channels, &err);
+    r->src_state = src_new(resample_method, r->channels, &err);
     if (err != 0 || !r->src_state)
         goto fail;
 
index a6ef30dffc85333d26d37d5f9893929b48dfda3d..b984a4f6da9651d7d7afd99c9324ca1b67e54829 100644 (file)
@@ -28,7 +28,7 @@
 
 struct pa_resampler;
 
-struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s);
+struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method);
 void pa_resampler_free(struct pa_resampler *r);
 
 size_t pa_resampler_request(struct pa_resampler *r, size_t out_length);
index 2541c8217ba4f44b1921307dbffcaab0f4ff1078..486a204439689ad848b9dd36a77f04e431b070f1 100644 (file)
@@ -49,7 +49,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con
     }
     
     if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec))
-        if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat)))
+        if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, s->core->resample_method)))
             return NULL;
     
     i = pa_xmalloc(sizeof(struct pa_sink_input));
index 1db88d3cc04b41d2060f050fc59ef8dbbd941a91..252c155cf9069d72008987d2b944748a60e513dd 100644 (file)
@@ -45,7 +45,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n
     }
 
     if (!pa_sample_spec_equal(&s->sample_spec, spec))
-        if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat)))
+        if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, s->core->resample_method)))
             return NULL;
     
     o = pa_xmalloc(sizeof(struct pa_source_output));
index 24773a7bca35c9dbe6dc732606b3da947181afdc..86f18f258806bcac5b6e41b4c067eefb1b6cd0eb 100644 (file)
@@ -390,6 +390,23 @@ char *pa_split(const char *c, const char *delimiter, const char**state) {
     return pa_xstrndup(current, l);
 }
 
+#define WHITESPACE " \t\n"
+
+char *pa_split_spaces(const char *c, const char **state) {
+    const char *current = *state ? *state : c;
+    size_t l;
+
+    if (*current)
+        return NULL;
+
+    current += strspn(current, WHITESPACE);
+    l = strcspn(current, WHITESPACE);
+
+    *state = current+l;
+
+    return pa_xstrndup(current, l);
+}
+
 const char *pa_strsignal(int sig) {
     switch(sig) {
         case SIGINT: return "SIGINT";
index f5cda2006b6d79395683df75a1b24ec6705412f8..07072df6f799e85de2040403596c1c05119d357f 100644 (file)
@@ -60,6 +60,7 @@ int pa_fd_set_cloexec(int fd, int b);
 int pa_parse_boolean(const char *s);
 
 char *pa_split(const char *c, const char*delimiters, const char **state);
+char *pa_split_spaces(const char *c, const char **state);
 
 const char *pa_strsignal(int sig);