mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-10 13:29:58 -05:00
Merge branch 'master' of git://0pointer.de/pulseaudio into dbus-work
Conflicts: src/Makefile.am src/daemon/daemon-conf.c src/daemon/daemon.conf.in src/modules/module-stream-restore.c src/pulse/client-conf.c src/pulsecore/namereg.c
This commit is contained in:
commit
bcaba0b1b4
134 changed files with 15076 additions and 12812 deletions
|
|
@ -26,14 +26,16 @@
|
|||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <pulse/xmalloc.h>
|
||||
|
||||
#include <pulsecore/atomic.h>
|
||||
#include <pulsecore/macro.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"
|
||||
|
||||
|
|
@ -76,7 +78,7 @@ static void asyncmsgq_free(pa_asyncmsgq *a) {
|
|||
struct asyncmsgq_item *i;
|
||||
pa_assert(a);
|
||||
|
||||
while ((i = pa_asyncq_pop(a->asyncq, 0))) {
|
||||
while ((i = pa_asyncq_pop(a->asyncq, FALSE))) {
|
||||
|
||||
pa_assert(!i->semaphore);
|
||||
|
||||
|
|
@ -172,11 +174,11 @@ int pa_asyncmsgq_send(pa_asyncmsgq *a, pa_msgobject *object, int code, const voi
|
|||
return i.ret;
|
||||
}
|
||||
|
||||
int pa_asyncmsgq_get(pa_asyncmsgq *a, pa_msgobject **object, int *code, void **userdata, int64_t *offset, pa_memchunk *chunk, pa_bool_t wait) {
|
||||
int pa_asyncmsgq_get(pa_asyncmsgq *a, pa_msgobject **object, int *code, void **userdata, int64_t *offset, pa_memchunk *chunk, pa_bool_t wait_op) {
|
||||
pa_assert(PA_REFCNT_VALUE(a) > 0);
|
||||
pa_assert(!a->current);
|
||||
|
||||
if (!(a->current = pa_asyncq_pop(a->asyncq, wait))) {
|
||||
if (!(a->current = pa_asyncq_pop(a->asyncq, wait_op))) {
|
||||
/* pa_log("failure"); */
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -246,7 +248,7 @@ int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) {
|
|||
pa_memchunk chunk;
|
||||
int ret;
|
||||
|
||||
if (pa_asyncmsgq_get(a, &o, &c, &data, &offset, &chunk, 1) < 0)
|
||||
if (pa_asyncmsgq_get(a, &o, &c, &data, &offset, &chunk, TRUE) < 0)
|
||||
return -1;
|
||||
|
||||
ret = pa_asyncmsgq_dispatch(o, c, data, offset, &chunk);
|
||||
|
|
@ -269,7 +271,7 @@ int pa_asyncmsgq_process_one(pa_asyncmsgq *a) {
|
|||
|
||||
pa_assert(PA_REFCNT_VALUE(a) > 0);
|
||||
|
||||
if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, 0) < 0)
|
||||
if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, FALSE) < 0)
|
||||
return 0;
|
||||
|
||||
pa_asyncmsgq_ref(a);
|
||||
|
|
@ -323,3 +325,35 @@ int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, int64_
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pa_asyncmsgq_flush(pa_asyncmsgq *a, pa_bool_t run) {
|
||||
pa_assert(PA_REFCNT_VALUE(a) > 0);
|
||||
|
||||
for (;;) {
|
||||
pa_msgobject *object;
|
||||
int code;
|
||||
void *data;
|
||||
int64_t offset;
|
||||
pa_memchunk chunk;
|
||||
int ret;
|
||||
|
||||
if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, FALSE) < 0)
|
||||
return;
|
||||
|
||||
if (!run) {
|
||||
pa_asyncmsgq_done(a, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
pa_asyncmsgq_ref(a);
|
||||
ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk);
|
||||
pa_asyncmsgq_done(a, ret);
|
||||
pa_asyncmsgq_unref(a);
|
||||
}
|
||||
}
|
||||
|
||||
pa_bool_t pa_asyncmsgq_dispatching(pa_asyncmsgq *a) {
|
||||
pa_assert(PA_REFCNT_VALUE(a) > 0);
|
||||
|
||||
return !!a->current;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ 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);
|
||||
|
||||
void pa_asyncmsgq_flush(pa_asyncmsgq *a, pa_bool_t run);
|
||||
|
||||
/* For the reading side */
|
||||
int pa_asyncmsgq_read_fd(pa_asyncmsgq *q);
|
||||
int pa_asyncmsgq_read_before_poll(pa_asyncmsgq *a);
|
||||
|
|
@ -76,4 +78,6 @@ int pa_asyncmsgq_write_fd(pa_asyncmsgq *q);
|
|||
void pa_asyncmsgq_write_before_poll(pa_asyncmsgq *a);
|
||||
void pa_asyncmsgq_write_after_poll(pa_asyncmsgq *a);
|
||||
|
||||
pa_bool_t pa_asyncmsgq_dispatching(pa_asyncmsgq *a);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ struct pa_aupdate {
|
|||
pa_atomic_t read_lock;
|
||||
pa_mutex *write_lock;
|
||||
pa_semaphore *semaphore;
|
||||
pa_bool_t swapped;
|
||||
};
|
||||
|
||||
pa_aupdate *pa_aupdate_new(void) {
|
||||
|
|
@ -101,6 +102,8 @@ unsigned pa_aupdate_write_begin(pa_aupdate *a) {
|
|||
|
||||
n = (unsigned) pa_atomic_load(&a->read_lock);
|
||||
|
||||
a->swapped = FALSE;
|
||||
|
||||
return !WHICH(n);
|
||||
}
|
||||
|
||||
|
|
@ -119,11 +122,16 @@ unsigned pa_aupdate_write_swap(pa_aupdate *a) {
|
|||
break;
|
||||
}
|
||||
|
||||
a->swapped = TRUE;
|
||||
|
||||
return WHICH(n);
|
||||
}
|
||||
|
||||
void pa_aupdate_write_end(pa_aupdate *a) {
|
||||
pa_assert(a);
|
||||
|
||||
if (!a->swapped)
|
||||
pa_aupdate_write_swap(a);
|
||||
|
||||
pa_mutex_unlock(a->write_lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ unsigned pa_aupdate_write_swap(pa_aupdate *a);
|
|||
* pa_update_write_end(a)
|
||||
* }
|
||||
*
|
||||
* In some cases keeping both structures up-to-date might not be
|
||||
* necessary, since they are fully rebuilt on each iteration
|
||||
* anyway. In that case you may leave the _write_swap() call out, it
|
||||
* will then be done implicitly in the _write_end() invocation.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <sys/stat.h>
|
||||
|
||||
#include <pulse/util.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulsecore/core-error.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/log.h>
|
||||
|
|
@ -147,47 +148,46 @@ 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) {
|
||||
static char *normalize_path(const char *fn) {
|
||||
|
||||
pa_assert(fn);
|
||||
pa_assert(s);
|
||||
pa_assert(l > 0);
|
||||
|
||||
#ifndef OS_IS_WIN32
|
||||
if (fn[0] != '/') {
|
||||
#else
|
||||
if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
|
||||
#endif
|
||||
char homedir[PATH_MAX];
|
||||
char *homedir, *s;
|
||||
|
||||
if (!pa_get_home_dir(homedir, sizeof(homedir)))
|
||||
if (!(homedir = pa_get_home_dir_malloc()))
|
||||
return NULL;
|
||||
|
||||
#ifndef OS_IS_WIN32
|
||||
pa_snprintf(s, l, "%s/%s", homedir, fn);
|
||||
#else
|
||||
pa_snprintf(s, l, "%s\\%s", homedir, fn);
|
||||
#endif
|
||||
s = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", homedir, fn);
|
||||
pa_xfree(homedir);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
return fn;
|
||||
return pa_xstrdup(fn);
|
||||
}
|
||||
|
||||
/* Load a cookie from a file in the home directory. If the specified
|
||||
* path starts with /, use it as absolute path instead. */
|
||||
int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
|
||||
char path[PATH_MAX];
|
||||
const char *p;
|
||||
char *p;
|
||||
int ret;
|
||||
|
||||
pa_assert(fn);
|
||||
pa_assert(data);
|
||||
pa_assert(length > 0);
|
||||
|
||||
if (!(p = normalize_path(fn, path, sizeof(path))))
|
||||
if (!(p = normalize_path(fn)))
|
||||
return -2;
|
||||
|
||||
return pa_authkey_load(p, data, length);
|
||||
ret = pa_authkey_load(p, data, length);
|
||||
pa_xfree(p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Store the specified cookie in the specified cookie file */
|
||||
|
|
@ -195,14 +195,13 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) {
|
|||
int fd = -1;
|
||||
int unlock = 0, ret = -1;
|
||||
ssize_t r;
|
||||
char path[PATH_MAX];
|
||||
const char *p;
|
||||
char *p;
|
||||
|
||||
pa_assert(fn);
|
||||
pa_assert(data);
|
||||
pa_assert(length > 0);
|
||||
|
||||
if (!(p = normalize_path(fn, path, sizeof(path))))
|
||||
if (!(p = normalize_path(fn)))
|
||||
return -2;
|
||||
|
||||
if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
|
||||
|
|
@ -232,5 +231,7 @@ finish:
|
|||
}
|
||||
}
|
||||
|
||||
pa_xfree(p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ char *pa_sink_list_to_string(pa_core *c) {
|
|||
pa_strbuf_printf(
|
||||
s,
|
||||
"\tfixed latency: %0.2f ms\n",
|
||||
(double) pa_sink_get_requested_latency(sink) / PA_USEC_PER_MSEC);
|
||||
(double) pa_sink_get_fixed_latency(sink) / PA_USEC_PER_MSEC);
|
||||
|
||||
if (sink->card)
|
||||
pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name);
|
||||
|
|
@ -415,7 +415,7 @@ char *pa_source_list_to_string(pa_core *c) {
|
|||
pa_strbuf_printf(
|
||||
s,
|
||||
"\tfixed latency: %0.2f ms\n",
|
||||
(double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC);
|
||||
(double) pa_source_get_fixed_latency(source) / PA_USEC_PER_MSEC);
|
||||
|
||||
if (source->monitor_of)
|
||||
pa_strbuf_printf(s, "\tmonitor_of: %u\n", source->monitor_of->index);
|
||||
|
|
@ -482,7 +482,7 @@ char *pa_source_output_list_to_string(pa_core *c) {
|
|||
s,
|
||||
" index: %u\n"
|
||||
"\tdriver: <%s>\n"
|
||||
"\tflags: %s%s%s%s%s%s%s%s%s%s\n"
|
||||
"\tflags: %s%s%s%s%s%s%s%s%s%s%s\n"
|
||||
"\tstate: %s\n"
|
||||
"\tsource: %u <%s>\n"
|
||||
"\tcurrent latency: %0.2f ms\n"
|
||||
|
|
@ -501,7 +501,8 @@ char *pa_source_output_list_to_string(pa_core *c) {
|
|||
o->flags & PA_SOURCE_OUTPUT_FIX_RATE ? "FIX_RATE " : "",
|
||||
o->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "",
|
||||
o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "",
|
||||
o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "",
|
||||
o->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_ON_SUSPEND " : "",
|
||||
o->flags & PA_SOURCE_OUTPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "",
|
||||
state_table[pa_source_output_get_state(o)],
|
||||
o->source->index, o->source->name,
|
||||
(double) pa_source_output_get_latency(o, NULL) / PA_USEC_PER_MSEC,
|
||||
|
|
@ -564,7 +565,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
|
|||
s,
|
||||
" index: %u\n"
|
||||
"\tdriver: <%s>\n"
|
||||
"\tflags: %s%s%s%s%s%s%s%s%s%s\n"
|
||||
"\tflags: %s%s%s%s%s%s%s%s%s%s%s\n"
|
||||
"\tstate: %s\n"
|
||||
"\tsink: %u <%s>\n"
|
||||
"\tvolume: %s\n"
|
||||
|
|
@ -587,7 +588,8 @@ char *pa_sink_input_list_to_string(pa_core *c) {
|
|||
i->flags & PA_SINK_INPUT_FIX_RATE ? "FIX_RATE " : "",
|
||||
i->flags & PA_SINK_INPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "",
|
||||
i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "",
|
||||
i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "",
|
||||
i->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_SUSPEND " : "",
|
||||
i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "",
|
||||
state_table[pa_sink_input_get_state(i)],
|
||||
i->sink->index, i->sink->name,
|
||||
pa_cvolume_snprint(cv, sizeof(cv), &v),
|
||||
|
|
|
|||
|
|
@ -278,6 +278,30 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *sectio
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pa_config_parse_not_bool(
|
||||
const char *filename, unsigned line,
|
||||
const char *section,
|
||||
const char *lvalue, const char *rvalue,
|
||||
void *data, void *userdata) {
|
||||
|
||||
int k;
|
||||
pa_bool_t *b = 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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*b = !k;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pa_config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
|
||||
char **s = data;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *section
|
|||
int pa_config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
|
||||
int pa_config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
|
||||
int pa_config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
|
||||
int pa_config_parse_not_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
|
||||
int pa_config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -494,13 +494,14 @@ int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) {
|
|||
struct dirent *e;
|
||||
|
||||
while ((e = readdir(dir))) {
|
||||
char p[PATH_MAX];
|
||||
char *p;
|
||||
|
||||
if (e->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
pa_snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name);
|
||||
p = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", pathname, e->d_name);
|
||||
add_file(c, p);
|
||||
pa_xfree(p);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
|
|
|||
|
|
@ -101,6 +101,10 @@
|
|||
#include "rtkit.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/personality.h>
|
||||
#endif
|
||||
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/util.h>
|
||||
#include <pulse/utf8.h>
|
||||
|
|
@ -552,12 +556,20 @@ 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) {
|
||||
size_t k;
|
||||
|
||||
pa_assert(b);
|
||||
pa_assert(s);
|
||||
pa_assert(l > 0);
|
||||
|
||||
strncpy(b, s, l);
|
||||
b[l-1] = 0;
|
||||
k = strlen(s);
|
||||
|
||||
if (k > l-1)
|
||||
k = l-1;
|
||||
|
||||
memcpy(b, s, k);
|
||||
b[k] = 0;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
|
@ -1328,26 +1340,32 @@ int pa_unlock_lockfile(const char *fn, int fd) {
|
|||
}
|
||||
|
||||
static char *get_pulse_home(void) {
|
||||
char h[PATH_MAX];
|
||||
char *h;
|
||||
struct stat st;
|
||||
char *ret = NULL;
|
||||
|
||||
if (!pa_get_home_dir(h, sizeof(h))) {
|
||||
if (!(h = pa_get_home_dir_malloc())) {
|
||||
pa_log_error("Failed to get home directory.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (stat(h, &st) < 0) {
|
||||
pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno));
|
||||
return NULL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (st.st_uid != getuid()) {
|
||||
pa_log_error("Home directory %s not ours.", h);
|
||||
errno = EACCES;
|
||||
return NULL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
return pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
|
||||
ret = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
|
||||
|
||||
finish:
|
||||
pa_xfree(h);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *pa_get_state_dir(void) {
|
||||
|
|
@ -1372,6 +1390,50 @@ char *pa_get_state_dir(void) {
|
|||
return d;
|
||||
}
|
||||
|
||||
char *pa_get_home_dir_malloc(void) {
|
||||
char *homedir;
|
||||
size_t allocated = 128;
|
||||
|
||||
for (;;) {
|
||||
homedir = pa_xmalloc(allocated);
|
||||
|
||||
if (!pa_get_home_dir(homedir, allocated)) {
|
||||
pa_xfree(homedir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strlen(homedir) < allocated - 1)
|
||||
break;
|
||||
|
||||
pa_xfree(homedir);
|
||||
allocated *= 2;
|
||||
}
|
||||
|
||||
return homedir;
|
||||
}
|
||||
|
||||
char *pa_get_binary_name_malloc(void) {
|
||||
char *t;
|
||||
size_t allocated = 128;
|
||||
|
||||
for (;;) {
|
||||
t = pa_xmalloc(allocated);
|
||||
|
||||
if (!pa_get_binary_name(t, allocated)) {
|
||||
pa_xfree(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strlen(t) < allocated - 1)
|
||||
break;
|
||||
|
||||
pa_xfree(t);
|
||||
allocated *= 2;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static char* make_random_dir(mode_t m) {
|
||||
static const char table[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
|
|
@ -1481,7 +1543,7 @@ char *pa_get_runtime_dir(void) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:runtime", d, mid);
|
||||
k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-runtime", d, mid);
|
||||
pa_xfree(d);
|
||||
pa_xfree(mid);
|
||||
|
||||
|
|
@ -1626,14 +1688,15 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
|
|||
if (local) {
|
||||
const char *e;
|
||||
char *lfn;
|
||||
char h[PATH_MAX];
|
||||
char *h;
|
||||
FILE *f;
|
||||
|
||||
if ((e = getenv("PULSE_CONFIG_PATH")))
|
||||
fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
|
||||
else if (pa_get_home_dir(h, sizeof(h)))
|
||||
else if ((h = pa_get_home_dir_malloc())) {
|
||||
fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
|
||||
else
|
||||
pa_xfree(h);
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
#ifdef OS_IS_WIN32
|
||||
|
|
@ -1713,13 +1776,14 @@ char *pa_find_config_file(const char *global, const char *local, const char *env
|
|||
if (local) {
|
||||
const char *e;
|
||||
char *lfn;
|
||||
char h[PATH_MAX];
|
||||
char *h;
|
||||
|
||||
if ((e = getenv("PULSE_CONFIG_PATH")))
|
||||
fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
|
||||
else if (pa_get_home_dir(h, sizeof(h)))
|
||||
else if ((h = pa_get_home_dir_malloc())) {
|
||||
fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
|
||||
else
|
||||
pa_xfree(h);
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
#ifdef OS_IS_WIN32
|
||||
|
|
@ -1904,7 +1968,7 @@ static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:%s", rtp, mid, fn);
|
||||
r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-%s", rtp, mid, fn);
|
||||
pa_xfree(mid);
|
||||
} else
|
||||
r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", rtp, fn);
|
||||
|
|
@ -2801,3 +2865,28 @@ char* pa_maybe_prefix_path(const char *path, const char *prefix) {
|
|||
|
||||
return pa_sprintf_malloc("%s" PA_PATH_SEP "%s", prefix, path);
|
||||
}
|
||||
|
||||
size_t pa_pipe_buf(int fd) {
|
||||
|
||||
#ifdef _PC_PIPE_BUF
|
||||
long n;
|
||||
|
||||
if ((n = fpathconf(fd, _PC_PIPE_BUF)) >= 0)
|
||||
return (size_t) n;
|
||||
#endif
|
||||
|
||||
#ifdef PIPE_BUF
|
||||
return PIPE_BUF;
|
||||
#else
|
||||
return 4096;
|
||||
#endif
|
||||
}
|
||||
|
||||
void pa_reset_personality(void) {
|
||||
|
||||
#ifdef __linux__
|
||||
if (personality(PER_LINUX) < 0)
|
||||
pa_log_warn("Uh, personality() failed: %s", pa_cstrerror(errno));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ char* pa_find_config_file(const char *global, const char *local, const char *env
|
|||
|
||||
char *pa_get_runtime_dir(void);
|
||||
char *pa_get_state_dir(void);
|
||||
char *pa_get_home_dir_malloc(void);
|
||||
char *pa_get_binary_name_malloc(void);
|
||||
char *pa_runtime_path(const char *fn);
|
||||
char *pa_state_path(const char *fn, pa_bool_t prepend_machine_id);
|
||||
|
||||
|
|
@ -243,4 +245,9 @@ char **pa_split_spaces_strv(const char *s);
|
|||
|
||||
char* pa_maybe_prefix_path(const char *path, const char *prefix);
|
||||
|
||||
/* Returns size of the specified pipe or 4096 on failure */
|
||||
size_t pa_pipe_buf(int fd);
|
||||
|
||||
void pa_reset_personality(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
510
src/pulsecore/database-simple.c
Normal file
510
src/pulsecore/database-simple.c
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
/***
|
||||
This file is part of PulseAudio.
|
||||
|
||||
Copyright 2009 Nokia Corporation
|
||||
Contact: Maemo Multimedia <multimedia@maemo.org>
|
||||
|
||||
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 <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/log.h>
|
||||
#include <pulsecore/core-error.h>
|
||||
#include <pulsecore/hashmap.h>
|
||||
|
||||
#include "database.h"
|
||||
|
||||
|
||||
typedef struct simple_data {
|
||||
char *filename;
|
||||
char *tmp_filename;
|
||||
pa_hashmap *map;
|
||||
pa_bool_t read_only;
|
||||
} simple_data;
|
||||
|
||||
typedef struct entry {
|
||||
pa_datum key;
|
||||
pa_datum data;
|
||||
} entry;
|
||||
|
||||
void pa_datum_free(pa_datum *d) {
|
||||
pa_assert(d);
|
||||
|
||||
pa_xfree(d->data);
|
||||
d->data = NULL;
|
||||
d->size = 0;
|
||||
}
|
||||
|
||||
static int compare_func(const void *a, const void *b) {
|
||||
const pa_datum *aa, *bb;
|
||||
|
||||
aa = (const pa_datum*)a;
|
||||
bb = (const pa_datum*)b;
|
||||
|
||||
if (aa->size != bb->size)
|
||||
return aa->size > bb->size ? 1 : -1;
|
||||
|
||||
return memcmp(aa->data, bb->data, aa->size);
|
||||
}
|
||||
|
||||
/* pa_idxset_string_hash_func modified for our use */
|
||||
static unsigned hash_func(const void *p) {
|
||||
const pa_datum *d;
|
||||
unsigned hash = 0;
|
||||
const char *c;
|
||||
unsigned i;
|
||||
|
||||
d = (const pa_datum*)p;
|
||||
c = d->data;
|
||||
|
||||
for (i = 0; i < d->size; i++) {
|
||||
hash = 31 * hash + (unsigned) *c;
|
||||
c++;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static entry* new_entry(const pa_datum *key, const pa_datum *data) {
|
||||
entry *e;
|
||||
|
||||
pa_assert(key);
|
||||
pa_assert(data);
|
||||
|
||||
e = pa_xnew0(entry, 1);
|
||||
e->key.data = key->size > 0 ? pa_xmemdup(key->data, key->size) : NULL;
|
||||
e->key.size = key->size;
|
||||
e->data.data = data->size > 0 ? pa_xmemdup(data->data, data->size) : NULL;
|
||||
e->data.size = data->size;
|
||||
return e;
|
||||
}
|
||||
|
||||
static void free_entry(entry *e) {
|
||||
if (e) {
|
||||
if (e->key.data)
|
||||
pa_xfree(e->key.data);
|
||||
if (e->data.data)
|
||||
pa_xfree(e->data.data);
|
||||
pa_xfree(e);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_uint(FILE *f, uint32_t *res) {
|
||||
size_t items = 0;
|
||||
uint8_t values[4];
|
||||
uint32_t tmp;
|
||||
int i;
|
||||
|
||||
items = fread(&values, sizeof(values), sizeof(uint8_t), f);
|
||||
|
||||
if (feof(f)) /* EOF */
|
||||
return 0;
|
||||
|
||||
if (ferror(f))
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
tmp = values[i];
|
||||
*res += (tmp << (i*8));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
static int read_data(FILE *f, void **data, ssize_t *length) {
|
||||
size_t items = 0;
|
||||
uint32_t data_len = 0;
|
||||
|
||||
pa_assert(f);
|
||||
|
||||
*data = NULL;
|
||||
*length = 0;
|
||||
|
||||
if ((items = read_uint(f, &data_len)) <= 0)
|
||||
return -1;
|
||||
|
||||
if (data_len > 0) {
|
||||
*data = pa_xmalloc0(data_len);
|
||||
items = fread(*data, data_len, 1, f);
|
||||
|
||||
if (feof(f)) /* EOF */
|
||||
goto reset;
|
||||
|
||||
if (ferror(f))
|
||||
goto reset;
|
||||
|
||||
*length = data_len;
|
||||
|
||||
} else { /* no data? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
reset:
|
||||
pa_xfree(*data);
|
||||
*data = NULL;
|
||||
*length = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int fill_data(simple_data *db, FILE *f) {
|
||||
pa_datum key;
|
||||
pa_datum data;
|
||||
void *d = NULL;
|
||||
ssize_t l = 0;
|
||||
pa_bool_t append = FALSE;
|
||||
enum { FIELD_KEY = 0, FIELD_DATA } field = FIELD_KEY;
|
||||
|
||||
pa_assert(db);
|
||||
pa_assert(db->map);
|
||||
|
||||
errno = 0;
|
||||
|
||||
key.size = 0;
|
||||
key.data = NULL;
|
||||
|
||||
while (!read_data(f, &d, &l)) {
|
||||
|
||||
switch (field) {
|
||||
case FIELD_KEY:
|
||||
key.data = d;
|
||||
key.size = l;
|
||||
field = FIELD_DATA;
|
||||
break;
|
||||
case FIELD_DATA:
|
||||
data.data = d;
|
||||
data.size = l;
|
||||
append = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (append) {
|
||||
entry *e = pa_xnew0(entry, 1);
|
||||
e->key.data = key.data;
|
||||
e->key.size = key.size;
|
||||
e->data.data = data.data;
|
||||
e->data.size = data.size;
|
||||
pa_hashmap_put(db->map, &e->key, e);
|
||||
append = FALSE;
|
||||
field = FIELD_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(f)) {
|
||||
pa_log_warn("read error. %s", pa_cstrerror(errno));
|
||||
pa_database_clear((pa_database*)db);
|
||||
}
|
||||
|
||||
if (field == FIELD_DATA && d)
|
||||
pa_xfree(d);
|
||||
|
||||
return pa_hashmap_size(db->map);
|
||||
}
|
||||
|
||||
pa_database* pa_database_open(const char *fn, pa_bool_t for_write) {
|
||||
FILE *f;
|
||||
char *path;
|
||||
simple_data *db;
|
||||
|
||||
pa_assert(fn);
|
||||
|
||||
path = pa_sprintf_malloc("%s."CANONICAL_HOST".simple", fn);
|
||||
errno = 0;
|
||||
|
||||
f = fopen(path, "r");
|
||||
|
||||
if (f || errno == ENOENT) { /* file not found is ok */
|
||||
db = pa_xnew0(simple_data, 1);
|
||||
db->map = pa_hashmap_new(hash_func, compare_func);
|
||||
db->filename = pa_xstrdup(path);
|
||||
db->tmp_filename = pa_sprintf_malloc(".%s.tmp", db->filename);
|
||||
db->read_only = !for_write;
|
||||
|
||||
if (f) {
|
||||
fill_data(db, f);
|
||||
fclose(f);
|
||||
}
|
||||
} else {
|
||||
if (errno == 0)
|
||||
errno = EIO;
|
||||
db = NULL;
|
||||
}
|
||||
|
||||
pa_xfree(path);
|
||||
|
||||
return (pa_database*) db;
|
||||
}
|
||||
|
||||
void pa_database_close(pa_database *database) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
pa_assert(db);
|
||||
|
||||
pa_database_sync(database);
|
||||
pa_database_clear(database);
|
||||
pa_xfree(db->filename);
|
||||
pa_xfree(db->tmp_filename);
|
||||
pa_hashmap_free(db->map, NULL, NULL);
|
||||
pa_xfree(db);
|
||||
}
|
||||
|
||||
pa_datum* pa_database_get(pa_database *database, const pa_datum *key, pa_datum* data) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
entry *e;
|
||||
|
||||
pa_assert(db);
|
||||
pa_assert(key);
|
||||
pa_assert(data);
|
||||
|
||||
e = pa_hashmap_get(db->map, key);
|
||||
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
||||
data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
|
||||
data->size = e->data.size;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int pa_database_set(pa_database *database, const pa_datum *key, const pa_datum* data, pa_bool_t overwrite) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
entry *e;
|
||||
int ret = 0;
|
||||
|
||||
pa_assert(db);
|
||||
pa_assert(key);
|
||||
pa_assert(data);
|
||||
|
||||
if (db->read_only)
|
||||
return -1;
|
||||
|
||||
e = new_entry(key, data);
|
||||
|
||||
if (pa_hashmap_put(db->map, &e->key, e) < 0) {
|
||||
/* entry with same key exists in hashmap */
|
||||
entry *r;
|
||||
if (overwrite) {
|
||||
r = pa_hashmap_remove(db->map, key);
|
||||
pa_hashmap_put(db->map, &e->key, e);
|
||||
} else {
|
||||
/* wont't overwrite, so clean new entry */
|
||||
r = e;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
free_entry(r);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pa_database_unset(pa_database *database, const pa_datum *key) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
entry *e;
|
||||
|
||||
pa_assert(db);
|
||||
pa_assert(key);
|
||||
|
||||
e = pa_hashmap_remove(db->map, key);
|
||||
if (!e)
|
||||
return -1;
|
||||
|
||||
free_entry(e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pa_database_clear(pa_database *database) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
entry *e;
|
||||
|
||||
pa_assert(db);
|
||||
|
||||
while ((e = pa_hashmap_steal_first(db->map)))
|
||||
free_entry(e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed pa_database_size(pa_database *database) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
pa_assert(db);
|
||||
|
||||
return (signed) pa_hashmap_size(db->map);
|
||||
}
|
||||
|
||||
pa_datum* pa_database_first(pa_database *database, pa_datum *key, pa_datum *data) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
entry *e;
|
||||
|
||||
pa_assert(db);
|
||||
pa_assert(key);
|
||||
|
||||
e = pa_hashmap_first(db->map);
|
||||
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
||||
key->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
|
||||
key->size = e->key.size;
|
||||
|
||||
if (data) {
|
||||
data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
|
||||
data->size = e->data.size;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
pa_datum* pa_database_next(pa_database *database, const pa_datum *key, pa_datum *next, pa_datum *data) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
entry *e;
|
||||
entry *search;
|
||||
void *state;
|
||||
pa_bool_t pick_now;
|
||||
|
||||
pa_assert(db);
|
||||
pa_assert(next);
|
||||
|
||||
if (!key)
|
||||
return pa_database_first(database, next, data);
|
||||
|
||||
search = pa_hashmap_get(db->map, key);
|
||||
|
||||
state = NULL;
|
||||
pick_now = FALSE;
|
||||
|
||||
while ((e = pa_hashmap_iterate(db->map, &state, NULL))) {
|
||||
if (pick_now)
|
||||
break;
|
||||
|
||||
if (search == e)
|
||||
pick_now = TRUE;
|
||||
}
|
||||
|
||||
if (!pick_now || !e)
|
||||
return NULL;
|
||||
|
||||
next->data = e->key.size > 0 ? pa_xmemdup(e->key.data, e->key.size) : NULL;
|
||||
next->size = e->key.size;
|
||||
|
||||
if (data) {
|
||||
data->data = e->data.size > 0 ? pa_xmemdup(e->data.data, e->data.size) : NULL;
|
||||
data->size = e->data.size;
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
static int write_uint(FILE *f, const uint32_t num) {
|
||||
size_t items;
|
||||
uint8_t values[4];
|
||||
int i;
|
||||
errno = 0;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
values[i] = (num >> (i*8)) & 0xFF;
|
||||
|
||||
items = fwrite(&values, sizeof(values), sizeof(uint8_t), f);
|
||||
|
||||
if (ferror(f))
|
||||
return -1;
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
static int write_data(FILE *f, void *data, const size_t length) {
|
||||
size_t items;
|
||||
uint32_t len;
|
||||
|
||||
len = length;
|
||||
if ((items = write_uint(f, len)) <= 0)
|
||||
return -1;
|
||||
|
||||
items = fwrite(data, length, 1, f);
|
||||
|
||||
if (ferror(f) || items != 1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_entry(FILE *f, const entry *e) {
|
||||
pa_assert(f);
|
||||
pa_assert(e);
|
||||
|
||||
if (write_data(f, e->key.data, e->key.size) < 0)
|
||||
return -1;
|
||||
if (write_data(f, e->data.data, e->data.size) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pa_database_sync(pa_database *database) {
|
||||
simple_data *db = (simple_data*)database;
|
||||
FILE *f;
|
||||
void *state;
|
||||
entry *e;
|
||||
|
||||
pa_assert(db);
|
||||
|
||||
if (db->read_only)
|
||||
return 0;
|
||||
|
||||
errno = 0;
|
||||
|
||||
f = fopen(db->tmp_filename, "w");
|
||||
|
||||
if (!f)
|
||||
goto fail;
|
||||
|
||||
state = NULL;
|
||||
while((e = pa_hashmap_iterate(db->map, &state, NULL))) {
|
||||
if (write_entry(f, e) < 0) {
|
||||
pa_log_warn("error while writing to file. %s", pa_cstrerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
||||
if (rename(db->tmp_filename, db->filename) < 0) {
|
||||
pa_log_warn("error while renaming file. %s", pa_cstrerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (f)
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -667,7 +667,7 @@ void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
|
|||
|
||||
pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
|
||||
|
||||
while ((key = pa_proplist_iterate(proplist, state))) {
|
||||
while ((key = pa_proplist_iterate(proplist, &state))) {
|
||||
const void *value = NULL;
|
||||
size_t nbytes;
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ pa_hook_result_t pa_hook_fire(pa_hook *hook, void *data) {
|
|||
|
||||
hook->n_firing ++;
|
||||
|
||||
for (slot = hook->slots; slot; slot = slot->next) {
|
||||
PA_LLIST_FOREACH(slot, hook->slots) {
|
||||
if (slot->dead)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,10 +55,16 @@ static pa_mutex *mutex;
|
|||
static unsigned n_ref = 0;
|
||||
static int lock_fd = -1;
|
||||
static pa_mutex *lock_fd_mutex = NULL;
|
||||
static pa_bool_t taken = FALSE;
|
||||
static pa_thread *thread;
|
||||
static pa_thread *thread = NULL;
|
||||
static int pipe_fd[2] = { -1, -1 };
|
||||
|
||||
static enum {
|
||||
STATE_IDLE,
|
||||
STATE_OWNING,
|
||||
STATE_TAKEN,
|
||||
STATE_FAILED
|
||||
} state = STATE_IDLE;
|
||||
|
||||
static void destroy_mutex(void) PA_GCC_DESTRUCTOR;
|
||||
|
||||
static int ref(void) {
|
||||
|
|
@ -67,15 +73,16 @@ static int ref(void) {
|
|||
|
||||
pa_assert(pipe_fd[0] >= 0);
|
||||
pa_assert(pipe_fd[1] >= 0);
|
||||
pa_assert(lock_fd_mutex);
|
||||
|
||||
n_ref++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pa_assert(lock_fd < 0);
|
||||
pa_assert(!lock_fd_mutex);
|
||||
pa_assert(!taken);
|
||||
pa_assert(state == STATE_IDLE);
|
||||
pa_assert(lock_fd < 0);
|
||||
pa_assert(!thread);
|
||||
pa_assert(pipe_fd[0] < 0);
|
||||
pa_assert(pipe_fd[1] < 0);
|
||||
|
|
@ -83,14 +90,14 @@ static int ref(void) {
|
|||
if (pipe(pipe_fd) < 0)
|
||||
return -1;
|
||||
|
||||
lock_fd_mutex = pa_mutex_new(FALSE, FALSE);
|
||||
|
||||
pa_make_fd_cloexec(pipe_fd[0]);
|
||||
pa_make_fd_cloexec(pipe_fd[1]);
|
||||
|
||||
pa_make_fd_nonblock(pipe_fd[1]);
|
||||
pa_make_fd_nonblock(pipe_fd[0]);
|
||||
|
||||
lock_fd_mutex = pa_mutex_new(FALSE, FALSE);
|
||||
|
||||
n_ref = 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -107,15 +114,18 @@ static void unref(pa_bool_t after_fork) {
|
|||
if (n_ref > 0)
|
||||
return;
|
||||
|
||||
pa_assert(!taken);
|
||||
|
||||
if (thread) {
|
||||
pa_thread_free(thread);
|
||||
thread = NULL;
|
||||
}
|
||||
|
||||
pa_mutex_lock(lock_fd_mutex);
|
||||
if (lock_fd >= 0) {
|
||||
|
||||
pa_assert(state != STATE_TAKEN);
|
||||
|
||||
if (state == STATE_OWNING) {
|
||||
|
||||
pa_assert(lock_fd >= 0);
|
||||
|
||||
if (after_fork)
|
||||
pa_close(lock_fd);
|
||||
|
|
@ -127,10 +137,12 @@ static void unref(pa_bool_t after_fork) {
|
|||
|
||||
pa_unlock_lockfile(lf, lock_fd);
|
||||
pa_xfree(lf);
|
||||
|
||||
lock_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
lock_fd = -1;
|
||||
state = STATE_IDLE;
|
||||
|
||||
pa_mutex_unlock(lock_fd_mutex);
|
||||
|
||||
pa_mutex_free(lock_fd_mutex);
|
||||
|
|
@ -205,15 +217,24 @@ static void thread_func(void *u) {
|
|||
|
||||
if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) {
|
||||
pa_log_warn(_("Cannot access autospawn lock."));
|
||||
goto finish;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((fd = pa_lock_lockfile(lf)) < 0)
|
||||
goto finish;
|
||||
goto fail;
|
||||
|
||||
pa_mutex_lock(lock_fd_mutex);
|
||||
pa_assert(lock_fd < 0);
|
||||
pa_assert(state == STATE_IDLE);
|
||||
lock_fd = fd;
|
||||
state = STATE_OWNING;
|
||||
pa_mutex_unlock(lock_fd_mutex);
|
||||
|
||||
goto finish;
|
||||
|
||||
fail:
|
||||
pa_mutex_lock(lock_fd_mutex);
|
||||
pa_assert(state == STATE_IDLE);
|
||||
state = STATE_FAILED;
|
||||
pa_mutex_unlock(lock_fd_mutex);
|
||||
|
||||
finish:
|
||||
|
|
@ -238,12 +259,10 @@ static void create_mutex(void) {
|
|||
}
|
||||
|
||||
static void destroy_mutex(void) {
|
||||
|
||||
if (mutex)
|
||||
pa_mutex_free(mutex);
|
||||
}
|
||||
|
||||
|
||||
int pa_autospawn_lock_init(void) {
|
||||
int ret = -1;
|
||||
|
||||
|
|
@ -273,13 +292,18 @@ int pa_autospawn_lock_acquire(pa_bool_t block) {
|
|||
|
||||
empty_pipe();
|
||||
|
||||
if (lock_fd >= 0 && !taken) {
|
||||
taken = TRUE;
|
||||
if (state == STATE_OWNING) {
|
||||
state = STATE_TAKEN;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lock_fd < 0)
|
||||
if (state == STATE_FAILED) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (state == STATE_IDLE)
|
||||
if (start_thread() < 0)
|
||||
break;
|
||||
|
||||
|
|
@ -310,8 +334,8 @@ void pa_autospawn_lock_release(void) {
|
|||
pa_mutex_lock(mutex);
|
||||
pa_assert(n_ref >= 1);
|
||||
|
||||
pa_assert(taken);
|
||||
taken = FALSE;
|
||||
pa_assert(state == STATE_TAKEN);
|
||||
state = STATE_OWNING;
|
||||
|
||||
ping();
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ struct pa_memimport_segment {
|
|||
unsigned n_blocks;
|
||||
};
|
||||
|
||||
/* A collection of multiple segments */
|
||||
struct pa_memimport {
|
||||
pa_mutex *mutex;
|
||||
|
||||
|
|
@ -257,7 +258,8 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) {
|
|||
slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * (size_t) idx));
|
||||
|
||||
if (!slot) {
|
||||
pa_log_info("Pool full");
|
||||
if (pa_log_ratelimit())
|
||||
pa_log_debug("Pool full");
|
||||
pa_atomic_inc(&p->stat.n_pool_full);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -509,13 +511,16 @@ static void memblock_free(pa_memblock *b) {
|
|||
|
||||
/* FIXME! This should be implemented lock-free */
|
||||
|
||||
segment = b->per_type.imported.segment;
|
||||
pa_assert(segment);
|
||||
import = segment->import;
|
||||
pa_assert(import);
|
||||
pa_assert_se(segment = b->per_type.imported.segment);
|
||||
pa_assert_se(import = segment->import);
|
||||
|
||||
pa_mutex_lock(import->mutex);
|
||||
pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id));
|
||||
|
||||
pa_assert_se(pa_hashmap_remove(
|
||||
import->blocks,
|
||||
PA_UINT32_TO_PTR(b->per_type.imported.id)));
|
||||
|
||||
pa_assert(segment->n_blocks >= 1);
|
||||
if (-- segment->n_blocks <= 0)
|
||||
segment_detach(segment);
|
||||
|
||||
|
|
@ -525,6 +530,7 @@ static void memblock_free(pa_memblock *b) {
|
|||
|
||||
if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0)
|
||||
pa_xfree(b);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -657,7 +663,8 @@ pa_memblock *pa_memblock_will_need(pa_memblock *b) {
|
|||
|
||||
/* Self-locked. This function is not multiple-caller safe */
|
||||
static void memblock_replace_import(pa_memblock *b) {
|
||||
pa_memimport_segment *seg;
|
||||
pa_memimport_segment *segment;
|
||||
pa_memimport *import;
|
||||
|
||||
pa_assert(b);
|
||||
pa_assert(b->type == PA_MEMBLOCK_IMPORTED);
|
||||
|
|
@ -667,23 +674,22 @@ static void memblock_replace_import(pa_memblock *b) {
|
|||
pa_atomic_dec(&b->pool->stat.n_imported);
|
||||
pa_atomic_sub(&b->pool->stat.imported_size, (int) b->length);
|
||||
|
||||
seg = b->per_type.imported.segment;
|
||||
pa_assert(seg);
|
||||
pa_assert(seg->import);
|
||||
pa_assert_se(segment = b->per_type.imported.segment);
|
||||
pa_assert_se(import = segment->import);
|
||||
|
||||
pa_mutex_lock(seg->import->mutex);
|
||||
pa_mutex_lock(import->mutex);
|
||||
|
||||
pa_hashmap_remove(
|
||||
seg->import->blocks,
|
||||
PA_UINT32_TO_PTR(b->per_type.imported.id));
|
||||
pa_assert_se(pa_hashmap_remove(
|
||||
import->blocks,
|
||||
PA_UINT32_TO_PTR(b->per_type.imported.id)));
|
||||
|
||||
memblock_make_local(b);
|
||||
|
||||
if (-- seg->n_blocks <= 0) {
|
||||
pa_mutex_unlock(seg->import->mutex);
|
||||
segment_detach(seg);
|
||||
} else
|
||||
pa_mutex_unlock(seg->import->mutex);
|
||||
pa_assert(segment->n_blocks >= 1);
|
||||
if (-- segment->n_blocks <= 0)
|
||||
segment_detach(segment);
|
||||
|
||||
pa_mutex_unlock(import->mutex);
|
||||
}
|
||||
|
||||
pa_mempool* pa_mempool_new(pa_bool_t shared, size_t size) {
|
||||
|
|
@ -956,6 +962,11 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i
|
|||
|
||||
pa_mutex_lock(i->mutex);
|
||||
|
||||
if ((b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(block_id)))) {
|
||||
pa_memblock_ref(b);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX)
|
||||
goto finish;
|
||||
|
||||
|
|
@ -985,12 +996,11 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i
|
|||
|
||||
seg->n_blocks++;
|
||||
|
||||
stat_add(b);
|
||||
|
||||
finish:
|
||||
pa_mutex_unlock(i->mutex);
|
||||
|
||||
if (b)
|
||||
stat_add(b);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -692,6 +692,12 @@ size_t pa_memblockq_get_minreq(pa_memblockq *bq) {
|
|||
return bq->minreq;
|
||||
}
|
||||
|
||||
size_t pa_memblockq_get_maxrewind(pa_memblockq *bq) {
|
||||
pa_assert(bq);
|
||||
|
||||
return bq->maxrewind;
|
||||
}
|
||||
|
||||
int64_t pa_memblockq_get_read_index(pa_memblockq *bq) {
|
||||
pa_assert(bq);
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ size_t pa_memblockq_get_prebuf(pa_memblockq *bq);
|
|||
/* Returns the minimal request value */
|
||||
size_t pa_memblockq_get_minreq(pa_memblockq *bq);
|
||||
|
||||
/* Returns the maximal rewind value */
|
||||
size_t pa_memblockq_get_maxrewind(pa_memblockq *bq);
|
||||
|
||||
/* Return the base unit in bytes */
|
||||
size_t pa_memblockq_get_base(pa_memblockq *bq);
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include <pulsecore/aupdate.h>
|
||||
#include <pulsecore/atomic.h>
|
||||
#include <pulsecore/once.h>
|
||||
#include <pulsecore/mutex.h>
|
||||
|
||||
#include "memtrap.h"
|
||||
|
||||
|
|
@ -49,6 +50,7 @@ struct pa_memtrap {
|
|||
|
||||
static pa_memtrap *memtraps[2] = { NULL, NULL };
|
||||
static pa_aupdate *aupdate;
|
||||
static pa_static_mutex mutex = PA_STATIC_MUTEX_INIT; /* only required to serialize access to the write side */
|
||||
|
||||
static void allocate_aupdate(void) {
|
||||
PA_ONCE_BEGIN {
|
||||
|
|
@ -63,7 +65,7 @@ pa_bool_t pa_memtrap_is_good(pa_memtrap *m) {
|
|||
}
|
||||
|
||||
static void sigsafe_error(const char *s) {
|
||||
write(STDERR_FILENO, s, strlen(s));
|
||||
(void) write(STDERR_FILENO, s, strlen(s));
|
||||
}
|
||||
|
||||
static void signal_handler(int sig, siginfo_t* si, void *data) {
|
||||
|
|
@ -124,6 +126,7 @@ static void memtrap_unlink(pa_memtrap *m, unsigned j) {
|
|||
pa_memtrap* pa_memtrap_add(const void *start, size_t size) {
|
||||
pa_memtrap *m = NULL;
|
||||
unsigned j;
|
||||
pa_mutex *mx;
|
||||
|
||||
pa_assert(start);
|
||||
pa_assert(size > 0);
|
||||
|
|
@ -138,33 +141,45 @@ pa_memtrap* pa_memtrap_add(const void *start, size_t size) {
|
|||
|
||||
allocate_aupdate();
|
||||
|
||||
mx = pa_static_mutex_get(&mutex, FALSE, TRUE);
|
||||
pa_mutex_lock(mx);
|
||||
|
||||
j = pa_aupdate_write_begin(aupdate);
|
||||
memtrap_link(m, j);
|
||||
j = pa_aupdate_write_swap(aupdate);
|
||||
memtrap_link(m, j);
|
||||
pa_aupdate_write_end(aupdate);
|
||||
|
||||
pa_mutex_unlock(mx);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void pa_memtrap_remove(pa_memtrap *m) {
|
||||
unsigned j;
|
||||
pa_mutex *mx;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
allocate_aupdate();
|
||||
|
||||
mx = pa_static_mutex_get(&mutex, FALSE, TRUE);
|
||||
pa_mutex_lock(mx);
|
||||
|
||||
j = pa_aupdate_write_begin(aupdate);
|
||||
memtrap_unlink(m, j);
|
||||
j = pa_aupdate_write_swap(aupdate);
|
||||
memtrap_unlink(m, j);
|
||||
pa_aupdate_write_end(aupdate);
|
||||
|
||||
pa_mutex_unlock(mx);
|
||||
|
||||
pa_xfree(m);
|
||||
}
|
||||
|
||||
pa_memtrap *pa_memtrap_update(pa_memtrap *m, const void *start, size_t size) {
|
||||
unsigned j;
|
||||
pa_mutex *mx;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
|
|
@ -176,6 +191,9 @@ pa_memtrap *pa_memtrap_update(pa_memtrap *m, const void *start, size_t size) {
|
|||
|
||||
allocate_aupdate();
|
||||
|
||||
mx = pa_static_mutex_get(&mutex, FALSE, TRUE);
|
||||
pa_mutex_lock(mx);
|
||||
|
||||
j = pa_aupdate_write_begin(aupdate);
|
||||
|
||||
if (m->start == start && m->size == size)
|
||||
|
|
@ -194,6 +212,8 @@ pa_memtrap *pa_memtrap_update(pa_memtrap *m, const void *start, size_t size) {
|
|||
unlock:
|
||||
pa_aupdate_write_end(aupdate);
|
||||
|
||||
pa_mutex_unlock(mx);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -167,26 +167,33 @@ void pa_namereg_unregister(pa_core *c, const char *name) {
|
|||
pa_assert_se(e = pa_hashmap_remove(c->namereg, name));
|
||||
|
||||
if (c->default_sink == e->data) {
|
||||
pa_sink *new_default = pa_idxset_first(c->sinks, &idx);
|
||||
pa_sink *new_default = NULL;
|
||||
|
||||
if (new_default == e->data)
|
||||
new_default = pa_idxset_next(c->sinks, &idx);
|
||||
/* FIXME: the selection here should be based priority values on
|
||||
* the sinks */
|
||||
|
||||
PA_IDXSET_FOREACH(new_default, c->sinks, idx) {
|
||||
if (new_default != e->data && PA_SINK_IS_LINKED(pa_sink_get_state(new_default)))
|
||||
break;
|
||||
}
|
||||
|
||||
pa_namereg_set_default_sink(c, new_default);
|
||||
|
||||
} else if (c->default_source == e->data) {
|
||||
pa_source *new_default;
|
||||
pa_source *new_default = NULL;
|
||||
|
||||
for (new_default = pa_idxset_first(c->sources, &idx); new_default; new_default = pa_idxset_next(c->sources, &idx)) {
|
||||
if (new_default != e->data && !new_default->monitor_of)
|
||||
/* First, try to find one that isn't a monitor */
|
||||
PA_IDXSET_FOREACH(new_default, c->sources, idx) {
|
||||
if (new_default != e->data && !new_default->monitor_of && PA_SOURCE_IS_LINKED(pa_source_get_state(new_default)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!new_default) {
|
||||
new_default = pa_idxset_first(c->sources, &idx);
|
||||
|
||||
if (new_default == e->data)
|
||||
new_default = pa_idxset_next(c->sources, &idx);
|
||||
/* Then, fallback to a monitor */
|
||||
PA_IDXSET_FOREACH(new_default, c->sources, idx) {
|
||||
if (new_default != e->data && PA_SOURCE_IS_LINKED(pa_source_get_state(new_default)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pa_namereg_set_default_source(c, new_default);
|
||||
|
|
@ -249,6 +256,9 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type) {
|
|||
pa_sink* pa_namereg_set_default_sink(pa_core*c, pa_sink *s) {
|
||||
pa_assert(c);
|
||||
|
||||
if (s && !PA_SINK_IS_LINKED(pa_sink_get_state(s)))
|
||||
return NULL;
|
||||
|
||||
if (c->default_sink != s) {
|
||||
c->default_sink = s;
|
||||
pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
|
||||
|
|
@ -260,6 +270,9 @@ pa_sink* pa_namereg_set_default_sink(pa_core*c, pa_sink *s) {
|
|||
pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) {
|
||||
pa_assert(c);
|
||||
|
||||
if (s && !PA_SOURCE_IS_LINKED(pa_source_get_state(s)))
|
||||
return NULL;
|
||||
|
||||
if (c->default_source != s) {
|
||||
c->default_source = s;
|
||||
pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
|
||||
|
|
@ -270,14 +283,47 @@ pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) {
|
|||
|
||||
/* XXX: After removing old functionality, has this function become useless? */
|
||||
pa_sink *pa_namereg_get_default_sink(pa_core *c) {
|
||||
pa_sink *s;
|
||||
uint32_t idx;
|
||||
|
||||
pa_assert(c);
|
||||
|
||||
return c->default_sink;
|
||||
if (!c->default_sink || PA_SINK_IS_LINKED(pa_sink_get_state(c->default_sink)))
|
||||
return c->default_sink;
|
||||
|
||||
/* The old default sink has become unlinked, set a new one. */
|
||||
|
||||
/* FIXME: the selection here should be based priority values on
|
||||
* the sinks */
|
||||
|
||||
PA_IDXSET_FOREACH(s, c->sinks, idx)
|
||||
if (PA_SINK_IS_LINKED(pa_sink_get_state(s)))
|
||||
return pa_namereg_set_default_sink(c, s);
|
||||
|
||||
return pa_namereg_set_default_sink(c, NULL);
|
||||
}
|
||||
|
||||
/* XXX: After removing old functionality, has this function become useless? */
|
||||
pa_source *pa_namereg_get_default_source(pa_core *c) {
|
||||
pa_source *s;
|
||||
uint32_t idx;
|
||||
|
||||
pa_assert(c);
|
||||
|
||||
return c->default_source;
|
||||
if (!c->default_source || PA_SOURCE_IS_LINKED(pa_source_get_state(c->default_source)))
|
||||
return c->default_source;
|
||||
|
||||
/* The old default source has become unlinked, set a new one. */
|
||||
|
||||
/* First, try to find one that isn't a monitor */
|
||||
PA_IDXSET_FOREACH(s, c->sources, idx)
|
||||
if (!s->monitor_of && PA_SOURCE_IS_LINKED(pa_source_get_state(s)))
|
||||
return pa_namereg_set_default_source(c, s);
|
||||
|
||||
/* Then, fallback to a monitor */
|
||||
PA_IDXSET_FOREACH(s, c->sources, idx)
|
||||
if (PA_SOURCE_IS_LINKED(pa_source_get_state(s)))
|
||||
return pa_namereg_set_default_source(c, s);
|
||||
|
||||
return pa_namereg_set_default_source(c, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,10 +186,12 @@ void pa_init_proplist(pa_proplist *p) {
|
|||
}
|
||||
|
||||
if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_BINARY)) {
|
||||
char t[PATH_MAX];
|
||||
if (pa_get_binary_name(t, sizeof(t))) {
|
||||
char *t;
|
||||
|
||||
if ((t = pa_get_binary_name_malloc())) {
|
||||
char *c = pa_utf8_filter(t);
|
||||
pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_BINARY, c);
|
||||
pa_xfree(t);
|
||||
pa_xfree(c);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -762,6 +762,7 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata,
|
|||
return -1;
|
||||
|
||||
switch (code) {
|
||||
|
||||
case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
|
||||
pa_tagstruct *t;
|
||||
int l = 0;
|
||||
|
|
@ -1130,6 +1131,12 @@ static void playback_stream_request_bytes(playback_stream *s) {
|
|||
|
||||
m = pa_memblockq_pop_missing(s->memblockq);
|
||||
|
||||
/* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu)", */
|
||||
/* (unsigned long) m, */
|
||||
/* pa_memblockq_get_tlength(s->memblockq), */
|
||||
/* pa_memblockq_get_minreq(s->memblockq), */
|
||||
/* pa_memblockq_get_length(s->memblockq)); */
|
||||
|
||||
if (m <= 0)
|
||||
return;
|
||||
|
||||
|
|
@ -1143,7 +1150,6 @@ static void playback_stream_request_bytes(playback_stream *s) {
|
|||
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Called from main context */
|
||||
static void playback_stream_send_killed(playback_stream *p) {
|
||||
pa_tagstruct *t;
|
||||
|
|
@ -1345,7 +1351,9 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
|
|||
/* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
|
||||
|
||||
if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
|
||||
pa_log_warn("Failed to push data into queue");
|
||||
|
||||
if (pa_log_ratelimit())
|
||||
pa_log_warn("Failed to push data into queue");
|
||||
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
|
||||
pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
|
||||
}
|
||||
|
|
@ -1617,6 +1625,9 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
|
|||
s = PLAYBACK_STREAM(i->userdata);
|
||||
playback_stream_assert_ref(s);
|
||||
|
||||
if (!dest)
|
||||
return;
|
||||
|
||||
fix_playback_buffer_attr(s);
|
||||
pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
|
||||
pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
|
||||
|
|
@ -1752,6 +1763,9 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
|
|||
s = RECORD_STREAM(o->userdata);
|
||||
record_stream_assert_ref(s);
|
||||
|
||||
if (!dest)
|
||||
return;
|
||||
|
||||
fix_record_buffer_attr_pre(s);
|
||||
pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
|
||||
pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
|
||||
|
|
@ -1951,7 +1965,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
|
|||
(no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
|
||||
(variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
|
||||
(dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
|
||||
(fail_on_suspend ? PA_SINK_INPUT_FAIL_ON_SUSPEND : 0);
|
||||
(fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0);
|
||||
|
||||
/* Only since protocol version 15 there's a seperate muted_set
|
||||
* flag. For older versions we synthesize it here */
|
||||
|
|
@ -2207,7 +2221,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
|
|||
(no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
|
||||
(variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
|
||||
(dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
|
||||
(fail_on_suspend ? PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND : 0);
|
||||
(fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
|
||||
|
||||
s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
|
||||
pa_proplist_free(p);
|
||||
|
|
@ -2550,7 +2564,7 @@ static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uin
|
|||
reply = reply_new(tag);
|
||||
pa_tagstruct_put_usec(reply,
|
||||
s->current_sink_latency +
|
||||
pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sample_spec));
|
||||
pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
|
||||
pa_tagstruct_put_usec(reply, 0);
|
||||
pa_tagstruct_put_boolean(reply,
|
||||
s->playing_for > 0 &&
|
||||
|
|
@ -2689,7 +2703,9 @@ static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uin
|
|||
CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
|
||||
CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
|
||||
|
||||
if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
|
||||
if (!s->memchunk.memblock)
|
||||
pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
|
||||
else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
|
||||
pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
|
||||
else
|
||||
pa_pstream_send_simple_ack(c->pstream, tag);
|
||||
|
|
@ -3321,6 +3337,7 @@ static void command_set_volume(
|
|||
pa_source *source = NULL;
|
||||
pa_sink_input *si = NULL;
|
||||
const char *name = NULL;
|
||||
const char *client_name;
|
||||
|
||||
pa_native_connection_assert_ref(c);
|
||||
pa_assert(t);
|
||||
|
|
@ -3367,12 +3384,20 @@ static void command_set_volume(
|
|||
|
||||
CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
|
||||
|
||||
if (sink)
|
||||
client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
|
||||
|
||||
if (sink) {
|
||||
pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
|
||||
pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE, TRUE);
|
||||
else if (source)
|
||||
} else if (source) {
|
||||
pa_log_debug("Client %s changes volume of sink %s.", client_name, source->name);
|
||||
pa_source_set_volume(source, &volume, TRUE);
|
||||
else if (si)
|
||||
} else if (si) {
|
||||
pa_log_debug("Client %s changes volume of sink %s.",
|
||||
client_name,
|
||||
pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
|
||||
pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
|
||||
}
|
||||
|
||||
pa_pstream_send_simple_ack(c->pstream, tag);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -347,13 +347,17 @@ void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) {
|
|||
size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
|
||||
pa_assert(r);
|
||||
|
||||
return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz;
|
||||
/* Let's round up here */
|
||||
|
||||
return (((((out_length + r->o_fz-1) / r->o_fz) * r->i_ss.rate) + r->o_ss.rate-1) / r->o_ss.rate) * r->i_fz;
|
||||
}
|
||||
|
||||
size_t pa_resampler_result(pa_resampler *r, size_t in_length) {
|
||||
pa_assert(r);
|
||||
|
||||
return (((in_length / r->i_fz)*r->o_ss.rate)/r->i_ss.rate) * r->o_fz;
|
||||
/* Let's round up here */
|
||||
|
||||
return (((((in_length + r->i_fz-1) / r->i_fz) * r->o_ss.rate) + r->i_ss.rate-1) / r->i_ss.rate) * r->o_fz;
|
||||
}
|
||||
|
||||
size_t pa_resampler_max_block_size(pa_resampler *r) {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@
|
|||
#define MADV_REMOVE 9
|
||||
#endif
|
||||
|
||||
#define MAX_SHM_SIZE (PA_ALIGN(1024*1024*64))
|
||||
/* 1 GiB at max */
|
||||
#define MAX_SHM_SIZE (PA_ALIGN(1024*1024*1024))
|
||||
|
||||
#ifdef __linux__
|
||||
/* On Linux we know that the shared memory blocks are files in
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ static void sink_input_free(pa_object *o);
|
|||
pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) {
|
||||
pa_assert(data);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
pa_zero(*data);
|
||||
data->resample_method = PA_RESAMPLER_INVALID;
|
||||
data->proplist = pa_proplist_new();
|
||||
|
||||
|
|
@ -114,6 +114,7 @@ static void reset_callbacks(pa_sink_input *i) {
|
|||
i->update_max_request = NULL;
|
||||
i->update_sink_requested_latency = NULL;
|
||||
i->update_sink_latency_range = NULL;
|
||||
i->update_sink_fixed_latency = NULL;
|
||||
i->attach = NULL;
|
||||
i->detach = NULL;
|
||||
i->suspend = NULL;
|
||||
|
|
@ -142,6 +143,7 @@ int pa_sink_input_new(
|
|||
pa_assert(_i);
|
||||
pa_assert(core);
|
||||
pa_assert(data);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (data->client)
|
||||
pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
|
||||
|
|
@ -220,7 +222,7 @@ int pa_sink_input_new(
|
|||
if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0)
|
||||
return r;
|
||||
|
||||
if ((flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) &&
|
||||
if ((flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) &&
|
||||
pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) {
|
||||
pa_log_warn("Failed to create sink input: sink is suspended.");
|
||||
return -PA_ERR_BADSTATE;
|
||||
|
|
@ -348,6 +350,7 @@ int pa_sink_input_new(
|
|||
/* Called from main context */
|
||||
static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
|
||||
pa_assert(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!i->sink)
|
||||
return;
|
||||
|
|
@ -362,6 +365,7 @@ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
|
|||
static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) {
|
||||
pa_sink_input *ssync;
|
||||
pa_assert(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (state == PA_SINK_INPUT_DRAINED)
|
||||
state = PA_SINK_INPUT_RUNNING;
|
||||
|
|
@ -400,7 +404,9 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state)
|
|||
void pa_sink_input_unlink(pa_sink_input *i) {
|
||||
pa_bool_t linked;
|
||||
pa_source_output *o, *p = NULL;
|
||||
|
||||
pa_assert(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
/* See pa_sink_unlink() for a couple of comments how this function
|
||||
* works */
|
||||
|
|
@ -471,6 +477,7 @@ static void sink_input_free(pa_object *o) {
|
|||
pa_sink_input* i = PA_SINK_INPUT(o);
|
||||
|
||||
pa_assert(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(pa_sink_input_refcnt(i) == 0);
|
||||
|
||||
if (PA_SINK_INPUT_IS_LINKED(i->state))
|
||||
|
|
@ -502,7 +509,9 @@ static void sink_input_free(pa_object *o) {
|
|||
/* Called from main context */
|
||||
void pa_sink_input_put(pa_sink_input *i) {
|
||||
pa_sink_input_state_t state;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
pa_assert(i->state == PA_SINK_INPUT_INIT);
|
||||
|
||||
|
|
@ -538,6 +547,7 @@ void pa_sink_input_put(pa_sink_input *i) {
|
|||
/* Called from main context */
|
||||
void pa_sink_input_kill(pa_sink_input*i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
|
||||
i->kill(i);
|
||||
|
|
@ -548,6 +558,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) {
|
|||
pa_usec_t r[2] = { 0, 0 };
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
|
||||
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
|
||||
|
|
@ -569,6 +580,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
|
|||
size_t ilength;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(slength, &i->sink->sample_spec));
|
||||
pa_assert(chunk);
|
||||
|
|
@ -706,8 +718,9 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
|
|||
|
||||
/* Called from thread context */
|
||||
void pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
|
||||
pa_assert(nbytes > 0);
|
||||
|
|
@ -721,8 +734,9 @@ void pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec *
|
|||
void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
|
||||
size_t lbq;
|
||||
pa_bool_t called = FALSE;
|
||||
pa_sink_input_assert_ref(i);
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
|
||||
|
||||
|
|
@ -789,9 +803,29 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam
|
|||
i->thread_info.dont_rewind_render = FALSE;
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
size_t pa_sink_input_get_max_rewind(pa_sink_input *i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
|
||||
return i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, i->sink->thread_info.max_rewind) : i->sink->thread_info.max_rewind;
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
size_t pa_sink_input_get_max_request(pa_sink_input *i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
|
||||
/* We're not verifying the status here, to allow this to be called
|
||||
* in the state change handler between _INIT and _RUNNING */
|
||||
|
||||
return i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, i->sink->thread_info.max_request) : i->sink->thread_info.max_request;
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
|
||||
|
||||
|
|
@ -804,6 +838,7 @@ void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the
|
|||
/* Called from thread context */
|
||||
void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
|
||||
|
||||
|
|
@ -814,15 +849,16 @@ void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the
|
|||
/* Called from thread context */
|
||||
pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
|
||||
if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
|
||||
usec = i->sink->fixed_latency;
|
||||
usec = i->sink->thread_info.fixed_latency;
|
||||
|
||||
if (usec != (pa_usec_t) -1)
|
||||
usec = PA_CLAMP(usec, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
|
||||
|
||||
i->thread_info.requested_sink_latency = usec;
|
||||
pa_sink_invalidate_requested_latency(i->sink);
|
||||
pa_sink_invalidate_requested_latency(i->sink, TRUE);
|
||||
|
||||
return usec;
|
||||
}
|
||||
|
|
@ -830,6 +866,7 @@ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa
|
|||
/* Called from main context */
|
||||
pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
|
||||
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
|
||||
|
|
@ -841,7 +878,7 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec)
|
|||
|
||||
if (i->sink) {
|
||||
if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
|
||||
usec = i->sink->fixed_latency;
|
||||
usec = pa_sink_get_fixed_latency(i->sink);
|
||||
|
||||
if (usec != (pa_usec_t) -1) {
|
||||
pa_usec_t min_latency, max_latency;
|
||||
|
|
@ -858,6 +895,7 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec)
|
|||
/* Called from main context */
|
||||
pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
|
||||
pa_usec_t usec = 0;
|
||||
|
|
@ -876,6 +914,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
|
|||
pa_cvolume v;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
pa_assert(volume);
|
||||
pa_assert(pa_cvolume_valid(volume));
|
||||
|
|
@ -922,6 +961,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
|
|||
/* Called from main context */
|
||||
pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
|
||||
if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
|
||||
|
|
@ -939,6 +979,7 @@ pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) {
|
|||
unsigned c;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(v);
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
|
||||
|
|
@ -959,6 +1000,7 @@ void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) {
|
|||
pa_cvolume _v;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
pa_assert(!v || pa_cvolume_compatible(v, &i->sample_spec));
|
||||
|
||||
|
|
@ -985,8 +1027,8 @@ void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) {
|
|||
|
||||
/* Called from main context */
|
||||
void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
|
||||
pa_assert(i);
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
|
||||
if (!i->muted == !mute)
|
||||
|
|
@ -1002,6 +1044,7 @@ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
|
|||
/* Called from main context */
|
||||
pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
|
||||
return i->muted;
|
||||
|
|
@ -1010,6 +1053,7 @@ pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) {
|
|||
/* Called from main thread */
|
||||
void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (p)
|
||||
pa_proplist_update(i->proplist, mode, p);
|
||||
|
|
@ -1023,6 +1067,7 @@ void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_p
|
|||
/* Called from main context */
|
||||
void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
|
||||
sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING);
|
||||
|
|
@ -1031,6 +1076,7 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) {
|
|||
/* Called from main context */
|
||||
int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
pa_return_val_if_fail(i->thread_info.resampler, -PA_ERR_BADSTATE);
|
||||
|
||||
|
|
@ -1049,13 +1095,14 @@ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
|
|||
void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
|
||||
const char *old;
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!name && !pa_proplist_contains(i->proplist, PA_PROP_MEDIA_NAME))
|
||||
return;
|
||||
|
||||
old = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME);
|
||||
|
||||
if (old && name && !strcmp(old, name))
|
||||
if (old && name && pa_streq(old, name))
|
||||
return;
|
||||
|
||||
if (name)
|
||||
|
|
@ -1072,6 +1119,7 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
|
|||
/* Called from main context */
|
||||
pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
return i->actual_resample_method;
|
||||
}
|
||||
|
|
@ -1079,6 +1127,7 @@ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
|
|||
/* Called from main context */
|
||||
pa_bool_t pa_sink_input_may_move(pa_sink_input *i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
|
||||
if (i->flags & PA_SINK_INPUT_DONT_MOVE)
|
||||
|
|
@ -1095,6 +1144,7 @@ pa_bool_t pa_sink_input_may_move(pa_sink_input *i) {
|
|||
/* Called from main context */
|
||||
pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
pa_sink_assert_ref(dest);
|
||||
|
||||
|
|
@ -1123,6 +1173,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
|
|||
int r;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
pa_assert(i->sink);
|
||||
|
||||
|
|
@ -1177,6 +1228,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
|
|||
pa_resampler *new_resampler;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
pa_assert(!i->sink);
|
||||
pa_sink_assert_ref(dest);
|
||||
|
|
@ -1266,11 +1318,30 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
void pa_sink_input_fail_move(pa_sink_input *i) {
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
pa_assert(!i->sink);
|
||||
|
||||
/* Check if someone wants this sink input? */
|
||||
if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_STOP)
|
||||
return;
|
||||
|
||||
if (i->moving)
|
||||
i->moving(i, NULL);
|
||||
|
||||
pa_sink_input_kill(i);
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
|
||||
int r;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
|
||||
pa_assert(i->sink);
|
||||
pa_sink_assert_ref(dest);
|
||||
|
|
@ -1289,6 +1360,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
|
|||
}
|
||||
|
||||
if ((r = pa_sink_input_finish_move(i, dest, save)) < 0) {
|
||||
pa_sink_input_fail_move(i);
|
||||
pa_sink_input_unref(i);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1301,7 +1373,9 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
|
|||
/* Called from IO thread context */
|
||||
void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state) {
|
||||
pa_bool_t corking, uncorking;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
|
||||
if (state == i->thread_info.state)
|
||||
return;
|
||||
|
|
@ -1411,6 +1485,7 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
|
|||
/* Called from main thread */
|
||||
pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED)
|
||||
return pa_atomic_load(&i->thread_info.drained) ? PA_SINK_INPUT_DRAINED : PA_SINK_INPUT_RUNNING;
|
||||
|
|
@ -1421,6 +1496,7 @@ pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) {
|
|||
/* Called from IO context */
|
||||
pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
|
||||
if (PA_SINK_INPUT_IS_LINKED(i->thread_info.state))
|
||||
return pa_memblockq_is_empty(i->thread_info.render_memblockq);
|
||||
|
|
@ -1445,6 +1521,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam
|
|||
* rewound. */
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_assert_io_context(i);
|
||||
|
||||
nbytes = PA_MAX(i->thread_info.rewrite_nbytes, nbytes);
|
||||
|
||||
|
|
@ -1511,8 +1588,11 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam
|
|||
/* Called from main context */
|
||||
pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(ret);
|
||||
|
||||
/* FIXME: Shouldn't access resampler object from main context! */
|
||||
|
||||
pa_silence_memchunk_get(
|
||||
&i->core->silence_cache,
|
||||
i->core->mempool,
|
||||
|
|
@ -1529,6 +1609,7 @@ void pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist *
|
|||
pa_sink_input_send_event_hook_data hook_data;
|
||||
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(event);
|
||||
|
||||
if (!i->send_event)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ typedef enum pa_sink_input_state {
|
|||
PA_SINK_INPUT_RUNNING, /*< The stream is alive and kicking */
|
||||
PA_SINK_INPUT_CORKED, /*< The stream was corked on user request */
|
||||
PA_SINK_INPUT_UNLINKED /*< The stream is dead */
|
||||
/* FIXME: we need a state for MOVING here */
|
||||
} pa_sink_input_state_t;
|
||||
|
||||
static inline pa_bool_t PA_SINK_INPUT_IS_LINKED(pa_sink_input_state_t x) {
|
||||
|
|
@ -58,7 +59,8 @@ typedef enum pa_sink_input_flags {
|
|||
PA_SINK_INPUT_FIX_RATE = 64,
|
||||
PA_SINK_INPUT_FIX_CHANNELS = 128,
|
||||
PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256,
|
||||
PA_SINK_INPUT_FAIL_ON_SUSPEND = 512
|
||||
PA_SINK_INPUT_NO_CREATE_ON_SUSPEND = 512,
|
||||
PA_SINK_INPUT_KILL_ON_SUSPEND = 1024
|
||||
} pa_sink_input_flags_t;
|
||||
|
||||
struct pa_sink_input {
|
||||
|
|
@ -137,6 +139,10 @@ struct pa_sink_input {
|
|||
* from IO context. */
|
||||
void (*update_sink_latency_range) (pa_sink_input *i); /* may be NULL */
|
||||
|
||||
/* Called whenver the fixed latency of the sink changes, if there
|
||||
* is one. Called from IO context. */
|
||||
void (*update_sink_fixed_latency) (pa_sink_input *i); /* may be NULL */
|
||||
|
||||
/* If non-NULL this function is called when the input is first
|
||||
* connected to a sink or when the rtpoll/asyncmsgq fields
|
||||
* change. You usually don't need to implement this function
|
||||
|
|
@ -159,7 +165,9 @@ struct pa_sink_input {
|
|||
/* If non-NULL called whenever the sink input is moved to a new
|
||||
* sink. Called from main context after the sink input has been
|
||||
* detached from the old sink and before it has been attached to
|
||||
* the new sink. */
|
||||
* the new sink. If dest is NULL the move was executed in two
|
||||
* phases and the second one failed; the stream will be destroyed
|
||||
* after this call. */
|
||||
void (*moving) (pa_sink_input *i, pa_sink *dest); /* may be NULL */
|
||||
|
||||
/* Supposed to unlink and destroy this stream. Called from main
|
||||
|
|
@ -303,6 +311,10 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b);
|
|||
|
||||
int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
|
||||
|
||||
/* This returns the sink's fields converted into out sample type */
|
||||
size_t pa_sink_input_get_max_rewind(pa_sink_input *i);
|
||||
size_t pa_sink_input_get_max_request(pa_sink_input *i);
|
||||
|
||||
/* Callable by everyone from main thread*/
|
||||
|
||||
/* External code may request disconnection with this function */
|
||||
|
|
@ -333,6 +345,7 @@ pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest); /* may thi
|
|||
* new sink */
|
||||
int pa_sink_input_start_move(pa_sink_input *i);
|
||||
int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save);
|
||||
void pa_sink_input_fail_move(pa_sink_input *i);
|
||||
|
||||
pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i);
|
||||
|
||||
|
|
@ -359,4 +372,7 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret);
|
|||
/* To be used by sink.c only */
|
||||
void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v);
|
||||
|
||||
#define pa_sink_input_assert_io_context(s) \
|
||||
pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state))
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static void sink_free(pa_object *s);
|
|||
pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
|
||||
pa_assert(data);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
pa_zero(*data);
|
||||
data->proplist = pa_proplist_new();
|
||||
|
||||
return data;
|
||||
|
|
@ -177,6 +177,7 @@ pa_sink* pa_sink_new(
|
|||
pa_assert(core);
|
||||
pa_assert(data);
|
||||
pa_assert(data->name);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
s = pa_msgobject_new(pa_sink);
|
||||
|
||||
|
|
@ -255,13 +256,10 @@ pa_sink* pa_sink_new(
|
|||
s->muted = data->muted;
|
||||
s->refresh_volume = s->refresh_muted = FALSE;
|
||||
|
||||
s->fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
|
||||
|
||||
reset_callbacks(s);
|
||||
s->userdata = NULL;
|
||||
|
||||
s->asyncmsgq = NULL;
|
||||
s->rtpoll = NULL;
|
||||
|
||||
/* As a minor optimization we just steal the list instead of
|
||||
* copying it here */
|
||||
|
|
@ -294,6 +292,7 @@ pa_sink* pa_sink_new(
|
|||
&s->sample_spec,
|
||||
0);
|
||||
|
||||
s->thread_info.rtpoll = NULL;
|
||||
s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
|
||||
s->thread_info.soft_volume = s->soft_volume;
|
||||
s->thread_info.soft_muted = s->muted;
|
||||
|
|
@ -306,7 +305,9 @@ pa_sink* pa_sink_new(
|
|||
s->thread_info.requested_latency = 0;
|
||||
s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
|
||||
s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
|
||||
s->thread_info.fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
|
||||
|
||||
/* FIXME: This should probably be moved to pa_sink_put() */
|
||||
pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
|
||||
|
||||
if (s->card)
|
||||
|
|
@ -348,6 +349,7 @@ pa_sink* pa_sink_new(
|
|||
s->monitor_source->monitor_of = s;
|
||||
|
||||
pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
|
||||
pa_source_set_fixed_latency(s->monitor_source, s->thread_info.fixed_latency);
|
||||
pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
|
||||
|
||||
return s;
|
||||
|
|
@ -360,6 +362,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
|
|||
pa_sink_state_t original_state;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (s->state == state)
|
||||
return 0;
|
||||
|
|
@ -396,9 +399,9 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
|
|||
|
||||
/* We're suspending or resuming, tell everyone about it */
|
||||
|
||||
for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)))
|
||||
PA_IDXSET_FOREACH(i, s->inputs, idx)
|
||||
if (s->state == PA_SINK_SUSPENDED &&
|
||||
(i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND))
|
||||
(i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND))
|
||||
pa_sink_input_kill(i);
|
||||
else if (i->suspend)
|
||||
i->suspend(i, state == PA_SINK_SUSPENDED);
|
||||
|
|
@ -413,12 +416,12 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
|
|||
/* Called from main context */
|
||||
void pa_sink_put(pa_sink* s) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
pa_assert(s->state == PA_SINK_INIT);
|
||||
|
||||
/* The following fields must be initialized properly when calling _put() */
|
||||
pa_assert(s->asyncmsgq);
|
||||
pa_assert(s->rtpoll);
|
||||
pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
|
||||
|
||||
/* Generally, flags should be initialized via pa_sink_new(). As a
|
||||
|
|
@ -436,11 +439,11 @@ void pa_sink_put(pa_sink* s) {
|
|||
|
||||
pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SINK_DECIBEL_VOLUME));
|
||||
pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
|
||||
pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
|
||||
pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0));
|
||||
pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY));
|
||||
pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_DYNAMIC_LATENCY));
|
||||
|
||||
pa_assert(s->monitor_source->fixed_latency == s->fixed_latency);
|
||||
pa_assert(s->monitor_source->thread_info.fixed_latency == s->thread_info.fixed_latency);
|
||||
pa_assert(s->monitor_source->thread_info.min_latency == s->thread_info.min_latency);
|
||||
pa_assert(s->monitor_source->thread_info.max_latency == s->thread_info.max_latency);
|
||||
|
||||
|
|
@ -458,6 +461,7 @@ void pa_sink_unlink(pa_sink* s) {
|
|||
pa_sink_input *i, *j = NULL;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
/* Please note that pa_sink_unlink() does more than simply
|
||||
* reversing pa_sink_put(). It also undoes the registrations
|
||||
|
|
@ -507,6 +511,7 @@ static void sink_free(pa_object *o) {
|
|||
pa_sink_input *i;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(pa_sink_refcnt(s) == 0);
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->state))
|
||||
|
|
@ -547,9 +552,10 @@ static void sink_free(pa_object *o) {
|
|||
pa_xfree(s);
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
/* Called from main context, and not while the IO thread is active, please */
|
||||
void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
s->asyncmsgq = q;
|
||||
|
||||
|
|
@ -557,11 +563,32 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
|
|||
pa_source_set_asyncmsgq(s->monitor_source, q);
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
/* Called from main context, and not while the IO thread is active, please */
|
||||
void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t value) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
/* For now, allow only a minimal set of flags to be changed. */
|
||||
pa_assert((mask & ~(PA_SINK_DYNAMIC_LATENCY|PA_SINK_LATENCY)) == 0);
|
||||
|
||||
s->flags = (s->flags & ~mask) | (value & mask);
|
||||
|
||||
pa_source_update_flags(s->monitor_source,
|
||||
((mask & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
|
||||
((mask & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0),
|
||||
((value & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
|
||||
((value & PA_SINK_DYNAMIC_LATENCY) ? PA_SINK_DYNAMIC_LATENCY : 0));
|
||||
}
|
||||
|
||||
/* Called from IO context, or before _put() from main context */
|
||||
void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
|
||||
s->rtpoll = p;
|
||||
s->thread_info.rtpoll = p;
|
||||
|
||||
if (s->monitor_source)
|
||||
pa_source_set_rtpoll(s->monitor_source, p);
|
||||
|
|
@ -570,6 +597,7 @@ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
|
|||
/* Called from main context */
|
||||
int pa_sink_update_status(pa_sink*s) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
if (s->state == PA_SINK_SUSPENDED)
|
||||
|
|
@ -581,6 +609,7 @@ int pa_sink_update_status(pa_sink*s) {
|
|||
/* Called from main context */
|
||||
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
pa_assert(cause != 0);
|
||||
|
||||
|
|
@ -609,6 +638,7 @@ pa_queue *pa_sink_move_all_start(pa_sink *s, pa_queue *q) {
|
|||
uint32_t idx;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
if (!q)
|
||||
|
|
@ -633,12 +663,13 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
|
|||
pa_sink_input *i;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
pa_assert(q);
|
||||
|
||||
while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
|
||||
if (pa_sink_input_finish_move(i, s, save) < 0)
|
||||
pa_sink_input_kill(i);
|
||||
pa_sink_input_fail_move(i);
|
||||
|
||||
pa_sink_input_unref(i);
|
||||
}
|
||||
|
|
@ -649,13 +680,13 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
|
|||
/* Called from main context */
|
||||
void pa_sink_move_all_fail(pa_queue *q) {
|
||||
pa_sink_input *i;
|
||||
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(q);
|
||||
|
||||
while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
|
||||
if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_OK) {
|
||||
pa_sink_input_kill(i);
|
||||
pa_sink_input_unref(i);
|
||||
}
|
||||
pa_sink_input_fail_move(i);
|
||||
pa_sink_input_unref(i);
|
||||
}
|
||||
|
||||
pa_queue_free(q, NULL, NULL);
|
||||
|
|
@ -665,11 +696,15 @@ void pa_sink_move_all_fail(pa_queue *q) {
|
|||
void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
|
||||
pa_sink_input *i;
|
||||
void *state = NULL;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
|
||||
/* If nobody requested this and this is actually no real rewind
|
||||
* then we can short cut this */
|
||||
* then we can short cut this. Please note that this means that
|
||||
* not all rewind requests triggered upstream will always be
|
||||
* translated in actual requests! */
|
||||
if (!s->thread_info.rewind_requested && nbytes <= 0)
|
||||
return;
|
||||
|
||||
|
|
@ -682,7 +717,7 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
|
|||
if (nbytes > 0)
|
||||
pa_log_debug("Processing rewind...");
|
||||
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_sink_input_process_rewind(i, nbytes);
|
||||
}
|
||||
|
|
@ -700,6 +735,7 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns
|
|||
size_t mixlength = *length;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(info);
|
||||
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
|
||||
|
|
@ -739,6 +775,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *
|
|||
unsigned n_unreffed = 0;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(result);
|
||||
pa_assert(result->memblock);
|
||||
pa_assert(result->length > 0);
|
||||
|
|
@ -834,6 +871,7 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
|
|||
size_t block_size_max;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(length, &s->sample_spec));
|
||||
pa_assert(result);
|
||||
|
|
@ -920,6 +958,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
|
|||
size_t length, block_size_max;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
pa_assert(target);
|
||||
pa_assert(target->memblock);
|
||||
|
|
@ -1003,6 +1042,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
|
|||
size_t l, d;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
pa_assert(target);
|
||||
pa_assert(target->memblock);
|
||||
|
|
@ -1037,6 +1077,7 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
|
|||
unsigned n;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
pa_assert(length > 0);
|
||||
pa_assert(pa_frame_aligned(length, &s->sample_spec));
|
||||
|
|
@ -1128,6 +1169,7 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) {
|
|||
pa_usec_t usec = 0;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
/* The returned value is supposed to be in the time domain of the sound card! */
|
||||
|
|
@ -1149,6 +1191,7 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
|
|||
pa_msgobject *o;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
|
||||
/* The returned value is supposed to be in the time domain of the sound card! */
|
||||
|
|
@ -1161,7 +1204,7 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
|
|||
|
||||
o = PA_MSGOBJECT(s);
|
||||
|
||||
/* We probably should make this a proper vtable callback instead of going through process_msg() */
|
||||
/* FIXME: We probably should make this a proper vtable callback instead of going through process_msg() */
|
||||
|
||||
if (o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
|
||||
return -1;
|
||||
|
|
@ -1215,6 +1258,7 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
|
|||
uint32_t idx;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(new_volume);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
|
||||
|
|
@ -1271,6 +1315,7 @@ void pa_sink_propagate_flat_volume(pa_sink *s) {
|
|||
uint32_t idx;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
|
||||
|
||||
|
|
@ -1319,6 +1364,7 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
|
|||
pa_bool_t virtual_volume_changed;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
pa_assert(volume);
|
||||
pa_assert(pa_cvolume_valid(volume));
|
||||
|
|
@ -1360,6 +1406,7 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
|
|||
/* Called from main thread. Only to be called by sink implementor */
|
||||
void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(volume);
|
||||
|
||||
s->soft_volume = *volume;
|
||||
|
|
@ -1373,6 +1420,8 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
|
|||
/* Called from main thread */
|
||||
const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_bool_t reference) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
if (s->refresh_volume || force_refresh) {
|
||||
struct pa_cvolume old_virtual_volume = s->virtual_volume;
|
||||
|
|
@ -1386,6 +1435,12 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_boo
|
|||
|
||||
s->reference_volume = s->virtual_volume;
|
||||
|
||||
/* Something got changed in the hardware. It probably
|
||||
* makes sense to save changed hw settings given that hw
|
||||
* volume changes not triggered by PA are almost certainly
|
||||
* done by the user. */
|
||||
s->save_volume = TRUE;
|
||||
|
||||
if (s->flags & PA_SINK_FLAT_VOLUME)
|
||||
pa_sink_propagate_flat_volume(s);
|
||||
|
||||
|
|
@ -1397,17 +1452,17 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_boo
|
|||
}
|
||||
|
||||
/* Called from main thread */
|
||||
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume, pa_bool_t save) {
|
||||
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
/* The sink implementor may call this if the volume changed to make sure everyone is notified */
|
||||
if (pa_cvolume_equal(&s->virtual_volume, new_volume)) {
|
||||
s->save_volume = s->save_volume || save;
|
||||
if (pa_cvolume_equal(&s->virtual_volume, new_volume))
|
||||
return;
|
||||
}
|
||||
|
||||
s->reference_volume = s->virtual_volume = *new_volume;
|
||||
s->save_volume = save;
|
||||
s->save_volume = TRUE;
|
||||
|
||||
if (s->flags & PA_SINK_FLAT_VOLUME)
|
||||
pa_sink_propagate_flat_volume(s);
|
||||
|
|
@ -1420,6 +1475,7 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute, pa_bool_t save) {
|
|||
pa_bool_t old_muted;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
old_muted = s->muted;
|
||||
|
|
@ -1439,6 +1495,8 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute, pa_bool_t save) {
|
|||
pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
if (s->refresh_muted || force_refresh) {
|
||||
pa_bool_t old_muted = s->muted;
|
||||
|
|
@ -1449,6 +1507,8 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
|
|||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
|
||||
|
||||
if (old_muted != s->muted) {
|
||||
s->save_muted = TRUE;
|
||||
|
||||
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
|
||||
|
||||
/* Make sure the soft mute status stays in sync */
|
||||
|
|
@ -1456,22 +1516,23 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return s->muted;
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save) {
|
||||
void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
/* The sink implementor may call this if the volume changed to make sure everyone is notified */
|
||||
|
||||
if (s->muted == new_muted) {
|
||||
s->save_muted = s->save_muted || save;
|
||||
if (s->muted == new_muted)
|
||||
return;
|
||||
}
|
||||
|
||||
s->muted = new_muted;
|
||||
s->save_muted = save;
|
||||
s->save_muted = TRUE;
|
||||
|
||||
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
|
||||
}
|
||||
|
|
@ -1479,6 +1540,7 @@ void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save) {
|
|||
/* Called from main thread */
|
||||
pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (p)
|
||||
pa_proplist_update(s->proplist, mode, p);
|
||||
|
|
@ -1492,16 +1554,18 @@ pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist
|
|||
}
|
||||
|
||||
/* Called from main thread */
|
||||
/* FIXME -- this should be dropped and be merged into pa_sink_update_proplist() */
|
||||
void pa_sink_set_description(pa_sink *s, const char *description) {
|
||||
const char *old;
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
|
||||
return;
|
||||
|
||||
old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
|
||||
|
||||
if (old && description && !strcmp(old, description))
|
||||
if (old && description && pa_streq(old, description))
|
||||
return;
|
||||
|
||||
if (description)
|
||||
|
|
@ -1528,6 +1592,7 @@ unsigned pa_sink_linked_by(pa_sink *s) {
|
|||
unsigned ret;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
ret = pa_idxset_size(s->inputs);
|
||||
|
|
@ -1546,6 +1611,7 @@ unsigned pa_sink_used_by(pa_sink *s) {
|
|||
unsigned ret;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
ret = pa_idxset_size(s->inputs);
|
||||
|
|
@ -1564,6 +1630,7 @@ unsigned pa_sink_check_suspend(pa_sink *s) {
|
|||
uint32_t idx;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!PA_SINK_IS_LINKED(s->state))
|
||||
return 0;
|
||||
|
|
@ -1597,8 +1664,9 @@ static void sync_input_volumes_within_thread(pa_sink *s) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
|
||||
while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
|
||||
if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
|
||||
continue;
|
||||
|
||||
|
|
@ -1701,7 +1769,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
|
|||
if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
|
||||
pa_sink_input_unref(i);
|
||||
|
||||
pa_sink_invalidate_requested_latency(s);
|
||||
pa_sink_invalidate_requested_latency(s, TRUE);
|
||||
pa_sink_request_rewind(s, (size_t) -1);
|
||||
|
||||
/* In flat volume mode we need to update the volume as
|
||||
|
|
@ -1723,10 +1791,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
|
|||
size_t sink_nbytes, total_nbytes;
|
||||
|
||||
/* Get the latency of the sink */
|
||||
if (!(s->flags & PA_SINK_LATENCY) ||
|
||||
PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
|
||||
usec = 0;
|
||||
|
||||
usec = pa_sink_get_latency_within_thread(s);
|
||||
sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
|
||||
total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
|
||||
|
||||
|
|
@ -1747,7 +1812,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
|
|||
if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
|
||||
pa_sink_input_unref(i);
|
||||
|
||||
pa_sink_invalidate_requested_latency(s);
|
||||
pa_sink_invalidate_requested_latency(s, TRUE);
|
||||
|
||||
pa_log_debug("Requesting rewind due to started move");
|
||||
pa_sink_request_rewind(s, (size_t) -1);
|
||||
|
|
@ -1785,10 +1850,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
|
|||
size_t nbytes;
|
||||
|
||||
/* Get the latency of the sink */
|
||||
if (!(s->flags & PA_SINK_LATENCY) ||
|
||||
PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
|
||||
usec = 0;
|
||||
|
||||
usec = pa_sink_get_latency_within_thread(s);
|
||||
nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
|
||||
|
||||
if (nbytes > 0)
|
||||
|
|
@ -1876,6 +1938,9 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
|
|||
pa_usec_t *usec = userdata;
|
||||
*usec = pa_sink_get_requested_latency_within_thread(s);
|
||||
|
||||
/* Yes, that's right, the IO thread will see -1 when no
|
||||
* explicit requested latency is configured, the main
|
||||
* thread will see max_latency */
|
||||
if (*usec == (pa_usec_t) -1)
|
||||
*usec = s->thread_info.max_latency;
|
||||
|
||||
|
|
@ -1899,6 +1964,16 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
|
|||
return 0;
|
||||
}
|
||||
|
||||
case PA_SINK_MESSAGE_GET_FIXED_LATENCY:
|
||||
|
||||
*((pa_usec_t*) userdata) = s->thread_info.fixed_latency;
|
||||
return 0;
|
||||
|
||||
case PA_SINK_MESSAGE_SET_FIXED_LATENCY:
|
||||
|
||||
pa_sink_set_fixed_latency_within_thread(s, (pa_usec_t) offset);
|
||||
return 0;
|
||||
|
||||
case PA_SINK_MESSAGE_GET_MAX_REWIND:
|
||||
|
||||
*((size_t*) userdata) = s->thread_info.max_rewind;
|
||||
|
|
@ -1934,9 +2009,10 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause)
|
|||
int ret = 0;
|
||||
|
||||
pa_core_assert_ref(c);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(cause != 0);
|
||||
|
||||
for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
|
||||
PA_IDXSET_FOREACH(sink, c->sinks, idx) {
|
||||
int r;
|
||||
|
||||
if ((r = pa_sink_suspend(sink, suspend, cause)) < 0)
|
||||
|
|
@ -1949,6 +2025,7 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause)
|
|||
/* Called from main thread */
|
||||
void pa_sink_detach(pa_sink *s) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
|
||||
|
|
@ -1957,6 +2034,7 @@ void pa_sink_detach(pa_sink *s) {
|
|||
/* Called from main thread */
|
||||
void pa_sink_attach(pa_sink *s) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
|
||||
|
|
@ -1968,9 +2046,10 @@ void pa_sink_detach_within_thread(pa_sink *s) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
|
||||
if (i->detach)
|
||||
i->detach(i);
|
||||
|
||||
|
|
@ -1984,9 +2063,10 @@ void pa_sink_attach_within_thread(pa_sink *s) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
|
||||
if (i->attach)
|
||||
i->attach(i);
|
||||
|
||||
|
|
@ -1997,6 +2077,7 @@ void pa_sink_attach_within_thread(pa_sink *s) {
|
|||
/* Called from IO thread */
|
||||
void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
|
||||
|
||||
if (s->thread_info.state == PA_SINK_SUSPENDED)
|
||||
|
|
@ -2026,15 +2107,15 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
|
|||
pa_usec_t monitor_latency;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
|
||||
if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
|
||||
return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
|
||||
return PA_CLAMP(s->thread_info.fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
|
||||
|
||||
if (s->thread_info.requested_latency_valid)
|
||||
return s->thread_info.requested_latency;
|
||||
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
|
||||
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
|
||||
if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
|
||||
(result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
|
||||
result = i->thread_info.requested_sink_latency;
|
||||
|
|
@ -2062,6 +2143,7 @@ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
|
|||
pa_usec_t usec = 0;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SINK_IS_LINKED(s->state));
|
||||
|
||||
if (s->state == PA_SINK_SUSPENDED)
|
||||
|
|
@ -2077,16 +2159,16 @@ void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
|
||||
if (max_rewind == s->thread_info.max_rewind)
|
||||
return;
|
||||
|
||||
s->thread_info.max_rewind = max_rewind;
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->thread_info.state)) {
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
|
||||
if (PA_SINK_IS_LINKED(s->thread_info.state))
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
|
||||
pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
|
||||
}
|
||||
|
||||
if (s->monitor_source)
|
||||
pa_source_set_max_rewind_within_thread(s->monitor_source, s->thread_info.max_rewind);
|
||||
|
|
@ -2095,6 +2177,7 @@ void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
|
|||
/* Called from main thread */
|
||||
void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->state))
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
|
||||
|
|
@ -2107,6 +2190,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
|
||||
if (max_request == s->thread_info.max_request)
|
||||
return;
|
||||
|
|
@ -2116,7 +2200,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
|
|||
if (PA_SINK_IS_LINKED(s->thread_info.state)) {
|
||||
pa_sink_input *i;
|
||||
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
|
||||
pa_sink_input_update_max_request(i, s->thread_info.max_request);
|
||||
}
|
||||
}
|
||||
|
|
@ -2124,6 +2208,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
|
|||
/* Called from main thread */
|
||||
void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->state))
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0);
|
||||
|
|
@ -2132,23 +2217,24 @@ void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
|
|||
}
|
||||
|
||||
/* Called from IO thread */
|
||||
void pa_sink_invalidate_requested_latency(pa_sink *s) {
|
||||
void pa_sink_invalidate_requested_latency(pa_sink *s, pa_bool_t dynamic) {
|
||||
pa_sink_input *i;
|
||||
void *state = NULL;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
|
||||
if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
|
||||
if ((s->flags & PA_SINK_DYNAMIC_LATENCY))
|
||||
s->thread_info.requested_latency_valid = FALSE;
|
||||
else if (dynamic)
|
||||
return;
|
||||
|
||||
s->thread_info.requested_latency_valid = FALSE;
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->thread_info.state)) {
|
||||
|
||||
if (s->update_requested_latency)
|
||||
s->update_requested_latency(s);
|
||||
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
|
||||
if (i->update_sink_requested_latency)
|
||||
i->update_sink_requested_latency(i);
|
||||
}
|
||||
|
|
@ -2157,6 +2243,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) {
|
|||
/* Called from main thread */
|
||||
void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
/* min_latency == 0: no limit
|
||||
* min_latency anything else: specified limit
|
||||
|
|
@ -2191,6 +2278,7 @@ void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_
|
|||
/* Called from main thread */
|
||||
void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(min_latency);
|
||||
pa_assert(max_latency);
|
||||
|
||||
|
|
@ -2209,9 +2297,8 @@ void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *ma
|
|||
|
||||
/* Called from IO thread */
|
||||
void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
|
||||
void *state = NULL;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
|
||||
pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
|
||||
pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
|
||||
|
|
@ -2222,27 +2309,36 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency,
|
|||
max_latency == ABSOLUTE_MAX_LATENCY) ||
|
||||
(s->flags & PA_SINK_DYNAMIC_LATENCY));
|
||||
|
||||
if (s->thread_info.min_latency == min_latency &&
|
||||
s->thread_info.max_latency == max_latency)
|
||||
return;
|
||||
|
||||
s->thread_info.min_latency = min_latency;
|
||||
s->thread_info.max_latency = max_latency;
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->thread_info.state)) {
|
||||
pa_sink_input *i;
|
||||
void *state = NULL;
|
||||
|
||||
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
|
||||
if (i->update_sink_latency_range)
|
||||
i->update_sink_latency_range(i);
|
||||
}
|
||||
|
||||
pa_sink_invalidate_requested_latency(s);
|
||||
pa_sink_invalidate_requested_latency(s, FALSE);
|
||||
|
||||
pa_source_set_latency_range_within_thread(s->monitor_source, min_latency, max_latency);
|
||||
}
|
||||
|
||||
/* Called from main thread, before the sink is put */
|
||||
/* Called from main thread */
|
||||
void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
pa_assert(pa_sink_get_state(s) == PA_SINK_INIT);
|
||||
if (s->flags & PA_SINK_DYNAMIC_LATENCY) {
|
||||
pa_assert(latency == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (latency < ABSOLUTE_MIN_LATENCY)
|
||||
latency = ABSOLUTE_MIN_LATENCY;
|
||||
|
|
@ -2250,14 +2346,69 @@ void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) {
|
|||
if (latency > ABSOLUTE_MAX_LATENCY)
|
||||
latency = ABSOLUTE_MAX_LATENCY;
|
||||
|
||||
s->fixed_latency = latency;
|
||||
if (PA_SINK_IS_LINKED(s->state))
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_FIXED_LATENCY, NULL, (int64_t) latency, NULL) == 0);
|
||||
else
|
||||
s->thread_info.fixed_latency = latency;
|
||||
|
||||
pa_source_set_fixed_latency(s->monitor_source, latency);
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
pa_usec_t pa_sink_get_fixed_latency(pa_sink *s) {
|
||||
pa_usec_t latency;
|
||||
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (s->flags & PA_SINK_DYNAMIC_LATENCY)
|
||||
return 0;
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->state))
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_FIXED_LATENCY, &latency, 0, NULL) == 0);
|
||||
else
|
||||
latency = s->thread_info.fixed_latency;
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
||||
/* Called from IO thread */
|
||||
void pa_sink_set_fixed_latency_within_thread(pa_sink *s, pa_usec_t latency) {
|
||||
pa_sink_assert_ref(s);
|
||||
pa_sink_assert_io_context(s);
|
||||
|
||||
if (s->flags & PA_SINK_DYNAMIC_LATENCY) {
|
||||
pa_assert(latency == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pa_assert(latency >= ABSOLUTE_MIN_LATENCY);
|
||||
pa_assert(latency <= ABSOLUTE_MAX_LATENCY);
|
||||
|
||||
if (s->thread_info.fixed_latency == latency)
|
||||
return;
|
||||
|
||||
s->thread_info.fixed_latency = latency;
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->thread_info.state)) {
|
||||
pa_sink_input *i;
|
||||
void *state = NULL;
|
||||
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
|
||||
if (i->update_sink_fixed_latency)
|
||||
i->update_sink_fixed_latency(i);
|
||||
}
|
||||
|
||||
pa_sink_invalidate_requested_latency(s, FALSE);
|
||||
|
||||
pa_source_set_fixed_latency_within_thread(s->monitor_source, latency);
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
size_t pa_sink_get_max_rewind(pa_sink *s) {
|
||||
size_t r;
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!PA_SINK_IS_LINKED(s->state))
|
||||
return s->thread_info.max_rewind;
|
||||
|
|
@ -2271,6 +2422,7 @@ size_t pa_sink_get_max_rewind(pa_sink *s) {
|
|||
size_t pa_sink_get_max_request(pa_sink *s) {
|
||||
size_t r;
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!PA_SINK_IS_LINKED(s->state))
|
||||
return s->thread_info.max_request;
|
||||
|
|
@ -2284,7 +2436,8 @@ size_t pa_sink_get_max_request(pa_sink *s) {
|
|||
int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
|
||||
pa_device_port *port;
|
||||
|
||||
pa_assert(s);
|
||||
pa_sink_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!s->set_port) {
|
||||
pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
|
||||
|
|
@ -2315,7 +2468,6 @@ int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
|
||||
const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ typedef struct pa_device_port pa_device_port;
|
|||
#include <pulsecore/rtpoll.h>
|
||||
#include <pulsecore/card.h>
|
||||
#include <pulsecore/queue.h>
|
||||
#include <pulsecore/thread-mq.h>
|
||||
|
||||
#define PA_MAX_INPUTS_PER_SINK 32
|
||||
|
||||
|
|
@ -101,12 +102,9 @@ struct pa_sink {
|
|||
pa_bool_t save_muted:1;
|
||||
|
||||
pa_asyncmsgq *asyncmsgq;
|
||||
pa_rtpoll *rtpoll;
|
||||
|
||||
pa_memchunk silence;
|
||||
|
||||
pa_usec_t fixed_latency; /* for sinks with PA_SINK_DYNAMIC_LATENCY this is 0 */
|
||||
|
||||
pa_hashmap *ports;
|
||||
pa_device_port *active_port;
|
||||
|
||||
|
|
@ -155,9 +153,14 @@ struct pa_sink {
|
|||
pa_sink_state_t state;
|
||||
pa_hashmap *inputs;
|
||||
|
||||
pa_rtpoll *rtpoll;
|
||||
|
||||
pa_cvolume soft_volume;
|
||||
pa_bool_t soft_muted:1;
|
||||
|
||||
/* The requested latency is used for dynamic latency
|
||||
* sinks. For fixed latency sinks it is always identical to
|
||||
* the fixed_latency. See below. */
|
||||
pa_bool_t requested_latency_valid:1;
|
||||
pa_usec_t requested_latency;
|
||||
|
||||
|
|
@ -173,8 +176,15 @@ struct pa_sink {
|
|||
size_t rewind_nbytes;
|
||||
pa_bool_t rewind_requested;
|
||||
|
||||
/* Both dynamic and fixed latencies will be clamped to this
|
||||
* range. */
|
||||
pa_usec_t min_latency; /* we won't go below this latency */
|
||||
pa_usec_t max_latency; /* An upper limit for the latencies */
|
||||
|
||||
/* 'Fixed' simply means that the latency is exclusively
|
||||
* decided on by the sink, and the clients have no influence
|
||||
* in changing it */
|
||||
pa_usec_t fixed_latency; /* for sinks with PA_SINK_DYNAMIC_LATENCY this is 0 */
|
||||
} thread_info;
|
||||
|
||||
void *userdata;
|
||||
|
|
@ -200,6 +210,8 @@ typedef enum pa_sink_message {
|
|||
PA_SINK_MESSAGE_DETACH,
|
||||
PA_SINK_MESSAGE_SET_LATENCY_RANGE,
|
||||
PA_SINK_MESSAGE_GET_LATENCY_RANGE,
|
||||
PA_SINK_MESSAGE_SET_FIXED_LATENCY,
|
||||
PA_SINK_MESSAGE_GET_FIXED_LATENCY,
|
||||
PA_SINK_MESSAGE_GET_MAX_REWIND,
|
||||
PA_SINK_MESSAGE_GET_MAX_REQUEST,
|
||||
PA_SINK_MESSAGE_SET_MAX_REWIND,
|
||||
|
|
@ -267,8 +279,10 @@ void pa_sink_detach(pa_sink *s);
|
|||
void pa_sink_attach(pa_sink *s);
|
||||
|
||||
void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume);
|
||||
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume, pa_bool_t save);
|
||||
void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save);
|
||||
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume);
|
||||
void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted);
|
||||
|
||||
void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t value);
|
||||
|
||||
pa_bool_t pa_device_init_description(pa_proplist *p);
|
||||
pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink);
|
||||
|
|
@ -280,6 +294,7 @@ pa_bool_t pa_device_init_intended_roles(pa_proplist *p);
|
|||
pa_usec_t pa_sink_get_latency(pa_sink *s);
|
||||
pa_usec_t pa_sink_get_requested_latency(pa_sink *s);
|
||||
void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency);
|
||||
pa_usec_t pa_sink_get_fixed_latency(pa_sink *s);
|
||||
|
||||
size_t pa_sink_get_max_rewind(pa_sink *s);
|
||||
size_t pa_sink_get_max_request(pa_sink *s);
|
||||
|
|
@ -331,16 +346,23 @@ void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind);
|
|||
void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request);
|
||||
|
||||
void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency);
|
||||
void pa_sink_set_fixed_latency_within_thread(pa_sink *s, pa_usec_t latency);
|
||||
|
||||
/*** To be called exclusively by sink input drivers, from IO context */
|
||||
|
||||
void pa_sink_request_rewind(pa_sink*s, size_t nbytes);
|
||||
|
||||
void pa_sink_invalidate_requested_latency(pa_sink *s);
|
||||
void pa_sink_invalidate_requested_latency(pa_sink *s, pa_bool_t dynamic);
|
||||
|
||||
pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s);
|
||||
|
||||
pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra);
|
||||
void pa_device_port_free(pa_device_port *p);
|
||||
|
||||
/* Verify that we called in IO context (aka 'thread context), or that
|
||||
* the sink is not yet set up, i.e. the thread not set up yet. See
|
||||
* pa_assert_io_context() in thread-mq.h for more information. */
|
||||
#define pa_sink_assert_io_context(s) \
|
||||
pa_assert(pa_thread_mq_get() || !PA_SINK_IS_LINKED((s)->state))
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ static void source_output_free(pa_object* mo);
|
|||
pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) {
|
||||
pa_assert(data);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
pa_zero(*data);
|
||||
data->resample_method = PA_RESAMPLER_INVALID;
|
||||
data->proplist = pa_proplist_new();
|
||||
|
||||
|
|
@ -84,6 +84,7 @@ static void reset_callbacks(pa_source_output *o) {
|
|||
o->update_max_rewind = NULL;
|
||||
o->update_source_requested_latency = NULL;
|
||||
o->update_source_latency_range = NULL;
|
||||
o->update_source_fixed_latency = NULL;
|
||||
o->attach = NULL;
|
||||
o->detach = NULL;
|
||||
o->suspend = NULL;
|
||||
|
|
@ -111,6 +112,7 @@ int pa_source_output_new(
|
|||
pa_assert(_o);
|
||||
pa_assert(core);
|
||||
pa_assert(data);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (data->client)
|
||||
pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
|
||||
|
|
@ -166,7 +168,7 @@ int pa_source_output_new(
|
|||
if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data)) < 0)
|
||||
return r;
|
||||
|
||||
if ((flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND) &&
|
||||
if ((flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND) &&
|
||||
pa_source_get_state(data->source) == PA_SOURCE_SUSPENDED) {
|
||||
pa_log("Failed to create source output: source is suspended.");
|
||||
return -PA_ERR_BADSTATE;
|
||||
|
|
@ -262,6 +264,7 @@ int pa_source_output_new(
|
|||
/* Called from main context */
|
||||
static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) {
|
||||
pa_assert(o);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!o->source)
|
||||
return;
|
||||
|
|
@ -275,6 +278,7 @@ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state)
|
|||
/* Called from main context */
|
||||
static void source_output_set_state(pa_source_output *o, pa_source_output_state_t state) {
|
||||
pa_assert(o);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (o->state == state)
|
||||
return;
|
||||
|
|
@ -294,6 +298,7 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_
|
|||
void pa_source_output_unlink(pa_source_output*o) {
|
||||
pa_bool_t linked;
|
||||
pa_assert(o);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
/* See pa_sink_unlink() for a couple of comments how this function
|
||||
* works */
|
||||
|
|
@ -346,6 +351,7 @@ static void source_output_free(pa_object* mo) {
|
|||
pa_source_output *o = PA_SOURCE_OUTPUT(mo);
|
||||
|
||||
pa_assert(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(pa_source_output_refcnt(o) == 0);
|
||||
|
||||
if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
|
||||
|
|
@ -371,7 +377,9 @@ static void source_output_free(pa_object* mo) {
|
|||
/* Called from main context */
|
||||
void pa_source_output_put(pa_source_output *o) {
|
||||
pa_source_output_state_t state;
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
pa_assert(o->state == PA_SOURCE_OUTPUT_INIT);
|
||||
|
||||
|
|
@ -395,6 +403,7 @@ void pa_source_output_put(pa_source_output *o) {
|
|||
/* Called from main context */
|
||||
void pa_source_output_kill(pa_source_output*o) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
|
||||
o->kill(o);
|
||||
|
|
@ -405,6 +414,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o, pa_usec_t *source_la
|
|||
pa_usec_t r[2] = { 0, 0 };
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
|
||||
pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
|
||||
|
|
@ -424,6 +434,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
|
|||
size_t limit, mbs = 0;
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_assert_io_context(o);
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
|
||||
pa_assert(chunk);
|
||||
pa_assert(pa_frame_aligned(chunk->length, &o->source->sample_spec));
|
||||
|
|
@ -499,8 +510,9 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
|
|||
|
||||
/* Called from thread context */
|
||||
void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in source sample spec */) {
|
||||
pa_source_output_assert_ref(o);
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_assert_io_context(o);
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
|
||||
|
||||
|
|
@ -525,9 +537,18 @@ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in so
|
|||
pa_memblockq_rewind(o->thread_info.delay_memblockq, nbytes);
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
size_t pa_source_output_get_max_rewind(pa_source_output *o) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_assert_io_context(o);
|
||||
|
||||
return o->thread_info.resampler ? pa_resampler_request(o->thread_info.resampler, o->source->thread_info.max_rewind) : o->source->thread_info.max_rewind;
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* in the source's sample spec */) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_assert_io_context(o);
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
|
||||
|
||||
|
|
@ -538,15 +559,16 @@ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* i
|
|||
/* Called from thread context */
|
||||
pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_assert_io_context(o);
|
||||
|
||||
if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
|
||||
usec = o->source->fixed_latency;
|
||||
usec = o->source->thread_info.fixed_latency;
|
||||
|
||||
if (usec != (pa_usec_t) -1)
|
||||
usec = PA_CLAMP(usec, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
|
||||
|
||||
o->thread_info.requested_source_latency = usec;
|
||||
pa_source_invalidate_requested_latency(o->source);
|
||||
pa_source_invalidate_requested_latency(o->source, TRUE);
|
||||
|
||||
return usec;
|
||||
}
|
||||
|
|
@ -554,6 +576,7 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output
|
|||
/* Called from main context */
|
||||
pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) {
|
||||
pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
|
||||
|
|
@ -565,7 +588,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t
|
|||
|
||||
if (o->source) {
|
||||
if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
|
||||
usec = o->source->fixed_latency;
|
||||
usec = pa_source_get_fixed_latency(o->source);
|
||||
|
||||
if (usec != (pa_usec_t) -1) {
|
||||
pa_usec_t min_latency, max_latency;
|
||||
|
|
@ -582,6 +605,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t
|
|||
/* Called from main context */
|
||||
pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) {
|
||||
pa_usec_t usec = 0;
|
||||
|
|
@ -598,6 +622,7 @@ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
|
|||
/* Called from main context */
|
||||
void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
|
||||
source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING);
|
||||
|
|
@ -606,6 +631,7 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
|
|||
/* Called from main context */
|
||||
int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
pa_return_val_if_fail(o->thread_info.resampler, -PA_ERR_BADSTATE);
|
||||
|
||||
|
|
@ -623,6 +649,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
|
|||
/* Called from main context */
|
||||
void pa_source_output_set_name(pa_source_output *o, const char *name) {
|
||||
const char *old;
|
||||
pa_assert_ctl_context();
|
||||
pa_source_output_assert_ref(o);
|
||||
|
||||
if (!name && !pa_proplist_contains(o->proplist, PA_PROP_MEDIA_NAME))
|
||||
|
|
@ -647,11 +674,12 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) {
|
|||
/* Called from main thread */
|
||||
void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (p)
|
||||
pa_proplist_update(o->proplist, mode, p);
|
||||
|
||||
if (PA_SINK_IS_LINKED(o->state)) {
|
||||
if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
|
||||
pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
|
||||
pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
|
||||
}
|
||||
|
|
@ -660,6 +688,7 @@ void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode
|
|||
/* Called from main context */
|
||||
pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
return o->actual_resample_method;
|
||||
}
|
||||
|
|
@ -667,6 +696,7 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
|
|||
/* Called from main context */
|
||||
pa_bool_t pa_source_output_may_move(pa_source_output *o) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
|
||||
if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
|
||||
|
|
@ -708,6 +738,7 @@ int pa_source_output_start_move(pa_source_output *o) {
|
|||
int r;
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
pa_assert(o->source);
|
||||
|
||||
|
|
@ -739,6 +770,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
|
|||
pa_resampler *new_resampler;
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
pa_assert(!o->source);
|
||||
pa_source_assert_ref(dest);
|
||||
|
|
@ -815,11 +847,30 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
void pa_source_output_fail_move(pa_source_output *o) {
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
pa_assert(!o->source);
|
||||
|
||||
/* Check if someone wants this source output? */
|
||||
if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_STOP)
|
||||
return;
|
||||
|
||||
if (o->moving)
|
||||
o->moving(o, NULL);
|
||||
|
||||
pa_source_output_kill(o);
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t save) {
|
||||
int r;
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
|
||||
pa_assert(o->source);
|
||||
pa_source_assert_ref(dest);
|
||||
|
|
@ -838,6 +889,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav
|
|||
}
|
||||
|
||||
if ((r = pa_source_output_finish_move(o, dest, save)) < 0) {
|
||||
pa_source_output_fail_move(o);
|
||||
pa_source_output_unref(o);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -850,6 +902,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav
|
|||
/* Called from IO thread context */
|
||||
void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_output_state_t state) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_assert_io_context(o);
|
||||
|
||||
if (state == o->thread_info.state)
|
||||
return;
|
||||
|
|
@ -906,11 +959,13 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int
|
|||
return -PA_ERR_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
void pa_source_output_send_event(pa_source_output *o, const char *event, pa_proplist *data) {
|
||||
pa_proplist *pl = NULL;
|
||||
pa_source_output_send_event_hook_data hook_data;
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(event);
|
||||
|
||||
if (!o->send_event)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ typedef enum pa_source_output_flags {
|
|||
PA_SOURCE_OUTPUT_FIX_RATE = 64,
|
||||
PA_SOURCE_OUTPUT_FIX_CHANNELS = 128,
|
||||
PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND = 256,
|
||||
PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND = 512
|
||||
PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND = 512,
|
||||
PA_SOURCE_OUTPUT_KILL_ON_SUSPEND = 1024
|
||||
} pa_source_output_flags_t;
|
||||
|
||||
struct pa_source_output {
|
||||
|
|
@ -108,6 +109,10 @@ struct pa_source_output {
|
|||
* from IO context. */
|
||||
void (*update_source_latency_range) (pa_source_output *o); /* may be NULL */
|
||||
|
||||
/* Called whenver the fixed latency of the source changes, if there
|
||||
* is one. Called from IO context. */
|
||||
void (*update_source_fixed_latency) (pa_source_output *i); /* may be NULL */
|
||||
|
||||
/* If non-NULL this function is called when the output is first
|
||||
* connected to a source. Called from IO thread context */
|
||||
void (*attach) (pa_source_output *o); /* may be NULL */
|
||||
|
|
@ -127,7 +132,9 @@ struct pa_source_output {
|
|||
/* If non-NULL called whenever the source output is moved to a new
|
||||
* source. Called from main context after the stream was detached
|
||||
* from the old source and before it is attached to the new
|
||||
* source. */
|
||||
* source. If dest is NULL the move was executed in two
|
||||
* phases and the second one failed; the stream will be destroyed
|
||||
* after this call. */
|
||||
void (*moving) (pa_source_output *o, pa_source *dest); /* may be NULL */
|
||||
|
||||
/* Supposed to unlink and destroy this stream. Called from main
|
||||
|
|
@ -238,6 +245,8 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b);
|
|||
|
||||
int pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
|
||||
|
||||
size_t pa_source_output_get_max_rewind(pa_source_output *o);
|
||||
|
||||
/* Callable by everyone */
|
||||
|
||||
/* External code may request disconnection with this funcion */
|
||||
|
|
@ -260,6 +269,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav
|
|||
* new source */
|
||||
int pa_source_output_start_move(pa_source_output *o);
|
||||
int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t save);
|
||||
void pa_source_output_fail_move(pa_source_output *o);
|
||||
|
||||
#define pa_source_output_get_state(o) ((o)->state)
|
||||
|
||||
|
|
@ -277,4 +287,7 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int
|
|||
|
||||
pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec);
|
||||
|
||||
#define pa_source_output_assert_io_context(s) \
|
||||
pa_assert(pa_thread_mq_get() || !PA_SOURCE_OUTPUT_IS_LINKED((s)->state))
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <pulse/timeval.h>
|
||||
#include <pulse/util.h>
|
||||
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/source-output.h>
|
||||
#include <pulsecore/namereg.h>
|
||||
#include <pulsecore/core-subscribe.h>
|
||||
|
|
@ -52,7 +53,7 @@ static void source_free(pa_object *o);
|
|||
pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data) {
|
||||
pa_assert(data);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
pa_zero(*data);
|
||||
data->proplist = pa_proplist_new();
|
||||
|
||||
return data;
|
||||
|
|
@ -145,6 +146,7 @@ pa_source* pa_source_new(
|
|||
pa_assert(core);
|
||||
pa_assert(data);
|
||||
pa_assert(data->name);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
s = pa_msgobject_new(pa_source);
|
||||
|
||||
|
|
@ -224,13 +226,10 @@ pa_source* pa_source_new(
|
|||
s->muted = data->muted;
|
||||
s->refresh_volume = s->refresh_muted = FALSE;
|
||||
|
||||
s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
|
||||
|
||||
reset_callbacks(s);
|
||||
s->userdata = NULL;
|
||||
|
||||
s->asyncmsgq = NULL;
|
||||
s->rtpoll = NULL;
|
||||
|
||||
/* As a minor optimization we just steal the list instead of
|
||||
* copying it here */
|
||||
|
|
@ -263,6 +262,7 @@ pa_source* pa_source_new(
|
|||
&s->sample_spec,
|
||||
0);
|
||||
|
||||
s->thread_info.rtpoll = NULL;
|
||||
s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
|
||||
s->thread_info.soft_volume = s->soft_volume;
|
||||
s->thread_info.soft_muted = s->muted;
|
||||
|
|
@ -272,6 +272,7 @@ pa_source* pa_source_new(
|
|||
s->thread_info.requested_latency = 0;
|
||||
s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
|
||||
s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
|
||||
s->thread_info.fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
|
||||
|
||||
pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
|
||||
|
||||
|
|
@ -297,6 +298,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) {
|
|||
pa_source_state_t original_state;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (s->state == state)
|
||||
return 0;
|
||||
|
|
@ -333,27 +335,26 @@ static int source_set_state(pa_source *s, pa_source_state_t state) {
|
|||
|
||||
/* We're suspending or resuming, tell everyone about it */
|
||||
|
||||
for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
|
||||
PA_IDXSET_FOREACH(o, s->outputs, idx)
|
||||
if (s->state == PA_SOURCE_SUSPENDED &&
|
||||
(o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND))
|
||||
(o->flags & PA_SOURCE_OUTPUT_KILL_ON_SUSPEND))
|
||||
pa_source_output_kill(o);
|
||||
else if (o->suspend)
|
||||
o->suspend(o, state == PA_SOURCE_SUSPENDED);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
void pa_source_put(pa_source *s) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
pa_assert(s->state == PA_SOURCE_INIT);
|
||||
|
||||
/* The following fields must be initialized properly when calling _put() */
|
||||
pa_assert(s->asyncmsgq);
|
||||
pa_assert(s->rtpoll);
|
||||
pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
|
||||
|
||||
/* Generally, flags should be initialized via pa_source_new(). As
|
||||
|
|
@ -368,7 +369,7 @@ void pa_source_put(pa_source *s) {
|
|||
|
||||
pa_assert((s->flags & PA_SOURCE_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SOURCE_DECIBEL_VOLUME));
|
||||
pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
|
||||
pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
|
||||
pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0));
|
||||
|
||||
pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
|
||||
|
||||
|
|
@ -382,6 +383,7 @@ void pa_source_unlink(pa_source *s) {
|
|||
pa_source_output *o, *j = NULL;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
/* See pa_sink_unlink() for a couple of comments how this function
|
||||
* works. */
|
||||
|
|
@ -423,6 +425,7 @@ static void source_free(pa_object *o) {
|
|||
pa_source *s = PA_SOURCE(o);
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(pa_source_refcnt(s) == 0);
|
||||
|
||||
if (PA_SOURCE_IS_LINKED(s->state))
|
||||
|
|
@ -458,23 +461,40 @@ static void source_free(pa_object *o) {
|
|||
pa_xfree(s);
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
/* Called from main context, and not while the IO thread is active, please */
|
||||
void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
s->asyncmsgq = q;
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
/* Called from main context, and not while the IO thread is active, please */
|
||||
void pa_source_update_flags(pa_source *s, pa_source_flags_t mask, pa_source_flags_t value) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
/* For now, allow only a minimal set of flags to be changed. */
|
||||
pa_assert((mask & ~(PA_SOURCE_DYNAMIC_LATENCY|PA_SOURCE_LATENCY)) == 0);
|
||||
|
||||
s->flags = (s->flags & ~mask) | (value & mask);
|
||||
}
|
||||
|
||||
/* Called from IO context, or before _put() from main context */
|
||||
void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
|
||||
s->rtpoll = p;
|
||||
s->thread_info.rtpoll = p;
|
||||
}
|
||||
|
||||
/* Called from main context */
|
||||
int pa_source_update_status(pa_source*s) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
if (s->state == PA_SOURCE_SUSPENDED)
|
||||
|
|
@ -486,6 +506,7 @@ int pa_source_update_status(pa_source*s) {
|
|||
/* Called from main context */
|
||||
int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
pa_assert(cause != 0);
|
||||
|
||||
|
|
@ -513,6 +534,7 @@ int pa_source_sync_suspend(pa_source *s) {
|
|||
pa_sink_state_t state;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
pa_assert(s->monitor_of);
|
||||
|
||||
|
|
@ -532,6 +554,7 @@ pa_queue *pa_source_move_all_start(pa_source *s, pa_queue *q) {
|
|||
uint32_t idx;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
if (!q)
|
||||
|
|
@ -556,12 +579,13 @@ void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
|
|||
pa_source_output *o;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
pa_assert(q);
|
||||
|
||||
while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
|
||||
if (pa_source_output_finish_move(o, s, save) < 0)
|
||||
pa_source_output_kill(o);
|
||||
pa_source_output_fail_move(o);
|
||||
|
||||
pa_source_output_unref(o);
|
||||
}
|
||||
|
|
@ -572,13 +596,13 @@ void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
|
|||
/* Called from main context */
|
||||
void pa_source_move_all_fail(pa_queue *q) {
|
||||
pa_source_output *o;
|
||||
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(q);
|
||||
|
||||
while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
|
||||
if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
|
||||
pa_source_output_kill(o);
|
||||
pa_source_output_unref(o);
|
||||
}
|
||||
pa_source_output_fail_move(o);
|
||||
pa_source_output_unref(o);
|
||||
}
|
||||
|
||||
pa_queue_free(q, NULL, NULL);
|
||||
|
|
@ -590,17 +614,18 @@ void pa_source_process_rewind(pa_source *s, size_t nbytes) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
|
||||
|
||||
if (s->thread_info.state == PA_SOURCE_SUSPENDED)
|
||||
return;
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
if (s->thread_info.state == PA_SOURCE_SUSPENDED)
|
||||
return;
|
||||
|
||||
pa_log_debug("Processing rewind...");
|
||||
|
||||
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
|
||||
PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_process_rewind(o, nbytes);
|
||||
}
|
||||
|
|
@ -612,6 +637,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
|
||||
pa_assert(chunk);
|
||||
|
||||
|
|
@ -651,6 +677,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
|
|||
/* Called from IO thread context */
|
||||
void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert(o->thread_info.direct_on_input);
|
||||
|
|
@ -682,6 +709,7 @@ pa_usec_t pa_source_get_latency(pa_source *s) {
|
|||
pa_usec_t usec;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
if (s->state == PA_SOURCE_SUSPENDED)
|
||||
|
|
@ -701,6 +729,7 @@ pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
|
|||
pa_msgobject *o;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
|
||||
|
||||
/* The returned value is supposed to be in the time domain of the sound card! */
|
||||
|
|
@ -727,6 +756,7 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save
|
|||
pa_bool_t virtual_volume_changed;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
pa_assert(volume);
|
||||
pa_assert(pa_cvolume_valid(volume));
|
||||
|
|
@ -752,6 +782,7 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save
|
|||
/* Called from main thread. Only to be called by source implementor */
|
||||
void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(volume);
|
||||
|
||||
if (PA_SOURCE_IS_LINKED(s->state))
|
||||
|
|
@ -763,6 +794,7 @@ void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
|
|||
/* Called from main thread */
|
||||
const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
if (s->refresh_volume || force_refresh) {
|
||||
|
|
@ -773,26 +805,28 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
|
|||
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
|
||||
|
||||
if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
|
||||
if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
|
||||
s->save_volume = TRUE;
|
||||
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
|
||||
}
|
||||
}
|
||||
|
||||
return &s->virtual_volume;
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume, pa_bool_t save) {
|
||||
void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
/* The source implementor may call this if the volume changed to make sure everyone is notified */
|
||||
|
||||
if (pa_cvolume_equal(&s->virtual_volume, new_volume)) {
|
||||
s->save_volume = s->save_volume || save;
|
||||
if (pa_cvolume_equal(&s->virtual_volume, new_volume))
|
||||
return;
|
||||
}
|
||||
|
||||
s->virtual_volume = *new_volume;
|
||||
s->save_volume = save;
|
||||
s->save_volume = TRUE;
|
||||
|
||||
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
|
||||
}
|
||||
|
|
@ -802,6 +836,7 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) {
|
|||
pa_bool_t old_muted;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
old_muted = s->muted;
|
||||
|
|
@ -820,6 +855,7 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) {
|
|||
/* Called from main thread */
|
||||
pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
if (s->refresh_muted || force_refresh) {
|
||||
|
|
@ -831,6 +867,8 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
|
|||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
|
||||
|
||||
if (old_muted != s->muted) {
|
||||
s->save_muted = TRUE;
|
||||
|
||||
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
|
||||
|
||||
/* Make sure the soft mute status stays in sync */
|
||||
|
|
@ -842,18 +880,18 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
|
|||
}
|
||||
|
||||
/* Called from main thread */
|
||||
void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save) {
|
||||
void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
/* The source implementor may call this if the mute state changed to make sure everyone is notified */
|
||||
|
||||
if (s->muted == new_muted) {
|
||||
s->save_muted = s->save_muted || save;
|
||||
if (s->muted == new_muted)
|
||||
return;
|
||||
}
|
||||
|
||||
s->muted = new_muted;
|
||||
s->save_muted = save;
|
||||
s->save_muted = TRUE;
|
||||
|
||||
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
|
||||
}
|
||||
|
|
@ -861,6 +899,7 @@ void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save) {
|
|||
/* Called from main thread */
|
||||
pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (p)
|
||||
pa_proplist_update(s->proplist, mode, p);
|
||||
|
|
@ -874,16 +913,18 @@ pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_prop
|
|||
}
|
||||
|
||||
/* Called from main thread */
|
||||
/* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
|
||||
void pa_source_set_description(pa_source *s, const char *description) {
|
||||
const char *old;
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
|
||||
return;
|
||||
|
||||
old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
|
||||
|
||||
if (old && description && !strcmp(old, description))
|
||||
if (old && description && pa_streq(old, description))
|
||||
return;
|
||||
|
||||
if (description)
|
||||
|
|
@ -901,6 +942,7 @@ void pa_source_set_description(pa_source *s, const char *description) {
|
|||
unsigned pa_source_linked_by(pa_source *s) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
pa_assert_ctl_context();
|
||||
|
||||
return pa_idxset_size(s->outputs);
|
||||
}
|
||||
|
|
@ -911,6 +953,7 @@ unsigned pa_source_used_by(pa_source *s) {
|
|||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
pa_assert_ctl_context();
|
||||
|
||||
ret = pa_idxset_size(s->outputs);
|
||||
pa_assert(ret >= s->n_corked);
|
||||
|
|
@ -925,6 +968,7 @@ unsigned pa_source_check_suspend(pa_source *s) {
|
|||
uint32_t idx;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!PA_SOURCE_IS_LINKED(s->state))
|
||||
return 0;
|
||||
|
|
@ -1006,7 +1050,7 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
|
|||
if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
|
||||
pa_source_output_unref(o);
|
||||
|
||||
pa_source_invalidate_requested_latency(s);
|
||||
pa_source_invalidate_requested_latency(s, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1086,6 +1130,16 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
|
|||
return 0;
|
||||
}
|
||||
|
||||
case PA_SOURCE_MESSAGE_GET_FIXED_LATENCY:
|
||||
|
||||
*((pa_usec_t*) userdata) = s->thread_info.fixed_latency;
|
||||
return 0;
|
||||
|
||||
case PA_SOURCE_MESSAGE_SET_FIXED_LATENCY:
|
||||
|
||||
pa_source_set_fixed_latency_within_thread(s, (pa_usec_t) offset);
|
||||
return 0;
|
||||
|
||||
case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
|
||||
|
||||
*((size_t*) userdata) = s->thread_info.max_rewind;
|
||||
|
|
@ -1120,6 +1174,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus
|
|||
int ret = 0;
|
||||
|
||||
pa_core_assert_ref(c);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(cause != 0);
|
||||
|
||||
for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
|
||||
|
|
@ -1138,6 +1193,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus
|
|||
/* Called from main thread */
|
||||
void pa_source_detach(pa_source *s) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
|
||||
|
|
@ -1146,6 +1202,7 @@ void pa_source_detach(pa_source *s) {
|
|||
/* Called from main thread */
|
||||
void pa_source_attach(pa_source *s) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
|
||||
|
|
@ -1157,9 +1214,10 @@ void pa_source_detach_within_thread(pa_source *s) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
|
||||
|
||||
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
|
||||
PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
|
||||
if (o->detach)
|
||||
o->detach(o);
|
||||
}
|
||||
|
|
@ -1170,9 +1228,10 @@ void pa_source_attach_within_thread(pa_source *s) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
|
||||
|
||||
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
|
||||
PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
|
||||
if (o->attach)
|
||||
o->attach(o);
|
||||
}
|
||||
|
|
@ -1184,15 +1243,15 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
|
||||
if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
|
||||
return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
|
||||
return PA_CLAMP(s->thread_info.fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
|
||||
|
||||
if (s->thread_info.requested_latency_valid)
|
||||
return s->thread_info.requested_latency;
|
||||
|
||||
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
|
||||
|
||||
PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
|
||||
if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
|
||||
(result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
|
||||
result = o->thread_info.requested_source_latency;
|
||||
|
|
@ -1214,6 +1273,7 @@ pa_usec_t pa_source_get_requested_latency(pa_source *s) {
|
|||
pa_usec_t usec = 0;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(PA_SOURCE_IS_LINKED(s->state));
|
||||
|
||||
if (s->state == PA_SOURCE_SUSPENDED)
|
||||
|
|
@ -1230,21 +1290,22 @@ void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
|
|||
void *state = NULL;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
|
||||
if (max_rewind == s->thread_info.max_rewind)
|
||||
return;
|
||||
|
||||
s->thread_info.max_rewind = max_rewind;
|
||||
|
||||
if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
|
||||
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
|
||||
if (PA_SOURCE_IS_LINKED(s->thread_info.state))
|
||||
PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
|
||||
pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (PA_SOURCE_IS_LINKED(s->state))
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
|
||||
|
|
@ -1253,17 +1314,18 @@ void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
|
|||
}
|
||||
|
||||
/* Called from IO thread */
|
||||
void pa_source_invalidate_requested_latency(pa_source *s) {
|
||||
void pa_source_invalidate_requested_latency(pa_source *s, pa_bool_t dynamic) {
|
||||
pa_source_output *o;
|
||||
void *state = NULL;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
|
||||
if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
|
||||
if ((s->flags & PA_SOURCE_DYNAMIC_LATENCY))
|
||||
s->thread_info.requested_latency_valid = FALSE;
|
||||
else if (dynamic)
|
||||
return;
|
||||
|
||||
s->thread_info.requested_latency_valid = FALSE;
|
||||
|
||||
if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
|
||||
|
||||
if (s->update_requested_latency)
|
||||
|
|
@ -1275,12 +1337,13 @@ void pa_source_invalidate_requested_latency(pa_source *s) {
|
|||
}
|
||||
|
||||
if (s->monitor_of)
|
||||
pa_sink_invalidate_requested_latency(s->monitor_of);
|
||||
pa_sink_invalidate_requested_latency(s->monitor_of, dynamic);
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
/* min_latency == 0: no limit
|
||||
* min_latency anything else: specified limit
|
||||
|
|
@ -1315,6 +1378,7 @@ void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t
|
|||
/* Called from main thread */
|
||||
void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
pa_assert(min_latency);
|
||||
pa_assert(max_latency);
|
||||
|
||||
|
|
@ -1333,9 +1397,8 @@ void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t
|
|||
|
||||
/* Called from IO thread, and from main thread before pa_source_put() is called */
|
||||
void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
|
||||
void *state = NULL;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
|
||||
pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
|
||||
pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
|
||||
|
|
@ -1347,25 +1410,34 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten
|
|||
(s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
|
||||
s->monitor_of);
|
||||
|
||||
if (s->thread_info.min_latency == min_latency &&
|
||||
s->thread_info.max_latency == max_latency)
|
||||
return;
|
||||
|
||||
s->thread_info.min_latency = min_latency;
|
||||
s->thread_info.max_latency = max_latency;
|
||||
|
||||
if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
|
||||
pa_source_output *o;
|
||||
void *state = NULL;
|
||||
|
||||
while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
|
||||
PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
|
||||
if (o->update_source_latency_range)
|
||||
o->update_source_latency_range(o);
|
||||
}
|
||||
|
||||
pa_source_invalidate_requested_latency(s);
|
||||
pa_source_invalidate_requested_latency(s, FALSE);
|
||||
}
|
||||
|
||||
/* Called from main thread, before the source is put */
|
||||
void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
|
||||
if (s->flags & PA_SOURCE_DYNAMIC_LATENCY) {
|
||||
pa_assert(latency == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (latency < ABSOLUTE_MIN_LATENCY)
|
||||
latency = ABSOLUTE_MIN_LATENCY;
|
||||
|
|
@ -1373,12 +1445,64 @@ void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
|
|||
if (latency > ABSOLUTE_MAX_LATENCY)
|
||||
latency = ABSOLUTE_MAX_LATENCY;
|
||||
|
||||
s->fixed_latency = latency;
|
||||
if (PA_SOURCE_IS_LINKED(s->state))
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_FIXED_LATENCY, NULL, (int64_t) latency, NULL) == 0);
|
||||
else
|
||||
s->thread_info.fixed_latency = latency;
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
pa_usec_t pa_source_get_fixed_latency(pa_source *s) {
|
||||
pa_usec_t latency;
|
||||
|
||||
pa_source_assert_ref(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (s->flags & PA_SOURCE_DYNAMIC_LATENCY)
|
||||
return 0;
|
||||
|
||||
if (PA_SOURCE_IS_LINKED(s->state))
|
||||
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_FIXED_LATENCY, &latency, 0, NULL) == 0);
|
||||
else
|
||||
latency = s->thread_info.fixed_latency;
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
||||
/* Called from IO thread */
|
||||
void pa_source_set_fixed_latency_within_thread(pa_source *s, pa_usec_t latency) {
|
||||
pa_source_assert_ref(s);
|
||||
pa_source_assert_io_context(s);
|
||||
|
||||
if (s->flags & PA_SOURCE_DYNAMIC_LATENCY) {
|
||||
pa_assert(latency == 0);
|
||||
return;
|
||||
}
|
||||
|
||||
pa_assert(latency >= ABSOLUTE_MIN_LATENCY);
|
||||
pa_assert(latency <= ABSOLUTE_MAX_LATENCY);
|
||||
|
||||
if (s->thread_info.fixed_latency == latency)
|
||||
return;
|
||||
|
||||
s->thread_info.fixed_latency = latency;
|
||||
|
||||
if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
|
||||
pa_source_output *o;
|
||||
void *state = NULL;
|
||||
|
||||
PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
|
||||
if (o->update_source_fixed_latency)
|
||||
o->update_source_fixed_latency(o);
|
||||
}
|
||||
|
||||
pa_source_invalidate_requested_latency(s, FALSE);
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
size_t pa_source_get_max_rewind(pa_source *s) {
|
||||
size_t r;
|
||||
pa_assert_ctl_context();
|
||||
pa_source_assert_ref(s);
|
||||
|
||||
if (!PA_SOURCE_IS_LINKED(s->state))
|
||||
|
|
@ -1394,9 +1518,10 @@ int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
|
|||
pa_device_port *port;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_ctl_context();
|
||||
|
||||
if (!s->set_port) {
|
||||
pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
|
||||
pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s->index, s->name);
|
||||
return -PA_ERR_NOTIMPLEMENTED;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ typedef struct pa_source pa_source;
|
|||
#include <pulsecore/source-output.h>
|
||||
#include <pulsecore/card.h>
|
||||
#include <pulsecore/queue.h>
|
||||
#include <pulsecore/thread-mq.h>
|
||||
|
||||
#define PA_MAX_OUTPUTS_PER_SOURCE 32
|
||||
|
||||
|
|
@ -89,12 +90,9 @@ struct pa_source {
|
|||
pa_bool_t save_muted:1;
|
||||
|
||||
pa_asyncmsgq *asyncmsgq;
|
||||
pa_rtpoll *rtpoll;
|
||||
|
||||
pa_memchunk silence;
|
||||
|
||||
pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */
|
||||
|
||||
pa_hashmap *ports;
|
||||
pa_device_port *active_port;
|
||||
|
||||
|
|
@ -139,6 +137,8 @@ struct pa_source {
|
|||
pa_source_state_t state;
|
||||
pa_hashmap *outputs;
|
||||
|
||||
pa_rtpoll *rtpoll;
|
||||
|
||||
pa_cvolume soft_volume;
|
||||
pa_bool_t soft_muted:1;
|
||||
|
||||
|
|
@ -151,7 +151,9 @@ struct pa_source {
|
|||
|
||||
pa_usec_t min_latency; /* we won't go below this latency */
|
||||
pa_usec_t max_latency; /* An upper limit for the latencies */
|
||||
} thread_info;
|
||||
|
||||
pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */
|
||||
} thread_info;
|
||||
|
||||
void *userdata;
|
||||
};
|
||||
|
|
@ -173,6 +175,8 @@ typedef enum pa_source_message {
|
|||
PA_SOURCE_MESSAGE_DETACH,
|
||||
PA_SOURCE_MESSAGE_SET_LATENCY_RANGE,
|
||||
PA_SOURCE_MESSAGE_GET_LATENCY_RANGE,
|
||||
PA_SOURCE_MESSAGE_SET_FIXED_LATENCY,
|
||||
PA_SOURCE_MESSAGE_GET_FIXED_LATENCY,
|
||||
PA_SOURCE_MESSAGE_GET_MAX_REWIND,
|
||||
PA_SOURCE_MESSAGE_SET_MAX_REWIND,
|
||||
PA_SOURCE_MESSAGE_MAX
|
||||
|
|
@ -237,17 +241,20 @@ void pa_source_detach(pa_source *s);
|
|||
void pa_source_attach(pa_source *s);
|
||||
|
||||
void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume);
|
||||
void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume, pa_bool_t save);
|
||||
void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save);
|
||||
void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume);
|
||||
void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted);
|
||||
|
||||
int pa_source_sync_suspend(pa_source *s);
|
||||
|
||||
void pa_source_update_flags(pa_source *s, pa_source_flags_t mask, pa_source_flags_t value);
|
||||
|
||||
/*** May be called by everyone, from main context */
|
||||
|
||||
/* The returned value is supposed to be in the time domain of the sound card! */
|
||||
pa_usec_t pa_source_get_latency(pa_source *s);
|
||||
pa_usec_t pa_source_get_requested_latency(pa_source *s);
|
||||
void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency);
|
||||
pa_usec_t pa_source_get_fixed_latency(pa_source *s);
|
||||
|
||||
size_t pa_source_get_max_rewind(pa_source *s);
|
||||
|
||||
|
|
@ -257,6 +264,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus
|
|||
|
||||
void pa_source_set_volume(pa_source *source, const pa_cvolume *volume, pa_bool_t save);
|
||||
const pa_cvolume *pa_source_get_volume(pa_source *source, pa_bool_t force_refresh);
|
||||
|
||||
void pa_source_set_mute(pa_source *source, pa_bool_t mute, pa_bool_t save);
|
||||
pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh);
|
||||
|
||||
|
|
@ -288,11 +296,16 @@ void pa_source_detach_within_thread(pa_source *s);
|
|||
pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s);
|
||||
|
||||
void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind);
|
||||
|
||||
void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency);
|
||||
void pa_source_set_fixed_latency_within_thread(pa_source *s, pa_usec_t latency);
|
||||
|
||||
/*** To be called exclusively by source output drivers, from IO context */
|
||||
|
||||
void pa_source_invalidate_requested_latency(pa_source *s);
|
||||
void pa_source_invalidate_requested_latency(pa_source *s, pa_bool_t dynamic);
|
||||
pa_usec_t pa_source_get_latency_within_thread(pa_source *s);
|
||||
|
||||
#define pa_source_assert_io_context(s) \
|
||||
pa_assert(pa_thread_mq_get() || !PA_SOURCE_IS_LINKED((s)->state))
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -68,23 +68,24 @@ int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) {
|
|||
} else {
|
||||
/* child */
|
||||
|
||||
pa_reset_priority();
|
||||
pa_reset_personality();
|
||||
|
||||
pa_assert_se(pa_close(pipe_fds[0]) == 0);
|
||||
pa_assert_se(dup2(pipe_fds[1], 1) == 1);
|
||||
pa_assert_se(dup2(pipe_fds[1], STDOUT_FILENO) == STDOUT_FILENO);
|
||||
|
||||
if (pipe_fds[1] != 1)
|
||||
if (pipe_fds[1] != STDOUT_FILENO)
|
||||
pa_assert_se(pa_close(pipe_fds[1]) == 0);
|
||||
|
||||
pa_close(0);
|
||||
pa_assert_se(open("/dev/null", O_RDONLY) == 0);
|
||||
pa_close(STDIN_FILENO);
|
||||
pa_assert_se(open("/dev/null", O_RDONLY) == STDIN_FILENO);
|
||||
|
||||
pa_close(2);
|
||||
pa_assert_se(open("/dev/null", O_WRONLY) == 2);
|
||||
pa_close(STDERR_FILENO);
|
||||
pa_assert_se(open("/dev/null", O_WRONLY) == STDERR_FILENO);
|
||||
|
||||
pa_close_all(-1);
|
||||
pa_reset_sigs(-1);
|
||||
pa_unblock_sigs(-1);
|
||||
pa_reset_priority();
|
||||
|
||||
#ifdef PR_SET_PDEATHSIG
|
||||
/* On Linux we can use PR_SET_PDEATHSIG to have the helper
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static void asyncmsgq_read_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io
|
|||
pa_memchunk chunk;
|
||||
|
||||
/* Check whether there is a message for us to process */
|
||||
while (pa_asyncmsgq_get(aq, &object, &code, &data, &offset, &chunk, 0) == 0) {
|
||||
while (pa_asyncmsgq_get(aq, &object, &code, &data, &offset, &chunk, 0) >= 0) {
|
||||
int ret;
|
||||
|
||||
ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk);
|
||||
|
|
@ -104,6 +104,15 @@ void pa_thread_mq_init(pa_thread_mq *q, pa_mainloop_api *mainloop, pa_rtpoll *rt
|
|||
void pa_thread_mq_done(pa_thread_mq *q) {
|
||||
pa_assert(q);
|
||||
|
||||
/* Since we are called from main context we can be sure that the
|
||||
* inq is empty. However, the outq might still contain messages
|
||||
* for the main loop, which we need to dispatch (e.g. release
|
||||
* msgs, other stuff). Hence do so if we aren't currently
|
||||
* dispatching anyway. */
|
||||
|
||||
if (!pa_asyncmsgq_dispatching(q->outq))
|
||||
pa_asyncmsgq_flush(q->outq, TRUE);
|
||||
|
||||
q->mainloop->io_free(q->read_event);
|
||||
q->mainloop->io_free(q->write_event);
|
||||
q->read_event = q->write_event = NULL;
|
||||
|
|
|
|||
|
|
@ -45,4 +45,12 @@ void pa_thread_mq_install(pa_thread_mq *q);
|
|||
/* Return the pa_thread_mq object that is set for the current thread */
|
||||
pa_thread_mq *pa_thread_mq_get(void);
|
||||
|
||||
/* Verify that we are in control context (aka 'main context'). */
|
||||
#define pa_assert_ctl_context(s) \
|
||||
pa_assert(!pa_thread_mq_get())
|
||||
|
||||
/* Verify that we are in IO context (aka 'thread context'). */
|
||||
#define pa_assert_io_context(s) \
|
||||
pa_assert(pa_thread_mq_get())
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -108,29 +108,11 @@ pa_smoother* pa_smoother_new(
|
|||
s = pa_xnew(pa_smoother, 1);
|
||||
s->adjust_time = adjust_time;
|
||||
s->history_time = history_time;
|
||||
s->time_offset = 0;
|
||||
s->min_history = min_history;
|
||||
s->monotonic = monotonic;
|
||||
|
||||
s->px = s->py = 0;
|
||||
s->dp = 1;
|
||||
|
||||
s->ex = s->ey = s->ry = 0;
|
||||
s->de = 1;
|
||||
|
||||
s->history_idx = 0;
|
||||
s->n_history = 0;
|
||||
|
||||
s->last_y = s->last_x = 0;
|
||||
|
||||
s->abc_valid = FALSE;
|
||||
|
||||
s->paused = FALSE;
|
||||
s->smoothing = smoothing;
|
||||
|
||||
s->min_history = min_history;
|
||||
|
||||
s->paused = paused;
|
||||
s->time_offset = s->pause_time = time_offset;
|
||||
pa_smoother_reset(s, time_offset, paused);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
@ -514,9 +496,26 @@ pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay)
|
|||
return (pa_usec_t) llrint((double) y_delay / nde);
|
||||
}
|
||||
|
||||
void pa_smoother_reset(pa_smoother *s) {
|
||||
void pa_smoother_reset(pa_smoother *s, pa_usec_t time_offset, pa_bool_t paused) {
|
||||
pa_assert(s);
|
||||
|
||||
s->px = s->py = 0;
|
||||
s->dp = 1;
|
||||
|
||||
s->ex = s->ey = s->ry = 0;
|
||||
s->de = 1;
|
||||
|
||||
s->history_idx = 0;
|
||||
s->n_history = 0;
|
||||
|
||||
s->last_y = s->last_x = 0;
|
||||
|
||||
s->abc_valid = FALSE;
|
||||
|
||||
s->paused = paused;
|
||||
s->time_offset = s->pause_time = time_offset;
|
||||
|
||||
#ifdef DEBUG_DATA
|
||||
pa_log_debug("reset()");
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ void pa_smoother_set_time_offset(pa_smoother *s, pa_usec_t x_offset);
|
|||
void pa_smoother_pause(pa_smoother *s, pa_usec_t x);
|
||||
void pa_smoother_resume(pa_smoother *s, pa_usec_t x, pa_bool_t abrupt);
|
||||
|
||||
void pa_smoother_reset(pa_smoother *s);
|
||||
void pa_smoother_reset(pa_smoother *s, pa_usec_t time_offset, pa_bool_t paused);
|
||||
|
||||
void pa_smoother_fix_now(pa_smoother *s);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue