]> code.delx.au - pulseaudio/commitdiff
Merge most of elmarco/rtclock2
authorLennart Poettering <lennart@poettering.net>
Mon, 22 Jun 2009 21:09:46 +0000 (23:09 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 22 Jun 2009 21:09:46 +0000 (23:09 +0200)
Merge commit 'e4d914c945c13d23b131d7ba75fbdd03cb6d0043'

42 files changed:
.gitignore
Makefile.am
bootstrap.sh
configure.ac
m4/shave.m4 [deleted file]
shave-libtool.in [deleted file]
shave.in [deleted file]
src/Makefile.am
src/daemon/caps.c
src/daemon/caps.h
src/daemon/daemon-conf.c
src/daemon/daemon.conf.in
src/daemon/default.pa.in
src/daemon/main.c
src/modules/alsa/alsa-sink.c
src/modules/alsa/alsa-source.c
src/modules/bluetooth/module-bluetooth-device.c
src/modules/jack/module-jack-sink.c
src/modules/jack/module-jack-source.c
src/modules/module-card-restore.c
src/modules/module-combine.c
src/modules/module-device-restore.c
src/modules/module-esound-sink.c
src/modules/module-intended-roles.c [new file with mode: 0644]
src/modules/module-null-sink.c
src/modules/module-pipe-sink.c
src/modules/module-pipe-source.c
src/modules/module-rescue-streams.c
src/modules/module-sine-source.c
src/modules/module-stream-restore.c
src/modules/module-tunnel.c
src/modules/oss/module-oss.c
src/modules/raop/module-raop-sink.c
src/pulsecore/core-util.c
src/pulsecore/core-util.h
src/pulsecore/rtkit.c [new file with mode: 0644]
src/pulsecore/rtkit.h [new file with mode: 0644]
src/pulsecore/rtpoll.c
src/pulsecore/rtpoll.h
src/pulsecore/rtsig.c [deleted file]
src/pulsecore/rtsig.h [deleted file]
src/tests/rtpoll-test.c

index fae5b471c9a451d4aa7b90b7366b8156dd962175..85c0fe5f0d59506f4ae5308f03a11a89735b482c 100644 (file)
@@ -1,6 +1,4 @@
 .version
-shave
-shave-libtool
 .*.swp
 ABOUT-NLS
 intltool-extract.in
index 2448e7489f4e19696c7a756c0474a78766df2b8e..4d45a07d0966d1d0c647b049534eb31ffa1a2f5b 100644 (file)
@@ -62,12 +62,6 @@ dist-hook:
        fi
        echo $(VERSION) > $(distdir)/.tarball-version
 
-update-shave:
-       for i in shave.in shave.m4 shave-libtool.in; do \
-               wget -O $$i http://git.lespiau.name/cgit/shave/blob/\?path=shave/$$i ; \
-       done
-       mv shave.m4 m4/
-
 .PHONY: homepage distcleancheck doxygen
 
 # see git-version-gen
index c7737a6eddc0dd1d273a838d56ae443a1d2532b9..d5025db61a06056b6a4ca22224cc7ab84b98e520 100755 (executable)
@@ -16,7 +16,7 @@
 # along with PulseAudio; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
-VERSION=1.10
+VERSION=1.11
 
 run_versioned() {
     local P
@@ -83,7 +83,7 @@ else
     run_versioned automake "$VERSION" --copy --foreign --add-missing
 
     if test "x$NOCONFIGURE" = "x"; then
-        CFLAGS="-g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --enable-force-preopen --enable-shave "$@"
+        CFLAGS="-g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --enable-force-preopen "$@"
         make clean
     fi
 fi
index bb8afa4f17470743104e4dca989346ccc7989f16..4e385ce073e1edc8606f6f624196fdc5d1bccedf 100644 (file)
@@ -27,7 +27,7 @@ AC_INIT([pulseaudio], m4_esyscmd([./git-version-gen .tarball-version]),
 AC_CONFIG_SRCDIR([src/daemon/main.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_HEADERS([config.h])
-AM_INIT_AUTOMAKE([foreign 1.10 -Wall -Wno-portability])
+AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules])
 
 m4_define(pa_major, `echo $VERSION |  cut -d. -f 1`)
 m4_define(pa_minor, `echo $VERSION |  cut -d. -f 2`)
@@ -76,6 +76,8 @@ case $host in
       ;;
 esac
 
+AM_SILENT_RULES([yes])
+
 #### Checks for programs. ####
 
 # mkdir -p
@@ -1152,44 +1154,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 +1240,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
@@ -1363,8 +1318,6 @@ AM_CONDITIONAL([FORCE_PREOPEN], [test "x$FORCE_PREOPEN" = "xyes"])
 
 AC_CONFIG_FILES([
 Makefile
-shave
-shave-libtool
 src/Makefile
 man/Makefile
 libpulse.pc
@@ -1377,7 +1330,6 @@ src/pulse/version.h
 po/Makefile.in
 ])
 
-SHAVE_INIT
 AC_OUTPUT
 
 # ==========================================================================
@@ -1461,11 +1413,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 +1466,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 +1473,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}
diff --git a/m4/shave.m4 b/m4/shave.m4
deleted file mode 100644 (file)
index 0a3509e..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-dnl Make automake/libtool output more friendly to humans
-dnl  Damien Lespiau <damien.lespiau@gmail.com>
-dnl
-dnl SHAVE_INIT([shavedir],[default_mode])
-dnl
-dnl shavedir: the directory where the shave scripts are, it defaults to
-dnl           $(top_builddir)
-dnl default_mode: (enable|disable) default shave mode.  This parameter
-dnl               controls shave's behaviour when no option has been
-dnl               given to configure.  It defaults to disable.
-dnl
-dnl * SHAVE_INIT should be called late in your configure.(ac|in) file (just
-dnl   before AC_CONFIG_FILE/AC_OUTPUT is perfect.  This macro rewrites CC and
-dnl   LIBTOOL, you don't want the configure tests to have these variables
-dnl   re-defined.
-dnl * This macro requires GNU make's -s option.
-
-AC_DEFUN([_SHAVE_ARG_ENABLE],
-[
-  AC_ARG_ENABLE([shave],
-    AS_HELP_STRING(
-      [--enable-shave],
-      [use shave to make the build pretty [[default=$1]]]),,
-      [enable_shave=$1]
-    )
-])
-
-AC_DEFUN([SHAVE_INIT],
-[
-  dnl you can tweak the default value of enable_shave
-  m4_if([$2], [enable], [_SHAVE_ARG_ENABLE(yes)], [_SHAVE_ARG_ENABLE(no)])
-
-  if test x"$enable_shave" = xyes; then
-    dnl where can we find the shave scripts?
-    m4_if([$1],,
-      [shavedir="$ac_pwd"],
-      [shavedir="$ac_pwd/$1"])
-    AC_SUBST(shavedir)
-
-    dnl make is now quiet
-    AC_SUBST([MAKEFLAGS], [-s])
-    AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`'])
-
-    dnl we need sed
-    AC_CHECK_PROG(SED,sed,sed,false)
-
-    dnl substitute libtool
-    SHAVE_SAVED_LIBTOOL=$LIBTOOL
-    LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'"
-    AC_SUBST(LIBTOOL)
-
-    dnl substitute cc/cxx
-    SHAVE_SAVED_CC=$CC
-    SHAVE_SAVED_CXX=$CXX
-    SHAVE_SAVED_FC=$FC
-    SHAVE_SAVED_F77=$F77
-    SHAVE_SAVED_OBJC=$OBJC
-    CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}"
-    CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}"
-    FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}"
-    F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}"
-    OBJC="${SHELL} ${shavedir}/shave objc ${SHAVE_SAVED_OBJC}"
-    AC_SUBST(CC)
-    AC_SUBST(CXX)
-    AC_SUBST(FC)
-    AC_SUBST(F77)
-    AC_SUBST(OBJC)
-
-    V=@
-  else
-    V=1
-  fi
-  Q='$(V:1=)'
-  AC_SUBST(V)
-  AC_SUBST(Q)
-])
-
diff --git a/shave-libtool.in b/shave-libtool.in
deleted file mode 100644 (file)
index 1f3a720..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/sh
-
-# we need sed
-SED=@SED@
-if test -z "$SED" ; then
-SED=sed
-fi
-
-lt_unmangle ()
-{
-   last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
-}
-
-# the real libtool to use
-LIBTOOL="$1"
-shift
-
-# if 1, don't print anything, the underlaying wrapper will do it
-pass_though=0
-
-# scan the arguments, keep the right ones for libtool, and discover the mode
-preserved_args=
-while test "$#" -gt 0; do
-    opt="$1"
-    shift
-
-    case $opt in
-    --mode=*)
-        mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
-        preserved_args="$preserved_args $opt"
-        ;;
-    -o)
-        lt_output="$1"
-        preserved_args="$preserved_args $opt"
-       ;;
-    *)
-        preserved_args="$preserved_args $opt"
-        ;;
-      esac
-done
-
-case "$mode" in
-compile)
-    # shave will be called and print the actual CC/CXX/LINK line
-    preserved_args="$preserved_args --shave-mode=$mode"
-    pass_though=1
-    ;;
-link)
-    preserved_args="$preserved_args --shave-mode=$mode"
-    Q="  LINK  "
-    ;;
-*)
-    # let's u
-    # echo "*** libtool: Unimplemented mode: $mode, fill a bug report"
-    ;;
-esac
-
-lt_unmangle "$lt_output"
-output=$last_result
-
-if test -z $V; then
-    if test $pass_though -eq 0; then
-        echo "$Q$output"
-    fi
-    $LIBTOOL --silent $preserved_args
-else
-    echo $LIBTOOL $preserved_args
-    $LIBTOOL $preserved_args
-fi
diff --git a/shave.in b/shave.in
deleted file mode 100644 (file)
index 5c16f27..0000000
--- a/shave.in
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/bin/sh
-
-# we need sed
-SED=@SED@
-if test -z "$SED" ; then
-SED=sed
-fi
-
-lt_unmangle ()
-{
-   last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'`
-}
-
-# the tool to wrap (cc, cxx, ar, ranlib, ..)
-tool="$1"
-shift
-
-# the reel tool (to call)
-REEL_TOOL="$1"
-shift
-
-pass_through=0
-preserved_args=
-while test "$#" -gt 0; do
-    opt="$1"
-    shift
-
-    case $opt in
-    --shave-mode=*)
-        mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'`
-       ;;
-    -o)
-        lt_output="$1"
-        preserved_args="$preserved_args $opt"
-       ;;
-    *)
-        preserved_args="$preserved_args $opt"
-        ;;
-      esac
-done
-
-# mode=link is handled in the libtool wrapper
-case "$mode,$tool" in
-link,*)
-    pass_through=1
-    ;;
-*,cxx)
-    Q="  CXX   "
-    ;;
-*,cc)
-    Q="  CC    "
-    ;;
-*,fc)
-    Q="  FC    "
-    ;;
-*,f77)
-    Q="  F77   "
-    ;;
-*,objc)
-    Q="  OBJC   "
-    ;;
-*,*)
-    # should not happen
-    Q="  CC    "
-    ;;
-esac
-
-lt_unmangle "$lt_output"
-output=$last_result
-
-if test -z $V; then
-    if test $pass_through -eq 0; then
-        echo "$Q$output"
-    fi
-    $REEL_TOOL $preserved_args
-else
-    echo $REEL_TOOL $preserved_args
-    $REEL_TOOL $preserved_args
-fi
index b4904803b1e401f99b8b18d694e350c09686c62d..c580ece89a7fd3ace0109722726a1aaeef988b6e 100644 (file)
@@ -119,7 +119,6 @@ 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 \
@@ -189,16 +188,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          #
 ###################################
@@ -579,6 +568,7 @@ libpulsecommon_@PA_MAJORMINORMICRO@_la_SOURCES = \
                pulsecore/core-error.c pulsecore/core-error.h \
                pulsecore/core-rtclock.c pulsecore/core-rtclock.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 \
@@ -828,7 +818,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 \
@@ -982,6 +971,7 @@ modlibexec_LTLIBRARIES += \
                module-default-device-restore.la \
                module-always-sink.la \
                module-rescue-streams.la \
+               module-intended-roles.la \
                module-suspend-on-idle.la \
                module-http-protocol-tcp.la \
                module-sine.la \
@@ -1215,6 +1205,7 @@ SYMDEF_FILES = \
                modules/module-default-device-restore-symdef.h \
                modules/module-always-sink-symdef.h \
                modules/module-rescue-streams-symdef.h \
+               modules/module-intended-roles-symdef.h \
                modules/module-suspend-on-idle-symdef.h \
                modules/module-hal-detect-symdef.h \
                modules/module-udev-detect-symdef.h \
@@ -1547,6 +1538,12 @@ module_rescue_streams_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_rescue_streams_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la
 module_rescue_streams_la_CFLAGS = $(AM_CFLAGS)
 
+# Automatically move streams to devices that are intended for their roles
+module_intended_roles_la_SOURCES = modules/module-intended-roles.c
+module_intended_roles_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_intended_roles_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la
+module_intended_roles_la_CFLAGS = $(AM_CFLAGS)
+
 # Suspend-on-idle module
 module_suspend_on_idle_la_SOURCES = modules/module-suspend-on-idle.c
 module_suspend_on_idle_la_LDFLAGS = $(MODULE_LDFLAGS)
@@ -1661,11 +1658,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' \
@@ -1742,6 +1735,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 {" ; \
index d2ae8d0e72797dcba27ba8184aadbebf35bf82c0..294be494ed073b655b5783e93952b4dad4bbed13 100644 (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
+}
index 94241a9a0d1b61bba1625274de45a23068472db1..5d0ee62e0bc1721909868d9f1272309fdcdcd3e9 100644 (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
index 664e4fdea2d885731f51f16f65d74491b866c6d2..9010f2f6528d085e6df7fb450bbfc5422f6660ca 100644 (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,
index d119716dc8cc0a2ed3031cde7c2f037e8393d292..6931359c1d1fb6aee15b160cebd1f6f83a52d75e 100644 (file)
@@ -33,7 +33,7 @@
 ; high-priority = yes
 ; nice-level = -11
 
-; realtime-scheduling = no
+; realtime-scheduling = yes
 ; realtime-priority = 5
 
 ; exit-idle-time = 20
index a35ff8ff480f9e2e108cbc2c4b985567620ca5dd..00c000eb9d82104c82892134bcedf4c3a8cd923d 100755 (executable)
@@ -100,6 +100,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
 
index 399034e96789a340b785b7bac1ea8f570eb74173..22759a3850b7c1652dfbce902c76282b09e78a11 100644 (file)
@@ -85,7 +85,7 @@
 #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>
 #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 +380,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 +423,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 +430,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 +462,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 +546,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 +694,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 +749,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 +797,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)
index 9116a69fc20662a179cae93bafd7f37771aeeddd..c584362dc553c486f3d02257e67f9e1533a2d387 100644 (file)
@@ -1213,7 +1213,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;
index ede9306f1c501ee2ee57f173c7b591883fadddf6..a6760e1e7686287d2d11fae71ff4198db9bb0219 100644 (file)
@@ -1095,7 +1095,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;
index 68ac3acc3d31f7690b3393f0bbb4b229ca94e69b..e7c6d5e404028da0f2d14932513ca24ff7aac924 100644 (file)
@@ -1266,7 +1266,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;
index 290038e72973d946926e81b28655431270175f21..fc976fa72a6d1def62e5e0817e1596df6e637895 100644 (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;
index ef89a98e5633d3d3c1bf91527fbcc41e24bab484..a898e0e5ac8430df5d637fb475981caea41c3eb0 100644 (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;
index 6b057b4ccc67fbf204803b3b2b5a05db3597dee8..7dea94f78740aebc20465ce2347474348726a442 100644 (file)
@@ -195,7 +195,7 @@ static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new
         if (!new_data->active_profile) {
             pa_log_info("Restoring profile for card %s.", new_data->name);
             pa_card_new_data_set_profile(new_data, e->profile);
-            new_data->save_profile = FALSE;
+            new_data->save_profile = TRUE;
         } else
             pa_log_debug("Not restoring profile for card %s, because already set.", new_data->name);
 
index 757dbda43960baa569dbdba5c76a51d2480af73b..d50e59aeb1d94047cf211a20dcb5ef3ba74d3ace 100644 (file)
@@ -278,7 +278,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_now();
     u->thread_info.in_null_mode = FALSE;
index 8c15d454ff42e30f2d8279ac681d8a743392ce39..120b762c143eb65f1af047204a827c919ef80d02 100644 (file)
@@ -292,10 +292,10 @@ static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new
     char *name;
     struct entry *e;
 
+    pa_assert(c);
     pa_assert(new_data);
-
-    if (!u->restore_port)
-        return PA_HOOK_OK;
+    pa_assert(u);
+    pa_assert(u->restore_port);
 
     name = pa_sprintf_malloc("sink:%s", new_data->name);
 
@@ -305,7 +305,7 @@ static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new
             if (!new_data->active_port) {
                 pa_log_info("Restoring port for sink %s.", name);
                 pa_sink_new_data_set_port(new_data, e->port);
-                new_data->save_port = FALSE;
+                new_data->save_port = TRUE;
             } else
                 pa_log_debug("Not restoring port for sink %s, because already set.", name);
         }
@@ -322,7 +322,10 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *
     char *name;
     struct entry *e;
 
+    pa_assert(c);
     pa_assert(new_data);
+    pa_assert(u);
+    pa_assert(u->restore_volume || u->restore_muted);
 
     name = pa_sprintf_malloc("sink:%s", new_data->name);
 
@@ -339,7 +342,7 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *
                 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
                 pa_sink_new_data_set_volume(new_data, &v);
 
-                new_data->save_volume = FALSE;
+                new_data->save_volume = TRUE;
             } else
                 pa_log_debug("Not restoring volume for sink %s, because already set.", new_data->name);
         }
@@ -349,7 +352,7 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *
             if (!new_data->muted_is_set) {
                 pa_log_info("Restoring mute state for sink %s.", new_data->name);
                 pa_sink_new_data_set_muted(new_data, e->muted);
-                new_data->save_muted = FALSE;
+                new_data->save_muted = TRUE;
             } else
                 pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
         }
@@ -366,10 +369,10 @@ static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data
     char *name;
     struct entry *e;
 
+    pa_assert(c);
     pa_assert(new_data);
-
-    if (!u->restore_port)
-        return PA_HOOK_OK;
+    pa_assert(u);
+    pa_assert(u->restore_port);
 
     name = pa_sprintf_malloc("source:%s", new_data->name);
 
@@ -379,7 +382,7 @@ static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data
             if (!new_data->active_port) {
                 pa_log_info("Restoring port for source %s.", name);
                 pa_source_new_data_set_port(new_data, e->port);
-                new_data->save_port = FALSE;
+                new_data->save_port = TRUE;
             } else
                 pa_log_debug("Not restoring port for source %s, because already set.", name);
         }
@@ -396,7 +399,10 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da
     char *name;
     struct entry *e;
 
+    pa_assert(c);
     pa_assert(new_data);
+    pa_assert(u);
+    pa_assert(u->restore_volume || u->restore_muted);
 
     name = pa_sprintf_malloc("source:%s", new_data->name);
 
@@ -413,7 +419,7 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da
                 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
                 pa_source_new_data_set_volume(new_data, &v);
 
-                new_data->save_volume = FALSE;
+                new_data->save_volume = TRUE;
             } else
                 pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name);
         }
@@ -423,7 +429,7 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da
             if (!new_data->muted_is_set) {
                 pa_log_info("Restoring mute state for source %s.", new_data->name);
                 pa_source_new_data_set_muted(new_data, e->muted);
-                new_data->save_muted = FALSE;
+                new_data->save_muted = TRUE;
             } else
                 pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
         }
index b26b465dfeb0a1b572e3a5a8da80f4348d28d824..d7c678ca9d5a3cda1961e3d67ac6cd335ee33aed 100644 (file)
@@ -201,7 +201,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_now());
 
diff --git a/src/modules/module-intended-roles.c b/src/modules/module-intended-roles.c
new file mode 100644 (file)
index 0000000..036600e
--- /dev/null
@@ -0,0 +1,439 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2009 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
+  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 <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <pulse/xmalloc.h>
+#include <pulse/volume.h>
+#include <pulse/timeval.h>
+#include <pulse/util.h>
+
+#include <pulsecore/core-error.h>
+#include <pulsecore/module.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/log.h>
+#include <pulsecore/core-subscribe.h>
+#include <pulsecore/sink-input.h>
+#include <pulsecore/source-output.h>
+#include <pulsecore/namereg.h>
+#include <pulsecore/protocol-native.h>
+#include <pulsecore/pstream.h>
+#include <pulsecore/pstream-util.h>
+#include <pulsecore/database.h>
+
+#include "module-stream-restore-symdef.h"
+
+PA_MODULE_AUTHOR("Lennart Poettering");
+PA_MODULE_DESCRIPTION("Automatically set device of streams based of intended roles of devices");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(TRUE);
+PA_MODULE_USAGE(
+        "on_hotplug=<When new device becomes available, recheck streams?> "
+        "on_rescue=<When device becomes unavailable, recheck streams?>");
+
+static const char* const valid_modargs[] = {
+    "on_hotplug",
+    "on_rescue",
+    NULL
+};
+
+struct userdata {
+    pa_core *core;
+    pa_module *module;
+    pa_hook_slot
+        *sink_input_new_hook_slot,
+        *source_output_new_hook_slot,
+        *sink_put_hook_slot,
+        *source_put_hook_slot,
+        *sink_unlink_hook_slot,
+        *source_unlink_hook_slot;
+
+    pa_bool_t on_hotplug:1;
+    pa_bool_t on_rescue:1;
+};
+
+static pa_bool_t role_match(pa_proplist *proplist, const char *role) {
+    const char *ir;
+    char *r;
+    const char *state;
+
+    if (!(ir = pa_proplist_gets(proplist, PA_PROP_DEVICE_INTENDED_ROLES)))
+        return FALSE;
+
+    while ((r = pa_split_spaces(ir, &state))) {
+
+        if (pa_streq(role, r)) {
+            pa_xfree(r);
+            return TRUE;
+        }
+
+        pa_xfree(r);
+    }
+
+    return FALSE;
+}
+
+static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u) {
+    const char *role;
+    pa_sink *s, *def;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(new_data);
+    pa_assert(u);
+
+    if (!new_data->proplist) {
+        pa_log_debug("New stream lacks property data.");
+        return PA_HOOK_OK;
+    }
+
+    if (new_data->sink) {
+        pa_log_debug("Not setting device for stream %s, because already set.", pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)));
+        return PA_HOOK_OK;
+    }
+
+    if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE))) {
+        pa_log_debug("Not setting device for stream %s, because it lacks role.", pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)));
+        return PA_HOOK_OK;
+    }
+
+    /* Prefer the default sink over any other sink, just in case... */
+    if ((def = pa_namereg_get_default_sink(c)))
+        if (role_match(def->proplist, role)) {
+            new_data->sink = def;
+            new_data->save_sink = FALSE;
+            return PA_HOOK_OK;
+        }
+
+    PA_IDXSET_FOREACH(s, c->sinks, idx) {
+        if (s == def)
+            continue;
+
+        if (role_match(s->proplist, role)) {
+            new_data->sink = s;
+            new_data->save_sink = FALSE;
+            return PA_HOOK_OK;
+        }
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
+    const char *role;
+    pa_source *s, *def;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(new_data);
+    pa_assert(u);
+
+    if (!new_data->proplist) {
+        pa_log_debug("New stream lacks property data.");
+        return PA_HOOK_OK;
+    }
+
+    if (new_data->source) {
+        pa_log_debug("Not setting device for stream %s, because already set.", pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)));
+        return PA_HOOK_OK;
+    }
+
+    if (!(role = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_ROLE))) {
+        pa_log_debug("Not setting device for stream %s, because it lacks role.", pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)));
+        return PA_HOOK_OK;
+    }
+
+    /* Prefer the default source over any other source, just in case... */
+    if ((def = pa_namereg_get_default_source(c)))
+        if (role_match(def->proplist, role)) {
+            new_data->source = def;
+            new_data->save_source = FALSE;
+            return PA_HOOK_OK;
+        }
+
+    PA_IDXSET_FOREACH(s, c->sources, idx) {
+        if (s == def)
+            continue;
+
+        if (role_match(s->proplist, role)) {
+            new_data->source = s;
+            new_data->save_source = FALSE;
+            return PA_HOOK_OK;
+        }
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
+    pa_sink_input *si;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(sink);
+    pa_assert(u);
+    pa_assert(u->on_hotplug);
+
+    PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
+        const char *role;
+
+        if (si->sink == sink)
+            continue;
+
+        if (si->save_sink)
+            continue;
+
+        if (!(role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE)))
+            continue;
+
+        if (role_match(si->sink->proplist, role))
+            continue;
+
+        if (!role_match(sink->proplist, role))
+            continue;
+
+        pa_sink_input_move_to(si, sink, FALSE);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
+    pa_source_output *so;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(source);
+    pa_assert(u);
+    pa_assert(u->on_hotplug);
+
+    PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
+        const char *role;
+
+        if (so->source == source)
+            continue;
+
+        if (so->save_source)
+            continue;
+
+        if (so->direct_on_input)
+            continue;
+
+        if (!(role = pa_proplist_gets(so->proplist, PA_PROP_MEDIA_ROLE)))
+            continue;
+
+        if (role_match(so->source->proplist, role))
+            continue;
+
+        if (!role_match(source->proplist, role))
+            continue;
+
+        pa_source_output_move_to(so, source, FALSE);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
+    pa_sink_input *si;
+    uint32_t idx;
+    pa_sink *def;
+
+    pa_assert(c);
+    pa_assert(sink);
+    pa_assert(u);
+    pa_assert(u->on_rescue);
+
+    /* There's no point in doing anything if the core is shut down anyway */
+    if (c->state == PA_CORE_SHUTDOWN)
+        return PA_HOOK_OK;
+
+    /* If there not default sink, then there is no sink at all */
+    if (!(def = pa_namereg_get_default_sink(c)))
+        return PA_HOOK_OK;
+
+    PA_IDXSET_FOREACH(si, sink->inputs, idx) {
+        const char *role;
+        uint32_t jdx;
+        pa_sink *d;
+
+        if (!(role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE)))
+            continue;
+
+        /* Would the default sink fit? If so, let's use it */
+        if (def != sink && role_match(def->proplist, role)) {
+            pa_sink_input_move_to(si, def, FALSE);
+            continue;
+        }
+
+        /* Try to find some other fitting sink */
+        PA_IDXSET_FOREACH(d, c->sinks, jdx) {
+            if (d == def || d == sink)
+                continue;
+
+            if (role_match(d->proplist, role)) {
+                pa_sink_input_move_to(si, d, FALSE);
+                break;
+            }
+        }
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
+    pa_source_output *so;
+    uint32_t idx;
+    pa_source *def;
+
+    pa_assert(c);
+    pa_assert(source);
+    pa_assert(u);
+    pa_assert(u->on_rescue);
+
+    /* There's no point in doing anything if the core is shut down anyway */
+    if (c->state == PA_CORE_SHUTDOWN)
+        return PA_HOOK_OK;
+
+    /* If there not default source, then there is no source at all */
+    if (!(def = pa_namereg_get_default_source(c)))
+        return PA_HOOK_OK;
+
+    PA_IDXSET_FOREACH(so, source->outputs, idx) {
+        const char *role;
+        uint32_t jdx;
+        pa_source *d;
+
+        if (so->direct_on_input)
+            continue;
+
+        if (!(role = pa_proplist_gets(so->proplist, PA_PROP_MEDIA_ROLE)))
+            continue;
+
+        /* Would the default source fit? If so, let's use it */
+        if (def != source && role_match(def->proplist, role) && !source->monitor_of == !def->monitor_of) {
+            pa_source_output_move_to(so, def, FALSE);
+            continue;
+        }
+
+        /* Try to find some other fitting source */
+        PA_IDXSET_FOREACH(d, c->sources, jdx) {
+            if (d == def || d == source)
+                continue;
+
+            if (role_match(d->proplist, role) && !source->monitor_of == !d->monitor_of) {
+                pa_source_output_move_to(so, d, FALSE);
+                break;
+            }
+        }
+    }
+
+    return PA_HOOK_OK;
+}
+
+int pa__init(pa_module*m) {
+    pa_modargs *ma = NULL;
+    struct userdata *u;
+    pa_bool_t on_hotplug = TRUE, on_rescue = TRUE;
+
+    pa_assert(m);
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log("Failed to parse module arguments");
+        goto fail;
+    }
+
+    if (pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
+        pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
+        pa_log("on_hotplug= and on_rescue= expect boolean arguments");
+        goto fail;
+    }
+
+    m->userdata = u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
+    u->on_hotplug = on_hotplug;
+    u->on_rescue = on_rescue;
+
+    /* A little bit later than module-stream-restore */
+    u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY+10, (pa_hook_cb_t) sink_input_new_hook_callback, u);
+    u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY+10, (pa_hook_cb_t) source_output_new_hook_callback, u);
+
+    if (on_hotplug) {
+        /* A little bit later than module-stream-restore */
+        u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) sink_put_hook_callback, u);
+        u->source_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) source_put_hook_callback, u);
+    }
+
+    if (on_rescue) {
+        /* A little bit later than module-stream-restore, a little bit earlier than module-rescue-streams, ... */
+        u->sink_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+10, (pa_hook_cb_t) sink_unlink_hook_callback, NULL);
+        u->source_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+10, (pa_hook_cb_t) source_unlink_hook_callback, NULL);
+    }
+
+    pa_modargs_free(ma);
+    return 0;
+
+fail:
+    pa__done(m);
+
+    if (ma)
+        pa_modargs_free(ma);
+
+    return  -1;
+}
+
+void pa__done(pa_module*m) {
+    struct userdata* u;
+
+    pa_assert(m);
+
+    if (!(u = m->userdata))
+        return;
+
+    if (u->sink_input_new_hook_slot)
+        pa_hook_slot_free(u->sink_input_new_hook_slot);
+    if (u->source_output_new_hook_slot)
+        pa_hook_slot_free(u->source_output_new_hook_slot);
+
+    if (u->sink_put_hook_slot)
+        pa_hook_slot_free(u->sink_put_hook_slot);
+    if (u->source_put_hook_slot)
+        pa_hook_slot_free(u->source_put_hook_slot);
+
+    if (u->sink_unlink_hook_slot)
+        pa_hook_slot_free(u->sink_unlink_hook_slot);
+    if (u->source_unlink_hook_slot)
+        pa_hook_slot_free(u->source_unlink_hook_slot);
+
+    pa_xfree(u);
+}
index 2669776d2824167f7fc8a2c6069b7f12901ecd1f..36c50b05358bb9a1ea782a8d4596bd4e0e2fa31f 100644 (file)
@@ -209,7 +209,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_now();
 
index 5b0f64142ca2699118a490cdf4e1022e02e2283b..8a7dc84655ce533af947a3ceeef834c64f93000b 100644 (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;
index 61c9fc0eb61e5b8f5d1162d858ae57397518879e..e5609fb599bc4824e47dfe366e77d0bd9594163d 100644 (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;
index c22711aef8493d008e8b0402f7b0651ca9880330..e933cc2e50330c06cb68900df656843ef6202900 100644 (file)
@@ -65,14 +65,14 @@ static pa_hook_result_t sink_hook_callback(pa_core *c, pa_sink *sink, void* user
         return PA_HOOK_OK;
     }
 
-    if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SINK)) || target == sink) {
+    if (!(target = pa_namereg_get_default_sink(c)) || target == sink) {
 
         PA_IDXSET_FOREACH(target, c->sinks, idx)
             if (target != sink)
                 break;
 
         if (!target) {
-            pa_log_info("No evacuation sink found.");
+            pa_log_debug("No evacuation sink found.");
             return PA_HOOK_OK;
         }
     }
@@ -108,7 +108,7 @@ static pa_hook_result_t source_hook_callback(pa_core *c, pa_source *source, void
         return PA_HOOK_OK;
     }
 
-    if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SOURCE)) || target == source) {
+    if (!(target = pa_namereg_get_default_source(c)) || target == source) {
 
         PA_IDXSET_FOREACH(target, c->sources, idx)
             if (target != source && !target->monitor_of == !source->monitor_of)
@@ -146,8 +146,10 @@ int pa__init(pa_module*m) {
     }
 
     m->userdata = u = pa_xnew(struct userdata, 1);
-    u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_hook_callback, NULL);
-    u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_hook_callback, NULL);
+
+    /* A little bit later than module-stream-restore, module-intended-roles... */
+    u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE+20, (pa_hook_cb_t) sink_hook_callback, NULL);
+    u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE+20, (pa_hook_cb_t) source_hook_callback, NULL);
 
     pa_modargs_free(ma);
     return 0;
