new configuration subsystem

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@210 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2004-09-17 19:45:44 +00:00
parent 07d563d6c3
commit 63b35d002a
23 changed files with 626 additions and 231 deletions

View file

@ -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

View 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

39
polyp/client.conf Normal file
View file

@ -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

View file

@ -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;
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);
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);
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();
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);
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;
}
int pa_conf_env(struct pa_conf *c) {
char *e;
if ((e = getenv(ENV_DL_SEARCH_PATH))) {
pa_xfree(c->dl_search_path);
c->dl_search_path = pa_xstrdup(e);
}
if ((e = getenv(ENV_SCRIPT_FILE))) {
pa_xfree(c->default_script_file);
c->default_script_file = pa_xstrdup(e);
}
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);

View 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);

138
polyp/config-client.c Normal file
View file

@ -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;
}

36
polyp/config-client.h Normal file
View file

@ -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

168
polyp/confparser.c Normal file
View file

@ -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;
}

37
polyp/confparser.h Normal file
View file

@ -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

View 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);

View 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);

View 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

View 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)

View 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);

View 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)
@ -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 {

View 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);

View 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);

View 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;

View 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);

View 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));

View 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));

View 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";

View 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);