summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2004-09-17 19:45:44 +0000
committerLennart Poettering <lennart@poettering.net>2004-09-17 19:45:44 +0000
commit63b35d002aa6902618235e1a30dca37de52ff65e (patch)
tree7db206df74b36c6e2e78df2b758c72dddb49a025
parent07d563d6c304166bd5bd47731a337387316991f6 (diff)
new configuration subsystem
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@210 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r--doc/todo1
-rw-r--r--polyp/Makefile.am15
-rw-r--r--polyp/client.conf39
-rw-r--r--polyp/conf.c279
-rw-r--r--polyp/conf.h1
-rw-r--r--polyp/config-client.c138
-rw-r--r--polyp/config-client.h36
-rw-r--r--polyp/confparser.c168
-rw-r--r--polyp/confparser.h37
-rw-r--r--polyp/core.c3
-rw-r--r--polyp/core.h2
-rw-r--r--polyp/daemon.conf (renamed from polyp/config)22
-rw-r--r--polyp/main.c6
-rw-r--r--polyp/polyplib-context.c63
-rw-r--r--polyp/polyplib-internal.h9
-rw-r--r--polyp/polyplib-scache.c2
-rw-r--r--polyp/polyplib-stream.c6
-rw-r--r--polyp/resampler.c4
-rw-r--r--polyp/resampler.h2
-rw-r--r--polyp/sink-input.c2
-rw-r--r--polyp/source-output.c2
-rw-r--r--polyp/util.c17
-rw-r--r--polyp/util.h1
23 files changed, 625 insertions, 230 deletions
diff --git a/doc/todo b/doc/todo
index bcc78f51b..fe06df780 100644
--- 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
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index fc3fb18d2..d49c7c481 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -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
index 000000000..070d75bd2
--- /dev/null
+++ b/polyp/client.conf
@@ -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
diff --git a/polyp/conf.c b/polyp/conf.c
index b74a5ede2..efc471af7 100644
--- a/polyp/conf.c
+++ b/polyp/conf.c
@@ -27,12 +27,34 @@
#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);
diff --git a/polyp/conf.h b/polyp/conf.h
index dafb3797a..ace5396d4 100644
--- a/polyp/conf.h
+++ b/polyp/conf.h
@@ -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
index 000000000..758927f3a
--- /dev/null
+++ b/polyp/config-client.c
@@ -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
index 000000000..1b1c519dd
--- /dev/null
+++ b/polyp/config-client.h
@@ -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
index 000000000..8f551b954
--- /dev/null
+++ b/polyp/confparser.c
@@ -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
index 000000000..a0eb52d0d
--- /dev/null
+++ b/polyp/confparser.h
@@ -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
diff --git a/polyp/core.c b/polyp/core.c
index 58035087a..cf2d383c4 100644
--- a/polyp/core.c
+++ b/polyp/core.c
@@ -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);
diff --git a/polyp/core.h b/polyp/core.h
index 980888f62..62959d0af 100644
--- a/polyp/core.h
+++ b/polyp/core.h
@@ -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);
diff --git a/polyp/config b/polyp/daemon.conf
index b404bc408..a277bb4fd 100644
--- a/polyp/config
+++ b/polyp/daemon.conf
@@ -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
diff --git a/polyp/main.c b/polyp/main.c
index e44fc0134..3b25a030e 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -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)
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index 64f9074c7..04ee3d897 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -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);
diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h
index 4c44ee98d..1d0e41d8a 100644
--- a/polyp/polyplib-internal.h
+++ b/polyp/polyplib-internal.h
@@ -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)
@@ -41,14 +42,8 @@
#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 {
diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c
index 8215eaec1..7221420c8 100644
--- a/polyp/polyplib-scache.c
+++ b/polyp/polyplib-scache.c
@@ -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);
diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c
index 532d1700f..6055a2204 100644
--- a/polyp/polyplib-stream.c
+++ b/polyp/polyplib-stream.c
@@ -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);
diff --git a/polyp/resampler.c b/polyp/resampler.c
index 4742ce212..e8dd01b9f 100644
--- a/polyp/resampler.c
+++ b/polyp/resampler.c
@@ -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;
diff --git a/polyp/resampler.h b/polyp/resampler.h
index a6ef30dff..b984a4f6d 100644
--- a/polyp/resampler.h
+++ b/polyp/resampler.h
@@ -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);
diff --git a/polyp/sink-input.c b/polyp/sink-input.c
index 2541c8217..486a20443 100644
--- a/polyp/sink-input.c
+++ b/polyp/sink-input.c
@@ -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));
diff --git a/polyp/source-output.c b/polyp/source-output.c
index 1db88d3cc..252c155cf 100644
--- a/polyp/source-output.c
+++ b/polyp/source-output.c
@@ -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));
diff --git a/polyp/util.c b/polyp/util.c
index 24773a7bc..86f18f258 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -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";
diff --git a/polyp/util.h b/polyp/util.h
index f5cda2006..07072df6f 100644
--- a/polyp/util.h
+++ b/polyp/util.h
@@ -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);