From a10b7cda4eb9aaa0523c429621bb31fd1246cc05 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Jul 2009 14:25:13 +0200 Subject: native: don't hit assert when user uploads zero-sized sample --- src/pulsecore/protocol-native.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index cda7ef57..96184bd2 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2689,7 +2689,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); -- cgit From 28e4625a52dedbf9f3697b3b3bb5b6ea59f336c9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Jul 2009 20:20:55 +0200 Subject: memblock: rearrange locking order --- src/pulsecore/memblock.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 9a57895b..2c3f98a5 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -257,7 +257,7 @@ 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"); + pa_log_debug("Pool full"); pa_atomic_inc(&p->stat.n_pool_full); return NULL; } @@ -509,13 +509,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_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 +528,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 +661,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 +672,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, + 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) { -- cgit From 7dabe051cdd3980887a78a6cfe8e06666e2b21c9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Jul 2009 20:22:38 +0200 Subject: memtrap: properly lock access to memtrap changer --- src/pulsecore/memtrap.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/memtrap.c b/src/pulsecore/memtrap.c index e06f60ca..7d917450 100644 --- a/src/pulsecore/memtrap.c +++ b/src/pulsecore/memtrap.c @@ -37,6 +37,7 @@ #include #include #include +#include #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 { @@ -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; } -- cgit From d18eb61bd2fe5940bccc2b5fcda4029159021d00 Mon Sep 17 00:00:00 2001 From: Diego Elio 'Flameeyes' Pettenò Date: Fri, 17 Jul 2009 21:05:49 +0200 Subject: Again make sure that the wait() definition is not shadowed. Rename the parameter in pa_asyncmsgq_get() to wait_op. --- src/pulsecore/asyncmsgq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c index e191b05f..083d9de2 100644 --- a/src/pulsecore/asyncmsgq.c +++ b/src/pulsecore/asyncmsgq.c @@ -172,11 +172,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; } -- cgit From 0225ef68f2876bebd14977882db313fd7f3f6d64 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Jul 2009 15:50:02 +0100 Subject: memtrap: clarify that we are not interested in the return value of write() --- src/pulsecore/memtrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/memtrap.c b/src/pulsecore/memtrap.c index 7d917450..c647e507 100644 --- a/src/pulsecore/memtrap.c +++ b/src/pulsecore/memtrap.c @@ -65,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) { -- cgit From 3b01d3a53f3b9261b30c1f7e5fe28d269c28cdf0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 23 Jul 2009 13:40:23 +0200 Subject: protocol-native: use the right samplerate The render_memblockq is expressed in the sample_spec of the sink, not of the particular stream before resampling. --- src/pulsecore/protocol-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 96184bd2..9a37c565 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -2550,7 +2550,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 && -- cgit From 5a0ef5fd139151b285720f2c9edf3b559556c86d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jul 2009 19:12:53 +0200 Subject: daemon: replace colons by dash in per-machine directory names for compat with weird filesystems --- src/pulsecore/core-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 04e7eb24..5f777d5b 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1481,7 +1481,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); @@ -1904,7 +1904,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); -- cgit From 5e24b6dff532ef82e028a78f020a826032493b2e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 15:49:22 +0200 Subject: memblock: try to hit an assert earlier when ref counting doesn't work --- src/pulsecore/memblock.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 2c3f98a5..3bc10de5 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -96,6 +96,7 @@ struct pa_memimport_segment { unsigned n_blocks; }; +/* A collection of multiple segments */ struct pa_memimport { pa_mutex *mutex; @@ -514,9 +515,9 @@ static void memblock_free(pa_memblock *b) { 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) @@ -677,9 +678,9 @@ static void memblock_replace_import(pa_memblock *b) { 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))); memblock_make_local(b); @@ -960,6 +961,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; @@ -989,12 +995,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; } -- cgit From 5efb07281d5be1cddaed5b0610325fedd7f599ec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Jul 2009 20:13:52 +0200 Subject: alsa: throw timing data away after device resume --- src/pulsecore/time-smoother.c | 41 ++++++++++++++++++++--------------------- src/pulsecore/time-smoother.h | 2 +- 2 files changed, 21 insertions(+), 22 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 9d5a0705..1289f2b6 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -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 */ } diff --git a/src/pulsecore/time-smoother.h b/src/pulsecore/time-smoother.h index 5244a7e7..63d33e48 100644 --- a/src/pulsecore/time-smoother.h +++ b/src/pulsecore/time-smoother.h @@ -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); -- cgit From e5c2256e360df3662295b8cc0594568e425e8679 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 01:59:58 +0200 Subject: pipe: replace PIPE_BUF macro pa pa_pipe_buf call This should help portability to platforms that lack PIPE_BUF. Based on a patch from Samuel Thibault. See ticket #546 --- src/pulsecore/core-util.c | 16 ++++++++++++++++ src/pulsecore/core-util.h | 3 +++ 2 files changed, 19 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 5f777d5b..d01efa23 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2779,3 +2779,19 @@ 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 +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 96a0480a..b5e8453b 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -236,4 +236,7 @@ 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); + #endif -- cgit From c6ea9fecc9acd70642ae45b01300484f6b900c6b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 02:01:58 +0200 Subject: core-util: rework pa_strlcpy() to not rely on strncpy() strncpy() is very slow since it resets the entire destination buffer. Replace usage of strncpy by memcpy(). --- src/pulsecore/core-util.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index d01efa23..99644d7c 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -552,12 +552,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; } -- cgit From 49fd8ee72e76cd27a978a843ecc58ad10fe077bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 02:03:22 +0200 Subject: core-util: replace remaining fixed size destination string functions by _malloc() versions This helps portability to GNU/Hurd. Patch originally from Samuel Thibault but modified. Closes ticket #546 --- src/pulsecore/authkey.c | 37 +++++++++++----------- src/pulsecore/core-scache.c | 5 +-- src/pulsecore/core-util.c | 74 ++++++++++++++++++++++++++++++++++++------- src/pulsecore/core-util.h | 2 ++ src/pulsecore/proplist-util.c | 6 ++-- 5 files changed, 91 insertions(+), 33 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index 1e31d076..15613e27 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -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; } diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index 4c5a4b26..fde12ecf 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -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); diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 99644d7c..d4baf697 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -1336,26 +1336,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) { @@ -1380,6 +1386,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" @@ -1634,14 +1684,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 @@ -1721,13 +1772,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 diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index b5e8453b..6de4b771 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -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); diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c index d9769bc7..23864bcb 100644 --- a/src/pulsecore/proplist-util.c +++ b/src/pulsecore/proplist-util.c @@ -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); } } -- cgit From 277822053c2f070940e5a996b9a6d95645d74590 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 1 Aug 2009 03:10:19 +0200 Subject: autospawn: if creating the lock file fails, pass error code cleanly back to main process This makes sure PA clients don't hang if $HOME is for some reason unsuitable for autospawn lockfiles. Closes #539 --- src/pulsecore/lock-autospawn.c | 66 ++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 21 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c index 4436974d..c0df7938 100644 --- a/src/pulsecore/lock-autospawn.c +++ b/src/pulsecore/lock-autospawn.c @@ -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(); -- cgit From ff52588c7b1353542e44633f366b3fda2ba49269 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 5 Aug 2009 03:52:15 +0200 Subject: smoother: readd #ifdef protection --- src/pulsecore/time-smoother.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index 1289f2b6..d6c37878 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -515,7 +515,7 @@ void pa_smoother_reset(pa_smoother *s, pa_usec_t time_offset, pa_bool_t paused) s->paused = paused; s->time_offset = s->pause_time = time_offset; - /* #ifdef DEBUG_DATA */ +#ifdef DEBUG_DATA pa_log_debug("reset()"); -/* #endif */ +#endif } -- cgit From 51b3899348bf29dd88b56691aeea9f57895dfd14 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Aug 2009 23:55:06 +0200 Subject: core: save volume/mute changes coming from the hardware automatically Volume changes coming from the lower layers are most likely changes triggered by the user, so let's save them automatically. --- src/pulsecore/sink.c | 25 +++++++++++++++---------- src/pulsecore/sink.h | 4 ++-- src/pulsecore/source.c | 22 +++++++++++----------- src/pulsecore/source.h | 4 ++-- 4 files changed, 30 insertions(+), 25 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index d8f3c7d1..73a70625 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1386,6 +1386,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 +1403,15 @@ 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); /* 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); @@ -1449,6 +1453,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 +1462,21 @@ 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); /* 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); } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index d16fcc01..7a8cdaf1 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -267,8 +267,8 @@ 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); 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); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 74f38bc5..ad7462b1 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -773,26 +773,26 @@ 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); /* 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); } @@ -831,6 +831,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 +844,16 @@ 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); /* 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); } diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 7e9fd8b7..d22e7ca5 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -237,8 +237,8 @@ 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); -- cgit From 7d4916379bbf05384ad199004949cc220822aa5f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 7 Aug 2009 23:58:45 +0200 Subject: ladspa/remap: make sure we process all requested rewinds unconditionally In some situations a rewind request travelling downstream might be optimized away on its way and an upstream rewind processing might never come back. Hence, call _process_rewind() before each _render()just to make sure we processed them all. --- src/pulsecore/sink.c | 7 +++++-- src/pulsecore/source.c | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 73a70625..5e9662c2 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -665,11 +665,14 @@ 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_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 +685,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); } diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index ad7462b1..b8af148f 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -592,15 +592,15 @@ void pa_source_process_rewind(pa_source *s, size_t nbytes) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state)); - if (s->thread_info.state == PA_SOURCE_SUSPENDED) + if (nbytes <= 0) return; - if (nbytes <= 0) + 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); } -- cgit From 8998cba6839a46f11daec411c83a1b35723c5117 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 20:14:31 +0200 Subject: conf: add pa_config_parse_not_bool() for parsing inverse boolean configuration options --- src/pulsecore/conf-parser.c | 24 ++++++++++++++++++++++++ src/pulsecore/conf-parser.h | 1 + 2 files changed, 25 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 2dc9a223..b4ab23cc 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -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; diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h index 08e17ca7..c6c8a148 100644 --- a/src/pulsecore/conf-parser.h +++ b/src/pulsecore/conf-parser.h @@ -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 -- cgit From ef176ecb62a8f04bd14ca37e7c2a40469f0bb8ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:36:52 +0200 Subject: core-util: move personality resetting into core-util --- src/pulsecore/core-util.c | 13 +++++++++++++ src/pulsecore/core-util.h | 2 ++ 2 files changed, 15 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index d4baf697..6494244e 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -101,6 +101,10 @@ #include "rtkit.h" #endif +#ifdef __linux__ +#include +#endif + #include #include #include @@ -2855,3 +2859,12 @@ size_t pa_pipe_buf(int fd) { 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 + +} diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 6de4b771..3d3aec71 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -241,4 +241,6 @@ 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 -- cgit From 286ab2f19370c7a0041897435614b2c6aadc8e70 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:40:38 +0200 Subject: memblock: rate limit 'Pool full' message --- src/pulsecore/memblock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index 3bc10de5..441b397b 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -258,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_debug("Pool full"); + if (pa_log_ratelimit()) + pa_log_debug("Pool full"); pa_atomic_inc(&p->stat.n_pool_full); return NULL; } -- cgit From 17d57415f5abad5b7c30301227054b4c899bc705 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 12 Aug 2009 21:43:06 +0200 Subject: start-child: clean up child environment a bit better --- src/pulsecore/start-child.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c index 7774bde6..b3bce131 100644 --- a/src/pulsecore/start-child.c +++ b/src/pulsecore/start-child.c @@ -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 -- cgit From 9a95fe49c848d2711dcdcf4c407e626e41e4657f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Aug 2009 02:14:19 +0200 Subject: core: add assert macros for verifying calling context This adds pa_assert_io_context() and pa_assert_ctl_context() in addition to a few related macros. When called they will fail when the current execution context is not IO resp. not control context. (aka 'thread' context vs. 'main' context) --- src/pulsecore/sink-input.c | 52 ++++++++++++++++++++++--- src/pulsecore/sink-input.h | 3 ++ src/pulsecore/sink.c | 89 +++++++++++++++++++++++++++++++++++-------- src/pulsecore/sink.h | 7 ++++ src/pulsecore/source-output.c | 33 ++++++++++++++-- src/pulsecore/source-output.h | 3 ++ src/pulsecore/source.c | 66 ++++++++++++++++++++++++++++---- src/pulsecore/source.h | 4 ++ src/pulsecore/thread-mq.h | 8 ++++ 9 files changed, 234 insertions(+), 31 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index a5f96351..c7837298 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -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(); @@ -142,6 +142,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); @@ -348,6 +349,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 +364,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 +403,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 +476,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 +508,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 +546,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 +557,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 +579,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 +717,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 +733,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)); @@ -792,6 +805,7 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam /* 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 +818,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,6 +829,7 @@ 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; @@ -830,6 +846,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); @@ -858,6 +875,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 +894,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 +941,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 +959,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 +980,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 +1007,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 +1024,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 +1033,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 +1047,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 +1056,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 +1075,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 +1099,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 +1107,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 +1124,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 +1153,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 +1208,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); @@ -1271,6 +1303,7 @@ 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); @@ -1301,7 +1334,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 +1446,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 +1457,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 +1482,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 +1549,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 +1570,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) diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 98144d41..5ede1ca8 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -359,4 +359,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 diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 5e9662c2..edcf5bdd 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -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); @@ -360,6 +361,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; @@ -413,6 +415,7 @@ 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); @@ -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)) @@ -550,6 +555,7 @@ static void sink_free(pa_object *o) { /* Called from main context */ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); s->asyncmsgq = q; @@ -560,6 +566,7 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { /* Called from main context */ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) { pa_sink_assert_ref(s); + pa_assert_ctl_context(); s->rtpoll = p; @@ -570,6 +577,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 +589,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 +618,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,6 +643,7 @@ 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); @@ -649,6 +660,8 @@ 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)))) { @@ -667,6 +680,7 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) { 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 @@ -703,6 +717,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) { @@ -742,6 +757,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); @@ -837,6 +853,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); @@ -923,6 +940,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); @@ -1006,6 +1024,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); @@ -1040,6 +1059,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)); @@ -1131,6 +1151,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! */ @@ -1152,6 +1173,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! */ @@ -1218,6 +1240,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); @@ -1274,6 +1297,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); @@ -1322,6 +1346,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)); @@ -1363,6 +1388,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; @@ -1376,6 +1402,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; @@ -1408,6 +1436,8 @@ 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_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)) @@ -1427,6 +1457,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; @@ -1446,6 +1477,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; @@ -1472,6 +1505,8 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) { /* Called from main thread */ 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 */ @@ -1487,6 +1522,7 @@ void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) { /* 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); @@ -1500,16 +1536,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) @@ -1536,6 +1574,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); @@ -1554,6 +1593,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); @@ -1572,6 +1612,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; @@ -1605,8 +1646,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; @@ -1942,9 +1984,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) @@ -1957,6 +2000,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); @@ -1965,6 +2009,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); @@ -1976,9 +2021,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); @@ -1992,9 +2038,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); @@ -2005,6 +2052,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) @@ -2034,6 +2082,7 @@ 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); @@ -2070,6 +2119,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) @@ -2085,16 +2135,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); @@ -2103,6 +2153,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); @@ -2115,6 +2166,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; @@ -2124,7 +2176,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); } } @@ -2132,6 +2184,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); @@ -2145,6 +2198,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) { void *state = NULL; pa_sink_assert_ref(s); + pa_sink_assert_io_context(s); if (!(s->flags & PA_SINK_DYNAMIC_LATENCY)) return; @@ -2156,7 +2210,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) { 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); } @@ -2165,6 +2219,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 @@ -2199,6 +2254,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); @@ -2220,6 +2276,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_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); @@ -2236,7 +2293,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, 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) if (i->update_sink_latency_range) i->update_sink_latency_range(i); } @@ -2249,7 +2306,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, /* Called from main thread, before the sink is put */ 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 (latency < ABSOLUTE_MIN_LATENCY) @@ -2266,6 +2323,7 @@ void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) { 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; @@ -2279,6 +2337,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; @@ -2292,7 +2351,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); @@ -2323,7 +2383,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; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 7a8cdaf1..13033960 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -42,6 +42,7 @@ typedef struct pa_device_port pa_device_port; #include #include #include +#include #define PA_MAX_INPUTS_PER_SINK 32 @@ -343,4 +344,10 @@ 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 diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 4ba25ae4..fdc00e15 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -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(); @@ -111,6 +111,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); @@ -262,6 +263,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 +277,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 +297,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 +350,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 +376,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 +402,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 +413,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 +433,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 +509,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)); @@ -528,6 +539,7 @@ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in so /* 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,6 +550,7 @@ 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; @@ -554,6 +567,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); @@ -582,6 +596,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 +613,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 +622,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 +640,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 +665,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 +679,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 +687,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 +729,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 +761,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); @@ -820,6 +843,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav 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); @@ -850,6 +874,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 +931,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) diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 9824e160..7b32c866 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -277,4 +277,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 diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index b8af148f..97a20b91 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -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); @@ -297,6 +299,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; @@ -348,6 +351,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) { /* 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); @@ -382,6 +386,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 +428,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)) @@ -460,6 +466,7 @@ static void source_free(pa_object *o) { /* Called from main context */ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { + pa_assert_ctl_context(); pa_source_assert_ref(s); s->asyncmsgq = q; @@ -467,6 +474,7 @@ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { /* Called from main context */ void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) { + pa_assert_ctl_context(); pa_source_assert_ref(s); s->rtpoll = p; @@ -475,6 +483,7 @@ void pa_source_set_rtpoll(pa_source *s, pa_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 +495,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 +523,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 +543,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,6 +568,7 @@ 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); @@ -572,6 +585,8 @@ 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)))) { @@ -590,6 +605,7 @@ 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 (nbytes <= 0) @@ -612,6 +628,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 +668,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 +700,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 +720,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 +747,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 +773,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 +785,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) { @@ -785,6 +808,8 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) { /* Called from main thread */ 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 */ @@ -802,6 +827,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 +846,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) { @@ -846,6 +873,8 @@ 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_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 */ @@ -861,6 +890,7 @@ void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) { /* 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 +904,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 +933,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 +944,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 +959,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; @@ -1120,6 +1155,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 +1174,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 +1183,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 +1195,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 +1209,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,6 +1224,7 @@ 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); @@ -1214,6 +1255,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 +1272,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); @@ -1258,6 +1301,7 @@ void pa_source_invalidate_requested_latency(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; @@ -1281,6 +1325,7 @@ void pa_source_invalidate_requested_latency(pa_source *s) { /* 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 +1360,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); @@ -1336,6 +1382,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten 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); @@ -1364,6 +1411,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten /* 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); @@ -1379,6 +1427,7 @@ void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) { /* 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 +1443,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; } diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index d22e7ca5..001122bc 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -43,6 +43,7 @@ typedef struct pa_source pa_source; #include #include #include +#include #define PA_MAX_OUTPUTS_PER_SOURCE 32 @@ -295,4 +296,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten void pa_source_invalidate_requested_latency(pa_source *s); 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 diff --git a/src/pulsecore/thread-mq.h b/src/pulsecore/thread-mq.h index 3b5e0e78..96839d25 100644 --- a/src/pulsecore/thread-mq.h +++ b/src/pulsecore/thread-mq.h @@ -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 -- cgit From 5ee4069e9e68f81a71d208bb720d0c6bc6112fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Aug 2009 02:17:24 +0200 Subject: core: add functions to query max_rewind/max_request values from streams --- src/pulsecore/sink-input.c | 19 +++++++++++++++++++ src/pulsecore/sink-input.h | 4 ++++ src/pulsecore/source-output.c | 8 ++++++++ src/pulsecore/source-output.h | 2 ++ 4 files changed, 33 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index c7837298..1f67d0fb 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -802,6 +802,25 @@ 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); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 5ede1ca8..cd424e87 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -303,6 +303,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 */ diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index fdc00e15..5d79dbbb 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -536,6 +536,14 @@ 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); diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 7b32c866..4bf88ca4 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -238,6 +238,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 */ -- cgit From b0cabfe16b5e44ec44828ad342ae5a48dedcc6e6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:14:35 +0200 Subject: shm: bump shm size limit to 1GB --- src/pulsecore/shm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 6e428426..fbf777a4 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -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 -- cgit From a42c597f0aef863ee38065c52fbe60d382f9d5e8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:16:28 +0200 Subject: memblockq: add pa_memblockq_get_maxrewind() API --- src/pulsecore/memblockq.c | 6 ++++++ src/pulsecore/memblockq.h | 3 +++ 2 files changed, 9 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 77f9efc9..32758be3 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -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); diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 146d261b..587c364b 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -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); -- cgit From 446fb2c9fea4f9c3f268868547f5f11c287ecba0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:17:48 +0200 Subject: asyncmsgq: add pa_asyncmsgq_flush() call --- src/pulsecore/asyncmsgq.c | 36 ++++++++++++++++++++++++++++++++---- src/pulsecore/asyncmsgq.h | 2 ++ 2 files changed, 34 insertions(+), 4 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c index 083d9de2..36721406 100644 --- a/src/pulsecore/asyncmsgq.c +++ b/src/pulsecore/asyncmsgq.c @@ -26,14 +26,16 @@ #include #include +#include + #include +#include #include #include #include #include #include #include -#include #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); @@ -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,29 @@ 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); + } +} diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h index 1f38207a..26f528f6 100644 --- a/src/pulsecore/asyncmsgq.h +++ b/src/pulsecore/asyncmsgq.h @@ -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); -- cgit From 9e21182e018db8755dea6368eed93a1a2b93f6f7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:18:23 +0200 Subject: thread-mq: never drop queued messages for the main loop Previously we might have dropped messages from IO trheads to the main thread. This tuend out to be problematic since this cause SHM release messages to be lost. More visibly however this could cause playback freezing when moving streams between sinks and removing the old sink right away. --- src/pulsecore/thread-mq.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c index 34f92a7e..ec67ae87 100644 --- a/src/pulsecore/thread-mq.c +++ b/src/pulsecore/thread-mq.c @@ -104,6 +104,13 @@ 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. */ + + 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; -- cgit From fecd0dc801b0f4c9a929fb7ef00f4bd7f0e3d06c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 04:21:09 +0200 Subject: resampler: round up when estimating input/output sizes --- src/pulsecore/resampler.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 17fb8480..59e0a0c1 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -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) { -- cgit From 72d2540e8dc47e101ac9d5ae24eee1b95e8dbcfa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Aug 2009 19:31:05 +0200 Subject: protocol-native: log explicitly each time a client triggers a volume change --- src/pulsecore/protocol-native.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 9a37c565..03372204 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -3323,6 +3323,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); @@ -3369,12 +3370,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("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("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("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); } -- cgit From 0989be13f6b5f71872f381fe2b5a7379702f20bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:03:50 +0200 Subject: core: introduce pa_{sink_input|source_output}_fail_move() --- src/pulsecore/sink-input.c | 19 +++++++++++++++++++ src/pulsecore/sink-input.h | 5 ++++- src/pulsecore/sink.c | 8 +++----- src/pulsecore/source-output.c | 19 +++++++++++++++++++ src/pulsecore/source-output.h | 5 ++++- src/pulsecore/source.c | 8 +++----- 6 files changed, 52 insertions(+), 12 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 1f67d0fb..3a9915f0 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1317,6 +1317,24 @@ 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; @@ -1341,6 +1359,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; } diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index cd424e87..9088d6a1 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -159,7 +159,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 @@ -337,6 +339,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); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index edcf5bdd..65c6374b 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -649,7 +649,7 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) { 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); } @@ -665,10 +665,8 @@ void pa_sink_move_all_fail(pa_queue *q) { 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); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 5d79dbbb..8cb361c9 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -846,6 +846,24 @@ 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; @@ -870,6 +888,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; } diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 4bf88ca4..6e3475a6 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -127,7 +127,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 @@ -262,6 +264,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) diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 97a20b91..5731663b 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -574,7 +574,7 @@ void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) { 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); } @@ -590,10 +590,8 @@ void pa_source_move_all_fail(pa_queue *q) { 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); -- cgit From e53d2fc6b57f90d937f2680fa56461d4042de87a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:05:17 +0200 Subject: native: handle moving() callback with NULL destination properly --- src/pulsecore/protocol-native.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 03372204..a6124788 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.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; @@ -1143,7 +1144,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; @@ -1617,6 +1617,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 +1755,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); -- cgit From e4db56bf0763abaaa34796f5b0234b3cd2cf4d3c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:12:53 +0200 Subject: core: split of FAIL_ON_SUSPEND into KILL_ON_SUSPEND and NO_CREATE_ON_SUSPEND --- src/pulsecore/cli-text.c | 10 ++++++---- src/pulsecore/protocol-native.c | 4 ++-- src/pulsecore/sink-input.c | 2 +- src/pulsecore/sink-input.h | 3 ++- src/pulsecore/sink.c | 4 ++-- src/pulsecore/source-output.c | 2 +- src/pulsecore/source-output.h | 3 ++- src/pulsecore/source.c | 5 ++--- 8 files changed, 18 insertions(+), 15 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index 9395513d..ace5e719 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -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), diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index a6124788..b6989aec 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1957,7 +1957,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 */ @@ -2213,7 +2213,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); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 3a9915f0..1b3ea92d 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -221,7 +221,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; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 9088d6a1..c1f8082c 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -58,7 +58,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 { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 65c6374b..90c9d85d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -398,9 +398,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); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 8cb361c9..2b3a0c58 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -167,7 +167,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; diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 6e3475a6..b78a02b9 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -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 { diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 5731663b..a44275c0 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -336,15 +336,14 @@ 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; } -- cgit From 58d441f7ea7994d5a0e8bc5397e2986707eb466b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:16:25 +0200 Subject: log: place more rate limit invocations --- src/pulsecore/protocol-native.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index b6989aec..b578746e 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1345,7 +1345,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); } -- cgit From 4eb59fb90e474a81f2d626bc4fc7db083fafed7a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:26:00 +0200 Subject: core: move rtpoll to thread_info sub structure --- src/pulsecore/sink.c | 11 +++++------ src/pulsecore/sink.h | 3 ++- src/pulsecore/source.c | 9 ++++----- src/pulsecore/source.h | 3 ++- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 90c9d85d..1f9a9797 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -262,7 +262,6 @@ pa_sink* pa_sink_new( s->userdata = NULL; s->asyncmsgq = NULL; - s->rtpoll = NULL; /* As a minor optimization we just steal the list instead of * copying it here */ @@ -295,6 +294,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; @@ -421,7 +421,6 @@ void pa_sink_put(pa_sink* s) { /* 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 @@ -563,12 +562,12 @@ 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 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_assert_ctl_context(); + 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); @@ -1184,7 +1183,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; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 13033960..33145df3 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -102,7 +102,6 @@ struct pa_sink { pa_bool_t save_muted:1; pa_asyncmsgq *asyncmsgq; - pa_rtpoll *rtpoll; pa_memchunk silence; @@ -156,6 +155,8 @@ struct pa_sink { pa_sink_state_t state; pa_hashmap *inputs; + pa_rtpoll *rtpoll; + pa_cvolume soft_volume; pa_bool_t soft_muted:1; diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index a44275c0..028d6795 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -232,7 +232,6 @@ pa_source* pa_source_new( s->userdata = NULL; s->asyncmsgq = NULL; - s->rtpoll = NULL; /* As a minor optimization we just steal the list instead of * copying it here */ @@ -265,6 +264,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; @@ -356,7 +356,6 @@ void pa_source_put(pa_source *s) { /* 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 @@ -465,18 +464,18 @@ static void source_free(pa_object *o) { /* Called from main context */ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { - pa_assert_ctl_context(); pa_source_assert_ref(s); + pa_assert_ctl_context(); s->asyncmsgq = q; } /* Called from main context */ void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) { - pa_assert_ctl_context(); pa_source_assert_ref(s); + pa_source_assert_io_context(s); - s->rtpoll = p; + s->thread_info.rtpoll = p; } /* Called from main context */ diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 001122bc..6c0a2903 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -90,7 +90,6 @@ struct pa_source { pa_bool_t save_muted:1; pa_asyncmsgq *asyncmsgq; - pa_rtpoll *rtpoll; pa_memchunk silence; @@ -140,6 +139,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; -- cgit From 350a2bc846559bb274ba70f928bb42a9472050bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:48:14 +0200 Subject: core: make fixed latency dynamically changeable This of course makes the name 'fixed' a bit of a misnomer. However the definitions are now like this: fixed latency: the latency may change during runtime, but is solely controlled by the backend, the client has no influence. dynamic latency: the latency may change during runtime, influenced by the requests of the clients. i.e. fixed vs. dynamic is from the perspective of the client. --- src/pulsecore/cli-text.c | 4 +- src/pulsecore/sink-input.c | 7 +-- src/pulsecore/sink-input.h | 4 ++ src/pulsecore/sink.c | 101 +++++++++++++++++++++++++++++++++++------- src/pulsecore/sink.h | 18 ++++++-- src/pulsecore/source-output.c | 7 +-- src/pulsecore/source-output.h | 4 ++ src/pulsecore/source.c | 101 ++++++++++++++++++++++++++++++++++-------- src/pulsecore/source.h | 14 ++++-- 9 files changed, 210 insertions(+), 50 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index ace5e719..a5530991 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -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); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 1b3ea92d..f6d9ac73 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -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; @@ -851,13 +852,13 @@ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa 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; } @@ -877,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; diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index c1f8082c..c1820830 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -138,6 +138,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 diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 1f9a9797..fd95f75d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -256,8 +256,6 @@ 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; @@ -307,6 +305,7 @@ 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; pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0); @@ -349,6 +348,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; @@ -438,11 +438,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); @@ -1748,7 +1748,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 @@ -1794,7 +1794,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); @@ -1946,6 +1946,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; @@ -2082,13 +2092,12 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *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; @@ -2190,18 +2199,18 @@ 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) @@ -2295,16 +2304,20 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, 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; @@ -2312,10 +2325,64 @@ 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; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 33145df3..55bca7f4 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -105,8 +105,6 @@ struct pa_sink { 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; @@ -160,6 +158,9 @@ struct pa_sink { 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; @@ -175,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; @@ -202,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, @@ -282,6 +292,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); @@ -333,12 +344,13 @@ 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); diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index 2b3a0c58..3803a6cc 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -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; @@ -561,13 +562,13 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output 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; } @@ -587,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; diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index b78a02b9..a70a3fdb 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -109,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 */ diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 028d6795..8970d8e4 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -226,8 +226,6 @@ 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; @@ -274,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); @@ -370,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); @@ -1037,7 +1036,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; } @@ -1117,6 +1116,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; @@ -1223,13 +1232,12 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *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; @@ -1292,18 +1300,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) @@ -1315,7 +1323,7 @@ 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 */ @@ -1375,8 +1383,6 @@ 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); @@ -1390,18 +1396,23 @@ 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 */ @@ -1409,7 +1420,10 @@ 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; @@ -1417,7 +1431,58 @@ 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 */ diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index 6c0a2903..bb085a0b 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -93,8 +93,6 @@ struct pa_source { 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; @@ -153,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; }; @@ -175,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 @@ -250,6 +252,7 @@ int pa_source_sync_suspend(pa_source *s); 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); @@ -259,6 +262,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); @@ -290,11 +294,13 @@ 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) \ -- cgit From 3f9c67a7fb959acd35228f1e7455baf2aacc793b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:52:50 +0200 Subject: core: call pa_sink_get_latency_within_thread() instead of going directly via process_msg() --- src/pulsecore/sink.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index fd95f75d..e8268892 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1770,10 +1770,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); @@ -1832,10 +1829,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) -- cgit From c6080d8c61df4991b96f4f144e58848f6c440440 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:54:02 +0200 Subject: core: don't update latency range if not changed --- src/pulsecore/sink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index e8268892..77908c9a 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -2273,8 +2273,6 @@ 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); @@ -2287,11 +2285,16 @@ 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; PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) if (i->update_sink_latency_range) -- cgit From 3c271ae0605fcf1b6ca9ddfb21bda54a783e9926 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:54:25 +0200 Subject: core: document difference between IO and main thread view on requested latency --- src/pulsecore/sink.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 77908c9a..c1589f2d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1917,6 +1917,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; -- cgit From d7d86e32ddea61e93e39f55a9f7e91b8d696dfab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:54:51 +0200 Subject: native-protocol: downgrade volume change log messages --- src/pulsecore/protocol-native.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index b578746e..280707e2 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1131,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; @@ -3381,13 +3387,13 @@ static void command_set_volume( client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); if (sink) { - pa_log("Client %s changes volume of sink %s.", client_name, sink->name); + 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) { - pa_log("Client %s changes volume of sink %s.", client_name, source->name); + pa_log_debug("Client %s changes volume of sink %s.", client_name, source->name); pa_source_set_volume(source, &volume, TRUE); } else if (si) { - pa_log("Client %s changes volume of sink %s.", + 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); -- cgit From d9e4605e09e01cc64e3d37452ea0b5c2783a0085 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 00:55:31 +0200 Subject: hook-list: make use of PA_LLIST_FOREACH --- src/pulsecore/hook-list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c index a00116d1..d9b9917d 100644 --- a/src/pulsecore/hook-list.c +++ b/src/pulsecore/hook-list.c @@ -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; -- cgit From ea5cdcbe52e3e1ac6189fb6472fafe61fbfdd73c Mon Sep 17 00:00:00 2001 From: Juho Hämäläinen Date: Wed, 12 Aug 2009 18:30:14 +0300 Subject: database: simple hashmap based database implementation --- src/pulsecore/database-simple.c | 510 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100644 src/pulsecore/database-simple.c (limited to 'src/pulsecore') diff --git a/src/pulsecore/database-simple.c b/src/pulsecore/database-simple.c new file mode 100644 index 00000000..1f4caf71 --- /dev/null +++ b/src/pulsecore/database-simple.c @@ -0,0 +1,510 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Nokia Corporation + Contact: Maemo Multimedia + + 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 +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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; +} -- cgit From 0c08dbd9b926ec94084dd47069627ed6eda1c1d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 03:41:13 +0200 Subject: core: introduce pa_{sink|source}_update_flags() --- src/pulsecore/sink.c | 22 +++++++++++++++++++++- src/pulsecore/sink.h | 2 ++ src/pulsecore/source.c | 18 ++++++++++++++++-- src/pulsecore/source.h | 2 ++ 4 files changed, 41 insertions(+), 3 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index c1589f2d..c79aa79d 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -551,7 +551,7 @@ 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(); @@ -562,6 +562,26 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) { pa_source_set_asyncmsgq(s->monitor_source, q); } +/* 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); diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 55bca7f4..3cd7e59d 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -282,6 +282,8 @@ 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); 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); pa_bool_t pa_device_init_intended_roles(pa_proplist *p); diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 8970d8e4..46f049ef 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -461,7 +461,7 @@ 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(); @@ -469,7 +469,21 @@ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) { 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); diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index bb085a0b..6f33de06 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -246,6 +246,8 @@ 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! */ -- cgit From 0c20e740f64bac462463552c0b7e056848b78836 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 22:22:57 +0200 Subject: asyncmsgq: introduce pa_asyncmsgq_dispatching() --- src/pulsecore/asyncmsgq.c | 6 ++++++ src/pulsecore/asyncmsgq.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c index 36721406..b0804f79 100644 --- a/src/pulsecore/asyncmsgq.c +++ b/src/pulsecore/asyncmsgq.c @@ -351,3 +351,9 @@ void pa_asyncmsgq_flush(pa_asyncmsgq *a, pa_bool_t run) { pa_asyncmsgq_unref(a); } } + +pa_bool_t pa_asyncmsgq_dispatching(pa_asyncmsgq *a) { + pa_assert(PA_REFCNT_VALUE(a) > 0); + + return !!a->current; +} diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h index 26f528f6..1085c2f0 100644 --- a/src/pulsecore/asyncmsgq.h +++ b/src/pulsecore/asyncmsgq.h @@ -78,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 -- cgit From 011add1c838f65e87a7abaec2792f510d3b0bb20 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Aug 2009 22:23:42 +0200 Subject: thread-mq: do final q flush only when we aren't dispatching anyway --- src/pulsecore/thread-mq.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c index ec67ae87..73997a74 100644 --- a/src/pulsecore/thread-mq.c +++ b/src/pulsecore/thread-mq.c @@ -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); @@ -107,9 +107,11 @@ void pa_thread_mq_done(pa_thread_mq *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. */ + * msgs, other stuff). Hence do so if we aren't currently + * dispatching anyway. */ - pa_asyncmsgq_flush(q->outq, TRUE); + 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); -- cgit From 4c29ba9c332dd682ced5ed668aede16aa5861128 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Aug 2009 00:45:23 +0200 Subject: modules: add various checks to avoid selecting objects that are not linked or in another unclear state --- src/pulsecore/namereg.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'src/pulsecore') diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 9df2f583..e26923d4 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -223,6 +223,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); @@ -234,6 +237,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); @@ -244,14 +250,19 @@ pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) { pa_sink *pa_namereg_get_default_sink(pa_core *c) { pa_sink *s; + uint32_t idx; pa_assert(c); - if (c->default_sink) + if (c->default_sink && PA_SINK_IS_LINKED(pa_sink_get_state(c->default_sink))) return c->default_sink; - if ((s = pa_idxset_first(c->sinks, NULL))) - return pa_namereg_set_default_sink(c, s); + /* 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 NULL; } @@ -262,15 +273,18 @@ pa_source *pa_namereg_get_default_source(pa_core *c) { pa_assert(c); - if (c->default_source) + if (c->default_source && PA_SOURCE_IS_LINKED(pa_source_get_state(c->default_source))) return c->default_source; - for (s = PA_SOURCE(pa_idxset_first(c->sources, &idx)); s; s = PA_SOURCE(pa_idxset_next(c->sources, &idx))) - if (!s->monitor_of) + /* 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); - if ((s = pa_idxset_first(c->sources, NULL))) - 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 NULL; } -- cgit From 8dd0d871a7dd2d97c63ec8e38e1b408637d1b639 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Aug 2009 00:45:56 +0200 Subject: core: add to FIXMEs --- src/pulsecore/sink-input.h | 1 + src/pulsecore/sink.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index c1820830..b5502c45 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -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) { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index c79aa79d..717584f2 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -307,6 +307,7 @@ pa_sink* pa_sink_new( 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) -- cgit From 01e4b61a910afdd21f860fadbe98075735c2bf51 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Aug 2009 02:02:51 +0200 Subject: aupdate: implicitly call _write_swap() if it wasn't called explicitly --- src/pulsecore/aupdate.c | 8 ++++++++ src/pulsecore/aupdate.h | 4 ++++ 2 files changed, 12 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/aupdate.c b/src/pulsecore/aupdate.c index 56ebb8e5..85b6e00e 100644 --- a/src/pulsecore/aupdate.c +++ b/src/pulsecore/aupdate.c @@ -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); } diff --git a/src/pulsecore/aupdate.h b/src/pulsecore/aupdate.h index 072e382d..fb38ffa2 100644 --- a/src/pulsecore/aupdate.h +++ b/src/pulsecore/aupdate.h @@ -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 -- cgit