diff options
Diffstat (limited to 'src/pulsecore')
-rw-r--r-- | src/pulsecore/conf-parser.c | 18 | ||||
-rw-r--r-- | src/pulsecore/conf-parser.h | 3 | ||||
-rw-r--r-- | src/pulsecore/core-util.c | 47 | ||||
-rw-r--r-- | src/pulsecore/core-util.h | 1 | ||||
-rw-r--r-- | src/pulsecore/core.c | 9 | ||||
-rw-r--r-- | src/pulsecore/core.h | 3 | ||||
-rw-r--r-- | src/pulsecore/idxset.c | 5 | ||||
-rw-r--r-- | src/pulsecore/lock-autospawn.c | 330 | ||||
-rw-r--r-- | src/pulsecore/lock-autospawn.h | 32 | ||||
-rw-r--r-- | src/pulsecore/memblock.c | 18 | ||||
-rw-r--r-- | src/pulsecore/memblock.h | 2 | ||||
-rw-r--r-- | src/pulsecore/prioq.c | 256 | ||||
-rw-r--r-- | src/pulsecore/prioq.h | 64 | ||||
-rw-r--r-- | src/pulsecore/proplist-util.c | 2 | ||||
-rw-r--r-- | src/pulsecore/protocol-native.c | 2 | ||||
-rw-r--r-- | src/pulsecore/resampler.c | 39 | ||||
-rw-r--r-- | src/pulsecore/resampler.h | 7 | ||||
-rw-r--r-- | src/pulsecore/sink-input.c | 3 | ||||
-rw-r--r-- | src/pulsecore/source-output.c | 3 |
19 files changed, 802 insertions, 42 deletions
diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 6b0e1d56..58ceab91 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -166,6 +166,24 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, return 0; } +int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + size_t *i = data; + uint32_t k; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atou(rvalue, &k) < 0) { + pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); + return -1; + } + + *i = (size_t) k; + return 0; +} + int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { int k; pa_bool_t *b = data; diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h index 7eb1fae2..a5174fce 100644 --- a/src/pulsecore/conf-parser.h +++ b/src/pulsecore/conf-parser.h @@ -39,8 +39,9 @@ typedef struct pa_config_item { * NULL */ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata); -/* Generic parsers for integers, booleans and strings */ +/* Generic parsers for integers, size_t, booleans and strings */ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index ad00f4f4..0bc5cb40 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -42,6 +42,7 @@ #include <dirent.h> #include <regex.h> #include <langinfo.h> +#include <sys/utsname.h> #ifdef HAVE_STRTOF_L #include <locale.h> @@ -1314,31 +1315,43 @@ static char* make_random_dir(mode_t m) { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; - char fn[24] = "/tmp/pulse-"; + const char *tmpdir; + char *fn; + size_t pathlen; - fn[sizeof(fn)-1] = 0; + if (!(tmpdir = getenv("TMPDIR"))) + if (!(tmpdir = getenv("TMP"))) + if (!(tmpdir = getenv("TEMP"))) + tmpdir = getenv("TEMPDIR"); + + if (!tmpdir || !pa_is_path_absolute(tmpdir)) + tmpdir = "/tmp"; + + fn = pa_sprintf_malloc("%s/pulse-XXXXXXXXXXXX", tmpdir); + pathlen = strlen(fn); for (;;) { - unsigned i; + size_t i; int r; mode_t u; int saved_errno; - for (i = 11; i < sizeof(fn)-1; i++) + for (i = pathlen - 12; i < pathlen; i++) fn[i] = table[rand() % (sizeof(table)-1)]; u = umask((~m) & 0777); r = mkdir(fn, m); + saved_errno = errno; umask(u); + errno = saved_errno; if (r >= 0) - return pa_xstrdup(fn); - - errno = saved_errno; + return fn; if (errno != EEXIST) { pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno)); + pa_xfree(fn); return NULL; } } @@ -1369,6 +1382,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) { char *pa_get_runtime_dir(void) { char *d, *k = NULL, *p = NULL, *t = NULL, *mid; struct stat st; + mode_t m; /* The runtime directory shall contain dynamic data that needs NOT * to be kept accross reboots and is usuallly private to the user, @@ -1377,10 +1391,9 @@ char *pa_get_runtime_dir(void) { * this directory, we link it to a random subdir in /tmp, if it * was not explicitly configured. */ - if ((d = getenv("PULSE_RUNTIME_PATH"))) { - mode_t m; + m = pa_in_system_mode() ? 0755U : 0700U; - m = pa_in_system_mode() ? 0755U : 0700U; + if ((d = getenv("PULSE_RUNTIME_PATH"))) { if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) { pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); @@ -1393,6 +1406,11 @@ char *pa_get_runtime_dir(void) { if (!(d = get_pulse_home())) goto fail; + if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) { + pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); + goto fail; + } + if (!(mid = pa_machine_id())) { pa_xfree(d); goto fail; @@ -2333,7 +2351,7 @@ int pa_reset_sigs(int except, ...) { int pa_reset_sigsv(const int except[]) { int sig; - for (sig = 1; sig < _NSIG; sig++) { + for (sig = 1; sig < NSIG; sig++) { pa_bool_t reset = TRUE; switch (sig) { @@ -2445,5 +2463,12 @@ char *pa_machine_id(void) { /* If no hostname was set we use the POSIX hostid. It's usually * the IPv4 address. Mit not be that stable. */ return pa_sprintf_malloc("%08lx", (unsigned long) gethostid); +} + +char *pa_uname_string(void) { + struct utsname u; + + pa_assert_se(uname(&u) == 0); + return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version); } diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index c9e307f5..df8ce3f8 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -191,5 +191,6 @@ pa_bool_t pa_in_system_mode(void); #define pa_streq(a,b) (!strcmp((a),(b))) char *pa_machine_id(void); +char *pa_uname_string(void); #endif diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 6f8a2929..5761bbc7 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -66,7 +66,7 @@ static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t o static void core_free(pa_object *o); -pa_core* pa_core_new(pa_mainloop_api *m, int shared) { +pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size) { pa_core* c; pa_mempool *pool; int j; @@ -74,14 +74,14 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { pa_assert(m); if (shared) { - if (!(pool = pa_mempool_new(shared))) { + if (!(pool = pa_mempool_new(shared, shm_size))) { pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool."); - shared = 0; + shared = FALSE; } } if (!shared) { - if (!(pool = pa_mempool_new(shared))) { + if (!(pool = pa_mempool_new(shared, shm_size))) { pa_log("pa_mempool_new() failed."); return NULL; } @@ -138,6 +138,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->realtime_scheduling = FALSE; c->realtime_priority = 5; c->disable_remixing = FALSE; + c->disable_lfe_remixing = FALSE; for (j = 0; j < PA_CORE_HOOK_MAX; j++) pa_hook_init(&c->hooks[j], c); diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index eb768418..39559082 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -124,6 +124,7 @@ struct pa_core { pa_bool_t running_as_daemon:1; pa_bool_t realtime_scheduling:1; pa_bool_t disable_remixing:1; + pa_bool_t disable_lfe_remixing:1; pa_resample_method_t resample_method; int realtime_priority; @@ -140,7 +141,7 @@ enum { PA_CORE_MESSAGE_MAX }; -pa_core* pa_core_new(pa_mainloop_api *m, int shared); +pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size); /* Check whether noone is connected to this core */ void pa_core_check_idle(pa_core *c); diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index b6423efd..24a28db7 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -80,7 +80,7 @@ unsigned pa_idxset_trivial_hash_func(const void *p) { } int pa_idxset_trivial_compare_func(const void *a, const void *b) { - return a != b; + return a < b ? -1 : (a > b ? 1 : 0); } pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) { @@ -318,8 +318,7 @@ void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { hash = *idx % NBUCKETS; - if (!(e = index_scan(s, hash, *idx))) - return NULL; + e = index_scan(s, hash, *idx); if (e && e->iterate_next) e = e->iterate_next; diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c new file mode 100644 index 00000000..d36b669e --- /dev/null +++ b/src/pulsecore/lock-autospawn.c @@ -0,0 +1,330 @@ +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <sys/poll.h> +#include <signal.h> +#include <pthread.h> + +#include <pulse/i18n.h> +#include <pulse/xmalloc.h> + +#include <pulsecore/mutex.h> +#include <pulsecore/thread.h> +#include <pulsecore/core-util.h> + +#include "lock-autospawn.h" + +/* So, why do we have this complex code here with threads and pipes + * and stuff? For two reasons: POSIX file locks are per-process, not + * per-file descriptor. That means that two contexts within the same + * process that try to create the autospawn lock might end up assuming + * they both managed to lock the file. And then, POSIX locking + * operations are synchronous. If two contexts run from the same event + * loop it must be made sure that they do not block each other, but + * that the locking operation can happen asynchronously. */ + +#define AUTOSPAWN_LOCK "autospawn.lock" + +static pa_mutex *mutex; + +static unsigned n_ref = 0; +static int lock_fd = -1; +static pa_mutex *lock_fd_mutex = NULL; +static pa_bool_t taken = FALSE; +static pa_thread *thread; +static int pipe_fd[2] = { -1, -1 }; + +static void destroy_mutex(void) PA_GCC_DESTRUCTOR; + +static int ref(void) { + + if (n_ref > 0) { + + pa_assert(pipe_fd[0] >= 0); + pa_assert(pipe_fd[1] >= 0); + + n_ref++; + + return 0; + } + + pa_assert(lock_fd < 0); + pa_assert(!lock_fd_mutex); + pa_assert(!taken); + pa_assert(!thread); + pa_assert(pipe_fd[0] < 0); + pa_assert(pipe_fd[1] < 0); + + if (pipe(pipe_fd) < 0) + return -1; + + lock_fd_mutex = pa_mutex_new(FALSE, FALSE); + + pa_make_fd_cloexec(pipe_fd[0]); + pa_make_fd_cloexec(pipe_fd[1]); + + pa_make_fd_nonblock(pipe_fd[1]); + pa_make_fd_nonblock(pipe_fd[0]); + + n_ref = 1; + return 0; +} + +static void unref(pa_bool_t after_fork) { + + pa_assert(n_ref > 0); + pa_assert(pipe_fd[0] >= 0); + pa_assert(pipe_fd[1] >= 0); + pa_assert(lock_fd_mutex); + + n_ref--; + + if (n_ref > 0) + return; + + pa_assert(!taken); + + if (thread) { + pa_thread_free(thread); + thread = NULL; + } + + pa_mutex_lock(lock_fd_mutex); + if (lock_fd >= 0) { + + if (after_fork) + pa_close(lock_fd); + else { + char *lf; + + if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) + pa_log_warn(_("Cannot access autospawn lock.")); + + pa_unlock_lockfile(lf, lock_fd); + pa_xfree(lf); + + lock_fd = -1; + } + } + pa_mutex_unlock(lock_fd_mutex); + + pa_mutex_free(lock_fd_mutex); + lock_fd_mutex = NULL; + + pa_close(pipe_fd[0]); + pa_close(pipe_fd[1]); + pipe_fd[0] = pipe_fd[1] = -1; +} + +static void ping(void) { + ssize_t s; + + pa_assert(pipe_fd[1] >= 0); + + for (;;) { + char x = 'x'; + + if ((s = write(pipe_fd[1], &x, 1)) == 1) + break; + + pa_assert(s < 0); + + if (errno == EAGAIN) + break; + + pa_assert(errno == EINTR); + } +} + +static void wait_for_ping(void) { + ssize_t s; + char x; + struct pollfd pfd; + int k; + + pa_assert(pipe_fd[0] >= 0); + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = pipe_fd[0]; + pfd.events = POLLIN; + + if ((k = poll(&pfd, 1, -1)) != 1) { + pa_assert(k < 0); + pa_assert(errno == EINTR); + } else if ((s = read(pipe_fd[0], &x, 1)) != 1) { + pa_assert(s < 0); + pa_assert(errno == EAGAIN); + } +} + +static void empty_pipe(void) { + char x[16]; + ssize_t s; + + pa_assert(pipe_fd[0] >= 0); + + if ((s = read(pipe_fd[0], &x, sizeof(x))) < 1) { + pa_assert(s < 0); + pa_assert(errno == EAGAIN); + } +} + +static void thread_func(void *u) { + int fd; + char *lf; + sigset_t fullset; + + /* No signals in this thread please */ + sigfillset(&fullset); + pthread_sigmask(SIG_BLOCK, &fullset, NULL); + + if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) { + pa_log_warn(_("Cannot access autospawn lock.")); + goto finish; + } + + if ((fd = pa_lock_lockfile(lf)) < 0) + goto finish; + + pa_mutex_lock(lock_fd_mutex); + pa_assert(lock_fd < 0); + lock_fd = fd; + pa_mutex_unlock(lock_fd_mutex); + +finish: + pa_xfree(lf); + + ping(); +} + +static int start_thread(void) { + + if (!thread) + if (!(thread = pa_thread_new(thread_func, NULL))) + return -1; + + return 0; +} + +static void create_mutex(void) { + PA_ONCE_BEGIN { + mutex = pa_mutex_new(FALSE, FALSE); + } PA_ONCE_END; +} + +static void destroy_mutex(void) { + + if (mutex) + pa_mutex_free(mutex); +} + + +int pa_autospawn_lock_init(void) { + int ret = -1; + + create_mutex(); + pa_mutex_lock(mutex); + + if (ref() < 0) + ret = -1; + else + ret = pipe_fd[0]; + + pa_mutex_unlock(mutex); + + return ret; +} + +int pa_autospawn_lock_acquire(pa_bool_t block) { + int ret = -1; + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + pa_mutex_lock(lock_fd_mutex); + + for (;;) { + + empty_pipe(); + + if (lock_fd >= 0 && !taken) { + taken = TRUE; + ret = 1; + break; + } + + if (lock_fd < 0) + if (start_thread() < 0) + break; + + if (!block) { + ret = 0; + break; + } + + pa_mutex_unlock(lock_fd_mutex); + pa_mutex_unlock(mutex); + + wait_for_ping(); + + pa_mutex_lock(mutex); + pa_mutex_lock(lock_fd_mutex); + } + + pa_mutex_unlock(lock_fd_mutex); + + pa_mutex_unlock(mutex); + + return ret; +} + +void pa_autospawn_lock_release(void) { + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + pa_assert(taken); + taken = FALSE; + + ping(); + + pa_mutex_unlock(mutex); +} + +void pa_autospawn_lock_done(pa_bool_t after_fork) { + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + unref(after_fork); + + pa_mutex_unlock(mutex); +} diff --git a/src/pulsecore/lock-autospawn.h b/src/pulsecore/lock-autospawn.h new file mode 100644 index 00000000..c04c4bd1 --- /dev/null +++ b/src/pulsecore/lock-autospawn.h @@ -0,0 +1,32 @@ +#ifndef foopulselockautospawnhfoo +#define foopulselockautospawnhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include <pulsecore/macro.h> + +int pa_autospawn_lock_init(void); +int pa_autospawn_lock_acquire(pa_bool_t block); +void pa_autospawn_lock_release(void); +void pa_autospawn_lock_done(pa_bool_t after_fork); + +#endif diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 6d12acdc..400a4e1e 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -680,8 +680,9 @@ static void memblock_replace_import(pa_memblock *b) { pa_mutex_unlock(seg->import->mutex); } -pa_mempool* pa_mempool_new(pa_bool_t shared) { +pa_mempool* pa_mempool_new(pa_bool_t shared, size_t size) { pa_mempool *p; + char t1[64], t2[64]; p = pa_xnew(pa_mempool, 1); @@ -692,13 +693,26 @@ pa_mempool* pa_mempool_new(pa_bool_t shared) { if (p->block_size < PA_PAGE_SIZE) p->block_size = PA_PAGE_SIZE; - p->n_blocks = PA_MEMPOOL_SLOTS_MAX; + if (size <= 0) + p->n_blocks = PA_MEMPOOL_SLOTS_MAX; + else { + p->n_blocks = (unsigned) (size / p->block_size); + + if (p->n_blocks < 2) + p->n_blocks = 2; + } if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) { pa_xfree(p); return NULL; } + pa_log_debug("Using %s memory pool with %u slots of size %s each, total size is %s", + p->memory.shared ? "shared" : "private", + p->n_blocks, + pa_bytes_snprint(t1, sizeof(t1), (unsigned) p->block_size), + pa_bytes_snprint(t2, sizeof(t2), (unsigned) (p->n_blocks * p->block_size))); + memset(&p->stat, 0, sizeof(p->stat)); pa_atomic_store(&p->n_init, 0); diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index efe55b02..b1eab2a9 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -117,7 +117,7 @@ pa_mempool * pa_memblock_get_pool(pa_memblock *b); pa_memblock *pa_memblock_will_need(pa_memblock *b); /* The memory block manager */ -pa_mempool* pa_mempool_new(pa_bool_t shared); +pa_mempool* pa_mempool_new(pa_bool_t shared, size_t size); void pa_mempool_free(pa_mempool *p); const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p); void pa_mempool_vacuum(pa_mempool *p); diff --git a/src/pulsecore/prioq.c b/src/pulsecore/prioq.c new file mode 100644 index 00000000..693dc517 --- /dev/null +++ b/src/pulsecore/prioq.c @@ -0,0 +1,256 @@ +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pulse/xmalloc.h> + +#include <pulsecore/flist.h> + +#include "prioq.h" + +struct pa_prioq_item { + void *value; + unsigned idx; +}; + +struct pa_prioq { + pa_prioq_item **items; + unsigned n_items; + unsigned n_allocated; + pa_compare_func_t compare_func; +}; + +PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree); + +pa_prioq *pa_prioq_new(pa_compare_func_t compare_func) { + + pa_prioq *q; + + q = pa_xnew(pa_prioq, 1); + q->compare_func = compare_func; + q->n_items = 0; + q->n_allocated = 64; + q->items = pa_xnew(pa_prioq_item*, q->n_allocated); + + return q; +} + +void pa_prioq_free(pa_prioq *q, pa_free2_cb_t free_cb, void *userdata) { + pa_prioq_item **i, **e; + + pa_assert(q); + + for (i = q->items, e = q->items + q->n_items; i < e; i++) { + + if (!*i) + continue; + + if (free_cb) + free_cb((*i)->value, userdata); + + pa_xfree(*i); + } + + pa_xfree(q->items); + pa_xfree(q); +} + +static void shuffle_up(pa_prioq *q, pa_prioq_item *i) { + unsigned j; + + pa_assert(q); + pa_assert(i); + + j = i->idx; + + while (j > 0) { + unsigned k; + + k = (j-1)/2; + + if (q->compare_func(q->items[k]->value, i->value) < 0) + break; + + q->items[k]->idx = j; + q->items[j] = q->items[k]; + + j = k; + } + + i->idx = j; + q->items[j] = i; + +} + +pa_prioq_item* pa_prioq_put(pa_prioq *q, void *p) { + pa_prioq_item *i; + + pa_assert(q); + + if (q->n_items >= q->n_allocated) { + q->n_allocated = PA_MAX(q->n_items+1, q->n_allocated)*2; + q->items = pa_xrealloc(q->items, sizeof(pa_prioq_item*) * q->n_allocated); + } + + if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) + i = pa_xnew(pa_prioq_item, 1); + + i->value = p; + i->idx = q->n_items++; + + shuffle_up(q, i); + + return i; +} + +void* pa_prioq_peek(pa_prioq *q) { + pa_assert(q); + + if (q->n_items <= 0) + return NULL; + + return q->items[0]->value; +} + +void* pa_prioq_pop(pa_prioq *q){ + pa_assert(q); + + if (q->n_items <= 0) + return NULL; + + return pa_prioq_remove(q, q->items[0]); +} + +static void swap(pa_prioq *q, unsigned j, unsigned k) { + pa_prioq_item *t; + + pa_assert(q); + pa_assert(j < q->n_items); + pa_assert(k < q->n_items); + + pa_assert(q->items[j]->idx == j); + pa_assert(q->items[k]->idx == k); + + t = q->items[j]; + + q->items[j]->idx = k; + q->items[j] = q->items[k]; + + q->items[k]->idx = j; + q->items[k] = t; +} + +static void shuffle_down(pa_prioq *q, unsigned idx) { + + pa_assert(q); + pa_assert(idx < q->n_items); + + for (;;) { + unsigned j, k, s; + + k = (idx+1)*2; /* right child */ + j = k-1; /* left child */ + + if (j >= q->n_items) + break; + + if (q->compare_func(q->items[j]->value, q->items[idx]->value) < 0) + + /* So our left child is smaller than we are, let's + * remember this fact */ + s = j; + else + s = idx; + + if (k < q->n_items && + q->compare_func(q->items[k]->value, q->items[s]->value) < 0) + + /* So our right child is smaller than we are, let's + * remember this fact */ + s = k; + + /* s now points to the smallest of the three items */ + + if (s == idx) + /* No swap necessary, we're done */ + break; + + swap(q, idx, s); + idx = s; + } +} + +void* pa_prioq_remove(pa_prioq *q, pa_prioq_item *i) { + void *p; + + pa_assert(q); + pa_assert(i); + pa_assert(q->n_items >= 1); + + p = i->value; + + if (q->n_items-1 == i->idx) { + /* We are the last entry, so let's just remove us and good */ + q->n_items--; + + } else { + + /* We are not the last entry, we need to replace ourselves + * with the last node and reshuffle */ + + q->items[i->idx] = q->items[q->n_items-1]; + q->items[i->idx]->idx = i->idx; + q->n_items--; + + shuffle_down(q, i->idx); + } + + if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0) + pa_xfree(i); + + return p; +} + +unsigned pa_prioq_size(pa_prioq *q) { + pa_assert(q); + + return q->n_items; +} + +pa_bool_t pa_prioq_isempty(pa_prioq *q) { + pa_assert(q); + + return q->n_items == 0; +} + +void pa_prioq_reshuffle(pa_prioq *q, pa_prioq_item *i) { + pa_assert(q); + pa_assert(i); + + /* This will move the entry down as far as necessary */ + shuffle_down(q, i->idx); + + /* And this will move the entry up as far as necessary */ + shuffle_up(q, i); +} diff --git a/src/pulsecore/prioq.h b/src/pulsecore/prioq.h new file mode 100644 index 00000000..fd3550b7 --- /dev/null +++ b/src/pulsecore/prioq.h @@ -0,0 +1,64 @@ +#ifndef foopulsecoreprioqhfoo +#define foopulsecoreprioqhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include <inttypes.h> + +#include <pulsecore/macro.h> +#include <pulsecore/idxset.h> + +/* A heap-based priority queue. Removal and insertion is O(log + * n). Removal can happen a the top or at any position referenced by a + * pa_prioq_item. */ + +typedef struct pa_prioq pa_prioq; +typedef struct pa_prioq_item pa_prioq_item; + +/* Instantiate a new prioq with the specified comparison functions */ +pa_prioq* pa_prioq_new(pa_compare_func_t compare_func); + +/* Free the prioq. When the prioq is not empty the specified function is called for every entry contained */ +void pa_prioq_free(pa_prioq *q, pa_free2_cb_t free_cb, void *userdata); + +/* Store a new item in the prioq. */ +pa_prioq_item* pa_prioq_put(pa_prioq *q, void* data); + +/* Get the item on the top of the queue, but don't remove it from the queue*/ +void* pa_prioq_peek(pa_prioq*q); + +/* Get the item on the top of the queue, and remove it from thq queue */ +void* pa_prioq_pop(pa_prioq*q); + +/* Remove an arbitrary from theq prioq, returning it's data */ +void* pa_prioq_remove(pa_prioq*q, pa_prioq_item *i); + +/* The priority of an item was modified. Adjustthe queue to that */ +void pa_prioq_reshuffle(pa_prioq *q, pa_prioq_item *i); + +/* Return the current number of items in the prioq */ +unsigned pa_prioq_size(pa_prioq*s); + +/* Return TRUE of the prioq is empty */ +pa_bool_t pa_prioq_isempty(pa_prioq *s); + +#endif diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c index 6005775e..4d505f57 100644 --- a/src/pulsecore/proplist-util.c +++ b/src/pulsecore/proplist-util.c @@ -37,7 +37,7 @@ void pa_init_proplist(pa_proplist *p) { int a, b; -#ifndef HAVE_DECL_ENVIRON +#if !HAVE_DECL_ENVIRON extern char **environ; #endif char **e; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 6ccee571..5c6dbf44 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2192,6 +2192,7 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta if (c->version < 10 || (c->version >= 13 && !shm_on_remote)) do_shm = FALSE; +#ifdef HAVE_CREDS if (do_shm) { /* Only enable SHM if both sides are owned by the same * user. This is a security measure because otherwise data @@ -2201,6 +2202,7 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid) do_shm = FALSE; } +#endif pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm)); pa_pstream_enable_shm(c->pstream, do_shm); diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 45cd68c1..b2d512c8 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -716,7 +716,11 @@ static void calc_map_table(pa_resampler *r) { * channels for LFE. */ for (ic = 0; ic < r->i_ss.channels; ic++) { - r->map_table[oc][ic] = 1.0f / (float) r->i_ss.channels; + + if (!(r->flags & PA_RESAMPLER_NO_LFE)) + r->map_table[oc][ic] = 1.0f / (float) r->i_ss.channels; + else + r->map_table[oc][ic] = 0; /* Please note that a channel connected to LFE * doesn't really count as connected. */ @@ -851,7 +855,7 @@ static void calc_map_table(pa_resampler *r) { } } - if (ic_unconnected_lfe > 0) { + if (ic_unconnected_lfe > 0 && !(r->flags & PA_RESAMPLER_NO_LFE)) { /* OK, so there is an unconnected LFE channel. Let's mix * it into all channels, with factor 0.375 */ @@ -1414,40 +1418,46 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i unsigned j; j = ((r->peaks.o_counter * r->i_ss.rate) / r->o_ss.rate); - j = j > r->peaks.i_counter ? j - r->peaks.i_counter : 0; - if (j >= in_n_frames) - break; + if (j > r->peaks.i_counter) + j -= r->peaks.i_counter; + else + j = 0; pa_assert(o_index * fz < pa_memblock_get_length(output->memblock)); if (r->work_format == PA_SAMPLE_S16NE) { unsigned i, c; - int16_t *s = (int16_t*) ((uint8_t*) src + fz * j); + int16_t *s = (int16_t*) ((uint8_t*) src + fz * start); int16_t *d = (int16_t*) ((uint8_t*) dst + fz * o_index); - for (i = start; i <= j; i++) + for (i = start; i <= j && i < in_n_frames; i++) + for (c = 0; c < r->o_ss.channels; c++, s++) { int16_t n; n = (int16_t) (*s < 0 ? -*s : *s); - if (n > r->peaks.max_i[c]) + if (PA_UNLIKELY(n > r->peaks.max_i[c])) r->peaks.max_i[c] = n; } + if (i >= in_n_frames) + break; + for (c = 0; c < r->o_ss.channels; c++, d++) { - *d = r->peaks.max_i[c]; - r->peaks.max_i[c] = 0; + *d = r->peaks.max_i[c]; + r->peaks.max_i[c] = 0; } + } else { unsigned i, c; - float *s = (float*) ((uint8_t*) src + fz * j); + float *s = (float*) ((uint8_t*) src + fz * start); float *d = (float*) ((uint8_t*) dst + fz * o_index); pa_assert(r->work_format == PA_SAMPLE_FLOAT32NE); - for (i = start; i <= j; i++) + for (i = start; i <= j && i < in_n_frames; i++) for (c = 0; c < r->o_ss.channels; c++, s++) { float n = fabsf(*s); @@ -1455,13 +1465,16 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i r->peaks.max_f[c] = n; } + if (i >= in_n_frames) + break; + for (c = 0; c < r->o_ss.channels; c++, d++) { *d = r->peaks.max_f[c]; r->peaks.max_f[c] = 0; } } - start = j+1; + start = j; } pa_memblock_release(input->memblock); diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index 5e302a9b..87110cc2 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -49,9 +49,10 @@ typedef enum pa_resample_method { } pa_resample_method_t; typedef enum pa_resample_flags { - PA_RESAMPLER_VARIABLE_RATE = 1, - PA_RESAMPLER_NO_REMAP = 2, /* implies NO_REMIX */ - PA_RESAMPLER_NO_REMIX = 4 + PA_RESAMPLER_VARIABLE_RATE = 0x0001U, + PA_RESAMPLER_NO_REMAP = 0x0002U, /* implies NO_REMIX */ + PA_RESAMPLER_NO_REMIX = 0x0004U, + PA_RESAMPLER_NO_LFE = 0x0008U } pa_resample_flags_t; pa_resampler* pa_resampler_new( diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 7d80242f..326a7e2c 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -201,7 +201,8 @@ pa_sink_input* pa_sink_input_new( data->resample_method, ((flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | ((flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | - (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { + (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | + (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 5df950a8..d76f6e4e 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -171,7 +171,8 @@ pa_source_output* pa_source_output_new( data->resample_method, ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | ((flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | - (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { + (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | + (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } |