diff options
Diffstat (limited to 'src/pulsecore')
79 files changed, 2648 insertions, 1081 deletions
diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c index 03e9f0df..f64931a5 100644 --- a/src/pulsecore/asyncq.c +++ b/src/pulsecore/asyncq.c @@ -71,7 +71,7 @@ PA_STATIC_FLIST_DECLARE(localq, 0, pa_xfree); #define PA_ASYNCQ_CELLS(x) ((pa_atomic_ptr_t*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_asyncq)))) -static int reduce(pa_asyncq *l, int value) { +static unsigned reduce(pa_asyncq *l, unsigned value) { return value & (unsigned) (l->size - 1); } @@ -132,7 +132,7 @@ void pa_asyncq_free(pa_asyncq *l, pa_free_cb_t free_cb) { } static int push(pa_asyncq*l, void *p, pa_bool_t wait) { - int idx; + unsigned idx; pa_atomic_ptr_t *cells; pa_assert(l); @@ -220,7 +220,7 @@ void pa_asyncq_post(pa_asyncq*l, void *p) { } void* pa_asyncq_pop(pa_asyncq*l, pa_bool_t wait) { - int idx; + unsigned idx; void *ret; pa_atomic_ptr_t *cells; @@ -263,7 +263,7 @@ int pa_asyncq_read_fd(pa_asyncq *q) { } int pa_asyncq_read_before_poll(pa_asyncq *l) { - int idx; + unsigned idx; pa_atomic_ptr_t *cells; pa_assert(l); @@ -280,8 +280,6 @@ int pa_asyncq_read_before_poll(pa_asyncq *l) { if (pa_fdsem_before_poll(l->write_fdsem) >= 0) return 0; } - - return 0; } void pa_asyncq_read_after_poll(pa_asyncq *l) { diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h index a91c4d56..9c58c661 100644 --- a/src/pulsecore/atomic.h +++ b/src/pulsecore/atomic.h @@ -23,6 +23,8 @@ USA. ***/ +#include <pulsecore/macro.h> + /* * atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*). It is * not guaranteed however, that sizeof(AO_t) == sizeof(size_t). @@ -35,7 +37,7 @@ * On gcc >= 4.1 we use the builtin atomic functions. otherwise we use * libatomic_ops */ -# + #ifndef PACKAGE #error "Please include config.h before including this file!" #endif @@ -80,8 +82,8 @@ static inline int pa_atomic_dec(pa_atomic_t *a) { return pa_atomic_sub(a, 1); } -/* Returns non-zero when the operation was successful. */ -static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { +/* Returns TRUE when the operation was successful. */ +static inline pa_bool_t pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { return __sync_bool_compare_and_swap(&a->value, old_i, new_i); } @@ -101,13 +103,13 @@ static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { __sync_synchronize(); } -static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { +static inline pa_bool_t pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { return __sync_bool_compare_and_swap(&a->value, (long) old_p, (long) new_p); } #elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__)) -#error "The native atomic operations implementation for AMD64 has not been tested. libatomic_ops is known to not work properly on AMD64 and your gcc version is too old for the gcc-builtin atomic ops support. You have three options now: make the native atomic operations implementation for AMD64 work, fix libatomic_ops, or upgrade your GCC." +#warn "The native atomic operations implementation for AMD64 has not been tested thoroughly. libatomic_ops is known to not work properly on AMD64 and your gcc version is too old for the gcc-builtin atomic ops support. You have three options now: test the native atomic operations implementation for AMD64, fix libatomic_ops, or upgrade your GCC." /* Addapted from glibc */ @@ -147,14 +149,14 @@ static inline int pa_atomic_dec(pa_atomic_t *a) { return pa_atomic_sub(a, 1); } -static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { +static inline pa_bool_t pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { int result; __asm__ __volatile__ ("lock; cmpxchgl %2, %1" : "=a" (result), "=m" (a->value) : "r" (new_i), "m" (a->value), "0" (old_i)); - return result == oldval; + return result == old_i; } typedef struct pa_atomic_ptr { @@ -171,14 +173,14 @@ static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { a->value = (unsigned long) p; } -static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { +static inline pa_bool_t pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { void *result; __asm__ __volatile__ ("lock; cmpxchgq %q2, %1" : "=a" (result), "=m" (a->value) : "r" (new_p), "m" (a->value), "0" (old_p)); - return result; + return result == old_p; } #elif defined(ATOMIC_ARM_INLINE_ASM) @@ -255,7 +257,7 @@ static inline int pa_atomic_dec(pa_atomic_t *a) { return pa_atomic_sub(a, 1); } -static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { +static inline pa_bool_t pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { unsigned long not_equal, not_exclusive; pa_memory_barrier(); @@ -289,7 +291,7 @@ static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { pa_memory_barrier(); } -static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { +static inline pa_bool_t pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { unsigned long not_equal, not_exclusive; pa_memory_barrier(); @@ -377,8 +379,8 @@ static inline int pa_atomic_dec(pa_atomic_t *a) { return pa_atomic_sub(a, 1); } -/* Returns non-zero when the operation was successful. */ -static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { +/* Returns TRUE when the operation was successful. */ +static inline pa_bool_t pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { pa_bool_t failed; do { failed = !!__kernel_cmpxchg(old_i, new_i, &a->value); @@ -402,7 +404,7 @@ static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { pa_memory_barrier(); } -static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { +static inline pa_bool_t pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { pa_bool_t failed; do { failed = !!__kernel_cmpxchg_u((unsigned long) old_p, (unsigned long) new_p, &a->value); @@ -420,7 +422,7 @@ typedef struct pa_atomic { volatile AO_t value; } pa_atomic_t; -#define PA_ATOMIC_INIT(v) { .value = (v) } +#define PA_ATOMIC_INIT(v) { .value = (AO_t) (v) } static inline int pa_atomic_load(const pa_atomic_t *a) { return (int) AO_load_full((AO_t*) &a->value); @@ -431,23 +433,23 @@ static inline void pa_atomic_store(pa_atomic_t *a, int i) { } static inline int pa_atomic_add(pa_atomic_t *a, int i) { - return AO_fetch_and_add_full(&a->value, (AO_t) i); + return (int) AO_fetch_and_add_full(&a->value, (AO_t) i); } static inline int pa_atomic_sub(pa_atomic_t *a, int i) { - return AO_fetch_and_add_full(&a->value, (AO_t) -i); + return (int) AO_fetch_and_add_full(&a->value, (AO_t) -i); } static inline int pa_atomic_inc(pa_atomic_t *a) { - return AO_fetch_and_add1_full(&a->value); + return (int) AO_fetch_and_add1_full(&a->value); } static inline int pa_atomic_dec(pa_atomic_t *a) { - return AO_fetch_and_sub1_full(&a->value); + return (int) AO_fetch_and_sub1_full(&a->value); } -static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { - return AO_compare_and_swap_full(&a->value, old_i, new_i); +static inline pa_bool_t pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) { + return AO_compare_and_swap_full(&a->value, (unsigned long) old_i, (unsigned long) new_i); } typedef struct pa_atomic_ptr { @@ -464,7 +466,7 @@ static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) { AO_store_full(&a->value, (AO_t) p); } -static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { +static inline pa_bool_t pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) { return AO_compare_and_swap_full(&a->value, (AO_t) old_p, (AO_t) new_p); } diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c index f3f40f80..b122feee 100644 --- a/src/pulsecore/authkey.c +++ b/src/pulsecore/authkey.c @@ -54,8 +54,8 @@ static int generate(int fd, void *ret_data, size_t length) { pa_random(ret_data, length); - lseek(fd, 0, SEEK_SET); - (void) ftruncate(fd, 0); + lseek(fd, (off_t) 0, SEEK_SET); + (void) ftruncate(fd, (off_t) 0); if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) { pa_log("Failed to write cookie file: %s", pa_cstrerror(errno)); @@ -88,7 +88,7 @@ static int load(const char *fn, void *data, size_t length) { if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) { if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY|O_NOCTTY)) < 0) { - pa_log("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } else writable = 0; @@ -105,7 +105,7 @@ static int load(const char *fn, void *data, size_t length) { pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length); if (!writable) { - pa_log("Unable to write cookie to read only file"); + pa_log_warn("Unable to write cookie to read-only file"); goto finish; } @@ -140,7 +140,7 @@ int pa_authkey_load(const char *path, void *data, size_t length) { pa_assert(length > 0); if ((ret = load(path, data, length)) < 0) - pa_log("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt"); + pa_log_warn("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt"); return ret; } @@ -206,7 +206,7 @@ int pa_authkey_save(const char *fn, const void *data, size_t length) { return -2; if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) { - pa_log("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); + pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno)); goto finish; } diff --git a/src/pulsecore/autoload.c b/src/pulsecore/autoload.c index 26c294b2..8c84cee5 100644 --- a/src/pulsecore/autoload.c +++ b/src/pulsecore/autoload.c @@ -158,7 +158,7 @@ void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { e->in_action = 0; } -static void free_func(void *p, PA_GCC_UNUSED void *userdata) { +static void free_func(void *p, void *userdata) { pa_autoload_entry *e = p; pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL); entry_free(e); diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index a80933fa..b5ff98db 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -117,6 +117,10 @@ static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); +static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail); /* A method table for all available commands */ @@ -167,6 +171,10 @@ static const struct command commands[] = { { "suspend-sink", pa_cli_command_suspend_sink, "Suspend sink (args: index|name, bool)", 3}, { "suspend-source", pa_cli_command_suspend_source, "Suspend source (args: index|name, bool)", 3}, { "suspend", pa_cli_command_suspend, "Suspend all sinks and all sources (args: bool)", 2}, + { "set-log-level", pa_cli_command_log_level, "Change the log level (args: numeric level)", 2}, + { "set-log-meta", pa_cli_command_log_meta, "Show source code location in log messages (args: bool)", 2}, + { "set-log-time", pa_cli_command_log_time, "Show timestamps in log messages (args: bool)", 2}, + { "set-log-backtrace", pa_cli_command_log_backtrace, "Show bakctrace in log messages (args: frames)", 2}, { NULL, NULL, NULL, 0 } }; @@ -318,22 +326,22 @@ static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", (unsigned) pa_atomic_load(&stat->n_allocated), - pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->allocated_size))); + pa_bytes_snprint(s, sizeof(s), (unsigned) pa_atomic_load(&stat->allocated_size))); pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", (unsigned) pa_atomic_load(&stat->n_accumulated), - pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->accumulated_size))); + pa_bytes_snprint(s, sizeof(s), (unsigned) pa_atomic_load(&stat->accumulated_size))); pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n", (unsigned) pa_atomic_load(&stat->n_imported), - pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->imported_size))); + pa_bytes_snprint(s, sizeof(s), (unsigned) pa_atomic_load(&stat->imported_size))); pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n", (unsigned) pa_atomic_load(&stat->n_exported), - pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->exported_size))); + pa_bytes_snprint(s, sizeof(s), (unsigned) pa_atomic_load(&stat->exported_size))); pa_strbuf_printf(buf, "Total sample cache size: %s.\n", - pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c))); + pa_bytes_snprint(s, sizeof(s), (unsigned) pa_scache_total_size(c))); pa_strbuf_printf(buf, "Default sample spec: %s\n", pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec)); @@ -1203,6 +1211,102 @@ static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, p return 0; } +static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { + const char *m; + uint32_t level; + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + if (!(m = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a log level (0..4).\n"); + return -1; + } + + if (pa_atou(m, &level) < 0 || level >= PA_LOG_LEVEL_MAX) { + pa_strbuf_puts(buf, "Failed to parse log level.\n"); + return -1; + } + + pa_log_set_maximal_level(level); + + return 0; +} + +static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { + const char *m; + pa_bool_t b; + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + if (!(m = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a boolean.\n"); + return -1; + } + + if ((b = pa_parse_boolean(m)) < 0) { + pa_strbuf_puts(buf, "Failed to parse log meta switch.\n"); + return -1; + } + + pa_log_set_show_meta(b); + + return 0; +} + +static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { + const char *m; + pa_bool_t b; + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + if (!(m = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a boolean.\n"); + return -1; + } + + if ((b = pa_parse_boolean(m)) < 0) { + pa_strbuf_puts(buf, "Failed to parse log meta switch.\n"); + return -1; + } + + pa_log_set_show_time(b); + + return 0; +} + +static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { + const char *m; + uint32_t nframes; + + pa_core_assert_ref(c); + pa_assert(t); + pa_assert(buf); + pa_assert(fail); + + if (!(m = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a backtrace level.\n"); + return -1; + } + + if (pa_atou(m, &nframes) < 0 || nframes >= 1000) { + pa_strbuf_puts(buf, "Failed to parse backtrace level.\n"); + return -1; + } + + pa_log_set_show_backtrace(nframes); + + return 0; +} + static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) { pa_module *m; pa_sink *sink; @@ -1251,8 +1355,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b nl = 1; } - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink))); - pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink))); + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE))); + pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE))); pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED)); } @@ -1265,8 +1369,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b nl = 1; } - pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source))); - pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source))); + pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, FALSE))); + pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, FALSE))); pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(pa_source_get_state(source) == PA_SOURCE_SUSPENDED)); } diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c index c92fca20..7bbc2660 100644 --- a/src/pulsecore/cli-text.c +++ b/src/pulsecore/cli-text.c @@ -149,10 +149,12 @@ char *pa_sink_list_to_string(pa_core *c) { sink->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "", sink->flags & PA_SINK_LATENCY ? "LATENCY " : "", state_table[pa_sink_get_state(sink)], - pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)), - pa_yes_no(pa_sink_get_mute(sink)), - (double) pa_sink_get_latency(sink) / PA_USEC_PER_MSEC, - (double) pa_sink_get_requested_latency(sink) / PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC, + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)), + pa_yes_no(pa_sink_get_mute(sink, FALSE)), + (double) pa_sink_get_latency(sink) / (double) PA_USEC_PER_MSEC, + (double) pa_sink_get_requested_latency(sink) / (double) PA_USEC_PER_MSEC, + (double) min_latency / PA_USEC_PER_MSEC, + (double) max_latency / PA_USEC_PER_MSEC, (unsigned long) pa_sink_get_max_request(sink) / 1024, (unsigned long) pa_sink_get_max_rewind(sink) / 1024, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, @@ -222,10 +224,12 @@ char *pa_source_list_to_string(pa_core *c) { source->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "", source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "", state_table[pa_source_get_state(source)], - pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source)), - pa_yes_no(pa_source_get_mute(source)), + pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source, FALSE)), + pa_yes_no(pa_source_get_mute(source, FALSE)), (double) pa_source_get_latency(source) / PA_USEC_PER_MSEC, - (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC, + (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC, + (double) min_latency / PA_USEC_PER_MSEC, + (double) max_latency / PA_USEC_PER_MSEC, (unsigned long) pa_source_get_max_rewind(source) / 1024, pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map), @@ -411,7 +415,7 @@ char *pa_scache_list_to_string(pa_core *c) { if (e->memchunk.memblock) { pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map); - l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); + l = (double) e->memchunk.length / (double) pa_bytes_per_second(&e->sample_spec); } pa_strbuf_printf( diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c index 4aec45d7..ef6d6bb6 100644 --- a/src/pulsecore/conf-parser.c +++ b/src/pulsecore/conf-parser.c @@ -148,7 +148,7 @@ finish: return r; } -int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { +int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { int *i = data; int32_t k; @@ -166,7 +166,43 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, return 0; } -int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { +int pa_config_parse_unsigned(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + unsigned *u = data; + uint32_t k; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atou(rvalue, &k) < 0) { + pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); + return -1; + } + + *u = (unsigned) k; + return 0; +} + +int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { + size_t *i = data; + uint32_t k; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_atou(rvalue, &k) < 0) { + pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); + return -1; + } + + *i = (size_t) k; + return 0; +} + +int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { int k; pa_bool_t *b = data; @@ -185,7 +221,7 @@ int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue return 0; } -int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) { +int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) { char **s = data; pa_assert(filename); diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h index 7eb1fae2..48a0fd26 100644 --- a/src/pulsecore/conf-parser.h +++ b/src/pulsecore/conf-parser.h @@ -39,8 +39,10 @@ typedef struct pa_config_item { * NULL */ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata); -/* Generic parsers for integers, booleans and strings */ +/* Generic parsers for integers, size_t, booleans and strings */ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_unsigned(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); +int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata); diff --git a/src/pulsecore/core-scache.c b/src/pulsecore/core-scache.c index 75fa2ff1..1d080e11 100644 --- a/src/pulsecore/core-scache.c +++ b/src/pulsecore/core-scache.c @@ -63,7 +63,7 @@ #define UNLOAD_POLL_TIME 60 -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) { pa_core *c = userdata; struct timeval ntv; @@ -98,7 +98,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { pa_assert(c); pa_assert(name); - if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) { + if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, FALSE))) { if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); @@ -111,7 +111,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { } else { e = pa_xnew(pa_scache_entry, 1); - if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) { + if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, TRUE)) { pa_xfree(e); return NULL; } @@ -134,9 +134,9 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { e->lazy = FALSE; e->last_used_time = 0; - memset(&e->sample_spec, 0, sizeof(e->sample_spec)); + pa_sample_spec_init(&e->sample_spec); pa_channel_map_init(&e->channel_map); - pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); + pa_cvolume_init(&e->volume); pa_proplist_sets(e->proplist, PA_PROP_MEDIA_ROLE, "event"); @@ -159,10 +159,12 @@ int pa_scache_add_item( pa_assert(c); pa_assert(name); pa_assert(!ss || pa_sample_spec_valid(ss)); - pa_assert(!map || (pa_channel_map_valid(map) && ss && ss->channels == map->channels)); + pa_assert(!map || (pa_channel_map_valid(map) && ss && pa_channel_map_compatible(map, ss))); - if (ss && !map) + if (ss && !map) { pa_channel_map_init_extend(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT); + map = &tmap; + } if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX) return -1; @@ -170,12 +172,13 @@ int pa_scache_add_item( if (!(e = scache_add_item(c, name))) return -1; - memset(&e->sample_spec, 0, sizeof(e->sample_spec)); + pa_sample_spec_init(&e->sample_spec); pa_channel_map_init(&e->channel_map); + pa_cvolume_init(&e->volume); if (ss) { e->sample_spec = *ss; - e->volume.channels = e->sample_spec.channels; + pa_cvolume_reset(&e->volume, ss->channels); } if (map) @@ -282,7 +285,7 @@ int pa_scache_remove_item(pa_core *c, const char *name) { return 0; } -static void free_cb(void *p, PA_GCC_UNUSED void *userdata) { +static void free_cb(void *p, void *userdata) { pa_scache_entry *e = p; pa_assert(e); @@ -310,17 +313,21 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t pa_assert(name); pa_assert(sink); - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, FALSE))) return -1; if (e->lazy && !e->memchunk.memblock) { + pa_channel_map old_channel_map = e->channel_map; + if (pa_sound_file_load(c->mempool, e->filename, &e->sample_spec, &e->channel_map, &e->memchunk) < 0) return -1; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); - if (e->volume.channels > e->sample_spec.channels) - e->volume.channels = e->sample_spec.channels; + if (pa_cvolume_valid(&e->volume)) + pa_cvolume_remap(&e->volume, &old_channel_map, &e->channel_map); + else + pa_cvolume_reset(&e->volume, e->sample_spec.channels); } if (!e->memchunk.memblock) @@ -383,7 +390,7 @@ uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) { pa_assert(c); pa_assert(name); - if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) + if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, FALSE))) return PA_IDXSET_INVALID; return e->index; diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c index 6107002b..c70d8adc 100644 --- a/src/pulsecore/core-subscribe.c +++ b/src/pulsecore/core-subscribe.c @@ -42,7 +42,7 @@ struct pa_subscription { pa_core *core; - int dead; + pa_bool_t dead; pa_subscription_cb_t callback; void *userdata; @@ -72,7 +72,7 @@ pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_su s = pa_xnew(pa_subscription, 1); s->core = c; - s->dead = 0; + s->dead = FALSE; s->callback = callback; s->userdata = userdata; s->mask = m; @@ -86,7 +86,7 @@ void pa_subscription_free(pa_subscription*s) { pa_assert(s); pa_assert(!s->dead); - s->dead = 1; + s->dead = TRUE; sched_event(s->core); } @@ -145,7 +145,7 @@ static void dump_event(const char * prefix, pa_subscription_event*e) { [PA_SUBSCRIPTION_EVENT_REMOVE] = "REMOVE" }; - pa_log("%s event (%s|%s|%u)", + pa_log_debug("%s event (%s|%s|%u)", prefix, fac_table[e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK], type_table[e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK], @@ -234,7 +234,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i * entry in the queue. */ free_event(i); - pa_log_debug("dropped redundant event."); + pa_log_debug("Dropped redundant event due to remove event."); continue; } @@ -242,7 +242,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i /* This object has changed. If a "new" or "change" event for * this object is still in the queue we can exit. */ - pa_log_debug("dropped redundant event."); + pa_log_debug("Dropped redundant event due to change event."); return; } } diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index b2c91e45..dde34d7b 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -40,6 +40,9 @@ #include <sys/stat.h> #include <sys/time.h> #include <dirent.h> +#include <regex.h> +#include <langinfo.h> +#include <sys/utsname.h> #ifdef HAVE_STRTOF_L #include <locale.h> @@ -111,6 +114,8 @@ int pa_set_root(HANDLE handle) { strcpy(library_path, PULSE_ROOTENV "="); + /* FIXME: Needs to set errno */ + if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH)) return 0; @@ -168,7 +173,7 @@ void pa_make_fd_cloexec(int fd) { /** Creates a directory securely */ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { struct stat st; - int r; + int r, saved_errno; pa_assert(dir); @@ -220,7 +225,10 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { return 0; fail: + saved_errno = errno; rmdir(dir); + errno = saved_errno; + return -1; } @@ -230,6 +238,7 @@ char *pa_parent_dir(const char *fn) { if ((slash = (char*) pa_path_get_filename(dir)) == dir) { pa_xfree(dir); + errno = ENOENT; return NULL; } @@ -337,7 +346,7 @@ ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) { ret += r; data = (uint8_t*) data + r; - size -= r; + size -= (size_t) r; } return ret; @@ -368,7 +377,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { ret += r; data = (const uint8_t*) data + r; - size -= r; + size -= (size_t) r; } return ret; @@ -390,7 +399,15 @@ int pa_close(int fd) { } #endif - return close(fd); + for (;;) { + int r; + + if ((r = close(fd)) >= 0) + return r; + + if (errno != EINTR) + return r; + } } /* Print a warning messages in case that the given signal is not @@ -437,7 +454,7 @@ void pa_check_signal_is_blocked(int sig) { /* The following function is based on an example from the GNU libc * documentation. This function is similar to GNU's asprintf(). */ char *pa_sprintf_malloc(const char *format, ...) { - int size = 100; + size_t size = 100; char *c = NULL; pa_assert(format); @@ -454,11 +471,11 @@ char *pa_sprintf_malloc(const char *format, ...) { c[size-1] = 0; - if (r > -1 && r < size) + if (r > -1 && (size_t) r < size) return c; if (r > -1) /* glibc 2.1 */ - size = r+1; + size = (size_t) r+1; else /* glibc 2.0 */ size *= 2; } @@ -467,7 +484,7 @@ char *pa_sprintf_malloc(const char *format, ...) { /* Same as the previous function, but use a va_list instead of an * ellipsis */ char *pa_vsprintf_malloc(const char *format, va_list ap) { - int size = 100; + size_t size = 100; char *c = NULL; pa_assert(format); @@ -484,11 +501,11 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { c[size-1] = 0; - if (r > -1 && r < size) + if (r > -1 && (size_t) r < size) return c; if (r > -1) /* glibc 2.1 */ - size = r+1; + size = (size_t) r+1; else /* glibc 2.0 */ size *= 2; } @@ -546,6 +563,8 @@ int pa_make_realtime(int rtprio) { pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority); return 0; #else + + errno = ENOTSUP; return -1; #endif } @@ -653,6 +672,7 @@ int pa_raise_priority(int nice_level) { if (nice_level < 0) { if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) { pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError()); + errno = EPERM; return .-1; } else pa_log_info("Successfully gained high priority class."); @@ -679,15 +699,55 @@ void pa_reset_priority(void) { #endif } +static int match(const char *expr, const char *v) { + int k; + regex_t re; + int r; + + if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) { + errno = EINVAL; + return -1; + } + + if ((k = regexec(&re, v, 0, NULL, 0)) == 0) + r = 1; + else if (k == REG_NOMATCH) + r = 0; + else + r = -1; + + regfree(&re); + + if (r < 0) + errno = EINVAL; + + return r; +} + /* Try to parse a boolean string value.*/ int pa_parse_boolean(const char *v) { + const char *expr; + int r; pa_assert(v); + /* First we check language independant */ if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) return 1; else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) return 0; + /* And then we check language dependant */ + if ((expr = nl_langinfo(YESEXPR))) + if (expr[0]) + if ((r = match(expr, v)) > 0) + return 1; + + if ((expr = nl_langinfo(NOEXPR))) + if (expr[0]) + if ((r = match(expr, v)) > 0) + return 0; + + errno = EINVAL; return -1; } @@ -875,11 +935,18 @@ static int is_group(gid_t gid, const char *name) { #else n = -1; #endif - if (n < 0) n = 512; - data = pa_xmalloc(n); + if (n < 0) + n = 512; + + data = pa_xmalloc((size_t) n); + + errno = 0; + if (getgrgid_r(gid, &group, data, (size_t) n, &result) < 0 || !result) { + pa_log("getgrgid_r(%u): %s", (unsigned) gid, pa_cstrerror(errno)); + + if (!errno) + errno = ENOENT; - if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno)); goto finish; } @@ -890,8 +957,14 @@ finish: #else /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not * support getgrgid_r. */ + + errno = 0; if ((result = getgrgid(gid)) == NULL) { pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno)); + + if (!errno) + errno = ENOENT; + goto finish; } @@ -906,27 +979,32 @@ finish: /* Check the current user is member of the specified group */ int pa_own_uid_in_group(const char *name, gid_t *gid) { GETGROUPS_T *gids, tgid; - int n = sysconf(_SC_NGROUPS_MAX); - int r = -1, i; + long n = sysconf(_SC_NGROUPS_MAX); + int r = -1, i, k; pa_assert(n > 0); - gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); + gids = pa_xmalloc(sizeof(GETGROUPS_T) * (size_t) n); - if ((n = getgroups(n, gids)) < 0) { + if ((n = getgroups((int) n, gids)) < 0) { pa_log("getgroups(): %s", pa_cstrerror(errno)); goto finish; } for (i = 0; i < n; i++) { - if (is_group(gids[i], name) > 0) { + + if ((k = is_group(gids[i], name)) < 0) + goto finish; + else if (k > 0) { *gid = gids[i]; r = 1; goto finish; } } - if (is_group(tgid = getgid(), name) > 0) { + if ((k = is_group(tgid = getgid(), name)) < 0) + goto finish; + else if (k > 0) { *gid = tgid; r = 1; goto finish; @@ -949,18 +1027,25 @@ int pa_uid_in_group(uid_t uid, const char *name) { int r = -1; g_n = sysconf(_SC_GETGR_R_SIZE_MAX); - g_buf = pa_xmalloc(g_n); + g_buf = pa_xmalloc((size_t) g_n); p_n = sysconf(_SC_GETPW_R_SIZE_MAX); - p_buf = pa_xmalloc(p_n); + p_buf = pa_xmalloc((size_t) p_n); + + errno = 0; + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) { + + if (!errno) + errno = ENOENT; - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) goto finish; + } r = 0; for (i = gr->gr_mem; *i; i++) { struct passwd pwbuf, *pw; + errno = 0; if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) continue; @@ -985,10 +1070,16 @@ gid_t pa_get_gid_of_group(const char *name) { struct group grbuf, *gr; g_n = sysconf(_SC_GETGR_R_SIZE_MAX); - g_buf = pa_xmalloc(g_n); + g_buf = pa_xmalloc((size_t) g_n); + + errno = 0; + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) { + + if (!errno) + errno = ENOENT; - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) goto finish; + } ret = gr->gr_gid; @@ -1014,19 +1105,23 @@ int pa_check_in_group(gid_t g) { #else /* HAVE_GRP_H */ int pa_own_uid_in_group(const char *name, gid_t *gid) { + errno = ENOSUP; return -1; } int pa_uid_in_group(uid_t uid, const char *name) { + errno = ENOSUP; return -1; } gid_t pa_get_gid_of_group(const char *name) { + errno = ENOSUP; return (gid_t) -1; } int pa_check_in_group(gid_t g) { + errno = ENOSUP; return -1; } @@ -1040,7 +1135,7 @@ int pa_lock_fd(int fd, int b) { /* Try a R/W lock first */ - flock.l_type = b ? F_WRLCK : F_UNLCK; + flock.l_type = (short) (b ? F_WRLCK : F_UNLCK); flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; @@ -1067,6 +1162,8 @@ int pa_lock_fd(int fd, int b) { return 0; pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError()); + + /* FIXME: Needs to set errno! */ #endif return -1; @@ -1133,8 +1230,11 @@ int pa_lock_lockfile(const char *fn) { fail: - if (fd >= 0) + if (fd >= 0) { + int saved_errno = errno; pa_close(fd); + errno = saved_errno; + } return -1; } @@ -1180,6 +1280,7 @@ static char *get_pulse_home(void) { if (st.st_uid != getuid()) { pa_log_error("Home directory %s not ours.", h); + errno = EACCES; return NULL; } @@ -1199,7 +1300,7 @@ char *pa_get_state_dir(void) { /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same * dir then this will break. */ - if (pa_make_secure_dir(d, 0700, (pid_t) -1, (pid_t) -1) < 0) { + if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1) < 0) { pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); pa_xfree(d); return NULL; @@ -1214,31 +1315,43 @@ static char* make_random_dir(mode_t m) { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; - char fn[24] = "/tmp/pulse-"; + const char *tmpdir; + char *fn; + size_t pathlen; + + if (!(tmpdir = getenv("TMPDIR"))) + if (!(tmpdir = getenv("TMP"))) + if (!(tmpdir = getenv("TEMP"))) + tmpdir = getenv("TEMPDIR"); + + if (!tmpdir || !pa_is_path_absolute(tmpdir)) + tmpdir = "/tmp"; - fn[sizeof(fn)-1] = 0; + fn = pa_sprintf_malloc("%s/pulse-XXXXXXXXXXXX", tmpdir); + pathlen = strlen(fn); for (;;) { - unsigned i; + size_t i; int r; mode_t u; int saved_errno; - for (i = 11; i < sizeof(fn)-1; i++) + for (i = pathlen - 12; i < pathlen; i++) fn[i] = table[rand() % (sizeof(table)-1)]; u = umask((~m) & 0777); r = mkdir(fn, m); + saved_errno = errno; umask(u); + errno = saved_errno; if (r >= 0) - return pa_xstrdup(fn); - - errno = saved_errno; + return fn; if (errno != EEXIST) { pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno)); + pa_xfree(fn); return NULL; } } @@ -1269,6 +1382,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) { char *pa_get_runtime_dir(void) { char *d, *k = NULL, *p = NULL, *t = NULL, *mid; struct stat st; + mode_t m; /* The runtime directory shall contain dynamic data that needs NOT * to be kept accross reboots and is usuallly private to the user, @@ -1277,12 +1391,11 @@ char *pa_get_runtime_dir(void) { * this directory, we link it to a random subdir in /tmp, if it * was not explicitly configured. */ - if ((d = getenv("PULSE_RUNTIME_PATH"))) { - mode_t m; + m = pa_in_system_mode() ? 0755U : 0700U; - m = pa_in_system_mode() ? 0755 : 0700; + if ((d = getenv("PULSE_RUNTIME_PATH"))) { - if (pa_make_secure_dir(d, m, (pid_t) -1, (pid_t) -1) < 0) { + if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) { pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); goto fail; } @@ -1293,6 +1406,11 @@ char *pa_get_runtime_dir(void) { if (!(d = get_pulse_home())) goto fail; + if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) { + pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); + goto fail; + } + if (!(mid = pa_machine_id())) { pa_xfree(d); goto fail; @@ -1332,6 +1450,7 @@ char *pa_get_runtime_dir(void) { /* Make sure that this actually makes sense */ if (!pa_is_path_absolute(p)) { pa_log_error("Path %s in link %s is not absolute.", p, k); + errno = ENOENT; goto fail; } @@ -1423,6 +1542,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + /* FIXME: Needs to set errno! */ return NULL; fn = buf; #endif @@ -1453,6 +1573,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) { + /* FIXME: Needs to set errno! */ pa_xfree(lfn); return NULL; } @@ -1481,6 +1602,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + /* FIXME: Needs to set errno! */ return NULL; global = buf; #endif @@ -1492,9 +1614,9 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env return f; } - } else - errno = ENOENT; + } + errno = ENOENT; return NULL; } @@ -1511,6 +1633,7 @@ char *pa_find_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + /* FIXME: Needs to set errno! */ return NULL; fn = buf; #endif @@ -1536,6 +1659,7 @@ char *pa_find_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) { + /* FIXME: Needs to set errno! */ pa_xfree(lfn); return NULL; } @@ -1560,14 +1684,16 @@ char *pa_find_config_file(const char *global, const char *local, const char *env if (global) { #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + /* FIXME: Needs to set errno! */ return NULL; global = buf; #endif if (access(global, R_OK) == 0) return pa_xstrdup(global); - } else - errno = ENOENT; + } + + errno = ENOENT; return NULL; } @@ -1604,6 +1730,7 @@ static int hexc(char c) { if (c >= 'a' && c <= 'f') return c - 'a' + 10; + errno = EINVAL; return -1; } @@ -1742,11 +1869,16 @@ int pa_atoi(const char *s, int32_t *ret_i) { errno = 0; l = strtol(s, &x, 0); - if (!x || *x || errno != 0) + if (!x || *x || errno) { + if (!errno) + errno = EINVAL; return -1; + } - if ((int32_t) l != l) + if ((int32_t) l != l) { + errno = ERANGE; return -1; + } *ret_i = (int32_t) l; @@ -1764,11 +1896,16 @@ int pa_atou(const char *s, uint32_t *ret_u) { errno = 0; l = strtoul(s, &x, 0); - if (!x || *x || errno != 0) + if (!x || *x || errno) { + if (!errno) + errno = EINVAL; return -1; + } - if ((uint32_t) l != l) + if ((uint32_t) l != l) { + errno = ERANGE; return -1; + } *ret_u = (uint32_t) l; @@ -1786,7 +1923,6 @@ static void c_locale_destroy(void) { int pa_atod(const char *s, double *ret_d) { char *x = NULL; double f; - int r = 0; pa_assert(s); pa_assert(ret_d); @@ -1812,17 +1948,20 @@ int pa_atod(const char *s, double *ret_d) { f = strtod(s, &x); } - if (!x || *x || errno != 0) - r = -1; - else - *ret_d = f; + if (!x || *x || errno) { + if (!errno) + errno = EINVAL; + return -1; + } - return r; + *ret_d = f; + + return 0; } /* Same as snprintf, but guarantees NUL-termination on every platform */ -int pa_snprintf(char *str, size_t size, const char *format, ...) { - int ret; +size_t pa_snprintf(char *str, size_t size, const char *format, ...) { + size_t ret; va_list ap; pa_assert(str); @@ -1837,7 +1976,7 @@ int pa_snprintf(char *str, size_t size, const char *format, ...) { } /* Same as vsnprintf, but guarantees NUL-termination on every platform */ -int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) { +size_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int ret; pa_assert(str); @@ -1849,9 +1988,12 @@ int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) { str[size-1] = 0; if (ret < 0) - ret = strlen(str); + return strlen(str); - return PA_MIN((int) size-1, ret); + if ((size_t) ret > size-1) + return size-1; + + return (size_t) ret; } /* Truncate the specified string, but guarantee that the string @@ -1875,7 +2017,7 @@ char *pa_getcwd(void) { size_t l = 128; for (;;) { - char *p = pa_xnew(char, l); + char *p = pa_xmalloc(l); if (getcwd(p, l)) return p; @@ -1900,7 +2042,7 @@ void *pa_will_need(const void *p, size_t l) { pa_assert(l > 0); a = PA_PAGE_ALIGN_PTR(p); - size = (const uint8_t*) p + l - (const uint8_t*) a; + size = (size_t) ((const uint8_t*) p + l - (const uint8_t*) a); #ifdef HAVE_POSIX_MADVISE if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) { @@ -1921,10 +2063,11 @@ void *pa_will_need(const void *p, size_t l) { if (rlim.rlim_cur < PA_PAGE_SIZE) { pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r)); + errno = EPERM; return (void*) p; } - bs = PA_PAGE_ALIGN(rlim.rlim_cur); + bs = PA_PAGE_ALIGN((size_t) rlim.rlim_cur); #else bs = PA_PAGE_SIZE*4; #endif @@ -1976,7 +2119,7 @@ char *pa_readlink(const char *p) { char *c; ssize_t n; - c = pa_xnew(char, l); + c = pa_xmalloc(l); if ((n = readlink(p, c, l-1)) < 0) { pa_xfree(c); @@ -1995,8 +2138,8 @@ char *pa_readlink(const char *p) { int pa_close_all(int except_fd, ...) { va_list ap; - int n = 0, i, r; - int *p; + unsigned n = 0, i; + int r, *p; va_start(ap, except_fd); @@ -2123,8 +2266,8 @@ int pa_close_allv(const int except_fds[]) { int pa_unblock_sigs(int except, ...) { va_list ap; - int n = 0, i, r; - int *p; + unsigned n = 0, i; + int r, *p; va_start(ap, except); @@ -2172,8 +2315,8 @@ int pa_unblock_sigsv(const int except[]) { int pa_reset_sigs(int except, ...) { va_list ap; - int n = 0, i, r; - int *p; + unsigned n = 0, i; + int *p, r; va_start(ap, except); @@ -2208,7 +2351,7 @@ int pa_reset_sigs(int except, ...) { int pa_reset_sigsv(const int except[]) { int sig; - for (sig = 1; sig < _NSIG; sig++) { + for (sig = 1; sig < NSIG; sig++) { pa_bool_t reset = TRUE; switch (sig) { @@ -2266,36 +2409,48 @@ char *pa_machine_id(void) { FILE *f; size_t l; + /* The returned value is supposed be some kind of ascii identifier + * that is unique and stable across reboots. */ + + /* First we try the D-Bus UUID, which is the best option we have, + * since it fits perfectly our needs and is not as volatile as the + * hostname which might be set from dhcp. */ + if ((f = fopen(PA_MACHINE_ID, "r"))) { char ln[34] = "", *r; r = fgets(ln, sizeof(ln)-1, f); fclose(f); - if (r) - return pa_xstrdup(pa_strip_nl(ln)); + pa_strip_nl(ln); + + if (ln[0]) + return pa_xstrdup(ln); } - l = 100; + /* The we fall back to the host name. It supposed to be somewhat + * unique, at least in a network, but may change. */ + l = 100; for (;;) { char *c; - c = pa_xnew(char, l); + c = pa_xmalloc(l); if (!pa_get_host_name(c, l)) { - if (errno == EINVAL || errno == ENAMETOOLONG) { + if (errno != EINVAL && errno != ENAMETOOLONG) + break; + + } else if (strlen(c) < l-1) { + + if (*c == 0) { pa_xfree(c); - l *= 2; - continue; + break; } - return NULL; - } - - if (strlen(c) < l-1) return c; + } /* Hmm, the hostname is as long the space we offered the * function, we cannot know if it fully fit in, so let's play @@ -2304,4 +2459,31 @@ char *pa_machine_id(void) { pa_xfree(c); l *= 2; } + + /* If no hostname was set we use the POSIX hostid. It's usually + * the IPv4 address. Mit not be that stable. */ + return pa_sprintf_malloc("%08lx", (unsigned long) gethostid); +} + +char *pa_uname_string(void) { + struct utsname u; + + pa_assert_se(uname(&u) == 0); + + return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version); } + +#ifdef HAVE_VALGRIND_MEMCHECK_H +pa_bool_t pa_in_valgrind(void) { + static int b = 0; + + /* To make heisenbugs a bit simpler to find we check for $VALGRIND + * here instead of really checking whether we run in valgrind or + * not. */ + + if (b < 1) + b = getenv("VALGRIND") ? 2 : 1; + + return b > 1; +} +#endif diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h index 838e4ad3..fd6ee896 100644 --- a/src/pulsecore/core-util.h +++ b/src/pulsecore/core-util.h @@ -35,6 +35,10 @@ #include <pulse/gccmacro.h> #include <pulsecore/macro.h> +#ifndef PACKAGE +#error "Please include config.h before including this file!" +#endif + struct timeval; /* These resource limits are pretty new on Linux, let's define them @@ -127,8 +131,8 @@ int pa_atoi(const char *s, int32_t *ret_i); int pa_atou(const char *s, uint32_t *ret_u); int pa_atod(const char *s, double *ret_d); -int pa_snprintf(char *str, size_t size, const char *format, ...); -int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap); +size_t pa_snprintf(char *str, size_t size, const char *format, ...); +size_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap); char *pa_truncate_utf8(char *c, size_t l); @@ -142,29 +146,35 @@ static inline int pa_is_power_of_two(unsigned n) { return !(n & (n - 1)); } -static inline unsigned pa_make_power_of_two(unsigned n) { - unsigned j = n; +static inline unsigned pa_ulog2(unsigned n) { - if (pa_is_power_of_two(n)) - return n; + if (n <= 1) + return 0; - while (j) { - j = j >> 1; - n = n | j; - } +#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + return 8U * (unsigned) sizeof(unsigned) - (unsigned) __builtin_clz(n) - 1; +#else +{ + unsigned r = 0; - return n + 1; -} + for (;;) { + n = n >> 1; -static inline unsigned pa_ulog2(unsigned n) { - unsigned r = 0; + if (!n) + return r; - while (n) { r++; - n = n >> 1; } +} +#endif +} + +static inline unsigned pa_make_power_of_two(unsigned n) { + + if (pa_is_power_of_two(n)) + return n; - return r; + return 1U << (pa_ulog2(n) + 1); } void pa_close_pipe(int fds[2]); @@ -185,5 +195,15 @@ pa_bool_t pa_in_system_mode(void); #define pa_streq(a,b) (!strcmp((a),(b))) char *pa_machine_id(void); +char *pa_uname_string(void); + + +#ifdef HAVE_VALGRIND_MEMCHECK_H +pa_bool_t pa_in_valgrind(void); +#else +static inline pa_bool_t pa_in_valgrind(void) { + return FALSE; +} +#endif #endif diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 5c594b02..5761bbc7 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -66,7 +66,7 @@ static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t o static void core_free(pa_object *o); -pa_core* pa_core_new(pa_mainloop_api *m, int shared) { +pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size) { pa_core* c; pa_mempool *pool; int j; @@ -74,14 +74,14 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { pa_assert(m); if (shared) { - if (!(pool = pa_mempool_new(shared))) { + if (!(pool = pa_mempool_new(shared, shm_size))) { pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool."); - shared = 0; + shared = FALSE; } } if (!shared) { - if (!(pool = pa_mempool_new(shared))) { + if (!(pool = pa_mempool_new(shared, shm_size))) { pa_log("pa_mempool_new() failed."); return NULL; } @@ -138,6 +138,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) { c->realtime_scheduling = FALSE; c->realtime_priority = 5; c->disable_remixing = FALSE; + c->disable_lfe_remixing = FALSE; for (j = 0; j < PA_CORE_HOOK_MAX; j++) pa_hook_init(&c->hooks[j], c); @@ -200,10 +201,11 @@ static void core_free(pa_object *o) { pa_xfree(c); } -static void exit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { +static void exit_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { pa_core *c = userdata; pa_assert(c->exit_event == e); + pa_log_info("We are idle, quitting..."); pa_core_exit(c, TRUE, 0); } diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index eb768418..f796fb93 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -49,6 +49,7 @@ typedef enum pa_core_hook { PA_CORE_HOOK_SINK_UNLINK_POST, PA_CORE_HOOK_SINK_STATE_CHANGED, PA_CORE_HOOK_SINK_PROPLIST_CHANGED, + PA_CORE_HOOK_SINK_SET_VOLUME, PA_CORE_HOOK_SOURCE_NEW, PA_CORE_HOOK_SOURCE_FIXATE, PA_CORE_HOOK_SOURCE_PUT, @@ -65,6 +66,7 @@ typedef enum pa_core_hook { PA_CORE_HOOK_SINK_INPUT_MOVE_POST, PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED, PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED, + PA_CORE_HOOK_SINK_INPUT_SET_VOLUME, PA_CORE_HOOK_SOURCE_OUTPUT_NEW, PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE, PA_CORE_HOOK_SOURCE_OUTPUT_PUT, @@ -124,6 +126,7 @@ struct pa_core { pa_bool_t running_as_daemon:1; pa_bool_t realtime_scheduling:1; pa_bool_t disable_remixing:1; + pa_bool_t disable_lfe_remixing:1; pa_resample_method_t resample_method; int realtime_priority; @@ -140,7 +143,7 @@ enum { PA_CORE_MESSAGE_MAX }; -pa_core* pa_core_new(pa_mainloop_api *m, int shared); +pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size); /* Check whether noone is connected to this core */ void pa_core_check_idle(pa_core *c); diff --git a/src/pulsecore/endianmacros.h b/src/pulsecore/endianmacros.h index 26336918..1b94de17 100644 --- a/src/pulsecore/endianmacros.h +++ b/src/pulsecore/endianmacros.h @@ -46,9 +46,14 @@ #endif static inline float PA_FLOAT32_SWAP(float x) { - uint32_t i = *(uint32_t*) &x; - i = PA_UINT32_SWAP(i); - return *(float*) &i; + union { + float f; + uint32_t u; + } t; + + t.f = x; + t.u = PA_UINT32_SWAP(t.u); + return t.f; } #define PA_MAYBE_INT16_SWAP(c,x) ((c) ? PA_INT32_SWAP(x) : x) diff --git a/src/pulsecore/envelope.c b/src/pulsecore/envelope.c index e2691611..7f2252e9 100644 --- a/src/pulsecore/envelope.c +++ b/src/pulsecore/envelope.c @@ -153,11 +153,11 @@ void pa_envelope_free(pa_envelope *e) { } static int32_t linear_interpolate_int(pa_usec_t x1, int32_t _y1, pa_usec_t x2, int32_t y2, pa_usec_t x3) { - return (int32_t) (_y1 + (x3 - x1) * (float) (y2 - _y1) / (float) (x2 - x1)); + return (int32_t) ((double) _y1 + (double) (x3 - x1) * (double) (y2 - _y1) / (double) (x2 - x1)); } static float linear_interpolate_float(pa_usec_t x1, float _y1, pa_usec_t x2, float y2, pa_usec_t x3) { - return _y1 + (x3 - x1) * (y2 - _y1) / (x2 - x1); + return _y1 + ((float) x3 - (float) x1) * (y2 - _y1) / ((float) x2 - (float) x1); } static int32_t item_get_int(pa_envelope_item *i, pa_usec_t x) { @@ -573,11 +573,11 @@ static float linear_get_float(pa_envelope *e, int v) { if (!e->points[v].cached_valid) { e->points[v].cached_dy_dx = (e->points[v].y.f[e->points[v].n_current+1] - e->points[v].y.f[e->points[v].n_current]) / - (e->points[v].x[e->points[v].n_current+1] - e->points[v].x[e->points[v].n_current]); + ((float) e->points[v].x[e->points[v].n_current+1] - (float) e->points[v].x[e->points[v].n_current]); e->points[v].cached_valid = TRUE; } - return e->points[v].y.f[e->points[v].n_current] + (e->x - e->points[v].x[e->points[v].n_current]) * e->points[v].cached_dy_dx; + return e->points[v].y.f[e->points[v].n_current] + (float) (e->x - e->points[v].x[e->points[v].n_current]) * e->points[v].cached_dy_dx; } void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { @@ -605,7 +605,7 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { uint8_t *t; for (t = p; n > 0; n -= fs) { - int16_t factor = linear_get_int(e, v); + int32_t factor = linear_get_int(e, v); unsigned c; e->x += fs; @@ -620,13 +620,13 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { uint8_t *t; for (t = p; n > 0; n -= fs) { - int16_t factor = linear_get_int(e, v); + int32_t factor = linear_get_int(e, v); unsigned c; e->x += fs; for (c = 0; c < e->sample_spec.channels; c++, t++) { int16_t k = st_ulaw2linear16(*t); - *t = (uint8_t) st_14linear2ulaw(((factor * k) / 0x10000) >> 2); + *t = (uint8_t) st_14linear2ulaw((int16_t) (((factor * k) / 0x10000) >> 2)); } } @@ -637,13 +637,13 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { uint8_t *t; for (t = p; n > 0; n -= fs) { - int16_t factor = linear_get_int(e, v); + int32_t factor = linear_get_int(e, v); unsigned c; e->x += fs; for (c = 0; c < e->sample_spec.channels; c++, t++) { int16_t k = st_alaw2linear16(*t); - *t = (uint8_t) st_13linear2alaw(((factor * k) / 0x10000) >> 3); + *t = (uint8_t) st_13linear2alaw((int16_t) (((factor * k) / 0x10000) >> 3)); } } @@ -659,7 +659,7 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { e->x += fs; for (c = 0; c < e->sample_spec.channels; c++, t++) - *t = (factor * *t) / 0x10000; + *t = (int16_t) ((factor * *t) / 0x10000); } break; @@ -674,7 +674,7 @@ void pa_envelope_apply(pa_envelope *e, pa_memchunk *chunk) { e->x += fs; for (c = 0; c < e->sample_spec.channels; c++, t++) { - int16_t r = (factor * PA_INT16_SWAP(*t)) / 0x10000; + int16_t r = (int16_t) ((factor * PA_INT16_SWAP(*t)) / 0x10000); *t = PA_INT16_SWAP(r); } } diff --git a/src/pulsecore/fdsem.c b/src/pulsecore/fdsem.c index 1531e3db..380f34f5 100644 --- a/src/pulsecore/fdsem.c +++ b/src/pulsecore/fdsem.c @@ -41,39 +41,15 @@ #include <pulsecore/pipe.h> #endif -#ifdef __linux__ - -#if !defined(__NR_eventfd) && defined(__i386__) -#define __NR_eventfd 323 -#endif - -#if !defined(__NR_eventfd) && defined(__x86_64__) -#define __NR_eventfd 284 -#endif - -#if !defined(__NR_eventfd) && defined(__arm__) -#define __NR_eventfd (__NR_SYSCALL_BASE+351) -#endif - -#if !defined(SYS_eventfd) && defined(__NR_eventfd) -#define SYS_eventfd __NR_eventfd -#endif - -#ifdef SYS_eventfd -#define HAVE_EVENTFD - -static inline long eventfd(unsigned count) { - return syscall(SYS_eventfd, count); -} - -#endif +#ifdef HAVE_SYS_EVENTFD_H +#include <sys/eventfd.h> #endif #include "fdsem.h" struct pa_fdsem { int fds[2]; -#ifdef HAVE_EVENTFD +#ifdef HAVE_SYS_EVENTFD_H int efd; #endif @@ -85,8 +61,8 @@ pa_fdsem *pa_fdsem_new(void) { f = pa_xmalloc(PA_ALIGN(sizeof(pa_fdsem)) + PA_ALIGN(sizeof(pa_fdsem_data))); -#ifdef HAVE_EVENTFD - if ((f->efd = eventfd(0)) >= 0) { +#ifdef HAVE_SYS_EVENTFD_H + if ((f->efd = eventfd(0, 0)) >= 0) { pa_make_fd_cloexec(f->efd); f->fds[0] = f->fds[1] = -1; } else @@ -116,7 +92,7 @@ pa_fdsem *pa_fdsem_open_shm(pa_fdsem_data *data, int event_fd) { pa_assert(data); pa_assert(event_fd >= 0); -#ifdef HAVE_EVENTFD +#ifdef HAVE_SYS_EVENTFD_H f = pa_xnew(pa_fdsem, 1); f->efd = event_fd; @@ -134,11 +110,11 @@ pa_fdsem *pa_fdsem_new_shm(pa_fdsem_data *data, int* event_fd) { pa_assert(data); pa_assert(event_fd); -#ifdef HAVE_EVENTFD +#ifdef HAVE_SYS_EVENTFD_H f = pa_xnew(pa_fdsem, 1); - if ((f->efd = eventfd(0)) < 0) { + if ((f->efd = eventfd(0, 0)) < 0) { pa_xfree(f); return NULL; } @@ -159,7 +135,7 @@ pa_fdsem *pa_fdsem_new_shm(pa_fdsem_data *data, int* event_fd) { void pa_fdsem_free(pa_fdsem *f) { pa_assert(f); -#ifdef HAVE_EVENTFD +#ifdef HAVE_SYS_EVENTFD_H if (f->efd >= 0) pa_close(f->efd); #endif @@ -178,7 +154,7 @@ static void flush(pa_fdsem *f) { do { char x[10]; -#ifdef HAVE_EVENTFD +#ifdef HAVE_SYS_EVENTFD_H if (f->efd >= 0) { uint64_t u; @@ -195,7 +171,7 @@ static void flush(pa_fdsem *f) { continue; } - } while (pa_atomic_sub(&f->data->in_pipe, r) > r); + } while (pa_atomic_sub(&f->data->in_pipe, (int) r) > (int) r); } void pa_fdsem_post(pa_fdsem *f) { @@ -211,7 +187,7 @@ void pa_fdsem_post(pa_fdsem *f) { for (;;) { -#ifdef HAVE_EVENTFD +#ifdef HAVE_SYS_EVENTFD_H if (f->efd >= 0) { uint64_t u = 1; @@ -247,7 +223,7 @@ void pa_fdsem_wait(pa_fdsem *f) { char x[10]; ssize_t r; -#ifdef HAVE_EVENTFD +#ifdef HAVE_SYS_EVENTFD_H if (f->efd >= 0) { uint64_t u; @@ -265,7 +241,7 @@ void pa_fdsem_wait(pa_fdsem *f) { continue; } - pa_atomic_sub(&f->data->in_pipe, r); + pa_atomic_sub(&f->data->in_pipe, (int) r); } pa_assert_se(pa_atomic_dec(&f->data->waiting) >= 1); @@ -285,7 +261,7 @@ int pa_fdsem_try(pa_fdsem *f) { int pa_fdsem_get(pa_fdsem *f) { pa_assert(f); -#ifdef HAVE_EVENTFD +#ifdef HAVE_SYS_EVENTFD_H if (f->efd >= 0) return f->efd; #endif diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h index 2d8422f9..512dd357 100644 --- a/src/pulsecore/flist.h +++ b/src/pulsecore/flist.h @@ -26,6 +26,7 @@ #include <pulse/gccmacro.h> #include <pulsecore/once.h> +#include <pulsecore/core-util.h> /* A multiple-reader multipler-write lock-free free list implementation */ @@ -56,6 +57,8 @@ void* pa_flist_pop(pa_flist*l); } \ static void name##_flist_destructor(void) PA_GCC_DESTRUCTOR; \ static void name##_flist_destructor(void) { \ + if (!pa_in_valgrind()) \ + return; \ if (name##_flist.flist) \ pa_flist_free(name##_flist.flist, (free_cb)); \ } \ diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index fb4497b8..24a28db7 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -66,7 +66,7 @@ unsigned pa_idxset_string_hash_func(const void *p) { const char *c; for (c = p; *c; c++) - hash = 31 * hash + *c; + hash = 31 * hash + (unsigned) *c; return hash; } @@ -80,7 +80,7 @@ unsigned pa_idxset_trivial_hash_func(const void *p) { } int pa_idxset_trivial_compare_func(const void *a, const void *b) { - return a != b; + return a < b ? -1 : (a > b ? 1 : 0); } pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) { @@ -318,8 +318,7 @@ void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) { hash = *idx % NBUCKETS; - if (!(e = index_scan(s, hash, *idx))) - return NULL; + e = index_scan(s, hash, *idx); if (e && e->iterate_next) e = e->iterate_next; diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c index 90afaafd..88174c05 100644 --- a/src/pulsecore/ioline.c +++ b/src/pulsecore/ioline.c @@ -164,7 +164,7 @@ void pa_ioline_puts(pa_ioline *l, const char *c) { /* In case the allocated buffer is too small, enlarge it. */ if (l->wbuf_valid_length + len > l->wbuf_length) { size_t n = l->wbuf_valid_length+len; - char *new = pa_xnew(char, n); + char *new = pa_xnew(char, (unsigned) n); if (l->wbuf) { memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length); @@ -285,7 +285,7 @@ static int do_read(pa_ioline *l) { memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length); } else { /* Enlarge the buffer */ - char *new = pa_xnew(char, n); + char *new = pa_xnew(char, (unsigned) n); if (l->rbuf_valid_length) memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length); pa_xfree(l->rbuf); @@ -315,10 +315,10 @@ static int do_read(pa_ioline *l) { return -1; } - l->rbuf_valid_length += r; + l->rbuf_valid_length += (size_t) r; /* Look if a line has been terminated in the newly read data */ - scan_for_lines(l, l->rbuf_valid_length - r); + scan_for_lines(l, l->rbuf_valid_length - (size_t) r); } return 0; @@ -346,8 +346,8 @@ static int do_write(pa_ioline *l) { return -1; } - l->wbuf_index += r; - l->wbuf_valid_length -= r; + l->wbuf_index += (size_t) r; + l->wbuf_valid_length -= (size_t) r; /* A shortcut for the next time */ if (l->wbuf_valid_length == 0) diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c index 7b5f865b..6d5080fb 100644 --- a/src/pulsecore/ipacl.c +++ b/src/pulsecore/ipacl.c @@ -122,7 +122,7 @@ pa_ip_acl* pa_ip_acl_new(const char *s) { if (e.bits < 128) { int t = 0, i; - for (i = 0, bits = e.bits; i < 16; i++) { + for (i = 0, bits = (uint32_t) e.bits; i < 16; i++) { if (bits >= 8) bits -= 8; diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c new file mode 100644 index 00000000..d36b669e --- /dev/null +++ b/src/pulsecore/lock-autospawn.c @@ -0,0 +1,330 @@ +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <sys/poll.h> +#include <signal.h> +#include <pthread.h> + +#include <pulse/i18n.h> +#include <pulse/xmalloc.h> + +#include <pulsecore/mutex.h> +#include <pulsecore/thread.h> +#include <pulsecore/core-util.h> + +#include "lock-autospawn.h" + +/* So, why do we have this complex code here with threads and pipes + * and stuff? For two reasons: POSIX file locks are per-process, not + * per-file descriptor. That means that two contexts within the same + * process that try to create the autospawn lock might end up assuming + * they both managed to lock the file. And then, POSIX locking + * operations are synchronous. If two contexts run from the same event + * loop it must be made sure that they do not block each other, but + * that the locking operation can happen asynchronously. */ + +#define AUTOSPAWN_LOCK "autospawn.lock" + +static pa_mutex *mutex; + +static unsigned n_ref = 0; +static int lock_fd = -1; +static pa_mutex *lock_fd_mutex = NULL; +static pa_bool_t taken = FALSE; +static pa_thread *thread; +static int pipe_fd[2] = { -1, -1 }; + +static void destroy_mutex(void) PA_GCC_DESTRUCTOR; + +static int ref(void) { + + if (n_ref > 0) { + + pa_assert(pipe_fd[0] >= 0); + pa_assert(pipe_fd[1] >= 0); + + n_ref++; + + return 0; + } + + pa_assert(lock_fd < 0); + pa_assert(!lock_fd_mutex); + pa_assert(!taken); + pa_assert(!thread); + pa_assert(pipe_fd[0] < 0); + pa_assert(pipe_fd[1] < 0); + + if (pipe(pipe_fd) < 0) + return -1; + + lock_fd_mutex = pa_mutex_new(FALSE, FALSE); + + pa_make_fd_cloexec(pipe_fd[0]); + pa_make_fd_cloexec(pipe_fd[1]); + + pa_make_fd_nonblock(pipe_fd[1]); + pa_make_fd_nonblock(pipe_fd[0]); + + n_ref = 1; + return 0; +} + +static void unref(pa_bool_t after_fork) { + + pa_assert(n_ref > 0); + pa_assert(pipe_fd[0] >= 0); + pa_assert(pipe_fd[1] >= 0); + pa_assert(lock_fd_mutex); + + n_ref--; + + if (n_ref > 0) + return; + + pa_assert(!taken); + + if (thread) { + pa_thread_free(thread); + thread = NULL; + } + + pa_mutex_lock(lock_fd_mutex); + if (lock_fd >= 0) { + + if (after_fork) + pa_close(lock_fd); + else { + char *lf; + + if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) + pa_log_warn(_("Cannot access autospawn lock.")); + + pa_unlock_lockfile(lf, lock_fd); + pa_xfree(lf); + + lock_fd = -1; + } + } + pa_mutex_unlock(lock_fd_mutex); + + pa_mutex_free(lock_fd_mutex); + lock_fd_mutex = NULL; + + pa_close(pipe_fd[0]); + pa_close(pipe_fd[1]); + pipe_fd[0] = pipe_fd[1] = -1; +} + +static void ping(void) { + ssize_t s; + + pa_assert(pipe_fd[1] >= 0); + + for (;;) { + char x = 'x'; + + if ((s = write(pipe_fd[1], &x, 1)) == 1) + break; + + pa_assert(s < 0); + + if (errno == EAGAIN) + break; + + pa_assert(errno == EINTR); + } +} + +static void wait_for_ping(void) { + ssize_t s; + char x; + struct pollfd pfd; + int k; + + pa_assert(pipe_fd[0] >= 0); + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = pipe_fd[0]; + pfd.events = POLLIN; + + if ((k = poll(&pfd, 1, -1)) != 1) { + pa_assert(k < 0); + pa_assert(errno == EINTR); + } else if ((s = read(pipe_fd[0], &x, 1)) != 1) { + pa_assert(s < 0); + pa_assert(errno == EAGAIN); + } +} + +static void empty_pipe(void) { + char x[16]; + ssize_t s; + + pa_assert(pipe_fd[0] >= 0); + + if ((s = read(pipe_fd[0], &x, sizeof(x))) < 1) { + pa_assert(s < 0); + pa_assert(errno == EAGAIN); + } +} + +static void thread_func(void *u) { + int fd; + char *lf; + sigset_t fullset; + + /* No signals in this thread please */ + sigfillset(&fullset); + pthread_sigmask(SIG_BLOCK, &fullset, NULL); + + if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) { + pa_log_warn(_("Cannot access autospawn lock.")); + goto finish; + } + + if ((fd = pa_lock_lockfile(lf)) < 0) + goto finish; + + pa_mutex_lock(lock_fd_mutex); + pa_assert(lock_fd < 0); + lock_fd = fd; + pa_mutex_unlock(lock_fd_mutex); + +finish: + pa_xfree(lf); + + ping(); +} + +static int start_thread(void) { + + if (!thread) + if (!(thread = pa_thread_new(thread_func, NULL))) + return -1; + + return 0; +} + +static void create_mutex(void) { + PA_ONCE_BEGIN { + mutex = pa_mutex_new(FALSE, FALSE); + } PA_ONCE_END; +} + +static void destroy_mutex(void) { + + if (mutex) + pa_mutex_free(mutex); +} + + +int pa_autospawn_lock_init(void) { + int ret = -1; + + create_mutex(); + pa_mutex_lock(mutex); + + if (ref() < 0) + ret = -1; + else + ret = pipe_fd[0]; + + pa_mutex_unlock(mutex); + + return ret; +} + +int pa_autospawn_lock_acquire(pa_bool_t block) { + int ret = -1; + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + pa_mutex_lock(lock_fd_mutex); + + for (;;) { + + empty_pipe(); + + if (lock_fd >= 0 && !taken) { + taken = TRUE; + ret = 1; + break; + } + + if (lock_fd < 0) + if (start_thread() < 0) + break; + + if (!block) { + ret = 0; + break; + } + + pa_mutex_unlock(lock_fd_mutex); + pa_mutex_unlock(mutex); + + wait_for_ping(); + + pa_mutex_lock(mutex); + pa_mutex_lock(lock_fd_mutex); + } + + pa_mutex_unlock(lock_fd_mutex); + + pa_mutex_unlock(mutex); + + return ret; +} + +void pa_autospawn_lock_release(void) { + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + pa_assert(taken); + taken = FALSE; + + ping(); + + pa_mutex_unlock(mutex); +} + +void pa_autospawn_lock_done(pa_bool_t after_fork) { + + create_mutex(); + pa_mutex_lock(mutex); + pa_assert(n_ref >= 1); + + unref(after_fork); + + pa_mutex_unlock(mutex); +} diff --git a/src/pulsecore/lock-autospawn.h b/src/pulsecore/lock-autospawn.h new file mode 100644 index 00000000..c04c4bd1 --- /dev/null +++ b/src/pulsecore/lock-autospawn.h @@ -0,0 +1,32 @@ +#ifndef foopulselockautospawnhfoo +#define foopulselockautospawnhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include <pulsecore/macro.h> + +int pa_autospawn_lock_init(void); +int pa_autospawn_lock_acquire(pa_bool_t block); +void pa_autospawn_lock_release(void); +void pa_autospawn_lock_done(pa_bool_t after_fork); + +#endif diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c index 5eda4f65..adf2f112 100644 --- a/src/pulsecore/log.c +++ b/src/pulsecore/log.c @@ -30,6 +30,10 @@ #include <string.h> #include <errno.h> +#ifdef HAVE_EXECINFO_H +#include <execinfo.h> +#endif + #ifdef HAVE_SYSLOG_H #include <syslog.h> #endif @@ -37,19 +41,27 @@ #include <pulse/utf8.h> #include <pulse/xmalloc.h> #include <pulse/util.h> +#include <pulse/timeval.h> #include <pulsecore/macro.h> #include <pulsecore/core-util.h> +#include <pulsecore/rtclock.h> +#include <pulsecore/once.h> #include "log.h" #define ENV_LOGLEVEL "PULSE_LOG" #define ENV_LOGMETA "PULSE_LOG_META" +#define ENV_LOGTIME "PULSE_LOG_TIME" +#define ENV_LOGBACKTRACE "PULSE_LOG_BACKTRACE" static char *log_ident = NULL, *log_ident_local = NULL; static pa_log_target_t log_target = PA_LOG_STDERR; -static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL; -static pa_log_level_t maximal_level = PA_LOG_NOTICE; +static pa_log_func_t user_log_func = NULL; +static pa_log_level_t maximal_level = PA_LOG_ERROR; +static unsigned show_backtrace = 0; +static pa_bool_t show_meta = FALSE; +static pa_bool_t show_time = FALSE; #ifdef HAVE_SYSLOG_H static const int level_to_syslog[] = { @@ -81,6 +93,9 @@ void pa_log_set_ident(const char *p) { /* To make valgrind shut up. */ static void ident_destructor(void) PA_GCC_DESTRUCTOR; static void ident_destructor(void) { + if (!pa_in_valgrind()) + return; + pa_xfree(log_ident); pa_xfree(log_ident_local); } @@ -91,13 +106,81 @@ void pa_log_set_maximal_level(pa_log_level_t l) { maximal_level = l; } -void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) { +void pa_log_set_target(pa_log_target_t t, pa_log_func_t func) { pa_assert(t == PA_LOG_USER || !func); log_target = t; user_log_func = func; } +void pa_log_set_show_meta(pa_bool_t b) { + show_meta = b; +} + +void pa_log_set_show_time(pa_bool_t b) { + show_time = b; +} + +void pa_log_set_show_backtrace(unsigned nlevels) { + show_backtrace = nlevels; +} + +#ifdef HAVE_EXECINFO_H + +static char* get_backtrace(unsigned show_nframes) { + void* trace[32]; + int n_frames; + char **symbols, *e, *r; + unsigned j, n; + size_t a; + + if (show_nframes <= 0) + return NULL; + + n_frames = backtrace(trace, PA_ELEMENTSOF(trace)); + + if (n_frames <= 0) + return NULL; + + symbols = backtrace_symbols(trace, n_frames); + + if (!symbols) + return NULL; + + n = PA_MIN((unsigned) n_frames, show_nframes); + + a = 4; + + for (j = 0; j < n; j++) { + if (j > 0) + a += 2; + a += strlen(symbols[j]); + } + + r = pa_xnew(char, a); + + strcpy(r, " ("); + e = r + 2; + + for (j = 0; j < n; j++) { + if (j > 0) { + strcpy(e, "<<"); + e += 2; + } + + strcpy(e, symbols[j]); + e += strlen(symbols[j]); + } + + strcpy(e, ")"); + + free(symbols); + + return r; +} + +#endif + void pa_log_levelv_meta( pa_log_level_t level, const char*file, @@ -109,31 +192,82 @@ void pa_log_levelv_meta( const char *e; char *t, *n; int saved_errno = errno; + char *bt = NULL; + pa_log_level_t ml; +#ifdef HAVE_EXECINFO_H + unsigned show_bt; +#endif /* We don't use dynamic memory allocation here to minimize the hit * in RT threads */ - char text[1024], location[128]; + char text[4096], location[128], timestamp[32]; pa_assert(level < PA_LOG_LEVEL_MAX); pa_assert(format); - if ((e = getenv(ENV_LOGLEVEL))) - maximal_level = atoi(e); + ml = maximal_level; - if (level > maximal_level) { + if (PA_UNLIKELY((e = getenv(ENV_LOGLEVEL)))) { + pa_log_level_t eml = (pa_log_level_t) atoi(e); + + if (eml > ml) + ml = eml; + } + + if (PA_LIKELY(level > ml)) { errno = saved_errno; return; } pa_vsnprintf(text, sizeof(text), format, ap); - if (getenv(ENV_LOGMETA) && file && line > 0 && func) + if ((show_meta || getenv(ENV_LOGMETA)) && file && line > 0 && func) pa_snprintf(location, sizeof(location), "[%s:%i %s()] ", file, line, func); else if (file) pa_snprintf(location, sizeof(location), "%s: ", pa_path_get_filename(file)); else location[0] = 0; + if (show_time || getenv(ENV_LOGTIME)) { + static pa_usec_t start, last; + pa_usec_t u, a, r; + + u = pa_rtclock_usec(); + + PA_ONCE_BEGIN { + start = u; + last = u; + } PA_ONCE_END; + + r = u - last; + a = u - start; + + /* This is not thread safe, but this is a debugging tool only + * anyway. */ + last = u; + + pa_snprintf(timestamp, sizeof(timestamp), "(%4llu.%03llu|%4llu.%03llu) ", + (unsigned long long) (a / PA_USEC_PER_SEC), + (unsigned long long) (((a / PA_USEC_PER_MSEC)) % 1000), + (unsigned long long) (r / PA_USEC_PER_SEC), + (unsigned long long) (((r / PA_USEC_PER_MSEC)) % 1000)); + + } else + timestamp[0] = 0; + +#ifdef HAVE_EXECINFO_H + show_bt = show_backtrace; + + if ((e = getenv(ENV_LOGBACKTRACE))) { + unsigned ebt = (unsigned) atoi(e); + + if (ebt > show_bt) + show_bt = ebt; + } + + bt = get_backtrace(show_bt); +#endif + if (!pa_utf8_valid(text)) pa_log_level(level, __FILE__": invalid UTF-8 string following below:"); @@ -148,19 +282,22 @@ void pa_log_levelv_meta( switch (log_target) { case PA_LOG_STDERR: { - const char *prefix = "", *suffix = ""; + const char *prefix = "", *suffix = "", *grey = ""; char *local_t; #ifndef OS_IS_WIN32 /* Yes indeed. Useless, but fun! */ if (isatty(STDERR_FILENO)) { - if (level <= PA_LOG_ERROR) { + if (level <= PA_LOG_ERROR) prefix = "\x1B[1;31m"; - suffix = "\x1B[0m"; - } else if (level <= PA_LOG_WARN) { + else if (level <= PA_LOG_WARN) prefix = "\x1B[1m"; + + if (bt) + grey = "\x1B[2m"; + + if (grey[0] || prefix[0]) suffix = "\x1B[0m"; - } } #endif @@ -168,9 +305,9 @@ void pa_log_levelv_meta( * minimize the hit in RT threads */ local_t = pa_utf8_to_locale(t); if (!local_t) - fprintf(stderr, "%c: %s%s%s%s\n", level_to_char[level], location, prefix, t, suffix); + fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, grey, pa_strempty(bt), suffix); else { - fprintf(stderr, "%c: %s%s%s%s\n", level_to_char[level], location, prefix, local_t, suffix); + fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, local_t, grey, pa_strempty(bt), suffix); pa_xfree(local_t); } @@ -185,9 +322,9 @@ void pa_log_levelv_meta( local_t = pa_utf8_to_locale(t); if (!local_t) - syslog(level_to_syslog[level], "%s%s", location, t); + syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, t, pa_strempty(bt)); else { - syslog(level_to_syslog[level], "%s%s", location, local_t); + syslog(level_to_syslog[level], "%s%s%s%s", timestamp, location, local_t, pa_strempty(bt)); pa_xfree(local_t); } @@ -199,7 +336,7 @@ void pa_log_levelv_meta( case PA_LOG_USER: { char x[1024]; - pa_snprintf(x, sizeof(x), "%s%s", location, t); + pa_snprintf(x, sizeof(x), "%s%s%s", timestamp, location, t); user_log_func(level, x); break; diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h index 2047696e..3d66e903 100644 --- a/src/pulsecore/log.h +++ b/src/pulsecore/log.h @@ -25,6 +25,8 @@ #include <stdarg.h> #include <stdlib.h> + +#include <pulsecore/macro.h> #include <pulse/gccmacro.h> /* A simple logging subsystem */ @@ -49,11 +51,16 @@ typedef enum pa_log_level { /* Set an identification for the current daemon. Used when logging to syslog. */ void pa_log_set_ident(const char *p); +typedef void (*pa_log_func_t)(pa_log_level_t t, const char*s); + /* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ -void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t t, const char*s)); +void pa_log_set_target(pa_log_target_t t, pa_log_func_t func); -/* Minimal log level */ +/* Maximal log level */ void pa_log_set_maximal_level(pa_log_level_t l); +void pa_log_set_show_meta(pa_bool_t b); +void pa_log_set_show_time(pa_bool_t b); +void pa_log_set_show_backtrace(unsigned nlevels); void pa_log_level_meta( pa_log_level_t level, diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h index fd33b7bb..f9ce949a 100644 --- a/src/pulsecore/macro.h +++ b/src/pulsecore/macro.h @@ -30,7 +30,6 @@ #include <stdio.h> #include <stdlib.h> -#include <pulsecore/log.h> #include <pulse/gccmacro.h> #ifndef PACKAGE @@ -40,7 +39,7 @@ #ifndef PA_LIKELY #ifdef __GNUC__ #define PA_LIKELY(x) (__builtin_expect(!!(x),1)) -#define PA_UNLIKELY(x) (__builtin_expect((x),0)) +#define PA_UNLIKELY(x) (__builtin_expect(!!(x),0)) #else #define PA_LIKELY(x) (x) #define PA_UNLIKELY(x) (x) @@ -208,7 +207,7 @@ typedef int pa_bool_t; #define PA_PATH_SEP_CHAR '/' #endif -#ifdef __GNUC__ +#if defined(__GNUC__) && defined(__ELF__) #define PA_WARN_REFERENCE(sym, msg) \ __asm__(".section .gnu.warning." #sym); \ @@ -221,4 +220,13 @@ typedef int pa_bool_t; #endif +#if defined(__i386__) || defined(__x86_64__) +#define PA_DEBUG_TRAP __asm__("int $3") +#else +#define PA_DEBUG_TRAP raise(SIGTRAP) +#endif + +/* We include this at the very last place */ +#include <pulsecore/log.h> + #endif diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c index b43113d6..d9e1bf1c 100644 --- a/src/pulsecore/memblock.c +++ b/src/pulsecore/memblock.c @@ -31,6 +31,10 @@ #include <signal.h> #include <errno.h> +#ifdef HAVE_VALGRIND_MEMCHECK_H +#include <valgrind/memcheck.h> +#endif + #include <pulse/xmalloc.h> #include <pulse/def.h> @@ -158,14 +162,14 @@ static void stat_add(pa_memblock*b) { pa_assert(b->pool); pa_atomic_inc(&b->pool->stat.n_allocated); - pa_atomic_add(&b->pool->stat.allocated_size, b->length); + pa_atomic_add(&b->pool->stat.allocated_size, (int) b->length); pa_atomic_inc(&b->pool->stat.n_accumulated); - pa_atomic_add(&b->pool->stat.accumulated_size, b->length); + pa_atomic_add(&b->pool->stat.accumulated_size, (int) b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { pa_atomic_inc(&b->pool->stat.n_imported); - pa_atomic_add(&b->pool->stat.imported_size, b->length); + pa_atomic_add(&b->pool->stat.imported_size, (int) b->length); } pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]); @@ -181,14 +185,14 @@ static void stat_remove(pa_memblock *b) { pa_assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length); pa_atomic_dec(&b->pool->stat.n_allocated); - pa_atomic_sub(&b->pool->stat.allocated_size, b->length); + pa_atomic_sub(&b->pool->stat.allocated_size, (int) b->length); if (b->type == PA_MEMBLOCK_IMPORTED) { pa_assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); pa_assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); pa_atomic_dec(&b->pool->stat.n_imported); - pa_atomic_sub(&b->pool->stat.imported_size, b->length); + pa_atomic_sub(&b->pool->stat.imported_size, (int) b->length); } pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]); @@ -248,7 +252,7 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { if ((unsigned) (idx = pa_atomic_inc(&p->n_init)) >= p->n_blocks) pa_atomic_dec(&p->n_init); else - slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * idx)); + slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * (size_t) idx)); if (!slot) { pa_log_info("Pool full"); @@ -257,6 +261,12 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) { } } +/* #ifdef HAVE_VALGRIND_MEMCHECK_H */ +/* if (PA_UNLIKELY(pa_in_valgrind())) { */ +/* VALGRIND_MALLOCLIKE_BLOCK(slot, p->block_size, 0, 0); */ +/* } */ +/* #endif */ + return slot; } @@ -272,7 +282,7 @@ static unsigned mempool_slot_idx(pa_mempool *p, void *ptr) { pa_assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr); pa_assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size); - return ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size; + return (unsigned) ((size_t) ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size); } /* No lock necessary */ @@ -519,13 +529,19 @@ static void memblock_free(pa_memblock *b) { case PA_MEMBLOCK_POOL_EXTERNAL: case PA_MEMBLOCK_POOL: { struct mempool_slot *slot; - int call_free; + pa_bool_t call_free; slot = mempool_slot_by_ptr(b->pool, pa_atomic_ptr_load(&b->data)); pa_assert(slot); call_free = b->type == PA_MEMBLOCK_POOL_EXTERNAL; +/* #ifdef HAVE_VALGRIND_MEMCHECK_H */ +/* if (PA_UNLIKELY(pa_in_valgrind())) { */ +/* VALGRIND_FREELIKE_BLOCK(slot, b->pool->block_size); */ +/* } */ +/* #endif */ + /* The free list dimensions should easily allow all slots * to fit in, hence try harder if pushing this slot into * the free list fails */ @@ -647,7 +663,7 @@ static void memblock_replace_import(pa_memblock *b) { pa_assert(pa_atomic_load(&b->pool->stat.n_imported) > 0); pa_assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length); pa_atomic_dec(&b->pool->stat.n_imported); - pa_atomic_sub(&b->pool->stat.imported_size, b->length); + pa_atomic_sub(&b->pool->stat.imported_size, (int) b->length); seg = b->per_type.imported.segment; pa_assert(seg); @@ -668,8 +684,9 @@ static void memblock_replace_import(pa_memblock *b) { pa_mutex_unlock(seg->import->mutex); } -pa_mempool* pa_mempool_new(pa_bool_t shared) { +pa_mempool* pa_mempool_new(pa_bool_t shared, size_t size) { pa_mempool *p; + char t1[64], t2[64]; p = pa_xnew(pa_mempool, 1); @@ -680,13 +697,26 @@ pa_mempool* pa_mempool_new(pa_bool_t shared) { if (p->block_size < PA_PAGE_SIZE) p->block_size = PA_PAGE_SIZE; - p->n_blocks = PA_MEMPOOL_SLOTS_MAX; + if (size <= 0) + p->n_blocks = PA_MEMPOOL_SLOTS_MAX; + else { + p->n_blocks = (unsigned) (size / p->block_size); + + if (p->n_blocks < 2) + p->n_blocks = 2; + } if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) { pa_xfree(p); return NULL; } + pa_log_debug("Using %s memory pool with %u slots of size %s each, total size is %s", + p->memory.shared ? "shared" : "private", + p->n_blocks, + pa_bytes_snprint(t1, sizeof(t1), (unsigned) p->block_size), + pa_bytes_snprint(t2, sizeof(t2), (unsigned) (p->n_blocks * p->block_size))); + memset(&p->stat, 0, sizeof(p->stat)); pa_atomic_store(&p->n_init, 0); @@ -754,7 +784,7 @@ void pa_mempool_vacuum(pa_mempool *p) { ; while ((slot = pa_flist_pop(list))) { - pa_shm_punch(&p->memory, (uint8_t*) slot - (uint8_t*) p->memory.ptr, p->block_size); + pa_shm_punch(&p->memory, (size_t) ((uint8_t*) slot - (uint8_t*) p->memory.ptr), p->block_size); while (pa_flist_push(p->free_slots, slot)) ; @@ -967,7 +997,7 @@ void pa_memexport_free(pa_memexport *e) { pa_mutex_lock(e->mutex); while (e->used_slots) - pa_memexport_process_release(e, e->used_slots - e->slots); + pa_memexport_process_release(e, (uint32_t) (e->used_slots - e->slots)); pa_mutex_unlock(e->mutex); pa_mutex_lock(e->pool->mutex); @@ -1006,7 +1036,7 @@ int pa_memexport_process_release(pa_memexport *e, uint32_t id) { pa_assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) b->length); pa_atomic_dec(&e->pool->stat.n_exported); - pa_atomic_sub(&e->pool->stat.exported_size, b->length); + pa_atomic_sub(&e->pool->stat.exported_size, (int) b->length); pa_memblock_unref(b); @@ -1034,7 +1064,7 @@ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) { slot->block->per_type.imported.segment->import != i) continue; - idx = slot - e->slots; + idx = (uint32_t) (slot - e->slots); e->revoke_cb(e, idx, e->userdata); pa_memexport_process_release(e, idx); } @@ -1095,7 +1125,7 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 PA_LLIST_PREPEND(struct memexport_slot, e->used_slots, slot); slot->block = b; - *block_id = slot - e->slots; + *block_id = (uint32_t) (slot - e->slots); pa_mutex_unlock(e->mutex); /* pa_log("Got block id %u", *block_id); */ @@ -1115,13 +1145,13 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32 pa_assert((uint8_t*) data + b->length <= (uint8_t*) memory->ptr + memory->size); *shm_id = memory->id; - *offset = (uint8_t*) data - (uint8_t*) memory->ptr; + *offset = (size_t) ((uint8_t*) data - (uint8_t*) memory->ptr); *size = b->length; pa_memblock_release(b); pa_atomic_inc(&e->pool->stat.n_exported); - pa_atomic_add(&e->pool->stat.exported_size, b->length); + pa_atomic_add(&e->pool->stat.exported_size, (int) b->length); return 0; } diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h index efe55b02..b1eab2a9 100644 --- a/src/pulsecore/memblock.h +++ b/src/pulsecore/memblock.h @@ -117,7 +117,7 @@ pa_mempool * pa_memblock_get_pool(pa_memblock *b); pa_memblock *pa_memblock_will_need(pa_memblock *b); /* The memory block manager */ -pa_mempool* pa_mempool_new(pa_bool_t shared); +pa_mempool* pa_mempool_new(pa_bool_t shared, size_t size); void pa_mempool_free(pa_mempool *p); const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p); void pa_mempool_vacuum(pa_mempool *p); diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index 841b9075..265da37f 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -84,7 +84,8 @@ pa_memblockq* pa_memblockq_new( pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu maxrewind=%lu", (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) base, (unsigned long) prebuf, (unsigned long) minreq, (unsigned long) maxrewind); - bq->missing = bq->requested = bq->maxlength = bq->tlength = bq->prebuf = bq->minreq = bq->maxrewind = 0; + bq->missing = 0; + bq->requested = bq->maxlength = bq->tlength = bq->prebuf = bq->minreq = bq->maxrewind = 0; bq->in_prebuf = TRUE; pa_memblockq_set_maxlength(bq, maxlength); @@ -215,7 +216,7 @@ static void drop_backlog(pa_memblockq *bq) { int64_t boundary; pa_assert(bq); - boundary = bq->read_index - bq->maxrewind; + boundary = bq->read_index - (int64_t) bq->maxrewind; while (bq->blocks && (bq->blocks->index + (int64_t) bq->blocks->chunk.length <= boundary)) drop_block(bq, bq->blocks); @@ -227,10 +228,10 @@ static pa_bool_t can_push(pa_memblockq *bq, size_t l) { pa_assert(bq); if (bq->read_index > bq->write_index) { - size_t d = bq->read_index - bq->write_index; + int64_t d = bq->read_index - bq->write_index; - if (l > d) - l -= d; + if ((int64_t) l > d) + l -= (size_t) d; else return TRUE; } @@ -239,7 +240,7 @@ static pa_bool_t can_push(pa_memblockq *bq, size_t l) { /* Make sure that the list doesn't get too long */ if (bq->write_index + (int64_t) l > end) - if (bq->write_index + l - bq->read_index > bq->maxlength) + if (bq->write_index + (int64_t) l - bq->read_index > (int64_t) bq->maxlength) return FALSE; return TRUE; @@ -294,7 +295,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* This entry isn't touched at all, let's skip it */ q = q->prev; } else if (bq->write_index <= q->index && - bq->write_index + chunk.length >= q->index + q->chunk.length) { + bq->write_index + (int64_t) chunk.length >= q->index + (int64_t) q->chunk.length) { /* This entry is fully replaced by the new entry, so let's drop it */ @@ -306,7 +307,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* The write index points into this memblock, so let's * truncate or split it */ - if (bq->write_index + chunk.length < q->index + q->chunk.length) { + if (bq->write_index + (int64_t) chunk.length < q->index + (int64_t) q->chunk.length) { /* We need to save the end of this memchunk */ struct list_item *p; @@ -320,11 +321,11 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { pa_memblock_ref(p->chunk.memblock); /* Calculate offset */ - d = bq->write_index + chunk.length - q->index; + d = (size_t) (bq->write_index + (int64_t) chunk.length - q->index); pa_assert(d > 0); /* Drop it from the new entry */ - p->index = q->index + d; + p->index = q->index + (int64_t) d; p->chunk.length -= d; /* Add it to the list */ @@ -339,7 +340,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { } /* Truncate the chunk */ - if (!(q->chunk.length = bq->write_index - q->index)) { + if (!(q->chunk.length = (size_t) (bq->write_index - q->index))) { struct list_item *p; p = q; q = q->prev; @@ -357,8 +358,8 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* The job overwrites the current entry at the end, so let's drop the beginning of this entry */ - d = bq->write_index + chunk.length - q->index; - q->index += d; + d = (size_t) (bq->write_index + (int64_t) chunk.length - q->index); + q->index += (int64_t) d; q->chunk.index += d; q->chunk.length -= d; @@ -373,11 +374,11 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { /* Try to merge memory blocks */ if (q->chunk.memblock == chunk.memblock && - q->chunk.index + (int64_t)q->chunk.length == chunk.index && - bq->write_index == q->index + (int64_t)q->chunk.length) { + q->chunk.index + q->chunk.length == chunk.index && + bq->write_index == q->index + (int64_t) q->chunk.length) { q->chunk.length += chunk.length; - bq->write_index += chunk.length; + bq->write_index += (int64_t) chunk.length; goto finish; } } else @@ -389,7 +390,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { n->chunk = chunk; pa_memblock_ref(n->chunk.memblock); n->index = bq->write_index; - bq->write_index += n->chunk.length; + bq->write_index += (int64_t) n->chunk.length; n->next = q ? q->next : bq->blocks; n->prev = q; @@ -411,10 +412,10 @@ finish: delta = bq->write_index - old; if (delta >= (int64_t) bq->requested) { - delta -= bq->requested; + delta -= (int64_t) bq->requested; bq->requested = 0; } else { - bq->requested -= delta; + bq->requested -= (size_t) delta; delta = 0; } @@ -471,7 +472,7 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { /* How much silence shall we return? */ if (bq->current_read) - length = bq->current_read->index - bq->read_index; + length = (size_t) (bq->current_read->index - bq->read_index); else if (bq->write_index > bq->read_index) length = (size_t) (bq->write_index - bq->read_index); else @@ -506,8 +507,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) { pa_assert(bq->read_index >= bq->current_read->index); d = bq->read_index - bq->current_read->index; - chunk->index += d; - chunk->length -= d; + chunk->index += (size_t) d; + chunk->length -= (size_t) d; return 0; } @@ -533,20 +534,20 @@ void pa_memblockq_drop(pa_memblockq *bq, size_t length) { /* We go through this piece by piece to make sure we don't * drop more than allowed by prebuf */ - p = bq->current_read->index + bq->current_read->chunk.length; + p = bq->current_read->index + (int64_t) bq->current_read->chunk.length; pa_assert(p >= bq->read_index); d = p - bq->read_index; if (d > (int64_t) length) - d = length; + d = (int64_t) length; bq->read_index += d; - length -= d; + length -= (size_t) d; } else { /* The list is empty, there's nothing we could drop */ - bq->read_index += length; + bq->read_index += (int64_t) length; break; } } @@ -563,8 +564,8 @@ void pa_memblockq_rewind(pa_memblockq *bq, size_t length) { /* This is kind of the inverse of pa_memblockq_drop() */ - bq->read_index -= length; - bq->missing -= length; + bq->read_index -= (int64_t) length; + bq->missing -= (int64_t) length; } pa_bool_t pa_memblockq_is_readable(pa_memblockq *bq) { @@ -628,10 +629,10 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) { delta = bq->write_index - old; if (delta >= (int64_t) bq->requested) { - delta -= bq->requested; + delta -= (int64_t) bq->requested; bq->requested = 0; } else if (delta >= 0) { - bq->requested -= delta; + bq->requested -= (size_t) delta; delta = 0; } @@ -652,10 +653,10 @@ void pa_memblockq_flush_write(pa_memblockq *bq) { delta = bq->write_index - old; if (delta >= (int64_t) bq->requested) { - delta -= bq->requested; + delta -= (int64_t) bq->requested; bq->requested = 0; } else if (delta >= 0) { - bq->requested -= delta; + bq->requested -= (size_t) delta; delta = 0; } @@ -874,7 +875,7 @@ int pa_memblockq_splice(pa_memblockq *bq, pa_memblockq *source) { pa_memblock_unref(chunk.memblock); } else - pa_memblockq_seek(bq, chunk.length, PA_SEEK_RELATIVE); + pa_memblockq_seek(bq, (int64_t) chunk.length, PA_SEEK_RELATIVE); pa_memblockq_drop(bq, chunk.length); } diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h index 4b9450f6..31f908df 100644 --- a/src/pulsecore/memblockq.h +++ b/src/pulsecore/memblockq.h @@ -155,7 +155,7 @@ void pa_memblockq_set_maxlength(pa_memblockq *memblockq, size_t maxlength); /* m void pa_memblockq_set_tlength(pa_memblockq *memblockq, size_t tlength); /* might modify minreq, too */ void pa_memblockq_set_prebuf(pa_memblockq *memblockq, size_t prebuf); /* might modify minreq, too */ void pa_memblockq_set_minreq(pa_memblockq *memblockq, size_t minreq); -void pa_memblockq_set_maxrewind(pa_memblockq *memblockq, size_t rewind); /* Set the maximum history size */ +void pa_memblockq_set_maxrewind(pa_memblockq *memblockq, size_t maxrewind); /* Set the maximum history size */ void pa_memblockq_set_silence(pa_memblockq *memblockq, pa_memchunk *silence); /* Call pa_memchunk_willneed() for every chunk in the queue from the current read pointer to the end */ diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c index d257b4ce..9e60125e 100644 --- a/src/pulsecore/modargs.c +++ b/src/pulsecore/modargs.c @@ -183,7 +183,7 @@ fail: return NULL; } -static void free_func(void *p, PA_GCC_UNUSED void*userdata) { +static void free_func(void *p, void*userdata) { struct entry *e = p; pa_assert(e); diff --git a/src/pulsecore/module.c b/src/pulsecore/module.c index dbafa8c9..9b17cb91 100644 --- a/src/pulsecore/module.c +++ b/src/pulsecore/module.c @@ -48,7 +48,7 @@ #define UNLOAD_POLL_TIME 2 -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) { pa_core *c = PA_CORE(userdata); struct timeval ntv; @@ -59,7 +59,7 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED pa_module_unload_unused(c); pa_gettimeofday(&ntv); - pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000); + pa_timeval_add(&ntv, UNLOAD_POLL_TIME*PA_USEC_PER_SEC); m->time_restart(e, &ntv); } @@ -124,7 +124,7 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { if (m->auto_unload && !c->module_auto_unload_event) { struct timeval ntv; pa_gettimeofday(&ntv); - pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000); + pa_timeval_add(&ntv, UNLOAD_POLL_TIME*PA_USEC_PER_SEC); c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c); } @@ -190,7 +190,7 @@ void pa_module_unload_by_index(pa_core *c, uint32_t idx, pa_bool_t force) { pa_assert(c); pa_assert(idx != PA_IDXSET_INVALID); - if (m->core->disallow_module_loading && !force) + if (c->disallow_module_loading && !force) return; if (!(m = pa_idxset_remove_by_index(c->modules, idx))) diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c index 30420546..ecd8def8 100644 --- a/src/pulsecore/namereg.c +++ b/src/pulsecore/namereg.c @@ -45,12 +45,13 @@ struct namereg_entry { void *data; }; -static int is_valid_char(char c) { +static pa_bool_t is_valid_char(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || + c == '-' || c == '_'; } @@ -77,10 +78,10 @@ char* pa_namereg_make_valid_name(const char *name) { if (*name == 0) return NULL; - n = pa_xnew(char, strlen(name)+1); + n = pa_xmalloc(strlen(name)+1); for (a = name, b = n; *a && (a-name < PA_NAME_MAX); a++, b++) - *b = is_valid_char(*a) ? *a : '_'; + *b = (char) (is_valid_char(*a) ? *a : '_'); *b = 0; @@ -97,7 +98,7 @@ void pa_namereg_free(pa_core *c) { pa_hashmap_free(c->namereg, NULL, NULL); } -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) { +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, pa_bool_t fail) { struct namereg_entry *e; char *n = NULL; @@ -136,7 +137,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t return NULL; } - k = pa_xnew(char, l+4); + k = pa_xmalloc(l+4); for (i = 2; i <= 99; i++) { pa_snprintf(k, l+4, "%s.%u", name, i); diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h index 3c1de8e7..f4581006 100644 --- a/src/pulsecore/namereg.h +++ b/src/pulsecore/namereg.h @@ -35,7 +35,7 @@ typedef enum pa_namereg_type { void pa_namereg_free(pa_core *c); -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, pa_bool_t fail); void pa_namereg_unregister(pa_core *c, const char *name); void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, pa_bool_t autoload); int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h index 7dcfa2eb..2ee4fc31 100644 --- a/src/pulsecore/object.h +++ b/src/pulsecore/object.h @@ -42,7 +42,7 @@ struct pa_object { pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(const char *type_name)); #define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), #type, type##_check_type) -#define pa_object_free ((void (*) (pa_object* o)) pa_xfree) +#define pa_object_free ((void (*) (pa_object* _obj)) pa_xfree) int pa_object_check_type(const char *type); diff --git a/src/pulsecore/once.c b/src/pulsecore/once.c index 989741dc..3d4543cb 100644 --- a/src/pulsecore/once.c +++ b/src/pulsecore/once.c @@ -28,13 +28,13 @@ #include "once.h" -int pa_once_begin(pa_once *control) { +pa_bool_t pa_once_begin(pa_once *control) { pa_mutex *m; pa_assert(control); if (pa_atomic_load(&control->done)) - return 0; + return FALSE; pa_atomic_inc(&control->ref); @@ -50,15 +50,17 @@ int pa_once_begin(pa_once *control) { * wait until it is unlocked */ pa_mutex_lock(m); + pa_assert(pa_atomic_load(&control->done)); + pa_once_end(control); - return 0; + return FALSE; } pa_assert_se(m = pa_mutex_new(FALSE, FALSE)); pa_mutex_lock(m); if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m)) - return 1; + return TRUE; pa_mutex_unlock(m); pa_mutex_free(m); @@ -91,4 +93,3 @@ void pa_run_once(pa_once *control, pa_once_func_t func) { pa_once_end(control); } } - diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h index 576d40fa..c0191ef0 100644 --- a/src/pulsecore/once.h +++ b/src/pulsecore/once.h @@ -38,7 +38,7 @@ typedef struct pa_once { } /* Not to be called directly, use the macros defined below instead */ -int pa_once_begin(pa_once *o); +pa_bool_t pa_once_begin(pa_once *o); void pa_once_end(pa_once *o); #define PA_ONCE_BEGIN \ diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c index f2b6b2cf..c5cd7fe7 100644 --- a/src/pulsecore/parseaddr.c +++ b/src/pulsecore/parseaddr.c @@ -51,20 +51,29 @@ static char *parse_host(const char *s, uint16_t *ret_port) { if (!(e = strchr(s+1, ']'))) return NULL; - if (e[1] == ':') - *ret_port = atoi(e+2); - else if (e[1] != 0) + if (e[1] == ':') { + uint32_t p; + + if (pa_atou(e+2, &p) < 0) + return NULL; + + *ret_port = (uint16_t) p; + } else if (e[1] != 0) return NULL; - return pa_xstrndup(s+1, e-s-1); + return pa_xstrndup(s+1, (size_t) (e-s-1)); } else { char *e; + uint32_t p; if (!(e = strrchr(s, ':'))) return pa_xstrdup(s); - *ret_port = atoi(e+1); - return pa_xstrndup(s, e-s); + if (pa_atou(e+1, &p) < 0) + return NULL; + + *ret_port = (uint16_t) p; + return pa_xstrndup(s, (size_t) (e-s)); } } diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index e6a6ae4d..00df0f79 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -255,7 +255,7 @@ finish: return ret; } -static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { +static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata) { struct reply_info*r = userdata; pa_assert(r); diff --git a/src/pulsecore/pid.c b/src/pulsecore/pid.c index addb17cc..bf9ba983 100644 --- a/src/pulsecore/pid.c +++ b/src/pulsecore/pid.c @@ -73,6 +73,7 @@ static pid_t read_pid(const char *fn, int fd) { if (pa_atou(t, &pid) < 0) { pa_log_warn("Failed to parse PID file '%s'", fn); + errno = EINVAL; return (pid_t) -1; } @@ -110,7 +111,7 @@ static int open_pid_file(const char *fn, int mode) { goto fail; } - /* Does the file still exist in the file system? When ye, w're done, otherwise restart */ + /* Does the file still exist in the file system? When yes, we're done, otherwise restart */ if (st.st_nlink >= 1) break; @@ -131,8 +132,10 @@ static int open_pid_file(const char *fn, int mode) { fail: if (fd >= 0) { + int saved_errno = errno; pa_lock_fd(fd, 0); pa_close(fd); + errno = saved_errno; } return -1; @@ -154,8 +157,11 @@ static int proc_name_ours(pid_t pid, const char *procname) { char stored[64]; if (!(fgets(stored, sizeof(stored), f))) { + int saved_errno = feof(f) ? EINVAL : errno; pa_log_info("Failed to read from %s: %s", bn, feof(f) ? "EOF" : pa_cstrerror(errno)); fclose(f); + + errno = saved_errno; return -1; } @@ -165,20 +171,22 @@ static int proc_name_ours(pid_t pid, const char *procname) { good = pa_startswith(stored, expected); pa_xfree(expected); -#if !defined(__OPTIMIZE__) +/*#if !defined(__OPTIMIZE__)*/ if (!good) { /* libtool likes to rename our binary names ... */ expected = pa_sprintf_malloc("%lu (lt-%s)", (unsigned long) pid, procname); good = pa_startswith(stored, expected); pa_xfree(expected); } -#endif +/*#endif*/ return !!good; } -#endif +#else return 1; +#endif + } /* Create a new PID file for the current process. */ @@ -203,6 +211,7 @@ int pa_pid_file_create(const char *procname) { if ((pid = read_pid(fn, fd)) == (pid_t) -1) pa_log_warn("Corrupt PID file, overwriting."); else if (pid > 0) { + int ours = 1; #ifdef OS_IS_WIN32 if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) { @@ -210,11 +219,13 @@ int pa_pid_file_create(const char *procname) { #else if (kill(pid, 0) >= 0 || errno != ESRCH) { #endif - int ours = 1; if (procname) - if ((ours = proc_name_ours(pid, procname)) < 0) + if ((ours = proc_name_ours(pid, procname)) < 0) { + pa_log_warn("Could not check to see if pid %lu is a pulseaudio process. " + "Asssuming it is and the daemon is already running.", (unsigned long) pid); goto fail; + } if (ours) { pa_log("Daemon already running."); @@ -227,7 +238,7 @@ int pa_pid_file_create(const char *procname) { } /* Overwrite the current PID file */ - if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) { + if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, (off_t) 0) < 0) { pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -280,7 +291,7 @@ int pa_pid_file_remove(void) { goto fail; } - if (ftruncate(fd, 0) < 0) { + if (ftruncate(fd, (off_t) 0) < 0) { pa_log_warn("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno)); goto fail; } @@ -342,8 +353,13 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) { if (!(fn = pa_runtime_path("pid"))) goto fail; - if ((fd = open_pid_file(fn, O_RDONLY)) < 0) + if ((fd = open_pid_file(fn, O_RDONLY)) < 0) { + + if (errno == ENOENT) + errno = ESRCH; + goto fail; + } if ((*pid = read_pid(fn, fd)) == (pid_t) -1) goto fail; @@ -354,8 +370,10 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) { if ((ours = proc_name_ours(*pid, procname)) < 0) goto fail; - if (!ours) + if (!ours) { + errno = ESRCH; goto fail; + } } ret = kill(*pid, sig); @@ -363,8 +381,10 @@ int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) { fail: if (fd >= 0) { + int saved_errno = errno; pa_lock_fd(fd, 0); pa_close(fd); + errno = saved_errno; } #ifdef __linux__ diff --git a/src/pulsecore/prioq.c b/src/pulsecore/prioq.c new file mode 100644 index 00000000..693dc517 --- /dev/null +++ b/src/pulsecore/prioq.c @@ -0,0 +1,256 @@ +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <pulse/xmalloc.h> + +#include <pulsecore/flist.h> + +#include "prioq.h" + +struct pa_prioq_item { + void *value; + unsigned idx; +}; + +struct pa_prioq { + pa_prioq_item **items; + unsigned n_items; + unsigned n_allocated; + pa_compare_func_t compare_func; +}; + +PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree); + +pa_prioq *pa_prioq_new(pa_compare_func_t compare_func) { + + pa_prioq *q; + + q = pa_xnew(pa_prioq, 1); + q->compare_func = compare_func; + q->n_items = 0; + q->n_allocated = 64; + q->items = pa_xnew(pa_prioq_item*, q->n_allocated); + + return q; +} + +void pa_prioq_free(pa_prioq *q, pa_free2_cb_t free_cb, void *userdata) { + pa_prioq_item **i, **e; + + pa_assert(q); + + for (i = q->items, e = q->items + q->n_items; i < e; i++) { + + if (!*i) + continue; + + if (free_cb) + free_cb((*i)->value, userdata); + + pa_xfree(*i); + } + + pa_xfree(q->items); + pa_xfree(q); +} + +static void shuffle_up(pa_prioq *q, pa_prioq_item *i) { + unsigned j; + + pa_assert(q); + pa_assert(i); + + j = i->idx; + + while (j > 0) { + unsigned k; + + k = (j-1)/2; + + if (q->compare_func(q->items[k]->value, i->value) < 0) + break; + + q->items[k]->idx = j; + q->items[j] = q->items[k]; + + j = k; + } + + i->idx = j; + q->items[j] = i; + +} + +pa_prioq_item* pa_prioq_put(pa_prioq *q, void *p) { + pa_prioq_item *i; + + pa_assert(q); + + if (q->n_items >= q->n_allocated) { + q->n_allocated = PA_MAX(q->n_items+1, q->n_allocated)*2; + q->items = pa_xrealloc(q->items, sizeof(pa_prioq_item*) * q->n_allocated); + } + + if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items)))) + i = pa_xnew(pa_prioq_item, 1); + + i->value = p; + i->idx = q->n_items++; + + shuffle_up(q, i); + + return i; +} + +void* pa_prioq_peek(pa_prioq *q) { + pa_assert(q); + + if (q->n_items <= 0) + return NULL; + + return q->items[0]->value; +} + +void* pa_prioq_pop(pa_prioq *q){ + pa_assert(q); + + if (q->n_items <= 0) + return NULL; + + return pa_prioq_remove(q, q->items[0]); +} + +static void swap(pa_prioq *q, unsigned j, unsigned k) { + pa_prioq_item *t; + + pa_assert(q); + pa_assert(j < q->n_items); + pa_assert(k < q->n_items); + + pa_assert(q->items[j]->idx == j); + pa_assert(q->items[k]->idx == k); + + t = q->items[j]; + + q->items[j]->idx = k; + q->items[j] = q->items[k]; + + q->items[k]->idx = j; + q->items[k] = t; +} + +static void shuffle_down(pa_prioq *q, unsigned idx) { + + pa_assert(q); + pa_assert(idx < q->n_items); + + for (;;) { + unsigned j, k, s; + + k = (idx+1)*2; /* right child */ + j = k-1; /* left child */ + + if (j >= q->n_items) + break; + + if (q->compare_func(q->items[j]->value, q->items[idx]->value) < 0) + + /* So our left child is smaller than we are, let's + * remember this fact */ + s = j; + else + s = idx; + + if (k < q->n_items && + q->compare_func(q->items[k]->value, q->items[s]->value) < 0) + + /* So our right child is smaller than we are, let's + * remember this fact */ + s = k; + + /* s now points to the smallest of the three items */ + + if (s == idx) + /* No swap necessary, we're done */ + break; + + swap(q, idx, s); + idx = s; + } +} + +void* pa_prioq_remove(pa_prioq *q, pa_prioq_item *i) { + void *p; + + pa_assert(q); + pa_assert(i); + pa_assert(q->n_items >= 1); + + p = i->value; + + if (q->n_items-1 == i->idx) { + /* We are the last entry, so let's just remove us and good */ + q->n_items--; + + } else { + + /* We are not the last entry, we need to replace ourselves + * with the last node and reshuffle */ + + q->items[i->idx] = q->items[q->n_items-1]; + q->items[i->idx]->idx = i->idx; + q->n_items--; + + shuffle_down(q, i->idx); + } + + if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0) + pa_xfree(i); + + return p; +} + +unsigned pa_prioq_size(pa_prioq *q) { + pa_assert(q); + + return q->n_items; +} + +pa_bool_t pa_prioq_isempty(pa_prioq *q) { + pa_assert(q); + + return q->n_items == 0; +} + +void pa_prioq_reshuffle(pa_prioq *q, pa_prioq_item *i) { + pa_assert(q); + pa_assert(i); + + /* This will move the entry down as far as necessary */ + shuffle_down(q, i->idx); + + /* And this will move the entry up as far as necessary */ + shuffle_up(q, i); +} diff --git a/src/pulsecore/prioq.h b/src/pulsecore/prioq.h new file mode 100644 index 00000000..fd3550b7 --- /dev/null +++ b/src/pulsecore/prioq.h @@ -0,0 +1,64 @@ +#ifndef foopulsecoreprioqhfoo +#define foopulsecoreprioqhfoo + +/*** + This file is part of PulseAudio. + + Copyright 2008 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include <inttypes.h> + +#include <pulsecore/macro.h> +#include <pulsecore/idxset.h> + +/* A heap-based priority queue. Removal and insertion is O(log + * n). Removal can happen a the top or at any position referenced by a + * pa_prioq_item. */ + +typedef struct pa_prioq pa_prioq; +typedef struct pa_prioq_item pa_prioq_item; + +/* Instantiate a new prioq with the specified comparison functions */ +pa_prioq* pa_prioq_new(pa_compare_func_t compare_func); + +/* Free the prioq. When the prioq is not empty the specified function is called for every entry contained */ +void pa_prioq_free(pa_prioq *q, pa_free2_cb_t free_cb, void *userdata); + +/* Store a new item in the prioq. */ +pa_prioq_item* pa_prioq_put(pa_prioq *q, void* data); + +/* Get the item on the top of the queue, but don't remove it from the queue*/ +void* pa_prioq_peek(pa_prioq*q); + +/* Get the item on the top of the queue, and remove it from thq queue */ +void* pa_prioq_pop(pa_prioq*q); + +/* Remove an arbitrary from theq prioq, returning it's data */ +void* pa_prioq_remove(pa_prioq*q, pa_prioq_item *i); + +/* The priority of an item was modified. Adjustthe queue to that */ +void pa_prioq_reshuffle(pa_prioq *q, pa_prioq_item *i); + +/* Return the current number of items in the prioq */ +unsigned pa_prioq_size(pa_prioq*s); + +/* Return TRUE of the prioq is empty */ +pa_bool_t pa_prioq_isempty(pa_prioq *s); + +#endif diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c index 6005775e..4d505f57 100644 --- a/src/pulsecore/proplist-util.c +++ b/src/pulsecore/proplist-util.c @@ -37,7 +37,7 @@ void pa_init_proplist(pa_proplist *p) { int a, b; -#ifndef HAVE_DECL_ENVIRON +#if !HAVE_DECL_ENVIRON extern char **environ; #endif char **e; diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 4f121a3a..460119a9 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -184,7 +184,7 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, /* 8 */ { sizeof(int), NULL, "sample loop" }, { sizeof(int), NULL, "sample stop" }, - { -1, NULL, "TODO: sample kill" }, + { (size_t) -1, NULL, "TODO: sample kill" }, { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "standby" }, /* NOOP! */ { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "resume" }, /* NOOP! */ /* 13 */ @@ -194,8 +194,8 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { sizeof(int), esd_proto_server_info, "server info" }, { sizeof(int), esd_proto_all_info, "all info" }, - { -1, NULL, "TODO: subscribe" }, - { -1, NULL, "TODO: unsubscribe" }, + { (size_t) -1, NULL, "TODO: subscribe" }, + { (size_t) -1, NULL, "TODO: unsubscribe" }, { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, { 3 * sizeof(int), NULL, "sample pan" }, @@ -309,7 +309,7 @@ static void connection_write(connection *c, const void *data, size_t length) { static void format_esd2native(int format, pa_bool_t swap_bytes, pa_sample_spec *ss) { pa_assert(ss); - ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + ss->channels = (uint8_t) (((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1); if ((format & ESD_MASK_BITS) == ESD_BITS16) ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE; else @@ -334,7 +334,7 @@ static int format_native2esd(pa_sample_spec *ss) { /*** esound commands ***/ -static int esd_proto_connect(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_connect(connection *c, esd_proto_t request, const void *data, size_t length) { uint32_t ekey; int ok; @@ -377,7 +377,7 @@ static int esd_proto_connect(connection *c, PA_GCC_UNUSED esd_proto_t request, c return 0; } -static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_play(connection *c, esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; pa_sample_spec ss; @@ -397,7 +397,7 @@ static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t reques rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); data = (const char*) data + sizeof(int32_t); - ss.rate = rate; + ss.rate = (uint32_t) rate; format_esd2native(format, c->swap_byte_order, &ss); CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification"); @@ -430,7 +430,7 @@ static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t reques CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); - l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); + l = (size_t) ((double) pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); c->input_memblockq = pa_memblockq_new( 0, l, @@ -455,7 +455,7 @@ static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t reques c->protocol->n_player++; - pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq)); + pa_atomic_store(&c->playback.missing, (int) pa_memblockq_missing(c->input_memblockq)); pa_sink_input_put(c->sink_input); @@ -482,7 +482,7 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); data = (const char*) data + sizeof(int32_t); - ss.rate = rate; + ss.rate = (uint32_t) rate; format_esd2native(format, c->swap_byte_order, &ss); CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); @@ -561,7 +561,7 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi return 0; } -static int esd_proto_get_latency(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_get_latency(connection *c, esd_proto_t request, const void *data, size_t length) { pa_sink *sink; int32_t latency; @@ -572,7 +572,7 @@ static int esd_proto_get_latency(connection *c, PA_GCC_UNUSED esd_proto_t reques if (!(sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK, 1))) latency = 0; else { - double usec = pa_sink_get_latency(sink); + double usec = (double) pa_sink_get_latency(sink); latency = (int) ((usec*44100)/1000000); } @@ -581,7 +581,7 @@ static int esd_proto_get_latency(connection *c, PA_GCC_UNUSED esd_proto_t reques return 0; } -static int esd_proto_server_info(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_server_info(connection *c, esd_proto_t request, const void *data, size_t length) { int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16; int32_t response; pa_sink *sink; @@ -591,7 +591,7 @@ static int esd_proto_server_info(connection *c, PA_GCC_UNUSED esd_proto_t reques pa_assert(length == sizeof(int32_t)); if ((sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK, 1))) { - rate = sink->sample_spec.rate; + rate = (int32_t) sink->sample_spec.rate; format = format_native2esd(&sink->sample_spec); } @@ -641,9 +641,9 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da if (conn->sink_input) { pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); - rate = conn->sink_input->sample_spec.rate; - lvolume = (volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; - rvolume = (volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + rate = (int32_t) conn->sink_input->sample_spec.rate; + lvolume = (int32_t) ((volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + rvolume = (int32_t) ((volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); format = format_native2esd(&conn->sink_input->sample_spec); } @@ -706,15 +706,15 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da connection_write(c, name, ESD_NAME_MAX); /* rate */ - rate = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ce->sample_spec.rate); connection_write(c, &rate, sizeof(int32_t)); /* left */ - lvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + lvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ((ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM)); connection_write(c, &lvolume, sizeof(int32_t)); /*right*/ - rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + rvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) ((ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM)); connection_write(c, &rvolume, sizeof(int32_t)); /*format*/ @@ -736,7 +736,7 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da return 0; } -static int esd_proto_stream_pan(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *data, size_t length) { int32_t ok; uint32_t idx, lvolume, rvolume; connection *conn; @@ -772,7 +772,7 @@ static int esd_proto_stream_pan(connection *c, PA_GCC_UNUSED esd_proto_t request return 0; } -static int esd_proto_sample_cache(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_cache(connection *c, esd_proto_t request, const void *data, size_t length) { pa_sample_spec ss; int32_t format, rate, sc_length; uint32_t idx; @@ -790,7 +790,7 @@ static int esd_proto_sample_cache(connection *c, PA_GCC_UNUSED esd_proto_t reque rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); data = (const char*)data + sizeof(int32_t); - ss.rate = rate; + ss.rate = (uint32_t) rate; format_esd2native(format, c->swap_byte_order, &ss); CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); @@ -807,9 +807,9 @@ static int esd_proto_sample_cache(connection *c, PA_GCC_UNUSED esd_proto_t reque CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); pa_assert(!c->scache.memchunk.memblock); - c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, sc_length); + c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, (size_t) sc_length); c->scache.memchunk.index = 0; - c->scache.memchunk.length = sc_length; + c->scache.memchunk.length = (size_t) sc_length; c->scache.sample_spec = ss; pa_assert(!c->scache.name); c->scache.name = pa_xstrdup(name); @@ -824,7 +824,7 @@ static int esd_proto_sample_cache(connection *c, PA_GCC_UNUSED esd_proto_t reque return 0; } -static int esd_proto_sample_get_id(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_get_id(connection *c, esd_proto_t request, const void *data, size_t length) { int32_t ok; uint32_t idx; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; @@ -840,7 +840,7 @@ static int esd_proto_sample_get_id(connection *c, PA_GCC_UNUSED esd_proto_t requ ok = -1; if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) - ok = idx + 1; + ok = (int32_t) idx + 1; connection_write(c, &ok, sizeof(int32_t)); @@ -867,12 +867,12 @@ static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, con if ((sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK, 1))) if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM, c->client->proplist, NULL) >= 0) - ok = idx + 1; + ok = (int32_t) idx + 1; } else { pa_assert(request == ESD_PROTO_SAMPLE_FREE); if (pa_scache_remove_item(c->protocol->core, name) >= 0) - ok = idx + 1; + ok = (int32_t) idx + 1; } } @@ -881,7 +881,7 @@ static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, con return 0; } -static int esd_proto_standby_or_resume(connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { +static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const void *data, size_t length) { int32_t ok; connection_assert_ref(c); @@ -919,7 +919,9 @@ static int do_read(connection *c) { return -1; } - if ((c->read_data_length+= r) >= sizeof(c->request)) { + c->read_data_length += (size_t) r; + + if (c->read_data_length >= sizeof(c->request)) { struct proto_handler *handler; c->request = PA_MAYBE_INT32_SWAP(c->swap_byte_order, c->request); @@ -970,7 +972,8 @@ static int do_read(connection *c) { return -1; } - if ((c->read_data_length += r) >= handler->data_length) { + c->read_data_length += (size_t) r; + if (c->read_data_length >= handler->data_length) { size_t l = c->read_data_length; pa_assert(handler->proc); @@ -1000,7 +1003,7 @@ static int do_read(connection *c) { return -1; } - c->scache.memchunk.index += r; + c->scache.memchunk.index += (size_t) r; pa_assert(c->scache.memchunk.index <= c->scache.memchunk.length); if (c->scache.memchunk.index == c->scache.memchunk.length) { @@ -1033,7 +1036,7 @@ static int do_read(connection *c) { /* pa_log("STREAMING_DATA"); */ - if (!(l = pa_atomic_load(&c->playback.missing))) + if (!(l = (size_t) pa_atomic_load(&c->playback.missing))) return 0; if (c->playback.current_memblock) { @@ -1071,12 +1074,12 @@ static int do_read(connection *c) { chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; - chunk.length = r; + chunk.length = (size_t) r; - c->playback.memblock_index += r; + c->playback.memblock_index += (size_t) r; pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL); - pa_atomic_sub(&c->playback.missing, r); + pa_atomic_sub(&c->playback.missing, (int) r); } return 0; @@ -1100,7 +1103,8 @@ static int do_write(connection *c) { return -1; } - if ((c->write_data_index +=r) >= c->write_data_length) + c->write_data_index += (size_t) r; + if (c->write_data_index >= c->write_data_length) c->write_data_length = c->write_data_index = 0; } else if (c->state == ESD_STREAMING_DATA && c->source_output) { @@ -1129,7 +1133,7 @@ static int do_write(connection *c) { return -1; } - pa_memblockq_drop(c->output_memblockq, r); + pa_memblockq_drop(c->output_memblockq, (size_t) r); } return 0; @@ -1288,7 +1292,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk m = pa_memblockq_pop_missing(c->input_memblockq); if (m > 0) - if (pa_atomic_add(&c->playback.missing, m) <= 0) + if (pa_atomic_add(&c->playback.missing, (int) m) <= 0) pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); return 0; @@ -1574,7 +1578,7 @@ int pa_esound_options_parse(pa_esound_options *o, pa_core *c, pa_modargs *ma) { if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { pa_ip_acl *ipa; - if (!(o->auth_ip_acl = pa_ip_acl_new(acl))) { + if (!(ipa = pa_ip_acl_new(acl))) { pa_log("Failed to parse IP ACL '%s'", acl); return -1; } diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index b9f6f083..56e86cb4 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -469,51 +469,102 @@ static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, i return 0; } -static void fix_record_buffer_attr_pre(record_stream *s, pa_bool_t adjust_latency, uint32_t *maxlength, uint32_t *fragsize) { +static void fix_record_buffer_attr_pre( + record_stream *s, + pa_bool_t adjust_latency, + pa_bool_t early_requests, + uint32_t *maxlength, + uint32_t *fragsize) { + + size_t frame_size; + pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec; + pa_assert(s); pa_assert(maxlength); pa_assert(fragsize); + frame_size = pa_frame_size(&s->source_output->sample_spec); + if (*maxlength == (uint32_t) -1 || *maxlength > MAX_MEMBLOCKQ_LENGTH) *maxlength = MAX_MEMBLOCKQ_LENGTH; if (*maxlength <= 0) - *maxlength = pa_frame_size(&s->source_output->sample_spec); + *maxlength = (uint32_t) frame_size; if (*fragsize == (uint32_t) -1) - *fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec); + *fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec); if (*fragsize <= 0) - *fragsize = pa_frame_size(&s->source_output->sample_spec); + *fragsize = (uint32_t) frame_size; + + orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(*fragsize, &s->source_output->sample_spec); - if (adjust_latency) { - pa_usec_t fragsize_usec; + if (early_requests) { + + /* In early request mode we need to emulate the classic + * fragment-based playback model. We do this setting the source + * latency to the fragment size. */ + + source_usec = fragsize_usec; + + } else if (adjust_latency) { /* So, the user asked us to adjust the latency according to * what the source can provide. Half the latency will be * spent on the hw buffer, half of it in the async buffer * queue we maintain for each client. */ - fragsize_usec = pa_bytes_to_usec(*fragsize, &s->source_output->sample_spec); + source_usec = fragsize_usec/2; + + } else { + + /* Ok, the user didn't ask us to adjust the latency, hence we + * don't */ - s->source_latency = pa_source_output_set_requested_latency(s->source_output, fragsize_usec/2); + source_usec = 0; + } + + if (source_usec > 0) + s->source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec); + else + s->source_latency = 0; + + if (early_requests) { + + /* Ok, we didn't necessarily get what we were asking for, so + * let's tell the user */ + + fragsize_usec = s->source_latency; + + } else if (adjust_latency) { + + /* Now subtract what we actually got */ if (fragsize_usec >= s->source_latency*2) fragsize_usec -= s->source_latency; else fragsize_usec = s->source_latency; + } - *fragsize = pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec); - } else - s->source_latency = 0; + if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) != + pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec)) + + *fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec); + + if (*fragsize <= 0) + *fragsize = (uint32_t) frame_size; } -static void fix_record_buffer_attr_post(record_stream *s, uint32_t *maxlength, uint32_t *fragsize) { +static void fix_record_buffer_attr_post( + record_stream *s, + uint32_t *maxlength, + uint32_t *fragsize) { + size_t base; pa_assert(s); pa_assert(maxlength); pa_assert(fragsize); - *maxlength = pa_memblockq_get_maxlength(s->memblockq); + *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq); base = pa_frame_size(&s->source_output->sample_spec); @@ -524,7 +575,7 @@ static void fix_record_buffer_attr_post(record_stream *s, uint32_t *maxlength, u if (s->fragment_size > *maxlength) s->fragment_size = *maxlength; - *fragsize = s->fragment_size; + *fragsize = (uint32_t) s->fragment_size; } static record_stream* record_stream_new( @@ -538,7 +589,8 @@ static record_stream* record_stream_new( pa_source_output_flags_t flags, pa_proplist *p, pa_bool_t adjust_latency, - pa_sink_input *direct_on_input) { + pa_sink_input *direct_on_input, + pa_bool_t early_requests) { record_stream *s; pa_source_output *source_output; @@ -584,7 +636,7 @@ static record_stream* record_stream_new( s->source_output->suspend = source_output_suspend_cb; s->source_output->userdata = s; - fix_record_buffer_attr_pre(s, adjust_latency, maxlength, fragsize); + fix_record_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, fragsize); s->memblockq = pa_memblockq_new( 0, @@ -666,10 +718,10 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, uint32_t l = 0; for (;;) { - if ((l = pa_atomic_load(&s->missing)) <= 0) + if ((l = (uint32_t) pa_atomic_load(&s->missing)) <= 0) break; - if (pa_atomic_cmpxchg(&s->missing, l, 0)) + if (pa_atomic_cmpxchg(&s->missing, (int) l, 0)) break; } @@ -690,6 +742,8 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: { pa_tagstruct *t; +/* pa_log("signalling underflow"); */ + /* Report that we're empty */ t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW); @@ -734,9 +788,17 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, return 0; } -static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_latency, uint32_t *maxlength, uint32_t *tlength, uint32_t* prebuf, uint32_t* minreq) { +static void fix_playback_buffer_attr_pre( + playback_stream *s, + pa_bool_t adjust_latency, + pa_bool_t early_requests, + uint32_t *maxlength, + uint32_t *tlength, + uint32_t* prebuf, + uint32_t* minreq) { + size_t frame_size; - pa_usec_t tlength_usec, minreq_usec, sink_usec; + pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec; pa_assert(s); pa_assert(maxlength); @@ -749,29 +811,39 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la if (*maxlength == (uint32_t) -1 || *maxlength > MAX_MEMBLOCKQ_LENGTH) *maxlength = MAX_MEMBLOCKQ_LENGTH; if (*maxlength <= 0) - *maxlength = frame_size; + *maxlength = (uint32_t) frame_size; if (*tlength == (uint32_t) -1) - *tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); + *tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); if (*tlength <= 0) - *tlength = frame_size; + *tlength = (uint32_t) frame_size; if (*minreq == (uint32_t) -1) - *minreq = pa_usec_to_bytes(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); + *minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); if (*minreq <= 0) - *minreq = frame_size; + *minreq = (uint32_t) frame_size; if (*tlength < *minreq+frame_size) - *tlength = *minreq+frame_size; + *tlength = *minreq+(uint32_t) frame_size; - tlength_usec = pa_bytes_to_usec(*tlength, &s->sink_input->sample_spec); - minreq_usec = pa_bytes_to_usec(*minreq, &s->sink_input->sample_spec); + orig_tlength_usec = tlength_usec = pa_bytes_to_usec(*tlength, &s->sink_input->sample_spec); + orig_minreq_usec = minreq_usec = pa_bytes_to_usec(*minreq, &s->sink_input->sample_spec); pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms", (double) tlength_usec / PA_USEC_PER_MSEC, (double) minreq_usec / PA_USEC_PER_MSEC); - if (adjust_latency) { + if (early_requests) { + + /* In early request mode we need to emulate the classic + * fragment-based playback model. We do this setting the sink + * latency to the fragment size. */ + + sink_usec = minreq_usec; + + pa_log_debug("Early requests mode enabled, configuring sink latency to minreq."); + + } else if (adjust_latency) { /* So, the user asked us to adjust the latency of the stream * buffer according to the what the sink can provide. The @@ -795,6 +867,8 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la else sink_usec = 0; + pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency."); + } else { /* Ok, the user didn't ask us to adjust the latency, but we @@ -805,11 +879,21 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la sink_usec = (tlength_usec - minreq_usec*2); else sink_usec = 0; + + pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq."); } s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec); - if (adjust_latency) { + if (early_requests) { + + /* Ok, we didn't necessarily get what we were asking for, so + * let's tell the user */ + + minreq_usec = s->sink_latency; + + } else if (adjust_latency) { + /* Ok, we didn't necessarily get what we were asking for, so * let's subtract from what we asked for for the remaining * buffer space */ @@ -823,22 +907,33 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la if (tlength_usec < s->sink_latency + 2*minreq_usec) tlength_usec = s->sink_latency + 2*minreq_usec; - *tlength = pa_usec_to_bytes(tlength_usec, &s->sink_input->sample_spec); - *minreq = pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec); + if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) != + pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec)) + *tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec); + + if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) != + pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec)) + *minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec); if (*minreq <= 0) { - *minreq += frame_size; - *tlength += frame_size*2; + *minreq = (uint32_t) frame_size; + *tlength += (uint32_t) frame_size*2; } if (*tlength <= *minreq) - *tlength = *minreq*2 + frame_size; + *tlength = *minreq*2 + (uint32_t) frame_size; if (*prebuf == (uint32_t) -1 || *prebuf > *tlength) *prebuf = *tlength; } -static void fix_playback_buffer_attr_post(playback_stream *s, uint32_t *maxlength, uint32_t *tlength, uint32_t* prebuf, uint32_t* minreq) { +static void fix_playback_buffer_attr_post( + playback_stream *s, + uint32_t *maxlength, + uint32_t *tlength, + uint32_t* prebuf, + uint32_t* minreq) { + pa_assert(s); pa_assert(maxlength); pa_assert(tlength); @@ -864,11 +959,13 @@ static playback_stream* playback_stream_new( uint32_t *minreq, pa_cvolume *volume, pa_bool_t muted, + pa_bool_t muted_set, uint32_t syncid, uint32_t *missing, pa_sink_input_flags_t flags, pa_proplist *p, - pa_bool_t adjust_latency) { + pa_bool_t adjust_latency, + pa_bool_t early_requests) { playback_stream *s, *ssync; pa_sink_input *sink_input; @@ -883,7 +980,6 @@ static playback_stream* playback_stream_new( pa_assert(tlength); pa_assert(prebuf); pa_assert(minreq); - pa_assert(volume); pa_assert(missing); pa_assert(p); @@ -916,8 +1012,10 @@ static playback_stream* playback_stream_new( data.sink = sink; pa_sink_input_new_data_set_sample_spec(&data, ss); pa_sink_input_new_data_set_channel_map(&data, map); - pa_sink_input_new_data_set_volume(&data, volume); - pa_sink_input_new_data_set_muted(&data, muted); + if (volume) + pa_sink_input_new_data_set_volume(&data, volume); + if (muted_set) + pa_sink_input_new_data_set_muted(&data, muted); data.sync_base = ssync ? ssync->sink_input : NULL; sink_input = pa_sink_input_new(c->protocol->core, &data, flags); @@ -949,7 +1047,7 @@ static playback_stream* playback_stream_new( start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0; - fix_playback_buffer_attr_pre(s, adjust_latency, maxlength, tlength, prebuf, minreq); + fix_playback_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, tlength, prebuf, minreq); pa_sink_input_get_silence(sink_input, &silence); s->memblockq = pa_memblockq_new( @@ -982,7 +1080,6 @@ static playback_stream* playback_stream_new( return s; } - /* Called from thread context */ static void playback_stream_request_bytes(playback_stream *s) { size_t m, previous_missing; @@ -996,7 +1093,7 @@ static void playback_stream_request_bytes(playback_stream *s) { /* pa_log("request_bytes(%lu)", (unsigned long) m); */ - previous_missing = pa_atomic_add(&s->missing, m); + previous_missing = (size_t) pa_atomic_add(&s->missing, (int) m); if (pa_memblockq_prebuf_active(s->memblockq) || (previous_missing < s->minreq && previous_missing+m >= s->minreq)) @@ -1142,7 +1239,7 @@ static void handle_seek(playback_stream *s, int64_t indexw) { pa_log_debug("Requesting rewind due to end of underrun."); pa_sink_input_request_rewind(s->sink_input, - s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for, + (size_t) (s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for), FALSE, TRUE); } @@ -1156,7 +1253,7 @@ static void handle_seek(playback_stream *s, int64_t indexw) { * let's have it usk us again */ pa_log_debug("Requesting rewind due to rewrite."); - pa_sink_input_request_rewind(s->sink_input, indexr - indexw, TRUE, FALSE); + pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE); } } @@ -1196,7 +1293,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { 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, chunk->length, PA_SEEK_RELATIVE); + pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE); } handle_seek(s, windex); @@ -1426,7 +1523,7 @@ static void sink_input_moved_cb(pa_sink_input *i) { prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq); minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq); - fix_playback_buffer_attr_pre(s, TRUE, &maxlength, &tlength, &prebuf, &minreq); + fix_playback_buffer_attr_pre(s, TRUE, FALSE, &maxlength, &tlength, &prebuf, &minreq); pa_memblockq_set_maxlength(s->memblockq, maxlength); pa_memblockq_set_tlength(s->memblockq, tlength); pa_memblockq_set_prebuf(s->memblockq, prebuf); @@ -1525,7 +1622,7 @@ static void source_output_moved_cb(pa_source_output *o) { fragsize = (uint32_t) s->fragment_size; maxlength = (uint32_t) pa_memblockq_get_length(s->memblockq); - fix_record_buffer_attr_pre(s, TRUE, &maxlength, &fragsize); + fix_record_buffer_attr_pre(s, TRUE, FALSE, &maxlength, &fragsize); pa_memblockq_set_maxlength(s->memblockq, maxlength); fix_record_buffer_attr_post(s, &maxlength, &fragsize); @@ -1572,7 +1669,7 @@ static pa_tagstruct *reply_new(uint32_t tag) { return reply; } -static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); playback_stream *s; uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid, missing; @@ -1592,10 +1689,14 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC no_move = FALSE, variable_rate = FALSE, muted = FALSE, - adjust_latency = FALSE; + adjust_latency = FALSE, + early_requests = FALSE, + dont_inhibit_auto_suspend = FALSE, + muted_set = FALSE; pa_sink_input_flags_t flags = 0; pa_proplist *p; + pa_bool_t volume_set = TRUE; pa_native_connection_assert_ref(c); pa_assert(t); @@ -1621,7 +1722,9 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(sink_name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); @@ -1660,6 +1763,26 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } } + if (c->version >= 14) { + + if (pa_tagstruct_get_boolean(t, &volume_set) < 0 || + pa_tagstruct_get_boolean(t, &early_requests) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + + if (c->version >= 15) { + + if (pa_tagstruct_get_boolean(t, &muted_set) < 0 || + pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + if (!pa_tagstruct_eof(t)) { protocol_error(c); pa_proplist_free(p); @@ -1691,9 +1814,14 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) | (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) | (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) | - (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0); + (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) | + (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0); + + /* Only since protocol version 15 there's a seperate muted_set + * flag. For older versions we synthesize it here */ + muted_set = muted_set || muted; - s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, &volume, muted, syncid, &missing, flags, p, adjust_latency); + s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1735,7 +1863,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t channel; @@ -1793,7 +1921,7 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); record_stream *s; uint32_t maxlength, fragment_size; @@ -1813,7 +1941,9 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ no_move = FALSE, variable_rate = FALSE, adjust_latency = FALSE, - peak_detect = FALSE; + peak_detect = FALSE, + early_requests = FALSE, + dont_inhibit_auto_suspend = FALSE; pa_source_output_flags_t flags = 0; pa_proplist *p; uint32_t direct_on_input_idx = PA_INVALID_INDEX; @@ -1835,9 +1965,11 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name(source_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || (*source_name && pa_utf8_valid(source_name)), tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); p = pa_proplist_new(); @@ -1874,6 +2006,24 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } } + if (c->version >= 14) { + + if (pa_tagstruct_get_boolean(t, &early_requests) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + + if (c->version >= 15) { + + if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + if (!pa_tagstruct_eof(t)) { protocol_error(c); pa_proplist_free(p); @@ -1914,9 +2064,10 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) | (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) | (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | - (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0); + (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) | + (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0); - s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input); + s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input, early_requests); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1953,7 +2104,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); int ret; @@ -1972,11 +2123,11 @@ static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ } -static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const void*cookie; pa_tagstruct *reply; - pa_bool_t shm_on_remote, do_shm; + pa_bool_t shm_on_remote = FALSE, do_shm; pa_native_connection_assert_ref(c); pa_assert(t); @@ -2071,6 +2222,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t if (c->version < 10 || (c->version >= 13 && !shm_on_remote)) do_shm = FALSE; +#ifdef HAVE_CREDS if (do_shm) { /* Only enable SHM if both sides are owned by the same * user. This is a security measure because otherwise data @@ -2080,6 +2232,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid) do_shm = FALSE; } +#endif pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm)); pa_pstream_enable_shm(c->pstream, do_shm); @@ -2103,7 +2256,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t #endif } -static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *name = NULL; pa_proplist *p; @@ -2143,7 +2296,7 @@ static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *name; uint32_t idx = PA_IDXSET_INVALID; @@ -2158,7 +2311,7 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); if (command == PA_COMMAND_LOOKUP_SINK) { pa_sink *sink; @@ -2181,7 +2334,7 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin } } -static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; playback_stream *s; @@ -2203,7 +2356,7 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC pa_asyncmsgq_post(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_DRAIN, PA_UINT_TO_PTR(tag), 0, NULL, NULL); } -static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; const pa_mempool_stat *stat; @@ -2225,11 +2378,11 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size)); pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated)); pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size)); - pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); + pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core)); pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; playback_stream *s; @@ -2275,7 +2428,7 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; record_stream *s; @@ -2307,7 +2460,7 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); upload_stream *s; uint32_t length; @@ -2349,7 +2502,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID))) name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); s = upload_stream_new(c, &ss, &map, name, length, p); pa_proplist_free(p); @@ -2362,7 +2515,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t channel; upload_stream *s; @@ -2391,7 +2544,7 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ upload_stream_unlink(s); } -static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t sink_index; pa_volume_t volume; @@ -2414,8 +2567,10 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui return; } - CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); if (sink_index != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); @@ -2451,7 +2606,7 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *name; @@ -2465,7 +2620,7 @@ static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); if (pa_scache_remove_item(c->protocol->core, name) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); @@ -2509,8 +2664,8 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin PA_TAG_SAMPLE_SPEC, &fixed_ss, PA_TAG_CHANNEL_MAP, &sink->channel_map, PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_sink_get_volume(sink), - PA_TAG_BOOLEAN, pa_sink_get_mute(sink), + PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE), + PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE), PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL, PA_TAG_USEC, pa_sink_get_latency(sink), @@ -2540,8 +2695,8 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s PA_TAG_SAMPLE_SPEC, &fixed_ss, PA_TAG_CHANNEL_MAP, &source->channel_map, PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_source_get_volume(source), - PA_TAG_BOOLEAN, pa_source_get_mute(source), + PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE), + PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE), PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, PA_TAG_USEC, pa_source_get_latency(source), @@ -2577,7 +2732,7 @@ static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { pa_tagstruct_putu32(t, module->index); pa_tagstruct_puts(t, module->name); pa_tagstruct_puts(t, module->argument); - pa_tagstruct_putu32(t, module->n_used); + pa_tagstruct_putu32(t, (uint32_t) module->n_used); pa_tagstruct_put_boolean(t, module->auto_unload); } @@ -2597,7 +2752,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_put_cvolume(t, &s->volume); + pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s)); pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency)); pa_tagstruct_put_usec(t, sink_latency); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); @@ -2650,7 +2805,7 @@ static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0); pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &e->channel_map); - pa_tagstruct_putu32(t, e->memchunk.length); + pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length); pa_tagstruct_put_boolean(t, e->lazy); pa_tagstruct_puts(t, e->filename); @@ -2658,7 +2813,7 @@ static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s pa_tagstruct_put_proplist(t, e->proplist); } -static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; pa_sink *sink = NULL; @@ -2668,7 +2823,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u pa_sink_input *si = NULL; pa_source_output *so = NULL; pa_scache_entry *sce = NULL; - const char *name; + const char *name = NULL; pa_tagstruct *reply; pa_native_connection_assert_ref(c); @@ -2686,7 +2841,10 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); if (command == PA_COMMAND_GET_SINK_INFO) { if (idx != PA_INVALID_INDEX) @@ -2737,7 +2895,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_idxset *i; uint32_t idx; @@ -2797,7 +2955,7 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; char txt[256]; @@ -2847,7 +3005,7 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint3 pa_pstream_send_tagstruct(c->pstream, t); } -static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_subscription_mask_t m; @@ -2876,7 +3034,7 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint } static void command_set_volume( - PA_GCC_UNUSED pa_pdispatch *pd, + pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, @@ -2903,7 +3061,10 @@ static void command_set_volume( } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); switch (command) { @@ -2943,7 +3104,7 @@ static void command_set_volume( } static void command_set_mute( - PA_GCC_UNUSED pa_pdispatch *pd, + pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, @@ -2970,7 +3131,10 @@ static void command_set_mute( } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); switch (command) { @@ -3011,7 +3175,7 @@ static void command_set_mute( pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; pa_bool_t b; @@ -3034,10 +3198,14 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); pa_sink_input_cork(s->sink_input, b); + + if (b) + s->is_underrun = TRUE; + pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_trigger_or_flush_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; playback_stream *s; @@ -3077,7 +3245,7 @@ static void command_trigger_or_flush_or_prebuf_playback_stream(PA_GCC_UNUSED pa_ pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; record_stream *s; @@ -3102,7 +3270,7 @@ static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; record_stream *s; @@ -3142,7 +3310,7 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) { playback_stream *s; - pa_bool_t adjust_latency = FALSE; + pa_bool_t adjust_latency = FALSE, early_requests = FALSE; s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); @@ -3156,12 +3324,13 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u PA_TAG_U32, &minreq, PA_TAG_INVALID) < 0 || (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) || + (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - fix_playback_buffer_attr_pre(s, adjust_latency, &maxlength, &tlength, &prebuf, &minreq); + fix_playback_buffer_attr_pre(s, adjust_latency, early_requests, &maxlength, &tlength, &prebuf, &minreq); pa_memblockq_set_maxlength(s->memblockq, maxlength); pa_memblockq_set_tlength(s->memblockq, tlength); pa_memblockq_set_prebuf(s->memblockq, prebuf); @@ -3179,7 +3348,7 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u } else { record_stream *s; - pa_bool_t adjust_latency = FALSE; + pa_bool_t adjust_latency = FALSE, early_requests = FALSE; pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR); s = pa_idxset_get_by_index(c->record_streams, idx); @@ -3191,12 +3360,13 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u PA_TAG_U32, &fragsize, PA_TAG_INVALID) < 0 || (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) || + (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - fix_record_buffer_attr_pre(s, adjust_latency, &maxlength, &fragsize); + fix_record_buffer_attr_pre(s, adjust_latency, early_requests, &maxlength, &fragsize); pa_memblockq_set_maxlength(s->memblockq, maxlength); fix_record_buffer_attr_post(s, &maxlength, &fragsize); @@ -3387,7 +3557,7 @@ static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t if (!z) break; - changed += pa_proplist_unset(p, z) >= 0; + changed += (unsigned) (pa_proplist_unset(p, z) >= 0); pa_xfree(z); } @@ -3413,7 +3583,7 @@ static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t } } -static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *s; @@ -3427,13 +3597,13 @@ static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, u } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !s || (*s && pa_utf8_valid(s)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID); pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; const char *name; @@ -3473,7 +3643,7 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; @@ -3521,7 +3691,7 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 pa_native_connection_unref(c); } -static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_module *m; const char *name, *argument; @@ -3551,7 +3721,7 @@ static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; pa_module *m; @@ -3573,7 +3743,7 @@ static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_add_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *name, *module, *argument; uint32_t type; @@ -3608,7 +3778,7 @@ static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED u pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_remove_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *name = NULL; uint32_t type, idx = PA_IDXSET_INVALID; @@ -3644,12 +3814,12 @@ static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); - pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1); + pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0U : 1U); pa_tagstruct_puts(t, e->module); pa_tagstruct_puts(t, e->argument); } -static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const pa_autoload_entry *a = NULL; uint32_t type, idx; @@ -3683,7 +3853,7 @@ static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNU pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; @@ -3713,14 +3883,14 @@ static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX; - const char *name = NULL; + const char *name_device = NULL; pa_native_connection_assert_ref(c); pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_getu32(t, &idx_device) < 0 || - pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &name_device) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -3728,7 +3898,11 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + + CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name(name_device), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID); if (command == PA_COMMAND_MOVE_SINK_INPUT) { pa_sink_input *si = NULL; @@ -3739,7 +3913,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag if (idx_device != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device); else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK, 1); CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY); @@ -3758,7 +3932,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag if (idx_device != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device); else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE, 1); CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY); @@ -3789,7 +3963,10 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || !*name || pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); if (command == PA_COMMAND_SUSPEND_SINK) { @@ -3862,7 +4039,10 @@ static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || !*name || pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); if (idx != PA_INVALID_INDEX) m = pa_idxset_get_by_index(c->protocol->core->modules, idx); @@ -3912,6 +4092,8 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o return; } +/* pa_log("got %lu bytes", (unsigned long) chunk->length); */ + if (playback_stream_isinstance(stream)) { playback_stream *ps = PLAYBACK_STREAM(stream); @@ -4299,7 +4481,7 @@ int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) { if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { pa_ip_acl *ipa; - if (!(o->auth_ip_acl = pa_ip_acl_new(acl))) { + if (!(ipa = pa_ip_acl_new(acl))) { pa_log("Failed to parse IP ACL '%s'", acl); return -1; } diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c index 78874bb9..743bf2ee 100644 --- a/src/pulsecore/protocol-simple.c +++ b/src/pulsecore/protocol-simple.c @@ -159,7 +159,7 @@ static int do_read(connection *c) { connection_assert_ref(c); - if (!c->sink_input || (l = pa_atomic_load(&c->playback.missing)) <= 0) + if (!c->sink_input || (l = (size_t) pa_atomic_load(&c->playback.missing)) <= 0) return 0; if (c->playback.current_memblock) { @@ -173,7 +173,7 @@ static int do_read(connection *c) { } if (!c->playback.current_memblock) { - pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, 0)); + pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, (size_t) -1)); c->playback.memblock_index = 0; space = pa_memblock_get_length(c->playback.current_memblock); @@ -197,12 +197,12 @@ static int do_read(connection *c) { chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; - chunk.length = r; + chunk.length = (size_t) r; - c->playback.memblock_index += r; + c->playback.memblock_index += (size_t) r; pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL); - pa_atomic_sub(&c->playback.missing, r); + pa_atomic_sub(&c->playback.missing, (int) r); return 0; } @@ -240,7 +240,7 @@ static int do_write(connection *c) { return -1; } - pa_memblockq_drop(c->output_memblockq, r); + pa_memblockq_drop(c->output_memblockq, (size_t) r); return 0; } @@ -377,7 +377,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk m = pa_memblockq_pop_missing(c->input_memblockq); if (m > 0) - if (pa_atomic_add(&c->playback.missing, m) <= 0) + if (pa_atomic_add(&c->playback.missing, (int) m) <= 0) pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); return 0; @@ -492,6 +492,8 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp c->parent.parent.free = connection_free; c->parent.process_msg = connection_process_msg; c->io = io; + pa_iochannel_set_callback(c->io, io_callback, c); + c->sink_input = NULL; c->source_output = NULL; c->input_memblockq = c->output_memblockq = NULL; @@ -546,7 +548,7 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp pa_sink_input_set_requested_latency(c->sink_input, DEFAULT_SINK_LATENCY); - l = (size_t) (pa_bytes_per_second(&o->sample_spec)*PLAYBACK_BUFFER_SECONDS); + l = (size_t) ((double) pa_bytes_per_second(&o->sample_spec)*PLAYBACK_BUFFER_SECONDS); c->input_memblockq = pa_memblockq_new( 0, l, @@ -558,7 +560,7 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp NULL); pa_iochannel_socket_set_rcvbuf(io, l); - pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq)); + pa_atomic_store(&c->playback.missing, (int) pa_memblockq_missing(c->input_memblockq)); pa_sink_input_put(c->sink_input); } @@ -610,7 +612,6 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp pa_source_output_put(c->source_output); } - pa_iochannel_set_callback(c->io, io_callback, c); pa_idxset_put(p->connections, c, NULL); return; @@ -689,6 +690,9 @@ pa_simple_options* pa_simple_options_new(void) { o = pa_xnew0(pa_simple_options, 1); PA_REFCNT_INIT(o); + o->record = FALSE; + o->playback = TRUE; + return o; } @@ -733,14 +737,14 @@ int pa_simple_options_parse(pa_simple_options *o, pa_core *c, pa_modargs *ma) { pa_xfree(o->default_sink); o->default_sink = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); - enabled = FALSE; + enabled = o->record; if (pa_modargs_get_value_boolean(ma, "record", &enabled) < 0) { pa_log("record= expects a boolean argument."); return -1; } o->record = enabled; - enabled = TRUE; + enabled = o->playback; if (pa_modargs_get_value_boolean(ma, "playback", &enabled) < 0) { pa_log("playback= expects a boolean argument."); return -1; diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 6b1af67b..7ff8edc9 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -283,7 +283,7 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo return p; } -static void item_free(void *item, PA_GCC_UNUSED void *q) { +static void item_free(void *item, void *q) { struct item_info *i = item; pa_assert(i); @@ -488,7 +488,7 @@ static void prepare_next_write_item(pa_pstream *p) { pa_assert(p->write.current->packet); p->write.data = p->write.current->packet->data; - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl((uint32_t) p->write.current->packet->length); } else if (p->write.current->type == PA_PSTREAM_ITEM_SHMRELEASE) { @@ -511,7 +511,7 @@ static void prepare_next_write_item(pa_pstream *p) { p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32)); p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_LO] = htonl((uint32_t) ((uint64_t) p->write.current->offset)); - flags = p->write.current->seek_mode & PA_FLAG_SEEKMASK; + flags = (uint32_t) (p->write.current->seek_mode & PA_FLAG_SEEKMASK); if (p->use_shm) { uint32_t block_id, shm_id; @@ -542,7 +542,7 @@ static void prepare_next_write_item(pa_pstream *p) { } if (send_payload) { - p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length); + p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl((uint32_t) p->write.current->chunk.length); p->write.memchunk = p->write.current->chunk; pa_memblock_ref(p->write.memchunk.memblock); p->write.data = NULL; @@ -607,7 +607,7 @@ static int do_write(pa_pstream *p) { if (release_memblock) pa_memblock_release(release_memblock); - p->write.index += r; + p->write.index += (size_t) r; if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE + ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) { pa_assert(p->write.current); @@ -675,7 +675,7 @@ static int do_read(pa_pstream *p) { if (release_memblock) pa_memblock_release(release_memblock); - p->read.index += r; + p->read.index += (size_t) r; if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) { uint32_t flags, length, channel; @@ -769,7 +769,7 @@ static int do_read(pa_pstream *p) { if (p->read.memblock && p->recieve_memblock_callback) { /* Is this memblock data? Than pass it to the user */ - l = (p->read.index - r) < PA_PSTREAM_DESCRIPTOR_SIZE ? p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE : (size_t) r; + l = (p->read.index - (size_t) r) < PA_PSTREAM_DESCRIPTOR_SIZE ? (size_t) (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE) : (size_t) r; if (l > 0) { pa_memchunk chunk; diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index c82f4c1e..b2d512c8 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -373,7 +373,7 @@ size_t pa_resampler_max_block_size(pa_resampler *r) { /* We deduce the "largest" sample spec we're using during the * conversion */ - ss.channels = PA_MAX(r->i_ss.channels, r->o_ss.channels); + ss.channels = (uint8_t) (PA_MAX(r->i_ss.channels, r->o_ss.channels)); /* We silently assume that the format enum is ordered by size */ ss.format = PA_MAX(r->i_ss.format, r->o_ss.format); @@ -642,7 +642,7 @@ static void calc_map_table(pa_resampler *r) { if (n > 0) for (ic = 0; ic < r->i_ss.channels; ic++) if (on_left(r->i_cm.map[ic])) { - r->map_table[oc][ic] = 1.0 / n; + r->map_table[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -663,7 +663,7 @@ static void calc_map_table(pa_resampler *r) { if (n > 0) for (ic = 0; ic < r->i_ss.channels; ic++) if (on_right(r->i_cm.map[ic])) { - r->map_table[oc][ic] = 1.0 / n; + r->map_table[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -684,7 +684,7 @@ static void calc_map_table(pa_resampler *r) { if (n > 0) { for (ic = 0; ic < r->i_ss.channels; ic++) if (on_center(r->i_cm.map[ic])) { - r->map_table[oc][ic] = 1.0 / n; + r->map_table[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } } else { @@ -701,7 +701,7 @@ static void calc_map_table(pa_resampler *r) { if (n > 0) for (ic = 0; ic < r->i_ss.channels; ic++) if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) { - r->map_table[oc][ic] = 1.0 / n; + r->map_table[oc][ic] = 1.0f / (float) n; ic_connected[ic] = TRUE; } @@ -716,7 +716,11 @@ static void calc_map_table(pa_resampler *r) { * channels for LFE. */ for (ic = 0; ic < r->i_ss.channels; ic++) { - r->map_table[oc][ic] = 1.0 / r->i_ss.channels; + + if (!(r->flags & PA_RESAMPLER_NO_LFE)) + r->map_table[oc][ic] = 1.0f / (float) r->i_ss.channels; + else + r->map_table[oc][ic] = 0; /* Please note that a channel connected to LFE * doesn't really count as connected. */ @@ -763,12 +767,12 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (ic_connected[ic]) { - r->map_table[oc][ic] *= .9; + r->map_table[oc][ic] *= .9f; continue; } if (on_left(r->i_cm.map[ic])) - r->map_table[oc][ic] = .1 / ic_unconnected_left; + r->map_table[oc][ic] = .1f / (float) ic_unconnected_left; } } } @@ -788,12 +792,12 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (ic_connected[ic]) { - r->map_table[oc][ic] *= .9; + r->map_table[oc][ic] *= .9f; continue; } if (on_right(r->i_cm.map[ic])) - r->map_table[oc][ic] = .1 / ic_unconnected_right; + r->map_table[oc][ic] = .1f / (float) ic_unconnected_right; } } } @@ -814,12 +818,12 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (ic_connected[ic]) { - r->map_table[oc][ic] *= .9; + r->map_table[oc][ic] *= .9f; continue; } if (on_center(r->i_cm.map[ic])) { - r->map_table[oc][ic] = .1 / ic_unconnected_center; + r->map_table[oc][ic] = .1f / (float) ic_unconnected_center; mixed_in = TRUE; } } @@ -840,18 +844,18 @@ static void calc_map_table(pa_resampler *r) { for (ic = 0; ic < r->i_ss.channels; ic++) { if (ic_connected[ic]) { - r->map_table[oc][ic] *= .75; + r->map_table[oc][ic] *= .75f; continue; } if (on_center(r->i_cm.map[ic])) - r->map_table[oc][ic] = .375 / ic_unconnected_center; + r->map_table[oc][ic] = .375f / (float) ic_unconnected_center; } } } } - if (ic_unconnected_lfe > 0) { + if (ic_unconnected_lfe > 0 && !(r->flags & PA_RESAMPLER_NO_LFE)) { /* OK, so there is an unconnected LFE channel. Let's mix * it into all channels, with factor 0.375 */ @@ -862,7 +866,7 @@ static void calc_map_table(pa_resampler *r) { continue; for (oc = 0; oc < r->o_ss.channels; oc++) - r->map_table[oc][ic] = 0.375 / ic_unconnected_lfe; + r->map_table[oc][ic] = 0.375f / (float) ic_unconnected_lfe; } } } @@ -905,7 +909,7 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) if (!r->to_work_format_func || !input->length) return input; - n_samples = (input->length / r->i_fz) * r->i_ss.channels; + n_samples = (unsigned) ((input->length / r->i_fz) * r->i_ss.channels); r->buf1.index = 0; r->buf1.length = r->w_sz * n_samples; @@ -974,7 +978,7 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { if (!r->map_required || !input->length) return input; - in_n_samples = input->length / r->w_sz; + in_n_samples = (unsigned) (input->length / r->w_sz); n_frames = in_n_samples / r->i_ss.channels; out_n_samples = n_frames * r->o_ss.channels; @@ -994,8 +998,8 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { memset(dst, 0, r->buf2.length); - o_skip = r->w_sz * r->o_ss.channels; - i_skip = r->w_sz * r->i_ss.channels; + o_skip = (int) (r->w_sz * r->o_ss.channels); + i_skip = (int) (r->w_sz * r->i_ss.channels); switch (r->work_format) { case PA_SAMPLE_FLOAT32NE: @@ -1013,7 +1017,7 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { (float*) dst + oc, o_skip, (float*) dst + oc, o_skip, (float*) src + ic, i_skip, - n_frames, + (int) n_frames, &one, &r->map_table[oc][ic]); } } @@ -1037,7 +1041,7 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { (int16_t*) dst + oc, o_skip, (int16_t*) dst + oc, o_skip, (int16_t*) src + ic, i_skip, - n_frames, + (int) n_frames, &one, &one); } else @@ -1046,8 +1050,8 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { (int16_t*) dst + oc, o_skip, (int16_t*) dst + oc, o_skip, (int16_t*) src + ic, i_skip, - n_frames, - 1.0, r->map_table[oc][ic]); + (int) n_frames, + 1.0f, r->map_table[oc][ic]); } } @@ -1077,8 +1081,8 @@ static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) { if (!r->impl_resample || !input->length) return input; - in_n_samples = input->length / r->w_sz; - in_n_frames = in_n_samples / r->o_ss.channels; + in_n_samples = (unsigned) (input->length / r->w_sz); + in_n_frames = (unsigned) (in_n_samples / r->o_ss.channels); out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_FRAMES; out_n_samples = out_n_frames * r->o_ss.channels; @@ -1112,8 +1116,8 @@ static pa_memchunk *convert_from_work_format(pa_resampler *r, pa_memchunk *input if (!r->from_work_format_func || !input->length) return input; - n_samples = input->length / r->w_sz; - n_frames = n_samples / r->o_ss.channels; + n_samples = (unsigned) (input->length / r->w_sz); + n_frames = n_samples / r->o_ss.channels; r->buf4.index = 0; r->buf4.length = r->o_fz * n_frames; @@ -1178,10 +1182,10 @@ static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, un memset(&data, 0, sizeof(data)); data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); - data.input_frames = in_n_frames; + data.input_frames = (long int) in_n_frames; data.data_out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index); - data.output_frames = *out_n_frames; + data.output_frames = (long int) *out_n_frames; data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; data.end_of_input = 0; @@ -1192,7 +1196,7 @@ static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, un pa_memblock_release(input->memblock); pa_memblock_release(output->memblock); - *out_n_frames = data.output_frames_gen; + *out_n_frames = (unsigned) data.output_frames_gen; } static void libsamplerate_update_rates(pa_resampler *r) { @@ -1354,7 +1358,7 @@ static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned pa_assert(o_index * fz < pa_memblock_get_length(output->memblock)); oil_memcpy((uint8_t*) dst + fz * o_index, - (uint8_t*) src + fz * j, fz); + (uint8_t*) src + fz * j, (int) fz); } pa_memblock_release(input->memblock); @@ -1414,40 +1418,46 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i unsigned j; j = ((r->peaks.o_counter * r->i_ss.rate) / r->o_ss.rate); - j = j > r->peaks.i_counter ? j - r->peaks.i_counter : 0; - if (j >= in_n_frames) - break; + if (j > r->peaks.i_counter) + j -= r->peaks.i_counter; + else + j = 0; pa_assert(o_index * fz < pa_memblock_get_length(output->memblock)); if (r->work_format == PA_SAMPLE_S16NE) { unsigned i, c; - int16_t *s = (int16_t*) ((uint8_t*) src + fz * j); + int16_t *s = (int16_t*) ((uint8_t*) src + fz * start); int16_t *d = (int16_t*) ((uint8_t*) dst + fz * o_index); - for (i = start; i <= j; i++) + for (i = start; i <= j && i < in_n_frames; i++) + for (c = 0; c < r->o_ss.channels; c++, s++) { int16_t n; - n = *s < 0 ? -*s : *s; + n = (int16_t) (*s < 0 ? -*s : *s); - if (n > r->peaks.max_i[c]) + if (PA_UNLIKELY(n > r->peaks.max_i[c])) r->peaks.max_i[c] = n; } + if (i >= in_n_frames) + break; + for (c = 0; c < r->o_ss.channels; c++, d++) { - *d = r->peaks.max_i[c]; - r->peaks.max_i[c] = 0; + *d = r->peaks.max_i[c]; + r->peaks.max_i[c] = 0; } + } else { unsigned i, c; - float *s = (float*) ((uint8_t*) src + fz * j); + float *s = (float*) ((uint8_t*) src + fz * start); float *d = (float*) ((uint8_t*) dst + fz * o_index); pa_assert(r->work_format == PA_SAMPLE_FLOAT32NE); - for (i = start; i <= j; i++) + for (i = start; i <= j && i < in_n_frames; i++) for (c = 0; c < r->o_ss.channels; c++, s++) { float n = fabsf(*s); @@ -1455,13 +1465,16 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i r->peaks.max_f[c] = n; } + if (i >= in_n_frames) + break; + for (c = 0; c < r->o_ss.channels; c++, d++) { *d = r->peaks.max_f[c]; r->peaks.max_f[c] = 0; } } - start = j+1; + start = j; } pa_memblock_release(input->memblock); @@ -1523,7 +1536,7 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned p = pa_memblock_acquire(b); /* Copy the remaining data into it */ - l = r->ffmpeg.buf[c].length; + l = (unsigned) r->ffmpeg.buf[c].length; if (r->ffmpeg.buf[c].memblock) { t = (int16_t*) ((uint8_t*) pa_memblock_acquire(r->ffmpeg.buf[c].memblock) + r->ffmpeg.buf[c].index); memcpy(p, t, l); @@ -1543,18 +1556,18 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned pa_memblock_release(input->memblock); /* Calculate the resulting number of frames */ - in = in_n_frames + l / sizeof(int16_t); + in = (unsigned) in_n_frames + l / (unsigned) sizeof(int16_t); /* Allocate buffer for the result */ w = pa_memblock_new(r->mempool, *out_n_frames * sizeof(int16_t)); q = pa_memblock_acquire(w); /* Now, resample */ - used_frames = av_resample(r->ffmpeg.state, - q, p, - &consumed_frames, - in, *out_n_frames, - c >= (unsigned) r->o_ss.channels-1); + used_frames = (unsigned) av_resample(r->ffmpeg.state, + q, p, + &consumed_frames, + (int) in, (int) *out_n_frames, + c >= (unsigned) (r->o_ss.channels-1)); pa_memblock_release(b); @@ -1562,8 +1575,8 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned pa_assert(consumed_frames <= (int) in); if (consumed_frames < (int) in) { r->ffmpeg.buf[c].memblock = b; - r->ffmpeg.buf[c].index = consumed_frames * sizeof(int16_t); - r->ffmpeg.buf[c].length = (in - consumed_frames) * sizeof(int16_t); + r->ffmpeg.buf[c].index = (size_t) consumed_frames * sizeof(int16_t); + r->ffmpeg.buf[c].length = (size_t) (in - (unsigned) consumed_frames) * sizeof(int16_t); } else pa_memblock_unref(b); @@ -1605,7 +1618,7 @@ static int ffmpeg_init(pa_resampler *r) { * internally only uses these hardcoded values, so let's use them * here for now as well until ffmpeg makes this configurable. */ - if (!(r->ffmpeg.state = av_resample_init(r->o_ss.rate, r->i_ss.rate, 16, 10, 0, 0.8))) + if (!(r->ffmpeg.state = av_resample_init((int) r->o_ss.rate, (int) r->i_ss.rate, 16, 10, 0, 0.8))) return -1; r->impl_free = ffmpeg_free; diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index 5e302a9b..87110cc2 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -49,9 +49,10 @@ typedef enum pa_resample_method { } pa_resample_method_t; typedef enum pa_resample_flags { - PA_RESAMPLER_VARIABLE_RATE = 1, - PA_RESAMPLER_NO_REMAP = 2, /* implies NO_REMIX */ - PA_RESAMPLER_NO_REMIX = 4 + PA_RESAMPLER_VARIABLE_RATE = 0x0001U, + PA_RESAMPLER_NO_REMAP = 0x0002U, /* implies NO_REMIX */ + PA_RESAMPLER_NO_REMIX = 0x0004U, + PA_RESAMPLER_NO_LFE = 0x0008U } pa_resample_flags_t; pa_resampler* pa_resampler_new( diff --git a/src/pulsecore/rtclock.h b/src/pulsecore/rtclock.h index 705de48f..aa2cdace 100644 --- a/src/pulsecore/rtclock.h +++ b/src/pulsecore/rtclock.h @@ -23,6 +23,7 @@ ***/ #include <pulsecore/macro.h> +#include <pulse/sample.h> struct timeval; diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c index a67a5516..543262bc 100644 --- a/src/pulsecore/rtpoll.c +++ b/src/pulsecore/rtpoll.c @@ -394,7 +394,7 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait) { #endif #endif - r = poll(p->pollfd, p->n_pollfd_used, (!wait || p->quit || p->timer_enabled) ? (timeout.tv_sec*1000) + (timeout.tv_usec / 1000) : -1); + r = poll(p->pollfd, p->n_pollfd_used, (!wait || p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1); if (r < 0) { if (errno == EAGAIN || errno == EINTR) diff --git a/src/pulsecore/rtsig.c b/src/pulsecore/rtsig.c index 4df217c3..4cd6aa8f 100644 --- a/src/pulsecore/rtsig.c +++ b/src/pulsecore/rtsig.c @@ -40,7 +40,7 @@ static void _free_rtsig(void *p) { pa_rtsig_put(PA_PTR_TO_INT(p)); } -PA_STATIC_FLIST_DECLARE(rtsig_flist, pa_make_power_of_two(SIGRTMAX-SIGRTMIN+1), NULL); +PA_STATIC_FLIST_DECLARE(rtsig_flist, pa_make_power_of_two((unsigned) (SIGRTMAX-SIGRTMIN+1)), NULL); PA_STATIC_TLS_DECLARE(rtsig_tls, _free_rtsig); static pa_atomic_t rtsig_current = PA_ATOMIC_INIT(-1); diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c index b42b79d1..9f0f795c 100644 --- a/src/pulsecore/sample-util.c +++ b/src/pulsecore/sample-util.c @@ -31,6 +31,8 @@ #include <liboil/liboilfuncs.h> #include <liboil/liboil.h> +#include <pulse/timeval.h> + #include <pulsecore/log.h> #include <pulsecore/macro.h> #include <pulsecore/g711.h> @@ -85,7 +87,6 @@ static uint8_t silence_byte(pa_sample_format_t format) { default: pa_assert_not_reached(); } - return 0; } void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { @@ -97,56 +98,62 @@ void* pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { return p; } -static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_sample_spec *spec) { - unsigned k; - - pa_assert(streams); - pa_assert(spec); +static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) { + unsigned channel; - for (k = 0; k < nstreams; k++) { - unsigned channel; + pa_assert(linear); + pa_assert(volume); - for (channel = 0; channel < spec->channels; channel++) { - pa_mix_info *m = streams + k; - m->linear[channel].i = (int32_t) (pa_sw_volume_to_linear(m->volume.values[channel]) * 0x10000); - } - } + for (channel = 0; channel < volume->channels; channel++) + linear[channel] = (int32_t) lrint(pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); } -static void calc_linear_integer_volume(int32_t linear[], const pa_cvolume *volume) { +static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) { unsigned channel; pa_assert(linear); pa_assert(volume); for (channel = 0; channel < volume->channels; channel++) - linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000); + linear[channel] = (float) pa_sw_volume_to_linear(volume->values[channel]); } -static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_sample_spec *spec) { - unsigned k; +static void calc_linear_integer_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { + unsigned k, channel; + float linear[PA_CHANNELS_MAX]; pa_assert(streams); pa_assert(spec); + pa_assert(volume); + + calc_linear_float_volume(linear, volume); for (k = 0; k < nstreams; k++) { - unsigned channel; for (channel = 0; channel < spec->channels; channel++) { pa_mix_info *m = streams + k; - m->linear[channel].f = pa_sw_volume_to_linear(m->volume.values[channel]); + m->linear[channel].i = (int32_t) lrint(pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel] * 0x10000); } } } -static void calc_linear_float_volume(float linear[], const pa_cvolume *volume) { - unsigned channel; +static void calc_linear_float_stream_volumes(pa_mix_info streams[], unsigned nstreams, const pa_cvolume *volume, const pa_sample_spec *spec) { + unsigned k, channel; + float linear[PA_CHANNELS_MAX]; - pa_assert(linear); + pa_assert(streams); + pa_assert(spec); pa_assert(volume); - for (channel = 0; channel < volume->channels; channel++) - linear[channel] = pa_sw_volume_to_linear(volume->values[channel]); + calc_linear_float_volume(linear, volume); + + for (k = 0; k < nstreams; k++) { + + for (channel = 0; channel < spec->channels; channel++) { + pa_mix_info *m = streams + k; + m->linear[channel].f = (float) (pa_sw_volume_to_linear(m->volume.values[channel]) * linear[channel]); + } + } } size_t pa_mix( @@ -160,7 +167,8 @@ size_t pa_mix( pa_cvolume full_volume; unsigned k; - size_t d = 0; + unsigned z; + void *end; pa_assert(streams); pa_assert(data); @@ -170,45 +178,46 @@ size_t pa_mix( if (!volume) volume = pa_cvolume_reset(&full_volume, spec->channels); + if (mute || pa_cvolume_is_muted(volume) || nstreams <= 0) { + pa_silence_memory(data, length, spec); + return length; + } + for (k = 0; k < nstreams; k++) streams[k].ptr = (uint8_t*) pa_memblock_acquire(streams[k].chunk.memblock) + streams[k].chunk.index; + for (z = 0; z < nstreams; z++) + if (length > streams[z].chunk.length) + length = streams[z].chunk.length; + + end = (uint8_t*) data + length; + switch (spec->format) { case PA_SAMPLE_S16NE:{ unsigned channel = 0; - int32_t linear[PA_CHANNELS_MAX]; - calc_linear_integer_stream_volumes(streams, nstreams, spec); - calc_linear_integer_volume(linear, volume); + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d += sizeof(int16_t)) { + while (data < end) { int32_t sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; int32_t v, cv = m->linear[channel].i; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - v = *((int16_t*) m->ptr); - v = (v * cv) / 0x10000; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = *((int16_t*) m->ptr); + v = (v * cv) / 0x10000; sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); } sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); - sum = (sum * linear[channel]) / 0x10000; *((int16_t*) data) = (int16_t) sum; data = (uint8_t*) data + sizeof(int16_t); @@ -222,38 +231,28 @@ size_t pa_mix( case PA_SAMPLE_S16RE:{ unsigned channel = 0; - int32_t linear[PA_CHANNELS_MAX]; - calc_linear_integer_stream_volumes(streams, nstreams, spec); - calc_linear_integer_volume(linear, volume); + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d += sizeof(int16_t)) { + while (data < end) { int32_t sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; int32_t v, cv = m->linear[channel].i; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - v = PA_INT16_SWAP(*((int16_t*) m->ptr)); - v = (v * cv) / 0x10000; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = PA_INT16_SWAP(*((int16_t*) m->ptr)); + v = (v * cv) / 0x10000; sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(int16_t); } sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); - sum = (sum * linear[channel]) / 0x10000; *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum); data = (uint8_t*) data + sizeof(int16_t); @@ -267,39 +266,29 @@ size_t pa_mix( case PA_SAMPLE_S32NE:{ unsigned channel = 0; - int32_t linear[PA_CHANNELS_MAX]; - calc_linear_integer_stream_volumes(streams, nstreams, spec); - calc_linear_integer_volume(linear, volume); + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d += sizeof(int32_t)) { + while (data < end) { int64_t sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; - int64_t v; int32_t cv = m->linear[channel].i; + int64_t v; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - v = *((int32_t*) m->ptr); - v = (v * cv) / 0x10000; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = *((int32_t*) m->ptr); + v = (v * cv) / 0x10000; sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); } sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); - sum = (sum * linear[channel]) / 0x10000; *((int32_t*) data) = (int32_t) sum; data = (uint8_t*) data + sizeof(int32_t); @@ -313,39 +302,29 @@ size_t pa_mix( case PA_SAMPLE_S32RE:{ unsigned channel = 0; - int32_t linear[PA_CHANNELS_MAX]; - calc_linear_integer_stream_volumes(streams, nstreams, spec); - calc_linear_integer_volume(linear, volume); + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d += sizeof(int32_t)) { + while (data < end) { int64_t sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; - int64_t v; int32_t cv = m->linear[channel].i; + int64_t v; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - v = PA_INT32_SWAP(*((int32_t*) m->ptr)); - v = (v * cv) / 0x10000; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = PA_INT32_SWAP(*((int32_t*) m->ptr)); + v = (v * cv) / 0x10000; sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(int32_t); } sum = PA_CLAMP_UNLIKELY(sum, -0x80000000LL, 0x7FFFFFFFLL); - sum = (sum * linear[channel]) / 0x10000; *((int32_t*) data) = PA_INT32_SWAP((int32_t) sum); data = (uint8_t*) data + sizeof(int32_t); @@ -359,37 +338,27 @@ size_t pa_mix( case PA_SAMPLE_U8: { unsigned channel = 0; - int32_t linear[PA_CHANNELS_MAX]; - calc_linear_integer_stream_volumes(streams, nstreams, spec); - calc_linear_integer_volume(linear, volume); + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d ++) { + while (data < end) { int32_t sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; int32_t v, cv = m->linear[channel].i; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - v = (int32_t) *((uint8_t*) m->ptr) - 0x80; - v = (v * cv) / 0x10000; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = (int32_t) *((uint8_t*) m->ptr) - 0x80; + v = (v * cv) / 0x10000; sum += v; + m->ptr = (uint8_t*) m->ptr + 1; } - sum = (sum * linear[channel]) / 0x10000; sum = PA_CLAMP_UNLIKELY(sum, -0x80, 0x7F); *((uint8_t*) data) = (uint8_t) (sum + 0x80); @@ -404,39 +373,29 @@ size_t pa_mix( case PA_SAMPLE_ULAW: { unsigned channel = 0; - int32_t linear[PA_CHANNELS_MAX]; - calc_linear_integer_stream_volumes(streams, nstreams, spec); - calc_linear_integer_volume(linear, volume); + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d ++) { + while (data < end) { int32_t sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; int32_t v, cv = m->linear[channel].i; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr)); - v = (v * cv) / 0x10000; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = (int32_t) st_ulaw2linear16(*((uint8_t*) m->ptr)); + v = (v * cv) / 0x10000; sum += v; + m->ptr = (uint8_t*) m->ptr + 1; } sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); - sum = (sum * linear[channel]) / 0x10000; - *((uint8_t*) data) = (uint8_t) st_14linear2ulaw(sum >> 2); + *((uint8_t*) data) = (uint8_t) st_14linear2ulaw((int16_t) sum >> 2); data = (uint8_t*) data + 1; @@ -449,39 +408,29 @@ size_t pa_mix( case PA_SAMPLE_ALAW: { unsigned channel = 0; - int32_t linear[PA_CHANNELS_MAX]; - calc_linear_integer_stream_volumes(streams, nstreams, spec); - calc_linear_integer_volume(linear, volume); + calc_linear_integer_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d ++) { + while (data < end) { int32_t sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; int32_t v, cv = m->linear[channel].i; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr)); - v = (v * cv) / 0x10000; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = (int32_t) st_alaw2linear16(*((uint8_t*) m->ptr)); + v = (v * cv) / 0x10000; sum += v; + m->ptr = (uint8_t*) m->ptr + 1; } sum = PA_CLAMP_UNLIKELY(sum, -0x8000, 0x7FFF); - sum = (sum * linear[channel]) / 0x10000; - *((uint8_t*) data) = (uint8_t) st_13linear2alaw(sum >> 3); + *((uint8_t*) data) = (uint8_t) st_13linear2alaw((int16_t) sum >> 3); data = (uint8_t*) data + 1; @@ -494,37 +443,27 @@ size_t pa_mix( case PA_SAMPLE_FLOAT32NE: { unsigned channel = 0; - float linear[PA_CHANNELS_MAX]; - calc_linear_float_stream_volumes(streams, nstreams, spec); - calc_linear_float_volume(linear, volume); + calc_linear_float_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d += sizeof(float)) { + while (data < end) { float sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; float v, cv = m->linear[channel].f; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - v = *((float*) m->ptr); - v *= cv; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = *((float*) m->ptr); + v *= cv; sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(float); } - sum *= linear[channel]; *((float*) data) = sum; data = (uint8_t*) data + sizeof(float); @@ -540,38 +479,27 @@ size_t pa_mix( unsigned channel = 0; float linear[PA_CHANNELS_MAX]; - calc_linear_float_stream_volumes(streams, nstreams, spec); - calc_linear_float_volume(linear, volume); + calc_linear_float_stream_volumes(streams, nstreams, volume, spec); - for (d = 0;; d += sizeof(float)) { + while (data < end) { float sum = 0; unsigned i; - if (PA_UNLIKELY(d >= length)) - goto finish; - for (i = 0; i < nstreams; i++) { pa_mix_info *m = streams + i; float v, cv = m->linear[channel].f; - if (PA_UNLIKELY(d >= m->chunk.length)) - goto finish; - - if (PA_UNLIKELY(cv <= 0) || PA_UNLIKELY(!!mute) || PA_UNLIKELY(linear[channel] <= 0)) - v = 0; - else { - uint32_t z = *(uint32_t*) m->ptr; - z = PA_UINT32_SWAP(z); - v = *((float*) &z); - v *= cv; - } + if (PA_UNLIKELY(cv <= 0)) + continue; + v = PA_FLOAT32_SWAP(*(float*) m->ptr); + v *= cv; sum += v; + m->ptr = (uint8_t*) m->ptr + sizeof(float); } - sum *= linear[channel]; - *((uint32_t*) data) = PA_UINT32_SWAP(*(uint32_t*) &sum); + *((float*) data) = PA_FLOAT32_SWAP(sum); data = (uint8_t*) data + sizeof(float); @@ -583,16 +511,14 @@ size_t pa_mix( } default: - pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); + pa_log_error("Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format)); pa_assert_not_reached(); } -finish: - for (k = 0; k < nstreams; k++) pa_memblock_release(streams[k].chunk.memblock); - return d; + return length; } @@ -624,14 +550,15 @@ void pa_volume_memchunk( switch (spec->format) { case PA_SAMPLE_S16NE: { - int16_t *d; - size_t n; + int16_t *d, *e; unsigned channel; int32_t linear[PA_CHANNELS_MAX]; calc_linear_integer_volume(linear, volume); - for (channel = 0, d = ptr, n = c->length/sizeof(int16_t); n > 0; d++, n--) { + e = (int16_t*) ptr + c->length/sizeof(int16_t); + + for (channel = 0, d = ptr; d < e; d++) { int32_t t; t = (int32_t)(*d); @@ -646,17 +573,18 @@ void pa_volume_memchunk( } case PA_SAMPLE_S16RE: { - int16_t *d; - size_t n; + int16_t *d, *e; unsigned channel; int32_t linear[PA_CHANNELS_MAX]; calc_linear_integer_volume(linear, volume); - for (channel = 0, d = ptr, n = c->length/sizeof(int16_t); n > 0; d++, n--) { + e = (int16_t*) ptr + c->length/sizeof(int16_t); + + for (channel = 0, d = ptr; d < e; d++) { int32_t t; - t = (int32_t)(PA_INT16_SWAP(*d)); + t = (int32_t) PA_INT16_SWAP(*d); t = (t * linear[channel]) / 0x10000; t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); *d = PA_INT16_SWAP((int16_t) t); @@ -669,14 +597,15 @@ void pa_volume_memchunk( } case PA_SAMPLE_S32NE: { - int32_t *d; - size_t n; + int32_t *d, *e; unsigned channel; int32_t linear[PA_CHANNELS_MAX]; calc_linear_integer_volume(linear, volume); - for (channel = 0, d = ptr, n = c->length/sizeof(int32_t); n > 0; d++, n--) { + e = (int32_t*) ptr + c->length/sizeof(int32_t); + + for (channel = 0, d = ptr; d < e; d++) { int64_t t; t = (int64_t)(*d); @@ -691,17 +620,18 @@ void pa_volume_memchunk( } case PA_SAMPLE_S32RE: { - int32_t *d; - size_t n; + int32_t *d, *e; unsigned channel; int32_t linear[PA_CHANNELS_MAX]; calc_linear_integer_volume(linear, volume); - for (channel = 0, d = ptr, n = c->length/sizeof(int32_t); n > 0; d++, n--) { + e = (int32_t*) ptr + c->length/sizeof(int32_t); + + for (channel = 0, d = ptr; d < e; d++) { int64_t t; - t = (int64_t)(PA_INT32_SWAP(*d)); + t = (int64_t) PA_INT32_SWAP(*d); t = (t * linear[channel]) / 0x10000; t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL); *d = PA_INT32_SWAP((int32_t) t); @@ -714,14 +644,15 @@ void pa_volume_memchunk( } case PA_SAMPLE_U8: { - uint8_t *d; - size_t n; + uint8_t *d, *e; unsigned channel; int32_t linear[PA_CHANNELS_MAX]; calc_linear_integer_volume(linear, volume); - for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) { + e = (uint8_t*) ptr + c->length; + + for (channel = 0, d = ptr; d < e; d++) { int32_t t; t = (int32_t) *d - 0x80; @@ -736,20 +667,21 @@ void pa_volume_memchunk( } case PA_SAMPLE_ULAW: { - uint8_t *d; - size_t n; + uint8_t *d, *e; unsigned channel; int32_t linear[PA_CHANNELS_MAX]; calc_linear_integer_volume(linear, volume); - for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) { + e = (uint8_t*) ptr + c->length; + + for (channel = 0, d = ptr; d < e; d++) { int32_t t; t = (int32_t) st_ulaw2linear16(*d); t = (t * linear[channel]) / 0x10000; t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *d = (uint8_t) st_14linear2ulaw(t >> 2); + *d = (uint8_t) st_14linear2ulaw((int16_t) t >> 2); if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; @@ -758,20 +690,21 @@ void pa_volume_memchunk( } case PA_SAMPLE_ALAW: { - uint8_t *d; - size_t n; + uint8_t *d, *e; unsigned channel; int32_t linear[PA_CHANNELS_MAX]; calc_linear_integer_volume(linear, volume); - for (channel = 0, d = ptr, n = c->length; n > 0; d++, n--) { + e = (uint8_t*) ptr + c->length; + + for (channel = 0, d = ptr; d < e; d++) { int32_t t; t = (int32_t) st_alaw2linear16(*d); t = (t * linear[channel]) / 0x10000; t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF); - *d = (uint8_t) st_13linear2alaw(t >> 3); + *d = (uint8_t) st_13linear2alaw((int16_t) t >> 3); if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; @@ -786,8 +719,8 @@ void pa_volume_memchunk( unsigned channel; d = ptr; - skip = spec->channels * sizeof(float); - n = c->length/sizeof(float)/spec->channels; + skip = (int) (spec->channels * sizeof(float)); + n = (unsigned) (c->length/sizeof(float)/spec->channels); for (channel = 0; channel < spec->channels; channel ++) { float v, *t; @@ -797,28 +730,26 @@ void pa_volume_memchunk( v = (float) pa_sw_volume_to_linear(volume->values[channel]); t = d + channel; - oil_scalarmult_f32(t, skip, t, skip, &v, n); + oil_scalarmult_f32(t, skip, t, skip, &v, (int) n); } break; } case PA_SAMPLE_FLOAT32RE: { - uint32_t *d; - size_t n; + float *d, *e; unsigned channel; float linear[PA_CHANNELS_MAX]; calc_linear_float_volume(linear, volume); - for (channel = 0, d = ptr, n = c->length/sizeof(float); n > 0; d++, n--) { + e = (float*) ptr + c->length/sizeof(float); + + for (channel = 0, d = ptr; d < e; d++) { float t; - uint32_t z; - z = PA_UINT32_SWAP(*d); - t = *(float*) &z; + t = PA_FLOAT32_SWAP(*d); t *= linear[channel]; - z = *(uint32_t*) &t; - *d = PA_UINT32_SWAP(z); + *d = PA_FLOAT32_SWAP(t); if (PA_UNLIKELY(++channel >= spec->channels)) channel = 0; @@ -846,7 +777,7 @@ size_t pa_frame_align(size_t l, const pa_sample_spec *ss) { return (l/fs) * fs; } -int pa_frame_aligned(size_t l, const pa_sample_spec *ss) { +pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) { size_t fs; pa_assert(ss); @@ -877,7 +808,7 @@ void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, u d = (uint8_t*) dst + c * ss; for (j = 0; j < n; j ++) { - oil_memcpy(d, s, ss); + oil_memcpy(d, s, (int) ss); s = (uint8_t*) s + ss; d = (uint8_t*) d + fs; } @@ -905,7 +836,7 @@ void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, d = dst[c]; for (j = 0; j < n; j ++) { - oil_memcpy(d, s, ss); + oil_memcpy(d, s, (int) ss); s = (uint8_t*) s + fs; d = (uint8_t*) d + ss; } @@ -1008,7 +939,7 @@ void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const vo if (format == PA_SAMPLE_FLOAT32NE) { float minus_one = -1.0, plus_one = 1.0; - oil_clip_f32(d, dstr, s, sstr, n, &minus_one, &plus_one); + oil_clip_f32(d, (int) dstr, s, (int) sstr, (int) n, &minus_one, &plus_one); } else { pa_assert(format == PA_SAMPLE_FLOAT32RE); @@ -1017,7 +948,7 @@ void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const vo float f; f = PA_FLOAT32_SWAP(*s); - f = PA_CLAMP_UNLIKELY(f, -1.0, 1.0); + f = PA_CLAMP_UNLIKELY(f, -1.0f, 1.0f); *d = PA_FLOAT32_SWAP(f); s = (const float*) ((const uint8_t*) s + sstr); @@ -1025,3 +956,34 @@ void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const vo } } } + +/* Similar to pa_bytes_to_usec() but rounds up, not down */ + +pa_usec_t pa_bytes_to_usec_round_up(uint64_t length, const pa_sample_spec *spec) { + size_t fs; + pa_usec_t usec; + + pa_assert(spec); + + fs = pa_frame_size(spec); + length = (length + fs - 1) / fs; + + usec = (pa_usec_t) length * PA_USEC_PER_SEC; + + return (usec + spec->rate - 1) / spec->rate; +} + +/* Similar to pa_usec_to_bytes() but rounds up, not down */ + +size_t pa_usec_to_bytes_round_up(pa_usec_t t, const pa_sample_spec *spec) { + uint64_t u; + pa_assert(spec); + + u = (uint64_t) t * (uint64_t) spec->rate; + + u = (u + PA_USEC_PER_SEC - 1) / PA_USEC_PER_SEC; + + u *= pa_frame_size(spec); + + return (size_t) u; +} diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h index cef70750..2fe2c81d 100644 --- a/src/pulsecore/sample-util.h +++ b/src/pulsecore/sample-util.h @@ -71,11 +71,14 @@ void pa_volume_memchunk( size_t pa_frame_align(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; -int pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; +pa_bool_t pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE; void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n); void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n); void pa_sample_clamp(pa_sample_format_t format, void *dst, size_t dstr, const void *src, size_t sstr, unsigned n); +pa_usec_t pa_bytes_to_usec_round_up(uint64_t length, const pa_sample_spec *spec); +size_t pa_usec_to_bytes_round_up(pa_usec_t t, const pa_sample_spec *spec); + #endif diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index 41670f27..159c4655 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -70,13 +70,13 @@ void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b) { for (; n > 0; n--) { int16_t s = *(a++); - *(b++) = ((float) INT16_FROM(s))/0x7FFF; + *(b++) = ((float) INT16_FROM(s))/(float) 0x7FFF; } #else { static const double add = 0, factor = 1.0/0x7FFF; - oil_scaleconv_f32_s16(b, a, n, &add, &factor); + oil_scaleconv_f32_s16(b, a, (int) n, &add, &factor); } #endif } @@ -95,7 +95,7 @@ void pa_sconv_s32le_to_float32ne(unsigned n, const int32_t *a, float *b) { #else { static const double add = 0, factor = 1.0/0x7FFFFFFF; - oil_scaleconv_f32_s32(b, a, n, &add, &factor); + oil_scaleconv_f32_s32(b, a, (int) n, &add, &factor); } #endif } @@ -110,15 +110,15 @@ void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) { int16_t s; float v = *(a++); - v = PA_CLAMP_UNLIKELY(v, -1, 1); - s = (int16_t) (v * 0x7FFF); + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.f); + s = (int16_t) lrintf(v * 0x7FFF); *(b++) = INT16_TO(s); } #else { static const double add = 0, factor = 0x7FFF; - oil_scaleconv_s16_f32(b, a, n, &add, &factor); + oil_scaleconv_s16_f32(b, a, (int) n, &add, &factor); } #endif } @@ -133,15 +133,15 @@ void pa_sconv_s32le_from_float32ne(unsigned n, const float *a, int32_t *b) { int32_t s; float v = *(a++); - v = PA_CLAMP_UNLIKELY(v, -1, 1); - s = (int32_t) ((double) v * (double) 0x7FFFFFFF); + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.0f); + s = (int32_t) lrint((double) v * (double) 0x7FFFFFFF); *(b++) = INT32_TO(s); } #else { static const double add = 0, factor = 0x7FFFFFFF; - oil_scaleconv_s32_f32(b, a, n, &add, &factor); + oil_scaleconv_s32_f32(b, a, (int) n, &add, &factor); } #endif } @@ -153,8 +153,7 @@ void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b) { for (; n > 0; n--) { int16_t s = *(a++); float k = ((float) INT16_FROM(s))/0x7FFF; - uint32_t *j = (uint32_t*) &k; - *j = PA_UINT32_SWAP(*j); + k = PA_FLOAT32_SWAP(k); *(b++) = k; } } @@ -166,8 +165,7 @@ void pa_sconv_s32le_to_float32re(unsigned n, const int32_t *a, float *b) { for (; n > 0; n--) { int32_t s = *(a++); float k = (float) (((double) INT32_FROM(s))/0x7FFFFFFF); - uint32_t *j = (uint32_t*) &k; - *j = PA_UINT32_SWAP(*j); + k = PA_FLOAT32_SWAP(k); *(b++) = k; } } @@ -179,10 +177,9 @@ void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b) { for (; n > 0; n--) { int16_t s; float v = *(a++); - uint32_t *j = (uint32_t*) &v; - *j = PA_UINT32_SWAP(*j); - v = PA_CLAMP_UNLIKELY(v, -1, 1); - s = (int16_t) (v * 0x7FFF); + v = PA_FLOAT32_SWAP(v); + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.0f); + s = (int16_t) lrintf(v * 0x7FFF); *(b++) = INT16_TO(s); } } @@ -194,10 +191,9 @@ void pa_sconv_s32le_from_float32re(unsigned n, const float *a, int32_t *b) { for (; n > 0; n--) { int32_t s; float v = *(a++); - uint32_t *j = (uint32_t*) &v; - *j = PA_UINT32_SWAP(*j); - v = PA_CLAMP_UNLIKELY(v, -1, 1); - s = (int32_t) ((double) v * 0x7FFFFFFF); + v = PA_FLOAT32_SWAP(v); + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.0f); + s = (int32_t) lrint((double) v * 0x7FFFFFFF); *(b++) = INT32_TO(s); } } @@ -219,7 +215,7 @@ void pa_sconv_s32le_to_s16re(unsigned n, const int32_t*a, int16_t *b) { for (; n > 0; n--) { int16_t s = (int16_t) (INT32_FROM(*a) >> 16); - *b = PA_UINT32_SWAP(s); + *b = PA_INT16_SWAP(s); a++; b++; } @@ -241,7 +237,7 @@ void pa_sconv_s32le_from_s16re(unsigned n, const int16_t *a, int32_t *b) { pa_assert(b); for (; n > 0; n--) { - int32_t s = ((int32_t) PA_UINT16_SWAP(*a)) << 16; + int32_t s = ((int32_t) PA_INT16_SWAP(*a)) << 16; *b = INT32_TO(s); a++; b++; diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index 581e4681..6c4d420e 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -46,7 +46,7 @@ static void u8_to_float32ne(unsigned n, const uint8_t *a, float *b) { pa_assert(a); pa_assert(b); - oil_scaleconv_f32_u8(b, a, n, &add, &factor); + oil_scaleconv_f32_u8(b, a, (int) n, &add, &factor); } static void u8_from_float32ne(unsigned n, const float *a, uint8_t *b) { @@ -55,7 +55,7 @@ static void u8_from_float32ne(unsigned n, const float *a, uint8_t *b) { pa_assert(a); pa_assert(b); - oil_scaleconv_u8_f32(b, a, n, &add, &factor); + oil_scaleconv_u8_f32(b, a, (int) n, &add, &factor); } static void u8_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) { @@ -64,9 +64,9 @@ static void u8_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) { pa_assert(a); pa_assert(b); - oil_conv_s16_u8(b, 2, a, 1, n); - oil_scalaradd_s16(b, 2, b, 2, &add, n); - oil_scalarmult_s16(b, 2, b, 2, &factor, n); + oil_conv_s16_u8(b, 2, a, 1, (int) n); + oil_scalaradd_s16(b, 2, b, 2, &add, (int) n); + oil_scalarmult_s16(b, 2, b, 2, &factor, (int) n); } static void u8_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) { @@ -84,7 +84,7 @@ static void float32ne_to_float32ne(unsigned n, const float *a, float *b) { pa_assert(a); pa_assert(b); - oil_memcpy(b, a, sizeof(float) * n); + oil_memcpy(b, a, (int) (sizeof(float) * n)); } static void float32re_to_float32ne(unsigned n, const float *a, float *b) { @@ -101,7 +101,7 @@ static void s16ne_to_s16ne(unsigned n, const int16_t *a, int16_t *b) { pa_assert(a); pa_assert(b); - oil_memcpy(b, a, sizeof(int16_t) * n); + oil_memcpy(b, a, (int) (sizeof(int16_t) * n)); } static void s16re_to_s16ne(unsigned n, const int16_t *a, int16_t *b) { @@ -109,7 +109,7 @@ static void s16re_to_s16ne(unsigned n, const int16_t *a, int16_t *b) { pa_assert(b); for (; n > 0; n--, a++, b++) - *b = PA_UINT16_SWAP(*a); + *b = PA_INT16_SWAP(*a); } /* ulaw */ @@ -128,9 +128,9 @@ static void ulaw_from_float32ne(unsigned n, const float *a, uint8_t *b) { for (; n > 0; n--) { float v = *(a++); - v = PA_CLAMP_UNLIKELY(v, -1, 1); + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.0f); v *= 0x1FFF; - *(b++) = st_14linear2ulaw((int16_t) v); + *(b++) = st_14linear2ulaw((int16_t) lrintf(v)); } } @@ -166,9 +166,9 @@ static void alaw_from_float32ne(unsigned n, const float *a, uint8_t *b) { for (; n > 0; n--, a++, b++) { float v = *a; - v = PA_CLAMP_UNLIKELY(v, -1, 1); + v = PA_CLAMP_UNLIKELY(v, -1.0f, 1.0f); v *= 0xFFF; - *b = st_13linear2alaw((int16_t) v); + *b = st_13linear2alaw((int16_t) lrintf(v)); } } @@ -177,7 +177,7 @@ static void alaw_to_s16ne(unsigned n, const int8_t *a, int16_t *b) { pa_assert(b); for (; n > 0; n--, a++, b++) - *b = st_alaw2linear16(*a); + *b = st_alaw2linear16((uint8_t) *a); } static void alaw_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) { diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index 298bf716..c59d247c 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -73,10 +73,10 @@ struct shm_marker PA_GCC_PACKED { pa_atomic_t marker; /* 0xbeefcafe */ pa_atomic_t pid; - uint64_t *_reserverd1; - uint64_t *_reserverd2; - uint64_t *_reserverd3; - uint64_t *_reserverd4; + uint64_t _reserved1; + uint64_t _reserved2; + uint64_t _reserved3; + uint64_t _reserved4; }; static char *segment_name(char *fn, size_t l, unsigned id) { @@ -105,7 +105,7 @@ int pa_shm_create_rw(pa_shm *m, size_t size, pa_bool_t shared, mode_t mode) { m->size = size; #ifdef MAP_ANONYMOUS - if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)) == MAP_FAILED) { + if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } @@ -138,12 +138,12 @@ int pa_shm_create_rw(pa_shm *m, size_t size, pa_bool_t shared, mode_t mode) { m->size = size + PA_ALIGN(sizeof(struct shm_marker)); - if (ftruncate(fd, m->size) < 0) { + if (ftruncate(fd, (off_t) m->size) < 0) { pa_log("ftruncate() failed: %s", pa_cstrerror(errno)); goto fail; } - if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { + if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } @@ -235,7 +235,7 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) { /* Align this to multiples of the page size */ ptr = (uint8_t*) m->ptr + offset; - o = (uint8_t*) ptr - (uint8_t*) PA_PAGE_ALIGN_PTR(ptr); + o = (size_t) ((uint8_t*) ptr - (uint8_t*) PA_PAGE_ALIGN_PTR(ptr)); if (o > 0) { ps = PA_PAGE_SIZE; @@ -289,9 +289,9 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) { goto fail; } - m->size = st.st_size; + m->size = (size_t) st.st_size; - if ((m->ptr = mmap(NULL, m->size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + if ((m->ptr = mmap(NULL, m->size, PROT_READ, MAP_SHARED, fd, (off_t) 0)) == MAP_FAILED) { pa_log("mmap() failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 64a6cdf9..0e1224f1 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -75,7 +75,7 @@ void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cv pa_assert(data); if ((data->volume_is_set = !!volume)) - data->volume = *volume; + data->volume = data->virtual_volume = *volume; } void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) { @@ -108,6 +108,7 @@ static void reset_callbacks(pa_sink_input *i) { i->kill = NULL; i->get_latency = NULL; i->state_change = NULL; + i->may_move_to = NULL; } /* Called from main context */ @@ -119,6 +120,7 @@ pa_sink_input* pa_sink_input_new( pa_sink_input *i; pa_resampler *resampler = NULL; char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_channel_map original_cm; pa_assert(core); pa_assert(data); @@ -141,20 +143,25 @@ pa_sink_input* pa_sink_input_new( pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec)); if (!data->channel_map_is_set) { - if (data->sink->channel_map.channels == data->sample_spec.channels) + if (pa_channel_map_compatible(&data->sink->channel_map, &data->sample_spec)) data->channel_map = data->sink->channel_map; else - pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT)); + pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); } pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); - pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec)); - if (!data->volume_is_set) + if (!data->volume_is_set) { pa_cvolume_reset(&data->volume, data->sample_spec.channels); + pa_cvolume_reset(&data->virtual_volume, data->sample_spec.channels); + } pa_return_null_if_fail(pa_cvolume_valid(&data->volume)); - pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec)); + + pa_return_null_if_fail(pa_cvolume_valid(&data->virtual_volume)); + pa_return_null_if_fail(pa_cvolume_compatible(&data->virtual_volume, &data->sample_spec)); if (!data->muted_is_set) data->muted = FALSE; @@ -165,6 +172,8 @@ pa_sink_input* pa_sink_input_new( if (flags & PA_SINK_INPUT_FIX_RATE) data->sample_spec.rate = data->sink->sample_spec.rate; + original_cm = data->channel_map; + if (flags & PA_SINK_INPUT_FIX_CHANNELS) { data->sample_spec.channels = data->sink->sample_spec.channels; data->channel_map = data->sink->channel_map; @@ -174,8 +183,7 @@ pa_sink_input* pa_sink_input_new( pa_assert(pa_channel_map_valid(&data->channel_map)); /* Due to the fixing of the sample spec the volume might not match anymore */ - if (data->volume.channels != data->sample_spec.channels) - pa_cvolume_set(&data->volume, data->sample_spec.channels, pa_cvolume_avg(&data->volume)); + pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map); if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; @@ -201,7 +209,8 @@ pa_sink_input* pa_sink_input_new( data->resample_method, ((flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | ((flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | - (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { + (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | + (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -226,7 +235,9 @@ pa_sink_input* pa_sink_input_new( i->sample_spec = data->sample_spec; i->channel_map = data->channel_map; + i->virtual_volume = data->virtual_volume; i->volume = data->volume; + i->muted = data->muted; if (data->sync_base) { @@ -535,7 +546,7 @@ int pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa * data, so let's just hand out silence */ pa_atomic_store(&i->thread_info.drained, 1); - pa_memblockq_seek(i->thread_info.render_memblockq, slength, PA_SEEK_RELATIVE); + pa_memblockq_seek(i->thread_info.render_memblockq, (int64_t) slength, PA_SEEK_RELATIVE); i->thread_info.playing_for = 0; if (i->thread_info.underrun_for != (uint64_t) -1) i->thread_info.underrun_for += ilength; @@ -756,14 +767,11 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) if (PA_SINK_INPUT_IS_LINKED(i->state)) pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); - else { + else /* If this sink input is not realized yet, we have to touch * the thread info data directly */ - usec = fixup_latency(i->sink, usec); i->thread_info.requested_sink_latency = usec; - i->sink->thread_info.requested_latency_valid = FALSE; - } return usec; } @@ -786,17 +794,34 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) { /* Called from main context */ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { + pa_sink_input_set_volume_data data; + pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(volume); + pa_assert(pa_cvolume_valid(volume)); + pa_assert(pa_cvolume_compatible(volume, &i->sample_spec)); + + data.sink_input = i; + data.virtual_volume = *volume; + data.volume = *volume; + + /* If you change something here, consider looking into + * module-flat-volume.c as well since it uses very similar + * code. */ - if (pa_cvolume_equal(&i->volume, volume)) + if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], &data) < 0) return; - i->volume = *volume; + if (!pa_cvolume_equal(&i->volume, &data.volume)) { + i->volume = data.volume; + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, &data.volume, 0, NULL) == 0); + } - pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, &i->volume, 0, NULL) == 0); - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + if (!pa_cvolume_equal(&i->virtual_volume, &data.virtual_volume)) { + i->virtual_volume = data.virtual_volume; + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + } } /* Called from main context */ @@ -804,7 +829,7 @@ const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - return &i->volume; + return &i->virtual_volume; } /* Called from main context */ @@ -887,6 +912,35 @@ 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_to(pa_sink_input *i, pa_sink *dest) { + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + pa_sink_assert_ref(dest); + + if (dest == i->sink) + return TRUE; + + if (i->flags & PA_SINK_INPUT_DONT_MOVE) + return FALSE; + + if (i->sync_next || i->sync_prev) { + pa_log_warn("Moving synchronised streams not supported."); + return FALSE; + } + + if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { + pa_log_warn("Failed to move sink input: too many inputs per sink."); + return FALSE; + } + + if (i->may_move_to) + if (!i->may_move_to(i, dest)) + return FALSE; + + return TRUE; +} + +/* Called from main context */ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { pa_resampler *new_resampler; pa_sink *origin; @@ -902,18 +956,8 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { if (dest == origin) return 0; - if (i->flags & PA_SINK_INPUT_DONT_MOVE) - return -1; - - if (i->sync_next || i->sync_prev) { - pa_log_warn("Moving synchronised streams not supported."); + if (!pa_sink_input_may_move_to(i, dest)) return -1; - } - - if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log_warn("Failed to move sink input: too many inputs per sink."); - return -1; - } /* Kill directly connected outputs */ while ((o = pa_idxset_first(i->direct_outputs, NULL))) { @@ -1032,6 +1076,9 @@ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state } else if (uncorking) { + i->thread_info.underrun_for = (uint64_t) -1; + i->thread_info.playing_for = 0; + pa_log_debug("Requesting rewind due to uncorking"); /* OK, we're being uncorked. Make sure we're not rewound when diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index c07a7404..27125988 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -56,7 +56,8 @@ typedef enum pa_sink_input_flags { PA_SINK_INPUT_NO_REMIX = 16, PA_SINK_INPUT_FIX_FORMAT = 32, PA_SINK_INPUT_FIX_RATE = 64, - PA_SINK_INPUT_FIX_CHANNELS = 128 + PA_SINK_INPUT_FIX_CHANNELS = 128, + PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256, } pa_sink_input_flags_t; struct pa_sink_input { @@ -89,6 +90,8 @@ struct pa_sink_input { pa_sink_input *sync_prev, *sync_next; + pa_cvolume virtual_volume; + pa_cvolume volume; pa_bool_t muted; @@ -154,10 +157,15 @@ struct pa_sink_input { returns */ pa_usec_t (*get_latency) (pa_sink_input *i); /* may be NULL */ - /* If non_NULL this function is called from thread context if the + /* If non-NULL this function is called from thread context if the * state changes. The old state is found in thread_info.state. */ void (*state_change) (pa_sink_input *i, pa_sink_input_state_t state); /* may be NULL */ + /* If non-NULL this function is called before this sink input is + * move to a sink and if it returns FALSE the move will not + * be allowed */ + pa_bool_t (*may_move_to) (pa_sink_input *i, pa_sink *s); /* may be NULL */ + struct { pa_sink_input_state_t state; pa_atomic_t drained; @@ -212,19 +220,22 @@ typedef struct pa_sink_input_new_data { pa_sink *sink; + pa_resample_method_t resample_method; + + pa_sink_input *sync_base; + pa_sample_spec sample_spec; - pa_bool_t sample_spec_is_set; pa_channel_map channel_map; - pa_bool_t channel_map_is_set; - pa_cvolume volume; - pa_bool_t volume_is_set; - pa_bool_t muted; - pa_bool_t muted_is_set; + pa_cvolume virtual_volume; - pa_resample_method_t resample_method; + pa_cvolume volume; + pa_bool_t muted:1; - pa_sink_input *sync_base; + pa_bool_t sample_spec_is_set:1; + pa_bool_t channel_map_is_set:1; + pa_bool_t volume_is_set:1; + pa_bool_t muted_is_set:1; } pa_sink_input_new_data; pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data); @@ -239,6 +250,12 @@ typedef struct pa_sink_input_move_hook_data { pa_sink *destination; } pa_sink_input_move_hook_data; +typedef struct pa_sink_set_input_volume_data { + pa_sink_input *sink_input; + pa_cvolume virtual_volume; + pa_cvolume volume; +} pa_sink_input_set_volume_data; + /* To be called by the implementing module only */ pa_sink_input* pa_sink_input_new( @@ -281,6 +298,7 @@ pa_bool_t pa_sink_input_get_mute(pa_sink_input *i); pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest); +pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest); 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 4102f31d..a6027e70 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -663,7 +663,6 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume); if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) { - pa_log("adjusting volume "); pa_memchunk_make_writable(result, 0); if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) pa_silence_memchunk(result, &s->sample_spec); @@ -844,30 +843,55 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { /* Called from main thread */ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) { pa_bool_t changed; + pa_sink_set_volume_data data; pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); pa_assert(volume); + pa_assert(pa_cvolume_valid(volume)); + pa_assert(pa_cvolume_compatible(volume, &s->sample_spec)); - changed = !pa_cvolume_equal(volume, &s->volume); - s->volume = *volume; + data.sink = s; + data.volume = *volume; + + changed = !pa_cvolume_equal(&data.volume, &s->volume); + + if (changed) { + if (pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_SET_VOLUME], &data) < 0) + return; + + changed = !pa_cvolume_equal(&data.volume, &s->volume); + } + + s->volume = data.volume; if (s->set_volume && s->set_volume(s) < 0) s->set_volume = NULL; if (!s->set_volume) - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, volume, 0, NULL); + pa_sink_set_soft_volume(s, volume); if (changed) pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } /* Called from main thread */ -const pa_cvolume *pa_sink_get_volume(pa_sink *s) { +void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) { + pa_sink_assert_ref(s); + pa_assert(volume); + + if (PA_SINK_IS_LINKED(s->state)) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, volume, 0, NULL); + else + s->thread_info.soft_volume = *volume; +} + +/* Called from main thread */ +const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); - if (s->refresh_volume) { + if (s->refresh_volume || force_refresh) { struct pa_cvolume old_volume = s->volume; if (s->get_volume && s->get_volume(s) < 0) @@ -904,12 +928,12 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) { } /* Called from main thread */ -pa_bool_t pa_sink_get_mute(pa_sink *s) { +pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) { pa_sink_assert_ref(s); pa_assert(PA_SINK_IS_LINKED(s->state)); - if (s->refresh_muted) { + if (s->refresh_muted || force_refresh) { pa_bool_t old_muted = s->muted; if (s->get_mute && s->get_mute(s) < 0) @@ -967,7 +991,7 @@ unsigned pa_sink_linked_by(pa_sink *s) { ret = pa_idxset_size(s->inputs); /* We add in the number of streams connected to us here. Please - * not the asymmmetry to pa_sink_used_by()! */ + * note the asymmmetry to pa_sink_used_by()! */ if (s->monitor_source) ret += pa_source_linked_by(s->monitor_source); @@ -991,6 +1015,38 @@ unsigned pa_sink_used_by(pa_sink *s) { return ret - s->n_corked; } +/* Called from main thread */ +unsigned pa_sink_check_suspend(pa_sink *s) { + unsigned ret; + pa_sink_input *i; + uint32_t idx; + + pa_sink_assert_ref(s); + pa_assert(PA_SINK_IS_LINKED(s->state)); + + ret = 0; + + for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) { + pa_sink_input_state_t st; + + st = pa_sink_input_get_state(i); + pa_assert(PA_SINK_INPUT_IS_LINKED(st)); + + if (st == PA_SINK_INPUT_CORKED) + continue; + + if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND) + continue; + + ret ++; + } + + if (s->monitor_source) + ret += pa_source_check_suspend(s->monitor_source); + + return ret; +} + /* Called from IO thread, except when it is not */ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { pa_sink *s = PA_SINK(o); @@ -1031,11 +1087,15 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse pa_sink_input_set_state_within_thread(i, i->state); + /* The requested latency of the sink input needs to be + * fixed up and then configured on the sink */ + + if (i->thread_info.requested_sink_latency != (pa_usec_t) -1) + pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency); + pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind); pa_sink_input_update_max_request(i, s->thread_info.max_request); - pa_sink_invalidate_requested_latency(s); - /* We don't rewind here automatically. This is left to the * sink input implementor because some sink inputs need a * slow start, i.e. need some time to buffer client @@ -1147,11 +1207,12 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse if (i->attach) i->attach(i); + if (i->thread_info.requested_sink_latency != (pa_usec_t) -1) + pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency); + pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind); pa_sink_input_update_max_request(i, s->thread_info.max_request); - pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency); - if (i->thread_info.state != PA_SINK_INPUT_CORKED) { pa_usec_t usec = 0; size_t nbytes; @@ -1413,7 +1474,6 @@ void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) { /* Called from IO thread */ void pa_sink_set_max_request(pa_sink *s, size_t max_request) { - pa_sink_input *i; void *state = NULL; pa_sink_assert_ref(s); @@ -1424,6 +1484,8 @@ void pa_sink_set_max_request(pa_sink *s, size_t max_request) { s->thread_info.max_request = 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_sink_input_update_max_request(i, s->thread_info.max_request); } diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 604be269..c5a73214 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -180,21 +180,22 @@ typedef enum pa_sink_message { typedef struct pa_sink_new_data { char *name; - pa_bool_t namereg_fail; pa_proplist *proplist; const char *driver; pa_module *module; pa_sample_spec sample_spec; - pa_bool_t sample_spec_is_set; pa_channel_map channel_map; - pa_bool_t channel_map_is_set; - pa_cvolume volume; - pa_bool_t volume_is_set; - pa_bool_t muted; - pa_bool_t muted_is_set; + pa_bool_t muted :1; + + pa_bool_t sample_spec_is_set:1; + pa_bool_t channel_map_is_set:1; + pa_bool_t volume_is_set:1; + pa_bool_t muted_is_set:1; + + pa_bool_t namereg_fail:1; } pa_sink_new_data; pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data); @@ -205,6 +206,11 @@ void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volum void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute); void pa_sink_new_data_done(pa_sink_new_data *data); +typedef struct pa_sink_set_volume_data { + pa_sink *sink; + pa_cvolume volume; +} pa_sink_set_volume_data; + /* To be called exclusively by the sink driver, from main context */ pa_sink* pa_sink_new( @@ -239,12 +245,14 @@ int pa_sink_suspend(pa_sink *s, pa_bool_t suspend); int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend); void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume); -const pa_cvolume *pa_sink_get_volume(pa_sink *sink); +void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume); +const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh); void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute); -pa_bool_t pa_sink_get_mute(pa_sink *sink); +pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refres); unsigned pa_sink_linked_by(pa_sink *s); /* Number of connected streams */ unsigned pa_sink_used_by(pa_sink *s); /* Number of connected streams which are not corked */ +unsigned pa_sink_check_suspend(pa_sink *s); /* Returns how many streams are active that don't allow suspensions */ #define pa_sink_get_state(s) ((s)->state) /* To be called exclusively by the sink driver, from IO context */ diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c index e69a63da..6739effd 100644 --- a/src/pulsecore/socket-client.c +++ b/src/pulsecore/socket-client.c @@ -187,7 +187,7 @@ static void connect_defer_cb(pa_mainloop_api *m, pa_defer_event *e, void *userda do_call(c); } -static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { +static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_socket_client *c = userdata; pa_assert(m); @@ -283,7 +283,7 @@ static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size else pa_make_socket_low_delay(c->fd); - if (do_connect(c, sa, salen) < 0) + if (do_connect(c, sa, (socklen_t) salen) < 0) return -1; return 0; @@ -370,7 +370,7 @@ pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[ #ifdef HAVE_LIBASYNCNS -static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { +static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_socket_client *c = userdata; struct addrinfo *res = NULL; int ret; @@ -437,7 +437,7 @@ static void start_timeout(pa_socket_client *c) { pa_assert(!c->timeout_event); pa_gettimeofday(&tv); - pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000); + pa_timeval_add(&tv, CONNECT_TIMEOUT * PA_USEC_PER_SEC); c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c); } diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c index 9885a02b..a600e0a6 100644 --- a/src/pulsecore/socket-server.c +++ b/src/pulsecore/socket-server.c @@ -199,7 +199,7 @@ pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *file pa_make_socket_low_delay(fd); - if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) { + if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) { pa_log("bind(): %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 8b2a29b9..c30c16eb 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -170,10 +170,10 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk if (u->readf_function) { fs = pa_frame_size(&i->sample_spec); - n = u->readf_function(u->sndfile, p, length/fs); + n = u->readf_function(u->sndfile, p, (sf_count_t) (length/fs)); } else { fs = 1; - n = sf_read_raw(u->sndfile, p, length); + n = sf_read_raw(u->sndfile, p, (sf_count_t) length); } pa_memblock_release(tchunk.memblock); @@ -186,7 +186,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk break; } - tchunk.length = n * fs; + tchunk.length = (size_t) n * fs; pa_memblockq_push(u->memblockq, &tchunk); pa_memblock_unref(tchunk.memblock); @@ -310,8 +310,8 @@ int pa_play_file( break; } - ss.rate = sfinfo.samplerate; - ss.channels = sfinfo.channels; + ss.rate = (uint32_t) sfinfo.samplerate; + ss.channels = (uint8_t) sfinfo.channels; if (!pa_sample_spec_valid(&ss)) { pa_log("Unsupported sample format in file %s", fname); diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c index 3183ede6..380cef16 100644 --- a/src/pulsecore/sound-file.c +++ b/src/pulsecore/sound-file.c @@ -89,7 +89,7 @@ int pa_sound_file_load( case SF_FORMAT_PCM_U8: case SF_FORMAT_PCM_S8: ss->format = PA_SAMPLE_S16NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_short; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *_ptr, sf_count_t frames)) sf_readf_short; break; case SF_FORMAT_ULAW: @@ -104,12 +104,12 @@ int pa_sound_file_load( case SF_FORMAT_DOUBLE: default: ss->format = PA_SAMPLE_FLOAT32NE; - readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *ptr, sf_count_t frames)) sf_readf_float; + readf_function = (sf_count_t (*)(SNDFILE *sndfile, void *_ptr, sf_count_t frames)) sf_readf_float; break; } - ss->rate = sfinfo.samplerate; - ss->channels = sfinfo.channels; + ss->rate = (uint32_t) sfinfo.samplerate; + ss->channels = (uint8_t) sfinfo.channels; if (!pa_sample_spec_valid(ss)) { pa_log("Unsupported sample format in file %s", fname); @@ -119,7 +119,7 @@ int pa_sound_file_load( if (map) pa_channel_map_init_extend(map, ss->channels, PA_CHANNEL_MAP_DEFAULT); - if ((l = pa_frame_size(ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { + if ((l = pa_frame_size(ss) * (size_t) sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { pa_log("File too large"); goto finish; } @@ -131,7 +131,7 @@ int pa_sound_file_load( ptr = pa_memblock_acquire(chunk->memblock); if ((readf_function && readf_function(sf, ptr, sfinfo.frames) != sfinfo.frames) || - (!readf_function && sf_read_raw(sf, ptr, l) != (sf_count_t) l)) { + (!readf_function && sf_read_raw(sf, ptr, (sf_count_t) l) != (sf_count_t) l)) { pa_log("Premature file end"); goto finish; } @@ -189,15 +189,15 @@ int pa_sound_file_too_big_to_cache(const char *fname) { break; } - ss.rate = sfinfo.samplerate; - ss.channels = sfinfo.channels; + ss.rate = (uint32_t) sfinfo.samplerate; + ss.channels = (uint8_t) sfinfo.channels; if (!pa_sample_spec_valid(&ss)) { pa_log("Unsupported sample format in file %s", fname); return -1; } - if ((pa_frame_size(&ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { + if ((pa_frame_size(&ss) * (size_t) sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) { pa_log("File too large: %s", fname); return 1; } diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index dbf3af94..376402fa 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -90,6 +90,7 @@ static void reset_callbacks(pa_source_output *o) { o->kill = NULL; o->get_latency = NULL; o->state_change = NULL; + o->may_move_to = NULL; } /* Called from main context */ @@ -124,14 +125,14 @@ pa_source_output* pa_source_output_new( pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec)); if (!data->channel_map_is_set) { - if (data->source->channel_map.channels == data->sample_spec.channels) + if (pa_channel_map_compatible(&data->source->channel_map, &data->sample_spec)) data->channel_map = data->source->channel_map; else - pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT)); + pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); } pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); - pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec)); if (flags & PA_SOURCE_OUTPUT_FIX_FORMAT) data->sample_spec.format = data->source->sample_spec.format; @@ -171,7 +172,8 @@ pa_source_output* pa_source_output_new( data->resample_method, ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | ((flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | - (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { + (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) | + (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) { pa_log_warn("Unsupported resampling operation."); return NULL; } @@ -397,7 +399,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { if (pa_memblockq_push(o->thread_info.delay_memblockq, chunk) < 0) { pa_log_debug("Delay queue overflow!"); - pa_memblockq_seek(o->thread_info.delay_memblockq, chunk->length, PA_SEEK_RELATIVE); + pa_memblockq_seek(o->thread_info.delay_memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE); } limit = o->process_rewind ? 0 : o->source->thread_info.max_rewind; @@ -511,14 +513,11 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0); - else { + else /* If this source output is not realized yet, we have to touch * the thread info data directly */ - usec = fixup_latency(o->source, usec); o->thread_info.requested_source_latency = usec; - o->source->thread_info.requested_latency_valid = FALSE; - } return usec; } @@ -595,6 +594,32 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { return o->resample_method; } +pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) { + pa_source_output_assert_ref(o); + pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); + pa_source_assert_ref(dest); + + if (dest == o->source) + return TRUE; + + if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) + return FALSE; + + if (o->direct_on_input) + return FALSE; + + if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { + pa_log_warn("Failed to move source output: too many outputs per source."); + return FALSE; + } + + if (o->may_move_to) + if (!o->may_move_to(o, dest)) + return FALSE; + + return TRUE; +} + /* Called from main context */ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { pa_source *origin; @@ -610,17 +635,9 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) { if (dest == origin) return 0; - if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE) + if (!pa_source_output_may_move_to(o, dest)) return -1; - if (o->direct_on_input) - return -1; - - if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { - pa_log_warn("Failed to move source output: too many outputs per source."); - return -1; - } - if (o->thread_info.resampler && pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 61825b22..f011f9bd 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -52,7 +52,8 @@ typedef enum pa_source_output_flags { PA_SOURCE_OUTPUT_NO_REMIX = 16, PA_SOURCE_OUTPUT_FIX_FORMAT = 32, PA_SOURCE_OUTPUT_FIX_RATE = 64, - PA_SOURCE_OUTPUT_FIX_CHANNELS = 128 + PA_SOURCE_OUTPUT_FIX_CHANNELS = 128, + PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND = 256 } pa_source_output_flags_t; struct pa_source_output { @@ -126,10 +127,15 @@ struct pa_source_output { returns */ pa_usec_t (*get_latency) (pa_source_output *o); /* may be NULL */ - /* If non_NULL this function is called from thread context if the + /* If non-NULL this function is called from thread context if the * state changes. The old state is found in thread_info.state. */ void (*state_change) (pa_source_output *o, pa_source_output_state_t state); /* may be NULL */ + /* If non-NULL this function is called before this source output + * is moved to a source and if it returns FALSE the move + * will not be allowed */ + pa_bool_t (*may_move_to) (pa_source_output *o, pa_source *s); /* may be NULL */ + struct { pa_source_output_state_t state; @@ -174,12 +180,13 @@ typedef struct pa_source_output_new_data { pa_source *source; + pa_resample_method_t resample_method; + pa_sample_spec sample_spec; - pa_bool_t sample_spec_is_set; pa_channel_map channel_map; - pa_bool_t channel_map_is_set; - pa_resample_method_t resample_method; + pa_bool_t sample_spec_is_set:1; + pa_bool_t channel_map_is_set:1; } pa_source_output_new_data; pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data); @@ -219,6 +226,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *i, pa_usec_t *source_la pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); +pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest); int pa_source_output_move_to(pa_source_output *o, pa_source *dest); #define pa_source_output_get_state(o) ((o)->state) diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 31620690..7d927faa 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -520,18 +520,29 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) { s->set_volume = NULL; if (!s->set_volume) - pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, volume, 0, NULL); + pa_source_set_soft_volume(s, volume); if (changed) pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); } /* Called from main thread */ -const pa_cvolume *pa_source_get_volume(pa_source *s) { +void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) { + pa_source_assert_ref(s); + pa_assert(volume); + + if (PA_SOURCE_IS_LINKED(s->state)) + pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, volume, 0, NULL); + else + s->thread_info.soft_volume = *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(PA_SOURCE_IS_LINKED(s->state)); - if (s->refresh_volume) { + if (s->refresh_volume || force_refresh) { pa_cvolume old_volume = s->volume; if (s->get_volume && s->get_volume(s) < 0) @@ -568,12 +579,12 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute) { } /* Called from main thread */ -pa_bool_t pa_source_get_mute(pa_source *s) { +pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) { pa_source_assert_ref(s); pa_assert(PA_SOURCE_IS_LINKED(s->state)); - if (s->refresh_muted) { + if (s->refresh_muted || force_refresh) { pa_bool_t old_muted = s->muted; if (s->get_mute && s->get_mute(s) < 0) @@ -634,6 +645,35 @@ unsigned pa_source_used_by(pa_source *s) { return ret - s->n_corked; } +/* Called from main thread */ +unsigned pa_source_check_suspend(pa_source *s) { + unsigned ret; + pa_source_output *o; + uint32_t idx; + + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_IS_LINKED(s->state)); + + ret = 0; + + for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) { + pa_source_output_state_t st; + + st = pa_source_output_get_state(o); + pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st)); + + if (st == PA_SOURCE_OUTPUT_CORKED) + continue; + + if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND) + continue; + + ret ++; + } + + return ret; +} + /* Called from IO thread, except when it is not */ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { pa_source *s = PA_SOURCE(object); @@ -659,6 +699,9 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ pa_source_output_set_state_within_thread(o, o->state); + if (o->thread_info.requested_source_latency != (pa_usec_t) -1) + pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency); + pa_source_output_update_max_rewind(o, s->thread_info.max_rewind); /* We don't just invalidate the requested latency here, diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index f4a17e8d..aaf904b4 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -168,21 +168,22 @@ typedef enum pa_source_message { typedef struct pa_source_new_data { char *name; - pa_bool_t namereg_fail; pa_proplist *proplist; const char *driver; pa_module *module; pa_sample_spec sample_spec; - pa_bool_t sample_spec_is_set; pa_channel_map channel_map; - pa_bool_t channel_map_is_set; - pa_cvolume volume; - pa_bool_t volume_is_set; - pa_bool_t muted; - pa_bool_t muted_is_set; + pa_bool_t muted:1; + + pa_bool_t volume_is_set:1; + pa_bool_t muted_is_set:1; + pa_bool_t sample_spec_is_set:1; + pa_bool_t channel_map_is_set:1; + + pa_bool_t namereg_fail:1; } pa_source_new_data; pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data); @@ -226,12 +227,14 @@ int pa_source_suspend(pa_source *s, pa_bool_t suspend); int pa_source_suspend_all(pa_core *c, pa_bool_t suspend); void pa_source_set_volume(pa_source *source, const pa_cvolume *volume); -const pa_cvolume *pa_source_get_volume(pa_source *source); +void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume); +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 pa_source_get_mute(pa_source *source); +pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh); unsigned pa_source_linked_by(pa_source *s); /* Number of connected streams */ unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that are not corked */ +unsigned pa_source_check_suspend(pa_source *s); /* Returns how many streams are active that don't allow suspensions */ #define pa_source_get_state(s) ((pa_source_state_t) (s)->state) /* To be called exclusively by the source driver, from IO context */ diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c index 1661383d..7774bde6 100644 --- a/src/pulsecore/start-child.c +++ b/src/pulsecore/start-child.c @@ -66,11 +66,6 @@ int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) { return pipe_fds[0]; } else { -#ifdef __linux__ - DIR* d; -#endif - int max_fd, i; - /* child */ pa_reset_priority(); @@ -87,48 +82,9 @@ int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) { pa_close(2); pa_assert_se(open("/dev/null", O_WRONLY) == 2); -#ifdef __linux__ - - if ((d = opendir("/proc/self/fd/"))) { - - struct dirent *de; - - while ((de = readdir(d))) { - char *e = NULL; - int fd; - - if (de->d_name[0] == '.') - continue; - - errno = 0; - fd = strtol(de->d_name, &e, 10); - pa_assert(errno == 0 && e && *e == 0); - - if (fd >= 3 && dirfd(d) != fd) - pa_close(fd); - } - - closedir(d); - } else { - -#endif - - max_fd = 1024; - -#ifdef HAVE_SYS_RESOURCE_H - { - struct rlimit r; - if (getrlimit(RLIMIT_NOFILE, &r) == 0) - max_fd = r.rlim_max; - } -#endif - - for (i = 3; i < max_fd; i++) - pa_close(i); - -#ifdef __linux__ - } -#endif + pa_close_all(-1); + pa_reset_sigs(-1); + pa_unblock_sigs(-1); #ifdef PR_SET_PDEATHSIG /* On Linux we can use PR_SET_PDEATHSIG to have the helper @@ -139,16 +95,6 @@ int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) { prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); #endif -#ifdef SIGPIPE - /* Make sure that SIGPIPE kills the child process */ - signal(SIGPIPE, SIG_DFL); -#endif - -#ifdef SIGTERM - /* Make sure that SIGTERM kills the child process */ - signal(SIGTERM, SIG_DFL); -#endif - execl(name, name, argv1, NULL); _exit(1); } diff --git a/src/pulsecore/strbuf.c b/src/pulsecore/strbuf.c index b59b6f49..540faef9 100644 --- a/src/pulsecore/strbuf.c +++ b/src/pulsecore/strbuf.c @@ -77,7 +77,7 @@ char *pa_strbuf_tostring(pa_strbuf *sb) { pa_assert(sb); - e = t = pa_xnew(char, sb->length+1); + e = t = pa_xmalloc(sb->length+1); for (c = sb->head; c; c = c->next) { pa_assert((size_t) (e-t) <= sb->length); @@ -150,8 +150,8 @@ void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) { /* Append a printf() style formatted string to the string buffer. */ /* The following is based on an example from the GNU libc documentation */ -int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { - int size = 100; +size_t pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { + size_t size = 100; struct chunk *c = NULL; pa_assert(sb); @@ -168,14 +168,14 @@ int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) { CHUNK_TO_TEXT(c)[size-1] = 0; va_end(ap); - if (r > -1 && r < size) { - c->length = r; + if (r > -1 && (size_t) r < size) { + c->length = (size_t) r; append(sb, c); - return r; + return (size_t) r; } if (r > -1) /* glibc 2.1 */ - size = r+1; + size = (size_t) r+1; else /* glibc 2.0 */ size *= 2; } diff --git a/src/pulsecore/strbuf.h b/src/pulsecore/strbuf.h index 24c876d5..ac68d7be 100644 --- a/src/pulsecore/strbuf.h +++ b/src/pulsecore/strbuf.h @@ -31,7 +31,7 @@ void pa_strbuf_free(pa_strbuf *sb); char *pa_strbuf_tostring(pa_strbuf *sb); char *pa_strbuf_tostring_free(pa_strbuf *sb); -int pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); +size_t pa_strbuf_printf(pa_strbuf *sb, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); void pa_strbuf_puts(pa_strbuf *sb, const char *t); void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t m); diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c index b0ed59ef..62a30144 100644 --- a/src/pulsecore/tagstruct.c +++ b/src/pulsecore/tagstruct.c @@ -154,7 +154,7 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) { extend(t, 5+length); t->data[t->length] = PA_TAG_ARBITRARY; - tmp = htonl(length); + tmp = htonl((uint32_t) length); memcpy(t->data+t->length+1, &tmp, 4); if (length) memcpy(t->data+t->length+5, p, length); @@ -165,7 +165,7 @@ void pa_tagstruct_put_boolean(pa_tagstruct*t, pa_bool_t b) { pa_assert(t); extend(t, 1); - t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE; + t->data[t->length] = (uint8_t) (b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE); t->length += 1; } @@ -175,9 +175,9 @@ void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) { extend(t, 9); t->data[t->length] = PA_TAG_TIMEVAL; - tmp = htonl(tv->tv_sec); + tmp = htonl((uint32_t) tv->tv_sec); memcpy(t->data+t->length+1, &tmp, 4); - tmp = htonl(tv->tv_usec); + tmp = htonl((uint32_t) tv->tv_usec); memcpy(t->data+t->length+5, &tmp, 4); t->length += 9; } @@ -228,7 +228,7 @@ void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { unsigned i; pa_assert(t); - extend(t, 2 + map->channels); + extend(t, 2 + (size_t) map->channels); t->data[t->length++] = PA_TAG_CHANNEL_MAP; t->data[t->length++] = map->channels; @@ -435,9 +435,9 @@ int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) { return -1; memcpy(&tv->tv_sec, t->data+t->rindex+1, 4); - tv->tv_sec = ntohl(tv->tv_sec); + tv->tv_sec = (time_t) ntohl((uint32_t) tv->tv_sec); memcpy(&tv->tv_usec, t->data+t->rindex+5, 4); - tv->tv_usec = ntohl(tv->tv_usec); + tv->tv_usec = (suseconds_t) ntohl((uint32_t) tv->tv_usec); t->rindex += 9; return 0; } @@ -523,7 +523,7 @@ int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { for (i = 0; i < map->channels; i ++) map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; - t->rindex += 2 + map->channels; + t->rindex += 2 + (size_t) map->channels; return 0; } diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index 20ed16d9..ade398f9 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -41,6 +41,7 @@ struct pa_thread { pa_thread_func_t thread_func; void *userdata; pa_atomic_t running; + pa_bool_t joined; }; struct pa_tls { @@ -82,6 +83,7 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) { t = pa_xnew(pa_thread, 1); t->thread_func = thread_func; t->userdata = userdata; + t->joined = FALSE; pa_atomic_store(&t->running, 0); if (pthread_create(&t->id, NULL, internal_thread_func, t) < 0) { @@ -115,7 +117,12 @@ void pa_thread_free(pa_thread *t) { int pa_thread_join(pa_thread *t) { pa_assert(t); + pa_assert(t->thread_func); + + if (t->joined) + return -1; + t->joined = TRUE; return pthread_join(t->id, NULL); } @@ -132,6 +139,7 @@ pa_thread* pa_thread_self(void) { t->id = pthread_self(); t->thread_func = NULL; t->userdata = NULL; + t->joined = TRUE; pa_atomic_store(&t->running, 2); PA_STATIC_TLS_SET(current_thread, t); @@ -192,4 +200,3 @@ void *pa_tls_set(pa_tls *t, void *userdata) { pa_assert_se(pthread_setspecific(t->key, userdata) == 0); return r; } - diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index f3aca13e..eabe9ba4 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -25,6 +25,7 @@ #include <pulse/def.h> #include <pulsecore/once.h> +#include <pulsecore/core-util.h> #ifndef PACKAGE #error "Please include config.h before including this file!" @@ -69,6 +70,8 @@ void *pa_tls_set(pa_tls *t, void *userdata); static void name##_tls_destructor(void) PA_GCC_DESTRUCTOR; \ static void name##_tls_destructor(void) { \ static void (*_free_cb)(void*) = free_cb; \ + if (!pa_in_valgrind()) \ + return; \ if (!name##_tls.tls) \ return; \ if (_free_cb) { \ @@ -86,7 +89,7 @@ void *pa_tls_set(pa_tls *t, void *userdata); } \ struct __stupid_useless_struct_to_allow_trailing_semicolon -#ifdef HAVE_TLS_BUILTIN +#ifdef SUPPORT_TLS___THREAD /* An optimized version of the above that requires no dynamic * allocation if the compiler supports __thread */ #define PA_STATIC_TLS_DECLARE_NO_FREE(name) \ diff --git a/src/pulsecore/time-smoother.c b/src/pulsecore/time-smoother.c index d0231486..65621948 100644 --- a/src/pulsecore/time-smoother.c +++ b/src/pulsecore/time-smoother.c @@ -209,8 +209,8 @@ static double avg_gradient(pa_smoother *s, pa_usec_t x) { i = s->history_idx; for (j = s->n_history; j > 0; j--) { - ax += s->history_x[i]; - ay += s->history_y[i]; + ax += (int64_t) s->history_x[i]; + ay += (int64_t) s->history_y[i]; c++; REDUCE_INC(i); @@ -236,7 +236,7 @@ static double avg_gradient(pa_smoother *s, pa_usec_t x) { REDUCE_INC(i); } - r = (double) k / t; + r = (double) k / (double) t; return (s->monotonic && r < 0) ? 0 : r; } @@ -268,8 +268,8 @@ static void calc_abc(pa_smoother *s) { /* Calculate a, b, c for y=ax^3+bx^2+cx */ s->c = de; - s->b = (((double) (3*ky)/kx - dp - 2*de)) / kx; - s->a = (dp/kx - 2*s->b - de/kx) / (3*kx); + s->b = (((double) (3*ky)/ (double) kx - dp - (double) (2*de))) / (double) kx; + s->a = (dp/(double) kx - 2*s->b - de/(double) kx) / (double) (3*kx); s->abc_valid = TRUE; } @@ -284,7 +284,7 @@ static void estimate(pa_smoother *s, pa_usec_t x, pa_usec_t *y, double *deriv) { /* The requested point is right of the point where we wanted * to be on track again, thus just linearly estimate */ - t = (int64_t) s->py + (int64_t) (s->dp * (x - s->px)); + t = (int64_t) s->py + (int64_t) llrint(s->dp * (double) (x - s->px)); if (t < 0) t = 0; @@ -313,7 +313,7 @@ static void estimate(pa_smoother *s, pa_usec_t x, pa_usec_t *y, double *deriv) { /* Move back from origin */ ty += (double) s->ey; - *y = ty >= 0 ? (pa_usec_t) ty : 0; + *y = ty >= 0 ? (pa_usec_t) llrint(ty) : 0; /* Horner scheme */ if (deriv) @@ -360,7 +360,7 @@ void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) { /* And calculate when we want to be on track again */ s->px = s->ex + s->adjust_time; - s->py = s->ry + s->dp *s->adjust_time; + s->py = s->ry + (pa_usec_t) llrint(s->dp * (double) s->adjust_time); s->abc_valid = FALSE; @@ -456,7 +456,7 @@ pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay) /* pa_log_debug("translate(%llu) = %llu (%0.2f)", (unsigned long long) y_delay, (unsigned long long) ((double) y_delay / nde), nde); */ - return (pa_usec_t) ((double) y_delay / nde); + return (pa_usec_t) llrint((double) y_delay / nde); } void pa_smoother_reset(pa_smoother *s) { diff --git a/src/pulsecore/tokenizer.c b/src/pulsecore/tokenizer.c index d1e0836b..07a9f3ac 100644 --- a/src/pulsecore/tokenizer.c +++ b/src/pulsecore/tokenizer.c @@ -34,7 +34,7 @@ #include "tokenizer.h" -static void token_free(void *p, PA_GCC_UNUSED void *userdata) { +static void token_free(void *p, void *userdata) { pa_xfree(p); } diff --git a/src/pulsecore/x11prop.c b/src/pulsecore/x11prop.c index 9e75f63a..7f91ba3c 100644 --- a/src/pulsecore/x11prop.c +++ b/src/pulsecore/x11prop.c @@ -32,7 +32,7 @@ void pa_x11_set_prop(Display *d, const char *name, const char *data) { Atom a = XInternAtom(d, name, False); - XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, strlen(data)+1); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, (int) (strlen(data)+1)); } void pa_x11_del_prop(Display *d, const char *name) { @@ -49,7 +49,7 @@ char* pa_x11_get_prop(Display *d, const char *name, char *p, size_t l) { char *ret = NULL; Atom a = XInternAtom(d, name, False); - if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (l+2)/4, False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) + if (XGetWindowProperty(d, RootWindow(d, 0), a, 0, (long) ((l+2)/4), False, XA_STRING, &actual_type, &actual_format, &nitems, &nbytes_after, &prop) != Success) goto finish; if (actual_type != XA_STRING) diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c index 17f8e6a4..332ebb2e 100644 --- a/src/pulsecore/x11wrap.c +++ b/src/pulsecore/x11wrap.c @@ -91,7 +91,7 @@ static void work(pa_x11_wrapper *w) { } /* IO notification event for the X11 display connection */ -static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { +static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_x11_wrapper *w = userdata; pa_assert(m); @@ -118,7 +118,7 @@ static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { } /* IO notification event for X11 internal connections */ -static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { +static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_x11_wrapper *w = userdata; pa_assert(m); |