new configuration subsystem

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@198 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2004-09-13 23:28:30 +00:00
parent fbefe67d52
commit 829656c5fc
23 changed files with 755 additions and 231 deletions

View file

@ -24,7 +24,17 @@ MAINTAINERCLEANFILES=README
noinst_DATA = README noinst_DATA = README
pkgconfigdir = $(libdir)/pkgconfig pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc
if HAVE_GLIB20
pkgconfig_DATA += \
polyplib-glib-mainloop.pc
endif
if HAVE_GLIB12
pkgconfig_DATA += \
polyplib-glib12-mainloop.pc
endif
README: README:
rm -f README rm -f README

View file

@ -40,10 +40,12 @@ AC_SUBST(INCLTDL)
AC_SUBST(LIBLTDL) AC_SUBST(LIBLTDL)
AC_LIBTOOL_DLOPEN AC_LIBTOOL_DLOPEN
AC_PROG_LIBTOOL AC_PROG_LIBTOOL
AC_PROG_LEX
AC_PROG_YACC
# Checks for header files. # Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h]) AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h syslog.h])
ACX_PTHREAD ACX_PTHREAD
AC_PATH_XTRA AC_PATH_XTRA
@ -70,6 +72,7 @@ AC_FUNC_MEMCMP
AC_FUNC_MMAP AC_FUNC_MMAP
AC_FUNC_REALLOC AC_FUNC_REALLOC
AC_FUNC_SETPGRP AC_FUNC_SETPGRP
AC_FUNC_VPRINTF
AC_TYPE_SIGNAL AC_TYPE_SIGNAL
AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp]) AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul pow strcasecmp])
AC_FUNC_STAT AC_FUNC_STAT

View file

@ -11,15 +11,14 @@
rename streams/contexts rename streams/contexts
- more complete pactl - more complete pactl
- add sample directory - add sample directory
- config file for command line arguments
- option to use default fragment size on alsa drivers - option to use default fragment size on alsa drivers
- lazy sample cache - lazy sample cache
- per-channel volume - per-channel volume
- merge pa_context_connect_* - merge pa_context_connect_*
- input latency - input latency
- fix tcp/native - fix tcp/native
- suid
- add volume to create_stream command in native protocol - add volume to create_stream command in native protocol
- udp based protocol
** later *** ** later ***
- xmlrpc/http - xmlrpc/http

View file

@ -24,23 +24,24 @@ modlibdir=$(libdir)/polypaudio-@PA_MAJORMINOR@
AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS) AM_CFLAGS=-D_GNU_SOURCE -I$(top_srcdir) $(PTHREAD_CFLAGS)
AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\"
AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/polypaudio.pa\" AM_CFLAGS+=-DDEFAULT_SCRIPT_FILE=\"$(polypconfdir)/default.pa\"
AM_CFLAGS+=-DDEFAULT_CONFIG_FILE=\"$(polypconfdir)/config\"
AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\" AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"
AM_LDADD=$(PTHREAD_LIBS) -lm AM_LDADD=$(PTHREAD_LIBS) -lm
AM_LIBADD=$(PTHREAD_LIBS) -lm AM_LIBADD=$(PTHREAD_LIBS) -lm
EXTRA_DIST = polypaudio.pa depmod.py esdcompat.sh.in EXTRA_DIST = default.pa config depmod.py esdcompat.sh.in
bin_PROGRAMS = polypaudio pacat pactl pamodinfo bin_PROGRAMS = polypaudio pacat pactl
bin_SCRIPTS = esdcompat.sh bin_SCRIPTS = esdcompat.sh
noinst_PROGRAMS = \ noinst_PROGRAMS = \
mainloop-test \ mainloop-test \
pacat-simple \ pacat-simple \
parec-simple \ parec-simple \
cpulimit-test \ cpulimit-test \
cpulimit-test2 cpulimit-test2
polypconf_DATA=polypaudio.pa polypconf_DATA=default.pa config
BUILT_SOURCES=polyplib-version.h BUILT_SOURCES=polyplib-version.h
@ -153,19 +154,15 @@ polypaudio_SOURCES = idxset.c idxset.h \
cpulimit.c cpulimit.h \ cpulimit.c cpulimit.h \
log.c log.h \ log.c log.h \
gcc-printf.h \ gcc-printf.h \
modinfo.c modinfo.h modinfo.c modinfo.h \
conf.c conf.h \
dumpmodules.c dumpmodules.h
polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
polypaudio_INCLUDES = $(INCLTDL) polypaudio_INCLUDES = $(INCLTDL)
polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(LEXLIB)
polypaudio_LDFLAGS=-export-dynamic polypaudio_LDFLAGS=-export-dynamic
pamodinfo_SOURCES = log.c log.h pamodinfo.c pamodinfo.h modinfo.c modinfo.h util.c util.h xmalloc.c xmalloc.h
pamodinfo_CFLAGS = $(AM_CFLAGS)
pamodinfo_INCLUDES = $(INCLTDL)
pamodinfo_LDADD = $(AM_LDADD) $(LIBLTDL)
pamodinfo_LDFLAGS=-export-dynamic
libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h
libprotocol_simple_la_LDFLAGS = -avoid-version libprotocol_simple_la_LDFLAGS = -avoid-version
libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la
@ -535,3 +532,7 @@ esdcompat.sh: esdcompat.sh.in Makefile
sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \
-e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \
-e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@ -e 's,@POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@
install-exec-hook:
chown root:root $(DESTDIR)$(bindir)/polypaudio
chmod u+s $(DESTDIR)$(bindir)/polypaudio

View file

@ -35,29 +35,48 @@
#include "strbuf.h" #include "strbuf.h"
#include "xmalloc.h" #include "xmalloc.h"
#define ENV_CONFIG_FILE "POLYP_CONFIG" enum {
ARG_HELP = 256,
ARG_VERSION,
ARG_DUMP_CONF,
ARG_DUMP_MODULES,
ARG_DAEMONIZE,
ARG_FAIL,
ARG_VERBOSE,
ARG_HIGH_PRIORITY,
ARG_STAY_ROOT,
ARG_DISALLOW_MODULE_LOADING,
ARG_EXIT_IDLE_TIME,
ARG_MODULE_IDLE_TIME,
ARG_LOG_TARGET,
ARG_LOAD,
ARG_FILE,
ARG_DL_SEARCH_PATH,
};
char* config_file(void) { static struct option long_options[] = {
char *p, *h; {"help", 0, 0, ARG_HELP},
{"version", 0, 0, ARG_VERSION},
{"dump-conf", 0, 0, ARG_DUMP_CONF},
{"dump-modules", 0, 0, ARG_DUMP_MODULES},
{"daemonize", 2, 0, ARG_DAEMONIZE},
{"fail", 2, 0, ARG_FAIL},
{"verbose", 2, 0, ARG_VERBOSE},
{"high-priority", 2, 0, ARG_HIGH_PRIORITY},
{"stay-root", 2, 0, ARG_STAY_ROOT},
{"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING},
{"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME},
{"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME},
{"log-target", 1, 0, ARG_LOG_TARGET},
{"load", 1, 0, ARG_LOAD},
{"file", 1, 0, ARG_FILE},
{"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH},
{NULL, 0, 0, 0}
};
if ((p = getenv(ENV_CONFIG_FILE)))
return pa_xstrdup(p);
if ((h = getenv("HOME"))) {
struct stat st;
p = pa_sprintf_malloc("%s/.polypaudio", h);
if (stat(p, &st) >= 0)
return p;
pa_xfree(p);
}
return pa_xstrdup(DEFAULT_CONFIG_FILE);
}
void pa_cmdline_help(const char *argv0) { void pa_cmdline_help(const char *argv0) {
const char *e; const char *e;
char *cfg = config_file();
if ((e = strrchr(argv0, '/'))) if ((e = strrchr(argv0, '/')))
e++; e++;
@ -65,133 +84,170 @@ void pa_cmdline_help(const char *argv0) {
e = argv0; e = argv0;
printf("%s [options]\n" printf("%s [options]\n"
" -r Try to set high process priority (only available as root)\n" " -h, --help Show this help\n"
" -R Don't drop root if SETUID root\n" " --version Show version\n"
" -L MODULE Load the specified plugin module with the specified argument\n" " --dump-conf Dump default configuration\n"
" -F FILE Run the specified script\n" " --dump-modules Dump list of available modules\n\n"
" -C Open a command line on the running TTY\n"
" -n Don't load configuration file (%s)\n"
" -D Daemonize after loading the modules\n"
" -d Disallow module loading after startup\n"
" -f Dont quit when the startup fails\n"
" -v Verbose startup\n"
" -X SECS Terminate the daemon after the last client quit and this time passed\n"
" -h Show this help\n"
" -l TARGET Specify the log target (syslog, stderr, auto)\n"
" -p DIR Append a directory to the search path for dynamic modules\n"
" -V Show version\n", e, cfg);
pa_xfree(cfg); " -D, --daemonize[=BOOL] Daemonize after startup\n"
" --fail[=BOOL] Quit when startup fails\n"
" --verbose[=BOOL] Be slightly more verbose\n"
" --high-priority[=BOOL] Try to set high process priority (only available as root)\n"
" --stay-root[=BOOL] Don't drop root if SETUID root\n"
" --disallow-module-loading[=BOOL] Disallow module loading after startup\n"
" --exit-idle-time=SECS Terminate the daemon when idle and this time passed\n"
" --module-idle-time=SECS Unload autoloaded modules when idle and this time passed\n"
" --log-target={auto,syslog,stderr} Specify the log target\n"
" -p, --dl-search-path=PATH Set the search path for dynamic shared objects (plugins)\n\n"
" -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with the specified argument\n"
" -F, --file=FILENAME Run the specified script\n"
" -C Open a command line on the running TTY after startup\n\n"
" -n Don't load default script file\n", e);
} }
struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { int pa_cmdline_parse(struct pa_conf *conf, int argc, char *const argv [], int *d) {
char c, *cfg;
struct pa_cmdline *cmdline = NULL;
struct pa_strbuf *buf = NULL; struct pa_strbuf *buf = NULL;
int no_default_config_file = 0; int c;
assert(argc && argv); assert(conf && argc && argv);
cmdline = pa_xmalloc(sizeof(struct pa_cmdline));
cmdline->daemonize =
cmdline->help =
cmdline->verbose =
cmdline->high_priority =
cmdline->stay_root =
cmdline->version =
cmdline->disallow_module_loading = 0;
cmdline->fail = cmdline->auto_log_target = 1;
cmdline->quit_after_last_client_time = -1;
cmdline->log_target = -1;
cmdline->dl_search_path = NULL;
buf = pa_strbuf_new(); buf = pa_strbuf_new();
assert(buf); assert(buf);
if (conf->script_commands)
pa_strbuf_puts(buf, conf->script_commands);
while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:l:p:")) != -1) { while ((c = getopt_long(argc, argv, "L:F:ChDnp:", long_options, NULL)) != -1) {
switch (c) { switch (c) {
case ARG_HELP:
case 'h':
conf->help = 1;
break;
case ARG_VERSION:
conf->version = 1;
break;
case ARG_DUMP_CONF:
conf->dump_conf = 1;
break;
case ARG_DUMP_MODULES:
conf->dump_modules = 1;
break;
case ARG_LOAD:
case 'L': case 'L':
pa_strbuf_printf(buf, "load %s\n", optarg); pa_strbuf_printf(buf, "load %s\n", optarg);
break; break;
case ARG_FILE:
case 'F': case 'F':
pa_strbuf_printf(buf, ".include %s\n", optarg); pa_strbuf_printf(buf, ".include %s\n", optarg);
break; break;
case 'C': case 'C':
pa_strbuf_puts(buf, "load module-cli\n"); pa_strbuf_puts(buf, "load module-cli\n");
break; break;
case ARG_DAEMONIZE:
case 'D': case 'D':
cmdline->daemonize = 1; if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --daemonize expects boolean argument\n");
goto fail;
}
break; break;
case 'h':
cmdline->help = 1; case ARG_FAIL:
if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --fail expects boolean argument\n");
goto fail;
}
break; break;
case 'f':
cmdline->fail = 0; case ARG_VERBOSE:
if ((conf->verbose = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --verbose expects boolean argument\n");
goto fail;
}
break; break;
case 'v':
cmdline->verbose = 1; case ARG_HIGH_PRIORITY:
if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --high-priority expects boolean argument\n");
goto fail;
}
break; break;
case 'r':
cmdline->high_priority = 1; case ARG_STAY_ROOT:
if ((conf->stay_root = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
pa_log(__FILE__": --stay-root expects boolean argument\n");
goto fail;
}
break; break;
case 'R':
cmdline->stay_root = 1; case ARG_DISALLOW_MODULE_LOADING:
break; if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
case 'V': pa_log(__FILE__": --disallow-module-loading expects boolean argument\n");
cmdline->version = 1; goto fail;
break; }
case 'n':
no_default_config_file = 1;
break;
case 'd':
cmdline->disallow_module_loading = 1;
break;
case 'X':
cmdline->quit_after_last_client_time = atoi(optarg);
break; break;
case 'p': case 'p':
if (cmdline->dl_search_path) case ARG_DL_SEARCH_PATH:
pa_xfree(cmdline->dl_search_path); pa_xfree(conf->dl_search_path);
cmdline->dl_search_path = pa_xstrdup(optarg); conf->dl_search_path = *optarg ? pa_xstrdup(optarg) : NULL;
break; break;
case 'l':
case 'n':
pa_xfree(conf->default_script_file);
conf->default_script_file = NULL;
break;
case ARG_LOG_TARGET:
if (!strcmp(optarg, "syslog")) { if (!strcmp(optarg, "syslog")) {
cmdline->auto_log_target = 0; conf->auto_log_target = 0;
cmdline->log_target = PA_LOG_SYSLOG; conf->log_target = PA_LOG_SYSLOG;
} else if (!strcmp(optarg, "stderr")) { } else if (!strcmp(optarg, "stderr")) {
cmdline->auto_log_target = 0; conf->auto_log_target = 0;
cmdline->log_target = PA_LOG_STDERR; conf->log_target = PA_LOG_STDERR;
} else if (!strcmp(optarg, "auto")) } else if (!strcmp(optarg, "auto"))
cmdline->auto_log_target = 1; conf->auto_log_target = 1;
else { else {
pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n"); pa_log(__FILE__": Invalid log target: use either 'syslog', 'stderr' or 'auto'.\n");
goto fail; goto fail;
} }
break; break;
case ARG_EXIT_IDLE_TIME:
conf->exit_idle_time = atoi(optarg);
break;
case ARG_MODULE_IDLE_TIME:
conf->module_idle_time = atoi(optarg);
break;
default: default:
goto fail; goto fail;
} }
} }
if (!no_default_config_file) { pa_xfree(conf->script_commands);
cfg = config_file(); conf->script_commands = pa_strbuf_tostring_free(buf);
pa_strbuf_printf(buf, ".include %s\n", cfg);
pa_xfree(cfg); if (!conf->script_commands) {
pa_xfree(conf->script_commands);
conf->script_commands = NULL;
} }
cmdline->cli_commands = pa_strbuf_tostring_free(buf); *d = optind;
return cmdline;
return 0;
fail: fail:
if (cmdline)
pa_cmdline_free(cmdline);
if (buf) if (buf)
pa_strbuf_free(buf); pa_strbuf_free(buf);
return NULL;
} return -1;
void pa_cmdline_free(struct pa_cmdline *cmd) {
assert(cmd);
pa_xfree(cmd->cli_commands);
pa_xfree(cmd->dl_search_path);
pa_xfree(cmd);
} }

View file

@ -22,26 +22,9 @@
USA. USA.
***/ ***/
#include "log.h" #include "conf.h"
struct pa_cmdline { int pa_cmdline_parse(struct pa_conf*c, int argc, char *const argv [], int *d);
int daemonize,
help,
fail,
verbose,
high_priority,
stay_root,
version,
disallow_module_loading,
quit_after_last_client_time,
auto_log_target;
char *cli_commands;
char *dl_search_path;
enum pa_log_target log_target;
};
struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []);
void pa_cmdline_free(struct pa_cmdline *cmd);
void pa_cmdline_help(const char *argv0); void pa_cmdline_help(const char *argv0);

285
polyp/conf.c Normal file
View file

@ -0,0 +1,285 @@
/* $Id$ */
/***
This file is part of polypaudio.
polypaudio is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/stat.h>
#include "conf.h"
#include "util.h"
#include "xmalloc.h"
#include "strbuf.h"
static const struct pa_conf default_conf = {
.help = 0,
.daemonize = 0,
.dump_conf = 0,
.dump_modules = 0,
.fail = 1,
.verbose = 0,
.high_priority = 0,
.stay_root = 0,
.version = 0,
.disallow_module_loading = 0,
.exit_idle_time = -1,
.module_idle_time = 20,
.auto_log_target = 1,
.script_commands = NULL,
.dl_search_path = NULL,
.default_script_file = NULL,
.log_target = PA_LOG_SYSLOG,
};
#define ENV_SCRIPT_FILE "POLYP_SCRIPT"
#define ENV_CONFIG_FILE "POLYP_CONFIG"
#ifndef DEFAULT_SCRIPT_FILE
#define DEFAULT_SCRIPT_FILE "/etc/polypaudio/default.pa"
#endif
#ifndef DEFAULT_CONFIG_FILE
#define DEFAULT_CONFIG_FILE "/etc/polypaudio/config"
#endif
#define DEFAULT_SCRIPT_FILE_LOCAL ".polypaudio.pa"
#define DEFAULT_CONFIG_FILE_LOCAL ".polypaudio.conf"
char* default_file(const char *envvar, const char *global, const char *local) {
char *p, *h;
assert(envvar && global && local);
if ((p = getenv(envvar)))
return pa_xstrdup(p);
if ((h = getenv("HOME"))) {
struct stat st;
p = pa_sprintf_malloc("%s/%s", h, local);
if (stat(p, &st) >= 0)
return p;
pa_xfree(p);
}
return pa_xstrdup(global);
}
struct pa_conf* pa_conf_new(void) {
struct pa_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
c->default_script_file = default_file(ENV_SCRIPT_FILE, DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_LOCAL);
return c;
}
void pa_conf_free(struct pa_conf *c) {
assert(c);
pa_xfree(c->script_commands);
pa_xfree(c->dl_search_path);
pa_xfree(c->default_script_file);
pa_xfree(c);
}
#define WHITESPACE " \t\n"
#define COMMENTS "#;\n"
#define PARSE_BOOLEAN(t, v) \
do { \
if (!strcmp(lvalue, t)) { \
int b; \
if ((b = pa_parse_boolean(rvalue)) < 0) \
goto fail; \
c->v = b; \
return 0; \
} \
} while (0)
#define PARSE_STRING(t, v) \
do { \
if (!strcmp(lvalue, t)) { \
pa_xfree(c->v); \
c->v = *rvalue ? pa_xstrdup(rvalue) : NULL; \
return 0; \
} \
} while (0)
#define PARSE_INTEGER(t, v) \
do { \
if (!strcmp(lvalue, t)) { \
char *x = NULL; \
int i = strtol(rvalue, &x, 0); \
if (!x || *x) \
goto fail; \
c->v = i; \
return 0; \
} \
} while(0)
static int next_assignment(struct pa_conf *c, char *lvalue, char *rvalue, unsigned n) {
PARSE_BOOLEAN("daemonize", daemonize);
PARSE_BOOLEAN("fail", fail);
PARSE_BOOLEAN("verbose", verbose);
PARSE_BOOLEAN("high-priority", high_priority);
PARSE_BOOLEAN("stay-root", stay_root);
PARSE_BOOLEAN("disallow-module-loading", disallow_module_loading);
PARSE_INTEGER("exit-idle-time", exit_idle_time);
PARSE_INTEGER("module-idle-time", module_idle_time);
PARSE_STRING("dl-search-path", dl_search_path);
PARSE_STRING("default-script-file", default_script_file);
if (!strcmp(lvalue, "log-target")) {
if (!strcmp(rvalue, "auto"))
c->auto_log_target = 1;
else if (!strcmp(rvalue, "syslog")) {
c->auto_log_target = 0;
c->log_target = PA_LOG_SYSLOG;
} else if (!strcmp(rvalue, "stderr")) {
c->auto_log_target = 0;
c->log_target = PA_LOG_STDERR;
} else
goto fail;
return 0;
}
fail:
pa_log(__FILE__": line %u: parse error.\n", n);
return -1;
}
#undef PARSE_STRING
#undef PARSE_BOOLEAN
static int in_string(char c, const char *s) {
for (; *s; s++)
if (*s == c)
return 1;
return 0;
}
static char *strip(char *s) {
char *b = s+strspn(s, WHITESPACE);
char *e, *l = NULL;
for (e = b; *e; e++)
if (!in_string(*e, WHITESPACE))
l = e;
if (l)
*(l+1) = 0;
return b;
}
static int parse_line(struct pa_conf *conf, char *l, unsigned n) {
char *e, *c, *b = l+strspn(l, WHITESPACE);
if ((c = strpbrk(b, COMMENTS)))
*c = 0;
if (!*b)
return 0;
if (!(e = strchr(b, '='))) {
pa_log(__FILE__": line %u: missing '='.\n", n);
return -1;
}
*e = 0;
e++;
return next_assignment(conf, strip(b), strip(e), n);
}
int pa_conf_load(struct pa_conf *c, const char *filename) {
FILE *f;
int r = 0;
unsigned n = 0;
char *def = NULL;
assert(c);
if (!filename)
filename = def = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL);
if (!(f = fopen(filename, "r"))) {
if (errno != ENOENT)
pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s\n", filename, strerror(errno));
goto finish;
}
while (!feof(f)) {
char l[256];
if (!fgets(l, sizeof(l), f)) {
if (!feof(f))
pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s\n", filename, strerror(errno));
break;
}
if (parse_line(c, l, ++n) < 0)
r = -1;
}
finish:
if (f)
fclose(f);
pa_xfree(def);
return r;
}
char *pa_conf_dump(struct pa_conf *c) {
struct pa_strbuf *s = pa_strbuf_new();
char *d;
d = default_file(ENV_CONFIG_FILE, DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_LOCAL);
pa_strbuf_printf(s, "### Default configuration file: %s ###\n\n", d);
pa_strbuf_printf(s, "verbose = %i\n", !!c->verbose);
pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize);
pa_strbuf_printf(s, "fail = %i\n", !!c->fail);
pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority);
pa_strbuf_printf(s, "stay-root = %i\n", !!c->stay_root);
pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading);
pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time);
pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time);
pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : "");
pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file);
pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr"));
pa_strbuf_printf(s, "\n### EOF ###\n");
pa_xfree(d);
return pa_strbuf_tostring_free(s);
}

51
polyp/conf.h Normal file
View file

@ -0,0 +1,51 @@
#ifndef fooconfhfoo
#define fooconfhfoo
/* $Id$ */
/***
This file is part of polypaudio.
polypaudio is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#include "log.h"
struct pa_conf {
int help,
version,
dump_conf,
dump_modules,
daemonize,
fail,
verbose,
high_priority,
stay_root,
disallow_module_loading,
exit_idle_time,
module_idle_time,
auto_log_target;
char *script_commands, *dl_search_path, *default_script_file;
enum pa_log_target log_target;
};
struct pa_conf* pa_conf_new(void);
void pa_conf_free(struct pa_conf*c);
int pa_conf_load(struct pa_conf *c, const char *filename);
char *pa_conf_dump(struct pa_conf *c);
#endif

61
polyp/config Normal file
View file

@ -0,0 +1,61 @@
# $Id$
#
# This file is part of polypaudio.
#
# polypaudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# polypaudio is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with polypaudio; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
## Configuration file for polypaudio. Default values are commented out.
## Use either ; or # for commenting
# Extra verbositiy
; verbose = 0
## Daemonize after startup
; daemonize = 0
## Quit if startup fails
; fail = 1
## Renice the daemon to level -15 and try to get SCHED_FIFO
## scheduling. This a good idea if you hear annyoing noise in the
## playback. However, this is a certain security issue.
; high-priority = 0
## Don't drop root rights on startup if called SUID root.
; stay-root = 0
## Disallow module loading after startup
; disallow-module-loading = 0
## Terminate the daemon after the last client quit and this time
## passed. Use a negative value to disable this feature.
; exit-idle-time = -1
## Unload autoloaded modules after being idle for this time
module-idle-time = 20
## The path were to look for dynamic shared objects (DSOs aka plugins).
## Specify an empty string for the default search path.
; dl-search-path =
## The default script file to load. Specify an empty string for not
## loading a default script file
; default-script-file = /etc/polyp/default.pa
## The default log target. Use either "stderr", "syslog" or
## "auto". The latter is equivalent to "sylog" in case daemonize is
## true, otherwise to "stderr".
; log-target = auto

View file

@ -61,7 +61,6 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
c->default_sample_spec.rate = 44100; c->default_sample_spec.rate = 44100;
c->default_sample_spec.channels = 2; c->default_sample_spec.channels = 2;
c->auto_unload_time = 20;
c->auto_unload_event = NULL; c->auto_unload_event = NULL;
c->subscription_defer_event = NULL; c->subscription_defer_event = NULL;
@ -73,7 +72,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
c->disallow_module_loading = 0; c->disallow_module_loading = 0;
c->quit_event = NULL; c->quit_event = NULL;
c->quit_after_last_client_time = -1;
c->exit_idle_time = -1;
c->module_idle_time = 20;
pa_check_for_sigpipe(); pa_check_for_sigpipe();
@ -129,10 +130,10 @@ static void quit_callback(struct pa_mainloop_api*m, struct pa_time_event *e, con
void pa_core_check_quit(struct pa_core *c) { void pa_core_check_quit(struct pa_core *c) {
assert(c); assert(c);
if (!c->quit_event && c->quit_after_last_client_time >= 0 && pa_idxset_ncontents(c->clients) == 0) { if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_ncontents(c->clients) == 0) {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
tv.tv_sec+= c->quit_after_last_client_time; tv.tv_sec+= c->exit_idle_time;
c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c); c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c);
} else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) { } else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) {
c->mainloop->time_free(c->quit_event); c->mainloop->time_free(c->quit_event);

View file

@ -38,7 +38,6 @@ struct pa_core {
char *default_source_name, *default_sink_name; char *default_source_name, *default_sink_name;
struct pa_sample_spec default_sample_spec; struct pa_sample_spec default_sample_spec;
int auto_unload_time;
struct pa_time_event *auto_unload_event; struct pa_time_event *auto_unload_event;
struct pa_defer_event *subscription_defer_event; struct pa_defer_event *subscription_defer_event;
@ -48,7 +47,7 @@ struct pa_core {
struct pa_memblock_stat *memblock_stat; struct pa_memblock_stat *memblock_stat;
int disallow_module_loading; int disallow_module_loading;
int quit_after_last_client_time; int exit_idle_time, module_idle_time;
struct pa_time_event *quit_event; struct pa_time_event *quit_event;
}; };

View file

@ -29,12 +29,11 @@
#include <stdio.h> #include <stdio.h>
#include <ltdl.h> #include <ltdl.h>
#include "dumpmodules.h"
#include "modinfo.h" #include "modinfo.h"
#define PREFIX "module-" #define PREFIX "module-"
static int verbose = 0;
static void short_info(const char *name, const char *path, struct pa_modinfo *i) { static void short_info(const char *name, const char *path, struct pa_modinfo *i) {
assert(name && i); assert(name && i);
printf("%-40s%s\n", name, i->description ? i->description : "n/a"); printf("%-40s%s\n", name, i->description ? i->description : "n/a");
@ -79,6 +78,7 @@ static void show_info(const char *name, const char *path, void (*info)(const cha
static int callback(const char *path, lt_ptr data) { static int callback(const char *path, lt_ptr data) {
const char *e; const char *e;
struct pa_conf *c = (data);
if ((e = (const char*) strrchr(path, '/'))) if ((e = (const char*) strrchr(path, '/')))
e++; e++;
@ -86,41 +86,16 @@ static int callback(const char *path, lt_ptr data) {
e = path; e = path;
if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1)) if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1))
show_info(e, path, verbose ? long_info : short_info); show_info(e, path, c->verbose ? long_info : short_info);
return 0; return 0;
} }
int main(int argc, char *argv[]) { void pa_dump_modules(struct pa_conf *c, int argc, char * const argv[]) {
int r = lt_dlinit(); if (argc > 0) {
char *path = NULL; int i;
int c; for (i = 0; i < argc; i++)
assert(r == 0); show_info(argv[i], NULL, long_info);
} else
while ((c = getopt(argc, argv, "p:v")) != -1) { lt_dlforeachfile(NULL, callback, c);
switch (c) {
case 'p':
path = optarg;
break;
case 'v':
verbose = 1;
break;
default:
return 1;
}
}
if (path)
lt_dlsetsearchpath(path);
#ifdef DLSEARCHPATH
else
lt_dlsetsearchpath(DLSEARCHPATH);
#endif
if (argc > optind)
show_info(argv[optind], NULL, long_info);
else
lt_dlforeachfile(NULL, callback, NULL);
lt_dlexit();
} }

29
polyp/dumpmodules.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef foodumpmoduleshfoo
#define foodumpmoduleshfoo
/* $Id*/
/***
This file is part of polypaudio.
polypaudio is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#include "conf.h"
void pa_dump_modules(struct pa_conf *c, int argc, char * const argv[]);
#endif

View file

@ -45,6 +45,8 @@
#include "xmalloc.h" #include "xmalloc.h"
#include "cpulimit.h" #include "cpulimit.h"
#include "log.h" #include "log.h"
#include "conf.h"
#include "dumpmodules.h"
static struct pa_mainloop *mainloop; static struct pa_mainloop *mainloop;
@ -99,40 +101,69 @@ static void close_pipe(int p[2]) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct pa_core *c; struct pa_core *c;
struct pa_cmdline *cmdline = NULL;
struct pa_strbuf *buf = NULL; struct pa_strbuf *buf = NULL;
struct pa_conf *conf;
char *s; char *s;
int r, retval = 1; int r, retval = 1, d = 0;
int daemon_pipe[2] = { -1, -1 }; int daemon_pipe[2] = { -1, -1 };
r = lt_dlinit();
assert(r == 0);
pa_log_set_ident("polypaudio"); pa_log_set_ident("polypaudio");
if (!(cmdline = pa_cmdline_parse(argc, argv))) { conf = pa_conf_new();
if (pa_conf_load(conf, NULL) < 0)
goto finish;
if (pa_cmdline_parse(conf, argc, argv, &d) < 0) {
pa_log(__FILE__": failed to parse command line.\n"); pa_log(__FILE__": failed to parse command line.\n");
goto finish; goto finish;
} }
pa_log_set_target(cmdline->auto_log_target ? PA_LOG_STDERR : cmdline->log_target, NULL); pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL);
if (cmdline->help) { if (conf->dl_search_path)
lt_dlsetsearchpath(conf->dl_search_path);
#ifdef DLSEARCHPATH
else
lt_dlsetsearchpath(DLSEARCHPATH);
#endif
if (conf->dump_modules) {
pa_dump_modules(conf, argc-d, argv+d);
retval = 0;
goto finish;
}
if (conf->dump_conf) {
char *s = pa_conf_dump(conf);
fputs(s, stdout);
pa_xfree(s);
retval = 0;
goto finish;
}
if (conf->help) {
pa_cmdline_help(argv[0]); pa_cmdline_help(argv[0]);
retval = 0; retval = 0;
goto finish; goto finish;
} }
if (cmdline->version) { if (conf->version) {
printf(PACKAGE_NAME" "PACKAGE_VERSION"\n"); printf(PACKAGE_NAME" "PACKAGE_VERSION"\n");
retval = 0; retval = 0;
goto finish; goto finish;
} }
if (cmdline->high_priority) if (conf->high_priority)
pa_raise_priority(); pa_raise_priority();
if (!cmdline->stay_root) if (!conf->stay_root)
drop_root(); drop_root();
if (cmdline->daemonize) { if (conf->daemonize) {
pid_t child; pid_t child;
if (pa_stdio_acquire() < 0) { if (pa_stdio_acquire() < 0) {
@ -168,7 +199,7 @@ int main(int argc, char *argv[]) {
daemon_pipe[0] = -1; daemon_pipe[0] = -1;
if (cmdline->auto_log_target) if (conf->auto_log_target)
pa_log_set_target(PA_LOG_SYSLOG, NULL); pa_log_set_target(PA_LOG_SYSLOG, NULL);
setsid(); setsid();
@ -178,15 +209,6 @@ int main(int argc, char *argv[]) {
close(1); close(1);
} }
r = lt_dlinit();
assert(r == 0);
if (cmdline->dl_search_path)
lt_dlsetsearchpath(cmdline->dl_search_path);
#ifdef DLSEARCHPATH
else
lt_dlsetsearchpath(DLSEARCHPATH);
#endif
pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t)); pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t));
@ -210,25 +232,28 @@ int main(int argc, char *argv[]) {
buf = pa_strbuf_new(); buf = pa_strbuf_new();
assert(buf); assert(buf);
r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose); if (conf->default_script_file)
pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail, &conf->verbose);
r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail, &conf->verbose);
pa_log(s = pa_strbuf_tostring_free(buf)); pa_log(s = pa_strbuf_tostring_free(buf));
pa_xfree(s); pa_xfree(s);
if (r < 0 && cmdline->fail) { if (r < 0 && conf->fail) {
pa_log(__FILE__": failed to initialize daemon.\n"); pa_log(__FILE__": failed to initialize daemon.\n");
if (cmdline->daemonize) if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
} else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) {
pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n"); pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n");
if (cmdline->daemonize) if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
} else { } else {
retval = 0; retval = 0;
if (cmdline->daemonize) if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval)); pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
c->disallow_module_loading = cmdline->disallow_module_loading; c->disallow_module_loading = conf->disallow_module_loading;
c->quit_after_last_client_time = cmdline->quit_after_last_client_time; c->exit_idle_time = conf->exit_idle_time;
c->module_idle_time = conf->module_idle_time;
pa_log(__FILE__": Daemon startup complete.\n"); pa_log(__FILE__": Daemon startup complete.\n");
if (pa_mainloop_run(mainloop, &retval) < 0) if (pa_mainloop_run(mainloop, &retval) < 0)
@ -242,16 +267,16 @@ int main(int argc, char *argv[]) {
pa_signal_done(); pa_signal_done();
pa_mainloop_free(mainloop); pa_mainloop_free(mainloop);
lt_dlexit();
pa_log(__FILE__": Daemon terminated.\n"); pa_log(__FILE__": Daemon terminated.\n");
finish: finish:
if (cmdline) if (conf)
pa_cmdline_free(cmdline); pa_conf_free(conf);
close_pipe(daemon_pipe); close_pipe(daemon_pipe);
lt_dlexit();
return retval; return retval;
} }

View file

@ -36,6 +36,7 @@
#include "sink.h" #include "sink.h"
#include "source.h" #include "source.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "util.h"
struct pa_modargs; struct pa_modargs;
@ -229,6 +230,7 @@ int pa_modargs_get_value_s32(struct pa_modargs *ma, const char *key, int32_t *va
int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value) { int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *value) {
const char *v; const char *v;
int r;
assert(ma && key && value); assert(ma && key && value);
if (!(v = pa_modargs_get_value(ma, key, NULL))) if (!(v = pa_modargs_get_value(ma, key, NULL)))
@ -237,13 +239,10 @@ int pa_modargs_get_value_boolean(struct pa_modargs *ma, const char *key, int *va
if (!*v) if (!*v)
return -1; return -1;
if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on")) if ((r = pa_parse_boolean(v)) < 0)
*value = 1;
else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off"))
*value = 0;
else
return -1; return -1;
*value = r;
return 0; return 0;
} }

View file

@ -38,7 +38,7 @@
#define PA_SYMBOL_INIT "pa__init" #define PA_SYMBOL_INIT "pa__init"
#define PA_SYMBOL_DONE "pa__done" #define PA_SYMBOL_DONE "pa__done"
#define UNLOAD_POLL_TIME 10 #define UNLOAD_POLL_TIME 2
static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) { static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, const struct timeval *tv, void *userdata) {
struct pa_core *c = userdata; struct pa_core *c = userdata;
@ -193,7 +193,7 @@ static int unused_callback(void *p, uint32_t index, int *del, void *userdata) {
time_t *now = userdata; time_t *now = userdata;
assert(p && del && now); assert(p && del && now);
if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->auto_unload_time <= *now) { if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) {
pa_module_free(m); pa_module_free(m);
*del = 1; *del = 1;
} }

View file

@ -286,7 +286,10 @@ static void stream_get_latency_callback(struct pa_stream *s, const struct pa_lat
return; return;
} }
fprintf(stderr, "Current latency is %f usecs.\n", (float) (i->buffer_usec+i->sink_usec+i->transport_usec)); fprintf(stderr, "Latency: buffer: %0.0f usec; sink: %0.0f usec; transport: %0.0f usec; total: %0.0f usec; synchronized clocks: %s.\n",
(float) i->buffer_usec, (float) i->sink_usec, (float) i->transport_usec,
(float) (i->buffer_usec+i->sink_usec+i->transport_usec),
i->synchronized_clocks ? "yes" : "no");
} }
/* Someone requested that the latency is shown */ /* Someone requested that the latency is shown */