index 33be66f567319728f6fa377cac23235ff1298093..9826e5f4f83ccbb951cf2db681c55bd6be1e1dfc 100644 (file)
@@ -167,7 +167,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_now();
 
index 99c69f660819757a931a3c4d61fe0bd6a1b997cd..7ae93c7da8948b61f7db5ea167913af4807a2437 100644 (file)
@@ -60,7 +60,9 @@ PA_MODULE_LOAD_ONCE(TRUE);
 PA_MODULE_USAGE(
         "restore_device=<Save/restore sinks/sources?> "
         "restore_volume=<Save/restore volumes?> "
-        "restore_muted=<Save/restore muted states?>");
+        "restore_muted=<Save/restore muted states?> "
+        "on_hotplug=<When new device becomes available, recheck streams?> "
+        "on_rescue=<When device becomes unavailable, recheck streams?>");
 
 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
@@ -69,6 +71,8 @@ static const char* const valid_modargs[] = {
     "restore_device",
     "restore_volume",
     "restore_muted",
+    "on_hotplug",
+    "on_rescue",
     NULL
 };
 
@@ -80,6 +84,10 @@ struct userdata {
         *sink_input_new_hook_slot,
         *sink_input_fixate_hook_slot,
         *source_output_new_hook_slot,
+        *sink_put_hook_slot,
+        *source_put_hook_slot,
+        *sink_unlink_hook_slot,
+        *source_unlink_hook_slot,
         *connection_unlink_hook_slot;
     pa_time_event *save_time_event;
     pa_database* database;
@@ -87,6 +95,8 @@ struct userdata {
     pa_bool_t restore_device:1;
     pa_bool_t restore_volume:1;
     pa_bool_t restore_muted:1;
+    pa_bool_t on_hotplug:1;
+    pa_bool_t on_rescue:1;
 
     pa_native_protocol *protocol;
     pa_idxset *subscribed;
@@ -350,10 +360,10 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
     char *name;
     struct entry *e;
 
+    pa_assert(c);
     pa_assert(new_data);
-
-    if (!u->restore_device)
-        return PA_HOOK_OK;
+    pa_assert(u);
+    pa_assert(u->restore_device);
 
     if (!(name = get_name(new_data->proplist, "sink-input")))
         return PA_HOOK_OK;
@@ -367,9 +377,9 @@ static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
                 if (!new_data->sink) {
                     pa_log_info("Restoring device for stream %s.", name);
                     new_data->sink = s;
-                    new_data->save_sink = FALSE;
+                    new_data->save_sink = TRUE;
                 } else
-                    pa_log_info("Not restoring device for stream %s, because already set.", name);
+                    pa_log_debug("Not restoring device for stream %s, because already set.", name);
             }
         }
 
@@ -385,10 +395,10 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
     char *name;
     struct entry *e;
 
+    pa_assert(c);
     pa_assert(new_data);
-
-    if (!u->restore_volume && !u->restore_muted)
-        return PA_HOOK_OK;
+    pa_assert(u);
+    pa_assert(u->restore_volume || u->restore_muted);
 
     if (!(name = get_name(new_data->proplist, "sink-input")))
         return PA_HOOK_OK;
@@ -407,7 +417,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
                 pa_sink_input_new_data_set_volume(new_data, &v);
 
                 new_data->volume_is_absolute = FALSE;
-                new_data->save_volume = FALSE;
+                new_data->save_volume = TRUE;
             } else
                 pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
         }
@@ -417,7 +427,7 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
             if (!new_data->muted_is_set) {
                 pa_log_info("Restoring mute state for sink input %s.", name);
                 pa_sink_input_new_data_set_muted(new_data, e->muted);
-                new_data->save_muted = FALSE;
+                new_data->save_muted = TRUE;
             } else
                 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name);
         }
@@ -434,10 +444,10 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
     char *name;
     struct entry *e;
 
+    pa_assert(c);
     pa_assert(new_data);
-
-    if (!u->restore_device)
-        return PA_HOOK_OK;
+    pa_assert(u);
+    pa_assert(u->restore_device);
 
     if (new_data->direct_on_input)
         return PA_HOOK_OK;
@@ -453,9 +463,9 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
                 if (!new_data->source) {
                     pa_log_info("Restoring device for stream %s.", name);
                     new_data->source = s;
-                    new_data->save_source = FALSE;
+                    new_data->save_source = TRUE;
                 } else
-                    pa_log_info("Not restoring device for stream %s, because already set", name);
+                    pa_log_debug("Not restoring device for stream %s, because already set", name);
             }
         }
 
@@ -467,6 +477,155 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
     return PA_HOOK_OK;
 }
 
+static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
+    pa_sink_input *si;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(sink);
+    pa_assert(u);
+    pa_assert(u->on_hotplug && u->restore_device);
+
+    PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
+        char *name;
+        struct entry *e;
+
+        if (si->sink == sink)
+            continue;
+
+        if (si->save_sink)
+            continue;
+
+        if (!(name = get_name(si->proplist, "sink-input")))
+            continue;
+
+        if ((e = read_entry(u, name))) {
+            if (e->device_valid && pa_streq(e->device, sink->name))
+                pa_sink_input_move_to(si, sink, TRUE);
+
+            pa_xfree(e);
+        }
+
+        pa_xfree(name);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
+    pa_source_output *so;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(source);
+    pa_assert(u);
+    pa_assert(u->on_hotplug && u->restore_device);
+
+    PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
+        char *name;
+        struct entry *e;
+
+        if (so->source == source)
+            continue;
+
+        if (so->save_source)
+            continue;
+
+        if (so->direct_on_input)
+            continue;
+
+        if (!(name = get_name(so->proplist, "source-input")))
+            continue;
+
+        if ((e = read_entry(u, name))) {
+            if (e->device_valid && pa_streq(e->device, source->name))
+                pa_source_output_move_to(so, source, TRUE);
+
+            pa_xfree(e);
+        }
+
+        pa_xfree(name);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
+    pa_sink_input *si;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(sink);
+    pa_assert(u);
+    pa_assert(u->on_rescue && u->restore_device);
+
+    /* There's no point in doing anything if the core is shut down anyway */
+    if (c->state == PA_CORE_SHUTDOWN)
+        return PA_HOOK_OK;
+
+    PA_IDXSET_FOREACH(si, sink->inputs, idx) {
+        char *name;
+        struct entry *e;
+
+        if (!(name = get_name(si->proplist, "sink-input")))
+            continue;
+
+        if ((e = read_entry(u, name))) {
+
+            if (e->device_valid) {
+                pa_sink *d;
+
+                if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SINK)) && d != sink)
+                    pa_sink_input_move_to(si, d, TRUE);
+            }
+
+            pa_xfree(e);
+        }
+
+        pa_xfree(name);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
+    pa_source_output *so;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_assert(source);
+    pa_assert(u);
+    pa_assert(u->on_rescue && u->restore_device);
+
+    /* There's no point in doing anything if the core is shut down anyway */
+    if (c->state == PA_CORE_SHUTDOWN)
+        return PA_HOOK_OK;
+
+    PA_IDXSET_FOREACH(so, source->outputs, idx) {
+        char *name;
+        struct entry *e;
+
+        if (!(name = get_name(so->proplist, "source-output")))
+            continue;
+
+        if ((e = read_entry(u, name))) {
+
+            if (e->device_valid) {
+                pa_source *d;
+
+                if ((d = pa_namereg_get(c, e->device, PA_NAMEREG_SOURCE)) && d != source)
+                    pa_source_output_move_to(so, d, TRUE);
+            }
+
+            pa_xfree(e);
+        }
+
+        pa_xfree(name);
+    }
+
+    return PA_HOOK_OK;
+}
+
 #define EXT_VERSION 1
 
 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
@@ -772,7 +931,7 @@ int pa__init(pa_module*m) {
     pa_sink_input *si;
     pa_source_output *so;
     uint32_t idx;
-    pa_bool_t restore_device = TRUE, restore_volume = TRUE, restore_muted = TRUE;
+    pa_bool_t restore_device = TRUE, restore_volume = TRUE, restore_muted = TRUE, on_hotplug = TRUE, on_rescue = TRUE;
 
     pa_assert(m);
 
@@ -783,8 +942,10 @@ int pa__init(pa_module*m) {
 
     if (pa_modargs_get_value_boolean(ma, "restore_device", &restore_device) < 0 ||
         pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
-        pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0) {
-        pa_log("restore_device=, restore_volume= and restore_muted= expect boolean arguments");
+        pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
+        pa_modargs_get_value_boolean(ma, "on_hotplug", &on_hotplug) < 0 ||
+        pa_modargs_get_value_boolean(ma, "on_rescue", &on_rescue) < 0) {
+        pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
         goto fail;
     }
 
@@ -797,6 +958,8 @@ int pa__init(pa_module*m) {
     u->restore_device = restore_device;
     u->restore_volume = restore_volume;
     u->restore_muted = restore_muted;
+    u->on_hotplug = on_hotplug;
+    u->on_rescue = on_rescue;
     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
     u->protocol = pa_native_protocol_get(m->core);
@@ -807,10 +970,23 @@ int pa__init(pa_module*m) {
     u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
 
     if (restore_device) {
+        /* A little bit earlier than module-intended-roles ... */
         u->sink_input_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_hook_callback, u);
         u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_new_hook_callback, u);
     }
 
+    if (restore_device && on_hotplug) {
+        /* A little bit earlier than module-intended-roles ... */
+        u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_put_hook_callback, u);
+        u->source_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE, (pa_hook_cb_t) source_put_hook_callback, u);
+    }
+
+    if (restore_device && on_rescue) {
+        /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
+        u->sink_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_unlink_hook_callback, NULL);
+        u->source_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) source_unlink_hook_callback, NULL);
+    }
+
     if (restore_volume || restore_muted)
         u->sink_input_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_fixate_hook_callback, u);
 
@@ -826,10 +1002,10 @@ int pa__init(pa_module*m) {
     pa_log_info("Sucessfully opened database file '%s'.", fname);
     pa_xfree(fname);
 
-    for (si = pa_idxset_first(m->core->sink_inputs, &idx); si; si = pa_idxset_next(m->core->sink_inputs, &idx))
+    PA_IDXSET_FOREACH(si, m->core->sink_inputs, idx)
         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, si->index, u);
 
-    for (so = pa_idxset_first(m->core->source_outputs, &idx); so; so = pa_idxset_next(m->core->source_outputs, &idx))
+    PA_IDXSET_FOREACH(so, m->core->source_outputs, idx)
         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, so->index, u);
 
     pa_modargs_free(ma);
@@ -862,6 +1038,16 @@ void pa__done(pa_module*m) {
     if (u->source_output_new_hook_slot)
         pa_hook_slot_free(u->source_output_new_hook_slot);
 
+    if (u->sink_put_hook_slot)
+        pa_hook_slot_free(u->sink_put_hook_slot);
+    if (u->source_put_hook_slot)
+        pa_hook_slot_free(u->source_put_hook_slot);
+
+    if (u->sink_unlink_hook_slot)
+        pa_hook_slot_free(u->sink_unlink_hook_slot);
+    if (u->source_unlink_hook_slot)
+        pa_hook_slot_free(u->source_unlink_hook_slot);
+
     if (u->connection_unlink_hook_slot)
         pa_hook_slot_free(u->connection_unlink_hook_slot);
 
index ce37bf474989f2d94efb3a2cd60f555597099cb4..d115382992e390ee540e3f61433d60def37028f4 100644 (file)
@@ -684,7 +684,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;
index b1afcfd6631e03eb0709e47b28229bd49932e0ee..c44b882b79b2740298361b9a7020b9edfbed67b9 100644 (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;
index c226b0c3605a3fd215091e01b96d1b919c3b4d1f..9699132df3981a871b53667a43dc6b1627ebf49d 100644 (file)
@@ -324,7 +324,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_now());
 
index a71ba0b073f4e74f1ee53e7a3e95916767241589..4550344f713eb65e75d11128c2ed2b347da60c51 100644 (file)
 
 #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
 #include <xlocale.h>
 #endif
 
+#ifdef HAVE_DBUS
+#include "rtkit.h"
+#endif
+
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
 #include <pulse/utf8.h>
@@ -552,127 +560,121 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
     return b;
 }
 
-/* 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
+static int set_scheduler(int rtprio) {
     struct sched_param sp;
-    int r, policy;
+    int r;
+#ifdef HAVE_DBUS
+    DBusError error;
+    DBusConnection *bus;
 
-    memset(&sp, 0, sizeof(sp));
-    policy = 0;
+    dbus_error_init(&error);
+#endif
 
-    if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
-        pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
-        return -1;
+    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 (policy == SCHED_FIFO && sp.sched_priority >= rtprio) {
-        pa_log_info("Thread already being scheduled with SCHED_FIFO with priority %i.", sp.sched_priority);
+    if ((r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp)) == 0) {
+        pa_log_debug("SCHED_RR worked.");
         return 0;
     }
 
-    sp.sched_priority = rtprio;
-    if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
+#ifdef HAVE_DBUS
+    /* Try to talk to RealtimeKit */
 
-        while (sp.sched_priority > 1) {
-            sp.sched_priority --;
+    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;
+    }
 
-            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;
-            }
-        }
+    r = rtkit_make_realtime(bus, 0, rtprio);
+    dbus_connection_unref(bus);
 
-        pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
-        return -1;
+    if (r >= 0) {
+        pa_log_debug("RealtimeKit worked.");
+        return 0;
     }
 
-    pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority);
-    return 0;
+    errno = -r;
 #else
+    errno = r;
+#endif
 
-    errno = ENOTSUP;
     return -1;
-#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) {
-
-    if (geteuid() == 0)
-        return TRUE;
+/* 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) {
 
-#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
-    {
-        struct rlimit rl;
+#ifdef _POSIX_PRIORITY_SCHEDULING
+    int p;
 
-        if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
-            if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY)
-                return TRUE;
+    if (set_scheduler(rtprio) >= 0) {
+        pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i.", rtprio);
+        return 0;
     }
-#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;
+    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;
+        }
 
-            if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
-                if (flag == CAP_SET) {
-                    cap_free(cap);
-                    return TRUE;
-                }
+    pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
+    return -1;
+#else
 
-            cap_free(cap);
-        }
-    }
+    errno = ENOTSUP;
+    return -1;
 #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;
+static int set_nice(int nice_level) {
+#ifdef HAVE_DBUS
+    DBusError error;
+    DBusConnection *bus;
+    int r;
 
-#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
-    {
-        struct rlimit rl;
+    dbus_error_init(&error);
+#endif
 
-        if (getrlimit(RLIMIT_NICE, &rl) >= 0)
-            if (rl.rlim_cur >= 21 || rl.rlim_cur == RLIM_INFINITY)
-                return TRUE;
+    if (setpriority(PRIO_PROCESS, 0, nice_level) >= 0) {
+        pa_log_debug("setpriority() worked.");
+        return 0;
     }
-#endif
 
-#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
-    {
-        cap_t cap;
+#ifdef HAVE_DBUS
+    /* Try to talk to RealtimeKit */
 
-        if ((cap = cap_get_proc())) {
-            cap_flag_value_t flag = CAP_CLEAR;
+    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;
+    }
 
-            if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
-                if (flag == CAP_SET) {
-                    cap_free(cap);
-                    return TRUE;
-                }
+    r = rtkit_make_high_priority(bus, 0, nice_level);
+    dbus_connection_unref(bus);
 
-            cap_free(cap);
-        }
+    if (r >= 0) {
+        pa_log_debug("RealtimeKit worked.");
+        return 0;
     }
+
+    errno = -r;
 #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 (set_nice(nice_level) >= 0) {
+        pa_log_info("Successfully gained nice level %i.", nice_level);
+        return 0;
+    }
 
-            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;
-            }
+    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_warn("setpriority(): %s", pa_cstrerror(errno));
-        return -1;
-    }
-
-    pa_log_info("Successfully gained nice level %i.", nice_level);
+    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
index b841edbbbbf3312d11569de928afeed99e170ca8..96a0480a813998245a7ff6c68bfe05c6a830f3b1 100644 (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) {
diff --git a/src/pulsecore/rtkit.c b/src/pulsecore/rtkit.c
new file mode 100644 (file)
index 0000000..aecc4e3
--- /dev/null
@@ -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
diff --git a/src/pulsecore/rtkit.h b/src/pulsecore/rtkit.h
new file mode 100644 (file)
index 0000000..2081b4e
--- /dev/null
@@ -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
index 9401debd319d2eab9abbdf11e94d1c6eae8d1a49..5cbec3211afb10e45071ea210f81fe41f5e7183c 100644 (file)
 #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/core-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) {
index 08776ef099da4aa15189a0261e3d66955b3df331..d2d69cade7fd279c3a26a58858457c9f1f37c892 100644 (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
diff --git a/src/pulsecore/rtsig.c b/src/pulsecore/rtsig.c
deleted file mode 100644 (file)
index 4cd6aa8..0000000
+++ /dev/null
@@ -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 */
diff --git a/src/pulsecore/rtsig.h b/src/pulsecore/rtsig.h
deleted file mode 100644 (file)
index e414122..0000000
+++ /dev/null
@@ -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
index 4ac96446046cb3fab660c72985b33b8fd5c9e4fd..1706cdfa56bad51fdb9aca3ffe16ce94ed72a1a8 100644 (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);