Merge branch 'master' into dbus-work

Conflicts:
	src/daemon/daemon-conf.c
	src/daemon/daemon-conf.h
	src/daemon/main.c
	src/pulsecore/dbus-util.h
This commit is contained in:
Tanu Kaskinen 2009-06-29 18:35:06 +03:00
commit 0bc538b08c
207 changed files with 33341 additions and 18718 deletions

View file

@ -39,6 +39,7 @@
#ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
@ -51,12 +52,13 @@ int setresgid(gid_t r, gid_t e, gid_t s);
int setresuid(uid_t r, uid_t e, uid_t s);
#endif
#ifdef HAVE_GETUID
/* Drop root rights when called SUID root */
void pa_drop_root(void) {
uid_t uid = getuid();
#ifdef HAVE_GETUID
uid_t uid;
uid = getuid();
if (uid == 0 || geteuid() != 0)
return;
@ -73,90 +75,19 @@ void pa_drop_root(void) {
pa_assert_se(getuid() == uid);
pa_assert_se(geteuid() == uid);
}
#else
void pa_drop_root(void) {
}
#endif
#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H)
/* Limit permitted capabilities set to CAPSYS_NICE */
void pa_limit_caps(void) {
cap_t caps;
cap_value_t nice_cap = CAP_SYS_NICE;
pa_assert_se(caps = cap_init());
pa_assert_se(cap_clear(caps) == 0);
pa_assert_se(cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET) == 0);
pa_assert_se(cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET) == 0);
if (cap_set_proc(caps) < 0)
/* Hmm, so we couldn't limit our caps, which probably means we
* hadn't any in the first place, so let's just make sure of
* that */
pa_drop_caps();
else
pa_log_info(_("Limited capabilities successfully to CAP_SYS_NICE."));
pa_assert_se(cap_free(caps) == 0);
pa_assert_se(prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0);
}
/* Drop all capabilities, effectively becoming a normal user */
void pa_drop_caps(void) {
cap_t caps;
#ifndef __OPTIMIZE__
/* Valgrind doesn't not know set_caps, so we bypass it here -- but
* only in development builds.*/
if (pa_in_valgrind() && !pa_have_caps())
return;
#endif
#ifdef HAVE_SYS_PRCTL_H
pa_assert_se(prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) == 0);
pa_assert_se(caps = cap_init());
pa_assert_se(cap_clear(caps) == 0);
pa_assert_se(cap_set_proc(caps) == 0);
pa_assert_se(cap_free(caps) == 0);
pa_assert_se(!pa_have_caps());
}
pa_bool_t pa_have_caps(void) {
cap_t caps;
cap_flag_value_t flag = CAP_CLEAR;
#ifdef __OPTIMIZE__
pa_assert_se(caps = cap_get_proc());
#else
if (!(caps = cap_get_proc()))
return FALSE;
#endif
pa_assert_se(cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0);
pa_assert_se(cap_free(caps) == 0);
return flag == CAP_SET;
}
#else
/* NOOPs in case capabilities are not available. */
void pa_limit_caps(void) {
}
void pa_drop_caps(void) {
pa_drop_root();
}
pa_bool_t pa_have_caps(void) {
return FALSE;
}
#ifdef HAVE_SYS_CAPABILITY_H
{
cap_t caps;
pa_assert_se(caps = cap_init());
pa_assert_se(cap_clear(caps) == 0);
pa_assert_se(cap_set_proc(caps) == 0);
pa_assert_se(cap_free(caps) == 0);
}
#endif
}

View file

@ -25,8 +25,5 @@
#include <pulsecore/macro.h>
void pa_drop_root(void);
void pa_drop_caps(void);
void pa_limit_caps(void);
pa_bool_t pa_have_caps(void);
#endif

View file

