mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2026-04-06 07:15:41 -04:00
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:
parent
6687dd0131
commit
a67c21f093
294 changed files with 79057 additions and 11614 deletions
|
|
@ -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
303
src/pulsecore/asyncmsgq.c
Normal 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
75
src/pulsecore/asyncmsgq.h
Normal 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
213
src/pulsecore/asyncq.c
Normal 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
56
src/pulsecore/asyncq.h
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@
|
|||
USA.
|
||||
***/
|
||||
|
||||
typedef enum pa_mixer {
|
||||
PA_MIXER_SOFTWARE,
|
||||
PA_MIXER_HARDWARE
|
||||
} pa_mixer_t;
|
||||
/* FIXME: Remove this shit */
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
276
src/pulsecore/fdsem.c
Normal 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
49
src/pulsecore/fdsem.h
Normal 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
|
||||
13
src/pulsecore/ffmpeg/Makefile
Normal file
13
src/pulsecore/ffmpeg/Makefile
Normal 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
|
||||
82
src/pulsecore/ffmpeg/avcodec.h
Normal file
82
src/pulsecore/ffmpeg/avcodec.h
Normal 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 */
|
||||
1
src/pulsecore/ffmpeg/dsputil.h
Normal file
1
src/pulsecore/ffmpeg/dsputil.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
/* empty file, just here to allow us to compile an unmodified resampler2.c */
|
||||
324
src/pulsecore/ffmpeg/resample2.c
Normal file
324
src/pulsecore/ffmpeg/resample2.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ++;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
64
src/pulsecore/ltdl-helper.c
Normal file
64
src/pulsecore/ltdl-helper.c
Normal 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;
|
||||
}
|
||||
34
src/pulsecore/ltdl-helper.h
Normal file
34
src/pulsecore/ltdl-helper.h
Normal 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
149
src/pulsecore/macro.h
Normal 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
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
49
src/pulsecore/msgobject.c
Normal 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
54
src/pulsecore/msgobject.h
Normal 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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
72
src/pulsecore/object.c
Normal 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
106
src/pulsecore/object.h
Normal 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
|
||||
|
|
@ -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. */
|
||||
}
|
||||
|
|
@ -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
96
src/pulsecore/once.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
#include "winsock.h"
|
||||
|
||||
#ifndef HAVE_SYS_POLL_H
|
||||
#ifndef HAVE_POLL_H
|
||||
|
||||
#include <pulsecore/core-util.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue