Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio

This commit is contained in:
Lennart Poettering 2009-06-22 22:36:31 +02:00
commit 374efbded4
56 changed files with 1035 additions and 942 deletions

View file

@ -1152,44 +1152,6 @@ AC_SUBST(DBUS_LIBS)
AC_SUBST(HAVE_DBUS)
AM_CONDITIONAL([HAVE_DBUS], [test "x$HAVE_DBUS" = x1])
#### PolicyKit support (optional) ####
AC_ARG_ENABLE([polkit],
AS_HELP_STRING([--disable-polkit],[Disable optional PolicyKit support]),
[
case "${enableval}" in
yes) polkit=yes ;;
no) polkit=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --disable-polkit) ;;
esac
],
[polkit=auto])
if test "x${polkit}" != xno ; then
PKG_CHECK_MODULES(POLKIT, [ polkit-dbus >= 0.7 ],
[
HAVE_POLKIT=1
AC_DEFINE([HAVE_POLKIT], 1, [Have PolicyKit])
policydir=`pkg-config polkit-dbus --variable prefix`/share/PolicyKit/policy/
AC_SUBST(policydir)
],
[
HAVE_POLKIT=0
if test "x$polkit" = xyes ; then
AC_MSG_ERROR([*** PolicyKit support not found])
fi
])
else
HAVE_POLKIT=0
fi
AC_SUBST(POLKIT_CFLAGS)
AC_SUBST(POLKIT_LIBS)
AC_SUBST(HAVE_POLKIT)
AM_CONDITIONAL([HAVE_POLKIT], [test "x$HAVE_POLKIT" = x1])
### IPv6 connection support (optional) ###
AC_ARG_ENABLE([ipv6],
@ -1276,15 +1238,6 @@ fi
AC_SUBST(PA_SYSTEM_GROUP)
AC_DEFINE_UNQUOTED(PA_SYSTEM_GROUP,"$PA_SYSTEM_GROUP", [Group for the PulseAudio system daemon])
AC_ARG_WITH(realtime_group,AS_HELP_STRING([--with-realtime-group=<group>],[Group for users that are allowed to start the PulseAudio daemon with realtime scheduling (realtime)]))
if test -z "$with_realtime_group" ; then
PA_REALTIME_GROUP=pulse-rt
else
PA_REALTIME_GROUP=$with_realtime_group
fi
AC_SUBST(PA_REALTIME_GROUP)
AC_DEFINE_UNQUOTED(PA_REALTIME_GROUP,"$PA_REALTIME_GROUP", [Realtime group])
AC_ARG_WITH(access_group,AS_HELP_STRING([--with-access-group=<group>],[Group which is allowed access to a system-wide PulseAudio daemon (pulse-access)]))
if test -z "$with_access_group" ; then
PA_ACCESS_GROUP=pulse-access
@ -1461,11 +1414,6 @@ if test "x${HAVE_BLUEZ}" = "x1" ; then
ENABLE_BLUEZ=yes
fi
ENABLE_POLKIT=no
if test "x${HAVE_POLKIT}" = "x1" ; then
ENABLE_POLKIT=yes
fi
ENABLE_GDBM=no
if test "x${HAVE_GDBM}" = "x1" ; then
ENABLE_GDBM=yes
@ -1519,7 +1467,6 @@ echo "
Enable BlueZ: ${ENABLE_BLUEZ}
Enable TCP Wrappers: ${ENABLE_TCPWRAP}
Enable libsamplerate: ${ENABLE_LIBSAMPLERATE}
Enable PolicyKit: ${ENABLE_POLKIT}
Enable IPv6: ${ENABLE_IPV6}
Enable OpenSSL (for Airtunes): ${ENABLE_OPENSSL}
Enable tdb: ${ENABLE_TDB}
@ -1527,7 +1474,6 @@ echo "
System User: ${PA_SYSTEM_USER}
System Group: ${PA_SYSTEM_GROUP}
Realtime Group: ${PA_REALTIME_GROUP}
Access Group: ${PA_ACCESS_GROUP}
Enable per-user EsounD socket: ${ENABLE_PER_USER_ESOUND_SOCKET}
Force preopen: ${FORCE_PREOPEN}

View file

@ -29,8 +29,8 @@ pulsecoreincludedir=$(includedir)/pulsecore
pulseconfdir=$(sysconfdir)/pulse
pulselibexecdir=$(libexecdir)/pulse
xdgautostartdir=$(sysconfdir)/xdg/autostart
alsaprofilesetsdir=$(datadir)/alsa-mixer/profile-sets
alsapathsdir=$(datadir)/alsa-mixer/paths
alsaprofilesetsdir=$(datadir)/pulseaudio/alsa-mixer/profile-sets
alsapathsdir=$(datadir)/pulseaudio/alsa-mixer/paths
udevrulesdir=/lib/udev/rules.d
###################################
@ -114,10 +114,10 @@ EXTRA_DIST = \
modules/module-defs.h.m4 \
daemon/pulseaudio.desktop.in \
map-file \
daemon/org.pulseaudio.policy.in \
modules/alsa/mixer/profile-sets/default.conf \
modules/alsa/mixer/profile-sets/native-instruments-audio4dj.conf \
modules/alsa/mixer/profile-sets/native-instruments-audio8dj.conf \
modules/alsa/mixer/profile-sets/78-pulseaudio.rules \
modules/alsa/mixer/profile-sets/90-pulseaudio.rules \
modules/alsa/mixer/paths/analog-input-aux.conf \
modules/alsa/mixer/paths/analog-input.conf \
modules/alsa/mixer/paths/analog-input.conf.common \
@ -183,16 +183,6 @@ else
pulseaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f))
endif
if HAVE_POLKIT
policy_in_files = daemon/org.pulseaudio.policy.in
policy_DATA = $(policy_in_files:.policy.in=.policy)
@INTLTOOL_POLICY_RULE@
pulseaudio_SOURCES += daemon/polkit.c daemon/polkit.h
pulseaudio_CFLAGS += $(POLKIT_CFLAGS)
pulseaudio_LDADD += $(POLKIT_LIBS)
endif
###################################
# Utility programs #
###################################
@ -572,6 +562,7 @@ libpulsecommon_@PA_MAJORMINORMICRO@_la_SOURCES = \
pulsecore/conf-parser.c pulsecore/conf-parser.h \
pulsecore/core-error.c pulsecore/core-error.h \
pulsecore/core-util.c pulsecore/core-util.h \
pulsecore/rtkit.c pulsecore/rtkit.h \
pulsecore/creds.h \
pulsecore/dynarray.c pulsecore/dynarray.h \
pulsecore/endianmacros.h \
@ -820,7 +811,6 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \
pulsecore/play-memchunk.c pulsecore/play-memchunk.h \
pulsecore/resampler.c pulsecore/resampler.h \
pulsecore/rtpoll.c pulsecore/rtpoll.h \
pulsecore/rtsig.c pulsecore/rtsig.h \
pulsecore/sample-util.c pulsecore/sample-util.h \
pulsecore/sconv-s16be.c pulsecore/sconv-s16be.h \
pulsecore/sconv-s16le.c pulsecore/sconv-s16le.h \
@ -1050,10 +1040,11 @@ modlibexec_LTLIBRARIES += \
alsaprofilesets_DATA = \
modules/alsa/mixer/profile-sets/default.conf \
modules/alsa/mixer/profile-sets/native-instruments-audio4dj.conf \
modules/alsa/mixer/profile-sets/native-instruments-audio8dj.conf
udevrules_DATA = \
modules/alsa/mixer/profile-sets/78-pulseaudio.rules
modules/alsa/mixer/profile-sets/90-pulseaudio.rules
alsapaths_DATA = \
modules/alsa/mixer/paths/analog-input-aux.conf \
@ -1660,11 +1651,7 @@ module_rygel_media_server_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
# Some minor stuff #
###################################
suid: pulseaudio .libs/lt-pulseaudio
chown root $^
chmod u+s $^
CLEANFILES = esdcompat client.conf default.pa system.pa daemon.conf start-pulseaudio-x11 daemon/pulseaudio.desktop daemon/org.pulseaudio.policy
CLEANFILES = esdcompat client.conf default.pa system.pa daemon.conf start-pulseaudio-x11 daemon/pulseaudio.desktop
esdcompat: daemon/esdcompat.in Makefile
sed -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \
@ -1741,6 +1728,11 @@ update-reserve:
wget -O modules/$$i http://git.0pointer.de/\?p=reserve.git\;a=blob_plain\;f=$$i\;hb=master ; \
done
update-rtkit:
for i in rtkit.c rtkit.h ; do \
wget -O pulsecore/$$i http://git.0pointer.de/\?p=rtkit.git\;a=blob_plain\;f=$$i\;hb=master ; \
done
# Automatically generate linker version script. We use the same one for all public .sos
update-map-file:
( echo "PULSE_0 {" ; \

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

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

View file

@ -33,7 +33,7 @@
; high-priority = yes
; nice-level = -11
; realtime-scheduling = no
; realtime-scheduling = yes
; realtime-priority = 5
; exit-idle-time = 20

View file

@ -84,7 +84,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>
@ -102,7 +101,6 @@
#include "dumpmodules.h"
#include "caps.h"
#include "ltdl-bind-now.h"
#include "polkit.h"
#ifdef HAVE_LIBWRAP
/* Only one instance of these variables */
@ -381,9 +379,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;
@ -426,30 +422,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);
@ -457,15 +429,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();
@ -490,150 +461,6 @@ int main(int argc, char *argv[]) {
pa_log_set_flags(PA_LOG_PRINT_TIME, PA_LOG_SET);
pa_log_set_show_backtrace(conf->log_backtrace);
pa_log_debug("Started as real root: %s, suid root: %s", pa_yes_no(real_root), pa_yes_no(suid_root));
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;
}
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;
@ -718,9 +545,9 @@ int main(int argc, char *argv[]) {
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)."));
else if (!real_root && conf->system_instance) {
else if (getuid() != 0 && conf->system_instance) {
pa_log(_("Root privileges required."));
goto finish;
}
@ -866,6 +693,13 @@ int main(int argc, char *argv[]) {
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;
@ -914,8 +748,8 @@ int main(int argc, char *argv[]) {
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()))
@ -962,13 +796,6 @@ int main(int argc, char *argv[]) {
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);
#endif
if (conf->lock_memory) {
#ifdef HAVE_SYS_MMAN_H
if (mlockall(MCL_FUTURE) < 0)

View file

@ -479,6 +479,7 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
snd_mixer_elem_t *me;
snd_mixer_selem_channel_id_t c;
pa_channel_position_mask_t mask = 0;
pa_volume_t max_channel_volume = PA_VOLUME_MUTED;
unsigned k;
pa_assert(m);
@ -545,6 +546,9 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
f = from_alsa_volume(value, e->min_volume, e->max_volume);
}
if (f > max_channel_volume)
max_channel_volume = f;
for (k = 0; k < cm->channels; k++)
if (e->masks[c][e->n_channels-1] & PA_CHANNEL_POSITION_MASK(cm->map[k]))
if (v->values[k] < f)
@ -555,7 +559,7 @@ static int element_get_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
for (k = 0; k < cm->channels; k++)
if (!(mask & PA_CHANNEL_POSITION_MASK(cm->map[k])))
v->values[k] = PA_VOLUME_NORM;
v->values[k] = max_channel_volume;
return 0;
}
@ -677,6 +681,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
snd_mixer_elem_t *me;
snd_mixer_selem_channel_id_t c;
pa_channel_position_mask_t mask = 0;
pa_volume_t max_channel_volume = PA_VOLUME_MUTED;
unsigned k;
pa_assert(m);
@ -696,11 +701,21 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
for (c = 0; c <= SND_MIXER_SCHN_LAST; c++) {
int r;
pa_volume_t f = PA_VOLUME_MUTED;
pa_bool_t found = FALSE;
for (k = 0; k < cm->channels; k++)
if (e->masks[c][e->n_channels-1] & PA_CHANNEL_POSITION_MASK(cm->map[k]))
if (e->masks[c][e->n_channels-1] & PA_CHANNEL_POSITION_MASK(cm->map[k])) {
found = TRUE;
if (v->values[k] > f)
f = v->values[k];
}
if (!found) {
/* Hmm, so this channel does not exist in the volume
* struct, so let's bind it to the overall max of the
* volume. */
f = pa_cvolume_max(v);
}
if (e->has_dB) {
long value = to_alsa_dB(f);
@ -756,6 +771,9 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
f = from_alsa_volume(value, e->min_volume, e->max_volume);
}
if (f > max_channel_volume)
max_channel_volume = f;
for (k = 0; k < cm->channels; k++)
if (e->masks[c][e->n_channels-1] & PA_CHANNEL_POSITION_MASK(cm->map[k]))
if (rv.values[k] < f)
@ -766,7 +784,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
for (k = 0; k < cm->channels; k++)
if (!(mask & PA_CHANNEL_POSITION_MASK(cm->map[k])))
rv.values[k] = PA_VOLUME_NORM;
rv.values[k] = max_channel_volume;
*v = rv;
return 0;

View file

@ -838,7 +838,6 @@ static int unsuspend(struct userdata *u) {
pa_log_info("Trying resume...");
snd_config_update_free_global();
if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_PLAYBACK,
/*SND_PCM_NONBLOCK|*/
SND_PCM_NO_AUTO_RESAMPLE|
@ -1213,7 +1212,6 @@ static void thread_func(void *userdata) {
pa_make_realtime(u->core->realtime_priority);
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
int ret;

View file

@ -787,8 +787,6 @@ static int unsuspend(struct userdata *u) {
pa_log_info("Trying resume...");
snd_config_update_free_global();
if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE,
/*SND_PCM_NONBLOCK|*/
SND_PCM_NO_AUTO_RESAMPLE|
@ -1096,7 +1094,6 @@ static void thread_func(void *userdata) {
pa_make_realtime(u->core->realtime_priority);
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
int ret;

View file

@ -735,20 +735,22 @@ static void alsa_error_handler(const char *file, int line, const char *function,
static pa_atomic_t n_error_handler_installed = PA_ATOMIC_INIT(0);
void pa_alsa_redirect_errors_inc(void) {
void pa_alsa_refcnt_inc(void) {
/* This is not really thread safe, but we do our best */
if (pa_atomic_inc(&n_error_handler_installed) == 0)
snd_lib_error_set_handler(alsa_error_handler);
}
void pa_alsa_redirect_errors_dec(void) {
void pa_alsa_refcnt_dec(void) {
int r;
pa_assert_se((r = pa_atomic_dec(&n_error_handler_installed)) >= 1);
if (r == 1)
if (r == 1) {
snd_lib_error_set_handler(NULL);
snd_config_update_free_global();
}
}
pa_bool_t pa_alsa_init_description(pa_proplist *p) {

View file

@ -114,8 +114,8 @@ snd_pcm_t *pa_alsa_open_by_template(
void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm);
void pa_alsa_dump_status(snd_pcm_t *pcm);
void pa_alsa_redirect_errors_inc(void);
void pa_alsa_redirect_errors_dec(void);
void pa_alsa_refcnt_inc(void);
void pa_alsa_refcnt_dec(void);
void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info);
void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card);

View file

@ -1,4 +1,22 @@
# For devices, where we have an Aux element
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; For devices where an 'Aux' element exists
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 90
@ -29,4 +47,16 @@ override-map.2 = all-left,all-right
switch = off
volume = off
[Element Mic/Line]
switch = off
volume = off
[Element TV Tuner]
switch = off
volume = off
[Element FM]
switch = off
volume = off
.include analog-input.conf.common

View file

@ -1,4 +1,22 @@
# For devices where we have an FM element
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; For devices where an 'FM' element exists
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 70

View file

@ -1,4 +1,22 @@
# For devices, where we have a Line element
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; For devices where a 'Line' element exists
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 90

View file

@ -1,4 +1,22 @@
# For devices where we have a Mic/Lineb element
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; For devices where a 'Mic/Line' element exists
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 90
@ -42,3 +60,4 @@ switch = off
volume = off
.include analog-input.conf.common
.include analog-input-mic.conf.common

View file

@ -1,4 +1,22 @@
# For devices where we have a Mic element
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; For devices where a 'Mic' element exists
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 100

View file

@ -1,3 +1,23 @@
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; Common element for all microphone inputs
;
; See analog-output.conf.common for an explanation on the directives
;;; 'Mic Select'
[Element Mic Select]

View file

@ -1,4 +1,22 @@
# For devices, where we have a TV Tuner element
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; For devices where a 'TV Tuner' element exists
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 70

View file

@ -1,4 +1,22 @@
# For devices, where we have a Video element
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; For devices where a 'Video' element exists
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 70
@ -28,4 +46,16 @@ volume = merge
override-map.1 = all
override-map.2 = all-left,all-right
[Element Mic/Line]
switch = off
volume = off
[Element TV Tuner]
switch = off
volume = off
[Element FM]
switch = off
volume = off
.include analog-input.conf.common

View file

@ -1,4 +1,23 @@
# A fallback for devices that lack seperate Mic/Line/Aux/Video elements
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; A fallback for devices that lack seperate Mic/Line/Aux/Video/TV
; Tuner/FM elements
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 100

View file

@ -1,30 +1,48 @@
# Mixer path for PulseAudio's ALSA backend. If multiple options by the
# same id are discovered they will be suffixed with a number to
# distuingish them, in the same order they appear here.
# This file is part of PulseAudio.
#
# Source selection should use the following names:
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# input -- If we don't know the exact kind of input
# input-microphone
# input-microphone-internal
# input-microphone-external
# input-linein
# input-video
# input-radio
# input-docking-microphone
# input-docking-linein
# input-docking
#
# We explicitly don't want to wrap the following sources:
#
# CD
# Synth/MIDI
# Phone
# Mix
# Digital/SPDIF
# Master
# PC Speaker
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; Mixer path for PulseAudio's ALSA backend, common elements for all
; input paths. If multiple options by the same id are discovered they
; will be suffixed with a number to distuingish them, in the same
; order they appear here.
;
; Source selection should use the following names:
;
; input -- If we don't know the exact kind of input
; input-microphone
; input-microphone-internal
; input-microphone-external
; input-linein
; input-video
; input-radio
; input-docking-microphone
; input-docking-linein
; input-docking
;
; We explicitly don't want to wrap the following sources:
;
; CD
; Synth/MIDI
; Phone
; Mix
; Digital/SPDIF
; Master
; PC Speaker
;
; See analog-output.conf.common for an explanation on the directives
;;; 'Input Source Select'

View file

@ -1,4 +1,22 @@
# Path for mixers that have a Headphone slider
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; Path for mixers that have a 'Headphone' control
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 90

View file

@ -1,5 +1,23 @@
# Intended for usage in laptops that have a seperate LFE speaker
# connected to the Master mono connector
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; Intended for usage in laptops that have a seperate LFE speaker
; connected to the Master mono connector
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 40

View file

@ -1,4 +1,22 @@
# Intended for usage on boards that have a seperate Mono output plug.
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; Intended for usage on boards that have a seperate Mono output plug.
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 50

View file

@ -1,4 +1,22 @@
# Intended for the 'default' output
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; Intended for the 'default' output
;
; See analog-output.conf.common for an explanation on the directives
[General]
priority = 100

View file

@ -1,26 +1,97 @@
# Common part of all paths
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
# [General]
# priority = ...
# description = ...
#
# [Option ...:...]
# name = ...
# priority = ...
#
# [Element ...]
# required = ignore | switch | volume | enumeration | any
# required-absent = ignore | switch | volume
#
# switch = ignore | mute | off | on | select
# volume = ignore | merge | off | zero
# enumeration = ignore | select
#
# direction = playback | capture
# direction-try-other = no | yes
#
# override-map.1 = ...
# override-map.2 = ...
; Common part of all paths
; So here's generally how mixer paths are used by PA: PA goes through
; a mixer path file from top to bottom and checks if a mixer element
; described therein exists. If so it is added to the list of mixer
; elements PA will control, keeping the order it read them in. If a
; mixer element described here has set the required= or
; required-absent= directives a path might not be accepted as valid
; and is ignored in its entirety (see below). However usually if a
; element listed here is missing this one element is ignored but not
; the entire path.
;
; When a device shall be muted/unmuted *all* elements listed in a path
; file with "switch = mute" will be toggled.
;
; When a device shall change its volume, PA will got through the list
; of all elements with "volume = merge" and set the volume on the
; first element. If that element does not support dB volumes, this is
; where the story ends. If it does support dB volumes, PA divides the
; requested volume by the volume that was set on this element, and
; then go on to the next element with "volume = merge" and then set
; that there, and so on. That way the first volume element in the
; path will be the one that does the 'biggest' part of the overall
; volume adjustment, with the remaining elements usually being set to
; some value next to 0dB. This logic makes sure we get the full range
; over all volume sliders and a very high granularity of volumes
; already in hardware.
;
; All switches and enumerations set to "select" are exposed via the
; "port" functionality of sinks/sources. Basically every possible
; switch setting and every possible enumeration setting will be
; combined and made into a "port". So make sure you don't list too
; many switches/enums for exposing, because the number of ports might
; rise exponentially.
;
; Only one path can be selected at a time. All paths that are valid
; for an audio device will be exposed as "port" for the sink/source.
; [General]
; priority = ... # Priority for this path
; description = ...
;
; [Option ...:...] # For each option of an enumeration or switch element
; # that shall be exposed as a sink/source port. Needs to
; # be named after the Element, followed by a colon, followed
; # by the option name, resp. on/off if the element is a switch.
; name = ... # Logical name to use in the path identifier
; priority = ... # Priority if this is made into a device port
;
; [Element ...] # For each element that we shall control
; required = ignore | switch | volume | enumeration | any # If set, require this element to be of this kind and available,
; # otherwise don't consider this path valid for the card
; required-absent = ignore | switch | volume # If set, require this element to not be of this kind and not
; # available, otherwise don't consider this path valid for the card
;
; switch = ignore | mute | off | on | select # What to do with this switch: ignore it, make it follow mute status,
; # always set it to off, always to on, or make it selectable as port.
; # If set to 'select' you need to define an Option section for on
; # and off
; volume = ignore | merge | off | zero # What to do with this volume: ignore it, merge it into the device
; # volume slider, always set it to the lowest value possible, or always
; # set it to 0 dB (for whatever that means)
; enumeration = ignore | select # What to do with this enumeration, ignore it or make it selectable
; # via device ports. If set to 'select' you need to define an Option section
; # for each of the items you want to expose
; direction = playback | capture # Is this relevant only for playback or capture? If not set this will implicitly be
; # set the direction of the PCM device is opened as. Generally this doesn't need to be set
; # unless you have a broken driver that has playback controls marked for capture or vice
; # versa
; direction-try-other = no | yes # If the element does not supported what is requested, try the other direction, too?
;
; override-map.1 = ... # Override the channel mask of the mixer control if the control only exposes a single channel
; override-map.2 = ... # Override the channel masks of the mixer control if the control only exposes two channels
; # Override maps should list for each element channel which high-level channels it controls via a
; # channel mask. A channel mask may either be the name of a single channel, or the words "all-left",
; # "all-right", "all-center", "all-front", "all-rear", and "all" to encode a specific subset of
; # channels in a mask
[Element PCM]
switch = mute

View file

@ -1,9 +0,0 @@
# do not edit this file, it will be overwritten on update
SUBSYSTEM!="sound", GOTO="pulseaudio_end"
ACTION!="change", GOTO="pulseaudio_end"
KERNEL!="card*", GOTO="pulseaudio_end"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="1978", ENV{PULSE_PROFILE_SET}="native-instruments-audio8dj.conf"
LABEL="pulseaudio_end"

View file

@ -0,0 +1,26 @@
# do not edit this file, it will be overwritten on update
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
SUBSYSTEM!="sound", GOTO="pulseaudio_end"
ACTION!="change", GOTO="pulseaudio_end"
KERNEL!="card*", GOTO="pulseaudio_end"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="1978", ENV{PULSE_PROFILE_SET}="native-instruments-audio8dj.conf"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="0839", ENV{PULSE_PROFILE_SET}="native-instruments-audio4dj.conf"
LABEL="pulseaudio_end"

View file

@ -1,22 +1,60 @@
# Profile definitions for PulseAudio's ALSA backend
# This file is part of PulseAudio.
#
# [Mapping id]
# device-strings = ...
# channel-map = ...
# description = ...
# paths-input = ...
# paths-output = ...
# element-input = ...
# element-output = ...
# priority = ...
# direction = any | input | output
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# [Profile id]
# input-mappings = ...
# output-mappings = ...
# description = ...
# priority = ...
# skip-probe = no | yes
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; Default profile definitions for the ALSA backend of PulseAudio. This
; is used as fallback for all cards that have no special mapping
; assigned. (and should be good enough for the vast majority of
; cards). Use the udev property PULSE_PROFILE_SET to assign a
; different profile set than this one to a device. So what is this
; about? Simply, what we do here is map ALSA devices to how they are
; exposed in PA. We say which ALSA device string to use to open a
; device, which channel mapping to use then, and which mixer path to
; use. This is encoded in a 'mapping'. Multiple of these mappings can
; be bound together in a 'profile' which is then directly exposed in
; the UI as a card profile. Each mapping assigned to a profile will
; result in one sink/source to be created if the profile is selected
; for the card.
; [General]
; auto-profiles = no | yes # Instead of defining all profiles manually, autogenerate
; # them by combining every input mapping with every output mapping.
;
; [Mapping id]
; device-strings = ... # ALSA device string. %f will be replaced by the card identifier.
; channel-map = ... # Channel mapping to use for this device
; description = ...
; paths-input = ... # A list of mixer paths to use. Every path in this list will be probed.
; # If multiple are found to be working they will be available as device ports
; paths-output = ...
; element-input = ... # Instead of configuring a full mixer path simply configure a single
; # mixer element for volume/mute handling
; element-output = ...
; priority = ...
; direction = any | input | output # Only useful for?
;
; [Profile id]
; input-mappings = ... # Lists mappings for sources on this profile, those mapping must be
; # defined in this file too
; output-mappings = ... # Lists mappings for sinks on this profile, those mappings must be
; # defined in this file too
; description = ...
; priority = ... # Numeric value to deduce priority for this profile
; skip-probe = no | yes # Skip probing for availability? If this is yes then this profile
; # will be assumed as working without probing. Makes initialization
; # a bit faster but only works if the card is really known well.
[General]
auto-profiles = yes
@ -99,6 +137,7 @@ channel-map = left,right
priority = 4
direction = output
; An example for defining multiple-sink profiles
#[Profile output:analog-stereo+output:iec958-stereo+input:analog-stereo]
#description = Foobar
#output-mappings = analog-stereo iec958-stereo

View file

@ -0,0 +1,91 @@
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio 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 Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
; Native Instruments Audio 4 DJ
;
; This card has two stereo pairs of input and two stereo pairs of
; output, named channels A and B. Channel B has an additional
; Headphone connector.
;
; We knowingly only define a subset of the theoretically possible
; mapping combinations as profiles here.
;
; See default.conf for an explanation on the directives used here.
[General]
auto-profiles = no
[Mapping analog-stereo-a]
description = Analog Stereo Channel A
device-strings = hw:%f,0,0
channel-map = left,right
[Mapping analog-stereo-b-output]
description = Analog Stereo Channel B (Headphones)
device-strings = hw:%f,0,1
channel-map = left,right
direction = output
[Mapping analog-stereo-b-input]
description = Analog Stereo Channel B
device-strings = hw:%f,0,1
channel-map = left,right
direction = input
[Profile output:analog-stereo-all+input:analog-stereo-all]
description = Analog Stereo Duplex Channels A, B (Headphones)
output-mappings = analog-stereo-a analog-stereo-b-output
input-mappings = analog-stereo-a analog-stereo-b-input
priority = 100
skip-probe = yes
[Profile output:analog-stereo-a+input:analog-stereo-a]
description = Analog Stereo Duplex Channel A
output-mappings = analog-stereo-a
input-mappings = analog-stereo-a
priority = 40
skip-probe = yes
[Profile output:analog-stereo-b+input:analog-stereo-b]
description = Analog Stereo Duplex Channel B (Headphones)
output-mappings = analog-stereo-b-output
input-mappings = analog-stereo-b-input
priority = 50
skip-probe = yes
[Profile output:analog-stereo-a]
description = Analog Stereo Output Channel A
output-mappings = analog-stereo-a
priority = 5
skip-probe = yes
[Profile output:analog-stereo-b]
description = Analog Stereo Output Channel B (Headphones)
output-mappings = analog-stereo-b-output
priority = 6
skip-probe = yes
[Profile input:analog-stereo-a]
description = Analog Stereo Input Channel A
input-mappings = analog-stereo-a
priority = 2
skip-probe = yes
[Profile input:analog-stereo-b]
description = Analog Stereo Input Channel B
input-mappings = analog-stereo-b-input
priority = 1
skip-probe = yes

View file

@ -22,6 +22,8 @@
;
; We knowingly only define a subset of the theoretically possible
; mapping combinations as profiles here.
;
; See default.conf for an explanation on the directives used here.
[General]
auto-profiles = no

View file

@ -287,8 +287,7 @@ int pa__init(pa_module *m) {
const char *description;
char *fn = NULL;
pa_alsa_redirect_errors_inc();
snd_config_update_free_global();
pa_alsa_refcnt_inc();
pa_assert(m);
@ -443,6 +442,5 @@ void pa__done(pa_module*m) {
pa_xfree(u);
finish:
snd_config_update_free_global();
pa_alsa_redirect_errors_dec();
pa_alsa_refcnt_dec();
}

View file

@ -82,8 +82,7 @@ int pa__init(pa_module*m) {
pa_assert(m);
pa_alsa_redirect_errors_inc();
snd_config_update_free_global();
pa_alsa_refcnt_inc();
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments");
@ -124,6 +123,5 @@ void pa__done(pa_module*m) {
if ((sink = m->userdata))
pa_alsa_sink_free(sink);
snd_config_update_free_global();
pa_alsa_redirect_errors_dec();
pa_alsa_refcnt_dec();
}

View file

@ -106,8 +106,7 @@ int pa__init(pa_module*m) {
pa_assert(m);
pa_alsa_redirect_errors_inc();
snd_config_update_free_global();
pa_alsa_refcnt_inc();
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments");
@ -148,6 +147,5 @@ void pa__done(pa_module*m) {
if ((source = m->userdata))
pa_alsa_source_free(source);
snd_config_update_free_global();
pa_alsa_redirect_errors_dec();
pa_alsa_refcnt_dec();
}

View file

@ -1265,7 +1265,6 @@ static void thread_func(void *userdata) {
goto fail;
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
struct pollfd *pollfd;

View file

@ -225,7 +225,6 @@ static void thread_func(void *userdata) {
pa_make_realtime(u->core->realtime_priority);
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
int ret;

View file

@ -196,7 +196,6 @@ static void thread_func(void *userdata) {
pa_make_realtime(u->core->realtime_priority);
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
int ret;

View file

@ -280,7 +280,6 @@ static void thread_func(void *userdata) {
pa_make_realtime(u->core->realtime_priority+1);
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
u->thread_info.timestamp = pa_rtclock_usec();
u->thread_info.in_null_mode = FALSE;

View file

@ -200,7 +200,6 @@ static void thread_func(void *userdata) {
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());

View file

@ -208,7 +208,6 @@ static void thread_func(void *userdata) {
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
u->timestamp = pa_rtclock_usec();

View file

@ -170,7 +170,6 @@ static void thread_func(void *userdata) {
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
struct pollfd *pollfd;

View file

@ -129,7 +129,6 @@ static void thread_func(void *userdata) {
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
int ret;

View file

@ -166,7 +166,6 @@ static void thread_func(void *userdata) {
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
u->timestamp = pa_rtclock_usec();

View file

@ -683,7 +683,6 @@ static void thread_func(void *userdata) {
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
int ret;

View file

@ -889,7 +889,6 @@ static void thread_func(void *userdata) {
pa_make_realtime(u->core->realtime_priority);
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
for (;;) {
int ret;

View file

@ -323,7 +323,6 @@ static void thread_func(void *userdata) {
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());

View file

@ -50,6 +50,10 @@
#ifdef HAVE_SCHED_H
#include <sched.h>
#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
#define SCHED_RESET_ON_FORK 0x40000000
#endif
#endif
#ifdef HAVE_SYS_RESOURCE_H
@ -92,6 +96,10 @@
#include <xlocale.h>
#endif
#ifdef HAVE_DBUS
#include "rtkit.h"
#endif
#include <pulse/xmalloc.h>
#include <pulse/util.h>
#include <pulse/utf8.h>
@ -552,46 +560,78 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
return b;
}
static int set_scheduler(int rtprio) {
struct sched_param sp;
int r;
#ifdef HAVE_DBUS
DBusError error;
DBusConnection *bus;
dbus_error_init(&error);
#endif
pa_zero(sp);
sp.sched_priority = rtprio;
#ifdef SCHED_RESET_ON_FORK
if ((r = pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &sp)) == 0) {
pa_log_debug("SCHED_RR|SCHED_RESET_ON_FORK worked.");
return 0;
}
#endif
if ((r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp)) == 0) {
pa_log_debug("SCHED_RR worked.");
return 0;
}
#ifdef HAVE_DBUS
/* Try to talk to RealtimeKit */
if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
pa_log("Failed to connect to system bus: %s\n", error.message);
dbus_error_free(&error);
errno = -EIO;
return -1;
}
r = rtkit_make_realtime(bus, 0, rtprio);
dbus_connection_unref(bus);
if (r >= 0) {
pa_log_debug("RealtimeKit worked.");
return 0;
}
errno = -r;
#else
errno = r;
#endif
return -1;
}
/* Make the current thread a realtime thread, and acquire the highest
* rtprio we can get that is less or equal the specified parameter. If
* the thread is already realtime, don't do anything. */
int pa_make_realtime(int rtprio) {
#ifdef _POSIX_PRIORITY_SCHEDULING
struct sched_param sp;
int r, policy;
int p;
memset(&sp, 0, sizeof(sp));
policy = 0;
if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
return -1;
}
if (policy == SCHED_FIFO && sp.sched_priority >= rtprio) {
pa_log_info("Thread already being scheduled with SCHED_FIFO with priority %i.", sp.sched_priority);
if (set_scheduler(rtprio) >= 0) {
pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i.", rtprio);
return 0;
}
sp.sched_priority = rtprio;
if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
while (sp.sched_priority > 1) {
sp.sched_priority --;
if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) == 0) {
pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i, which is lower than the requested %i.", sp.sched_priority, rtprio);
return 0;
}
for (p = rtprio-1; p >= 1; p--)
if (set_scheduler(p)) {
pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p, rtprio);
return 0;
}
pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
return -1;
}
pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority);
return 0;
pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
return -1;
#else
errno = ENOTSUP;
@ -599,80 +639,42 @@ int pa_make_realtime(int rtprio) {
#endif
}
/* This is merely used for giving the user a hint. This is not correct
* for anything security related */
pa_bool_t pa_can_realtime(void) {
static int set_nice(int nice_level) {
#ifdef HAVE_DBUS
DBusError error;
DBusConnection *bus;
int r;
if (geteuid() == 0)
return TRUE;
#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
{
struct rlimit rl;
if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY)
return TRUE;
}
dbus_error_init(&error);
#endif
#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
{
cap_t cap;
if ((cap = cap_get_proc())) {
cap_flag_value_t flag = CAP_CLEAR;
if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
if (flag == CAP_SET) {
cap_free(cap);
return TRUE;
}
cap_free(cap);
}
if (setpriority(PRIO_PROCESS, 0, nice_level) >= 0) {
pa_log_debug("setpriority() worked.");
return 0;
}
#ifdef HAVE_DBUS
/* Try to talk to RealtimeKit */
if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
pa_log("Failed to connect to system bus: %s\n", error.message);
dbus_error_free(&error);
errno = -EIO;
return -1;
}
r = rtkit_make_high_priority(bus, 0, nice_level);
dbus_connection_unref(bus);
if (r >= 0) {
pa_log_debug("RealtimeKit worked.");
return 0;
}
errno = -r;
#endif
return FALSE;
}
/* This is merely used for giving the user a hint. This is not correct
* for anything security related */
pa_bool_t pa_can_high_priority(void) {
if (geteuid() == 0)
return TRUE;
#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
{
struct rlimit rl;
if (getrlimit(RLIMIT_NICE, &rl) >= 0)
if (rl.rlim_cur >= 21 || rl.rlim_cur == RLIM_INFINITY)
return TRUE;
}
#endif
#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
{
cap_t cap;
if ((cap = cap_get_proc())) {
cap_flag_value_t flag = CAP_CLEAR;
if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
if (flag == CAP_SET) {
cap_free(cap);
return TRUE;
}
cap_free(cap);
}
}
#endif
return FALSE;
return -1;
}
/* Raise the priority of the current process as much as possible that
@ -680,22 +682,21 @@ pa_bool_t pa_can_high_priority(void) {
int pa_raise_priority(int nice_level) {
#ifdef HAVE_SYS_RESOURCE_H
if (setpriority(PRIO_PROCESS, 0, nice_level) < 0) {
int n;
int n;
for (n = nice_level+1; n < 0; n++) {
if (setpriority(PRIO_PROCESS, 0, n) == 0) {
pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
return 0;
}
}
pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
return -1;
if (set_nice(nice_level) >= 0) {
pa_log_info("Successfully gained nice level %i.", nice_level);
return 0;
}
pa_log_info("Successfully gained nice level %i.", nice_level);
for (n = nice_level+1; n < 0; n++)
if (set_nice(n) > 0) {
pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
return 0;
}
pa_log_info("Failed to acquire high-priority scheduling: %s", pa_cstrerror(errno));
return -1;
#endif
#ifdef OS_IS_WIN32
@ -703,9 +704,10 @@ int pa_raise_priority(int nice_level) {
if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
errno = EPERM;
return .-1;
} else
pa_log_info("Successfully gained high priority class.");
return -1;
}
pa_log_info("Successfully gained high priority class.");
}
#endif
@ -720,8 +722,8 @@ void pa_reset_priority(void) {
setpriority(PRIO_PROCESS, 0, 0);
memset(&sp, 0, sizeof(sp));
pa_assert_se(pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp) == 0);
pa_zero(sp);
pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp);
#endif
#ifdef OS_IS_WIN32

View file

@ -80,9 +80,6 @@ int pa_make_realtime(int rtprio);
int pa_raise_priority(int nice_level);
void pa_reset_priority(void);
pa_bool_t pa_can_realtime(void);
pa_bool_t pa_can_high_priority(void);
int pa_parse_boolean(const char *s) PA_GCC_PURE;
static inline const char *pa_yes_no(pa_bool_t b) {

189
src/pulsecore/rtkit.c Normal file
View file

@ -0,0 +1,189 @@
/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
Copyright 2009 Lennart Poettering
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
***/
#include <errno.h>
#include "rtkit.h"
#ifdef __linux__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
static pid_t _gettid(void) {
return (pid_t) syscall(SYS_gettid);
}
static int translate_error(const char *name) {
if (strcmp(name, DBUS_ERROR_NO_MEMORY) == 0)
return -ENOMEM;
if (strcmp(name, DBUS_ERROR_SERVICE_UNKNOWN) == 0 ||
strcmp(name, DBUS_ERROR_NAME_HAS_NO_OWNER) == 0)
return -ENOENT;
if (strcmp(name, DBUS_ERROR_ACCESS_DENIED) == 0 ||
strcmp(name, DBUS_ERROR_AUTH_FAILED) == 0)
return -EACCES;
return -EIO;
}
int rtkit_make_realtime(DBusConnection *connection, pid_t thread, int priority) {
DBusMessage *m = NULL, *r = NULL;
dbus_uint64_t u64;
dbus_uint32_t u32;
DBusError error;
int ret;
dbus_error_init(&error);
if (thread == 0)
thread = _gettid();
if (!(m = dbus_message_new_method_call(
RTKIT_SERVICE_NAME,
RTKIT_OBJECT_PATH,
"org.freedesktop.RealtimeKit1",
"MakeThreadRealtime"))) {
ret = -ENOMEM;
goto finish;
}
u64 = (dbus_uint64_t) thread;
u32 = (dbus_uint32_t) priority;
if (!dbus_message_append_args(
m,
DBUS_TYPE_UINT64, &u64,
DBUS_TYPE_UINT32, &u32,
DBUS_TYPE_INVALID)) {
ret = -ENOMEM;
goto finish;
}
if (!(r = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
ret = translate_error(error.name);
goto finish;
}
if (dbus_set_error_from_message(&error, r)) {
ret = translate_error(error.name);
goto finish;
}
ret = 0;
finish:
if (m)
dbus_message_unref(m);
if (r)
dbus_message_unref(r);
dbus_error_free(&error);
return ret;
}
int rtkit_make_high_priority(DBusConnection *connection, pid_t thread, int nice_level) {
DBusMessage *m = NULL, *r = NULL;
dbus_uint64_t u64;
dbus_int32_t s32;
DBusError error;
int ret;
dbus_error_init(&error);
if (thread == 0)
thread = _gettid();
if (!(m = dbus_message_new_method_call(
RTKIT_SERVICE_NAME,
RTKIT_OBJECT_PATH,
"org.freedesktop.RealtimeKit1",
"MakeThreadHighPriority"))) {
ret = -ENOMEM;
goto finish;
}
u64 = (dbus_uint64_t) thread;
s32 = (dbus_int32_t) nice_level;
if (!dbus_message_append_args(
m,
DBUS_TYPE_UINT64, &u64,
DBUS_TYPE_INT32, &s32,
DBUS_TYPE_INVALID)) {
ret = -ENOMEM;
goto finish;
}
if (!(r = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
ret = translate_error(error.name);
goto finish;
}
if (dbus_set_error_from_message(&error, r)) {
ret = translate_error(error.name);
goto finish;
}
ret = 0;
finish:
if (m)
dbus_message_unref(m);
if (r)
dbus_message_unref(r);
dbus_error_free(&error);
return ret;
}
#else
int rtkit_make_realtime(DBusConnection *connection, pid_t thread, int priority) {
return -ENOTSUP;
}
int rtkit_make_high_priority(DBusConnection *connection, pid_t thread, int nice_level) {
return -ENOTSUP;
}
#endif

62
src/pulsecore/rtkit.h Normal file
View file

@ -0,0 +1,62 @@
/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foortkithfoo
#define foortkithfoo
/***
Copyright 2009 Lennart Poettering
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
***/
#include <sys/types.h>
#include <dbus/dbus.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This is the reference implementation for a client for
* RealtimeKit. You don't have to use this, but if do, just copy these
* sources into your repository */
#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1"
#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1"
/* This is mostly equivalent to sched_setparam(thread, SCHED_RR, {
* .sched_priority = priority }). 'thread' needs to be a kernel thread
* id as returned by gettid(), not a pthread_t! If 'thread' is 0 the
* current thread is used. The returned value is a negative errno
* style error code, or 0 on success. */
int rtkit_make_realtime(DBusConnection *system_bus, pid_t thread, int priority);
/* This is mostly equivalent to setpriority(PRIO_PROCESS, thread,
* nice_level). 'thread' needs to be a kernel thread id as returned by
* gettid(), not a pthread_t! If 'thread' is 0 the current thread is
* used. The returned value is a negative errno style error code, or 0
* on success.*/
int rtkit_make_high_priority(DBusConnection *system_bus, pid_t thread, int nice_level);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -30,10 +30,6 @@
#include <string.h>
#include <errno.h>
#ifdef __linux__
#include <sys/utsname.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#else
@ -47,7 +43,6 @@
#include <pulsecore/rtclock.h>
#include <pulsecore/macro.h>
#include <pulsecore/llist.h>
#include <pulsecore/rtsig.h>
#include <pulsecore/flist.h>
#include <pulsecore/core-util.h>
#include <pulsecore/winsock.h>
@ -66,20 +61,9 @@ struct pa_rtpoll {
pa_bool_t scan_for_dead:1;
pa_bool_t running:1;
pa_bool_t installed:1;
pa_bool_t rebuild_needed:1;
pa_bool_t quit:1;
#ifdef HAVE_PPOLL
pa_bool_t timer_armed:1;
#ifdef __linux__
pa_bool_t dont_use_ppoll:1;
#endif
int rtsig;
sigset_t sigset_unblocked;
timer_t timer;
#endif
#ifdef DEBUG_TIMING
pa_usec_t timestamp;
pa_usec_t slept, awake;
@ -107,52 +91,20 @@ struct pa_rtpoll_item {
PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
static void signal_handler_noop(int s) { /* write(2, "signal\n", 7); */ }
pa_rtpoll *pa_rtpoll_new(void) {
pa_rtpoll *p;
p = pa_xnew(pa_rtpoll, 1);
#ifdef HAVE_PPOLL
#ifdef __linux__
/* ppoll is broken on Linux < 2.6.16 */
p->dont_use_ppoll = FALSE;
{
struct utsname u;
unsigned major, minor, micro;
pa_assert_se(uname(&u) == 0);
if (sscanf(u.release, "%u.%u.%u", &major, &minor, &micro) != 3 ||
(major < 2) ||
(major == 2 && minor < 6) ||
(major == 2 && minor == 6 && micro < 16))
p->dont_use_ppoll = TRUE;
}
#endif
p->rtsig = -1;
sigemptyset(&p->sigset_unblocked);
p->timer = (timer_t) -1;
p->timer_armed = FALSE;
#endif
p->n_pollfd_alloc = 32;
p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc);
p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc);
p->n_pollfd_used = 0;
memset(&p->next_elapse, 0, sizeof(p->next_elapse));
pa_zero(p->next_elapse);
p->timer_enabled = FALSE;
p->running = FALSE;
p->installed = FALSE;
p->scan_for_dead = FALSE;
p->rebuild_needed = FALSE;
p->quit = FALSE;
@ -167,46 +119,6 @@ pa_rtpoll *pa_rtpoll_new(void) {
return p;
}
void pa_rtpoll_install(pa_rtpoll *p) {
pa_assert(p);
pa_assert(!p->installed);
p->installed = TRUE;
#ifdef HAVE_PPOLL
# ifdef __linux__
if (p->dont_use_ppoll)
return;
# endif
if ((p->rtsig = pa_rtsig_get_for_thread()) < 0) {
pa_log_warn("Failed to reserve POSIX realtime signal.");
return;
}
pa_log_debug("Acquired POSIX realtime signal %s", pa_sig2str(p->rtsig));
{
sigset_t ss;
struct sigaction sa;
pa_assert_se(sigemptyset(&ss) == 0);
pa_assert_se(sigaddset(&ss, p->rtsig) == 0);
pa_assert_se(pthread_sigmask(SIG_BLOCK, &ss, &p->sigset_unblocked) == 0);
pa_assert_se(sigdelset(&p->sigset_unblocked, p->rtsig) == 0);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler_noop;
pa_assert_se(sigemptyset(&sa.sa_mask) == 0);
pa_assert_se(sigaction(p->rtsig, &sa, NULL) == 0);
/* We never reset the signal handler. Why should we? */
}
#endif
}
static void rtpoll_rebuild(pa_rtpoll *p) {
struct pollfd *e, *t;
@ -250,7 +162,6 @@ static void rtpoll_rebuild(pa_rtpoll *p) {
if (ra)
p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
}
static void rtpoll_item_destroy(pa_rtpoll_item *i) {
@ -279,11 +190,6 @@ void pa_rtpoll_free(pa_rtpoll *p) {
pa_xfree(p->pollfd);
pa_xfree(p->pollfd2);
#ifdef HAVE_PPOLL
if (p->timer != (timer_t) -1)
timer_delete(p->timer);
#endif
pa_xfree(p);
}
@ -321,7 +227,6 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait) {
pa_assert(p);
pa_assert(!p->running);
pa_assert(p->installed);
p->running = TRUE;
@ -402,22 +307,15 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait) {
/* OK, now let's sleep */
#ifdef HAVE_PPOLL
#ifdef __linux__
if (!p->dont_use_ppoll)
#endif
{
struct timespec ts;
ts.tv_sec = timeout.tv_sec;
ts.tv_nsec = timeout.tv_usec * 1000;
r = ppoll(p->pollfd, p->n_pollfd_used, (!wait || p->quit || p->timer_enabled) ? &ts : NULL, p->rtsig < 0 ? NULL : &p->sigset_unblocked);
r = ppoll(p->pollfd, p->n_pollfd_used, (!wait || p->quit || p->timer_enabled) ? &ts : NULL, NULL);
}
#ifdef __linux__
else
#endif
#endif
#else
r = poll(p->pollfd, p->n_pollfd_used, (!wait || p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1);
#endif
#ifdef DEBUG_TIMING
{
@ -472,73 +370,11 @@ finish:
return r < 0 ? r : !p->quit;
}
static void update_timer(pa_rtpoll *p) {
pa_assert(p);
#ifdef HAVE_PPOLL
#ifdef __linux__
if (p->dont_use_ppoll)
return;
#endif
if (p->timer == (timer_t) -1) {
struct sigevent se;
memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = p->rtsig;
if (timer_create(CLOCK_MONOTONIC, &se, &p->timer) < 0)
if (timer_create(CLOCK_REALTIME, &se, &p->timer) < 0) {
pa_log_warn("Failed to allocate POSIX timer: %s", pa_cstrerror(errno));
p->timer = (timer_t) -1;
}
}
if (p->timer != (timer_t) -1) {
struct itimerspec its;
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
sigset_t ss;
if (p->timer_armed) {
/* First disarm timer */
memset(&its, 0, sizeof(its));
pa_assert_se(timer_settime(p->timer, TIMER_ABSTIME, &its, NULL) == 0);
/* Remove a signal that might be waiting in the signal q */
pa_assert_se(sigemptyset(&ss) == 0);
pa_assert_se(sigaddset(&ss, p->rtsig) == 0);
sigtimedwait(&ss, NULL, &ts);
}
/* And install the new timer */
if (p->timer_enabled) {
memset(&its, 0, sizeof(its));
its.it_value.tv_sec = p->next_elapse.tv_sec;
its.it_value.tv_nsec = p->next_elapse.tv_usec*1000;
/* Make sure that 0,0 is not understood as
* "disarming" */
if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0)
its.it_value.tv_nsec = 1;
pa_assert_se(timer_settime(p->timer, TIMER_ABSTIME, &its, NULL) == 0);
}
p->timer_armed = p->timer_enabled;
}
#endif
}
void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, pa_usec_t usec) {
pa_assert(p);
pa_timeval_store(&p->next_elapse, usec);
p->timer_enabled = TRUE;
update_timer(p);
}
void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
@ -550,8 +386,6 @@ void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
pa_rtclock_get(&p->next_elapse);
pa_timeval_add(&p->next_elapse, usec);
p->timer_enabled = TRUE;
update_timer(p);
}
void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
@ -559,8 +393,6 @@ void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
memset(&p->next_elapse, 0, sizeof(p->next_elapse));
p->timer_enabled = FALSE;
update_timer(p);
}
pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds) {

View file

@ -62,9 +62,6 @@ typedef enum pa_rtpoll_priority {
pa_rtpoll *pa_rtpoll_new(void);
void pa_rtpoll_free(pa_rtpoll *p);
/* Install the rtpoll in the current thread */
void pa_rtpoll_install(pa_rtpoll *p);
/* Sleep on the rtpoll until the time event, or any of the fd events
* is triggered. If "wait" is 0 we don't sleep but only update the
* struct pollfd. Returns negative on error, positive if the loop

View file

@ -1,131 +0,0 @@
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; 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 <signal.h>
#include <pulsecore/macro.h>
#include <pulsecore/flist.h>
#include <pulsecore/once.h>
#include <pulsecore/thread.h>
#include <pulsecore/core-util.h>
#include "rtsig.h"
#ifdef SIGRTMIN
static void _free_rtsig(void *p) {
pa_rtsig_put(PA_PTR_TO_INT(p));
}
PA_STATIC_FLIST_DECLARE(rtsig_flist, pa_make_power_of_two((unsigned) (SIGRTMAX-SIGRTMIN+1)), NULL);
PA_STATIC_TLS_DECLARE(rtsig_tls, _free_rtsig);
static pa_atomic_t rtsig_current = PA_ATOMIC_INIT(-1);
static int rtsig_start = -1, rtsig_end = -1;
int pa_rtsig_get(void) {
void *p;
int sig;
if ((p = pa_flist_pop(PA_STATIC_FLIST_GET(rtsig_flist))))
return PA_PTR_TO_INT(p);
sig = pa_atomic_dec(&rtsig_current);
pa_assert(sig <= SIGRTMAX);
pa_assert(sig <= rtsig_end);
if (sig < rtsig_start) {
pa_atomic_inc(&rtsig_current);
return -1;
}
return sig;
}
int pa_rtsig_get_for_thread(void) {
int sig;
void *p;
if ((p = PA_STATIC_TLS_GET(rtsig_tls)))
return PA_PTR_TO_INT(p);
if ((sig = pa_rtsig_get()) < 0)
return -1;
PA_STATIC_TLS_SET(rtsig_tls, PA_INT_TO_PTR(sig));
return sig;
}
void pa_rtsig_put(int sig) {
pa_assert(sig >= rtsig_start);
pa_assert(sig <= rtsig_end);
pa_assert_se(pa_flist_push(PA_STATIC_FLIST_GET(rtsig_flist), PA_INT_TO_PTR(sig)) >= 0);
}
void pa_rtsig_configure(int start, int end) {
int s;
sigset_t ss;
pa_assert(pa_atomic_load(&rtsig_current) == -1);
pa_assert(SIGRTMIN <= start);
pa_assert(start <= end);
pa_assert(end <= SIGRTMAX);
rtsig_start = start;
rtsig_end = end;
sigemptyset(&ss);
for (s = rtsig_start; s <= rtsig_end; s++)
pa_assert_se(sigaddset(&ss, s) == 0);
pa_assert(pthread_sigmask(SIG_BLOCK, &ss, NULL) == 0);
/* We allocate starting from the end */
pa_atomic_store(&rtsig_current, rtsig_end);
}
#else /* SIGRTMIN */
int pa_rtsig_get(void) {
return -1;
}
int pa_rtsig_get_for_thread(void) {
return -1;
}
void pa_rtsig_put(int sig) {
}
void pa_rtsig_configure(int start, int end) {
}
#endif /* SIGRTMIN */

View file

@ -1,39 +0,0 @@
#ifndef foopulsertsighfoo
#define foopulsertsighfoo
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
/* Return the next unused POSIX Realtime signals */
int pa_rtsig_get(void);
/* If not called before in the current thread, return the next unused
* rtsig, and install it in a TLS region and give it up automatically
* when the thread shuts down */
int pa_rtsig_get_for_thread(void);
/* Give an rtsig back. */
void pa_rtsig_put(int sig);
/* Block all RT signals */
void pa_rtsig_configure(int start, int end);
#endif

View file

@ -26,7 +26,6 @@
#include <pulsecore/log.h>
#include <pulsecore/rtpoll.h>
#include <pulsecore/rtsig.h>
static int before(pa_rtpoll_item *i) {
pa_log("before");
@ -47,10 +46,6 @@ int main(int argc, char *argv[]) {
pa_rtpoll_item *i, *w;
struct pollfd *pollfd;
#ifdef SIGRTMIN
pa_rtsig_configure(SIGRTMIN+10, SIGRTMAX);
#endif
p = pa_rtpoll_new();
i = pa_rtpoll_item_new(p, PA_RTPOLL_EARLY, 1);
@ -64,7 +59,6 @@ int main(int argc, char *argv[]) {
w = pa_rtpoll_item_new(p, PA_RTPOLL_NORMAL, 0);
pa_rtpoll_item_set_before_callback(w, worker);
pa_rtpoll_install(p);
pa_rtpoll_set_timer_relative(p, 10000000); /* 10 s */
pa_rtpoll_run(p, 1);