merge 'lennart' branch back into trunk.

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1971 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2007-10-28 19:13:50 +00:00
parent 6687dd0131
commit a67c21f093
294 changed files with 79057 additions and 11614 deletions

View file

@ -1,145 +0,0 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <pulse/xmalloc.h>
#include "anotify.h"
#define EVENTS_MAX 16
struct pa_anotify {
pa_mainloop_api *api;
pa_anotify_cb_t callback;
void *userdata;
int fds[2];
pa_io_event *io_event;
pa_defer_event *defer_event;
uint8_t queued_events[EVENTS_MAX];
unsigned n_queued_events, queue_index;
};
static void dispatch_event(pa_anotify *a) {
assert(a);
assert(a->queue_index < a->n_queued_events);
a->callback(a->queued_events[a->queue_index++], a->userdata);
if (a->queue_index >= a->n_queued_events) {
a->n_queued_events = 0;
a->queue_index = 0;
a->api->io_enable(a->io_event, PA_IO_EVENT_INPUT);
a->api->defer_enable(a->defer_event, 0);
} else {
a->api->io_enable(a->io_event, 0);
a->api->defer_enable(a->defer_event, 1);
}
}
static void io_callback(
pa_mainloop_api *api,
pa_io_event *e,
int fd,
pa_io_event_flags_t events,
void *userdata) {
pa_anotify *a = userdata;
ssize_t r;
assert(a);
assert(events == PA_IO_EVENT_INPUT);
assert(a->n_queued_events == 0);
r = read(fd, a->queued_events, sizeof(a->queued_events));
assert(r > 0);
a->n_queued_events = (unsigned) r;
a->queue_index = 0;
/* Only dispatch a single event */
dispatch_event(a);
}
static void defer_callback(pa_mainloop_api *api, pa_defer_event *e, void *userdata) {
pa_anotify *a = userdata;
assert(a);
dispatch_event(a);
}
pa_anotify *pa_anotify_new(pa_mainloop_api*api, pa_anotify_cb_t cb, void *userdata) {
pa_anotify *a;
assert(api);
assert(cb);
a = pa_xnew(pa_anotify, 1);
if (pipe(a->fds) < 0) {
pa_xfree(a);
return NULL;
}
a->api = api;
a->callback = cb;
a->userdata = userdata;
a->io_event = api->io_new(api, a->fds[0], PA_IO_EVENT_INPUT, io_callback, a);
a->defer_event = api->defer_new(api, defer_callback, a);
a->api->defer_enable(a->defer_event, 0);
a->n_queued_events = 0;
return a;
}
void pa_anotify_free(pa_anotify *a) {
assert(a);
a->api->io_free(a->io_event);
a->api->defer_free(a->defer_event);
if (a->fds[0] >= 0)
close(a->fds[0]);
if (a->fds[1] >= 0)
close(a->fds[1]);
pa_xfree(a);
}
int pa_anotify_signal(pa_anotify *a, uint8_t event) {
ssize_t r;
assert(a);
r = write(a->fds[1], &event, 1);
return r != 1 ? -1 : 0;
}

303
src/pulsecore/asyncmsgq.c Normal file
View file

@ -0,0 +1,303 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <pulsecore/atomic.h>
#include <pulsecore/log.h>
#include <pulsecore/thread.h>
#include <pulsecore/semaphore.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-util.h>
#include <pulsecore/flist.h>
#include <pulse/xmalloc.h>
#include "asyncmsgq.h"
PA_STATIC_FLIST_DECLARE(asyncmsgq, 0, pa_xfree);
PA_STATIC_FLIST_DECLARE(semaphores, 0, (void(*)(void*)) pa_semaphore_free);
struct asyncmsgq_item {
int code;
pa_msgobject *object;
void *userdata;
pa_free_cb_t free_cb;
int64_t offset;
pa_memchunk memchunk;
pa_semaphore *semaphore;
int ret;
};
struct pa_asyncmsgq {
PA_REFCNT_DECLARE;
pa_asyncq *asyncq;
pa_mutex *mutex; /* only for the writer side */
struct asyncmsgq_item *current;
};
pa_asyncmsgq *pa_asyncmsgq_new(unsigned size) {
pa_asyncmsgq *a;
a = pa_xnew(pa_asyncmsgq, 1);
PA_REFCNT_INIT(a);
pa_assert_se(a->asyncq = pa_asyncq_new(size));
pa_assert_se(a->mutex = pa_mutex_new(FALSE, TRUE));
a->current = NULL;
return a;
}
static void asyncmsgq_free(pa_asyncmsgq *a) {
struct asyncmsgq_item *i;
pa_assert(a);
while ((i = pa_asyncq_pop(a->asyncq, 0))) {
pa_assert(!i->semaphore);
if (i->object)
pa_msgobject_unref(i->object);
if (i->memchunk.memblock)
pa_memblock_unref(i->memchunk.memblock);
if (i->free_cb)
i->free_cb(i->userdata);
if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), i) < 0)
pa_xfree(i);
}
pa_asyncq_free(a->asyncq, NULL);
pa_mutex_free(a->mutex);
pa_xfree(a);
}
pa_asyncmsgq* pa_asyncmsgq_ref(pa_asyncmsgq *q) {
pa_assert(PA_REFCNT_VALUE(q) > 0);
PA_REFCNT_INC(q);
return q;
}
void pa_asyncmsgq_unref(pa_asyncmsgq* q) {
pa_assert(PA_REFCNT_VALUE(q) > 0);
if (PA_REFCNT_DEC(q) <= 0)
asyncmsgq_free(q);
}
void pa_asyncmsgq_post(pa_asyncmsgq *a, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *chunk, pa_free_cb_t free_cb) {
struct asyncmsgq_item *i;
pa_assert(PA_REFCNT_VALUE(a) > 0);
if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(asyncmsgq))))
i = pa_xnew(struct asyncmsgq_item, 1);
i->code = code;
i->object = object ? pa_msgobject_ref(object) : NULL;
i->userdata = (void*) userdata;
i->free_cb = free_cb;
i->offset = offset;
if (chunk) {
pa_assert(chunk->memblock);
i->memchunk = *chunk;
pa_memblock_ref(i->memchunk.memblock);
} else
pa_memchunk_reset(&i->memchunk);
i->semaphore = NULL;
/* This mutex makes the queue multiple-writer safe. This lock is only used on the writing side */
pa_mutex_lock(a->mutex);
pa_assert_se(pa_asyncq_push(a->asyncq, i, 1) == 0);
pa_mutex_unlock(a->mutex);
}
int pa_asyncmsgq_send(pa_asyncmsgq *a, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *chunk) {
struct asyncmsgq_item i;
pa_assert(PA_REFCNT_VALUE(a) > 0);
i.code = code;
i.object = object;
i.userdata = (void*) userdata;
i.free_cb = NULL;
i.ret = -1;
i.offset = offset;
if (chunk) {
pa_assert(chunk->memblock);
i.memchunk = *chunk;
} else
pa_memchunk_reset(&i.memchunk);
if (!(i.semaphore = pa_flist_pop(PA_STATIC_FLIST_GET(semaphores))))
i.semaphore = pa_semaphore_new(0);
pa_assert_se(i.semaphore);
/* Thus mutex makes the queue multiple-writer safe. This lock is only used on the writing side */
pa_mutex_lock(a->mutex);
pa_assert_se(pa_asyncq_push(a->asyncq, &i, 1) == 0);
pa_mutex_unlock(a->mutex);
pa_semaphore_wait(i.semaphore);
if (pa_flist_push(PA_STATIC_FLIST_GET(semaphores), i.semaphore) < 0)
pa_semaphore_free(i.semaphore);
return i.ret;
}
int pa_asyncmsgq_get(pa_asyncmsgq *a, pa_msgobject **object, int *code, void **userdata, int64_t *offset, pa_memchunk *chunk, int wait) {
pa_assert(PA_REFCNT_VALUE(a) > 0);
pa_assert(!a->current);
if (!(a->current = pa_asyncq_pop(a->asyncq, wait))) {
/* pa_log("failure"); */
return -1;
}
/* pa_log("success"); */
if (code)
*code = a->current->code;
if (userdata)
*userdata = a->current->userdata;
if (offset)
*offset = a->current->offset;
if (object) {
if ((*object = a->current->object))
pa_msgobject_assert_ref(*object);
}
if (chunk)
*chunk = a->current->memchunk;
/* pa_log_debug("Get q=%p object=%p (%s) code=%i data=%p chunk.length=%lu", (void*) a, (void*) a->current->object, a->current->object ? a->current->object->parent.type_name : NULL, a->current->code, (void*) a->current->userdata, (unsigned long) a->current->memchunk.length); */
return 0;
}
void pa_asyncmsgq_done(pa_asyncmsgq *a, int ret) {
pa_assert(PA_REFCNT_VALUE(a) > 0);
pa_assert(a);
pa_assert(a->current);
if (a->current->semaphore) {
a->current->ret = ret;
pa_semaphore_post(a->current->semaphore);
} else {
if (a->current->free_cb)
a->current->free_cb(a->current->userdata);
if (a->current->object)
pa_msgobject_unref(a->current->object);
if (a->current->memchunk.memblock)
pa_memblock_unref(a->current->memchunk.memblock);
if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), a->current) < 0)
pa_xfree(a->current);
}
a->current = NULL;
}
int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) {
int c;
pa_assert(PA_REFCNT_VALUE(a) > 0);
pa_asyncmsgq_ref(a);
do {
pa_msgobject *o;
void *data;
int64_t offset;
pa_memchunk chunk;
int ret;
if (pa_asyncmsgq_get(a, &o, &c, &data, &offset, &chunk, 1) < 0)
return -1;
ret = pa_asyncmsgq_dispatch(o, c, data, offset, &chunk);
pa_asyncmsgq_done(a, ret);
} while (c != code);
pa_asyncmsgq_unref(a);
return 0;
}
int pa_asyncmsgq_process_one(pa_asyncmsgq *a) {
pa_msgobject *object;
int code;
void *data;
pa_memchunk chunk;
int64_t offset;
int ret;
pa_assert(PA_REFCNT_VALUE(a) > 0);
if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, 0) < 0)
return 0;
pa_asyncmsgq_ref(a);
ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk);
pa_asyncmsgq_done(a, ret);
pa_asyncmsgq_unref(a);
return 1;
}
int pa_asyncmsgq_get_fd(pa_asyncmsgq *a) {
pa_assert(PA_REFCNT_VALUE(a) > 0);
return pa_asyncq_get_fd(a->asyncq);
}
int pa_asyncmsgq_before_poll(pa_asyncmsgq *a) {
pa_assert(PA_REFCNT_VALUE(a) > 0);
return pa_asyncq_before_poll(a->asyncq);
}
void pa_asyncmsgq_after_poll(pa_asyncmsgq *a) {
pa_assert(PA_REFCNT_VALUE(a) > 0);
pa_asyncq_after_poll(a->asyncq);
}
int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *memchunk) {
if (object)
return object->process_msg(object, code, userdata, offset, memchunk);
return 0;
}

75
src/pulsecore/asyncmsgq.h Normal file
View file

@ -0,0 +1,75 @@
#ifndef foopulseasyncmsgqhfoo
#define foopulseasyncmsgqhfoo
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#include <sys/types.h>
#include <pulsecore/asyncq.h>
#include <pulsecore/memchunk.h>
#include <pulsecore/msgobject.h>
/* A simple asynchronous message queue, based on pa_asyncq. In
* contrast to pa_asyncq this one is multiple-writer safe, though
* still not multiple-reader safe. This queue is intended to be used
* for controlling real-time threads from normal-priority
* threads. Multiple-writer-safety is accomplished by using a mutex on
* the writer side. This queue is thus not useful for communication
* between several real-time threads.
*
* The queue takes messages consisting of:
* "Object" for which this messages is intended (may be NULL)
* A numeric message code
* Arbitrary userdata pointer (may be NULL)
* A memchunk (may be NULL)
*
* There are two functions for submitting messages: _post and
* _send. The former just enqueues the message asynchronously, the
* latter waits for completion, synchronously. */
enum {
PA_MESSAGE_SHUTDOWN = -1/* A generic message to inform the handler of this queue to quit */
};
typedef struct pa_asyncmsgq pa_asyncmsgq;
pa_asyncmsgq* pa_asyncmsgq_new(unsigned size);
pa_asyncmsgq* pa_asyncmsgq_ref(pa_asyncmsgq *q);
void pa_asyncmsgq_unref(pa_asyncmsgq* q);
void pa_asyncmsgq_post(pa_asyncmsgq *q, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *memchunk, pa_free_cb_t userdata_free_cb);
int pa_asyncmsgq_send(pa_asyncmsgq *q, pa_msgobject *object, int code, const void *userdata, int64_t offset, const pa_memchunk *memchunk);
int pa_asyncmsgq_get(pa_asyncmsgq *q, pa_msgobject **object, int *code, void **userdata, int64_t *offset, pa_memchunk *memchunk, int wait);
int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *memchunk);
void pa_asyncmsgq_done(pa_asyncmsgq *q, int ret);
int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code);
int pa_asyncmsgq_process_one(pa_asyncmsgq *a);
/* Just for the reading side */
int pa_asyncmsgq_get_fd(pa_asyncmsgq *q);
int pa_asyncmsgq_before_poll(pa_asyncmsgq *a);
void pa_asyncmsgq_after_poll(pa_asyncmsgq *a);
#endif

213
src/pulsecore/asyncq.c Normal file
View file

@ -0,0 +1,213 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <pulsecore/atomic.h>
#include <pulsecore/log.h>
#include <pulsecore/thread.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-util.h>
#include <pulse/xmalloc.h>
#include "asyncq.h"
#include "fdsem.h"
#define ASYNCQ_SIZE 128
/* For debugging purposes we can define _Y to put and extra thread
* yield between each operation. */
/* #define PROFILE */
#ifdef PROFILE
#define _Y pa_thread_yield()
#else
#define _Y do { } while(0)
#endif
struct pa_asyncq {
unsigned size;
unsigned read_idx;
unsigned write_idx;
pa_fdsem *read_fdsem, *write_fdsem;
};
#define PA_ASYNCQ_CELLS(x) ((pa_atomic_ptr_t*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_asyncq))))
static int is_power_of_two(unsigned size) {
return !(size & (size - 1));
}
static int reduce(pa_asyncq *l, int value) {
return value & (unsigned) (l->size - 1);
}
pa_asyncq *pa_asyncq_new(unsigned size) {
pa_asyncq *l;
if (!size)
size = ASYNCQ_SIZE;
pa_assert(is_power_of_two(size));
l = pa_xmalloc0(PA_ALIGN(sizeof(pa_asyncq)) + (sizeof(pa_atomic_ptr_t) * size));
l->size = size;
if (!(l->read_fdsem = pa_fdsem_new())) {
pa_xfree(l);
return NULL;
}
if (!(l->write_fdsem = pa_fdsem_new())) {
pa_fdsem_free(l->read_fdsem);
pa_xfree(l);
return NULL;
}
return l;
}
void pa_asyncq_free(pa_asyncq *l, pa_free_cb_t free_cb) {
pa_assert(l);
if (free_cb) {
void *p;
while ((p = pa_asyncq_pop(l, 0)))
free_cb(p);
}
pa_fdsem_free(l->read_fdsem);
pa_fdsem_free(l->write_fdsem);
pa_xfree(l);
}
int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
int idx;
pa_atomic_ptr_t *cells;
pa_assert(l);
pa_assert(p);
cells = PA_ASYNCQ_CELLS(l);
_Y;
idx = reduce(l, l->write_idx);
if (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)) {
if (!wait)
return -1;
/* pa_log("sleeping on push"); */
do {
pa_fdsem_wait(l->read_fdsem);
} while (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p));
}
_Y;
l->write_idx++;
pa_fdsem_post(l->write_fdsem);
return 0;
}
void* pa_asyncq_pop(pa_asyncq*l, int wait) {
int idx;
void *ret;
pa_atomic_ptr_t *cells;
pa_assert(l);
cells = PA_ASYNCQ_CELLS(l);
_Y;
idx = reduce(l, l->read_idx);
if (!(ret = pa_atomic_ptr_load(&cells[idx]))) {
if (!wait)
return NULL;
/* pa_log("sleeping on pop"); */
do {
pa_fdsem_wait(l->write_fdsem);
} while (!(ret = pa_atomic_ptr_load(&cells[idx])));
}
pa_assert(ret);
/* Guaranteed to succeed if we only have a single reader */
pa_assert_se(pa_atomic_ptr_cmpxchg(&cells[idx], ret, NULL));
_Y;
l->read_idx++;
pa_fdsem_post(l->read_fdsem);
return ret;
}
int pa_asyncq_get_fd(pa_asyncq *q) {
pa_assert(q);
return pa_fdsem_get(q->write_fdsem);
}
int pa_asyncq_before_poll(pa_asyncq *l) {
int idx;
pa_atomic_ptr_t *cells;
pa_assert(l);
cells = PA_ASYNCQ_CELLS(l);
_Y;
idx = reduce(l, l->read_idx);
for (;;) {
if (pa_atomic_ptr_load(&cells[idx]))
return -1;
if (pa_fdsem_before_poll(l->write_fdsem) >= 0)
return 0;
}
return 0;
}
void pa_asyncq_after_poll(pa_asyncq *l) {
pa_assert(l);
pa_fdsem_after_poll(l->write_fdsem);
}

56
src/pulsecore/asyncq.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef foopulseasyncqhfoo
#define foopulseasyncqhfoo
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#include <sys/types.h>
#include <pulse/def.h>
/* A simple, asynchronous, lock-free (if requested also wait-free)
* queue. Not multiple-reader/multiple-writer safe. If that is
* required both sides can be protected by a mutex each. --- Which is
* not a bad thing in most cases, since this queue is intended for
* communication between a normal thread and a single real-time
* thread. Only the real-time side needs to be lock-free/wait-free.
*
* If the queue is full and another entry shall be pushed, or when the
* queue is empty and another entry shall be popped and the "wait"
* argument is non-zero, the queue will block on a UNIX FIFO object --
* that will probably require locking on the kernel side -- which
* however is probably not problematic, because we do it only on
* starvation or overload in which case we have to block anyway. */
typedef struct pa_asyncq pa_asyncq;
pa_asyncq* pa_asyncq_new(unsigned size);
void pa_asyncq_free(pa_asyncq* q, pa_free_cb_t free_cb);
void* pa_asyncq_pop(pa_asyncq *q, int wait);
int pa_asyncq_push(pa_asyncq *q, void *p, int wait);
int pa_asyncq_get_fd(pa_asyncq *q);
int pa_asyncq_before_poll(pa_asyncq *a);
void pa_asyncq_after_poll(pa_asyncq *a);
#endif

View file

@ -24,48 +24,201 @@
USA.
***/
#include <atomic_ops.h>
/* atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*).
/*
* atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*). It is
* not guaranteed however, that sizeof(AO_t) == sizeof(size_t).
* however very likely.
*
* It is not guaranteed however, that sizeof(AO_t) == sizeof(size_t).
* however very likely. */
* For now we do only full memory barriers. Eventually we might want
* to support more elaborate memory barriers, in which case we will add
* suffixes to the function names.
*
* On gcc >= 4.1 we use the builtin atomic functions. otherwise we use
* libatomic_ops
*/
typedef struct pa_atomic_int {
volatile AO_t value;
} pa_atomic_int_t;
#ifndef PACKAGE
#error "Please include config.h before including this file!"
#endif
#ifdef HAVE_ATOMIC_BUILTINS
/* __sync based implementation */
typedef struct pa_atomic {
volatile int value;
} pa_atomic_t;
#define PA_ATOMIC_INIT(v) { .value = (v) }
/* For now we do only full memory barriers. Eventually we might want
* to support more elaborate memory barriers, in which case we will add
* suffixes to the function names */
static inline int pa_atomic_load(const pa_atomic_t *a) {
__sync_synchronize();
return a->value;
}
static inline int pa_atomic_load(const pa_atomic_int_t *a) {
static inline void pa_atomic_store(pa_atomic_t *a, int i) {
a->value = i;
__sync_synchronize();
}
/* Returns the previously set value */
static inline int pa_atomic_add(pa_atomic_t *a, int i) {
return __sync_fetch_and_add(&a->value, i);
}
/* Returns the previously set value */
static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
return __sync_fetch_and_sub(&a->value, i);
}
/* Returns the previously set value */
static inline int pa_atomic_inc(pa_atomic_t *a) {
return pa_atomic_add(a, 1);
}
/* Returns the previously set value */
static inline int pa_atomic_dec(pa_atomic_t *a) {
return pa_atomic_sub(a, 1);
}
/* Returns non-zero when the operation was successful. */
static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
return __sync_bool_compare_and_swap(&a->value, old_i, new_i);
}
typedef struct pa_atomic_ptr {
volatile unsigned long value;
} pa_atomic_ptr_t;
#define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) }
static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
__sync_synchronize();
return (void*) a->value;
}
static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
a->value = (unsigned long) p;
__sync_synchronize();
}
static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
return __sync_bool_compare_and_swap(&a->value, (long) old_p, (long) new_p);
}
#elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
#error "The native atomic operations implementation for AMD64 has not been tested. libatomic_ops is known to not work properly on AMD64 and your gcc version is too old for the gcc-builtin atomic ops support. You have three options now: make the native atomic operations implementation for AMD64 work, fix libatomic_ops, or upgrade your GCC."
/* Addapted from glibc */
typedef struct pa_atomic {
volatile int value;
} pa_atomic_t;
#define PA_ATOMIC_INIT(v) { .value = (v) }
static inline int pa_atomic_load(const pa_atomic_t *a) {
return a->value;
}
static inline void pa_atomic_store(pa_atomic_t *a, int i) {
a->value = i;
}
static inline int pa_atomic_add(pa_atomic_t *a, int i) {
int result;
__asm __volatile ("lock; xaddl %0, %1"
: "=r" (result), "=m" (a->value)
: "0" (i), "m" (a->value));
return result;
}
static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
return pa_atomic_add(a, -i);
}
static inline int pa_atomic_inc(pa_atomic_t *a) {
return pa_atomic_add(a, 1);
}
static inline int pa_atomic_dec(pa_atomic_t *a) {
return pa_atomic_sub(a, 1);
}
static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
int result;
__asm__ __volatile__ ("lock; cmpxchgl %2, %1"
: "=a" (result), "=m" (a->value)
: "r" (new_i), "m" (a->value), "0" (old_i));
return result == oldval;
}
typedef struct pa_atomic_ptr {
volatile unsigned long value;
} pa_atomic_ptr_t;
#define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) }
static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
return (void*) a->value;
}
static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
a->value = (unsigned long) p;
}
static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
void *result;
__asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
: "=a" (result), "=m" (a->value)
: "r" (new_p), "m" (a->value), "0" (old_p));
return result;
}
#else
/* libatomic_ops based implementation */
#include <atomic_ops.h>
typedef struct pa_atomic {
volatile AO_t value;
} pa_atomic_t;
#define PA_ATOMIC_INIT(v) { .value = (v) }
static inline int pa_atomic_load(const pa_atomic_t *a) {
return (int) AO_load_full((AO_t*) &a->value);
}
static inline void pa_atomic_store(pa_atomic_int_t *a, int i) {
static inline void pa_atomic_store(pa_atomic_t *a, int i) {
AO_store_full(&a->value, (AO_t) i);
}
static inline int pa_atomic_add(pa_atomic_int_t *a, int i) {
static inline int pa_atomic_add(pa_atomic_t *a, int i) {
return AO_fetch_and_add_full(&a->value, (AO_t) i);
}
static inline int pa_atomic_sub(pa_atomic_int_t *a, int i) {
static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
return AO_fetch_and_add_full(&a->value, (AO_t) -i);
}
static inline int pa_atomic_inc(pa_atomic_int_t *a) {
static inline int pa_atomic_inc(pa_atomic_t *a) {
return AO_fetch_and_add1_full(&a->value);
}
static inline int pa_atomic_dec(pa_atomic_int_t *a) {
static inline int pa_atomic_dec(pa_atomic_t *a) {
return AO_fetch_and_sub1_full(&a->value);
}
static inline int pa_atomic_cmpxchg(pa_atomic_int_t *a, int old_i, int new_i) {
static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
return AO_compare_and_swap_full(&a->value, old_i, new_i);
}
@ -73,6 +226,8 @@ typedef struct pa_atomic_ptr {
volatile AO_t value;
} pa_atomic_ptr_t;
#define PA_ATOMIC_PTR_INIT(v) { .value = (AO_t) (v) }
static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
return (void*) AO_load_full((AO_t*) &a->value);
}
@ -86,3 +241,5 @@ static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* n
}
#endif
#endif

View file

@ -21,44 +21,56 @@
USA.
***/
#include <assert.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <pulse/xmalloc.h>
#include <pulsecore/props.h>
#include <pulsecore/macro.h>
#include <pulsecore/log.h>
#include <pulsecore/refcnt.h>
#include "authkey-prop.h"
struct authkey_data {
int ref;
PA_REFCNT_DECLARE;
size_t length;
};
int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) {
struct authkey_data *a;
assert(c && name && data && len > 0);
pa_assert(c);
pa_assert(name);
pa_assert(data);
pa_assert(len > 0);
if (!(a = pa_property_get(c, name)))
return -1;
assert(a->length == len);
memcpy(data, a+1, len);
pa_assert(a->length == len);
memcpy(data, (uint8_t*) a + PA_ALIGN(sizeof(struct authkey_data)), len);
return 0;
}
int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len) {
struct authkey_data *a;
assert(c && name);
pa_assert(c);
pa_assert(name);
if (pa_property_get(c, name))
return -1;
a = pa_xmalloc(sizeof(struct authkey_data) + len);
a->ref = 1;
a = pa_xmalloc(PA_ALIGN(sizeof(struct authkey_data)) + len);
PA_REFCNT_INIT(a);
a->length = len;
memcpy(a+1, data, len);
memcpy((uint8_t*) a + PA_ALIGN(sizeof(struct authkey_data)), data, len);
pa_property_set(c, name, a);
@ -67,22 +79,27 @@ int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t l
void pa_authkey_prop_ref(pa_core *c, const char *name) {
struct authkey_data *a;
assert(c && name);
pa_assert(c);
pa_assert(name);
a = pa_property_get(c, name);
assert(a && a->ref >= 1);
a->ref++;
pa_assert(a);
pa_assert(PA_REFCNT_VALUE(a) >= 1);
PA_REFCNT_INC(a);
}
void pa_authkey_prop_unref(pa_core *c, const char *name) {
struct authkey_data *a;
assert(c && name);
pa_assert(c);
pa_assert(name);
a = pa_property_get(c, name);
assert(a && a->ref >= 1);
pa_assert(a);
pa_assert(PA_REFCNT_VALUE(a) >= 1);
if (!(--a->ref)) {
if (PA_REFCNT_DEC(a) <= 0) {
pa_property_remove(c, name);
pa_xfree(a);
}

View file

@ -26,7 +26,6 @@
#include <config.h>
#endif
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
@ -43,21 +42,25 @@
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/random.h>
#include <pulsecore/macro.h>
#include "authkey.h"
/* Generate a new authorization key, store it in file fd and return it in *data */
static int generate(int fd, void *ret_data, size_t length) {
ssize_t r;
assert(fd >= 0 && ret_data && length);
pa_assert(fd >= 0);
pa_assert(ret_data);
pa_assert(length > 0);
pa_random(ret_data, length);
lseek(fd, 0, SEEK_SET);
ftruncate(fd, 0);
(void) ftruncate(fd, 0);
if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) {
pa_log("failed to write cookie file: %s", pa_cstrerror(errno));
pa_log("Failed to write cookie file: %s", pa_cstrerror(errno));
return -1;
}
@ -68,6 +71,10 @@ static int generate(int fd, void *ret_data, size_t length) {
#define O_BINARY 0
#endif
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
/* Load an euthorization cookie from file fn and store it in data. If
* the cookie file doesn't exist, create it */
static int load(const char *fn, void *data, size_t length) {
@ -75,11 +82,15 @@ static int load(const char *fn, void *data, size_t length) {
int writable = 1;
int unlock = 0, ret = -1;
ssize_t r;
assert(fn && data && length);
if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
pa_assert(fn);
pa_assert(data);
pa_assert(length > 0);
if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY|O_NOCTTY)) < 0) {
pa_log("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
goto finish;
} else
writable = 0;
@ -88,15 +99,15 @@ static int load(const char *fn, void *data, size_t length) {
unlock = pa_lock_fd(fd, 1) >= 0;
if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
goto finish;
}
if ((size_t) r != length) {
pa_log_debug("got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length);
pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length);
if (!writable) {
pa_log("unable to write cookie to read only file");
pa_log("Unable to write cookie to read only file");
goto finish;
}
@ -113,7 +124,10 @@ finish:
if (unlock)
pa_lock_fd(fd, 0);
close(fd);
if (pa_close(fd) < 0) {
pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
ret = -1;
}
}
return ret;
@ -123,13 +137,12 @@ finish:
int pa_authkey_load(const char *path, void *data, size_t length) {
int ret;
assert(path && data && length);
pa_assert(path);
pa_assert(data);
pa_assert(length > 0);
ret = load(path, data, length);
if (ret < 0)
pa_log("Failed to load authorization key '%s': %s", path,
(ret == -1) ? pa_cstrerror(errno) : "file corrupt");
if ((ret = load(path, data, length)) < 0)
pa_log("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt");
return ret;
}
@ -137,7 +150,10 @@ int pa_authkey_load(const char *path, void *data, size_t length) {
/* If the specified file path starts with / return it, otherwise
* return path prepended with home directory */
static const char *normalize_path(const char *fn, char *s, size_t l) {
assert(fn && s && l > 0);
pa_assert(fn);
pa_assert(s);
pa_assert(l > 0);
#ifndef OS_IS_WIN32
if (fn[0] != '/') {
@ -145,13 +161,14 @@ static const char *normalize_path(const char *fn, char *s, size_t l) {
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);
pa_snprintf(s, l, "%s/%s", homedir, fn);
#else
snprintf(s, l, "%s\\%s", homedir, fn);
pa_snprintf(s, l, "%s\\%s", homedir, fn);
#endif
return s;
}
@ -164,7 +181,10 @@ static const char *normalize_path(const char *fn, char *s, size_t l) {
int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
char path[PATH_MAX];
const char *p;
assert(fn && data && length);
pa_assert(fn);
pa_assert(data);
pa_assert(length > 0);
if (!(p = normalize_path(fn, path, sizeof(path))))
return -2;
@ -179,20 +199,23 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) {
ssize_t r;
char path[PATH_MAX];
const char *p;
assert(fn && data && length);
pa_assert(fn);
pa_assert(data);
pa_assert(length > 0);
if (!(p = normalize_path(fn, path, sizeof(path))))
return -2;
if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
pa_log("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
goto finish;
}
unlock = pa_lock_fd(fd, 1) >= 0;
if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
goto finish;
}
@ -205,7 +228,10 @@ finish:
if (unlock)
pa_lock_fd(fd, 0);
close(fd);
if (pa_close(fd) < 0) {
pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
ret = -1;
}
}
return ret;

View file

@ -26,7 +26,6 @@
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -36,13 +35,14 @@
#include <pulsecore/memchunk.h>
#include <pulsecore/sound-file.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-scache.h>
#include <pulsecore/core-subscribe.h>
#include "autoload.h"
static void entry_free(pa_autoload_entry *e) {
assert(e);
pa_assert(e);
pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX);
pa_xfree(e->name);
pa_xfree(e->module);
@ -51,7 +51,8 @@ static void entry_free(pa_autoload_entry *e) {
}
static void entry_remove_and_free(pa_autoload_entry *e) {
assert(e && e->core);
pa_assert(e);
pa_assert(e->core);
pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL);
pa_hashmap_remove(e->core->autoload_hashmap, e->name);
@ -60,12 +61,14 @@ static void entry_remove_and_free(pa_autoload_entry *e) {
static pa_autoload_entry* entry_new(pa_core *c, const char *name) {
pa_autoload_entry *e = NULL;
assert(c && name);
pa_core_assert_ref(c);
pa_assert(name);
if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name)))
return NULL;
e = pa_xmalloc(sizeof(pa_autoload_entry));
e = pa_xnew(pa_autoload_entry, 1);
e->core = c;
e->name = pa_xstrdup(name);
e->module = e->argument = NULL;
@ -73,7 +76,7 @@ static pa_autoload_entry* entry_new(pa_core *c, const char *name) {
if (!c->autoload_hashmap)
c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
assert(c->autoload_hashmap);
pa_assert(c->autoload_hashmap);
pa_hashmap_put(c->autoload_hashmap, e->name, e);
@ -88,7 +91,11 @@ static pa_autoload_entry* entry_new(pa_core *c, const char *name) {
int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) {
pa_autoload_entry *e = NULL;
assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE));
pa_assert(c);
pa_assert(name);
pa_assert(module);
pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE);
if (!(e = entry_new(c, name)))
return -1;
@ -105,7 +112,10 @@ int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const c
int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) {
pa_autoload_entry *e;
assert(c && name && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE));
pa_assert(c);
pa_assert(name);
pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE);
if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type)
return -1;
@ -116,7 +126,9 @@ int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t ty
int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) {
pa_autoload_entry *e;
assert(c && idx != PA_IDXSET_INVALID);
pa_assert(c);
pa_assert(idx != PA_IDXSET_INVALID);
if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx)))
return -1;
@ -128,7 +140,9 @@ int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) {
void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) {
pa_autoload_entry *e;
pa_module *m;
assert(c && name);
pa_assert(c);
pa_assert(name);
if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type))
return;
@ -153,6 +167,7 @@ static void free_func(void *p, PA_GCC_UNUSED void *userdata) {
}
void pa_autoload_free(pa_core *c) {
if (c->autoload_hashmap) {
pa_hashmap_free(c->autoload_hashmap, free_func, NULL);
c->autoload_hashmap = NULL;
@ -166,7 +181,9 @@ void pa_autoload_free(pa_core *c) {
const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) {
pa_autoload_entry *e;
assert(c && name);
pa_core_assert_ref(c);
pa_assert(name);
if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type)
return NULL;
@ -176,7 +193,9 @@ const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa
const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) {
pa_autoload_entry *e;
assert(c && idx != PA_IDXSET_INVALID);
pa_core_assert_ref(c);
pa_assert(idx != PA_IDXSET_INVALID);
if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx)))
return NULL;

View file

@ -21,11 +21,14 @@
USA.
***/
#include <assert.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pulse/xmalloc.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "avahi-wrap.h"
@ -61,9 +64,9 @@ static pa_io_event_flags_t translate_io_flags(AvahiWatchEvent e) {
static void watch_callback(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
AvahiWatch *w = userdata;
assert(a);
assert(e);
assert(w);
pa_assert(a);
pa_assert(e);
pa_assert(w);
w->current_event = translate_io_flags_back(events);
w->callback(w, fd, w->current_event, w->userdata);
@ -74,12 +77,10 @@ static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event
pa_avahi_poll *p;
AvahiWatch *w;
assert(api);
assert(fd >= 0);
assert(callback);
p = api->userdata;
assert(p);
pa_assert(api);
pa_assert(fd >= 0);
pa_assert(callback);
pa_assert_se(p = api->userdata);
w = pa_xnew(AvahiWatch, 1);
w->avahi_poll = p;
@ -92,19 +93,19 @@ static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event
}
static void watch_update(AvahiWatch *w, AvahiWatchEvent event) {
assert(w);
pa_assert(w);
w->avahi_poll->mainloop->io_enable(w->io_event, translate_io_flags(event));
}
static AvahiWatchEvent watch_get_events(AvahiWatch *w) {
assert(w);
pa_assert(w);
return w->current_event;
}
static void watch_free(AvahiWatch *w) {
assert(w);
pa_assert(w);
w->avahi_poll->mainloop->io_free(w->io_event);
pa_xfree(w);
@ -120,9 +121,9 @@ struct AvahiTimeout {
static void timeout_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) {
AvahiTimeout *t = userdata;
assert(a);
assert(e);
assert(t);
pa_assert(a);
pa_assert(e);
pa_assert(t);
t->callback(t, t->userdata);
}
@ -131,11 +132,9 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv,
pa_avahi_poll *p;
AvahiTimeout *t;
assert(api);
assert(callback);
p = api->userdata;
assert(p);
pa_assert(api);
pa_assert(callback);
pa_assert_se(p = api->userdata);
t = pa_xnew(AvahiTimeout, 1);
t->avahi_poll = p;
@ -148,7 +147,7 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv,
}
static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
assert(t);
pa_assert(t);
if (t->time_event && tv)
t->avahi_poll->mainloop->time_restart(t->time_event, tv);
@ -161,7 +160,7 @@ static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
}
static void timeout_free(AvahiTimeout *t) {
assert(t);
pa_assert(t);
if (t->time_event)
t->avahi_poll->mainloop->time_free(t->time_event);
@ -171,7 +170,7 @@ static void timeout_free(AvahiTimeout *t) {
AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *m) {
pa_avahi_poll *p;
assert(m);
pa_assert(m);
p = pa_xnew(pa_avahi_poll, 1);
@ -190,9 +189,8 @@ AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *m) {
void pa_avahi_poll_free(AvahiPoll *api) {
pa_avahi_poll *p;
assert(api);
p = api->userdata;
assert(p);
pa_assert(api);
pa_assert_se(p = api->userdata);
pa_xfree(p);
}

View file

@ -28,7 +28,6 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
@ -95,6 +94,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb
static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
@ -114,6 +114,9 @@ static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf
static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
/* A method table for all available commands */
@ -130,13 +133,14 @@ static const struct command commands[] = {
{ "info", pa_cli_command_info, "Show comprehensive status", 1 },
{ "ls", pa_cli_command_info, NULL, 1 },
{ "list", pa_cli_command_info, NULL, 1 },
{ "load-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3},
{ "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2},
{ "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3},
{ "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3},
{ "load-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3},
{ "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2},
{ "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3},
{ "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index, volume)", 3},
{ "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3},
{ "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, mute)", 3},
{ "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, mute)", 3},
{ "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, bool)", 3},
{ "set-sink-input-mute", pa_cli_command_sink_input_mute, "Set the mute switch of a sink input (args: index, bool)", 3},
{ "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, bool)", 3},
{ "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2},
{ "set-default-source", pa_cli_command_source_default, "Set the default source (args: index|name)", 2},
{ "kill-client", pa_cli_command_kill_client, "Kill a client (args: index)", 2},
@ -159,6 +163,9 @@ static const struct command commands[] = {
{ "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3},
{ "move-source-output", pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3},
{ "vacuum", pa_cli_command_vacuum, NULL, 1},
{ "suspend-sink", pa_cli_command_suspend_sink, "Suspend sink (args: index|name, bool)", 3},
{ "suspend-source", pa_cli_command_suspend_source, "Suspend source (args: index|name, bool)", 3},
{ "suspend", pa_cli_command_suspend, "Suspend all sinks and all sources (args: bool)", 2},
{ NULL, NULL, NULL, 0 }
};
@ -174,15 +181,23 @@ static uint32_t parse_index(const char *n) {
return idx;
}
static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
assert(c && c->mainloop && t);
static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
c->mainloop->quit(c->mainloop, 0);
return 0;
}
static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const struct command*command;
assert(c && t && buf);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_strbuf_puts(buf, "Available commands:\n");
@ -192,67 +207,91 @@ static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
return 0;
}
static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char *s;
assert(c && t);
s = pa_module_list_to_string(c);
assert(s);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_assert_se(s = pa_module_list_to_string(c));
pa_strbuf_puts(buf, s);
pa_xfree(s);
return 0;
}
static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char *s;
assert(c && t);
s = pa_client_list_to_string(c);
assert(s);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_assert_se(s = pa_client_list_to_string(c));
pa_strbuf_puts(buf, s);
pa_xfree(s);
return 0;
}
static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char *s;
assert(c && t);
s = pa_sink_list_to_string(c);
assert(s);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_assert_se(s = pa_sink_list_to_string(c));
pa_strbuf_puts(buf, s);
pa_xfree(s);
return 0;
}
static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char *s;
assert(c && t);
s = pa_source_list_to_string(c);
assert(s);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_assert_se(s = pa_source_list_to_string(c));
pa_strbuf_puts(buf, s);
pa_xfree(s);
return 0;
}
static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char *s;
assert(c && t);
s = pa_sink_input_list_to_string(c);
assert(s);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_assert_se(s = pa_sink_input_list_to_string(c));
pa_strbuf_puts(buf, s);
pa_xfree(s);
return 0;
}
static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char *s;
assert(c && t);
s = pa_source_output_list_to_string(c);
assert(s);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_assert_se(s = pa_source_output_list_to_string(c));
pa_strbuf_puts(buf, s);
pa_xfree(s);
return 0;
}
static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char s[256];
const pa_mempool_stat *stat;
unsigned k;
@ -267,8 +306,10 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
[PA_MEMBLOCK_IMPORTED] = "IMPORTED",
};
assert(c);
assert(t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
stat = pa_mempool_get_stat(c->mempool);
@ -312,7 +353,11 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
}
static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_cli_command_stat(c, t, buf, fail);
pa_cli_command_modules(c, t, buf, fail);
pa_cli_command_sinks(c, t, buf, fail);
@ -325,10 +370,14 @@ static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int
return 0;
}
static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
pa_module *m;
const char *name;
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(name = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
@ -343,12 +392,16 @@ static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
return 0;
}
static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
pa_module *m;
uint32_t idx;
const char *i;
char *e;
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(i = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify the module index.\n");
@ -365,12 +418,17 @@ static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA
return 0;
}
static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *v;
pa_sink *sink;
uint32_t volume;
pa_cvolume cvolume;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
return -1;
@ -392,17 +450,22 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
}
pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume);
pa_sink_set_volume(sink, &cvolume);
return 0;
}
static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *v;
pa_sink_input *si;
pa_volume_t volume;
pa_cvolume cvolume;
uint32_t idx;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
return -1;
@ -433,12 +496,17 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb
return 0;
}
static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *v;
pa_source *source;
uint32_t volume;
pa_cvolume cvolume;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
return -1;
@ -460,15 +528,20 @@ static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *
}
pa_cvolume_set(&cvolume, source->sample_spec.channels, volume);
pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume);
pa_source_set_volume(source, &cvolume);
return 0;
}
static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *m;
pa_sink *sink;
int mute;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
return -1;
@ -489,15 +562,20 @@ static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf,
return -1;
}
pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute);
pa_sink_set_mute(sink, mute);
return 0;
}
static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *m;
pa_source *source;
int mute;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
return -1;
@ -518,13 +596,57 @@ static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
return -1;
}
pa_source_set_mute(source, PA_MIXER_HARDWARE, mute);
pa_source_set_mute(source, mute);
return 0;
}
static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *v;
pa_sink_input *si;
uint32_t idx;
int mute;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
return -1;
}
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
pa_strbuf_puts(buf, "Failed to parse index.\n");
return -1;
}
if (!(v = pa_tokenizer_get(t, 2))) {
pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
return -1;
}
if (pa_atoi(v, &mute) < 0) {
pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
return -1;
}
if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
pa_strbuf_puts(buf, "No sink input found with this index.\n");
return -1;
}
pa_sink_input_set_mute(si, mute);
return 0;
}
static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n;
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
@ -535,9 +657,13 @@ static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *b
return 0;
}
static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n;
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
@ -548,11 +674,15 @@ static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf
return 0;
}
static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n;
pa_client *client;
uint32_t idx;
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
@ -573,11 +703,15 @@ static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
return 0;
}
static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n;
pa_sink_input *sink_input;
uint32_t idx;
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
@ -598,11 +732,15 @@ static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf
return 0;
}
static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n;
pa_source_output *source_output;
uint32_t idx;
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
@ -623,20 +761,29 @@ static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_str
return 0;
}
static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char *s;
assert(c && t);
s = pa_scache_list_to_string(c);
assert(s);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_assert_se(s = pa_scache_list_to_string(c));
pa_strbuf_puts(buf, s);
pa_xfree(s);
return 0;
}
static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *sink_name;
pa_sink *sink;
assert(c && t && buf && fail);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
@ -658,7 +805,11 @@ static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n;
assert(c && t && buf && fail);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sample name.\n");
@ -676,7 +827,11 @@ static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *
static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *fname, *n;
int r;
assert(c && t && buf && fail);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
@ -696,7 +851,11 @@ static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *pname;
assert(c && t && buf && fail);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(pname = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a path name.\n");
@ -714,7 +873,11 @@ static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf
static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *fname, *sink_name;
pa_sink *sink;
assert(c && t && buf && fail);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
@ -732,7 +895,11 @@ static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf,
static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *a, *b;
assert(c && t && buf && fail);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) {
pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n");
@ -746,7 +913,11 @@ static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *b
static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *name;
assert(c && t && buf && fail);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(name = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a device name\n");
@ -761,25 +932,36 @@ static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf
return 0;
}
static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
char *s;
assert(c && t);
s = pa_autoload_list_to_string(c);
assert(s);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_assert_se(s = pa_autoload_list_to_string(c));
pa_strbuf_puts(buf, s);
pa_xfree(s);
return 0;
}
static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
assert(c && t);
static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_property_dump(c, buf);
return 0;
}
static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
assert(c);
assert(t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
pa_mempool_vacuum(c->mempool);
@ -792,6 +974,11 @@ static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf
pa_sink *sink;
uint32_t idx;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
return -1;
@ -830,6 +1017,11 @@ static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_str
pa_source *source;
uint32_t idx;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
return -1;
@ -862,7 +1054,105 @@ static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_str
return 0;
}
static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *m;
pa_sink *sink;
int suspend;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
return -1;
}
if (!(m = pa_tokenizer_get(t, 2))) {
pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
return -1;
}
if (pa_atoi(m, &suspend) < 0) {
pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
return -1;
}
if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) {
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
return -1;
}
pa_sink_suspend(sink, suspend);
return 0;
}
static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *n, *m;
pa_source *source;
int suspend;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
return -1;
}
if (!(m = pa_tokenizer_get(t, 2))) {
pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
return -1;
}
if (pa_atoi(m, &suspend) < 0) {
pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
return -1;
}
if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) {
pa_strbuf_puts(buf, "No source found by this name or index.\n");
return -1;
}
pa_source_suspend(source, suspend);
return 0;
}
static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
const char *m;
int suspend;
int ret;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(m = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
return -1;
}
if (pa_atoi(m, &suspend) < 0) {
pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
return -1;
}
ret = - (pa_sink_suspend_all(c, suspend) < 0);
if (pa_source_suspend_all(c, suspend) < 0)
ret = -1;
if (ret < 0)
pa_strbuf_puts(buf, "Failed to resume/suspend all sinks/sources.\n");
return 0;
}
static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
pa_module *m;
pa_sink *sink;
pa_source *source;
@ -874,7 +1164,10 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
void *i;
pa_autoload_entry *a;
assert(c && t);
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
time(&now);
@ -884,7 +1177,6 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
#endif
for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) {
if (m->auto_unload)
continue;
@ -900,7 +1192,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
nl = 0;
for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) {
if (sink->owner && sink->owner->auto_unload)
if (sink->module && sink->module->auto_unload)
continue;
if (!nl) {
@ -908,12 +1200,12 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
nl = 1;
}
pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE)));
pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink, PA_MIXER_HARDWARE));
pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink)));
pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink));
}
for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
if (source->owner && source->owner->auto_unload)
if (source->module && source->module->auto_unload)
continue;
if (!nl) {
@ -921,8 +1213,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
nl = 1;
}
pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE)));
pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source, PA_MIXER_HARDWARE));
pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source)));
pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source));
}
@ -972,6 +1264,10 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate) {
const char *cs;
pa_assert(c);
pa_assert(s);
pa_assert(buf);
cs = s+strspn(s, whitespace);
if (*cs == '#' || !*cs)
@ -1006,9 +1302,9 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b
if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) {
const char *filename = cs+l+strspn(cs+l, whitespace);
if (pa_cli_command_execute_file(c, filename, buf, fail) < 0)
if (*fail) return -1;
if (*fail)
return -1;
} else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) {
if (!ifstate) {
pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
@ -1020,6 +1316,7 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b
const char *filename = cs+l+strspn(cs+l, whitespace);
*ifstate = access(filename, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE;
pa_log_debug("Checking for existance of '%s': %s", filename, *ifstate == IFSTATE_TRUE ? "success" : "failure");
}
} else {
pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
@ -1034,14 +1331,13 @@ int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *b
if (ifstate && *ifstate == IFSTATE_FALSE)
return 0;
l = strcspn(cs, whitespace);
for (command = commands; command->name; command++)
if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
int ret;
pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
assert(t);
pa_assert(t);
ret = command->proc(c, t, buf, fail);
pa_tokenizer_free(t);
unknown = 0;
@ -1072,9 +1368,9 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int
int ifstate = IFSTATE_NONE;
int ret = -1;
assert(c);
assert(fn);
assert(buf);
pa_assert(c);
pa_assert(fn);
pa_assert(buf);
if (!(f = fopen(fn, "r"))) {
pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
@ -1104,9 +1400,9 @@ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail)
const char *p;
int ifstate = IFSTATE_NONE;
assert(c);
assert(s);
assert(buf);
pa_assert(c);
pa_assert(s);
pa_assert(buf);
p = s;
while (*p) {
@ -1125,3 +1421,4 @@ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail)
return 0;
}

View file

@ -25,7 +25,6 @@
#include <config.h>
#endif
#include <assert.h>
#include <string.h>
#include <pulse/volume.h>
@ -41,6 +40,7 @@
#include <pulsecore/sample-util.h>
#include <pulsecore/core-scache.h>
#include <pulsecore/autoload.h>
#include <pulsecore/macro.h>
#include "cli-text.h"
@ -48,10 +48,9 @@ char *pa_module_list_to_string(pa_core *c) {
pa_strbuf *s;
pa_module *m;
uint32_t idx = PA_IDXSET_INVALID;
assert(c);
pa_assert(c);
s = pa_strbuf_new();
assert(s);
pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules));
@ -72,10 +71,9 @@ char *pa_client_list_to_string(pa_core *c) {
pa_strbuf *s;
pa_client *client;
uint32_t idx = PA_IDXSET_INVALID;
assert(c);
pa_assert(c);
s = pa_strbuf_new();
assert(s);
pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients));
@ -93,10 +91,15 @@ char *pa_sink_list_to_string(pa_core *c) {
pa_strbuf *s;
pa_sink *sink;
uint32_t idx = PA_IDXSET_INVALID;
assert(c);
static const char* const state_table[] = {
[PA_SINK_RUNNING] = "RUNNING",
[PA_SINK_SUSPENDED] = "SUSPENDED",
[PA_SINK_IDLE] = "IDLE",
[PA_SINK_UNLINKED] = "UNLINKED"
};
pa_assert(c);
s = pa_strbuf_new();
assert(s);
pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks));
@ -108,22 +111,35 @@ char *pa_sink_list_to_string(pa_core *c) {
" %c index: %u\n"
"\tname: <%s>\n"
"\tdriver: <%s>\n"
"\tflags: %s%s%s\n"
"\tstate: %s\n"
"\tvolume: <%s>\n"
"\tmute: <%i>\n"
"\tlatency: <%0.0f usec>\n"
"\tmonitor_source: <%u>\n"
"\tmonitor source: <%u>\n"
"\tsample spec: <%s>\n"
"\tchannel map: <%s>\n",
"\tchannel map: <%s>\n"
"\tused by: <%u>\n"
"\tlinked by: <%u>\n",
c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ',
sink->index, sink->name,
sink->index,
sink->name,
sink->driver,
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)),
sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
sink->flags & PA_SINK_LATENCY ? "LATENCY " : "",
sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
state_table[pa_sink_get_state(sink)],
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)),
!!pa_sink_get_mute(sink),
(double) pa_sink_get_latency(sink),
sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map));
pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map),
pa_sink_used_by(sink),
pa_sink_linked_by(sink));
if (sink->owner)
pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index);
if (sink->module)
pa_strbuf_printf(s, "\tmodule: <%u>\n", sink->module->index);
if (sink->description)
pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description);
}
@ -135,15 +151,20 @@ char *pa_source_list_to_string(pa_core *c) {
pa_strbuf *s;
pa_source *source;
uint32_t idx = PA_IDXSET_INVALID;
assert(c);
static const char* const state_table[] = {
[PA_SOURCE_RUNNING] = "RUNNING",
[PA_SOURCE_SUSPENDED] = "SUSPENDED",
[PA_SOURCE_IDLE] = "IDLE",
[PA_SOURCE_UNLINKED] = "UNLINKED"
};
pa_assert(c);
s = pa_strbuf_new();
assert(s);
pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources));
for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX];
pa_strbuf_printf(
@ -151,21 +172,35 @@ char *pa_source_list_to_string(pa_core *c) {
" %c index: %u\n"
"\tname: <%s>\n"
"\tdriver: <%s>\n"
"\tflags: %s%s%s\n"
"\tstate: %s\n"
"\tvolume: <%s>\n"
"\tmute: <%u>\n"
"\tlatency: <%0.0f usec>\n"
"\tsample spec: <%s>\n"
"\tchannel map: <%s>\n",
"\tchannel map: <%s>\n"
"\tused by: <%u>\n"
"\tlinked by: <%u>\n",
c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ',
source->index,
source->name,
source->driver,
source->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
source->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
state_table[pa_source_get_state(source)],
pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source)),
!!pa_source_get_mute(source),
(double) pa_source_get_latency(source),
pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map));
pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map),
pa_source_used_by(source),
pa_source_linked_by(source));
if (source->monitor_of)
pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index);
if (source->owner)
pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index);
if (source->module)
pa_strbuf_printf(s, "\tmodule: <%u>\n", source->module->index);
if (source->description)
pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description);
}
@ -179,37 +214,41 @@ char *pa_source_output_list_to_string(pa_core *c) {
pa_source_output *o;
uint32_t idx = PA_IDXSET_INVALID;
static const char* const state_table[] = {
"RUNNING",
"CORKED",
"DISCONNECTED"
[PA_SOURCE_OUTPUT_RUNNING] = "RUNNING",
[PA_SOURCE_OUTPUT_CORKED] = "CORKED",
[PA_SOURCE_OUTPUT_UNLINKED] = "UNLINKED"
};
assert(c);
pa_assert(c);
s = pa_strbuf_new();
assert(s);
pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs));
for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
assert(o->source);
pa_assert(o->source);
pa_strbuf_printf(
s,
" index: %u\n"
"\tname: '%s'\n"
"\tdriver: <%s>\n"
"\tflags: %s%s\n"
"\tstate: %s\n"
"\tsource: <%u> '%s'\n"
"\tlatency: <%0.0f usec>\n"
"\tsample spec: <%s>\n"
"\tchannel map: <%s>\n"
"\tresample method: %s\n",
o->index,
o->name,
o->driver,
state_table[o->state],
o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "",
o->flags & PA_SOURCE_OUTPUT_DONT_MOVE ? "DONT_MOVE " : "",
state_table[pa_source_output_get_state(o)],
o->source->index, o->source->name,
(double) pa_source_output_get_latency(o),
pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
pa_resample_method_to_string(pa_source_output_get_resample_method(o)));
@ -227,30 +266,32 @@ char *pa_sink_input_list_to_string(pa_core *c) {
pa_sink_input *i;
uint32_t idx = PA_IDXSET_INVALID;
static const char* const state_table[] = {
"RUNNING",
"CORKED",
"DISCONNECTED"
[PA_SINK_INPUT_RUNNING] = "RUNNING",
[PA_SINK_INPUT_DRAINED] = "DRAINED",
[PA_SINK_INPUT_CORKED] = "CORKED",
[PA_SINK_INPUT_UNLINKED] = "UNLINKED"
};
assert(c);
pa_assert(c);
s = pa_strbuf_new();
assert(s);
pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs));
for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
assert(i->sink);
pa_assert(i->sink);
pa_strbuf_printf(
s,
" index: %u\n"
"\tname: <%s>\n"
"\tdriver: <%s>\n"
"\tflags: %s%s\n"
"\tstate: %s\n"
"\tsink: <%u> '%s'\n"
"\tvolume: <%s>\n"
"\tmute: <%i>\n"
"\tlatency: <%0.0f usec>\n"
"\tsample spec: <%s>\n"
"\tchannel map: <%s>\n"
@ -258,16 +299,19 @@ char *pa_sink_input_list_to_string(pa_core *c) {
i->index,
i->name,
i->driver,
state_table[i->state],
i->flags & PA_SINK_INPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "",
i->flags & PA_SINK_INPUT_DONT_MOVE ? "DONT_MOVE " : "",
state_table[pa_sink_input_get_state(i)],
i->sink->index, i->sink->name,
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)),
!!pa_sink_input_get_mute(i),
(double) pa_sink_input_get_latency(i),
pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
pa_resample_method_to_string(pa_sink_input_get_resample_method(i)));
if (i->module)
pa_strbuf_printf(s, "\towner module: <%u>\n", i->module->index);
pa_strbuf_printf(s, "\tmodule: <%u>\n", i->module->index);
if (i->client)
pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name);
}
@ -277,10 +321,9 @@ char *pa_sink_input_list_to_string(pa_core *c) {
char *pa_scache_list_to_string(pa_core *c) {
pa_strbuf *s;
assert(c);
pa_assert(c);
s = pa_strbuf_new();
assert(s);
pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_size(c->scache) : 0);
@ -326,10 +369,9 @@ char *pa_scache_list_to_string(pa_core *c) {
char *pa_autoload_list_to_string(pa_core *c) {
pa_strbuf *s;
assert(c);
pa_assert(c);
s = pa_strbuf_new();
assert(s);
pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_size(c->autoload_hashmap) : 0);

View file

@ -27,7 +27,6 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <pulse/xmalloc.h>
@ -45,6 +44,7 @@
#include <pulsecore/cli-text.h>
#include <pulsecore/cli-command.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "cli.h"
@ -68,19 +68,17 @@ static void client_kill(pa_client *c);
pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) {
char cname[256];
pa_cli *c;
assert(io);
pa_assert(io);
c = pa_xmalloc(sizeof(pa_cli));
c = pa_xnew(pa_cli, 1);
c->core = core;
c->line = pa_ioline_new(io);
assert(c->line);
pa_assert_se(c->line = pa_ioline_new(io));
c->userdata = NULL;
c->eof_callback = NULL;
pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
c->client = pa_client_new(core, __FILE__, cname);
assert(c->client);
pa_assert_se(c->client = pa_client_new(core, __FILE__, cname));
c->client->kill = client_kill;
c->client->userdata = c;
c->client->owner = m;
@ -94,7 +92,8 @@ pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) {
}
void pa_cli_free(pa_cli *c) {
assert(c);
pa_assert(c);
pa_ioline_close(c->line);
pa_ioline_unref(c->line);
pa_client_free(c->client);
@ -103,8 +102,9 @@ void pa_cli_free(pa_cli *c) {
static void client_kill(pa_client *client) {
pa_cli *c;
assert(client && client->userdata);
c = client->userdata;
pa_assert(client);
pa_assert_se(c = client->userdata);
pa_log_debug("CLI client killed.");
if (c->defer_kill)
@ -119,7 +119,9 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
pa_strbuf *buf;
pa_cli *c = userdata;
char *p;
assert(line && c);
pa_assert(line);
pa_assert(c);
if (!s) {
pa_log_debug("CLI got EOF from user.");
@ -129,8 +131,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
return;
}
buf = pa_strbuf_new();
assert(buf);
pa_assert_se(buf = pa_strbuf_new());
c->defer_kill++;
pa_cli_command_execute_line(c->core, s, buf, &c->fail);
c->defer_kill--;
@ -145,7 +146,8 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
}
void pa_cli_set_eof_callback(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) {
assert(c);
pa_assert(c);
c->eof_callback = cb;
c->userdata = userdata;
}

View file

@ -27,7 +27,6 @@
#endif
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -35,15 +34,16 @@
#include <pulsecore/core-subscribe.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "client.h"
pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) {
pa_client *c;
int r;
assert(core);
c = pa_xmalloc(sizeof(pa_client));
pa_core_assert_ref(core);
c = pa_xnew(pa_client, 1);
c->name = pa_xstrdup(name);
c->driver = pa_xstrdup(driver);
c->owner = NULL;
@ -52,10 +52,9 @@ pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) {
c->kill = NULL;
c->userdata = NULL;
r = pa_idxset_put(core->clients, c, &c->index);
assert(c->index != PA_IDXSET_INVALID && r >= 0);
pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0);
pa_log_info("created %u \"%s\"", c->index, c->name);
pa_log_info("Created %u \"%s\"", c->index, c->name);
pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index);
pa_core_check_quit(core);
@ -64,13 +63,14 @@ pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) {
}
void pa_client_free(pa_client *c) {
assert(c && c->core);
pa_assert(c);
pa_assert(c->core);
pa_idxset_remove_by_data(c->core->clients, c, NULL);
pa_core_check_quit(c->core);
pa_log_info("freed %u \"%s\"", c->index, c->name);
pa_log_info("Freed %u \"%s\"", c->index, c->name);
pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
pa_xfree(c->name);
pa_xfree(c->driver);
@ -78,7 +78,8 @@ void pa_client_free(pa_client *c) {
}
void pa_client_kill(pa_client *c) {
assert(c);
pa_assert(c);
if (!c->kill) {
pa_log_warn("kill() operation not implemented for client %u", c->index);
return;
@ -88,9 +89,9 @@ void pa_client_kill(pa_client *c) {
}
void pa_client_set_name(pa_client *c, const char *name) {
assert(c);
pa_assert(c);
pa_log_info("client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name);
pa_log_info("Client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name);
pa_xfree(c->name);
c->name = pa_xstrdup(name);

View file

@ -25,7 +25,6 @@
#include <config.h>
#endif
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
@ -35,6 +34,7 @@
#include <pulsecore/core-error.h>
#include <pulsecore/log.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include "conf-parser.h"
@ -43,7 +43,10 @@
/* Run the user supplied parser for an assignment */
static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) {
assert(filename && t && lvalue && rvalue);
pa_assert(filename);
pa_assert(t);
pa_assert(lvalue);
pa_assert(rvalue);
for (; t->parse; t++)
if (!strcmp(lvalue, t->lvalue))
@ -56,7 +59,7 @@ static int next_assignment(const char *filename, unsigned line, const pa_config_
/* Returns non-zero when c is contained in s */
static int in_string(char c, const char *s) {
assert(s);
pa_assert(s);
for (; *s; s++)
if (*s == c)
@ -107,7 +110,9 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void
int r = -1;
unsigned line = 0;
int do_close = !f;
assert(filename && t);
pa_assert(filename);
pa_assert(t);
if (!f && !(f = fopen(filename, "r"))) {
if (errno == ENOENT) {
@ -115,7 +120,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void
goto finish;
}
pa_log_warn("WARNING: failed to open configuration file '%s': %s",
pa_log_warn("Failed to open configuration file '%s': %s",
filename, pa_cstrerror(errno));
goto finish;
}
@ -126,7 +131,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void
if (feof(f))
break;
pa_log_warn("WARNING: failed to read configuration file '%s': %s",
pa_log_warn("Failed to read configuration file '%s': %s",
filename, pa_cstrerror(errno));
goto finish;
}
@ -148,7 +153,11 @@ finish:
int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
int *i = data;
int32_t k;
assert(filename && lvalue && rvalue && data);
pa_assert(filename);
pa_assert(lvalue);
pa_assert(rvalue);
pa_assert(data);
if (pa_atoi(rvalue, &k) < 0) {
pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
@ -161,7 +170,11 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue,
int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
int *b = data, k;
assert(filename && lvalue && rvalue && data);
pa_assert(filename);
pa_assert(lvalue);
pa_assert(rvalue);
pa_assert(data);
if ((k = pa_parse_boolean(rvalue)) < 0) {
pa_log("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
@ -175,7 +188,11 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue
int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
char **s = data;
assert(filename && lvalue && rvalue && data);
pa_assert(filename);
pa_assert(lvalue);
pa_assert(rvalue);
pa_assert(data);
pa_xfree(*s);
*s = *rvalue ? pa_xstrdup(rvalue) : NULL;

View file

@ -24,9 +24,6 @@
USA.
***/
typedef enum pa_mixer {
PA_MIXER_SOFTWARE,
PA_MIXER_HARDWARE
} pa_mixer_t;
/* FIXME: Remove this shit */
#endif

View file

@ -31,178 +31,50 @@
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include <pulse/utf8.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core-util.h>
#include <pulsecore/native-common.h>
#include <pulsecore/thread.h>
#include <pulsecore/macro.h>
#include <pulsecore/log.h>
#include "core-error.h"
#ifdef HAVE_PTHREAD
static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT;
static pthread_key_t tlsstr_key;
static void inittls(void) {
int ret;
ret = pthread_key_create(&tlsstr_key, pa_xfree);
if (ret) {
fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno);
exit(-1);
}
}
#elif HAVE_WINDOWS_H
static DWORD tlsstr_key = TLS_OUT_OF_INDEXES;
static DWORD monitor_key = TLS_OUT_OF_INDEXES;
static void inittls(void) {
HANDLE mutex;
char name[64];
sprintf(name, "pulse%d", (int)GetCurrentProcessId());
mutex = CreateMutex(NULL, FALSE, name);
if (!mutex) {
fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError());
exit(-1);
}
WaitForSingleObject(mutex, INFINITE);
if (tlsstr_key == TLS_OUT_OF_INDEXES) {
tlsstr_key = TlsAlloc();
monitor_key = TlsAlloc();
if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) {
fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError());
exit(-1);
}
}
ReleaseMutex(mutex);
CloseHandle(mutex);
}
/*
* This is incredibly brain dead, but this is necessary when dealing with
* the hell that is Win32.
*/
struct monitor_data {
HANDLE thread;
void *data;
};
static DWORD WINAPI monitor_thread(LPVOID param) {
struct monitor_data *data;
data = (struct monitor_data*)param;
assert(data);
WaitForSingleObject(data->thread, INFINITE);
CloseHandle(data->thread);
pa_xfree(data->data);
pa_xfree(data);
return 0;
}
static void start_monitor(void) {
HANDLE thread;
struct monitor_data *data;
data = pa_xnew(struct monitor_data, 1);
assert(data);
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS);
thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL);
assert(thread);
TlsSetValue(monitor_key, data);
CloseHandle(thread);
}
#else
/* Unsafe, but we have no choice */
static char *tlsstr;
#endif
PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
const char* pa_cstrerror(int errnum) {
const char *origbuf;
#ifdef HAVE_STRERROR_R
const char *original = NULL;
char *translated, *t;
char errbuf[128];
#endif
#ifdef HAVE_PTHREAD
char *tlsstr;
if ((t = PA_STATIC_TLS_GET(cstrerror)))
pa_xfree(t);
pthread_once(&cstrerror_once, inittls);
tlsstr = pthread_getspecific(tlsstr_key);
#elif defined(HAVE_WINDOWS_H)
char *tlsstr;
struct monitor_data *data;
inittls();
tlsstr = TlsGetValue(tlsstr_key);
if (!tlsstr)
start_monitor();
data = TlsGetValue(monitor_key);
#endif
if (tlsstr)
pa_xfree(tlsstr);
#ifdef HAVE_STRERROR_R
#ifdef __GLIBC__
origbuf = strerror_r(errnum, errbuf, sizeof(errbuf));
if (origbuf == NULL)
origbuf = "";
#else
#if defined(HAVE_STRERROR_R) && defined(__GLIBC__)
original = strerror_r(errnum, errbuf, sizeof(errbuf));
#elif defined(HAVE_STRERROR_R)
if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) {
origbuf = errbuf;
errbuf[sizeof(errbuf) - 1] = '\0';
} else
origbuf = "";
#endif
errbuf[sizeof(errbuf) - 1] = 0;
original = errbuf;
}
#else
/* This might not be thread safe, but we hope for the best */
origbuf = strerror(errnum);
original = strerror(errnum);
#endif
tlsstr = pa_locale_to_utf8(origbuf);
if (!tlsstr) {
fprintf(stderr, "Unable to convert, filtering\n");
tlsstr = pa_utf8_filter(origbuf);
if (!original) {
pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
original = errbuf;
}
#ifdef HAVE_PTHREAD
pthread_setspecific(tlsstr_key, tlsstr);
#elif defined(HAVE_WINDOWS_H)
TlsSetValue(tlsstr_key, tlsstr);
data->data = tlsstr;
#endif
if (!(translated = pa_locale_to_utf8(original))) {
pa_log_warn("Unable to convert error string to locale, filtering.");
translated = pa_utf8_filter(original);
}
return tlsstr;
PA_STATIC_TLS_SET(cstrerror, translated);
return translated;
}

View file

@ -26,7 +26,6 @@
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@ -60,6 +59,7 @@
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/core-error.h>
#include <pulsecore/macro.h>
#include "core-scache.h"
@ -68,7 +68,10 @@
static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
pa_core *c = userdata;
struct timeval ntv;
assert(c && c->mainloop == m && c->scache_auto_unload_event == e);
pa_assert(c);
pa_assert(c->mainloop == m);
pa_assert(c->scache_auto_unload_event == e);
pa_scache_unload_unused(c);
@ -78,7 +81,8 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED
}
static void free_entry(pa_scache_entry *e) {
assert(e);
pa_assert(e);
pa_namereg_unregister(e->core, e->name);
pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index);
pa_xfree(e->name);
@ -90,7 +94,9 @@ static void free_entry(pa_scache_entry *e) {
static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
pa_scache_entry *e;
assert(c && name);
pa_assert(c);
pa_assert(name);
if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) {
if (e->memchunk.memblock)
@ -98,11 +104,11 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
pa_xfree(e->filename);
assert(e->core == c);
pa_assert(e->core == c);
pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index);
} else {
e = pa_xmalloc(sizeof(pa_scache_entry));
e = pa_xnew(pa_scache_entry, 1);
if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) {
pa_xfree(e);
@ -114,7 +120,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
if (!c->scache) {
c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
assert(c->scache);
pa_assert(c->scache);
}
pa_idxset_put(c->scache, e, &e->index);
@ -139,7 +145,9 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) {
pa_scache_entry *e;
char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
assert(c && name);
pa_assert(c);
pa_assert(name);
if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX)
return -1;
@ -164,9 +172,9 @@ int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, c
if (idx)
*idx = e->index;
pa_log_debug("created sample \"%s\" (#%d), %d bytes with sample spec %s",
name, e->index, e->memchunk.length,
pa_sample_spec_snprint(st, sizeof(st), &e->sample_spec));
pa_log_debug("Created sample \"%s\" (#%d), %lu bytes with sample spec %s",
name, e->index, (unsigned long) e->memchunk.length,
pa_sample_spec_snprint(st, sizeof(st), &e->sample_spec));
return 0;
}
@ -184,6 +192,10 @@ int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint3
filename = buf;
#endif
pa_assert(c);
pa_assert(name);
pa_assert(filename);
if (pa_sound_file_load(c->mempool, filename, &ss, &map, &chunk) < 0)
return -1;
@ -203,7 +215,9 @@ int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename,
filename = buf;
#endif
assert(c && name);
pa_assert(c);
pa_assert(name);
pa_assert(filename);
if (!(e = scache_add_item(c, name)))
return -1;
@ -226,15 +240,17 @@ int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename,
int pa_scache_remove_item(pa_core *c, const char *name) {
pa_scache_entry *e;
assert(c && name);
pa_assert(c);
pa_assert(name);
if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
return -1;
if (pa_idxset_remove_by_data(c->scache, e, NULL) != e)
assert(0);
pa_assert(0);
pa_log_debug("removed sample \"%s\"", name);
pa_log_debug("Removed sample \"%s\"", name);
free_entry(e);
@ -243,12 +259,13 @@ int pa_scache_remove_item(pa_core *c, const char *name) {
static void free_cb(void *p, PA_GCC_UNUSED void *userdata) {
pa_scache_entry *e = p;
assert(e);
pa_assert(e);
free_entry(e);
}
void pa_scache_free(pa_core *c) {
assert(c);
pa_assert(c);
if (c->scache) {
pa_idxset_free(c->scache, free_cb, NULL);
@ -264,9 +281,9 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t
char *t;
pa_cvolume r;
assert(c);
assert(name);
assert(sink);
pa_assert(c);
pa_assert(name);
pa_assert(sink);
if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1)))
return -1;
@ -284,7 +301,7 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t
if (!e->memchunk.memblock)
return -1;
pa_log_debug("playing sample \"%s\" on \"%s\"", name, sink->name);
pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name);
t = pa_sprintf_malloc("sample:%s", name);
@ -304,9 +321,23 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t
return 0;
}
int pa_scache_play_item_by_name(pa_core *c, const char *name, const char*sink_name, pa_volume_t volume, int autoload) {
pa_sink *sink;
pa_assert(c);
pa_assert(name);
if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, autoload)))
return -1;
return pa_scache_play_item(c, name, sink, volume);
}
const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) {
pa_scache_entry *e;
assert(c && id != PA_IDXSET_INVALID);
pa_assert(c);
pa_assert(id != PA_IDXSET_INVALID);
if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id)))
return NULL;
@ -316,7 +347,9 @@ const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) {
uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) {
pa_scache_entry *e;
assert(c && name);
pa_assert(c);
pa_assert(name);
if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
return PA_IDXSET_INVALID;
@ -327,7 +360,8 @@ uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) {
uint32_t pa_scache_total_size(pa_core *c) {
pa_scache_entry *e;
uint32_t idx, sum = 0;
assert(c);
pa_assert(c);
if (!c->scache || !pa_idxset_size(c->scache))
return 0;
@ -343,7 +377,8 @@ void pa_scache_unload_unused(pa_core *c) {
pa_scache_entry *e;
time_t now;
uint32_t idx;
assert(c);
pa_assert(c);
if (!c->scache || !pa_idxset_size(c->scache))
return;
@ -370,6 +405,9 @@ static void add_file(pa_core *c, const char *pathname) {
struct stat st;
const char *e;
pa_core_assert_ref(c);
pa_assert(pathname);
e = pa_path_get_filename(pathname);
if (stat(pathname, &st) < 0) {
@ -385,7 +423,9 @@ static void add_file(pa_core *c, const char *pathname) {
int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) {
DIR *dir;
assert(c && pathname);
pa_core_assert_ref(c);
pa_assert(pathname);
/* First try to open this as directory */
if (!(dir = opendir(pathname))) {
@ -415,7 +455,7 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) {
if (e->d_name[0] == '.')
continue;
snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name);
pa_snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name);
add_file(c, p);
}
}

View file

@ -55,6 +55,7 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname);
int pa_scache_remove_item(pa_core *c, const char *name);
int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume);
int pa_scache_play_item_by_name(pa_core *c, const char *name, const char*sink_name, pa_volume_t volume, int autoload);
void pa_scache_free(pa_core *c);
const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id);

View file

@ -26,12 +26,12 @@
#endif
#include <stdio.h>
#include <assert.h>
#include <pulse/xmalloc.h>
#include <pulsecore/queue.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "core-subscribe.h"
@ -68,9 +68,9 @@ static void sched_event(pa_core *c);
pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_subscription_cb_t callback, void *userdata) {
pa_subscription *s;
assert(c);
assert(m);
assert(callback);
pa_assert(c);
pa_assert(m);
pa_assert(callback);
s = pa_xnew(pa_subscription, 1);
s->core = c;
@ -85,24 +85,24 @@ pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_su
/* Free a subscription object, effectively marking it for deletion */
void pa_subscription_free(pa_subscription*s) {
assert(s);
assert(!s->dead);
pa_assert(s);
pa_assert(!s->dead);
s->dead = 1;
sched_event(s->core);
}
static void free_subscription(pa_subscription *s) {
assert(s);
assert(s->core);
pa_assert(s);
pa_assert(s->core);
PA_LLIST_REMOVE(pa_subscription, s->core->subscriptions, s);
pa_xfree(s);
}
static void free_event(pa_subscription_event *s) {
assert(s);
assert(s->core);
pa_assert(s);
pa_assert(s->core);
if (!s->next)
s->core->subscription_event_last = s->prev;
@ -113,7 +113,7 @@ static void free_event(pa_subscription_event *s) {
/* Free all subscription objects */
void pa_subscription_free_all(pa_core *c) {
assert(c);
pa_assert(c);
while (c->subscriptions)
free_subscription(c->subscriptions);
@ -160,9 +160,9 @@ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) {
pa_core *c = userdata;
pa_subscription *s;
assert(c->mainloop == m);
assert(c);
assert(c->subscription_defer_event == de);
pa_assert(c->mainloop == m);
pa_assert(c);
pa_assert(c->subscription_defer_event == de);
c->mainloop->defer_enable(c->subscription_defer_event, 0);
@ -196,20 +196,20 @@ static void defer_cb(pa_mainloop_api *m, pa_defer_event *de, void *userdata) {
/* Schedule an mainloop event so that a pending subscription event is dispatched */
static void sched_event(pa_core *c) {
assert(c);
pa_assert(c);
if (!c->subscription_defer_event) {
c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c);
assert(c->subscription_defer_event);
pa_assert(c->subscription_defer_event);
}
c->mainloop->defer_enable(c->subscription_defer_event, 1);
}
/* Append a new subscription event to the subscription event queue and schedule a main loop event */
void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) {
void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx) {
pa_subscription_event *e;
assert(c);
pa_assert(c);
/* No need for queuing subscriptions of noone is listening */
if (!c->subscriptions)
@ -227,7 +227,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i
continue;
/* not the same object */
if (i->index != index)
if (i->index != idx)
continue;
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
@ -253,7 +253,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i
e = pa_xnew(pa_subscription_event, 1);
e->core = c;
e->type = t;
e->index = index;
e->index = idx;
PA_LLIST_INSERT_AFTER(pa_subscription_event, c->subscription_event_queue, c->subscription_event_last, e);
c->subscription_event_last = e;

View file

@ -31,7 +31,6 @@
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
@ -43,6 +42,10 @@
#include <sys/stat.h>
#include <sys/time.h>
#ifdef HAVE_STRTOF_L
#include <locale.h>
#endif
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
@ -55,6 +58,10 @@
#include <sys/capability.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
@ -75,14 +82,19 @@
#include <grp.h>
#endif
#ifdef HAVE_LIBSAMPLERATE
#include <samplerate.h>
#endif
#include <pulse/xmalloc.h>
#include <pulse/util.h>
#include <pulse/utf8.h>
#include <pulsecore/core-error.h>
#include <pulsecore/winsock.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/thread.h>
#include "core-util.h"
@ -93,10 +105,8 @@
#ifndef OS_IS_WIN32
#define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
#define PATH_SEP '/'
#else
#define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
#define PATH_SEP '\\'
#endif
#ifdef OS_IS_WIN32
@ -111,7 +121,7 @@ int pa_set_root(HANDLE handle) {
if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
return 0;
sep = strrchr(library_path, '\\');
sep = strrchr(library_path, PA_PATH_SEP_CHAR);
if (sep)
*sep = '\0';
@ -124,23 +134,42 @@ int pa_set_root(HANDLE handle) {
#endif
/** Make a file descriptor nonblock. Doesn't do any error checking */
void pa_make_nonblock_fd(int fd) {
void pa_make_fd_nonblock(int fd) {
#ifdef O_NONBLOCK
int v;
assert(fd >= 0);
pa_assert(fd >= 0);
pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0);
if (!(v & O_NONBLOCK))
pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 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("WARNING: Only sockets can be made non-blocking!");
pa_assert_se(WSAGetLastError() == WSAENOTSOCK);
pa_log_warn("Only sockets can be made non-blocking!");
}
#else
pa_log_warn("WARNING: Non-blocking I/O not supported.!");
pa_log_warn("Non-blocking I/O not supported.!");
#endif
}
/* Set the FD_CLOEXEC flag for a fd */
void pa_make_fd_cloexec(int fd) {
#ifdef FD_CLOEXEC
int v;
pa_assert(fd >= 0);
pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0);
if (!(v & FD_CLOEXEC))
pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0);
#endif
}
/** Creates a directory securely */
@ -148,7 +177,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
struct stat st;
int r;
assert(dir);
pa_assert(dir);
#ifdef OS_IS_WIN32
r = mkdir(dir);
@ -169,7 +198,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
uid = getuid();
if (gid == (gid_t)-1)
gid = getgid();
chown(dir, uid, gid);
(void) chown(dir, uid, gid);
#endif
#ifdef HAVE_CHMOD
@ -295,9 +324,9 @@ ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) {
ssize_t ret = 0;
int _type;
assert(fd >= 0);
assert(data);
assert(size);
pa_assert(fd >= 0);
pa_assert(data);
pa_assert(size);
if (!type) {
_type = 0;
@ -326,9 +355,9 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
ssize_t ret = 0;
int _type;
assert(fd >= 0);
assert(data);
assert(size);
pa_assert(fd >= 0);
pa_assert(data);
pa_assert(size);
if (!type) {
_type = 0;
@ -354,13 +383,12 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) {
/** Platform independent read function. Necessary since not all
* systems treat all file descriptors equal. */
int pa_close(int fd)
{
int pa_close(int fd) {
#ifdef OS_IS_WIN32
int ret;
ret = closesocket(fd);
if (ret == 0)
if ((ret = closesocket(fd)) == 0)
return 0;
if (WSAGetLastError() != WSAENOTSOCK) {
@ -407,9 +435,9 @@ void pa_check_signal_is_blocked(int sig) {
if (sa.sa_handler != SIG_DFL)
return;
pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig));
pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig));
#else /* HAVE_SIGACTION */
pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig));
pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig));
#endif
}
@ -419,7 +447,7 @@ char *pa_sprintf_malloc(const char *format, ...) {
int size = 100;
char *c = NULL;
assert(format);
pa_assert(format);
for(;;) {
int r;
@ -431,6 +459,8 @@ char *pa_sprintf_malloc(const char *format, ...) {
r = vsnprintf(c, size, format, ap);
va_end(ap);
c[size-1] = 0;
if (r > -1 && r < size)
return c;
@ -447,19 +477,20 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) {
int size = 100;
char *c = NULL;
assert(format);
pa_assert(format);
for(;;) {
int r;
va_list aq;
va_copy(aq, ap);
c = pa_xrealloc(c, size);
r = vsnprintf(c, size, format, aq);
va_copy(aq, ap);
r = vsnprintf(c, size, format, aq);
va_end(aq);
c[size-1] = 0;
if (r > -1 && r < size)
return c;
@ -472,35 +503,46 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) {
/* Similar to OpenBSD's strlcpy() function */
char *pa_strlcpy(char *b, const char *s, size_t l) {
assert(b && s && l > 0);
pa_assert(b);
pa_assert(s);
pa_assert(l > 0);
strncpy(b, s, l);
b[l-1] = 0;
return b;
}
#define NICE_LEVEL (-15)
/* Make the current thread a realtime thread*/
void pa_make_realtime(void) {
#ifdef _POSIX_PRIORITY_SCHEDULING
struct sched_param sp;
int r, policy;
memset(&sp, 0, sizeof(sp));
policy = 0;
if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
return;
}
sp.sched_priority = 1;
if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
return;
}
pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread.");
#endif
}
#define NICE_LEVEL (-11)
/* Raise the priority of the current process as much as possible and
sensible: set the nice level to -15 and enable realtime scheduling if
supported.*/
sensible: set the nice level to -15.*/
void pa_raise_priority(void) {
#if defined(HAVE_SYS_CAPABILITY_H)
cap_t caps;
/* Temporarily acquire CAP_SYS_NICE in the effective set */
if ((caps = cap_get_proc())) {
cap_t caps_new;
cap_value_t nice_cap = CAP_SYS_NICE;
if ((caps_new = cap_dup(caps))) {
cap_set_flag(caps_new, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET);
cap_set_flag(caps_new, CAP_PERMITTED, 1, &nice_cap, CAP_SET);
cap_set_proc(caps_new);
cap_free(caps_new);
}
}
#endif
#ifdef HAVE_SYS_RESOURCE_H
if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
@ -509,86 +551,26 @@ void pa_raise_priority(void) {
pa_log_info("Successfully gained nice level %i.", NICE_LEVEL);
#endif
#ifdef _POSIX_PRIORITY_SCHEDULING
{
struct sched_param sp;
if (sched_getparam(0, &sp) < 0) {
pa_log("sched_getparam(): %s", pa_cstrerror(errno));
goto fail;
}
sp.sched_priority = 1;
if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) {
pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno));
goto fail;
}
pa_log_info("Successfully enabled SCHED_FIFO scheduling.");
}
#endif
#ifdef OS_IS_WIN32
if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
else
pa_log_info("Successfully gained high priority class.");
#endif
fail:
#if defined(HAVE_SYS_CAPABILITY_H)
if (caps) {
/* Restore original caps */
cap_set_proc(caps);
cap_free(caps);
}
#endif
; /* We put this here to get the code to compile when
* HAVE_SYS_CAPABILITY_H is not defined. Don't remove unless you
* know what you do */
}
/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
/* 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;
sched_getparam(0, &sp);
sp.sched_priority = 0;
sched_setscheduler(0, SCHED_OTHER, &sp);
}
#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);
if ((v = fcntl(fd, F_GETFD, 0)) < 0)
return -1;
v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0);
if (fcntl(fd, F_SETFD, v) < 0)
return -1;
#endif
return 0;
}
/* Try to parse a boolean string value.*/
int pa_parse_boolean(const char *v) {
@ -639,31 +621,134 @@ char *pa_split_spaces(const char *c, const char **state) {
return pa_xstrndup(current, l);
}
/* Return the name of an UNIX signal. Similar to GNU's strsignal() */
const char *pa_strsignal(int sig) {
PA_STATIC_TLS_DECLARE(signame, pa_xfree);
/* Return the name of an UNIX signal. Similar to Solaris sig2str() */
const char *pa_sig2str(int sig) {
char *t;
if (sig <= 0)
goto fail;
#ifdef NSIG
if (sig >= NSIG)
goto fail;
#endif
#ifdef HAVE_SIG2STR
{
char buf[SIG2STR_MAX];
if (sig2str(sig, buf) == 0) {
pa_xfree(PA_STATIC_TLS_GET(signame));
t = pa_sprintf_malloc("SIG%s", buf);
PA_STATIC_TLS_SET(signame, t);
return t;
}
}
#else
switch(sig) {
case SIGINT: return "SIGINT";
case SIGTERM: return "SIGTERM";
#ifdef SIGHUP
case SIGHUP: return "SIGHUP";
#endif
case SIGINT: return "SIGINT";
#ifdef SIGQUIT
case SIGQUIT: return "SIGQUIT";
#endif
case SIGILL: return "SIGULL";
#ifdef SIGTRAP
case SIGTRAP: return "SIGTRAP";
#endif
case SIGABRT: return "SIGABRT";
#ifdef SIGBUS
case SIGBUS: return "SIGBUS";
#endif
case SIGFPE: return "SIGFPE";
#ifdef SIGKILL
case SIGKILL: return "SIGKILL";
#endif
#ifdef SIGUSR1
case SIGUSR1: return "SIGUSR1";
case SIGUSR1: return "SIGUSR1";
#endif
case SIGSEGV: return "SIGSEGV";
#ifdef SIGUSR2
case SIGUSR2: return "SIGUSR2";
#endif
#ifdef SIGXCPU
case SIGXCPU: return "SIGXCPU";
case SIGUSR2: return "SIGUSR2";
#endif
#ifdef SIGPIPE
case SIGPIPE: return "SIGPIPE";
case SIGPIPE: return "SIGPIPE";
#endif
#ifdef SIGALRM
case SIGALRM: return "SIGALRM";
#endif
case SIGTERM: return "SIGTERM";
#ifdef SIGSTKFLT
case SIGSTKFLT: return "SIGSTKFLT";
#endif
#ifdef SIGCHLD
case SIGCHLD: return "SIGCHLD";
case SIGCHLD: return "SIGCHLD";
#endif
#ifdef SIGHUP
case SIGHUP: return "SIGHUP";
#ifdef SIGCONT
case SIGCONT: return "SIGCONT";
#endif
#ifdef SIGSTOP
case SIGSTOP: return "SIGSTOP";
#endif
#ifdef SIGTSTP
case SIGTSTP: return "SIGTSTP";
#endif
#ifdef SIGTTIN
case SIGTTIN: return "SIGTTIN";
#endif
#ifdef SIGTTOU
case SIGTTOU: return "SIGTTOU";
#endif
#ifdef SIGURG
case SIGURG: return "SIGURG";
#endif
#ifdef SIGXCPU
case SIGXCPU: return "SIGXCPU";
#endif
#ifdef SIGXFSZ
case SIGXFSZ: return "SIGXFSZ";
#endif
#ifdef SIGVTALRM
case SIGVTALRM: return "SIGVTALRM";
#endif
#ifdef SIGPROF
case SIGPROF: return "SIGPROF";
#endif
#ifdef SIGWINCH
case SIGWINCH: return "SIGWINCH";
#endif
#ifdef SIGIO
case SIGIO: return "SIGIO";
#endif
#ifdef SIGPWR
case SIGPWR: return "SIGPWR";
#endif
#ifdef SIGSYS
case SIGSYS: return "SIGSYS";
#endif
default: return "UNKNOWN SIGNAL";
}
#ifdef SIGRTMIN
if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
pa_xfree(PA_STATIC_TLS_GET(signame));
t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN);
PA_STATIC_TLS_SET(signame, t);
return t;
}
#endif
#endif
fail:
pa_xfree(PA_STATIC_TLS_GET(signame));
t = pa_sprintf_malloc("SIG%i", sig);
PA_STATIC_TLS_SET(signame, t);
return t;
}
#ifdef HAVE_GRP_H
@ -715,7 +800,7 @@ int pa_own_uid_in_group(const char *name, gid_t *gid) {
int n = sysconf(_SC_NGROUPS_MAX);
int r = -1, i;
assert(n > 0);
pa_assert(n > 0);
gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
@ -861,8 +946,7 @@ int pa_lock_fd(int fd, int b) {
return 0;
}
pa_log("%slock: %s", !b? "un" : "",
pa_cstrerror(errno));
pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno));
#endif
#ifdef OS_IS_WIN32
@ -881,7 +965,7 @@ int pa_lock_fd(int fd, int b) {
/* Remove trailing newlines from a string */
char* pa_strip_nl(char *s) {
assert(s);
pa_assert(s);
s[strcspn(s, "\r\n")] = 0;
return s;
@ -890,38 +974,46 @@ char* pa_strip_nl(char *s) {
/* Create a temporary lock file and lock it. */
int pa_lock_lockfile(const char *fn) {
int fd = -1;
assert(fn);
pa_assert(fn);
for (;;) {
struct stat st;
if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
pa_log("failed to create lock file '%s': %s", fn,
pa_cstrerror(errno));
if ((fd = open(fn, O_CREAT|O_RDWR
#ifdef O_NOCTTY
|O_NOCTTY
#endif
#ifdef O_NOFOLLOW
|O_NOFOLLOW
#endif
, S_IRUSR|S_IWUSR)) < 0) {
pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno));
goto fail;
}
if (pa_lock_fd(fd, 1) < 0) {
pa_log("failed to lock file '%s'.", fn);
pa_log_warn("Failed to lock file '%s'.", fn);
goto fail;
}
if (fstat(fd, &st) < 0) {
pa_log("failed to fstat() file '%s'.", fn);
pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno));
goto fail;
}
/* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */
/* Check wheter the file has been removed meanwhile. When yes,
* restart this loop, otherwise, we're done */
if (st.st_nlink >= 1)
break;
if (pa_lock_fd(fd, 0) < 0) {
pa_log("failed to unlock file '%s'.", fn);
pa_log_warn("Failed to unlock file '%s'.", fn);
goto fail;
}
if (close(fd) < 0) {
pa_log("failed to close file '%s'.", fn);
if (pa_close(fd) < 0) {
pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
fd = -1;
goto fail;
}
@ -933,7 +1025,7 @@ int pa_lock_lockfile(const char *fn) {
fail:
if (fd >= 0)
close(fd);
pa_close(fd);
return -1;
}
@ -941,22 +1033,21 @@ fail:
/* Unlock a temporary lcok file */
int pa_unlock_lockfile(const char *fn, int fd) {
int r = 0;
assert(fn && fd >= 0);
pa_assert(fn);
pa_assert(fd >= 0);
if (unlink(fn) < 0) {
pa_log_warn("WARNING: unable to remove lock file '%s': %s",
fn, pa_cstrerror(errno));
pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
r = -1;
}
if (pa_lock_fd(fd, 0) < 0) {
pa_log_warn("WARNING: failed to unlock file '%s'.", fn);
pa_log_warn("Failed to unlock file '%s'.", fn);
r = -1;
}
if (close(fd) < 0) {
pa_log_warn("WARNING: failed to close lock file '%s': %s",
fn, pa_cstrerror(errno));
if (pa_close(fd) < 0) {
pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno));
r = -1;
}
@ -1019,10 +1110,8 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
return f;
}
if (errno != ENOENT) {
pa_log_warn("WARNING: failed to open configuration file '%s': %s",
lfn, pa_cstrerror(errno));
}
if (errno != ENOENT)
pa_log_warn("Failed to open configuration file '%s': %s", lfn, pa_cstrerror(errno));
pa_xfree(lfn);
}
@ -1051,7 +1140,10 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
size_t i = 0, j = 0;
const char hex[] = "0123456789abcdef";
assert(d && s && slength > 0);
pa_assert(d);
pa_assert(s);
pa_assert(slength > 0);
while (i < dlength && j+3 <= slength) {
s[j++] = hex[*d >> 4];
@ -1082,7 +1174,9 @@ static int hexc(char c) {
/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
size_t j = 0;
assert(p && d);
pa_assert(p);
pa_assert(d);
while (j < dlength && *p) {
int b;
@ -1109,8 +1203,8 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
int pa_startswith(const char *s, const char *pfx) {
size_t l;
assert(s);
assert(pfx);
pa_assert(s);
pa_assert(pfx);
l = strlen(pfx);
@ -1121,8 +1215,8 @@ int pa_startswith(const char *s, const char *pfx) {
int pa_endswith(const char *s, const char *sfx) {
size_t l1, l2;
assert(s);
assert(sfx);
pa_assert(s);
pa_assert(sfx);
l1 = strlen(s);
l2 = strlen(sfx);
@ -1146,17 +1240,17 @@ char *pa_runtime_path(const char *fn, char *s, size_t l) {
if ((e = getenv("PULSE_RUNTIME_PATH"))) {
if (fn)
snprintf(s, l, "%s%c%s", e, PATH_SEP, fn);
pa_snprintf(s, l, "%s%c%s", e, PA_PATH_SEP_CHAR, fn);
else
snprintf(s, l, "%s", e);
pa_snprintf(s, l, "%s", e);
} else {
char u[256];
if (fn)
snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
pa_snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PA_PATH_SEP_CHAR, fn);
else
snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
pa_snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
}
@ -1175,11 +1269,17 @@ char *pa_runtime_path(const char *fn, char *s, size_t l) {
int pa_atoi(const char *s, int32_t *ret_i) {
char *x = NULL;
long l;
assert(s && ret_i);
pa_assert(s);
pa_assert(ret_i);
errno = 0;
l = strtol(s, &x, 0);
if (!x || *x)
if (!x || *x || errno != 0)
return -1;
if ((int32_t) l != l)
return -1;
*ret_i = (int32_t) l;
@ -1191,14 +1291,219 @@ int pa_atoi(const char *s, int32_t *ret_i) {
int pa_atou(const char *s, uint32_t *ret_u) {
char *x = NULL;
unsigned long l;
assert(s && ret_u);
pa_assert(s);
pa_assert(ret_u);
errno = 0;
l = strtoul(s, &x, 0);
if (!x || *x)
if (!x || *x || errno != 0)
return -1;
if ((uint32_t) l != l)
return -1;
*ret_u = (uint32_t) l;
return 0;
}
#ifdef HAVE_STRTOF_L
static locale_t c_locale = NULL;
static void c_locale_destroy(void) {
freelocale(c_locale);
}
#endif
int pa_atof(const char *s, float *ret_f) {
char *x = NULL;
float f;
int r = 0;
pa_assert(s);
pa_assert(ret_f);
/* This should be locale independent */
#ifdef HAVE_STRTOF_L
PA_ONCE_BEGIN {
if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL)))
atexit(c_locale_destroy);
} PA_ONCE_END;
if (c_locale) {
errno = 0;
f = strtof_l(s, &x, c_locale);
} else
#endif
{
errno = 0;
#ifdef HAVE_STRTOF
f = strtof(s, &x);
#else
f = strtod(s, &x);
#endif
}
if (!x || *x || errno != 0)
r = -1;
else
*ret_f = f;
return r;
}
/* Same as snprintf, but guarantees NUL-termination on every platform */
int pa_snprintf(char *str, size_t size, const char *format, ...) {
int ret;
va_list ap;
pa_assert(str);
pa_assert(size > 0);
pa_assert(format);
va_start(ap, format);
ret = vsnprintf(str, size, format, ap);
va_end(ap);
str[size-1] = 0;
return ret;
}
/* Truncate the specified string, but guarantee that the string
* returned still validates as UTF8 */
char *pa_truncate_utf8(char *c, size_t l) {
pa_assert(c);
pa_assert(pa_utf8_valid(c));
if (strlen(c) <= l)
return c;
c[l] = 0;
while (l > 0 && !pa_utf8_valid(c))
c[--l] = 0;
return c;
}
char *pa_getcwd(void) {
size_t l = 128;
for (;;) {
char *p = pa_xnew(char, l);
if (getcwd(p, l))
return p;
if (errno != ERANGE)
return NULL;
pa_xfree(p);
l *= 2;
}
}
char *pa_make_path_absolute(const char *p) {
char *r;
char *cwd;
pa_assert(p);
if (p[0] == '/')
return pa_xstrdup(p);
if (!(cwd = pa_getcwd()))
return pa_xstrdup(p);
r = pa_sprintf_malloc("%s/%s", cwd, p);
pa_xfree(cwd);
return r;
}
void *pa_will_need(const void *p, size_t l) {
#ifdef RLIMIT_MEMLOCK
struct rlimit rlim;
#endif
const void *a;
size_t size;
int r;
size_t bs;
pa_assert(p);
pa_assert(l > 0);
a = PA_PAGE_ALIGN_PTR(p);
size = (const uint8_t*) p + l - (const uint8_t*) a;
#ifdef HAVE_POSIX_MADVISE
if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
pa_log_debug("posix_madvise() worked fine!");
return (void*) p;
}
#endif
/* Most likely the memory was not mmap()ed from a file and thus
* madvise() didn't work, so let's misuse mlock() do page this
* stuff back into RAM. Yeah, let's fuck with the MM! It's so
* inviting, the man page of mlock() tells us: "All pages that
* contain a part of the specified address range are guaranteed to
* be resident in RAM when the call returns successfully." */
#ifdef RLIMIT_MEMLOCK
pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0);
if (rlim.rlim_cur < PA_PAGE_SIZE) {
pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r));
return (void*) p;
}
bs = PA_PAGE_ALIGN(rlim.rlim_cur);
#else
bs = PA_PAGE_SIZE*4;
#endif
pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r));
#ifdef HAVE_MLOCK
while (size > 0 && bs > 0) {
if (bs > size)
bs = size;
if (mlock(a, bs) < 0) {
bs = PA_PAGE_ALIGN(bs / 2);
continue;
}
pa_assert_se(munlock(a, bs) == 0);
a = (const uint8_t*) a + bs;
size -= bs;
}
#endif
if (bs <= 0)
pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno));
else
pa_log_debug("mlock() worked fine!");
return (void*) p;
}
void pa_close_pipe(int fds[2]) {
pa_assert(fds);
if (fds[0] >= 0)
pa_assert_se(pa_close(fds[0]) == 0);
if (fds[1] >= 0)
pa_assert_se(pa_close(fds[1]) == 0);
fds[0] = fds[1] = -1;
}

View file

@ -34,7 +34,8 @@
struct timeval;
void pa_make_nonblock_fd(int fd);
void pa_make_fd_nonblock(int fd);
void pa_make_fd_cloexec(int fd);
int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid);
int pa_make_secure_parent_dir(const char *fn, mode_t, uid_t uid, gid_t gid);
@ -55,19 +56,18 @@ char *pa_strlcpy(char *b, const char *s, size_t l);
char *pa_parent_dir(const char *fn);
void pa_make_realtime(void);
void pa_raise_priority(void);
void pa_reset_priority(void);
int pa_fd_set_cloexec(int fd, int b);
int pa_parse_boolean(const char *s);
int pa_parse_boolean(const char *s) PA_GCC_PURE;
char *pa_split(const char *c, const char*delimiters, const char **state);
char *pa_split_spaces(const char *c, const char **state);
char *pa_strip_nl(char *s);
const char *pa_strsignal(int sig);
const char *pa_sig2str(int sig) PA_GCC_PURE;
int pa_own_uid_in_group(const char *name, gid_t *gid);
int pa_uid_in_group(uid_t uid, const char *name);
@ -84,12 +84,42 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength);
size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength);
int pa_startswith(const char *s, const char *pfx);
int pa_endswith(const char *s, const char *sfx);
int pa_startswith(const char *s, const char *pfx) PA_GCC_PURE;
int pa_endswith(const char *s, const char *sfx) PA_GCC_PURE;
char *pa_runtime_path(const char *fn, char *s, size_t l);
int pa_atoi(const char *s, int32_t *ret_i);
int pa_atou(const char *s, uint32_t *ret_u);
int pa_atof(const char *s, float *ret_f);
int pa_snprintf(char *str, size_t size, const char *format, ...);
char *pa_truncate_utf8(char *c, size_t l);
char *pa_getcwd(void);
char *pa_make_path_absolute(const char *p);
void *pa_will_need(const void *p, size_t l);
static inline int pa_is_power_of_two(unsigned n) {
return !(n & (n - 1));
}
static inline unsigned pa_make_power_of_two(unsigned n) {
unsigned j = n;
if (pa_is_power_of_two(n))
return n;
while (j) {
j = j >> 1;
n = n | j;
}
return n + 1;
}
void pa_close_pipe(int fds[2]);
#endif

View file

@ -27,7 +27,6 @@
#endif
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <signal.h>
@ -45,12 +44,36 @@
#include <pulsecore/props.h>
#include <pulsecore/random.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "core.h"
static PA_DEFINE_CHECK_TYPE(pa_core, pa_msgobject);
static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_core *c = PA_CORE(o);
pa_core_assert_ref(c);
switch (code) {
case PA_CORE_MESSAGE_UNLOAD_MODULE:
pa_module_unload(c, userdata);
return 0;
default:
return -1;
}
}
static void core_free(pa_object *o);
pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
pa_core* c;
pa_mempool *pool;
int j;
pa_assert(m);
if (shared) {
if (!(pool = pa_mempool_new(shared))) {
@ -66,7 +89,9 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
}
}
c = pa_xnew(pa_core, 1);
c = pa_msgobject_new(pa_core);
c->parent.parent.free = core_free;
c->parent.process_msg = core_process_msg;
c->mainloop = m;
c->clients = pa_idxset_new(NULL, NULL);
@ -87,6 +112,8 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
c->default_sample_spec.format = PA_SAMPLE_S16NE;
c->default_sample_spec.rate = 44100;
c->default_sample_spec.channels = 2;
c->default_n_fragments = 4;
c->default_fragment_size_msec = 25;
c->module_auto_unload_event = NULL;
c->module_defer_unload_event = NULL;
@ -99,22 +126,21 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
c->mempool = pool;
c->disallow_module_loading = 0;
c->quit_event = NULL;
c->exit_idle_time = -1;
c->module_idle_time = 20;
c->scache_idle_time = 20;
c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST;
c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE;
c->is_system_instance = 0;
c->disallow_module_loading = 0;
c->high_priority = 0;
pa_hook_init(&c->hook_sink_input_new, c);
pa_hook_init(&c->hook_sink_disconnect, c);
pa_hook_init(&c->hook_source_output_new, c);
pa_hook_init(&c->hook_source_disconnect, c);
for (j = 0; j < PA_CORE_HOOK_MAX; j++)
pa_hook_init(&c->hooks[j], c);
pa_property_init(c);
@ -123,28 +149,31 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
#ifdef SIGPIPE
pa_check_signal_is_blocked(SIGPIPE);
#endif
return c;
}
void pa_core_free(pa_core *c) {
assert(c);
static void core_free(pa_object *o) {
pa_core *c = PA_CORE(o);
int j;
pa_assert(c);
pa_module_unload_all(c);
assert(!c->modules);
pa_assert(!c->modules);
assert(pa_idxset_isempty(c->clients));
pa_assert(pa_idxset_isempty(c->clients));
pa_idxset_free(c->clients, NULL, NULL);
assert(pa_idxset_isempty(c->sinks));
pa_assert(pa_idxset_isempty(c->sinks));
pa_idxset_free(c->sinks, NULL, NULL);
assert(pa_idxset_isempty(c->sources));
pa_assert(pa_idxset_isempty(c->sources));
pa_idxset_free(c->sources, NULL, NULL);
assert(pa_idxset_isempty(c->source_outputs));
pa_assert(pa_idxset_isempty(c->source_outputs));
pa_idxset_free(c->source_outputs, NULL, NULL);
assert(pa_idxset_isempty(c->sink_inputs));
pa_assert(pa_idxset_isempty(c->sink_inputs));
pa_idxset_free(c->sink_inputs, NULL, NULL);
pa_scache_free(c);
@ -162,23 +191,21 @@ void pa_core_free(pa_core *c) {
pa_property_cleanup(c);
pa_hook_free(&c->hook_sink_input_new);
pa_hook_free(&c->hook_sink_disconnect);
pa_hook_free(&c->hook_source_output_new);
pa_hook_free(&c->hook_source_disconnect);
for (j = 0; j < PA_CORE_HOOK_MAX; j++)
pa_hook_free(&c->hooks[j]);
pa_xfree(c);
}
static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
pa_core *c = userdata;
assert(c->quit_event = e);
pa_assert(c->quit_event == e);
m->quit(m, 0);
}
void pa_core_check_quit(pa_core *c) {
assert(c);
pa_assert(c);
if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) {
struct timeval tv;

View file

@ -34,17 +34,51 @@
#include <pulsecore/queue.h>
#include <pulsecore/llist.h>
#include <pulsecore/hook-list.h>
#include <pulsecore/asyncmsgq.h>
typedef struct pa_core pa_core;
#include <pulsecore/core-subscribe.h>
#include <pulsecore/sink-input.h>
#include <pulsecore/msgobject.h>
typedef enum pa_core_hook {
PA_CORE_HOOK_SINK_NEW_POST,
PA_CORE_HOOK_SINK_UNLINK,
PA_CORE_HOOK_SINK_UNLINK_POST,
PA_CORE_HOOK_SINK_STATE_CHANGED,
PA_CORE_HOOK_SINK_DESCRIPTION_CHANGED,
PA_CORE_HOOK_SOURCE_NEW_POST,
PA_CORE_HOOK_SOURCE_UNLINK,
PA_CORE_HOOK_SOURCE_UNLINK_POST,
PA_CORE_HOOK_SOURCE_STATE_CHANGED,
PA_CORE_HOOK_SOURCE_DESCRIPTION_CHANGED,
PA_CORE_HOOK_SINK_INPUT_NEW,
PA_CORE_HOOK_SINK_INPUT_PUT,
PA_CORE_HOOK_SINK_INPUT_UNLINK,
PA_CORE_HOOK_SINK_INPUT_UNLINK_POST,
PA_CORE_HOOK_SINK_INPUT_MOVE,
PA_CORE_HOOK_SINK_INPUT_MOVE_POST,
PA_CORE_HOOK_SINK_INPUT_NAME_CHANGED,
PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED,
PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
PA_CORE_HOOK_SOURCE_OUTPUT_PUT,
PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK,
PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST,
PA_CORE_HOOK_SOURCE_OUTPUT_MOVE,
PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST,
PA_CORE_HOOK_SOURCE_OUTPUT_NAME_CHANGED,
PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED,
PA_CORE_HOOK_MAX
} pa_core_hook_t;
/* The core structure of PulseAudio. Every PulseAudio daemon contains
* exactly one of these. It is used for storing kind of global
* variables for the daemon. */
struct pa_core {
pa_msgobject parent;
/* A random value which may be used to identify this instance of
* PulseAudio. Not cryptographically secure in any way. */
uint32_t cookie;
@ -61,6 +95,8 @@ struct pa_core {
char *default_source_name, *default_sink_name;
pa_sample_spec default_sample_spec;
unsigned default_n_fragments, default_fragment_size_msec;
pa_time_event *module_auto_unload_event;
pa_defer_event *module_defer_unload_event;
@ -71,27 +107,30 @@ struct pa_core {
pa_mempool *mempool;
int disallow_module_loading, running_as_daemon;
int exit_idle_time, module_idle_time, scache_idle_time;
pa_time_event *quit_event;
pa_time_event *scache_auto_unload_event;
int disallow_module_loading, running_as_daemon;
pa_resample_method_t resample_method;
int is_system_instance;
int high_priority;
/* hooks */
pa_hook
hook_sink_input_new,
hook_sink_disconnect,
hook_source_output_new,
hook_source_disconnect;
pa_hook hooks[PA_CORE_HOOK_MAX];
};
PA_DECLARE_CLASS(pa_core);
#define PA_CORE(o) pa_core_cast(o)
enum {
PA_CORE_MESSAGE_UNLOAD_MODULE,
PA_CORE_MESSAGE_MAX
};
pa_core* pa_core_new(pa_mainloop_api *m, int shared);
void pa_core_free(pa_core*c);
/* Check whether noone is connected to this core */
void pa_core_check_quit(pa_core *c);

View file

@ -26,7 +26,9 @@
#include <sys/types.h>
/* config.h must be included before this file */
#ifndef PACKAGE
#error "Please include config.h before including this file!"
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>

View file

@ -26,10 +26,10 @@
#endif
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include "dynarray.h"
@ -52,7 +52,7 @@ pa_dynarray* pa_dynarray_new(void) {
void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) {
unsigned i;
assert(a);
pa_assert(a);
if (func)
for (i = 0; i < a->n_entries; i++)
@ -64,7 +64,7 @@ void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), voi
}
void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) {
assert(a);
pa_assert(a);
if (i >= a->n_allocated) {
unsigned n;
@ -85,21 +85,27 @@ void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) {
}
unsigned pa_dynarray_append(pa_dynarray*a, void *p) {
unsigned i = a->n_entries;
unsigned i;
pa_assert(a);
i = a->n_entries;
pa_dynarray_put(a, i, p);
return i;
}
void *pa_dynarray_get(pa_dynarray*a, unsigned i) {
assert(a);
pa_assert(a);
if (i >= a->n_entries)
return NULL;
assert(a->data);
pa_assert(a->data);
return a->data[i];
}
unsigned pa_dynarray_size(pa_dynarray*a) {
assert(a);
pa_assert(a);
return a->n_entries;
}

View file

@ -27,54 +27,68 @@
#include <inttypes.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#ifndef PACKAGE
#error "Please include config.h before including this file!"
#endif
#define INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
#define UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
#define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
#define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
#define MAYBE_INT32_SWAP(c,x) ((c) ? INT32_SWAP(x) : x)
#define MAYBE_UINT32_SWAP(c,x) ((c) ? UINT32_SWAP(x) : x)
#ifdef HAVE_BYTESWAP_H
#define PA_INT16_SWAP(x) ((int16_t) bswap_16((uint16_t) x))
#define PA_UINT16_SWAP(x) ((uint16_t) bswap_16((uint16_t) x))
#define PA_INT32_SWAP(x) ((int32_t) bswap_32((uint32_t) x))
#define PA_UINT32_SWAP(x) ((uint32_t) bswap_32((uint32_t) x))
#else
#define PA_INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
#define PA_UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
#define PA_INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
#define PA_UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
#endif
#define PA_MAYBE_INT16_SWAP(c,x) ((c) ? PA_INT32_SWAP(x) : x)
#define PA_MAYBE_UINT16_SWAP(c,x) ((c) ? PA_UINT32_SWAP(x) : x)
#define PA_MAYBE_INT32_SWAP(c,x) ((c) ? PA_INT32_SWAP(x) : x)
#define PA_MAYBE_UINT32_SWAP(c,x) ((c) ? PA_UINT32_SWAP(x) : x)
#ifdef WORDS_BIGENDIAN
#define INT16_FROM_LE(x) INT16_SWAP(x)
#define INT16_FROM_BE(x) ((int16_t)(x))
#define PA_INT16_FROM_LE(x) PA_INT16_SWAP(x)
#define PA_INT16_FROM_BE(x) ((int16_t)(x))
#define INT16_TO_LE(x) INT16_SWAP(x)
#define INT16_TO_BE(x) ((int16_t)(x))
#define PA_INT16_TO_LE(x) PA_INT16_SWAP(x)
#define PA_INT16_TO_BE(x) ((int16_t)(x))
#define UINT16_FROM_LE(x) UINT16_SWAP(x)
#define UINT16_FROM_BE(x) ((uint16_t)(x))
#define PA_UINT16_FROM_LE(x) PA_UINT16_SWAP(x)
#define PA_UINT16_FROM_BE(x) ((uint16_t)(x))
#define INT32_FROM_LE(x) INT32_SWAP(x)
#define INT32_FROM_BE(x) ((int32_t)(x))
#define PA_INT32_FROM_LE(x) PA_INT32_SWAP(x)
#define PA_INT32_FROM_BE(x) ((int32_t)(x))
#define UINT32_FROM_LE(x) UINT32_SWAP(x)
#define UINT32_FROM_BE(x) ((uint32_t)(x))
#define PA_UINT32_FROM_LE(x) PA_UINT32_SWAP(x)
#define PA_UINT32_FROM_BE(x) ((uint32_t)(x))
#define UINT32_TO_LE(x) UINT32_SWAP(x)
#define UINT32_TO_BE(x) ((uint32_t)(x))
#define PA_UINT32_TO_LE(x) PA_UINT32_SWAP(x)
#define PA_UINT32_TO_BE(x) ((uint32_t)(x))
#else
#define INT16_FROM_LE(x) ((int16_t)(x))
#define INT16_FROM_BE(x) INT16_SWAP(x)
#define PA_INT16_FROM_LE(x) ((int16_t)(x))
#define PA_INT16_FROM_BE(x) PA_INT16_SWAP(x)
#define INT16_TO_LE(x) ((int16_t)(x))
#define INT16_TO_BE(x) INT16_SWAP(x)
#define PA_INT16_TO_LE(x) ((int16_t)(x))
#define PA_INT16_TO_BE(x) PA_INT16_SWAP(x)
#define UINT16_FROM_LE(x) ((uint16_t)(x))
#define UINT16_FROM_BE(x) UINT16_SWAP(x)
#define PA_UINT16_FROM_LE(x) ((uint16_t)(x))
#define PA_UINT16_FROM_BE(x) PA_UINT16_SWAP(x)
#define INT32_FROM_LE(x) ((int32_t)(x))
#define INT32_FROM_BE(x) INT32_SWAP(x)
#define PA_INT32_FROM_LE(x) ((int32_t)(x))
#define PA_INT32_FROM_BE(x) PA_INT32_SWAP(x)
#define UINT32_FROM_LE(x) ((uint32_t)(x))
#define UINT32_FROM_BE(x) UINT32_SWAP(x)
#define PA_UINT32_FROM_LE(x) ((uint32_t)(x))
#define PA_UINT32_FROM_BE(x) PA_UINT32_SWAP(x)
#define UINT32_TO_LE(x) ((uint32_t)(x))
#define UINT32_TO_BE(x) UINT32_SWAP(x)
#define PA_UINT32_TO_LE(x) ((uint32_t)(x))
#define PA_UINT32_TO_BE(x) PA_UINT32_SWAP(x)
#endif
#endif

View file

@ -205,7 +205,7 @@ typedef int esd_client_state_t;
/* the endian key is transferred in binary, if it's read into int, */
/* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */
/* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */
#define ESD_SWAP_ENDIAN_KEY (UINT32_SWAP(ESD_ENDIAN_KEY))
#define ESD_SWAP_ENDIAN_KEY (PA_UINT32_SWAP(ESD_ENDIAN_KEY))
#endif

276
src/pulsecore/fdsem.c Normal file
View file

@ -0,0 +1,276 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <pulsecore/atomic.h>
#include <pulsecore/log.h>
#include <pulsecore/thread.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-util.h>
#include <pulse/xmalloc.h>
#ifndef HAVE_PIPE
#include <pulsecore/pipe.h>
#endif
#ifdef __linux__
#if !defined(__NR_eventfd) && defined(__i386__)
#define __NR_eventfd 323
#endif
#if !defined(__NR_eventfd) && defined(__x86_64__)
#define __NR_eventfd 284
#endif
#if !defined(SYS_eventfd) && defined(__NR_eventfd)
#define SYS_eventfd __NR_eventfd
#endif
#ifdef SYS_eventfd
#define HAVE_EVENTFD
static inline long eventfd(unsigned count) {
return syscall(SYS_eventfd, count);
}
#endif
#endif
#include "fdsem.h"
struct pa_fdsem {
int fds[2];
#ifdef HAVE_EVENTFD
int efd;
#endif
pa_atomic_t waiting;
pa_atomic_t signalled;
pa_atomic_t in_pipe;
};
pa_fdsem *pa_fdsem_new(void) {
pa_fdsem *f;
f = pa_xnew(pa_fdsem, 1);
#ifdef HAVE_EVENTFD
if ((f->efd = eventfd(0)) >= 0) {
pa_make_fd_cloexec(f->efd);
f->fds[0] = f->fds[1] = -1;
} else
#endif
{
if (pipe(f->fds) < 0) {
pa_xfree(f);
return NULL;
}
pa_make_fd_cloexec(f->fds[0]);
pa_make_fd_cloexec(f->fds[1]);
}
pa_atomic_store(&f->waiting, 0);
pa_atomic_store(&f->signalled, 0);
pa_atomic_store(&f->in_pipe, 0);
return f;
}
void pa_fdsem_free(pa_fdsem *f) {
pa_assert(f);
#ifdef HAVE_EVENTFD
if (f->efd >= 0)
pa_close(f->efd);
#endif
pa_close_pipe(f->fds);
pa_xfree(f);
}
static void flush(pa_fdsem *f) {
ssize_t r;
pa_assert(f);
if (pa_atomic_load(&f->in_pipe) <= 0)
return;
do {
char x[10];
#ifdef HAVE_EVENTFD
if (f->efd >= 0) {
uint64_t u;
if ((r = read(f->efd, &u, sizeof(u))) != sizeof(u)) {
pa_assert(r < 0 && errno == EINTR);
continue;
}
r = (ssize_t) u;
} else
#endif
if ((r = read(f->fds[0], &x, sizeof(x))) <= 0) {
pa_assert(r < 0 && errno == EINTR);
continue;
}
} while (pa_atomic_sub(&f->in_pipe, r) > r);
}
void pa_fdsem_post(pa_fdsem *f) {
pa_assert(f);
if (pa_atomic_cmpxchg(&f->signalled, 0, 1)) {
if (pa_atomic_load(&f->waiting)) {
ssize_t r;
char x = 'x';
pa_atomic_inc(&f->in_pipe);
for (;;) {
#ifdef HAVE_EVENTFD
if (f->efd >= 0) {
uint64_t u = 1;
if ((r = write(f->efd, &u, sizeof(u))) != sizeof(u)) {
pa_assert(r < 0 && errno == EINTR);
continue;
}
} else
#endif
if ((r = write(f->fds[1], &x, 1)) != 1) {
pa_assert(r < 0 && errno == EINTR);
continue;
}
break;
}
}
}
}
void pa_fdsem_wait(pa_fdsem *f) {
pa_assert(f);
flush(f);
if (pa_atomic_cmpxchg(&f->signalled, 1, 0))
return;
pa_atomic_inc(&f->waiting);
while (!pa_atomic_cmpxchg(&f->signalled, 1, 0)) {
char x[10];
ssize_t r;
#ifdef HAVE_EVENTFD
if (f->efd >= 0) {
uint64_t u;
if ((r = read(f->efd, &u, sizeof(u))) != sizeof(u)) {
pa_assert(r < 0 && errno == EINTR);
continue;
}
r = (ssize_t) u;
} else
#endif
if ((r = read(f->fds[0], &x, sizeof(x))) <= 0) {
pa_assert(r < 0 && errno == EINTR);
continue;
}
pa_atomic_sub(&f->in_pipe, r);
}
pa_assert_se(pa_atomic_dec(&f->waiting) >= 1);
}
int pa_fdsem_try(pa_fdsem *f) {
pa_assert(f);
flush(f);
if (pa_atomic_cmpxchg(&f->signalled, 1, 0))
return 1;
return 0;
}
int pa_fdsem_get(pa_fdsem *f) {
pa_assert(f);
#ifdef HAVE_EVENTFD
if (f->efd >= 0)
return f->efd;
#endif
return f->fds[0];
}
int pa_fdsem_before_poll(pa_fdsem *f) {
pa_assert(f);
flush(f);
if (pa_atomic_cmpxchg(&f->signalled, 1, 0))
return -1;
pa_atomic_inc(&f->waiting);
if (pa_atomic_cmpxchg(&f->signalled, 1, 0)) {
pa_assert_se(pa_atomic_dec(&f->waiting) >= 1);
return -1;
}
return 0;
}
int pa_fdsem_after_poll(pa_fdsem *f) {
pa_assert(f);
pa_assert_se(pa_atomic_dec(&f->waiting) >= 1);
flush(f);
if (pa_atomic_cmpxchg(&f->signalled, 1, 0))
return 1;
return 0;
}

49
src/pulsecore/fdsem.h Normal file
View file

@ -0,0 +1,49 @@
#ifndef foopulsefdsemhfoo
#define foopulsefdsemhfoo
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#include <sys/types.h>
#include <pulse/def.h>
/* A simple, asynchronous semaphore which uses fds for sleeping. In
* the best case all functions are lock-free unless sleeping is
* required. */
typedef struct pa_fdsem pa_fdsem;
pa_fdsem *pa_fdsem_new(void);
void pa_fdsem_free(pa_fdsem *f);
void pa_fdsem_post(pa_fdsem *f);
void pa_fdsem_wait(pa_fdsem *f);
int pa_fdsem_try(pa_fdsem *f);
int pa_fdsem_get(pa_fdsem *f);
int pa_fdsem_before_poll(pa_fdsem *f);
int pa_fdsem_after_poll(pa_fdsem *f);
#endif

View file

@ -0,0 +1,13 @@
# This is a dirty trick just to ease compilation with emacs
#
# This file is not intended to be distributed or anything
#
# So: don't touch it, even better ignore it!
all:
$(MAKE) -C ../..
clean:
$(MAKE) -C ../.. clean
.PHONY: all clean

View file

@ -0,0 +1,82 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg 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.
*
* FFmpeg 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 FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_H
#define AVCODEC_H
/* Just a heavily bastardized version of the original file from
* ffmpeg, just enough to get resample2.c to compile without
* modification -- Lennart */
#if !defined(PACKAGE) && defined(HAVE_CONFIG_H)
#include <config.h>
#endif
#include <sys/types.h>
#include <inttypes.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#define av_mallocz(l) calloc(1, (l))
#define av_malloc(l) malloc(l)
#define av_realloc(p,l) realloc((p),(l))
#define av_free(p) free(p)
static inline void av_freep(void *k) {
void **p = k;
if (p) {
free(*p);
*p = NULL;
}
}
static inline int av_clip(int a, int amin, int amax)
{
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
}
#define av_log(a,b,c)
#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
#define FFSIGN(a) ((a) > 0 ? 1 : -1)
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
struct AVResampleContext;
struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff);
int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx);
void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance);
void av_resample_close(struct AVResampleContext *c);
void av_build_filter(int16_t *filter, double factor, int tap_count, int phase_count, int scale, int type);
/*
* crude lrintf for non-C99 systems.
*/
#ifndef HAVE_LRINTF
#define lrintf(x) ((long int)(x))
#endif
#endif /* AVCODEC_H */

View file

@ -0,0 +1 @@
/* empty file, just here to allow us to compile an unmodified resampler2.c */

View file

@ -0,0 +1,324 @@
/*
* audio resampling
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg 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.
*
* FFmpeg 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 FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file resample2.c
* audio resampling
* @author Michael Niedermayer <michaelni@gmx.at>
*/
#include "avcodec.h"
#include "dsputil.h"
#ifndef CONFIG_RESAMPLE_HP
#define FILTER_SHIFT 15
#define FELEM int16_t
#define FELEM2 int32_t
#define FELEML int64_t
#define FELEM_MAX INT16_MAX
#define FELEM_MIN INT16_MIN
#define WINDOW_TYPE 9
#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE)
#define FILTER_SHIFT 30
#define FELEM int32_t
#define FELEM2 int64_t
#define FELEML int64_t
#define FELEM_MAX INT32_MAX
#define FELEM_MIN INT32_MIN
#define WINDOW_TYPE 12
#else
#define FILTER_SHIFT 0
#define FELEM double
#define FELEM2 double
#define FELEML double
#define WINDOW_TYPE 24
#endif
typedef struct AVResampleContext{
FELEM *filter_bank;
int filter_length;
int ideal_dst_incr;
int dst_incr;
int index;
int frac;
int src_incr;
int compensation_distance;
int phase_shift;
int phase_mask;
int linear;
}AVResampleContext;
/**
* 0th order modified bessel function of the first kind.
*/
static double bessel(double x){
double v=1;
double t=1;
int i;
x= x*x/4;
for(i=1; i<50; i++){
t *= x/(i*i);
v += t;
}
return v;
}
/**
* builds a polyphase filterbank.
* @param factor resampling factor
* @param scale wanted sum of coefficients for each filter
* @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16
*/
void av_build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){
int ph, i;
double x, y, w, tab[tap_count];
const int center= (tap_count-1)/2;
/* if upsampling, only need to interpolate, no filter */
if (factor > 1.0)
factor = 1.0;
for(ph=0;ph<phase_count;ph++) {
double norm = 0;
for(i=0;i<tap_count;i++) {
x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor;
if (x == 0) y = 1.0;
else y = sin(x) / x;
switch(type){
case 0:{
const float d= -0.5; //first order derivative = -0.5
x = fabs(((double)(i - center) - (double)ph / phase_count) * factor);
if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x);
else y= d*(-4 + 8*x - 5*x*x + x*x*x);
break;}
case 1:
w = 2.0*x / (factor*tap_count) + M_PI;
y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0.0106411 * cos(3*w);
break;
default:
w = 2.0*x / (factor*tap_count*M_PI);
y *= bessel(type*sqrt(FFMAX(1-w*w, 0)));
break;
}
tab[i] = y;
norm += y;
}
/* normalize so that an uniform color remains the same */
for(i=0;i<tap_count;i++) {
#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE
filter[ph * tap_count + i] = tab[i] / norm;
#else
filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm), FELEM_MIN, FELEM_MAX);
#endif
}
}
#if 0
{
#define LEN 1024
int j,k;
double sine[LEN + tap_count];
double filtered[LEN];
double maxff=-2, minff=2, maxsf=-2, minsf=2;
for(i=0; i<LEN; i++){
double ss=0, sf=0, ff=0;
for(j=0; j<LEN+tap_count; j++)
sine[j]= cos(i*j*M_PI/LEN);
for(j=0; j<LEN; j++){
double sum=0;
ph=0;
for(k=0; k<tap_count; k++)
sum += filter[ph * tap_count + k] * sine[k+j];
filtered[j]= sum / (1<<FILTER_SHIFT);
ss+= sine[j + center] * sine[j + center];
ff+= filtered[j] * filtered[j];
sf+= sine[j + center] * filtered[j];
}
ss= sqrt(2*ss/LEN);
ff= sqrt(2*ff/LEN);
sf= 2*sf/LEN;
maxff= FFMAX(maxff, ff);
minff= FFMIN(minff, ff);
maxsf= FFMAX(maxsf, sf);
minsf= FFMIN(minsf, sf);
if(i%11==0){
av_log(NULL, AV_LOG_ERROR, "i:%4d ss:%f ff:%13.6e-%13.6e sf:%13.6e-%13.6e\n", i, ss, maxff, minff, maxsf, minsf);
minff=minsf= 2;
maxff=maxsf= -2;
}
}
}
#endif
}
/**
* Initializes an audio resampler.
* Note, if either rate is not an integer then simply scale both rates up so they are.
*/
AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff){
AVResampleContext *c= av_mallocz(sizeof(AVResampleContext));
double factor= FFMIN(out_rate * cutoff / in_rate, 1.0);
int phase_count= 1<<phase_shift;
c->phase_shift= phase_shift;
c->phase_mask= phase_count-1;
c->linear= linear;
c->filter_length= FFMAX((int)ceil(filter_size/factor), 1);
c->filter_bank= av_mallocz(c->filter_length*(phase_count+1)*sizeof(FELEM));
av_build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<<FILTER_SHIFT, WINDOW_TYPE);
memcpy(&c->filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM));
c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1];
c->src_incr= out_rate;
c->ideal_dst_incr= c->dst_incr= in_rate * phase_count;
c->index= -phase_count*((c->filter_length-1)/2);
return c;
}
void av_resample_close(AVResampleContext *c){
av_freep(&c->filter_bank);
av_freep(&c);
}
/**
* Compensates samplerate/timestamp drift. The compensation is done by changing
* the resampler parameters, so no audible clicks or similar distortions ocur
* @param compensation_distance distance in output samples over which the compensation should be performed
* @param sample_delta number of output samples which should be output less
*
* example: av_resample_compensate(c, 10, 500)
* here instead of 510 samples only 500 samples would be output
*
* note, due to rounding the actual compensation might be slightly different,
* especially if the compensation_distance is large and the in_rate used during init is small
*/
void av_resample_compensate(AVResampleContext *c, int sample_delta, int compensation_distance){
// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr;
c->compensation_distance= compensation_distance;
c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance;
}
/**
* resamples.
* @param src an array of unconsumed samples
* @param consumed the number of samples of src which have been consumed are returned here
* @param src_size the number of unconsumed samples available
* @param dst_size the amount of space in samples available in dst
* @param update_ctx if this is 0 then the context wont be modified, that way several channels can be resampled with the same context
* @return the number of samples written in dst or -1 if an error occured
*/
int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){
int dst_index, i;
int index= c->index;
int frac= c->frac;
int dst_incr_frac= c->dst_incr % c->src_incr;
int dst_incr= c->dst_incr / c->src_incr;
int compensation_distance= c->compensation_distance;
if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){
int64_t index2= ((int64_t)index)<<32;
int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr;
dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr);
for(dst_index=0; dst_index < dst_size; dst_index++){
dst[dst_index] = src[index2>>32];
index2 += incr;
}
frac += dst_index * dst_incr_frac;
index += dst_index * dst_incr;
index += frac / c->src_incr;
frac %= c->src_incr;
}else{
for(dst_index=0; dst_index < dst_size; dst_index++){
FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask);
int sample_index= index >> c->phase_shift;
FELEM2 val=0;
if(sample_index < 0){
for(i=0; i<c->filter_length; i++)
val += src[FFABS(sample_index + i) % src_size] * filter[i];
}else if(sample_index + c->filter_length > src_size){
break;
}else if(c->linear){
FELEM2 v2=0;
for(i=0; i<c->filter_length; i++){
val += src[sample_index + i] * (FELEM2)filter[i];
v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length];
}
val+=(v2-val)*(FELEML)frac / c->src_incr;
}else{
for(i=0; i<c->filter_length; i++){
val += src[sample_index + i] * (FELEM2)filter[i];
}
}
#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE
dst[dst_index] = av_clip_int16(lrintf(val));
#else
val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;
dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val;
#endif
frac += dst_incr_frac;
index += dst_incr;
if(frac >= c->src_incr){
frac -= c->src_incr;
index++;
}
if(dst_index + 1 == compensation_distance){
compensation_distance= 0;
dst_incr_frac= c->ideal_dst_incr % c->src_incr;
dst_incr= c->ideal_dst_incr / c->src_incr;
}
}
}
*consumed= FFMAX(index, 0) >> c->phase_shift;
if(index>=0) index &= c->phase_mask;
if(compensation_distance){
compensation_distance -= dst_index;
assert(compensation_distance > 0);
}
if(update_ctx){
c->frac= frac;
c->index= index;
c->dst_incr= dst_incr_frac + c->src_incr*dst_incr;
c->compensation_distance= compensation_distance;
}
#if 0
if(update_ctx && !c->compensation_distance){
#undef rand
av_resample_compensate(c, rand() % (8000*2) - 8000, 8000*2);
av_log(NULL, AV_LOG_DEBUG, "%d %d %d\n", c->dst_incr, c->ideal_dst_incr, c->compensation_distance);
}
#endif
return dst_index;
}

View file

@ -25,12 +25,14 @@
#include <config.h>
#endif
#include <assert.h>
#include <pulse/xmalloc.h>
#include <pulsecore/atomic.h>
#include <pulsecore/log.h>
#include <pulsecore/thread.h>
#include <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include "flist.h"
@ -90,21 +92,18 @@ enum {
};
struct cell {
pa_atomic_int_t state;
pa_atomic_t state;
void *data;
};
struct pa_flist {
struct cell *cells;
unsigned size;
pa_atomic_int_t length;
pa_atomic_int_t read_idx;
pa_atomic_int_t write_idx;
pa_atomic_t length;
pa_atomic_t read_idx;
pa_atomic_t write_idx;
};
static int is_power_of_two(unsigned size) {
return !(size & (size - 1));
}
#define PA_FLIST_CELLS(x) ((struct cell*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_flist))))
pa_flist *pa_flist_new(unsigned size) {
pa_flist *l;
@ -112,12 +111,11 @@ pa_flist *pa_flist_new(unsigned size) {
if (!size)
size = FLIST_SIZE;
assert(is_power_of_two(size));
pa_assert(pa_is_power_of_two(size));
l = pa_xnew(pa_flist, 1);
l = pa_xmalloc0(PA_ALIGN(sizeof(pa_flist)) + (sizeof(struct cell) * size));
l->size = size;
l->cells = pa_xnew0(struct cell, size);
pa_atomic_store(&l->read_idx, 0);
pa_atomic_store(&l->write_idx, 0);
@ -131,32 +129,37 @@ static int reduce(pa_flist *l, int value) {
}
void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) {
assert(l);
pa_assert(l);
if (free_cb) {
struct cell *cells;
int len, idx;
cells = PA_FLIST_CELLS(l);
idx = reduce(l, pa_atomic_load(&l->read_idx));
len = pa_atomic_load(&l->length);
for (; len > 0; len--) {
if (pa_atomic_load(&l->cells[idx].state) == STATE_USED)
free_cb(l->cells[idx].data);
if (pa_atomic_load(&cells[idx].state) == STATE_USED)
free_cb(cells[idx].data);
idx = reduce(l, idx + 1);
}
}
pa_xfree(l->cells);
pa_xfree(l);
}
int pa_flist_push(pa_flist*l, void *p) {
int idx, len, n;
struct cell *cells;
assert(l);
assert(p);
pa_assert(l);
pa_assert(p);
cells = PA_FLIST_CELLS(l);
n = len = (int) l->size - pa_atomic_load(&l->length) + N_EXTRA_SCAN;
_Y;
@ -165,13 +168,13 @@ int pa_flist_push(pa_flist*l, void *p) {
for (; n > 0 ; n--) {
_Y;
if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_UNUSED, STATE_BUSY)) {
if (pa_atomic_cmpxchg(&cells[idx].state, STATE_UNUSED, STATE_BUSY)) {
_Y;
pa_atomic_inc(&l->write_idx);
_Y;
l->cells[idx].data = p;
cells[idx].data = p;
_Y;
pa_atomic_store(&l->cells[idx].state, STATE_USED);
pa_atomic_store(&cells[idx].state, STATE_USED);
_Y;
pa_atomic_inc(&l->length);
return 0;
@ -183,7 +186,7 @@ int pa_flist_push(pa_flist*l, void *p) {
#ifdef PROFILE
if (len > N_EXTRA_SCAN)
pa_log("WARNING: Didn't find free cell after %u iterations.", len);
pa_log_warn("Didn't find free cell after %u iterations.", len);
#endif
return -1;
@ -191,8 +194,11 @@ int pa_flist_push(pa_flist*l, void *p) {
void* pa_flist_pop(pa_flist*l) {
int idx, len, n;
struct cell *cells;
assert(l);
pa_assert(l);
cells = PA_FLIST_CELLS(l);
n = len = pa_atomic_load(&l->length) + N_EXTRA_SCAN;
_Y;
@ -201,14 +207,14 @@ void* pa_flist_pop(pa_flist*l) {
for (; n > 0 ; n--) {
_Y;
if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_USED, STATE_BUSY)) {
if (pa_atomic_cmpxchg(&cells[idx].state, STATE_USED, STATE_BUSY)) {
void *p;
_Y;
pa_atomic_inc(&l->read_idx);
_Y;
p = l->cells[idx].data;
p = cells[idx].data;
_Y;
pa_atomic_store(&l->cells[idx].state, STATE_UNUSED);
pa_atomic_store(&cells[idx].state, STATE_UNUSED);
_Y;
pa_atomic_dec(&l->length);
@ -221,7 +227,7 @@ void* pa_flist_pop(pa_flist*l) {
#ifdef PROFILE
if (len > N_EXTRA_SCAN)
pa_log("WARNING: Didn't find used cell after %u iterations.", len);
pa_log_warn("Didn't find used cell after %u iterations.", len);
#endif
return NULL;

View file

@ -26,6 +26,9 @@
#include <pulse/def.h>
#include <pulsecore/once.h>
#include <pulsecore/gccmacro.h>
/* A multiple-reader multipler-write lock-free free list implementation */
typedef struct pa_flist pa_flist;
@ -38,4 +41,28 @@ void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb);
int pa_flist_push(pa_flist*l, void *p);
void* pa_flist_pop(pa_flist*l);
/* Please not that the destructor stuff is not really necesary, we do
* this just to make valgrind output more useful. */
#define PA_STATIC_FLIST_DECLARE(name, size, free_cb) \
static struct { \
pa_flist *flist; \
pa_once once; \
} name##_flist = { NULL, PA_ONCE_INIT }; \
static void name##_flist_init(void) { \
name##_flist.flist = pa_flist_new(size); \
} \
static inline pa_flist* name##_flist_get(void) { \
pa_run_once(&name##_flist.once, name##_flist_init); \
return name##_flist.flist; \
} \
static void name##_flist_destructor(void) PA_GCC_DESTRUCTOR; \
static void name##_flist_destructor(void) { \
if (name##_flist.flist) \
pa_flist_free(name##_flist.flist, (free_cb)); \
} \
struct __stupid_useless_struct_to_allow_trailing_semicolon
#define PA_STATIC_FLIST_GET(name) (name##_flist_get())
#endif

View file

@ -43,30 +43,30 @@
#include "g711.h"
#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
#define QUANT_MASK (0xf) /* Quantization field mask. */
#define NSEGS (8) /* Number of A-law segments. */
#define SEG_SHIFT (4) /* Left shift for segment number. */
#define SEG_MASK (0x70) /* Segment field mask. */
#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
#define QUANT_MASK (0xf) /* Quantization field mask. */
#define NSEGS (8) /* Number of A-law segments. */
#define SEG_SHIFT (4) /* Left shift for segment number. */
#define SEG_MASK (0x70) /* Segment field mask. */
#if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION)
static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF,
0x1FF, 0x3FF, 0x7FF, 0xFFF};
0x1FF, 0x3FF, 0x7FF, 0xFFF};
static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF,
0x3FF, 0x7FF, 0xFFF, 0x1FFF};
0x3FF, 0x7FF, 0xFFF, 0x1FFF};
static int16_t search(
int16_t val,
int16_t *table,
int size)
int16_t val,
int16_t *table,
int size)
{
int i;
int i;
for (i = 0; i < size; i++) {
if (val <= *table++)
return (i);
}
return (size);
for (i = 0; i < size; i++) {
if (val <= *table++)
return (i);
}
return (size);
}
#endif /* !FAST_*_CONVERSION */
@ -77,55 +77,55 @@ static int16_t search(
* the data shifted such that it only contains information in the lower
* 13-bits.
*
* Linear Input Code Compressed Code
* ------------------------ ---------------
* 0000000wxyza 000wxyz
* 0000001wxyza 001wxyz
* 000001wxyzab 010wxyz
* 00001wxyzabc 011wxyz
* 0001wxyzabcd 100wxyz
* 001wxyzabcde 101wxyz
* 01wxyzabcdef 110wxyz
* 1wxyzabcdefg 111wxyz
* Linear Input Code Compressed Code
* ------------------------ ---------------
* 0000000wxyza 000wxyz
* 0000001wxyza 001wxyz
* 000001wxyzab 010wxyz
* 00001wxyzabc 011wxyz
* 0001wxyzabcd 100wxyz
* 001wxyzabcde 101wxyz
* 01wxyzabcdef 110wxyz
* 1wxyzabcdefg 111wxyz
*
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
*/
unsigned char st_13linear2alaw(
int16_t pcm_val) /* 2's complement (13-bit range) */
int16_t pcm_val) /* 2's complement (13-bit range) */
{
int16_t mask;
short seg;
unsigned char aval;
int16_t mask;
short seg;
unsigned char aval;
/* Have calling software do it since its already doing a shift
* from 32-bits down to 16-bits.
*/
/* pcm_val = pcm_val >> 3; */
/* Have calling software do it since its already doing a shift
* from 32-bits down to 16-bits.
*/
/* pcm_val = pcm_val >> 3; */
/* A-law using even bit inversion */
if (pcm_val >= 0) {
mask = 0xD5; /* sign (7th) bit = 1 */
} else {
mask = 0x55; /* sign bit = 0 */
pcm_val = -pcm_val - 1;
}
/* A-law using even bit inversion */
if (pcm_val >= 0) {
mask = 0xD5; /* sign (7th) bit = 1 */
} else {
mask = 0x55; /* sign bit = 0 */
pcm_val = -pcm_val - 1;
}
/* Convert the scaled magnitude to segment number. */
seg = search(pcm_val, seg_aend, 8);
/* Convert the scaled magnitude to segment number. */
seg = search(pcm_val, seg_aend, 8);
/* Combine the sign, segment, and quantization bits. */
/* Combine the sign, segment, and quantization bits. */
if (seg >= 8) /* out of range, return maximum value. */
return (unsigned char) (0x7F ^ mask);
else {
aval = (unsigned char) seg << SEG_SHIFT;
if (seg < 2)
aval |= (pcm_val >> 1) & QUANT_MASK;
else
aval |= (pcm_val >> seg) & QUANT_MASK;
return (aval ^ mask);
}
if (seg >= 8) /* out of range, return maximum value. */
return (unsigned char) (0x7F ^ mask);
else {
aval = (unsigned char) seg << SEG_SHIFT;
if (seg < 2)
aval |= (pcm_val >> 1) & QUANT_MASK;
else
aval |= (pcm_val >> seg) & QUANT_MASK;
return (aval ^ mask);
}
}
/*
@ -133,31 +133,31 @@ unsigned char st_13linear2alaw(
*
*/
int16_t st_alaw2linear16(
unsigned char a_val)
unsigned char a_val)
{
int16_t t;
int16_t seg;
int16_t t;
int16_t seg;
a_val ^= 0x55;
a_val ^= 0x55;
t = (a_val & QUANT_MASK) << 4;
seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
switch (seg) {
case 0:
t += 8;
break;
case 1:
t += 0x108;
break;
default:
t += 0x108;
t <<= seg - 1;
}
return ((a_val & SIGN_BIT) ? t : -t);
t = (a_val & QUANT_MASK) << 4;
seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
switch (seg) {
case 0:
t += 8;
break;
case 1:
t += 0x108;
break;
default:
t += 0x108;
t <<= seg - 1;
}
return ((a_val & SIGN_BIT) ? t : -t);
}
#endif /* !FAST_ALAW_CONVERSION */
#define BIAS (0x84) /* Bias for linear code. */
#define BIAS (0x84) /* Bias for linear code. */
#define CLIP 8159
#ifndef FAST_ULAW_CONVERSION
@ -171,16 +171,16 @@ int16_t st_alaw2linear16(
* is biased by adding 33 which shifts the encoding range from (0 - 8158) to
* (33 - 8191). The result can be seen in the following encoding table:
*
* Biased Linear Input Code Compressed Code
* ------------------------ ---------------
* 00000001wxyza 000wxyz
* 0000001wxyzab 001wxyz
* 000001wxyzabc 010wxyz
* 00001wxyzabcd 011wxyz
* 0001wxyzabcde 100wxyz
* 001wxyzabcdef 101wxyz
* 01wxyzabcdefg 110wxyz
* 1wxyzabcdefgh 111wxyz
* Biased Linear Input Code Compressed Code
* ------------------------ ---------------
* 00000001wxyza 000wxyz
* 0000001wxyzab 001wxyz
* 000001wxyzabc 010wxyz
* 00001wxyzabcd 011wxyz
* 0001wxyzabcde 100wxyz
* 001wxyzabcdef 101wxyz
* 01wxyzabcdefg 110wxyz
* 1wxyzabcdefgh 111wxyz
*
* Each biased linear code has a leading 1 which identifies the segment
* number. The value of the segment number is equal to 7 minus the number
@ -194,41 +194,41 @@ int16_t st_alaw2linear16(
* John Wiley & Sons, pps 98-111 and 472-476.
*/
unsigned char st_14linear2ulaw(
int16_t pcm_val) /* 2's complement (14-bit range) */
int16_t pcm_val) /* 2's complement (14-bit range) */
{
int16_t mask;
int16_t seg;
unsigned char uval;
int16_t mask;
int16_t seg;
unsigned char uval;
/* Have calling software do it since its already doing a shift
* from 32-bits down to 16-bits.
*/
/* pcm_val = pcm_val >> 2; */
/* Have calling software do it since its already doing a shift
* from 32-bits down to 16-bits.
*/
/* pcm_val = pcm_val >> 2; */
/* u-law inverts all bits */
/* Get the sign and the magnitude of the value. */
if (pcm_val < 0) {
pcm_val = -pcm_val;
mask = 0x7F;
} else {
mask = 0xFF;
}
if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */
pcm_val += (BIAS >> 2);
/* u-law inverts all bits */
/* Get the sign and the magnitude of the value. */
if (pcm_val < 0) {
pcm_val = -pcm_val;
mask = 0x7F;
} else {
mask = 0xFF;
}
if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */
pcm_val += (BIAS >> 2);
/* Convert the scaled magnitude to segment number. */
seg = search(pcm_val, seg_uend, 8);
/* Convert the scaled magnitude to segment number. */
seg = search(pcm_val, seg_uend, 8);
/*
* Combine the sign, segment, quantization bits;
* and complement the code word.
*/
if (seg >= 8) /* out of range, return maximum value. */
return (unsigned char) (0x7F ^ mask);
else {
uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
return (uval ^ mask);
}
/*
* Combine the sign, segment, quantization bits;
* and complement the code word.
*/
if (seg >= 8) /* out of range, return maximum value. */
return (unsigned char) (0x7F ^ mask);
else {
uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
return (uval ^ mask);
}
}
@ -242,21 +242,21 @@ unsigned char st_14linear2ulaw(
* original code word. This is in keeping with ISDN conventions.
*/
int16_t st_ulaw2linear16(
unsigned char u_val)
unsigned char u_val)
{
int16_t t;
int16_t t;
/* Complement to obtain normal u-law value. */
u_val = ~u_val;
/* Complement to obtain normal u-law value. */
u_val = ~u_val;
/*
* Extract and bias the quantization bits. Then
* shift up by the segment number and subtract out the bias.
*/
t = ((u_val & QUANT_MASK) << 3) + BIAS;
t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
/*
* Extract and bias the quantization bits. Then
* shift up by the segment number and subtract out the bias.
*/
t = ((u_val & QUANT_MASK) << 3) + BIAS;
t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
}
#endif /* !FAST_ULAW_CONVERSION */
@ -2413,52 +2413,52 @@ int main()
printf("int16_t _st_alaw2linear16[256] = {\n ");
for (x = 0; x < 256; x++)
{
printf("%8d,", st_alaw2linear16(x));
y++;
if (y == 7)
{
y = 0;
printf("\n ");
}
printf("%8d,", st_alaw2linear16(x));
y++;
if (y == 7)
{
y = 0;
printf("\n ");
}
}
printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n ");
y = 0;
for (x = 0; x < 0x2000; x++)
{
printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x));
y++;
if (y == 12)
{
y = 0;
printf("\n ");
}
printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x));
y++;
if (y == 12)
{
y = 0;
printf("\n ");
}
}
printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n ");
y = 0;
for (x = 0; x < 256; x++)
{
printf("%8d,", st_ulaw2linear16(x));
y++;
if (y == 7)
{
y = 0;
printf("\n ");
}
printf("%8d,", st_ulaw2linear16(x));
y++;
if (y == 7)
{
y = 0;
printf("\n ");
}
}
printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n ");
y = 0;
for (x = 0; x < 0x4000; x++)
{
printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x));
y++;
if (y == 12)
{
y = 0;
printf("\n ");
}
printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x));
y++;
if (y == 12)
{
y = 0;
printf("\n ");
}
}
printf("\n};\n");
@ -2468,64 +2468,64 @@ int main()
/* The following is not used by SoX but kept for reference */
#if 0
/* copy from CCITT G.711 specifications */
unsigned char _u2a[128] = { /* u- to A-law conversions */
1, 1, 2, 2, 3, 3, 4, 4,
5, 5, 6, 6, 7, 7, 8, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 27, 29, 31, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44,
46, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62,
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
unsigned char _u2a[128] = { /* u- to A-law conversions */
1, 1, 2, 2, 3, 3, 4, 4,
5, 5, 6, 6, 7, 7, 8, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 27, 29, 31, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44,
46, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62,
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
/* corrected:
81, 82, 83, 84, 85, 86, 87, 88,
81, 82, 83, 84, 85, 86, 87, 88,
should be: */
80, 82, 83, 84, 85, 86, 87, 88,
89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120,
121, 122, 123, 124, 125, 126, 127, 128};
80, 82, 83, 84, 85, 86, 87, 88,
89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120,
121, 122, 123, 124, 125, 126, 127, 128};
unsigned char _a2u[128] = { /* A- to u-law conversions */
1, 3, 5, 7, 9, 11, 13, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 32, 33, 33, 34, 34, 35, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 48, 49, 49,
50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 64,
65, 66, 67, 68, 69, 70, 71, 72,
unsigned char _a2u[128] = { /* A- to u-law conversions */
1, 3, 5, 7, 9, 11, 13, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 32, 33, 33, 34, 34, 35, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 48, 49, 49,
50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 64,
65, 66, 67, 68, 69, 70, 71, 72,
/* corrected:
73, 74, 75, 76, 77, 78, 79, 79,
73, 74, 75, 76, 77, 78, 79, 79,
should be: */
73, 74, 75, 76, 77, 78, 79, 80,
73, 74, 75, 76, 77, 78, 79, 80,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127};
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127};
/* A-law to u-law conversion */
unsigned char st_alaw2ulaw(
unsigned char aval)
unsigned char aval)
{
aval &= 0xff;
return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
(0x7F ^ _a2u[aval ^ 0x55]));
aval &= 0xff;
return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
(0x7F ^ _a2u[aval ^ 0x55]));
}
/* u-law to A-law conversion */
unsigned char st_ulaw2alaw(
unsigned char uval)
unsigned char uval)
{
uval &= 0xff;
return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
(unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
uval &= 0xff;
return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
(unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
}
#endif

View file

@ -52,4 +52,29 @@
#define PA_GCC_UNUSED
#endif
#ifdef __GNUC__
#define PA_GCC_DESTRUCTOR __attribute__ ((destructor))
#else
/** Call this function when process terminates */
#define PA_GCC_DESTRUCTOR
#endif
#ifndef PA_GCC_PURE
#ifdef __GNUCC__
#define PA_GCC_PURE __attribute__ ((pure))
#else
/** This function's return value depends only the arguments list and global state **/
#define PA_GCC_PURE
#endif
#endif
#ifndef PA_GCC_CONST
#ifdef __GNUCC__
#define PA_GCC_CONST __attribute__ ((const))
#else
/** This function's return value depends only the arguments list (stricter version of PA_GCC_PURE) **/
#define PA_GCC_CONST
#endif
#endif
#endif

View file

@ -26,13 +26,14 @@
#endif
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <pulse/xmalloc.h>
#include <pulsecore/idxset.h>
#include <pulsecore/log.h>
#include <pulsecore/flist.h>
#include <pulsecore/macro.h>
#include "hashmap.h"
@ -55,6 +56,8 @@ struct pa_hashmap {
pa_compare_func_t compare_func;
};
PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree);
pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) {
pa_hashmap *h;
@ -69,8 +72,8 @@ pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_f
}
static void remove(pa_hashmap *h, struct hashmap_entry *e) {
assert(h);
assert(e);
pa_assert(h);
pa_assert(e);
if (e->next)
e->next->previous = e->previous;
@ -84,16 +87,18 @@ static void remove(pa_hashmap *h, struct hashmap_entry *e) {
if (e->bucket_previous)
e->bucket_previous->bucket_next = e->bucket_next;
else {
assert(e->hash < h->size);
pa_assert(e->hash < h->size);
h->data[e->hash] = e->bucket_next;
}
pa_xfree(e);
if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
pa_xfree(e);
h->n_entries--;
}
void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) {
assert(h);
pa_assert(h);
while (h->first_entry) {
if (free_func)
@ -107,8 +112,8 @@ void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), v
static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) {
struct hashmap_entry *e;
assert(h);
assert(hash < h->size);
pa_assert(h);
pa_assert(hash < h->size);
for (e = h->data[hash]; e; e = e->bucket_next)
if (h->compare_func(e->key, key) == 0)
@ -120,14 +125,16 @@ static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key)
int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) {
struct hashmap_entry *e;
unsigned hash;
assert(h);
pa_assert(h);
hash = h->hash_func(key) % h->size;
if ((e = get(h, hash, key)))
return -1;
e = pa_xnew(struct hashmap_entry, 1);
if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries))))
e = pa_xnew(struct hashmap_entry, 1);
e->hash = hash;
e->key = key;
e->value = value;
@ -152,7 +159,7 @@ void* pa_hashmap_get(pa_hashmap *h, const void *key) {
unsigned hash;
struct hashmap_entry *e;
assert(h);
pa_assert(h);
hash = h->hash_func(key) % h->size;
@ -167,7 +174,7 @@ void* pa_hashmap_remove(pa_hashmap *h, const void *key) {
unsigned hash;
void *data;
assert(h);
pa_assert(h);
hash = h->hash_func(key) % h->size;
@ -184,8 +191,8 @@ unsigned pa_hashmap_size(pa_hashmap *h) {
}
void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) {
assert(h);
assert(state);
pa_assert(h);
pa_assert(state);
if (!*state)
*state = h->first_entry;
@ -207,7 +214,7 @@ void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) {
void* pa_hashmap_steal_first(pa_hashmap *h) {
void *data;
assert(h);
pa_assert(h);
if (!h->first_entry)
return NULL;
@ -218,7 +225,7 @@ void* pa_hashmap_steal_first(pa_hashmap *h) {
}
void *pa_hashmap_get_first(pa_hashmap *h) {
assert(h);
pa_assert(h);
if (!h->first_entry)
return NULL;

View file

@ -32,11 +32,13 @@
typedef struct pa_hashmap pa_hashmap;
typedef void (*pa_free2_cb_t)(void *p, void *userdata);
/* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */
pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func);
/* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */
void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata);
void pa_hashmap_free(pa_hashmap*, pa_free2_cb_t free_cb, void *userdata);
/* Returns non-zero when the entry already exists */
int pa_hashmap_put(pa_hashmap *h, const void *key, void *value);

View file

@ -21,10 +21,16 @@
USA.
***/
#include <pulsecore/hook-list.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pulsecore/macro.h>
#include "hook-list.h"
void pa_hook_init(pa_hook *hook, void *data) {
assert(hook);
pa_assert(hook);
PA_LLIST_HEAD_INIT(pa_hook_slot, hook->slots);
hook->last = NULL;
@ -33,8 +39,8 @@ void pa_hook_init(pa_hook *hook, void *data) {
}
static void slot_free(pa_hook *hook, pa_hook_slot *slot) {
assert(hook);
assert(slot);
pa_assert(hook);
pa_assert(slot);
if (hook->last == slot)
hook->last = slot->prev;
@ -45,8 +51,8 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) {
}
void pa_hook_free(pa_hook *hook) {
assert(hook);
assert(!hook->firing);
pa_assert(hook);
pa_assert(!hook->firing);
while (hook->slots)
slot_free(hook, hook->slots);
@ -57,7 +63,7 @@ void pa_hook_free(pa_hook *hook) {
pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) {
pa_hook_slot *slot;
assert(cb);
pa_assert(cb);
slot = pa_xnew(pa_hook_slot, 1);
slot->hook = hook;
@ -72,8 +78,8 @@ pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) {
}
void pa_hook_slot_free(pa_hook_slot *slot) {
assert(slot);
assert(!slot->dead);
pa_assert(slot);
pa_assert(!slot->dead);
if (slot->hook->firing > 0) {
slot->dead = 1;
@ -86,7 +92,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) {
pa_hook_slot *slot, *next;
pa_hook_result_t result = PA_HOOK_OK;
assert(hook);
pa_assert(hook);
hook->firing ++;

View file

@ -27,32 +27,35 @@
#endif
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include <pulsecore/flist.h>
#include "idxset.h"
typedef struct idxset_entry {
struct idxset_entry {
void *data;
uint32_t index;
unsigned hash_value;
struct idxset_entry *hash_prev, *hash_next;
struct idxset_entry* iterate_prev, *iterate_next;
} idxset_entry;
};
struct pa_idxset {
pa_hash_func_t hash_func;
pa_compare_func_t compare_func;
unsigned hash_table_size, n_entries;
idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail;
struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail;
uint32_t index, start_index, array_size;
};
PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree);
unsigned pa_idxset_string_hash_func(const void *p) {
unsigned hash = 0;
const char *c;
@ -82,7 +85,7 @@ pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_fun
s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func;
s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func;
s->hash_table_size = 127;
s->hash_table = pa_xnew0(idxset_entry*, s->hash_table_size);
s->hash_table = pa_xnew0(struct idxset_entry*, s->hash_table_size);
s->array = NULL;
s->array_size = 0;
s->index = 0;
@ -95,15 +98,17 @@ pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_fun
}
void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) {
assert(s);
pa_assert(s);
while (s->iterate_list_head) {
idxset_entry *e = s->iterate_list_head;
struct idxset_entry *e = s->iterate_list_head;
s->iterate_list_head = s->iterate_list_head->iterate_next;
if (free_func)
free_func(e->data, userdata);
pa_xfree(e);
if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
pa_xfree(e);
}
pa_xfree(s->hash_table);
@ -111,10 +116,10 @@ void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), v
pa_xfree(s);
}
static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) {
assert(p);
static struct idxset_entry* hash_scan(pa_idxset *s, struct idxset_entry* e, const void *p) {
pa_assert(p);
assert(s->compare_func);
pa_assert(s->compare_func);
for (; e; e = e->hash_next)
if (s->compare_func(e->data, p) == 0)
return e;
@ -124,8 +129,10 @@ static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) {
static void extend_array(pa_idxset *s, uint32_t idx) {
uint32_t i, j, l;
idxset_entry** n;
assert(idx >= s->start_index);
struct idxset_entry** n;
pa_assert(s);
pa_assert(idx >= s->start_index);
if (idx < s->start_index + s->array_size)
return;
@ -135,7 +142,7 @@ static void extend_array(pa_idxset *s, uint32_t idx) {
break;
l = idx - s->start_index - i + 100;
n = pa_xnew0(idxset_entry*, l);
n = pa_xnew0(struct idxset_entry*, l);
for (j = 0; j < s->array_size-i; j++)
n[j] = s->array[i+j];
@ -147,7 +154,9 @@ static void extend_array(pa_idxset *s, uint32_t idx) {
s->start_index += i;
}
static idxset_entry** array_index(pa_idxset*s, uint32_t idx) {
static struct idxset_entry** array_index(pa_idxset*s, uint32_t idx) {
pa_assert(s);
if (idx >= s->start_index + s->array_size)
return NULL;
@ -159,15 +168,15 @@ static idxset_entry** array_index(pa_idxset*s, uint32_t idx) {
int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) {
unsigned h;
idxset_entry *e, **a;
struct idxset_entry *e, **a;
assert(s);
assert(p);
pa_assert(s);
pa_assert(p);
assert(s->hash_func);
pa_assert(s->hash_func);
h = s->hash_func(p) % s->hash_table_size;
assert(s->hash_table);
pa_assert(s->hash_table);
if ((e = hash_scan(s, s->hash_table[h], p))) {
if (idx)
*idx = e->index;
@ -175,7 +184,8 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) {
return -1;
}
e = pa_xmalloc(sizeof(idxset_entry));
if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries))))
e = pa_xnew(struct idxset_entry, 1);
e->data = p;
e->index = s->index++;
e->hash_value = h;
@ -190,23 +200,23 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) {
/* Insert into array */
extend_array(s, e->index);
a = array_index(s, e->index);
assert(a && !*a);
pa_assert(a && !*a);
*a = e;
/* Insert into linked list */
e->iterate_next = NULL;
e->iterate_prev = s->iterate_list_tail;
if (s->iterate_list_tail) {
assert(s->iterate_list_head);
pa_assert(s->iterate_list_head);
s->iterate_list_tail->iterate_next = e;
} else {
assert(!s->iterate_list_head);
pa_assert(!s->iterate_list_head);
s->iterate_list_head = e;
}
s->iterate_list_tail = e;
s->n_entries++;
assert(s->n_entries >= 1);
pa_assert(s->n_entries >= 1);
if (idx)
*idx = e->index;
@ -215,8 +225,8 @@ int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) {
}
void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) {
idxset_entry **a;
assert(s);
struct idxset_entry **a;
pa_assert(s);
if (!(a = array_index(s, idx)))
return NULL;
@ -229,13 +239,15 @@ void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) {
void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) {
unsigned h;
idxset_entry *e;
assert(s && p);
struct idxset_entry *e;
assert(s->hash_func);
pa_assert(s);
pa_assert(p);
pa_assert(s->hash_func);
h = s->hash_func(p) % s->hash_table_size;
assert(s->hash_table);
pa_assert(s->hash_table);
if (!(e = hash_scan(s, s->hash_table[h], p)))
return NULL;
@ -245,13 +257,15 @@ void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) {
return e->data;
}
static void remove_entry(pa_idxset *s, idxset_entry *e) {
idxset_entry **a;
assert(s && e);
static void remove_entry(pa_idxset *s, struct idxset_entry *e) {
struct idxset_entry **a;
pa_assert(s);
pa_assert(e);
/* Remove from array */
a = array_index(s, e->index);
assert(a && *a && *a == e);
pa_assert(a && *a && *a == e);
*a = NULL;
/* Remove from linked list */
@ -274,17 +288,18 @@ static void remove_entry(pa_idxset *s, idxset_entry *e) {
else
s->hash_table[e->hash_value] = e->hash_next;
pa_xfree(e);
if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
pa_xfree(e);
assert(s->n_entries >= 1);
pa_assert(s->n_entries >= 1);
s->n_entries--;
}
void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) {
idxset_entry **a;
struct idxset_entry **a;
void *data;
assert(s);
pa_assert(s);
if (!(a = array_index(s, idx)))
return NULL;
@ -299,14 +314,16 @@ void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) {
}
void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) {
idxset_entry *e;
struct idxset_entry *e;
unsigned h;
void *r;
assert(s->hash_func);
pa_assert(s);
pa_assert(s->hash_func);
h = s->hash_func(data) % s->hash_table_size;
assert(s->hash_table);
pa_assert(s->hash_table);
if (!(e = hash_scan(s, s->hash_table[h], data)))
return NULL;
@ -320,8 +337,10 @@ void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) {
}
void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) {
idxset_entry **a, *e = NULL;
assert(s && idx);
struct idxset_entry **a, *e = NULL;
pa_assert(s);
pa_assert(idx);
if ((a = array_index(s, *idx)) && *a)
e = (*a)->iterate_next;
@ -337,7 +356,7 @@ void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) {
}
void* pa_idxset_first(pa_idxset *s, uint32_t *idx) {
assert(s);
pa_assert(s);
if (!s->iterate_list_head)
return NULL;
@ -348,9 +367,10 @@ void* pa_idxset_first(pa_idxset *s, uint32_t *idx) {
}
void *pa_idxset_next(pa_idxset *s, uint32_t *idx) {
idxset_entry **a, *e = NULL;
assert(s);
assert(idx);
struct idxset_entry **a, *e = NULL;
pa_assert(s);
pa_assert(idx);
if ((a = array_index(s, *idx)) && *a)
e = (*a)->iterate_next;
@ -365,13 +385,15 @@ void *pa_idxset_next(pa_idxset *s, uint32_t *idx) {
}
int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) {
idxset_entry *e;
assert(s && func);
struct idxset_entry *e;
pa_assert(s);
pa_assert(func);
e = s->iterate_list_head;
while (e) {
int del = 0, r;
idxset_entry *n = e->iterate_next;
struct idxset_entry *n = e->iterate_next;
r = func(e->data, e->index, &del, userdata);
@ -388,12 +410,14 @@ int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del,
}
unsigned pa_idxset_size(pa_idxset*s) {
assert(s);
pa_assert(s);
return s->n_entries;
}
int pa_idxset_isempty(pa_idxset *s) {
assert(s);
pa_assert(s);
return s->n_entries == 0;
}

View file

@ -44,11 +44,6 @@ int pa_idxset_trivial_compare_func(const void *a, const void *b);
unsigned pa_idxset_string_hash_func(const void *p);
int pa_idxset_string_compare_func(const void *a, const void *b);
#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p))
#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u))
#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p))
#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR(u)
typedef unsigned (*pa_hash_func_t)(const void *p);
typedef int (*pa_compare_func_t)(const void *a, const void *b);

View file

@ -47,7 +47,7 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) {
switch (af) {
case AF_INET:
snprintf(dst, cnt, "%d.%d.%d.%d",
pa_snprintf(dst, cnt, "%d.%d.%d.%d",
#ifdef WORDS_BIGENDIAN
(int)(in->s_addr >> 24) & 0xff,
(int)(in->s_addr >> 16) & 0xff,
@ -61,7 +61,7 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) {
#endif
break;
case AF_INET6:
snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
pa_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],

View file

@ -27,7 +27,6 @@
#endif
#include <stdlib.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@ -47,6 +46,7 @@
#include <pulsecore/core-util.h>
#include <pulsecore/socket-util.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "iochannel.h"
@ -58,21 +58,21 @@ struct pa_iochannel {
pa_iochannel_cb_t callback;
void*userdata;
int readable;
int writable;
int hungup;
pa_bool_t readable;
pa_bool_t writable;
pa_bool_t hungup;
int no_close;
pa_bool_t no_close;
pa_io_event* input_event, *output_event;
};
static void enable_mainloop_sources(pa_iochannel *io) {
assert(io);
pa_assert(io);
if (io->input_event == io->output_event && io->input_event) {
pa_io_event_flags_t f = PA_IO_EVENT_NULL;
assert(io->input_event);
pa_assert(io->input_event);
if (!io->readable)
f |= PA_IO_EVENT_INPUT;
@ -90,28 +90,28 @@ static void enable_mainloop_sources(pa_iochannel *io) {
static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
pa_iochannel *io = userdata;
int changed = 0;
pa_bool_t changed = FALSE;
assert(m);
assert(e);
assert(fd >= 0);
assert(userdata);
pa_assert(m);
pa_assert(e);
pa_assert(fd >= 0);
pa_assert(userdata);
if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
io->hungup = 1;
changed = 1;
io->hungup = TRUE;
changed = TRUE;
}
if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
io->readable = 1;
changed = 1;
assert(e == io->input_event);
io->readable = TRUE;
changed = TRUE;
pa_assert(e == io->input_event);
}
if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
io->writable = 1;
changed = 1;
assert(e == io->output_event);
io->writable = TRUE;
changed = TRUE;
pa_assert(e == io->output_event);
}
if (changed) {
@ -125,8 +125,8 @@ static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_fla
pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
pa_iochannel *io;
assert(m);
assert(ifd >= 0 || ofd >= 0);
pa_assert(m);
pa_assert(ifd >= 0 || ofd >= 0);
io = pa_xnew(pa_iochannel, 1);
io->ifd = ifd;
@ -136,26 +136,26 @@ pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
io->userdata = NULL;
io->callback = NULL;
io->readable = 0;
io->writable = 0;
io->hungup = 0;
io->no_close = 0;
io->readable = FALSE;
io->writable = FALSE;
io->hungup = FALSE;
io->no_close = FALSE;
io->input_event = io->output_event = NULL;
if (ifd == ofd) {
assert(ifd >= 0);
pa_make_nonblock_fd(io->ifd);
pa_assert(ifd >= 0);
pa_make_fd_nonblock(io->ifd);
io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io);
} else {
if (ifd >= 0) {
pa_make_nonblock_fd(io->ifd);
pa_make_fd_nonblock(io->ifd);
io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io);
}
if (ofd >= 0) {
pa_make_nonblock_fd(io->ofd);
pa_make_fd_nonblock(io->ofd);
io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io);
}
}
@ -164,7 +164,7 @@ pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
}
void pa_iochannel_free(pa_iochannel*io) {
assert(io);
pa_assert(io);
if (io->input_event)
io->mainloop->io_free(io->input_event);
@ -182,20 +182,20 @@ void pa_iochannel_free(pa_iochannel*io) {
pa_xfree(io);
}
int pa_iochannel_is_readable(pa_iochannel*io) {
assert(io);
pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
pa_assert(io);
return io->readable || io->hungup;
}
int pa_iochannel_is_writable(pa_iochannel*io) {
assert(io);
pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
pa_assert(io);
return io->writable && !io->hungup;
}
int pa_iochannel_is_hungup(pa_iochannel*io) {
assert(io);
pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
pa_assert(io);
return io->hungup;
}
@ -203,14 +203,13 @@ int pa_iochannel_is_hungup(pa_iochannel*io) {
ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
ssize_t r;
assert(io);
assert(data);
assert(l);
assert(io->ofd >= 0);
pa_assert(io);
pa_assert(data);
pa_assert(l);
pa_assert(io->ofd >= 0);
r = pa_write(io->ofd, data, l, &io->ofd_type);
if (r >= 0) {
io->writable = 0;
if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
io->writable = FALSE;
enable_mainloop_sources(io);
}
@ -220,13 +219,12 @@ ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
ssize_t r;
assert(io);
assert(data);
assert(io->ifd >= 0);
pa_assert(io);
pa_assert(data);
pa_assert(io->ifd >= 0);
r = pa_read(io->ifd, data, l, &io->ifd_type);
if (r >= 0) {
io->readable = 0;
if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
io->readable = FALSE;
enable_mainloop_sources(io);
}
@ -235,13 +233,13 @@ ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
#ifdef HAVE_CREDS
int pa_iochannel_creds_supported(pa_iochannel *io) {
pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
struct sockaddr_un sa;
socklen_t l;
assert(io);
assert(io->ifd >= 0);
assert(io->ofd == io->ifd);
pa_assert(io);
pa_assert(io->ifd >= 0);
pa_assert(io->ofd == io->ifd);
l = sizeof(sa);
@ -254,8 +252,8 @@ int pa_iochannel_creds_supported(pa_iochannel *io) {
int pa_iochannel_creds_enable(pa_iochannel *io) {
int t = 1;
assert(io);
assert(io->ifd >= 0);
pa_assert(io);
pa_assert(io->ifd >= 0);
if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
@ -273,10 +271,10 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l
struct ucred *u;
struct cmsghdr *cmsg;
assert(io);
assert(data);
assert(l);
assert(io->ofd >= 0);
pa_assert(io);
pa_assert(data);
pa_assert(l);
pa_assert(io->ofd >= 0);
memset(&iov, 0, sizeof(iov));
iov.iov_base = (void*) data;
@ -309,25 +307,25 @@ ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l
mh.msg_flags = 0;
if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
io->writable = 0;
io->writable = FALSE;
enable_mainloop_sources(io);
}
return r;
}
ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, int *creds_valid) {
ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) {
ssize_t r;
struct msghdr mh;
struct iovec iov;
uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))];
assert(io);
assert(data);
assert(l);
assert(io->ifd >= 0);
assert(creds);
assert(creds_valid);
pa_assert(io);
pa_assert(data);
pa_assert(l);
pa_assert(io->ifd >= 0);
pa_assert(creds);
pa_assert(creds_valid);
memset(&iov, 0, sizeof(iov));
iov.iov_base = data;
@ -353,17 +351,17 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
struct ucred u;
assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
pa_assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
memcpy(&u, CMSG_DATA(cmsg), sizeof(struct ucred));
creds->gid = u.gid;
creds->uid = u.uid;
*creds_valid = 1;
*creds_valid = TRUE;
break;
}
}
io->readable = 0;
io->readable = FALSE;
enable_mainloop_sources(io);
}
@ -373,46 +371,52 @@ ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_cr
#endif /* HAVE_CREDS */
void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
assert(io);
pa_assert(io);
io->callback = _callback;
io->userdata = userdata;
}
void pa_iochannel_set_noclose(pa_iochannel*io, int b) {
assert(io);
void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
pa_assert(io);
io->no_close = b;
io->no_close = !!b;
}
void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
assert(io);
assert(s);
assert(l);
pa_assert(io);
pa_assert(s);
pa_assert(l);
pa_socket_peer_to_string(io->ifd, s, l);
}
int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
assert(io);
pa_assert(io);
return pa_socket_set_rcvbuf(io->ifd, l);
}
int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
assert(io);
pa_assert(io);
return pa_socket_set_sndbuf(io->ofd, l);
}
pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
assert(io);
pa_assert(io);
return io->mainloop;
}
int pa_iochannel_get_recv_fd(pa_iochannel *io) {
assert(io);
pa_assert(io);
return io->ifd;
}
int pa_iochannel_get_send_fd(pa_iochannel *io) {
pa_assert(io);
return io->ofd;
}

View file

@ -25,10 +25,15 @@
USA.
***/
#ifndef PACKAGE
#error "Please include config.h before including this file!"
#endif
#include <sys/types.h>
#include <pulse/mainloop-api.h>
#include <pulsecore/creds.h>
#include <pulsecore/macro.h>
/* A wrapper around UNIX file descriptors for attaching them to the a
main event loop. Everytime new data may be read or be written to
@ -54,20 +59,20 @@ ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l);
ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l);
#ifdef HAVE_CREDS
int pa_iochannel_creds_supported(pa_iochannel *io);
pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io);
int pa_iochannel_creds_enable(pa_iochannel *io);
ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred);
ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, int *creds_valid);
ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, pa_bool_t *creds_valid);
#endif
int pa_iochannel_is_readable(pa_iochannel*io);
int pa_iochannel_is_writable(pa_iochannel*io);
int pa_iochannel_is_hungup(pa_iochannel*io);
pa_bool_t pa_iochannel_is_readable(pa_iochannel*io);
pa_bool_t pa_iochannel_is_writable(pa_iochannel*io);
pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io);
/* Don't close the file descirptors when the io channel is freed. By
* default the file descriptors are closed. */
void pa_iochannel_set_noclose(pa_iochannel*io, int b);
void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b);
/* Set the callback function that is called whenever data becomes available for read or write */
typedef void (*pa_iochannel_cb_t)(pa_iochannel*io, void *userdata);
@ -83,5 +88,6 @@ int pa_iochannel_socket_set_sndbuf(pa_iochannel*io, size_t l);
pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io);
int pa_iochannel_get_recv_fd(pa_iochannel *io);
int pa_iochannel_get_send_fd(pa_iochannel *io);
#endif

View file

@ -27,14 +27,16 @@
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <pulse/xmalloc.h>
#include <pulsecore/winsock.h>
#include <pulsecore/core-error.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/refcnt.h>
#include "ioline.h"
@ -42,10 +44,11 @@
#define READ_SIZE (1024)
struct pa_ioline {
PA_REFCNT_DECLARE;
pa_iochannel *io;
pa_defer_event *defer_event;
pa_mainloop_api *mainloop;
int ref;
int dead;
char *wbuf;
@ -65,9 +68,10 @@ static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata);
pa_ioline* pa_ioline_new(pa_iochannel *io) {
pa_ioline *l;
assert(io);
pa_assert(io);
l = pa_xnew(pa_ioline, 1);
PA_REFCNT_INIT(l);
l->io = io;
l->dead = 0;
@ -79,7 +83,6 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) {
l->callback = NULL;
l->userdata = NULL;
l->ref = 1;
l->mainloop = pa_iochannel_get_mainloop_api(io);
@ -94,7 +97,7 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) {
}
static void ioline_free(pa_ioline *l) {
assert(l);
pa_assert(l);
if (l->io)
pa_iochannel_free(l->io);
@ -108,24 +111,24 @@ static void ioline_free(pa_ioline *l) {
}
void pa_ioline_unref(pa_ioline *l) {
assert(l);
assert(l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
if ((--l->ref) <= 0)
if (PA_REFCNT_DEC(l) <= 0)
ioline_free(l);
}
pa_ioline* pa_ioline_ref(pa_ioline *l) {
assert(l);
assert(l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
l->ref++;
PA_REFCNT_INC(l);
return l;
}
void pa_ioline_close(pa_ioline *l) {
assert(l);
assert(l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
l->dead = 1;
@ -146,9 +149,9 @@ void pa_ioline_close(pa_ioline *l) {
void pa_ioline_puts(pa_ioline *l, const char *c) {
size_t len;
assert(l);
assert(l->ref >= 1);
assert(c);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
pa_assert(c);
if (l->dead)
return;
@ -158,7 +161,7 @@ void pa_ioline_puts(pa_ioline *l, const char *c) {
len = BUFFER_LIMIT - l->wbuf_valid_length;
if (len) {
assert(l->wbuf_length >= l->wbuf_valid_length);
pa_assert(l->wbuf_length >= l->wbuf_valid_length);
/* In case the allocated buffer is too small, enlarge it. */
if (l->wbuf_valid_length + len > l->wbuf_length) {
@ -178,7 +181,7 @@ void pa_ioline_puts(pa_ioline *l, const char *c) {
l->wbuf_index = 0;
}
assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length);
pa_assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length);
/* Append the new string */
memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len);
@ -189,17 +192,17 @@ void pa_ioline_puts(pa_ioline *l, const char *c) {
}
void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) {
assert(l);
assert(l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
l->callback = callback;
l->userdata = userdata;
}
static void failure(pa_ioline *l, int process_leftover) {
assert(l);
assert(l->ref >= 1);
assert(!l->dead);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
pa_assert(!l->dead);
if (process_leftover && l->rbuf_valid_length > 0) {
/* Pass the last missing bit to the client */
@ -220,7 +223,9 @@ static void failure(pa_ioline *l, int process_leftover) {
}
static void scan_for_lines(pa_ioline *l, size_t skip) {
assert(l && l->ref >= 1 && skip < l->rbuf_valid_length);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
pa_assert(skip < l->rbuf_valid_length);
while (!l->dead && l->rbuf_valid_length > skip) {
char *e, *p;
@ -255,7 +260,8 @@ static void scan_for_lines(pa_ioline *l, size_t skip) {
static int do_write(pa_ioline *l);
static int do_read(pa_ioline *l) {
assert(l && l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
while (!l->dead && pa_iochannel_is_readable(l->io)) {
ssize_t r;
@ -289,11 +295,11 @@ static int do_read(pa_ioline *l) {
len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
assert(len >= READ_SIZE);
pa_assert(len >= READ_SIZE);
/* Read some data */
if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) {
if (r < 0) {
if (r < 0 && errno != ECONNRESET) {
pa_log("read(): %s", pa_cstrerror(errno));
failure(l, 0);
} else
@ -314,13 +320,19 @@ static int do_read(pa_ioline *l) {
/* Try to flush the buffer */
static int do_write(pa_ioline *l) {
ssize_t r;
assert(l && l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) {
if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) {
pa_log("write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) <= 0) {
if (r < 0 && errno != EPIPE)
pa_log("write(): %s", pa_cstrerror(errno));
failure(l, 0);
return -1;
}
@ -337,8 +349,8 @@ static int do_write(pa_ioline *l) {
/* Try to flush read/write data */
static void do_work(pa_ioline *l) {
assert(l);
assert(l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
pa_ioline_ref(l);
@ -358,21 +370,28 @@ static void do_work(pa_ioline *l) {
static void io_callback(pa_iochannel*io, void *userdata) {
pa_ioline *l = userdata;
assert(io && l && l->ref >= 1);
pa_assert(io);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
do_work(l);
}
static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) {
pa_ioline *l = userdata;
assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
pa_assert(l->mainloop == m);
pa_assert(l->defer_event == e);
do_work(l);
}
void pa_ioline_defer_close(pa_ioline *l) {
assert(l);
assert(l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
l->defer_close = 1;
@ -384,8 +403,8 @@ void pa_ioline_printf(pa_ioline *l, const char *format, ...) {
char *t;
va_list ap;
assert(l);
assert(l->ref >= 1);
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
va_start(ap, format);
t = pa_vsprintf_malloc(format, ap);

View file

@ -46,13 +46,13 @@
#include <arpa/inet.h>
#endif
#include "winsock.h"
#include <pulse/xmalloc.h>
#include <pulsecore/core-util.h>
#include <pulsecore/llist.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/winsock.h>
#ifndef HAVE_INET_PTON
#include "inet_pton.h"
@ -77,7 +77,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) {
char *a;
pa_ip_acl *acl;
assert(s);
pa_assert(s);
acl = pa_xnew(pa_ip_acl, 1);
PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
@ -91,7 +91,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) {
*slash = 0;
slash++;
if (pa_atou(slash, &bits) < 0) {
pa_log("failed to parse number of bits: %s", slash);
pa_log_warn("Failed to parse number of bits: %s", slash);
goto fail;
}
} else
@ -102,21 +102,21 @@ pa_ip_acl* pa_ip_acl_new(const char *s) {
e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
if (e.bits > 32) {
pa_log("number of bits out of range: %i", e.bits);
pa_log_warn("Number of bits out of range: %i", e.bits);
goto fail;
}
e.family = AF_INET;
if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
} else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
if (e.bits > 128) {
pa_log("number of bits out of range: %i", e.bits);
pa_log_warn("Number of bits out of range: %i", e.bits);
goto fail;
}
e.family = AF_INET6;
@ -138,11 +138,11 @@ pa_ip_acl* pa_ip_acl_new(const char *s) {
}
if (t)
pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
}
} else {
pa_log("failed to parse address: %s", a);
pa_log_warn("Failed to parse address: %s", a);
goto fail;
}
@ -162,7 +162,7 @@ fail:
}
void pa_ip_acl_free(pa_ip_acl *acl) {
assert(acl);
pa_assert(acl);
while (acl->entries) {
struct acl_entry *e = acl->entries;
@ -178,8 +178,8 @@ int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
struct acl_entry *e;
socklen_t salen;
assert(acl);
assert(fd >= 0);
pa_assert(acl);
pa_assert(fd >= 0);
salen = sizeof(sa);
if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)

View file

@ -24,77 +24,86 @@
USA.
***/
#include <assert.h>
#include <pulsecore/macro.h>
/* Some macros for maintaining doubly linked lists */
/* The head of the linked list. Use this in the structure that shall
* contain the head of the linked list */
#define PA_LLIST_HEAD(t,name) t *name
#define PA_LLIST_HEAD(t,name) \
t *name
/* The pointers in the linked list's items. Use this in the item structure */
#define PA_LLIST_FIELDS(t) t *next, *prev
#define PA_LLIST_FIELDS(t) \
t *next, *prev
/* Initialize the list's head */
#define PA_LLIST_HEAD_INIT(t,item) do { (item) = (t*) NULL; } while(0)
#define PA_LLIST_HEAD_INIT(t,item) \
do { \
(item) = (t*) NULL; } \
while(0)
/* Initialize a list item */
#define PA_LLIST_INIT(t,item) do { \
t *_item = (item); \
assert(_item); \
_item->prev = _item->next = NULL; \
} while(0)
#define PA_LLIST_INIT(t,item) \
do { \
t *_item = (item); \
pa_assert(_item); \
_item->prev = _item->next = NULL; \
} while(0)
/* Prepend an item to the list */
#define PA_LLIST_PREPEND(t,head,item) do { \
t **_head = &(head), *_item = (item); \
assert(_item); \
if ((_item->next = *_head)) \
_item->next->prev = _item; \
_item->prev = NULL; \
*_head = _item; \
} while (0)
#define PA_LLIST_PREPEND(t,head,item) \
do { \
t **_head = &(head), *_item = (item); \
pa_assert(_item); \
if ((_item->next = *_head)) \
_item->next->prev = _item; \
_item->prev = NULL; \
*_head = _item; \
} while (0)
/* Remove an item from the list */
#define PA_LLIST_REMOVE(t,head,item) do { \
t **_head = &(head), *_item = (item); \
assert(_item); \
if (_item->next) \
_item->next->prev = _item->prev; \
if (_item->prev) \
_item->prev->next = _item->next; \
else {\
assert(*_head == _item); \
*_head = _item->next; \
} \
_item->next = _item->prev = NULL; \
} while(0)
#define PA_LLIST_REMOVE(t,head,item) \
do { \
t **_head = &(head), *_item = (item); \
pa_assert(_item); \
if (_item->next) \
_item->next->prev = _item->prev; \
if (_item->prev) \
_item->prev->next = _item->next; \
else { \
pa_assert(*_head == _item); \
*_head = _item->next; \
} \
_item->next = _item->prev = NULL; \
} while(0)
#define PA_LLIST_FIND_HEAD(t,item,head) \
do { \
t **_head = (head), *_item = (item); \
*_head = _item; \
assert(_head); \
while ((*_head)->prev) \
*_head = (*_head)->prev; \
} while (0)
#define PA_LLIST_INSERT_AFTER(t,head,a,b) \
do { \
t **_head = &(head), *_a = (a), *_b = (b); \
assert(_b); \
if (!_a) { \
if ((_b->next = *_head)) \
_b->next->prev = _b; \
_b->prev = NULL; \
*_head = _b; \
} else { \
if ((_b->next = _a->next)) \
_b->next->prev = _b; \
_b->prev = _a; \
_a->next = _b; \
} \
} while (0)
/* Find the head of the list */
#define PA_LLIST_FIND_HEAD(t,item,head) \
do { \
t **_head = (head), *_item = (item); \
*_head = _item; \
pa_assert(_head); \
while ((*_head)->prev) \
*_head = (*_head)->prev; \
} while (0)
/* Insert an item after another one (a = where, b = what) */
#define PA_LLIST_INSERT_AFTER(t,head,a,b) \
do { \
t **_head = &(head), *_a = (a), *_b = (b); \
pa_assert(_b); \
if (!_a) { \
if ((_b->next = *_head)) \
_b->next->prev = _b; \
_b->prev = NULL; \
*_head = _b; \
} else { \
if ((_b->next = _a->next)) \
_b->next->prev = _b; \
_b->prev = _a; \
_a->next = _b; \
} \
} while (0)
#endif

View file

@ -26,7 +26,6 @@
#include <config.h>
#endif
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
@ -40,6 +39,7 @@
#include <pulse/xmalloc.h>
#include <pulse/util.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-util.h>
#include "log.h"
@ -71,24 +71,30 @@ static const char level_to_char[] = {
};
void pa_log_set_ident(const char *p) {
if (log_ident)
pa_xfree(log_ident);
if (log_ident_local)
pa_xfree(log_ident_local);
pa_xfree(log_ident);
pa_xfree(log_ident_local);
log_ident = pa_xstrdup(p);
log_ident_local = pa_utf8_to_locale(log_ident);
if (!log_ident_local)
if (!(log_ident_local = pa_utf8_to_locale(log_ident)))
log_ident_local = pa_xstrdup(log_ident);
}
/* To make valgrind shut up. */
static void ident_destructor(void) PA_GCC_DESTRUCTOR;
static void ident_destructor(void) {
pa_xfree(log_ident);
pa_xfree(log_ident_local);
}
void pa_log_set_maximal_level(pa_log_level_t l) {
assert(l < PA_LOG_LEVEL_MAX);
pa_assert(l < PA_LOG_LEVEL_MAX);
maximal_level = l;
}
void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) {
assert(t == PA_LOG_USER || !func);
pa_assert(t == PA_LOG_USER || !func);
log_target = t;
user_log_func = func;
}
@ -104,8 +110,8 @@ void pa_log_levelv_meta(
const char *e;
char *text, *t, *n, *location;
assert(level < PA_LOG_LEVEL_MAX);
assert(format);
pa_assert(level < PA_LOG_LEVEL_MAX);
pa_assert(format);
if ((e = getenv(ENV_LOGLEVEL)))
maximal_level = atoi(e);
@ -221,6 +227,7 @@ void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) {
void pa_log_level(pa_log_level_t level, const char *format, ...) {
va_list ap;
va_start(ap, format);
pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
va_end(ap);

View file

@ -0,0 +1,64 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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 <stdlib.h>
#include <ctype.h>
#include <pulse/xmalloc.h>
#include <pulse/util.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include "ltdl-helper.h"
pa_void_func_t pa_load_sym(lt_dlhandle handle, const char *module, const char *symbol) {
char *sn, *c;
pa_void_func_t f;
pa_assert(handle);
pa_assert(module);
pa_assert(symbol);
if ((f = ((pa_void_func_t) (long) lt_dlsym(handle, symbol))))
return f;
/* As the .la files might have been cleansed from the system, we should
* try with the ltdl prefix as well. */
sn = pa_sprintf_malloc("%s_LTX_%s", module, symbol);
for (c = sn; *c; c++)
if (!isalnum(*c))
*c = '_';
f = (pa_void_func_t) (long) lt_dlsym(handle, sn);
pa_xfree(sn);
return f;
}

View file

@ -0,0 +1,34 @@
#ifndef foopulsecoreltdlhelperhfoo
#define foopulsecoreltdlhelperhfoo
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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.
***/
#include <ltdl.h>
typedef void (*pa_void_func_t)(void);
pa_void_func_t pa_load_sym(lt_dlhandle handle, const char*module, const char *symbol);
#endif

149
src/pulsecore/macro.h Normal file
View file

@ -0,0 +1,149 @@
#ifndef foopulsemacrohfoo
#define foopulsemacrohfoo
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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.
***/
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <limits.h>
#include <unistd.h>
#include <pulsecore/log.h>
#ifndef PACKAGE
#error "Please include config.h before including this file!"
#endif
#if defined(PAGE_SIZE)
#define PA_PAGE_SIZE ((size_t) PAGE_SIZE)
#elif defined(PAGESIZE)
#define PA_PAGE_SIZE ((size_t) PAGESIZE)
#elif defined(HAVE_SYSCONF)
#define PA_PAGE_SIZE ((size_t) (sysconf(_SC_PAGE_SIZE)))
#else
/* Let's hope it's like x86. */
#define PA_PAGE_SIZE ((size_t) 4096)
#endif
static inline size_t pa_align(size_t l) {
return (((l + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*));
}
#define PA_ALIGN(x) (pa_align(x))
static inline void* pa_page_align_ptr(const void *p) {
return (void*) (((size_t) p) & ~(PA_PAGE_SIZE-1));
}
#define PA_PAGE_ALIGN_PTR(x) (pa_page_align_ptr(x))
static inline size_t pa_page_align(size_t l) {
return l & ~(PA_PAGE_SIZE-1);
}
#define PA_PAGE_ALIGN(x) (pa_page_align(x))
#define PA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef CLAMP
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#endif
/* This type is not intended to be used in exported APIs! Use classic "int" there! */
#ifdef HAVE_STD_BOOL
typedef _Bool pa_bool_t;
#else
typedef int pa_bool_t;
#endif
#ifndef FALSE
#define FALSE ((pa_bool_t) 0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
#ifdef __GNUC__
#define PA_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define PA_PRETTY_FUNCTION ""
#endif
#define pa_return_if_fail(expr) \
do { \
if (!(expr)) { \
pa_log_debug("%s: Assertion <%s> failed.\n", PA_PRETTY_FUNCTION, #expr ); \
return; \
} \
} while(0)
#define pa_return_val_if_fail(expr, val) \
do { \
if (!(expr)) { \
pa_log_debug("%s: Assertion <%s> failed.\n", PA_PRETTY_FUNCTION, #expr ); \
return (val); \
} \
} while(0)
#define pa_return_null_if_fail(expr) pa_return_val_if_fail(expr, NULL)
#define pa_assert assert
#define pa_assert_not_reached() pa_assert(!"Should not be reached.")
/* An assert which guarantees side effects of x */
#ifdef NDEBUG
#define pa_assert_se(x) x
#else
#define pa_assert_se(x) pa_assert(x)
#endif
#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p))
#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u))
#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p))
#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR((uint32_t) u)
#define PA_PTR_TO_INT(p) ((int) PA_PTR_TO_UINT(p))
#define PA_INT_TO_PTR(u) PA_UINT_TO_PTR((int) u)
#define PA_PTR_TO_INT32(p) ((int32_t) PA_PTR_TO_UINT(p))
#define PA_INT32_TO_PTR(u) PA_UINT_TO_PTR((int32_t) u)
#ifdef OS_IS_WIN32
#define PA_PATH_SEP "\\"
#define PA_PATH_SEP_CHAR '\\'
#else
#define PA_PATH_SEP "/"
#define PA_PATH_SEP_CHAR '/'
#endif
#endif

View file

@ -27,10 +27,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include "mcalign.h"
@ -41,7 +41,7 @@ struct pa_mcalign {
pa_mcalign *pa_mcalign_new(size_t base) {
pa_mcalign *m;
assert(base);
pa_assert(base);
m = pa_xnew(pa_mcalign, 1);
@ -53,7 +53,7 @@ pa_mcalign *pa_mcalign_new(size_t base) {
}
void pa_mcalign_free(pa_mcalign *m) {
assert(m);
pa_assert(m);
if (m->leftover.memblock)
pa_memblock_unref(m->leftover.memblock);
@ -65,13 +65,13 @@ void pa_mcalign_free(pa_mcalign *m) {
}
void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
assert(m);
assert(c);
pa_assert(m);
pa_assert(c);
assert(c->memblock);
assert(c->length > 0);
pa_assert(c->memblock);
pa_assert(c->length > 0);
assert(!m->current.memblock);
pa_assert(!m->current.memblock);
/* Append to the leftover memory block */
if (m->leftover.memblock) {
@ -91,9 +91,10 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
} else {
size_t l;
void *lo_data, *m_data;
/* We have to copy */
assert(m->leftover.length < m->base);
pa_assert(m->leftover.length < m->base);
l = m->base - m->leftover.length;
if (l > c->length)
@ -102,10 +103,15 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
/* Can we use the current block? */
pa_memchunk_make_writable(&m->leftover, m->base);
memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l);
lo_data = pa_memblock_acquire(m->leftover.memblock);
m_data = pa_memblock_acquire(c->memblock);
memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.length, (uint8_t*) m_data + c->index, l);
pa_memblock_release(m->leftover.memblock);
pa_memblock_release(c->memblock);
m->leftover.length += l;
assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length);
pa_assert(m->leftover.length <= m->base);
pa_assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock));
if (c->length > l) {
/* Save the remainder of the memory block */
@ -128,12 +134,13 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
}
int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
assert(m);
assert(c);
pa_assert(m);
pa_assert(c);
/* First test if there's a leftover memory block available */
if (m->leftover.memblock) {
assert(m->leftover.length > 0 && m->leftover.length <= m->base);
pa_assert(m->leftover.length > 0);
pa_assert(m->leftover.length <= m->base);
/* The leftover memory block is not yet complete */
if (m->leftover.length < m->base)
@ -155,13 +162,13 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
/* Now let's see if there is other data available */
if (m->current.memblock) {
size_t l;
assert(m->current.length >= m->base);
pa_assert(m->current.length >= m->base);
/* The length of the returned memory block */
l = m->current.length;
l /= m->base;
l *= m->base;
assert(l > 0);
pa_assert(l > 0);
/* Prepare the returned block */
*c = m->current;
@ -169,7 +176,7 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
c->length = l;
/* Drop that from the current memory block */
assert(l <= m->current.length);
pa_assert(l <= m->current.length);
m->current.index += l;
m->current.length -= l;
@ -178,7 +185,7 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
pa_memblock_unref(m->current.memblock);
else {
/* Move the raimainder to leftover */
assert(m->current.length < m->base && !m->leftover.memblock);
pa_assert(m->current.length < m->base && !m->leftover.memblock);
m->leftover = m->current;
}
@ -194,10 +201,10 @@ int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
}
size_t pa_mcalign_csize(pa_mcalign *m, size_t l) {
assert(m);
assert(l > 0);
pa_assert(m);
pa_assert(l > 0);
assert(!m->current.memblock);
pa_assert(!m->current.memblock);
if (m->leftover.memblock)
l += m->leftover.length;

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,7 @@
#include <sys/types.h>
#include <inttypes.h>
#include <pulse/def.h>
#include <pulsecore/llist.h>
#include <pulsecore/refcnt.h>
#include <pulsecore/atomic.h>
@ -58,45 +59,25 @@ typedef struct pa_memexport pa_memexport;
typedef void (*pa_memimport_release_cb_t)(pa_memimport *i, uint32_t block_id, void *userdata);
typedef void (*pa_memexport_revoke_cb_t)(pa_memexport *e, uint32_t block_id, void *userdata);
struct pa_memblock {
pa_memblock_type_t type;
int read_only; /* boolean */
PA_REFCNT_DECLARE; /* the reference counter */
size_t length;
void *data;
pa_mempool *pool;
union {
struct {
void (*free_cb)(void *p); /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */
} user;
struct {
uint32_t id;
pa_memimport_segment *segment;
} imported;
} per_type;
};
/* Please note that updates to this structure are not locked,
* i.e. n_allocated might be updated at a point in time where
* n_accumulated is not yet. Take these values with a grain of salt,
* threy are here for purely statistical reasons.*/
* they are here for purely statistical reasons.*/
struct pa_mempool_stat {
pa_atomic_int_t n_allocated;
pa_atomic_int_t n_accumulated;
pa_atomic_int_t n_imported;
pa_atomic_int_t n_exported;
pa_atomic_int_t allocated_size;
pa_atomic_int_t accumulated_size;
pa_atomic_int_t imported_size;
pa_atomic_int_t exported_size;
pa_atomic_t n_allocated;
pa_atomic_t n_accumulated;
pa_atomic_t n_imported;
pa_atomic_t n_exported;
pa_atomic_t allocated_size;
pa_atomic_t accumulated_size;
pa_atomic_t imported_size;
pa_atomic_t exported_size;
pa_atomic_int_t n_too_large_for_pool;
pa_atomic_int_t n_pool_full;
pa_atomic_t n_too_large_for_pool;
pa_atomic_t n_pool_full;
pa_atomic_int_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX];
pa_atomic_int_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX];
pa_atomic_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX];
pa_atomic_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX];
};
/* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */
@ -120,9 +101,20 @@ pa_memblock* pa_memblock_ref(pa_memblock*b);
/* This special unref function has to be called by the owner of the
memory of a static memory block when he wants to release all
references to the memory. This causes the memory to be copied and
converted into a PA_MEMBLOCK_DYNAMIC type memory block */
converted into a pool or malloc'ed memory block. Please note that this
function is not multiple caller safe, i.e. needs to be locked
manually if called from more than one thread at the same time. */
void pa_memblock_unref_fixed(pa_memblock*b);
int pa_memblock_is_read_only(pa_memblock *b);
int pa_memblock_ref_is_one(pa_memblock *b);
void* pa_memblock_acquire(pa_memblock *b);
void pa_memblock_release(pa_memblock *b);
size_t pa_memblock_get_length(pa_memblock *b);
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(int shared);
void pa_mempool_free(pa_mempool *p);
@ -130,6 +122,7 @@ const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p);
void pa_mempool_vacuum(pa_mempool *p);
int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id);
int pa_mempool_is_shared(pa_mempool *p);
size_t pa_mempool_block_size_max(pa_mempool *p);
/* For recieving blocks from other nodes */
pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata);

View file

@ -28,7 +28,6 @@
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -36,23 +35,29 @@
#include <pulsecore/log.h>
#include <pulsecore/mcalign.h>
#include <pulsecore/macro.h>
#include <pulsecore/flist.h>
#include "memblockq.h"
struct memblock_list {
struct memblock_list *next, *prev;
struct list_item {
struct list_item *next, *prev;
int64_t index;
pa_memchunk chunk;
};
PA_STATIC_FLIST_DECLARE(list_items, 0, pa_xfree);
struct pa_memblockq {
struct memblock_list *blocks, *blocks_tail;
struct list_item *blocks, *blocks_tail;
unsigned n_blocks;
size_t maxlength, tlength, base, prebuf, minreq;
int64_t read_index, write_index;
enum { PREBUF, RUNNING } state;
pa_bool_t in_prebuf;
pa_memblock *silence;
pa_mcalign *mcalign;
int64_t missing;
size_t requested;
};
pa_memblockq* pa_memblockq_new(
@ -66,8 +71,8 @@ pa_memblockq* pa_memblockq_new(
pa_memblockq* bq;
assert(base > 0);
assert(maxlength >= base);
pa_assert(base > 0);
pa_assert(maxlength >= base);
bq = pa_xnew(pa_memblockq, 1);
bq->blocks = bq->blocks_tail = NULL;
@ -77,13 +82,13 @@ pa_memblockq* pa_memblockq_new(
bq->read_index = bq->write_index = idx;
pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu",
(unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq);
(unsigned long) maxlength, (unsigned long) tlength, (unsigned long) base, (unsigned long) prebuf, (unsigned long) minreq);
bq->maxlength = ((maxlength+base-1)/base)*base;
assert(bq->maxlength >= base);
pa_assert(bq->maxlength >= base);
bq->tlength = ((tlength+base-1)/base)*base;
if (!bq->tlength || bq->tlength >= bq->maxlength)
if (bq->tlength <= 0 || bq->tlength > bq->maxlength)
bq->tlength = bq->maxlength;
bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf;
@ -102,15 +107,18 @@ pa_memblockq* pa_memblockq_new(
pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu",
(unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq);
bq->state = bq->prebuf ? PREBUF : RUNNING;
bq->in_prebuf = bq->prebuf > 0;
bq->silence = silence ? pa_memblock_ref(silence) : NULL;
bq->mcalign = NULL;
bq->missing = bq->tlength;
bq->requested = 0;
return bq;
}
void pa_memblockq_free(pa_memblockq* bq) {
assert(bq);
pa_assert(bq);
pa_memblockq_flush(bq);
@ -123,11 +131,11 @@ void pa_memblockq_free(pa_memblockq* bq) {
pa_xfree(bq);
}
static void drop_block(pa_memblockq *bq, struct memblock_list *q) {
assert(bq);
assert(q);
static void drop_block(pa_memblockq *bq, struct list_item *q) {
pa_assert(bq);
pa_assert(q);
assert(bq->n_blocks >= 1);
pa_assert(bq->n_blocks >= 1);
if (q->prev)
q->prev->next = q->next;
@ -140,15 +148,17 @@ static void drop_block(pa_memblockq *bq, struct memblock_list *q) {
bq->blocks_tail = q->prev;
pa_memblock_unref(q->chunk.memblock);
pa_xfree(q);
if (pa_flist_push(PA_STATIC_FLIST_GET(list_items), q) < 0)
pa_xfree(q);
bq->n_blocks--;
}
static int can_push(pa_memblockq *bq, size_t l) {
static pa_bool_t can_push(pa_memblockq *bq, size_t l) {
int64_t end;
assert(bq);
pa_assert(bq);
if (bq->read_index > bq->write_index) {
size_t d = bq->read_index - bq->write_index;
@ -156,7 +166,7 @@ static int can_push(pa_memblockq *bq, size_t l) {
if (l > d)
l -= d;
else
return 1;
return TRUE;
}
end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0;
@ -164,21 +174,21 @@ static int can_push(pa_memblockq *bq, size_t l) {
/* Make sure that the list doesn't get too long */
if (bq->write_index + (int64_t)l > end)
if (bq->write_index + l - bq->read_index > bq->maxlength)
return 0;
return FALSE;
return 1;
return TRUE;
}
int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
struct memblock_list *q, *n;
struct list_item *q, *n;
pa_memchunk chunk;
int64_t old, delta;
assert(bq);
assert(uchunk);
assert(uchunk->memblock);
assert(uchunk->length > 0);
assert(uchunk->index + uchunk->length <= uchunk->memblock->length);
pa_assert(bq);
pa_assert(uchunk);
pa_assert(uchunk->memblock);
pa_assert(uchunk->length > 0);
pa_assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock));
if (uchunk->length % bq->base)
return -1;
@ -186,6 +196,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
if (!can_push(bq, uchunk->length))
return -1;
old = bq->write_index;
chunk = *uchunk;
if (bq->read_index > bq->write_index) {
@ -198,11 +209,11 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
if (chunk.length > d) {
chunk.index += d;
chunk.length -= d;
bq->write_index = bq->read_index;
bq->write_index += d;
} else {
/* We drop the incoming data completely */
bq->write_index += chunk.length;
return 0;
goto finish;
}
}
@ -212,10 +223,10 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
q = bq->blocks_tail;
while (q) {
if (bq->write_index >= q->index + (int64_t)q->chunk.length)
if (bq->write_index >= q->index + (int64_t) q->chunk.length)
/* We found the entry where we need to place the new entry immediately after */
break;
else if (bq->write_index + (int64_t)chunk.length <= q->index) {
else if (bq->write_index + (int64_t) chunk.length <= q->index) {
/* This entry isn't touched at all, let's skip it */
q = q->prev;
} else if (bq->write_index <= q->index &&
@ -223,7 +234,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
/* This entry is fully replaced by the new entry, so let's drop it */
struct memblock_list *p;
struct list_item *p;
p = q;
q = q->prev;
drop_block(bq, p);
@ -234,17 +245,19 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
if (bq->write_index + chunk.length < q->index + q->chunk.length) {
/* We need to save the end of this memchunk */
struct memblock_list *p;
struct list_item *p;
size_t d;
/* Create a new list entry for the end of thie memchunk */
p = pa_xnew(struct memblock_list, 1);
if (!(p = pa_flist_pop(PA_STATIC_FLIST_GET(list_items))))
p = pa_xnew(struct list_item, 1);
p->chunk = q->chunk;
pa_memblock_ref(p->chunk.memblock);
/* Calculate offset */
d = bq->write_index + chunk.length - q->index;
assert(d > 0);
pa_assert(d > 0);
/* Drop it from the new entry */
p->index = q->index + d;
@ -263,7 +276,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
/* Truncate the chunk */
if (!(q->chunk.length = bq->write_index - q->index)) {
struct memblock_list *p;
struct list_item *p;
p = q;
q = q->prev;
drop_block(bq, p);
@ -274,7 +287,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
} else {
size_t d;
assert(bq->write_index + (int64_t)chunk.length > q->index &&
pa_assert(bq->write_index + (int64_t)chunk.length > q->index &&
bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length &&
bq->write_index < q->index);
@ -287,12 +300,11 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
q = q->prev;
}
}
if (q) {
assert(bq->write_index >= q->index + (int64_t)q->chunk.length);
assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index));
pa_assert(bq->write_index >= q->index + (int64_t)q->chunk.length);
pa_assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index));
/* Try to merge memory blocks */
@ -302,13 +314,14 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
q->chunk.length += chunk.length;
bq->write_index += chunk.length;
return 0;
goto finish;
}
} else
assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index));
pa_assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index));
if (!(n = pa_flist_pop(PA_STATIC_FLIST_GET(list_items))))
n = pa_xnew(struct list_item, 1);
n = pa_xnew(struct memblock_list, 1);
n->chunk = chunk;
pa_memblock_ref(n->chunk.memblock);
n->index = bq->write_index;
@ -328,27 +341,52 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
bq->blocks = n;
bq->n_blocks++;
finish:
delta = bq->write_index - old;
if (delta >= bq->requested) {
delta -= bq->requested;
bq->requested = 0;
} else {
bq->requested -= delta;
delta = 0;
}
bq->missing -= delta;
return 0;
}
int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
assert(bq);
assert(chunk);
static pa_bool_t memblockq_check_prebuf(pa_memblockq *bq) {
pa_assert(bq);
if (bq->state == PREBUF) {
if (bq->in_prebuf) {
/* We need to pre-buffer */
if (pa_memblockq_get_length(bq) < bq->prebuf)
return -1;
return TRUE;
bq->state = RUNNING;
bq->in_prebuf = FALSE;
return FALSE;
} else {
} else if (bq->prebuf > 0 && bq->read_index >= bq->write_index) {
if (bq->prebuf > 0 && bq->read_index >= bq->write_index) {
bq->in_prebuf = TRUE;
return TRUE;
}
/* Buffer underflow protection */
bq->state = PREBUF;
return -1;
return FALSE;
}
}
int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
pa_assert(bq);
pa_assert(chunk);
/* We need to pre-buffer */
if (memblockq_check_prebuf(bq))
return -1;
/* Do we need to spit out silence? */
if (!bq->blocks || bq->blocks->index > bq->read_index) {
@ -362,8 +400,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
if (bq->silence) {
chunk->memblock = pa_memblock_ref(bq->silence);
if (!length || length > chunk->memblock->length)
length = chunk->memblock->length;
if (!length || length > pa_memblock_get_length(chunk->memblock))
length = pa_memblock_get_length(chunk->memblock);
chunk->length = length;
} else {
@ -382,7 +420,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
}
/* Ok, let's pass real data to the caller */
assert(bq->blocks->index == bq->read_index);
pa_assert(bq->blocks->index == bq->read_index);
*chunk = bq->blocks->chunk;
pa_memblock_ref(chunk->memblock);
@ -390,48 +428,23 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
return 0;
}
void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) {
assert(bq);
assert(length % bq->base == 0);
void pa_memblockq_drop(pa_memblockq *bq, size_t length) {
int64_t old, delta;
pa_assert(bq);
pa_assert(length % bq->base == 0);
assert(!chunk || length <= chunk->length);
if (chunk) {
if (bq->blocks && bq->blocks->index == bq->read_index) {
/* The first item in queue is valid */
/* Does the chunk match with what the user supplied us? */
if (memcmp(chunk, &bq->blocks->chunk, sizeof(pa_memchunk)) != 0)
return;
} else {
size_t l;
/* The first item in the queue is not yet relevant */
assert(!bq->blocks || bq->blocks->index > bq->read_index);
l = bq->blocks ? bq->blocks->index - bq->read_index : 0;
if (bq->silence) {
if (!l || l > bq->silence->length)
l = bq->silence->length;
}
/* Do the entries still match? */
if (chunk->index != 0 || chunk->length != l || chunk->memblock != bq->silence)
return;
}
}
old = bq->read_index;
while (length > 0) {
/* Do not drop any data when we are in prebuffering mode */
if (memblockq_check_prebuf(bq))
break;
if (bq->blocks) {
size_t d;
assert(bq->blocks->index >= bq->read_index);
pa_assert(bq->blocks->index >= bq->read_index);
d = (size_t) (bq->blocks->index - bq->read_index);
@ -446,7 +459,7 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length
bq->read_index += d;
}
assert(bq->blocks->index == bq->read_index);
pa_assert(bq->blocks->index == bq->read_index);
if (bq->blocks->chunk.length <= length) {
/* We need to drop the full block */
@ -472,35 +485,25 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length
break;
}
}
delta = bq->read_index - old;
bq->missing += delta;
}
int pa_memblockq_is_readable(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
if (bq->prebuf > 0) {
size_t l = pa_memblockq_get_length(bq);
if (memblockq_check_prebuf(bq))
return 0;
if (bq->state == PREBUF && l < bq->prebuf)
return 0;
if (l <= 0)
return 0;
}
if (pa_memblockq_get_length(bq) <= 0)
return 0;
return 1;
}
int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) {
assert(bq);
if (length % bq->base)
return 0;
return pa_memblockq_get_length(bq) + length <= bq->tlength;
}
size_t pa_memblockq_get_length(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
if (bq->write_index <= bq->read_index)
return 0;
@ -510,76 +513,106 @@ size_t pa_memblockq_get_length(pa_memblockq *bq) {
size_t pa_memblockq_missing(pa_memblockq *bq) {
size_t l;
assert(bq);
pa_assert(bq);
if ((l = pa_memblockq_get_length(bq)) >= bq->tlength)
return 0;
l = bq->tlength - l;
return (l >= bq->minreq) ? l : 0;
return l >= bq->minreq ? l : 0;
}
size_t pa_memblockq_get_minreq(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
return bq->minreq;
}
void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) {
assert(bq);
int64_t old, delta;
pa_assert(bq);
old = bq->write_index;
switch (seek) {
case PA_SEEK_RELATIVE:
bq->write_index += offset;
return;
break;
case PA_SEEK_ABSOLUTE:
bq->write_index = offset;
return;
break;
case PA_SEEK_RELATIVE_ON_READ:
bq->write_index = bq->read_index + offset;
return;
break;
case PA_SEEK_RELATIVE_END:
bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t)bq->blocks_tail->chunk.length : bq->read_index) + offset;
return;
bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t) bq->blocks_tail->chunk.length : bq->read_index) + offset;
break;
default:
pa_assert_not_reached();
}
assert(0);
delta = bq->write_index - old;
if (delta >= bq->requested) {
delta -= bq->requested;
bq->requested = 0;
} else if (delta >= 0) {
bq->requested -= delta;
delta = 0;
}
bq->missing -= delta;
}
void pa_memblockq_flush(pa_memblockq *bq) {
assert(bq);
int64_t old, delta;
pa_assert(bq);
while (bq->blocks)
drop_block(bq, bq->blocks);
assert(bq->n_blocks == 0);
pa_assert(bq->n_blocks == 0);
old = bq->write_index;
bq->write_index = bq->read_index;
pa_memblockq_prebuf_force(bq);
delta = bq->write_index - old;
if (delta > bq->requested) {
delta -= bq->requested;
bq->requested = 0;
} else if (delta >= 0) {
bq->requested -= delta;
delta = 0;
}
bq->missing -= delta;
}
size_t pa_memblockq_get_tlength(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
return bq->tlength;
}
int64_t pa_memblockq_get_read_index(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
return bq->read_index;
}
int64_t pa_memblockq_get_write_index(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
return bq->write_index;
}
int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) {
pa_memchunk rchunk;
assert(bq);
assert(chunk && bq->base);
pa_assert(bq);
pa_assert(chunk);
if (bq->base == 1)
return pa_memblockq_push(bq, chunk);
@ -606,36 +639,52 @@ int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) {
void pa_memblockq_shorten(pa_memblockq *bq, size_t length) {
size_t l;
assert(bq);
pa_assert(bq);
l = pa_memblockq_get_length(bq);
if (l > length)
pa_memblockq_drop(bq, NULL, l - length);
pa_memblockq_drop(bq, l - length);
}
void pa_memblockq_prebuf_disable(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
if (bq->state == PREBUF)
bq->state = RUNNING;
bq->in_prebuf = FALSE;
}
void pa_memblockq_prebuf_force(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
if (bq->state == RUNNING && bq->prebuf > 0)
bq->state = PREBUF;
if (!bq->in_prebuf && bq->prebuf > 0)
bq->in_prebuf = TRUE;
}
size_t pa_memblockq_get_maxlength(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
return bq->maxlength;
}
size_t pa_memblockq_get_prebuf(pa_memblockq *bq) {
assert(bq);
pa_assert(bq);
return bq->prebuf;
}
size_t pa_memblockq_pop_missing(pa_memblockq *bq) {
size_t l;
pa_assert(bq);
/* pa_log("pop: %lli", bq->missing); */
if (bq->missing <= 0)
return 0;
l = (size_t) bq->missing;
bq->missing = 0;
bq->requested += l;
return l;
}

View file

@ -62,7 +62,7 @@ typedef struct pa_memblockq pa_memblockq;
- minreq: pa_memblockq_missing() will only return values greater
than this value. Pass 0 for the default.
- silence: return this memblock whzen reading unitialized data
- silence: return this memblock when reading unitialized data
*/
pa_memblockq* pa_memblockq_new(
int64_t idx,
@ -83,26 +83,30 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *chunk);
* you know what you do. */
int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk);
/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */
/* Return a copy of the next memory chunk in the queue. It is not
* removed from the queue. There are two reasons this function might
* fail: 1. prebuffering is active, 2. queue is empty and no silence
* memblock was passed at initialization. If the queue is not empty,
* but we're currently at a hole in the queue and no silence memblock
* was passed we return the length of the hole in chunk->length. */
int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk);
/* Drop the specified bytes from the queue, but only if the first
* chunk in the queue matches the one passed here. If NULL is passed,
* this check isn't done. */
void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length);
/* Drop the specified bytes from the queue. */
void pa_memblockq_drop(pa_memblockq *bq, size_t length);
/* Test if the pa_memblockq is currently readable, that is, more data than base */
int pa_memblockq_is_readable(pa_memblockq *bq);
/* Test if the pa_memblockq is currently writable for the specified amount of bytes */
int pa_memblockq_is_writable(pa_memblockq *bq, size_t length);
/* Return the length of the queue in bytes */
size_t pa_memblockq_get_length(pa_memblockq *bq);
/* Return how many bytes are missing in queue to the specified fill amount */
size_t pa_memblockq_missing(pa_memblockq *bq);
/* Return the number of bytes that are missing since the last call to
* this function, reset the internal counter to 0. */
size_t pa_memblockq_pop_missing(pa_memblockq *bq);
/* Returns the minimal request value */
size_t pa_memblockq_get_minreq(pa_memblockq *bq);

View file

@ -27,40 +27,66 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include <pulsecore/core-util.h>
#include "memchunk.h"
void pa_memchunk_make_writable(pa_memchunk *c, size_t min) {
pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min) {
pa_memblock *n;
size_t l;
void *tdata, *sdata;
assert(c);
assert(c->memblock);
assert(PA_REFCNT_VALUE(c->memblock) > 0);
pa_assert(c);
pa_assert(c->memblock);
if (PA_REFCNT_VALUE(c->memblock) == 1 &&
!c->memblock->read_only &&
c->memblock->length >= c->index+min)
return;
if (pa_memblock_ref_is_one(c->memblock) &&
!pa_memblock_is_read_only(c->memblock) &&
pa_memblock_get_length(c->memblock) >= c->index+min)
return c;
l = c->length;
if (l < min)
l = min;
n = pa_memblock_new(c->memblock->pool, l);
memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length);
n = pa_memblock_new(pa_memblock_get_pool(c->memblock), l);
tdata = pa_memblock_acquire(n);
sdata = pa_memblock_acquire(c->memblock);
memcpy(tdata, (uint8_t*) sdata + c->index, c->length);
pa_memblock_release(n);
pa_memblock_release(c->memblock);
pa_memblock_unref(c->memblock);
c->memblock = n;
c->index = 0;
return c;
}
void pa_memchunk_reset(pa_memchunk *c) {
assert(c);
pa_memchunk* pa_memchunk_reset(pa_memchunk *c) {
pa_assert(c);
c->memblock = NULL;
c->length = c->index = 0;
return c;
}
pa_memchunk *pa_memchunk_will_need(const pa_memchunk *c) {
void *p;
pa_assert(c);
pa_assert(c->memblock);
/* A version of pa_memblock_will_need() that works on memchunks
* instead of memblocks */
p = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
pa_will_need(p, c->length);
pa_memblock_release(c->memblock);
return (pa_memchunk*) c;
}

View file

@ -37,11 +37,16 @@ typedef struct pa_memchunk {
/* Make a memchunk writable, i.e. make sure that the caller may have
* exclusive access to the memblock and it is not read_only. If needed
* the memblock in the structure is replaced by a copy. */
void pa_memchunk_make_writable(pa_memchunk *c, size_t min);
* the memblock in the structure is replaced by a copy. If min is not
* 0 it is made sure that the returned memblock is at least of the
* specified size, i.e. is enlarged if necessary. */
pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min);
/* Invalidate a memchunk. This does not free the cotaining memblock,
* but sets all members to zero. */
void pa_memchunk_reset(pa_memchunk *c);
pa_memchunk* pa_memchunk_reset(pa_memchunk *c);
/* Map a memory chunk back into memory if it was swapped out */
pa_memchunk *pa_memchunk_will_need(const pa_memchunk *c);
#endif

View file

@ -26,7 +26,6 @@
#endif
#include <ctype.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -39,6 +38,7 @@
#include <pulsecore/sink.h>
#include <pulsecore/source.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include "modargs.h"
@ -48,7 +48,10 @@ struct entry {
static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) {
struct entry *e;
assert(map && key && value);
pa_assert(map);
pa_assert(key);
pa_assert(value);
if (valid_keys) {
const char*const* v;
@ -63,10 +66,11 @@ static int add_key_value(pa_hashmap *map, char *key, char *value, const char* co
}
}
e = pa_xmalloc(sizeof(struct entry));
e = pa_xnew(struct entry, 1);
e->key = key;
e->value = value;
pa_hashmap_put(map, key, e);
return 0;
}
@ -74,7 +78,6 @@ pa_modargs *pa_modargs_new(const char *args, const char* const* valid_keys) {
pa_hashmap *map = NULL;
map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
assert(map);
if (args) {
enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state;
@ -166,10 +169,10 @@ fail:
return NULL;
}
static void free_func(void *p, PA_GCC_UNUSED void*userdata) {
struct entry *e = p;
assert(e);
pa_assert(e);
pa_xfree(e->key);
pa_xfree(e->value);
pa_xfree(e);
@ -192,7 +195,10 @@ const char *pa_modargs_get_value(pa_modargs *ma, const char *key, const char *de
int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
const char *v;
assert(ma && key && value);
pa_assert(ma);
pa_assert(key);
pa_assert(value);
if (!(v = pa_modargs_get_value(ma, key, NULL)))
return 0;
@ -205,7 +211,10 @@ int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
const char *v;
assert(ma && key && value);
pa_assert(ma);
pa_assert(key);
pa_assert(value);
if (!(v = pa_modargs_get_value(ma, key, NULL)))
return 0;
@ -219,7 +228,10 @@ int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) {
const char *v;
int r;
assert(ma && key && value);
pa_assert(ma);
pa_assert(key);
pa_assert(value);
if (!(v = pa_modargs_get_value(ma, key, NULL)))
return 0;
@ -238,9 +250,9 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
const char *format;
uint32_t channels;
pa_sample_spec ss;
assert(ma && rss);
/* DEBUG_TRAP;*/
pa_assert(ma);
pa_assert(rss);
ss = *rss;
if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0)
@ -263,16 +275,16 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
return 0;
}
int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) {
int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *rmap) {
pa_channel_map map;
const char *cm;
assert(ma);
assert(rmap);
pa_assert(ma);
pa_assert(rmap);
map = *rmap;
if ((cm = pa_modargs_get_value(ma, "channel_map", NULL)))
if ((cm = pa_modargs_get_value(ma, name ? name : "channel_map", NULL)))
if (!pa_channel_map_parse(&map, cm))
return -1;
@ -287,9 +299,9 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *r
pa_sample_spec ss;
pa_channel_map map;
assert(ma);
assert(rss);
assert(rmap);
pa_assert(ma);
pa_assert(rss);
pa_assert(rmap);
ss = *rss;
@ -299,7 +311,7 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *r
if (!pa_channel_map_init_auto(&map, ss.channels, def))
map.channels = 0;
if (pa_modargs_get_channel_map(ma, &map) < 0)
if (pa_modargs_get_channel_map(ma, NULL, &map) < 0)
return -1;
if (map.channels != ss.channels)

View file

@ -49,8 +49,8 @@ int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value);
/* Return sample spec data from the three arguments "rate", "format" and "channels" */
int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss);
/* Return channel map data from the argument "channel_map" */
int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *map);
/* Return channel map data from the argument "channel_map" if name is NULL, otherwise read from the specified argument */
int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *map);
/* Combination of pa_modargs_get_sample_spec() and
pa_modargs_get_channel_map(). Not always suitable, since this routine

View file

@ -26,12 +26,13 @@
#endif
#include <ltdl.h>
#include <assert.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/ltdl-helper.h>
#include "modinfo.h"
@ -40,30 +41,24 @@
#define PA_SYMBOL_USAGE "pa__get_usage"
#define PA_SYMBOL_VERSION "pa__get_version"
/* lt_dlsym() violates ISO C, so confide the breakage into this function to
* avoid warnings. */
typedef void (*fnptr)(void);
static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) {
return (fnptr) (long) lt_dlsym(handle, symbol);
}
pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) {
pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl, const char *module_name) {
pa_modinfo *i;
const char* (*func)(void);
assert(dl);
pa_assert(dl);
i = pa_xnew0(pa_modinfo, 1);
if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_AUTHOR)))
if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_AUTHOR)))
i->author = pa_xstrdup(func());
if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_DESCRIPTION)))
if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_DESCRIPTION)))
i->description = pa_xstrdup(func());
if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_USAGE)))
if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_USAGE)))
i->usage = pa_xstrdup(func());
if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_VERSION)))
if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_VERSION)))
i->version = pa_xstrdup(func());
return i;
@ -72,21 +67,23 @@ pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) {
pa_modinfo *pa_modinfo_get_by_name(const char *name) {
lt_dlhandle dl;
pa_modinfo *i;
assert(name);
pa_assert(name);
if (!(dl = lt_dlopenext(name))) {
pa_log("Failed to open module \"%s\": %s", name, lt_dlerror());
return NULL;
}
i = pa_modinfo_get_by_handle(dl);
i = pa_modinfo_get_by_handle(dl, name);
lt_dlclose(dl);
return i;
}
void pa_modinfo_free(pa_modinfo *i) {
assert(i);
pa_assert(i);
pa_xfree(i->author);
pa_xfree(i->description);
pa_xfree(i->usage);

View file

@ -34,7 +34,7 @@ typedef struct pa_modinfo {
} pa_modinfo;
/* Read meta data from an libtool handle */
pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl);
pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl, const char *module_name);
/* Read meta data from a module file */
pa_modinfo *pa_modinfo_get_by_name(const char *name);

View file

@ -29,7 +29,6 @@
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
@ -40,6 +39,8 @@
#include <pulsecore/core-subscribe.h>
#include <pulsecore/log.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include <pulsecore/ltdl-helper.h>
#include "module.h"
@ -48,69 +49,31 @@
#define UNLOAD_POLL_TIME 2
/* lt_dlsym() violates ISO C, so confide the breakage into this function to
* avoid warnings. */
typedef void (*fnptr)(void);
static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) {
return (fnptr) (long) lt_dlsym(handle, symbol);
}
static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
pa_core *c = userdata;
pa_core *c = PA_CORE(userdata);
struct timeval ntv;
assert(c && c->mainloop == m && c->module_auto_unload_event == e);
pa_core_assert_ref(c);
pa_assert(c->mainloop == m);
pa_assert(c->module_auto_unload_event == e);
pa_module_unload_unused(c);
pa_gettimeofday(&ntv);
ntv.tv_sec += UNLOAD_POLL_TIME;
pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000);
m->time_restart(e, &ntv);
}
static inline fnptr load_sym(lt_dlhandle handle, const char *module, const char *symbol) {
char *buffer, *ch;
size_t buflen;
fnptr res;
res = lt_dlsym_fn(handle, symbol);
if (res)
return res;
/* As the .la files might have been cleansed from the system, we should
* try with the ltdl prefix as well. */
buflen = strlen(symbol) + strlen(module) + strlen("_LTX_") + 1;
buffer = pa_xmalloc(buflen);
assert(buffer);
strcpy(buffer, module);
for (ch = buffer;*ch != '\0';ch++) {
if (!isalnum(*ch))
*ch = '_';
}
strcat(buffer, "_LTX_");
strcat(buffer, symbol);
res = lt_dlsym_fn(handle, buffer);
pa_xfree(buffer);
return res;
}
pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
pa_module *m = NULL;
int r;
assert(c && name);
pa_assert(c);
pa_assert(name);
if (c->disallow_module_loading)
goto fail;
m = pa_xmalloc(sizeof(pa_module));
m = pa_xnew(pa_module, 1);
m->name = pa_xstrdup(name);
m->argument = pa_xstrdup(argument);
@ -119,24 +82,19 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
goto fail;
}
if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_INIT))) {
if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) {
pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name);
goto fail;
}
if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_DONE))) {
pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name);
goto fail;
}
m->done = (void (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_DONE);
m->userdata = NULL;
m->core = c;
m->n_used = -1;
m->auto_unload = 0;
m->unload_requested = 0;
assert(m->init);
if (m->init(c, m) < 0) {
if (m->init(m) < 0) {
pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
goto fail;
}
@ -147,14 +105,12 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
if (!c->module_auto_unload_event) {
struct timeval ntv;
pa_gettimeofday(&ntv);
ntv.tv_sec += UNLOAD_POLL_TIME;
pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000);
c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c);
}
assert(c->module_auto_unload_event);
assert(c->modules);
r = pa_idxset_put(c->modules, m, &m->index);
assert(r >= 0 && m->index != PA_IDXSET_INVALID);
pa_assert_se(pa_idxset_put(c->modules, m, &m->index) >= 0);
pa_assert(m->index != PA_IDXSET_INVALID);
pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : "");
@ -178,14 +134,16 @@ fail:
}
static void pa_module_free(pa_module *m) {
assert(m && m->done && m->core);
pa_assert(m);
pa_assert(m->core);
if (m->core->disallow_module_loading)
return;
pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index);
m->done(m->core, m);
if (m->done)
m->done(m);
lt_dlclose(m->dl);
@ -199,9 +157,10 @@ static void pa_module_free(pa_module *m) {
}
void pa_module_unload(pa_core *c, pa_module *m) {
assert(c && m);
pa_assert(c);
pa_assert(m);
assert(c->modules);
pa_assert(c->modules);
if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL)))
return;
@ -210,9 +169,9 @@ void pa_module_unload(pa_core *c, pa_module *m) {
void pa_module_unload_by_index(pa_core *c, uint32_t idx) {
pa_module *m;
assert(c && idx != PA_IDXSET_INVALID);
pa_assert(c);
pa_assert(idx != PA_IDXSET_INVALID);
assert(c->modules);
if (!(m = pa_idxset_remove_by_index(c->modules, idx)))
return;
@ -221,13 +180,14 @@ void pa_module_unload_by_index(pa_core *c, uint32_t idx) {
static void free_callback(void *p, PA_GCC_UNUSED void *userdata) {
pa_module *m = p;
assert(m);
pa_assert(m);
pa_module_free(m);
}
void pa_module_unload_all(pa_core *c) {
pa_module *m;
assert(c);
pa_assert(c);
if (!c->modules)
return;
@ -252,7 +212,10 @@ void pa_module_unload_all(pa_core *c) {
static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *userdata) {
pa_module *m = p;
time_t *now = userdata;
assert(p && del && now);
pa_assert(m);
pa_assert(del);
pa_assert(now);
if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) {
pa_module_free(m);
@ -264,7 +227,7 @@ static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *
void pa_module_unload_unused(pa_core *c) {
time_t now;
assert(c);
pa_assert(c);
if (!c->modules)
return;
@ -275,7 +238,7 @@ void pa_module_unload_unused(pa_core *c) {
static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC_UNUSED void *userdata) {
pa_module *m = p;
assert(m);
pa_assert(m);
if (m->unload_requested) {
pa_module_free(m);
@ -286,18 +249,19 @@ static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC
}
static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) {
pa_core *core = userdata;
pa_core *core = PA_CORE(userdata);
pa_core_assert_ref(core);
api->defer_enable(e, 0);
if (!core->modules)
return;
pa_idxset_foreach(core->modules, unload_callback, NULL);
}
void pa_module_unload_request(pa_module *m) {
assert(m);
pa_assert(m);
m->unload_requested = 1;
@ -308,19 +272,19 @@ void pa_module_unload_request(pa_module *m) {
}
void pa_module_set_used(pa_module*m, int used) {
assert(m);
pa_assert(m);
if (m->n_used != used)
pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index);
if (m->n_used != used && used == 0)
if (used == 0 && m->n_used > 0)
time(&m->last_used_time);
m->n_used = used;
}
pa_modinfo *pa_module_get_info(pa_module *m) {
assert(m);
pa_assert(m);
return pa_modinfo_get_by_handle(m->dl);
return pa_modinfo_get_by_handle(m->dl, m->name);
}

View file

@ -39,8 +39,8 @@ struct pa_module {
lt_dlhandle dl;
int (*init)(pa_core *c, pa_module*m);
void (*done)(pa_core *c, pa_module*m);
int (*init)(pa_module*m);
void (*done)(pa_module*m);
void *userdata;
@ -62,9 +62,9 @@ void pa_module_unload_request(pa_module *m);
void pa_module_set_used(pa_module*m, int used);
#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; }
#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; }
#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; }
#define PA_MODULE_AUTHOR(s) const char *pa__get_author(void) { return s; }
#define PA_MODULE_DESCRIPTION(s) const char *pa__get_description(void) { return s; }
#define PA_MODULE_USAGE(s) const char *pa__get_usage(void) { return s; }
#define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; }
pa_modinfo *pa_module_get_info(pa_module *m);

49
src/pulsecore/msgobject.c Normal file
View file

@ -0,0 +1,49 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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 "msgobject.h"
PA_DEFINE_CHECK_TYPE(pa_msgobject, pa_object);
pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)) {
pa_msgobject *o;
pa_assert(size > sizeof(pa_msgobject));
pa_assert(type_name);
if (!check_type)
check_type = pa_msgobject_check_type;
pa_assert(check_type(type_name));
pa_assert(check_type("pa_object"));
pa_assert(check_type("pa_msgobject"));
o = PA_MSGOBJECT(pa_object_new_internal(size, type_name, check_type));
o->process_msg = NULL;
return o;
}

54
src/pulsecore/msgobject.h Normal file
View file

@ -0,0 +1,54 @@
#ifndef foopulsemsgobjecthfoo
#define foopulsemsgobjecthfoo
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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.
***/
#include <sys/types.h>
#include <pulse/xmalloc.h>
#include <pulsecore/refcnt.h>
#include <pulsecore/macro.h>
#include <pulsecore/object.h>
#include <pulsecore/memchunk.h>
typedef struct pa_msgobject pa_msgobject;
struct pa_msgobject {
pa_object parent;
int (*process_msg)(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
};
pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name));
int pa_msgobject_check_type(const char *type);
#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(type), #type, type##_check_type))
#define pa_msgobject_free ((void (*) (pa_msgobject* o)) pa_object_free)
#define PA_MSGOBJECT(o) pa_msgobject_cast(o)
PA_DECLARE_CLASS(pa_msgobject);
#endif

View file

@ -25,20 +25,16 @@
#include <config.h>
#endif
#include <assert.h>
#include <pthread.h>
#include <atomic_ops.h>
#include <errno.h>
#include <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include <pulsecore/log.h>
#include <pulsecore/core-error.h>
#include "mutex.h"
#define ASSERT_SUCCESS(x) do { \
int _r = (x); \
assert(_r == 0); \
} while(0)
struct pa_mutex {
pthread_mutex_t mutex;
};
@ -47,68 +43,88 @@ struct pa_cond {
pthread_cond_t cond;
};
pa_mutex* pa_mutex_new(int recursive) {
pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority) {
pa_mutex *m;
pthread_mutexattr_t attr;
int r;
pthread_mutexattr_init(&attr);
pa_assert_se(pthread_mutexattr_init(&attr) == 0);
if (recursive)
ASSERT_SUCCESS(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
pa_assert_se(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0);
#ifdef HAVE_PTHREAD_PRIO_INHERIT
if (inherit_priority)
pa_assert_se(pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT) == 0);
#endif
m = pa_xnew(pa_mutex, 1);
ASSERT_SUCCESS(pthread_mutex_init(&m->mutex, &attr));
#ifndef HAVE_PTHREAD_PRIO_INHERIT
pa_assert_se(pthread_mutex_init(&m->mutex, &attr) == 0);
#else
if ((r = pthread_mutex_init(&m->mutex, &attr))) {
/* If this failed, then this was probably due to non-available
* priority inheritance. In which case we fall back to normal
* mutexes. */
pa_assert(r == ENOTSUP && inherit_priority);
pa_assert_se(pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_NONE) == 0);
pa_assert_se(pthread_mutex_init(&m->mutex, &attr) == 0);
}
#endif
return m;
}
void pa_mutex_free(pa_mutex *m) {
assert(m);
pa_assert(m);
ASSERT_SUCCESS(pthread_mutex_destroy(&m->mutex));
pa_assert_se(pthread_mutex_destroy(&m->mutex) == 0);
pa_xfree(m);
}
void pa_mutex_lock(pa_mutex *m) {
assert(m);
pa_assert(m);
ASSERT_SUCCESS(pthread_mutex_lock(&m->mutex));
pa_assert_se(pthread_mutex_lock(&m->mutex) == 0);
}
void pa_mutex_unlock(pa_mutex *m) {
assert(m);
pa_assert(m);
ASSERT_SUCCESS(pthread_mutex_unlock(&m->mutex));
pa_assert_se(pthread_mutex_unlock(&m->mutex) == 0);
}
pa_cond *pa_cond_new(void) {
pa_cond *c;
c = pa_xnew(pa_cond, 1);
ASSERT_SUCCESS(pthread_cond_init(&c->cond, NULL));
pa_assert_se(pthread_cond_init(&c->cond, NULL) == 0);
return c;
}
void pa_cond_free(pa_cond *c) {
assert(c);
pa_assert(c);
ASSERT_SUCCESS(pthread_cond_destroy(&c->cond));
pa_assert_se(pthread_cond_destroy(&c->cond) == 0);
pa_xfree(c);
}
void pa_cond_signal(pa_cond *c, int broadcast) {
assert(c);
pa_assert(c);
if (broadcast)
ASSERT_SUCCESS(pthread_cond_broadcast(&c->cond));
pa_assert_se(pthread_cond_broadcast(&c->cond) == 0);
else
ASSERT_SUCCESS(pthread_cond_signal(&c->cond));
pa_assert_se(pthread_cond_signal(&c->cond) == 0);
}
int pa_cond_wait(pa_cond *c, pa_mutex *m) {
assert(c);
assert(m);
pa_assert(c);
pa_assert(m);
return pthread_cond_wait(&c->cond, &m->mutex);
}

View file

@ -40,7 +40,7 @@ struct pa_cond {
pa_hashmap *wait_events;
};
pa_mutex* pa_mutex_new(int recursive) {
pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority) {
pa_mutex *m;
m = pa_xnew(pa_mutex, 1);

View file

@ -24,9 +24,17 @@
USA.
***/
#include <pulsecore/macro.h>
typedef struct pa_mutex pa_mutex;
pa_mutex* pa_mutex_new(int recursive);
/* Please think twice before enabling priority inheritance. This is no
* magic wand! Use it only when the potentially priorized threads are
* good candidates for it. Don't use this blindly! Also, note that
* only very few operating systems actually implement this, hence this
* is merely a hint. */
pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority);
void pa_mutex_free(pa_mutex *m);
void pa_mutex_lock(pa_mutex *m);
void pa_mutex_unlock(pa_mutex *m);

View file

@ -27,7 +27,6 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
@ -38,6 +37,7 @@
#include <pulsecore/sink.h>
#include <pulsecore/core-subscribe.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include "namereg.h"
@ -90,23 +90,22 @@ static char* cleanup_name(const char *name) {
}
void pa_namereg_free(pa_core *c) {
assert(c);
pa_assert(c);
if (!c->namereg)
return;
assert(pa_hashmap_size(c->namereg) == 0);
pa_assert(pa_hashmap_size(c->namereg) == 0);
pa_hashmap_free(c->namereg, NULL, NULL);
}
const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) {
struct namereg_entry *e;
char *n = NULL;
int r;
assert(c);
assert(name);
assert(data);
pa_assert(c);
pa_assert(name);
pa_assert(data);
if (!*name)
return NULL;
@ -142,7 +141,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t
k = pa_xnew(char, l+4);
for (i = 2; i <= 99; i++) {
snprintf(k, l+4, "%s.%u", name, i);
pa_snprintf(k, l+4, "%s.%u", name, i);
if (!(e = pa_hashmap_get(c->namereg, k)))
break;
@ -163,8 +162,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t
e->name = n ? n : pa_xstrdup(name);
e->data = data;
r = pa_hashmap_put(c->namereg, e->name, e);
assert (r >= 0);
pa_assert_se(pa_hashmap_put(c->namereg, e->name, e) >= 0);
return e->name;
}
@ -172,11 +170,10 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t
void pa_namereg_unregister(pa_core *c, const char *name) {
struct namereg_entry *e;
assert(c);
assert(name);
pa_assert(c);
pa_assert(name);
e = pa_hashmap_remove(c->namereg, name);
assert(e);
pa_assert_se(e = pa_hashmap_remove(c->namereg, name));
pa_xfree(e->name);
pa_xfree(e);
@ -185,7 +182,7 @@ void pa_namereg_unregister(pa_core *c, const char *name) {
void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) {
struct namereg_entry *e;
uint32_t idx;
assert(c);
pa_assert(c);
if (!name) {
@ -245,8 +242,8 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int a
int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) {
char **s;
assert(c);
assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE);
pa_assert(c);
pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE);
s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name;
@ -269,7 +266,7 @@ int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type)
const char *pa_namereg_get_default_sink_name(pa_core *c) {
pa_sink *s;
assert(c);
pa_assert(c);
if (c->default_sink_name)
return c->default_sink_name;
@ -284,7 +281,7 @@ const char *pa_namereg_get_default_source_name(pa_core *c) {
pa_source *s;
uint32_t idx;
assert(c);
pa_assert(c);
if (c->default_source_name)
return c->default_source_name;

View file

@ -115,6 +115,11 @@ enum {
PA_COMMAND_MOVE_SINK_INPUT,
PA_COMMAND_MOVE_SOURCE_OUTPUT,
PA_COMMAND_SET_SINK_INPUT_MUTE,
PA_COMMAND_SUSPEND_SINK,
PA_COMMAND_SUSPEND_SOURCE,
PA_COMMAND_MAX
};

72
src/pulsecore/object.c Normal file
View file

@ -0,0 +1,72 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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 "object.h"
pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)) {
pa_object *o;
pa_assert(size > sizeof(pa_object));
pa_assert(type_name);
if (!check_type)
check_type = pa_object_check_type;
pa_assert(check_type(type_name));
pa_assert(check_type("pa_object"));
o = pa_xmalloc(size);
PA_REFCNT_INIT(o);
o->type_name = type_name;
o->free = pa_object_free;
o->check_type = check_type;
return o;
}
pa_object *pa_object_ref(pa_object *o) {
pa_object_assert_ref(o);
PA_REFCNT_INC(o);
return o;
}
void pa_object_unref(pa_object *o) {
pa_object_assert_ref(o);
if (PA_REFCNT_DEC(o) <= 0) {
pa_assert(o->free);
o->free(o);
}
}
int pa_object_check_type(const char *type_name) {
pa_assert(type_name);
return strcmp(type_name, "pa_object") == 0;
}

106
src/pulsecore/object.h Normal file
View file

@ -0,0 +1,106 @@
#ifndef foopulseobjecthfoo
#define foopulseobjecthfoo
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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.
***/
#include <string.h>
#include <sys/types.h>
#include <pulse/xmalloc.h>
#include <pulsecore/refcnt.h>
#include <pulsecore/macro.h>
typedef struct pa_object pa_object;
struct pa_object {
PA_REFCNT_DECLARE;
const char *type_name;
void (*free)(pa_object *o);
int (*check_type)(const char *type_name);
};
pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name));
#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), #type, type##_check_type)
#define pa_object_free ((void (*) (pa_object* o)) pa_xfree)
int pa_object_check_type(const char *type);
static inline int pa_object_isinstance(void *o) {
pa_object *obj = (pa_object*) o;
return obj ? obj->check_type("pa_object") : 0;
}
pa_object *pa_object_ref(pa_object *o);
void pa_object_unref(pa_object *o);
static inline int pa_object_refcnt(pa_object *o) {
return o ? PA_REFCNT_VALUE(o) : 0;
}
static inline pa_object* pa_object_cast(void *o) {
pa_object *obj = (pa_object*) o;
pa_assert(!obj || obj->check_type("pa_object"));
return obj;
}
#define pa_object_assert_ref(o) pa_assert(pa_object_refcnt(o) > 0)
#define PA_OBJECT(o) pa_object_cast(o)
#define PA_DECLARE_CLASS(c) \
static inline int c##_isinstance(void *o) { \
pa_object *obj = (pa_object*) o; \
return obj ? obj->check_type(#c) : 1; \
} \
static inline c* c##_cast(void *o) { \
pa_assert(c##_isinstance(o)); \
return (c*) o; \
} \
static inline c* c##_ref(c *o) { \
return (c*) pa_object_ref(PA_OBJECT(o)); \
} \
static inline void c##_unref(c* o) { \
pa_object_unref(PA_OBJECT(o)); \
} \
static inline int c##_refcnt(c* o) { \
return pa_object_refcnt(PA_OBJECT(o)); \
} \
static inline void c##_assert_ref(c *o) { \
pa_object_assert_ref(PA_OBJECT(o)); \
} \
struct __stupid_useless_struct_to_allow_trailing_semicolon
#define PA_DEFINE_CHECK_TYPE(c, parent) \
int c##_check_type(const char *type) { \
pa_assert(type); \
if (strcmp(type, #c) == 0) \
return 1; \
return parent##_check_type(type); \
} \
struct __stupid_useless_struct_to_allow_trailing_semicolon
#endif

View file

@ -1,71 +0,0 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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 <pthread.h>
#include <assert.h>
#include <pulsecore/mutex.h>
#include "once.h"
#define ASSERT_SUCCESS(x) do { \
int _r = (x); \
assert(_r == 0); \
} while(0)
static pa_mutex *global_mutex;
static pthread_once_t global_mutex_once = PTHREAD_ONCE_INIT;
static void global_mutex_once_func(void) {
global_mutex = pa_mutex_new(0);
}
void pa_once(pa_once_t *control, pa_once_func_t func) {
assert(control);
assert(func);
/* Create the global mutex */
ASSERT_SUCCESS(pthread_once(&global_mutex_once, global_mutex_once_func));
/* Create the local mutex */
pa_mutex_lock(global_mutex);
if (!control->mutex)
control->mutex = pa_mutex_new(1);
pa_mutex_unlock(global_mutex);
/* Execute function */
pa_mutex_lock(control->mutex);
if (!control->once_value) {
control->once_value = 1;
func();
}
pa_mutex_unlock(control->mutex);
/* Caveat: We have to make sure that the once func has completed
* before returning, even if the once func is not actually
* executed by us. Hence the awkward locking. */
}

View file

@ -1,69 +0,0 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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 <assert.h>
#include <stdio.h>
#include <windows.h>
#include <pulsecore/mutex.h>
#include "once.h"
void pa_once(pa_once_t *control, pa_once_func_t func) {
HANDLE mutex;
char name[64];
assert(control);
assert(func);
/* Create the global mutex */
sprintf(name, "pulse%d", (int)GetCurrentProcessId());
mutex = CreateMutex(NULL, FALSE, name);
assert(mutex);
/* Create the local mutex */
WaitForSingleObject(mutex, INFINITE);
if (!control->mutex)
control->mutex = pa_mutex_new(1);
ReleaseMutex(mutex);
CloseHandle(mutex);
/* Execute function */
pa_mutex_lock(control->mutex);
if (!control->once_value) {
control->once_value = 1;
func();
}
pa_mutex_unlock(control->mutex);
/* Caveat: We have to make sure that the once func has completed
* before returning, even if the once func is not actually
* executed by us. Hence the awkward locking. */
}

96
src/pulsecore/once.c Normal file
View file

@ -0,0 +1,96 @@
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 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 <pulsecore/macro.h>
#include <pulsecore/mutex.h>
#include "once.h"
int pa_once_begin(pa_once *control) {
pa_mutex *m;
pa_assert(control);
if (pa_atomic_load(&control->done))
return 0;
pa_atomic_inc(&control->ref);
/* Caveat: We have to make sure that the once func has completed
* before returning, even if the once func is not actually
* executed by us. Hence the awkward locking. */
for (;;) {
if ((m = pa_atomic_ptr_load(&control->mutex))) {
/* The mutex is stored in locked state, hence let's just
* wait until it is unlocked */
pa_mutex_lock(m);
pa_once_end(control);
return 0;
}
pa_assert_se(m = pa_mutex_new(FALSE, FALSE));
pa_mutex_lock(m);
if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m))
return 1;
pa_mutex_unlock(m);
pa_mutex_free(m);
}
}
void pa_once_end(pa_once *control) {
pa_mutex *m;
pa_assert(control);
pa_atomic_store(&control->done, 1);
pa_assert_se(m = pa_atomic_ptr_load(&control->mutex));
pa_mutex_unlock(m);
if (pa_atomic_dec(&control->ref) <= 1) {
pa_assert_se(pa_atomic_ptr_cmpxchg(&control->mutex, m, NULL));
pa_mutex_free(m);
}
}
/* Not reentrant -- how could it be? */
void pa_run_once(pa_once *control, pa_once_func_t func) {
pa_assert(control);
pa_assert(func);
if (pa_once_begin(control)) {
func();
pa_once_end(control);
}
}

View file

@ -25,16 +25,52 @@
***/
#include <pulsecore/mutex.h>
#include <pulsecore/atomic.h>
typedef struct pa_once {
unsigned int once_value;
pa_mutex *mutex;
} pa_once_t;
pa_atomic_ptr_t mutex;
pa_atomic_t ref, done;
} pa_once;
#define PA_ONCE_INIT { .once_value = 0, .mutex = NULL }
#define PA_ONCE_INIT \
{ \
.mutex = PA_ATOMIC_PTR_INIT(NULL), \
.ref = PA_ATOMIC_INIT(0), \
.done = PA_ATOMIC_INIT(0) \
}
/* Not to be called directly, use the macros defined below instead */
int pa_once_begin(pa_once *o);
void pa_once_end(pa_once *o);
#define PA_ONCE_BEGIN \
do { \
static pa_once _once = PA_ONCE_INIT; \
if (pa_once_begin(&_once)) {{
#define PA_ONCE_END \
} \
pa_once_end(&_once); \
} \
} while(0)
/*
Usage of these macros is like this:
void foo() {
PA_ONCE_BEGIN {
... stuff to be called just once ...
} PA_ONCE_END;
}
*/
/* Same API but calls a function */
typedef void (*pa_once_func_t) (void);
void pa_once(pa_once_t *o, pa_once_func_t f);
void pa_run_once(pa_once *o, pa_once_func_t f);
#endif

View file

@ -25,22 +25,22 @@
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include "packet.h"
pa_packet* pa_packet_new(size_t length) {
pa_packet *p;
assert(length);
pa_assert(length > 0);
p = pa_xmalloc(sizeof(pa_packet)+length);
p->ref = 1;
p = pa_xmalloc(PA_ALIGN(sizeof(pa_packet)) + length);
PA_REFCNT_INIT(p);
p->length = length;
p->data = (uint8_t*) (p+1);
p->data = (uint8_t*) p + PA_ALIGN(sizeof(pa_packet));
p->type = PA_PACKET_APPENDED;
return p;
@ -49,11 +49,11 @@ pa_packet* pa_packet_new(size_t length) {
pa_packet* pa_packet_new_dynamic(void* data, size_t length) {
pa_packet *p;
assert(data);
assert(length);
pa_assert(data);
pa_assert(length > 0);
p = pa_xnew(pa_packet, 1);
p->ref = 1;
PA_REFCNT_INIT(p);
p->length = length;
p->data = data;
p->type = PA_PACKET_DYNAMIC;
@ -62,18 +62,18 @@ pa_packet* pa_packet_new_dynamic(void* data, size_t length) {
}
pa_packet* pa_packet_ref(pa_packet *p) {
assert(p);
assert(p->ref >= 1);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) >= 1);
p->ref++;
PA_REFCNT_INC(p);
return p;
}
void pa_packet_unref(pa_packet *p) {
assert(p);
assert(p->ref >= 1);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) >= 1);
if (--p->ref == 0) {
if (PA_REFCNT_DEC(p) <= 0) {
if (p->type == PA_PACKET_DYNAMIC)
pa_xfree(p->data);
pa_xfree(p);

View file

@ -27,9 +27,11 @@
#include <sys/types.h>
#include <inttypes.h>
#include <pulsecore/refcnt.h>
typedef struct pa_packet {
PA_REFCNT_DECLARE;
enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type;
unsigned ref;
size_t length;
uint8_t *data;
} pa_packet;

View file

@ -26,13 +26,13 @@
#endif
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <pulse/xmalloc.h>
#include <pulse/util.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include "parseaddr.h"
@ -45,7 +45,9 @@
* Return a newly allocated string of the hostname and fill in *ret_port if specified */
static char *parse_host(const char *s, uint16_t *ret_port) {
assert(s && ret_port);
pa_assert(s);
pa_assert(ret_port);
if (*s == '[') {
char *e;
if (!(e = strchr(s+1, ']')))
@ -70,7 +72,10 @@ static char *parse_host(const char *s, uint16_t *ret_port) {
int pa_parse_address(const char *name, pa_parsed_address *ret_p) {
const char *p;
assert(name && ret_p);
pa_assert(name);
pa_assert(ret_p);
memset(ret_p, 0, sizeof(pa_parsed_address));
ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO;
@ -112,6 +117,5 @@ int pa_parse_address(const char *name, pa_parsed_address *ret_p) {
if (!(ret_p->path_or_host = parse_host(p, &ret_p->port)))
return -1;
return 0;
}

View file

@ -28,7 +28,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
@ -37,6 +36,8 @@
#include <pulsecore/llist.h>
#include <pulsecore/log.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include <pulsecore/refcnt.h>
#include "pdispatch.h"
@ -108,7 +109,7 @@ struct reply_info {
};
struct pa_pdispatch {
int ref;
PA_REFCNT_DECLARE;
pa_mainloop_api *mainloop;
const pa_pdispatch_cb_t *callback_table;
unsigned n_commands;
@ -119,7 +120,9 @@ struct pa_pdispatch {
};
static void reply_info_free(struct reply_info *r) {
assert(r && r->pdispatch && r->pdispatch->mainloop);
pa_assert(r);
pa_assert(r->pdispatch);
pa_assert(r->pdispatch->mainloop);
if (r->time_event)
r->pdispatch->mainloop->time_free(r->time_event);
@ -131,12 +134,12 @@ static void reply_info_free(struct reply_info *r) {
pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_t*table, unsigned entries) {
pa_pdispatch *pd;
assert(mainloop);
pa_assert(mainloop);
assert((entries && table) || (!entries && !table));
pa_assert((entries && table) || (!entries && !table));
pd = pa_xmalloc(sizeof(pa_pdispatch));
pd->ref = 1;
pd = pa_xnew(pa_pdispatch, 1);
PA_REFCNT_INIT(pd);
pd->mainloop = mainloop;
pd->callback_table = table;
pd->n_commands = entries;
@ -149,7 +152,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_
}
static void pdispatch_free(pa_pdispatch *pd) {
assert(pd);
pa_assert(pd);
while (pd->replies) {
if (pd->replies->free_cb)
@ -165,7 +168,7 @@ static void run_action(pa_pdispatch *pd, struct reply_info *r, uint32_t command,
pa_pdispatch_cb_t callback;
void *userdata;
uint32_t tag;
assert(r);
pa_assert(r);
pa_pdispatch_ref(pd);
@ -187,7 +190,12 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
uint32_t tag, command;
pa_tagstruct *ts = NULL;
int ret = -1;
assert(pd && packet && packet->data);
pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1);
pa_assert(packet);
pa_assert(PA_REFCNT_VALUE(packet) >= 1);
pa_assert(packet->data);
pa_pdispatch_ref(pd);
@ -195,7 +203,6 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
goto finish;
ts = pa_tagstruct_new(packet->data, packet->length);
assert(ts);
if (pa_tagstruct_getu32(ts, &command) < 0 ||
pa_tagstruct_getu32(ts, &tag) < 0)
@ -206,7 +213,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
char t[256];
char const *p;
if (!(p = command_names[command]))
snprintf((char*) (p = t), sizeof(t), "%u", command);
pa_snprintf((char*) (p = t), sizeof(t), "%u", command);
pa_log("Recieved opcode <%s>", p);
}
@ -248,7 +255,12 @@ finish:
static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
struct reply_info*r = userdata;
assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback);
pa_assert(r);
pa_assert(r->time_event == e);
pa_assert(r->pdispatch);
pa_assert(r->pdispatch->mainloop == m);
pa_assert(r->callback);
run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
}
@ -256,7 +268,10 @@ static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED c
void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb) {
struct reply_info *r;
struct timeval tv;
assert(pd && pd->ref >= 1 && cb);
pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1);
pa_assert(cb);
r = pa_xnew(struct reply_info, 1);
r->pdispatch = pd;
@ -268,21 +283,22 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa
pa_gettimeofday(&tv);
tv.tv_sec += timeout;
r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r);
assert(r->time_event);
pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r));
PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
}
int pa_pdispatch_is_pending(pa_pdispatch *pd) {
assert(pd);
pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1);
return !!pd->replies;
}
void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) {
assert(pd);
assert(!cb || pa_pdispatch_is_pending(pd));
pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1);
pa_assert(!cb || pa_pdispatch_is_pending(pd));
pd->drain_callback = cb;
pd->drain_userdata = userdata;
@ -290,7 +306,9 @@ void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *
void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
struct reply_info *r, *n;
assert(pd);
pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1);
for (r = pd->replies; r; r = n) {
n = r->next;
@ -301,21 +319,24 @@ void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
}
void pa_pdispatch_unref(pa_pdispatch *pd) {
assert(pd && pd->ref >= 1);
pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1);
if (!(--(pd->ref)))
if (PA_REFCNT_DEC(pd) <= 0)
pdispatch_free(pd);
}
pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {
assert(pd && pd->ref >= 1);
pd->ref++;
pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1);
PA_REFCNT_INC(pd);
return pd;
}
const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
assert(pd);
assert(pd->ref >= 1);
pa_assert(pd);
pa_assert(PA_REFCNT_VALUE(pd) >= 1);
return pd->creds;
}

View file

@ -33,7 +33,6 @@
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <limits.h>
#include <signal.h>
@ -47,6 +46,7 @@
#include <pulsecore/core-error.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "pid.h"
@ -57,11 +57,11 @@ static pid_t read_pid(const char *fn, int fd) {
char t[20], *e;
uint32_t pid;
assert(fn && fd >= 0);
pa_assert(fn);
pa_assert(fd >= 0);
if ((r = pa_loop_read(fd, t, sizeof(t)-1, NULL)) < 0) {
pa_log_warn("WARNING: failed to read PID file '%s': %s",
fn, pa_cstrerror(errno));
pa_log_warn("Failed to read PID file '%s': %s", fn, pa_cstrerror(errno));
return (pid_t) -1;
}
@ -73,7 +73,7 @@ static pid_t read_pid(const char *fn, int fd) {
*e = 0;
if (pa_atou(t, &pid) < 0) {
pa_log("WARNING: failed to parse PID file '%s'", fn);
pa_log_warn("Failed to parse PID file '%s'", fn);
return (pid_t) -1;
}
@ -83,13 +83,22 @@ static pid_t read_pid(const char *fn, int fd) {
static int open_pid_file(const char *fn, int mode) {
int fd = -1;
pa_assert(fn);
for (;;) {
struct stat st;
if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) {
if ((fd = open(fn, mode
#ifdef O_NOCTTY
|O_NOCTTY
#endif
#ifdef O_NOFOLLOW
|O_NOFOLLOW
#endif
, S_IRUSR|S_IWUSR
)) < 0) {
if (mode != O_RDONLY || errno != ENOENT)
pa_log_warn("WARNING: failed to open PID file '%s': %s",
fn, pa_cstrerror(errno));
pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
goto fail;
}
@ -98,8 +107,7 @@ static int open_pid_file(const char *fn, int mode) {
goto fail;
if (fstat(fd, &st) < 0) {
pa_log_warn("WARNING: failed to fstat() PID file '%s': %s",
fn, pa_cstrerror(errno));
pa_log_warn("Failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno));
goto fail;
}
@ -110,9 +118,9 @@ static int open_pid_file(const char *fn, int mode) {
if (pa_lock_fd(fd, 0) < 0)
goto fail;
if (close(fd) < 0) {
pa_log_warn("WARNING: failed to close file '%s': %s",
fn, pa_cstrerror(errno));
if (pa_close(fd) < 0) {
pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
fd = -1;
goto fail;
}
@ -125,7 +133,7 @@ fail:
if (fd >= 0) {
pa_lock_fd(fd, 0);
close(fd);
pa_close(fd);
}
return -1;
@ -150,7 +158,7 @@ int pa_pid_file_create(void) {
goto fail;
if ((pid = read_pid(fn, fd)) == (pid_t) -1)
pa_log("corrupt PID file, overwriting.");
pa_log_warn("Corrupt PID file, overwriting.");
else if (pid > 0) {
#ifdef OS_IS_WIN32
if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) {
@ -158,25 +166,24 @@ int pa_pid_file_create(void) {
#else
if (kill(pid, 0) >= 0 || errno != ESRCH) {
#endif
pa_log("daemon already running.");
pa_log("Daemon already running.");
goto fail;
}
pa_log("stale PID file, overwriting.");
pa_log_warn("Stale PID file, overwriting.");
}
/* Overwrite the current PID file */
if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) {
pa_log("failed to truncate PID file '%s': %s",
fn, pa_cstrerror(errno));
pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
goto fail;
}
snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
pa_snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
l = strlen(t);
if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) {
pa_log("failed to write PID file.");
pa_log("Failed to write PID file.");
goto fail;
}
@ -185,7 +192,11 @@ int pa_pid_file_create(void) {
fail:
if (fd >= 0) {
pa_lock_fd(fd, 0);
close(fd);
if (pa_close(fd) < 0) {
pa_log("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno));
ret = -1;
}
}
return ret;
@ -201,8 +212,7 @@ int pa_pid_file_remove(void) {
pa_runtime_path("pid", fn, sizeof(fn));
if ((fd = open_pid_file(fn, O_RDWR)) < 0) {
pa_log_warn("WARNING: failed to open PID file '%s': %s",
fn, pa_cstrerror(errno));
pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
goto fail;
}
@ -210,13 +220,12 @@ int pa_pid_file_remove(void) {
goto fail;
if (pid != getpid()) {
pa_log("WARNING: PID file '%s' not mine!", fn);
pa_log("PID file '%s' not mine!", fn);
goto fail;
}
if (ftruncate(fd, 0) < 0) {
pa_log_warn("WARNING: failed to truncate PID file '%s': %s",
fn, pa_cstrerror(errno));
pa_log_warn("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
goto fail;
}
@ -227,8 +236,7 @@ int pa_pid_file_remove(void) {
#endif
if (unlink(fn) < 0) {
pa_log_warn("WARNING: failed to remove PID file '%s': %s",
fn, pa_cstrerror(errno));
pa_log_warn("Failed to remove PID file '%s': %s", fn, pa_cstrerror(errno));
goto fail;
}
@ -238,7 +246,11 @@ fail:
if (fd >= 0) {
pa_lock_fd(fd, 0);
close(fd);
if (pa_close(fd) < 0) {
pa_log_warn("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno));
ret = -1;
}
}
return ret;
@ -280,7 +292,7 @@ fail:
if (fd >= 0) {
pa_lock_fd(fd, 0);
close(fd);
pa_close(fd);
}
return ret;

View file

@ -149,14 +149,14 @@ int pipe(int filedes[2]) {
return 0;
error:
if (listener >= 0)
pa_close(listener);
if (filedes[0] >= 0)
pa_close(filedes[0]);
if (filedes[1] >= 0)
pa_close(filedes[0]);
if (listener >= 0)
pa_close(listener);
if (filedes[0] >= 0)
pa_close(filedes[0]);
if (filedes[1] >= 0)
pa_close(filedes[0]);
return -1;
return -1;
}
#endif /* HAVE_PIPE */

View file

@ -26,7 +26,6 @@
#endif
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
@ -34,50 +33,171 @@
#include <pulsecore/sink-input.h>
#include <pulsecore/gccmacro.h>
#include <pulsecore/thread-mq.h>
#include "play-memblockq.h"
static void sink_input_kill(pa_sink_input *i) {
pa_memblockq *q;
assert(i);
assert(i->userdata);
typedef struct memblockq_stream {
pa_msgobject parent;
pa_core *core;
pa_sink_input *sink_input;
pa_memblockq *memblockq;
} memblockq_stream;
q = i->userdata;
enum {
MEMBLOCKQ_STREAM_MESSAGE_UNLINK,
};
pa_sink_input_disconnect(i);
pa_sink_input_unref(i);
PA_DECLARE_CLASS(memblockq_stream);
#define MEMBLOCKQ_STREAM(o) (memblockq_stream_cast(o))
static PA_DEFINE_CHECK_TYPE(memblockq_stream, pa_msgobject);
pa_memblockq_free(q);
static void memblockq_stream_unlink(memblockq_stream *u) {
pa_assert(u);
if (!u->sink_input)
return;
pa_sink_input_unlink(u->sink_input);
pa_sink_input_unref(u->sink_input);
u->sink_input = NULL;
memblockq_stream_unref(u);
}
static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
pa_memblockq *q;
assert(i);
assert(chunk);
assert(i->userdata);
static void memblockq_stream_free(pa_object *o) {
memblockq_stream *u = MEMBLOCKQ_STREAM(o);
pa_assert(u);
q = i->userdata;
memblockq_stream_unlink(u);
return pa_memblockq_peek(q, chunk);
if (u->memblockq)
pa_memblockq_free(u->memblockq);
pa_xfree(u);
}
static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) {
sink_input_kill(i);
static int memblockq_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
memblockq_stream *u = MEMBLOCKQ_STREAM(o);
memblockq_stream_assert_ref(u);
switch (code) {
case MEMBLOCKQ_STREAM_MESSAGE_UNLINK:
memblockq_stream_unlink(u);
break;
}
return 0;
}
static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) {
pa_memblockq *q;
static void sink_input_kill_cb(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
assert(i);
assert(length > 0);
assert( i->userdata);
memblockq_stream_unlink(MEMBLOCKQ_STREAM(i->userdata));
}
q = i->userdata;
static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
memblockq_stream *u;
pa_memblockq_drop(q, chunk, length);
pa_assert(i);
pa_assert(chunk);
u = MEMBLOCKQ_STREAM(i->userdata);
memblockq_stream_assert_ref(u);
if (pa_memblockq_get_length(q) <= 0)
pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i);
if (!u->memblockq)
return -1;
if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
pa_memblockq_free(u->memblockq);
u->memblockq = NULL;
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMBLOCKQ_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL);
return -1;
}
return 0;
}
static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
memblockq_stream *u;
pa_assert(i);
pa_assert(length > 0);
u = MEMBLOCKQ_STREAM(i->userdata);
memblockq_stream_assert_ref(u);
if (!u->memblockq)
return;
pa_memblockq_drop(u->memblockq, length);
}
pa_sink_input* pa_memblockq_sink_input_new(
pa_sink *sink,
const char *name,
const pa_sample_spec *ss,
const pa_channel_map *map,
pa_memblockq *q,
pa_cvolume *volume) {
memblockq_stream *u = NULL;
pa_sink_input_new_data data;
pa_assert(sink);
pa_assert(ss);
/* We allow creating this stream with no q set, so that it can be
* filled in later */
if (q && pa_memblockq_get_length(q) <= 0) {
pa_memblockq_free(q);
return NULL;
}
if (volume && pa_cvolume_is_muted(volume)) {
pa_memblockq_free(q);
return NULL;
}
u = pa_msgobject_new(memblockq_stream);
u->parent.parent.free = memblockq_stream_free;
u->parent.process_msg = memblockq_stream_process_msg;
u->core = sink->core;
u->sink_input = NULL;
u->memblockq = q;
pa_sink_input_new_data_init(&data);
data.sink = sink;
data.name = name;
data.driver = __FILE__;
pa_sink_input_new_data_set_sample_spec(&data, ss);
pa_sink_input_new_data_set_channel_map(&data, map);
pa_sink_input_new_data_set_volume(&data, volume);
if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0)))
goto fail;
u->sink_input->peek = sink_input_peek_cb;
u->sink_input->drop = sink_input_drop_cb;
u->sink_input->kill = sink_input_kill_cb;
u->sink_input->userdata = u;
if (q)
pa_memblockq_prebuf_disable(q);
/* The reference to u is dangling here, because we want
* to keep this stream around until it is fully played. */
/* This sink input is not "put" yet, i.e. pa_sink_input_put() has
* not been called! */
return pa_sink_input_ref(u->sink_input);
fail:
if (u)
memblockq_stream_unref(u);
return NULL;
}
int pa_play_memblockq(
@ -88,41 +208,29 @@ int pa_play_memblockq(
pa_memblockq *q,
pa_cvolume *volume) {
pa_sink_input *si;
pa_sink_input_new_data data;
pa_sink_input *i;
assert(sink);
assert(ss);
assert(q);
pa_assert(sink);
pa_assert(ss);
pa_assert(q);
if (pa_memblockq_get_length(q) <= 0) {
pa_memblockq_free(q);
return 0;
}
if (volume && pa_cvolume_is_muted(volume)) {
pa_memblockq_free(q);
return 0;
}
pa_sink_input_new_data_init(&data);
data.sink = sink;
data.name = name;
data.driver = __FILE__;
pa_sink_input_new_data_set_channel_map(&data, map);
pa_sink_input_new_data_set_sample_spec(&data, ss);
pa_sink_input_new_data_set_volume(&data, volume);
if (!(si = pa_sink_input_new(sink->core, &data, 0)))
if (!(i = pa_memblockq_sink_input_new(sink, name, ss, map, q, volume)))
return -1;
si->peek = sink_input_peek;
si->drop = sink_input_drop;
si->kill = sink_input_kill;
si->userdata = q;
pa_sink_notify(si->sink);
pa_sink_input_put(i);
pa_sink_input_unref(i);
return 0;
}
void pa_memblockq_sink_input_set_queue(pa_sink_input *i, pa_memblockq *q) {
memblockq_stream *u;
pa_sink_input_assert_ref(i);
u = MEMBLOCKQ_STREAM(i->userdata);
memblockq_stream_assert_ref(u);
if (u->memblockq)
pa_memblockq_free(u->memblockq);
u->memblockq = q;
}

View file

@ -27,6 +27,16 @@
#include <pulsecore/sink.h>
#include <pulsecore/memblockq.h>
pa_sink_input* pa_memblockq_sink_input_new(
pa_sink *sink,
const char *name,
const pa_sample_spec *ss,
const pa_channel_map *map,
pa_memblockq *q,
pa_cvolume *volume);
void pa_memblockq_sink_input_set_queue(pa_sink_input *i, pa_memblockq *q);
int pa_play_memblockq(
pa_sink *sink,
const char *name,

View file

@ -26,7 +26,6 @@
#endif
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
@ -34,53 +33,108 @@
#include <pulsecore/sink-input.h>
#include <pulsecore/gccmacro.h>
#include <pulsecore/thread-mq.h>
#include "play-memchunk.h"
static void sink_input_kill(pa_sink_input *i) {
pa_memchunk *c;
assert(i && i->userdata);
c = i->userdata;
typedef struct memchunk_stream {
pa_msgobject parent;
pa_core *core;
pa_sink_input *sink_input;
pa_memchunk memchunk;
} memchunk_stream;
pa_sink_input_disconnect(i);
pa_sink_input_unref(i);
enum {
MEMCHUNK_STREAM_MESSAGE_UNLINK,
};
pa_memblock_unref(c->memblock);
pa_xfree(c);
PA_DECLARE_CLASS(memchunk_stream);
#define MEMCHUNK_STREAM(o) (memchunk_stream_cast(o))
static PA_DEFINE_CHECK_TYPE(memchunk_stream, pa_msgobject);
static void memchunk_stream_unlink(memchunk_stream *u) {
pa_assert(u);
if (!u->sink_input)
return;
pa_sink_input_unlink(u->sink_input);
pa_sink_input_unref(u->sink_input);
u->sink_input = NULL;
memchunk_stream_unref(u);
}
static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
pa_memchunk *c;
assert(i && chunk && i->userdata);
c = i->userdata;
static void memchunk_stream_free(pa_object *o) {
memchunk_stream *u = MEMCHUNK_STREAM(o);
pa_assert(u);
if (c->length <= 0)
return -1;
memchunk_stream_unlink(u);
assert(c->memblock && c->memblock->length);
*chunk = *c;
pa_memblock_ref(c->memblock);
if (u->memchunk.memblock)
pa_memblock_unref(u->memchunk.memblock);
pa_xfree(u);
}
static int memchunk_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
memchunk_stream *u = MEMCHUNK_STREAM(o);
memchunk_stream_assert_ref(u);
switch (code) {
case MEMCHUNK_STREAM_MESSAGE_UNLINK:
memchunk_stream_unlink(u);
break;
}
return 0;
}
static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) {
sink_input_kill(i);
static void sink_input_kill_cb(pa_sink_input *i) {
pa_sink_input_assert_ref(i);
memchunk_stream_unlink(MEMCHUNK_STREAM(i->userdata));
}
static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) {
pa_memchunk *c;
assert(i && length && i->userdata);
c = i->userdata;
static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
memchunk_stream *u;
assert(!memcmp(chunk, c, sizeof(chunk)));
assert(length <= c->length);
pa_assert(i);
pa_assert(chunk);
u = MEMCHUNK_STREAM(i->userdata);
memchunk_stream_assert_ref(u);
c->length -= length;
c->index += length;
if (!u->memchunk.memblock)
return -1;
if (c->length <= 0)
pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i);
if (u->memchunk.length <= 0) {
pa_memblock_unref(u->memchunk.memblock);
u->memchunk.memblock = NULL;
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMCHUNK_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL);
return -1;
}
pa_assert(u->memchunk.memblock);
*chunk = u->memchunk;
pa_memblock_ref(chunk->memblock);
return 0;
}
static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
memchunk_stream *u;
pa_assert(i);
pa_assert(length > 0);
u = MEMCHUNK_STREAM(i->userdata);
memchunk_stream_assert_ref(u);
if (length < u->memchunk.length) {
u->memchunk.length -= length;
u->memchunk.index += length;
} else
u->memchunk.length = 0;
}
int pa_play_memchunk(
@ -91,38 +145,52 @@ int pa_play_memchunk(
const pa_memchunk *chunk,
pa_cvolume *volume) {
pa_sink_input *si;
pa_memchunk *nchunk;
memchunk_stream *u = NULL;
pa_sink_input_new_data data;
assert(sink);
assert(ss);
assert(chunk);
pa_assert(sink);
pa_assert(ss);
pa_assert(chunk);
if (volume && pa_cvolume_is_muted(volume))
return 0;
pa_memchunk_will_need(chunk);
u = pa_msgobject_new(memchunk_stream);
u->parent.parent.free = memchunk_stream_free;
u->parent.process_msg = memchunk_stream_process_msg;
u->core = sink->core;
u->memchunk = *chunk;
pa_memblock_ref(u->memchunk.memblock);
pa_sink_input_new_data_init(&data);
data.sink = sink;
data.name = name;
data.driver = __FILE__;
data.name = name;
pa_sink_input_new_data_set_sample_spec(&data, ss);
pa_sink_input_new_data_set_channel_map(&data, map);
pa_sink_input_new_data_set_volume(&data, volume);
if (!(si = pa_sink_input_new(sink->core, &data, 0)))
return -1;
if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0)))
goto fail;
si->peek = sink_input_peek;
si->drop = sink_input_drop;
si->kill = sink_input_kill;
u->sink_input->peek = sink_input_peek_cb;
u->sink_input->drop = sink_input_drop_cb;
u->sink_input->kill = sink_input_kill_cb;
u->sink_input->userdata = u;
si->userdata = nchunk = pa_xnew(pa_memchunk, 1);
*nchunk = *chunk;
pa_sink_input_put(u->sink_input);
pa_memblock_ref(chunk->memblock);
pa_sink_notify(si->sink);
/* The reference to u is dangling here, because we want to keep
* this stream around until it is fully played. */
return 0;
fail:
if (u)
memchunk_stream_unref(u);
return -1;
}

View file

@ -45,7 +45,7 @@
#include "winsock.h"
#ifndef HAVE_SYS_POLL_H
#ifndef HAVE_POLL_H
#include <pulsecore/core-util.h>

View file

@ -21,11 +21,13 @@
USA.
***/
#include <assert.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pulse/xmalloc.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "props.h"
@ -37,9 +39,11 @@ typedef struct pa_property {
/* Allocate a new property object */
static pa_property* property_new(const char *name, void *data) {
pa_property* p;
assert(name && data);
p = pa_xmalloc(sizeof(pa_property));
pa_assert(name);
pa_assert(data);
p = pa_xnew(pa_property, 1);
p->name = pa_xstrdup(name);
p->data = data;
@ -48,7 +52,7 @@ static pa_property* property_new(const char *name, void *data) {
/* Free a property object */
static void property_free(pa_property *p) {
assert(p);
pa_assert(p);
pa_xfree(p->name);
pa_xfree(p);
@ -56,7 +60,10 @@ static void property_free(pa_property *p) {
void* pa_property_get(pa_core *c, const char *name) {
pa_property *p;
assert(c && name && c->properties);
pa_assert(c);
pa_assert(name);
pa_assert(c->properties);
if (!(p = pa_hashmap_get(c->properties, name)))
return NULL;
@ -66,7 +73,11 @@ void* pa_property_get(pa_core *c, const char *name) {
int pa_property_set(pa_core *c, const char *name, void *data) {
pa_property *p;
assert(c && name && data && c->properties);
pa_assert(c);
pa_assert(name);
pa_assert(data);
pa_assert(c->properties);
if (pa_hashmap_get(c->properties, name))
return -1;
@ -78,7 +89,10 @@ int pa_property_set(pa_core *c, const char *name, void *data) {
int pa_property_remove(pa_core *c, const char *name) {
pa_property *p;
assert(c && name && c->properties);
pa_assert(c);
pa_assert(name);
pa_assert(c->properties);
if (!(p = pa_hashmap_remove(c->properties, name)))
return -1;
@ -88,18 +102,18 @@ int pa_property_remove(pa_core *c, const char *name) {
}
void pa_property_init(pa_core *c) {
assert(c);
pa_assert(c);
c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
}
void pa_property_cleanup(pa_core *c) {
assert(c);
pa_assert(c);
if (!c->properties)
return;
assert(!pa_hashmap_size(c->properties));
pa_assert(!pa_hashmap_size(c->properties));
pa_hashmap_free(c->properties, NULL, NULL);
c->properties = NULL;
@ -109,14 +123,17 @@ void pa_property_cleanup(pa_core *c) {
void pa_property_dump(pa_core *c, pa_strbuf *s) {
void *state = NULL;
pa_property *p;
assert(c && s);
pa_assert(c);
pa_assert(s);
while ((p = pa_hashmap_iterate(c->properties, &state, NULL)))
pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data);
}
int pa_property_replace(pa_core *c, const char *name, void *data) {
assert(c && name);
pa_assert(c);
pa_assert(name);
pa_property_remove(c, name);
return pa_property_set(c, name, data);

View file

@ -25,13 +25,13 @@
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <pulse/xmalloc.h>
#include <pulsecore/cli.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "protocol-cli.h"
@ -47,7 +47,8 @@ struct pa_protocol_cli {
static void cli_eof_cb(pa_cli*c, void*userdata) {
pa_protocol_cli *p = userdata;
assert(p);
pa_assert(p);
pa_idxset_remove_by_data(p->connections, c, NULL);
pa_cli_free(c);
}
@ -55,7 +56,10 @@ static void cli_eof_cb(pa_cli*c, void*userdata) {
static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
pa_protocol_cli *p = userdata;
pa_cli *c;
assert(s && io && p);
pa_assert(s);
pa_assert(io);
pa_assert(p);
if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@ -64,7 +68,6 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
}
c = pa_cli_new(p->core, io, p->module);
assert(c);
pa_cli_set_eof_callback(c, cli_eof_cb, p);
pa_idxset_put(p->connections, c, NULL);
@ -72,9 +75,11 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) {
pa_protocol_cli* p;
assert(core && server);
p = pa_xmalloc(sizeof(pa_protocol_cli));
pa_core_assert_ref(core);
pa_assert(server);
p = pa_xnew(pa_protocol_cli, 1);
p->module = m;
p->core = core;
p->server = server;
@ -86,12 +91,13 @@ pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa
}
static void free_connection(void *p, PA_GCC_UNUSED void *userdata) {
assert(p);
pa_assert(p);
pa_cli_free(p);
}
void pa_protocol_cli_free(pa_protocol_cli *p) {
assert(p);
pa_assert(p);
pa_idxset_free(p->connections, free_connection, NULL);
pa_socket_server_unref(p->server);

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,6 @@
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -34,6 +33,7 @@
#include <pulse/xmalloc.h>
#include <pulsecore/ioline.h>
#include <pulsecore/macro.h>
#include <pulsecore/log.h>
#include <pulsecore/namereg.h>
#include <pulsecore/cli-text.h>
@ -65,11 +65,12 @@ struct pa_protocol_http {
static void http_response(struct connection *c, int code, const char *msg, const char *mime) {
char s[256];
assert(c);
assert(msg);
assert(mime);
snprintf(s, sizeof(s),
pa_assert(c);
pa_assert(msg);
pa_assert(mime);
pa_snprintf(s, sizeof(s),
"HTTP/1.0 %i %s\n"
"Connection: close\n"
"Content-Type: %s\n"
@ -83,14 +84,14 @@ static void http_response(struct connection *c, int code, const char *msg, const
static void http_message(struct connection *c, int code, const char *msg, const char *text) {
char s[256];
assert(c);
pa_assert(c);
http_response(c, code, msg, "text/html");
if (!text)
text = msg;
snprintf(s, sizeof(s),
pa_snprintf(s, sizeof(s),
"<?xml version=\"1.0\"?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
"<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>%s</title></head>\n"
@ -103,21 +104,22 @@ static void http_message(struct connection *c, int code, const char *msg, const
static void connection_free(struct connection *c, int del) {
assert(c);
pa_assert(c);
if (c->url)
pa_xfree(c->url);
if (del)
pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
pa_ioline_unref(c->line);
pa_xfree(c);
}
static void line_callback(pa_ioline *line, const char *s, void *userdata) {
struct connection *c = userdata;
assert(line);
assert(c);
pa_assert(line);
pa_assert(c);
if (!s) {
/* EOF */
@ -223,7 +225,10 @@ fail:
static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
pa_protocol_http *p = userdata;
struct connection *c;
assert(s && io && p);
pa_assert(s);
pa_assert(io);
pa_assert(p);
if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@ -231,7 +236,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
return;
}
c = pa_xmalloc(sizeof(struct connection));
c = pa_xnew(struct connection, 1);
c->protocol = p;
c->line = pa_ioline_new(io);
c->state = REQUEST_LINE;
@ -243,9 +248,11 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) {
pa_protocol_http* p;
assert(core && server);
p = pa_xmalloc(sizeof(pa_protocol_http));
pa_core_assert_ref(core);
pa_assert(server);
p = pa_xnew(pa_protocol_http, 1);
p->module = m;
p->core = core;
p->server = server;
@ -257,12 +264,12 @@ pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server,
}
static void free_connection(void *p, PA_GCC_UNUSED void *userdata) {
assert(p);
pa_assert(p);
connection_free(p, 0);
}
void pa_protocol_http_free(pa_protocol_http *p) {
assert(p);
pa_assert(p);
pa_idxset_free(p->connections, free_connection, NULL);
pa_socket_server_unref(p->server);

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,6 @@
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
@ -41,101 +40,154 @@
#include <pulsecore/namereg.h>
#include <pulsecore/log.h>
#include <pulsecore/core-error.h>
#include <pulsecore/atomic.h>
#include <pulsecore/thread-mq.h>
#include "protocol-simple.h"
/* Don't allow more than this many concurrent connections */
#define MAX_CONNECTIONS 10
struct connection {
typedef struct connection {
pa_msgobject parent;
pa_protocol_simple *protocol;
pa_iochannel *io;
pa_sink_input *sink_input;
pa_source_output *source_output;
pa_client *client;
pa_memblockq *input_memblockq, *output_memblockq;
pa_defer_event *defer_event;
int dead;
struct {
pa_memblock *current_memblock;
size_t memblock_index, fragment_size;
pa_atomic_t missing;
} playback;
};
} connection;
PA_DECLARE_CLASS(connection);
#define CONNECTION(o) (connection_cast(o))
static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
struct pa_protocol_simple {
pa_module *module;
pa_core *core;
pa_socket_server*server;
pa_idxset *connections;
enum {
RECORD = 1,
PLAYBACK = 2,
DUPLEX = 3
} mode;
pa_sample_spec sample_spec;
char *source_name, *sink_name;
};
enum {
SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
SINK_INPUT_MESSAGE_DISABLE_PREBUF /* disabled prebuf, get playback started. */
};
enum {
CONNECTION_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
CONNECTION_MESSAGE_POST_DATA, /* data from source output to main loop */
CONNECTION_MESSAGE_UNLINK_CONNECTION /* Please drop a aconnection now */
};
#define PLAYBACK_BUFFER_SECONDS (.5)
#define PLAYBACK_BUFFER_FRAGMENTS (10)
#define RECORD_BUFFER_SECONDS (5)
#define RECORD_BUFFER_FRAGMENTS (100)
static void connection_free(struct connection *c) {
assert(c);
static void connection_unlink(connection *c) {
pa_assert(c);
pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
if (!c->protocol)
return;
if (c->sink_input) {
pa_sink_input_unlink(c->sink_input);
pa_sink_input_unref(c->sink_input);
c->sink_input = NULL;
}
if (c->source_output) {
pa_source_output_unlink(c->source_output);
pa_source_output_unref(c->source_output);
c->source_output = NULL;
}
if (c->client) {
pa_client_free(c->client);
c->client = NULL;
}
if (c->io) {
pa_iochannel_free(c->io);
c->io = NULL;
}
pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
c->protocol = NULL;
connection_unref(c);
}
static void connection_free(pa_object *o) {
connection *c = CONNECTION(o);
pa_assert(c);
connection_unref(c);
if (c->playback.current_memblock)
pa_memblock_unref(c->playback.current_memblock);
if (c->sink_input) {
pa_sink_input_disconnect(c->sink_input);
pa_sink_input_unref(c->sink_input);
}
if (c->source_output) {
pa_source_output_disconnect(c->source_output);
pa_source_output_unref(c->source_output);
}
if (c->client)
pa_client_free(c->client);
if (c->io)
pa_iochannel_free(c->io);
if (c->input_memblockq)
pa_memblockq_free(c->input_memblockq);
if (c->output_memblockq)
pa_memblockq_free(c->output_memblockq);
if (c->defer_event)
c->protocol->core->mainloop->defer_free(c->defer_event);
pa_xfree(c);
}
static int do_read(struct connection *c) {
static int do_read(connection *c) {
pa_memchunk chunk;
ssize_t r;
size_t l;
void *p;
if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq)))
connection_assert_ref(c);
if (!c->sink_input || (l = pa_atomic_load(&c->playback.missing)) <= 0)
return 0;
if (l > c->playback.fragment_size)
l = c->playback.fragment_size;
if (c->playback.current_memblock)
if (c->playback.current_memblock->length - c->playback.memblock_index < l) {
if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) {
pa_memblock_unref(c->playback.current_memblock);
c->playback.current_memblock = NULL;
c->playback.memblock_index = 0;
}
if (!c->playback.current_memblock) {
c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2);
assert(c->playback.current_memblock && c->playback.current_memblock->length >= l);
pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, l));
c->playback.memblock_index = 0;
}
if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) {
p = pa_memblock_acquire(c->playback.current_memblock);
r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l);
pa_memblock_release(c->playback.current_memblock);
if (r <= 0) {
if (r < 0 && (errno == EINTR || errno == EAGAIN))
return 0;
pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno));
return -1;
}
@ -143,50 +195,55 @@ static int do_read(struct connection *c) {
chunk.memblock = c->playback.current_memblock;
chunk.index = c->playback.memblock_index;
chunk.length = r;
assert(chunk.memblock);
c->playback.memblock_index += r;
assert(c->input_memblockq);
pa_memblockq_push_align(c->input_memblockq, &chunk);
assert(c->sink_input);
pa_sink_notify(c->sink_input->sink);
pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL);
pa_atomic_sub(&c->playback.missing, r);
return 0;
}
static int do_write(struct connection *c) {
static int do_write(connection *c) {
pa_memchunk chunk;
ssize_t r;
void *p;
connection_assert_ref(c);
if (!c->source_output)
return 0;
assert(c->output_memblockq);
if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) {
/* pa_log("peek failed"); */
return 0;
}
assert(chunk.memblock && chunk.length);
pa_assert(chunk.memblock);
pa_assert(chunk.length);
p = pa_memblock_acquire(chunk.memblock);
r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length);
pa_memblock_release(chunk.memblock);
pa_memblock_unref(chunk.memblock);
if (r < 0) {
if (errno == EINTR || errno == EAGAIN)
return 0;
if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) {
pa_memblock_unref(chunk.memblock);
pa_log("write(): %s", pa_cstrerror(errno));
return -1;
}
pa_memblockq_drop(c->output_memblockq, &chunk, r);
pa_memblock_unref(chunk.memblock);
pa_source_notify(c->source_output->source);
pa_memblockq_drop(c->output_memblockq, r);
return 0;
}
static void do_work(struct connection *c) {
assert(c);
assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
c->protocol->core->mainloop->defer_enable(c->defer_event, 0);
static void do_work(connection *c) {
connection_assert_ref(c);
if (c->dead)
return;
@ -207,103 +264,182 @@ static void do_work(struct connection *c) {
fail:
if (c->sink_input) {
/* If there is a sink input, we first drain what we already have read before shutting down the connection */
c->dead = 1;
pa_iochannel_free(c->io);
c->io = NULL;
pa_memblockq_prebuf_disable(c->input_memblockq);
pa_sink_notify(c->sink_input->sink);
pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_DISABLE_PREBUF, NULL, 0, NULL, NULL);
} else
connection_free(c);
connection_unlink(c);
}
/*** sink_input callbacks ***/
static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
connection *c = CONNECTION(o);
connection_assert_ref(c);
static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
struct connection*c;
assert(i && i->userdata && chunk);
c = i->userdata;
switch (code) {
case CONNECTION_MESSAGE_REQUEST_DATA:
do_work(c);
break;
if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) {
case CONNECTION_MESSAGE_POST_DATA:
/* pa_log("got data %u", chunk->length); */
pa_memblockq_push_align(c->output_memblockq, chunk);
do_work(c);
break;
if (c->dead)
connection_free(c);
return -1;
case CONNECTION_MESSAGE_UNLINK_CONNECTION:
connection_unlink(c);
break;
}
return 0;
}
static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
struct connection*c = i->userdata;
assert(i && c && length);
/*** sink_input callbacks ***/
pa_memblockq_drop(c->input_memblockq, chunk, length);
/* Called from thread context */
static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
pa_sink_input *i = PA_SINK_INPUT(o);
connection*c;
/* do something */
assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
pa_sink_input_assert_ref(i);
c = CONNECTION(i->userdata);
connection_assert_ref(c);
switch (code) {
case SINK_INPUT_MESSAGE_POST_DATA: {
pa_assert(chunk);
/* New data from the main loop */
pa_memblockq_push_align(c->input_memblockq, chunk);
/* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
return 0;
}
case SINK_INPUT_MESSAGE_DISABLE_PREBUF: {
pa_memblockq_prebuf_disable(c->input_memblockq);
return 0;
}
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
pa_usec_t *r = userdata;
*r = pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
/* Fall through, the default handler will add in the extra
* latency added by the resampler */
}
default:
return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
}
}
/* Called from thread context */
static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
connection *c;
int r;
pa_assert(i);
c = CONNECTION(i->userdata);
connection_assert_ref(c);
pa_assert(chunk);
r = pa_memblockq_peek(c->input_memblockq, chunk);
/* pa_log("peeked %u %i", r >= 0 ? chunk->length: 0, r); */
if (c->dead && r < 0)
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL);
return r;
}
/* Called from thread context */
static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
connection *c;
size_t old, new;
pa_assert(i);
c = CONNECTION(i->userdata);
connection_assert_ref(c);
pa_assert(length);
old = pa_memblockq_missing(c->input_memblockq);
pa_memblockq_drop(c->input_memblockq, length);
new = pa_memblockq_missing(c->input_memblockq);
if (new > old) {
if (pa_atomic_add(&c->playback.missing, new - old) <= 0)
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
}
}
/* Called from main context */
static void sink_input_kill_cb(pa_sink_input *i) {
assert(i && i->userdata);
connection_free((struct connection *) i->userdata);
}
pa_sink_input_assert_ref(i);
static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) {
struct connection*c = i->userdata;
assert(i && c);
return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
connection_unlink(CONNECTION(i->userdata));
}
/*** source_output callbacks ***/
/* Called from thread context */
static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
struct connection *c = o->userdata;
assert(o && c && chunk);
connection *c;
pa_memblockq_push(c->output_memblockq, chunk);
pa_assert(o);
c = CONNECTION(o->userdata);
pa_assert(c);
pa_assert(chunk);
/* do something */
assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
}
/* Called from main context */
static void source_output_kill_cb(pa_source_output *o) {
assert(o && o->userdata);
connection_free((struct connection *) o->userdata);
pa_source_output_assert_ref(o);
connection_unlink(CONNECTION(o->userdata));
}
/* Called from main context */
static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
struct connection*c = o->userdata;
assert(o && c);
connection*c;
pa_assert(o);
c = CONNECTION(o->userdata);
pa_assert(c);
return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
}
/*** client callbacks ***/
static void client_kill_cb(pa_client *c) {
assert(c && c->userdata);
connection_free((struct connection *) c->userdata);
static void client_kill_cb(pa_client *client) {
connection*c;
pa_assert(client);
c = CONNECTION(client->userdata);
pa_assert(c);
connection_unlink(c);
}
/*** pa_iochannel callbacks ***/
static void io_callback(pa_iochannel*io, void *userdata) {
struct connection *c = userdata;
assert(io && c && c->io == io);
connection *c = CONNECTION(userdata);
do_work(c);
}
/*** fixed callback ***/
static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) {
struct connection *c = userdata;
assert(a && c && c->defer_event == e);
connection_assert_ref(c);
pa_assert(io);
do_work(c);
}
@ -312,9 +448,12 @@ static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata)
static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
pa_protocol_simple *p = userdata;
struct connection *c = NULL;
connection *c = NULL;
char cname[256];
assert(s && io && p);
pa_assert(s);
pa_assert(io);
pa_assert(p);
if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@ -322,21 +461,22 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
return;
}
c = pa_xmalloc(sizeof(struct connection));
c = pa_msgobject_new(connection);
c->parent.parent.free = connection_free;
c->parent.process_msg = connection_process_msg;
c->io = io;
c->sink_input = NULL;
c->source_output = NULL;
c->defer_event = NULL;
c->input_memblockq = c->output_memblockq = NULL;
c->protocol = p;
c->playback.current_memblock = NULL;
c->playback.memblock_index = 0;
c->playback.fragment_size = 0;
c->dead = 0;
pa_atomic_store(&c->playback.missing, 0);
pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
c->client = pa_client_new(p->core, __FILE__, cname);
assert(c->client);
pa_assert_se(c->client = pa_client_new(p->core, __FILE__, cname));
c->client->owner = p->module;
c->client->kill = client_kill_cb;
c->client->userdata = c;
@ -357,10 +497,10 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
goto fail;
}
c->sink_input->parent.process_msg = sink_input_process_msg;
c->sink_input->peek = sink_input_peek_cb;
c->sink_input->drop = sink_input_drop_cb;
c->sink_input->kill = sink_input_kill_cb;
c->sink_input->get_latency = sink_input_get_latency_cb;
c->sink_input->userdata = c;
l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS);
@ -372,11 +512,12 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
(size_t) -1,
l/PLAYBACK_BUFFER_FRAGMENTS,
NULL);
assert(c->input_memblockq);
pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5);
c->playback.fragment_size = l/10;
c->playback.fragment_size = l/PLAYBACK_BUFFER_FRAGMENTS;
pa_sink_notify(c->sink_input->sink);
pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq));
pa_sink_input_put(c->sink_input);
}
if (p->mode & RECORD) {
@ -409,29 +550,29 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
0,
NULL);
pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2);
pa_source_notify(c->source_output->source);
pa_source_output_put(c->source_output);
}
pa_iochannel_set_callback(c->io, io_callback, c);
pa_idxset_put(p->connections, c, NULL);
c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c);
assert(c->defer_event);
p->core->mainloop->defer_enable(c->defer_event, 0);
return;
fail:
if (c)
connection_free(c);
connection_unlink(c);
}
pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
pa_protocol_simple* p = NULL;
int enable;
assert(core && server && ma);
p = pa_xmalloc0(sizeof(pa_protocol_simple));
pa_assert(core);
pa_assert(server);
pa_assert(ma);
p = pa_xnew0(pa_protocol_simple, 1);
p->module = m;
p->core = core;
p->server = server;
@ -472,23 +613,24 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv
fail:
if (p)
pa_protocol_simple_free(p);
return NULL;
}
void pa_protocol_simple_free(pa_protocol_simple *p) {
struct connection *c;
assert(p);
connection *c;
pa_assert(p);
if (p->connections) {
while((c = pa_idxset_first(p->connections, NULL)))
connection_free(c);
connection_unlink(c);
pa_idxset_free(p->connections, NULL, NULL);
}
if (p->server)
pa_socket_server_unref(p->server);
pa_xfree(p);
}

View file

@ -25,9 +25,8 @@
#include <config.h>
#endif
#include <assert.h>
#include <pulsecore/native-common.h>
#include <pulsecore/macro.h>
#include "pstream-util.h"
@ -35,20 +34,20 @@ void pa_pstream_send_tagstruct_with_creds(pa_pstream *p, pa_tagstruct *t, const
size_t length;
uint8_t *data;
pa_packet *packet;
assert(p);
assert(t);
data = pa_tagstruct_free_data(t, &length);
assert(data && length);
packet = pa_packet_new_dynamic(data, length);
assert(packet);
pa_assert(p);
pa_assert(t);
pa_assert_se(data = pa_tagstruct_free_data(t, &length));
pa_assert_se(packet = pa_packet_new_dynamic(data, length));
pa_pstream_send_packet(p, packet, creds);
pa_packet_unref(packet);
}
void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) {
pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
assert(t);
pa_tagstruct *t;
pa_assert_se(t = pa_tagstruct_new(NULL, 0));
pa_tagstruct_putu32(t, PA_COMMAND_ERROR);
pa_tagstruct_putu32(t, tag);
pa_tagstruct_putu32(t, error);
@ -56,8 +55,9 @@ void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) {
}
void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag) {
pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
assert(t);
pa_tagstruct *t;
pa_assert_se(t = pa_tagstruct_new(NULL, 0));
pa_tagstruct_putu32(t, PA_COMMAND_REPLY);
pa_tagstruct_putu32(t, tag);
pa_pstream_send_tagstruct(p, t);

View file

@ -28,7 +28,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#ifdef HAVE_SYS_SOCKET_H
@ -41,16 +40,17 @@
#include <netinet/in.h>
#endif
#include "winsock.h"
#include <pulse/xmalloc.h>
#include <pulsecore/winsock.h>
#include <pulsecore/queue.h>
#include <pulsecore/log.h>
#include <pulsecore/core-scache.h>
#include <pulsecore/creds.h>
#include <pulsecore/mutex.h>
#include <pulsecore/refcnt.h>
#include <pulsecore/flist.h>
#include <pulsecore/macro.h>
#include "pstream.h"
@ -84,7 +84,8 @@ typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX];
#define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t))
#define FRAME_SIZE_MAX_ALLOW PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */
#define FRAME_SIZE_MAX_USE (1024*64)
PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
struct item_info {
enum {
@ -94,7 +95,6 @@ struct item_info {
PA_PSTREAM_ITEM_SHMREVOKE
} type;
/* packet info */
pa_packet *packet;
#ifdef HAVE_CREDS
@ -118,8 +118,8 @@ struct pa_pstream {
pa_mainloop_api *mainloop;
pa_defer_event *defer_event;
pa_iochannel *io;
pa_queue *send_queue;
pa_mutex *mutex;
int dead;
@ -129,6 +129,7 @@ struct pa_pstream {
uint32_t shm_info[PA_PSTREAM_SHM_MAX];
void *data;
size_t index;
pa_memchunk memchunk;
} write;
struct {
@ -156,6 +157,12 @@ struct pa_pstream {
pa_pstream_notify_cb_t die_callback;
void *die_callback_userdata;
pa_pstream_block_id_cb_t revoke_callback;
void *revoke_callback_userdata;
pa_pstream_block_id_cb_t release_callback;
void *release_callback_userdata;
pa_mempool *mempool;
#ifdef HAVE_CREDS
@ -168,13 +175,11 @@ static int do_write(pa_pstream *p);
static int do_read(pa_pstream *p);
static void do_something(pa_pstream *p) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_pstream_ref(p);
pa_mutex_lock(p->mutex);
p->mainloop->defer_enable(p->defer_event, 0);
if (!p->dead && pa_iochannel_is_readable(p->io)) {
@ -188,28 +193,24 @@ static void do_something(pa_pstream *p) {
goto fail;
}
pa_mutex_unlock(p->mutex);
pa_pstream_unref(p);
return;
fail:
p->dead = 1;
if (p->die_callback)
p->die_callback(p, p->die_callback_userdata);
pa_mutex_unlock(p->mutex);
pa_pstream_unlink(p);
pa_pstream_unref(p);
}
static void io_callback(pa_iochannel*io, void *userdata) {
pa_pstream *p = userdata;
assert(p);
assert(p->io == io);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p->io == io);
do_something(p);
}
@ -217,9 +218,10 @@ static void io_callback(pa_iochannel*io, void *userdata) {
static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) {
pa_pstream *p = userdata;
assert(p);
assert(p->defer_event == e);
assert(p->mainloop == m);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p->defer_event == e);
pa_assert(p->mainloop == m);
do_something(p);
}
@ -229,9 +231,9 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd
pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *pool) {
pa_pstream *p;
assert(m);
assert(io);
assert(pool);
pa_assert(m);
pa_assert(io);
pa_assert(pool);
p = pa_xnew(pa_pstream, 1);
PA_REFCNT_INIT(p);
@ -239,17 +241,15 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo
pa_iochannel_set_callback(io, io_callback, p);
p->dead = 0;
p->mutex = pa_mutex_new(1);
p->mainloop = m;
p->defer_event = m->defer_new(m, defer_callback, p);
m->defer_enable(p->defer_event, 0);
p->send_queue = pa_queue_new();
assert(p->send_queue);
p->write.current = NULL;
p->write.index = 0;
pa_memchunk_reset(&p->write.memchunk);
p->read.memblock = NULL;
p->read.packet = NULL;
p->read.index = 0;
@ -262,6 +262,10 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo
p->drain_callback_userdata = NULL;
p->die_callback = NULL;
p->die_callback_userdata = NULL;
p->revoke_callback = NULL;
p->revoke_callback_userdata = NULL;
p->release_callback = NULL;
p->release_callback_userdata = NULL;
p->mempool = pool;
@ -281,56 +285,57 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo
return p;
}
static void item_free(void *item, PA_GCC_UNUSED void *p) {
static void item_free(void *item, PA_GCC_UNUSED void *q) {
struct item_info *i = item;
assert(i);
pa_assert(i);
if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) {
assert(i->chunk.memblock);
pa_assert(i->chunk.memblock);
pa_memblock_unref(i->chunk.memblock);
} else if (i->type == PA_PSTREAM_ITEM_PACKET) {
assert(i->packet);
pa_assert(i->packet);
pa_packet_unref(i->packet);
}
pa_xfree(i);
if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
pa_xfree(i);
}
static void pstream_free(pa_pstream *p) {
assert(p);
pa_assert(p);
pa_pstream_close(p);
pa_pstream_unlink(p);
pa_queue_free(p->send_queue, item_free, NULL);
if (p->write.current)
item_free(p->write.current, NULL);
if (p->write.memchunk.memblock)
pa_memblock_unref(p->write.memchunk.memblock);
if (p->read.memblock)
pa_memblock_unref(p->read.memblock);
if (p->read.packet)
pa_packet_unref(p->read.packet);
if (p->mutex)
pa_mutex_free(p->mutex);
pa_xfree(p);
}
void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds) {
struct item_info *i;
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
assert(packet);
pa_mutex_lock(p->mutex);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(packet);
if (p->dead)
goto finish;
return;
if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
i = pa_xnew(struct item_info, 1);
i = pa_xnew(struct item_info, 1);
i->type = PA_PSTREAM_ITEM_PACKET;
i->packet = pa_packet_ref(packet);
@ -340,37 +345,36 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre
#endif
pa_queue_push(p->send_queue, i);
p->mainloop->defer_enable(p->defer_event, 1);
finish:
pa_mutex_unlock(p->mutex);
}
void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) {
size_t length, idx;
size_t bsm;
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
assert(channel != (uint32_t) -1);
assert(chunk);
pa_mutex_lock(p->mutex);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(channel != (uint32_t) -1);
pa_assert(chunk);
if (p->dead)
goto finish;
return;
length = chunk->length;
idx = 0;
length = chunk->length;
bsm = pa_mempool_block_size_max(p->mempool);
while (length > 0) {
struct item_info *i;
size_t n;
i = pa_xnew(struct item_info, 1);
if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
i = pa_xnew(struct item_info, 1);
i->type = PA_PSTREAM_ITEM_MEMBLOCK;
n = length < FRAME_SIZE_MAX_USE ? length : FRAME_SIZE_MAX_USE;
n = MIN(length, bsm);
i->chunk.index = chunk->index + idx;
i->chunk.length = n;
i->chunk.memblock = pa_memblock_ref(chunk->memblock);
@ -389,27 +393,20 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa
}
p->mainloop->defer_enable(p->defer_event, 1);
finish:
pa_mutex_unlock(p->mutex);
}
static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) {
void pa_pstream_send_release(pa_pstream *p, uint32_t block_id) {
struct item_info *item;
pa_pstream *p = userdata;
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_mutex_lock(p->mutex);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (p->dead)
goto finish;
return;
/* pa_log("Releasing block %u", block_id); */
item = pa_xnew(struct item_info, 1);
if (!(item = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
item = pa_xnew(struct item_info, 1);
item->type = PA_PSTREAM_ITEM_SHMRELEASE;
item->block_id = block_id;
#ifdef HAVE_CREDS
@ -418,27 +415,35 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd
pa_queue_push(p->send_queue, item);
p->mainloop->defer_enable(p->defer_event, 1);
finish:
pa_mutex_unlock(p->mutex);
}
static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) {
struct item_info *item;
/* might be called from thread context */
static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) {
pa_pstream *p = userdata;
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_mutex_lock(p->mutex);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (p->dead)
goto finish;
return;
if (p->release_callback)
p->release_callback(p, block_id, p->release_callback_userdata);
else
pa_pstream_send_release(p, block_id);
}
void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id) {
struct item_info *item;
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (p->dead)
return;
/* pa_log("Revoking block %u", block_id); */
item = pa_xnew(struct item_info, 1);
if (!(item = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
item = pa_xnew(struct item_info, 1);
item->type = PA_PSTREAM_ITEM_SHMREVOKE;
item->block_id = block_id;
#ifdef HAVE_CREDS
@ -447,21 +452,33 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda
pa_queue_push(p->send_queue, item);
p->mainloop->defer_enable(p->defer_event, 1);
}
finish:
/* might be called from thread context */
static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) {
pa_pstream *p = userdata;
pa_mutex_unlock(p->mutex);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (p->revoke_callback)
p->revoke_callback(p, block_id, p->revoke_callback_userdata);
else
pa_pstream_send_revoke(p, block_id);
}
static void prepare_next_write_item(pa_pstream *p) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (!(p->write.current = pa_queue_pop(p->send_queue)))
p->write.current = pa_queue_pop(p->send_queue);
if (!p->write.current)
return;
p->write.index = 0;
p->write.data = NULL;
pa_memchunk_reset(&p->write.memchunk);
p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = 0;
p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1);
@ -471,7 +488,7 @@ static void prepare_next_write_item(pa_pstream *p) {
if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) {
assert(p->write.current->packet);
pa_assert(p->write.current->packet);
p->write.data = p->write.current->packet->data;
p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length);
@ -489,8 +506,8 @@ static void prepare_next_write_item(pa_pstream *p) {
uint32_t flags;
int send_payload = 1;
assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK);
assert(p->write.current->chunk.memblock);
pa_assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK);
pa_assert(p->write.current->chunk.memblock);
p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel);
p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32));
@ -502,7 +519,7 @@ static void prepare_next_write_item(pa_pstream *p) {
uint32_t block_id, shm_id;
size_t offset, length;
assert(p->export);
pa_assert(p->export);
if (pa_memexport_put(p->export,
p->write.current->chunk.memblock,
@ -528,7 +545,9 @@ static void prepare_next_write_item(pa_pstream *p) {
if (send_payload) {
p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length);
p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index;
p->write.memchunk = p->write.current->chunk;
pa_memblock_ref(p->write.memchunk.memblock);
p->write.data = NULL;
}
p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(flags);
@ -544,9 +563,10 @@ static int do_write(pa_pstream *p) {
void *d;
size_t l;
ssize_t r;
pa_memblock *release_memblock = NULL;
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (!p->write.current)
prepare_next_write_item(p);
@ -558,72 +578,105 @@ static int do_write(pa_pstream *p) {
d = (uint8_t*) p->write.descriptor + p->write.index;
l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index;
} else {
assert(p->write.data);
pa_assert(p->write.data || p->write.memchunk.memblock);
d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE;
if (p->write.data)
d = p->write.data;
else {
d = (uint8_t*) pa_memblock_acquire(p->write.memchunk.memblock) + p->write.memchunk.index;
release_memblock = p->write.memchunk.memblock;
}
d = (uint8_t*) d + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE;
l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE);
}
assert(l > 0);
pa_assert(l > 0);
#ifdef HAVE_CREDS
if (p->send_creds_now) {
if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_creds)) < 0)
return -1;
goto fail;
p->send_creds_now = 0;
} else
#endif
if ((r = pa_iochannel_write(p->io, d, l)) < 0)
return -1;
goto fail;
if (release_memblock)
pa_memblock_release(release_memblock);
p->write.index += r;
if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE + ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) {
assert(p->write.current);
item_free(p->write.current, (void *) 1);
pa_assert(p->write.current);
item_free(p->write.current, NULL);
p->write.current = NULL;
if (p->write.memchunk.memblock)
pa_memblock_unref(p->write.memchunk.memblock);
pa_memchunk_reset(&p->write.memchunk);
if (p->drain_callback && !pa_pstream_is_pending(p))
p->drain_callback(p, p->drain_callback_userdata);
}
return 0;
fail:
if (release_memblock)
pa_memblock_release(release_memblock);
return -1;
}
static int do_read(pa_pstream *p) {
void *d;
size_t l;
ssize_t r;
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_memblock *release_memblock = NULL;
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) {
d = (uint8_t*) p->read.descriptor + p->read.index;
l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index;
} else {
assert(p->read.data);
d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE;
pa_assert(p->read.data || p->read.memblock);
if (p->read.data)
d = p->read.data;
else {
d = pa_memblock_acquire(p->read.memblock);
release_memblock = p->read.memblock;
}
d = (uint8_t*) d + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE;
l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE);
}
#ifdef HAVE_CREDS
{
int b = 0;
pa_bool_t b = 0;
if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0)
return -1;
goto fail;
p->read_creds_valid = p->read_creds_valid || b;
}
#else
if ((r = pa_iochannel_read(p->io, d, l)) <= 0)
return -1;
goto fail;
#endif
if (release_memblock)
pa_memblock_release(release_memblock);
p->read.index += r;
if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) {
@ -643,7 +696,7 @@ static int do_read(pa_pstream *p) {
/* pa_log("Got release frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */
assert(p->export);
pa_assert(p->export);
pa_memexport_process_release(p->export, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI]));
goto frame_done;
@ -654,7 +707,7 @@ static int do_read(pa_pstream *p) {
/* pa_log("Got revoke frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */
assert(p->import);
pa_assert(p->import);
pa_memimport_process_revoke(p->import, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI]));
goto frame_done;
@ -667,7 +720,7 @@ static int do_read(pa_pstream *p) {
return -1;
}
assert(!p->read.packet && !p->read.memblock);
pa_assert(!p->read.packet && !p->read.memblock);
channel = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]);
@ -704,7 +757,7 @@ static int do_read(pa_pstream *p) {
/* Frame is a memblock frame */
p->read.memblock = pa_memblock_new(p->mempool, length);
p->read.data = p->read.memblock->data;
p->read.data = NULL;
} else {
pa_log_warn("Recieved memblock frame with invalid flags value.");
@ -771,9 +824,9 @@ static int do_read(pa_pstream *p) {
} else {
pa_memblock *b;
assert((ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA);
pa_assert((ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA);
assert(p->import);
pa_assert(p->import);
if (!(b = pa_memimport_get(p->import,
ntohl(p->read.shm_info[PA_PSTREAM_SHM_BLOCKID]),
@ -791,7 +844,7 @@ static int do_read(pa_pstream *p) {
chunk.memblock = b;
chunk.index = 0;
chunk.length = b->length;
chunk.length = pa_memblock_get_length(b);
offset = (int64_t) (
(((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) |
@ -819,92 +872,104 @@ frame_done:
p->read.memblock = NULL;
p->read.packet = NULL;
p->read.index = 0;
p->read.data = NULL;
#ifdef HAVE_CREDS
p->read_creds_valid = 0;
#endif
return 0;
fail:
if (release_memblock)
pa_memblock_release(release_memblock);
return -1;
}
void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_mutex_lock(p->mutex);
p->die_callback = cb;
p->die_callback_userdata = userdata;
pa_mutex_unlock(p->mutex);
}
void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_mutex_lock(p->mutex);
p->drain_callback = cb;
p->drain_callback_userdata = userdata;
pa_mutex_unlock(p->mutex);
}
void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_mutex_lock(p->mutex);
p->recieve_packet_callback = cb;
p->recieve_packet_callback_userdata = userdata;
pa_mutex_unlock(p->mutex);
}
void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
pa_mutex_lock(p->mutex);
p->recieve_memblock_callback = cb;
p->recieve_memblock_callback_userdata = userdata;
pa_mutex_unlock(p->mutex);
}
void pa_pstream_set_release_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata) {
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
p->release_callback = cb;
p->release_callback_userdata = userdata;
}
void pa_pstream_set_revoke_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata) {
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
p->release_callback = cb;
p->release_callback_userdata = userdata;
}
int pa_pstream_is_pending(pa_pstream *p) {
int b;
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_mutex_lock(p->mutex);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (p->dead)
b = 0;
else
b = p->write.current || !pa_queue_is_empty(p->send_queue);
pa_mutex_unlock(p->mutex);
return b;
}
void pa_pstream_unref(pa_pstream*p) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
if (PA_REFCNT_DEC(p) <= 0)
pstream_free(p);
}
pa_pstream* pa_pstream_ref(pa_pstream*p) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
PA_REFCNT_INC(p);
return p;
}
void pa_pstream_close(pa_pstream *p) {
assert(p);
void pa_pstream_unlink(pa_pstream *p) {
pa_assert(p);
pa_mutex_lock(p->mutex);
if (p->dead)
return;
p->dead = 1;
@ -932,15 +997,11 @@ void pa_pstream_close(pa_pstream *p) {
p->drain_callback = NULL;
p->recieve_packet_callback = NULL;
p->recieve_memblock_callback = NULL;
pa_mutex_unlock(p->mutex);
}
void pa_pstream_use_shm(pa_pstream *p, int enable) {
assert(p);
assert(PA_REFCNT_VALUE(p) > 0);
pa_mutex_lock(p->mutex);
pa_assert(p);
pa_assert(PA_REFCNT_VALUE(p) > 0);
p->use_shm = enable;
@ -956,6 +1017,4 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) {
p->export = NULL;
}
}
pa_mutex_unlock(p->mutex);
}

View file

@ -41,6 +41,7 @@ typedef struct pa_pstream pa_pstream;
typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata);
typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata);
typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata);
typedef void (*pa_pstream_block_id_cb_t)(pa_pstream *p, uint32_t block_id, void *userdata);
pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *p);
void pa_pstream_unref(pa_pstream*p);
@ -48,17 +49,20 @@ pa_pstream* pa_pstream_ref(pa_pstream*p);
void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds);
void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk);
void pa_pstream_send_release(pa_pstream *p, uint32_t block_id);
void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id);
void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata);
void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata);
void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata);
void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata);
void pa_pstream_set_release_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata);
void pa_pstream_set_revoke_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata);
int pa_pstream_is_pending(pa_pstream *p);
void pa_pstream_use_shm(pa_pstream *p, int enable);
void pa_pstream_close(pa_pstream *p);
void pa_pstream_unlink(pa_pstream *p);
#endif

View file

@ -25,13 +25,16 @@
#include <config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include <pulsecore/flist.h>
#include "queue.h"
PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree);
struct queue_entry {
struct queue_entry *next;
void *data;
@ -44,25 +47,24 @@ struct pa_queue {
pa_queue* pa_queue_new(void) {
pa_queue *q = pa_xnew(pa_queue, 1);
q->front = q->back = NULL;
q->length = 0;
return q;
}
void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) {
struct queue_entry *e;
assert(q);
e = q->front;
while (e) {
struct queue_entry *n = e->next;
void *data;
pa_assert(q);
while ((data = pa_queue_pop(q)))
if (destroy)
destroy(e->data, userdata);
destroy(data, userdata);
pa_xfree(e);
e = n;
}
pa_assert(!q->front);
pa_assert(!q->back);
pa_assert(q->length == 0);
pa_xfree(q);
}
@ -70,14 +72,20 @@ void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *
void pa_queue_push(pa_queue *q, void *p) {
struct queue_entry *e;
e = pa_xnew(struct queue_entry, 1);
pa_assert(q);
pa_assert(p);
if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries))))
e = pa_xnew(struct queue_entry, 1);
e->data = p;
e->next = NULL;
if (q->back)
if (q->back) {
pa_assert(q->front);
q->back->next = e;
else {
assert(!q->front);
} else {
pa_assert(!q->front);
q->front = e;
}
@ -88,17 +96,22 @@ void pa_queue_push(pa_queue *q, void *p) {
void* pa_queue_pop(pa_queue *q) {
void *p;
struct queue_entry *e;
assert(q);
pa_assert(q);
if (!(e = q->front))
return NULL;
q->front = e->next;
if (q->back == e)
if (q->back == e) {
pa_assert(!e->next);
q->back = NULL;
}
p = e->data;
pa_xfree(e);
if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
pa_xfree(e);
q->length--;
@ -106,6 +119,7 @@ void* pa_queue_pop(pa_queue *q) {
}
int pa_queue_is_empty(pa_queue *q) {
assert(q);
pa_assert(q);
return q->length == 0;
}

View file

@ -31,21 +31,22 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include "random.h"
static int has_whined = 0;
static const char *devices[] = { "/dev/urandom", "/dev/random", NULL };
static const char * const devices[] = { "/dev/urandom", "/dev/random", NULL };
static int random_proper(void *ret_data, size_t length) {
#ifdef OS_IS_WIN32
assert(ret_data && length);
pa_assert(ret_data);
pa_assert(length > 0);
return -1;
@ -53,9 +54,10 @@ static int random_proper(void *ret_data, size_t length) {
int fd, ret = -1;
ssize_t r = 0;
const char **device;
const char *const * device;
assert(ret_data && length);
pa_assert(ret_data);
pa_assert(length > 0);
device = devices;
@ -67,7 +69,7 @@ static int random_proper(void *ret_data, size_t length) {
if ((r = pa_loop_read(fd, ret_data, length, NULL)) < 0 || (size_t) r != length)
ret = -1;
close(fd);
pa_close(fd);
} else
ret = -1;
@ -84,7 +86,7 @@ void pa_random_seed(void) {
if (random_proper(&seed, sizeof(unsigned int)) < 0) {
if (!has_whined)
pa_log_warn("failed to get proper entropy. Falling back to seeding with current time.");
pa_log_warn("Failed to get proper entropy. Falling back to seeding with current time.");
has_whined = 1;
seed = (unsigned int) time(NULL);
@ -97,13 +99,14 @@ void pa_random(void *ret_data, size_t length) {
uint8_t *p;
size_t l;
assert(ret_data && length);
pa_assert(ret_data);
pa_assert(length > 0);
if (random_proper(ret_data, length) >= 0)
return;
if (!has_whined)
pa_log_warn("failed to get proper entropy. Falling back to unsecure pseudo RNG.");
pa_log_warn("Failed to get proper entropy. Falling back to unsecure pseudo RNG.");
has_whined = 1;
for (p = ret_data, l = length; l > 0; p++, l--)

Some files were not shown because too many files have changed in this diff Show more