Merge Pierre's changes

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@445 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2006-01-10 17:51:06 +00:00
parent 80ae72ce45
commit f7a99e9047
65 changed files with 3786 additions and 1050 deletions

View file

@ -17,11 +17,11 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4
SUBDIRS=polyp doc libltdl
EXTRA_DIST = bootstrap.sh LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4
SUBDIRS=libltdl polyp doc
MAINTAINERCLEANFILES=README
noinst_DATA = README
MAINTAINERCLEANFILES =
noinst_DATA =
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-browse.pc
@ -36,10 +36,16 @@ pkgconfig_DATA += \
polyplib-glib12-mainloop.pc
endif
if USE_LYNX
EXTRA_DIST += README
MAINTAINERCLEANFILES += README
noinst_DATA += README
README:
rm -f README
$(MAKE) -C doc README
cd $(srcdir) && ln -s doc/README README
endif
homepage: all dist doxygen
test -d $$HOME/homepage/private
@ -49,8 +55,8 @@ homepage: all dist doxygen
cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen
cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html
distcleancheck:
@:
#distcleancheck:
# @:
doxygen:
$(MAKE) -C doxygen doxygen

View file

@ -197,3 +197,44 @@ else
fi
AC_LANG_RESTORE
])dnl ACX_PTHREAD
AC_DEFUN([AC_CHECK_DEFINE],[
AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl
AC_CACHE_CHECK([for $1 defined], ac_var,
AC_TRY_COMPILE([#include <$2>],[
#ifdef $1
int ok;
#else
choke me
#endif
],AS_VAR_SET(ac_var, yes),AS_VAR_SET(ac_var, no)))
AS_IF([test AS_VAR_GET(ac_var) != "no"], [$3], [$4])dnl
AS_VAR_POPDEF([ac_var])dnl
])
AC_DEFUN([ACX_LIBWRAP], [
LIBWRAP_LIBS=
saved_LIBS="$LIBS"
LIBS="$LIBS -lwrap"
AC_MSG_CHECKING([for tcpwrap library and headers])
AC_LINK_IFELSE(
AC_LANG_PROGRAM(
[#include <tcpd.h>
#include <syslog.h>
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;],
[struct request_info *req;
return hosts_access (req);]),
[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?])
LIBWRAP_LIBS="-lwrap"
AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)])
LIBS="$saved_LIBS"
])
AC_DEFUN([ACX_LIRC], [
LIRC_CFLAGS=
LIRC_LIBS=
AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,[HAVE_LIRC=1
LIRC_LIBS=-llirc_client],HAVE_LIRC=0)],HAVE_LIRC=0)
])

View file

@ -35,166 +35,29 @@ if type -p stow > /dev/null && test -d /usr/local/stow ; then
ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}"
fi
# Checks for programs.
#### Checks for programs. ####
# CC
AC_PROG_CC
# libtool stuff
AC_LIBLTDL_INSTALLABLE
AC_SUBST(LTDLINCL)
AC_SUBST(LIBLTDL)
AC_LIBTOOL_DLOPEN
AC_PROG_LIBTOOL
AC_CONFIG_SUBDIRS(libltdl)
if test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then
AC_MSG_ERROR([[
*** Cannot find the libltdl development files.
*** Maybe you need to install the libltdl-dev package.
]])
fi
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h syslog.h])
ACX_PTHREAD
AC_PATH_XTRA
HAVE_X11=0
test "x$no_x" != "xyes" && HAVE_X11=1
AC_SUBST(HAVE_X11)
AM_CONDITIONAL(HAVE_X11, test "x$no_x" != "xyes")
if test "x$no_x" != "xyes" ; then
AC_DEFINE([HAVE_X11], 1, [Have X11])
fi
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_OFF_T
AC_HEADER_TIME
# Checks for library functions.
AC_FUNC_FORK
AC_PROG_GCC_TRADITIONAL
AC_FUNC_LSTAT
AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
AC_FUNC_MALLOC
AC_FUNC_MEMCMP
AC_FUNC_MMAP
AC_FUNC_REALLOC
AC_FUNC_SETPGRP
AC_FUNC_VPRINTF
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_SELECT_ARGTYPES
AC_TYPE_SIGNAL
AC_TYPE_UID_T
AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul strcasecmp putenv strchr strpbrk strdup getgrgid_r getpwuid_r regcomp ftruncate select])
AC_CHECK_LIB(m, pow)
AC_CHECK_FUNCS(pow)
AC_FUNC_STAT
AC_HEADER_SYS_WAIT
AC_HEADER_DIRENT
AC_C_BIGENDIAN
AC_FUNC_GETGROUPS
AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS=''])
AC_SUBST(CAP_LIBS)
AC_CHECK_HEADERS(sys/capability.h)
AC_CHECK_FUNCS(setresuid)
AC_CHECK_FUNCS(setreuid)
PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ])
AC_SUBST(LIBSAMPLERATE_CFLAGS)
AC_SUBST(LIBSAMPLERATE_LIBS)
PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.10 ])
AC_SUBST(LIBSNDFILE_CFLAGS)
AC_SUBST(LIBSNDFILE_LIBS)
PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [HAVE_ALSA=1], [HAVE_ALSA=0])
AC_SUBST(ASOUNDLIB_CFLAGS)
AC_SUBST(ASOUNDLIB_LIBS)
AC_SUBST(HAVE_ALSA)
AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, HAVE_GLIB20=0)
AC_SUBST(GLIB20_CFLAGS)
AC_SUBST(GLIB20_LIBS)
AC_SUBST(HAVE_GLIB20)
AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1])
PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], HAVE_GLIB12=1, HAVE_GLIB12=0)
AC_SUBST(GLIB12_CFLAGS)
AC_SUBST(GLIB12_LIBS)
AC_SUBST(HAVE_GLIB12)
AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1])
PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], HAVE_HOWL=1, HAVE_HOWL=0)
AC_SUBST(HOWL_CFLAGS)
AC_SUBST(HOWL_LIBS)
AC_SUBST(HAVE_HOWL)
AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1])
PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0)
AC_SUBST(LIBASYNCNS_CFLAGS)
AC_SUBST(LIBASYNCNS_LIBS)
AC_SUBST(HAVE_LIBASYNCNS)
AM_CONDITIONAL([HAVE_LIBASYNCNS], [test "x$HAVE_LIBASYNCNS" = x1])
if test "x$HAVE_LIBASYNCNS" != "x0" ; then
AC_DEFINE([HAVE_LIBASYNCNS], 1, [Have libasyncns?])
fi
AC_PATH_PROG([M4], [m4 gm4], [no])
if test "x$M4" = xno ; then
AC_MSG_ERROR([m4 missing])
fi
AC_MSG_CHECKING([for tcpwrap library and headers])
LIBWRAP_LIBS=
saved_LIBS="$LIBS"
LIBS="$LIBS -lwrap"
AC_LINK_IFELSE(
AC_LANG_PROGRAM(
[#include <tcpd.h>
#include <syslog.h>
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;],
[struct request_info *req;
return hosts_access (req);]),
[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?])
LIBWRAP_LIBS="-lwrap"
AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)])
AC_SUBST(LIBWRAP_LIBS)
LIBS="$saved_LIBS"
LIRC_CFLAGS=
LIRC_LIBS=
AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,[HAVE_LIRC=1
LIRC_LIBS=-llirc_client],HAVE_LIRC=0)],HAVE_LIRC=0)
AC_SUBST(LIRC_CFLAGS)
AC_SUBST(LIRC_LIBS)
AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1])
AC_CHECK_HEADER(linux/input.h,HAVE_EVDEV=1,HAVE_EVDEV=0)
AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = x1])
# If using GCC specify some additional parameters
if test "x$GCC" = "xyes" ; then
CFLAGS="$CFLAGS -pipe -W -Wall -pedantic"
AC_LANG_CONFTEST([int main() {}])
$CC -c conftest.c -std=c99 -Wno-unused-parameter $CFLAGS > /dev/null 2> /dev/null && CFLAGS="$CFLAGS -std=c99 -Wno-unused-parameter"
$CC -c conftest.c -std=gnu9x -Wno-unused-parameter $CFLAGS > /dev/null 2> /dev/null && CFLAGS="$CFLAGS -std=gnu9x -Wno-unused-parameter"
rm -f conftest.o
fi
# M4
AC_PATH_PROG([M4], [m4 gm4], [no])
if test "x$M4" = xno ; then
AC_MSG_ERROR([m4 missing])
fi
# LYNX documentation generation
AC_ARG_ENABLE(lynx,
AC_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation),
@ -212,9 +75,296 @@ if test x$lynx = xyes ; then
fi
fi
AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes])
AM_CONDITIONAL([USE_LYNX], [test "x$have_lynx" = xyes])
AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false)
#### libtool stuff ####
AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-browse.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h doc/FAQ.html])
AC_LTDL_ENABLE_INSTALL
AC_LIBLTDL_INSTALLABLE
AC_SUBST(LTDLINCL)
AC_SUBST(LIBLTDL)
AC_LIBTOOL_DLOPEN
AC_LIBTOOL_WIN32_DLL
AC_PROG_LIBTOOL
AC_CONFIG_SUBDIRS(libltdl)
if test "x$enable_ltdl_install" = "xno" && test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then
AC_MSG_ERROR([[
*** Cannot find the libltdl development files.
*** Maybe you need to install the libltdl-dev package.
]])
fi
#### Determine build environment ####
os_is_win32=0
case "$host_os" in
mingw*)
AC_DEFINE([OS_IS_WIN32], 1, [Build target is Windows.])
os_is_win32=1
;;
esac
AM_CONDITIONAL(OS_IS_WIN32, test "x$os_is_win32" = "x1")
###################################
# Basic environment checks #
###################################
#### Checks for header files. ####
# ISO
AC_HEADER_STDC
# POSIX
AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \
netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \
sys/resource.h sys/select.h sys/socket.h sys/wait.h \
syslog.h])
AC_CHECK_HEADERS([regex.h], [HAVE_REGEX=1], [HAVE_REGEX=0])
AC_CHECK_HEADERS([sys/un.h], [HAVE_AF_UNIX=1], [HAVE_AF_UNIX=0])
AM_CONDITIONAL(HAVE_REGEX, test "x$HAVE_REGEX" = "x1")
AM_CONDITIONAL(HAVE_AF_UNIX, test "x$HAVE_AF_UNIX" = "x1")
# XPG4-UNIX
AC_CHECK_HEADERS([sys/poll.h])
# Linux
AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0])
AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = "x1"])
# Windows
AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h])
# Other
AC_CHECK_HEADERS([sys/ioctl.h])
#### Typdefs, structures, etc. ####
AC_C_CONST
AC_C_BIGENDIAN
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_CHECK_TYPES(ssize_t, , [AC_DEFINE([ssize_t], [signed long],
[Define ssize_t if it is not done by the standard libs.])])
AC_TYPE_OFF_T
AC_TYPE_SIGNAL
AC_TYPE_UID_T
AC_CHECK_DEFINE([SIGXCPU], [signal.h], [HAVE_SIGXCPU=1], [HAVE_SIGXCPU=0])
AM_CONDITIONAL(HAVE_SIGXCPU, test "x$HAVE_SIGXCPU" = "x1")
# Solaris lacks this
AC_CHECK_DEFINE([INADDR_NONE], [netinet/in.h], [],
[AC_DEFINE([INADDR_NONE], [0xffffffff], [Define INADDR_NONE if not found in <netinet/in.h>])])
#### Check for libs ####
# ISO
AC_CHECK_LIB([m], [pow])
# POSIX
AC_CHECK_LIB([rt], [sched_setscheduler])
# BSD
AC_CHECK_LIB([socket], [connect])
# Non-standard
# This magic is needed so we do not needlessly add static libs to the win32
# build, disabling its ability to make dlls.
AC_CHECK_FUNCS([getopt_long], [], [AC_CHECK_LIB([iberty], [getopt_long])])
#### Check for functions ####
# POSIX
AC_FUNC_FORK
AC_FUNC_GETGROUPS
AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \
inet_ntop nanosleep setpgid setsid sigaction sleep])
AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0])
AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1")
# X/OPEN
AC_CHECK_FUNCS([readlink])
# SUSv2
AC_CHECK_FUNCS([ctime_r usleep])
# BSD
AC_CHECK_FUNCS([lstat])
# Non-standard
AC_CHECK_FUNCS(setresuid)
AC_CHECK_FUNCS(setreuid)
#### POSIX threads ####
ACX_PTHREAD
###################################
# External libraries #
###################################
#### X11 (optional) ####
HAVE_X11=0
# The macro tests the host, not the build target
if test "x$os_is_win32" != "x1" ; then
AC_PATH_XTRA
test "x$no_x" != "xyes" && HAVE_X11=1
fi
AC_SUBST(HAVE_X11)
AM_CONDITIONAL(HAVE_X11, test "x$HAVE_X11" = "x1")
if test "x$HAVE_X11" = "x1" ; then
AC_DEFINE([HAVE_X11], 1, [Have X11])
fi
#### Capabilities (optional) ####
CAP_LIBS=''
AC_ARG_WITH(
[caps],
AC_HELP_STRING([--without-caps],[Omit support for POSIX capabilities.]))
if test "x${with_caps}" != "xno"; then
AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS=''])
AC_CHECK_HEADERS([sys/capability.h])
fi
AC_SUBST(CAP_LIBS)
#### Sample rate conversion ####
PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ])
AC_SUBST(LIBSAMPLERATE_CFLAGS)
AC_SUBST(LIBSAMPLERATE_LIBS)
#### Sound file ####
PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.10 ])
AC_SUBST(LIBSNDFILE_CFLAGS)
AC_SUBST(LIBSNDFILE_LIBS)
#### OSS support (optional) ####
AC_CHECK_HEADERS([sys/soundcard.h], [HAVE_OSS=1], [HAVE_OSS=0])
AC_SUBST(HAVE_OSS)
AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1])
#### ALSA support (optional) ####
PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [HAVE_ALSA=1], [HAVE_ALSA=0])
AC_SUBST(ASOUNDLIB_CFLAGS)
AC_SUBST(ASOUNDLIB_LIBS)
AC_SUBST(HAVE_ALSA)
AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
#### Solaris audio support (optional) ####
AC_CHECK_HEADERS([sys/audio.h], [HAVE_SOLARIS=1], [HAVE_SOLARIS=0])
AC_SUBST(HAVE_SOLARIS)
AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1])
#### GLib 2 support (optional) ####
PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, HAVE_GLIB20=0)
AC_SUBST(GLIB20_CFLAGS)
AC_SUBST(GLIB20_LIBS)
AC_SUBST(HAVE_GLIB20)
AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1])
#### GLib 1 support (optional) ####
PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], HAVE_GLIB12=1, HAVE_GLIB12=0)
AC_SUBST(GLIB12_CFLAGS)
AC_SUBST(GLIB12_LIBS)
AC_SUBST(HAVE_GLIB12)
AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1])
#### Howl support (optional) ####
PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], HAVE_HOWL=1, HAVE_HOWL=0)
AC_SUBST(HOWL_CFLAGS)
AC_SUBST(HOWL_LIBS)
AC_SUBST(HAVE_HOWL)
AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1])
#### Async DNS support (optional) ####
PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0)
AC_SUBST(LIBASYNCNS_CFLAGS)
AC_SUBST(LIBASYNCNS_LIBS)
AC_SUBST(HAVE_LIBASYNCNS)
AM_CONDITIONAL([HAVE_LIBASYNCNS], [test "x$HAVE_LIBASYNCNS" = x1])
if test "x$HAVE_LIBASYNCNS" != "x0" ; then
AC_DEFINE([HAVE_LIBASYNCNS], 1, [Have libasyncns?])
fi
#### TCP wrappers (optional) ####
ACX_LIBWRAP
AC_SUBST(LIBWRAP_LIBS)
#### LIRC support (optional) ####
ACX_LIRC
AC_SUBST(LIRC_CFLAGS)
AC_SUBST(LIRC_LIBS)
AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1])
###################################
# Output #
###################################
AC_ARG_ENABLE(
[static-bins],
AC_HELP_STRING([--enable-static-bins],[Statically link executables.]),
[STATIC_BINS=1], [STATIC_BINS=0])
AM_CONDITIONAL([STATIC_BINS], [test "x$STATIC_BINS" = "x1"])
AC_ARG_WITH(
[preopen-mods],
AC_HELP_STRING([--with-preopen-mods],[Modules to preopen in daemon (default: all).]),
[PREOPEN_MODS=$withval], [PREOPEN_MODS="all"])
AM_CONDITIONAL([PREOPEN_MODS], [test "x$PREOPEN_MODS" != "xall"])
if test "x$PREOPEN_MODS" != "xall" ; then
tmpLIBS=""
for mod in $PREOPEN_MODS; do
tmpLIBS="$tmpLIBS module-$mod.la"
done
PREOPEN_MODS="$tmpLIBS"
AC_SUBST(PREOPEN_MODS)
fi
AC_CONFIG_FILES([
Makefile
polyp/Makefile
polyplib.pc
polyplib-simple.pc
polyplib-mainloop.pc
polyplib-browse.pc
polyplib-error.pc
polyplib-glib-mainloop.pc
polyplib-glib12-mainloop.pc
doc/Makefile
doc/README.html
doc/cli.html
doc/daemon.html
doc/modules.html
doxygen/Makefile
doxygen/doxygen.conf
polyp/polyplib-version.h
doc/FAQ.html
])
AC_OUTPUT

View file

@ -16,7 +16,7 @@
# along with polypaudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
noinst_DATA = README.html cli.html modules.html daemon.html README
noinst_DATA = README.html cli.html modules.html daemon.html
EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo FAQ.html.in
MAINTAINERCLEANFILES = README.html cli.html modules.html daemon.html FAQ.html
@ -26,6 +26,7 @@ if USE_LYNX
README: README.html
lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' > $@
noinst_DATA += README
CLEANFILES += README
endif

File diff suppressed because it is too large Load diff

View file

@ -63,7 +63,7 @@ static int generate(int fd, void *ret_data, size_t length) {
static int load(const char *fn, void *data, size_t length) {
int fd = -1;
int writable = 1;
int unlock = 0, ret;
int unlock = 0, ret = -1;
ssize_t r;
assert(fn && data && length);
@ -128,12 +128,20 @@ int pa_authkey_load(const char *path, void *data, size_t length) {
static const char *normalize_path(const char *fn, char *s, size_t l) {
assert(fn && s && l > 0);
#ifndef OS_IS_WIN32
if (fn[0] != '/') {
#else
if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
#endif
char homedir[PATH_MAX];
if (!pa_get_home_dir(homedir, sizeof(homedir)))
return NULL;
#ifndef OS_IS_WIN32
snprintf(s, l, "%s/%s", homedir, fn);
#else
snprintf(s, l, "%s\\%s", homedir, fn);
#endif
return s;
}

View file

@ -35,6 +35,8 @@
#include "log.h"
#include "caps.h"
#ifdef HAVE_GETUID
/* Drop root rights when called SUID root */
void pa_drop_root(void) {
uid_t uid = getuid();
@ -54,6 +56,13 @@ void pa_drop_root(void) {
#endif
}
#else
void pa_drop_root(void) {
}
#endif
#ifdef HAVE_SYS_CAPABILITY_H
/* Limit capabilities set to CAPSYS_NICE */

View file

@ -641,7 +641,11 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct
time(&now);
#ifdef HAVE_CTIME_R
pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
#else
pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
#endif
for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) {

View file

@ -19,6 +19,10 @@
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
@ -33,11 +37,21 @@
#include "authkey.h"
#ifndef DEFAULT_CONFIG_DIR
#define DEFAULT_CONFIG_DIR "/etc/polypaudio"
# ifndef OS_IS_WIN32
# define DEFAULT_CONFIG_DIR "/etc/polypaudio"
# else
# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%"
# endif
#endif
#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR"/client.conf"
#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf"
#ifndef OS_IS_WIN32
# define PATH_SEP "/"
#else
# define PATH_SEP "\\"
#endif
#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf"
#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf"
#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG"
#define ENV_DEFAULT_SINK "POLYP_SINK"

View file

@ -19,6 +19,10 @@
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <string.h>
#include <stdio.h>

View file

@ -89,7 +89,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
pa_random(&c->cookie, sizeof(c->cookie));
#ifdef SIGPIPE
pa_check_signal_is_blocked(SIGPIPE);
#endif
return c;
}
@ -144,7 +146,7 @@ void pa_core_check_quit(struct pa_core *c) {
if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_ncontents(c->clients) == 0) {
struct timeval tv;
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
tv.tv_sec+= c->exit_idle_time;
c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c);
} else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) {

View file

@ -23,15 +23,20 @@
#include <config.h>
#endif
#ifdef HAVE_SIGXCPU
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <signal.h>
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#include "cpulimit.h"
#include "util.h"
#include "log.h"
@ -219,3 +224,16 @@ void pa_cpu_limit_done(void) {
installed = 0;
}
}
#else /* HAVE_SIGXCPU */
struct pa_mainloop_api;
int pa_cpu_limit_init(struct pa_mainloop_api *m) {
return 0;
}
void pa_cpu_limit_done(void) {
}
#endif

View file

@ -37,13 +37,23 @@
#include "resampler.h"
#ifndef DEFAULT_CONFIG_DIR
#define DEFAULT_CONFIG_DIR "/etc/polypaudio"
# ifndef OS_IS_WIN32
# define DEFAULT_CONFIG_DIR "/etc/polypaudio"
# else
# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%"
# endif
#endif
#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR"/default.pa"
#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa"
#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR"/daemon.conf"
#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf"
#ifndef OS_IS_WIN32
# define PATH_SEP "/"
#else
# define PATH_SEP "\\"
#endif
#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa"
#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa"
#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf"
#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf"
#define ENV_SCRIPT_FILE "POLYP_SCRIPT"
#define ENV_CONFIG_FILE "POLYP_CONFIG"

43
polyp/default.pa.win32 Normal file
View file

@ -0,0 +1,43 @@
#
# This file is part of polypaudio.
#
# polypaudio 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 of the License, or
# (at your option) any later version.
#
# polypaudio is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with polypaudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
# Load audio drivers statically
load-module module-waveout sink_name=output source_name=input
load-module module-null-sink
# Load audio drivers automatically on access
#add-autoload-sink output module-waveout sink_name=output source_name=input
#add-autoload-source input module-waveout sink_name=output source_name=input
# Load several protocols
#load-module module-esound-protocol-tcp
#load-module module-native-protocol-tcp
#load-module module-simple-protocol-tcp
#load-module module-cli-protocol-tcp
# Make some devices default
set-default-sink output
set-default-source input
.nofail
# Load something to the sample cache
load-sample x11-bell %WINDIR%\Media\ding.wav
load-sample-dir-lazy %WINDIR%\Media\*.wav

46
polyp/dllmain.c Normal file
View file

@ -0,0 +1,46 @@
/* $Id: dllmain.c 317 2004-12-11 00:10:41Z lennart $ */
/***
This file is part of polypaudio.
polypaudio 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 of the License,
or (at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef OS_IS_WIN32
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
extern pa_set_root(HANDLE handle);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
if (fdwReason != DLL_PROCESS_ATTACH)
return TRUE;
if (!pa_set_root(hinstDLL))
return FALSE;
return TRUE;
}
#endif /* OS_IS_WIN32 */

View file

@ -31,6 +31,7 @@
#include "dumpmodules.h"
#include "modinfo.h"
#include "util.h"
#define PREFIX "module-"
@ -80,10 +81,7 @@ static int callback(const char *path, lt_ptr data) {
const char *e;
struct pa_daemon_conf *c = (data);
if ((e = (const char*) strrchr(path, '/')))
e++;
else
e = path;
e = pa_path_get_filename(path);
if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1))
show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info);

View file

@ -241,7 +241,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv)
struct timeval now;
assert(e && e->mainloop && !e->dead);
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
if (e->source) {
g_source_destroy(e->source);
g_source_unref(e->source);

View file

@ -233,7 +233,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv)
struct timeval now;
assert(e && e->mainloop && !e->dead);
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
if (e->source != (guint) -1)
g_source_remove(e->source);

80
polyp/inet_ntop.c Normal file
View file

@ -0,0 +1,80 @@
/* $Id: inet_ntop.c 428 2006-01-09 16:50:39Z ossman $ */
/***
This file is part of polypaudio.
polypaudio 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.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#ifndef HAVE_INET_NTOP
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include "winsock.h"
#include "inet_ntop.h"
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) {
struct in_addr *in = (struct in_addr*)src;
struct in6_addr *in6 = (struct in6_addr*)src;
assert(src && dst);
switch (af) {
case AF_INET:
snprintf(dst, cnt, "%d.%d.%d.%d",
#ifdef WORDS_BIGENDIAN
(int)(in->s_addr >> 24) & 0xff,
(int)(in->s_addr >> 16) & 0xff,
(int)(in->s_addr >> 8) & 0xff,
(int)(in->s_addr >> 0) & 0xff);
#else
(int)(in->s_addr >> 0) & 0xff,
(int)(in->s_addr >> 8) & 0xff,
(int)(in->s_addr >> 16) & 0xff,
(int)(in->s_addr >> 24) & 0xff);
#endif
break;
case AF_INET6:
snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
in6->s6_addr[ 0] << 8 | in6->s6_addr[ 1],
in6->s6_addr[ 2] << 8 | in6->s6_addr[ 3],
in6->s6_addr[ 4] << 8 | in6->s6_addr[ 5],
in6->s6_addr[ 6] << 8 | in6->s6_addr[ 7],
in6->s6_addr[ 8] << 8 | in6->s6_addr[ 9],
in6->s6_addr[10] << 8 | in6->s6_addr[11],
in6->s6_addr[12] << 8 | in6->s6_addr[13],
in6->s6_addr[14] << 8 | in6->s6_addr[15]);
break;
default:
errno = EAFNOSUPPORT;
return NULL;
}
return dst;
}
#endif /* INET_NTOP */

12
polyp/inet_ntop.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef fooinet_ntophfoo
#define fooinet_ntophfoo
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include "winsock.h"
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
#endif

View file

@ -28,6 +28,8 @@
#include <fcntl.h>
#include <unistd.h>
#include "winsock.h"
#include "iochannel.h"
#include "util.h"
#include "socket-util.h"
@ -189,7 +191,19 @@ ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) {
ssize_t r;
assert(io && data && l && io->ofd >= 0);
if ((r = write(io->ofd, data, l)) >= 0) {
#ifdef OS_IS_WIN32
r = send(io->ofd, data, l, 0);
if (r < 0) {
if (WSAGetLastError() != WSAENOTSOCK) {
errno = WSAGetLastError();
return r;
}
}
if (r < 0)
#endif
r = write(io->ofd, data, l);
if (r >= 0) {
io->writable = 0;
enable_mainloop_sources(io);
}
@ -201,7 +215,19 @@ ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) {
ssize_t r;
assert(io && data && io->ifd >= 0);
if ((r = read(io->ifd, data, l)) >= 0) {
#ifdef OS_IS_WIN32
r = recv(io->ifd, data, l, 0);
if (r < 0) {
if (WSAGetLastError() != WSAENOTSOCK) {
errno = WSAGetLastError();
return r;
}
}
if (r < 0)
#endif
r = read(io->ifd, data, l);
if (r >= 0) {
io->readable = 0;
enable_mainloop_sources(io);
}

View file

@ -25,9 +25,12 @@
#include <assert.h>
#include <stdarg.h>
#include <syslog.h>
#include <stdio.h>
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif
#include "log.h"
#include "xmalloc.h"
#include "util.h"
@ -39,6 +42,7 @@ static enum pa_log_target log_target = PA_LOG_STDERR;
static void (*user_log_func)(enum pa_log_level l, const char *s) = NULL;
static enum pa_log_level maximal_level = PA_LOG_NOTICE;
#ifdef HAVE_SYSLOG_H
static const int level_to_syslog[] = {
[PA_LOG_ERROR] = LOG_ERR,
[PA_LOG_WARN] = LOG_WARNING,
@ -46,6 +50,7 @@ static const int level_to_syslog[] = {
[PA_LOG_INFO] = LOG_INFO,
[PA_LOG_DEBUG] = LOG_DEBUG
};
#endif
void pa_log_set_ident(const char *p) {
if (log_ident)
@ -79,13 +84,15 @@ void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) {
case PA_LOG_STDERR:
vfprintf(stderr, format, ap);
break;
#ifdef HAVE_SYSLOG_H
case PA_LOG_SYSLOG:
openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER);
vsyslog(level_to_syslog[level], format, ap);
closelog();
break;
break;
#endif
case PA_LOG_USER: {
char *t = pa_vsprintf_malloc(format, ap);
assert(user_log_func);
@ -94,6 +101,7 @@ void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) {
}
case PA_LOG_NULL:
default:
break;
}

View file

@ -35,13 +35,20 @@
#include <memblock.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_LIBWRAP
#include <syslog.h>
#include <tcpd.h>
#endif
#include "winsock.h"
#include "core.h"
#include "mainloop.h"
#include "module.h"
@ -66,24 +73,47 @@ int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;
#endif
#ifdef OS_IS_WIN32
static void message_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) {
MSG msg;
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
raise(SIGTERM);
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
#endif
static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig));
switch (sig) {
#ifdef SIGUSR1
case SIGUSR1:
pa_module_load(userdata, "module-cli", NULL);
break;
#endif
#ifdef SIGUSR2
case SIGUSR2:
pa_module_load(userdata, "module-cli-protocol-unix", NULL);
break;
#endif
#ifdef SIGHUP
case SIGHUP: {
char *c = pa_full_status_string(userdata);
pa_log_notice(c);
pa_xfree(c);
return;
}
#endif
case SIGINT:
case SIGTERM:
@ -111,24 +141,42 @@ int main(int argc, char *argv[]) {
char *s;
int r, retval = 1, d = 0;
int daemon_pipe[2] = { -1, -1 };
gid_t gid = (gid_t) -1;
int suid_root;
int valid_pid_file = 0;
#ifdef HAVE_GETUID
gid_t gid = (gid_t) -1;
#endif
#ifdef OS_IS_WIN32
struct pa_defer_event *defer;
#endif
pa_limit_caps();
#ifdef HAVE_GETUID
suid_root = getuid() != 0 && geteuid() == 0;
if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) {
pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n");
pa_drop_root();
}
#else
suid_root = 0;
#endif
LTDL_SET_PRELOADED_SYMBOLS();
r = lt_dlinit();
assert(r == 0);
#ifdef OS_IS_WIN32
{
WSADATA data;
WSAStartup(MAKEWORD(2, 0), &data);
}
#endif
pa_log_set_ident("polypaudio");
conf = pa_daemon_conf_new();
@ -217,6 +265,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
#ifdef HAVE_FORK
if (pipe(daemon_pipe) < 0) {
pa_log(__FILE__": failed to create pipe.\n");
goto finish;
@ -248,13 +297,19 @@ int main(int argc, char *argv[]) {
close(daemon_pipe[0]);
daemon_pipe[0] = -1;
#endif
if (conf->auto_log_target)
pa_log_set_target(PA_LOG_SYSLOG, NULL);
#ifdef HAVE_SETSID
setsid();
#endif
#ifdef HAVE_SETPGID
setpgid(0,0);
#endif
#ifndef OS_IS_WIN32
close(0);
close(1);
close(2);
@ -262,23 +317,37 @@ int main(int argc, char *argv[]) {
open("/dev/null", O_RDONLY);
open("/dev/null", O_WRONLY);
open("/dev/null", O_WRONLY);
#else
FreeConsole();
#endif
#ifdef SIGTTOU
signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN);
#endif
#ifdef TIOCNOTTY
if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) {
ioctl(tty_fd, TIOCNOTTY, (char*) 0);
close(tty_fd);
}
#endif
}
chdir("/");
if (conf->use_pid_file) {
if (pa_pid_file_create() < 0) {
pa_log(__FILE__": pa_pid_file_create() failed.\n");
#ifdef HAVE_FORK
if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
#endif
goto finish;
}
@ -288,20 +357,34 @@ int main(int argc, char *argv[]) {
mainloop = pa_mainloop_new();
assert(mainloop);
c = pa_core_new(pa_mainloop_get_api(mainloop));
assert(c);
r = pa_signal_init(pa_mainloop_get_api(mainloop));
assert(r == 0);
pa_signal_new(SIGINT, signal_callback, c);
pa_signal_new(SIGTERM, signal_callback, c);
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
#ifdef OS_IS_WIN32
defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL);
assert(defer);
#endif
c = pa_core_new(pa_mainloop_get_api(mainloop));
assert(c);
if (conf->daemonize)
c->running_as_daemon = 1;
#ifdef SIGUSR1
pa_signal_new(SIGUSR1, signal_callback, c);
#endif
#ifdef SIGUSR2
pa_signal_new(SIGUSR2, signal_callback, c);
#endif
#ifdef SIGHUP
pa_signal_new(SIGHUP, signal_callback, c);
#endif
r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));
assert(r == 0);
@ -318,17 +401,23 @@ int main(int argc, char *argv[]) {
if (r < 0 && conf->fail) {
pa_log(__FILE__": failed to initialize daemon.\n");
#ifdef HAVE_FORK
if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
#endif
} else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) {
pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n");
#ifdef HAVE_FORK
if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
#endif
} else {
retval = 0;
#ifdef HAVE_FORK
if (conf->daemonize)
pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
#endif
c->disallow_module_loading = conf->disallow_module_loading;
c->exit_idle_time = conf->exit_idle_time;
@ -346,7 +435,11 @@ int main(int argc, char *argv[]) {
pa_log_info(__FILE__": Daemon shutdown initiated.\n");
}
}
#ifdef OS_IS_WIN32
pa_mainloop_get_api(mainloop)->defer_free(defer);
#endif
pa_core_free(c);
pa_cpu_limit_done();
@ -365,6 +458,10 @@ finish:
close_pipe(daemon_pipe);
#ifdef OS_IS_WIN32
WSACleanup();
#endif
lt_dlexit();
return retval;

View file

@ -30,6 +30,11 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "mainloop-signal.h"
#include "util.h"
@ -38,7 +43,11 @@
struct pa_signal_event {
int sig;
#ifdef HAVE_SIGACTION
struct sigaction saved_sigaction;
#else
void (*saved_handler)(int sig);
#endif
void (*callback) (struct pa_mainloop_api*a, struct pa_signal_event *e, int signal, void *userdata);
void *userdata;
void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_signal_event*e, void *userdata);
@ -48,16 +57,70 @@ struct pa_signal_event {
static struct pa_mainloop_api *api = NULL;
static int signal_pipe[2] = { -1, -1 };
static struct pa_io_event* io_event = NULL;
static struct pa_defer_event *defer_event = NULL;
static struct pa_signal_event *signals = NULL;
#ifdef OS_IS_WIN32
static unsigned int waiting_signals = 0;
static CRITICAL_SECTION crit;
#endif
static void signal_handler(int sig) {
#ifndef HAVE_SIGACTION
signal(sig, signal_handler);
#endif
write(signal_pipe[1], &sig, sizeof(sig));
#ifdef OS_IS_WIN32
EnterCriticalSection(&crit);
waiting_signals++;
LeaveCriticalSection(&crit);
#endif
}
static void dispatch(struct pa_mainloop_api*a, int sig) {
struct pa_signal_event*s;
for (s = signals; s; s = s->next)
if (s->sig == sig) {
assert(s->callback);
s->callback(a, s, sig, s->userdata);
break;
}
}
static void defer(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata) {
ssize_t r;
int sig;
unsigned int sigs;
#ifdef OS_IS_WIN32
EnterCriticalSection(&crit);
sigs = waiting_signals;
waiting_signals = 0;
LeaveCriticalSection(&crit);
#endif
while (sigs) {
if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
pa_log(__FILE__": read(): %s\n", strerror(errno));
return;
}
if (r != sizeof(sig)) {
pa_log(__FILE__": short read()\n");
return;
}
dispatch(a, sig);
sigs--;
}
}
static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) {
ssize_t r;
int sig;
struct pa_signal_event*s;
assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);
@ -73,19 +136,18 @@ static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enu
pa_log(__FILE__": short read()\n");
return;
}
for (s = signals; s; s = s->next)
if (s->sig == sig) {
assert(s->callback);
s->callback(a, s, sig, s->userdata);
break;
}
dispatch(a, sig);
}
int pa_signal_init(struct pa_mainloop_api *a) {
assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event);
assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event);
#ifdef OS_IS_WIN32
if (_pipe(signal_pipe, 200, _O_BINARY) < 0) {
#else
if (pipe(signal_pipe) < 0) {
#endif
pa_log(__FILE__": pipe() failed: %s\n", strerror(errno));
return -1;
}
@ -96,20 +158,36 @@ int pa_signal_init(struct pa_mainloop_api *a) {
pa_fd_set_cloexec(signal_pipe[1], 1);
api = a;
#ifndef OS_IS_WIN32
io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
assert(io_event);
#else
defer_event = api->defer_new(api, defer, NULL);
assert(defer_event);
InitializeCriticalSection(&crit);
#endif
return 0;
}
void pa_signal_done(void) {
assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event);
assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event));
while (signals)
pa_signal_free(signals);
api->io_free(io_event);
#ifndef OS_IS_WIN32
api->io_free(io_event);
io_event = NULL;
#else
api->defer_free(defer_event);
defer_event = NULL;
DeleteCriticalSection(&crit);
#endif
close(signal_pipe[0]);
close(signal_pipe[1]);
@ -120,7 +198,11 @@ void pa_signal_done(void) {
struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int sig, void *userdata), void *userdata) {
struct pa_signal_event *e = NULL;
#ifdef HAVE_SIGACTION
struct sigaction sa;
#endif
assert(sig > 0 && callback);
for (e = signals; e; e = e->next)
@ -133,12 +215,16 @@ struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainl
e->userdata = userdata;
e->destroy_callback = NULL;
#ifdef HAVE_SIGACTION
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(sig, &sa, &e->saved_sigaction) < 0)
#else
if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR)
#endif
goto fail;
e->previous = NULL;
@ -162,7 +248,11 @@ void pa_signal_free(struct pa_signal_event *e) {
else
signals = e->next;
#ifdef HAVE_SIGACTION
sigaction(e->sig, &e->saved_sigaction, NULL);
#else
signal(e->sig, e->saved_handler);
#endif
if (e->destroy_callback)
e->destroy_callback(api, e, e->userdata);

View file

@ -111,7 +111,7 @@ int main(int argc, char *argv[]) {
de = a->defer_new(a, dcb, NULL);
assert(de);
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
tv.tv_sec += 10;
te = a->time_new(a, &tv, tcb, NULL);

View file

@ -26,13 +26,20 @@
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/poll.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#else
#include "poll.h"
#endif
#include "winsock.h"
#include "mainloop.h"
#include "util.h"
#include "idxset.h"
@ -103,6 +110,26 @@ static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enu
e->destroy_callback = NULL;
e->pollfd = NULL;
#ifdef OS_IS_WIN32
{
fd_set xset;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO (&xset);
FD_SET (fd, &xset);
if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset,
SELECT_TYPE_ARG5 &tv) == -1) &&
(WSAGetLastError() == WSAENOTSOCK)) {
pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n");
e->dead = 1;
}
}
#endif
pa_idxset_put(m->io_events, e, NULL);
m->rebuild_pollfds = 1;
return e;
@ -457,7 +484,7 @@ static int calc_next_timeout(struct pa_mainloop *m) {
/* Let's save a system call */
if (!got_time) {
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
got_time = 1;
}
@ -498,7 +525,7 @@ static int dispatch_timeout(struct pa_mainloop *m) {
/* Let's save a system call */
if (!got_time) {
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
got_time = 1;
}

View file

@ -66,7 +66,7 @@ int main(int argc, char *argv[]) {
c.length = r;
pa_mcalign_push(a, &c);
fprintf(stderr, "Read %u bytes\n", r);
fprintf(stderr, "Read %d bytes\n", r);
c.index += r;

View file

@ -25,7 +25,12 @@
#include <assert.h>
#include <stdio.h>
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#else
#include "poll.h"
#endif
#include <asoundlib.h>

View file

@ -25,7 +25,12 @@
#include <assert.h>
#include <stdio.h>
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#else
#include "poll.h"
#endif
#include <asoundlib.h>

View file

@ -157,7 +157,7 @@ static void time_callback(struct pa_mainloop_api*a, struct pa_time_event* e, con
adjust_rates(u);
gettimeofday(&n, NULL);
pa_gettimeofday(&n);
n.tv_sec += u->adjust_time;
u->sink->core->mainloop->time_restart(e, &n);
}
@ -363,7 +363,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
pa_log_warn(__FILE__": WARNING: no slave sinks specified.\n");
if (u->adjust_time > 0) {
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
tv.tv_sec += u->adjust_time;
u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u);
}

View file

@ -144,7 +144,7 @@ static int do_write(struct userdata *u) {
pa_module_set_used(u->module, pa_idxset_ncontents(u->sink->inputs) + pa_idxset_ncontents(u->sink->monitor_source->outputs));
if (!u->memchunk.length)
if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0)
if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0)
return 0;
assert(u->memchunk.memblock && u->memchunk.length);

View file

@ -49,6 +49,17 @@ PA_MODULE_USAGE("device=<evdev device> sink=<sink name>")
#define DEFAULT_DEVICE "/dev/input/event0"
/*
* This isn't defined in older kernel headers and there is no way of
* detecting it.
*/
struct _input_id {
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
};
static const char* const valid_modargs[] = {
"device",
"sink",
@ -136,7 +147,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
struct pa_modargs *ma = NULL;
struct userdata *u;
int version;
struct input_id input_id;
struct _input_id input_id;
char name[256];
uint8_t evtype_bitmask[EV_MAX/8 + 1];
assert(c && m);

View file

@ -117,7 +117,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
pa_sink_set_owner(u->sink, m);
u->sink->description = pa_sprintf_malloc("NULL sink");
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u);
u->block_size = pa_bytes_per_second(&ss) / 10;

View file

@ -27,9 +27,20 @@
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <limits.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "winsock.h"
#include "module.h"
#include "socket-server.h"

436
polyp/module-solaris.c Normal file
View file

@ -0,0 +1,436 @@
/* $Id: module-oss.c 333 2005-01-08 21:36:53Z lennart $ */
/***
This file is part of polypaudio.
polypaudio 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 of the License,
or (at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stropts.h>
#include <sys/conf.h>
#include <sys/audio.h>
#include "iochannel.h"
#include "sink.h"
#include "source.h"
#include "module.h"
#include "sample-util.h"
#include "util.h"
#include "modargs.h"
#include "xmalloc.h"
#include "log.h"
#include "module-solaris-symdef.h"
PA_MODULE_AUTHOR("Pierre Ossman")
PA_MODULE_DESCRIPTION("Solaris Sink/Source")
PA_MODULE_VERSION(PACKAGE_VERSION)
PA_MODULE_USAGE("sink_name=<name for the sink> source_name=<name for the source> device=<OSS device> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> buffer_size=<record buffer size>")
#define PA_TYPEID_SOLARIS PA_TYPEID_MAKE('S', 'L', 'R', 'S')
struct userdata {
struct pa_sink *sink;
struct pa_source *source;
struct pa_iochannel *io;
struct pa_core *core;
struct pa_memchunk memchunk, silence;
uint32_t sample_size;
unsigned int written_bytes, read_bytes;
int fd;
struct pa_module *module;
};
static const char* const valid_modargs[] = {
"sink_name",
"source_name",
"device",
"record",
"playback",
"buffer_size",
"format",
"rate",
"channels",
NULL
};
#define DEFAULT_SINK_NAME "solaris_output"
#define DEFAULT_SOURCE_NAME "solaris_input"
#define DEFAULT_DEVICE "/dev/audio"
#define CHUNK_SIZE 2048
static void update_usage(struct userdata *u) {
pa_module_set_used(u->module,
(u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) +
(u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) +
(u->source ? pa_idxset_ncontents(u->source->outputs) : 0));
}
static void do_write(struct userdata *u) {
struct pa_memchunk *memchunk;
ssize_t r;
assert(u);
if (!u->sink || !pa_iochannel_is_writable(u->io))
return;
update_usage(u);
memchunk = &u->memchunk;
if (!memchunk->length)
if (pa_sink_render(u->sink, CHUNK_SIZE, memchunk) < 0)
memchunk = &u->silence;
assert(memchunk->memblock);
assert(memchunk->memblock->data);
assert(memchunk->length);
if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) {
pa_log(__FILE__": write() failed: %s\n", strerror(errno));
return;
}
if (memchunk == &u->silence)
assert(r % u->sample_size == 0);
else {
u->memchunk.index += r;
u->memchunk.length -= r;
if (u->memchunk.length <= 0) {
pa_memblock_unref(u->memchunk.memblock);
u->memchunk.memblock = NULL;
}
}
u->written_bytes += r;
}
static void do_read(struct userdata *u) {
struct pa_memchunk memchunk;
int err, l;
ssize_t r;
assert(u);
if (!u->source || !pa_iochannel_is_readable(u->io))
return;
update_usage(u);
err = ioctl(u->fd, I_NREAD, &l);
assert(err >= 0);
memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat);
assert(memchunk.memblock);
if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) {
pa_memblock_unref(memchunk.memblock);
if (errno != EAGAIN)
pa_log(__FILE__": read() failed: %s\n", strerror(errno));
return;
}
assert(r <= (ssize_t) memchunk.memblock->length);
memchunk.length = memchunk.memblock->length = r;
memchunk.index = 0;
pa_source_post(u->source, &memchunk);
pa_memblock_unref(memchunk.memblock);
u->read_bytes += r;
}
static void io_callback(struct pa_iochannel *io, void*userdata) {
struct userdata *u = userdata;
assert(u);
do_write(u);
do_read(u);
}
static pa_usec_t sink_get_latency_cb(struct pa_sink *s) {
pa_usec_t r = 0;
audio_info_t info;
int err;
struct userdata *u = s->userdata;
assert(s && u && u->sink);
err = ioctl(u->fd, AUDIO_GETINFO, &info);
assert(err >= 0);
r += pa_bytes_to_usec(u->written_bytes, &s->sample_spec);
r -= pa_bytes_to_usec(info.play.samples * u->sample_size, &s->sample_spec);
if (u->memchunk.memblock)
r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec);
return r;
}
static pa_usec_t source_get_latency_cb(struct pa_source *s) {
pa_usec_t r = 0;
struct userdata *u = s->userdata;
audio_info_t info;
int err;
assert(s && u && u->source);
err = ioctl(u->fd, AUDIO_GETINFO, &info);
assert(err >= 0);
r += pa_bytes_to_usec(info.record.samples * u->sample_size, &s->sample_spec);
r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec);
return r;
}
static int pa_solaris_auto_format(int fd, int mode, struct pa_sample_spec *ss) {
audio_info_t info;
AUDIO_INITINFO(&info);
if (mode != O_RDONLY) {
info.play.sample_rate = ss->rate;
info.play.channels = ss->channels;
switch (ss->format) {
case PA_SAMPLE_U8:
info.play.precision = 8;
info.play.encoding = AUDIO_ENCODING_LINEAR;
break;
case PA_SAMPLE_ALAW:
info.play.precision = 8;
info.play.encoding = AUDIO_ENCODING_ALAW;
break;
case PA_SAMPLE_ULAW:
info.play.precision = 8;
info.play.encoding = AUDIO_ENCODING_ULAW;
break;
case PA_SAMPLE_S16NE:
info.play.precision = 16;
info.play.encoding = AUDIO_ENCODING_LINEAR;
break;
default:
return -1;
}
}
if (mode != O_WRONLY) {
info.record.sample_rate = ss->rate;
info.record.channels = ss->channels;
switch (ss->format) {
case PA_SAMPLE_U8:
info.record.precision = 8;
info.record.encoding = AUDIO_ENCODING_LINEAR;
break;
case PA_SAMPLE_ALAW:
info.record.precision = 8;
info.record.encoding = AUDIO_ENCODING_ALAW;
break;
case PA_SAMPLE_ULAW:
info.record.precision = 8;
info.record.encoding = AUDIO_ENCODING_ULAW;
break;
case PA_SAMPLE_S16NE:
info.record.precision = 16;
info.record.encoding = AUDIO_ENCODING_LINEAR;
break;
default:
return -1;
}
}
if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
if (errno == EINVAL)
pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format.\n");
else
pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno));
return -1;
}
return 0;
}
static int pa_solaris_set_buffer(int fd, int buffer_size) {
audio_info_t info;
AUDIO_INITINFO(&info);
info.record.buffer_size = buffer_size;
if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
if (errno == EINVAL)
pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size.\n");
else
pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno));
return -1;
}
return 0;
}
int pa__init(struct pa_core *c, struct pa_module*m) {
struct userdata *u = NULL;
const char *p;
int fd = -1;
int buffer_size;
int mode;
int record = 1, playback = 1;
struct pa_sample_spec ss;
struct pa_modargs *ma = NULL;
assert(c && m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log(__FILE__": failed to parse module arguments.\n");
goto fail;
}
if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
pa_log(__FILE__": record= and playback= expect numeric argument.\n");
goto fail;
}
if (!playback && !record) {
pa_log(__FILE__": neither playback nor record enabled for device.\n");
goto fail;
}
mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
buffer_size = -1;
if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) {
pa_log(__FILE__": failed to parse buffer size argument\n");
goto fail;
}
ss = c->default_sample_spec;
if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
pa_log(__FILE__": failed to parse sample specification\n");
goto fail;
}
if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode)) < 0)
goto fail;
pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
if (pa_solaris_auto_format(fd, mode, &ss) < 0)
goto fail;
if ((mode != O_WRONLY) && (buffer_size >= 1))
if (pa_solaris_set_buffer(fd, buffer_size) < 0)
goto fail;
u = pa_xmalloc(sizeof(struct userdata));
u->core = c;
if (mode != O_WRONLY) {
u->source = pa_source_new(c, PA_TYPEID_SOLARIS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss);
assert(u->source);
u->source->userdata = u;
u->source->get_latency = source_get_latency_cb;
pa_source_set_owner(u->source, m);
u->source->description = pa_sprintf_malloc("Solaris PCM on '%s'", p);
} else
u->source = NULL;
if (mode != O_RDONLY) {
u->sink = pa_sink_new(c, PA_TYPEID_SOLARIS, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss);
assert(u->sink);
u->sink->get_latency = sink_get_latency_cb;
u->sink->userdata = u;
pa_sink_set_owner(u->sink, m);
u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p);
} else
u->sink = NULL;
assert(u->source || u->sink);
u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0);
assert(u->io);
pa_iochannel_set_callback(u->io, io_callback, u);
u->fd = fd;
u->memchunk.memblock = NULL;
u->memchunk.length = 0;
u->sample_size = pa_frame_size(&ss);
u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat);
assert(u->silence.memblock);
pa_silence_memblock(u->silence.memblock, &ss);
u->silence.index = 0;
u->written_bytes = 0;
u->read_bytes = 0;
u->module = m;
m->userdata = u;
pa_modargs_free(ma);
return 0;
fail:
if (fd >= 0)
close(fd);
if (ma)
pa_modargs_free(ma);
return -1;
}
void pa__done(struct pa_core *c, struct pa_module*m) {
struct userdata *u;
assert(c && m);
if (!(u = m->userdata))
return;
if (u->memchunk.memblock)
pa_memblock_unref(u->memchunk.memblock);
if (u->silence.memblock)
pa_memblock_unref(u->silence.memblock);
if (u->sink) {
pa_sink_disconnect(u->sink);
pa_sink_unref(u->sink);
}
if (u->source) {
pa_source_disconnect(u->source);
pa_source_unref(u->source);
}
pa_iochannel_free(u->io);
pa_xfree(u);
}

View file

@ -28,7 +28,6 @@
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
@ -284,7 +283,7 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman
return;
}
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) {
/* local and remote seem to have synchronized clocks */
@ -324,7 +323,7 @@ static void request_latency(struct userdata *u) {
pa_tagstruct_putu32(t, tag = u->ctag++);
pa_tagstruct_putu32(t, u->channel);
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
pa_tagstruct_put_timeval(t, &now);
pa_tagstruct_putu64(t, 0);
@ -536,7 +535,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e,
request_latency(u);
gettimeofday(&ntv, NULL);
pa_gettimeofday(&ntv);
ntv.tv_sec += LATENCY_INTERVAL;
m->time_restart(e, &ntv);
}
@ -650,7 +649,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
pa_source_set_owner(u->source, m);
#endif
gettimeofday(&ntv, NULL);
pa_gettimeofday(&ntv);
ntv.tv_sec += LATENCY_INTERVAL;
u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u);

583
polyp/module-waveout.c Normal file
View file

@ -0,0 +1,583 @@
/* $Id: module-waveout.c 333 2005-01-08 21:36:53Z lennart $ */
/***
This file is part of polypaudio.
polypaudio 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 of the License,
or (at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with polypaudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <windows.h>
#include <mmsystem.h>
#include <assert.h>
#include "sink.h"
#include "source.h"
#include "module.h"
#include "mainloop-api.h"
#include "modargs.h"
#include "sample-util.h"
#include "util.h"
#include "log.h"
#include "xmalloc.h"
#include "module-waveout-symdef.h"
PA_MODULE_AUTHOR("Pierre Ossman")
PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source")
PA_MODULE_VERSION(PACKAGE_VERSION)
PA_MODULE_USAGE("sink_name=<name for the sink> source_name=<name for the source> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<fragment size>")
#define PA_TYPEID_WAVEOUT PA_TYPEID_MAKE('W', 'A', 'V', 'E')
#define DEFAULT_SINK_NAME "wave_output"
#define DEFAULT_SOURCE_NAME "wave_input"
struct userdata {
struct pa_sink *sink;
struct pa_source *source;
struct pa_core *core;
struct pa_time_event *event;
struct pa_defer_event *defer;
pa_usec_t poll_timeout;
uint32_t fragments, fragment_size;
uint32_t free_ofrags, free_ifrags;
DWORD written_bytes;
int cur_ohdr, cur_ihdr;
unsigned int oremain;
WAVEHDR *ohdrs, *ihdrs;
struct pa_memchunk silence;
HWAVEOUT hwo;
HWAVEIN hwi;
struct pa_module *module;
CRITICAL_SECTION crit;
};
static const char* const valid_modargs[] = {
"sink_name",
"source_name",
"record",
"playback",
"fragments",
"fragment_size",
"format",
"rate",
"channels",
NULL
};
static void update_usage(struct userdata *u) {
pa_module_set_used(u->module,
(u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) +
(u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) +
(u->source ? pa_idxset_ncontents(u->source->outputs) : 0));
}
static void do_write(struct userdata *u)
{
uint32_t free_frags, remain;
struct pa_memchunk memchunk, *cur_chunk;
WAVEHDR *hdr;
MMRESULT res;
if (!u->sink)
return;
EnterCriticalSection(&u->crit);
free_frags = u->free_ofrags;
u->free_ofrags = 0;
LeaveCriticalSection(&u->crit);
while (free_frags) {
hdr = &u->ohdrs[u->cur_ohdr];
if (hdr->dwFlags & WHDR_PREPARED)
waveOutUnprepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
remain = u->oremain;
while (remain) {
cur_chunk = &memchunk;
if (pa_sink_render(u->sink, remain, cur_chunk) < 0) {
/*
* Don't fill with silence unless we're getting close to
* underflowing.
*/
if (free_frags > u->fragments/2)
cur_chunk = &u->silence;
else {
EnterCriticalSection(&u->crit);
u->free_ofrags += free_frags;
LeaveCriticalSection(&u->crit);
u->oremain = remain;
return;
}
}
assert(cur_chunk->memblock);
assert(cur_chunk->memblock->data);
assert(cur_chunk->length);
memcpy(hdr->lpData + u->fragment_size - remain,
(char*)cur_chunk->memblock->data + cur_chunk->index,
(cur_chunk->length < remain)?cur_chunk->length:remain);
remain -= (cur_chunk->length < remain)?cur_chunk->length:remain;
if (cur_chunk != &u->silence) {
pa_memblock_unref(cur_chunk->memblock);
cur_chunk->memblock = NULL;
}
}
res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
if (res != MMSYSERR_NOERROR) {
pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d\n",
res);
}
res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR));
if (res != MMSYSERR_NOERROR) {
pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d\n",
res);
}
u->written_bytes += u->fragment_size;
free_frags--;
u->cur_ohdr++;
u->cur_ohdr %= u->fragments;
u->oremain = u->fragment_size;
}
}
static void do_read(struct userdata *u)
{
uint32_t free_frags;
struct pa_memchunk memchunk;
WAVEHDR *hdr;
MMRESULT res;
if (!u->source)
return;
EnterCriticalSection(&u->crit);
free_frags = u->free_ifrags;
u->free_ifrags = 0;
LeaveCriticalSection(&u->crit);
while (free_frags) {
hdr = &u->ihdrs[u->cur_ihdr];
if (hdr->dwFlags & WHDR_PREPARED)
waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
if (hdr->dwBytesRecorded) {
memchunk.memblock = pa_memblock_new(hdr->dwBytesRecorded, u->core->memblock_stat);
assert(memchunk.memblock);
memcpy((char*)memchunk.memblock->data, hdr->lpData, hdr->dwBytesRecorded);
memchunk.length = memchunk.memblock->length = hdr->dwBytesRecorded;
memchunk.index = 0;
pa_source_post(u->source, &memchunk);
pa_memblock_unref(memchunk.memblock);
}
res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
if (res != MMSYSERR_NOERROR) {
pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d\n",
res);
}
res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR));
if (res != MMSYSERR_NOERROR) {
pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d\n",
res);
}
free_frags--;
u->cur_ihdr++;
u->cur_ihdr %= u->fragments;
}
}
static void poll_cb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) {
struct userdata *u = userdata;
struct timeval ntv;
assert(u);
update_usage(u);
do_write(u);
do_read(u);
pa_gettimeofday(&ntv);
pa_timeval_add(&ntv, u->poll_timeout);
a->time_restart(e, &ntv);
}
static void defer_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) {
struct userdata *u = userdata;
assert(u);
a->defer_enable(e, 0);
do_write(u);
do_read(u);
}
static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
struct userdata *u = (struct userdata *)inst;
if (msg != WOM_DONE)
return;
EnterCriticalSection(&u->crit);
u->free_ofrags++;
assert(u->free_ofrags <= u->fragments);
LeaveCriticalSection(&u->crit);
}
static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
struct userdata *u = (struct userdata *)inst;
if (msg != WIM_DATA)
return;
EnterCriticalSection(&u->crit);
u->free_ifrags++;
assert(u->free_ifrags <= u->fragments);
LeaveCriticalSection(&u->crit);
}
static pa_usec_t sink_get_latency_cb(struct pa_sink *s) {
struct userdata *u = s->userdata;
uint32_t free_frags;
MMTIME mmt;
assert(s && u && u->sink);
memset(&mmt, 0, sizeof(mmt));
mmt.wType = TIME_BYTES;
if (waveOutGetPosition(u->hwo, &mmt, sizeof(mmt)) == MMSYSERR_NOERROR)
return pa_bytes_to_usec(u->written_bytes - mmt.u.cb, &s->sample_spec);
else {
EnterCriticalSection(&u->crit);
free_frags = u->free_ofrags;
LeaveCriticalSection(&u->crit);
return pa_bytes_to_usec((u->fragments - free_frags) * u->fragment_size,
&s->sample_spec);
}
}
static pa_usec_t source_get_latency_cb(struct pa_source *s) {
pa_usec_t r = 0;
struct userdata *u = s->userdata;
uint32_t free_frags;
assert(s && u && u->sink);
EnterCriticalSection(&u->crit);
free_frags = u->free_ifrags;
LeaveCriticalSection(&u->crit);
r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &s->sample_spec);
fprintf(stderr, "Latency: %d us\n", (int)r);
return r;
}
static void notify_sink_cb(struct pa_sink *s) {
struct userdata *u = s->userdata;
assert(u);
u->core->mainloop->defer_enable(u->defer, 1);
}
static void notify_source_cb(struct pa_source *s) {
struct userdata *u = s->userdata;
assert(u);
u->core->mainloop->defer_enable(u->defer, 1);
}
static int ss_to_waveformat(struct pa_sample_spec *ss, LPWAVEFORMATEX wf) {
wf->wFormatTag = WAVE_FORMAT_PCM;
if (ss->channels > 2) {
pa_log_error(__FILE__": ERROR: More than two channels not supported.\n");
return -1;
}
wf->nChannels = ss->channels;
switch (ss->rate) {
case 8000:
case 11025:
case 22005:
case 44100:
break;
default:
pa_log_error(__FILE__": ERROR: Unsupported sample rate.\n");
return -1;
}
wf->nSamplesPerSec = ss->rate;
if (ss->format == PA_SAMPLE_U8)
wf->wBitsPerSample = 8;
else if (ss->format == PA_SAMPLE_S16NE)
wf->wBitsPerSample = 16;
else {
pa_log_error(__FILE__": ERROR: Unsupported sample format.\n");
return -1;
}
wf->nBlockAlign = wf->nChannels * wf->wBitsPerSample/8;
wf->nAvgBytesPerSec = wf->nSamplesPerSec * wf->nBlockAlign;
wf->cbSize = 0;
return 0;
}
int pa__init(struct pa_core *c, struct pa_module*m) {
struct userdata *u = NULL;
HWAVEOUT hwo = INVALID_HANDLE_VALUE;
HWAVEIN hwi = INVALID_HANDLE_VALUE;
WAVEFORMATEX wf;
int nfrags, frag_size;
int record = 1, playback = 1;
struct pa_sample_spec ss;
struct pa_modargs *ma = NULL;
unsigned int i;
struct timeval tv;
assert(c && m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log(__FILE__": failed to parse module arguments.\n");
goto fail;
}
if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
pa_log(__FILE__": record= and playback= expect boolean argument.\n");
goto fail;
}
if (!playback && !record) {
pa_log(__FILE__": neither playback nor record enabled for device.\n");
goto fail;
}
nfrags = 20;
frag_size = 1024;
if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
pa_log(__FILE__": failed to parse fragments arguments\n");
goto fail;
}
ss = c->default_sample_spec;
if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
pa_log(__FILE__": failed to parse sample specification\n");
goto fail;
}
if (ss_to_waveformat(&ss, &wf) < 0)
goto fail;
u = pa_xmalloc(sizeof(struct userdata));
if (record) {
if (waveInOpen(&hwi, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
goto fail;
if (waveInStart(hwi) != MMSYSERR_NOERROR)
goto fail;
pa_log_debug(__FILE__": Opened waveIn subsystem.\n");
}
if (playback) {
if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
goto fail;
pa_log_debug(__FILE__": Opened waveOut subsystem.\n");
}
InitializeCriticalSection(&u->crit);
if (hwi != INVALID_HANDLE_VALUE) {
u->source = pa_source_new(c, PA_TYPEID_WAVEOUT, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss);
assert(u->source);
u->source->userdata = u;
u->source->notify = notify_source_cb;
u->source->get_latency = source_get_latency_cb;
pa_source_set_owner(u->source, m);
u->source->description = pa_sprintf_malloc("Windows waveIn PCM");
} else
u->source = NULL;
if (hwo != INVALID_HANDLE_VALUE) {
u->sink = pa_sink_new(c, PA_TYPEID_WAVEOUT, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss);
assert(u->sink);
u->sink->notify = notify_sink_cb;
u->sink->get_latency = sink_get_latency_cb;
u->sink->userdata = u;
pa_sink_set_owner(u->sink, m);
u->sink->description = pa_sprintf_malloc("Windows waveOut PCM");
} else
u->sink = NULL;
assert(u->source || u->sink);
u->core = c;
u->hwi = hwi;
u->hwo = hwo;
u->fragments = nfrags;
u->free_ifrags = u->fragments;
u->free_ofrags = u->fragments;
u->fragment_size = frag_size - (frag_size % pa_frame_size(&ss));
u->written_bytes = 0;
u->oremain = u->fragment_size;
u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 3, &ss);
pa_gettimeofday(&tv);
pa_timeval_add(&tv, u->poll_timeout);
u->event = c->mainloop->time_new(c->mainloop, &tv, poll_cb, u);
assert(u->event);
u->defer = c->mainloop->defer_new(c->mainloop, defer_cb, u);
assert(u->defer);
c->mainloop->defer_enable(u->defer, 0);
u->cur_ihdr = 0;
u->cur_ohdr = 0;
u->ihdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
assert(u->ihdrs);
u->ohdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
assert(u->ohdrs);
for (i = 0;i < u->fragments;i++) {
u->ihdrs[i].dwBufferLength = u->fragment_size;
u->ohdrs[i].dwBufferLength = u->fragment_size;
u->ihdrs[i].lpData = pa_xmalloc(u->fragment_size);
assert(u->ihdrs);
u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size);
assert(u->ohdrs);
}
u->silence.length = u->fragment_size;
u->silence.memblock = pa_memblock_new(u->silence.length, u->core->memblock_stat);
assert(u->silence.memblock);
pa_silence_memblock(u->silence.memblock, &ss);
u->silence.index = 0;
u->module = m;
m->userdata = u;
pa_modargs_free(ma);
return 0;
fail:
if (hwi != INVALID_HANDLE_VALUE)
waveInClose(hwi);
if (hwo != INVALID_HANDLE_VALUE)
waveOutClose(hwo);
if (u)
pa_xfree(u);
if (ma)
pa_modargs_free(ma);
return -1;
}
void pa__done(struct pa_core *c, struct pa_module*m) {
struct userdata *u;
unsigned int i;
assert(c && m);
if (!(u = m->userdata))
return;
if (u->event)
c->mainloop->time_free(u->event);
if (u->defer)
c->mainloop->defer_free(u->defer);
if (u->sink) {
pa_sink_disconnect(u->sink);
pa_sink_unref(u->sink);
}
if (u->source) {
pa_source_disconnect(u->source);
pa_source_unref(u->source);
}
if (u->hwi != INVALID_HANDLE_VALUE) {
waveInReset(u->hwi);
waveInClose(u->hwi);
}
if (u->hwo != INVALID_HANDLE_VALUE) {
waveOutReset(u->hwo);
waveOutClose(u->hwo);
}
for (i = 0;i < u->fragments;i++) {
pa_xfree(u->ihdrs[i].lpData);
pa_xfree(u->ohdrs[i].lpData);
}
pa_xfree(u->ihdrs);
pa_xfree(u->ohdrs);
DeleteCriticalSection(&u->crit);
pa_xfree(u);
}

View file

@ -47,7 +47,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e,
pa_module_unload_unused(c);
gettimeofday(&ntv, NULL);
pa_gettimeofday(&ntv);
ntv.tv_sec += UNLOAD_POLL_TIME;
m->time_restart(e, &ntv);
}
@ -98,7 +98,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char
if (!c->module_auto_unload_event) {
struct timeval ntv;
gettimeofday(&ntv, NULL);
pa_gettimeofday(&ntv);
ntv.tv_sec += UNLOAD_POLL_TIME;
c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c);
}

View file

@ -92,7 +92,7 @@ fail:
int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) {
int format, channels, speed, reqformat;
static const int format_trans[] = {
static const int format_trans[PA_SAMPLE_MAX] = {
[PA_SAMPLE_U8] = AFMT_U8,
[PA_SAMPLE_ALAW] = AFMT_A_LAW,
[PA_SAMPLE_ULAW] = AFMT_MU_LAW,

View file

@ -480,8 +480,12 @@ int main(int argc, char *argv[]) {
assert(r == 0);
pa_signal_new(SIGINT, exit_signal_callback, NULL);
pa_signal_new(SIGTERM, exit_signal_callback, NULL);
#ifdef SIGUSR1
pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
#endif
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
if (!(stdio_event = mainloop_api->io_new(mainloop_api,
mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,

View file

@ -739,7 +739,9 @@ int main(int argc, char *argv[]) {
r = pa_signal_init(mainloop_api);
assert(r == 0);
pa_signal_new(SIGINT, exit_signal_callback, NULL);
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
if (!(context = pa_context_new(mainloop_api, client_name))) {
fprintf(stderr, "pa_context_new() failed.\n");

View file

@ -338,7 +338,9 @@ int main(int argc, char *argv[]) {
r = pa_signal_init(mainloop_api);
assert(r == 0);
pa_signal_new(SIGINT, exit_signal_callback, NULL);
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
/* Create a new connection context */
if (!(context = pa_context_new(mainloop_api, client_name))) {

View file

@ -32,6 +32,7 @@
#include "xmalloc.h"
#include "llist.h"
#include "log.h"
#include "util.h"
/*#define DEBUG_OPCODES */
@ -245,7 +246,7 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time
r->userdata = userdata;
r->tag = tag;
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
tv.tv_sec += timeout;
r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r);

View file

@ -35,6 +35,10 @@
#include <limits.h>
#include <signal.h>
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "pid.h"
#include "util.h"
#include "log.h"
@ -130,6 +134,10 @@ int pa_pid_file_create(void) {
pid_t pid;
size_t l;
#ifdef OS_IS_WIN32
HANDLE process;
#endif
pa_runtime_path("pid", fn, sizeof(fn));
if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0)
@ -138,7 +146,12 @@ int pa_pid_file_create(void) {
if ((pid = read_pid(fn, fd)) == (pid_t) -1)
pa_log(__FILE__": corrupt PID file, overwriting.\n");
else if (pid > 0) {
#ifdef OS_IS_WIN32
if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) {
CloseHandle(process);
#else
if (kill(pid, 0) >= 0 || errno != ESRCH) {
#endif
pa_log(__FILE__": daemon already running.\n");
goto fail;
}
@ -198,6 +211,12 @@ int pa_pid_file_remove(void) {
goto fail;
}
#ifdef OS_IS_WIN32
pa_lock_fd(fd, 0);
close(fd);
fd = -1;
#endif
if (unlink(fn) < 0) {
pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno));
goto fail;
@ -223,6 +242,8 @@ int pa_pid_file_check_running(pid_t *pid) {
return pa_pid_file_kill(0, pid);
}
#ifndef OS_IS_WIN32
/* Kill a current running daemon. Return non-zero on success, -1
* otherwise. If successful *pid contains the PID of the daemon
* process. */
@ -242,7 +263,7 @@ int pa_pid_file_kill(int sig, pid_t *pid) {
if ((*pid = read_pid(fn, fd)) == (pid_t) -1)
goto fail;
ret = kill(*pid, sig);
fail:
@ -255,3 +276,11 @@ fail:
return ret;
}
#else /* OS_IS_WIN32 */
int pa_pid_file_kill(int sig, pid_t *pid) {
return -1;
}
#endif

190
polyp/poll.c Normal file
View file

@ -0,0 +1,190 @@
/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */
/***
Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
Copyright (C) 2005, Cendio AB.
This file is part of polypaudio.
Based on work for the GNU C Library.
polypaudio is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with polypaudio; If not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
***/
/* Poll the file descriptors described by the NFDS structures starting at
FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
an event to occur; if TIMEOUT is -1, block until an event occurs.
Returns the number of file descriptors with events, zero if timed out,
or -1 for errors. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include "winsock.h"
#ifndef HAVE_SYS_POLL_H
#include "util.h"
#include "poll.h"
int poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
struct timeval tv;
fd_set rset, wset, xset;
struct pollfd *f;
int ready;
int maxfd = 0;
char data[64];
FD_ZERO (&rset);
FD_ZERO (&wset);
FD_ZERO (&xset);
if (nfds == 0) {
if (timeout >= 0) {
pa_msleep(timeout);
return 0;
}
#ifdef OS_IS_WIN32
/*
* Windows does not support signals properly so waiting for them would
* mean a deadlock.
*/
pa_msleep(100);
return 0;
#else
return select(0, NULL, NULL, NULL, NULL);
#endif
}
for (f = fds; f < &fds[nfds]; ++f) {
if (f->fd != -1) {
if (f->events & POLLIN)
FD_SET (f->fd, &rset);
if (f->events & POLLOUT)
FD_SET (f->fd, &wset);
if (f->events & POLLPRI)
FD_SET (f->fd, &xset);
if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
maxfd = f->fd;
}
}
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
if ((ready == -1) && (errno == EBADF)) {
ready = 0;
FD_ZERO (&rset);
FD_ZERO (&wset);
FD_ZERO (&xset);
maxfd = -1;
for (f = fds; f < &fds[nfds]; ++f) {
if (f->fd != -1) {
fd_set sngl_rset, sngl_wset, sngl_xset;
FD_ZERO (&sngl_rset);
FD_ZERO (&sngl_wset);
FD_ZERO (&sngl_xset);
if (f->events & POLLIN)
FD_SET (f->fd, &sngl_rset);
if (f->events & POLLOUT)
FD_SET (f->fd, &sngl_wset);
if (f->events & POLLPRI)
FD_SET (f->fd, &sngl_xset);
if (f->events & (POLLIN|POLLOUT|POLLPRI)) {
struct timeval singl_tv;
singl_tv.tv_sec = 0;
singl_tv.tv_usec = 0;
if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset,
SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
SELECT_TYPE_ARG5 &singl_tv) != -1) {
if (f->events & POLLIN)
FD_SET (f->fd, &rset);
if (f->events & POLLOUT)
FD_SET (f->fd, &wset);
if (f->events & POLLPRI)
FD_SET (f->fd, &xset);
if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
maxfd = f->fd;
++ready;
} else if (errno == EBADF)
f->revents |= POLLNVAL;
}
}
}
if (ready) {
/* Linux alters the tv struct... but it shouldn't matter here ...
* as we're going to be a little bit out anyway as we've just eaten
* more than a couple of cpu cycles above */
ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
}
}
#ifdef OS_IS_WIN32
errno = WSAGetLastError();
#endif
if (ready > 0) {
ready = 0;
for (f = fds; f < &fds[nfds]; ++f) {
f->revents = 0;
if (f->fd != -1) {
if (FD_ISSET (f->fd, &rset)) {
/* support for POLLHUP. An hung up descriptor does not
increase the return value! */
if (recv (f->fd, data, 64, MSG_PEEK) == -1) {
if (errno == ESHUTDOWN || errno == ECONNRESET ||
errno == ECONNABORTED || errno == ENETRESET) {
fprintf(stderr, "Hangup\n");
f->revents |= POLLHUP;
}
}
if (f->revents == 0)
f->revents |= POLLIN;
}
if (FD_ISSET (f->fd, &wset))
f->revents |= POLLOUT;
if (FD_ISSET (f->fd, &xset))
f->revents |= POLLPRI;
}
if (f->revents)
ready++;
}
}
return ready;
}
#endif /* HAVE_SYS_POLL_H */

57
polyp/poll.h Normal file
View file

@ -0,0 +1,57 @@
/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */
/***
Compatibility definitions for System V `poll' interface.
Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc.
Copyright (C) 2005, Cendio AB.
This file is part of polypaudio.
Based on work for the GNU C Library.
polypaudio is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
polypaudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with polypaudio; If not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
***/
/* Event types that can be polled for. These bits may be set in `events'
to indicate the interesting event types; they will appear in `revents'
to indicate the status of the file descriptor. */
#define POLLIN 0x001 /* There is data to read. */
#define POLLPRI 0x002 /* There is urgent data to read. */
#define POLLOUT 0x004 /* Writing now will not block. */
/* Event types always implicitly polled for. These bits need not be set in
`events', but they will appear in `revents' to indicate the status of
the file descriptor. */
#define POLLERR 0x008 /* Error condition. */
#define POLLHUP 0x010 /* Hung up. */
#define POLLNVAL 0x020 /* Invalid polling request. */
/* Type used for the number of file descriptors. */
typedef unsigned long int nfds_t;
/* Data structure describing a polling request. */
struct pollfd
{
int fd; /* File descriptor to poll. */
short int events; /* Types of events poller cares about. */
short int revents; /* Types of events that actually occurred. */
};
/* Poll the file descriptors described by the NFDS structures starting at
FDS. If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
an event to occur; if TIMEOUT is -1, block until an event occurs.
Returns the number of file descriptors with events, zero if timed out,
or -1 for errors. */
extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);

View file

@ -28,13 +28,24 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>
#include <limits.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include "winsock.h"
#include "polyplib-internal.h"
#include "polyplib-context.h"
@ -110,8 +121,10 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
c->autospawn_lock_fd = -1;
memset(&c->spawn_api, 0, sizeof(c->spawn_api));
c->do_autospawn = 0;
#ifdef SIGPIPE
pa_check_signal_is_blocked(SIGPIPE);
#endif
c->conf = pa_client_conf_new();
pa_client_conf_load(c->conf, NULL);
@ -372,6 +385,8 @@ finish:
static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata);
#ifndef OS_IS_WIN32
static int context_connect_spawn(struct pa_context *c) {
pid_t pid;
int status, r;
@ -485,6 +500,8 @@ fail:
return -1;
}
#endif /* OS_IS_WIN32 */
static int try_next_connection(struct pa_context *c) {
char *u = NULL;
int r = -1;
@ -499,10 +516,12 @@ static int try_next_connection(struct pa_context *c) {
if (!u) {
#ifndef OS_IS_WIN32
if (c->do_autospawn) {
r = context_connect_spawn(c);
goto finish;
}
#endif
pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
goto finish;

View file

@ -93,6 +93,7 @@ struct pa_stream {
uint32_t requested_bytes;
uint64_t counter;
pa_usec_t previous_time;
pa_usec_t previous_ipol_time;
enum pa_stream_state state;
struct pa_mcalign *mcalign;

View file

@ -66,6 +66,7 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st
s->counter = 0;
s->previous_time = 0;
s->previous_ipol_time = 0;
s->corked = 0;
s->interpolate = 0;
@ -217,7 +218,7 @@ static void ipol_callback(struct pa_mainloop_api *m, struct pa_time_event *e, co
s->ipol_requested = 1;
}
gettimeofday(&tv2, NULL);
pa_gettimeofday(&tv2);
pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC);
m->time_restart(e, &tv2);
@ -256,7 +257,7 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32
struct timeval tv;
pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL));
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */
assert(!s->ipol_event);
@ -412,7 +413,7 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c
pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish;
} else {
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) {
/* local and remote seem to have synchronized clocks */
@ -470,7 +471,7 @@ struct pa_operation* pa_stream_get_latency_info(struct pa_stream *s, void (*cb)(
pa_tagstruct_putu32(t, tag = s->context->ctag++);
pa_tagstruct_putu32(t, s->channel);
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
pa_tagstruct_put_timeval(t, &now);
pa_tagstruct_putu64(t, s->counter);
@ -581,7 +582,7 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru
s->ipol_usec = pa_stream_get_interpolated_time(s);
else if (s->corked && !b)
/* Unpausing */
gettimeofday(&s->ipol_timestamp, NULL);
pa_gettimeofday(&s->ipol_timestamp);
}
s->corked = b;
@ -702,7 +703,7 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *
usec = s->previous_time;
s->previous_time = usec;
return usec;
}
@ -762,10 +763,11 @@ pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s) {
usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp);
}
if (usec < s->previous_time)
usec = s->previous_time;
if (usec < s->previous_ipol_time)
usec = s->previous_ipol_time;
s->previous_ipol_time = usec;
s->previous_time = usec;
return usec;
}

View file

@ -239,11 +239,14 @@ static void* connection_write(struct connection *c, size_t length) {
return (uint8_t*) c->write_data+i;
}
static void format_esd2native(int format, struct pa_sample_spec *ss) {
static void format_esd2native(int format, int swap_bytes, struct pa_sample_spec *ss) {
assert(ss);
ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
ss->format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8;
if ((format & ESD_MASK_BITS) == ESD_BITS16)
ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE;
else
ss->format = PA_SAMPLE_U8;
}
static int format_native2esd(struct pa_sample_spec *ss) {
@ -303,7 +306,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons
rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
ss.rate = rate;
format_esd2native(format, &ss);
format_esd2native(format, c->swap_byte_order, &ss);
if (!pa_sample_spec_valid(&ss)) {
pa_log(__FILE__": invalid sample specification\n");
@ -359,7 +362,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co
rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
ss.rate = rate;
format_esd2native(format, &ss);
format_esd2native(format, c->swap_byte_order, &ss);
if (!pa_sample_spec_valid(&ss)) {
pa_log(__FILE__": invalid sample specification.\n");
@ -426,7 +429,6 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons
latency = 0;
else {
double usec = pa_sink_get_latency(sink);
usec += PLAYBACK_BUFFER_SECONDS*1000000; /* A better estimation would be a good idea! */
latency = (int) ((usec*44100)/1000000);
}
@ -603,7 +605,7 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con
rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
ss.rate = rate;
format_esd2native(format, &ss);
format_esd2native(format, c->swap_byte_order, &ss);
sc_length = (size_t) maybe_swap_endian_32(c->swap_byte_order, (*((int*)data + 2)));
@ -1099,7 +1101,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo
if (!c->authorized) {
struct timeval tv;
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
tv.tv_sec += AUTH_TIMEOUT;
c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
} else

View file

@ -928,7 +928,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma
pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq));
pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq));
pa_tagstruct_put_timeval(reply, &tv);
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
pa_tagstruct_put_timeval(reply, &now);
pa_tagstruct_putu64(reply, counter);
pa_pstream_send_tagstruct(c->pstream, reply);
@ -971,7 +971,7 @@ static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command
pa_tagstruct_put_boolean(reply, 0);
pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq));
pa_tagstruct_put_timeval(reply, &tv);
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
pa_tagstruct_put_timeval(reply, &now);
pa_tagstruct_putu64(reply, counter);
pa_pstream_send_tagstruct(c->pstream, reply);
@ -2024,7 +2024,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo
if (!c->authorized) {
struct timeval tv;
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
tv.tv_sec += AUTH_TIMEOUT;
c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
} else

View file

@ -27,7 +27,12 @@
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "winsock.h"
#include "pstream.h"
#include "queue.h"

View file

@ -19,6 +19,10 @@
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@ -31,13 +35,16 @@
#include "util.h"
#include "log.h"
#ifndef OS_IS_WIN32
#define RANDOM_DEVICE "/dev/urandom"
#endif
void pa_random(void *ret_data, size_t length) {
int fd;
ssize_t r = 0;
assert(ret_data && length);
#ifdef RANDOM_DEVICE
if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) {
if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length)
@ -45,17 +52,20 @@ void pa_random(void *ret_data, size_t length) {
close(fd);
}
#endif
if ((size_t) r != length) {
uint8_t *p;
size_t l;
#ifdef RANDOM_DEVICE
pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s"
", falling back to unsecure pseudo RNG.\n", strerror(errno));
#endif
srandom(time(NULL));
srand(time(NULL));
for (p = ret_data, l = length; l > 0; p++, l--)
*p = (uint8_t) random();
*p = (uint8_t) rand();
}
}

View file

@ -161,7 +161,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
size_t d;
for (d = 0;; d += sizeof(float)) {
float_t sum = 0;
pa_volume_t sum = 0;
unsigned c;
if (d >= length)

View file

@ -51,11 +51,19 @@ enum pa_sample_format {
#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE
/** 32 Bit IEEE floating point, native endian */
#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE
/** Signed 16 Bit PCM reverse endian */
#define PA_SAMPLE_S16RE PA_SAMPLE_S16LE
/** 32 Bit IEEE floating point, reverse endian */
#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE
#else
/** Signed 16 Bit PCM, native endian */
#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE
/** 32 Bit IEEE floating point, native endian */
#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE
/** Signed 16 Bit PCM reverse endian */
#define PA_SAMPLE_S16RE PA_SAMPLE_S16BE
/** 32 Bit IEEE floating point, reverse endian */
#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE
#endif
/** A Shortcut for PA_SAMPLE_FLOAT32NE */

View file

@ -32,7 +32,14 @@
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "scache.h"
#include "sink-input.h"
@ -55,7 +62,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e,
pa_scache_unload_unused(c);
gettimeofday(&ntv, NULL);
pa_gettimeofday(&ntv);
ntv.tv_sec += UNLOAD_POLL_TIME;
m->time_restart(e, &ntv);
}
@ -144,6 +151,13 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename
struct pa_memchunk chunk;
int r;
#ifdef OS_IS_WIN32
char buf[MAX_PATH];
if (ExpandEnvironmentStrings(filename, buf, MAX_PATH))
filename = buf;
#endif
if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0)
return -1;
@ -155,6 +169,14 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename
int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index) {
struct pa_scache_entry *e;
#ifdef OS_IS_WIN32
char buf[MAX_PATH];
if (ExpandEnvironmentStrings(filename, buf, MAX_PATH))
filename = buf;
#endif
assert(c && name);
if (!(e = scache_add_item(c, name)))
@ -165,7 +187,7 @@ int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *fil
if (!c->scache_auto_unload_event) {
struct timeval ntv;
gettimeofday(&ntv, NULL);
pa_gettimeofday(&ntv);
ntv.tv_sec += UNLOAD_POLL_TIME;
c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c);
}
@ -303,17 +325,16 @@ static void add_file(struct pa_core *c, const char *pathname) {
struct stat st;
const char *e;
if (!(e = strrchr(pathname, '/')))
e = pathname;
else
e++;
e = pa_path_get_filename(pathname);
if (stat(pathname, &st) < 0) {
pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno));
return;
}
#if defined(S_ISREG) && defined(S_ISLNK)
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
#endif
pa_scache_add_file_lazy(c, e, pathname, NULL);
}
@ -323,6 +344,7 @@ int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname) {
/* First try to open this as directory */
if (!(dir = opendir(pathname))) {
#ifdef HAVE_GLOB_H
glob_t p;
unsigned int i;
/* If that fails, try to open it as shell glob */
@ -336,6 +358,9 @@ int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname) {
add_file(c, p.gl_pathv[i]);
globfree(&p);
#else
return -1;
#endif
} else {
struct dirent *e;

View file

@ -31,14 +31,29 @@
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_LIBASYNCNS
#include <asyncns.h>
#endif
#include "winsock.h"
#include "socket-client.h"
#include "socket-util.h"
#include "util.h"
@ -120,7 +135,7 @@ static void do_call(struct pa_socket_client *c) {
goto finish;
lerror = sizeof(error);
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) {
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) {
pa_log(__FILE__": getsockopt(): %s\n", strerror(errno));
goto finish;
}
@ -198,18 +213,28 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui
return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
}
#ifdef HAVE_SYS_UN_H
struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) {
struct sockaddr_un sa;
assert(m && filename);
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_LOCAL;
sa.sun_family = AF_UNIX;
strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
}
#else /* HAVE_SYS_UN_H */
struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) {
return NULL;
}
#endif /* HAVE_SYS_UN_H */
static int sockaddr_prepare(struct pa_socket_client *c, const struct sockaddr *sa, size_t salen) {
assert(c);
assert(sa);
@ -377,7 +402,7 @@ static void start_timeout(struct pa_socket_client *c) {
assert(c);
assert(!c->timeout_event);
gettimeofday(&tv, NULL);
pa_gettimeofday(&tv);
pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000);
c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c);
}
@ -426,8 +451,9 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m,
assert(c->asyncns_query);
start_timeout(c);
}
#else
#else /* HAVE_LIBASYNCNS */
{
#ifdef HAVE_GETADDRINFO
int ret;
struct addrinfo *res = NULL;
@ -438,12 +464,37 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m,
if (res->ai_addr) {
if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
start_timeout(c);
start_timeout(c);
}
freeaddrinfo(res);
#else /* HAVE_GETADDRINFO */
struct hostent *host = NULL;
struct sockaddr_in s;
/* FIXME: PF_INET6 support */
if (hints.ai_family != PF_INET)
goto finish;
host = gethostbyname(a.path_or_host);
if (!host) {
unsigned int addr = inet_addr(a.path_or_host);
if (addr != INADDR_NONE)
host = gethostbyaddr((char*)&addr, 4, AF_INET);
}
if (!host)
goto finish;
s.sin_family = AF_INET;
memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr));
s.sin_port = port;
if ((c = pa_socket_client_new_sockaddr(m, &s, sizeof(s))))
start_timeout(c);
#endif /* HAVE_GETADDRINFO */
}
#endif
#endif /* HAVE_LIBASYNCNS */
}
}

View file

@ -23,11 +23,12 @@
***/
#include <inttypes.h>
#include <sys/socket.h>
#include "mainloop-api.h"
#include "iochannel.h"
struct sockaddr;
struct pa_socket_client;
struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port);

View file

@ -28,17 +28,36 @@
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#include <netinet/in.h>
#ifndef SUN_LEN
#define SUN_LEN(ptr) \
((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
#endif
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_LIBWRAP
#include <tcpd.h>
#endif
#ifndef HAVE_INET_NTOP
#include "inet_ntop.h"
#endif
#include "winsock.h"
#include "socket-server.h"
#include "socket-util.h"
#include "xmalloc.h"
@ -137,6 +156,8 @@ struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s) {
return s;
}
#ifdef HAVE_SYS_UN_H
struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) {
int fd = -1;
struct sockaddr_un sa;
@ -144,14 +165,14 @@ struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, co
assert(m && filename);
if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
pa_log(__FILE__": socket(): %s\n", strerror(errno));
goto fail;
}
pa_fd_set_cloexec(fd, 1);
sa.sun_family = AF_LOCAL;
sa.sun_family = AF_UNIX;
strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
@ -182,6 +203,14 @@ fail:
return NULL;
}
#else /* HAVE_SYS_UN_H */
struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) {
return NULL;
}
#endif /* HAVE_SYS_UN_H */
struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) {
struct pa_socket_server *ss;
int fd = -1;
@ -197,7 +226,7 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui
pa_fd_set_cloexec(fd, 1);
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
pa_log(__FILE__": setsockopt(): %s\n", strerror(errno));
pa_socket_tcp_low_delay(fd);
@ -246,7 +275,7 @@ struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, ui
pa_fd_set_cloexec(fd, 1);
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
pa_log(__FILE__": setsockopt(): %s\n", strerror(errno));
pa_socket_tcp_low_delay(fd);
@ -314,9 +343,9 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
switch (s->type) {
case SOCKET_SERVER_IPV6: {
struct sockaddr_in6 sa;
socklen_t l = sizeof(sa);
socklen_t sa_len = sizeof(sa);
if (getsockname(s->fd, (struct sockaddr*) &sa, &l) < 0) {
if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno));
return NULL;
}
@ -350,9 +379,9 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
case SOCKET_SERVER_IPV4: {
struct sockaddr_in sa;
socklen_t l = sizeof(sa);
socklen_t sa_len = sizeof(sa);
if (getsockname(s->fd, &sa, &l) < 0) {
if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno));
return NULL;
}

View file

@ -31,16 +31,33 @@
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in_systm.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#ifdef HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#ifdef HAVE_NETINET_TCP_H
#include <netinet/tcp.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include "winsock.h"
#include "socket-util.h"
#include "util.h"
@ -57,6 +74,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
return;
}
#ifndef OS_IS_WIN32
if (S_ISSOCK(st.st_mode)) {
union {
struct sockaddr sa;
@ -77,7 +95,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
ip & 0xFF,
ntohs(sa.in.sin_port));
return;
} else if (sa.sa.sa_family == AF_LOCAL) {
} else if (sa.sa.sa_family == AF_UNIX) {
snprintf(c, l, "UNIX socket client");
return;
}
@ -89,17 +107,18 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
snprintf(c, l, "STDIN/STDOUT client");
return;
}
#endif /* OS_IS_WIN32 */
snprintf(c, l, "Unknown client");
}
int pa_socket_low_delay(int fd) {
#ifdef SO_PRIORITY
int priority;
assert(fd >= 0);
#ifdef SO_PRIORITY
priority = 7;
if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0)
return -1;
#endif
@ -114,12 +133,13 @@ int pa_socket_tcp_low_delay(int fd) {
ret = pa_socket_low_delay(fd);
on = 1;
tos = 0;
#if defined(SOL_TCP) || defined(IPPROTO_TCP)
#if defined(SOL_TCP)
if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
#else
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
#endif
ret = -1;
#endif
@ -128,9 +148,9 @@ int pa_socket_tcp_low_delay(int fd) {
defined(IPPROTO_IP))
tos = IPTOS_LOWDELAY;
#ifdef SOL_IP
if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
#else
if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
#endif
ret = -1;
#endif
@ -142,7 +162,7 @@ int pa_socket_tcp_low_delay(int fd) {
int pa_socket_set_rcvbuf(int fd, size_t l) {
assert(fd >= 0);
/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { */
/* if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */
/* pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */
/* return -1; */
/* } */
@ -153,7 +173,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l) {
int pa_socket_set_sndbuf(int fd, size_t l) {
assert(fd >= 0);
/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { */
/* if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */
/* pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */
/* return -1; */
/* } */
@ -161,16 +181,18 @@ int pa_socket_set_sndbuf(int fd, size_t l) {
return 0;
}
#ifdef HAVE_SYS_UN_H
int pa_unix_socket_is_stale(const char *fn) {
struct sockaddr_un sa;
int fd = -1, ret = -1;
if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
pa_log(__FILE__": socket(): %s\n", strerror(errno));
goto finish;
}
sa.sun_family = AF_LOCAL;
sa.sun_family = AF_UNIX;
strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1);
sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
@ -202,3 +224,15 @@ int pa_unix_socket_remove_stale(const char *fn) {
return 0;
}
#else /* HAVE_SYS_UN_H */
int pa_unix_socket_is_stale(const char *fn) {
return -1;
}
int pa_unix_socket_remove_stale(const char *fn) {
return -1;
}
#endif /* HAVE_SYS_UN_H */

View file

@ -27,9 +27,14 @@
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <assert.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "winsock.h"
#include "tagstruct.h"
#include "xmalloc.h"
@ -118,7 +123,8 @@ void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) {
assert(t);
extend(t, 5);
t->data[t->length] = TAG_U32;
*((uint32_t*) (t->data+t->length+1)) = htonl(i);
i = htonl(i);
memcpy(t->data+t->length+1, &i, 4);
t->length += 5;
}
@ -131,21 +137,25 @@ void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c) {
}
void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss) {
uint32_t rate;
assert(t && ss);
extend(t, 7);
t->data[t->length] = TAG_SAMPLE_SPEC;
t->data[t->length+1] = (uint8_t) ss->format;
t->data[t->length+2] = ss->channels;
*(uint32_t*) (t->data+t->length+3) = htonl(ss->rate);
rate = htonl(ss->rate);
memcpy(t->data+t->length+3, &rate, 4);
t->length += 7;
}
void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) {
uint32_t tmp;
assert(t && p);
extend(t, 5+length);
t->data[t->length] = TAG_ARBITRARY;
*((uint32_t*) (t->data+t->length+1)) = htonl(length);
tmp = htonl(length);
memcpy(t->data+t->length+1, &tmp, 4);
if (length)
memcpy(t->data+t->length+5, p, length);
t->length += 5+length;
@ -159,29 +169,38 @@ void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b) {
}
void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv) {
uint32_t tmp;
assert(t);
extend(t, 9);
t->data[t->length] = TAG_TIMEVAL;
*((uint32_t*) (t->data+t->length+1)) = htonl(tv->tv_sec);
*((uint32_t*) (t->data+t->length+5)) = htonl(tv->tv_usec);
tmp = htonl(tv->tv_sec);
memcpy(t->data+t->length+1, &tmp, 4);
tmp = htonl(tv->tv_usec);
memcpy(t->data+t->length+5, &tmp, 4);
t->length += 9;
}
void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u) {
uint32_t tmp;
assert(t);
extend(t, 9);
t->data[t->length] = TAG_USEC;
*((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32));
*((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u);
tmp = htonl((uint32_t) (u >> 32));
memcpy(t->data+t->length+1, &tmp, 4);
tmp = htonl((uint32_t) u);
memcpy(t->data+t->length+5, &tmp, 4);
t->length += 9;
}
void pa_tagstruct_putu64(struct pa_tagstruct*t, uint64_t u) {
uint32_t tmp;
assert(t);
extend(t, 9);
t->data[t->length] = TAG_U64;
*((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32));
*((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u);
tmp = htonl((uint32_t) (u >> 32));
memcpy(t->data+t->length+1, &tmp, 4);
tmp = htonl((uint32_t) u);
memcpy(t->data+t->length+5, &tmp, 4);
t->length += 9;
}
@ -230,8 +249,9 @@ int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i) {
if (t->data[t->rindex] != TAG_U32)
return -1;
*i = ntohl(*((uint32_t*) (t->data+t->rindex+1)));
memcpy(i, t->data+t->rindex+1, 4);
*i = ntohl(*i);
t->rindex += 5;
return 0;
}
@ -261,13 +281,15 @@ int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *
ss->format = t->data[t->rindex+1];
ss->channels = t->data[t->rindex+2];
ss->rate = ntohl(*(uint32_t*) (t->data+t->rindex+3));
memcpy(&ss->rate, t->data+t->rindex+3, 4);
ss->rate = ntohl(ss->rate);
t->rindex += 7;
return 0;
}
int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length) {
uint32_t len;
assert(t && p);
if (t->rindex+5+length > t->length)
@ -276,7 +298,8 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le
if (t->data[t->rindex] != TAG_ARBITRARY)
return -1;
if (ntohl(*((uint32_t*) (t->data+t->rindex+1))) != length)
memcpy(&len, t->data+t->rindex+1, 4);
if (ntohl(len) != length)
return -1;
*p = t->data+t->rindex+5;
@ -319,15 +342,18 @@ int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv) {
if (t->data[t->rindex] != TAG_TIMEVAL)
return -1;
tv->tv_sec = ntohl(*((uint32_t*) (t->data+t->rindex+1)));
tv->tv_usec = ntohl(*((uint32_t*) (t->data+t->rindex+5)));
memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
tv->tv_sec = ntohl(tv->tv_sec);
memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
tv->tv_usec = ntohl(tv->tv_usec);
t->rindex += 9;
return 0;
}
int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) {
uint32_t tmp;
assert(t && u);
if (t->rindex+9 > t->length)
@ -336,13 +362,16 @@ int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) {
if (t->data[t->rindex] != TAG_USEC)
return -1;
*u = (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32;
*u |= (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+5)));
memcpy(&tmp, t->data+t->rindex+1, 4);
*u = (pa_usec_t) ntohl(tmp) << 32;
memcpy(&tmp, t->data+t->rindex+5, 4);
*u |= (pa_usec_t) ntohl(tmp);
t->rindex +=9;
return 0;
}
int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *u) {
uint32_t tmp;
assert(t && u);
if (t->rindex+9 > t->length)
@ -351,8 +380,10 @@ int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *u) {
if (t->data[t->rindex] != TAG_U64)
return -1;
*u = (uint64_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32;
*u |= (uint64_t) ntohl(*((uint32_t*) (t->data+t->rindex+5)));
memcpy(&tmp, t->data+t->rindex+1, 4);
*u = (pa_usec_t) ntohl(tmp) << 32;
memcpy(&tmp, t->data+t->rindex+5, 4);
*u |= (pa_usec_t) ntohl(tmp);
t->rindex +=9;
return 0;
}

View file

@ -32,35 +32,98 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#include <limits.h>
#include <unistd.h>
#include <grp.h>
#endif
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include <samplerate.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
#include "winsock.h"
#include "util.h"
#include "xmalloc.h"
#include "log.h"
#ifndef OS_IS_WIN32
#define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-"
#define PATH_SEP '/'
#else
#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-"
#define PATH_SEP '\\'
#endif
#ifdef OS_IS_WIN32
#define POLYP_ROOTENV "POLYP_ROOT"
int pa_set_root(HANDLE handle) {
char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep;
strcpy(library_path, POLYP_ROOTENV "=");
if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH))
return 0;
sep = strrchr(library_path, '\\');
if (sep)
*sep = '\0';
if (_putenv(library_path) < 0)
return 0;
return 1;
}
#endif
/** Make a file descriptor nonblock. Doesn't do any error checking */
void pa_make_nonblock_fd(int fd) {
#ifdef O_NONBLOCK
int v;
assert(fd >= 0);
if ((v = fcntl(fd, F_GETFL)) >= 0)
if (!(v & O_NONBLOCK))
fcntl(fd, F_SETFL, v|O_NONBLOCK);
#elif defined(OS_IS_WIN32)
u_long arg = 1;
if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
if (WSAGetLastError() == WSAENOTSOCK)
pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!\n");
}
#else
pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!\n");
#endif
}
/** Creates a directory securely */
@ -68,15 +131,27 @@ int pa_make_secure_dir(const char* dir) {
struct stat st;
assert(dir);
if (mkdir(dir, 0700) < 0)
#ifdef OS_IS_WIN32
if (mkdir(dir) < 0)
#else
if (mkdir(dir, 0700) < 0)
#endif
if (errno != EEXIST)
return -1;
if (lstat(dir, &st) < 0)
#ifdef HAVE_LSTAT
if (lstat(dir, &st) < 0)
#else
if (stat(dir, &st) < 0)
#endif
goto fail;
#ifndef OS_IS_WIN32
if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700))
goto fail;
#else
fprintf(stderr, "FIXME: pa_make_secure_dir()\n");
#endif
return 0;
@ -89,10 +164,11 @@ fail:
int pa_make_secure_parent_dir(const char *fn) {
int ret = -1;
char *slash, *dir = pa_xstrdup(fn);
if (!(slash = strrchr(dir, '/')))
slash = pa_path_get_filename(dir);
if (slash == fn)
goto finish;
*slash = 0;
*(slash-1) = 0;
if (pa_make_secure_dir(dir) < 0)
goto finish;
@ -153,6 +229,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) {
/* Print a warning messages in case that the given signal is not
* blocked or trapped */
void pa_check_signal_is_blocked(int sig) {
#ifdef HAVE_SIGACTION
struct sigaction sa;
sigset_t set;
@ -185,6 +262,9 @@ void pa_check_signal_is_blocked(int sig) {
return;
pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig));
#else /* HAVE_SIGACTION */
pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!\n", pa_strsignal(sig));
#endif
}
/* The following function is based on an example from the GNU libc
@ -240,29 +320,46 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) {
/* Return the current username in the specified string buffer. */
char *pa_get_user_name(char *s, size_t l) {
struct passwd pw, *r;
char buf[1024];
char *p;
char buf[1024];
#ifdef HAVE_PWD_H
struct passwd pw, *r;
#endif
assert(s && l > 0);
if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) {
#ifdef HAVE_PWD_H
#ifdef HAVE_GETPWUID_R
if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
#else
/* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
* that do not support getpwuid_r. */
if ((r = getpwuid(getuid())) == NULL) {
/* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
* that do not support getpwuid_r. */
if ((r = getpwuid(getuid())) == NULL) {
#endif
snprintf(s, l, "%lu", (unsigned long) getuid());
return s;
}
p = r->pw_name;
snprintf(s, l, "%lu", (unsigned long) getuid());
return s;
}
p = r->pw_name;
#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */
DWORD size = sizeof(buf);
if (!GetUserName(buf, &size))
return NULL;
p = buf;
#else /* HAVE_PWD_H */
return NULL;
#endif /* HAVE_PWD_H */
}
return pa_strlcpy(s, p, l);
}
}
/* Return the current hostname in the specified buffer. */
char *pa_get_host_name(char *s, size_t l) {
@ -278,19 +375,37 @@ char *pa_get_host_name(char *s, size_t l) {
/* Return the home directory of the current user */
char *pa_get_home_dir(char *s, size_t l) {
char *e;
#ifdef HAVE_PWD_H
char buf[1024];
struct passwd pw, *r;
#endif
assert(s && l);
if ((e = getenv("HOME")))
return pa_strlcpy(s, e, l);
if ((e = getenv("USERPROFILE")))
return pa_strlcpy(s, e, l);
#ifdef HAVE_PWD_H
#ifdef HAVE_GETPWUID_R
if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
pa_log(__FILE__": getpwuid_r() failed\n");
#else
/* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
* that do not support getpwuid_r. */
if ((r = getpwuid(getuid())) == NULL) {
pa_log(__FILE__": getpwuid_r() failed\n");
#endif
return NULL;
}
return pa_strlcpy(s, r->pw_dir, l);
#else /* HAVE_PWD_H */
return NULL;
#endif
}
/* Similar to OpenBSD's strlcpy() function */
@ -302,6 +417,42 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
return b;
}
int pa_gettimeofday(struct timeval *tv) {
#ifdef HAVE_GETTIMEOFDAY
return gettimeofday(tv, NULL);
#elif defined(OS_IS_WIN32)
/*
* Copied from implementation by Steven Edwards (LGPL).
* Found on wine mailing list.
*/
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define EPOCHFILETIME (116444736000000000i64)
#else
#define EPOCHFILETIME (116444736000000000LL)
#endif
FILETIME ft;
LARGE_INTEGER li;
__int64 t;
if (tv) {
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
t = li.QuadPart; /* In 100-nanosecond intervals */
t -= EPOCHFILETIME; /* Offset to the Epoch time */
t /= 10; /* In microseconds */
tv->tv_sec = (long)(t / 1000000);
tv->tv_usec = (long)(t % 1000000);
}
return 0;
#else
#error "Platform lacks gettimeofday() or equivalent function."
#endif
}
/* Calculate the difference between the two specfified timeval
* timestamsps. */
pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
@ -351,7 +502,7 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
pa_usec_t pa_timeval_age(const struct timeval *tv) {
struct timeval now;
assert(tv);
gettimeofday(&now, NULL);
pa_gettimeofday(&now);
return pa_timeval_diff(&now, tv);
}
@ -380,10 +531,12 @@ sensible: set the nice level to -15 and enable realtime scheduling if
supported.*/
void pa_raise_priority(void) {
#ifdef HAVE_SYS_RESOURCE_H
if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno));
else
pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL);
#endif
#ifdef _POSIX_PRIORITY_SCHEDULING
{
@ -403,10 +556,21 @@ void pa_raise_priority(void) {
pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n");
}
#endif
#ifdef OS_IS_WIN32
if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X\n", GetLastError());
else
pa_log_info(__FILE__": Successfully gained high priority class.\n");
#endif
}
/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
void pa_reset_priority(void) {
#ifdef OS_IS_WIN32
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
#endif
#ifdef _POSIX_PRIORITY_SCHEDULING
{
struct sched_param sp;
@ -416,11 +580,15 @@ void pa_reset_priority(void) {
}
#endif
#ifdef HAVE_SYS_RESOURCE_H
setpriority(PRIO_PROCESS, 0, 0);
#endif
}
/* Set the FD_CLOEXEC flag for a fd */
int pa_fd_set_cloexec(int fd, int b) {
#ifdef FD_CLOEXEC
int v;
assert(fd >= 0);
@ -431,7 +599,8 @@ int pa_fd_set_cloexec(int fd, int b) {
if (fcntl(fd, F_SETFD, v) < 0)
return -1;
#endif
return 0;
}
@ -439,6 +608,8 @@ int pa_fd_set_cloexec(int fd, int b) {
* only. This shoul be used for eyecandy only, don't rely on return
* non-NULL! */
char *pa_get_binary_name(char *s, size_t l) {
#ifdef HAVE_READLINK
char path[PATH_MAX];
int i;
assert(s && l);
@ -451,6 +622,15 @@ char *pa_get_binary_name(char *s, size_t l) {
s[i] = 0;
return s;
#elif defined(OS_IS_WIN32)
char path[PATH_MAX];
if (!GetModuleFileName(NULL, path, PATH_MAX))
return NULL;
pa_strlcpy(s, pa_path_get_filename(path), l);
return s;
#else
return NULL;
#endif
}
/* Return a pointer to the filename inside a path (which is the last
@ -458,7 +638,7 @@ char *pa_get_binary_name(char *s, size_t l) {
char *pa_path_get_filename(const char *p) {
char *fn;
if ((fn = strrchr(p, '/')))
if ((fn = strrchr(p, PATH_SEP)))
return fn+1;
return (char*) p;
@ -519,16 +699,29 @@ const char *pa_strsignal(int sig) {
switch(sig) {
case SIGINT: return "SIGINT";
case SIGTERM: return "SIGTERM";
#ifdef SIGUSR1
case SIGUSR1: return "SIGUSR1";
#endif
#ifdef SIGUSR2
case SIGUSR2: return "SIGUSR2";
#endif
#ifdef SIGXCPU
case SIGXCPU: return "SIGXCPU";
#endif
#ifdef SIGPIPE
case SIGPIPE: return "SIGPIPE";
#endif
#ifdef SIGCHLD
case SIGCHLD: return "SIGCHLD";
#endif
#ifdef SIGHUP
case SIGHUP: return "SIGHUP";
#endif
default: return "UNKNOWN SIGNAL";
}
}
#ifdef HAVE_GRP_H
/* Check whether the specified GID and the group name match */
static int is_group(gid_t gid, const char *name) {
@ -575,7 +768,7 @@ finish:
/* Check the current user is member of the specified group */
int pa_uid_in_group(const char *name, gid_t *gid) {
gid_t *gids, tgid;
long n = sysconf(_SC_NGROUPS_MAX);
GETGROUPS_T n = sysconf(_SC_NGROUPS_MAX);
int r = -1, i;
assert(n > 0);
@ -609,8 +802,18 @@ finish:
return r;
}
/* Lock or unlock a file entirely. (advisory) */
#else /* HAVE_GRP_H */
int pa_uid_in_group(const char *name, gid_t *gid) {
return -1;
}
#endif
/* Lock or unlock a file entirely.
(advisory on UNIX, mandatory on Windows) */
int pa_lock_fd(int fd, int b) {
#ifdef F_SETLKW
struct flock flock;
/* Try a R/W lock first */
@ -631,6 +834,19 @@ int pa_lock_fd(int fd, int b) {
}
pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno));
#endif
#ifdef OS_IS_WIN32
HANDLE h = (HANDLE)_get_osfhandle(fd);
if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
return 0;
if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
return 0;
pa_log(__FILE__": %slock failed: 0x%08X\n", !b ? "un" : "", GetLastError());
#endif
return -1;
}
@ -722,31 +938,51 @@ int pa_unlock_lockfile(const char *fn, int fd) {
* allocated buffer containing the used configuration file is
* stored there.*/
FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
const char *e;
const char *fn;
char h[PATH_MAX];
if (env && (e = getenv(env))) {
#ifdef OS_IS_WIN32
char buf[PATH_MAX];
if (!getenv(POLYP_ROOTENV))
pa_set_root(NULL);
#endif
if (env && (fn = getenv(env))) {
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
return NULL;
fn = buf;
#endif
if (result)
*result = pa_xstrdup(e);
return fopen(e, "r");
*result = pa_xstrdup(fn);
return fopen(fn, "r");
}
if (local && pa_get_home_dir(h, sizeof(h))) {
FILE *f;
char *l;
char *lfn;
l = pa_sprintf_malloc("%s/%s", h, local);
f = fopen(l, "r");
lfn = pa_sprintf_malloc("%s/%s", h, local);
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
return NULL;
lfn = buf;
#endif
f = fopen(lfn, "r");
if (f || errno != ENOENT) {
if (result)
*result = l;
else
pa_xfree(l);
*result = pa_xstrdup(lfn);
pa_xfree(lfn);
return f;
}
pa_xfree(l);
pa_xfree(lfn);
}
if (!global) {
@ -756,6 +992,12 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
return NULL;
}
#ifdef OS_IS_WIN32
if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
return NULL;
global = buf;
#endif
if (result)
*result = pa_xstrdup(global);
@ -823,11 +1065,14 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
/* Return the fully qualified domain name in *s */
char *pa_get_fqdn(char *s, size_t l) {
char hn[256];
#ifdef HAVE_GETADDRINFO
struct addrinfo *a, hints;
#endif
if (!pa_get_host_name(hn, sizeof(hn)))
return NULL;
#ifdef HAVE_GETADDRINFO
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_CANONNAME;
@ -838,6 +1083,9 @@ char *pa_get_fqdn(char *s, size_t l) {
pa_strlcpy(s, a->ai_canonname, l);
freeaddrinfo(a);
return s;
#else
return pa_strlcpy(s, hn, l);
#endif
}
/* Returns nonzero when *s starts with *pfx */
@ -855,21 +1103,44 @@ int pa_startswith(const char *s, const char *pfx) {
char *pa_runtime_path(const char *fn, char *s, size_t l) {
char u[256];
#ifndef OS_IS_WIN32
if (fn && *fn == '/')
#else
if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
#endif
return pa_strlcpy(s, fn, l);
snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : "");
if (fn)
snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
else
snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
#ifdef OS_IS_WIN32
{
char buf[l];
strcpy(buf, s);
ExpandEnvironmentStrings(buf, s, l);
}
#endif
return s;
}
/* Wait t milliseconds */
int pa_msleep(unsigned long t) {
#ifdef OS_IS_WIN32
Sleep(t);
return 0;
#elif defined(HAVE_NANOSLEEP)
struct timespec ts;
ts.tv_sec = t/1000;
ts.tv_nsec = (t % 1000) * 1000000;
return nanosleep(&ts, NULL);
#else
#error "Platform lacks a sleep function."
#endif
}
/* Convert the string s to a signed integer in *ret_i */

View file

@ -30,6 +30,8 @@
#include "gcc-printf.h"
#include "sample.h"
struct timeval;
void pa_make_nonblock_fd(int fd);
int pa_make_secure_dir(const char* dir);
@ -53,6 +55,7 @@ char *pa_get_home_dir(char *s, size_t l);
char *pa_path_get_filename(const char *p);
int pa_gettimeofday(struct timeval *tv);
pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b);
int pa_timeval_cmp(const struct timeval *a, const struct timeval *b);
pa_usec_t pa_timeval_age(const struct timeval *tv);

23
polyp/winsock.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef foowinsockhfoo
#define foowinsockhfoo
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#define ESHUTDOWN WSAESHUTDOWN
#define ECONNRESET WSAECONNRESET
#define ECONNABORTED WSAECONNABORTED
#define ENETRESET WSAENETRESET
#define EINPROGRESS WSAEINPROGRESS
#define EAFNOSUPPORT WSAEAFNOSUPPORT
#define ETIMEDOUT WSAETIMEDOUT
#define ECONNREFUSED WSAECONNREFUSED
#define EHOSTUNREACH WSAEHOSTUNREACH
#endif
#ifdef HAVE_WS2TCPIP_H
#include <ws2tcpip.h>
#endif
#endif

View file

@ -45,7 +45,9 @@
static void oom(void) {
static const char e[] = "Not enough memory\n";
pa_loop_write(STDERR_FILENO, e, sizeof(e)-1);
#ifdef SIGQUIT
raise(SIGQUIT);
#endif
_exit(1);
}