@ -31,6 +31,7 @@
#include <pulse/xmalloc.h>
#include <pulse/i18n.h>
#include <pulse/util.h>
#include <pulsecore/core-util.h>
#include <pulsecore/strbuf.h>
@ -109,15 +110,8 @@ static const struct option long_options[] = {
};
void pa_cmdline_help(const char *argv0) {
const char *e;
pa_assert(argv0);
if ((e = strrchr(argv0, '/')))
e++;
else
e = argv0;
printf(_("%s [options]\n\n"
"COMMANDS:\n"
" -h, --help Show this help\n"
@ -172,7 +166,8 @@ void pa_cmdline_help(const char *argv0) {
" -C Open a command line on the running TTY\n"
" after startup\n\n"
" -n Don't load default script file\n"), e);
" -n Don't load default script file\n"),
pa_path_get_filename(argv0));
}
int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) {

View file

@ -24,13 +24,14 @@
#endif
#include <pulse/error.h>
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core-util.h>
#include <pulsecore/core-error.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/rtclock.h>
#include "cpulimit.h"
@ -125,7 +126,7 @@ static void signal_handler(int sig) {
char t[256];
#endif
now = pa_rtclock_usec();
now = pa_rtclock_now();
elapsed = now - last_time;
#ifdef PRINT_CPU_LOAD
@ -184,7 +185,7 @@ int pa_cpu_limit_init(pa_mainloop_api *m) {
pa_assert(the_pipe[1] == -1);
pa_assert(!installed);
last_time = pa_rtclock_usec();
last_time = pa_rtclock_now();
/* Prepare the main loop pipe */
if (pipe(the_pipe) < 0) {

View file

@ -60,7 +60,7 @@ static const pa_daemon_conf default_conf = {
.fail = TRUE,
.high_priority = TRUE,
.nice_level = -11,
.realtime_scheduling = FALSE,
.realtime_scheduling = TRUE,
.realtime_priority = 5, /* Half of JACK's default rtprio */
.disallow_module_loading = FALSE,
.disallow_exit = FALSE,
@ -88,6 +88,7 @@ static const pa_daemon_conf default_conf = {
#endif
.no_cpu_limit = FALSE,
.disable_shm = FALSE,
.lock_memory = FALSE,
.default_n_fragments = 4,
.default_fragment_size_msec = 25,
.default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 },
@ -484,6 +485,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "no-cpu-limit", pa_config_parse_bool, &c->no_cpu_limit, NULL },
{ "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL },
{ "flat-volumes", pa_config_parse_bool, &c->flat_volumes, NULL },
{ "lock-memory", pa_config_parse_bool, &c->lock_memory, NULL },
{ "exit-idle-time", pa_config_parse_int, &c->exit_idle_time, NULL },
{ "scache-idle-time", pa_config_parse_int, &c->scache_idle_time, NULL },
{ "realtime-priority", parse_rtprio, c, NULL },
@ -633,23 +635,22 @@ FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c) {
return f;
}
static const char* const log_level_to_string[] = {
[PA_LOG_DEBUG] = "debug",
[PA_LOG_INFO] = "info",
[PA_LOG_NOTICE] = "notice",
[PA_LOG_WARN] = "warning",
[PA_LOG_ERROR] = "error"
};
static const char* const server_type_to_string[] = {
[PA_SERVER_TYPE_UNSET] = "!!UNSET!!",
[PA_SERVER_TYPE_USER] = "user",
[PA_SERVER_TYPE_SYSTEM] = "system",
[PA_SERVER_TYPE_NONE] = "none"
};
char *pa_daemon_conf_dump(pa_daemon_conf *c) {
static const char* const log_level_to_string[] = {
[PA_LOG_DEBUG] = "debug",
[PA_LOG_INFO] = "info",
[PA_LOG_NOTICE] = "notice",
[PA_LOG_WARN] = "warning",
[PA_LOG_ERROR] = "error"
};
static const char* const server_type_to_string[] = {
[PA_SERVER_TYPE_UNSET] = "!!UNSET!!",
[PA_SERVER_TYPE_USER] = "user",
[PA_SERVER_TYPE_SYSTEM] = "system",
[PA_SERVER_TYPE_NONE] = "none"
};
pa_strbuf *s;
char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
@ -678,6 +679,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf_printf(s, "no-cpu-limit = %s\n", pa_yes_no(c->no_cpu_limit));
pa_strbuf_printf(s, "disable-shm = %s\n", pa_yes_no(c->disable_shm));
pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes));
pa_strbuf_printf(s, "lock-memory = %s\n", pa_yes_no(c->lock_memory));
pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time);
pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time);
pa_strbuf_printf(s, "dl-search-path = %s\n", pa_strempty(c->dl_search_path));

View file

@ -74,7 +74,8 @@ typedef struct pa_daemon_conf {
disallow_exit,
log_meta,
log_time,
flat_volumes;
flat_volumes,
lock_memory;
pa_server_type_t local_server_type;
int exit_idle_time,
scache_idle_time,

View file

@ -28,15 +28,16 @@
; local-server-type = user
; disable-shm = no
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
; lock-memory = no
; no-cpu-limit = no
; high-priority = yes
; nice-level = -11
; realtime-scheduling = no
; realtime-scheduling = yes
; realtime-priority = 5
; exit-idle-time = 20
; module-idle-time = 20
; scache-idle-time = 20
; dl-search-path = (depends on architecture)
@ -56,8 +57,6 @@
; flat-volumes = yes
; no-cpu-limit = no
; rlimit-fsize = -1
; rlimit-data = -1
; rlimit-stack = -1

View file

@ -49,11 +49,11 @@ load-module module-augment-properties
#load-module module-pipe-sink
### Automatically load driver modules depending on the hardware available
.ifexists module-hal-detect@PA_SOEXT@
load-module module-hal-detect
.ifexists module-udev-detect@PA_SOEXT@
load-module module-udev-detect
.else
### Alternatively use the static hardware detection module (for systems that
### lack HAL support)
### lack udev support)
load-module module-detect
.endif
@ -103,6 +103,9 @@ load-module module-rescue-streams
### Make sure we always have a sink around, even if it is a null sink.
load-module module-always-sink
### Honour intended role device property
load-module module-intended-roles
### Automatically suspend sinks/sources that become idle for too long
load-module module-suspend-on-idle

View file

@ -40,6 +40,10 @@
#include <liboil/liboil.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@ -69,6 +73,7 @@
#include <pulsecore/lock-autospawn.h>
#include <pulsecore/winsock.h>
#include <pulsecore/core-error.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core.h>
#include <pulsecore/memblock.h>
#include <pulsecore/module.h>
@ -80,8 +85,6 @@
#include <pulsecore/pid.h>
#include <pulsecore/namereg.h>
#include <pulsecore/random.h>
#include <pulsecore/rtsig.h>
#include <pulsecore/rtclock.h>
#include <pulsecore/macro.h>
#include <pulsecore/mutex.h>
#include <pulsecore/thread.h>
@ -98,7 +101,6 @@
#include "dumpmodules.h"
#include "caps.h"
#include "ltdl-bind-now.h"
#include "polkit.h"
#include "server-lookup.h"
#ifdef HAVE_LIBWRAP
@ -130,7 +132,7 @@ static void message_cb(pa_mainloop_api*a, pa_time_event*e, const struct timeval
}
pa_timeval_add(pa_gettimeofday(&tvnext), 100000);
a->time_restart(e, &tvnext);
a->rtclock_time_restart(e, &tvnext);
}
#endif
@ -376,9 +378,7 @@ int main(int argc, char *argv[]) {
pa_mainloop *mainloop = NULL;
char *s;
int r = 0, retval = 1, d = 0;
pa_bool_t suid_root, real_root;
pa_bool_t valid_pid_file = FALSE;
gid_t gid = (gid_t) -1;
pa_bool_t ltdl_init = FALSE;
int passed_fd = -1;
const char *e;
@ -424,30 +424,6 @@ int main(int argc, char *argv[]) {
}
#endif
#ifdef HAVE_GETUID
real_root = getuid() == 0;
suid_root = !real_root && geteuid() == 0;
#else
real_root = FALSE;
suid_root = FALSE;
#endif
if (!real_root) {
/* Drop all capabilities except CAP_SYS_NICE */
pa_limit_caps();
/* Drop privileges, but keep CAP_SYS_NICE */
pa_drop_root();
/* After dropping root, the effective set is reset, hence,
* let's raise it again */
pa_limit_caps();
/* When capabilities are not supported we will not be able to
* acquire RT sched anymore. But yes, that's the way it is. It
* is just too risky tun let PA run as root all the time. */
}
if ((e = getenv("PULSE_PASSED_FD"))) {
passed_fd = atoi(e);
@ -455,15 +431,14 @@ int main(int argc, char *argv[]) {
passed_fd = -1;
}
/* We might be autospawned, in which case have no idea in which
* context we have been started. Let's cleanup our execution
* context as good as possible */
pa_drop_root();
pa_close_all(passed_fd, -1);
pa_reset_sigs(-1);
pa_unblock_sigs(-1);
/* At this point, we are a normal user, possibly with CAP_NICE if
* we were started SUID. If we are started as normal root, than we
* still are normal root. */
setlocale(LC_ALL, "");
pa_init_i18n();
@ -506,7 +481,7 @@ int main(int argc, char *argv[]) {
pa_assert_not_reached();
}
start_server = conf->local_server_type == PA_SERVER_TYPE_USER || (real_root && conf->local_server_type == PA_SERVER_TYPE_SYSTEM);
start_server = conf->local_server_type == PA_SERVER_TYPE_USER || (getuid() == 0 && conf->local_server_type == PA_SERVER_TYPE_SYSTEM);
if (!start_server && conf->local_server_type == PA_SERVER_TYPE_SYSTEM) {
pa_log_notice(_("System mode refused for non-root user. Only starting the D-Bus server lookup service."));
@ -514,165 +489,6 @@ int main(int argc, char *argv[]) {
}
#endif
pa_log_debug("Started as real root: %s, suid root: %s", pa_yes_no(real_root), pa_yes_no(suid_root));
#ifdef HAVE_DBUS
/* XXX: Uhh, goto programming... as if this wasn't hard enough to follow
* already. But if we won't start the full server, we want to just skip all
* the capability stuff. */
if (!start_server) {
if (!real_root && pa_have_caps())
pa_drop_caps();
goto after_caps_setup;
}
#endif
if (!real_root && pa_have_caps()) {
#ifdef HAVE_SYS_RESOURCE_H
struct rlimit rl;
#endif
pa_bool_t allow_high_priority = FALSE, allow_realtime = FALSE;
/* Let's better not enable high prio or RT by default */
if (conf->high_priority && !allow_high_priority) {
if (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) > 0) {
pa_log_info(_("We're in the group '%s', allowing high-priority scheduling."), PA_REALTIME_GROUP);
allow_high_priority = TRUE;
}
}
if (conf->realtime_scheduling && !allow_realtime) {
if (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) > 0) {
pa_log_info(_("We're in the group '%s', allowing real-time scheduling."), PA_REALTIME_GROUP);
allow_realtime = TRUE;
}
}
#ifdef HAVE_POLKIT
if (conf->high_priority && !allow_high_priority) {
if (pa_polkit_check("org.pulseaudio.acquire-high-priority") > 0) {
pa_log_info(_("PolicyKit grants us acquire-high-priority privilege."));
allow_high_priority = TRUE;
} else
pa_log_info(_("PolicyKit refuses acquire-high-priority privilege."));
}
if (conf->realtime_scheduling && !allow_realtime) {
if (pa_polkit_check("org.pulseaudio.acquire-real-time") > 0) {
pa_log_info(_("PolicyKit grants us acquire-real-time privilege."));
allow_realtime = TRUE;
} else
pa_log_info(_("PolicyKit refuses acquire-real-time privilege."));
}
#endif
if (!allow_high_priority && !allow_realtime) {
/* OK, there's no further need to keep CAP_NICE. Hence
* let's give it up early */
pa_drop_caps();
}
#ifdef RLIMIT_RTPRIO
if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
if (rl.rlim_cur > 0) {
pa_log_info("RLIMIT_RTPRIO is set to %u, allowing real-time scheduling.", (unsigned) rl.rlim_cur);
allow_realtime = TRUE;
}
#endif
#ifdef RLIMIT_NICE
if (getrlimit(RLIMIT_NICE, &rl) >= 0)
if (rl.rlim_cur > 20 ) {
pa_log_info("RLIMIT_NICE is set to %u, allowing high-priority scheduling.", (unsigned) rl.rlim_cur);
allow_high_priority = TRUE;
}
#endif
if ((conf->high_priority && !allow_high_priority) ||
(conf->realtime_scheduling && !allow_realtime))
pa_log_info(_("Called SUID root and real-time and/or high-priority scheduling was requested in the configuration. However, we lack the necessary privileges:\n"
"We are not in group '%s', PolicyKit refuse to grant us the requested privileges and we have no increase RLIMIT_NICE/RLIMIT_RTPRIO resource limits.\n"
"For enabling real-time/high-priority scheduling please acquire the appropriate PolicyKit privileges, or become a member of '%s', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user."),
PA_REALTIME_GROUP, PA_REALTIME_GROUP);
if (!allow_realtime)
conf->realtime_scheduling = FALSE;
if (!allow_high_priority)
conf->high_priority = FALSE;
}
#ifdef HAVE_SYS_RESOURCE_H
/* Reset resource limits. If we are run as root (for system mode)
* this might end up increasing the limits, which is intended
* behaviour. For all other cases, i.e. started as normal user, or
* SUID root at this point we should have no CAP_SYS_RESOURCE and
* increasing the limits thus should fail. Which is, too, intended
* behaviour */
set_all_rlimits(conf);
#endif
if (conf->high_priority && !pa_can_high_priority()) {
pa_log_info(_("High-priority scheduling enabled in configuration but not allowed by policy."));
conf->high_priority = FALSE;
}
if (conf->high_priority && (conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START))
pa_raise_priority(conf->nice_level);
pa_log_debug("Can realtime: %s, can high-priority: %s", pa_yes_no(pa_can_realtime()), pa_yes_no(pa_can_high_priority()));
if (!real_root && pa_have_caps()) {
pa_bool_t drop;
drop = (conf->cmd != PA_CMD_DAEMON && conf->cmd != PA_CMD_START) || !conf->realtime_scheduling;
#ifdef RLIMIT_RTPRIO
if (!drop) {
struct rlimit rl;
/* At this point we still have CAP_NICE if we were loaded
* SUID root. If possible let's acquire RLIMIT_RTPRIO
* instead and give CAP_NICE up. */
if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0) {
if (rl.rlim_cur >= 9)
drop = TRUE;
else {
rl.rlim_max = rl.rlim_cur = 9;
if (setrlimit(RLIMIT_RTPRIO, &rl) >= 0) {
pa_log_info(_("Successfully increased RLIMIT_RTPRIO"));
drop = TRUE;
} else
pa_log_warn(_("RLIMIT_RTPRIO failed: %s"), pa_cstrerror(errno));
}
}
}
#endif
if (drop) {
pa_log_info(_("Giving up CAP_NICE"));
pa_drop_caps();
suid_root = FALSE;
}
}
if (conf->realtime_scheduling && !pa_can_realtime()) {
pa_log_info(_("Real-time scheduling enabled in configuration but not allowed by policy."));
conf->realtime_scheduling = FALSE;
}
#ifdef HAVE_DBUS
after_caps_setup:
#endif
pa_log_debug("Can realtime: %s, can high-priority: %s", pa_yes_no(pa_can_realtime()), pa_yes_no(pa_can_high_priority()));
LTDL_SET_PRELOADED_SYMBOLS();
pa_ltdl_init();
ltdl_init = TRUE;
@ -757,10 +573,10 @@ after_caps_setup:
pa_assert(conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START);
}
if (real_root && !conf->system_instance)
if (getuid() == 0 && !conf->system_instance)
pa_log_warn(_("This program is not intended to be run as root (unless --system is specified)."));
#ifndef HAVE_DBUS /* A similar, only a notice worthy check was done earlier, if D-Bus is enabled. */
else if (!real_root && conf->system_instance) {
else if (getuid() != 0 && conf->system_instance) {
pa_log(_("Root privileges required."));
goto finish;
}
@ -907,6 +723,13 @@ after_caps_setup:
pa_assert_se(chdir("/") == 0);
umask(0022);
#ifdef HAVE_SYS_RESOURCE_H
set_all_rlimits(conf);
#endif
pa_rtclock_hrtimer_enable();
pa_raise_priority(conf->nice_level);
if (conf->system_instance)
if (change_user() < 0)
goto finish;
@ -955,8 +778,8 @@ after_caps_setup:
pa_xfree(s);
if ((s = pa_session_id())) {
pa_log_info(_("Session ID is %s."), s);
pa_xfree(s);
pa_log_info(_("Session ID is %s."), s);
pa_xfree(s);
}
if (!(s = pa_get_runtime_dir()))
@ -971,6 +794,11 @@ after_caps_setup:
pa_log_info(_("Running in system mode: %s"), pa_yes_no(pa_in_system_mode()));
if (pa_in_system_mode())
pa_log_warn(_("OK, so you are running PA in system mode. Please note that you most likely shouldn't be doing that.\n"
"If you do it nonetheless then it's your own fault if things don't work as expected.\n"
"Please read http://pulseaudio.org/wiki/WhatIsWrongWithSystemMode for an explanation why system mode is usually a bad idea."));
if (conf->use_pid_file) {
int z;
@ -998,12 +826,16 @@ after_caps_setup:
else
pa_log_info(_("Dude, your kernel stinks! The chef's recommendation today is Linux with high-resolution timers enabled!"));
pa_rtclock_hrtimer_enable();
#ifdef SIGRTMIN
/* Valgrind uses SIGRTMAX. To easy debugging we don't use it here */
pa_rtsig_configure(SIGRTMIN, SIGRTMAX-1);
if (conf->lock_memory) {
#ifdef HAVE_SYS_MMAN_H
if (mlockall(MCL_FUTURE) < 0)
pa_log_warn("mlockall() failed: %s", pa_cstrerror(errno));
else
pa_log_info("Sucessfully locked process into memory.");
#else
pa_log_warn("Memory locking requested but not supported on platform.");
#endif
}
pa_memtrap_install();
@ -1028,7 +860,9 @@ after_caps_setup:
c->running_as_daemon = !!conf->daemonize;
c->disallow_exit = conf->disallow_exit;
c->flat_volumes = conf->flat_volumes;
#ifdef HAVE_DBUS
c->server_type = conf->local_server_type;
#endif
pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0);
pa_signal_new(SIGINT, signal_callback, c);
@ -1044,7 +878,7 @@ after_caps_setup:
#endif
#ifdef OS_IS_WIN32
win32_timer = pa_mainloop_get_api(mainloop)->time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&win32_tv), message_cb, NULL);
win32_timer = pa_mainloop_get_api(mainloop)->rtclock_time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&win32_tv), message_cb, NULL);
#endif
oil_init();