View file

@ -144,7 +144,16 @@ struct pa_latency_info {
pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */ pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */
pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to the daemon. \since 0.5 */ pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to the daemon. \since 0.5 */
int playing; /**< Non-zero when the stream is currently playing */ int playing; /**< Non-zero when the stream is currently playing */
uint32_t queue_length; /**< Queue size in bytes. */ uint32_t queue_length; /**< Queue size in bytes. */
int synchronized_clocks; /**< Non-zero if the local and the
* remote machine have synchronized
* clocks. If synchronized clocks are
* detected transport_usec becomes much
* more reliable. However, the code that
* detects synchronized clocks is very
* limited und unreliable itself. \since
* 0.5 */
struct timeval timestamp; /**< The time when this latency info was current */
}; };
PA_C_DECL_END PA_C_DECL_END

View file

@ -347,12 +347,18 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) {
/* local and remote seem to have synchronized clocks */ /* local and remote seem to have synchronized clocks */
i.transport_usec = pa_timeval_diff(&remote, &local); i.transport_usec = pa_timeval_diff(&remote, &local);
else i.synchronized_clocks = 1;
i.timestamp = remote;
} else {
/* clocks are not synchronized, let's estimate latency then */ /* clocks are not synchronized, let's estimate latency then */
i.transport_usec = pa_timeval_diff(&now, &local)/2; i.transport_usec = pa_timeval_diff(&now, &local)/2;
i.synchronized_clocks = 0;
i.timestamp = local;
pa_timeval_add(&i.timestamp, i.transport_usec);
}
if (o->callback) { if (o->callback) {
void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback; void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback;

View file

@ -101,15 +101,15 @@ int pa_socket_low_delay(int fd) {
} }
int pa_socket_tcp_low_delay(int fd) { int pa_socket_tcp_low_delay(int fd) {
int ret, tos; int ret, tos, on;
assert(fd >= 0); assert(fd >= 0);
ret = pa_socket_low_delay(fd); ret = pa_socket_low_delay(fd);
/* on = 1; */ on = 1;
/* if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) */ if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
/* ret = -1; */ ret = -1;
tos = IPTOS_LOWDELAY; tos = IPTOS_LOWDELAY;
if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0) if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
@ -122,10 +122,10 @@ int pa_socket_tcp_low_delay(int fd) {
int pa_socket_set_rcvbuf(int fd, size_t l) { int pa_socket_set_rcvbuf(int fd, size_t l) {
assert(fd >= 0); assert(fd >= 0);
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { /* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { */
pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); /* pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */
return -1; /* return -1; */
} /* } */
return 0; return 0;
} }
@ -133,10 +133,10 @@ int pa_socket_set_rcvbuf(int fd, size_t l) {
int pa_socket_set_sndbuf(int fd, size_t l) { int pa_socket_set_sndbuf(int fd, size_t l) {
assert(fd >= 0); assert(fd >= 0);
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { /* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { */
pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); /* pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */
return -1; /* return -1; */
} /* } */
return 0; return 0;
} }

View file

@ -268,6 +268,22 @@ pa_usec_t pa_age(const struct timeval *tv) {
return pa_timeval_diff(&now, tv); return pa_timeval_diff(&now, tv);
} }
void pa_timeval_add(struct timeval *tv, pa_usec_t v) {
unsigned long secs;
assert(tv);
secs = (v/1000000);
tv->tv_sec += (unsigned long) secs;
v -= secs*1000000;
tv->tv_usec += v;
while (tv->tv_usec >= 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
#define NICE_LEVEL (-15) #define NICE_LEVEL (-15)
void pa_raise_priority(void) { void pa_raise_priority(void) {
@ -347,3 +363,13 @@ char *pa_path_get_filename(const char *p) {
return (char*) p; return (char*) p;
} }
int pa_parse_boolean(const char *v) {
if (!strcmp(v, "1") || !strcasecmp(v, "yes") || !strcasecmp(v, "y") || !strcasecmp(v, "on"))
return 1;
else if (!strcmp(v, "0") || !strcasecmp(v, "no") || !strcasecmp(v, "n") || !strcasecmp(v, "off"))
return 0;
return -1;
}

View file

@ -50,10 +50,13 @@ char *pa_path_get_filename(const char *p);
pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b);
int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); int pa_timeval_cmp(const struct timeval *a, const struct timeval *b);
pa_usec_t pa_age(const struct timeval *tv); pa_usec_t pa_age(const struct timeval *tv);
void pa_timeval_add(struct timeval *tv, pa_usec_t v);
void pa_raise_priority(void); void pa_raise_priority(void);
void pa_reset_priority(void); void pa_reset_priority(void);
int pa_fd_set_cloexec(int fd, int b); int pa_fd_set_cloexec(int fd, int b);
int pa_parse_boolean(const char *s);
#endif #endif